diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..5e724b4e0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,36 @@ +[submodule "LoopKit"] + path = LoopKit + url = https://github.com/LoopKit/LoopKit.git + branch = dev +[submodule "CGMBLEKit"] + path = CGMBLEKit + url = https://github.com/LoopKit/CGMBLEKit.git + branch = dev +[submodule "dexcom-share-client-swift"] + path = dexcom-share-client-swift + url = https://github.com/LoopKit/dexcom-share-client-swift.git + branch = dev +[submodule "RileyLinkKit"] + path = RileyLinkKit + url = https://github.com/LoopKit/RileyLinkKit + branch = dev +[submodule "OmniBLE"] + path = OmniBLE + url = https://github.com/LoopKit/OmniBLE.git + branch = dev +[submodule "G7SensorKit"] + path = G7SensorKit + url = https://github.com/LoopKit/G7SensorKit.git + branch = main +[submodule "OmniKit"] + path = OmniKit + url = https://github.com/LoopKit/OmniKit.git + branch = main +[submodule "MinimedKit"] + path = MinimedKit + url = https://github.com/LoopKit/MinimedKit.git + branch = main +[submodule "LibreTransmitter"] + path = LibreTransmitter + url = https://github.com/LoopKit/LibreTransmitter.git + branch = main diff --git a/CGMBLEKit b/CGMBLEKit new file mode 160000 index 000000000..4eb3c940b --- /dev/null +++ b/CGMBLEKit @@ -0,0 +1 @@ +Subproject commit 4eb3c940b0e99ae2715fc6462babd2597d46a845 diff --git a/Dependencies/CGMBLEKit/.gitignore b/Dependencies/CGMBLEKit/.gitignore deleted file mode 100644 index 5c13bfd07..000000000 --- a/Dependencies/CGMBLEKit/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -# OS X -.DS_Store - -# Xcode -build/ -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata -*.xccheckout -profile -*.moved-aside -DerivedData -*.hmap -*.ipa - -# Bundler -.bundle - -Carthage -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control -# -# Note: if you ignore the Pods directory, make sure to uncomment -# `pod install` in .travis.yml -# - -Pods/ -Carthage/ -.gitmodules diff --git a/Dependencies/CGMBLEKit/.travis.yml b/Dependencies/CGMBLEKit/.travis.yml deleted file mode 100644 index a3bec9909..000000000 --- a/Dependencies/CGMBLEKit/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: objective-c -osx_image: xcode12.2 - -before_script: - - ./Scripts/carthage.sh bootstrap - -script: - # Build frameworks and run tests - - travis_wait 25 xcodebuild -project CGMBLEKit.xcodeproj -scheme Shared build -destination name="iPhone 8" test | xcpretty - # Build apps - - xcodebuild -project CGMBLEKit.xcodeproj -scheme "CGMBLEKit Example" build -destination name="iPhone 8" | xcpretty - - xcodebuild -project CGMBLEKit.xcodeproj -scheme ResetTransmitter build -destination name="iPhone 8" - diff --git a/Dependencies/CGMBLEKit/CGMBLEKit Example/AppDelegate.swift b/Dependencies/CGMBLEKit/CGMBLEKit Example/AppDelegate.swift deleted file mode 100644 index aec716519..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit Example/AppDelegate.swift +++ /dev/null @@ -1,140 +0,0 @@ -// -// AppDelegate.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 10/1/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import CGMBLEKit -import CoreBluetooth - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate, TransmitterDelegate, TransmitterCommandSource { - - var window: UIWindow? - - static var sharedDelegate: AppDelegate { - return UIApplication.shared.delegate as! AppDelegate - } - - var transmitterID: String? { - didSet { - if let id = transmitterID { - transmitter = Transmitter( - id: id, - passiveModeEnabled: UserDefaults.standard.passiveModeEnabled - ) - transmitter?.stayConnected = UserDefaults.standard.stayConnected - transmitter?.delegate = self - transmitter?.commandSource = self - - UserDefaults.standard.transmitterID = id - } - glucose = nil - } - } - - var transmitter: Transmitter? - - let commandQueue = CommandQueue() - - var glucose: Glucose? - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - - transmitterID = UserDefaults.standard.transmitterID - - return true - } - - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - - if let transmitter = transmitter, !transmitter.stayConnected { - transmitter.stopScanning() - } - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - - transmitter?.resumeScanning() - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - // MARK: - TransmitterDelegate - - private let dateFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - - dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" - dateFormatter.locale = Locale(identifier: "en_US_POSIX") - - return dateFormatter - }() - - func dequeuePendingCommand(for transmitter: Transmitter) -> Command? { - return commandQueue.dequeue() - } - - func transmitter(_ transmitter: Transmitter, didFail command: Command, with error: Error) { - // TODO: implement - } - - func transmitter(_ transmitter: Transmitter, didComplete command: Command) { - // TODO: implement - } - - func transmitter(_ transmitter: Transmitter, didError error: Error) { - DispatchQueue.main.async { - if let vc = self.window?.rootViewController as? TransmitterDelegate { - vc.transmitter(transmitter, didError: error) - } - } - } - - func transmitter(_ transmitter: Transmitter, didRead glucose: Glucose) { - self.glucose = glucose - DispatchQueue.main.async { - if let vc = self.window?.rootViewController as? TransmitterDelegate { - vc.transmitter(transmitter, didRead: glucose) - } - } - } - - func transmitter(_ transmitter: Transmitter, didReadUnknownData data: Data) { - DispatchQueue.main.async { - if let vc = self.window?.rootViewController as? TransmitterDelegate { - vc.transmitter(transmitter, didReadUnknownData: data) - } - } - } - - func transmitter(_ transmitter: Transmitter, didReadBackfill glucose: [Glucose]) { - DispatchQueue.main.async { - if let vc = self.window?.rootViewController as? TransmitterDelegate { - vc.transmitter(transmitter, didReadBackfill: glucose) - } - } - } - - func transmitterDidConnect(_ transmitter: Transmitter) { - // Ignore - } - -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit Example/Assets.xcassets/AppIcon.appiconset/Contents.json b/Dependencies/CGMBLEKit/CGMBLEKit Example/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d8db8d65f..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit Example/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x" - }, - { - "idiom" : "ios-marketing", - "size" : "1024x1024", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/CGMBLEKit/CGMBLEKit Example/Base.lproj/LaunchScreen.storyboard b/Dependencies/CGMBLEKit/CGMBLEKit Example/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f83f6fd58..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit Example/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/CGMBLEKit/CGMBLEKit Example/Base.lproj/Main.storyboard b/Dependencies/CGMBLEKit/CGMBLEKit Example/Base.lproj/Main.storyboard deleted file mode 100644 index be42d9a18..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit Example/Base.lproj/Main.storyboard +++ /dev/null @@ -1,172 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/CGMBLEKit/CGMBLEKit Example/CommandQueue.swift b/Dependencies/CGMBLEKit/CGMBLEKit Example/CommandQueue.swift deleted file mode 100644 index b1aab75f3..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit Example/CommandQueue.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// CommandQueue.swift -// CGMBLEKit Example -// -// Created by Paul Dickens on 25/03/2018. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import CGMBLEKit - - -class CommandQueue { - private var list = Array() - private var lock = os_unfair_lock() - - func enqueue(_ element: Command) { - os_unfair_lock_lock(&lock) - list.append(element) - os_unfair_lock_unlock(&lock) - } - - func dequeue() -> Command? { - os_unfair_lock_lock(&lock) - defer { - os_unfair_lock_unlock(&lock) - } - if !list.isEmpty { - return list.removeFirst() - } else { - return nil - } - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit Example/Info.plist b/Dependencies/CGMBLEKit/CGMBLEKit Example/Info.plist deleted file mode 100644 index ac35d2b38..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit Example/Info.plist +++ /dev/null @@ -1,49 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 3.2 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UIBackgroundModes - - bluetooth-central - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Dependencies/CGMBLEKit/CGMBLEKit Example/NSUserDefaults.swift b/Dependencies/CGMBLEKit/CGMBLEKit Example/NSUserDefaults.swift deleted file mode 100644 index f9bd3a623..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit Example/NSUserDefaults.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// NSUserDefaults.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 11/24/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension UserDefaults { - var passiveModeEnabled: Bool { - get { - return bool(forKey: "passiveModeEnabled") - } - set { - set(newValue, forKey: "passiveModeEnabled") - } - } - - var stayConnected: Bool { - get { - return object(forKey: "stayConnected") != nil ? bool(forKey: "stayConnected") : true - } - set { - set(newValue, forKey: "stayConnected") - } - } - - var transmitterID: String { - get { - return string(forKey: "transmitterID") ?? "500000" - } - set { - set(newValue, forKey: "transmitterID") - } - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit Example/ViewController.swift b/Dependencies/CGMBLEKit/CGMBLEKit Example/ViewController.swift deleted file mode 100644 index f1d276699..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit Example/ViewController.swift +++ /dev/null @@ -1,200 +0,0 @@ -// -// ViewController.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 10/1/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import HealthKit -import CGMBLEKit - -class ViewController: UIViewController, TransmitterDelegate, UITextFieldDelegate { - - @IBOutlet weak var titleLabel: UILabel! - - @IBOutlet weak var subtitleLabel: UILabel! - - @IBOutlet weak var passiveModeEnabledSwitch: UISwitch! - - @IBOutlet weak var stayConnectedSwitch: UISwitch! - - @IBOutlet weak var transmitterIDField: UITextField! - - @IBOutlet weak var scanningIndicatorView: UIActivityIndicatorView! - - override func viewDidLoad() { - super.viewDidLoad() - - passiveModeEnabledSwitch.isOn = AppDelegate.sharedDelegate.transmitter?.passiveModeEnabled ?? false - - stayConnectedSwitch.isOn = AppDelegate.sharedDelegate.transmitter?.stayConnected ?? false - - transmitterIDField.text = AppDelegate.sharedDelegate.transmitter?.ID - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - updateIndicatorViewDisplay() - } - - // MARK: - Actions - - func updateIndicatorViewDisplay() { - if let transmitter = AppDelegate.sharedDelegate.transmitter, transmitter.isScanning { - scanningIndicatorView.startAnimating() - } else { - scanningIndicatorView.stopAnimating() - } - } - - @IBAction func toggleStayConnected(_ sender: UISwitch) { - AppDelegate.sharedDelegate.transmitter?.stayConnected = sender.isOn - UserDefaults.standard.stayConnected = sender.isOn - - updateIndicatorViewDisplay() - } - - @IBAction func togglePassiveMode(_ sender: UISwitch) { - AppDelegate.sharedDelegate.transmitter?.passiveModeEnabled = sender.isOn - UserDefaults.standard.passiveModeEnabled = sender.isOn - } - - @IBAction func start(_ sender: UIButton) { - let dialog = UIAlertController(title: "Confirm", message: "Start sensor session.", preferredStyle: .alert) - - dialog.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action: UIAlertAction!) in - AppDelegate.sharedDelegate.commandQueue.enqueue(.startSensor(at: Date())) - })) - - dialog.addAction(UIAlertAction(title: "Cancel", style: .cancel)) - - present(dialog, animated: true, completion: nil) - } - - @IBAction func calibrate(_ sender: UIButton) { - let dialog = UIAlertController(title: "Enter BG", message: "Calibrate sensor.", preferredStyle: .alert) - - let unit = HKUnit.milligramsPerDeciliter - - dialog.addTextField { (textField : UITextField!) in - textField.placeholder = unit.unitString - textField.keyboardType = .numberPad - } - - dialog.addAction(UIAlertAction(title: "Calibrate", style: .default, handler: { (action: UIAlertAction!) in - let textField = dialog.textFields![0] as UITextField - let minGlucose = HKQuantity(unit: HKUnit.milligramsPerDeciliter, doubleValue: 40) - let maxGlucose = HKQuantity(unit: HKUnit.milligramsPerDeciliter, doubleValue: 400) - - if let text = textField.text, let entry = Double(text) { - guard entry >= minGlucose.doubleValue(for: unit) && entry <= maxGlucose.doubleValue(for: unit) else { - // TODO: notify the user if the glucose is not in range - return - } - let glucose = HKQuantity(unit: unit, doubleValue: Double(entry)) - AppDelegate.sharedDelegate.commandQueue.enqueue(.calibrateSensor(to: glucose, at: Date())) - } - })) - - dialog.addAction(UIAlertAction(title: "Cancel", style: .cancel)) - - present(dialog, animated: true, completion: nil) - } - - @IBAction func stop(_ sender: UIButton) { - let dialog = UIAlertController(title: "Confirm", message: "Stop sensor session.", preferredStyle: .alert) - - dialog.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action: UIAlertAction!) in - AppDelegate.sharedDelegate.commandQueue.enqueue(.stopSensor(at: Date())) - })) - - dialog.addAction(UIAlertAction(title: "Cancel", style: .cancel)) - - present(dialog, animated: true, completion: nil) - } - - // MARK: - UITextFieldDelegate - - func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - if let text = textField.text { - let newString = text.replacingCharacters(in: range.rangeOfString(text), with: string) - - if newString.count > 6 { - return false - } else if newString.count == 6 { - AppDelegate.sharedDelegate.transmitterID = newString - textField.text = newString - - textField.resignFirstResponder() - - return false - } - } - - return true - } - - func textFieldDidEndEditing(_ textField: UITextField) { - if textField.text?.count != 6 { - textField.text = UserDefaults.standard.transmitterID - } - } - - func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { - return true - } - - func textFieldShouldReturn(_ textField: UITextField) -> Bool { - return true - } - - // MARK: - TransmitterDelegate - - func transmitter(_ transmitter: Transmitter, didError error: Error) { - print("Transmitter Error: \(error)") - titleLabel.text = NSLocalizedString("Error", comment: "Title displayed during error response") - - subtitleLabel.text = "\(error)" - } - - func transmitter(_ transmitter: Transmitter, didRead glucose: Glucose) { - let unit = HKUnit.milligramsPerDeciliter - if let value = glucose.glucose?.doubleValue(for: unit) { - titleLabel.text = "\(value) \(unit.unitString)" - } else { - titleLabel.text = String(describing: glucose.state) - } - - - let date = glucose.readDate - subtitleLabel.text = DateFormatter.localizedString(from: date, dateStyle: .none, timeStyle: .long) - } - - func transmitter(_ transmitter: Transmitter, didReadUnknownData data: Data) { - titleLabel.text = NSLocalizedString("Unknown Data", comment: "Title displayed during unknown data response") - subtitleLabel.text = data.hexadecimalString - } - - func transmitter(_ transmitter: Transmitter, didReadBackfill glucose: [Glucose]) { - titleLabel.text = NSLocalizedString("Backfill", comment: "Title displayed during backfill response") - subtitleLabel.text = String(describing: glucose.map { $0.glucose }) - } - - func transmitterDidConnect(_ transmitter: Transmitter) { - // Ignore - } - -} - - -private extension NSRange { - func rangeOfString(_ string: String) -> Range { - let startIndex = string.index(string.startIndex, offsetBy: location) - let endIndex = string.index(startIndex, offsetBy: length) - return startIndex.. - - - - diff --git a/Dependencies/CGMBLEKit/CGMBLEKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dependencies/CGMBLEKit/CGMBLEKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Dependencies/CGMBLEKit/CGMBLEKit.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Dependencies/CGMBLEKit/CGMBLEKit.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index 08de0be8d..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded - - - diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/AESCrypt.h b/Dependencies/CGMBLEKit/CGMBLEKit/AESCrypt.h deleted file mode 100644 index 357420d60..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/AESCrypt.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// AESCrypt.h -// xDripG5 -// -// Created by Nate Racklyeft on 6/17/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -#import - -@interface AESCrypt : NSObject - -NS_ASSUME_NONNULL_BEGIN - -+ (nullable NSData *)encryptData:(NSData *)data usingKey:(NSData *)key error:(NSError **)error; - -NS_ASSUME_NONNULL_END - -@end diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/AESCrypt.m b/Dependencies/CGMBLEKit/CGMBLEKit/AESCrypt.m deleted file mode 100644 index 1a0df4a1b..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/AESCrypt.m +++ /dev/null @@ -1,33 +0,0 @@ -// -// AESCrypt.m -// xDripG5 -// -// Created by Nate Racklyeft on 6/17/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -#import "AESCrypt.h" -#import - -@implementation AESCrypt - -+ (NSData *)encryptData:(NSData *)data usingKey:(NSData *)key error:(NSError * _Nullable __autoreleasing *)error -{ - NSMutableData *dataOut = [NSMutableData dataWithLength: data.length + kCCBlockSizeAES128]; - - CCCryptorStatus status = CCCrypt(kCCEncrypt, - kCCAlgorithmAES, - kCCOptionECBMode, - key.bytes, - key.length, - NULL, - data.bytes, - data.length, - dataOut.mutableBytes, - dataOut.length, - NULL); - - return status == kCCSuccess ? dataOut : nil; -} - -@end diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Base.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/Base.lproj/Localizable.strings deleted file mode 100644 index 864a138e0..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Base.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* Describes a low battery */ -"Low Battery" = "Low Battery"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Peripheral command was invalid"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Peripheral did not respond in time"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Peripheral isnʼt connected"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Sensor calibration is OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Sensor needs calibration"; - -/* Error description */ -"Unknown characteristic" = "Unknown characteristic"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/BluetoothManager.swift b/Dependencies/CGMBLEKit/CGMBLEKit/BluetoothManager.swift deleted file mode 100644 index 556bd2e39..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/BluetoothManager.swift +++ /dev/null @@ -1,350 +0,0 @@ -// -// BluetoothManager.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 10/1/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import CoreBluetooth -import Foundation -import os.log - - -protocol BluetoothManagerDelegate: AnyObject { - - /** - Tells the delegate that the bluetooth manager has finished connecting to and discovering all required services of its peripheral, or that it failed to do so - - - parameter manager: The bluetooth manager - - parameter peripheralManager: The peripheral manager - - parameter error: An error describing why bluetooth setup failed - */ - func bluetoothManager(_ manager: BluetoothManager, peripheralManager: PeripheralManager, isReadyWithError error: Error?) - - /** - Asks the delegate whether the discovered or restored peripheral should be connected - - - parameter manager: The bluetooth manager - - parameter peripheral: The found peripheral - - - returns: True if the peripheral should connect - */ - func bluetoothManager(_ manager: BluetoothManager, shouldConnectPeripheral peripheral: CBPeripheral) -> Bool - - /// Informs the delegate that the bluetooth manager received new data in the control characteristic - /// - /// - Parameters: - /// - manager: The bluetooth manager - /// - peripheralManager: The peripheral manager - /// - response: The data received on the control characteristic - func bluetoothManager(_ manager: BluetoothManager, peripheralManager: PeripheralManager, didReceiveControlResponse response: Data) - - /// Informs the delegate that the bluetooth manager received new data in the backfill characteristic - /// - /// - Parameters: - /// - manager: The bluetooth manager - /// - response: The data received on the backfill characteristic - func bluetoothManager(_ manager: BluetoothManager, didReceiveBackfillResponse response: Data) - - /// Informs the delegate that the bluetooth manager received new data in the authentication characteristic - /// - /// - Parameters: - /// - manager: The bluetooth manager - /// - peripheralManager: The peripheral manager - /// - response: The data received on the authentication characteristic - func bluetoothManager(_ manager: BluetoothManager, peripheralManager: PeripheralManager, didReceiveAuthenticationResponse response: Data) -} - - -class BluetoothManager: NSObject { - - var stayConnected: Bool { - get { - return lockedStayConnected.value - } - set { - lockedStayConnected.value = newValue - } - } - private let lockedStayConnected: Locked = Locked(true) - - weak var delegate: BluetoothManagerDelegate? - - private let log = OSLog(category: "BluetoothManager") - - /// Isolated to `managerQueue` - private var manager: CBCentralManager! = nil - - /// Isolated to `managerQueue` - private var peripheral: CBPeripheral? { - get { - return peripheralManager?.peripheral - } - set { - guard let peripheral = newValue else { - peripheralManager = nil - return - } - - if let peripheralManager = peripheralManager { - peripheralManager.peripheral = peripheral - } else { - peripheralManager = PeripheralManager( - peripheral: peripheral, - configuration: .dexcomG5, - centralManager: manager - ) - } - } - } - - var peripheralIdentifier: UUID? { - get { - return lockedPeripheralIdentifier.value - } - set { - lockedPeripheralIdentifier.value = newValue - } - } - private let lockedPeripheralIdentifier: Locked = Locked(nil) - - /// Isolated to `managerQueue` - private var peripheralManager: PeripheralManager? { - didSet { - oldValue?.delegate = nil - peripheralManager?.delegate = self - - peripheralIdentifier = peripheralManager?.peripheral.identifier - } - } - - // MARK: - Synchronization - - private let managerQueue = DispatchQueue(label: "com.loudnate.CGMBLEKit.bluetoothManagerQueue", qos: .unspecified) - - override init() { - super.init() - - managerQueue.sync { - self.manager = CBCentralManager(delegate: self, queue: managerQueue, options: [CBCentralManagerOptionRestoreIdentifierKey: "com.loudnate.CGMBLEKit"]) - } - } - - // MARK: - Actions - - func scanForPeripheral() { - dispatchPrecondition(condition: .notOnQueue(managerQueue)) - - managerQueue.sync { - self.managerQueue_scanForPeripheral() - } - } - - func disconnect() { - dispatchPrecondition(condition: .notOnQueue(managerQueue)) - - managerQueue.sync { - if manager.isScanning { - manager.stopScan() - } - - if let peripheral = peripheral { - manager.cancelPeripheralConnection(peripheral) - } - } - } - - private func managerQueue_scanForPeripheral() { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - guard manager.state == .poweredOn else { - return - } - - let currentState = peripheral?.state ?? .disconnected - guard currentState != .connected else { - return - } - - if let peripheralID = peripheralIdentifier, let peripheral = manager.retrievePeripherals(withIdentifiers: [peripheralID]).first { - log.debug("Re-connecting to known peripheral %{public}@", peripheral.identifier.uuidString) - self.peripheral = peripheral - self.manager.connect(peripheral) - } else if let peripheral = manager.retrieveConnectedPeripherals(withServices: [ - TransmitterServiceUUID.advertisement.cbUUID, - TransmitterServiceUUID.cgmService.cbUUID - ]).first, - delegate == nil || delegate!.bluetoothManager(self, shouldConnectPeripheral: peripheral) - { - log.debug("Found system-connected peripheral: %{public}@", peripheral.identifier.uuidString) - self.peripheral = peripheral - self.manager.connect(peripheral) - } else { - log.debug("Scanning for peripherals") - manager.scanForPeripherals(withServices: [ - TransmitterServiceUUID.advertisement.cbUUID - ], - options: nil - ) - } - } - - /** - - Persistent connections don't seem to work with the transmitter shutoff: The OS won't re-wake the - app unless it's scanning. - - The sleep gives the transmitter time to shut down, but keeps the app running. - - */ - fileprivate func scanAfterDelay() { - DispatchQueue.global(qos: .utility).async { - Thread.sleep(forTimeInterval: 2) - - self.scanForPeripheral() - } - } - - // MARK: - Accessors - - var isScanning: Bool { - dispatchPrecondition(condition: .notOnQueue(managerQueue)) - - var isScanning = false - managerQueue.sync { - isScanning = manager.isScanning - } - return isScanning - } - - override var debugDescription: String { - return [ - "## BluetoothManager", - peripheralManager.map(String.init(reflecting:)) ?? "No peripheral", - ].joined(separator: "\n") - } -} - - -extension BluetoothManager: CBCentralManagerDelegate { - func centralManagerDidUpdateState(_ central: CBCentralManager) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - peripheralManager?.centralManagerDidUpdateState(central) - log.default("%{public}@: %{public}@", #function, String(describing: central.state.rawValue)) - - switch central.state { - case .poweredOn: - managerQueue_scanForPeripheral() - case .resetting, .poweredOff, .unauthorized, .unknown, .unsupported: - fallthrough - @unknown default: - if central.isScanning { - central.stopScan() - } - } - } - - func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey] as? [CBPeripheral] { - for peripheral in peripherals { - if delegate == nil || delegate!.bluetoothManager(self, shouldConnectPeripheral: peripheral) { - log.default("Restoring peripheral from state: %{public}@", peripheral.identifier.uuidString) - self.peripheral = peripheral - } - } - } - } - - func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - log.info("%{public}@: %{public}@", #function, peripheral) - if delegate == nil || delegate!.bluetoothManager(self, shouldConnectPeripheral: peripheral) { - self.peripheral = peripheral - - central.connect(peripheral, options: nil) - - central.stopScan() - } - } - - func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - log.default("%{public}@: %{public}@", #function, peripheral) - if central.isScanning { - central.stopScan() - } - - peripheralManager?.centralManager(central, didConnect: peripheral) - - if case .poweredOn = manager.state, case .connected = peripheral.state, let peripheralManager = peripheralManager { - self.delegate?.bluetoothManager(self, peripheralManager: peripheralManager, isReadyWithError: nil) - } - } - - func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - log.default("%{public}@: %{public}@", #function, peripheral) - // Ignore errors indicating the peripheral disconnected remotely, as that's expected behavior - if let error = error as NSError?, CBError(_nsError: error).code != .peripheralDisconnected { - log.error("%{public}@: %{public}@", #function, error) - if let peripheralManager = peripheralManager { - self.delegate?.bluetoothManager(self, peripheralManager: peripheralManager, isReadyWithError: error) - } - } - - if stayConnected { - scanAfterDelay() - } - } - - func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - log.error("%{public}@: %{public}@", #function, String(describing: error)) - if let error = error, let peripheralManager = peripheralManager { - self.delegate?.bluetoothManager(self, peripheralManager: peripheralManager, isReadyWithError: error) - } - - if stayConnected { - scanAfterDelay() - } - } -} - - -extension BluetoothManager: PeripheralManagerDelegate { - func peripheralManager(_ manager: PeripheralManager, didReadRSSI RSSI: NSNumber, error: Error?) { - - } - - func peripheralManagerDidUpdateName(_ manager: PeripheralManager) { - - } - - func completeConfiguration(for manager: PeripheralManager) throws { - - } - - func peripheralManager(_ manager: PeripheralManager, didUpdateValueFor characteristic: CBCharacteristic) { - guard let value = characteristic.value else { - return - } - - switch CGMServiceCharacteristicUUID(rawValue: characteristic.uuid.uuidString.uppercased()) { - case .none, .communication?: - return - case .control?: - self.delegate?.bluetoothManager(self, peripheralManager: manager, didReceiveControlResponse: value) - case .backfill?: - self.delegate?.bluetoothManager(self, didReceiveBackfillResponse: value) - case .authentication?: - self.delegate?.bluetoothManager(self, peripheralManager: manager, didReceiveAuthenticationResponse: value) - } - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/BluetoothServices.swift b/Dependencies/CGMBLEKit/CGMBLEKit/BluetoothServices.swift deleted file mode 100644 index 85cce9cc7..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/BluetoothServices.swift +++ /dev/null @@ -1,87 +0,0 @@ -// -// BluetoothServices.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 10/16/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import CoreBluetooth - -/* -G5 BLE attributes, retrieved using LightBlue on 2015-10-01 - -These are the G4 details, for reference: -https://github.com/StephenBlackWasAlreadyTaken/xDrip/blob/af20e32652d19aa40becc1a39f6276cad187fdce/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/DexShareAttributes.java -*/ - -protocol CBUUIDRawValue: RawRepresentable {} -extension CBUUIDRawValue where RawValue == String { - var cbUUID: CBUUID { - return CBUUID(string: rawValue) - } -} - - -enum TransmitterServiceUUID: String, CBUUIDRawValue { - case deviceInfo = "180A" - case advertisement = "FEBC" - case cgmService = "F8083532-849E-531C-C594-30F1F86A4EA5" - - case serviceB = "F8084532-849E-531C-C594-30F1F86A4EA5" -} - - -enum DeviceInfoCharacteristicUUID: String, CBUUIDRawValue { - // Read - // "DexcomUN" - case manufacturerNameString = "2A29" -} - - -enum CGMServiceCharacteristicUUID: String, CBUUIDRawValue { - - // Read/Notify - case communication = "F8083533-849E-531C-C594-30F1F86A4EA5" - - // Write/Indicate - case control = "F8083534-849E-531C-C594-30F1F86A4EA5" - - // Write/Indicate - case authentication = "F8083535-849E-531C-C594-30F1F86A4EA5" - - // Read/Write/Notify - case backfill = "F8083536-849E-531C-C594-30F1F86A4EA5" - -// // Unknown attribute present on older G6 transmitters -// case unknown1 = "F8083537-849E-531C-C594-30F1F86A4EA5" -// -// // Updated G6 characteristic (read/notify) -// case unknown2 = "F8083538-849E-531C-C594-30F1F86A4EA5" -} - - -enum ServiceBCharacteristicUUID: String, CBUUIDRawValue { - // Write/Indicate - case characteristicE = "F8084533-849E-531C-C594-30F1F86A4EA5" - // Read/Write/Notify - case characteristicF = "F8084534-849E-531C-C594-30F1F86A4EA5" -} - - -extension PeripheralManager.Configuration { - static var dexcomG5: PeripheralManager.Configuration { - return PeripheralManager.Configuration( - serviceCharacteristics: [ - TransmitterServiceUUID.cgmService.cbUUID: [ - CGMServiceCharacteristicUUID.communication.cbUUID, - CGMServiceCharacteristicUUID.authentication.cbUUID, - CGMServiceCharacteristicUUID.control.cbUUID, - CGMServiceCharacteristicUUID.backfill.cbUUID, - ] - ], - notifyingCharacteristics: [:], - valueUpdateMacros: [:] - ) - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/CBPeripheral.swift b/Dependencies/CGMBLEKit/CGMBLEKit/CBPeripheral.swift deleted file mode 100644 index f64494c4a..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/CBPeripheral.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// CBPeripheral.swift -// xDripG5 -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import CoreBluetooth - - -// MARK: - Discovery helpers. -extension CBPeripheral { - func servicesToDiscover(from serviceUUIDs: [CBUUID]) -> [CBUUID] { - let knownServiceUUIDs = services?.compactMap({ $0.uuid }) ?? [] - return serviceUUIDs.filter({ !knownServiceUUIDs.contains($0) }) - } - - func characteristicsToDiscover(from characteristicUUIDs: [CBUUID], for service: CBService) -> [CBUUID] { - let knownCharacteristicUUIDs = service.characteristics?.compactMap({ $0.uuid }) ?? [] - return characteristicUUIDs.filter({ !knownCharacteristicUUIDs.contains($0) }) - } -} - - -extension Collection where Element: CBAttribute { - func itemWithUUID(_ uuid: CBUUID) -> Element? { - for attribute in self { - if attribute.uuid == uuid { - return attribute - } - } - - return nil - } - - func itemWithUUIDString(_ uuidString: String) -> Element? { - for attribute in self { - if attribute.uuid.uuidString == uuidString { - return attribute - } - } - - return nil - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/CGMBLEKit.h b/Dependencies/CGMBLEKit/CGMBLEKit/CGMBLEKit.h deleted file mode 100644 index 49882cc8e..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/CGMBLEKit.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// CGMBLEKit.h -// xDripG5 -// -// Created by Nathan Racklyeft on 12/30/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -#import -#import - -//! Project version number for CGMBLEKIt. -FOUNDATION_EXPORT double CGMBLEKitVersionNumber; - -//! Project version string for CGMBLEKit. -FOUNDATION_EXPORT const unsigned char CGMBLEKitVersionString[]; - diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Calibration.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Calibration.swift deleted file mode 100644 index fd05c906d..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Calibration.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// Calibration.swift -// xDripG5 -// -// Created by Paul Dickens on 17/03/2018. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - - -public struct Calibration { - init?(calibrationMessage: CalibrationDataRxMessage, activationDate: Date) { - guard calibrationMessage.glucose > 0 else { - return nil - } - - let unit = HKUnit.milligramsPerDeciliter - - glucose = HKQuantity(unit: unit, doubleValue: Double(calibrationMessage.glucose)) - date = activationDate.addingTimeInterval(TimeInterval(calibrationMessage.timestamp)) - } - - public let glucose: HKQuantity - public let date: Date -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/CalibrationState.swift b/Dependencies/CGMBLEKit/CGMBLEKit/CalibrationState.swift deleted file mode 100644 index 97ef0bc70..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/CalibrationState.swift +++ /dev/null @@ -1,106 +0,0 @@ -// -// CalibrationState.swift -// xDripG5 -// -// Created by Nate Racklyeft on 8/6/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public enum CalibrationState: RawRepresentable { - public typealias RawValue = UInt8 - - public enum State: RawValue { - case stopped = 1 - case warmup = 2 - - case needFirstInitialCalibration = 4 - case needSecondInitialCalibration = 5 - case ok = 6 - case needCalibration7 = 7 - case calibrationError8 = 8 - case calibrationError9 = 9 - case calibrationError10 = 10 - case sensorFailure11 = 11 - case sensorFailure12 = 12 - case calibrationError13 = 13 - case needCalibration14 = 14 - case sessionFailure15 = 15 - case sessionFailure16 = 16 - case sessionFailure17 = 17 - case questionMarks = 18 - } - - case known(State) - case unknown(RawValue) - - public init(rawValue: RawValue) { - guard let state = State(rawValue: rawValue) else { - self = .unknown(rawValue) - return - } - - self = .known(state) - } - - public var rawValue: RawValue { - switch self { - case .known(let state): - return state.rawValue - case .unknown(let rawValue): - return rawValue - } - } - - public var hasReliableGlucose: Bool { - guard case .known(let state) = self else { - return false - } - - switch state { - case .stopped, - .warmup, - .needFirstInitialCalibration, - .needSecondInitialCalibration, - .calibrationError8, - .calibrationError9, - .calibrationError10, - .sensorFailure11, - .sensorFailure12, - .calibrationError13, - .sessionFailure15, - .sessionFailure16, - .sessionFailure17, - .questionMarks: - return false - case .ok, .needCalibration7, .needCalibration14: - return true - } - } -} - -extension CalibrationState: Equatable { - public static func ==(lhs: CalibrationState, rhs: CalibrationState) -> Bool { - switch (lhs, rhs) { - case (.known(let lhs), .known(let rhs)): - return lhs == rhs - case (.unknown(let lhs), .unknown(let rhs)): - return lhs == rhs - default: - return false - } - } -} - -extension CalibrationState: CustomStringConvertible { - public var description: String { - switch self { - case .known(let state): - return String(describing: state) - case .unknown(let value): - return ".unknown(\(value))" - } - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Command.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Command.swift deleted file mode 100644 index c9d0e2beb..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Command.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// Command.swift -// xDripG5 -// -// Created by Paul Dickens on 22/03/2018. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - - -public enum Command: RawRepresentable { - public typealias RawValue = [String: Any] - - case startSensor(at: Date) - case stopSensor(at: Date) - case calibrateSensor(to: HKQuantity, at: Date) - case resetTransmitter - - public init?(rawValue: RawValue) { - guard let action = rawValue["action"] as? Action.RawValue else { - return nil - } - - let date = rawValue["date"] as? Date - - switch Action(rawValue: action) { - case .startSensor?: - guard let date = date else { - return nil - } - self = .startSensor(at: date) - case .stopSensor?: - guard let date = date else { - return nil - } - self = .stopSensor(at: date) - case .calibrateSensor?: - guard let date = date, let glucose = rawValue["glucose"] as? HKQuantity else { - return nil - } - self = .calibrateSensor(to: glucose, at: date) - case .resetTransmitter?: - self = .resetTransmitter - case .none: - return nil - } - } - - private enum Action: Int { - case startSensor, stopSensor, calibrateSensor, resetTransmitter - } - - public var rawValue: RawValue { - switch self { - case .startSensor(let date): - return [ - "action": Action.startSensor.rawValue, - "date": date - ] - case .stopSensor(let date): - return [ - "action": Action.stopSensor.rawValue, - "date": date - ] - case .calibrateSensor(let glucose, let date): - return [ - "action": Action.calibrateSensor.rawValue, - "date": date, - "glucose": glucose - ] - case .resetTransmitter: - return [ - "action": Action.resetTransmitter.rawValue - ] - } - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Glucose+SensorDisplayable.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Glucose+SensorDisplayable.swift deleted file mode 100644 index e37feaa4d..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Glucose+SensorDisplayable.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// GlucoseRxMessage.swift -// Loop -// -// Created by Nathan Racklyeft on 5/30/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import LoopKit - - -extension Glucose: GlucoseDisplayable { - public var isStateValid: Bool { - return state == .known(.ok) && status == .ok - } - - public var stateDescription: String { - var messages = [String]() - - switch state { - case .known(.ok): - break // Suppress the "OK" message - default: - messages.append(state.localizedDescription) - } - - switch self.status { - case .ok: - if messages.isEmpty { - messages.append(status.localizedDescription) - } else { - break // Suppress the "OK" message - } - case .lowBattery, .unknown: - messages.append(status.localizedDescription) - } - - return messages.joined(separator: ". ") - } - - public var trendType: GlucoseTrend? { - guard trend < Int(Int8.max) else { - return nil - } - - switch trend { - case let x where x <= -30: - return .downDownDown - case let x where x <= -20: - return .downDown - case let x where x <= -10: - return .down - case let x where x < 10: - return .flat - case let x where x < 20: - return .up - case let x where x < 30: - return .upUp - default: - return .upUpUp - } - } - - public var isLocal: Bool { - return true - } - - // TODO Placeholders. This functionality will come with LOOP-1311 - public var glucoseRangeCategory: GlucoseRangeCategory? { - return nil - } -} - -extension Glucose { - public var condition: GlucoseCondition? { - if glucoseMessage.glucose < GlucoseLimits.minimum { - return .belowRange - } else if glucoseMessage.glucose > GlucoseLimits.maximum { - return .aboveRange - } else { - return nil - } - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Glucose.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Glucose.swift deleted file mode 100644 index 20decf45f..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Glucose.swift +++ /dev/null @@ -1,111 +0,0 @@ -// -// Glucose.swift -// xDripG5 -// -// Created by Nate Racklyeft on 8/6/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - -enum GlucoseLimits { - static var minimum: UInt16 = 40 - static var maximum: UInt16 = 400 -} - -public struct Glucose { - let glucoseMessage: GlucoseSubMessage - let timeMessage: TransmitterTimeRxMessage - - init( - transmitterID: String, - glucoseMessage: GlucoseRxMessage, - timeMessage: TransmitterTimeRxMessage, - calibrationMessage: CalibrationDataRxMessage? = nil, - activationDate: Date - ) { - self.init( - transmitterID: transmitterID, - status: glucoseMessage.status, - glucoseMessage: glucoseMessage.glucose, - timeMessage: timeMessage, - calibrationMessage: calibrationMessage, - activationDate: activationDate - ) - } - - init( - transmitterID: String, - status: UInt8, - glucoseMessage: GlucoseSubMessage, - timeMessage: TransmitterTimeRxMessage, - calibrationMessage: CalibrationDataRxMessage? = nil, - activationDate: Date - ) { - self.transmitterID = transmitterID - self.glucoseMessage = glucoseMessage - self.timeMessage = timeMessage - self.status = TransmitterStatus(rawValue: status) - self.activationDate = activationDate - - sessionStartDate = activationDate.addingTimeInterval(TimeInterval(timeMessage.sessionStartTime)) - sessionExpDate = activationDate.addingTimeInterval(TimeInterval(timeMessage.sessionStartTime) + (10*24*60*60)) - readDate = activationDate.addingTimeInterval(TimeInterval(glucoseMessage.timestamp)) - lastCalibration = calibrationMessage != nil ? Calibration(calibrationMessage: calibrationMessage!, activationDate: activationDate) : nil - } - - // MARK: - Transmitter Info - public let transmitterID: String - public let status: TransmitterStatus - public let activationDate: Date - public let sessionStartDate: Date - public let sessionExpDate: Date - - // MARK: - Glucose Info - public let lastCalibration: Calibration? - public let readDate: Date - - public var isDisplayOnly: Bool { - return glucoseMessage.glucoseIsDisplayOnly - } - - public var glucose: HKQuantity? { - guard state.hasReliableGlucose && glucoseMessage.glucose >= 39 else { - return nil - } - - let unit = HKUnit.milligramsPerDeciliter - - return HKQuantity(unit: unit, doubleValue: Double(min(max(glucoseMessage.glucose, GlucoseLimits.minimum), GlucoseLimits.maximum))) - } - - public var state: CalibrationState { - return CalibrationState(rawValue: glucoseMessage.state) - } - - public var trend: Int { - return Int(glucoseMessage.trend) - } - - public var trendRate: HKQuantity? { - guard glucoseMessage.trend < Int8.max && glucoseMessage.trend > Int8.min else { - return nil - } - - let unit = HKUnit.milligramsPerDeciliterPerMinute - return HKQuantity(unit: unit, doubleValue: Double(glucoseMessage.trend) / 10) - } - - // An identifier for this reading thatʼs consistent between backfill/live data - public var syncIdentifier: String { - return "\(transmitterID) \(glucoseMessage.timestamp)" - } -} - - -extension Glucose: Equatable { - public static func ==(lhs: Glucose, rhs: Glucose) -> Bool { - return lhs.glucoseMessage == rhs.glucoseMessage && lhs.syncIdentifier == rhs.syncIdentifier - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Info.plist b/Dependencies/CGMBLEKit/CGMBLEKit/Info.plist deleted file mode 100644 index 1635817ed..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.2 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/AuthChallengeRxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/AuthChallengeRxMessage.swift deleted file mode 100644 index 40904d7f0..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/AuthChallengeRxMessage.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// AuthChallengeRxMessage.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 11/22/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct AuthChallengeRxMessage: TransmitterRxMessage { - let isAuthenticated: Bool - let isBonded: Bool - - init?(data: Data) { - guard data.count >= 3 else { - return nil - } - - guard data.starts(with: .authChallengeRx) else { - return nil - } - - isAuthenticated = data[1] == 0x1 - isBonded = data[2] == 0x1 - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/AuthChallengeTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/AuthChallengeTxMessage.swift deleted file mode 100644 index 6ce551cc0..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/AuthChallengeTxMessage.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// AuthChallengeTxMessage.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 11/22/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct AuthChallengeTxMessage: TransmitterTxMessage { - let challengeHash: Data - - var data: Data { - var data = Data(for: .authChallengeTx) - data.append(challengeHash) - return data - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/AuthRequestRxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/AuthRequestRxMessage.swift deleted file mode 100644 index 3843891ac..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/AuthRequestRxMessage.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// AuthRequestRxMessage.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 11/22/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct AuthRequestRxMessage: TransmitterRxMessage { - let tokenHash: Data - let challenge: Data - - init?(data: Data) { - guard data.count >= 17 else { - return nil - } - - guard data.starts(with: .authRequestRx) else { - return nil - } - - tokenHash = data.subdata(in: 1..<9) - challenge = data.subdata(in: 9..<17) - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/AuthRequestTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/AuthRequestTxMessage.swift deleted file mode 100644 index 9aaf9d585..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/AuthRequestTxMessage.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// AuthRequestTxMessage.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 11/22/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct AuthRequestTxMessage: TransmitterTxMessage { - let singleUseToken: Data - let endByte: UInt8 = 0x2 - - init() { - let uuid = UUID().uuid - - singleUseToken = Data([uuid.0, uuid.1, uuid.2, uuid.3, - uuid.4, uuid.5, uuid.6, uuid.7]) - } - - var data: Data { - var data = Data(for: .authRequestTx) - data.append(singleUseToken) - data.append(endByte) - return data - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/BatteryStatusTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/BatteryStatusTxMessage.swift deleted file mode 100644 index 8cabbe897..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/BatteryStatusTxMessage.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// BatteryStatusTxMessage.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 3/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct BatteryStatusTxMessage { - let opcode: Opcode = .batteryStatusTx - - // Response: 23003c012f01cd021f247bae -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/BondRequestTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/BondRequestTxMessage.swift deleted file mode 100644 index 70601d976..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/BondRequestTxMessage.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// BondRequestTxMessage.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 11/23/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -/// Initiates a bond with the central -struct BondRequestTxMessage: TransmitterTxMessage { - var data: Data { - return Data(for: .bondRequest) - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/CalibrateGlucoseRxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/CalibrateGlucoseRxMessage.swift deleted file mode 100644 index aaa6d8c4a..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/CalibrateGlucoseRxMessage.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// CalibrateGlucoseRxMessage.swift -// xDripG5 -// -// Created by Paul Dickens on 25/02/2018. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - - -public struct CalibrateGlucoseRxMessage: TransmitterRxMessage { - init?(data: Data) { - guard data.count == 5 && data.isCRCValid else { - return nil - } - - guard data.starts(with: .calibrateGlucoseRx) else { - return nil - } - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/CalibrateGlucoseTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/CalibrateGlucoseTxMessage.swift deleted file mode 100644 index 3b318689b..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/CalibrateGlucoseTxMessage.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// CalibrateGlucoseTxMessage.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 3/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct CalibrateGlucoseTxMessage: RespondableMessage { - typealias Response = CalibrateGlucoseRxMessage - - let time: UInt32 - let glucose: UInt16 - - var data: Data { - var data = Data(for: .calibrateGlucoseTx) - data.append(glucose) - data.append(time) - return data.appendingCRC() - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/CalibrationDataRxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/CalibrationDataRxMessage.swift deleted file mode 100644 index 1f77efe87..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/CalibrationDataRxMessage.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// CalibrationDataRxMessage.swift -// Pods -// -// Created by Nate Racklyeft on 9/18/16. -// -// - -import Foundation - - -struct CalibrationDataRxMessage: TransmitterRxMessage { - let glucose: UInt16 - let timestamp: UInt32 - - init?(data: Data) { - guard data.count == 19 && data.isCRCValid else { - return nil - } - - guard data.starts(with: .calibrationDataRx) else { - return nil - } - - glucose = data[11..<13].toInt() & 0xfff - timestamp = data[13..<17].toInt() - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/CalibrationDataTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/CalibrationDataTxMessage.swift deleted file mode 100644 index 89e42af55..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/CalibrationDataTxMessage.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// CalibrationDataTxMessage.swift -// xDripG5 -// -// Created by Paul Dickens on 17/03/2018. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - - -struct CalibrationDataTxMessage: RespondableMessage { - typealias Response = CalibrationDataRxMessage - - var data: Data { - return Data(for: .calibrationDataTx).appendingCRC() - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/DisconnectTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/DisconnectTxMessage.swift deleted file mode 100644 index 856a7319a..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/DisconnectTxMessage.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// DisconnectTxMessage.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 11/23/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct DisconnectTxMessage: TransmitterTxMessage { - var data: Data { - return Data(for: .disconnectTx) - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/FirmwareVersionTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/FirmwareVersionTxMessage.swift deleted file mode 100644 index 7578177da..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/FirmwareVersionTxMessage.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// FirmwareVersionTxMessage.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 3/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct FirmwareVersionTxMessage { - let opcode: Opcode = .firmwareVersionTx -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/GlucoseBackfillMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/GlucoseBackfillMessage.swift deleted file mode 100644 index 9030caf78..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/GlucoseBackfillMessage.swift +++ /dev/null @@ -1,122 +0,0 @@ -// -// GlucoseBackfillMessage.swift -// xDripG5 -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -// 50 05 02 00 b7ff5200 66045300 00000000 0000 7138 - -struct GlucoseBackfillTxMessage: RespondableMessage { - typealias Response = GlucoseBackfillRxMessage - - let byte1: UInt8 - let byte2: UInt8 - let identifier: UInt8 - - let startTime: UInt32 - let endTime: UInt32 - - let length: UInt32 = 0 - let backfillCRC: UInt16 = 0 - - var data: Data { - var data = Data(for: .glucoseBackfillTx) - data.append(contentsOf: [byte1, byte2, identifier]) - data.append(startTime) - data.append(endTime) - data.append(length) - data.append(backfillCRC) - - return data.appendingCRC() - } -} - -// 51 00 01 00 b7ff5200 66045300 32000000 e6cb 9805 - -struct GlucoseBackfillRxMessage: TransmitterRxMessage { - let status: UInt8 - let backfillStatus: UInt8 - let identifier: UInt8 - let startTime: UInt32 - let endTime: UInt32 - let bufferLength: UInt32 - let bufferCRC: UInt16 - - init?(data: Data) { - guard data.count == 20, - data.isCRCValid, - data.starts(with: .glucoseBackfillRx) - else { - return nil - } - - status = data[1] - backfillStatus = data[2] - identifier = data[3] - startTime = data[4..<8].toInt() - endTime = data[8..<12].toInt() - bufferLength = data[12..<16].toInt() - bufferCRC = data[16..<18].toInt() - } -} - -// 0100bc460000b7ff52008b0006eee30053008500 -// 020006eb0f025300800006ee3a0353007e0006f5 -// 030066045300790006f8 - -struct GlucoseBackfillFrameBuffer { - let identifier: UInt8 - private var frames: [Data] = [] - - init(identifier: UInt8) { - self.identifier = identifier - } - - mutating func append(_ frame: Data) { - // Byte 0 is the frame index - // Byte 1 is the identifier - guard frame.count > 2, - frame[0] == frames.count + 1, - frame[1] == identifier else { - return - } - - frames.append(frame) - } - - var count: Int { - return frames.reduce(0, { $0 + $1.count }) - } - - var crc16: UInt16 { - return frames.reduce(into: Data(), { $0.append($1) }).crc16 - } - - var glucose: [GlucoseSubMessage] { - // Drop the first 2 bytes from each frame - let data = frames.reduce(into: Data(), { $0.append($1.dropFirst(2)) }) - - // Drop the first 4 bytes from the combined message - // Byte 0: ?? - // Byte 1: ?? - // Byte 2: ?? (only seen 0 so far) - // Byte 3: ?? (only seen 0 so far) - let glucoseData = data.dropFirst(4) - - return stride( - from: glucoseData.startIndex, - to: glucoseData.endIndex, - by: GlucoseSubMessage.size - ).compactMap { - let range = $0..<$0.advanced(by: GlucoseSubMessage.size) - guard glucoseData.endIndex >= range.endIndex else { - return nil - } - - return GlucoseSubMessage(data: glucoseData[range]) - } - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/GlucoseHistoryTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/GlucoseHistoryTxMessage.swift deleted file mode 100644 index 44abfdd05..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/GlucoseHistoryTxMessage.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// GlucoseHistoryTxMessage.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 3/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct GlucoseHistoryTxMessage { - let opcode: Opcode = .glucoseHistoryTx -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/GlucoseRxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/GlucoseRxMessage.swift deleted file mode 100644 index f945d2213..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/GlucoseRxMessage.swift +++ /dev/null @@ -1,88 +0,0 @@ -// -// GlucoseRxMessage.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 11/23/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public struct GlucoseSubMessage: TransmitterRxMessage { - static let size = 8 - - public let timestamp: UInt32 - public let glucoseIsDisplayOnly: Bool - public let glucose: UInt16 - public let state: UInt8 - public let trend: Int8 - - init?(data: Data) { - guard data.count >= GlucoseSubMessage.size else { - return nil - } - - var start = data.startIndex - var end = start.advanced(by: 4) - timestamp = data[start.. 0 - glucose = glucoseBytes & 0xfff - - start = end - end = start.advanced(by: 1) - state = data[start] - - start = end - end = start.advanced(by: 1) - trend = Int8(bitPattern: data[start]) - } -} - - -public struct GlucoseRxMessage: TransmitterRxMessage { - public let status: UInt8 - public let sequence: UInt32 - public let glucose: GlucoseSubMessage - - init?(data: Data) { - guard data.count >= 16 && data.isCRCValid else { - return nil - } - - guard data.starts(with: .glucoseRx) || data.starts(with: .glucoseG6Rx) else { - return nil - } - - status = data[1] - sequence = data[2..<6].toInt() - - guard let glucose = GlucoseSubMessage(data: data[6...]) else { - return nil - } - self.glucose = glucose - } -} - -extension GlucoseSubMessage: Equatable { - public static func ==(lhs: GlucoseSubMessage, rhs: GlucoseSubMessage) -> Bool { - return lhs.timestamp == rhs.timestamp && - lhs.glucoseIsDisplayOnly == rhs.glucoseIsDisplayOnly && - lhs.glucose == rhs.glucose && - lhs.state == rhs.state && - lhs.trend == rhs.trend - } -} - - -extension GlucoseRxMessage: Equatable { - public static func ==(lhs: GlucoseRxMessage, rhs: GlucoseRxMessage) -> Bool { - return lhs.status == rhs.status && - lhs.sequence == rhs.sequence && - lhs.glucose == rhs.glucose - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/GlucoseTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/GlucoseTxMessage.swift deleted file mode 100644 index f20f6fa66..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/GlucoseTxMessage.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// GlucoseTxMessage.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 11/23/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct GlucoseTxMessage: RespondableMessage { - typealias Response = GlucoseRxMessage - - var data: Data { - return Data(for: .glucoseTx).appendingCRC() - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/KeepAliveTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/KeepAliveTxMessage.swift deleted file mode 100644 index 67e33c55a..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/KeepAliveTxMessage.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// KeepAliveTxMessage.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 11/23/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct KeepAliveTxMessage: TransmitterTxMessage { - let time: UInt8 - - var data: Data { - var data = Data(for: .keepAlive) - data.append(time) - return data - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/ResetMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/ResetMessage.swift deleted file mode 100644 index acaaf5d23..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/ResetMessage.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// ResetMessage.swift -// xDripG5 -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - - -struct ResetTxMessage: RespondableMessage { - typealias Response = ResetRxMessage - - var data: Data { - return Data(for: .resetTx).appendingCRC() - } -} - - -struct ResetRxMessage: TransmitterRxMessage { - let status: UInt8 - - init?(data: Data) { - guard data.count >= 2, data.starts(with: .resetRx) else { - return nil - } - - status = data[1] - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/SessionStartRxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/SessionStartRxMessage.swift deleted file mode 100644 index f38ca5f04..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/SessionStartRxMessage.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// SessionStartRxMessage.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 6/4/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct SessionStartRxMessage: TransmitterRxMessage { - let status: UInt8 - let received: UInt8 - - // I've only seen examples of these 2 values matching - let requestedStartTime: UInt32 - let sessionStartTime: UInt32 - - let transmitterTime: UInt32 - - init?(data: Data) { - guard data.count == 17 && data.isCRCValid else { - return nil - } - - guard data.starts(with: .sessionStartRx) else { - return nil - } - - status = data[1] - received = data[2] - requestedStartTime = data[3..<7].toInt() - sessionStartTime = data[7..<11].toInt() - transmitterTime = data[11..<15].toInt() - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/SessionStartTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/SessionStartTxMessage.swift deleted file mode 100644 index faa2c1513..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/SessionStartTxMessage.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// SessionStartTxMessage.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 3/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct SessionStartTxMessage: RespondableMessage { - typealias Response = SessionStartRxMessage - - /// Time since activation in Dex seconds - let startTime: UInt32 - - /// Time in seconds since Unix Epoch - let secondsSince1970: UInt32 - - var data: Data { - var data = Data(for: .sessionStartTx) - data.append(startTime) - data.append(secondsSince1970) - return data.appendingCRC() - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/SessionStopRxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/SessionStopRxMessage.swift deleted file mode 100644 index a2f86792f..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/SessionStopRxMessage.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// SessionStopRxMessage.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 6/4/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct SessionStopRxMessage: TransmitterRxMessage { - let status: UInt8 - let received: UInt8 - let sessionStopTime: UInt32 - let sessionStartTime: UInt32 - let transmitterTime: UInt32 - - init?(data: Data) { - guard data.count == 17 && data.isCRCValid else { - return nil - } - - guard data.starts(with: .sessionStopRx) else { - return nil - } - - status = data[1] - received = data[2] - sessionStopTime = data[3..<7].toInt() - sessionStartTime = data[7..<11].toInt() - transmitterTime = data[11..<15].toInt() - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/SessionStopTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/SessionStopTxMessage.swift deleted file mode 100644 index 0c320a576..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/SessionStopTxMessage.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// SessionStopTxMessage.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 3/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct SessionStopTxMessage: RespondableMessage { - typealias Response = SessionStopRxMessage - - let stopTime: UInt32 - - var data: Data { - var data = Data(for: .sessionStopTx) - data.append(stopTime) - return data.appendingCRC() - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterMessage.swift deleted file mode 100644 index f6c9908f8..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterMessage.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// TransmitterCommand.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 11/22/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -/// A data sequence written to the transmitter -protocol TransmitterTxMessage { - - /// The data to write - var data: Data { get } - -} - - -protocol RespondableMessage: TransmitterTxMessage { - associatedtype Response: TransmitterRxMessage -} - - -/// A data sequence received by the transmitter -protocol TransmitterRxMessage { - - - init?(data: Data) - -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterTimeRxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterTimeRxMessage.swift deleted file mode 100644 index 837eab755..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterTimeRxMessage.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// TransmitterTimeRxMessage.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 11/23/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct TransmitterTimeRxMessage: TransmitterRxMessage { - let status: UInt8 - let currentTime: UInt32 - let sessionStartTime: UInt32 - - init?(data: Data) { - guard data.count == 16 && data.isCRCValid else { - return nil - } - - guard data.starts(with: .transmitterTimeRx) else { - return nil - } - - status = data[1] - currentTime = data[2..<6].toInt() - sessionStartTime = data[6..<10].toInt() - - } -} - -extension TransmitterTimeRxMessage: Equatable { } - -func ==(lhs: TransmitterTimeRxMessage, rhs: TransmitterTimeRxMessage) -> Bool { - return lhs.currentTime == rhs.currentTime -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterTimeTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterTimeTxMessage.swift deleted file mode 100644 index 5f2e29e6a..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterTimeTxMessage.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// TransmitterTimeTxMessage.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 11/23/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct TransmitterTimeTxMessage: RespondableMessage { - typealias Response = TransmitterTimeRxMessage - - var data: Data { - return Data(for: .transmitterTimeTx).appendingCRC() - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterVersionRxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterVersionRxMessage.swift deleted file mode 100644 index 4854385b5..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterVersionRxMessage.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// TransmitterVersionRxMessage.swift -// xDripG5 -// -// Created by Nate Racklyeft on 9/29/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct TransmitterVersionRxMessage: TransmitterRxMessage { - let status: UInt8 - let firmwareVersion: [UInt8] - - init?(data: Data) { - guard data.count == 19 && data.isCRCValid else { - return nil - } - - guard data.starts(with: .transmitterVersionRx) else { - return nil - } - - status = data[1] - firmwareVersion = data[2..<6].map { $0 } - } - -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterVersionTxMessage.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterVersionTxMessage.swift deleted file mode 100644 index 60df2c7fd..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Messages/TransmitterVersionTxMessage.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// TransmitterVersionTxMessage.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 3/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -struct TransmitterVersionTxMessage { - typealias Response = TransmitterVersionRxMessage - - let opcode: Opcode = .transmitterVersionTx -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/NSData+CRC.swift b/Dependencies/CGMBLEKit/CGMBLEKit/NSData+CRC.swift deleted file mode 100644 index b635a1168..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/NSData+CRC.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// NSData+CRC.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 4/7/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -/** - CRC-CCITT (XModem) - - [http://www.lammertbies.nl/comm/info/crc-calculation.html]() - - [http://web.mit.edu/6.115/www/amulet/xmodem.htm]() - */ -extension Collection where Element == UInt8 { - private var crcCCITTXModem: UInt16 { - var crc: UInt16 = 0 - - for byte in self { - crc ^= UInt16(byte) << 8 - - for _ in 0..<8 { - if crc & 0x8000 != 0 { - crc = crc << 1 ^ 0x1021 - } else { - crc = crc << 1 - } - } - } - - return crc - } - - var crc16: UInt16 { - return crcCCITTXModem - } -} - - -extension UInt8 { - var crc16: UInt16 { - return [self].crc16 - } -} - - -extension Data { - var isCRCValid: Bool { - return dropLast(2).crc16 == suffix(2).toInt() - } - - func appendingCRC() -> Data { - var data = self - data.append(crc16) - return data - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/OSLog.swift b/Dependencies/CGMBLEKit/CGMBLEKit/OSLog.swift deleted file mode 100644 index 67e76120e..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/OSLog.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// OSLog.swift -// Loop -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import os.log - - -extension OSLog { - convenience init(category: String) { - self.init(subsystem: "com.loopkit.CGMBLEKit", category: category) - } - - func debug(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .debug, args) - } - - func info(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .info, args) - } - - func `default`(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .default, args) - } - - func error(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .error, args) - } - - private func log(_ message: StaticString, type: OSLogType, _ args: [CVarArg]) { - switch args.count { - case 0: - os_log(message, log: self, type: type) - case 1: - os_log(message, log: self, type: type, args[0]) - case 2: - os_log(message, log: self, type: type, args[0], args[1]) - case 3: - os_log(message, log: self, type: type, args[0], args[1], args[2]) - case 4: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3]) - case 5: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4]) - default: - os_log(message, log: self, type: type, args) - } - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Opcode.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Opcode.swift deleted file mode 100644 index 233c2382f..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Opcode.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// Opcode.swift -// xDripG5 -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -enum Opcode: UInt8 { - // Auth - case authRequestTx = 0x01 - - case authRequestRx = 0x03 - case authChallengeTx = 0x04 - case authChallengeRx = 0x05 - case keepAlive = 0x06 // auth; setAdvertisementParametersTx for control - case bondRequest = 0x07 - - // Control - case disconnectTx = 0x09 - - case setAdvertisementParametersRx = 0x1c - - case firmwareVersionTx = 0x20 - case firmwareVersionRx = 0x21 - case batteryStatusTx = 0x22 - case batteryStatusRx = 0x23 - case transmitterTimeTx = 0x24 - case transmitterTimeRx = 0x25 - case sessionStartTx = 0x26 - case sessionStartRx = 0x27 - case sessionStopTx = 0x28 - case sessionStopRx = 0x29 - - case glucoseTx = 0x30 - case glucoseRx = 0x31 - case calibrationDataTx = 0x32 - case calibrationDataRx = 0x33 - case calibrateGlucoseTx = 0x34 - case calibrateGlucoseRx = 0x35 - - case glucoseHistoryTx = 0x3e - - case resetTx = 0x42 - case resetRx = 0x43 - - case transmitterVersionTx = 0x4a - case transmitterVersionRx = 0x4b - - case glucoseG6Tx = 0x4e - case glucoseG6Rx = 0x4f - - case glucoseBackfillTx = 0x50 - case glucoseBackfillRx = 0x51 -} - - -extension Data { - init(for opcode: Opcode) { - self.init([opcode.rawValue]) - } - - func starts(with opcode: Opcode) -> Bool { - guard count > 0 else { - return false - } - - return self[startIndex] == opcode.rawValue - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/PeripheralManager+G5.swift b/Dependencies/CGMBLEKit/CGMBLEKit/PeripheralManager+G5.swift deleted file mode 100644 index b0114529b..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/PeripheralManager+G5.swift +++ /dev/null @@ -1,150 +0,0 @@ -// -// PeripheralManager+G5.swift -// xDripG5 -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import CoreBluetooth -import os.log - - -private let log = OSLog(category: "PeripheralManager+G5") - - -extension PeripheralManager { - private func getCharacteristicWithUUID(_ uuid: CGMServiceCharacteristicUUID) -> CBCharacteristic? { - return peripheral.getCharacteristicWithUUID(uuid) - } - - func setNotifyValue(_ enabled: Bool, - for characteristicUUID: CGMServiceCharacteristicUUID, - timeout: TimeInterval = 2) throws - { - guard let characteristic = getCharacteristicWithUUID(characteristicUUID) else { - throw PeripheralManagerError.unknownCharacteristic - } - - try setNotifyValue(enabled, for: characteristic, timeout: timeout) - } - - func readMessage( - for characteristicUUID: CGMServiceCharacteristicUUID, - timeout: TimeInterval = 2 - ) throws -> R - { - guard let characteristic = getCharacteristicWithUUID(characteristicUUID) else { - throw PeripheralManagerError.unknownCharacteristic - } - - var capturedResponse: R? - - try runCommand(timeout: timeout) { - addCondition(.valueUpdate(characteristic: characteristic, matching: { (data) -> Bool in - guard let value = data else { - return false - } - - guard let response = R(data: value) else { - // We don't recognize the contents. Keep listening. - return false - } - - capturedResponse = response - return true - })) - - peripheral.readValue(for: characteristic) - } - - guard let response = capturedResponse else { - // TODO: This is an "unknown value" issue, not a timeout - if let value = characteristic.value { - log.error("Unknown response data: %{public}@", value.hexadecimalString) - } - throw PeripheralManagerError.timeout - } - - return response - } - - /// - Throws: PeripheralManagerError - func writeMessage(_ message: T, - for characteristicUUID: CGMServiceCharacteristicUUID, - type: CBCharacteristicWriteType = .withResponse, - timeout: TimeInterval = 2 - ) throws -> T.Response - { - guard let characteristic = getCharacteristicWithUUID(characteristicUUID) else { - throw PeripheralManagerError.unknownCharacteristic - } - - var capturedResponse: T.Response? - - try runCommand(timeout: timeout) { - if case .withResponse = type { - addCondition(.write(characteristic: characteristic)) - } - - if characteristic.isNotifying { - addCondition(.valueUpdate(characteristic: characteristic, matching: { (data) -> Bool in - guard let value = data else { - return false - } - - guard let response = T.Response(data: value) else { - // We don't recognize the contents. Keep listening. - return false - } - - capturedResponse = response - return true - })) - } - - peripheral.writeValue(message.data, for: characteristic, type: type) - } - - guard let response = capturedResponse else { - // TODO: This is an "unknown value" issue, not a timeout - if let value = characteristic.value { - log.error("Unknown response data: %{public}@", value.hexadecimalString) - } - throw PeripheralManagerError.timeout - } - - return response - } - - /// - Throws: PeripheralManagerError - func writeMessage(_ message: TransmitterTxMessage, - for characteristicUUID: CGMServiceCharacteristicUUID, - type: CBCharacteristicWriteType = .withResponse, - timeout: TimeInterval = 2) throws - { - guard let characteristic = getCharacteristicWithUUID(characteristicUUID) else { - throw PeripheralManagerError.unknownCharacteristic - } - - try writeValue(message.data, for: characteristic, type: type, timeout: timeout) - } -} - - -fileprivate extension CBPeripheral { - func getServiceWithUUID(_ uuid: TransmitterServiceUUID) -> CBService? { - return services?.itemWithUUIDString(uuid.rawValue) - } - - func getCharacteristicForServiceUUID(_ serviceUUID: TransmitterServiceUUID, withUUIDString UUIDString: String) -> CBCharacteristic? { - guard let characteristics = getServiceWithUUID(serviceUUID)?.characteristics else { - return nil - } - - return characteristics.itemWithUUIDString(UUIDString) - } - - func getCharacteristicWithUUID(_ uuid: CGMServiceCharacteristicUUID) -> CBCharacteristic? { - return getCharacteristicForServiceUUID(.cgmService, withUUIDString: uuid.rawValue) - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/PeripheralManager.swift b/Dependencies/CGMBLEKit/CGMBLEKit/PeripheralManager.swift deleted file mode 100644 index 8239e101c..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/PeripheralManager.swift +++ /dev/null @@ -1,471 +0,0 @@ -// -// PeripheralManager.swift -// xDripG5 -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import CoreBluetooth -import Foundation -import os.log - - -class PeripheralManager: NSObject { - - private let log = OSLog(category: "PeripheralManager") - - /// - /// This is mutable, because CBPeripheral instances can seemingly become invalid, and need to be periodically re-fetched from CBCentralManager - var peripheral: CBPeripheral { - didSet { - guard oldValue !== peripheral else { - return - } - - log.error("Replacing peripheral reference %{public}@ -> %{public}@", oldValue, peripheral) - - oldValue.delegate = nil - peripheral.delegate = self - - queue.sync { - self.needsConfiguration = true - } - } - } - - /// The dispatch queue used to serialize operations on the peripheral - let queue = DispatchQueue(label: "com.loopkit.PeripheralManager.queue", qos: .unspecified) - - /// The condition used to signal command completion - private let commandLock = NSCondition() - - /// The required conditions for the operation to complete - private var commandConditions = [CommandCondition]() - - /// Any error surfaced during the active operation - private var commandError: Error? - - private(set) weak var central: CBCentralManager? - - let configuration: Configuration - - // Confined to `queue` - private var needsConfiguration = true - - weak var delegate: PeripheralManagerDelegate? { - didSet { - queue.sync { - needsConfiguration = true - } - } - } - - init(peripheral: CBPeripheral, configuration: Configuration, centralManager: CBCentralManager) { - self.peripheral = peripheral - self.central = centralManager - self.configuration = configuration - - super.init() - - peripheral.delegate = self - - assertConfiguration() - } -} - - -// MARK: - Nested types -extension PeripheralManager { - struct Configuration { - var serviceCharacteristics: [CBUUID: [CBUUID]] = [:] - var notifyingCharacteristics: [CBUUID: [CBUUID]] = [:] - var valueUpdateMacros: [CBUUID: (_ manager: PeripheralManager) -> Void] = [:] - } - - enum CommandCondition { - case notificationStateUpdate(characteristicUUID: CBUUID, enabled: Bool) - case valueUpdate(characteristic: CBCharacteristic, matching: ((Data?) -> Bool)?) - case write(characteristic: CBCharacteristic) - case discoverServices - case discoverCharacteristicsForService(serviceUUID: CBUUID) - } -} - -protocol PeripheralManagerDelegate: AnyObject { - func peripheralManager(_ manager: PeripheralManager, didUpdateValueFor characteristic: CBCharacteristic) - - func peripheralManager(_ manager: PeripheralManager, didReadRSSI RSSI: NSNumber, error: Error?) - - func peripheralManagerDidUpdateName(_ manager: PeripheralManager) - - func completeConfiguration(for manager: PeripheralManager) throws -} - - -// MARK: - Operation sequence management -extension PeripheralManager { - func configureAndRun(_ block: @escaping (_ manager: PeripheralManager) -> Void) -> (() -> Void) { - return { - if !self.needsConfiguration && self.peripheral.services == nil { - self.log.error("Configured peripheral has no services. Reconfiguring…") - } - - if self.needsConfiguration || self.peripheral.services == nil { - do { - try self.applyConfiguration() - self.log.default("Peripheral configuration completed") - } catch let error { - self.log.error("Error applying peripheral configuration: %@", String(describing: error)) - // Will retry - } - - do { - if let delegate = self.delegate { - try delegate.completeConfiguration(for: self) - self.log.default("Delegate configuration completed") - self.needsConfiguration = false - } else { - self.log.error("No delegate set configured") - } - } catch let error { - self.log.error("Error applying delegate configuration: %@", String(describing: error)) - // Will retry - } - } - - block(self) - } - } - - func perform(_ block: @escaping (_ manager: PeripheralManager) -> Void) { - queue.async(execute: configureAndRun(block)) - } - - private func assertConfiguration() { - perform { (_) in - // Intentionally empty to trigger configuration if necessary - } - } - - private func applyConfiguration(discoveryTimeout: TimeInterval = 2) throws { - try discoverServices(configuration.serviceCharacteristics.keys.map { $0 }, timeout: discoveryTimeout) - - for service in peripheral.services ?? [] { - guard let characteristics = configuration.serviceCharacteristics[service.uuid] else { - // Not all services may have characteristics - continue - } - - try discoverCharacteristics(characteristics, for: service, timeout: discoveryTimeout) - } - - for (serviceUUID, characteristicUUIDs) in configuration.notifyingCharacteristics { - guard let service = peripheral.services?.itemWithUUID(serviceUUID) else { - throw PeripheralManagerError.unknownCharacteristic - } - - for characteristicUUID in characteristicUUIDs { - guard let characteristic = service.characteristics?.itemWithUUID(characteristicUUID) else { - throw PeripheralManagerError.unknownCharacteristic - } - - guard !characteristic.isNotifying else { - continue - } - - try setNotifyValue(true, for: characteristic, timeout: discoveryTimeout) - } - } - } -} - - -// MARK: - Synchronous Commands -extension PeripheralManager { - /// - Throws: PeripheralManagerError - func runCommand(timeout: TimeInterval, command: () -> Void) throws { - // Prelude - dispatchPrecondition(condition: .onQueue(queue)) - guard central?.state == .poweredOn && peripheral.state == .connected else { - throw PeripheralManagerError.notReady - } - - commandLock.lock() - - defer { - commandLock.unlock() - } - - guard commandConditions.isEmpty else { - throw PeripheralManagerError.invalidConfiguration - } - - // Run - command() - - guard !commandConditions.isEmpty else { - // If the command didn't add any conditions, then finish immediately - return - } - - // Postlude - let signaled = commandLock.wait(until: Date(timeIntervalSinceNow: timeout)) - - defer { - commandError = nil - commandConditions = [] - } - - guard signaled else { - throw PeripheralManagerError.timeout - } - - if let error = commandError { - throw PeripheralManagerError.cbPeripheralError(error) - } - } - - /// It's illegal to call this without first acquiring the commandLock - /// - /// - Parameter condition: The condition to add - func addCondition(_ condition: CommandCondition) { - dispatchPrecondition(condition: .onQueue(queue)) - commandConditions.append(condition) - } - - func discoverServices(_ serviceUUIDs: [CBUUID], timeout: TimeInterval) throws { - let servicesToDiscover = peripheral.servicesToDiscover(from: serviceUUIDs) - - guard servicesToDiscover.count > 0 else { - return - } - - try runCommand(timeout: timeout) { - addCondition(.discoverServices) - - peripheral.discoverServices(serviceUUIDs) - } - } - - func discoverCharacteristics(_ characteristicUUIDs: [CBUUID], for service: CBService, timeout: TimeInterval) throws { - let characteristicsToDiscover = peripheral.characteristicsToDiscover(from: characteristicUUIDs, for: service) - - guard characteristicsToDiscover.count > 0 else { - return - } - - try runCommand(timeout: timeout) { - addCondition(.discoverCharacteristicsForService(serviceUUID: service.uuid)) - - peripheral.discoverCharacteristics(characteristicsToDiscover, for: service) - } - } - - /// - Throws: PeripheralManagerError - func setNotifyValue(_ enabled: Bool, for characteristic: CBCharacteristic, timeout: TimeInterval) throws { - try runCommand(timeout: timeout) { - addCondition(.notificationStateUpdate(characteristicUUID: characteristic.uuid, enabled: enabled)) - - peripheral.setNotifyValue(enabled, for: characteristic) - } - } - - /// - Throws: PeripheralManagerError - func readValue(for characteristic: CBCharacteristic, timeout: TimeInterval) throws -> Data? { - try runCommand(timeout: timeout) { - addCondition(.valueUpdate(characteristic: characteristic, matching: nil)) - - peripheral.readValue(for: characteristic) - } - - return characteristic.value - } - - /// - Throws: PeripheralManagerError - func wait(for characteristic: CBCharacteristic, timeout: TimeInterval) throws -> Data { - try runCommand(timeout: timeout) { - addCondition(.valueUpdate(characteristic: characteristic, matching: nil)) - } - - guard let value = characteristic.value else { - throw PeripheralManagerError.timeout - } - - return value - } - - /// - Throws: PeripheralManagerError - func writeValue(_ value: Data, for characteristic: CBCharacteristic, type: CBCharacteristicWriteType, timeout: TimeInterval) throws { - try runCommand(timeout: timeout) { - if case .withResponse = type { - addCondition(.write(characteristic: characteristic)) - } - - peripheral.writeValue(value, for: characteristic, type: type) - } - } -} - - -// MARK: - Delegate methods executed on the central's queue -extension PeripheralManager: CBPeripheralDelegate { - - func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .discoverServices = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .discoverCharacteristicsForService(serviceUUID: service.uuid) = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .notificationStateUpdate(characteristicUUID: characteristic.uuid, enabled: characteristic.isNotifying) = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .write(characteristic: characteristic) = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { - commandLock.lock() - - var notifyDelegate = false - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .valueUpdate(characteristic: characteristic, matching: let matching) = condition { - return matching?(characteristic.value) ?? true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } else if let macro = configuration.valueUpdateMacros[characteristic.uuid] { - macro(self) - } else if commandConditions.isEmpty { - notifyDelegate = true // execute after the unlock - } - - commandLock.unlock() - - if notifyDelegate { - // If we weren't expecting this notification, pass it along to the delegate - delegate?.peripheralManager(self, didUpdateValueFor: characteristic) - } - } - - func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) { - delegate?.peripheralManager(self, didReadRSSI: RSSI, error: error) - } - - func peripheralDidUpdateName(_ peripheral: CBPeripheral) { - delegate?.peripheralManagerDidUpdateName(self) - } -} - - -extension PeripheralManager: CBCentralManagerDelegate { - func centralManagerDidUpdateState(_ central: CBCentralManager) { - switch central.state { - case .poweredOn: - assertConfiguration() - default: - break - } - } - - func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { - switch peripheral.state { - case .connected: - assertConfiguration() - default: - break - } - } -} - - -extension PeripheralManager { - public override var debugDescription: String { - var items = [ - "## PeripheralManager", - "peripheral: \(peripheral)", - ] - queue.sync { - items.append("needsConfiguration: \(needsConfiguration)") - } - return items.joined(separator: "\n") - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/PeripheralManagerError.swift b/Dependencies/CGMBLEKit/CGMBLEKit/PeripheralManagerError.swift deleted file mode 100644 index 6c599eca4..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/PeripheralManagerError.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// PeripheralManagerError.swift -// xDripG5 -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import CoreBluetooth - - -enum PeripheralManagerError: Error { - case cbPeripheralError(Error) - case notReady - case invalidConfiguration - case timeout - case unknownCharacteristic -} - - -extension PeripheralManagerError: LocalizedError { - var errorDescription: String? { - switch self { - case .cbPeripheralError(let error): - return error.localizedDescription - case .notReady: - return LocalizedString("Peripheral isnʼt connected", comment: "Not ready error description") - case .invalidConfiguration: - return LocalizedString("Peripheral command was invalid", comment: "invlid config error description") - case .timeout: - return LocalizedString("Peripheral did not respond in time", comment: "Timeout error description") - case .unknownCharacteristic: - return LocalizedString("Unknown characteristic", comment: "Error description") - } - } - - var failureReason: String? { - switch self { - case .cbPeripheralError(let error as NSError): - return error.localizedFailureReason - default: - return errorDescription - } - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/Transmitter.swift b/Dependencies/CGMBLEKit/CGMBLEKit/Transmitter.swift deleted file mode 100644 index 4484e1ecc..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/Transmitter.swift +++ /dev/null @@ -1,576 +0,0 @@ -// -// Transmitter.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 11/22/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import CoreBluetooth -import HealthKit -import os.log - - -public protocol TransmitterDelegate: AnyObject { - func transmitterDidConnect(_ transmitter: Transmitter) - - func transmitter(_ transmitter: Transmitter, didError error: Error) - - func transmitter(_ transmitter: Transmitter, didRead glucose: Glucose) - - func transmitter(_ transmitter: Transmitter, didReadBackfill glucose: [Glucose]) - - func transmitter(_ transmitter: Transmitter, didReadUnknownData data: Data) -} - -/// These methods are called on a private background queue. It is the responsibility of the client to ensure thread-safety. -public protocol TransmitterCommandSource: AnyObject { - func dequeuePendingCommand(for transmitter: Transmitter) -> Command? - - func transmitter(_ transmitter: Transmitter, didFail command: Command, with error: Error) - - func transmitter(_ transmitter: Transmitter, didComplete command: Command) -} - -public enum TransmitterError: Error { - case authenticationError(String) - case controlError(String) - case observationError(String) -} - -extension TransmitterError: CustomStringConvertible { - public var description: String { - switch self { - case .authenticationError(let description): - return description - case .controlError(let description): - return description - case .observationError(let description): - return description - } - } -} - - -public final class Transmitter: BluetoothManagerDelegate { - - /// The ID of the transmitter to connect to - public var ID: String { - return id.id - } - - private var id: TransmitterID - - public var passiveModeEnabled: Bool - - public weak var delegate: TransmitterDelegate? - - public weak var commandSource: TransmitterCommandSource? - - // MARK: - Passive observation state, confined to `bluetoothManager.managerQueue` - - /// The initial activation date of the transmitter - private var activationDate: Date? - - /// The last-observed time message - private var lastTimeMessage: TransmitterTimeRxMessage? { - didSet { - if let time = lastTimeMessage { - activationDate = Date(timeIntervalSinceNow: -TimeInterval(time.currentTime)) - } else { - activationDate = nil - } - } - } - - /// The last-observed calibration message - private var lastCalibrationMessage: CalibrationDataRxMessage? - - /// The backfill data buffer - private var backfillBuffer: GlucoseBackfillFrameBuffer? - - // MARK: - - - private let log = OSLog(category: "Transmitter") - - private let bluetoothManager = BluetoothManager() - - private let delegateQueue = DispatchQueue(label: "com.loudnate.CGMBLEKit.delegateQueue", qos: .unspecified) - - public init(id: String, peripheralIdentifier: UUID? = nil, passiveModeEnabled: Bool = false) { - self.id = TransmitterID(id: id) - self.passiveModeEnabled = passiveModeEnabled - - bluetoothManager.peripheralIdentifier = peripheralIdentifier - bluetoothManager.delegate = self - } - - public func resumeScanning() { - if stayConnected { - bluetoothManager.scanForPeripheral() - } - } - - public func stopScanning() { - bluetoothManager.disconnect() - } - - public var isScanning: Bool { - return bluetoothManager.isScanning - } - - public var peripheralIdentifier: UUID? { - get { - return bluetoothManager.peripheralIdentifier - } - set { - bluetoothManager.peripheralIdentifier = newValue - } - } - - public var stayConnected: Bool { - get { - return bluetoothManager.stayConnected - } - set { - bluetoothManager.stayConnected = newValue - - if newValue { - bluetoothManager.scanForPeripheral() - } - } - } - - // MARK: - BluetoothManagerDelegate - - func bluetoothManager(_ manager: BluetoothManager, peripheralManager: PeripheralManager, isReadyWithError error: Error?) { - if let error = error { - delegateQueue.async { - self.delegate?.transmitter(self, didError: error) - } - return - } - - delegateQueue.async { - self.delegate?.transmitterDidConnect(self) - } - - peripheralManager.perform { (peripheral) in - if self.passiveModeEnabled { - self.log.debug("Listening for authentication responses in passive mode") - do { - try peripheral.listenToCharacteristic(.authentication) - } catch let error { - self.delegateQueue.async { - self.delegate?.transmitter(self, didError: error) - } - } - } else { - do { - self.log.debug("Authenticating with transmitter") - let status = try peripheral.authenticate(id: self.id) - - if !status.isBonded { - self.log.debug("Requesting bond") - try peripheral.requestBond() - - self.log.debug("Bonding request sent. Waiting user to respond.") - } - - try peripheral.enableNotify(shouldWaitForBond: !status.isBonded) - defer { - self.log.debug("Initiating a disconnect") - peripheral.disconnect() - } - - self.log.debug("Reading time") - let timeMessage = try peripheral.readTimeMessage() - - let activationDate = Date(timeIntervalSinceNow: -TimeInterval(timeMessage.currentTime)) - self.log.debug("Determined activation date: %@", String(describing: activationDate)) - - while let command = self.commandSource?.dequeuePendingCommand(for: self) { - self.log.debug("Sending command: %@", String(describing: command)) - do { - _ = try peripheral.sendCommand(command, activationDate: activationDate) - self.commandSource?.transmitter(self, didComplete: command) - } catch let error { - self.commandSource?.transmitter(self, didFail: command, with: error) - } - } - - self.log.debug("Reading glucose") - let glucoseMessage = try peripheral.readGlucose() - self.log.debug("Reading calibration data") - let calibrationMessage = try? peripheral.readCalibrationData() - - let glucose = Glucose( - transmitterID: self.id.id, - glucoseMessage: glucoseMessage, - timeMessage: timeMessage, - calibrationMessage: calibrationMessage, - activationDate: activationDate - ) - - self.delegateQueue.async { - self.delegate?.transmitter(self, didRead: glucose) - } - } catch let error { - self.delegateQueue.async { - self.delegate?.transmitter(self, didError: error) - } - } - } - } - } - - func bluetoothManager(_ manager: BluetoothManager, shouldConnectPeripheral peripheral: CBPeripheral) -> Bool { - /// The Dexcom G5 advertises a peripheral name of "DexcomXX" - /// where "XX" is the last-two characters of the transmitter ID. - if let name = peripheral.name, name.suffix(2) == id.id.suffix(2) { - return true - } else { - self.log.info("Not connecting to peripheral: %{public}@", peripheral.name ?? String(describing: peripheral)) - return false - } - } - - func bluetoothManager(_ manager: BluetoothManager, peripheralManager: PeripheralManager, didReceiveControlResponse response: Data) { - guard passiveModeEnabled else { return } - - guard response.count > 0 else { return } - - switch Opcode(rawValue: response[0]) { - case .glucoseRx?, .glucoseG6Rx?: - if let glucoseMessage = GlucoseRxMessage(data: response), - let timeMessage = lastTimeMessage, - let activationDate = activationDate - { - delegateQueue.async { - self.delegate?.transmitter(self, didRead: Glucose(transmitterID: self.id.id, glucoseMessage: glucoseMessage, timeMessage: timeMessage, calibrationMessage: self.lastCalibrationMessage, activationDate: activationDate)) - } - } else { - delegateQueue.async { - self.delegate?.transmitter(self, didError: TransmitterError.observationError("Unable to handle glucose control response")) - } - } - - peripheralManager.perform { (peripheral) in - // Subscribe to backfill updates - do { - try peripheral.listenToCharacteristic(.backfill) - } catch let error { - self.log.error("Error trying to enable notifications on backfill characteristic: %{public}@", String(describing: error)) - self.delegateQueue.async { - self.delegate?.transmitter(self, didError: error) - } - } - } - case .transmitterTimeRx?: - if let timeMessage = TransmitterTimeRxMessage(data: response) { - self.lastTimeMessage = timeMessage - } - case .glucoseBackfillRx?: - guard let backfillMessage = GlucoseBackfillRxMessage(data: response) else { - break - } - - guard let backfillBuffer = backfillBuffer else { - log.error("Received GlucoseBackfillRxMessage %{public}@ but backfillBuffer is nil", String(describing: backfillMessage)) - self.delegateQueue.async { - self.delegate?.transmitter(self, didError: TransmitterError.observationError("Received GlucoseBackfillRxMessage but backfillBuffer is nil")) - } - break - } - - guard let timeMessage = lastTimeMessage, let activationDate = activationDate else { - log.error("Received GlucoseBackfillRxMessage %{public}@ but activationDate is unknown", String(describing: backfillMessage)) - self.delegateQueue.async { - self.delegate?.transmitter(self, didError: TransmitterError.observationError("Received GlucoseBackfillRxMessage but activationDate is unknown")) - } - break - } - - guard backfillMessage.bufferLength == backfillBuffer.count else { - log.error("GlucoseBackfillRxMessage expected buffer length %d, but was %d", backfillMessage.bufferLength, backfillBuffer.count) - self.delegateQueue.async { - self.delegate?.transmitter(self, didError: TransmitterError.observationError("GlucoseBackfillRxMessage expected buffer length \(backfillMessage.bufferLength), but was \(backfillBuffer.count): \(response.hexadecimalString) ")) - } - break - } - - guard backfillMessage.bufferCRC == backfillBuffer.crc16 else { - log.error("GlucoseBackfillRxMessage expected CRC %04x, but was %04x", backfillMessage.bufferCRC, backfillBuffer.crc16) - self.delegateQueue.async { - self.delegate?.transmitter(self, didError: TransmitterError.observationError("GlucoseBackfillRxMessage expected CRC \(backfillMessage.bufferCRC), but was \(backfillBuffer.crc16)")) - } - break - } - - let glucose = backfillBuffer.glucose.map { - Glucose(transmitterID: id.id, status: backfillMessage.status, glucoseMessage: $0, timeMessage: timeMessage, activationDate: activationDate) - } - - guard glucose.count > 0 else { - break - } - - guard glucose.first!.glucoseMessage.timestamp == backfillMessage.startTime, - glucose.last!.glucoseMessage.timestamp == backfillMessage.endTime, - glucose.first!.glucoseMessage.timestamp <= glucose.last!.glucoseMessage.timestamp - else { - log.error("GlucoseBackfillRxMessage time interval not reflected in glucose: %{public}@, buffer: %{public}@", response.hexadecimalString, String(reflecting: backfillBuffer)) - - self.delegateQueue.async { - self.delegate?.transmitter(self, didError: TransmitterError.observationError("GlucoseBackfillRxMessage time interval not reflected in glucose: \(backfillMessage.startTime) - \(backfillMessage.endTime), buffer: \(glucose.first!.glucoseMessage.timestamp) - \(glucose.last!.glucoseMessage.timestamp)")) - } - break - } - - delegateQueue.async { - self.delegate?.transmitter(self, didReadBackfill: glucose) - } - case .calibrationDataRx?: - guard let calibrationDataMessage = CalibrationDataRxMessage(data: response) else { - break - } - - lastCalibrationMessage = calibrationDataMessage - case .none: - delegateQueue.async { - self.delegate?.transmitter(self, didReadUnknownData: response) - } - default: - // We ignore all other known opcodes - break - } - } - - func bluetoothManager(_ manager: BluetoothManager, didReceiveBackfillResponse response: Data) { - guard response.count > 2 else { - return - } - - if response[0] == 1 { - log.info("Starting new backfill buffer with ID %d", response[1]) - - self.backfillBuffer = GlucoseBackfillFrameBuffer(identifier: response[1]) - } - - log.info("appending to backfillBuffer: %@", response.hexadecimalString) - - self.backfillBuffer?.append(response) - } - - func bluetoothManager(_ manager: BluetoothManager, peripheralManager: PeripheralManager, didReceiveAuthenticationResponse response: Data) { - - if let message = AuthChallengeRxMessage(data: response), message.isBonded, message.isAuthenticated { - self.log.debug("Observed authenticated session. enabling notifications for control characteristic.") - peripheralManager.perform { (peripheral) in - // Stopping updates from authentication simultaneously with Dexcom's app causes CoreBluetooth to get into a weird state. - /* - do { - try peripheral.stopListeningToCharacteristic(.authentication) - } catch let error { - self.log.error("Error trying to disable notifications on authentication characteristic: %{public}@", String(describing: error)) - } - */ - - do { - try peripheral.listenToCharacteristic(.control) - } catch let error { - self.log.error("Error trying to enable notifications on control characteristic: %{public}@", String(describing: error)) - self.delegateQueue.async { - self.delegate?.transmitter(self, didError: error) - } - } - } - } else { - self.log.debug("Ignoring authentication response: %{public}@", response.hexadecimalString) - } - } -} - -extension Transmitter: CustomDebugStringConvertible { - public var debugDescription: String { - return [ - "## Transmitter", - String(reflecting: bluetoothManager), - ].joined(separator: "\n") - } -} - - -struct TransmitterID { - let id: String - - init(id: String) { - self.id = id - } - - private var cryptKey: Data? { - return "00\(id)00\(id)".data(using: .utf8) - } - - func computeHash(of data: Data) -> Data? { - guard data.count == 8, let key = cryptKey else { - return nil - } - - var doubleData = Data(capacity: data.count * 2) - doubleData.append(data) - doubleData.append(data) - - guard let outData = try? AESCrypt.encryptData(doubleData, usingKey: key) else { - return nil - } - - return outData[0..<8] - } -} - - -// MARK: - Helpers -fileprivate extension PeripheralManager { - func authenticate(id: TransmitterID) throws -> AuthChallengeRxMessage { - let authMessage = AuthRequestTxMessage() - - do { - try writeMessage(authMessage, for: .authentication) - } catch let error { - throw TransmitterError.authenticationError("Error writing transmitter challenge: \(error)") - } - - let authResponse: AuthRequestRxMessage - do { - authResponse = try readMessage(for: .authentication) - } catch let error { - throw TransmitterError.authenticationError("Unable to parse auth challenge: \(error)") - } - - guard authResponse.tokenHash == id.computeHash(of: authMessage.singleUseToken) else { - throw TransmitterError.authenticationError("Transmitter failed auth challenge") - } - - guard let challengeHash = id.computeHash(of: authResponse.challenge) else { - throw TransmitterError.authenticationError("Failed to compute challenge hash for transmitter ID") - } - - do { - try writeMessage(AuthChallengeTxMessage(challengeHash: challengeHash), for: .authentication) - } catch let error { - throw TransmitterError.authenticationError("Error writing challenge response: \(error)") - } - - let challengeResponse: AuthChallengeRxMessage - do { - challengeResponse = try readMessage(for: .authentication) - } catch let error { - throw TransmitterError.authenticationError("Unable to parse auth status: \(error)") - } - - guard challengeResponse.isAuthenticated else { - throw TransmitterError.authenticationError("Transmitter rejected auth challenge") - } - - return challengeResponse - } - - func requestBond() throws { - do { - try writeMessage(KeepAliveTxMessage(time: 25), for: .authentication) - } catch let error { - throw TransmitterError.authenticationError("Error writing keep-alive for bond: \(error)") - } - - do { - try writeMessage(BondRequestTxMessage(), for: .authentication) - } catch let error { - throw TransmitterError.authenticationError("Error writing bond request: \(error)") - } - } - - func enableNotify(shouldWaitForBond: Bool = false) throws { - do { - if shouldWaitForBond { - try setNotifyValue(true, for: .control, timeout: 15) - } else { - try setNotifyValue(true, for: .control) - } - } catch let error { - throw TransmitterError.controlError("Error enabling notification: \(error)") - } - } - - func readTimeMessage() throws -> TransmitterTimeRxMessage { - do { - return try writeMessage(TransmitterTimeTxMessage(), for: .control) - } catch let error { - throw TransmitterError.controlError("Error getting time: \(error)") - } - } - - /// - Throws: TransmitterError.controlError - func sendCommand(_ command: Command, activationDate: Date) throws -> TransmitterRxMessage { - do { - switch command { - case .startSensor(let date): - let startTime = UInt32(date.timeIntervalSince(activationDate)) - let secondsSince1970 = UInt32(date.timeIntervalSince1970) - return try writeMessage(SessionStartTxMessage(startTime: startTime, secondsSince1970: secondsSince1970), for: .control) - case .stopSensor(let date): - let stopTime = UInt32(date.timeIntervalSince(activationDate)) - return try writeMessage(SessionStopTxMessage(stopTime: stopTime), for: .control) - case .calibrateSensor(let glucose, let date): - let glucoseValue = UInt16(glucose.doubleValue(for: .milligramsPerDeciliter).rounded()) - let time = UInt32(date.timeIntervalSince(activationDate)) - return try writeMessage(CalibrateGlucoseTxMessage(time: time, glucose: glucoseValue), for: .control) - case .resetTransmitter: - return try writeMessage(ResetTxMessage(), for: .control) - } - } catch let error { - throw TransmitterError.controlError("Error during \(command): \(error)") - } - } - - func readGlucose() throws -> GlucoseRxMessage { - do { - return try writeMessage(GlucoseTxMessage(), for: .control) - } catch let error { - throw TransmitterError.controlError("Error getting glucose: \(error)") - } - } - - func readCalibrationData() throws -> CalibrationDataRxMessage { - do { - return try writeMessage(CalibrationDataTxMessage(), for: .control) - } catch let error { - throw TransmitterError.controlError("Error getting calibration data: \(error)") - } - } - - func disconnect() { - do { - try setNotifyValue(false, for: .control) - try writeMessage(DisconnectTxMessage(), for: .control) - } catch { - } - } - - func listenToCharacteristic(_ characteristic: CGMServiceCharacteristicUUID) throws { - do { - try setNotifyValue(true, for: characteristic) - } catch let error { - throw TransmitterError.controlError("Error enabling notification for \(characteristic): \(error)") - } - } - - func stopListeningToCharacteristic(_ characteristic: CGMServiceCharacteristicUUID) throws { - do { - try setNotifyValue(false, for: characteristic) - } catch let error { - throw TransmitterError.controlError("Error disabling notification for \(characteristic): \(error)") - } - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/TransmitterManager.swift b/Dependencies/CGMBLEKit/CGMBLEKit/TransmitterManager.swift deleted file mode 100644 index 4942087c2..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/TransmitterManager.swift +++ /dev/null @@ -1,523 +0,0 @@ -// -// TransmitterManager.swift -// Loop -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import HealthKit -import LoopKit -import ShareClient -import os.log - - -public struct TransmitterManagerState: RawRepresentable, Equatable { - public typealias RawValue = CGMManager.RawStateValue - - public static let version = 1 - - public var transmitterID: String - - public var passiveModeEnabled: Bool = true - - public var shouldSyncToRemoteService: Bool - - public init(transmitterID: String, shouldSyncToRemoteService: Bool = false) { - self.transmitterID = transmitterID - self.shouldSyncToRemoteService = shouldSyncToRemoteService - } - - public init?(rawValue: RawValue) { - guard let transmitterID = rawValue["transmitterID"] as? String - else { - return nil - } - - let shouldSyncToRemoteService = rawValue["shouldSyncToRemoteService"] as? Bool ?? false - - self.init(transmitterID: transmitterID, shouldSyncToRemoteService: shouldSyncToRemoteService) - } - - public var rawValue: RawValue { - return [ - "transmitterID": transmitterID, - "shouldSyncToRemoteService": shouldSyncToRemoteService, - ] - } -} - - -public protocol TransmitterManagerObserver: AnyObject { - func transmitterManagerDidUpdateLatestReading(_ manager: TransmitterManager) -} - - -public class TransmitterManager: TransmitterDelegate { - private var state: TransmitterManagerState - - private let observers = WeakSynchronizedSet() - - - public var hasValidSensorSession: Bool { - // TODO: we should decode and persist transmitter session state - return !state.transmitterID.isEmpty - } - - public var cgmManagerStatus: CGMManagerStatus { - return CGMManagerStatus(hasValidSensorSession: hasValidSensorSession, device: device) - } - - public required init(state: TransmitterManagerState) { - self.state = state - self.transmitter = Transmitter(id: state.transmitterID, passiveModeEnabled: state.passiveModeEnabled) - self.shareManager = ShareClientManager() - - self.transmitter.delegate = self - - #if targetEnvironment(simulator) - setupSimulatedSampleGenerator() - #endif - - } - - #if targetEnvironment(simulator) - var simulatedSampleGeneratorTimer: DispatchSourceTimer? - - private func setupSimulatedSampleGenerator() { - - let timer = DispatchSource.makeTimerSource(queue: DispatchQueue(label: "com.loopkit.simulatedSampleGenerator")) - timer.schedule(deadline: .now() + .seconds(10), repeating: .minutes(5)) - timer.setEventHandler(handler: { [weak self] in - self?.generateSimulatedSample() - }) - self.simulatedSampleGeneratorTimer = timer - timer.resume() - } - - private func generateSimulatedSample() { - let timestamp = Date() - let syncIdentifier = "\(self.state.transmitterID) \(timestamp)" - let period = TimeInterval(hours: 3) - func glucoseValueFunc(timestamp: Date, period: Double) -> Double { - return 100 + 20 * cos(timestamp.timeIntervalSinceReferenceDate.remainder(dividingBy: period) / period * Double.pi * 2) - } - let glucoseValue = glucoseValueFunc(timestamp: timestamp, period: period) - let prevGlucoseValue = glucoseValueFunc(timestamp: timestamp - period, period: period) - let trendRateValue = glucoseValue - prevGlucoseValue - let trend: GlucoseTrend? = { - switch trendRateValue { - case -0.01...0.01: - return .flat - case -2 ..< -0.01: - return .down - case -5 ..< -2: - return .downDown - case -Double.greatestFiniteMagnitude ..< -5: - return .downDownDown - case 0.01...2: - return .up - case 2...5: - return .upUp - case 5...Double.greatestFiniteMagnitude: - return .upUpUp - default: - return nil - } - }() - - let quantity = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: glucoseValue) - let trendRate = HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: trendRateValue) - let sample = NewGlucoseSample(date: timestamp, quantity: quantity, condition: nil, trend: trend, trendRate: trendRate, isDisplayOnly: false, wasUserEntered: false, syncIdentifier: syncIdentifier) - self.updateDelegate(with: .newData([sample])) - } - #endif - - required convenience public init?(rawState: CGMManager.RawStateValue) { - guard let state = TransmitterManagerState(rawValue: rawState) else { - return nil - } - - self.init(state: state) - } - - public var rawState: CGMManager.RawStateValue { - return state.rawValue - } - - func logDeviceCommunication(_ message: String, type: DeviceLogEntryType = .send) { - } - - public var shouldSyncToRemoteService: Bool { - get { - return state.shouldSyncToRemoteService - } - set { - self.state.shouldSyncToRemoteService = newValue - notifyDelegateOfStateChange() - } - } - - public var cgmManagerDelegate: CGMManagerDelegate? { - get { - return shareManager.cgmManagerDelegate - } - set { - shareManager.cgmManagerDelegate = newValue - } - } - - public var delegateQueue: DispatchQueue! { - get { - return shareManager.delegateQueue - } - set { - shareManager.delegateQueue = newValue - } - } - - private(set) public var latestConnection: Date? { - get { - return lockedLatestConnection.value - } - set { - lockedLatestConnection.value = newValue - } - } - private let lockedLatestConnection: Locked = Locked(nil) - - public let shareManager: ShareClientManager - - public let transmitter: Transmitter - let log = OSLog(category: "TransmitterManager") - - public var providesBLEHeartbeat: Bool { - return dataIsFresh - } - - public var glucoseDisplay: GlucoseDisplayable? { - let transmitterDate = latestReading?.readDate ?? .distantPast - let shareDate = shareManager.latestBackfill?.startDate ?? .distantPast - - if transmitterDate >= shareDate { - return latestReading - } else { - return shareManager.glucoseDisplay - } - } - - public var managedDataInterval: TimeInterval? { - if transmitter.passiveModeEnabled { - return .hours(3) - } - - return shareManager.managedDataInterval - } - - private(set) public var latestReading: Glucose? { - get { - return lockedLatestReading.value - } - set { - lockedLatestReading.value = newValue - } - } - private let lockedLatestReading: Locked = Locked(nil) - - private var dataIsFresh: Bool { - guard let latestGlucose = latestReading, - latestGlucose.readDate > Date(timeIntervalSinceNow: .minutes(-4.5)) else { - return false - } - - return true - } - - public func fetchNewDataIfNeeded(_ completion: @escaping (CGMReadingResult) -> Void) { - // Ensure our transmitter connection is active - transmitter.resumeScanning() - - // If our last glucose was less than 4.5 minutes ago, don't fetch. - guard !dataIsFresh else { - completion(.noData) - return - } - - if let latestReading = latestReading { - log.default("Fetching new glucose from Share because last reading is %{public}.1f minutes old", latestReading.readDate.timeIntervalSinceNow.minutes) - } else { - log.default("Fetching new glucose from Share because we don't have a previous reading") - } - - shareManager.fetchNewDataIfNeeded(completion) - } - - public var device: HKDevice? { - return nil - } - - public var debugDescription: String { - return [ - "## \(String(describing: type(of: self)))", - "latestReading: \(String(describing: latestReading))", - "latestConnection: \(String(describing: latestConnection))", - "dataIsFresh: \(dataIsFresh)", - "providesBLEHeartbeat: \(providesBLEHeartbeat)", - shareManager.debugDescription, - "observers.count: \(observers.cleanupDeallocatedElements().count)", - String(reflecting: transmitter), - ].joined(separator: "\n") - } - - private func updateDelegate(with result: CGMReadingResult) { - if let manager = self as? CGMManager { - shareManager.delegate.notify { (delegate) in - delegate?.cgmManager(manager, hasNew: result) - } - } - - notifyObserversOfLatestReading() - } - - private func notifyDelegateOfStateChange() { - if let manager = self as? CGMManager { - shareManager.delegate.notify { (delegate) in - delegate?.cgmManagerDidUpdateState(manager) - } - } - } - - - // MARK: - TransmitterDelegate - - public func transmitterDidConnect(_ transmitter: Transmitter) { - log.default("%{public}@", #function) - latestConnection = Date() - logDeviceCommunication("Connected", type: .connection) - } - - public func transmitter(_ transmitter: Transmitter, didError error: Error) { - log.error("%{public}@: %{public}@", #function, String(describing: error)) - updateDelegate(with: .error(error)) - logDeviceCommunication("Error: \(error)", type: .error) - } - - public func transmitter(_ transmitter: Transmitter, didRead glucose: Glucose) { - guard glucose != latestReading else { - updateDelegate(with: .noData) - return - } - - latestReading = glucose - - logDeviceCommunication("New reading: \(glucose.readDate)", type: .receive) - - guard glucose.state.hasReliableGlucose else { - log.default("%{public}@: Unreliable glucose: %{public}@", #function, String(describing: glucose.state)) - updateDelegate(with: .error(CalibrationError.unreliableState(glucose.state))) - return - } - - guard let quantity = glucose.glucose else { - updateDelegate(with: .noData) - return - } - - log.default("%{public}@: New glucose", #function) - - updateDelegate(with: .newData([ - NewGlucoseSample( - date: glucose.readDate, - quantity: quantity, - condition: glucose.condition, - trend: glucose.trendType, - trendRate: glucose.trendRate, - isDisplayOnly: glucose.isDisplayOnly, - wasUserEntered: glucose.isDisplayOnly, - syncIdentifier: glucose.syncIdentifier, - device: device - ) - ])) - } - - public func transmitter(_ transmitter: Transmitter, didReadBackfill glucose: [Glucose]) { - let samples = glucose.compactMap { (glucose) -> NewGlucoseSample? in - guard glucose != latestReading, glucose.state.hasReliableGlucose, let quantity = glucose.glucose else { - return nil - } - - return NewGlucoseSample( - date: glucose.readDate, - quantity: quantity, - condition: glucose.condition, - trend: glucose.trendType, - trendRate: glucose.trendRate, - isDisplayOnly: glucose.isDisplayOnly, - wasUserEntered: glucose.isDisplayOnly, - syncIdentifier: glucose.syncIdentifier, - device: device - ) - } - - guard samples.count > 0 else { - return - } - - updateDelegate(with: .newData(samples)) - - logDeviceCommunication("New backfill: \(String(describing: samples.first?.date))", type: .receive) - } - - public func transmitter(_ transmitter: Transmitter, didReadUnknownData data: Data) { - log.error("Unknown sensor data: %{public}@", data.hexadecimalString) - // This can be used for protocol discovery, but isn't necessary for normal operation - - logDeviceCommunication("Unknown sensor data: \(data.hexadecimalString)", type: .error) - } -} - - -// MARK: - Observer management -extension TransmitterManager { - public func addObserver(_ observer: TransmitterManagerObserver, queue: DispatchQueue) { - observers.insert(observer, queue: queue) - } - - public func removeObserver(_ observer: TransmitterManagerObserver) { - observers.removeElement(observer) - } - - private func notifyObserversOfLatestReading() { - observers.forEach { (observer) in - observer.transmitterManagerDidUpdateLatestReading(self) - } - } -} - - -public class G5CGMManager: TransmitterManager, CGMManager { - public let managerIdentifier: String = "DexG5Transmitter" - - public let localizedTitle = LocalizedString("Dexcom G5", comment: "CGM display title") - - public let isOnboarded = true // No distinction between created and onboarded - - public var appURL: URL? { - return URL(string: "dexcomcgm://") - } - - public override var device: HKDevice? { - return HKDevice( - name: "CGMBLEKit", - manufacturer: "Dexcom", - model: "G5 Mobile", - hardwareVersion: nil, - firmwareVersion: nil, - softwareVersion: String(CGMBLEKitVersionNumber), - localIdentifier: nil, - udiDeviceIdentifier: "00386270000002" - ) - } - - override func logDeviceCommunication(_ message: String, type: DeviceLogEntryType = .send) { - self.cgmManagerDelegate?.deviceManager(self, logEventForDeviceIdentifier: transmitter.ID, type: type, message: message, completion: nil) - } - -} - - -public class G6CGMManager: TransmitterManager, CGMManager { - public let managerIdentifier: String = "DexG6Transmitter" - - public let localizedTitle = LocalizedString("Dexcom G6", comment: "CGM display title") - - public let isOnboarded = true // No distinction between created and onboarded - - public var appURL: URL? { - return nil - } - - public override var device: HKDevice? { - return HKDevice( - name: "CGMBLEKit", - manufacturer: "Dexcom", - model: "G6", - hardwareVersion: nil, - firmwareVersion: nil, - softwareVersion: String(CGMBLEKitVersionNumber), - localIdentifier: nil, - udiDeviceIdentifier: "00386270000385" - ) - } - - override func logDeviceCommunication(_ message: String, type: DeviceLogEntryType = .send) { - self.cgmManagerDelegate?.deviceManager(self, logEventForDeviceIdentifier: transmitter.ID, type: type, message: message, completion: nil) - } -} - - -enum CalibrationError: Error { - case unreliableState(CalibrationState) -} - -extension CalibrationError: LocalizedError { - var errorDescription: String? { - switch self { - case .unreliableState: - return LocalizedString("Glucose data is unavailable", comment: "Error description for unreliable state") - } - } - - var failureReason: String? { - switch self { - case .unreliableState(let state): - return state.localizedDescription - } - } -} - -extension CalibrationState { - public var localizedDescription: String { - switch self { - case .known(let state): - switch state { - case .needCalibration7, .needCalibration14, .needFirstInitialCalibration, .needSecondInitialCalibration, .calibrationError8, .calibrationError9, .calibrationError10, .calibrationError13: - return LocalizedString("Sensor needs calibration", comment: "The description of sensor calibration state when sensor needs calibration.") - case .ok: - return LocalizedString("Sensor calibration is OK", comment: "The description of sensor calibration state when sensor calibration is ok.") - case .stopped, .sensorFailure11, .sensorFailure12, .sessionFailure15, .sessionFailure16, .sessionFailure17: - return LocalizedString("Sensor is stopped", comment: "The description of sensor calibration state when sensor sensor is stopped.") - case .warmup, .questionMarks: - return LocalizedString("Sensor is warming up", comment: "The description of sensor calibration state when sensor sensor is warming up.") - } - case .unknown(let rawValue): - return String(format: LocalizedString("Sensor is in unknown state %1$d", comment: "The description of sensor calibration state when raw value is unknown. (1: missing data details)"), rawValue) - } - } -} - -// MARK: - AlertResponder implementation -extension G5CGMManager { - public func acknowledgeAlert(alertIdentifier: Alert.AlertIdentifier, completion: @escaping (Error?) -> Void) { - completion(nil) - } -} - -// MARK: - AlertSoundVendor implementation -extension G5CGMManager { - public func getSoundBaseURL() -> URL? { return nil } - public func getSounds() -> [Alert.Sound] { return [] } -} - -// MARK: - AlertResponder implementation -extension G6CGMManager { - public func acknowledgeAlert(alertIdentifier: Alert.AlertIdentifier, completion: @escaping (Error?) -> Void) { - completion(nil) - } -} - -// MARK: - AlertSoundVendor implementation -extension G6CGMManager { - public func getSoundBaseURL() -> URL? { return nil } - public func getSounds() -> [Alert.Sound] { return [] } -} - diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/TransmitterStatus.swift b/Dependencies/CGMBLEKit/CGMBLEKit/TransmitterStatus.swift deleted file mode 100644 index f2792f990..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/TransmitterStatus.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// TransmitterStatus.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 3/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public enum TransmitterStatus { - public typealias RawValue = UInt8 - - case ok - case lowBattery - case unknown(RawValue) - - init(rawValue: RawValue) { - switch rawValue { - case 0: - self = .ok - case 0x81: - self = .lowBattery - default: - self = .unknown(rawValue) - } - } -} - - -extension TransmitterStatus: Equatable { } - -public func ==(lhs: TransmitterStatus, rhs: TransmitterStatus) -> Bool { - switch (lhs, rhs) { - case (.ok, .ok), (.lowBattery, .lowBattery): - return true - case (.unknown(let left), .unknown(let right)) where left == right: - return true - default: - return false - } -} - - -extension TransmitterStatus { - public var localizedDescription: String { - switch self { - case .ok: - return LocalizedString("OK", comment: "Describes a functioning transmitter") - case .lowBattery: - return LocalizedString("Low Battery", comment: "Describes a low battery") - case .unknown(let value): - return "TransmitterStatus.unknown(\(value))" - } - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/ar.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/ar.lproj/Localizable.strings deleted file mode 100644 index c1182284f..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/ar.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* Describes a low battery */ -"Low Battery" = "Low Battery"; - -/* Describes a functioning transmitter */ -"OK" = "موافق"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Peripheral command was invalid"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Peripheral did not respond in time"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Peripheral isnʼt connected"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Sensor calibration is OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Sensor needs calibration"; - -/* Error description */ -"Unknown characteristic" = "Unknown characteristic"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/ca.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/ca.lproj/Localizable.strings deleted file mode 100644 index 864a138e0..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/ca.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* Describes a low battery */ -"Low Battery" = "Low Battery"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Peripheral command was invalid"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Peripheral did not respond in time"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Peripheral isnʼt connected"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Sensor calibration is OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Sensor needs calibration"; - -/* Error description */ -"Unknown characteristic" = "Unknown characteristic"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/cs.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/cs.lproj/Localizable.strings deleted file mode 100644 index e62935a3d..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/cs.lproj/Localizable.strings +++ /dev/null @@ -1,18 +0,0 @@ -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Údaje o glukóze nejsou k dispozici"; - -/* Describes a low battery */ -"Low Battery" = "Vybitá baterie"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Periferní zařízení nereagovalo včas"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Senzor je zastaven"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Senzor se zahřívá"; - diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/da.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/da.lproj/Localizable.strings deleted file mode 100644 index 58183ae30..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/da.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glukosedata ikke tilgængeligt"; - -/* Describes a low battery */ -"Low Battery" = "lavt batteri"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Kommando for ekstern enhed var ugyldig"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Ekstern enhed svarede ikke i tide"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Ekstern enhed er ikke forbundet"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Sensorkalibrering er OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor i ukendt tilstand %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Sensor er stoppet"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Sensor varmer op"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Sensoren har brug for kalibrering"; - -/* Error description */ -"Unknown characteristic" = "Ukendt karakteristik"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/de.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/de.lproj/Localizable.strings deleted file mode 100644 index 79b76dae0..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/de.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glukosedaten nicht verfügbar"; - -/* Describes a low battery */ -"Low Battery" = "Batterie schwach"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Peripheriebefehl war ungültig"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Peripherie antwortet nicht rechtzeitig"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Peripherie ist nicht verbunden"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Sensorkalibrierung OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor befindet sich in unbekanntem Zustand %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Sensor gestoppt"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Sensor befindet sich in der Aufwärmphase"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Sensor benötigt Kalibrierung"; - -/* Error description */ -"Unknown characteristic" = "Unbekannte Charakteristik"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/es.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/es.lproj/Localizable.strings deleted file mode 100644 index ff8a32114..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/es.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Los datos de glucosa no están disponibles"; - -/* Describes a low battery */ -"Low Battery" = "Batería Baja"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "El comando del dispositivo periférico no es válido"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "El dispositivo periférico no respondió a tiempo"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "El dispositivo periférico no está conectado"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Calibración de sensor está OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "El sensor está en estado desconocido %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "El sensor está en pausa"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "El sensor se está calentando"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Sensor se necesita de calibración"; - -/* Error description */ -"Unknown characteristic" = "Característica desconocida"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/fi.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/fi.lproj/Localizable.strings deleted file mode 100644 index 4bea17df0..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/fi.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glukoositietoja ei ole saatavilla"; - -/* Describes a low battery */ -"Low Battery" = "Akku lähes tyhjä"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Oheislaitekomento oli virheellinen"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Ulkoinen laite ei vastannut ajoissa"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Ulkoinen laite ei ole yhdistetty"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Anturin kalibrointi onnistui"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Anturi on tuntemattomassa tilassa %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Anturi on pysäytetty"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Anturi lämpenee"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Anturi tarvitsee kalibroinnin"; - -/* Error description */ -"Unknown characteristic" = "Tuntematon ominaisuus"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/fr.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/fr.lproj/Localizable.strings deleted file mode 100644 index 4546ce581..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/fr.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Les données de glycémie ne sont pas disponibles"; - -/* Describes a low battery */ -"Low Battery" = "Batterie faible"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "La commande périphérique a retourné une commande invalide"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Le périphérique n’a pas répondu à temps"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Le périphérique n’est pas connecté"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Étalonnage de capteur OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Le capteur est dans un état inconnu %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Le capteur est arrêté"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Le capteur est en préchauffage"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Capteur doit être étalonné"; - -/* Error description */ -"Unknown characteristic" = "Caractéristique inconnue"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/he.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/he.lproj/Localizable.strings deleted file mode 100644 index 41fce61a7..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/he.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* Describes a low battery */ -"Low Battery" = "סוללה חלשה"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Peripheral command was invalid"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Peripheral did not respond in time"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Peripheral isnʼt connected"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Sensor calibration is OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "מצב החישן אינו ידוע %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "חיישן נעצר"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "חיישן מתחמם"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Sensor needs calibration"; - -/* Error description */ -"Unknown characteristic" = "מאפיין לא ידוע"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/hi.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/hi.lproj/Localizable.strings deleted file mode 100644 index aeef608c0..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/hi.lproj/Localizable.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Error description for unreliable state */ -"Glucose data is unavailable" = "ग्लूकोस डेटा उपलब्ध नहीं है"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "सेन्सर समाप्त हो गया"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "सेन्सर अपने शुरुआती समय में है"; - diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/hu.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/hu.lproj/Localizable.strings deleted file mode 100644 index 864a138e0..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/hu.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* Describes a low battery */ -"Low Battery" = "Low Battery"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Peripheral command was invalid"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Peripheral did not respond in time"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Peripheral isnʼt connected"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Sensor calibration is OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Sensor needs calibration"; - -/* Error description */ -"Unknown characteristic" = "Unknown characteristic"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/it.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/it.lproj/Localizable.strings deleted file mode 100644 index ae5c809c0..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/it.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "I dati della glicemia non sono disponibili"; - -/* Describes a low battery */ -"Low Battery" = "Batteria Bassa"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Il comando della periferica non era valido"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "La periferica non ha risposto entro il tempo limite"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "La periferica non è connessa"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "La calibrazione del sensore è valida"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Il Sensore è in un stato %1$d sconosciuto"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Il Sensore è fermo"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Il sensore è in fase di avvio"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Il sensore necessita di calibrazione"; - -/* Error description */ -"Unknown characteristic" = "Caratteristica sconosciuta"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/ja.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/ja.lproj/Localizable.strings deleted file mode 100644 index 171184016..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/ja.lproj/Localizable.strings +++ /dev/null @@ -1,39 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "グルコースデータがありません"; - -/* Describes a low battery */ -"Low Battery" = "電池残量低下"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "危機が時間内に反応しませんでした"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "危機が接続されていません"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "センサーの較正はできています"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "センサーの状態が不明です %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "センサーが停止しています"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "センサーが準備中です"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "センサーの較正が必要です"; - -/* Error description */ -"Unknown characteristic" = "エラー不明"; - diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/nb.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/nb.lproj/Localizable.strings deleted file mode 100644 index cadb73a83..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/nb.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Blodsukker er utilgjengelig"; - -/* Describes a low battery */ -"Low Battery" = "Lavt batterinivå"; - -/* Describes a functioning transmitter */ -"OK" = "Ok"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Perifer kommando var ugyldig"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Tilbehøret svarte ikke i tide"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Tilbehøret er ikke tilkoblet"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Sensorkalibrering er OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor er i ukjent tilstand %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Sensor er stoppet"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Sensor varmer opp"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Sensor trenger kalibrering"; - -/* Error description */ -"Unknown characteristic" = "Ukjent karakteristikk"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/nl.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/nl.lproj/Localizable.strings deleted file mode 100644 index 781d48264..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/nl.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucosegegevens zijn niet beschikbaar"; - -/* Describes a low battery */ -"Low Battery" = "Batterij bijna leeg"; - -/* Describes a functioning transmitter */ -"OK" = "Ok"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Apparaat commando was ongeldig"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Apparaat reageerde niet op tijd"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Apparaat is niet verbonden"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Sensorkalibratie is OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Onbekende sensorstatus %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Sensor gestopt"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Sensor aan het opwarmen"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Sensor moet worden gekalibreerd"; - -/* Error description */ -"Unknown characteristic" = "Onbekende eigenschap"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/pl.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/pl.lproj/Localizable.strings deleted file mode 100644 index f2bc41430..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/pl.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Dane o poziomie glukozy są niedostępne"; - -/* Describes a low battery */ -"Low Battery" = "Słaba bateria"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Polecenie urządzenia peryferyjnego było nieprawidłowe"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Urz. peryferyjne nie odpowiada"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Urz. peryferyjne jest niepodłączone"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Kalibracja sensora powiodła się"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor jest w nieznanym stanie %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Sensor został zatrzymany"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Sensor jest w fazie rozruchu"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Sensor wymaga kalibracji"; - -/* Error description */ -"Unknown characteristic" = "Nieznany błąd"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/pt-BR.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/pt-BR.lproj/Localizable.strings deleted file mode 100644 index f9ced47e3..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Os dados de glicose não estão disponíveis"; - -/* Describes a low battery */ -"Low Battery" = "Bateria Fraca"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Peripheral command was invalid"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Acessório não respondeu a tempo"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Acessório não está conectado"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "A calibração do sensor está OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "O sensor está em um estado desconhecido %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "O sensor está parado"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "O sensor está aquecendo"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "O sensor precisa de calibração"; - -/* Error description */ -"Unknown characteristic" = "Característica Desconhecida"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/pt-PT.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/pt-PT.lproj/Localizable.strings deleted file mode 100644 index 864a138e0..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/pt-PT.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* Describes a low battery */ -"Low Battery" = "Low Battery"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Peripheral command was invalid"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Peripheral did not respond in time"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Peripheral isnʼt connected"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Sensor calibration is OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Sensor needs calibration"; - -/* Error description */ -"Unknown characteristic" = "Unknown characteristic"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/ro.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/ro.lproj/Localizable.strings deleted file mode 100644 index 93e588a28..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/ro.lproj/Localizable.strings +++ /dev/null @@ -1,42 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Datele despre glucoză nu sunt disponibile"; - -/* Describes a low battery */ -"Low Battery" = "Baterie descărcată"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Comanda dispozitivului este nevalidă"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Dispozitivul periferic nu a răspuns în timp util"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Dispozitivul periferic nu este conectat"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Calibrarea senzorului este OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Starea senzorului este necunoscută"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Senzorul e oprit"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Senzorul se pregătește"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Senzorul are nevoie de calibrare"; - -/* Error description */ -"Unknown characteristic" = "Caracteristică necunoscută"; - diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/ru.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/ru.lproj/Localizable.strings deleted file mode 100644 index ca294360d..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/ru.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Данные глюкозы недоступны"; - -/* Describes a low battery */ -"Low Battery" = "Батарейка садится"; - -/* Describes a functioning transmitter */ -"OK" = "ОК"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Неправильно сформирован запрос."; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Периферийное устройство не отозвалось вовремя"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Соединение с периферийным устройством не установлено"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Калибровка сенсора ОК"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Неизвестное состояние сенсора%1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Сенсор остановлен"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Сенсор прогревается"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Сенсор требует калибровки"; - -/* Error description */ -"Unknown characteristic" = "Неизвестная характеристика"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/sk.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/sk.lproj/Localizable.strings deleted file mode 100644 index 88ec60590..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/sk.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Údaje o glykémii nie sú k dispozícii"; - -/* Describes a low battery */ -"Low Battery" = "Slabá batéria"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Periférny príkaz bol neplatný"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Periférne zariadenie nereagovalo načas"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Periférne zariadenie nie je pripojené"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Kalibrácia senzora je vporiadku"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Senzor je v neznámom stave %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Senzor je zastavený"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Senzor sa zahrieva"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Senzor potrebuje kalibráciu"; - -/* Error description */ -"Unknown characteristic" = "Neznáma charakteristika"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/sv.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/sv.lproj/Localizable.strings deleted file mode 100644 index 7ee7bf9a8..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/sv.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glukosvärden är inte tillgängliga"; - -/* Describes a low battery */ -"Low Battery" = "Lågt batteri"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Enhetskommando var ogiltigt"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Enheten svarade inte inom utsatt tid"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Enheten är inte ansluten"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Sensorkalibrering lyckades"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensorns status är okänd %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Sensorn har stoppats"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Sensorn värmer upp"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Sensorn behöver kalibreras"; - -/* Error description */ -"Unknown characteristic" = "Okänd data"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/tr.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/tr.lproj/Localizable.strings deleted file mode 100644 index 492f87b77..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/tr.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "KŞ verileri mevcut değil"; - -/* Describes a low battery */ -"Low Battery" = "Düşük Pil"; - -/* Describes a functioning transmitter */ -"OK" = "Tamam"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Çevre birimi komutu geçersiz"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Çevre birimi zamanında yanıt vermedi"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Çevre birimi bağlı değil"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Sensör kalibrasyonu tamam"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensör bilinmeyen durumda %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Sensör durdu"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Sensör ısınıyor"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Sensörün kalibrasyona ihtiyacı var"; - -/* Error description */ -"Unknown characteristic" = "Bilinmeyen karakteristik"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/uk.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/uk.lproj/Localizable.strings deleted file mode 100644 index 7660749e3..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/uk.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Дані глюкози недоступні"; - -/* Describes a low battery */ -"Low Battery" = "Низький заряд батареї"; - -/* Describes a functioning transmitter */ -"OK" = "ОК"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Неправильно сформовано запит."; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Периферійний пристрій не озвався вчасно"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "З'єднання з периферійним пристроєм не встановлено"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Калібрування сенсора ОК"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Сенсор знаходиться в невідомому стані%1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Сенсор зупинений"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Сенсор прогрівається"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Сенсор вимагає калібрування"; - -/* Error description */ -"Unknown characteristic" = "Невідома характеристика"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/vi.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/vi.lproj/Localizable.strings deleted file mode 100644 index 329ab73b3..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/vi.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Dữ liệu glucose không có sẵn"; - -/* Describes a low battery */ -"Low Battery" = "pin yếu"; - -/* Describes a functioning transmitter */ -"OK" = "OK"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Câu lệnh không hợp lệ"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Ngoại vi không đáp ứng kịp thời"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Ngoại vi không được kết nối"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "Hiệu chuẩn cảm biến là OK"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Cảm biến ở trạng thái không xác định %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "Cảm biến bị dừng"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "Cảm biến đang nóng lên"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "Cảm biến cần hiệu chuẩn"; - -/* Error description */ -"Unknown characteristic" = "Đặc điểm không xác định"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKit/zh-Hans.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKit/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 5a6ae3671..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKit/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,41 +0,0 @@ -/* CGM display title */ -"Dexcom G5" = "Dexcom G 5"; - -/* CGM display title */ -"Dexcom G6" = "Dexcom G6"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "葡萄糖数据不可用"; - -/* Describes a low battery */ -"Low Battery" = "电量低"; - -/* Describes a functioning transmitter */ -"OK" = "Ok"; - -/* invlid config error description */ -"Peripheral command was invalid" = "Peripheral command was invalid"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "外设没有及时响应"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "外围设备未连接"; - -/* The description of sensor calibration state when sensor calibration is ok. */ -"Sensor calibration is OK" = "传感器校准成功"; - -/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "传感器处于未知状态 %1$d"; - -/* The description of sensor calibration state when sensor sensor is stopped. */ -"Sensor is stopped" = "传感器停止"; - -/* The description of sensor calibration state when sensor sensor is warming up. */ -"Sensor is warming up" = "传感器在启动中"; - -/* The description of sensor calibration state when sensor needs calibration. */ -"Sensor needs calibration" = "传感器需要校准"; - -/* Error description */ -"Unknown characteristic" = "未知特性"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitG5Plugin/CGMBLEKitG5Plugin-Bridging-Header.h b/Dependencies/CGMBLEKit/CGMBLEKitG5Plugin/CGMBLEKitG5Plugin-Bridging-Header.h deleted file mode 100644 index 1b2cb5d6d..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitG5Plugin/CGMBLEKitG5Plugin-Bridging-Header.h +++ /dev/null @@ -1,4 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - diff --git a/Dependencies/CGMBLEKit/CGMBLEKitG5Plugin/CGMBLEKitG5Plugin.swift b/Dependencies/CGMBLEKit/CGMBLEKitG5Plugin/CGMBLEKitG5Plugin.swift deleted file mode 100644 index 9cc6d70dd..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitG5Plugin/CGMBLEKitG5Plugin.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// CGMBLEKitG5Plugin.swift -// CGMBLEKitG5Plugin -// -// Created by Nathaniel Hamming on 2019-12-19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import os.log -import LoopKitUI -import CGMBLEKit -import CGMBLEKitUI - -class CGMBLEKitG5Plugin: NSObject, CGMManagerUIPlugin { - private let log = OSLog(category: "CGMBLEKitG5Plugin") - - public var cgmManagerType: CGMManagerUI.Type? { - return G5CGMManager.self - } - - override init() { - super.init() - log.default("Instantiated") - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitG5Plugin/Info.plist b/Dependencies/CGMBLEKit/CGMBLEKitG5Plugin/Info.plist deleted file mode 100644 index 844749bbc..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitG5Plugin/Info.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright © 2019 LoopKit Authors. All rights reserved. - NSPrincipalClass - CGMBLEKitG5Plugin - com.loopkit.Loop.CGMManagerDisplayName - Dexcom G5 - com.loopkit.Loop.CGMManagerIdentifier - DexG5Transmitter - - diff --git a/Dependencies/CGMBLEKit/CGMBLEKitG6Plugin/CGMBLEKitG6Plugin-Bridging-Header.h b/Dependencies/CGMBLEKit/CGMBLEKitG6Plugin/CGMBLEKitG6Plugin-Bridging-Header.h deleted file mode 100644 index 1b2cb5d6d..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitG6Plugin/CGMBLEKitG6Plugin-Bridging-Header.h +++ /dev/null @@ -1,4 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - diff --git a/Dependencies/CGMBLEKit/CGMBLEKitG6Plugin/CGMBLEKitG6Plugin.swift b/Dependencies/CGMBLEKit/CGMBLEKitG6Plugin/CGMBLEKitG6Plugin.swift deleted file mode 100644 index 8b8ceef4a..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitG6Plugin/CGMBLEKitG6Plugin.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// CGMBLEKitG6Plugin.swift -// CGMBLEKitG6Plugin -// -// Created by Nathaniel Hamming on 2019-12-13. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import os.log -import LoopKitUI -import CGMBLEKit -import CGMBLEKitUI - -class CGMBLEKitG6Plugin: NSObject, CGMManagerUIPlugin { - private let log = OSLog(category: "CGMBLEKitG6Plugin") - - public var cgmManagerType: CGMManagerUI.Type? { - return G6CGMManager.self - } - - override init() { - super.init() - log.default("Instantiated") - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitG6Plugin/Info.plist b/Dependencies/CGMBLEKit/CGMBLEKitG6Plugin/Info.plist deleted file mode 100644 index 50536dbb7..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitG6Plugin/Info.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright © 2019 LoopKit Authors. All rights reserved. - NSPrincipalClass - CGMBLEKitG6Plugin - com.loopkit.Loop.CGMManagerDisplayName - Dexcom G6 - com.loopkit.Loop.CGMManagerIdentifier - DexG6Transmitter - - diff --git a/Dependencies/CGMBLEKit/CGMBLEKitTests/CalibrationDataRxMessageTests.swift b/Dependencies/CGMBLEKit/CGMBLEKitTests/CalibrationDataRxMessageTests.swift deleted file mode 100644 index bae53c139..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitTests/CalibrationDataRxMessageTests.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// CalibrationDataRxMessageTests.swift -// xDripG5 -// -// Created by Nate Racklyeft on 9/18/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import CGMBLEKit - - -class CalibrationDataRxMessageTests: XCTestCase { - - func testMessage() { - let data = Data(hexadecimalString: "33002b290090012900ae00800050e929001225")! - XCTAssertNotNil(CalibrationDataRxMessage(data: data)) - } - -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitTests/GlucoseBackfillMessageTests.swift b/Dependencies/CGMBLEKit/CGMBLEKitTests/GlucoseBackfillMessageTests.swift deleted file mode 100644 index 99671ac53..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitTests/GlucoseBackfillMessageTests.swift +++ /dev/null @@ -1,433 +0,0 @@ -// -// GlucoseBackfillMessageTests.swift -// xDripG5Tests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import CGMBLEKit - -class GlucoseBackfillMessageTests: XCTestCase { - - func testTxMessage() { - let message = GlucoseBackfillTxMessage(byte1: 5, byte2: 2, identifier: 0, startTime: 5439415, endTime: 5440614) // 20 minutes - - XCTAssertEqual(Data(hexadecimalString: "50050200b7ff5200660453000000000000007138")!, message.data) - } - - func testRxMessage() { - let message = GlucoseBackfillRxMessage(data: Data(hexadecimalString: "51000100b7ff52006604530032000000e6cb9805")!)! - - XCTAssertEqual(.ok, TransmitterStatus(rawValue: message.status)) - XCTAssertEqual(1, message.backfillStatus) - XCTAssertEqual(0, message.identifier) - XCTAssertEqual(5439415, message.startTime) - XCTAssertEqual(5440614, message.endTime) - XCTAssertEqual(50, message.bufferLength) - XCTAssertEqual(0xcbe6, message.bufferCRC) - - // 0xbc46 - // 0b10111100 01000110 - var buffer = GlucoseBackfillFrameBuffer(identifier: message.identifier) - buffer.append(Data(hexadecimalString: "0100bc460000b7ff52008b0006eee30053008500")!) - buffer.append(Data(hexadecimalString: "020006eb0f025300800006ee3a0353007e0006f5")!) - buffer.append(Data(hexadecimalString: "030066045300790006f8")!) - - XCTAssertEqual(Int(message.bufferLength), buffer.count) - XCTAssertEqual(message.bufferCRC, buffer.crc16) - - let messages = buffer.glucose - - XCTAssertEqual(139, messages[0].glucose) - XCTAssertEqual(5439415, messages[0].timestamp) - XCTAssertEqual(.known(.ok), CalibrationState(rawValue: messages[0].state)) - XCTAssertEqual(-18, messages[0].trend) - - XCTAssertEqual(133, messages[1].glucose) - XCTAssertEqual(5439715, messages[1].timestamp) - XCTAssertEqual(.known(.ok), CalibrationState(rawValue: messages[1].state)) - XCTAssertEqual(-21, messages[1].trend) - - XCTAssertEqual(128, messages[2].glucose) - XCTAssertEqual(5440015, messages[2].timestamp) - XCTAssertEqual(.known(.ok), CalibrationState(rawValue: messages[2].state)) - XCTAssertEqual(-18, messages[2].trend) - - XCTAssertEqual(126, messages[3].glucose) - XCTAssertEqual(5440314, messages[3].timestamp) - XCTAssertEqual(.known(.ok), CalibrationState(rawValue: messages[3].state)) - XCTAssertEqual(-11, messages[3].trend) - - XCTAssertEqual(121, messages[4].glucose) - XCTAssertEqual(5440614, messages[4].timestamp) - XCTAssertEqual(.known(.ok), CalibrationState(rawValue: messages[4].state)) - XCTAssertEqual(-08, messages[4].trend) - - XCTAssertEqual(message.startTime, messages.first!.timestamp) - XCTAssertEqual(message.endTime, messages.last!.timestamp) - - XCTAssertTrue(messages.first!.timestamp <= messages.last!.timestamp) - } - - func testGlucoseBackfill2() { - let message = GlucoseBackfillTxMessage(byte1: 5, byte2: 2, identifier: 0, startTime: 4648682, endTime: 4650182) // 25 minutes - - XCTAssertEqual(Data(hexadecimalString: "50050200eaee4600c6f446000000000000009f6d")!, message.data, message.data.hexadecimalString) - - let response = GlucoseBackfillRxMessage(data: Data(hexadecimalString: "51000103eaee4600c6f446003a0000004f3ac9e6")!)! - - XCTAssertEqual(.ok, TransmitterStatus(rawValue: response.status)) - XCTAssertEqual(1, response.backfillStatus) - XCTAssertEqual(3, response.identifier) - XCTAssertEqual(4648682, response.startTime) - XCTAssertEqual(4650182, response.endTime) - XCTAssertEqual(58, response.bufferLength) - XCTAssertEqual(0x3a4f, response.bufferCRC) - - // 0x6e3c - // 0b01101110 00111100 - var buffer = GlucoseBackfillFrameBuffer(identifier: 0xc0) - buffer.append(Data(hexadecimalString: "01c06e3c0000eaee4600920007fd16f046009500")!) - buffer.append(Data(hexadecimalString: "02c0070042f14600960007026ef2460099000704")!) - buffer.append(Data(hexadecimalString: "03c09af3460093000700c6f44600900007fc")!) - - XCTAssertEqual(Int(response.bufferLength), buffer.count) - XCTAssertEqual(response.bufferCRC, buffer.crc16) - - let messages = buffer.glucose - - XCTAssertEqual(response.startTime, messages.first!.timestamp) - XCTAssertEqual(response.endTime, messages.last!.timestamp) - - XCTAssertTrue(messages.first!.timestamp <= messages.last!.timestamp) - - XCTAssertEqual(6, messages.count) - } - - func testMalformedBackfill() { - var buffer = GlucoseBackfillFrameBuffer(identifier: 0) - buffer.append(Data(hexadecimalString: "0100bc460000b7ff52008b0006eee30053008500")!) - buffer.append(Data(hexadecimalString: "020006eb0f025300800006ee3a0353007e0006")!) - - XCTAssertEqual(3, buffer.glucose.count) - } - - func testGlucoseBackfill3() { - let response = GlucoseBackfillRxMessage(data: Data(hexadecimalString: "510001023d6a0e00c16d0e00280000005b1a9154")!)! - - XCTAssertEqual(.ok, TransmitterStatus(rawValue: response.status)) - XCTAssertEqual(1, response.backfillStatus) - XCTAssertEqual(2, response.identifier) - XCTAssertEqual(944701, response.startTime) - XCTAssertEqual(945601, response.endTime) - XCTAssertEqual(40, response.bufferLength) - XCTAssertEqual(0x1A5B, response.bufferCRC) - - // 0x440c - // 0b01000100 00001100 - var buffer = GlucoseBackfillFrameBuffer(identifier: 0x80) - buffer.append(Data(hexadecimalString: "0180440c00003d6a0e005c0007fe696b0e005d00")!) - buffer.append(Data(hexadecimalString: "028007ff956c0e005e000700c16d0e005d000700")!) - - XCTAssertEqual(Int(response.bufferLength), buffer.count) - XCTAssertEqual(response.bufferCRC, buffer.crc16) - - let messages = buffer.glucose - - XCTAssertEqual(response.startTime, messages.first!.timestamp) - XCTAssertEqual(response.endTime, messages.last!.timestamp) - - XCTAssertTrue(messages.first!.timestamp <= messages.last!.timestamp) - - XCTAssertEqual(4, messages.count) - } - - func testGlucoseBackfill4() { - let response = GlucoseBackfillRxMessage(data: Data(hexadecimalString: "51000103c9740e004d780e0028000000235bd94c")!)! - - XCTAssertEqual(.ok, TransmitterStatus(rawValue: response.status)) - XCTAssertEqual(1, response.backfillStatus) - XCTAssertEqual(3, response.identifier) - XCTAssertEqual(947401, response.startTime) - XCTAssertEqual(948301, response.endTime) - XCTAssertEqual(40, response.bufferLength) - XCTAssertEqual(0x5B23, response.bufferCRC) - - // 0x04d0 - // 0b00000100 11010000 - var buffer = GlucoseBackfillFrameBuffer(identifier: 0xc0) - buffer.append(Data(hexadecimalString: "01c04d0c0000c9740e005a000700f5750e005800")!) - buffer.append(Data(hexadecimalString: "02c007ff21770e00590007ff4d780e0059000700")!) - - XCTAssertEqual(Int(response.bufferLength), buffer.count) - XCTAssertEqual(response.bufferCRC, buffer.crc16) - - let messages = buffer.glucose - - XCTAssertEqual(response.startTime, messages.first!.timestamp) - XCTAssertEqual(response.endTime, messages.last!.timestamp) - - XCTAssertTrue(messages.first!.timestamp <= messages.last!.timestamp) - - XCTAssertEqual(4, messages.count) - } - - func testNotGlucoseBackfill1() { - let response = GlucoseBackfillRxMessage(data: Data(hexadecimalString: "5100010339410e0085a90e00ac06000070ca9143")!)! - - XCTAssertEqual(.ok, TransmitterStatus(rawValue: response.status)) - XCTAssertEqual(1, response.backfillStatus) - XCTAssertEqual(3, response.identifier) - XCTAssertEqual(934201, response.startTime) - XCTAssertEqual(960901, response.endTime) - XCTAssertEqual(1708, response.bufferLength) - XCTAssertEqual(0xCA70, response.bufferCRC) - - // 0x4a4f - // 0b01001010 01001111 - var buffer = GlucoseBackfillFrameBuffer(identifier: 0xc0) - buffer.append(Data(hexadecimalString: "01c04a4f4a5558ef554453b7392a0df008571a7f")!) - buffer.append(Data(hexadecimalString: "02c0451e0d74bdec596b633cf2b03d511ef3d048")!) - buffer.append(Data(hexadecimalString: "03c009145e959ca51f7a1663ca31676b175d7bc7")!) - buffer.append(Data(hexadecimalString: "04c0de00c954fcd3281d5163ed873cdc136fca3e")!) - buffer.append(Data(hexadecimalString: "05c0c7da188dd5fbb8997206da1cc8d0c22f8434")!) - buffer.append(Data(hexadecimalString: "06c04d50b29df06b12e7162f2d73fd553e44e469")!) - buffer.append(Data(hexadecimalString: "07c02b4bb61d66cf6e949ee0f07dbe0cc12127ae")!) - buffer.append(Data(hexadecimalString: "08c03bf887be09ece7595adfee494b25368103b4")!) - buffer.append(Data(hexadecimalString: "09c07eefb9b5398468a53f00355341d19b50c8b1")!) - buffer.append(Data(hexadecimalString: "0ac028f0ddb4dc09a2c74deedf7fdff13fcd6b0e")!) - buffer.append(Data(hexadecimalString: "0bc0ad2d7311ac9ec1908fb7ee5557c463ea4fea")!) - buffer.append(Data(hexadecimalString: "0cc0bf3c62d9aa62d7c3d447c959b51d31fd016d")!) - buffer.append(Data(hexadecimalString: "0dc0278116abd1252ad66c894a39ed7c6d72086e")!) - buffer.append(Data(hexadecimalString: "0ec0aaee3bf9b05ccb7b23e1c27d777173c4d9fd")!) - buffer.append(Data(hexadecimalString: "0fc044048720d76a696249737f999f944995e44e")!) - buffer.append(Data(hexadecimalString: "10c0495e4cb7f22327a920a843de1b4522a68108")!) - buffer.append(Data(hexadecimalString: "11c058c482389192ed920e322b71900d747a9492")!) - buffer.append(Data(hexadecimalString: "12c0eac06906ff4863f0e8da07d1ead29fc15bd3")!) - buffer.append(Data(hexadecimalString: "13c0c0be38548fe9e229c64c9c0f3e9b4c4c1d83")!) - buffer.append(Data(hexadecimalString: "14c018a936bdde548e4244093e77c87adda0a1cf")!) - buffer.append(Data(hexadecimalString: "15c0fb97d1d147dd0bc6552faa4d62ab553e1682")!) - buffer.append(Data(hexadecimalString: "16c0f15f8cb77decb934bfe0c711a026dd4bf36b")!) - buffer.append(Data(hexadecimalString: "17c0bd268b0eee07ed20a0f3856ea449b1503708")!) - buffer.append(Data(hexadecimalString: "18c00872ed5a996a13480b81fc82b6ca1e7dd379")!) - buffer.append(Data(hexadecimalString: "19c06fb4c5bc84e63688b0a77edbab85bfb61b45")!) - buffer.append(Data(hexadecimalString: "1ac071d29d30edb43db6b8e114bbbcd67f9dd3a9")!) - buffer.append(Data(hexadecimalString: "1bc0569e17a8a80c015def11ddce1b8f194ff6e2")!) - buffer.append(Data(hexadecimalString: "1cc0df79ffbc1e077fe249b47550feb5dcd53044")!) - buffer.append(Data(hexadecimalString: "1dc0b557e2ba03caed61de30221b0330e1cc49b1")!) - buffer.append(Data(hexadecimalString: "1ec006f05e739d737939baf8b14a8b7a6faae96e")!) - buffer.append(Data(hexadecimalString: "1fc00b82d430e9e75fb8e7e2affbdd292a41fad2")!) - buffer.append(Data(hexadecimalString: "20c0fbf8e8f2686aaaf19d2809eecd3bd4f63516")!) - buffer.append(Data(hexadecimalString: "21c0a7df809e73538e459c1a9cd27a566f636e22")!) - buffer.append(Data(hexadecimalString: "22c0dbb3c23d7d7847dee77311287e6c6b192eb4")!) - buffer.append(Data(hexadecimalString: "23c0d30038d70241a80b9e390778a897dd1632cc")!) - buffer.append(Data(hexadecimalString: "24c0177b23127b464c07a499abeff05f13e40998")!) - buffer.append(Data(hexadecimalString: "25c0855350c7c4a335e95d2e569996639e8341b4")!) - buffer.append(Data(hexadecimalString: "26c0d42874475710a50764d4a4166c0e420aff7f")!) - buffer.append(Data(hexadecimalString: "27c0facb1d61cb8057de64546fc9f24f93603093")!) - buffer.append(Data(hexadecimalString: "28c080befb84f22c60d398f017dde114d0557b27")!) - buffer.append(Data(hexadecimalString: "29c07555e92425342c0674b62fa517b13ba0e3b0")!) - buffer.append(Data(hexadecimalString: "2ac0923624bce36c89fade1f66bd7ae1e8e7d598")!) - buffer.append(Data(hexadecimalString: "2bc0d345ceea668373d31f95b03a6ee7fff1a3b5")!) - buffer.append(Data(hexadecimalString: "2cc045e409b8d31dd53ae9d353f35738819fbb79")!) - buffer.append(Data(hexadecimalString: "2dc0a5d31fd3c3b7b217d3f79b245d3714b0523d")!) - buffer.append(Data(hexadecimalString: "2ec0eb576e0193584bff8ecada0dc54e4ebde86c")!) - buffer.append(Data(hexadecimalString: "2fc092b8ef52003f8b76e90d920ca738c998bb70")!) - buffer.append(Data(hexadecimalString: "30c07cfa0f7a69d14b79f605d254a164fd67c658")!) - buffer.append(Data(hexadecimalString: "31c049a329162e03f41c12db845b73301f5bbb81")!) - buffer.append(Data(hexadecimalString: "32c08a21ca0995b5aa413897ea9e2b7c563ced07")!) - buffer.append(Data(hexadecimalString: "33c05d51a18e19209f1c55054bd2f74677c71070")!) - buffer.append(Data(hexadecimalString: "34c0299e29ae5576a220b0b767fc4e898aaf2df1")!) - buffer.append(Data(hexadecimalString: "35c0bbb554546b69c53b4b3a63bd524bfbe728e6")!) - buffer.append(Data(hexadecimalString: "36c0cd4e8c6e10e72950e66bfa0d23b954a7aede")!) - buffer.append(Data(hexadecimalString: "37c0ea5df836af737298d44b4b156ced47727920")!) - buffer.append(Data(hexadecimalString: "38c02303edefc4916cfdba55829426c153d0d30c")!) - buffer.append(Data(hexadecimalString: "39c0dfee091fea60c2da239c9aabef8eddbe49b5")!) - buffer.append(Data(hexadecimalString: "3ac02788f23fb030e7606329ed24cbee10bc20eb")!) - buffer.append(Data(hexadecimalString: "3bc00a601d46c10bab8cdf04513a47550b0e4fe5")!) - buffer.append(Data(hexadecimalString: "3cc072ea5e514432c81e325464e1ac2d659378d2")!) - buffer.append(Data(hexadecimalString: "3dc0f050e994caa508fdea7202ed70a4acc6e8ab")!) - buffer.append(Data(hexadecimalString: "3ec069ab0d13863943415b492569db29b9594dbe")!) - buffer.append(Data(hexadecimalString: "3fc02c37277a98b88956f0def9ad866f44ca6d9f")!) - buffer.append(Data(hexadecimalString: "40c0e5bd6aa2dbd835fab2ec238de4a635a3f6cb")!) - buffer.append(Data(hexadecimalString: "41c0aafa8812d94d5fe722b3ecfb74eb4c12c622")!) - buffer.append(Data(hexadecimalString: "42c08c5b4bb2f28069fc6f9dcb26bc84c0cc01c7")!) - buffer.append(Data(hexadecimalString: "43c04ad95cefa1f62a18fa2c5a05bac208685cdb")!) - buffer.append(Data(hexadecimalString: "44c0ffe910ddc010b30f457578ab24a866b8a94d")!) - buffer.append(Data(hexadecimalString: "45c01b0bb36e58f401eb15da2e6710721e39c573")!) - buffer.append(Data(hexadecimalString: "46c06165075618fc9626c53acdd9cb8bcfb0719f")!) - buffer.append(Data(hexadecimalString: "47c081599f76725e30d4de39cdcc7f7c0c918d68")!) - buffer.append(Data(hexadecimalString: "48c0563b99dce4913105b793f4d539fe668feef6")!) - buffer.append(Data(hexadecimalString: "49c04ebaaf9f4dfda6cac4d617cd07098fec39f0")!) - buffer.append(Data(hexadecimalString: "4ac04c1ae961bc4f3e2cd395396dc8098bbf4bd5")!) - buffer.append(Data(hexadecimalString: "4bc0d95ed88f296e8d68c35085af86e5ef8d8bf0")!) - buffer.append(Data(hexadecimalString: "4cc0658ccce111259ce8ac5cbedfc46deda77433")!) - buffer.append(Data(hexadecimalString: "4dc05fda2f8d2885082db4b1356c5e2a0e830471")!) - buffer.append(Data(hexadecimalString: "4ec066c7813ff84a9da11fe343e5a95bbfa3082c")!) - buffer.append(Data(hexadecimalString: "4fc03bcfd6fe6d9657d04f06ed7bc461ebe18d47")!) - buffer.append(Data(hexadecimalString: "50c035bbe880ba24d7c84f73ae061b33d62a1845")!) - buffer.append(Data(hexadecimalString: "51c0650f0a6bbc91b2771549cf49a5a4faf8b278")!) - buffer.append(Data(hexadecimalString: "52c07ac551477e6cd10fe6a3b43d62b02569d110")!) - buffer.append(Data(hexadecimalString: "53c005f79d6de0ec017e7a0c98961ce6770f885d")!) - buffer.append(Data(hexadecimalString: "54c0d05fee0b5f5bf9de8c61b58f8634ecbf3347")!) - buffer.append(Data(hexadecimalString: "55c0e0c7d345fbc40f35aed12e82f8ccb0ed9335")!) - buffer.append(Data(hexadecimalString: "56c0b1c8b263179e")!) - - XCTAssertEqual(Int(response.bufferLength), buffer.count) - XCTAssertEqual(response.bufferCRC, buffer.crc16) - - let messages = buffer.glucose - - XCTAssertNotEqual(response.startTime, messages.first!.timestamp) - XCTAssertNotEqual(response.endTime, messages.last!.timestamp) - - XCTAssertEqual(191, messages.count) - } - - func testNotGlucoseBackfill2() { - let response = GlucoseBackfillRxMessage(data: Data(hexadecimalString: "51000102b1aa0e00e5b20e00a000000020a39b7e")!)! - - XCTAssertEqual(.ok, TransmitterStatus(rawValue: response.status)) - XCTAssertEqual(1, response.backfillStatus) - XCTAssertEqual(2, response.identifier) - XCTAssertEqual(961201, response.startTime) - XCTAssertEqual(963301, response.endTime) - XCTAssertEqual(160, response.bufferLength) - XCTAssertEqual(0xA320, response.bufferCRC) - - // 0xcde3 - // 0b11001101 11100011 - var buffer = GlucoseBackfillFrameBuffer(identifier: 0x80) - buffer.append(Data(hexadecimalString: "0180cde3fd48248e37a7bf6c2d9d78d4bfef6d5b")!) - buffer.append(Data(hexadecimalString: "02809f074c9039b6d3b841f422cf36398338f98c")!) - buffer.append(Data(hexadecimalString: "038004160a5a1ad37c382f3ca23ea215c644f7b6")!) - buffer.append(Data(hexadecimalString: "04802ed7376fa7c83c3ecf0b645233f9b3c80238")!) - buffer.append(Data(hexadecimalString: "05805692724e630a703f01b0a942250f725553d2")!) - buffer.append(Data(hexadecimalString: "06804ca2727a4051033a550da80905caf77c735d")!) - buffer.append(Data(hexadecimalString: "07808f937b4b9602c5dd6fa13ae983e00783b28e")!) - buffer.append(Data(hexadecimalString: "088069846e672c106b339159ead9ee1c08e1a159")!) - - XCTAssertEqual(Int(response.bufferLength), buffer.count) - XCTAssertEqual(response.bufferCRC, buffer.crc16) - - let messages = buffer.glucose - - XCTAssertNotEqual(response.startTime, messages.first!.timestamp) - XCTAssertNotEqual(response.endTime, messages.last!.timestamp) - XCTAssertFalse(messages.first!.timestamp <= messages.last!.timestamp) - - XCTAssertEqual(17, messages.count) - } - - func testNotGlucoseBackfill3() { - let response = GlucoseBackfillRxMessage(data: Data(hexadecimalString: "51000102b6a36500010c6600ac0600000147db0a")!)! - - XCTAssertEqual(.ok, TransmitterStatus(rawValue: response.status)) - XCTAssertEqual(1, response.backfillStatus) - XCTAssertEqual(2, response.identifier) - XCTAssertEqual(6661046, response.startTime) - XCTAssertEqual(6687745, response.endTime) - XCTAssertEqual(1708, response.bufferLength) - XCTAssertEqual(0x4701, response.bufferCRC) - - var buffer = GlucoseBackfillFrameBuffer(identifier: 0x80) - buffer.append(Data(hexadecimalString: "0180e1234bdf92845cec52822a8894854582b2b2")!) - buffer.append(Data(hexadecimalString: "02800f8a38cc876ad33ae0acdc25921132cc6f0d")!) - buffer.append(Data(hexadecimalString: "038032a6cd9e6d447916dd0b9699e499ae79b8d1")!) - buffer.append(Data(hexadecimalString: "048045f4b95e0ad80955d3a899d6083bd142f863")!) - buffer.append(Data(hexadecimalString: "05809cf9c189744ab66f6ca5c2833ef27442fa71")!) - buffer.append(Data(hexadecimalString: "068053694b279275f0d23eb826681e20e5ebb79d")!) - buffer.append(Data(hexadecimalString: "078098b921155eb5aed63119d5faec3ef3e53a37")!) - buffer.append(Data(hexadecimalString: "08807c87277557a0828e8dc81ff76f1a6e197103")!) - buffer.append(Data(hexadecimalString: "0980b8378b133898ce73f7989d67360123e9fdd8")!) - buffer.append(Data(hexadecimalString: "0a80383ce19d943a38796b594ff95a2dc93bd6a2")!) - buffer.append(Data(hexadecimalString: "0b806b548c5997dc67ed4fe07bcf236d59dd7f94")!) - buffer.append(Data(hexadecimalString: "0c802cb2382f40a06fde5f2dff3f0b8226a11f12")!) - buffer.append(Data(hexadecimalString: "0d8029800ae513c5b7bc8ea733544b7da84ded17")!) - buffer.append(Data(hexadecimalString: "0e80a95b6c3d36183e4409f916a6f1f775af338e")!) - buffer.append(Data(hexadecimalString: "0f80d098732f2abcf4a90628f321a048349142ff")!) - buffer.append(Data(hexadecimalString: "108077294e9d029bdc0602c76671d88ff4a87596")!) - buffer.append(Data(hexadecimalString: "1180bac50f8d705f6732c34b935a0b06545d6d8f")!) - buffer.append(Data(hexadecimalString: "1280cf6b9eb0d2f0059c1a7b5c65acb83eb43836")!) - buffer.append(Data(hexadecimalString: "13802f408f68fc7e48858daecf64d01f3f61827e")!) - buffer.append(Data(hexadecimalString: "1480cd5975c1062ed45311a2602c0bbc9c78cf21")!) - buffer.append(Data(hexadecimalString: "1580b6e27f3350bc7d4eb908313710931cbd4f23")!) - buffer.append(Data(hexadecimalString: "168061f70e5e27e8b72faecfbb58b6b6ff65cbf0")!) - buffer.append(Data(hexadecimalString: "178066bdd3a0b1e1ed0af8b2af88dcb1f4b1c3a4")!) - buffer.append(Data(hexadecimalString: "18801eb9326019bca25b74804d196c04d079e495")!) - buffer.append(Data(hexadecimalString: "1980a29097393f81aaef79ef421af54ccd3c35ed")!) - buffer.append(Data(hexadecimalString: "1a80a3039b0372ddd79ef65293e4e99484573ab3")!) - buffer.append(Data(hexadecimalString: "1b807e755140ea79b1913a7c491e606b7d1e4542")!) - buffer.append(Data(hexadecimalString: "1c800c968daf03958bd8784e1cf8cea4fa903a80")!) - buffer.append(Data(hexadecimalString: "1d8044c5c7baebadbf8e6877d725ab84484e6755")!) - buffer.append(Data(hexadecimalString: "1e8036be160e8a03d2c07552fc513c8869170528")!) - buffer.append(Data(hexadecimalString: "1f8038483ab634e7707e9ab8c8e3f87dd67f423f")!) - buffer.append(Data(hexadecimalString: "2080f184e4457558d9b7944f21d6421b717ddfb1")!) - buffer.append(Data(hexadecimalString: "2180bb4da6197852102a3a04b8acccea3c54f0f9")!) - buffer.append(Data(hexadecimalString: "2280da93975f3ea1c39d2aff5dbbc4b183b66044")!) - buffer.append(Data(hexadecimalString: "23804678951cdc83923fe5a88bda66221a48360b")!) - buffer.append(Data(hexadecimalString: "2480aa9dc3fee16106bd551754d896da72ff772c")!) - buffer.append(Data(hexadecimalString: "2580b825bb4eba580b57caadda1b90b449a8f2c5")!) - buffer.append(Data(hexadecimalString: "2680117b62c286b395d2bf016848c65953595f19")!) - buffer.append(Data(hexadecimalString: "27806d524b2b191bd9582f47fd3956ab851207af")!) - buffer.append(Data(hexadecimalString: "2880c7df85c2ee5e9b3f5ae68ffba44a86e237e8")!) - buffer.append(Data(hexadecimalString: "2980947fec3646851a510c8a61c0b3b7d90e410b")!) - buffer.append(Data(hexadecimalString: "2a8014b04b3ff32e4d9d16f46880533cf4562af4")!) - buffer.append(Data(hexadecimalString: "2b80c754e48edfa84f2f3b29976ce59cc110747d")!) - buffer.append(Data(hexadecimalString: "2c8095a3ab4b66254954a51ca5e5c92d07be80fc")!) - buffer.append(Data(hexadecimalString: "2d80bc4afa73d7f222f1b9e56083171057e32ca3")!) - buffer.append(Data(hexadecimalString: "2e80c88dbe9a052d7ffd29d2f665bdd66811712f")!) - buffer.append(Data(hexadecimalString: "2f804d2f9ee36fd6f3f48c30429c1629e39bbe3f")!) - buffer.append(Data(hexadecimalString: "30808b01f598fc6420d85b3190d15f8d55f43faf")!) - buffer.append(Data(hexadecimalString: "31801c171908c8ded10e81123f453c571c8f5199")!) - buffer.append(Data(hexadecimalString: "32806275a5652f2447f63f1ab5d0dac84387d80c")!) - buffer.append(Data(hexadecimalString: "3380f095361816ab06f0209a6ec3411c8f0c6ce1")!) - buffer.append(Data(hexadecimalString: "3480a99ac0dae0c87f6a1d4ee4fe4e19671c29ba")!) - buffer.append(Data(hexadecimalString: "3580811db50e1625a3b88305ea5c34b53e20700e")!) - buffer.append(Data(hexadecimalString: "36800fbf211b6a454c788aa17b0cf14db76695a9")!) - buffer.append(Data(hexadecimalString: "3780dfc186d1c189114f182709efc464f48c6b2f")!) - buffer.append(Data(hexadecimalString: "38805e629e8e6457b1ec149897210cb6336b123f")!) - buffer.append(Data(hexadecimalString: "398045d4dc9f4c074ec0e926a8d1768ae92b4866")!) - buffer.append(Data(hexadecimalString: "3a801edf0d5d1c1a86c90c5eeef69e115fdd513a")!) - buffer.append(Data(hexadecimalString: "3b8084223228b158081b465c74454450ec19a4c1")!) - buffer.append(Data(hexadecimalString: "3c80fa306d71fc211bd9b9e55aeb16c582d21ec2")!) - buffer.append(Data(hexadecimalString: "3d8072d8bbec74f1436958db431a92fc66cf5dd2")!) - buffer.append(Data(hexadecimalString: "3e80888ef69a91f8dbb0ce70b6e5ec9289245878")!) - buffer.append(Data(hexadecimalString: "3f8069c0d6d14e580be92f87a3255e124b25b451")!) - buffer.append(Data(hexadecimalString: "4080b3cbae3d50ea52720bf5029243a4a9fea906")!) - buffer.append(Data(hexadecimalString: "4180384321d07a4b5378aa272c9a7247830624b8")!) - buffer.append(Data(hexadecimalString: "4280acf0b265dd82b68aeec5114161a34135b30e")!) - buffer.append(Data(hexadecimalString: "43802d709c604266db64a4b5a5e6f6d8cfd7ece1")!) - buffer.append(Data(hexadecimalString: "44807b48711b0630cd919dbf9ea7bf81efa1e8f1")!) - buffer.append(Data(hexadecimalString: "4580c0282b679f9746ece875482d5e9a5ed59cb8")!) - buffer.append(Data(hexadecimalString: "46808c7b718de4299f081449cce9aa9afadfcea9")!) - buffer.append(Data(hexadecimalString: "478066cd4c36d6e816413b15955c958da4d8e866")!) - buffer.append(Data(hexadecimalString: "48809b5170078157c542236bc7a09c96bc559069")!) - buffer.append(Data(hexadecimalString: "49800be65a0bce639c69cd3d64db0fa22570756f")!) - buffer.append(Data(hexadecimalString: "4a80e5ebd5381b077a8ac56e952b631256a076cc")!) - buffer.append(Data(hexadecimalString: "4b80fb32d28e39021d49dc7b7ee65272ca1f28c1")!) - buffer.append(Data(hexadecimalString: "4c8004486cc3dcad9f39c602d3ed9030e327cec3")!) - buffer.append(Data(hexadecimalString: "4d809a5800c6d647c5f99e40a15327957745dce1")!) - buffer.append(Data(hexadecimalString: "4e80d03a0b5368fda78b28d3975500ab160ac693")!) - buffer.append(Data(hexadecimalString: "4f80dbc5ea65f540933f858a425ecdb378f62990")!) - buffer.append(Data(hexadecimalString: "50802e7980ce9365ad4e434308fb2a8102dc9f6a")!) - buffer.append(Data(hexadecimalString: "5180b71311e183ad9feecfd43b68072d5a9ad4af")!) - buffer.append(Data(hexadecimalString: "5280e721c37d2b57f95cbf5f51025fb22b6ca60c")!) - buffer.append(Data(hexadecimalString: "53805749eb01f070a5b015dcd0f68f5fea0b40c6")!) - buffer.append(Data(hexadecimalString: "5480fae4ee747357e4d73265ad9411c565c41865")!) - buffer.append(Data(hexadecimalString: "5580b75e9c62c7c2aa3ea3f94d219ef7330077d7")!) - buffer.append(Data(hexadecimalString: "5680f2c59ee6b54a")!) - - XCTAssertEqual(Int(response.bufferLength), buffer.count) - XCTAssertEqual(response.bufferCRC, buffer.crc16) - - let messages = buffer.glucose - - XCTAssertNotEqual(response.startTime, messages.first!.timestamp) - XCTAssertNotEqual(response.endTime, messages.last!.timestamp) - XCTAssertFalse(messages.first!.timestamp <= messages.last!.timestamp) - - XCTAssertEqual(191, messages.count) - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitTests/GlucoseRxMessageTests.swift b/Dependencies/CGMBLEKit/CGMBLEKitTests/GlucoseRxMessageTests.swift deleted file mode 100644 index a966dba6d..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitTests/GlucoseRxMessageTests.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// GlucoseRxMessageTests.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 3/5/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import CGMBLEKit - - -class GlucoseRxMessageTests: XCTestCase { - - func testMessageData() { - let data = Data(hexadecimalString: "3100680a00008a715700cc0006ffc42a")! - let message = GlucoseRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(2664, message.sequence) - XCTAssertEqual(5730698, message.glucose.timestamp) - XCTAssertFalse(message.glucose.glucoseIsDisplayOnly) - XCTAssertEqual(204, message.glucose.glucose) - XCTAssertEqual(6, message.glucose.state) - XCTAssertEqual(-1, message.glucose.trend) - } - - func testNegativeTrend() { - let data = Data(hexadecimalString: "31006f0a0000be7957007a0006e4818d")! - let message = GlucoseRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(2671, message.sequence) - XCTAssertEqual(5732798, message.glucose.timestamp) - XCTAssertFalse(message.glucose.glucoseIsDisplayOnly) - XCTAssertEqual(122, message.glucose.glucose) - XCTAssertEqual(6, message.glucose.state) - XCTAssertEqual(-28, message.glucose.trend) - } - - func testDisplayOnly() { - let data = Data(hexadecimalString: "3100700a0000f17a5700584006e3cee9")! - let message = GlucoseRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(2672, message.sequence) - XCTAssertEqual(5733105, message.glucose.timestamp) - XCTAssertTrue(message.glucose.glucoseIsDisplayOnly) - XCTAssertEqual(88, message.glucose.glucose) - XCTAssertEqual(6, message.glucose.state) - XCTAssertEqual(-29, message.glucose.trend) - } - - func testOldTransmitter() { - let data = Data(hexadecimalString: "3100aa00000095a078008b00060a8b34")! - let message = GlucoseRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(170, message.sequence) - XCTAssertEqual(7905429, message.glucose.timestamp) // 90 days, status is still OK - XCTAssertFalse(message.glucose.glucoseIsDisplayOnly) - XCTAssertEqual(139, message.glucose.glucose) - XCTAssertEqual(6, message.glucose.state) - XCTAssertEqual(10, message.glucose.trend) - } - - func testZeroSequence() { - let data = Data(hexadecimalString: "3100000000008eb14d00820006f6a038")! - let message = GlucoseRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(0, message.sequence) - XCTAssertEqual(5091726, message.glucose.timestamp) - XCTAssertFalse(message.glucose.glucoseIsDisplayOnly) - XCTAssertEqual(130, message.glucose.glucose) - XCTAssertEqual(6, message.glucose.state) - XCTAssertEqual(-10, message.glucose.trend) - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitTests/GlucoseTests.swift b/Dependencies/CGMBLEKit/CGMBLEKitTests/GlucoseTests.swift deleted file mode 100644 index 119136a66..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitTests/GlucoseTests.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// GlucoseTests.swift -// xDripG5 -// -// Created by Nate Racklyeft on 8/6/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -import HealthKit -@testable import CGMBLEKit - -class GlucoseTests: XCTestCase { - - var timeMessage: TransmitterTimeRxMessage! - var calendar = Calendar(identifier: .gregorian) - var activationDate: Date! - - override func setUp() { - super.setUp() - - let data = Data(hexadecimalString: "2500470272007cff710001000000fa1d")! - timeMessage = TransmitterTimeRxMessage(data: data)! - - calendar.timeZone = TimeZone(identifier: "UTC")! - - activationDate = calendar.date(from: DateComponents(year: 2016, month: 10, day: 1))! - } - - func testMessageData() { - let data = Data(hexadecimalString: "3100680a00008a715700cc0006ffc42a")! - let message = GlucoseRxMessage(data: data)! - let glucose = Glucose(transmitterID: "123456", glucoseMessage: message, timeMessage: timeMessage, activationDate: activationDate) - - XCTAssertEqual(TransmitterStatus.ok, glucose.status) - XCTAssertEqual(calendar.date(from: DateComponents(year: 2016, month: 12, day: 6, hour: 7, minute: 51, second: 38))!, glucose.readDate) - XCTAssertEqual(calendar.date(from: DateComponents(year: 2016, month: 12, day: 26, hour: 11, minute: 16, second: 12))!, glucose.sessionStartDate) - XCTAssertFalse(glucose.isDisplayOnly) - XCTAssertEqual(204, glucose.glucose?.doubleValue(for: .milligramsPerDeciliter)) - XCTAssertEqual(.known(.ok), glucose.state) - XCTAssertEqual(-1, glucose.trend) - } - - func testNegativeTrend() { - let data = Data(hexadecimalString: "31006f0a0000be7957007a0006e4818d")! - let message = GlucoseRxMessage(data: data)! - let glucose = Glucose(transmitterID: "123456", glucoseMessage: message, timeMessage: timeMessage, activationDate: activationDate) - - XCTAssertEqual(TransmitterStatus.ok, glucose.status) - XCTAssertEqual(calendar.date(from: DateComponents(year: 2016, month: 12, day: 6, hour: 8, minute: 26, second: 38))!, glucose.readDate) - XCTAssertFalse(glucose.isDisplayOnly) - XCTAssertEqual(122, glucose.glucose?.doubleValue(for: .milligramsPerDeciliter)) - XCTAssertEqual(.known(.ok), glucose.state) - XCTAssertEqual(-28, glucose.trend) - } - - func testDisplayOnly() { - let data = Data(hexadecimalString: "3100700a0000f17a5700584006e3cee9")! - let message = GlucoseRxMessage(data: data)! - let glucose = Glucose(transmitterID: "123456", glucoseMessage: message, timeMessage: timeMessage, activationDate: activationDate) - - XCTAssertEqual(TransmitterStatus.ok, glucose.status) - XCTAssertEqual(calendar.date(from: DateComponents(year: 2016, month: 12, day: 6, hour: 8, minute: 31, second: 45))!, glucose.readDate) - XCTAssertTrue(glucose.isDisplayOnly) - XCTAssertEqual(88, glucose.glucose?.doubleValue(for: .milligramsPerDeciliter)) - XCTAssertEqual(.known(.ok), glucose.state) - XCTAssertEqual(-29, message.glucose.trend) - } - - func testOldTransmitter() { - let data = Data(hexadecimalString: "3100aa00000095a078008b00060a8b34")! - let message = GlucoseRxMessage(data: data)! - let glucose = Glucose(transmitterID: "123456", glucoseMessage: message, timeMessage: timeMessage, activationDate: activationDate) - - XCTAssertEqual(TransmitterStatus.ok, glucose.status) - XCTAssertEqual(calendar.date(from: DateComponents(year: 2016, month: 12, day: 31, hour: 11, minute: 57, second: 09))!, glucose.readDate) // 90 days, status is still OK - XCTAssertFalse(glucose.isDisplayOnly) - XCTAssertEqual(139, glucose.glucose?.doubleValue(for: .milligramsPerDeciliter)) - XCTAssertEqual(.known(.ok), glucose.state) - XCTAssertEqual(10, message.glucose.trend) - } - -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitTests/Info.plist b/Dependencies/CGMBLEKit/CGMBLEKitTests/Info.plist deleted file mode 100644 index 6a4169050..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitTests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 3.2 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - - diff --git a/Dependencies/CGMBLEKit/CGMBLEKitTests/SessionStartRxMessageTests.swift b/Dependencies/CGMBLEKit/CGMBLEKitTests/SessionStartRxMessageTests.swift deleted file mode 100644 index f261a996c..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitTests/SessionStartRxMessageTests.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// SessionStartRxMessageTests.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 6/4/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import CGMBLEKit - -/// Thanks to https://github.com/mthatcher for the fixtures! -class SessionStartRxMessageTests: XCTestCase { - - func testSuccessfulStart() { - var data = Data(hexadecimalString: "2700014bf871004bf87100e9f8710095d9")! - var message = SessionStartRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(1, message.received) - XCTAssertEqual(7469131, message.requestedStartTime) - XCTAssertEqual(7469131, message.sessionStartTime) - XCTAssertEqual(7469289, message.transmitterTime) - - data = Data(hexadecimalString: "2700012bfd71002bfd710096fd71000f6a")! - message = SessionStartRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(1, message.received) - XCTAssertEqual(7470379, message.requestedStartTime) - XCTAssertEqual(7470379, message.sessionStartTime) - XCTAssertEqual(7470486, message.transmitterTime) - - data = Data(hexadecimalString: "2700017cff71007cff7100eeff7100aeed")! - message = SessionStartRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(1, message.received) - XCTAssertEqual(7470972, message.requestedStartTime) - XCTAssertEqual(7470972, message.sessionStartTime) - XCTAssertEqual(7471086, message.transmitterTime) - } - -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitTests/SessionStopRxMessageTests.swift b/Dependencies/CGMBLEKit/CGMBLEKitTests/SessionStopRxMessageTests.swift deleted file mode 100644 index 3812e2f43..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitTests/SessionStopRxMessageTests.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// SessionStopRxMessageTests.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 6/4/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import CGMBLEKit - -/// Thanks to https://github.com/mthatcher for the fixtures! -class SessionStopRxMessageTests: XCTestCase { - - func testSuccessfulStop() { - var data = Data(hexadecimalString: "29000128027200ffffffff47027200ba85")! - var message = SessionStopRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(1, message.received) - XCTAssertEqual(7471656, message.sessionStopTime) - XCTAssertEqual(0xffffffff, message.sessionStartTime) - XCTAssertEqual(7471687, message.transmitterTime) - - data = Data(hexadecimalString: "2900013ffe7100ffffffffc2fe71008268")! - message = SessionStopRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(1, message.received) - XCTAssertEqual(7470655, message.sessionStopTime) - XCTAssertEqual(0xffffffff, message.sessionStartTime) - XCTAssertEqual(7470786, message.transmitterTime) - - data = Data(hexadecimalString: "290001f5fb7100ffffffff6afc7100fa8a")! - message = SessionStopRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(1, message.received) - XCTAssertEqual(7470069, message.sessionStopTime) - XCTAssertEqual(0xffffffff, message.sessionStartTime) - XCTAssertEqual(7470186, message.transmitterTime) - } - -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitTests/TransmitterIDTests.swift b/Dependencies/CGMBLEKit/CGMBLEKitTests/TransmitterIDTests.swift deleted file mode 100644 index 7fffe4bf2..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitTests/TransmitterIDTests.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// TransmitterIDTests.swift -// xDripG5Tests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import CGMBLEKit - -class TransmitterIDTests: XCTestCase { - - /// Sanity check the hash computation path - func testComputeHash() { - let id = TransmitterID(id: "123456") - - XCTAssertEqual("e60d4a7999b0fbb2", id.computeHash(of: Data(hexadecimalString: "0123456789abcdef")!)!.hexadecimalString) - } - -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitTests/TransmitterTimeRxMessageTests.swift b/Dependencies/CGMBLEKit/CGMBLEKitTests/TransmitterTimeRxMessageTests.swift deleted file mode 100644 index 1106ceea5..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitTests/TransmitterTimeRxMessageTests.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// TransmitterTimeRxMessageTests.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 6/4/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import CGMBLEKit - -/// Thanks to https://github.com/mthatcher for the fixtures! -class TransmitterTimeRxMessageTests: XCTestCase { - - func testNoSession() { - var data = Data(hexadecimalString: "2500e8f87100ffffffff010000000a70")! - var message = TransmitterTimeRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(7469288, message.currentTime) - XCTAssertEqual(0xffffffff, message.sessionStartTime) - - data = Data(hexadecimalString: "250096fd7100ffffffff01000000226d")! - message = TransmitterTimeRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(7470486, message.currentTime) - XCTAssertEqual(0xffffffff, message.sessionStartTime) - - data = Data(hexadecimalString: "2500eeff7100ffffffff010000008952")! - message = TransmitterTimeRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(7471086, message.currentTime) - XCTAssertEqual(0xffffffff, message.sessionStartTime) - } - - func testInSession() { - var data = Data(hexadecimalString: "2500470272007cff710001000000fa1d")! - var message = TransmitterTimeRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(7471687, message.currentTime) - XCTAssertEqual(7470972, message.sessionStartTime) - - data = Data(hexadecimalString: "2500beb24d00f22d4d000100000083c0")! - message = TransmitterTimeRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual(5092030, message.currentTime) - XCTAssertEqual(5058034, message.sessionStartTime) - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitTests/TransmitterVersionRxMessageTests.swift b/Dependencies/CGMBLEKit/CGMBLEKitTests/TransmitterVersionRxMessageTests.swift deleted file mode 100644 index d7ab08497..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitTests/TransmitterVersionRxMessageTests.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// TransmitterVersionRxMessageTests.swift -// xDripG5 -// -// Created by Nate Racklyeft on 9/29/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import CGMBLEKit - -class TransmitterVersionRxMessageTests: XCTestCase { - - func testRxMessage() { - let data = Data(hexadecimalString: "4b0001000011df2900005100037000f00009b6")! - let message = TransmitterVersionRxMessage(data: data)! - - XCTAssertEqual(0, message.status) - XCTAssertEqual([1, 0, 0, 17], message.firmwareVersion) - } - -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/Assets.xcassets/Contents.json b/Dependencies/CGMBLEKit/CGMBLEKitUI/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/Assets.xcassets/g6.imageset/Contents.json b/Dependencies/CGMBLEKit/CGMBLEKitUI/Assets.xcassets/g6.imageset/Contents.json deleted file mode 100644 index 691ef107b..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/Assets.xcassets/g6.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "g6.png", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/Assets.xcassets/g6.imageset/g6.png b/Dependencies/CGMBLEKit/CGMBLEKitUI/Assets.xcassets/g6.imageset/g6.png deleted file mode 100644 index babfdfeb3..000000000 Binary files a/Dependencies/CGMBLEKit/CGMBLEKitUI/Assets.xcassets/g6.imageset/g6.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/Base.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/Base.lproj/Localizable.strings deleted file mode 100644 index 8ed9ea571..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/Base.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancel"; - -/* Title describing glucose date */ -"Date" = "Date"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Delete CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glucose"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glucose (Adjusted)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Latest Calibration"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Latest Reading"; - -/* Section title for latest connection date */ -"Latest Connection" = "Latest Connection"; - -/* Button title to open CGM app */ -"Open App" = "Open App"; - -/* Title describing sensor session age */ -"Session Age" = "Session Age"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Remote Data Synchronization"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor Expires"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor Expired"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Status"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Transmitter Age"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "Transmitter ID"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Upload Readings"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/Base.lproj/TransmitterManagerSetup.storyboard b/Dependencies/CGMBLEKit/CGMBLEKitUI/Base.lproj/TransmitterManagerSetup.storyboard deleted file mode 100644 index 57ddeefaf..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/Base.lproj/TransmitterManagerSetup.storyboard +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - - - - - - - - - - - - - - The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/CGMBLEKitUI.h b/Dependencies/CGMBLEKit/CGMBLEKitUI/CGMBLEKitUI.h deleted file mode 100644 index ce5764e08..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/CGMBLEKitUI.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// CGMBLEKitUI.h -// CGMBLEKitUI -// -// Created by Nathan Racklyeft on 7/28/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -#import - -//! Project version number for CGMBLEKitUI. -FOUNDATION_EXPORT double CGMBLEKitUIVersionNumber; - -//! Project version string for CGMBLEKitUI. -FOUNDATION_EXPORT const unsigned char CGMBLEKitUIVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/IdentifiableClass.swift b/Dependencies/CGMBLEKit/CGMBLEKitUI/IdentifiableClass.swift deleted file mode 100644 index 4f3c5f308..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/IdentifiableClass.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// IdentifiableClass.swift -// Naterade -// -// Created by Nathan Racklyeft on 5/22/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -protocol IdentifiableClass: AnyObject { - static var className: String { get } -} - - -extension IdentifiableClass { - static var className: String { - return NSStringFromClass(self).components(separatedBy: ".").last! - } -} - - -extension UITableViewCell: IdentifiableClass { } diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/Info.plist b/Dependencies/CGMBLEKit/CGMBLEKitUI/Info.plist deleted file mode 100644 index 506539df6..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.2 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/TransmitterIDSetupViewController.swift b/Dependencies/CGMBLEKit/CGMBLEKitUI/TransmitterIDSetupViewController.swift deleted file mode 100644 index fc3cd5a47..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/TransmitterIDSetupViewController.swift +++ /dev/null @@ -1,151 +0,0 @@ -// -// TransmitterIDSetupViewController.swift -// CGMBLEKitUI -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit -import LoopKitUI -import CGMBLEKit -import ShareClient - -class TransmitterIDSetupViewController: SetupTableViewController { - - lazy private(set) var shareManager = ShareClientManager() - - private func updateShareUsername() { - shareUsernameLabel.text = shareManager.shareService.username ?? SettingsTableViewCell.TapToSetString - } - - private(set) var transmitterID: String? { - get { - return transmitterIDTextField.text - } - set { - transmitterIDTextField.text = newValue - } - } - - private func updateStateForSettings() { - let isReadyToRead = transmitterID?.count == 6 - - if isReadyToRead { - continueState = .completed - } else { - continueState = .inputSettings - } - } - - private enum State { - case loadingView - case inputSettings - case completed - } - - private var continueState: State = .loadingView { - didSet { - switch continueState { - case .loadingView: - updateStateForSettings() - case .inputSettings: - footerView.primaryButton.isEnabled = false - case .completed: - footerView.primaryButton.isEnabled = true - } - } - } - - override func continueButtonPressed(_ sender: Any) { - if continueState == .completed, - let setupViewController = navigationController as? TransmitterSetupViewController, - let transmitterID = transmitterID - { - setupViewController.completeSetup(state: TransmitterManagerState(transmitterID: transmitterID)) - } - } - - override func cancelButtonPressed(_ sender: Any) { - if transmitterIDTextField.isFirstResponder { - transmitterIDTextField.resignFirstResponder() - } else { - super.cancelButtonPressed(sender) - } - } - - override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { - return continueState == .completed - } - - // MARK: - - - @IBOutlet private var shareUsernameLabel: UILabel! - - @IBOutlet private var transmitterIDTextField: UITextField! - - override func viewDidLoad() { - super.viewDidLoad() - - updateShareUsername() - - continueState = .inputSettings - } - - // MARK: - UITableViewDelegate - - private enum Section: Int { - case transmitterID - case share - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - switch Section(rawValue: indexPath.section)! { - case .transmitterID: - tableView.deselectRow(at: indexPath, animated: false) - case .share: - let authVC = AuthenticationViewController(authentication: shareManager.shareService) - authVC.authenticationObserver = { [weak self] (service) in - self?.shareManager.shareService = service - self?.updateShareUsername() - } - - show(authVC, sender: nil) - } - } -} - - -extension TransmitterIDSetupViewController: UITextFieldDelegate { - func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - guard let text = textField.text, let stringRange = Range(range, in: text) else { - updateStateForSettings() - return true - } - - let newText = text.replacingCharacters(in: stringRange, with: string) - - if newText.count >= 6 { - if newText.count == 6 { - textField.text = newText - textField.resignFirstResponder() - } - - updateStateForSettings() - return false - } - - textField.text = newText - updateStateForSettings() - return false - } - - func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { - return true - } - - func textFieldShouldReturn(_ textField: UITextField) -> Bool { - textField.resignFirstResponder() - return true - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/TransmitterManager+UI.swift b/Dependencies/CGMBLEKit/CGMBLEKitUI/TransmitterManager+UI.swift deleted file mode 100644 index bbe0fe353..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/TransmitterManager+UI.swift +++ /dev/null @@ -1,88 +0,0 @@ -// -// TransmitterManager+UI.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import HealthKit -import CGMBLEKit - - -extension G5CGMManager: CGMManagerUI { - public static var onboardingImage: UIImage? { - return nil - } - - public static func setupViewController(bluetoothProvider: BluetoothProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) -> SetupUIResult { - let setupVC = TransmitterSetupViewController.instantiateFromStoryboard() - setupVC.cgmManagerType = self - return .userInteractionRequired(setupVC) - } - - public func settingsViewController(bluetoothProvider: BluetoothProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) ->CGMManagerViewController { - let settings = TransmitterSettingsViewController(cgmManager: self, displayGlucoseUnitObservable: displayGlucoseUnitObservable) - let nav = CGMManagerSettingsNavigationViewController(rootViewController: settings) - return nav - } - - public var smallImage: UIImage? { - return nil - } - - // TODO Placeholder. - public var cgmStatusHighlight: DeviceStatusHighlight? { - return nil - } - - // TODO Placeholder. - public var cgmStatusBadge: DeviceStatusBadge? { - return nil - } - - // TODO Placeholder. - public var cgmLifecycleProgress: DeviceLifecycleProgress? { - return nil - } -} - - -extension G6CGMManager: CGMManagerUI { - public static var onboardingImage: UIImage? { - return nil - } - - public static func setupViewController(bluetoothProvider: BluetoothProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) -> SetupUIResult { - let setupVC = TransmitterSetupViewController.instantiateFromStoryboard() - setupVC.cgmManagerType = self - return .userInteractionRequired(setupVC) - } - - public func settingsViewController(bluetoothProvider: BluetoothProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) ->CGMManagerViewController { - let settings = TransmitterSettingsViewController(cgmManager: self, displayGlucoseUnitObservable: displayGlucoseUnitObservable) - let nav = CGMManagerSettingsNavigationViewController(rootViewController: settings) - return nav - } - - public var smallImage: UIImage? { - UIImage(named: "g6", in: Bundle(for: TransmitterSetupViewController.self), compatibleWith: nil)! - } - - // TODO Placeholder. - public var cgmStatusHighlight: DeviceStatusHighlight? { - return nil - } - - // TODO Placeholder. - public var cgmStatusBadge: DeviceStatusBadge? { - return nil - } - - // TODO Placeholder. - public var cgmLifecycleProgress: DeviceLifecycleProgress? { - return nil - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/TransmitterSettingsViewController.swift b/Dependencies/CGMBLEKit/CGMBLEKitUI/TransmitterSettingsViewController.swift deleted file mode 100644 index 94d7f385c..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/TransmitterSettingsViewController.swift +++ /dev/null @@ -1,558 +0,0 @@ -// -// TransmitterSettingsViewController.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import Combine -import HealthKit -import LoopKit -import LoopKitUI -import CGMBLEKit -import ShareClientUI - -class TransmitterSettingsViewController: UITableViewController { - - let cgmManager: TransmitterManager & CGMManagerUI - - private let displayGlucoseUnitObservable: DisplayGlucoseUnitObservable - - private lazy var cancellables = Set() - - private var glucoseUnit: HKUnit { - displayGlucoseUnitObservable.displayGlucoseUnit - } - - init(cgmManager: TransmitterManager & CGMManagerUI, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable) { - self.cgmManager = cgmManager - self.displayGlucoseUnitObservable = displayGlucoseUnitObservable - - super.init(style: .grouped) - - cgmManager.addObserver(self, queue: .main) - - displayGlucoseUnitObservable.$displayGlucoseUnit - .sink { [weak self] _ in self?.tableView.reloadData() } - .store(in: &cancellables) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - title = cgmManager.localizedTitle - - tableView.rowHeight = UITableView.automaticDimension - tableView.estimatedRowHeight = 44 - - tableView.sectionHeaderHeight = UITableView.automaticDimension - tableView.estimatedSectionHeaderHeight = 55 - - tableView.register(SettingsTableViewCell.self, forCellReuseIdentifier: SettingsTableViewCell.className) - tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className) - tableView.register(SwitchTableViewCell.self, forCellReuseIdentifier: SwitchTableViewCell.className) - let button = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped(_:))) - self.navigationItem.setRightBarButton(button, animated: false) - } - - @objc func doneTapped(_ sender: Any) { - complete() - } - - private func complete() { - if let nav = navigationController as? SettingsNavigationViewController { - nav.notifyComplete() - } - } - - override func viewWillAppear(_ animated: Bool) { - if clearsSelectionOnViewWillAppear { - // Manually invoke the delegate for rows deselecting on appear - for indexPath in tableView.indexPathsForSelectedRows ?? [] { - _ = tableView(tableView, willDeselectRowAt: indexPath) - } - } - - super.viewWillAppear(animated) - } - - // MARK: - UITableViewDataSource - - private enum Section: Int, CaseIterable { - case transmitterID - case remoteDataSync - case latestReading - case latestCalibration - case latestConnection - case ages - case share - case delete - } - - override func numberOfSections(in tableView: UITableView) -> Int { - return Section.allCases.count - } - - private enum LatestReadingRow: Int, CaseIterable { - case glucose - case date - case trend - case status - } - - private enum LatestCalibrationRow: Int, CaseIterable { - case glucose - case date - } - - private enum LatestConnectionRow: Int, CaseIterable { - case date - } - - private enum AgeRow: Int, CaseIterable { - case sensorAge - case sensorCountdown - case sensorExpirationDate - case transmitter - } - - private enum ShareRow: Int, CaseIterable { - case settings - case openApp - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch Section(rawValue: section)! { - case .transmitterID: - return 1 - case .remoteDataSync: - return 1 - case .latestReading: - return LatestReadingRow.allCases.count - case .latestCalibration: - return LatestCalibrationRow.allCases.count - case .latestConnection: - return LatestConnectionRow.allCases.count - case .ages: - return AgeRow.allCases.count - case .share: - return ShareRow.allCases.count - case .delete: - return 1 - } - } - - private lazy var glucoseFormatter: QuantityFormatter = { - let formatter = QuantityFormatter() - formatter.setPreferredNumberFormatter(for: glucoseUnit) - return formatter - }() - - private lazy var dateFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .long - formatter.timeStyle = .long - formatter.doesRelativeDateFormatting = true - return formatter - }() - - private lazy var sensorExpirationFullFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .full - formatter.timeStyle = .short - formatter.doesRelativeDateFormatting = true - //formatter.dateFormat = "E, MMM d 'at' h:mm a" - return formatter - }() - - private lazy var sensorExpirationRelativeFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .long - formatter.timeStyle = .short - formatter.doesRelativeDateFormatting = true - return formatter - }() - - private lazy var sensorExpAbsFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .long - formatter.timeStyle = .short - formatter.doesRelativeDateFormatting = false - return formatter - }() - - private lazy var sessionLengthFormatter: DateComponentsFormatter = { - let formatter = DateComponentsFormatter() - formatter.allowedUnits = [.day, .hour, .minute] - formatter.unitsStyle = .full - formatter.maximumUnitCount = 2 - return formatter - }() - - private lazy var transmitterLengthFormatter: DateComponentsFormatter = { - let formatter = DateComponentsFormatter() - formatter.allowedUnits = [.day] - formatter.unitsStyle = .full - return formatter - }() - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch Section(rawValue: indexPath.section)! { - case .transmitterID: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) as! SettingsTableViewCell - - cell.textLabel?.text = LocalizedString("Transmitter ID", comment: "The title text for the Dexcom G5/G6 transmitter ID config value") - - cell.detailTextLabel?.text = cgmManager.transmitter.ID - - return cell - case .remoteDataSync: - let switchCell = tableView.dequeueReusableCell(withIdentifier: SwitchTableViewCell.className, for: indexPath) as! SwitchTableViewCell - - switchCell.selectionStyle = .none - switchCell.switch?.isOn = cgmManager.shouldSyncToRemoteService - switchCell.textLabel?.text = LocalizedString("Upload Readings", comment: "The title text for the upload glucose switch cell") - - switchCell.switch?.addTarget(self, action: #selector(uploadEnabledChanged(_:)), for: .valueChanged) - - return switchCell - case .latestReading: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) as! SettingsTableViewCell - let glucose = cgmManager.latestReading - - switch LatestReadingRow(rawValue: indexPath.row)! { - case .glucose: - cell.setGlucose(glucose?.glucose, unit: glucoseUnit, formatter: glucoseFormatter, isDisplayOnly: glucose?.isDisplayOnly ?? false) - case .date: - cell.setGlucoseDate(glucose?.readDate, formatter: dateFormatter) - case .trend: - cell.textLabel?.text = LocalizedString("Trend", comment: "Title describing glucose trend") - - if let trendRate = glucose?.trendRate { - let glucoseUnitPerMinute = glucoseUnit.unitDivided(by: .minute()) - let trendPerMinute = HKQuantity(unit: glucoseUnit, doubleValue: trendRate.doubleValue(for: glucoseUnitPerMinute)) - - if let formatted = glucoseFormatter.string(from: trendPerMinute, for: glucoseUnit) { - cell.detailTextLabel?.text = String(format: LocalizedString("%@/min", comment: "Format string for glucose trend per minute. (1: glucose value and unit)"), formatted) - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - case .status: - cell.textLabel?.text = LocalizedString("Status", comment: "Title describing CGM calibration and battery state") - - if let stateDescription = glucose?.stateDescription, !stateDescription.isEmpty { - cell.detailTextLabel?.text = stateDescription - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - } - - return cell - case .latestCalibration: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) as! SettingsTableViewCell - let calibration = cgmManager.latestReading?.lastCalibration - - switch LatestCalibrationRow(rawValue: indexPath.row)! { - case .glucose: - cell.setGlucose(calibration?.glucose, unit: glucoseUnit, formatter: glucoseFormatter, isDisplayOnly: false) - case .date: - cell.setGlucoseDate(calibration?.date, formatter: dateFormatter) - } - - return cell - case .latestConnection: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) as! SettingsTableViewCell - let connection = cgmManager.latestConnection - - switch LatestConnectionRow(rawValue: indexPath.row)! { - case .date: - cell.setGlucoseDate(connection, formatter: dateFormatter) - cell.accessoryType = .disclosureIndicator - } - - return cell - case .ages: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) as! SettingsTableViewCell - let glucose = cgmManager.latestReading - - switch AgeRow(rawValue: indexPath.row)! { - case .sensorAge: - cell.textLabel?.text = LocalizedString("Session Age", comment: "Title describing sensor session age") - - if let stateDescription = glucose?.stateDescription, !stateDescription.isEmpty && !stateDescription.contains("stopped") { - if let sessionStart = cgmManager.latestReading?.sessionStartDate { - cell.detailTextLabel?.text = sessionLengthFormatter.string(from: Date().timeIntervalSince(sessionStart)) - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - - case .sensorCountdown: - cell.textLabel?.text = LocalizedString("Sensor Expires", comment: "Title describing sensor sensor expiration") - - if let stateDescription = glucose?.stateDescription, !stateDescription.isEmpty && !stateDescription.contains("stopped") { - if let sessionExp = cgmManager.latestReading?.sessionExpDate { - let sessionCountDown = sessionExp.timeIntervalSince(Date()) - if sessionCountDown < 0 { - cell.textLabel?.text = LocalizedString("Sensor Expired", comment: "Title describing past sensor sensor expiration") - cell.detailTextLabel?.text = (sessionLengthFormatter.string(from: sessionCountDown * -1) ?? "") + " ago" - } else { - cell.detailTextLabel?.text = sessionLengthFormatter.string(from: sessionCountDown) - } - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - - case .sensorExpirationDate: - cell.textLabel?.text = "" - if let stateDescription = glucose?.stateDescription, !stateDescription.isEmpty && !stateDescription.contains("stopped") { - if let sessionExp = cgmManager.latestReading?.sessionExpDate { - if sensorExpirationRelativeFormatter.string(from: sessionExp) == sensorExpAbsFormatter.string(from: sessionExp) { - cell.detailTextLabel?.text = sensorExpirationFullFormatter.string(from: sessionExp) - } else { - cell.detailTextLabel?.text = sensorExpirationRelativeFormatter.string(from: sessionExp) - } - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - - case .transmitter: - cell.textLabel?.text = LocalizedString("Transmitter Age", comment: "Title describing transmitter session age") - - if let activation = cgmManager.latestReading?.activationDate { - cell.detailTextLabel?.text = transmitterLengthFormatter.string(from: Date().timeIntervalSince(activation)) - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - } - - return cell - case .share: - switch ShareRow(rawValue: indexPath.row)! { - case .settings: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) as! SettingsTableViewCell - let service = cgmManager.shareManager.shareService - - cell.textLabel?.text = service.title - cell.detailTextLabel?.text = service.username ?? SettingsTableViewCell.TapToSetString - cell.accessoryType = .disclosureIndicator - - return cell - case .openApp: - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) - - cell.textLabel?.text = LocalizedString("Open App", comment: "Button title to open CGM app") - - return cell - } - case .delete: - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell - - cell.textLabel?.text = LocalizedString("Delete CGM", comment: "Title text for the button to remove a CGM from Loop") - cell.textLabel?.textAlignment = .center - cell.tintColor = .delete - cell.isEnabled = true - return cell - } - } - - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - switch Section(rawValue: section)! { - case .transmitterID: - return nil - case .remoteDataSync: - return LocalizedString("Remote Data Synchronization", comment: "Section title for remote data synchronization") - case .latestReading: - return LocalizedString("Latest Reading", comment: "Section title for latest glucose reading") - case .latestCalibration: - return LocalizedString("Latest Calibration", comment: "Section title for latest glucose calibration") - case .latestConnection: - return LocalizedString("Latest Connection", comment: "Section title for latest connection date") - case .ages: - return nil - case .share: - return nil - case .delete: - return " " // Use an empty string for more dramatic spacing - } - } - - override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { - switch Section(rawValue: indexPath.section)! { - case .transmitterID: - return false - case .remoteDataSync: - return false - case .latestReading: - return false - case .latestCalibration: - return false - case .latestConnection: - return true - case .ages: - return false - case .share: - return true - case .delete: - return true - } - } - - override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { - if self.tableView(tableView, shouldHighlightRowAt: indexPath) { - return indexPath - } else { - return nil - } - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - switch Section(rawValue: indexPath.section)! { - case .transmitterID: - break - case .remoteDataSync: - break - case .latestReading: - break - case .latestCalibration: - break - case .latestConnection: - let vc = CommandResponseViewController(command: { (completionHandler) -> String in - return String(reflecting: self.cgmManager) - }) - vc.title = self.title - show(vc, sender: nil) - case .ages: - break - case .share: - switch ShareRow(rawValue: indexPath.row)! { - case .settings: - let vc = ShareClientSettingsViewController(cgmManager: cgmManager.shareManager, displayGlucoseUnitObservable: displayGlucoseUnitObservable, allowsDeletion: false) - show(vc, sender: nil) - return // Don't deselect - case .openApp: - if let appURL = URL(string: "dexcomg6://") { - UIApplication.shared.open(appURL) - } - } - case .delete: - let confirmVC = UIAlertController(cgmDeletionHandler: { - self.cgmManager.notifyDelegateOfDeletion { - DispatchQueue.main.async { - self.complete() - } - } - }) - - present(confirmVC, animated: true) { - tableView.deselectRow(at: indexPath, animated: true) - } - } - - tableView.deselectRow(at: indexPath, animated: true) - } - - override func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? { - switch Section(rawValue: indexPath.section)! { - case .transmitterID: - break - case .remoteDataSync: - break - case .latestReading: - break - case .latestCalibration: - break - case .latestConnection: - break - case .ages: - break - case .share: - switch ShareRow(rawValue: indexPath.row)! { - case .settings: - tableView.reloadRows(at: [indexPath], with: .fade) - case .openApp: - break - } - case .delete: - break - } - - return indexPath - } - - @objc private func uploadEnabledChanged(_ sender: UISwitch) { - cgmManager.shouldSyncToRemoteService = sender.isOn - } -} - - -extension TransmitterSettingsViewController: TransmitterManagerObserver { - func transmitterManagerDidUpdateLatestReading(_ manager: TransmitterManager) { - tableView.reloadData() - } -} - - -private extension UIAlertController { - convenience init(cgmDeletionHandler handler: @escaping () -> Void) { - self.init( - title: nil, - message: LocalizedString("Are you sure you want to delete this CGM?", comment: "Confirmation message for deleting a CGM"), - preferredStyle: .actionSheet - ) - - addAction(UIAlertAction( - title: LocalizedString("Delete CGM", comment: "Button title to delete CGM"), - style: .destructive, - handler: { (_) in - handler() - } - )) - - let cancel = LocalizedString("Cancel", comment: "The title of the cancel action in an action sheet") - addAction(UIAlertAction(title: cancel, style: .cancel, handler: nil)) - } -} - - -private extension SettingsTableViewCell { - func setGlucose(_ glucose: HKQuantity?, unit: HKUnit, formatter: QuantityFormatter, isDisplayOnly: Bool) { - if isDisplayOnly { - textLabel?.text = LocalizedString("Glucose (Adjusted)", comment: "Describes a glucose value adjusted to reflect a recent calibration") - } else { - textLabel?.text = LocalizedString("Glucose", comment: "Title describing glucose value") - } - - if let quantity = glucose, let formatted = formatter.string(from: quantity, for: unit) { - detailTextLabel?.text = formatted - } else { - detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - } - - func setGlucoseDate(_ date: Date?, formatter: DateFormatter) { - textLabel?.text = LocalizedString("Date", comment: "Title describing glucose date") - - if let date = date { - detailTextLabel?.text = formatter.string(from: date) - } else { - detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/TransmitterSetupViewController.swift b/Dependencies/CGMBLEKit/CGMBLEKitUI/TransmitterSetupViewController.swift deleted file mode 100644 index 8ab4c2fdd..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/TransmitterSetupViewController.swift +++ /dev/null @@ -1,96 +0,0 @@ -// -// TransmitterSetupViewController.swift -// CGMBLEKitUI -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit -import LoopKitUI -import CGMBLEKit -import ShareClient - -class TransmitterSetupViewController: UINavigationController, CGMManagerOnboarding, UINavigationControllerDelegate, CompletionNotifying { - class func instantiateFromStoryboard() -> TransmitterSetupViewController { - return UIStoryboard(name: "TransmitterManagerSetup", bundle: Bundle(for: TransmitterSetupViewController.self)).instantiateInitialViewController() as! TransmitterSetupViewController - } - - weak var cgmManagerOnboardingDelegate: CGMManagerOnboardingDelegate? - weak var completionDelegate: CompletionDelegate? - - var cgmManagerType: TransmitterManager.Type! - - override func viewDidLoad() { - super.viewDidLoad() - - delegate = self - view.backgroundColor = .systemGroupedBackground - navigationBar.shadowImage = UIImage() - } - - func completeSetup(state: TransmitterManagerState) { - if let manager = cgmManagerType.init(state: state) as? CGMManagerUI { - cgmManagerOnboardingDelegate?.cgmManagerOnboarding(didCreateCGMManager: manager) - cgmManagerOnboardingDelegate?.cgmManagerOnboarding(didOnboardCGMManager: manager) - completionDelegate?.completionNotifyingDidComplete(self) - } - } - - // MARK: - UINavigationControllerDelegate - - func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { - // Read state values - let viewControllers = navigationController.viewControllers - let count = navigationController.viewControllers.count - - if count >= 2 { - switch viewControllers[count - 2] { - case _ as TransmitterIDSetupViewController: - break - default: - break - } - } - - if let setupViewController = viewController as? SetupTableViewController { - setupViewController.delegate = self - } - - // Set state values - switch viewController { - case _ as TransmitterIDSetupViewController: - break - default: - break - } - - // Adjust the appearance for the main setup view controllers only - if viewController is SetupTableViewController { - navigationBar.isTranslucent = false - navigationBar.shadowImage = UIImage() - } else { - navigationBar.isTranslucent = true - navigationBar.shadowImage = nil - viewController.navigationItem.largeTitleDisplayMode = .never - } - } - - func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { - - // Adjust the appearance for the main setup view controllers only - if viewController is SetupTableViewController { - navigationBar.isTranslucent = false - navigationBar.shadowImage = UIImage() - } else { - navigationBar.isTranslucent = true - navigationBar.shadowImage = nil - } - } -} - -extension TransmitterSetupViewController: SetupTableViewControllerDelegate { - public func setupTableViewControllerCancelButtonPressed(_ viewController: SetupTableViewController) { - completionDelegate?.completionNotifyingDidComplete(self) - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/UIColor.swift b/Dependencies/CGMBLEKit/CGMBLEKitUI/UIColor.swift deleted file mode 100644 index 0095c6b71..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/UIColor.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// UIColor.swift -// LoopKitUI -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - - -extension UIColor { - static let delete = UIColor.higRed() -} - - -// MARK: - HIG colors -// See: https://developer.apple.com/ios/human-interface-guidelines/visual-design/color/ -extension UIColor { - private static func higRed() -> UIColor { - return UIColor(red: 1, green: 59 / 255, blue: 48 / 255, alpha: 1) - } -} diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/ar.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/ar.lproj/Localizable.strings deleted file mode 100644 index a0e15f3cd..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/ar.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "هل أنت متأكد أنك تريد حذف هذا CGM؟"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "إلغاء"; - -/* Title describing glucose date */ -"Date" = "Date"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "حذف CGM"; - -/* Title describing glucose value */ -"Glucose" = "قراءات السكر"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glucose (Adjusted)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Latest Calibration"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Latest Reading"; - -/* Section title for latest connection date */ -"Latest Connection" = "Latest Connection"; - -/* Button title to open CGM app */ -"Open App" = "Open App"; - -/* Title describing sensor session age */ -"Session Age" = "Session Age"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Remote Data Synchronization"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor Expires"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor Expired"; - -/* Title describing CGM calibration and battery state */ -"Status" = "الحالة"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Transmitter Age"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "Transmitter ID"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Upload Readings"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/ar.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/ar.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index e019c4c51..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/ar.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Credentials"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Transmitter Setup"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "تفاصيل"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "Transmitter ID"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Enter the 6-digit transmitter ID"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/ca.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/ca.lproj/Localizable.strings deleted file mode 100644 index 8ed9ea571..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/ca.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancel"; - -/* Title describing glucose date */ -"Date" = "Date"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Delete CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glucose"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glucose (Adjusted)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Latest Calibration"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Latest Reading"; - -/* Section title for latest connection date */ -"Latest Connection" = "Latest Connection"; - -/* Button title to open CGM app */ -"Open App" = "Open App"; - -/* Title describing sensor session age */ -"Session Age" = "Session Age"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Remote Data Synchronization"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor Expires"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor Expired"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Status"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Transmitter Age"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "Transmitter ID"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Upload Readings"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/ca.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/ca.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index d35f2a677..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/ca.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Credentials"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Transmitter Setup"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detail"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "Transmitter ID"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Enter the 6-digit transmitter ID"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/cs.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/cs.lproj/Localizable.strings deleted file mode 100644 index ea9199eee..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/cs.lproj/Localizable.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Zrušit"; - -/* Title describing glucose value */ -"Glucose" = "Glukóza"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Status"; - diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/da.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/da.lproj/Localizable.strings deleted file mode 100644 index 60cb50e5b..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/da.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Er du sikker på, at du vil slette denne CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuller"; - -/* Title describing glucose date */ -"Date" = "Dato"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Slet CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glukose"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Blodsukker (justeret)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Seneste kalibrering"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Seneste aflæsning"; - -/* Section title for latest connection date */ -"Latest Connection" = "Seneste forbindelse"; - -/* Button title to open CGM app */ -"Open App" = "Åben app"; - -/* Title describing sensor session age */ -"Session Age" = "Session-alder"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Synkronisering af fjerndata"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor udløber"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor udløbet"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Status"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Sender alder"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "Sender ID"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Upload aflæsninger"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/da.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/da.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index 8c2011431..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/da.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Legitimationsoplysninger"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Senderopsætning"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detalje"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "Sender-ID'et kan findes trykt på bagsiden af ​​enheden, på den side af boksen, den kom i, og fra indstillingsmenuerne på modtageren og mobilappen."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "Sender ID"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Data kan downloades over internettet fra Share, når transmitterforbindelsen mislykkes."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Indtast det 6-cifrede sender-ID"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/de.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/de.lproj/Localizable.strings deleted file mode 100644 index 99cf84b4d..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/de.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Sind Sie sicher, dass Sie dieses CGM löschen wollen?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Abbrechen"; - -/* Title describing glucose date */ -"Date" = "Datum"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "CGM löschen"; - -/* Title describing glucose value */ -"Glucose" = "Blutzucker"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "BZ-Wert (angepasst)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Letzte Kalibrierung"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Letzter Wert"; - -/* Section title for latest connection date */ -"Latest Connection" = "Letzte Verbindung"; - -/* Button title to open CGM app */ -"Open App" = "App öffnen"; - -/* Title describing sensor session age */ -"Session Age" = "Sitzungsalter"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Remote Daten Synchronisation"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor läuft ab"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor abgelaufen"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Status"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Transmitteralter"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "Transmitter-ID"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Werte hochladen"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/de.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/de.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index 1cd9ff533..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/de.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Logindaten"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Transmitter-Setup"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detail"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "Die Transmitter-ID befindet sich auf der Rückseite des Transmitters, an der Seite der Verpackung und in den Einstellungsmenüs des Empfängers sowie der Dexcom-App."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "Transmitter-ID"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Daten können über das Internet von Share heruntergeladen werden, wenn die Verbindung zum Transmitter unterbrochen ist."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Geben Sie die 6-stellige Transmitter-ID ein"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/en.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/en.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index 41859f853..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/en.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,24 +0,0 @@ - -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Credentials"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Transmitter Setup"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detail"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "Transmitter ID"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Enter the 6-digit transmitter ID"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/es.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/es.lproj/Localizable.strings deleted file mode 100644 index e421c7212..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/es.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "¿Está seguro de que quiere eliminar este MCG?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancelar"; - -/* Title describing glucose date */ -"Date" = "Fecha"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Eliminar MCG"; - -/* Title describing glucose value */ -"Glucose" = "Glucosa"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glucose (Adjusted)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Calibración más reciente"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Dato más reciente"; - -/* Section title for latest connection date */ -"Latest Connection" = "Conexión más reciente"; - -/* Button title to open CGM app */ -"Open App" = "Abrir App"; - -/* Title describing sensor session age */ -"Session Age" = "Tiempo de sesión del sensor"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Sincronización remota de datos"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "El sensor caduca"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor caducado"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Estado"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Edad del transmisor"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "Identificación del transmisor"; - -/* Title describing glucose trend */ -"Trend" = "Tendencia"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Subir Datos"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/es.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/es.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index d58d85944..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/es.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Credenciales"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Configuración del transmisor"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detalle"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "La identificación del transmisor puede encontrarse en la parte trasera del dispositivo, en el lateral de la caja en la que venía, o en los menús de ajustes del receptor y la app del teléfono móvil. "; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "Identificación del transmisor"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Los datos pueden descargarse, vía internet, desde el Share cuando la conexión del transmisor falla."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Introduzca la identificación de 6 cifras del transmisor"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/fi.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/fi.lproj/Localizable.strings deleted file mode 100644 index f29f7366e..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/fi.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Haluatko varmasti poistaa CGM:n?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Kumoa"; - -/* Title describing glucose date */ -"Date" = "Aika"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Poista CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glukoosi"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glukoosi (säädetty)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Viimeisin kalibrointi"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Viimeisin lukema"; - -/* Section title for latest connection date */ -"Latest Connection" = "Viimeisin yhteys"; - -/* Button title to open CGM app */ -"Open App" = "Avaa sovellus"; - -/* Title describing sensor session age */ -"Session Age" = "Session ikä"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Etätietojen synkronointi"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor Expires"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor Expired"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Tila"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Lähettimen ikä"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "Lähettimen tunniste"; - -/* Title describing glucose trend */ -"Trend" = "Suunta"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Lataa lukemat"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/fi.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/fi.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index 61a0e9075..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/fi.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Tunnukset"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Lähettimen asennus"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detail"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "Lähettimen tunniste on painettu lähettimen pohjaan ja tuotepakkauksen sivulle. Se löytyy myös vastaanottimen ja mobiilisovelluksen asetusvalikosta."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "Lähettimen tunniste"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Tiedot voidaan ladata Internetistä Share-palvelimelta, kun yhteys lähettimeen epäonnistuu."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Syötä 6-numeroinen lähettimen tunniste"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/fr.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/fr.lproj/Localizable.strings deleted file mode 100644 index e7ec3a113..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/fr.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Voulez-vous vraiment supprimer ce CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuler"; - -/* Title describing glucose date */ -"Date" = "Date"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Effacer le CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glycémie"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glycémie (ajustée)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Dernier étalonnage"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Dernière mesure"; - -/* Section title for latest connection date */ -"Latest Connection" = "Dernière connexion"; - -/* Button title to open CGM app */ -"Open App" = "Ouvrir l’application"; - -/* Title describing sensor session age */ -"Session Age" = "L’âge de la session"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Synchronisation des données à distance"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Le capteur expire"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Capteur expiré"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Statut"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "L’âge du transmetteur"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "ID du transmetteur"; - -/* Title describing glucose trend */ -"Trend" = "Tendance"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Envoyer les données"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/fr.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/fr.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index dcb51c6b7..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/fr.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Identifiant"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Configuration du transmetteur"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Détail"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "L’ID du transmetteur se trouve sur le dos de l’appareil, sur la boîte dans laquelle il est fourni, et depuis les menus de réglages du récepteur et de l’application mobile."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "ID du transmetteur"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Les données peuvent être téléchargées depuis Internet avec Share quand la connexion au transmetteur échoue."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Entrez l’ID du transmetteur, composé de 6 lettres et chiffres"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/he.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/he.lproj/Localizable.strings deleted file mode 100644 index 1a2dc0123..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/he.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancel"; - -/* Title describing glucose date */ -"Date" = "Date"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Delete CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glucose"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glucose (Adjusted)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Latest Calibration"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Latest Reading"; - -/* Section title for latest connection date */ -"Latest Connection" = "חיבור אחרון"; - -/* Button title to open CGM app */ -"Open App" = "Open App"; - -/* Title describing sensor session age */ -"Session Age" = "Session Age"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Remote Data Synchronization"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor Expires"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor Expired"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Status"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Transmitter Age"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "Transmitter ID"; - -/* Title describing glucose trend */ -"Trend" = "מגמה"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Upload Readings"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/he.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/he.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index d35f2a677..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/he.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Credentials"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Transmitter Setup"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detail"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "Transmitter ID"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Enter the 6-digit transmitter ID"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/hi.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/hi.lproj/Localizable.strings deleted file mode 100644 index 82f4a5b2e..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/hi.lproj/Localizable.strings +++ /dev/null @@ -1,15 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/मिनट"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "निरस्त"; - -/* Title describing glucose value */ -"Glucose" = "शुगर"; - -/* Title describing glucose trend */ -"Trend" = "ट्रेंड"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "अपलोड रीडिंग्स"; - diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/hu.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/hu.lproj/Localizable.strings deleted file mode 100644 index a38f99d48..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/hu.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Mégse"; - -/* Title describing glucose date */ -"Date" = "Dátum"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "CGM kitörlése"; - -/* Title describing glucose value */ -"Glucose" = "Glükóz"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glucose (Adjusted)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Latest Calibration"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Latest Reading"; - -/* Section title for latest connection date */ -"Latest Connection" = "Latest Connection"; - -/* Button title to open CGM app */ -"Open App" = "Open App"; - -/* Title describing sensor session age */ -"Session Age" = "Session Age"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Remote Data Synchronization"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor Expires"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor Expired"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Status"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Transmitter Age"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "Jeladó ID"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Upload Readings"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/hu.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/hu.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index a71c1f12a..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/hu.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Credentials"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Transmitter Setup"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detail"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "Jeladó ID"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Enter the 6-digit transmitter ID"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/it.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/it.lproj/Localizable.strings deleted file mode 100644 index b21240f0c..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/it.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Sei sicuro di voler eliminare questo CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annulla"; - -/* Title describing glucose date */ -"Date" = "Data"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Elimina CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glicemia"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glicemie (Corrette)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Ultima calibrazione"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Ultima lettura"; - -/* Section title for latest connection date */ -"Latest Connection" = "Ultima connessione"; - -/* Button title to open CGM app */ -"Open App" = "Apri app"; - -/* Title describing sensor session age */ -"Session Age" = "Età sessione"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Sincronizzazione dei dati remoti"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Scadenza sensore"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensore scaduto"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Stato"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Età trasmettitore"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "ID trasmettitore"; - -/* Title describing glucose trend */ -"Trend" = "Tendenza"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Carica letture"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/it.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/it.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index 8d0cf342a..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/it.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Credenziali"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Configurazione trasmettitore"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Dettaglio"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "L'ID del trasmettitore è riportato sul retro del dispositivo, ai lati della confezione di imballaggio e nel menù impostazioni del ricevitore dell’app per dispositivi mobili."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "ID trasmettitore"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "In caso di problemi di connessione del trasmettitore, puoi scaricare i dati da Internet grazie alla funzionalità Share."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Inserisci ID a 6 cifre del trasmettitore"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/ja.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/ja.lproj/Localizable.strings deleted file mode 100644 index 056dbceb2..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/ja.lproj/Localizable.strings +++ /dev/null @@ -1,46 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/分"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "このCGMを削除しますか?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "キャンセル"; - -/* Title describing glucose date */ -"Date" = "日付"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "CGMを削除"; - -/* Title describing glucose value */ -"Glucose" = "血糖値"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "グルコース (調整後)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "直近の較正"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "最新の読み取り"; - -/* Button title to open CGM app */ -"Open App" = "アプリを開く"; - -/* Title describing sensor session age */ -"Session Age" = "セッション経過時間"; - -/* Title describing CGM calibration and battery state */ -"Status" = "ステータス"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "トランスミッター経過時間"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "トランスミッタ ID"; - -/* Title describing glucose trend */ -"Trend" = "トレンド"; - diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/ja.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/ja.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index ece0fced0..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/ja.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "証明"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "トランスミッター設定"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detail"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "トランスミッターの接続ができないときに、インターネットでShareからデータをダウンロードできます。"; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "6桁のトランスミッタIDを入力"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "トランスミッターIDは、トランスミッタ―の底面、パッケージの側面、またはレシーバとモバイルアプリの設定メニューで確認できます。"; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "トランスミッタ ID"; - diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/nb.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/nb.lproj/Localizable.strings deleted file mode 100644 index 96ca0c89f..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/nb.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Er du sikker på at du vil slette CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Avbryt"; - -/* Title describing glucose date */ -"Date" = "Dato"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Slett CGM"; - -/* Title describing glucose value */ -"Glucose" = "Blodsukker"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Blodsukker (Justert)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Siste kalibrering"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Siste måling"; - -/* Section title for latest connection date */ -"Latest Connection" = "Siste forbindelse"; - -/* Button title to open CGM app */ -"Open App" = "Åpne app"; - -/* Title describing sensor session age */ -"Session Age" = "Alder på økt"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Synkronisering av eksterne data"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor utløper"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor utløpt"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Status"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Alder på sender"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "Sender ID"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Last opp avlesninger"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/nb.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/nb.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index 16ee36585..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/nb.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Påloggingsinformasjon"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Sett opp sender"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detalj"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "Sender ID finner du på baksiden av senderen, eller på siden av esken den kom i, eller under innstillinger i appen til senderen."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "Sender ID"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Data kan lastes ned over internett fra Share-server om tilkobling til sender ikke fungerer."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Skriv 6-siffret sender ID"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/nl.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/nl.lproj/Localizable.strings deleted file mode 100644 index 06e70a8fc..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/nl.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Weet je zeker dat je deze CGM wilt verwijderen"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuleer"; - -/* Title describing glucose date */ -"Date" = "Datum"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Verwijder CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glucosewaarde"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glucose (Aangepast)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Laatste kalibratie"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Laatste meting"; - -/* Section title for latest connection date */ -"Latest Connection" = "Laatste verbinding"; - -/* Button title to open CGM app */ -"Open App" = "App openen"; - -/* Title describing sensor session age */ -"Session Age" = "Sessieduur"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Synchronisatie van gegevens op afstand"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor verloopt"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor verlopen"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Status"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Zenderleeftijd"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "Zenderserienummer"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Upload metingen"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/nl.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/nl.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index de9b65084..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/nl.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Toegangsgegevens"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Zender instellen"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detail"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "Het serienummer van de zender staat achter op het apparaat, op de zijkant van de verpakking en in het instellingenmenu van de ontvanger en de app."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "Serienummer van de zender"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Gegevens kunnen via het internet van Share gedownload worden wanneer de verbinding met de zender uitvalt."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Vul het 6 cijferige serienummer van de zender in"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/pl.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/pl.lproj/Localizable.strings deleted file mode 100644 index 0cf8c4034..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/pl.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Czy na pewno chcesz usunąć ten CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Anuluj"; - -/* Title describing glucose date */ -"Date" = "Data"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Usuń CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glukoza"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glukoza (skorygowana)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Ostatnia kalibracja"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Ostatni odczyt"; - -/* Section title for latest connection date */ -"Latest Connection" = "Ostatnie połączenie"; - -/* Button title to open CGM app */ -"Open App" = "Otwórz aplikację"; - -/* Title describing sensor session age */ -"Session Age" = "Wiek sesji"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Zdalna synchronizacja danych"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor Wygasa"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor wygasł"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Status"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Wiek nadajnika"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "ID nadajnika"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Wysyłaj odczyty"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/pl.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/pl.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index b5d9b207a..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/pl.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Dane uwierzytelniające"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Konfiguracja nadajnika"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detail"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "ID nadajnika jest nadrukowany z tyłu urządzenia, z boku opakowania, w którym go dostarczono oraz jest dostępny w menu ustawień odbiornika i w aplikacji mobilnej."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "ID nadajnika"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Dane można pobrać przez internet z Share, kiedy połączenie nadajnika się nie powiedzie."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Wprowadź 6-cyfrowy ID nadajnika"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/pt-BR.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/pt-BR.lproj/Localizable.strings deleted file mode 100644 index 998d78c7d..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Você está certo que quer remover este CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancelar"; - -/* Title describing glucose date */ -"Date" = "Data"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Remover CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glicose"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glicose (Ajustada)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Última Calibração"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Leitura mais Recente"; - -/* Section title for latest connection date */ -"Latest Connection" = "Latest Connection"; - -/* Button title to open CGM app */ -"Open App" = "Abrir App"; - -/* Title describing sensor session age */ -"Session Age" = "Idade da Sessão"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Remote Data Synchronization"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor Expires"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor Expired"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Estado"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Idade do Transmissor"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "ID do Transmissor"; - -/* Title describing glucose trend */ -"Trend" = "Tendência"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Upload Readings"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/pt-BR.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/pt-BR.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index abc113fad..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/pt-BR.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Credenciais"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Configuração do Transmissor"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detail"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "O ID do transmissor pode ser encontrado impresso na parte traseira do dispositivo, na parte lateral da caixa em que ele veio e nos menus de configurações do receptor e do aplicativo móvel."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "ID do Transmissor"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Os dados podem ser baixados pela Internet a partir do compartilhamento quando a conexão do transmissor falhar."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Digite o ID do transmissor de 6 dígitos"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/pt-PT.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/pt-PT.lproj/Localizable.strings deleted file mode 100644 index f4938cd39..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/pt-PT.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancelar"; - -/* Title describing glucose date */ -"Date" = "Data"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Delete CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glucose"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glucose (Adjusted)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Latest Calibration"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Latest Reading"; - -/* Section title for latest connection date */ -"Latest Connection" = "Latest Connection"; - -/* Button title to open CGM app */ -"Open App" = "Open App"; - -/* Title describing sensor session age */ -"Session Age" = "Session Age"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Remote Data Synchronization"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor Expires"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor Expired"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Status"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Transmitter Age"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "ID do transmissor"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Upload Readings"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/pt-PT.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/pt-PT.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index d2e12ca3c..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/pt-PT.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Credentials"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Transmitter Setup"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detail"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "ID do transmissor"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Enter the 6-digit transmitter ID"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/ro.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/ro.lproj/Localizable.strings deleted file mode 100644 index b1b86fb0a..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/ro.lproj/Localizable.strings +++ /dev/null @@ -1,61 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "/min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Sunteți sigur că doriți să ștergeți acest CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Renunță"; - -/* Title describing glucose date */ -"Date" = "Data"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Ștergeți CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glucoza"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glucoză (ajustată)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Ultima calibrare"; - -/* Section title for latest connection date */ -"Latest Connection" = "Ultima conexiune"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Ultima citire"; - -/* Button title to open CGM app */ -"Open App" = "Deschide aplicația"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Sincronizarea datelor"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Senzorul a expirat"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Senzorul expiră"; - -/* Title describing sensor session age */ -"Session Age" = "Vechime sesiune"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Stare"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Vechime transmițător"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "ID transmițător"; - -/* Title describing glucose trend */ -"Trend" = "Tendinţă"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Urcă citirile de glicemie"; - diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/ro.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/ro.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index e7b353c4a..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/ro.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Autentificare"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Setare transmițător"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detail"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Pot fi transferate date prin Internet din Share atunci când eșuează conexiunea cu transmițătorul"; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Introduceți ID-ul din 6 cifre al transmițătorului"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "ID-ul transmițătorului poate fi găsit fie pe pe spatele dispozitivului sau pe cutia cu care a venit sau poate fi văzut în setările receiver-ului sau a aplicației mobile."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "ID transmițător"; - diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/ru.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/ru.lproj/Localizable.strings deleted file mode 100644 index 04528f042..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/ru.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/мин"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Вы уверены, что хотите удалить этот CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Отмена"; - -/* Title describing glucose date */ -"Date" = "Дата"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Удалить CGM"; - -/* Title describing glucose value */ -"Glucose" = "Глюкоза"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "ГК (корректированная)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Последняя калибровка"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Последние данные"; - -/* Section title for latest connection date */ -"Latest Connection" = "Последнее подключение"; - -/* Button title to open CGM app */ -"Open App" = "Открыть приложение"; - -/* Title describing sensor session age */ -"Session Age" = "Сенсор отработал"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Удаленная синхронизация данных"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Сенсор истекает"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Сенсор истек"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Статус"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Трансмиттер отработал"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "ID трансмиттера"; - -/* Title describing glucose trend */ -"Trend" = "Тенденция"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Загрузить показания"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/ru.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/ru.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index 9bda4bb2c..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/ru.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Учетные данные"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Настройка трансмиттера"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Подробности"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "Номер трансмиттера находится на обратной стороне устройства, сбоку кпаковочной коробки, в настройках ресивера и мобильного приложения."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "ID трансмиттера"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Данные могут быть загружены с серверов Share если не произойдет соединение трансмиттера."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Введите шестизначный идентификатор трансмиттера"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/sk.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/sk.lproj/Localizable.strings deleted file mode 100644 index 937e98dc2..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/sk.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@ /min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Naozaj chcete odstrániť toto CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Zrušiť"; - -/* Title describing glucose date */ -"Date" = "Dátum"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Odstrániť CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glykémia"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glykémia (upravená)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Posledná kalibrácia"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Posledné čítanie"; - -/* Section title for latest connection date */ -"Latest Connection" = "Posledné pripojenie"; - -/* Button title to open CGM app */ -"Open App" = "Otvoriť aplikáciu"; - -/* Title describing sensor session age */ -"Session Age" = "Dĺžka relácie"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Diaľková sychronizácia dát"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Platnosť senzora vyprší"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Platnosť senzora vypršala"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Stav"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Vek vysielača"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "ID vysielača"; - -/* Title describing glucose trend */ -"Trend" = "Vývoj"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Načítať údaje"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/sk.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/sk.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index 04704c918..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/sk.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Poverenia"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Nastavenie vysielača"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Podrobnosti"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "ID vysielača nájdete vytlačené na zadnej strane zariadenia, na boku škatule, v ktorej bol dodaný, a v ponuke nastavení prijímača a mobilnej aplikácie."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "ID vysielača"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Údaje je možné stiahnuť cez internet zo Share, keď zlyhá pripojenie vysielača."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Zadajte 6-miestne ID vysielača"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/sv.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/sv.lproj/Localizable.strings deleted file mode 100644 index 001306638..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/sv.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@ min"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Är du säker på att du vill radera denna CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Avbryt"; - -/* Title describing glucose date */ -"Date" = "Tid"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Radera CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glukos"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Glukos (justerad)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Senaste kalibrering"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Senaste avläsning"; - -/* Section title for latest connection date */ -"Latest Connection" = "Senaste anslutning"; - -/* Button title to open CGM app */ -"Open App" = "Öppna appen"; - -/* Title describing sensor session age */ -"Session Age" = "Sessionsålder"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Synkronisering av fjärrlagrad data"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor går ut"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensor har gått ut"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Status"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Ålder på sändare"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "Sändar-ID"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Ladda upp avläsningar"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/sv.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/sv.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index fd047db6f..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/sv.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Inloggningsuppgifter"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Sändarinställningar"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detalj"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "Sändar-ID kan hittas tryckt på baksidan av enheten, på sidan av lådan den kom i, samt från inställningsmenyn för mottagaren och mobilappen."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "Sändar-ID"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Data kan laddas ned från Dexcom Share (via Internet) om sändaranslutningen skulle misslyckas."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Ange 6-siffrigt sändar-ID"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/tr.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/tr.lproj/Localizable.strings deleted file mode 100644 index e36520bfb..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/tr.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/dk"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Bu CGM'i silmek istediğinizden emin misiniz?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "İptal"; - -/* Title describing glucose date */ -"Date" = "Tarih"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "CGM Sil"; - -/* Title describing glucose value */ -"Glucose" = "Kan şekeri"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "KŞ (Düzeltilmiş)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Son Kalibrasyon"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Son Okuma"; - -/* Section title for latest connection date */ -"Latest Connection" = "Son Bağlantı"; - -/* Button title to open CGM app */ -"Open App" = "Uygulamayı aç"; - -/* Title describing sensor session age */ -"Session Age" = "Sensör Yaşı"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Uzaktan Veri Senkronizasyonu"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensörün Süresi Doluyor"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Sensörün Süresi Doldu"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Durum"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Verici Yaşı"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "Verici Kimliği"; - -/* Title describing glucose trend */ -"Trend" = "Eğilim"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Okumaları Yükle"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/tr.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/tr.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index 08a70c9fa..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/tr.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Kimlik bilgileri"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Verici Kurulumu"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Detay"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "Verici kimliğini, cihazın arkasında, geldiği kutunun yan tarafında, alıcının mobil uygulamasının ayarlar menüsünde bulabilirsiniz."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "Verici Kimliği"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Verici bağlantısı başarısız olduğunda Dexcom Share üzerinden veriler indirilebilir."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "6 basamaklı verici kimliğini girin"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/uk.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/uk.lproj/Localizable.strings deleted file mode 100644 index a3e72e51e..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/uk.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/хв"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Ви впевнені, що хочете видалити цей CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Відмінити"; - -/* Title describing glucose date */ -"Date" = "Дата"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Видалити CGM"; - -/* Title describing glucose value */ -"Glucose" = "Глюкоза"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Глюкоза (коригована)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Остання калібровка"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Останнє читання"; - -/* Section title for latest connection date */ -"Latest Connection" = "Останнє підключення"; - -/* Button title to open CGM app */ -"Open App" = "Відкрити додаток"; - -/* Title describing sensor session age */ -"Session Age" = "Вік Сенсору"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Віддалена синхронізація даних"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Сенсор закінчується"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Сенсор минув"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Статус"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Трансмітер відпрацював"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "ID передавача"; - -/* Title describing glucose trend */ -"Trend" = "Тренди"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Вивантажити читання"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/uk.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/uk.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index db7351553..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/uk.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Облікові дані"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Налаштування Трасмітера"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Детальніше"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "ID Трансмітера вказано на зворотній стороні девайса, на бічній стороні упаковки, а також в меню налаштувань ресивера та мобільного додатку."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "ID трансмітера"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Дані можуть бути завантажені по мережі через Sharе, у разі помилки зʼєднання трансмітера."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Введіть 6-значний ID трансмітера"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/vi.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/vi.lproj/Localizable.strings deleted file mode 100644 index e2071ad2d..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/vi.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/phút"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Bạn có chắc sẽ xóa CGM này?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Hủy bỏ"; - -/* Title describing glucose date */ -"Date" = "Ngày"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Xóa CGM"; - -/* Title describing glucose value */ -"Glucose" = "Đường huyết"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "Đường huyết (Được điều chỉnh)"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "Lần hiệu chỉnh gần nhất"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Kết quả đọc mới nhất"; - -/* Section title for latest connection date */ -"Latest Connection" = "Kết nối gần đây nhất"; - -/* Button title to open CGM app */ -"Open App" = "Mở ứng dụng"; - -/* Title describing sensor session age */ -"Session Age" = "Thời gian sử dụng sensor"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "Đồng bộ hoá dữ liệu từ xa"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Cảm biến hết hạn"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "Cảm biến đã hết hạn"; - -/* Title describing CGM calibration and battery state */ -"Status" = "Tình trạng"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "Thời gian sử dụng Transmitter"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "Số ID của Transmitter"; - -/* Title describing glucose trend */ -"Trend" = "Xu hướng"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Glucose đang tải lên"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/vi.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/vi.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index f05016023..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/vi.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "Thông tin xác thực"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "Cài đặt Transmitter"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "Chi tiết"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "Số ID của Transmitter có thể được tìm thấy trên vỏ hộp hoặc bên hông hộp và trong phần Menu cài đặt cũng như trên ứng dụng của điện thoại."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "Số ID của Transmitter"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "Dữ liệu có thể được tải xuống qua đường truyền Internet trên ứng dụng Share khi kết nối với transmitter bị đứt."; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dữ liệu từ Dexcom Share"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "Nhập 6 số ID của Transmitter"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/zh-Hans.lproj/Localizable.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 7606ebf3c..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/分钟"; - -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "确认要删除该CGM吗?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "取消"; - -/* Title describing glucose date */ -"Date" = "日期"; - -/* Button title to delete CGM -Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "删除CGM"; - -/* Title describing glucose value */ -"Glucose" = "葡萄糖"; - -/* Describes a glucose value adjusted to reflect a recent calibration */ -"Glucose (Adjusted)" = "血糖"; - -/* Section title for latest glucose calibration */ -"Latest Calibration" = "最近一次较准"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "最新血糖值"; - -/* Section title for latest connection date */ -"Latest Connection" = "上一次连接"; - -/* Button title to open CGM app */ -"Open App" = "打开软件"; - -/* Title describing sensor session age */ -"Session Age" = "传感器启动天数"; - -/* Section title for remote data synchronization */ -"Remote Data Synchronization" = "远程数据同步"; - -/* Title describing sensor expiration */ -"Sensor Expires" = "Sensor Expires"; - -/* Title describing past sensor expiration */ -"Sensor Expired" = "传感器已过期"; - -/* Title describing CGM calibration and battery state */ -"Status" = "状态"; - -/* Title describing transmitter session age */ -"Transmitter Age" = "发射器使用天数"; - -/* The title text for the Dexcom G5/G6 transmitter ID config value */ -"Transmitter ID" = "发射器编号"; - -/* Title describing glucose trend */ -"Trend" = "趋势"; - -/* The title text for the upload glucose switch cell */ -"Upload Readings" = "Upload Readings"; diff --git a/Dependencies/CGMBLEKit/CGMBLEKitUI/zh-Hans.lproj/TransmitterManagerSetup.strings b/Dependencies/CGMBLEKit/CGMBLEKitUI/zh-Hans.lproj/TransmitterManagerSetup.strings deleted file mode 100644 index 73e7ebb50..000000000 --- a/Dependencies/CGMBLEKit/CGMBLEKitUI/zh-Hans.lproj/TransmitterManagerSetup.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Class = "UILabel"; text = "Credentials"; ObjectID = "5oU-vK-JHQ"; */ -"5oU-vK-JHQ.text" = "密钥"; - -/* Class = "UITableViewController"; title = "Transmitter Setup"; ObjectID = "Dds-49-o7G"; */ -"Dds-49-o7G.title" = "设置发射器"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "GOT-KQ-cEh"; */ -"GOT-KQ-cEh.text" = "详情"; - -/* Class = "UITableViewSection"; footerTitle = "The transmitter ID can be found printed on the back of the device, on the side of the box it came in, and from within the settings menus of the receiver and mobile app."; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.footerTitle" = "发射器编号可在发射器包装盒背面找到,或者可在Dexcom Moblie软件及接受器的“setting”-“Transmitter”中找到"; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "Qub-6B-0aB"; */ -"Qub-6B-0aB.headerTitle" = "发射器编号"; - -/* Class = "UITableViewSection"; footerTitle = "Data can be downloaded over the Internet from Share when the transmitter connection fails."; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.footerTitle" = "当无法连接发射器时,可通过网络从Dexcom远程下载数据"; - -/* Class = "UITableViewSection"; headerTitle = "Dexcom Share"; ObjectID = "k1N-Rg-XDy"; */ -"k1N-Rg-XDy.headerTitle" = "Dexcom远程"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit transmitter ID"; ObjectID = "nKX-TW-GhD"; */ -"nKX-TW-GhD.placeholder" = "请输入6位发射器编号"; diff --git a/Dependencies/CGMBLEKit/CODE_OF_CONDUCT.md b/Dependencies/CGMBLEKit/CODE_OF_CONDUCT.md deleted file mode 100644 index 8079e4550..000000000 --- a/Dependencies/CGMBLEKit/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,72 +0,0 @@ -# Code of Conduct - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or -advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the maintaner [via email](mailto:loudnate@gmail.com). All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ \ No newline at end of file diff --git a/Dependencies/CGMBLEKit/Common/Data.swift b/Dependencies/CGMBLEKit/Common/Data.swift deleted file mode 100644 index a7587d651..000000000 --- a/Dependencies/CGMBLEKit/Common/Data.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// NSData.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 3/5/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension Data { - private func toDefaultEndian(_: T.Type) -> T { - return self.withUnsafeBytes({ (rawBufferPointer: UnsafeRawBufferPointer) -> T in - let bufferPointer = rawBufferPointer.bindMemory(to: T.self) - guard let pointer = bufferPointer.baseAddress else { - return 0 - } - return T(pointer.pointee) - }) - } - - func to(_ type: T.Type) -> T { - return T(littleEndian: toDefaultEndian(type)) - } - - func toInt() -> T { - return to(T.self) - } - - func toBigEndian(_ type: T.Type) -> T { - return T(bigEndian: toDefaultEndian(type)) - } - - mutating func append(_ newElement: T) { - withUnsafePointer(to: newElement.littleEndian) { (ptr: UnsafePointer) in - append(UnsafeBufferPointer(start: ptr, count: 1)) - } - } - - mutating func appendBigEndian(_ newElement: T) { - withUnsafePointer(to: newElement.bigEndian) { (ptr: UnsafePointer) in - append(UnsafeBufferPointer(start: ptr, count: 1)) - } - } - - init(_ value: T) { - self = withUnsafePointer(to: value.littleEndian) { (ptr: UnsafePointer) -> Data in - return Data(buffer: UnsafeBufferPointer(start: ptr, count: 1)) - } - } - - init(bigEndian value: T) { - self = withUnsafePointer(to: value.bigEndian) { (ptr: UnsafePointer) -> Data in - return Data(buffer: UnsafeBufferPointer(start: ptr, count: 1)) - } - } -} - - -// String conversion methods, adapted from https://stackoverflow.com/questions/40276322/hex-binary-string-conversion-in-swift/40278391#40278391 -extension Data { - init?(hexadecimalString: String) { - self.init(capacity: hexadecimalString.utf16.count / 2) - - // Convert 0 ... 9, a ... f, A ...F to their decimal value, - // return nil for all other input characters - func decodeNibble(u: UInt16) -> UInt8? { - switch u { - case 0x30 ... 0x39: // '0'-'9' - return UInt8(u - 0x30) - case 0x41 ... 0x46: // 'A'-'F' - return UInt8(u - 0x41 + 10) // 10 since 'A' is 10, not 0 - case 0x61 ... 0x66: // 'a'-'f' - return UInt8(u - 0x61 + 10) // 10 since 'a' is 10, not 0 - default: - return nil - } - } - - var even = true - var byte: UInt8 = 0 - for c in hexadecimalString.utf16 { - guard let val = decodeNibble(u: c) else { return nil } - if even { - byte = val << 4 - } else { - byte += val - self.append(byte) - } - even = !even - } - guard even else { return nil } - } - - var hexadecimalString: String { - return map { String(format: "%02hhx", $0) }.joined() - } -} diff --git a/Dependencies/CGMBLEKit/Common/HKUnit.swift b/Dependencies/CGMBLEKit/Common/HKUnit.swift deleted file mode 100644 index 69e6f9aed..000000000 --- a/Dependencies/CGMBLEKit/Common/HKUnit.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// HKUnit.swift -// xDripG5 -// -// Created by Nate Racklyeft on 8/6/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -extension HKUnit { - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: HKUnit.literUnit(with: .deci)) - }() - - static let milligramsPerDeciliterPerMinute: HKUnit = { - return HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) - }() -} diff --git a/Dependencies/CGMBLEKit/Common/LocalizedString.swift b/Dependencies/CGMBLEKit/Common/LocalizedString.swift deleted file mode 100644 index 831ab950f..000000000 --- a/Dependencies/CGMBLEKit/Common/LocalizedString.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// LocalizedString.swift -// LoopUI -// -// Created by Kathryn DiSimone on 8/15/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -internal class FrameworkBundle { - static let main = Bundle(for: FrameworkBundle.self) -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: FrameworkBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: FrameworkBundle.main, comment: comment) - } -} diff --git a/Dependencies/CGMBLEKit/Common/Locked.swift b/Dependencies/CGMBLEKit/Common/Locked.swift deleted file mode 100644 index fd6e35b10..000000000 --- a/Dependencies/CGMBLEKit/Common/Locked.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// Locked.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import os.lock - - -internal class Locked { - private var lock = os_unfair_lock() - private var _value: T - - init(_ value: T) { - os_unfair_lock_lock(&lock) - defer { os_unfair_lock_unlock(&lock) } - _value = value - } - - var value: T { - get { - os_unfair_lock_lock(&lock) - defer { os_unfair_lock_unlock(&lock) } - return _value - } - set { - os_unfair_lock_lock(&lock) - defer { os_unfair_lock_unlock(&lock) } - _value = newValue - } - } - - func mutate(_ changes: (_ value: inout T) -> Void) -> T { - os_unfair_lock_lock(&lock) - defer { os_unfair_lock_unlock(&lock) } - changes(&_value) - return _value - } -} diff --git a/Dependencies/CGMBLEKit/Common/TimeInterval.swift b/Dependencies/CGMBLEKit/Common/TimeInterval.swift deleted file mode 100644 index 5a8046a6c..000000000 --- a/Dependencies/CGMBLEKit/Common/TimeInterval.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// NSTimeInterval.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension TimeInterval { - static func hours(_ hours: Double) -> TimeInterval { - return self.init(hours: hours) - } - - static func minutes(_ minutes: Int) -> TimeInterval { - return self.init(minutes: Double(minutes)) - } - - static func minutes(_ minutes: Double) -> TimeInterval { - return self.init(minutes: minutes) - } - - static func seconds(_ seconds: Double) -> TimeInterval { - return self.init(seconds) - } - - static func milliseconds(_ milliseconds: Double) -> TimeInterval { - return self.init(milliseconds / 1000) - } - - init(minutes: Double) { - self.init(minutes * 60) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - init(seconds: Double) { - self.init(seconds) - } - - init(milliseconds: Double) { - self.init(milliseconds / 1000) - } - - var milliseconds: Double { - return self * 1000 - } - - var minutes: Double { - return self / 60.0 - } - - var hours: Double { - return minutes / 60.0 - } - -} diff --git a/Dependencies/CGMBLEKit/LICENSE b/Dependencies/CGMBLEKit/LICENSE deleted file mode 100644 index b1adb5791..000000000 --- a/Dependencies/CGMBLEKit/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Nathan Racklyeft - -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/Dependencies/CGMBLEKit/Pod/CGMBLEKit.h b/Dependencies/CGMBLEKit/Pod/CGMBLEKit.h deleted file mode 100644 index a28840359..000000000 --- a/Dependencies/CGMBLEKit/Pod/CGMBLEKit.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// CGMBLEKit.h -// xDripG5 -// -// Created by Nathan Racklyeft on 12/31/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - - -#import \ No newline at end of file diff --git a/Dependencies/CGMBLEKit/README.md b/Dependencies/CGMBLEKit/README.md deleted file mode 100644 index 370d086ea..000000000 --- a/Dependencies/CGMBLEKit/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# CGMBLEKit - -[![CI Status](http://img.shields.io/travis/LoopKit/CGMBLEKit.svg?style=flat)](https://travis-ci.org/LoopKit/CGMBLEKit) -[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) - -A iOS framework providing an interface for communicating with the G5 and G6 glucose transmitters over Bluetooth. - -*Please note this project is neither created nor backed by Dexcom, Inc. This software is not intended for use in therapy.* - -## Requirements - -This framework connects to a G5 or G6 Mobile Transmitter via Bluetooth LE. It does not connect to the G4 Share Receiver or any earlier CGM products. - -## Frameworks Installation - -### Carthage - -CGMBLEKit is available through [Carthage](https://github.com/Carthage/Carthage). To install it, add the following line to your Cartfile: - -```ruby -github "LoopKit/CGMBLEKit" -``` - -Note that you'll need to confgure your target to link against `CommonCrypto.framework` in addition to `CGMBLEKit.framework` - -## Usage - -If you plan to run your app alongside the G5 Mobile application, make sure to set `passiveModeEnabled` to true. - -### Examples - -[glucose-badge](https://github.com/dennisgove/glucose-badge) – Display the latest glucose values as an app icon badge - -## ResetTransmitter App Installation - -Download the CGMBLEKit code by clicking on the green `Clone or Download` button (scroll up on this page and you'll find it), then select `Download Zip` - -![ResetTransmitter help](https://github.com/Kdisimone/images/blob/master/resetTransmitter-first.png) - -Then navigate to the `CGMBLEKit` folder that just downloaded to your computer. Double-click on the `CGMBLEKit.xcodeproj` file to open the project in Xcode. - -![ResetTransmitter help](https://github.com/Kdisimone/images/blob/master/resetTransmitter-download.png) - -To install the ResetTransmitter App on your iPhone, simply make sure to sign the ResetTransmitter target and then select just the `ResetTransmitter` scheme in the build area. Make sure your iPhone is plugged into the computer, select your iPhone from the top of the `Devices` in the 4th circled area, screenshot below. Note: You do not have to change bundle IDs or anything beyond the steps listed. - -![ResetTransmitter help](https://github.com/Kdisimone/images/blob/master/resetTransmitter.png) - - -## Code of Conduct - -Please note that this project is released with a [Contributor Code of Conduct](https://github.com/LoopKit/LoopKit/blob/master/CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. - -## License - -CGMBLEKit is available under the MIT license. See the LICENSE file for more info. diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/AppDelegate.swift b/Dependencies/CGMBLEKit/ResetTransmitter/AppDelegate.swift deleted file mode 100644 index 548924db7..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/AppDelegate.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// AppDelegate.swift -// ResetTransmitter -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? - - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - return true - } - - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - -} - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Contents.json b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2a71258dd..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,200 +0,0 @@ -{ - "images" : [ - { - "filename" : "Icon-App-20x20@2x.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "filename" : "Icon-App-20x20@3x.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "filename" : "Icon-App-29x29@2x.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "Icon-App-29x29@3x.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "filename" : "Icon-App-40x40@2x.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "filename" : "Icon-App-40x40@3x.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "filename" : "Icon-App-60x60@2x.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "filename" : "Icon-App-60x60@3x.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "filename" : "Icon-App-20x20@1x.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "filename" : "Icon-App-20x20@2x-1.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "filename" : "Icon-App-29x29@1x.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "filename" : "Icon-App-29x29@2x-1.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "Icon-App-40x40@1x.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "filename" : "Icon-App-40x40@2x-1.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "filename" : "Icon-App-76x76@1x.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "filename" : "Icon-App-76x76@2x.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "filename" : "Icon-App-83.5x83.5@2x.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "filename" : "ItunesArtwork@2x.png", - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - }, - { - "filename" : "Icon-24@2x.png", - "idiom" : "watch", - "role" : "notificationCenter", - "scale" : "2x", - "size" : "24x24", - "subtype" : "38mm" - }, - { - "filename" : "Icon-27.5@2x.png", - "idiom" : "watch", - "role" : "notificationCenter", - "scale" : "2x", - "size" : "27.5x27.5", - "subtype" : "42mm" - }, - { - "filename" : "Icon-29@2x.png", - "idiom" : "watch", - "role" : "companionSettings", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "Icon-29@3x.png", - "idiom" : "watch", - "role" : "companionSettings", - "scale" : "3x", - "size" : "29x29" - }, - { - "filename" : "Icon-40@2x.png", - "idiom" : "watch", - "role" : "appLauncher", - "scale" : "2x", - "size" : "40x40", - "subtype" : "38mm" - }, - { - "filename" : "Icon-44@2x.png", - "idiom" : "watch", - "role" : "appLauncher", - "scale" : "2x", - "size" : "44x44", - "subtype" : "40mm" - }, - { - "idiom" : "watch", - "role" : "appLauncher", - "scale" : "2x", - "size" : "50x50", - "subtype" : "44mm" - }, - { - "filename" : "Icon-86@2x.png", - "idiom" : "watch", - "role" : "quickLook", - "scale" : "2x", - "size" : "86x86", - "subtype" : "38mm" - }, - { - "filename" : "Icon-98@2x.png", - "idiom" : "watch", - "role" : "quickLook", - "scale" : "2x", - "size" : "98x98", - "subtype" : "42mm" - }, - { - "idiom" : "watch", - "role" : "quickLook", - "scale" : "2x", - "size" : "108x108", - "subtype" : "44mm" - }, - { - "idiom" : "watch-marketing", - "scale" : "1x", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "pre-rendered" : true - } -} diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-24@2x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-24@2x.png deleted file mode 100644 index 4cfc34bb3..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-24@2x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-27.5@2x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-27.5@2x.png deleted file mode 100644 index fac9f63d5..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-27.5@2x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png deleted file mode 100644 index bfb19c6c9..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png deleted file mode 100644 index bc77717c2..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png deleted file mode 100644 index 4611f6119..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-44@2x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-44@2x.png deleted file mode 100644 index 8c9c491f7..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-44@2x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-86@2x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-86@2x.png deleted file mode 100644 index 7382fd4ec..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-86@2x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-98@2x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-98@2x.png deleted file mode 100644 index 53651595c..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-98@2x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 4235ba2ee..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png deleted file mode 100644 index f76b80973..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index f76b80973..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 3b386794f..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index d8c8bf64c..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png deleted file mode 100644 index bfb19c6c9..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index bfb19c6c9..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index bc77717c2..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index f76b80973..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png deleted file mode 100644 index 4611f6119..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 4611f6119..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index 2b0077e73..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 2b0077e73..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 3316556cf..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index eb05243fb..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 3118eea32..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index f491307c1..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png deleted file mode 100644 index 43214e1a7..000000000 Binary files a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png and /dev/null differ diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/Contents.json b/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/Contents.json deleted file mode 100644 index da4a164c9..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Base.lproj/LaunchScreen.storyboard b/Dependencies/CGMBLEKit/ResetTransmitter/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 94b34243e..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Base.lproj/Main.storyboard b/Dependencies/CGMBLEKit/ResetTransmitter/Base.lproj/Main.storyboard deleted file mode 100644 index 4211c49dc..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/Base.lproj/Main.storyboard +++ /dev/null @@ -1,272 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started. -This may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account. -Resetting cannot be undone. -Use at your own risk. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/CompletionViewController.swift b/Dependencies/CGMBLEKit/ResetTransmitter/CompletionViewController.swift deleted file mode 100644 index dd8bff906..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/CompletionViewController.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// CompletionViewController.swift -// ResetTransmitter -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import UserNotifications - -class CompletionViewController: UITableViewController { - - @IBOutlet weak var textView: UITextView! - - override func viewDidLoad() { - super.viewDidLoad() - - if UIApplication.shared.applicationState == .background { - let content = UNMutableNotificationContent() - content.badge = 1 - content.title = NSLocalizedString("Transmitter Reset Complete", comment: "Notification title for background completion notification") - content.body = textView.text - content.sound = .default - - let request = UNNotificationRequest(identifier: "Completion", content: content, trigger: nil) - - UNUserNotificationCenter.current().add(request, withCompletionHandler: nil) - } - } - - override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { - return false - } - - override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { - return nil - } -} diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Info.plist b/Dependencies/CGMBLEKit/ResetTransmitter/Info.plist deleted file mode 100644 index 1917f1cb1..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/Info.plist +++ /dev/null @@ -1,55 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Reset - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 3.2 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - NSBluetoothAlwaysUsageDescription - Bluetooth is used to communicate with continuous glucose monitor devices - NSBluetoothPeripheralUsageDescription - Bluetooth is used to communicate with continuous glucose monitor devices - UIBackgroundModes - - bluetooth-central - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/ResetManager.swift b/Dependencies/CGMBLEKit/ResetTransmitter/ResetManager.swift deleted file mode 100644 index 5acfabfa8..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/ResetManager.swift +++ /dev/null @@ -1,145 +0,0 @@ -// -// ResetManager.swift -// ResetTransmitter -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import CGMBLEKit -import os.log - - -class ResetManager { - enum State { - case initialized - case resetting(transmitter: Transmitter) - case completed - } - - private(set) var state: State { - get { - return lockedState.value - } - set { - let oldValue = state - - if case .resetting(let transmitter) = oldValue { - transmitter.stayConnected = false - transmitter.stopScanning() - transmitter.delegate = nil - transmitter.commandSource = nil - } - - lockedState.value = newValue - - if case .resetting(let transmitter) = newValue { - transmitter.delegate = self - transmitter.commandSource = self - transmitter.resumeScanning() - } - - os_log("State changed: %{public}@ -> %{public}@", log: log, type: .debug, String(describing: oldValue), String(describing: newValue)) - delegate?.resetManager(self, didChangeStateFrom: oldValue) - } - } - private let lockedState = Locked(State.initialized) - - private let log = OSLog(subsystem: "com.loopkit.CGMBLEKit", category: "ResetManager") - - weak var delegate: ResetManagerDelegate? -} - - -protocol ResetManagerDelegate: class { - func resetManager(_ manager: ResetManager, didError error: Error) - - func resetManager(_ manager: ResetManager, didChangeStateFrom oldState: ResetManager.State) -} - - -extension ResetManager { - func cancel() { - guard case .resetting = state else { - return - } - - state = .initialized - } - - func resetTransmitter(withID id: String) { - guard id.count == 6 else { - return - } - - switch state { - case .initialized, .completed: - break - case .resetting(transmitter: let transmitter): - guard transmitter.ID != id else { - return - } - } - - state = .resetting(transmitter: Transmitter(id: id, passiveModeEnabled: false)) - - #if targetEnvironment(simulator) - DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5)) { - self.delegate?.resetManager(self, didError: TransmitterError.controlError("Simulated Error")) - - DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5)) { - if case .resetting = self.state { - self.state = .completed - } - } - } - #endif - } -} - - -extension ResetManager: TransmitterDelegate { - - func transmitter(_ transmitter: Transmitter, didError error: Error) { - os_log("Transmitter error: %{public}@", log: log, type: .error, String(describing: error)) - delegate?.resetManager(self, didError: error) - } - - func transmitter(_ transmitter: Transmitter, didRead glucose: Glucose) { - // Not interested - } - - func transmitter(_ transmitter: Transmitter, didReadBackfill glucose: [Glucose]) { - // Not interested - } - - func transmitter(_ transmitter: Transmitter, didReadUnknownData data: Data) { - // Not interested - } - - func transmitterDidConnect(_ transmitter: Transmitter) { - // Not interested - } - -} - - -extension ResetManager: TransmitterCommandSource { - func dequeuePendingCommand(for transmitter: Transmitter) -> Command? { - if case .resetting = state { - return .resetTransmitter - } - - return nil - } - - func transmitter(_ transmitter: Transmitter, didFail command: Command, with error: Error) { - os_log("Command error: %{public}@", log: log, type: .error, String(describing: error)) - delegate?.resetManager(self, didError: error) - } - - func transmitter(_ transmitter: Transmitter, didComplete command: Command) { - if case .resetTransmitter = command { - state = .completed - } - } -} diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/ResetViewController.swift b/Dependencies/CGMBLEKit/ResetTransmitter/ResetViewController.swift deleted file mode 100644 index 8d16d5ea3..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/ResetViewController.swift +++ /dev/null @@ -1,269 +0,0 @@ -// -// ResetViewController.swift -// ResetTransmitter -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import UserNotifications - - -class ResetViewController: UITableViewController { - - @IBOutlet public weak var aboutText: UITextView! - - - private enum State { - case empty - case needsConfiguration - case configured - case resetting - case completed - } - - private var state: State = .empty { - didSet { - guard oldValue != state else { - return - } - - lastError = nil - updateButtonState() - updateTransmitterIDFieldState() - updateStatusIndicatorState() - - if state == .completed { - performSegue(withIdentifier: "CompletionViewController", sender: self) - } - } - } - - @IBOutlet var hairlines: [UIView]! - - @IBOutlet weak var resetButton: Button! - - @IBOutlet weak var transmitterIDField: TextField! - - @IBOutlet weak var spinner: UIActivityIndicatorView! - - @IBOutlet weak var errorLabel: UILabel! - - @IBOutlet weak var buttonTopSpace: NSLayoutConstraint! - - private var needsButtonTopSpaceUpdate = true - - private var lastError: Error? - - private lazy var resetManager: ResetManager = { - let manager = ResetManager() - manager.delegate = self - return manager - }() - - override func viewDidLoad() { - super.viewDidLoad() - - for hairline in hairlines { - for constraint in hairline.constraints { - constraint.constant = 1 / UIScreen.main.scale - } - } - - self.navigationController?.delegate = self - self.navigationController?.navigationBar.shadowImage = UIImage() - - state = .needsConfiguration - - // Setting this color in code because the nib isn't being applied correctly - if #available(iOS 13.0, *) { - aboutText.textColor = .secondaryLabel - } - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .sound, .alert]) { (success, error) in - // - } - } - - override func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - - state = .needsConfiguration - } - - override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - // Update the constraint once to fit the height of the screen - if indexPath.section == tableView.numberOfSections - 1 && needsButtonTopSpaceUpdate { - needsButtonTopSpaceUpdate = false - let currentValue = buttonTopSpace.constant - let suggestedValue = max(0, tableView.bounds.size.height - tableView.contentSize.height - tableView.safeAreaInsets.bottom - tableView.safeAreaInsets.top) - - if abs(currentValue - suggestedValue) > .ulpOfOne { - buttonTopSpace.constant = suggestedValue - } - } - - return UITableView.automaticDimension - } - - override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { - return false - } - - override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { - return nil - } - - // MARK: - Actions - - @IBAction func performAction(_ sender: Any) { - switch state { - case .empty, .needsConfiguration: - // Actions are not allowed - break - case .configured: - // Begin reset - resetTransmitter(withID: transmitterIDField.text ?? "") - case .resetting: - // Cancel pending reset - resetManager.cancel() - case .completed: - // Ignore actions here - break - } - } - - private func resetTransmitter(withID id: String) { - let controller = UIAlertController( - title: NSLocalizedString("Are you sure you want to reset this transmitter?", comment: "Title of the reset confirmation sheet"), - message: NSLocalizedString("It will take up to 10 minutes to complete.", comment: "Message of the reset confirmation sheet"), preferredStyle: .actionSheet - ) - - controller.addAction(UIAlertAction( - title: NSLocalizedString("Reset", comment: "Reset button title"), - style: .destructive, - handler: { (action) in - self.resetManager.resetTransmitter(withID: id) - } - )) - - controller.addAction(UIAlertAction( - title: NSLocalizedString("Cancel", comment: "Title of button to cancel reset"), - style: .cancel, - handler: nil - )) - - present(controller, animated: true, completion: nil) - } -} - - -// MARK: - UI state management -extension ResetViewController { - private func updateButtonState() { - switch state { - case .empty, .needsConfiguration: - resetButton.isEnabled = false - case .configured, .resetting, .completed: - resetButton.isEnabled = true - } - - switch state { - case .empty, .needsConfiguration, .configured: - resetButton.setTitle(NSLocalizedString("Reset", comment: "Title of button to begin reset"), for: .normal) - resetButton.tintColor = .red - case .resetting, .completed: - resetButton.setTitle(NSLocalizedString("Cancel", comment: "Title of button to cancel reset"), for: .normal) - resetButton.tintColor = .darkGray - } - } - - private func updateTransmitterIDFieldState() { - switch state { - case .empty, .needsConfiguration: - transmitterIDField.text = "" - transmitterIDField.isEnabled = true - case .configured: - transmitterIDField.isEnabled = true - case .resetting, .completed: - transmitterIDField.isEnabled = false - } - } - - private func updateStatusIndicatorState() { - switch self.state { - case .empty, .needsConfiguration, .configured, .completed: - self.spinner.stopAnimating() - self.errorLabel.superview?.isHidden = true - case .resetting: - self.spinner.startAnimating() - if let error = lastError { - self.errorLabel.text = String(describing: error) - } - self.errorLabel.superview?.isHidden = - (self.lastError == nil) - } - } -} - - -extension ResetViewController: ResetManagerDelegate { - func resetManager(_ manager: ResetManager, didError error: Error) { - DispatchQueue.main.async { - self.lastError = error - self.updateStatusIndicatorState() - } - } - - func resetManager(_ manager: ResetManager, didChangeStateFrom oldState: ResetManager.State) { - DispatchQueue.main.async { - switch manager.state { - case .initialized: - self.state = .configured - case .resetting: - self.state = .resetting - case .completed: - self.state = .completed - } - } - } -} - -extension ResetViewController: UINavigationControllerDelegate { - func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask { - return .portrait - } -} - -extension ResetViewController: UITextFieldDelegate { - func textFieldShouldReturn(_ textField: UITextField) -> Bool { - textField.resignFirstResponder() - return false - } - - func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - guard let text = textField.text, let stringRange = Range(range, in: text) else { - state = .needsConfiguration - return true - } - - let newText = text.replacingCharacters(in: stringRange, with: string) - - if newText.count >= 6 { - if newText.count == 6 { - textField.text = newText - textField.resignFirstResponder() - } - - state = .configured - return false - } - - state = .needsConfiguration - return true - } -} diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Views/Button.swift b/Dependencies/CGMBLEKit/ResetTransmitter/Views/Button.swift deleted file mode 100644 index c5a09ad22..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/Views/Button.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// Button.swift -// ResetTransmitter -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - - -class Button: UIButton { - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - } - - override func awakeFromNib() { - super.awakeFromNib() - - backgroundColor = tintColor - layer.cornerRadius = 6 - - titleLabel?.adjustsFontForContentSizeCategory = true - contentEdgeInsets.top = 14 - contentEdgeInsets.bottom = 14 - setTitleColor(.white, for: .normal) - } - - override func tintColorDidChange() { - super.tintColorDidChange() - - backgroundColor = tintColor - } - - override func prepareForInterfaceBuilder() { - super.prepareForInterfaceBuilder() - - tintColor = .blue - tintColorDidChange() - } - - override var isHighlighted: Bool { - didSet { - alpha = isHighlighted ? 0.5 : 1 - } - } - - override var isEnabled: Bool { - didSet { - tintAdjustmentMode = isEnabled ? .automatic : .dimmed - } - } -} diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Views/ParagraphView.swift b/Dependencies/CGMBLEKit/ResetTransmitter/Views/ParagraphView.swift deleted file mode 100644 index d51a6818c..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/Views/ParagraphView.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// ParagraphView.swift -// ResetTransmitter -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - -class ParagraphView: UITextView { - - override func awakeFromNib() { - super.awakeFromNib() - - textContainer.lineFragmentPadding = 0 - - let paragraphStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle - paragraphStyle.paragraphSpacing = 10 - - attributedText = NSAttributedString( - string: text, - attributes: [ - .paragraphStyle: paragraphStyle, - .font: UIFont.preferredFont(forTextStyle: .body) - ] - ) - } - -} diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/Views/TextField.swift b/Dependencies/CGMBLEKit/ResetTransmitter/Views/TextField.swift deleted file mode 100644 index f57695efb..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/Views/TextField.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// TextField.swift -// ResetTransmitter -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - -class TextField: UITextField { - - private let textInset = UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0) - - override func editingRect(forBounds bounds: CGRect) -> CGRect { - return bounds.inset(by: textInset) - } - - override func textRect(forBounds bounds: CGRect) -> CGRect { - return bounds.inset(by: textInset) - } - - override func placeholderRect(forBounds bounds: CGRect) -> CGRect { - return bounds.inset(by: textInset) - } - -} diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/ar.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/ar.lproj/Localizable.strings deleted file mode 100644 index 3bff73093..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/ar.lproj/Localizable.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Title of button to cancel reset */ -"Cancel" = "إلغاء"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/cs.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/cs.lproj/Localizable.strings deleted file mode 100644 index d510fc10d..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/cs.lproj/Localizable.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Title of button to cancel reset */ -"Cancel" = "Zrušit"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/da.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/da.lproj/InfoPlist.strings deleted file mode 100644 index 9f338c04f..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/da.lproj/InfoPlist.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Nulstil"; - -/* Bundle name */ -"CFBundleName" = "NulstilSender"; - -/* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "Bluetooth bliver brugt til at kommunikere med din insulinpumpe og din blodsukkermonitor"; - -/* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "Bluetooth bliver brugt til at kommunikere med din insulinpumpe og din blodsukkermonitor"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/da.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/da.lproj/Localizable.strings deleted file mode 100644 index 3a231b53c..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/da.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Er du sikker på, at du vil nulstille denne sender?"; - -/* Title of button to cancel reset */ -"Cancel" = "Annuller"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Det vil tage op til 10 minutter at gennemføre."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Nulstil"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Nulstilling af senderen er fuldført"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/da.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/da.lproj/Main.strings deleted file mode 100644 index bc5b2196d..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/da.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Nulstil fuldført"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Nulstil senderen"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "Dette værktøj kan nulstille uret på en sender, der har nået sin udløbsdato, så det kan starte nye sensorsessioner.\nDette kan have utilsigtede konsekvenser for datatjenester, som f.eks. Dexcom Clarity og Dexcom Share, især når du bruger en nulstillet sender med det samme konto.\nGenindstilling kan ikke fortrydes.\nBenyttes på egen risiko."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Indtast det 6-cifrede ID"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Fejl optræder her. Og det kan blive meget langt, og det er OK]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Nulstil"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "Senderen er nulstillet. Tilslut til appen for at begynde en ny sensorsession."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "Sender ID"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/de.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/de.lproj/InfoPlist.strings deleted file mode 100644 index 97ceaac90..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/de.lproj/InfoPlist.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Reset"; - -/* Bundle name */ -"CFBundleName" = "ResetTransmitter"; - -/* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "Bluetooth wird verwendet für die Kommunikation mit CGM-Geräten"; - -/* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "Bluetooth wird verwendet für die Kommunikation mit CGM-Geräten"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/de.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/de.lproj/Localizable.strings deleted file mode 100644 index 04be07ed8..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/de.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Möchten Sie das CGM wirklich löschen?"; - -/* Title of button to cancel reset */ -"Cancel" = "Abbrechen"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Der Vorgang kann bis zu 10 Minuten dauern."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Reset"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "TZurücksetzen des Transmitters abgeschlossen"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/de.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/de.lproj/Main.strings deleted file mode 100644 index 81a8b84de..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/de.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Zurücksetzen abgeschlossen"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Transmitter zurücksetzen"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "TMit diesem Tool kann ein Transmitter, dessen Ablaufdatum erreicht ist, zurückgesetzt werden, sodass Sensorsitzungen erneut gestartet werden können.\nDies kann unbeabsichtigte Konsequenzen für Datendienste wie Clarity und Share haben, insbesondere wenn ein zurückgesetzter Transmitter mit demselben Konto verwendet wird.\nDas Zurücksetzen kann nicht rückgängig gemacht werden.\nBenutzung auf eigene Gefahr!"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Geben Sie die 6-stellige ID ein"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Error goes here. And it can get very long and that's OK]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Reset"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "Der Transmitter wurde erfolgreich zurückgesetzt. Verbinden Sie ihn mit der App, um eine neue Sensorsitzung zu starten."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "Transmitter-ID"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/en.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/en.lproj/Localizable.strings deleted file mode 100644 index db64ce8a9..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/en.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Are you sure you want to reset this transmitter?"; - -/* Title of button to cancel reset */ -"Cancel" = "Cancel"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "It will take up to 10 minutes to complete."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Reset"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Transmitter Reset Complete"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/en.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/en.lproj/Main.strings deleted file mode 100644 index 67b6c4e60..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/en.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ - -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Reset Complete"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Reset Transmitter"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Enter the 6-digit ID"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Reset"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Error goes here. And it can get very long and that's OK]"; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "Transmitter ID"; diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/es.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/es.lproj/InfoPlist.strings deleted file mode 100644 index 22d32822b..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/es.lproj/InfoPlist.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Reiniciar"; - -/* Bundle name */ -"CFBundleName" = "Resetear Transmisor"; - -/* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "El bluetooth se utiliza para la comunicación con dispositivos de monitoreo continuo de glucosa"; - -/* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "El bluetooth se utiliza para la comunicación con dispositivos de monitoreo continuo de glucosa"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/es.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/es.lproj/Localizable.strings deleted file mode 100644 index f02454953..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/es.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "¿Está usted seguro de querer reiniciar este transmisor?"; - -/* Title of button to cancel reset */ -"Cancel" = "Cancelar"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Puede tardar en completarse hasta 10 minutos."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Reiniciar"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Reinicio del transmisor completado"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/es.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/es.lproj/Main.strings deleted file mode 100644 index 37f955b03..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/es.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Reinicio completado"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Reiniciar el transmisor"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "Esta herramienta puede reiniciar el reloj de un transmisor que ha caducado y permite comenzar una nueva sesión de funcionamiento en el sensor.\nEsto puede tener consecuencias inintencionadas con los servidores de datos como Clarity o Share, especialmente si se usa un transmisor reiniciado con la misma cuenta.\nUna vez reiniciado, no se puede volver atrás.\nÚselo bajo su propio riesgo."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Introduzca la identificación de 6 cifras"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[El error se localiza aquí. Puede ser muy largo, pero no importa]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Reiniciar"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "El transmisor se ha reiniciado con éxito. Conéctelo a la app para empezar una sesión nueva del sensor."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "Identificación del transmisor"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/fi.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/fi.lproj/InfoPlist.strings deleted file mode 100644 index 6b1c385c4..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/fi.lproj/InfoPlist.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Nollaa"; - -/* Bundle name */ -"CFBundleName" = "ResetTransmitter"; - -/* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "Bluetoothia käytetään kommunikointiin glukoosinseurantalaitteiden kanssa."; - -/* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "Bluetoothia käytetään kommunikointiin glukoosinseurantalaitteiden kanssa."; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/fi.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/fi.lproj/Localizable.strings deleted file mode 100644 index b296ca434..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/fi.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Haluatko varmasti nollata lähettimen?"; - -/* Title of button to cancel reset */ -"Cancel" = "Kumoa"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Valmistuminen voi kestää 10 minuuttia."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Nollaa"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Lähettimen nollaus valmis"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/fi.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/fi.lproj/Main.strings deleted file mode 100644 index 211e31662..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/fi.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Nollaus valmis"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Nollaa lähetin"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "Tämä työkalu nollaa kellon vanhentuneessa lähettimessä mahdollistaen lähettimen käytön jatkamisen.\n \n Nollauksella voi olla odottamattomia seurauksia esimerkiksi Clarity- ja Share-palveluihin, erityisesti, kun nollattua lähetintä käytetään samalla käyttäjätilillä.\n Nollausta ei voi perua.\n Käytä omalla vastuullasi."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Syötä 6-numeroinen tunniste"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Virhe tulee tähän. Se voi olla hyvin pitkä ja se on OK]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Nollaa"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "Lähettimen nollaus onnistui. Yhdistä se sovellukseen ja aloita uusi sensorin sessio."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "Lähettimen tunniste"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/fr.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/fr.lproj/InfoPlist.strings deleted file mode 100644 index e00546126..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/fr.lproj/InfoPlist.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Réinitialiser"; - -/* Bundle name */ -"CFBundleName" = "ResetTransmitter"; - -/* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "Bluetooth est utilisé pour communiquer avec les dispositifs de surveillance continue du glucose."; - -/* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "Bluetooth est utilisé pour communiquer avec les dispositifs de surveillance continue du glucose."; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/fr.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/fr.lproj/Localizable.strings deleted file mode 100644 index d911e447a..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/fr.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Voulez-vous vraiment réinitialiser ce transmetteur?"; - -/* Title of button to cancel reset */ -"Cancel" = "Annuler"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Cela prendra jusqu’à 10 minutes pour terminer."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Réinitialiser"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Réinitialisation du transmetteur terminée"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/fr.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/fr.lproj/Main.strings deleted file mode 100644 index 9c503d994..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/fr.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Réinitialisation terminée"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Réinitialiser le transmetteur"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "Cet outil peut réinitialiser l’horloge interne d’un transmetteur qui a atteint sa date de péremption, permettant de l’utiliser à nouveau.\nCeci pourrait avoir des conséquences involontaires pour des services de données, comme Clarity et Share, surtout en utilisant un transmetteur réinitialisé avec le même compte.\nLa réinitialisation est définitive.\nVous utilisez cette fonctionnalité à vos propres risques.."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Entrez l’ID, composé de 6 lettres et chiffres"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[L’erreur se place ici. Elle peut être très longue, ce n’est pas embêtant.]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Réinitialiser"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "La réinitialisation du transmetteur a réussi. Connectez-le à l’application mobile pour commencer une nouvelle session de capteur."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "ID du transmetteur"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/he.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/he.lproj/InfoPlist.strings deleted file mode 100644 index a9bface77..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/he.lproj/InfoPlist.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Reset"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/he.lproj/LaunchScreen.strings b/Dependencies/CGMBLEKit/ResetTransmitter/he.lproj/LaunchScreen.strings deleted file mode 100644 index 8b1378917..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/he.lproj/LaunchScreen.strings +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/he.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/he.lproj/Localizable.strings deleted file mode 100644 index db64ce8a9..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/he.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Are you sure you want to reset this transmitter?"; - -/* Title of button to cancel reset */ -"Cancel" = "Cancel"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "It will take up to 10 minutes to complete."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Reset"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Transmitter Reset Complete"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/he.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/he.lproj/Main.strings deleted file mode 100644 index dfdc8bd60..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/he.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Reset Complete"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Reset Transmitter"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Enter the 6-digit ID"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Error goes here. And it can get very long and that's OK]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Reset"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "Transmitter ID"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/hi.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/hi.lproj/Localizable.strings deleted file mode 100644 index bc1817c5d..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/hi.lproj/Localizable.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Title of button to cancel reset */ -"Cancel" = "निरस्त"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/it.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/it.lproj/InfoPlist.strings deleted file mode 100644 index 38df0d9c8..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/it.lproj/InfoPlist.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Ripristina"; - -/* Bundle name */ -"CFBundleName" = "Resetta trasmettitore"; - -/* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "Il Bluetooth viene utilizzato per comunicare con i dispositivi di monitoraggio continuo del glucosio"; - -/* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "Il Bluetooth viene utilizzato per comunicare con i dispositivi di monitoraggio continuo del glucosio"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/it.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/it.lproj/Localizable.strings deleted file mode 100644 index 4d6ff62e3..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/it.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Sei sicuro di voler resettare questo trasmettitore?"; - -/* Title of button to cancel reset */ -"Cancel" = "Annulla"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "L’operazione richiederà circa 10 minuti."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Ripristina"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Ripristino trasmettitore completato"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/it.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/it.lproj/Main.strings deleted file mode 100644 index 85c6d672c..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/it.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Ripristino completato"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Ripristina trasmettitore"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "Questo strumento può ripristinare l'orologio di un trasmettitore che ha raggiunto la data di scadenza, consentendo di avviare nuove sessioni del sensore. Questo può avere effetti indesiderati su servizi di dati come Clarity e Share, soprattutto se il ripristino avviene con lo stesso account. Il ripristino non può essere annullato. Effettualo a tuo rischio e pericolo."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Inserisci ID a 6 cifre"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[L'errore va qui. Può essere molto lungo, ma va bene]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Ripristina"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "Il trasmettitore è stato ripristinato. Collegalo all’app per avviare una nuova sessione di misurazione."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "ID trasmettitore"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/ja.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/ja.lproj/InfoPlist.strings deleted file mode 100644 index 82343093e..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/ja.lproj/InfoPlist.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "リセット"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/ja.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/ja.lproj/Localizable.strings deleted file mode 100644 index 79ca0f80e..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/ja.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "この送信機をリセットしてもよろしいですか?"; - -/* Title of button to cancel reset */ -"Cancel" = "キャンセル"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "完了するまでに最大10分かかります。"; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "リセット"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "リセット完了"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/ja.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/ja.lproj/Main.strings deleted file mode 100644 index 5ec5e4f65..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/ja.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "リセット完了"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "トランスミッターをリセットする"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "このツールは、使用期限に達したトランスミッターの時刻をリセットし、新たにセンサーのセッションを始められるようにします。\nリセットされたトランスミッターを同じアカウントで使うときは特に、ClarityやShareなどのデータサービスに意図しない影響を及ぼすことがあります。\nリセットは元に戻すことができません。\nご自身の責任で使用してください。"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "6桁のトランスミッタIDを入力"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Error goes here. And it can get very long and that's OK]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "リセット"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "トランスミッターのリセットが完了しました。新たにセンサーのセッションを始めるにはアプリを接続してください。"; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "トランスミッタ ID"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/nb.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/nb.lproj/InfoPlist.strings deleted file mode 100644 index 0673c068b..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/nb.lproj/InfoPlist.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Nullstille"; - -/* Bundle name */ -"CFBundleName" = "ResetTransmitter"; - -/* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "Bluetooth brukes til å kommunisere med kontinuerlige blodsukker monitorenheter"; - -/* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "Bluetooth brukes til å kommunisere med kontinuerlige blodsukker monitorenheter"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/nb.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/nb.lproj/Localizable.strings deleted file mode 100644 index 512d4b918..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/nb.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Er du sikker på at du vil nullstille denne senderen?"; - -/* Title of button to cancel reset */ -"Cancel" = "Avbryt"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Det kan ta opptil 10 minutter å gjennomføre."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Nullstille"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Nullstilling av sender er ferdig"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/nb.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/nb.lproj/Main.strings deleted file mode 100644 index 4cd87cf6f..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/nb.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Nullstilling Ferdig"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Nullstill Sender"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "Dette verktøyet kan nullstille klokken på en sender som har gått ut på dato, slik at senderen kan brukes på nytt. Dette kan ha uante konsekvenser for eksterne data-tjenester, som Clarity og Share, og spesielt om sender brukes igjen med samme konto. Nullstilling kan ikke angres. Bruk på egen risiko."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Skriv inn 6-siffret ID"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Feil skrives her. Den kan være veldig lang, og det er helt greit]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Nullstille"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "Sender er nå nullstillt. Koble den til appen for å starte en ny sensorøkt."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "Sender ID"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/nl.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/nl.lproj/InfoPlist.strings deleted file mode 100644 index d422d5cdf..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/nl.lproj/InfoPlist.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Reset"; - -/* Bundle name */ -"CFBundleName" = "ResetZender"; - -/* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "Bluetooth wordt gebruikt om te communiceren met continue glucosemeters"; - -/* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "Bluetooth wordt gebruikt om te communiceren met continue glucosemeters"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/nl.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/nl.lproj/Localizable.strings deleted file mode 100644 index 1ef84da95..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/nl.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Weet je zeker dat je deze zender wilt resetten?"; - -/* Title of button to cancel reset */ -"Cancel" = "Annuleer"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Voltooiing kan tot 10 minuten duren."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Reset"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Reset Zender Compleet"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/nl.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/nl.lproj/Main.strings deleted file mode 100644 index edd6a6494..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/nl.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Reset Compleet"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Reset Zender"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "Deze methode kan de klok van de zender resetten als de vervaldatum is bereikt, zodat een nieuwe sensorsessie gestart kan worden.\nDit heeft mogelijk onbedoelde gevolgen voor services als Clarity en Share. Met name als hetzelfde account wordt gebruikt om een zender te resetten.\nResetten kan niet ongedaan gemaakt worden.\nGebruik op eigen risico"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Vul de 6 cijferige ID in"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Hier komt de foutmelding. Deze kan erg lang zijn en dat is OK]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Reset"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "De zender is succesvol gereset. Verbind de zender met de app om een nieuwe sensorsessie te beginnen."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "Zenderserienummer"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/pl.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/pl.lproj/InfoPlist.strings deleted file mode 100644 index 14730691c..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/pl.lproj/InfoPlist.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Resetuj"; - -/* Bundle name */ -"CFBundleName" = "Zresetuj transmiter"; - -/* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "Bluetooth służy do komunikacji z urządzeniami do ciągłego monitorowania glukozy"; - -/* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "Bluetooth służy do komunikacji z urządzeniami do ciągłego monitorowania glukozy"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/pl.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/pl.lproj/Localizable.strings deleted file mode 100644 index be844db5a..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/pl.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Czy na pewno chcesz zresetować ten nadajnik?"; - -/* Title of button to cancel reset */ -"Cancel" = "Anuluj"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Procedura zajmie do 10 minut."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Resetuj"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Resetowanie nadajnika zakończone"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/pl.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/pl.lproj/Main.strings deleted file mode 100644 index 130fae1f7..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/pl.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Resetowanie zakończone"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Zresetuj nadajnik"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "To narzędzie może zresetować zegar nadajnika, który osiągnął termin ważności, umożliwiając ponowne rozpoczęcie sesji sensora. Może to mieć niepożądane konsekwencje dla usług danych, takich jak Clarity i Share, zwłaszcza w przypadku użytkowania zresetowanego nadajnika z tym samym kontem. Resetowania nie można cofnąć. Wykonujesz je na własne ryzyko."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Wprowadź 6-cyfrowy ID"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Oto błąd. Jego treść może być bardzo długa i to normalne]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Resetuj"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "Nadajnik został skutecznie zresetowany. Podłącz go do apliakcji, aby rozpocząć nową sesję sensora."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "ID nadajnika"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/pt-BR.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/pt-BR.lproj/InfoPlist.strings deleted file mode 100644 index 8c502bc76..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/pt-BR.lproj/InfoPlist.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Restabelecer"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/pt-BR.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/pt-BR.lproj/Localizable.strings deleted file mode 100644 index 66afc957a..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Tem certeza de que deseja redefinir este transmissor?"; - -/* Title of button to cancel reset */ -"Cancel" = "Cancelar"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Levará 10 minutos para concluir."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Restabelecer"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Redefinição do Transmissor Concluída"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/pt-BR.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/pt-BR.lproj/Main.strings deleted file mode 100644 index 367b469f8..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/pt-BR.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Redefinição Concluída"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Redefinir Transmissor"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "Esta ferramenta pode redefinir o relógio em um transmissor que atingiu sua data de validade, permitindo que novas sessões de sensor sejam iniciadas novamente.\n Isso pode ter consequências indesejadas para serviços de dados, como Clarity e Share, especialmente ao usar um transmissor redefinido com a mesmo conta.\n A redefinição não pode ser desfeita.\n Use por sua conta e risco."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Digite o ID de 6 dígitos"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Erro aqui. E pode demorar muito mas tudo bem]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Restabelecer"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "O transmissor foi redefinido com sucesso. Conecte-o ao aplicativo para iniciar uma nova sessão de sensor."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "ID do Transmissor"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/ro.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/ro.lproj/InfoPlist.strings deleted file mode 100644 index e828ab423..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/ro.lproj/InfoPlist.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Resetare"; - -/* Bundle name */ -"CFBundleName" = "ResetTransmitter"; - -/* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "Bluetooth este utilizat pentru a comunica cu dispozitivele de monitorizare continuă a glicemiei"; - -/* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "Bluetooth este utilizat pentru a comunica cu dispozitivele de monitorizare continuă a glicemiei"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/ro.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/ro.lproj/Localizable.strings deleted file mode 100644 index 0cfa490ee..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/ro.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Sigur doriți să resetați acest transmițător?"; - -/* Title of button to cancel reset */ -"Cancel" = "Renunță"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Vor fi necesare maxim 10 minute pentru finalizare"; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Resetare"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Resetare transmițător finalizată"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/ro.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/ro.lproj/Main.strings deleted file mode 100644 index 03476dc05..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/ro.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Resetare finalizată"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Resetare transmițător"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "Acest utilitar poate reseta ceasul dintr-un transmițător ce a depășit data de expirare, permițând pornirea unor noi sesiuni de senzor.\nResetarea poate cauza consecințe nedorite pentru serviciile care colectează date, cum ar fi Clarity sau Share, în special când utilizați un transmițător resetat cu același cont.\nResetarea nu poate fi anulată.\nA se utiliza pe proprie răspundere."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Introduceți ID-ul din 6 cifre"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Eroarea apare aici. Și poate fi foarte lungă și suntem OK cu asta]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Resetare"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "Transmițătorul a fost resetat cu succes. Conectați-l la aplicație pentru a porni o nouă sesiune de senzor."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "ID transmițător"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/ru.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/ru.lproj/InfoPlist.strings deleted file mode 100644 index 7146f1d88..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/ru.lproj/InfoPlist.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Сброс"; - -/* Bundle name */ -"CFBundleName" = "ResetTransmitter"; - -/* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "Bluetooth используется для связи с устройствами непрерывного мониторинга глюкозы"; - -/* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "Bluetooth используется для связи с устройствами непрерывного мониторинга глюкозы"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/ru.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/ru.lproj/Localizable.strings deleted file mode 100644 index d2e7cb8f2..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/ru.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Вы уверены, что хотите сбросить этот трансмиттер?"; - -/* Title of button to cancel reset */ -"Cancel" = "Отмена"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Может занять до десяти минут."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Сброс"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Сброс данных трансмиттера завершен"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/ru.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/ru.lproj/Main.strings deleted file mode 100644 index 42ec97366..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/ru.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Сброс завершен"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Сбросить трансмиттер"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "Этот инструмент поможет сбросить счетчик времени на трансмиттере, достигшем окончания срока работы. Может повлечь непреднамеренные последствия в службах сбора данных Clarity и Share, особенно при использовании трансмиттера с той же учетной записью. Сброс отменить невозможно. Пользуйтесь на свой риск."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Введите шестизначный идентификатор"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Ошибка здесь. И это может быть очень долго, и это нормально]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Сброс"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "Трансмиттер успешно сброшен. Подключите его к родному приложению, чтобы запустить новый сенсор."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "ID трансмиттера"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/sk.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/sk.lproj/InfoPlist.strings deleted file mode 100644 index 8b22dfaf2..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/sk.lproj/InfoPlist.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Resetovať"; - -/* Bundle name */ -"CFBundleName" = "ResetovaťVysielač"; - -/* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "Bluetooth sa používa na komunikáciu so zariadeniami pre kontinuálne snímanie glykémie."; - -/* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "Bluetooth sa používa na komunikáciu so zariadeniami pre kontinuálne snímanie glykémie."; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/sk.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/sk.lproj/Localizable.strings deleted file mode 100644 index 9c38268df..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/sk.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Naozaj chcete resetovať tento vysielač?"; - -/* Title of button to cancel reset */ -"Cancel" = "Zrušiť"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Dokončenie bude trvať do 10 minút."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Resetovať"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Resetovanie vysielača je dokončené"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/sk.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/sk.lproj/Main.strings deleted file mode 100644 index d3a973ef6..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/sk.lproj/Main.strings +++ /dev/null @@ -1,21 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Obnovenie dokončené"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Resetovať vysielač"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "Tento nástroj môže resetovať hodiny na vysielači, ktorý dosiahol dátum vypršania platnosti, čo umožňuje opätovné spustenie nových relácií senzora.\nTo môže mať neželané dôsledky pre dátové služby, ako je Clarity a Share, najmä ak používate resetovaný vysielač s rovnakým účtom.\nResetovanie sa nedá vrátiť späť.\nPoužitie na vlastné riziko."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Zadajte 6-miestne ID"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Resetovať"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "Vysielač bol úspešne resetovaný. Pripojte ho k aplikácii a začnite novú reláciu senzora."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "ID vysielača"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/sv.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/sv.lproj/InfoPlist.strings deleted file mode 100644 index c4012d222..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/sv.lproj/InfoPlist.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Återställ"; - -/* Bundle name */ -"CFBundleName" = "ResetTransmitter"; - -/* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "Bluetooth används för kommunikation med kontinuerliga blodglukosmätare"; - -/* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "Bluetooth används för kommunikation med kontinuerliga blodglukosmätare"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/sv.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/sv.lproj/Localizable.strings deleted file mode 100644 index c0790a14f..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/sv.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Är du säker på att du vill återställa denna sändare?"; - -/* Title of button to cancel reset */ -"Cancel" = "Avbryt"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Det kan ta upp till 10 minuter innan allt är återställt."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Återställ"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Återställning av sändaren är nu genomförd"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/sv.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/sv.lproj/Main.strings deleted file mode 100644 index 592c3df1c..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/sv.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Återställning färdig"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Återställ sändare"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "Detta verktyg kan återställa klockan på en sändare som har nått sitt utgångsdatum, därigenom tillåta att en ny sensor kan startas. Detta kan få oväntade följder för tjänster som hanterar datan, t.ex. Clarity och Share, speciellt när man använder en återställd sändare med samma konto. Återställning kan inte ångras."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Ange ditt 6-siffriga sändar-ID"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Här står felen. Och det kan bli väldigt långt, vilket är OK]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Återställ"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "Sändaren har blivit återställd. Anslut den till appen för att börja ny session."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "Sändari-ID"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/tr.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/tr.lproj/InfoPlist.strings deleted file mode 100644 index 099a9ff65..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/tr.lproj/InfoPlist.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Sıfırla"; - -/* Bundle name */ -"CFBundleName" = "Vericiyi Sıfırla"; - -/* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "Bluetooth, sürekli glikoz izleme cihazlarıyla iletişim kurmak için kullanılır"; - -/* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "Bluetooth, sürekli glikoz izleme cihazlarıyla iletişim kurmak için kullanılır"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/tr.lproj/LaunchScreen.strings b/Dependencies/CGMBLEKit/ResetTransmitter/tr.lproj/LaunchScreen.strings deleted file mode 100644 index 8b1378917..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/tr.lproj/LaunchScreen.strings +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/tr.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/tr.lproj/Localizable.strings deleted file mode 100644 index f986051c5..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/tr.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Bu vericiyi sıfırlamak istediğinizden emin misiniz?"; - -/* Title of button to cancel reset */ -"Cancel" = "İptal"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Tamamlanması 10 dakika kadar sürecektir."; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Sıfırla"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Verici Sıfırlama Tamamlandı"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/tr.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/tr.lproj/Main.strings deleted file mode 100644 index e3b51e152..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/tr.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Sıfırlama Tamamlandı"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Vericiyi Sıfırla"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "Bu araç, son kullanma tarihine ulaşmış bir vericideki saati sıfırlayarak yeni sensör oturumlarının yeniden başlatılmasını sağlayabilir.\nÖzellikle aynı hesapla, sıfırlanan bir verici kullanıldığında, Clarity ve Share gibi veri hizmetleri için istenmeyen sonuçları olabilir.\nSıfırlama geri alınamaz.\nKullanımı kendi sorumluluğunuzdadır."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "6 basamaklı kimliği girin"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Hata buraya gider. Ve çok uzun olabilir ve sorun değil]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Sıfırla"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "Verici başarıyla sıfırlandı. Yeni bir sensör oturumu başlatmak için uygulamaya bağlayın."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "Verici Kimliği"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/vi.lproj/InfoPlist.strings b/Dependencies/CGMBLEKit/ResetTransmitter/vi.lproj/InfoPlist.strings deleted file mode 100644 index 887b25478..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/vi.lproj/InfoPlist.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Khôi phục lại"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/vi.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/vi.lproj/Localizable.strings deleted file mode 100644 index ac0eb33d1..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/vi.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "Bạn có chắc muốn cài lại transmitter này không?"; - -/* Title of button to cancel reset */ -"Cancel" = "Hủy bỏ"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "Cần 10 phút để hoàn thành công việc"; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "Khôi phục lại"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "Cài lại Transmitter hoàn tất"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/vi.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/vi.lproj/Main.strings deleted file mode 100644 index 326e317ad..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/vi.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "Cài lại hoàn tất"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "Cài lại Transmitter"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "Tác vụ này có thể đảo ngược đồng hồ trên transmitter khi đến ngày hết hạn và cho phép tiếp tục sử dụng sensor mới.\nĐiều này có thể có hậu quả không lường được đối với các dịch vụ về dữ liệu ví dụ như trên ứng dụng Clarity và Share, đặc biệt là khi thực hiện việc cài lại transmitter mà sử dụng cùng một tài khoản.\nViệc cài đặt không thể được thực hiện.\nBạn tự chịu mọi rủi ro."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "Nhập 6 số ID"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[Lỗi ở đây. Và có thể mất nhiều thời gian nhưng sẽ ổn thôi]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "Khôi phục lại"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "Việc cài lại Transmitter đã hoàn tất. Kết nối với ứng dụng để bắt đầu khởi động sensor."; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "Số ID của Transmitter"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/zh-Hans.lproj/Localizable.strings b/Dependencies/CGMBLEKit/ResetTransmitter/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 770ca160c..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,16 +0,0 @@ -/* Title of the reset confirmation sheet */ -"Are you sure you want to reset this transmitter?" = "确定要重置发射器么"; - -/* Title of button to cancel reset */ -"Cancel" = "取消"; - -/* Message of the reset confirmation sheet */ -"It will take up to 10 minutes to complete." = "该操作可能需要10分钟"; - -/* Reset button title - Title of button to begin reset */ -"Reset" = "重置"; - -/* Notification title for background completion notification */ -"Transmitter Reset Complete" = "发射器已重置"; - diff --git a/Dependencies/CGMBLEKit/ResetTransmitter/zh-Hans.lproj/Main.strings b/Dependencies/CGMBLEKit/ResetTransmitter/zh-Hans.lproj/Main.strings deleted file mode 100644 index e4a62c671..000000000 --- a/Dependencies/CGMBLEKit/ResetTransmitter/zh-Hans.lproj/Main.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UINavigationItem"; title = "Reset Complete"; ObjectID = "3SD-s3-7OM"; */ -"3SD-s3-7OM.title" = "重置已完成"; - -/* Class = "UINavigationItem"; title = "Reset Transmitter"; ObjectID = "7nc-6t-4hZ"; */ -"7nc-6t-4hZ.title" = "重置发射器"; - -/* Class = "UITextView"; text = "This tool can reset the clock on a transmitter that has reached its expiration date, allowing new sensor sessions to again be started.\nThis may have unintended consequences for data services, such as Clarity and Share, especially when using a reset transmitter with the same account.\nResetting cannot be undone.\nUse at your own risk."; ObjectID = "cJ3-Gc-pnc"; */ -"cJ3-Gc-pnc.text" = "该操作将会把发射器使用时间清零,此后可以继续重新启动传感器.这可能会导致Dexcom远程数据故障,尤其是使用同一个Dexcom账户上传数据.重置可能会失败,请自行承担相关风险"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit ID"; ObjectID = "G4a-ia-wQC"; */ -"G4a-ia-wQC.placeholder" = "输入6位数字编号"; - -/* Class = "UILabel"; text = "[Error goes here. And it can get very long and that's OK]"; ObjectID = "gYy-Zz-y12"; */ -"gYy-Zz-y12.text" = "[发生错误,请耐心等待]"; - -/* Class = "UIButton"; normalTitle = "Reset"; ObjectID = "LBC-6R-q79"; */ -"LBC-6R-q79.normalTitle" = "重置"; - -/* Class = "UITextView"; text = "The transmitter has been successfully reset. Connect it to the app to begin a new sensor session."; ObjectID = "MbK-kj-ejl"; */ -"MbK-kj-ejl.text" = "发射器已重置,请重新连接,并启动传感器"; - -/* Class = "UITableViewSection"; headerTitle = "Transmitter ID"; ObjectID = "vNG-r7-RbP"; */ -"vNG-r7-RbP.headerTitle" = "发射器编号"; - diff --git a/Dependencies/G7SensorKit/.gitignore b/Dependencies/G7SensorKit/.gitignore deleted file mode 100644 index 72baa4591..000000000 --- a/Dependencies/G7SensorKit/.gitignore +++ /dev/null @@ -1,91 +0,0 @@ -# Xcode -# -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore -.DS_Store - -## User settings -xcuserdata/ - -## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) -*.xcscmblueprint -*.xccheckout - -## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) -build/ -DerivedData/ -*.moved-aside -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 - -## Obj-C/Swift specific -*.hmap - -## App packaging -*.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 -# *.xcodeproj -# -# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata -# hence it is not needed unless you have added a package configuration file to your project -# .swiftpm - -.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/Dependencies/G7SensorKit/Common/Data.swift b/Dependencies/G7SensorKit/Common/Data.swift deleted file mode 100644 index a7587d651..000000000 --- a/Dependencies/G7SensorKit/Common/Data.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// NSData.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 3/5/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension Data { - private func toDefaultEndian(_: T.Type) -> T { - return self.withUnsafeBytes({ (rawBufferPointer: UnsafeRawBufferPointer) -> T in - let bufferPointer = rawBufferPointer.bindMemory(to: T.self) - guard let pointer = bufferPointer.baseAddress else { - return 0 - } - return T(pointer.pointee) - }) - } - - func to(_ type: T.Type) -> T { - return T(littleEndian: toDefaultEndian(type)) - } - - func toInt() -> T { - return to(T.self) - } - - func toBigEndian(_ type: T.Type) -> T { - return T(bigEndian: toDefaultEndian(type)) - } - - mutating func append(_ newElement: T) { - withUnsafePointer(to: newElement.littleEndian) { (ptr: UnsafePointer) in - append(UnsafeBufferPointer(start: ptr, count: 1)) - } - } - - mutating func appendBigEndian(_ newElement: T) { - withUnsafePointer(to: newElement.bigEndian) { (ptr: UnsafePointer) in - append(UnsafeBufferPointer(start: ptr, count: 1)) - } - } - - init(_ value: T) { - self = withUnsafePointer(to: value.littleEndian) { (ptr: UnsafePointer) -> Data in - return Data(buffer: UnsafeBufferPointer(start: ptr, count: 1)) - } - } - - init(bigEndian value: T) { - self = withUnsafePointer(to: value.bigEndian) { (ptr: UnsafePointer) -> Data in - return Data(buffer: UnsafeBufferPointer(start: ptr, count: 1)) - } - } -} - - -// String conversion methods, adapted from https://stackoverflow.com/questions/40276322/hex-binary-string-conversion-in-swift/40278391#40278391 -extension Data { - init?(hexadecimalString: String) { - self.init(capacity: hexadecimalString.utf16.count / 2) - - // Convert 0 ... 9, a ... f, A ...F to their decimal value, - // return nil for all other input characters - func decodeNibble(u: UInt16) -> UInt8? { - switch u { - case 0x30 ... 0x39: // '0'-'9' - return UInt8(u - 0x30) - case 0x41 ... 0x46: // 'A'-'F' - return UInt8(u - 0x41 + 10) // 10 since 'A' is 10, not 0 - case 0x61 ... 0x66: // 'a'-'f' - return UInt8(u - 0x61 + 10) // 10 since 'a' is 10, not 0 - default: - return nil - } - } - - var even = true - var byte: UInt8 = 0 - for c in hexadecimalString.utf16 { - guard let val = decodeNibble(u: c) else { return nil } - if even { - byte = val << 4 - } else { - byte += val - self.append(byte) - } - even = !even - } - guard even else { return nil } - } - - var hexadecimalString: String { - return map { String(format: "%02hhx", $0) }.joined() - } -} diff --git a/Dependencies/G7SensorKit/Common/HKUnit.swift b/Dependencies/G7SensorKit/Common/HKUnit.swift deleted file mode 100644 index 69e6f9aed..000000000 --- a/Dependencies/G7SensorKit/Common/HKUnit.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// HKUnit.swift -// xDripG5 -// -// Created by Nate Racklyeft on 8/6/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -extension HKUnit { - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: HKUnit.literUnit(with: .deci)) - }() - - static let milligramsPerDeciliterPerMinute: HKUnit = { - return HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) - }() -} diff --git a/Dependencies/G7SensorKit/Common/LocalizedString.swift b/Dependencies/G7SensorKit/Common/LocalizedString.swift deleted file mode 100644 index 831ab950f..000000000 --- a/Dependencies/G7SensorKit/Common/LocalizedString.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// LocalizedString.swift -// LoopUI -// -// Created by Kathryn DiSimone on 8/15/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -internal class FrameworkBundle { - static let main = Bundle(for: FrameworkBundle.self) -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: FrameworkBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: FrameworkBundle.main, comment: comment) - } -} diff --git a/Dependencies/G7SensorKit/Common/Locked.swift b/Dependencies/G7SensorKit/Common/Locked.swift deleted file mode 100644 index fd6e35b10..000000000 --- a/Dependencies/G7SensorKit/Common/Locked.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// Locked.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import os.lock - - -internal class Locked { - private var lock = os_unfair_lock() - private var _value: T - - init(_ value: T) { - os_unfair_lock_lock(&lock) - defer { os_unfair_lock_unlock(&lock) } - _value = value - } - - var value: T { - get { - os_unfair_lock_lock(&lock) - defer { os_unfair_lock_unlock(&lock) } - return _value - } - set { - os_unfair_lock_lock(&lock) - defer { os_unfair_lock_unlock(&lock) } - _value = newValue - } - } - - func mutate(_ changes: (_ value: inout T) -> Void) -> T { - os_unfair_lock_lock(&lock) - defer { os_unfair_lock_unlock(&lock) } - changes(&_value) - return _value - } -} diff --git a/Dependencies/G7SensorKit/Common/TimeInterval.swift b/Dependencies/G7SensorKit/Common/TimeInterval.swift deleted file mode 100644 index 5a8046a6c..000000000 --- a/Dependencies/G7SensorKit/Common/TimeInterval.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// NSTimeInterval.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension TimeInterval { - static func hours(_ hours: Double) -> TimeInterval { - return self.init(hours: hours) - } - - static func minutes(_ minutes: Int) -> TimeInterval { - return self.init(minutes: Double(minutes)) - } - - static func minutes(_ minutes: Double) -> TimeInterval { - return self.init(minutes: minutes) - } - - static func seconds(_ seconds: Double) -> TimeInterval { - return self.init(seconds) - } - - static func milliseconds(_ milliseconds: Double) -> TimeInterval { - return self.init(milliseconds / 1000) - } - - init(minutes: Double) { - self.init(minutes * 60) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - init(seconds: Double) { - self.init(seconds) - } - - init(milliseconds: Double) { - self.init(milliseconds / 1000) - } - - var milliseconds: Double { - return self * 1000 - } - - var minutes: Double { - return self / 60.0 - } - - var hours: Double { - return minutes / 60.0 - } - -} diff --git a/Dependencies/G7SensorKit/G7SensorKit.xcodeproj/project.pbxproj b/Dependencies/G7SensorKit/G7SensorKit.xcodeproj/project.pbxproj deleted file mode 100644 index 73d3df64d..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1193 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 56; - objects = { - -/* Begin PBXBuildFile section */ - C109F14A291ECCE2008EA5B6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C109F149291ECCE2008EA5B6 /* Assets.xcassets */; }; - C109F14C291ED66F008EA5B6 /* G7GlucoseMessageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C109F14B291ED66F008EA5B6 /* G7GlucoseMessageTests.swift */; }; - C139829829295D7D0047DB5F /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F514A291EB6F000555EB5 /* HKUnit.swift */; }; - C1409A07291EC21C006BE8D0 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5126291EAF2F00555EB5 /* OSLog.swift */; }; - C1409A09291EC22F006BE8D0 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1409A08291EC22F006BE8D0 /* OSLog.swift */; }; - C1409A0B291EC258006BE8D0 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1409A0A291EC258006BE8D0 /* OSLog.swift */; }; - C1409A0C291EC2F8006BE8D0 /* G7SensorKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C17F50C6291EAC3800555EB5 /* G7SensorKit.framework */; }; - C1409A0D291EC2F8006BE8D0 /* G7SensorKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C17F50C6291EAC3800555EB5 /* G7SensorKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - C1409A0F291EC2FB006BE8D0 /* G7SensorKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C17F50F8291EAC9100555EB5 /* G7SensorKitUI.framework */; }; - C1409A10291EC2FB006BE8D0 /* G7SensorKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C17F50F8291EAC9100555EB5 /* G7SensorKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - C17F50CF291EAC3800555EB5 /* G7SensorKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C17F50C6291EAC3800555EB5 /* G7SensorKit.framework */; }; - C17F50D4291EAC3800555EB5 /* G7SensorKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F50D3291EAC3800555EB5 /* G7SensorKitTests.swift */; }; - C17F50D5291EAC3800555EB5 /* G7SensorKit.h in Headers */ = {isa = PBXBuildFile; fileRef = C17F50C9291EAC3800555EB5 /* G7SensorKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C17F50E9291EAC6500555EB5 /* G7BackfillMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F50DF291EAC6500555EB5 /* G7BackfillMessage.swift */; }; - C17F50EA291EAC6500555EB5 /* G7DeviceStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F50E0291EAC6500555EB5 /* G7DeviceStatus.swift */; }; - C17F50EB291EAC6500555EB5 /* G7Sensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F50E1291EAC6500555EB5 /* G7Sensor.swift */; }; - C17F50EC291EAC6500555EB5 /* G7LastReading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F50E2291EAC6500555EB5 /* G7LastReading.swift */; }; - C17F50ED291EAC6500555EB5 /* G7Opcode.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F50E3291EAC6500555EB5 /* G7Opcode.swift */; }; - C17F50EE291EAC6500555EB5 /* G7PeripheralManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F50E4291EAC6500555EB5 /* G7PeripheralManager.swift */; }; - C17F50EF291EAC6500555EB5 /* G7CGMManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F50E5291EAC6500555EB5 /* G7CGMManager.swift */; }; - C17F50F0291EAC6500555EB5 /* G7CGMManagerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F50E6291EAC6500555EB5 /* G7CGMManagerState.swift */; }; - C17F50F1291EAC6500555EB5 /* G7BluetoothManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F50E7291EAC6500555EB5 /* G7BluetoothManager.swift */; }; - C17F50F2291EAC6500555EB5 /* G7GlucoseMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F50E8291EAC6500555EB5 /* G7GlucoseMessage.swift */; }; - C17F50FB291EAC9100555EB5 /* G7SensorKitUI.h in Headers */ = {isa = PBXBuildFile; fileRef = C17F50FA291EAC9100555EB5 /* G7SensorKitUI.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C17F5106291EAC9D00555EB5 /* G7SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5100291EAC9D00555EB5 /* G7SettingsViewModel.swift */; }; - C17F5107291EAC9D00555EB5 /* G7StartupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5101291EAC9D00555EB5 /* G7StartupView.swift */; }; - C17F5108291EAC9D00555EB5 /* G7SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5102291EAC9D00555EB5 /* G7SettingsView.swift */; }; - C17F5109291EAC9D00555EB5 /* G7CGMManager+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5103291EAC9D00555EB5 /* G7CGMManager+UI.swift */; }; - C17F510A291EAC9D00555EB5 /* G7UICoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5104291EAC9D00555EB5 /* G7UICoordinator.swift */; }; - C17F5120291EACCD00555EB5 /* G7SensorPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = C17F511F291EACCD00555EB5 /* G7SensorPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C17F5125291EACE400555EB5 /* G7SensorPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5124291EACE400555EB5 /* G7SensorPlugin.swift */; }; - C17F5135291EB06A00555EB5 /* AlgorithmState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5134291EB06A00555EB5 /* AlgorithmState.swift */; }; - C17F5138291EB0A800555EB5 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5137291EB0A800555EB5 /* Data.swift */; }; - C17F513A291EB0D900555EB5 /* GlucoseLimits.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5139291EB0D900555EB5 /* GlucoseLimits.swift */; }; - C17F513C291EB13D00555EB5 /* Locked.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F513B291EB13D00555EB5 /* Locked.swift */; }; - C17F513E291EB1A500555EB5 /* BluetoothServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F513D291EB1A500555EB5 /* BluetoothServices.swift */; }; - C17F5140291EB27D00555EB5 /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F513F291EB27D00555EB5 /* TimeInterval.swift */; }; - C17F5143291EB36700555EB5 /* AuthChallengeRxMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5142291EB36700555EB5 /* AuthChallengeRxMessage.swift */; }; - C17F5145291EB45900555EB5 /* CBPeripheral.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5144291EB45900555EB5 /* CBPeripheral.swift */; }; - C17F5147291EB57700555EB5 /* SensorMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5146291EB57700555EB5 /* SensorMessage.swift */; }; - C17F5149291EB6B600555EB5 /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5148291EB6B600555EB5 /* LocalizedString.swift */; }; - C17F514B291EB6F000555EB5 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F514A291EB6F000555EB5 /* HKUnit.swift */; }; - C17F514D291EB79E00555EB5 /* AlgorithmError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F514C291EB79E00555EB5 /* AlgorithmError.swift */; }; - C17F514F291EB87600555EB5 /* G7SensorKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C17F50C6291EAC3800555EB5 /* G7SensorKit.framework */; }; - C17F5156291EBD8600555EB5 /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F5155291EBD8600555EB5 /* Image.swift */; }; - C17F5157291EBD9900555EB5 /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F513F291EB27D00555EB5 /* TimeInterval.swift */; }; - C19C9F4529C9115B00A6D3D0 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C19C9F4729C9115B00A6D3D0 /* Localizable.strings */; }; - C19C9F4A29C9117500A6D3D0 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C19C9F4C29C9117500A6D3D0 /* Localizable.strings */; }; - C19C9F4E29C91C4C00A6D3D0 /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = C19C9F4D29C91C4C00A6D3D0 /* LocalizedString.swift */; }; - C1E71720292D84FE00DA646F /* G7ProgressBarState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E7171F292D84FE00DA646F /* G7ProgressBarState.swift */; }; - CEC751E129D8837D006E9D24 /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEC751E029D8837D006E9D24 /* LoopKitUI.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - C17F50D0291EAC3800555EB5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C17F50BD291EAC3800555EB5 /* Project object */; - proxyType = 1; - remoteGlobalIDString = C17F50C5291EAC3800555EB5; - remoteInfo = G7SensorKit; - }; - C17F512B291EAFA100555EB5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C17F50BD291EAC3800555EB5 /* Project object */; - proxyType = 1; - remoteGlobalIDString = C17F50C5291EAC3800555EB5; - remoteInfo = G7SensorKit; - }; - C17F512F291EAFA100555EB5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C17F50BD291EAC3800555EB5 /* Project object */; - proxyType = 1; - remoteGlobalIDString = C17F50F7291EAC9100555EB5; - remoteInfo = G7SensorKitUI; - }; - C17F5151291EB87600555EB5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C17F50BD291EAC3800555EB5 /* Project object */; - proxyType = 1; - remoteGlobalIDString = C17F50C5291EAC3800555EB5; - remoteInfo = G7SensorKit; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - C1409A0E291EC2F8006BE8D0 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - C1409A0D291EC2F8006BE8D0 /* G7SensorKit.framework in Embed Frameworks */, - C1409A10291EC2FB006BE8D0 /* G7SensorKitUI.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 193F1E3D2B44C18000525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; - 193F1E3E2B44C18100525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; - C1086B0E29C9169100D46E65 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - C1086B0F29C9169100D46E65 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - C109F149291ECCE2008EA5B6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - C109F14B291ED66F008EA5B6 /* G7GlucoseMessageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7GlucoseMessageTests.swift; sourceTree = ""; }; - C10A0FE529C91688006F4CD8 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - C10A0FE629C91688006F4CD8 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - C10A851B29C916A200EAE6B3 /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = ""; }; - C10A851C29C916A200EAE6B3 /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = ""; }; - C110930529C9169800AD9503 /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; - C110930629C9169800AD9503 /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; - C125E0C029C9168100AB13C5 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - C125E0C129C9168100AB13C5 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - C12E6F0729C9166900E6FDBE /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - C12E6F0829C9166900E6FDBE /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - C13C056529C916AA00ED3803 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - C13C056629C916AA00ED3803 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - C14091FA29C9167100ADD112 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - C14091FB29C9167100ADD112 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - C1409A08291EC22F006BE8D0 /* OSLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; - C1409A0A291EC258006BE8D0 /* OSLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; - C149257929C916B200F94598 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - C149257A29C916B200F94598 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - C14BF96629C916560055FA98 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; - C158585E29C916BA00EA08EA /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - C158585F29C916BA00EA08EA /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - C17F50C6291EAC3800555EB5 /* G7SensorKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = G7SensorKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C17F50C9291EAC3800555EB5 /* G7SensorKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = G7SensorKit.h; sourceTree = ""; }; - C17F50CE291EAC3800555EB5 /* G7SensorKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = G7SensorKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - C17F50D3291EAC3800555EB5 /* G7SensorKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = G7SensorKitTests.swift; sourceTree = ""; }; - C17F50DF291EAC6500555EB5 /* G7BackfillMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7BackfillMessage.swift; sourceTree = ""; }; - C17F50E0291EAC6500555EB5 /* G7DeviceStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7DeviceStatus.swift; sourceTree = ""; }; - C17F50E1291EAC6500555EB5 /* G7Sensor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7Sensor.swift; sourceTree = ""; }; - C17F50E2291EAC6500555EB5 /* G7LastReading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7LastReading.swift; sourceTree = ""; }; - C17F50E3291EAC6500555EB5 /* G7Opcode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7Opcode.swift; sourceTree = ""; }; - C17F50E4291EAC6500555EB5 /* G7PeripheralManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7PeripheralManager.swift; sourceTree = ""; }; - C17F50E5291EAC6500555EB5 /* G7CGMManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7CGMManager.swift; sourceTree = ""; }; - C17F50E6291EAC6500555EB5 /* G7CGMManagerState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7CGMManagerState.swift; sourceTree = ""; }; - C17F50E7291EAC6500555EB5 /* G7BluetoothManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7BluetoothManager.swift; sourceTree = ""; }; - C17F50E8291EAC6500555EB5 /* G7GlucoseMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7GlucoseMessage.swift; sourceTree = ""; }; - C17F50F8291EAC9100555EB5 /* G7SensorKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = G7SensorKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C17F50FA291EAC9100555EB5 /* G7SensorKitUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = G7SensorKitUI.h; sourceTree = ""; }; - C17F5100291EAC9D00555EB5 /* G7SettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7SettingsViewModel.swift; sourceTree = ""; }; - C17F5101291EAC9D00555EB5 /* G7StartupView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7StartupView.swift; sourceTree = ""; }; - C17F5102291EAC9D00555EB5 /* G7SettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7SettingsView.swift; sourceTree = ""; }; - C17F5103291EAC9D00555EB5 /* G7CGMManager+UI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "G7CGMManager+UI.swift"; sourceTree = ""; }; - C17F5104291EAC9D00555EB5 /* G7UICoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7UICoordinator.swift; sourceTree = ""; }; - C17F511D291EACCD00555EB5 /* G7SensorPlugin.loopplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = G7SensorPlugin.loopplugin; sourceTree = BUILT_PRODUCTS_DIR; }; - C17F511F291EACCD00555EB5 /* G7SensorPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = G7SensorPlugin.h; sourceTree = ""; }; - C17F5124291EACE400555EB5 /* G7SensorPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = G7SensorPlugin.swift; sourceTree = ""; }; - C17F5126291EAF2F00555EB5 /* OSLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; - C17F5134291EB06A00555EB5 /* AlgorithmState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlgorithmState.swift; sourceTree = ""; }; - C17F5137291EB0A800555EB5 /* Data.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; }; - C17F5139291EB0D900555EB5 /* GlucoseLimits.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseLimits.swift; sourceTree = ""; }; - C17F513B291EB13D00555EB5 /* Locked.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Locked.swift; sourceTree = ""; }; - C17F513D291EB1A500555EB5 /* BluetoothServices.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothServices.swift; sourceTree = ""; }; - C17F513F291EB27D00555EB5 /* TimeInterval.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeInterval.swift; sourceTree = ""; }; - C17F5142291EB36700555EB5 /* AuthChallengeRxMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthChallengeRxMessage.swift; sourceTree = ""; }; - C17F5144291EB45900555EB5 /* CBPeripheral.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CBPeripheral.swift; sourceTree = ""; }; - C17F5146291EB57700555EB5 /* SensorMessage.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; path = SensorMessage.swift; sourceTree = ""; }; - C17F5148291EB6B600555EB5 /* LocalizedString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizedString.swift; sourceTree = ""; }; - C17F514A291EB6F000555EB5 /* HKUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKUnit.swift; sourceTree = ""; }; - C17F514C291EB79E00555EB5 /* AlgorithmError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmError.swift; sourceTree = ""; }; - C17F5155291EBD8600555EB5 /* Image.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Image.swift; sourceTree = ""; }; - C17F5158291EBE7500555EB5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C19277AE29C916C200311AB7 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - C19277AF29C916C200311AB7 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - C19C9F4629C9115B00A6D3D0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - C19C9F4D29C91C4C00A6D3D0 /* LocalizedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedString.swift; sourceTree = ""; }; - C19C9F4F29C91ED400A6D3D0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - C1AEF8AF29C916CA001F6F41 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - C1AEF8B029C916CA001F6F41 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - C1B6638F29C916EC001556A8 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1B6639029C916EC001556A8 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1C140DE29C916D20051AFF1 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - C1C140DF29C916D20051AFF1 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - C1C86C0A29C916DC0060D000 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - C1C86C0B29C916DC0060D000 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - C1CCD81429C916F600A1158E /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - C1CCD81529C916F600A1158E /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - C1CDA74429C916E400DDC69C /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - C1CDA74529C916E400DDC69C /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - C1CE705E29C916FE00E70F9D /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - C1CE705F29C916FE00E70F9D /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - C1E3B2FF29C9170800A06681 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - C1E3B30029C9170800A06681 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - C1E7171F292D84FE00DA646F /* G7ProgressBarState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = G7ProgressBarState.swift; sourceTree = ""; }; - C1E9A8EB29C9170F00478AA9 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - C1F6C1FA29C9166000C74579 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - C1F6C1FB29C9166000C74579 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - CEC751E029D8837D006E9D24 /* LoopKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LoopKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - C17F50C3291EAC3800555EB5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - CEC751E129D8837D006E9D24 /* LoopKitUI.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C17F50CB291EAC3800555EB5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C17F50CF291EAC3800555EB5 /* G7SensorKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C17F50F5291EAC9100555EB5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C17F514F291EB87600555EB5 /* G7SensorKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C17F511A291EACCD00555EB5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C1409A0C291EC2F8006BE8D0 /* G7SensorKit.framework in Frameworks */, - C1409A0F291EC2FB006BE8D0 /* G7SensorKitUI.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - C17F50BC291EAC3800555EB5 = { - isa = PBXGroup; - children = ( - C17F5136291EB07F00555EB5 /* Common */, - C17F50C8291EAC3800555EB5 /* G7SensorKit */, - C17F50D2291EAC3800555EB5 /* G7SensorKitTests */, - C17F50F9291EAC9100555EB5 /* G7SensorKitUI */, - C17F511E291EACCD00555EB5 /* G7SensorPlugin */, - C17F50C7291EAC3800555EB5 /* Products */, - C17F5128291EAFA100555EB5 /* Frameworks */, - ); - sourceTree = ""; - }; - C17F50C7291EAC3800555EB5 /* Products */ = { - isa = PBXGroup; - children = ( - C17F50C6291EAC3800555EB5 /* G7SensorKit.framework */, - C17F50CE291EAC3800555EB5 /* G7SensorKitTests.xctest */, - C17F50F8291EAC9100555EB5 /* G7SensorKitUI.framework */, - C17F511D291EACCD00555EB5 /* G7SensorPlugin.loopplugin */, - ); - name = Products; - sourceTree = ""; - }; - C17F50C8291EAC3800555EB5 /* G7SensorKit */ = { - isa = PBXGroup; - children = ( - C19C9F4729C9115B00A6D3D0 /* Localizable.strings */, - C17F513D291EB1A500555EB5 /* BluetoothServices.swift */, - C17F514C291EB79E00555EB5 /* AlgorithmError.swift */, - C17F5134291EB06A00555EB5 /* AlgorithmState.swift */, - C17F5144291EB45900555EB5 /* CBPeripheral.swift */, - C17F50DE291EAC6500555EB5 /* G7CGMManager */, - C17F50C9291EAC3800555EB5 /* G7SensorKit.h */, - C17F5139291EB0D900555EB5 /* GlucoseLimits.swift */, - C17F5141291EB34800555EB5 /* Messages */, - C1409A08291EC22F006BE8D0 /* OSLog.swift */, - ); - path = G7SensorKit; - sourceTree = ""; - }; - C17F50D2291EAC3800555EB5 /* G7SensorKitTests */ = { - isa = PBXGroup; - children = ( - C17F50D3291EAC3800555EB5 /* G7SensorKitTests.swift */, - C109F14B291ED66F008EA5B6 /* G7GlucoseMessageTests.swift */, - ); - path = G7SensorKitTests; - sourceTree = ""; - }; - C17F50DE291EAC6500555EB5 /* G7CGMManager */ = { - isa = PBXGroup; - children = ( - C17F50DF291EAC6500555EB5 /* G7BackfillMessage.swift */, - C17F50E7291EAC6500555EB5 /* G7BluetoothManager.swift */, - C17F50E5291EAC6500555EB5 /* G7CGMManager.swift */, - C17F50E6291EAC6500555EB5 /* G7CGMManagerState.swift */, - C17F50E0291EAC6500555EB5 /* G7DeviceStatus.swift */, - C17F50E2291EAC6500555EB5 /* G7LastReading.swift */, - C17F50E4291EAC6500555EB5 /* G7PeripheralManager.swift */, - C17F50E1291EAC6500555EB5 /* G7Sensor.swift */, - ); - path = G7CGMManager; - sourceTree = ""; - }; - C17F50F9291EAC9100555EB5 /* G7SensorKitUI */ = { - isa = PBXGroup; - children = ( - C19C9F4C29C9117500A6D3D0 /* Localizable.strings */, - C1E7171E292D84B500DA646F /* Views */, - C109F149291ECCE2008EA5B6 /* Assets.xcassets */, - C17F5154291EBD7100555EB5 /* Extensions */, - C17F50FF291EAC9D00555EB5 /* G7CGMManager */, - C17F50FA291EAC9100555EB5 /* G7SensorKitUI.h */, - C17F5126291EAF2F00555EB5 /* OSLog.swift */, - C19C9F4D29C91C4C00A6D3D0 /* LocalizedString.swift */, - ); - path = G7SensorKitUI; - sourceTree = ""; - }; - C17F50FF291EAC9D00555EB5 /* G7CGMManager */ = { - isa = PBXGroup; - children = ( - C17F5103291EAC9D00555EB5 /* G7CGMManager+UI.swift */, - C17F5104291EAC9D00555EB5 /* G7UICoordinator.swift */, - ); - path = G7CGMManager; - sourceTree = ""; - }; - C17F511E291EACCD00555EB5 /* G7SensorPlugin */ = { - isa = PBXGroup; - children = ( - C17F511F291EACCD00555EB5 /* G7SensorPlugin.h */, - C17F5124291EACE400555EB5 /* G7SensorPlugin.swift */, - C17F5158291EBE7500555EB5 /* Info.plist */, - C1409A0A291EC258006BE8D0 /* OSLog.swift */, - ); - path = G7SensorPlugin; - sourceTree = ""; - }; - C17F5128291EAFA100555EB5 /* Frameworks */ = { - isa = PBXGroup; - children = ( - CEC751E029D8837D006E9D24 /* LoopKitUI.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - C17F5136291EB07F00555EB5 /* Common */ = { - isa = PBXGroup; - children = ( - C17F5137291EB0A800555EB5 /* Data.swift */, - C17F5148291EB6B600555EB5 /* LocalizedString.swift */, - C17F513B291EB13D00555EB5 /* Locked.swift */, - C17F514A291EB6F000555EB5 /* HKUnit.swift */, - C17F513F291EB27D00555EB5 /* TimeInterval.swift */, - ); - path = Common; - sourceTree = ""; - }; - C17F5141291EB34800555EB5 /* Messages */ = { - isa = PBXGroup; - children = ( - C17F50E3291EAC6500555EB5 /* G7Opcode.swift */, - C17F5146291EB57700555EB5 /* SensorMessage.swift */, - C17F50E8291EAC6500555EB5 /* G7GlucoseMessage.swift */, - C17F5142291EB36700555EB5 /* AuthChallengeRxMessage.swift */, - ); - path = Messages; - sourceTree = ""; - }; - C17F5154291EBD7100555EB5 /* Extensions */ = { - isa = PBXGroup; - children = ( - C17F5155291EBD8600555EB5 /* Image.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - C1E7171E292D84B500DA646F /* Views */ = { - isa = PBXGroup; - children = ( - C17F5102291EAC9D00555EB5 /* G7SettingsView.swift */, - C17F5100291EAC9D00555EB5 /* G7SettingsViewModel.swift */, - C17F5101291EAC9D00555EB5 /* G7StartupView.swift */, - C1E7171F292D84FE00DA646F /* G7ProgressBarState.swift */, - ); - path = Views; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - C17F50C1291EAC3800555EB5 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - C17F50D5291EAC3800555EB5 /* G7SensorKit.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C17F50F3291EAC9100555EB5 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - C17F50FB291EAC9100555EB5 /* G7SensorKitUI.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C17F5118291EACCD00555EB5 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - C17F5120291EACCD00555EB5 /* G7SensorPlugin.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - C17F50C5291EAC3800555EB5 /* G7SensorKit */ = { - isa = PBXNativeTarget; - buildConfigurationList = C17F50D8291EAC3800555EB5 /* Build configuration list for PBXNativeTarget "G7SensorKit" */; - buildPhases = ( - C17F50C1291EAC3800555EB5 /* Headers */, - C17F50C2291EAC3800555EB5 /* Sources */, - C17F50C3291EAC3800555EB5 /* Frameworks */, - C17F50C4291EAC3800555EB5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = G7SensorKit; - productName = G7SensorKit; - productReference = C17F50C6291EAC3800555EB5 /* G7SensorKit.framework */; - productType = "com.apple.product-type.framework"; - }; - C17F50CD291EAC3800555EB5 /* G7SensorKitTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = C17F50DB291EAC3800555EB5 /* Build configuration list for PBXNativeTarget "G7SensorKitTests" */; - buildPhases = ( - C17F50CA291EAC3800555EB5 /* Sources */, - C17F50CB291EAC3800555EB5 /* Frameworks */, - C17F50CC291EAC3800555EB5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - C17F50D1291EAC3800555EB5 /* PBXTargetDependency */, - ); - name = G7SensorKitTests; - productName = G7SensorKitTests; - productReference = C17F50CE291EAC3800555EB5 /* G7SensorKitTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - C17F50F7291EAC9100555EB5 /* G7SensorKitUI */ = { - isa = PBXNativeTarget; - buildConfigurationList = C17F50FC291EAC9100555EB5 /* Build configuration list for PBXNativeTarget "G7SensorKitUI" */; - buildPhases = ( - C17F50F3291EAC9100555EB5 /* Headers */, - C17F50F4291EAC9100555EB5 /* Sources */, - C17F50F5291EAC9100555EB5 /* Frameworks */, - C17F50F6291EAC9100555EB5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - C17F5152291EB87600555EB5 /* PBXTargetDependency */, - ); - name = G7SensorKitUI; - productName = G7SensorKitUI; - productReference = C17F50F8291EAC9100555EB5 /* G7SensorKitUI.framework */; - productType = "com.apple.product-type.framework"; - }; - C17F511C291EACCD00555EB5 /* G7SensorPlugin */ = { - isa = PBXNativeTarget; - buildConfigurationList = C17F5121291EACCD00555EB5 /* Build configuration list for PBXNativeTarget "G7SensorPlugin" */; - buildPhases = ( - C17F5118291EACCD00555EB5 /* Headers */, - C17F5119291EACCD00555EB5 /* Sources */, - C17F511A291EACCD00555EB5 /* Frameworks */, - C17F511B291EACCD00555EB5 /* Resources */, - C1409A0E291EC2F8006BE8D0 /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - C17F512C291EAFA100555EB5 /* PBXTargetDependency */, - C17F5130291EAFA100555EB5 /* PBXTargetDependency */, - ); - name = G7SensorPlugin; - productName = G7SensorPlugin; - productReference = C17F511D291EACCD00555EB5 /* G7SensorPlugin.loopplugin */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - C17F50BD291EAC3800555EB5 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1410; - LastUpgradeCheck = 1410; - ORGANIZATIONNAME = "LoopKit Authors"; - TargetAttributes = { - C17F50C5291EAC3800555EB5 = { - CreatedOnToolsVersion = 14.1; - }; - C17F50CD291EAC3800555EB5 = { - CreatedOnToolsVersion = 14.1; - }; - C17F50F7291EAC9100555EB5 = { - CreatedOnToolsVersion = 14.1; - }; - C17F511C291EACCD00555EB5 = { - CreatedOnToolsVersion = 14.1; - LastSwiftMigration = 1410; - }; - }; - }; - buildConfigurationList = C17F50C0291EAC3800555EB5 /* Build configuration list for PBXProject "G7SensorKit" */; - compatibilityVersion = "Xcode 14.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - es, - nb, - it, - fr, - nl, - de, - ar, - "zh-Hans", - da, - fi, - he, - ja, - pl, - "pt-BR", - ro, - ru, - sv, - tr, - vi, - sk, - hi, - cs, - uk, - "pt-PT", - ca, - hu, - ); - mainGroup = C17F50BC291EAC3800555EB5; - productRefGroup = C17F50C7291EAC3800555EB5 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - C17F50C5291EAC3800555EB5 /* G7SensorKit */, - C17F50CD291EAC3800555EB5 /* G7SensorKitTests */, - C17F50F7291EAC9100555EB5 /* G7SensorKitUI */, - C17F511C291EACCD00555EB5 /* G7SensorPlugin */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - C17F50C4291EAC3800555EB5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C19C9F4529C9115B00A6D3D0 /* Localizable.strings in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C17F50CC291EAC3800555EB5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C17F50F6291EAC9100555EB5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C109F14A291ECCE2008EA5B6 /* Assets.xcassets in Resources */, - C19C9F4A29C9117500A6D3D0 /* Localizable.strings in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C17F511B291EACCD00555EB5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - C17F50C2291EAC3800555EB5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C17F50EF291EAC6500555EB5 /* G7CGMManager.swift in Sources */, - C17F5147291EB57700555EB5 /* SensorMessage.swift in Sources */, - C17F50E9291EAC6500555EB5 /* G7BackfillMessage.swift in Sources */, - C17F50ED291EAC6500555EB5 /* G7Opcode.swift in Sources */, - C17F5140291EB27D00555EB5 /* TimeInterval.swift in Sources */, - C17F50F0291EAC6500555EB5 /* G7CGMManagerState.swift in Sources */, - C17F5145291EB45900555EB5 /* CBPeripheral.swift in Sources */, - C17F513A291EB0D900555EB5 /* GlucoseLimits.swift in Sources */, - C17F5143291EB36700555EB5 /* AuthChallengeRxMessage.swift in Sources */, - C17F50EA291EAC6500555EB5 /* G7DeviceStatus.swift in Sources */, - C1409A09291EC22F006BE8D0 /* OSLog.swift in Sources */, - C17F5135291EB06A00555EB5 /* AlgorithmState.swift in Sources */, - C17F50F1291EAC6500555EB5 /* G7BluetoothManager.swift in Sources */, - C17F5138291EB0A800555EB5 /* Data.swift in Sources */, - C17F514B291EB6F000555EB5 /* HKUnit.swift in Sources */, - C17F50EC291EAC6500555EB5 /* G7LastReading.swift in Sources */, - C17F513C291EB13D00555EB5 /* Locked.swift in Sources */, - C17F513E291EB1A500555EB5 /* BluetoothServices.swift in Sources */, - C17F5149291EB6B600555EB5 /* LocalizedString.swift in Sources */, - C17F514D291EB79E00555EB5 /* AlgorithmError.swift in Sources */, - C17F50EB291EAC6500555EB5 /* G7Sensor.swift in Sources */, - C17F50F2291EAC6500555EB5 /* G7GlucoseMessage.swift in Sources */, - C17F50EE291EAC6500555EB5 /* G7PeripheralManager.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C17F50CA291EAC3800555EB5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C109F14C291ED66F008EA5B6 /* G7GlucoseMessageTests.swift in Sources */, - C17F50D4291EAC3800555EB5 /* G7SensorKitTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C17F50F4291EAC9100555EB5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C17F5108291EAC9D00555EB5 /* G7SettingsView.swift in Sources */, - C17F5157291EBD9900555EB5 /* TimeInterval.swift in Sources */, - C19C9F4E29C91C4C00A6D3D0 /* LocalizedString.swift in Sources */, - C17F5156291EBD8600555EB5 /* Image.swift in Sources */, - C139829829295D7D0047DB5F /* HKUnit.swift in Sources */, - C1409A07291EC21C006BE8D0 /* OSLog.swift in Sources */, - C17F510A291EAC9D00555EB5 /* G7UICoordinator.swift in Sources */, - C17F5109291EAC9D00555EB5 /* G7CGMManager+UI.swift in Sources */, - C17F5107291EAC9D00555EB5 /* G7StartupView.swift in Sources */, - C1E71720292D84FE00DA646F /* G7ProgressBarState.swift in Sources */, - C17F5106291EAC9D00555EB5 /* G7SettingsViewModel.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C17F5119291EACCD00555EB5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C1409A0B291EC258006BE8D0 /* OSLog.swift in Sources */, - C17F5125291EACE400555EB5 /* G7SensorPlugin.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - C17F50D1291EAC3800555EB5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = C17F50C5291EAC3800555EB5 /* G7SensorKit */; - targetProxy = C17F50D0291EAC3800555EB5 /* PBXContainerItemProxy */; - }; - C17F512C291EAFA100555EB5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = C17F50C5291EAC3800555EB5 /* G7SensorKit */; - targetProxy = C17F512B291EAFA100555EB5 /* PBXContainerItemProxy */; - }; - C17F5130291EAFA100555EB5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = C17F50F7291EAC9100555EB5 /* G7SensorKitUI */; - targetProxy = C17F512F291EAFA100555EB5 /* PBXContainerItemProxy */; - }; - C17F5152291EB87600555EB5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = C17F50C5291EAC3800555EB5 /* G7SensorKit */; - targetProxy = C17F5151291EB87600555EB5 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - C19C9F4729C9115B00A6D3D0 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - C19C9F4629C9115B00A6D3D0 /* en */, - C1F6C1FA29C9166000C74579 /* cs */, - C12E6F0729C9166900E6FDBE /* da */, - C14091FA29C9167100ADD112 /* de */, - C125E0C029C9168100AB13C5 /* es */, - C10A0FE529C91688006F4CD8 /* fi */, - C1086B0E29C9169100D46E65 /* fr */, - C110930529C9169800AD9503 /* he */, - C10A851B29C916A200EAE6B3 /* hi */, - C13C056529C916AA00ED3803 /* it */, - C149257929C916B200F94598 /* ja */, - C158585E29C916BA00EA08EA /* nb */, - C19277AE29C916C200311AB7 /* nl */, - C1AEF8AF29C916CA001F6F41 /* pl */, - C1C140DE29C916D20051AFF1 /* pt-BR */, - C1C86C0A29C916DC0060D000 /* ro */, - C1CDA74429C916E400DDC69C /* ru */, - C1B6638F29C916EC001556A8 /* sk */, - C1CCD81429C916F600A1158E /* sv */, - C1CE705E29C916FE00E70F9D /* tr */, - C1E3B2FF29C9170800A06681 /* vi */, - 193F1E3D2B44C18000525770 /* hu */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - C19C9F4C29C9117500A6D3D0 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - C14BF96629C916560055FA98 /* ar */, - C1F6C1FB29C9166000C74579 /* cs */, - C12E6F0829C9166900E6FDBE /* da */, - C14091FB29C9167100ADD112 /* de */, - C125E0C129C9168100AB13C5 /* es */, - C10A0FE629C91688006F4CD8 /* fi */, - C1086B0F29C9169100D46E65 /* fr */, - C110930629C9169800AD9503 /* he */, - C10A851C29C916A200EAE6B3 /* hi */, - C13C056629C916AA00ED3803 /* it */, - C149257A29C916B200F94598 /* ja */, - C158585F29C916BA00EA08EA /* nb */, - C19277AF29C916C200311AB7 /* nl */, - C1AEF8B029C916CA001F6F41 /* pl */, - C1C140DF29C916D20051AFF1 /* pt-BR */, - C1C86C0B29C916DC0060D000 /* ro */, - C1CDA74529C916E400DDC69C /* ru */, - C1B6639029C916EC001556A8 /* sk */, - C1CCD81529C916F600A1158E /* sv */, - C1CE705F29C916FE00E70F9D /* tr */, - C1E3B30029C9170800A06681 /* vi */, - C1E9A8EB29C9170F00478AA9 /* zh-Hans */, - C19C9F4F29C91ED400A6D3D0 /* en */, - 193F1E3E2B44C18100525770 /* hu */, - ); - name = Localizable.strings; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - C17F50D6291EAC3800555EB5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = 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_DOCUMENTATION_COMMENTS = YES; - 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - 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 = 15.1; - LOCALIZED_STRING_MACRO_NAMES = ( - NSLocalizedString, - CFCopyLocalizedString, - LocalizedString, - ); - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - C17F50D7291EAC3800555EB5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = 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_DOCUMENTATION_COMMENTS = YES; - 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - 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 = 15.1; - LOCALIZED_STRING_MACRO_NAMES = ( - NSLocalizedString, - CFCopyLocalizedString, - LocalizedString, - ); - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - C17F50D9291EAC3800555EB5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( - "@executable_path/../Frameworks", - "@loader_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 12.6; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.G7SensorKit; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SDKROOT = auto; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - C17F50DA291EAC3800555EB5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( - "@executable_path/../Frameworks", - "@loader_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 12.6; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.G7SensorKit; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SDKROOT = auto; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; - C17F50DC291EAC3800555EB5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - GENERATE_INFOPLIST_FILE = YES; - MACOSX_DEPLOYMENT_TARGET = 12.6; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.G7SensorKitTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - C17F50DD291EAC3800555EB5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - GENERATE_INFOPLIST_FILE = YES; - MACOSX_DEPLOYMENT_TARGET = 12.6; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.G7SensorKitTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; - C17F50FD291EAC9100555EB5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.G7SensorKitUI; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - C17F50FE291EAC9100555EB5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.G7SensorKitUI; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - C17F5122291EACCD00555EB5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = G7SensorPlugin/Info.plist; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_DYLIB_INSTALL_NAME = ""; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.G7SensorPlugin; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - WRAPPER_EXTENSION = loopplugin; - }; - name = Debug; - }; - C17F5123291EACCD00555EB5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = G7SensorPlugin/Info.plist; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_DYLIB_INSTALL_NAME = ""; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.G7SensorPlugin; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - VALIDATE_PRODUCT = YES; - WRAPPER_EXTENSION = loopplugin; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - C17F50C0291EAC3800555EB5 /* Build configuration list for PBXProject "G7SensorKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C17F50D6291EAC3800555EB5 /* Debug */, - C17F50D7291EAC3800555EB5 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C17F50D8291EAC3800555EB5 /* Build configuration list for PBXNativeTarget "G7SensorKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C17F50D9291EAC3800555EB5 /* Debug */, - C17F50DA291EAC3800555EB5 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C17F50DB291EAC3800555EB5 /* Build configuration list for PBXNativeTarget "G7SensorKitTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C17F50DC291EAC3800555EB5 /* Debug */, - C17F50DD291EAC3800555EB5 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C17F50FC291EAC9100555EB5 /* Build configuration list for PBXNativeTarget "G7SensorKitUI" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C17F50FD291EAC9100555EB5 /* Debug */, - C17F50FE291EAC9100555EB5 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C17F5121291EACCD00555EB5 /* Build configuration list for PBXNativeTarget "G7SensorPlugin" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C17F5122291EACCD00555EB5 /* Debug */, - C17F5123291EACCD00555EB5 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = C17F50BD291EAC3800555EB5 /* Project object */; -} diff --git a/Dependencies/G7SensorKit/G7SensorKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Dependencies/G7SensorKit/G7SensorKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Dependencies/G7SensorKit/G7SensorKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dependencies/G7SensorKit/G7SensorKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Dependencies/G7SensorKit/G7SensorKit/AlgorithmError.swift b/Dependencies/G7SensorKit/G7SensorKit/AlgorithmError.swift deleted file mode 100644 index e46f2beaf..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/AlgorithmError.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// AlgorithmError.swift -// G7SensorKit -// -// Created by Pete Schwamb on 11/11/22. -// - -import Foundation - -enum AlgorithmError: Error { - case unreliableState(AlgorithmState) -} - -extension AlgorithmError: LocalizedError { - var errorDescription: String? { - switch self { - case .unreliableState: - return LocalizedString("Glucose data is unavailable", comment: "Error description for unreliable state") - } - } - - var failureReason: String? { - switch self { - case .unreliableState(let state): - return state.localizedDescription - } - } -} - - -extension AlgorithmState { - public var localizedDescription: String { - switch self { - case .known(let state): - switch state { - case .ok: - return LocalizedString("Sensor is OK", comment: "The description of sensor algorithm state when sensor is ok.") - case .stopped: - return LocalizedString("Sensor is stopped", comment: "The description of sensor algorithm state when sensor is stopped.") - case .warmup, .questionMarks: - return LocalizedString("Sensor is warming up", comment: "The description of sensor algorithm state when sensor is warming up.") - case .expired: - return LocalizedString("Sensor expired", comment: "The description of sensor algorithm state when sensor is expired.") - case .sensorFailed: - return LocalizedString("Sensor failed", comment: "The description of sensor algorithm state when sensor failed.") - } - case .unknown(let rawValue): - return String(format: LocalizedString("Sensor is in unknown state %1$d", comment: "The description of sensor algorithm state when raw value is unknown. (1: missing data details)"), rawValue) - } - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/AlgorithmState.swift b/Dependencies/G7SensorKit/G7SensorKit/AlgorithmState.swift deleted file mode 100644 index 93e5c404b..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/AlgorithmState.swift +++ /dev/null @@ -1,125 +0,0 @@ -// -// CalibrationState.swift -// xDripG5 -// -// Created by Nate Racklyeft on 8/6/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public enum AlgorithmState: RawRepresentable { - public typealias RawValue = UInt8 - - public enum State: RawValue { - case stopped = 1 - case warmup = 2 - case ok = 6 - case questionMarks = 18 - case expired = 24 - case sensorFailed = 25 - } - - case known(State) - case unknown(RawValue) - - public init(rawValue: RawValue) { - guard let state = State(rawValue: rawValue) else { - self = .unknown(rawValue) - return - } - - self = .known(state) - } - - public var rawValue: RawValue { - switch self { - case .known(let state): - return state.rawValue - case .unknown(let rawValue): - return rawValue - } - } - - public var sensorFailed: Bool { - guard case .known(let state) = self else { - return false - } - - switch state { - case .sensorFailed: - return true - default: - return false - } - } - - public var isInWarmup: Bool { - guard case .known(let state) = self else { - return false - } - - switch state { - case .warmup: - return true - default: - return false - } - } - - public var isInSensorError: Bool { - guard case .known(let state) = self else { - return false - } - - switch state { - case .questionMarks: - return true - default: - return false - } - } - - - public var hasReliableGlucose: Bool { - guard case .known(let state) = self else { - return false - } - - switch state { - case .stopped, - .warmup, - .questionMarks, - .expired, - .sensorFailed: - return false - case .ok: - return true - } - } -} - -extension AlgorithmState: Equatable { - public static func ==(lhs: AlgorithmState, rhs: AlgorithmState) -> Bool { - switch (lhs, rhs) { - case (.known(let lhs), .known(let rhs)): - return lhs == rhs - case (.unknown(let lhs), .unknown(let rhs)): - return lhs == rhs - default: - return false - } - } -} - -extension AlgorithmState: CustomStringConvertible { - public var description: String { - switch self { - case .known(let state): - return String(describing: state) - case .unknown(let value): - return ".unknown(\(value))" - } - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/BluetoothServices.swift b/Dependencies/G7SensorKit/G7SensorKit/BluetoothServices.swift deleted file mode 100644 index cf35cb79e..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/BluetoothServices.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// BluetoothServices.swift -// xDripG5 -// -// Created by Nathan Racklyeft on 10/16/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import CoreBluetooth - -protocol CBUUIDRawValue: RawRepresentable {} -extension CBUUIDRawValue where RawValue == String { - var cbUUID: CBUUID { - return CBUUID(string: rawValue) - } -} - - -enum SensorServiceUUID: String, CBUUIDRawValue { - case deviceInfo = "180A" - case advertisement = "FEBC" - case cgmService = "F8083532-849E-531C-C594-30F1F86A4EA5" - - case serviceB = "F8084532-849E-531C-C594-30F1F86A4EA5" -} - - -enum DeviceInfoCharacteristicUUID: String, CBUUIDRawValue { - // Read - // "DexcomUN" - case manufacturerNameString = "2A29" -} - - -enum CGMServiceCharacteristicUUID: String, CBUUIDRawValue { - - // Read/Notify - case communication = "F8083533-849E-531C-C594-30F1F86A4EA5" - - // Write/Indicate - case control = "F8083534-849E-531C-C594-30F1F86A4EA5" - - // Write/Indicate - case authentication = "F8083535-849E-531C-C594-30F1F86A4EA5" - - // Read/Write/Notify - case backfill = "F8083536-849E-531C-C594-30F1F86A4EA5" -} - - -enum ServiceBCharacteristicUUID: String, CBUUIDRawValue { - // Write/Indicate - case characteristicE = "F8084533-849E-531C-C594-30F1F86A4EA5" - // Read/Write/Notify - case characteristicF = "F8084534-849E-531C-C594-30F1F86A4EA5" -} - - -extension G7PeripheralManager.Configuration { - static var dexcomG7: G7PeripheralManager.Configuration { - return G7PeripheralManager.Configuration( - serviceCharacteristics: [ - SensorServiceUUID.cgmService.cbUUID: [ - //CGMServiceCharacteristicUUID.communication.cbUUID, // Unused for now - CGMServiceCharacteristicUUID.authentication.cbUUID, - CGMServiceCharacteristicUUID.control.cbUUID, - CGMServiceCharacteristicUUID.backfill.cbUUID, - ] - ], - notifyingCharacteristics: [:], - valueUpdateMacros: [:] - ) - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/CBPeripheral.swift b/Dependencies/G7SensorKit/G7SensorKit/CBPeripheral.swift deleted file mode 100644 index f64494c4a..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/CBPeripheral.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// CBPeripheral.swift -// xDripG5 -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import CoreBluetooth - - -// MARK: - Discovery helpers. -extension CBPeripheral { - func servicesToDiscover(from serviceUUIDs: [CBUUID]) -> [CBUUID] { - let knownServiceUUIDs = services?.compactMap({ $0.uuid }) ?? [] - return serviceUUIDs.filter({ !knownServiceUUIDs.contains($0) }) - } - - func characteristicsToDiscover(from characteristicUUIDs: [CBUUID], for service: CBService) -> [CBUUID] { - let knownCharacteristicUUIDs = service.characteristics?.compactMap({ $0.uuid }) ?? [] - return characteristicUUIDs.filter({ !knownCharacteristicUUIDs.contains($0) }) - } -} - - -extension Collection where Element: CBAttribute { - func itemWithUUID(_ uuid: CBUUID) -> Element? { - for attribute in self { - if attribute.uuid == uuid { - return attribute - } - } - - return nil - } - - func itemWithUUIDString(_ uuidString: String) -> Element? { - for attribute in self { - if attribute.uuid.uuidString == uuidString { - return attribute - } - } - - return nil - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7BackfillMessage.swift b/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7BackfillMessage.swift deleted file mode 100644 index 2658cb4dc..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7BackfillMessage.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// G7BackfillMessage.swift -// CGMBLEKit -// -// Created by Pete Schwamb on 9/25/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -public struct G7BackfillMessage: Equatable { - - public let timestamp: UInt32 // Seconds since pairing - public let glucose: UInt16? - public let glucoseIsDisplayOnly: Bool - public let algorithmState: AlgorithmState - public let trend: Double? - - public let data: Data - - public var hasReliableGlucose: Bool { - return algorithmState.hasReliableGlucose - } - - init?(data: Data) { - // 0 1 2 3 4 5 6 7 8 - // TTTTTT BGBG SS TR - // 45a100 00 9600 06 0f fc - - guard data.count == 9 else { - return nil - } - - timestamp = data[0..<4].toInt() - - let glucoseBytes = data[4..<6].to(UInt16.self) - - if glucoseBytes != 0xffff { - glucose = glucoseBytes & 0xfff - glucoseIsDisplayOnly = (glucoseBytes & 0xf000) > 0 - } else { - glucose = nil - glucoseIsDisplayOnly = false - } - - algorithmState = AlgorithmState(rawValue: data[6]) - - if data[8] == 0x7f { - trend = nil - } else { - trend = Double(Int8(bitPattern: data[8])) / 10 - } - - self.data = data - } - - public var trendType: LoopKit.GlucoseTrend? { - guard let trend = trend else { - return nil - } - - switch trend { - case let x where x <= -3.0: - return .downDownDown - case let x where x <= -2.0: - return .downDown - case let x where x <= -1.0: - return .down - case let x where x < 1.0: - return .flat - case let x where x < 2.0: - return .up - case let x where x < 3.0: - return .upUp - default: - return .upUpUp - } - } - - public var condition: GlucoseCondition? { - guard let glucose = glucose else { - return nil - } - - if glucose < GlucoseLimits.minimum { - return .belowRange - } else if glucose > GlucoseLimits.maximum { - return .aboveRange - } else { - return nil - } - } -} - -extension G7BackfillMessage: CustomDebugStringConvertible { - public var debugDescription: String { - return "G7BackfillMessage(glucose:\(String(describing: glucose)), glucoseIsDisplayOnly:\(glucoseIsDisplayOnly) timestamp:\(timestamp), data:\(data.hexadecimalString))" - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7BluetoothManager.swift b/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7BluetoothManager.swift deleted file mode 100644 index 62ab5fc8b..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7BluetoothManager.swift +++ /dev/null @@ -1,433 +0,0 @@ -// -// G7BluetoothManager.swift -// CGMBLEKit -// -// Created by Pete Schwamb on 11/11/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import CoreBluetooth -import Foundation -import os.log - - -enum PeripheralConnectionCommand { - case connect - case makeActive - case ignore -} - -protocol G7BluetoothManagerDelegate: AnyObject { - - /** - Tells the delegate that the bluetooth manager has finished connecting to and discovering all required services of its peripheral - - - parameter manager: The bluetooth manager - - parameter peripheralManager: The peripheral manager - - parameter error: An error describing why bluetooth setup failed - - - returns: True if scanning should stop - */ - func bluetoothManager(_ manager: G7BluetoothManager, readied peripheralManager: G7PeripheralManager) -> Bool - - /** - Tells the delegate that the bluetooth manager encountered an error while connecting to and discovering required services of a peripheral - - - parameter manager: The bluetooth manager - - parameter peripheralManager: The peripheral manager - - parameter error: An error describing why bluetooth setup failed - */ - func bluetoothManager(_ manager: G7BluetoothManager, readyingFailed peripheralManager: G7PeripheralManager, with error: Error) - - /** - Asks the delegate if the discovered or restored peripheral is active or should be connected to - - - parameter manager: The bluetooth manager - - parameter peripheral: The found peripheral - - - returns: PeripheralConnectionCommand indicating what should be done with this peripheral - */ - func bluetoothManager(_ manager: G7BluetoothManager, shouldConnectPeripheral peripheral: CBPeripheral) -> PeripheralConnectionCommand - - /// Informs the delegate that the bluetooth manager received new data in the control characteristic - /// - /// - Parameters: - /// - manager: The bluetooth manager - /// - peripheralManager: The peripheral manager - /// - response: The data received on the control characteristic - func bluetoothManager(_ manager: G7BluetoothManager, peripheralManager: G7PeripheralManager, didReceiveControlResponse response: Data) - - /// Informs the delegate that the bluetooth manager received new data in the backfill characteristic - /// - /// - Parameters: - /// - manager: The bluetooth manager - /// - response: The data received on the backfill characteristic - func bluetoothManager(_ manager: G7BluetoothManager, didReceiveBackfillResponse response: Data) - - /// Informs the delegate that the bluetooth manager received new data in the authentication characteristic - /// - /// - Parameters: - /// - manager: The bluetooth manager - /// - peripheralManager: The peripheral manager - /// - response: The data received on the authentication characteristic - func bluetoothManager(_ manager: G7BluetoothManager, peripheralManager: G7PeripheralManager, didReceiveAuthenticationResponse response: Data) - - /// Informs the delegate that the bluetooth manager started or stopped scanning - /// - /// - Parameters: - /// - manager: The bluetooth manager - func bluetoothManagerScanningStatusDidChange(_ manager: G7BluetoothManager) - - /// Informs the delegate that a peripheral disconnected - /// - /// - Parameters: - /// - manager: The bluetooth manager - func peripheralDidDisconnect(_ manager: G7BluetoothManager, peripheralManager: G7PeripheralManager, wasRemoteDisconnect: Bool) -} - - -class G7BluetoothManager: NSObject { - - weak var delegate: G7BluetoothManagerDelegate? - - private let log = OSLog(category: "G7BluetoothManager") - - /// Isolated to `managerQueue` - private var centralManager: CBCentralManager! = nil - - /// Isolated to `managerQueue` - private var activePeripheral: CBPeripheral? { - get { - return activePeripheralManager?.peripheral - } - } - - /// Isolated to `managerQueue` - private var managedPeripherals: [UUID:G7PeripheralManager] = [:] - - var activePeripheralIdentifier: UUID? { - get { - return lockedPeripheralIdentifier.value - } - } - private let lockedPeripheralIdentifier: Locked = Locked(nil) - - /// Isolated to `managerQueue` - private var activePeripheralManager: G7PeripheralManager? { - didSet { - oldValue?.delegate = nil - lockedPeripheralIdentifier.value = activePeripheralManager?.peripheral.identifier - } - } - - // MARK: - Synchronization - - private let managerQueue = DispatchQueue(label: "com.loudnate.CGMBLEKit.bluetoothManagerQueue", qos: .unspecified) - - override init() { - super.init() - - managerQueue.sync { - self.centralManager = CBCentralManager(delegate: self, queue: managerQueue, options: [CBCentralManagerOptionRestoreIdentifierKey: "com.loudnate.CGMBLEKit"]) - } - } - - // MARK: - Actions - - func scanForPeripheral() { - dispatchPrecondition(condition: .notOnQueue(managerQueue)) - - managerQueue.sync { - self.managerQueue_scanForPeripheral() - } - } - - func forgetPeripheral() { - managerQueue.sync { - self.activePeripheralManager = nil - } - } - - func stopScanning() { - managerQueue.sync { - managerQueue_stopScanning() - } - } - - private func managerQueue_stopScanning() { - if centralManager.isScanning { - log.debug("Stopping scan") - centralManager.stopScan() - delegate?.bluetoothManagerScanningStatusDidChange(self) - } - } - - func disconnect() { - dispatchPrecondition(condition: .notOnQueue(managerQueue)) - - managerQueue.sync { - if centralManager.isScanning { - log.debug("Stopping scan on disconnect") - centralManager.stopScan() - delegate?.bluetoothManagerScanningStatusDidChange(self) - } - - if let peripheral = activePeripheral { - centralManager.cancelPeripheralConnection(peripheral) - } - } - } - - private func managerQueue_scanForPeripheral() { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - guard centralManager.state == .poweredOn else { - return - } - - let currentState = activePeripheral?.state ?? .disconnected - guard currentState != .connected else { - return - } - - if let peripheralID = activePeripheralIdentifier, let peripheral = centralManager.retrievePeripherals(withIdentifiers: [peripheralID]).first { - log.debug("Retrieved peripheral %{public}@", peripheral.identifier.uuidString) - handleDiscoveredPeripheral(peripheral) - } else { - for peripheral in centralManager.retrieveConnectedPeripherals(withServices: [ - SensorServiceUUID.advertisement.cbUUID, - SensorServiceUUID.cgmService.cbUUID - ]) { - handleDiscoveredPeripheral(peripheral) - } - } - - if activePeripheral == nil { - log.debug("Scanning for peripherals") - centralManager.scanForPeripherals(withServices: [ - SensorServiceUUID.advertisement.cbUUID - ], - options: nil - ) - delegate?.bluetoothManagerScanningStatusDidChange(self) - } - } - - /** - - Persistent connections don't seem to work with the transmitter shutoff: The OS won't re-wake the - app unless it's scanning. - - The sleep gives the transmitter time to shut down, but keeps the app running. - - */ - fileprivate func scanAfterDelay() { - DispatchQueue.global(qos: .utility).async { - Thread.sleep(forTimeInterval: 2) - - self.scanForPeripheral() - } - } - - // MARK: - Accessors - - var isScanning: Bool { - dispatchPrecondition(condition: .notOnQueue(managerQueue)) - - var isScanning = false - managerQueue.sync { - isScanning = centralManager.isScanning - } - return isScanning - } - - var isConnected: Bool { - dispatchPrecondition(condition: .notOnQueue(managerQueue)) - - var isConnected = false - managerQueue.sync { - isConnected = activePeripheral?.state == .connected - } - return isConnected - } - - private func handleDiscoveredPeripheral(_ peripheral: CBPeripheral) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - if let delegate = delegate { - switch delegate.bluetoothManager(self, shouldConnectPeripheral: peripheral) { - case .makeActive: - log.debug("Making peripheral active: %{public}@", peripheral.identifier.uuidString) - - if let peripheralManager = activePeripheralManager { - peripheralManager.peripheral = peripheral - } else { - activePeripheralManager = G7PeripheralManager( - peripheral: peripheral, - configuration: .dexcomG7, - centralManager: centralManager - ) - activePeripheralManager?.delegate = self - } - self.managedPeripherals[peripheral.identifier] = activePeripheralManager - self.centralManager.connect(peripheral) - - case .connect: - log.debug("Connecting to peripheral: %{public}@", peripheral.identifier.uuidString) - self.centralManager.connect(peripheral) - let peripheralManager = G7PeripheralManager( - peripheral: peripheral, - configuration: .dexcomG7, - centralManager: centralManager - ) - peripheralManager.delegate = self - self.managedPeripherals[peripheral.identifier] = peripheralManager - case .ignore: - break - } - } - } - - override var debugDescription: String { - return [ - "## BluetoothManager", - activePeripheralManager.map(String.init(reflecting:)) ?? "No peripheral", - ].joined(separator: "\n") - } -} - - -extension G7BluetoothManager: CBCentralManagerDelegate { - func centralManagerDidUpdateState(_ central: CBCentralManager) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - activePeripheralManager?.centralManagerDidUpdateState(central) - log.default("%{public}@: %{public}@", #function, String(describing: central.state.rawValue)) - - switch central.state { - case .poweredOn: - managerQueue_scanForPeripheral() - case .resetting, .poweredOff, .unauthorized, .unknown, .unsupported: - fallthrough - @unknown default: - if central.isScanning { - log.debug("Stopping scan on central not powered on") - central.stopScan() - delegate?.bluetoothManagerScanningStatusDidChange(self) - } - } - } - - func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey] as? [CBPeripheral] { - for peripheral in peripherals { - log.default("Restoring peripheral from state: %{public}@", peripheral.identifier.uuidString) - handleDiscoveredPeripheral(peripheral) - } - } - } - - func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - log.info("%{public}@: %{public}@, data = %{public}@", #function, peripheral, String(describing: advertisementData)) - - managerQueue.async { - self.handleDiscoveredPeripheral(peripheral) - } - } - - func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - log.default("%{public}@: %{public}@", #function, peripheral) - - if let peripheralManager = managedPeripherals[peripheral.identifier] { - peripheralManager.centralManager(central, didConnect: peripheral) - - if let delegate = delegate, case .poweredOn = centralManager.state, case .connected = peripheral.state { - if delegate.bluetoothManager(self, readied: peripheralManager) { - managerQueue_stopScanning() - } - } - } - } - - func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - log.default("%{public}@: %{public}@", #function, peripheral) - // Ignore errors indicating the peripheral disconnected remotely, as that's expected behavior - if let error = error as NSError?, CBError(_nsError: error).code != .peripheralDisconnected { - log.error("%{public}@: %{public}@", #function, error) - if let peripheralManager = activePeripheralManager { - self.delegate?.bluetoothManager(self, readyingFailed: peripheralManager, with: error) - } - } - - if let peripheralManager = managedPeripherals[peripheral.identifier] { - let remoteDisconnect: Bool - if let error = error as NSError?, CBError(_nsError: error).code == .peripheralDisconnected { - remoteDisconnect = true - } else { - remoteDisconnect = false - } - self.delegate?.peripheralDidDisconnect(self, peripheralManager: peripheralManager, wasRemoteDisconnect: remoteDisconnect) - } - - if peripheral != activePeripheral { - managedPeripherals.removeValue(forKey: peripheral.identifier) - } - - scanAfterDelay() - } - - func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - log.error("%{public}@: %{public}@", #function, String(describing: error)) - if let error = error, let peripheralManager = activePeripheralManager { - self.delegate?.bluetoothManager(self, readyingFailed: peripheralManager, with: error) - } - - if peripheral != activePeripheral { - managedPeripherals.removeValue(forKey: peripheral.identifier) - } - - scanAfterDelay() - } -} - - -extension G7BluetoothManager: G7PeripheralManagerDelegate { - func peripheralManager(_ manager: G7PeripheralManager, didReadRSSI RSSI: NSNumber, error: Error?) { - - } - - func peripheralManagerDidUpdateName(_ manager: G7PeripheralManager) { - } - - func peripheralManagerDidConnect(_ manager: G7PeripheralManager) { - } - - func completeConfiguration(for manager: G7PeripheralManager) throws { - } - - func peripheralManager(_ manager: G7PeripheralManager, didUpdateValueFor characteristic: CBCharacteristic) { - guard let value = characteristic.value else { - return - } - - switch CGMServiceCharacteristicUUID(rawValue: characteristic.uuid.uuidString.uppercased()) { - case .none, .communication?: - return - case .control?: - self.delegate?.bluetoothManager(self, peripheralManager: manager, didReceiveControlResponse: value) - case .backfill?: - self.delegate?.bluetoothManager(self, didReceiveBackfillResponse: value) - case .authentication?: - self.delegate?.bluetoothManager(self, peripheralManager: manager, didReceiveAuthenticationResponse: value) - } - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7CGMManager.swift b/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7CGMManager.swift deleted file mode 100644 index 267438b8f..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7CGMManager.swift +++ /dev/null @@ -1,470 +0,0 @@ -// -// G7CGMManager.swift -// CGMBLEKit -// -// Created by Pete Schwamb on 9/24/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit -import os.log -import HealthKit - - - -public protocol G7StateObserver: AnyObject { - func g7StateDidUpdate(_ state: G7CGMManagerState?) - func g7ConnectionStatusDidChange() -} - -public class G7CGMManager: CGMManager { - private let log = OSLog(category: "G7CGMManager") - - public var state: G7CGMManagerState { - return lockedState.value - } - - private func setState(_ changes: (_ state: inout G7CGMManagerState) -> Void) -> Void { - return setStateWithResult(changes) - } - - @discardableResult - private func mutateState(_ changes: (_ state: inout G7CGMManagerState) -> Void) -> G7CGMManagerState { - return setStateWithResult({ (state) -> G7CGMManagerState in - changes(&state) - return state - }) - } - - private func setStateWithResult(_ changes: (_ state: inout G7CGMManagerState) -> ReturnType) -> ReturnType { - var oldValue: G7CGMManagerState! - var returnType: ReturnType! - let newValue = lockedState.mutate { (state) in - oldValue = state - returnType = changes(&state) - } - - if oldValue != newValue { - delegate.notify { delegate in - delegate?.cgmManagerDidUpdateState(self) - delegate?.cgmManager(self, didUpdate: self.cgmManagerStatus) - } - - g7StateObservers.forEach { (observer) in - observer.g7StateDidUpdate(newValue) - } - } - - return returnType - } - private let lockedState: Locked - - private let g7StateObservers = WeakSynchronizedSet() - - public weak var cgmManagerDelegate: CGMManagerDelegate? { - get { - return delegate.delegate - } - set { - delegate.delegate = newValue - } - } - - public var delegateQueue: DispatchQueue! { - get { - return delegate.queue - } - set { - delegate.queue = newValue - } - } - - private let delegate = WeakSynchronizedDelegate() - - public var providesBLEHeartbeat: Bool = true - - public var managedDataInterval: TimeInterval? { - return .hours(3) - } - - public var shouldSyncToRemoteService: Bool { - return state.uploadReadings - } - - public var glucoseDisplay: GlucoseDisplayable? { - return latestReading - } - - public var isScanning: Bool { - return sensor.isScanning - } - - public var isConnected: Bool { - return sensor.isConnected - } - - public var sensorName: String? { - return state.sensorID - } - - public var sensorActivatedAt: Date? { - return state.activatedAt - } - - public var sensorExpiresAt: Date? { - guard let activatedAt = sensorActivatedAt else { - return nil - } - return activatedAt.addingTimeInterval(G7Sensor.lifetime) - } - - public var sensorEndsAt: Date? { - guard let activatedAt = sensorActivatedAt else { - return nil - } - return activatedAt.addingTimeInterval(G7Sensor.lifetime + G7Sensor.gracePeriod) - } - - - public var sensorFinishesWarmupAt: Date? { - guard let activatedAt = sensorActivatedAt else { - return nil - } - return activatedAt.addingTimeInterval(G7Sensor.warmupDuration) - } - - public var latestReading: G7GlucoseMessage? { - return state.latestReading - } - - public var lastConnect: Date? { - return state.latestConnect - } - - public var latestReadingTimestamp: Date? { - return state.latestReadingTimestamp - } - - public var uploadReadings: Bool { - get { - return state.uploadReadings - } - set { - mutateState { state in - state.uploadReadings = newValue - } - } - } - - public let sensor: G7Sensor - - public var cgmManagerStatus: LoopKit.CGMManagerStatus { - return CGMManagerStatus(hasValidSensorSession: true, device: device) - } - - public var lifecycleState: G7SensorLifecycleState { - if state.sensorID == nil { - return .searching - } - if let sensorEndsAt = sensorEndsAt, sensorEndsAt.timeIntervalSinceNow < 0 { - return .expired - } - if let algorithmState = latestReading?.algorithmState { - if algorithmState.isInWarmup { - return .warmup - } - if algorithmState.sensorFailed { - return .failed - } - } - if let sensorExpiresAt = sensorExpiresAt, sensorExpiresAt.timeIntervalSinceNow < 0 { - return .gracePeriod - } - return .ok - } - - - public func fetchNewDataIfNeeded(_ completion: @escaping (LoopKit.CGMReadingResult) -> Void) { - sensor.resumeScanning() - completion(.noData) - } - - public init() { - lockedState = Locked(G7CGMManagerState()) - sensor = G7Sensor(sensorID: nil) - sensor.delegate = self - } - - public required init?(rawState: RawStateValue) { - let state = G7CGMManagerState(rawValue: rawState) - lockedState = Locked(state) - sensor = G7Sensor(sensorID: state.sensorID) - sensor.delegate = self - } - - public var rawState: RawStateValue { - return state.rawValue - } - - public var debugDescription: String { - let lines = [ - "## G7CGMManager", - "sensorID: \(String(describing: state.sensorID))", - "activatedAt: \(String(describing: state.activatedAt))", - "latestReading: \(String(describing: state.latestReading))", - "latestReadingTimestamp: \(String(describing: state.latestReadingTimestamp))", - "latestConnect: \(String(describing: state.latestConnect))", - "uploadReadings: \(String(describing: state.uploadReadings))", - ] - return lines.joined(separator: "\n") - } - - public func acknowledgeAlert(alertIdentifier: LoopKit.Alert.AlertIdentifier, completion: @escaping (Error?) -> Void) { - completion(nil) - } - - public func getSoundBaseURL() -> URL? { return nil } - public func getSounds() -> [Alert.Sound] { return [] } - - public let managerIdentifier: String = "G7CGMManager" - - public let localizedTitle = LocalizedString("Dexcom G7", comment: "CGM display title") - - public let isOnboarded = true // No distinction between created and onboarded - - public var appURL: URL? { - return nil - } - - public func scanForNewSensor() { - logDeviceCommunication("Forgetting existing sensor and starting scan for new sensor.", type: .connection) - - mutateState { state in - state.sensorID = nil - state.activatedAt = nil - } - sensor.scanForNewSensor() - } - - public var device: HKDevice? { - return HKDevice( - name: "CGMBLEKit", - manufacturer: "Dexcom", - model: "G7", - hardwareVersion: nil, - firmwareVersion: nil, - softwareVersion: String(G7SensorKitVersionNumber), - localIdentifier: nil, - udiDeviceIdentifier: "00386270001863" - ) - } - - func logDeviceCommunication(_ message: String, type: DeviceLogEntryType = .send) { - self.cgmManagerDelegate?.deviceManager(self, logEventForDeviceIdentifier: state.sensorID, type: type, message: message, completion: nil) - } - - private func updateDelegate(with result: CGMReadingResult) { - delegateQueue?.async { - self.cgmManagerDelegate?.cgmManager(self, hasNew: result) - } - } -} - -extension G7CGMManager { - // MARK: - G7StateObserver - - public func addStateObserver(_ observer: G7StateObserver, queue: DispatchQueue) { - g7StateObservers.insert(observer, queue: queue) - } - - public func removeStateObserver(_ observer: G7StateObserver) { - g7StateObservers.removeElement(observer) - } -} - -extension G7CGMManager: G7SensorDelegate { - public func sensor(_ sensor: G7Sensor, didDiscoverNewSensor name: String, activatedAt: Date) -> Bool { - logDeviceCommunication("New sensor \(name) discovered, activated at \(activatedAt)", type: .connection) - - let shouldSwitchToNewSensor = true - - if shouldSwitchToNewSensor { - mutateState { state in - state.sensorID = name - state.activatedAt = activatedAt - } - } - - return shouldSwitchToNewSensor - } - - public func sensorDidConnect(_ sensor: G7Sensor, name: String) { - mutateState { state in - state.latestConnect = Date() - } - logDeviceCommunication("Sensor connected", type: .connection) - } - - public func sensorDisconnected(_ sensor: G7Sensor, suspectedEndOfSession: Bool) { - logDeviceCommunication("Sensor disconnected: suspectedEndOfSession=\(suspectedEndOfSession)", type: .connection) - if suspectedEndOfSession { - scanForNewSensor() - } - } - - public func sensor(_ sensor: G7Sensor, didError error: Error) { - logDeviceCommunication("Sensor error \(error)", type: .error) - } - - public func sensor(_ sensor: G7Sensor, didRead message: G7GlucoseMessage) { - - guard message != latestReading else { - logDeviceCommunication("Sensor reading duplicate: \(message)", type: .error) - updateDelegate(with: .noData) - return - } - - guard let activationDate = sensor.activationDate else { - logDeviceCommunication("Unable to process sensor reading without activation date.", type: .error) - return - } - - logDeviceCommunication("Sensor didRead \(message)", type: .receive) - - let latestReadingTimestamp = activationDate.addingTimeInterval(TimeInterval(message.glucoseTimestamp)) - - mutateState { state in - state.latestReading = message - state.latestReadingTimestamp = latestReadingTimestamp - } - - guard let glucose = message.glucose else { - updateDelegate(with: .noData) - return - } - - guard message.hasReliableGlucose else { - updateDelegate(with: .error(AlgorithmError.unreliableState(message.algorithmState))) - return - } - - let unit = HKUnit.milligramsPerDeciliter - let quantity = HKQuantity(unit: unit, doubleValue: Double(min(max(glucose, GlucoseLimits.minimum), GlucoseLimits.maximum))) - - updateDelegate(with: .newData([ - NewGlucoseSample( - date: latestReadingTimestamp, - quantity: quantity, - condition: message.condition, - trend: message.trendType, - trendRate: message.trendRate, - isDisplayOnly: message.glucoseIsDisplayOnly, - wasUserEntered: message.glucoseIsDisplayOnly, - syncIdentifier: generateSyncIdentifier(timestamp: message.glucoseTimestamp), - device: device - ) - ])) - } - - private func generateSyncIdentifier(timestamp: UInt32) -> String { - guard let activatedAt = state.activatedAt, let sensorID = state.sensorID else { - return "invalid" - } - - return "\(activatedAt.timeIntervalSince1970.hours) \(sensorID) \(timestamp)" - } - - public func sensor(_ sensor: G7Sensor, didReadBackfill backfill: [G7BackfillMessage]) { - for msg in backfill { - logDeviceCommunication("Sensor didReadBackfill \(msg)", type: .receive) - } - - guard let activationDate = sensor.activationDate else { - log.error("Unable to process backfill without activation date.") - return - } - - let unit = HKUnit.milligramsPerDeciliter - - let samples = backfill.compactMap { entry -> NewGlucoseSample? in - guard let glucose = entry.glucose else { - return nil - } - - guard entry.hasReliableGlucose else { - logDeviceCommunication("Backfill reading unreliable: \(entry)", type: .receive) - return nil - } - - let quantity = HKQuantity(unit: unit, doubleValue: Double(min(max(glucose, GlucoseLimits.minimum), GlucoseLimits.maximum))) - - return NewGlucoseSample( - date: activationDate.addingTimeInterval(TimeInterval(entry.timestamp)), - quantity: quantity, - condition: entry.condition, - trend: entry.trendType, - trendRate: entry.trendRate, - isDisplayOnly: entry.glucoseIsDisplayOnly, - wasUserEntered: entry.glucoseIsDisplayOnly, - syncIdentifier: generateSyncIdentifier(timestamp: entry.timestamp), - device: device - ) - } - - updateDelegate(with: .newData(samples)) - } - - public func sensorConnectionStatusDidUpdate(_ sensor: G7Sensor) { - g7StateObservers.forEach { (observer) in - observer.g7ConnectionStatusDidChange() - } - } -} - -extension G7BackfillMessage { - public var trendRate: HKQuantity? { - guard let trend = trend else { - return nil - } - return HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: trend) - } -} - -extension G7GlucoseMessage: GlucoseDisplayable { - public var isStateValid: Bool { - return hasReliableGlucose - } - - public var trendRate: HKQuantity? { - guard let trend = trend else { - return nil - } - return HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: trend) - } - - public var glucoseQuantity: HKQuantity? { - guard let glucose = glucose else { - return nil - } - return HKQuantity(unit: .milligramsPerDeciliter, doubleValue: Double(glucose)) - } - - public var isLocal: Bool { - return true - } - - public var glucoseRangeCategory: LoopKit.GlucoseRangeCategory? { - guard let glucose = glucose else { - return nil - } - - if glucose < GlucoseLimits.minimum { - return .belowRange - } else if glucose > GlucoseLimits.maximum { - return .aboveRange - } else { - return nil - } - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7CGMManagerState.swift b/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7CGMManagerState.swift deleted file mode 100644 index 948b02f78..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7CGMManagerState.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// G7CGMManagerState.swift -// CGMBLEKit -// -// Created by Pete Schwamb on 9/26/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - - -public struct G7CGMManagerState: RawRepresentable, Equatable { - public typealias RawValue = CGMManager.RawStateValue - - public var sensorID: String? - public var activatedAt: Date? - public var latestReading: G7GlucoseMessage? - public var latestReadingTimestamp: Date? - public var latestConnect: Date? - public var uploadReadings: Bool = false - - init() { - } - - public init(rawValue: RawValue) { - self.sensorID = rawValue["sensorID"] as? String - self.activatedAt = rawValue["activatedAt"] as? Date - if let readingData = rawValue["latestReading"] as? Data { - latestReading = G7GlucoseMessage(data: readingData) - } - self.latestReadingTimestamp = rawValue["latestReadingTimestamp"] as? Date - self.latestConnect = rawValue["latestConnect"] as? Date - self.uploadReadings = rawValue["uploadReadings"] as? Bool ?? false - } - - public var rawValue: RawValue { - var rawValue: RawValue = [:] - rawValue["sensorID"] = sensorID - rawValue["activatedAt"] = activatedAt - rawValue["latestReading"] = latestReading?.data - rawValue["latestReadingTimestamp"] = latestReadingTimestamp - rawValue["latestConnect"] = latestConnect - rawValue["uploadReadings"] = uploadReadings - return rawValue - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7DeviceStatus.swift b/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7DeviceStatus.swift deleted file mode 100644 index 2cbfaaff9..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7DeviceStatus.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// G7DeviceStatus.swift -// CGMBLEKit -// -// Created by Pete Schwamb on 10/23/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import LoopKit -import LoopKitUI - -public struct G7DeviceStatusHighlight: DeviceStatusHighlight, Equatable { - public let localizedMessage: String - public let imageName: String - public let state: DeviceStatusHighlightState - init(localizedMessage: String, imageName: String, state: DeviceStatusHighlightState) { - self.localizedMessage = localizedMessage - self.imageName = imageName - self.state = state - } -} - diff --git a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7LastReading.swift b/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7LastReading.swift deleted file mode 100644 index f77efb212..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7LastReading.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// G7LastReading.swift -// CGMBLEKit -// -// Created by Pete Schwamb on 10/4/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -struct G7LastReading { - let glucose: Int? - let timestamp: Date - let sensorTimestamp: Date -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7PeripheralManager.swift b/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7PeripheralManager.swift deleted file mode 100644 index fcef3b72a..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7PeripheralManager.swift +++ /dev/null @@ -1,567 +0,0 @@ -// -// G7PeripheralManager.swift -// CGMBLEKit -// -// Created by Pete Schwamb on 11/11/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import CoreBluetooth -import Foundation -import os.log - - -enum PeripheralManagerError: Error { - case cbPeripheralError(Error) - case notReady - case invalidConfiguration - case timeout - case unknownCharacteristic -} - -class G7PeripheralManager: NSObject { - - private let log = OSLog(category: "G7PeripheralManager") - - /// - /// This is mutable, because CBPeripheral instances can seemingly become invalid, and need to be periodically re-fetched from CBCentralManager - var peripheral: CBPeripheral { - didSet { - guard oldValue !== peripheral else { - return - } - - log.error("Replacing peripheral reference %{public}@ -> %{public}@", oldValue, peripheral) - - oldValue.delegate = nil - peripheral.delegate = self - - queue.sync { - self.needsConfiguration = true - } - } - } - - /// The dispatch queue used to serialize operations on the peripheral - let queue = DispatchQueue(label: "com.loopkit.PeripheralManager.queue", qos: .unspecified) - - /// The condition used to signal command completion - private let commandLock = NSCondition() - - /// The required conditions for the operation to complete - private var commandConditions = [CommandCondition]() - - /// Any error surfaced during the active operation - private var commandError: Error? - - private(set) weak var central: CBCentralManager? - - let configuration: Configuration - - // Confined to `queue` - private var needsConfiguration = true - - weak var delegate: G7PeripheralManagerDelegate? { - didSet { - queue.sync { - needsConfiguration = true - } - } - } - - init(peripheral: CBPeripheral, configuration: Configuration, centralManager: CBCentralManager) { - self.peripheral = peripheral - self.central = centralManager - self.configuration = configuration - - super.init() - - peripheral.delegate = self - - assertConfiguration() - } -} - - -// MARK: - Nested types -extension G7PeripheralManager { - struct Configuration { - var serviceCharacteristics: [CBUUID: [CBUUID]] = [:] - var notifyingCharacteristics: [CBUUID: [CBUUID]] = [:] - var valueUpdateMacros: [CBUUID: (_ manager: G7PeripheralManager) -> Void] = [:] - } - - enum CommandCondition { - case notificationStateUpdate(characteristicUUID: CBUUID, enabled: Bool) - case valueUpdate(characteristic: CBCharacteristic, matching: ((Data?) -> Bool)?) - case write(characteristic: CBCharacteristic) - case discoverServices - case discoverCharacteristicsForService(serviceUUID: CBUUID) - } -} - -protocol G7PeripheralManagerDelegate: AnyObject { - func peripheralManager(_ manager: G7PeripheralManager, didUpdateValueFor characteristic: CBCharacteristic) - - func peripheralManager(_ manager: G7PeripheralManager, didReadRSSI RSSI: NSNumber, error: Error?) - - func peripheralManagerDidUpdateName(_ manager: G7PeripheralManager) - - func completeConfiguration(for manager: G7PeripheralManager) throws -} - - -// MARK: - Operation sequence management -extension G7PeripheralManager { - func configureAndRun(_ block: @escaping (_ manager: G7PeripheralManager) -> Void) -> (() -> Void) { - return { - if !self.needsConfiguration && self.peripheral.services == nil { - self.log.error("Configured peripheral has no services. Reconfiguring…") - } - - if self.needsConfiguration || self.peripheral.services == nil { - do { - try self.applyConfiguration() - self.log.default("Peripheral configuration completed") - if let delegate = self.delegate { - try delegate.completeConfiguration(for: self) - self.log.default("Delegate configuration completed") - self.needsConfiguration = false - } else { - self.log.error("No delegate set configured") - } - } catch let error { - self.log.error("Error applying peripheral configuration: %@", String(describing: error)) - // Will retry - } - - } - - block(self) - } - } - - func perform(_ block: @escaping (_ manager: G7PeripheralManager) -> Void) { - queue.async(execute: configureAndRun(block)) - } - - private func assertConfiguration() { - log.debug("assertConfiguration") - perform { (_) in - // Intentionally empty to trigger configuration if necessary - } - } - - private func applyConfiguration(discoveryTimeout: TimeInterval = 2) throws { - try discoverServices(configuration.serviceCharacteristics.keys.map { $0 }, timeout: discoveryTimeout) - - for service in peripheral.services ?? [] { - guard let characteristics = configuration.serviceCharacteristics[service.uuid] else { - // Not all services may have characteristics - continue - } - - try discoverCharacteristics(characteristics, for: service, timeout: discoveryTimeout) - } - - for (serviceUUID, characteristicUUIDs) in configuration.notifyingCharacteristics { - guard let service = peripheral.services?.itemWithUUID(serviceUUID) else { - throw PeripheralManagerError.unknownCharacteristic - } - - for characteristicUUID in characteristicUUIDs { - guard let characteristic = service.characteristics?.itemWithUUID(characteristicUUID) else { - throw PeripheralManagerError.unknownCharacteristic - } - - guard !characteristic.isNotifying else { - continue - } - - try setNotifyValue(true, for: characteristic, timeout: discoveryTimeout) - } - } - } -} - -extension CBManagerState { - var description: String { - switch self { - case .poweredOff: - return "poweredOff" - case .poweredOn: - return "poweredOff" - case .resetting: - return "resetting" - case .unauthorized: - return "unauthorized" - case .unknown: - return "unknown" - case .unsupported: - return "unsupported" - @unknown default: - return "unknown(\(rawValue))" - } - } -} - -extension CBPeripheralState { - var description: String { - switch self { - case .connected: - return "connected" - case .disconnected: - return "disconnected" - case .connecting: - return "connecting" - case .disconnecting: - return "disconnecting" - @unknown default: - return "unknown(\(rawValue))" - } - } -} - - -// MARK: - Synchronous Commands -extension G7PeripheralManager { - /// - Throws: PeripheralManagerError - func runCommand(timeout: TimeInterval, command: () -> Void) throws { - // Prelude - dispatchPrecondition(condition: .onQueue(queue)) - guard central?.state == .poweredOn && peripheral.state == .connected else { - log.debug("Unable to run command: central state = %{public}@, peripheral state = %{public}@", String(describing: central?.state.description), String(describing: peripheral.state)) - throw PeripheralManagerError.notReady - } - - commandLock.lock() - - defer { - commandLock.unlock() - } - - guard commandConditions.isEmpty else { - throw PeripheralManagerError.invalidConfiguration - } - - // Run - command() - - guard !commandConditions.isEmpty else { - // If the command didn't add any conditions, then finish immediately - return - } - - // Postlude - let signaled = commandLock.wait(until: Date(timeIntervalSinceNow: timeout)) - - defer { - commandError = nil - commandConditions = [] - } - - guard signaled else { - throw PeripheralManagerError.timeout - } - - if let error = commandError { - throw PeripheralManagerError.cbPeripheralError(error) - } - } - - /// It's illegal to call this without first acquiring the commandLock - /// - /// - Parameter condition: The condition to add - func addCondition(_ condition: CommandCondition) { - dispatchPrecondition(condition: .onQueue(queue)) - commandConditions.append(condition) - } - - func discoverServices(_ serviceUUIDs: [CBUUID], timeout: TimeInterval) throws { - let servicesToDiscover = peripheral.servicesToDiscover(from: serviceUUIDs) - - log.debug("Discovering servicesToDiscover %@", String(describing: servicesToDiscover)) - - guard servicesToDiscover.count > 0 else { - return - } - - try runCommand(timeout: timeout) { - addCondition(.discoverServices) - - log.debug("discoverServices %@", String(describing: serviceUUIDs)) - - peripheral.discoverServices(serviceUUIDs) - } - } - - func discoverCharacteristics(_ characteristicUUIDs: [CBUUID], for service: CBService, timeout: TimeInterval) throws { - - log.debug("all uuids: %@", String(describing: characteristicUUIDs)) - - let knownCharacteristicUUIDs = service.characteristics?.compactMap({ $0.uuid }) ?? [] - log.debug("knownCharacteristicUUIDs: %@", String(describing: knownCharacteristicUUIDs)) - - let characteristicsToDiscover = peripheral.characteristicsToDiscover(from: characteristicUUIDs, for: service) - - log.debug("characteristicsToDiscover: %@", String(describing: characteristicsToDiscover)) - - guard characteristicsToDiscover.count > 0 else { - return - } - - try runCommand(timeout: timeout) { - addCondition(.discoverCharacteristicsForService(serviceUUID: service.uuid)) - - log.debug("Discovering characteristics %@ for %@", String(describing: characteristicsToDiscover), String(describing: peripheral)) - peripheral.discoverCharacteristics(characteristicsToDiscover, for: service) - } - } - - /// - Throws: PeripheralManagerError - func setNotifyValue(_ enabled: Bool, for characteristic: CBCharacteristic, timeout: TimeInterval) throws { - try runCommand(timeout: timeout) { - addCondition(.notificationStateUpdate(characteristicUUID: characteristic.uuid, enabled: enabled)) - log.debug("Set notify %@ for %@", String(describing: enabled), String(describing: peripheral)) - peripheral.setNotifyValue(enabled, for: characteristic) - } - } - - /// - Throws: PeripheralManagerError - func readValue(for characteristic: CBCharacteristic, timeout: TimeInterval) throws -> Data? { - try runCommand(timeout: timeout) { - addCondition(.valueUpdate(characteristic: characteristic, matching: nil)) - - peripheral.readValue(for: characteristic) - } - - return characteristic.value - } - - /// - Throws: PeripheralManagerError - func wait(for characteristic: CBCharacteristic, timeout: TimeInterval) throws -> Data { - try runCommand(timeout: timeout) { - addCondition(.valueUpdate(characteristic: characteristic, matching: nil)) - } - - guard let value = characteristic.value else { - throw PeripheralManagerError.timeout - } - - return value - } - - /// - Throws: PeripheralManagerError - func writeValue(_ value: Data, for characteristic: CBCharacteristic, type: CBCharacteristicWriteType, timeout: TimeInterval) throws { - try runCommand(timeout: timeout) { - if case .withResponse = type { - addCondition(.write(characteristic: characteristic)) - } - - peripheral.writeValue(value, for: characteristic, type: type) - } - } -} - - -// MARK: - Delegate methods executed on the central's queue -extension G7PeripheralManager: CBPeripheralDelegate { - - func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .discoverServices = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .discoverCharacteristicsForService(serviceUUID: service.uuid) = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .notificationStateUpdate(characteristicUUID: characteristic.uuid, enabled: characteristic.isNotifying) = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .write(characteristic: characteristic) = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { - commandLock.lock() - - var notifyDelegate = false - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .valueUpdate(characteristic: characteristic, matching: let matching) = condition { - return matching?(characteristic.value) ?? true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } else if let macro = configuration.valueUpdateMacros[characteristic.uuid] { - macro(self) - } else if commandConditions.isEmpty { - notifyDelegate = true // execute after the unlock - } - - commandLock.unlock() - - if notifyDelegate { - // If we weren't expecting this notification, pass it along to the delegate - delegate?.peripheralManager(self, didUpdateValueFor: characteristic) - } - } - - func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) { - delegate?.peripheralManager(self, didReadRSSI: RSSI, error: error) - } - - func peripheralDidUpdateName(_ peripheral: CBPeripheral) { - delegate?.peripheralManagerDidUpdateName(self) - } -} - - -extension G7PeripheralManager: CBCentralManagerDelegate { - func centralManagerDidUpdateState(_ central: CBCentralManager) { - switch central.state { - case .poweredOn: - log.debug("centralManagerDidUpdateState to poweredOn") - assertConfiguration() - default: - break - } - } - - func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { - log.debug("didConnect to %{public}@", peripheral.identifier.uuidString) - switch peripheral.state { - case .connected: - assertConfiguration() - default: - break - } - } -} - - -extension G7PeripheralManager { - public override var debugDescription: String { - var items = [ - "## G7PeripheralManager", - "peripheral: \(peripheral)", - ] - queue.sync { - items.append("needsConfiguration: \(needsConfiguration)") - } - return items.joined(separator: "\n") - } -} - -extension G7PeripheralManager { - private func getCharacteristicWithUUID(_ uuid: CGMServiceCharacteristicUUID) -> CBCharacteristic? { - return peripheral.getCharacteristicWithUUID(uuid) - } - - func setNotifyValue(_ enabled: Bool, - for characteristicUUID: CGMServiceCharacteristicUUID, - timeout: TimeInterval = 2) throws - { - guard let characteristic = getCharacteristicWithUUID(characteristicUUID) else { - throw PeripheralManagerError.unknownCharacteristic - } - - try setNotifyValue(enabled, for: characteristic, timeout: timeout) - } - -} - - -fileprivate extension CBPeripheral { - func getServiceWithUUID(_ uuid: SensorServiceUUID) -> CBService? { - return services?.itemWithUUIDString(uuid.rawValue) - } - - func getCharacteristicForServiceUUID(_ serviceUUID: SensorServiceUUID, withUUIDString UUIDString: String) -> CBCharacteristic? { - guard let characteristics = getServiceWithUUID(serviceUUID)?.characteristics else { - return nil - } - - return characteristics.itemWithUUIDString(UUIDString) - } - - func getCharacteristicWithUUID(_ uuid: CGMServiceCharacteristicUUID) -> CBCharacteristic? { - return getCharacteristicForServiceUUID(.cgmService, withUUIDString: uuid.rawValue) - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7Sensor.swift b/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7Sensor.swift deleted file mode 100644 index 20667e9f0..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/G7CGMManager/G7Sensor.swift +++ /dev/null @@ -1,311 +0,0 @@ -// -// G7Sensor.swift -// CGMBLEKit -// -// Created by Pete Schwamb on 9/24/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import CoreBluetooth -import HealthKit -import os.log - - -public protocol G7SensorDelegate: AnyObject { - func sensorDidConnect(_ sensor: G7Sensor, name: String) - - func sensorDisconnected(_ sensor: G7Sensor, suspectedEndOfSession: Bool) - - func sensor(_ sensor: G7Sensor, didError error: Error) - - func sensor(_ sensor: G7Sensor, didRead glucose: G7GlucoseMessage) - - func sensor(_ sensor: G7Sensor, didReadBackfill backfill: [G7BackfillMessage]) - - // If this returns true, then start following this sensor - func sensor(_ sensor: G7Sensor, didDiscoverNewSensor name: String, activatedAt: Date) -> Bool - - // This is triggered for connection/disconnection events, and enabling/disabling scan - func sensorConnectionStatusDidUpdate(_ sensor: G7Sensor) -} - -public enum G7SensorError: Error { - case authenticationError(String) - case controlError(String) - case observationError(String) -} - -extension G7SensorError: CustomStringConvertible { - public var description: String { - switch self { - case .authenticationError(let description): - return description - case .controlError(let description): - return description - case .observationError(let description): - return description - } - } -} - -public enum G7SensorLifecycleState { - case searching - case warmup - case ok - case failed - case gracePeriod - case expired -} - - -public final class G7Sensor: G7BluetoothManagerDelegate { - public static let lifetime = TimeInterval(hours: 10 * 24) - public static let warmupDuration = TimeInterval(minutes: 25) - public static let gracePeriod = TimeInterval(hours: 12) - - public weak var delegate: G7SensorDelegate? - - // MARK: - Passive observation state, confined to `bluetoothManager.managerQueue` - - /// The initial activation date of the sensor - var activationDate: Date? - - /// The date of last connection - private var lastConnection: Date? - - /// Used to detect connections that do not authenticate, signalling possible sensor switchover - private var pendingAuth: Bool = false - - /// The backfill data buffer - private var backfillBuffer: [G7BackfillMessage] = [] - - // MARK: - - - private let log = OSLog(category: "G7Sensor") - - private let bluetoothManager = G7BluetoothManager() - - private let delegateQueue = DispatchQueue(label: "com.loopkit.G7Sensor.delegateQueue", qos: .unspecified) - - private var sensorID: String? - - public func setSensorId(_ newId: String) { - self.sensorID = newId - } - - public init(sensorID: String?) { - self.sensorID = sensorID - bluetoothManager.delegate = self - } - - public func scanForNewSensor() { - self.sensorID = nil - bluetoothManager.disconnect() - bluetoothManager.forgetPeripheral() - bluetoothManager.scanForPeripheral() - } - - public func resumeScanning() { - bluetoothManager.scanForPeripheral() - } - - public func stopScanning() { - bluetoothManager.disconnect() - } - - public var isScanning: Bool { - return bluetoothManager.isScanning - } - - public var isConnected: Bool { - return bluetoothManager.isConnected - } - - private func handleGlucoseMessage(message: G7GlucoseMessage, peripheralManager: G7PeripheralManager) { - activationDate = Date().addingTimeInterval(-TimeInterval(message.glucoseTimestamp)) - peripheralManager.perform { (peripheral) in - self.log.debug("Listening for backfill responses") - // Subscribe to backfill updates - do { - try peripheral.listenToCharacteristic(.backfill) - } catch let error { - self.log.error("Error trying to enable notifications on backfill characteristic: %{public}@", String(describing: error)) - self.delegateQueue.async { - self.delegate?.sensor(self, didError: error) - } - } - } - if sensorID == nil, let name = peripheralManager.peripheral.name, let activationDate = activationDate { - delegateQueue.async { - guard let delegate = self.delegate else { - return - } - - if delegate.sensor(self, didDiscoverNewSensor: name, activatedAt: activationDate) { - self.sensorID = name - self.activationDate = activationDate - self.delegate?.sensor(self, didRead: message) - self.bluetoothManager.stopScanning() - } - } - } else if sensorID != nil { - delegateQueue.async { - self.delegate?.sensor(self, didRead: message) - } - } else { - self.log.error("Dropping unhandled glucose message: %{public}@", String(describing: message)) - } - } - - // MARK: - BluetoothManagerDelegate - - func bluetoothManager(_ manager: G7BluetoothManager, readied peripheralManager: G7PeripheralManager) -> Bool { - var shouldStopScanning = false; - - if let sensorID = sensorID, sensorID == peripheralManager.peripheral.name { - shouldStopScanning = true - delegateQueue.async { - self.delegate?.sensorDidConnect(self, name: sensorID) - } - } - - peripheralManager.perform { (peripheral) in - self.log.info("Listening for authentication responses for %{public}@", String(describing: peripheralManager.peripheral.name)) - do { - try peripheral.listenToCharacteristic(.authentication) - self.pendingAuth = true - } catch let error { - self.delegateQueue.async { - self.delegate?.sensor(self, didError: error) - } - } - } - return shouldStopScanning - } - - func bluetoothManager(_ manager: G7BluetoothManager, readyingFailed peripheralManager: G7PeripheralManager, with error: Error) { - delegateQueue.async { - self.delegate?.sensor(self, didError: error) - } - } - - func peripheralDidDisconnect(_ manager: G7BluetoothManager, peripheralManager: G7PeripheralManager, wasRemoteDisconnect: Bool) { - if let sensorID = sensorID, sensorID == peripheralManager.peripheral.name { - - let suspectedEndOfSession: Bool - if pendingAuth && wasRemoteDisconnect { - suspectedEndOfSession = true // Normal disconnect without auth is likely that G7 app stopped this session - } else { - suspectedEndOfSession = false - } - pendingAuth = false - - delegateQueue.async { - self.delegate?.sensorDisconnected(self, suspectedEndOfSession: suspectedEndOfSession) - } - } - } - - func bluetoothManager(_ manager: G7BluetoothManager, shouldConnectPeripheral peripheral: CBPeripheral) -> PeripheralConnectionCommand { - - guard let name = peripheral.name else { - log.debug("Not connecting to unnamed peripheral: %{public}@", String(describing: peripheral)) - return .ignore - } - - /// The Dexcom G7 advertises a peripheral name of "DXCMxx", and later reports a full name of "Dexcomxx" - /// Dexcom One+ peripheral name start with "DX02" - if name.hasPrefix("DXCM") || name.hasPrefix("DX02"){ - // If we're following this name or if we're scanning, connect - if let sensorName = sensorID, name.suffix(2) == sensorName.suffix(2) { - return .makeActive - } else if sensorID == nil { - return .connect - } - } - - log.info("Not connecting to peripheral: %{public}@", name) - return .ignore - } - - func bluetoothManager(_ manager: G7BluetoothManager, peripheralManager: G7PeripheralManager, didReceiveControlResponse response: Data) { - - guard response.count > 0 else { return } - - log.debug("Received control response: %{public}@", response.hexadecimalString) - - switch G7Opcode(rawValue: response[0]) { - case .glucoseTx?: - if let glucoseMessage = G7GlucoseMessage(data: response) { - handleGlucoseMessage(message: glucoseMessage, peripheralManager: peripheralManager) - } else { - delegateQueue.async { - self.delegate?.sensor(self, didError: G7SensorError.observationError("Unable to handle glucose control response")) - } - } - case .backfillFinished: - if backfillBuffer.count > 0 { - delegateQueue.async { - self.delegate?.sensor(self, didReadBackfill: self.backfillBuffer) - self.backfillBuffer = [] - } - } - default: - // We ignore all other known opcodes - break - } - } - - func bluetoothManager(_ manager: G7BluetoothManager, didReceiveBackfillResponse response: Data) { - - log.debug("Received backfill response: %{public}@", response.hexadecimalString) - - guard response.count == 9 else { - return - } - - if let msg = G7BackfillMessage(data: response) { - backfillBuffer.append(msg) - } - } - - func bluetoothManager(_ manager: G7BluetoothManager, peripheralManager: G7PeripheralManager, didReceiveAuthenticationResponse response: Data) { - - if let message = AuthChallengeRxMessage(data: response), message.isBonded, message.isAuthenticated { - log.debug("Observed authenticated session. enabling notifications for control characteristic.") - pendingAuth = false - peripheralManager.perform { (peripheral) in - do { - try peripheral.listenToCharacteristic(.control) - } catch let error { - self.log.error("Error trying to enable notifications on control characteristic: %{public}@", String(describing: error)) - self.delegateQueue.async { - self.delegate?.sensor(self, didError: error) - } - } - } - } else { - log.debug("Ignoring authentication response: %{public}@", response.hexadecimalString) - } - } - - func bluetoothManagerScanningStatusDidChange(_ manager: G7BluetoothManager) { - self.delegateQueue.async { - self.delegate?.sensorConnectionStatusDidUpdate(self) - } - } -} - - -// MARK: - Helpers -fileprivate extension G7PeripheralManager { - - func listenToCharacteristic(_ characteristic: CGMServiceCharacteristicUUID) throws { - do { - try setNotifyValue(true, for: characteristic) - } catch let error { - throw G7SensorError.controlError("Error enabling notification for \(characteristic): \(error)") - } - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/G7SensorKit.h b/Dependencies/G7SensorKit/G7SensorKit/G7SensorKit.h deleted file mode 100644 index a1e44ad8e..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/G7SensorKit.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// G7SensorKit.h -// G7SensorKit -// -// Created by Pete Schwamb on 11/11/22. -// - -#import - -//! Project version number for G7SensorKit. -FOUNDATION_EXPORT double G7SensorKitVersionNumber; - -//! Project version string for G7SensorKit. -FOUNDATION_EXPORT const unsigned char G7SensorKitVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/G7SensorKit/G7SensorKit/GlucoseLimits.swift b/Dependencies/G7SensorKit/G7SensorKit/GlucoseLimits.swift deleted file mode 100644 index b9e7bff6e..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/GlucoseLimits.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// GlucoseLimits.swift -// G7SensorKit -// -// Created by Pete Schwamb on 9/24/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -enum GlucoseLimits { - static var minimum: UInt16 = 40 - static var maximum: UInt16 = 400 -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/Messages/AuthChallengeRxMessage.swift b/Dependencies/G7SensorKit/G7SensorKit/Messages/AuthChallengeRxMessage.swift deleted file mode 100644 index 3968f77c5..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/Messages/AuthChallengeRxMessage.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// AuthChallengeRxMessage.swift -// xDrip5 -// -// Created by Nathan Racklyeft on 11/22/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - -struct AuthChallengeRxMessage: SensorMessage { - let isAuthenticated: Bool - let isBonded: Bool - - init?(data: Data) { - guard data.count >= 3 else { - return nil - } - - guard data.starts(with: .authChallengeRx) else { - return nil - } - - isAuthenticated = data[1] == 0x1 - isBonded = data[2] == 0x1 - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/Messages/G7GlucoseMessage.swift b/Dependencies/G7SensorKit/G7SensorKit/Messages/G7GlucoseMessage.swift deleted file mode 100644 index c67d40552..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/Messages/G7GlucoseMessage.swift +++ /dev/null @@ -1,130 +0,0 @@ -// -// G7GlucoseMessage.swift -// CGMBLEKit -// -// Created by Pete Schwamb on 9/24/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -public struct G7GlucoseMessage: SensorMessage, Equatable { - //public let status: UInt8 - //public let sequence: UInt32 - public let glucose: UInt16? - public let predicted: UInt16? - public let glucoseIsDisplayOnly: Bool - public let messageTimestamp: UInt32 // Seconds since pairing of the *message*. Subtract age to get timestamp of glucose - public let algorithmState: AlgorithmState - public let sequence: UInt16 - public let trend: Double? - public let data: Data - public let age: UInt8 // Amount of time elapsed (seconds) from sensor reading to BLE comms - - public var hasReliableGlucose: Bool { - return algorithmState.hasReliableGlucose - } - - public var glucoseTimestamp: UInt32 { - return messageTimestamp - UInt32(age) - } - - public var trendType: LoopKit.GlucoseTrend? { - guard let trend = trend else { - return nil - } - - switch trend { - case let x where x <= -3.0: - return .downDownDown - case let x where x <= -2.0: - return .downDown - case let x where x <= -1.0: - return .down - case let x where x < 1.0: - return .flat - case let x where x < 2.0: - return .up - case let x where x < 3.0: - return .upUp - default: - return .upUpUp - } - } - - public var condition: GlucoseCondition? { - guard let glucose = glucose else { - return nil - } - - if glucose < GlucoseLimits.minimum { - return .belowRange - } else if glucose > GlucoseLimits.maximum { - return .aboveRange - } else { - return nil - } - } - - init?(data: Data) { - // 0 1 2 3 4 5 6 7 8 9 10 11 1213 14 15 1617 18 - // TTTTTTTT SQSQ AG BGBG SS TR PRPR C - // 0x4e 00 d5070000 0900 00 01 05 00 6100 06 01 ffff 0e - // TTTTTTTT = timestamp - // SQSQ = sequence - // AG = age - // BGBG = glucose - // SS = algorithm state - // TR = trend - // PRPR = predicted - // C = calibration - - guard data.count >= 19 else { - return nil - } - - guard data[1] == 00 else { - return nil - } - - messageTimestamp = data[2..<6].toInt() - - sequence = data[6..<8].to(UInt16.self) - - age = data[10] - - let glucoseData = data[12..<14].to(UInt16.self) - if glucoseData != 0xffff { - glucose = glucoseData & 0xfff - glucoseIsDisplayOnly = (data[18] & 0x10) > 0 - } else { - glucose = nil - glucoseIsDisplayOnly = false - } - - let predictionData = data[16..<18].to(UInt16.self) - if predictionData != 0xffff { - predicted = predictionData & 0xfff - } else { - predicted = nil - } - - algorithmState = AlgorithmState(rawValue: data[14]) - - if data[15] == 0x7f { - trend = nil - } else { - trend = Double(Int8(bitPattern: data[15])) / 10 - } - - self.data = data - } - -} - -extension G7GlucoseMessage: CustomDebugStringConvertible { - public var debugDescription: String { - return "G7GlucoseMessage(glucose:\(String(describing: glucose)), sequence:\(sequence) glucoseIsDisplayOnly:\(glucoseIsDisplayOnly) state:\(String(describing: algorithmState)) messageTimestamp:\(messageTimestamp) age:\(age), data:\(data.hexadecimalString))" - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/Messages/G7Opcode.swift b/Dependencies/G7SensorKit/G7SensorKit/Messages/G7Opcode.swift deleted file mode 100644 index 3f4272f60..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/Messages/G7Opcode.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// G7Opcode.swift -// CGMBLEKit -// -// Created by Pete Schwamb on 9/24/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -enum G7Opcode: UInt8 { - case authChallengeRx = 0x05 - case glucoseTx = 0x4e - case backfillFinished = 0x59 -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/Messages/SensorMessage.swift b/Dependencies/G7SensorKit/G7SensorKit/Messages/SensorMessage.swift deleted file mode 100644 index 1e3cef6ff..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/Messages/SensorMessage.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// SensorMessage.swift -// G7SensorKit -// -// Created by Pete Schwamb on 9/24/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension Data { - func starts(with opcode: G7Opcode) -> Bool { - guard count > 0 else { - return false - } - - return self[startIndex] == opcode.rawValue - } -} - -/// A data sequence received by the sensor -protocol SensorMessage { - init?(data: Data) -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/OSLog.swift b/Dependencies/G7SensorKit/G7SensorKit/OSLog.swift deleted file mode 100644 index 25f8f4922..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/OSLog.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// OSLog.swift -// Loop -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import os.log - - -extension OSLog { - convenience init(category: String) { - self.init(subsystem: "org.loopkit.G7SensorKit", category: category) - } - - func debug(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .debug, args) - } - - func info(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .info, args) - } - - func `default`(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .default, args) - } - - func error(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .error, args) - } - - private func log(_ message: StaticString, type: OSLogType, _ args: [CVarArg]) { - switch args.count { - case 0: - os_log(message, log: self, type: type) - case 1: - os_log(message, log: self, type: type, args[0]) - case 2: - os_log(message, log: self, type: type, args[0], args[1]) - case 3: - os_log(message, log: self, type: type, args[0], args[1], args[2]) - case 4: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3]) - case 5: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4]) - default: - os_log(message, log: self, type: type, args) - } - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKit/cs.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/cs.lproj/Localizable.strings deleted file mode 100644 index 2545fb307..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/cs.lproj/Localizable.strings +++ /dev/null @@ -1,21 +0,0 @@ -/* CGM display title */ -"Dexcom G7" = "Dexcom G7"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Údaje o glukóze nejsou k dispozici"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Platnost senzoru vypršela"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Senzor selhal"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Senzor je v pořádku"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Senzor je zastaven"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Senzor se zahřívá"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/da.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/da.lproj/Localizable.strings deleted file mode 100644 index 7e7f79204..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/da.lproj/Localizable.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* CGM display title */ -"Dexcom G7" = "Dexcom G7"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glukosedata ikke tilgængeligt"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor udløbet"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensorfejl"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor i ukendt tilstand %1$d"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor er OK"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Sensor er stoppet"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor varmer op"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/de.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/de.lproj/Localizable.strings deleted file mode 100644 index ec8749479..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/de.lproj/Localizable.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* CGM display title */ -"Dexcom G7" = "Dexcom G7"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Blutzuckerdaten sind nicht verfügbar"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor abgelaufen"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensorfehler"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor befindet sich in unbekanntem Zustand %1$d"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor ist OK"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Sensor ist gestoppt"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor befindet sich in der Aufwärmphase"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/en.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/en.lproj/Localizable.strings deleted file mode 100644 index 233b32c18..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/en.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - G7SensorKit - - Created by Pete Schwamb on 3/20/23. - -*/ diff --git a/Dependencies/G7SensorKit/G7SensorKit/es.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/es.lproj/Localizable.strings deleted file mode 100644 index b52e36f89..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/es.lproj/Localizable.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* CGM display title */ -"Dexcom G7" = "Dexcom G7"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Los datos de glucosa no están disponibles"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor caducado"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Fallo del sensor"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "El sensor está en estado desconocido %1$d"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "El sensor está bien"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "El sensor está en pausa"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "El sensor se está calentando"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/fi.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/fi.lproj/Localizable.strings deleted file mode 100644 index d3d114f90..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/fi.lproj/Localizable.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glukoositietoja ei ole saatavilla"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Anturi on tuntemattomassa tilassa %1$d"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Anturi on pysäytetty"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Anturi lämpenee"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/fr.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/fr.lproj/Localizable.strings deleted file mode 100644 index 7b655b0e0..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/fr.lproj/Localizable.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* CGM display title */ -"Dexcom G7" = "Dexcom G7"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Les données de glycémie ne sont pas disponibles"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Capteur expiré"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Erreur de capteur"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Le capteur est dans un état inconnu %1$d"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Le capteur est OK"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Le capteur est arrêté"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Le capteur est en préchauffage"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/he.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/he.lproj/Localizable.strings deleted file mode 100644 index 6232d3755..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/he.lproj/Localizable.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "חיישן נעצר"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "חיישן מתחמם"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/hi.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/hi.lproj/Localizable.strings deleted file mode 100644 index 966b632aa..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/hi.lproj/Localizable.strings +++ /dev/null @@ -1,21 +0,0 @@ -/* CGM display title */ -"Dexcom G7" = "Dexcom G7"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "ग्लूकोस डेटा उपलब्ध नहीं है"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "सेन्सर समाप्त हो गया"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "सेन्सर ख़राब हो गया है"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "सेन्सर सही है"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "सेन्सर समाप्त हो गया"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "सेन्सर अपने शुरुआती समय में है"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/hu.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/hu.lproj/Localizable.strings deleted file mode 100644 index 233b32c18..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/hu.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - G7SensorKit - - Created by Pete Schwamb on 3/20/23. - -*/ diff --git a/Dependencies/G7SensorKit/G7SensorKit/it.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/it.lproj/Localizable.strings deleted file mode 100644 index d24f3b1fa..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/it.lproj/Localizable.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* CGM display title */ -"Dexcom G7" = "Dexcom G7"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "I dati della glicemia non sono disponibili"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensore scaduto"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensore Fallito"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Il Sensore e' in un stato%1$d sconosciuto"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensore è OK"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Il Sensore e' fermato"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Il Sensore si sta riscaldando"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/ja.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/ja.lproj/Localizable.strings deleted file mode 100644 index 5e068ee72..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/ja.lproj/Localizable.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Error description for unreliable state */ -"Glucose data is unavailable" = "グルコースデータがありません"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "センサーの状態が不明です %1$d"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "センサーが停止しています"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "センサーが準備中です"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/nb.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/nb.lproj/Localizable.strings deleted file mode 100644 index a09c40602..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/nb.lproj/Localizable.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* CGM display title */ -"Dexcom G7" = "Dexcom G7"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Blodsukker er utilgjengelig"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor utløpt"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor feilet"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor er i ukjent tilstand %1$d"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor er OK"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Sensor er stoppet"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor varmer opp"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/nl.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/nl.lproj/Localizable.strings deleted file mode 100644 index c04a5ea12..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/nl.lproj/Localizable.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* CGM display title */ -"Dexcom G7" = "Dexcom G7"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucosegegevens zijn niet beschikbaar"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor verlopen"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor mislukt"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Onbekende sensorstatus %1$d"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is OK"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Sensor gestopt"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor aan het opwarmen"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/pl.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/pl.lproj/Localizable.strings deleted file mode 100644 index ee07e274c..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/pl.lproj/Localizable.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* CGM display title */ -"Dexcom G7" = "Dexcom G7"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Dane o poziomie glukozy są niedostępne"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor stracił ważność"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Błąd sensora"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor jest w nieznanym stanie %1$d"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor jest OK"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Sensor został zatrzymany"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor jest w fazie rozruchu"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/pt-BR.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/pt-BR.lproj/Localizable.strings deleted file mode 100644 index cb6222931..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Os dados de glicose não estão disponíveis"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "O sensor está em um estado desconhecido %1$d"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "O sensor está parado"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "O sensor está aquecendo"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/ro.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/ro.lproj/Localizable.strings deleted file mode 100644 index 47fdefeef..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/ro.lproj/Localizable.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* CGM display title */ -"Dexcom G7" = "Dexcom G7"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Datele despre glucoză nu sunt disponibile"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Senzorul a expirat"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Senzorul a eșuat"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Starea senzorului este necunoscută"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Senzorul este OK"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Senzorul e oprit"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Senzorul se pregătește"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/ru.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/ru.lproj/Localizable.strings deleted file mode 100644 index e19db179b..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/ru.lproj/Localizable.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* CGM display title */ -"Dexcom G7" = "Dexcom G7"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Данные глюкозы недоступны"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Сенсор истек"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Ошибка сенсора"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Неизвестное состояние сенсора%1$d"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Сенсор ОК"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Сенсор остановлен"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Сенсор прогревается"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/sk.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/sk.lproj/Localizable.strings deleted file mode 100644 index 4972ecebe..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/sk.lproj/Localizable.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* CGM display title */ -"Dexcom G7" = "Dexcom G7"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Údaje o glykémii nie sú k dispozícii"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Platnosť senzora vypršala"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Senzor zlyhal"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Senzor je v neznámom stave %1$d"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Senzor je v poriadku"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Senzor je zastavený"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Senzor sa zahrieva"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/sv.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/sv.lproj/Localizable.strings deleted file mode 100644 index 7eb4c335f..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/sv.lproj/Localizable.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glukosvärden är inte tillgängliga"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensorns status är okänd %1$d"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Sensorn har stoppats"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensorn värmer upp"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/tr.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/tr.lproj/Localizable.strings deleted file mode 100644 index f7f296ac7..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/tr.lproj/Localizable.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* CGM display title */ -"Dexcom G7" = "Dexcom G7"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "KŞ verileri mevcut değil"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensörün süresi doldu"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensör hatası"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensör bilinmeyen durumda %1$d"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensör iyi durumda"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Sensör durdu"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensör ısınıyor"; - diff --git a/Dependencies/G7SensorKit/G7SensorKit/vi.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKit/vi.lproj/Localizable.strings deleted file mode 100644 index 71e436ce2..000000000 --- a/Dependencies/G7SensorKit/G7SensorKit/vi.lproj/Localizable.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Dữ liệu glucose không có sẵn"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Cảm biến ở trạng thái không xác định %1$d"; - -/* The description of sensor algorithm state when sensor is stopped. */ -"Sensor is stopped" = "Cảm biến bị dừng"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Cảm biến đang nóng lên"; - diff --git a/Dependencies/G7SensorKit/G7SensorKitTests/G7GlucoseMessageTests.swift b/Dependencies/G7SensorKit/G7SensorKitTests/G7GlucoseMessageTests.swift deleted file mode 100644 index bd6c9040c..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitTests/G7GlucoseMessageTests.swift +++ /dev/null @@ -1,160 +0,0 @@ -// -// G7GlucoseMessageTests.swift -// CGMBLEKitTests -// -// Created by Pete Schwamb on 9/25/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import G7SensorKit - -final class G7GlucoseMessageTests: XCTestCase { - - func testG7MessageData() { - let data = Data(hexadecimalString: "4e00c35501002601000106008a00060187000f")! - let message = G7GlucoseMessage(data: data)! - - XCTAssertEqual(138, message.glucose) - XCTAssertEqual(87485, message.glucoseTimestamp) - XCTAssert(!message.glucoseIsDisplayOnly) - } - - func testG7MessageDataWithCalibration() { - let data = Data(hexadecimalString: "4e000ec10d00c00b00010000680006fe63001f")! - let message = G7GlucoseMessage(data: data)! - - XCTAssertEqual(104, message.glucose) - XCTAssertEqual(901390, message.glucoseTimestamp) - XCTAssert(message.glucoseIsDisplayOnly) - } - - func testG7MessageDataLifecycle() { - let startupMessagesHex = [ - "4e00b6000000010000006600ffff017fffff00", // 0 - "4e00cd000000030000010500ffff027fffff01", // 1 - "4e00f90100000400000105009100027effff02", // 2 - "4e00250300000500000105007d00027effff02", // 3 - "4e0051040000060000010500650002dfffff02", // 4 - "4e007d0500000700000105004e0002e7ffff02", // 5 - "4e00ab060000080000010700540006f5ffff0e", // 6 - "4e00d507000009000001050061000601ffff0e", // 7 - "4e004d440e00d40b0001d46b650018036a000e", // 8 - ] - let messages = startupMessagesHex.map { G7GlucoseMessage(data: Data(hexadecimalString: $0)!)! } - - XCTAssertNil(messages[0].glucose) - XCTAssertNil(messages[1].glucose) - XCTAssertEqual(145, messages[2].glucose) - - XCTAssertEqual(.known(.stopped), messages[0].algorithmState) - XCTAssertEqual(.known(.warmup), messages[1].algorithmState) - XCTAssertEqual(.known(.warmup), messages[2].algorithmState) - XCTAssertEqual(.known(.warmup), messages[3].algorithmState) - XCTAssertEqual(.known(.warmup), messages[4].algorithmState) - XCTAssertEqual(.known(.warmup), messages[5].algorithmState) - XCTAssertEqual(.known(.ok), messages[6].algorithmState) - XCTAssertEqual(.known(.ok), messages[7].algorithmState) - XCTAssertEqual(.known(.expired), messages[8].algorithmState) - - XCTAssertEqual(1, messages[0].sequence) - XCTAssertEqual(3, messages[1].sequence) - XCTAssertEqual(4, messages[2].sequence) - XCTAssertEqual(5, messages[3].sequence) - XCTAssertEqual(6, messages[4].sequence) - XCTAssertEqual(7, messages[5].sequence) - XCTAssertEqual(8, messages[6].sequence) - XCTAssertEqual(9, messages[7].sequence) - XCTAssertEqual(3028, messages[8].sequence) - - - XCTAssertEqual(80, messages[0].glucoseTimestamp) - XCTAssertEqual(200, messages[1].glucoseTimestamp) - XCTAssertEqual(500, messages[2].glucoseTimestamp) - XCTAssertEqual(800, messages[3].glucoseTimestamp) - XCTAssertEqual(1100, messages[4].glucoseTimestamp) - XCTAssertEqual(1400, messages[5].glucoseTimestamp) - XCTAssertEqual(1700, messages[6].glucoseTimestamp) - XCTAssertEqual(2000, messages[7].glucoseTimestamp) - XCTAssertEqual(934777, messages[8].glucoseTimestamp) - } - - func testG7MessageDataDetails() { - // 0 1 2 3 4 5 6 7 8 9 10 11 1213 14 15 16 17 18 - // TTTTTTTT SQSQ AG BGBG SS C - // 4e 00 a89c0000 8800 00 01 04 00 8d00 06 03 8a 00 0f - - //2022-09-12 09:18:06.821253 readEGV(txTime=40104,seq=136,session=1,age=4,value=141,pred=138,algo=6,subAlgo=15,rate=3) - let data = Data(hexadecimalString: "4e00a89c00008800000104008d0006038a000f")! - let message = G7GlucoseMessage(data: data)! - - XCTAssertEqual(141, message.glucose) - XCTAssertEqual(40100, message.glucoseTimestamp) - XCTAssertEqual(136, message.sequence) - XCTAssertEqual(4, message.age) - XCTAssertEqual(138, message.predicted) - XCTAssertEqual(0.3, message.trend) - XCTAssertEqual(.known(.ok), message.algorithmState) - - XCTAssert(!message.glucoseIsDisplayOnly) - } - - func testG7MessageDataNegativeRate() { - let data = Data(hexadecimalString: "4e00c6cc0d00ca0b00010500610006fe5b000f")! - let message = G7GlucoseMessage(data: data)! - XCTAssertEqual(-0.2, message.trend) - } - - func testG7MessageDataMissingRate() { - let data = Data(hexadecimalString: "4e00c6cc0d00ca0b000105006100067f5b000f")! - let message = G7GlucoseMessage(data: data)! - XCTAssertNil(message.trend) - } -} - - - -// Activated 2022-09-24 17:39:31 +0000 - -// 0 1 2 3 4 5 6 7 8 9 10 11 1213 14 15 16 17 18 -// TTTTTTTT BGBG SS C -// 2022-09-24 17:47:23 4e 00 ea010000 04 00 00 01 05 00 6c00 02 7e ff ff 02 -// 2022-09-24 17:52:27 4e 00 1a030000 05 00 00 01 09 00 5300 02 7e ff ff 02 -// 2022-09-24 17:57:25 4e 00 44040000 06 00 00 01 07 00 4500 02 e7 ff ff 02 -// 2022-09-24 18:02:27 4e 00 73050000 07 00 00 01 0a 00 3a00 02 f4 ff ff 02 -// 2022-09-24 18:07:21 4e 00 99060000 08 00 00 01 04 00 4800 06 02 ff ff 0e -// 2022-09-24 18:22:26 4e 00 220a0000 0b 00 00 01 09 00 4f00 06 fe ff ff 0e - -// 2022-09-24 18:27:22 4e 00 4a0b0000 0c 00 00 01 05 00 4900 06 f9 37 00 0f -// 2022-09-24 18:27:23 (txInfo: 7815(379013053518), SW13354, 73 mg⁠/⁠dL, Predictive: 55 mg⁠/⁠dL, Rate: -0.7 @ 2022-09-24T13:27:17-05:00, sessionInfo: Optional(Start: 2022-09-24T12:40:17-05:00, End: 2022-10-05T00:40:17-05:00)), isTimeCertain: true - -// 2022-09-24 22:32:24 4e 00 b7440000 3d 00 00 01 06 00 7f00 06 03 83 00 0f -//2022-09-24 17:32:27.248461 -0500 info 388 Dexcom G7 DisplayState: displayingGlucose(txInfo: 7815(379013053518), SW13354, 127 mg⁠/⁠dL, Predictive: 131 mg⁠/⁠dL, Rate: 0.3 @ 2022-09-24T17:32:18-05:00, sessionInfo: Optional(Start: 2022-09-24T12:40:18-05:00, End: 2022-10-05T00:40:18-05:00)), isTimeCertain: true - - - - -// 0 1 2 3 4 5 6 7 8 9 10 11 1213 14 15 16 17 18 -// TTTTTTTT BGBG SS C -// 2022-10-04 23:27:39 106 timestamp:902888 4e 00 e8c60d00 c5 0b 00 01 03 00 6a00 06 01 6a 00 0f -// 2022-10-04 23:32:40 101 timestamp:903189 4e 00 15c80d00 c6 0b 00 01 04 00 6500 06 fe 61 00 0f -// 2022-10-04 23:37:39 98 timestamp:903488 4e 00 40c90d00 c7 0b 00 01 03 00 6200 06 fc 5e 00 0f -// 2022-10-04 23:42:39 100 timestamp:903789 4e 00 6dca0d00 c8 0b 00 01 04 00 6400 06 ff 5e 00 0f -// 2022-10-04 23:47:41 97 timestamp:904090 4e 00 9acb0d00 c9 0b 00 01 05 00 6100 06 fd 5c 00 0f - -// 2022-10-04 23:52:41 97 timestamp:904390 4e 00 c6cc0d00 ca 0b 00 01 05 00 6100 06 fe 5b 00 0f - -// 2022-10-04 23:52:41.100991 -0500 info 289 Dexcom G7 calBounds(signature=65,lastBG=100,lastBGTime=901259,processing=completeHigh,permitted=true,lastDisplay=phone,lastProcessingTime=901565) -// 2022-10-04 23:52:41.260740 -0500 info 289 Dexcom G7 DisplayState: displayingGlucose(txInfo: 7815(379013053518), SW13354, 97 mg⁠/⁠dL, Predictive: 91 mg⁠/⁠dL, Rate: -0.2 @ 2022-10-04T23:52:36-05:00, sessionInfo: Optional(Start: 2022-09-24T12:40:36-05:00, End: 2022-10-05T00:40:36-05:00)), isTimeCertain: true -// - -// 2022-10-04 23:57:52 98 timestamp:904701 4e 00 fdcd0d00 cb 0b 00 01 10 00 6200 06 00 5c 00 0f -// 2022-10-05 00:02:40 96 timestamp:904989 4e 00 1dcf0d00 cc 0b 00 01 04 00 6000 06 fe 5b 00 0f -// 2022-10-05 00:07:39 95 timestamp:905288 4e 00 48d00d00 cd 0b 00 01 03 00 5f00 06 fe 5a 00 0f -// 2022-10-05 08:17:43 101 timestamp:934692 4e 00 24430e00 d4 0b 00 01 ab 6a 6500 18 03 6a 00 0e -// 2022-10-05 08:22:40 101 timestamp:934989 4e 00 4d440e00 d4 0b 00 01 d4 6b 6500 18 03 6a 00 0e -// 2022-10-05 08:27:40 101 timestamp:935289 4e 00 79450e00 d4 0b 00 01 00 6d 6500 18 03 6a 00 0e -// 2022-10-05 08:32:42 101 timestamp:935590 4e 00 a6460e00 d4 0b 00 01 2d 6e 6500 18 03 6a 00 0e -// 2022-10-05 08:37:42 101 timestamp:935890 4e 00 d2470e00 d4 0b 00 01 59 6f 6500 18 03 6a 00 0e -// 2022-10-05 08:42:39 101 timestamp:936188 4e 00 fc480e00 d4 0b 00 01 83 70 6500 18 03 6a 00 0e -// 2022-10-05 08:47:39 101 timestamp:936488 4e 00 284a0e00 d4 0b 00 01 af 71 6500 18 03 6a 00 0e diff --git a/Dependencies/G7SensorKit/G7SensorKitTests/G7SensorKitTests.swift b/Dependencies/G7SensorKit/G7SensorKitTests/G7SensorKitTests.swift deleted file mode 100644 index 3b3d87195..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitTests/G7SensorKitTests.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// G7SensorKitTests.swift -// G7SensorKitTests -// -// Created by Pete Schwamb on 11/11/22. -// - -import XCTest -@testable import G7SensorKit - -class G7SensorKitTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. - } - - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } - } - -} diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/Assets.xcassets/Contents.json b/Dependencies/G7SensorKit/G7SensorKitUI/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/Assets.xcassets/g7.imageset/Contents.json b/Dependencies/G7SensorKit/G7SensorKitUI/Assets.xcassets/g7.imageset/Contents.json deleted file mode 100644 index b729fd599..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/Assets.xcassets/g7.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "g7.png", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/Assets.xcassets/g7.imageset/g7.png b/Dependencies/G7SensorKit/G7SensorKitUI/Assets.xcassets/g7.imageset/g7.png deleted file mode 100644 index 624f20c56..000000000 Binary files a/Dependencies/G7SensorKit/G7SensorKitUI/Assets.xcassets/g7.imageset/g7.png and /dev/null differ diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/Extensions/Image.swift b/Dependencies/G7SensorKit/G7SensorKitUI/Extensions/Image.swift deleted file mode 100644 index 2d9195642..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/Extensions/Image.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// Image.swift -// CGMBLEKitUI -// -// Created by Pete Schwamb on 9/24/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import SwiftUI - -extension Image { - init(frameworkImage name: String, decorative: Bool = false) { - if decorative { - self.init(decorative: name, bundle: FrameworkBundle.main) - } else { - self.init(name, bundle: FrameworkBundle.main) - } - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/G7CGMManager/G7CGMManager+UI.swift b/Dependencies/G7SensorKit/G7SensorKitUI/G7CGMManager/G7CGMManager+UI.swift deleted file mode 100644 index f5820d832..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/G7CGMManager/G7CGMManager+UI.swift +++ /dev/null @@ -1,139 +0,0 @@ -// -// G7CGMManager+UI.swift -// CGMBLEKitUI -// -// Created by Pete Schwamb on 9/24/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import G7SensorKit -import LoopKitUI -import LoopKit - -public struct G7DeviceStatusHighlight: DeviceStatusHighlight, Equatable { - public let localizedMessage: String - public let imageName: String - public let state: DeviceStatusHighlightState - init(localizedMessage: String, imageName: String, state: DeviceStatusHighlightState) { - self.localizedMessage = localizedMessage - self.imageName = imageName - self.state = state - } -} - -extension G7CGMManager: CGMManagerUI { - public static var onboardingImage: UIImage? { - return nil - } - - public static func setupViewController(bluetoothProvider: BluetoothProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) -> SetupUIResult { - - let vc = G7UICoordinator(colorPalette: colorPalette, displayGlucoseUnitObservable: displayGlucoseUnitObservable, allowDebugFeatures: allowDebugFeatures) - return .userInteractionRequired(vc) - } - - public func settingsViewController(bluetoothProvider: BluetoothProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) ->CGMManagerViewController { - - return G7UICoordinator(cgmManager: self, colorPalette: colorPalette, displayGlucoseUnitObservable: displayGlucoseUnitObservable, allowDebugFeatures: allowDebugFeatures) - } - - public var smallImage: UIImage? { - UIImage(named: "g7", in: Bundle(for: G7SettingsViewModel.self), compatibleWith: nil)! - } - - // TODO Placeholder. - public var cgmStatusHighlight: DeviceStatusHighlight? { - - if lifecycleState == .searching { - return G7DeviceStatusHighlight( - localizedMessage: LocalizedString("Searching for\nSensor", comment: "G7 Status highlight text for searching for sensor"), - imageName: "dot.radiowaves.left.and.right", - state: .normalCGM) - } - - if lifecycleState == .expired { - return G7DeviceStatusHighlight( - localizedMessage: LocalizedString("Sensor\nExpired", comment: "G7 Status highlight text for sensor expired"), - imageName: "clock", - state: .normalCGM) - } - - if lifecycleState == .failed { - return G7DeviceStatusHighlight( - localizedMessage: LocalizedString("Sensor\nFailed", comment: "G7 Status highlight text for sensor failed"), - imageName: "exclamationmark.circle.fill", - state: .critical) - } - - if let latestReadingReceivedAt = state.latestReadingTimestamp, latestReadingReceivedAt.timeIntervalSinceNow < -.minutes(15) { - return G7DeviceStatusHighlight( - localizedMessage: LocalizedString("Signal\nLoss", comment: "G7 Status highlight text for signal loss"), - imageName: "exclamationmark.circle.fill", - state: .warning) - } - - if let latestReading = latestReading, latestReading.algorithmState.isInSensorError { - return G7DeviceStatusHighlight( - localizedMessage: LocalizedString("Sensor\nIssue", comment: "G7 Status highlight text for sensor error"), - imageName: "exclamationmark.circle.fill", - state: .warning) - } - - if lifecycleState == .warmup { - return G7DeviceStatusHighlight( - localizedMessage: LocalizedString("Sensor\nWarmup", comment: "G7 Status highlight text for sensor warmup"), - imageName: "clock", - state: .normalCGM) - } - return nil - } - - // TODO Placeholder. - public var cgmStatusBadge: DeviceStatusBadge? { - if lifecycleState == .gracePeriod { - return G7DeviceStatusBadge(image: UIImage(systemName: "clock"), state: .critical) - } - return nil - } - - // TODO Placeholder. - public var cgmLifecycleProgress: DeviceLifecycleProgress? { - switch lifecycleState { - case .ok: - // show remaining lifetime, if < 24 hours - guard let expiration = sensorExpiresAt else { - return nil - } - let remaining = max(0, expiration.timeIntervalSinceNow) - - if remaining < .hours(24) { - return G7LifecycleProgress(percentComplete: 1-(remaining/G7Sensor.lifetime), progressState: .warning) - } - return nil - case .gracePeriod: - guard let endTime = sensorEndsAt else { - return nil - } - let remaining = max(0, endTime.timeIntervalSinceNow) - return G7LifecycleProgress(percentComplete: 1-(remaining/G7Sensor.gracePeriod), progressState: .critical) - case .expired: - return G7LifecycleProgress(percentComplete: 1, progressState: .critical) - default: - return nil - } - } -} - -struct G7DeviceStatusBadge: DeviceStatusBadge { - var image: UIImage? - - var state: LoopKitUI.DeviceStatusBadgeState -} - - -struct G7LifecycleProgress: DeviceLifecycleProgress { - var percentComplete: Double - - var progressState: LoopKit.DeviceLifecycleProgressState -} diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/G7CGMManager/G7UICoordinator.swift b/Dependencies/G7SensorKit/G7SensorKitUI/G7CGMManager/G7UICoordinator.swift deleted file mode 100644 index 87bf0168f..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/G7CGMManager/G7UICoordinator.swift +++ /dev/null @@ -1,91 +0,0 @@ -// -// G7UICoordinator.swift -// CGMBLEKitUI -// -// Created by Pete Schwamb on 9/24/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKitUI -import G7SensorKit - -class G7UICoordinator: UINavigationController, CGMManagerOnboarding, CompletionNotifying, UINavigationControllerDelegate { - var cgmManagerOnboardingDelegate: LoopKitUI.CGMManagerOnboardingDelegate? - var completionDelegate: LoopKitUI.CompletionDelegate? - var cgmManager: G7CGMManager? - var displayGlucoseUnitObservable: DisplayGlucoseUnitObservable - - var colorPalette: LoopUIColorPalette - - init(cgmManager: G7CGMManager? = nil, - colorPalette: LoopUIColorPalette, - displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, - allowDebugFeatures: Bool) - { - self.cgmManager = cgmManager - self.colorPalette = colorPalette - self.displayGlucoseUnitObservable = displayGlucoseUnitObservable - super.init(navigationBarClass: UINavigationBar.self, toolbarClass: UIToolbar.self) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - delegate = self - - navigationBar.prefersLargeTitles = true // Ensure nav bar text is displayed correctly - - let viewController = initialView() - setViewControllers([viewController], animated: false) - } - - private func initialView() -> UIViewController { - if cgmManager == nil { - let rootView = G7StartupView( - didContinue: { [weak self] in self?.completeSetup() }, - didCancel: { [weak self] in - if let self = self { - self.completionDelegate?.completionNotifyingDidComplete(self) - } - } - ) - let hostingController = DismissibleHostingController(rootView: rootView, colorPalette: colorPalette) - hostingController.navigationItem.largeTitleDisplayMode = .never - hostingController.title = nil - return hostingController - } else { - let view = G7SettingsView( - didFinish: { [weak self] in - if let self = self { - self.completionDelegate?.completionNotifyingDidComplete(self) - } - }, - deleteCGM: { [ weak self] in - self?.cgmManager?.notifyDelegateOfDeletion { - DispatchQueue.main.async { - if let self = self { - self.completionDelegate?.completionNotifyingDidComplete(self) - self.dismiss(animated: true) - } - } - } - }, - viewModel: G7SettingsViewModel(cgmManager: cgmManager!, displayGlucoseUnitObservable: displayGlucoseUnitObservable) - ) - let hostingController = DismissibleHostingController(rootView: view, colorPalette: colorPalette) - return hostingController - } - } - - func completeSetup() { - cgmManager = G7CGMManager() - cgmManagerOnboardingDelegate?.cgmManagerOnboarding(didCreateCGMManager: cgmManager!) - cgmManagerOnboardingDelegate?.cgmManagerOnboarding(didOnboardCGMManager: cgmManager!) - completionDelegate?.completionNotifyingDidComplete(self) - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/G7SensorKitUI.h b/Dependencies/G7SensorKit/G7SensorKitUI/G7SensorKitUI.h deleted file mode 100644 index b549da0d8..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/G7SensorKitUI.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// G7SensorKitUI.h -// G7SensorKitUI -// -// Created by Pete Schwamb on 11/11/22. -// - -#import - -//! Project version number for G7SensorKitUI. -FOUNDATION_EXPORT double G7SensorKitUIVersionNumber; - -//! Project version string for G7SensorKitUI. -FOUNDATION_EXPORT const unsigned char G7SensorKitUIVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/LocalizedString.swift b/Dependencies/G7SensorKit/G7SensorKitUI/LocalizedString.swift deleted file mode 100644 index 68b75aa5a..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/LocalizedString.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// LocalizedString.swift -// G7SensorKitUI -// -// Created by Pete Schwamb on 3/20/23. -// - -import Foundation - -internal class FrameworkBundle { - static let main = Bundle(for: FrameworkBundle.self) -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: FrameworkBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: FrameworkBundle.main, comment: comment) - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/OSLog.swift b/Dependencies/G7SensorKit/G7SensorKitUI/OSLog.swift deleted file mode 100644 index f09e87ea6..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/OSLog.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// OSLog.swift -// Loop -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import os.log - - -extension OSLog { - convenience init(category: String) { - self.init(subsystem: "org.loopkit.G7SensorKitUI", category: category) - } - - func debug(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .debug, args) - } - - func info(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .info, args) - } - - func `default`(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .default, args) - } - - func error(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .error, args) - } - - private func log(_ message: StaticString, type: OSLogType, _ args: [CVarArg]) { - switch args.count { - case 0: - os_log(message, log: self, type: type) - case 1: - os_log(message, log: self, type: type, args[0]) - case 2: - os_log(message, log: self, type: type, args[0], args[1]) - case 3: - os_log(message, log: self, type: type, args[0], args[1], args[2]) - case 4: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3]) - case 5: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4]) - default: - os_log(message, log: self, type: type, args) - } - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/Views/G7ProgressBarState.swift b/Dependencies/G7SensorKit/G7SensorKitUI/Views/G7ProgressBarState.swift deleted file mode 100644 index 652a6111f..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/Views/G7ProgressBarState.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// G7ProgressBarState.swift -// G7SensorKitUI -// -// Created by Pete Schwamb on 11/22/22. -// - -import Foundation - -enum G7ProgressBarState { - case warmupProgress - case lifetimeRemaining - case gracePeriodRemaining - case sensorFailed - case sensorExpired - case searchingForSensor - - var label: String { - switch self { - case .searchingForSensor: - return LocalizedString("Searching for sensor", comment: "G7 Progress bar label when searching for sensor") - case .sensorExpired: - return LocalizedString("Sensor expired", comment: "G7 Progress bar label when sensor expired") - case .warmupProgress: - return LocalizedString("Warmup completes", comment: "G7 Progress bar label when sensor in warmup") - case .sensorFailed: - return LocalizedString("Sensor failed", comment: "G7 Progress bar label when sensor failed") - case .lifetimeRemaining: - return LocalizedString("Sensor expires", comment: "G7 Progress bar label when sensor lifetime progress showing") - case .gracePeriodRemaining: - return LocalizedString("Grace period remaining", comment: "G7 Progress bar label when sensor grace period progress showing") - } - } - - var labelColor: ColorStyle { - switch self { - case .sensorExpired: - return .critical - default: - return .normal - } - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/Views/G7SettingsView.swift b/Dependencies/G7SensorKit/G7SensorKitUI/Views/G7SettingsView.swift deleted file mode 100644 index 322fc78fb..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/Views/G7SettingsView.swift +++ /dev/null @@ -1,208 +0,0 @@ -// -// G7SettingsView.swift -// CGMBLEKitUI -// -// Created by Pete Schwamb on 9/25/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import SwiftUI -import G7SensorKit -import LoopKitUI - -struct G7SettingsView: View { - - private var durationFormatter: RelativeDateTimeFormatter = { - let formatter = RelativeDateTimeFormatter() - formatter.unitsStyle = .full - return formatter - }() - - @Environment(\.guidanceColors) private var guidanceColors - @Environment(\.glucoseTintColor) private var glucoseTintColor - - var didFinish: (() -> Void) - var deleteCGM: (() -> Void) - @ObservedObject var viewModel: G7SettingsViewModel - - @State private var showingDeletionSheet = false - - init(didFinish: @escaping () -> Void, deleteCGM: @escaping () -> Void, viewModel: G7SettingsViewModel) { - self.didFinish = didFinish - self.deleteCGM = deleteCGM - self.viewModel = viewModel - } - - private var timeFormatter: DateFormatter = { - let formatter = DateFormatter() - - formatter.dateStyle = .short - formatter.timeStyle = .short - - return formatter - }() - - var body: some View { - List { - Section() { - VStack { - headerImage - progressBar - } - } - if let activatedAt = viewModel.activatedAt { - HStack { - Text(LocalizedString("Sensor Start", comment: "title for g7 settings row showing sensor start time")) - Spacer() - Text(timeFormatter.string(from: activatedAt)) - .foregroundColor(.secondary) - } - HStack { - Text(LocalizedString("Sensor Expiration", comment: "title for g7 settings row showing sensor expiration time")) - Spacer() - Text(timeFormatter.string(from: activatedAt.addingTimeInterval(G7Sensor.lifetime))) - .foregroundColor(.secondary) - } - HStack { - Text(LocalizedString("Grace Period End", comment: "title for g7 settings row showing sensor grace period end time")) - Spacer() - Text(timeFormatter.string(from: activatedAt.addingTimeInterval(G7Sensor.lifetime + G7Sensor.gracePeriod))) - .foregroundColor(.secondary) - } - } - - Section(LocalizedString("Last Reading", comment: "")) { - LabeledValueView(label: LocalizedString("Glucose", comment: "Field label"), - value: viewModel.lastGlucoseString) - LabeledDateView(label: LocalizedString("Time", comment: "Field label"), - date: viewModel.latestReadingTimestamp, - dateFormatter: viewModel.dateFormatter) - LabeledValueView(label: LocalizedString("Trend", comment: "Field label"), - value: viewModel.lastGlucoseTrendString) - } - - Section(LocalizedString("Bluetooth", comment: "")) { - if let name = viewModel.sensorName { - HStack { - Text(LocalizedString("Name", comment: "title for g7 settings row showing BLE Name")) - Spacer() - Text(name) - .foregroundColor(.secondary) - } - } - if viewModel.scanning { - HStack { - Text(LocalizedString("Scanning", comment: "title for g7 settings connection status when scanning")) - Spacer() - SwiftUI.ProgressView() - } - } else { - if viewModel.connected { - Text(LocalizedString("Connected", comment: "title for g7 settings connection status when connected")) - } else { - HStack { - Text(LocalizedString("Connecting", comment: "title for g7 settings connection status when connecting")) - Spacer() - SwiftUI.ProgressView() - } - } - } - if let lastConnect = viewModel.lastConnect { - LabeledValueView(label: LocalizedString("Last Connect", comment: "title for g7 settings row showing sensor last connect time"), - value: timeFormatter.string(from: lastConnect)) - } - } - - Section(LocalizedString("Configuration", comment: "")) { - HStack { - Toggle(LocalizedString("Upload Readings", comment: "title for g7 config settings to upload readings"), isOn: $viewModel.uploadReadings) - } - } - - Section () { - if !self.viewModel.scanning { - Button(LocalizedString("Scan for new sensor", comment: ""), action: { - self.viewModel.scanForNewSensor() - }) - } - - deleteCGMButton - } - } - .insetGroupedListStyle() - .navigationBarItems(trailing: doneButton) - .navigationBarTitle(LocalizedString("Dexcom G7", comment: "Navigation bar title for G7SettingsView")) - } - - private var deleteCGMButton: some View { - Button(action: { - showingDeletionSheet = true - }, label: { - Text(LocalizedString("Delete CGM", comment: "Button label for removing CGM")) - .foregroundColor(.red) - }).actionSheet(isPresented: $showingDeletionSheet) { - ActionSheet( - title: Text("Are you sure you want to delete this CGM?"), - buttons: [ - .destructive(Text("Delete CGM")) { - self.deleteCGM() - }, - .cancel(), - ] - ) - } - } - - private var headerImage: some View { - VStack(alignment: .center) { - Image(frameworkImage: "g7") - .resizable() - .aspectRatio(contentMode: ContentMode.fit) - .frame(height: 150) - .padding(.horizontal) - }.frame(maxWidth: .infinity) - } - - @ViewBuilder - private var progressBar: some View { - VStack(alignment: .leading, spacing: 4) { - HStack(alignment: .firstTextBaseline) { - Text(viewModel.progressBarState.label) - .font(.system(size: 17)) - .foregroundColor(color(for: viewModel.progressBarState.labelColor)) - - Spacer() - if let referenceDate = viewModel.progressReferenceDate { - Text(durationFormatter.localizedString(for: referenceDate, relativeTo: Date())) - .foregroundColor(.secondary) - } - } - ProgressView(value: viewModel.progressBarProgress) - .accentColor(color(for: viewModel.progressBarColorStyle)) - } - } - - private func color(for colorStyle: ColorStyle) -> Color { - switch colorStyle { - case .glucose: - return glucoseTintColor - case .warning: - return guidanceColors.warning - case .critical: - return guidanceColors.critical - case .normal: - return .primary - case .dimmed: - return .secondary - } - } - - - private var doneButton: some View { - Button("Done", action: { - self.didFinish() - }) - } - -} diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/Views/G7SettingsViewModel.swift b/Dependencies/G7SensorKit/G7SensorKitUI/Views/G7SettingsViewModel.swift deleted file mode 100644 index 8513d2b5a..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/Views/G7SettingsViewModel.swift +++ /dev/null @@ -1,218 +0,0 @@ -// -// G7SettingsViewModel.swift -// CGMBLEKitUI -// -// Created by Pete Schwamb on 10/4/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import G7SensorKit -import LoopKit -import LoopKitUI -import HealthKit - -public enum ColorStyle { - case glucose, warning, critical, normal, dimmed -} - -class G7SettingsViewModel: ObservableObject { - @Published private(set) var scanning: Bool = false - @Published private(set) var connected: Bool = false - @Published private(set) var sensorName: String? - @Published private(set) var activatedAt: Date? - @Published private(set) var lastConnect: Date? - @Published private(set) var latestReadingTimestamp: Date? - @Published var uploadReadings: Bool = false { - didSet { - cgmManager.uploadReadings = uploadReadings - } - } - - var displayGlucoseUnitObservable: DisplayGlucoseUnitObservable - - private var lastReading: G7GlucoseMessage? - - lazy var dateFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .short - formatter.timeStyle = .short - return formatter - }() - - private lazy var glucoseFormatter: QuantityFormatter = { - let formatter = QuantityFormatter() - formatter.setPreferredNumberFormatter(for: displayGlucoseUnitObservable.displayGlucoseUnit) - formatter.numberFormatter.notANumberSymbol = "–" - return formatter - }() - - private let quantityFormatter = QuantityFormatter() - - private var cgmManager: G7CGMManager - - var progressBarState: G7ProgressBarState { - switch cgmManager.lifecycleState { - case .searching: - return .searchingForSensor - case .ok: - return .lifetimeRemaining - case .warmup: - return .warmupProgress - case .failed: - return .sensorFailed - case .gracePeriod: - return .gracePeriodRemaining - case .expired: - return .sensorExpired - } - } - - init(cgmManager: G7CGMManager, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable) { - self.cgmManager = cgmManager - self.displayGlucoseUnitObservable = displayGlucoseUnitObservable - updateValues() - - self.cgmManager.addStateObserver(self, queue: DispatchQueue.main) - } - - func updateValues() { - scanning = cgmManager.isScanning - sensorName = cgmManager.sensorName - activatedAt = cgmManager.sensorActivatedAt - connected = cgmManager.isConnected - lastConnect = cgmManager.lastConnect - lastReading = cgmManager.latestReading - latestReadingTimestamp = cgmManager.latestReadingTimestamp - uploadReadings = cgmManager.state.uploadReadings - } - - var progressBarColorStyle: ColorStyle { - switch progressBarState { - case .warmupProgress: - return .glucose - case .searchingForSensor: - return .dimmed - case .sensorExpired, .sensorFailed: - return .critical - case .lifetimeRemaining: - guard let remaining = progressValue else { - return .dimmed - } - if remaining > .hours(24) { - return .glucose - } else { - return .warning - } - case .gracePeriodRemaining: - return .critical - } - } - - var progressBarProgress: Double { - switch progressBarState { - case .searchingForSensor: - return 0 - case .warmupProgress: - guard let value = progressValue, value > 0 else { - return 0 - } - return 1 - value / G7Sensor.warmupDuration - case .lifetimeRemaining: - guard let value = progressValue, value > 0 else { - return 0 - } - return 1 - value / G7Sensor.lifetime - case .gracePeriodRemaining: - guard let value = progressValue, value > 0 else { - return 0 - } - return 1 - value / G7Sensor.gracePeriod - case .sensorExpired, .sensorFailed: - return 1 - } - } - - var progressReferenceDate: Date? { - switch progressBarState { - case .searchingForSensor: - return nil - case .sensorExpired, .gracePeriodRemaining: - return cgmManager.sensorEndsAt - case .warmupProgress: - return cgmManager.sensorFinishesWarmupAt - case .lifetimeRemaining: - return cgmManager.sensorExpiresAt - case .sensorFailed: - return nil - } - } - - var progressValue: TimeInterval? { - switch progressBarState { - case .sensorExpired, .sensorFailed, .searchingForSensor: - guard let sensorEndsAt = cgmManager.sensorEndsAt else { - return nil - } - return sensorEndsAt.timeIntervalSinceNow - case .warmupProgress: - guard let warmupFinishedAt = cgmManager.sensorFinishesWarmupAt else { - return nil - } - return max(0, warmupFinishedAt.timeIntervalSinceNow) - case .lifetimeRemaining: - guard let expiration = cgmManager.sensorExpiresAt else { - return nil - } - return max(0, expiration.timeIntervalSinceNow) - case .gracePeriodRemaining: - guard let sensorEndsAt = cgmManager.sensorEndsAt else { - return nil - } - return max(0, sensorEndsAt.timeIntervalSinceNow) - } - } - - func scanForNewSensor() { - cgmManager.scanForNewSensor() - } - - var lastGlucoseString: String { - guard let lastReading = lastReading, lastReading.hasReliableGlucose, let quantity = lastReading.glucoseQuantity else { - return LocalizedString("– – –", comment: "No glucose value representation (3 dashes for mg/dL)") - } - - switch lastReading.glucoseRangeCategory { - case .some(.belowRange): - return LocalizedString("LOW", comment: "String displayed instead of a glucose value below the CGM range") - case .some(.aboveRange): - return LocalizedString("HIGH", comment: "String displayed instead of a glucose value above the CGM range") - default: - quantityFormatter.setPreferredNumberFormatter(for: displayGlucoseUnitObservable.displayGlucoseUnit) - let valueStr = quantityFormatter.string(from: quantity, for: displayGlucoseUnitObservable.displayGlucoseUnit, includeUnit: false) ?? "" - return String(format: "%@ %@", valueStr, displayGlucoseUnitObservable.displayGlucoseUnit.shortLocalizedUnitString()) - } - } - - var lastGlucoseTrendString: String { - if let lastReading = lastReading, lastReading.hasReliableGlucose, let trendRate = lastReading.trendRate { - let glucoseUnitPerMinute = displayGlucoseUnitObservable.displayGlucoseUnit.unitDivided(by: .minute()) - // This seemingly strange replacement of glucose units is only to display the unit string correctly - let trendPerMinute = HKQuantity(unit: displayGlucoseUnitObservable.displayGlucoseUnit, doubleValue: trendRate.doubleValue(for: glucoseUnitPerMinute)) - let formatted = glucoseFormatter.string(from: trendPerMinute, for: displayGlucoseUnitObservable.displayGlucoseUnit)! - return String(format: LocalizedString("%@/min", comment: "Format string for glucose trend per minute. (1: glucose value and unit)"), formatted) - } else { - return "" - } - } -} - -extension G7SettingsViewModel: G7StateObserver { - func g7StateDidUpdate(_ state: G7CGMManagerState?) { - updateValues() - } - - func g7ConnectionStatusDidChange() { - updateValues() - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/Views/G7StartupView.swift b/Dependencies/G7SensorKit/G7SensorKitUI/Views/G7StartupView.swift deleted file mode 100644 index af76fb0da..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/Views/G7StartupView.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// G7StartupView.swift -// CGMBLEKitUI -// -// Created by Pete Schwamb on 9/24/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import SwiftUI - -struct G7StartupView: View { - var didContinue: (() -> Void)? - var didCancel: (() -> Void)? - - var body: some View { - VStack(alignment: .center, spacing: 20) { - Spacer() - Text(LocalizedString("Dexcom G7", comment: "Title on WelcomeView")) - .font(.largeTitle) - .fontWeight(.semibold) - VStack(alignment: .center) { - Image(frameworkImage: "g7") - .resizable() - .aspectRatio(contentMode: ContentMode.fit) - .frame(height: 120) - .padding(.horizontal) - }.frame(maxWidth: .infinity) - Text(LocalizedString("iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management.", comment: "Descriptive text on G7StartupView")) - .fixedSize(horizontal: false, vertical: true) - .foregroundColor(.secondary) - Spacer() - Button(action: { self.didContinue?() }) { - Text(LocalizedString("Continue", comment:"Button title for starting setup")) - .actionButtonStyle(.primary) - } - Button(action: { self.didCancel?() } ) { - Text(LocalizedString("Cancel", comment: "Button text to cancel G7 setup")).padding(.top, 20) - } - } - .padding() - .environment(\.horizontalSizeClass, .compact) - .navigationBarTitle("") - .navigationBarHidden(true) - } -} - -struct WelcomeView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - G7StartupView() - } - .previewDevice("iPod touch (7th generation)") - } -} diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/ar.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/ar.lproj/Localizable.strings deleted file mode 100644 index 9b9a6b952..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/ar.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancel"; - -/* No comment provided by engineer. */ -"Configuration" = "Configuration"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Connected"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Connecting"; - -/* Button title for starting setup */ -"Continue" = "Continue"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Done"; - -/* Field label */ -"Glucose" = "Glucose"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* No comment provided by engineer. */ -"Last Reading" = "Last Reading"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Scan for new sensor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Start sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/* Field label */ -"Time" = "Time"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/cs.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/cs.lproj/Localizable.strings deleted file mode 100644 index 087836a06..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/cs.lproj/Localizable.strings +++ /dev/null @@ -1,46 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Zrušit"; - -/* No comment provided by engineer. */ -"Configuration" = "Konfigurace"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Připojeno"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Připojuji"; - -/* Button title for starting setup */ -"Continue" = "Pokračovat"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Hotovo"; - -/* Field label */ -"Glucose" = "Glukóza"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Konec dodatečné lhůty"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Zbývající dodatečná lhůta"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Název"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Platnost senzoru vypršela"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Senzor selhal"; - diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/da.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/da.lproj/Localizable.strings deleted file mode 100644 index 25ddad8ad..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/da.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Er du sikker på, at du vil slette denne CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Annuller"; - -/* No comment provided by engineer. */ -"Configuration" = "Konfiguration"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Tilsluttet"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Tilslutter"; - -/* Button title for starting setup */ -"Continue" = "Fortsæt"; - -/* Button label for removing CGM */ -"Delete CGM" = "Slet CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "OK"; - -/* Field label */ -"Glucose" = "Glukose"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Nådeperiodens Slut"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Tilbageværende nådeperiode"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HØJ"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Sidste Forbindelse"; - -/* No comment provided by engineer. */ -"Last Reading" = "Sidste Aflæsning"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS kan læse G7 CGM-data, men du skal stadig bruge Dexcom G7-appen til parring, kalibrering og anden sensorkontrol."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LAV"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Navn"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Scan efter ny sensor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanner"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Søger efter\nSensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Søger efter sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nUdløbet"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\nFejlede"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nProblem"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Udløber"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor udløbet"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor udløber"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor fejlede"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Start sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signaltab"; - -/* Field label */ -"Time" = "Tid"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Aflæsninger"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup fuldfører"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/de.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/de.lproj/Localizable.strings deleted file mode 100644 index e9ae6ef1b..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/de.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = ""; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Möchten Sie das CGM wirklich löschen?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Abbrechen"; - -/* No comment provided by engineer. */ -"Configuration" = "Konfiguration"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Verbunden"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Verbinden"; - -/* Button title for starting setup */ -"Continue" = "Fortsetzen"; - -/* Button label for removing CGM */ -"Delete CGM" = "CGM löschen"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Fertig"; - -/* Field label */ -"Glucose" = "Blutzucker"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Ende der Karenzfrist"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Verbleibende Karenzfrist"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HOCH"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Letzte Verbindung"; - -/* No comment provided by engineer. */ -"Last Reading" = "Letzte Messung"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS kann CGM Daten direkt vom G7 lesen. Zum Verbinden, Kalibrieren und erweitertem Sensor Management benötigt man die G7 App."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "NIEDRIG"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Nach neuem Sensor suchen"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scannt"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Suche nach\nSensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Suche nach Sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nabgelaufen"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensorverbindung\nfehlfeschlagen"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nFehler"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nAufwärmphase"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Ablaufdatum"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor abgelaufen"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor abgelaufen"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensorfehler"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Starte den Sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nVerlust"; - -/* Field label */ -"Time" = "Uhrzeit"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload von Messwerten"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Aufwärmphase abgeschlossen"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/en.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/en.lproj/Localizable.strings deleted file mode 100644 index 8fb5899d1..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/en.lproj/Localizable.strings +++ /dev/null @@ -1,118 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancel"; - -/* No comment provided by engineer. */ -"Configuration" = "Configuration"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Connected"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Connecting"; - -/* Button title for starting setup */ -"Continue" = "Continue"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Done"; - -/* Field label */ -"Glucose" = "Glucose"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* No comment provided by engineer. */ -"Last Reading" = "Last Reading"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Scan for new sensor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Start sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/* Field label */ -"Time" = "Time"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/es.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/es.lproj/Localizable.strings deleted file mode 100644 index 4b41e6d16..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/es.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancelar"; - -/* No comment provided by engineer. */ -"Configuration" = "Configuracion"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Conectado"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Conectando"; - -/* Button title for starting setup */ -"Continue" = "Continuar"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Hecho"; - -/* Field label */ -"Glucose" = "Glucose"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* No comment provided by engineer. */ -"Last Reading" = "Last Reading"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Nombre"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Scan for new sensor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Start sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/* Field label */ -"Time" = "Tiempo"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/fi.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/fi.lproj/Localizable.strings deleted file mode 100644 index 3b24a01c1..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/fi.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancel"; - -/* No comment provided by engineer. */ -"Configuration" = "Configuration"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Yhdistetty"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Yhdistetään"; - -/* Button title for starting setup */ -"Continue" = "Jatka"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Done"; - -/* Field label */ -"Glucose" = "Glucose"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* No comment provided by engineer. */ -"Last Reading" = "Last Reading"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Scan for new sensor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Start sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/* Field label */ -"Time" = "Time"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/fr.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/fr.lproj/Localizable.strings deleted file mode 100644 index e02d131d6..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/fr.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Annuler"; - -/* No comment provided by engineer. */ -"Configuration" = "Configuration"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Connecté"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Connexion en cours"; - -/* Button title for starting setup */ -"Continue" = "Continuer"; - -/* Button label for removing CGM */ -"Delete CGM" = "Supprimer CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Terminé"; - -/* Field label */ -"Glucose" = "Glycémie"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Fin de la Période de Grâce"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Période de grâce restante"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Dernière Connexion"; - -/* No comment provided by engineer. */ -"Last Reading" = "Last Reading"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS peut lire les données G7 de la CGM mais vous devez toujours utiliser l'application Dexcom G7 pour associer, calibrer et gérer les capteurs."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Nom"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Rechercher un nouveau capteur"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Balayage"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Recherche d'un\ncapteur"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Recherche d’un capteur"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Capteur\n expiré"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Capteur\na échoué"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Capteur\nproblème"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Capteur\nRéchauffement"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Capteur expiré"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Capteur expiré"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Capteura échoué"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Démarrer le capteur"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nPerte"; - -/* Field label */ -"Time" = "Heure"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "L'échauffement est terminé"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/he.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/he.lproj/Localizable.strings deleted file mode 100644 index 53ce1a9b4..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/he.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancel"; - -/* No comment provided by engineer. */ -"Configuration" = "Configuration"; - -/* title for g7 settings connection status when connected */ -"Connected" = "מחובר"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "מתחבר"; - -/* Button title for starting setup */ -"Continue" = "Continue"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Done"; - -/* Field label */ -"Glucose" = "Glucose"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* No comment provided by engineer. */ -"Last Reading" = "Last Reading"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Scan for new sensor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Start sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/* Field label */ -"Time" = "Time"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/hi.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/hi.lproj/Localizable.strings deleted file mode 100644 index e99df8c7f..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/hi.lproj/Localizable.strings +++ /dev/null @@ -1,97 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/मिनट"; - -/* Button text to cancel G7 setup */ -"Cancel" = "निरस्त"; - -/* title for g7 settings connection status when connected */ -"Connected" = "कनेक्ट हो गया"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "कनेक्ट हो रहा है"; - -/* Button title for starting setup */ -"Continue" = "जारी"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Field label */ -"Glucose" = "शुगर"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "ग्रेस समय समाप्त"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "बचा हुआ ग्रेस समय"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "लास्ट कनेक्ट"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "लूप G7 सीजीएम की रीडिंग्स पढ़ सकता है लेकिन सीजीएम सेन्सर के मैनज्मेंट, सेन्सर पैरिंग और कैलिब्रेशन की लिए dexcom का G7 ऐप ही इस्तेमाल करना चाहिए।"; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "नाम"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "स्कैनिंग"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "सेन्सर ढूँड रहा है"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "सेन्सर ढूँड रहा है"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "सेन्सर समाप्त"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "सेन्सर ख़राब"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "सेन्सर ख़राबी"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "सेन्सर का शुरुआती समय"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "सेन्सर समाप्ति"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "सेन्सर समाप्त हो गया"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "सेन्सर समाप्त"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "सेन्सर ख़राब हो गया है"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "सेन्सर शुरू"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "सिग्नल लॉस"; - -/* Field label */ -"Time" = "समय"; - -/* Field label */ -"Trend" = "ट्रेंड"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "अपलोड रीडिंग्स"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "शुरुआती वॉर्म अप पूर्ण"; - diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/hu.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/hu.lproj/Localizable.strings deleted file mode 100644 index d5a77fe52..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/hu.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Mégse"; - -/* No comment provided by engineer. */ -"Configuration" = "Beállítások"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Connected"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Connecting"; - -/* Button title for starting setup */ -"Continue" = "Continue"; - -/* Button label for removing CGM */ -"Delete CGM" = "CGM kitörlése"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Kész"; - -/* Field label */ -"Glucose" = "Glükóz"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* No comment provided by engineer. */ -"Last Reading" = "Last Reading"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Megnevezés"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Scan for new sensor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Start sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/* Field label */ -"Time" = "Idő"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/it.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/it.lproj/Localizable.strings deleted file mode 100644 index 02213ad8e..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/it.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Sei sicuro di voler cancellare questo CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancella"; - -/* No comment provided by engineer. */ -"Configuration" = "Impostazioni"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Connesso"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "In fase di Connessione"; - -/* Button title for starting setup */ -"Continue" = "Continua"; - -/* Button label for removing CGM */ -"Delete CGM" = "Cancella CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Fine"; - -/* Field label */ -"Glucose" = "Glicemie"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Fine periodo di tolleranza"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Periodo di tolleranza residuo"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "ALTO"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Ultima Connessione"; - -/* No comment provided by engineer. */ -"Last Reading" = "Ultima lettura"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS è in grado di leggere i dati CGM di G7, ma è comunque necessario utilizzare l'App Dexcom G7 per l'accoppiamento, la calibrazione e la gestione di altri sensori."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "BASSO"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Nome"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Scansiona nuovo sensore"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Lettura"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Ricerca del sensore \n"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Ricerca del sensore in corso"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensore \n scaduto"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensore \n Fallito"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Problema al sensore \n"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Riscaldamento sensore \n"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Scadenza Sensore"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensore scaduto"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Il sensore scade"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensore fallito"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Avvia sensore"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Perdita segnale \n"; - -/* Field label */ -"Time" = "Tempo"; - -/* Field label */ -"Trend" = "Tendenza"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Carica Letture"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Avvio completato"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/ja.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/ja.lproj/Localizable.strings deleted file mode 100644 index d3dba4faa..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/ja.lproj/Localizable.strings +++ /dev/null @@ -1,36 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "---"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/分"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "このCGMを削除しますか?"; - -/* Button text to cancel G7 setup */ -"Cancel" = "キャンセル"; - -/* No comment provided by engineer. */ -"Configuration" = "コンフィグレーション"; - -/* title for g7 settings connection status when connected */ -"Connected" = "接続済み"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "接続しています"; - -/* Button title for starting setup */ -"Continue" = "次へ"; - -/* Button label for removing CGM */ -"Delete CGM" = "CGMを削除"; - -/* Field label */ -"Glucose" = "血糖値"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "プリセット名"; - -/* Field label */ -"Trend" = "トレンド"; - diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/nb.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/nb.lproj/Localizable.strings deleted file mode 100644 index e1e1b0148..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/nb.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Sikker på at du vil slette denne CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Avbryt"; - -/* No comment provided by engineer. */ -"Configuration" = "Oppsett"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Tilkoblet"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Kobler til"; - -/* Button title for starting setup */ -"Continue" = "Fortsett"; - -/* Button label for removing CGM */ -"Delete CGM" = "Slett CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Ferdig"; - -/* Field label */ -"Glucose" = "Blodsukker"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Slutt på utsettelsesperiode"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Utsettelsesperiode som gjenstår"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HØYT"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Siste tilkobling"; - -/* No comment provided by engineer. */ -"Last Reading" = "Siste måling"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS kan lese data fra Dexcom G7, men du må fremdeles bruke Dexcom G7-appen for å koble til sender, kalibrere og andre innstillinger for sensoren."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LAVT"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Navn"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Søk etter ny sensor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Skanner"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Søker etter\nSensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Søker etter sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nUtløpt"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\nFeilet"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nFeil"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nOppvarming"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor utløper"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensoren er utløpt"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor utløper"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensoren feilet"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Start sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nTapt"; - -/* Field label */ -"Time" = "Tidspunkt"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Last opp avlesninger"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Oppvarming fullført"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/nl.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/nl.lproj/Localizable.strings deleted file mode 100644 index 05c99a6d7..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/nl.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Weet je zeker dat je deze CGM wilt vewijderen?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluethooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Annuleer"; - -/* No comment provided by engineer. */ -"Configuration" = "Instellingen"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Verbonden"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Bezig met verbinden"; - -/* Button title for starting setup */ -"Continue" = "Vervolg"; - -/* Button label for removing CGM */ -"Delete CGM" = "Verwijder CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "OK"; - -/* Field label */ -"Glucose" = "Glucosewaarde"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Einde coulance periode"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Resterende coulance periode"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HOOG"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Laatste connectie"; - -/* No comment provided by engineer. */ -"Last Reading" = "Laatste stand"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS kan G7 CGM-gegevens lezen, maar je moet nog steeds de Dexcom G7 App gebruiken voor koppeling, kalibratie en ander sensorbeheer."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LAAG"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Naam"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Nieuwe sensor aan het scannen"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Aan het scannen"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Zoeken naar\nsensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Sensor aan het zoeken"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nverlopen"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\nmislukt"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nprobleem"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nopwarmen"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor verloopt"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor verlopen"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor verloopt"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor mislukt"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Start sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signaal\nverlies"; - -/* Field label */ -"Time" = "Tijd"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Lezingen uploaden"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Opwarmen voltooid"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/pl.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/pl.lproj/Localizable.strings deleted file mode 100644 index b20033e2f..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/pl.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Anuluj"; - -/* No comment provided by engineer. */ -"Configuration" = "Configuration"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Połączono"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Łączenie"; - -/* Button title for starting setup */ -"Continue" = "Kontynuuj"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Done"; - -/* Field label */ -"Glucose" = "Glucose"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* No comment provided by engineer. */ -"Last Reading" = "Last Reading"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Scan for new sensor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Start sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/* Field label */ -"Time" = "Czas"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/pt-BR.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/pt-BR.lproj/Localizable.strings deleted file mode 100644 index a5dbae60d..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancelar"; - -/* No comment provided by engineer. */ -"Configuration" = "Ajustes"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Conectado"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Conectando"; - -/* Button title for starting setup */ -"Continue" = "Continuar"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "OK"; - -/* Field label */ -"Glucose" = "Glicose"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* No comment provided by engineer. */ -"Last Reading" = "Last Reading"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Nome"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Scan for new sensor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Start sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/* Field label */ -"Time" = "Hora"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/pt-PT.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/pt-PT.lproj/Localizable.strings deleted file mode 100644 index 71efa1317..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/pt-PT.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancelar"; - -/* No comment provided by engineer. */ -"Configuration" = "Ajustes"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Connected"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Connecting"; - -/* Button title for starting setup */ -"Continue" = "Continue"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "OK"; - -/* Field label */ -"Glucose" = "Glucose"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* No comment provided by engineer. */ -"Last Reading" = "Last Reading"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Nome"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Scan for new sensor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Start sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/* Field label */ -"Time" = "Hora"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/ro.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/ro.lproj/Localizable.strings deleted file mode 100644 index 17af25cd9..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/ro.lproj/Localizable.strings +++ /dev/null @@ -1,118 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Sunteți sigur că doriți să ștergeți acest CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Renunță"; - -/* No comment provided by engineer. */ -"Configuration" = "Configurare"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Conectat"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Conectare"; - -/* Button title for starting setup */ -"Continue" = "Continuă"; - -/* Button label for removing CGM */ -"Delete CGM" = "Ștergeți CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Realizat"; - -/* Field label */ -"Glucose" = "Glucoza"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Sfârșitul perioadei de grație"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Perioada de grație rămasă"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIPER"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Ultima conectare"; - -/* No comment provided by engineer. */ -"Last Reading" = "Ultima citire"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "Loop poate citi datele G7 CGM, dar pentru cuplare, calibrare și alte activități de gestionare a senzorului, va trebui să folosiți aplicația Dexcom G7."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "HIPO"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Nume"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Scanați pentru un senzor nou"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanare"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Detectarea senzorului"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Detectarea senzorului"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Senzorul a expirat"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Senzorul a eșuat"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Problemă cu senzorul"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Senzorul se încălzește"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Expirarea senzorului"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Senzorul a expirat"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Senzorul expiră"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Senzorul a eșuat"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Pornirea senzorului"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Pierdere de semnal"; - -/* Field label */ -"Time" = "Timp"; - -/* Field label */ -"Trend" = "Tendinţă"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Urcă citirile de glicemie"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Încălzirea s-a încheiat"; - diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/ru.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/ru.lproj/Localizable.strings deleted file mode 100644 index 1fca7ed02..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/ru.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/мин"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Вы уверены, что хотите удалить текущий CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Отмена"; - -/* No comment provided by engineer. */ -"Configuration" = "Конфигурация"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Подключено"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Подключение"; - -/* Button title for starting setup */ -"Continue" = "Продолжить"; - -/* Button label for removing CGM */ -"Delete CGM" = "Удалить CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Готово"; - -/* Field label */ -"Glucose" = "Глюкоза"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Период отсрочки"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Оставшийся период отсрочки"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "ВЫСОКИЙ"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Последнее подключение"; - -/* No comment provided by engineer. */ -"Last Reading" = "Последнее считывание"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS может считывать G7 CGM данные, но Вы все равно должны использовать Dexcom G7 App для сопряжения, калибровки и управления датчиком."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "НИЗКИЙ"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Название"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Сканирование нового датчика"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Сканирование"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Поиск\nДатчика"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Поиск датчика"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Датчик\nИстек"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Датчик\nСбой"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Датчик\nПроблема"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Датчик\nПрогрев"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Датчик истекает"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Срок действия датчика истек"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Датчик заканчивается"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Сбой датчика"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Запуск датчика"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Сигнал\nПотерян"; - -/* Field label */ -"Time" = "Время"; - -/* Field label */ -"Trend" = "Тенденция"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Выгружать данные"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Прогрев завершается"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/sk.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/sk.lproj/Localizable.strings deleted file mode 100644 index 7844483e0..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/sk.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Ste si istí, že chcete tento CGM vymazať?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancel"; - -/* No comment provided by engineer. */ -"Configuration" = "Nastavenie"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Pripojené"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Pripája sa"; - -/* Button title for starting setup */ -"Continue" = "Pokračovať"; - -/* Button label for removing CGM */ -"Delete CGM" = "Odstrániť senzor"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Done"; - -/* Field label */ -"Glucose" = "Glucose"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Dodatočná doba na výmenu senzoru končí"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Zostávajúce predĺžené obdobie"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "VYSOKÉ"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* No comment provided by engineer. */ -"Last Reading" = "Posledná hodnota"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS dokáže čítať dáta z G7 CGM, ale stále musíte používať aplikáciu Dexcom G7 na párovanie, kalibráciu a ďalšiu správu senzora."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "NÍZKE"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Načítať nový senzor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Skenuje sa"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Vyhľadávam\nsenzor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Vyhľadávam nový senzor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Senzor\nexspiroval"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Senzor\nzlyhal"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Problém\nsenzoru"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Zahrievanie\nsenzoru"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Senzor exspiruje"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Senzor exspiroval"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Senzor exspiruje"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Senzor štartu"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Strata\nsignálu"; - -/* Field label */ -"Time" = "Time"; - -/* Field label */ -"Trend" = "Vývoj"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Nahrať merania"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Zahrievanie senzora dokončené"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/sv.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/sv.lproj/Localizable.strings deleted file mode 100644 index a5ffc0790..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/sv.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "År du säker på att du vill ta bort denna CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Avbryt"; - -/* No comment provided by engineer. */ -"Configuration" = "Konfiguration"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Ansluten"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Ansluter"; - -/* Button title for starting setup */ -"Continue" = "Fortsätt"; - -/* Button label for removing CGM */ -"Delete CGM" = "Radera CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Klar"; - -/* Field label */ -"Glucose" = "Glukos"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Reservperiod slutar"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Tid kvar av reservtid"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HÖGT"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Senaste anslutning"; - -/* No comment provided by engineer. */ -"Last Reading" = "Senaste avläsning"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS kan läsa G7 CGM-värden, men du måste alltjämt använda Dexcom G7-appen för parkoppling, kalibrering samt hantering av sensorn."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LÅGT"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Namn"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Skanna efter ny sensor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Skannar"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Söker efter\nSensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Söker efter sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nUtgått"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\nmisslyckades"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensorproblem"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nUppvärmning"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensorns utgångsdatum"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensorns livslängd är slut"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensorn går ut"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensorn misslyckades"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Starta Sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal-\nförlust"; - -/* Field label */ -"Time" = "Tid"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Ladda upp blodsocker"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Uppvärming av sensor"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/tr.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/tr.lproj/Localizable.strings deleted file mode 100644 index d25f3f78f..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/tr.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/dak"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Vazgeç"; - -/* No comment provided by engineer. */ -"Configuration" = "Yapılandırma"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Bağlandı"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Bağlanıyor"; - -/* Button title for starting setup */ -"Continue" = "Devam et"; - -/* Button label for removing CGM */ -"Delete CGM" = "CGM'i Sil"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Tamam"; - -/* Field label */ -"Glucose" = "Glikoz"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Yetkisiz Kullanım Sonu"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Kalan ek süre"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "YÜKSEK"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Son Bağlantı"; - -/* No comment provided by engineer. */ -"Last Reading" = "Son Okuma Değeri"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS, G7 CGM verilerini okuyabilir ancak yine de eşleştirme, kalibrasyon ve diğer sensör yönetimi için Dexcom G7 Uygulamasını kullanmanız gerekir."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "DÜŞÜK"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "İsim"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Yeni sensör için tara"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Taranıyor"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Sensör\nAranıyor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Sensör aranıyor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensör\nSüresi Doldu"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensör\nArızalı"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensör\nSorunu"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensör\nIsınıyor"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensör Süre Sonu"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensör süresi doldu"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensör süresi doluyor"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensör arızalı"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensörü başlatın"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Sinyal\nKaybı"; - -/* Field label */ -"Time" = "Saat"; - -/* Field label */ -"Trend" = "Eğilim"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Okumaları Yükle"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Isınma tamamlandı"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/uk.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/uk.lproj/Localizable.strings deleted file mode 100644 index d22dc14d9..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/uk.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/хв"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Ви впевнені, що хочете видалити цей CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Відмінити"; - -/* No comment provided by engineer. */ -"Configuration" = "Налаштування"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Під'єднаний"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Під'єднання"; - -/* Button title for starting setup */ -"Continue" = "Продовжити"; - -/* Button label for removing CGM */ -"Delete CGM" = "Видалити CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Готово"; - -/* Field label */ -"Glucose" = "Глюкоза"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Час до блокування"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Період витонченості, що залишився"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "ВИСОКИЙ"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Останнє підключення"; - -/* No comment provided by engineer. */ -"Last Reading" = "Останнє читання"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS може читати дані G7 CGM, але ви все одно повинні використовувати додаток Dexcom G7 для парування, калібрування та іншого управління сенсором."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "НИЗЬКИЙ"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Ім’я"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Сканувати новий Сенсор"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Сканування"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Пошук\nСенсору"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Пошук Сенсору"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Сенсор\nЗакінчився"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Сенсори\nНе вдалося"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Сенсор\nПроблема"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Сенсор\nПрогрів"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Термін дії Сенсору"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Термін Сенсору закінчився"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Сенсор закінчується"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Не вдалося встановити Сенсор"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Запустити сенсор"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Сигнал\nВтрата"; - -/* Field label */ -"Time" = "Час"; - -/* Field label */ -"Trend" = "Тренди"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Вивантажити читання"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Прогрів виконано"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/vi.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/vi.lproj/Localizable.strings deleted file mode 100644 index 21559a57b..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/vi.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "---"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/phút"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Bạn có chắc sẽ xóa CGM này?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Hủy bỏ"; - -/* No comment provided by engineer. */ -"Configuration" = "Cấu hình"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Đã kết nối"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Đang kết nối"; - -/* Button title for starting setup */ -"Continue" = "Tiếp tục"; - -/* Button label for removing CGM */ -"Delete CGM" = "Xóa CGM"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "Hoàn thành"; - -/* Field label */ -"Glucose" = "Đường huyết"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Thời gian ân huệ kết thúc"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Thời gian ân huệ còn lại"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "CAO"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Kết nối gần đây nhất"; - -/* No comment provided by engineer. */ -"Last Reading" = "Kết quả đọc gần nhất"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS có thể đọc dữ liệu G7 CGM tuy nhiên bạn nên dùng app của Dexcom G7 để ghép đôi, hiệu chỉnh và quản lý sensor."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "THẤP"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Tên"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Scan để thay sensor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Đang quét"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Đang tìm kiếm \n sensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Đang tìm kiếm cảm biến"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\n hết hạn"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\n thất bại"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\n có vấn đề"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\n đang khởi động"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Cảm biến hết hạn"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Cảm biến đã hết hạn"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor hết hạn"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Lỗi cảm biến"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Bắt đầu sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Tín hiệu\n mất"; - -/* Field label */ -"Time" = "Thời gian"; - -/* Field label */ -"Trend" = "Xu hướng"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Glucose đang tải lên"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Khởi động hoàn tất"; diff --git a/Dependencies/G7SensorKit/G7SensorKitUI/zh-Hans.lproj/Localizable.strings b/Dependencies/G7SensorKit/G7SensorKitUI/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 2111b941b..000000000 --- a/Dependencies/G7SensorKit/G7SensorKitUI/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,117 +0,0 @@ -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* No comment provided by engineer. */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* No comment provided by engineer. */ -"Bluetooth" = "Bluetooth"; - -/* Button text to cancel G7 setup */ -"Cancel" = "取消"; - -/* No comment provided by engineer. */ -"Configuration" = "配置"; - -/* title for g7 settings connection status when connected */ -"Connected" = "已连接"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "正在连接"; - -/* Button title for starting setup */ -"Continue" = "继续"; - -/* Button label for removing CGM */ -"Delete CGM" = "删除CGM数据源"; - -/* Navigation bar title for G7SettingsView - Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* No comment provided by engineer. */ -"Done" = "完成"; - -/* Field label */ -"Glucose" = "葡萄糖"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* No comment provided by engineer. */ -"Last Reading" = "Last Reading"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "设备名称"; - -/* No comment provided by engineer. */ -"Scan for new sensor" = "Scan for new sensor"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for sensor failed */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Start sensor"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/* Field label */ -"Time" = "时间"; - -/* Field label */ -"Trend" = "Trend"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; diff --git a/Dependencies/G7SensorKit/G7SensorPlugin/G7SensorPlugin.h b/Dependencies/G7SensorKit/G7SensorPlugin/G7SensorPlugin.h deleted file mode 100644 index ef99685fa..000000000 --- a/Dependencies/G7SensorKit/G7SensorPlugin/G7SensorPlugin.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// G7SensorPlugin.h -// G7SensorPlugin -// -// Created by Pete Schwamb on 11/11/22. -// - -#import - -//! Project version number for G7SensorPlugin. -FOUNDATION_EXPORT double G7SensorPluginVersionNumber; - -//! Project version string for G7SensorPlugin. -FOUNDATION_EXPORT const unsigned char G7SensorPluginVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/G7SensorKit/G7SensorPlugin/G7SensorPlugin.swift b/Dependencies/G7SensorKit/G7SensorPlugin/G7SensorPlugin.swift deleted file mode 100644 index a2b16ffa1..000000000 --- a/Dependencies/G7SensorKit/G7SensorPlugin/G7SensorPlugin.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// CGMBLEKitG7Plugin.swift -// CGMBLEKitG7Plugin -// -// Created by Pete Schwamb on 9/24/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import os.log -import LoopKitUI -import G7SensorKit -import G7SensorKitUI - -class G7SensorPlugin: NSObject, CGMManagerUIPlugin { - private let log = OSLog(category: "G7Plugin") - - public var cgmManagerType: CGMManagerUI.Type? { - return G7CGMManager.self - } - - override init() { - super.init() - log.default("Instantiated") - } -} diff --git a/Dependencies/G7SensorKit/G7SensorPlugin/Info.plist b/Dependencies/G7SensorKit/G7SensorPlugin/Info.plist deleted file mode 100644 index 86c3457b2..000000000 --- a/Dependencies/G7SensorKit/G7SensorPlugin/Info.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - 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 - NSHumanReadableCopyright - Copyright © 2019 LoopKit Authors. All rights reserved. - NSPrincipalClass - G7SensorPlugin - com.loopkit.Loop.CGMManagerDisplayName - Dexcom G7 - com.loopkit.Loop.CGMManagerIdentifier - G7CGMManager - - diff --git a/Dependencies/G7SensorKit/G7SensorPlugin/OSLog.swift b/Dependencies/G7SensorKit/G7SensorPlugin/OSLog.swift deleted file mode 100644 index 03224267c..000000000 --- a/Dependencies/G7SensorKit/G7SensorPlugin/OSLog.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// OSLog.swift -// Loop -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import os.log - - -extension OSLog { - convenience init(category: String) { - self.init(subsystem: "org.loopkit.G7SensorPlugin", category: category) - } - - func debug(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .debug, args) - } - - func info(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .info, args) - } - - func `default`(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .default, args) - } - - func error(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .error, args) - } - - private func log(_ message: StaticString, type: OSLogType, _ args: [CVarArg]) { - switch args.count { - case 0: - os_log(message, log: self, type: type) - case 1: - os_log(message, log: self, type: type, args[0]) - case 2: - os_log(message, log: self, type: type, args[0], args[1]) - case 3: - os_log(message, log: self, type: type, args[0], args[1], args[2]) - case 4: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3]) - case 5: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4]) - default: - os_log(message, log: self, type: type, args) - } - } -} diff --git a/Dependencies/G7SensorKit/README.md b/Dependencies/G7SensorKit/README.md deleted file mode 100644 index 973711959..000000000 --- a/Dependencies/G7SensorKit/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Loop Plugin for G7 Sensor -Requires use of official G7 app \ No newline at end of file diff --git a/Dependencies/G7SensorKit/ar.lproj/Localizable.strings b/Dependencies/G7SensorKit/ar.lproj/Localizable.strings deleted file mode 100644 index cdf9de583..000000000 --- a/Dependencies/G7SensorKit/ar.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* Button title for starting setup */ -"Continue" = "Continue"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancel"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor expired"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor failed"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensor Start"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* Field label */ -"Glucose" = "Glucose"; - -"Last Reading" = "Last Reading"; - -"Time" = "Time"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Connected"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Connecting"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* Configuration */ -"Configuration" = "Configuration"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* Button */ -"Scan for new sensor" = "Scan for new sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; diff --git a/Dependencies/G7SensorKit/ca.lproj/Localizable.strings b/Dependencies/G7SensorKit/ca.lproj/Localizable.strings deleted file mode 100644 index cdf9de583..000000000 --- a/Dependencies/G7SensorKit/ca.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* Button title for starting setup */ -"Continue" = "Continue"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancel"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor expired"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor failed"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensor Start"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* Field label */ -"Glucose" = "Glucose"; - -"Last Reading" = "Last Reading"; - -"Time" = "Time"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Connected"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Connecting"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* Configuration */ -"Configuration" = "Configuration"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* Button */ -"Scan for new sensor" = "Scan for new sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; diff --git a/Dependencies/G7SensorKit/da.lproj/Localizable.strings b/Dependencies/G7SensorKit/da.lproj/Localizable.strings deleted file mode 100644 index d5a287e65..000000000 --- a/Dependencies/G7SensorKit/da.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS kan læse G7 CGM-data, men du skal stadig bruge Dexcom G7-appen til parring, kalibrering og anden sensorkontrol."; - -/* Button title for starting setup */ -"Continue" = "Fortsæt"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Annuller"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glukosedata ikke tilgængeligt"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor er OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor er stoppet"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor varmer op"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor udløbet"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor fejlede"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor i ukendt tilstand %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensor Start"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Udløber"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Nådeperiodens Slut"; - -/* Field label */ -"Glucose" = "Glukose"; - -"Last Reading" = "Sidste Aflæsning"; - -"Time" = "Tid"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Navn"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanner"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Tilsluttet"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Tilslutter"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Sidste Forbindelse"; - -/* Configuration */ -"Configuration" = "Konfiguration"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Aflæsninger"; - -/* Button */ -"Scan for new sensor" = "Scan efter ny sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Slet CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LAV"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HØJ"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Søger efter sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor udløbet"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup fuldfører"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup fuldfører"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor fejlede"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor udløber"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Tilbageværende nådeperiode"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Søger efter\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nUdløbet"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nFejlede"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signaltab"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nProblem"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; diff --git a/Dependencies/G7SensorKit/de.lproj/Localizable.strings b/Dependencies/G7SensorKit/de.lproj/Localizable.strings deleted file mode 100644 index ac6fad5f7..000000000 --- a/Dependencies/G7SensorKit/de.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS kann CGM Daten direkt vom G7 lesen. Zum Verbinden, Kalibrieren und erweitertes Sensor Management benötigt man die G7 App."; - -/* Button title for starting setup */ -"Continue" = "Fortsetzen"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Abbrechen"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glukosewerte sind nicht verfügbar"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor ist OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor ist gestoppt"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor ist in der Aufwärmphase"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor abgelaufen"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensorfehler"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor ist in unbekanntem Zustand %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensorstart"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Ablaufdatum"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Ende der Karenzfrist"; - -/* Field label */ -"Glucose" = "Blutzucker"; - -"Last Reading" = "Letzte Messung"; - -"Time" = "Uhrzeit"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scannt"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Verbunden"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Verbinden"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Letzte Verbindung"; - -/* Configuration */ -"Configuration" = "Konfiguration"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Werte hochladen"; - -/* Button */ -"Scan for new sensor" = "Nach neuem Sensor suchen"; - -/* Button label for removing CGM */ -"Delete CGM" = "CGM löschen"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "NIEDRIG"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HOCH"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Suche nach Sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor abgelaufen"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Aufwärmphase abgeschlossen"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Aufwärmphase abgeschlossen"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensorfehler"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor abgelaufen"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Verbleibende Karenzfrist"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Suche nach\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nabgelaufen"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensorverbindung\nfehlfeschlagen"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nVerlust"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nFehler"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nAufwärmphase"; diff --git a/Dependencies/G7SensorKit/en.lproj/Localizable.strings b/Dependencies/G7SensorKit/en.lproj/Localizable.strings deleted file mode 100644 index cdf9de583..000000000 --- a/Dependencies/G7SensorKit/en.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* Button title for starting setup */ -"Continue" = "Continue"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancel"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor expired"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor failed"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensor Start"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* Field label */ -"Glucose" = "Glucose"; - -"Last Reading" = "Last Reading"; - -"Time" = "Time"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Connected"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Connecting"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* Configuration */ -"Configuration" = "Configuration"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* Button */ -"Scan for new sensor" = "Scan for new sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; diff --git a/Dependencies/G7SensorKit/es.lproj/Localizable.strings b/Dependencies/G7SensorKit/es.lproj/Localizable.strings deleted file mode 100644 index 785196761..000000000 --- a/Dependencies/G7SensorKit/es.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* Button title for starting setup */ -"Continue" = "Continuar"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancelar"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor expired"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor failed"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensor Start"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* Field label */ -"Glucose" = "Glucose"; - -"Last Reading" = "Last Reading"; - -"Time" = "Tiempo"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Nombre"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Conectado"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Conectando"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* Configuration */ -"Configuration" = "Configuracion"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* Button */ -"Scan for new sensor" = "Scan for new sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; diff --git a/Dependencies/G7SensorKit/fi.lproj/Localizable.strings b/Dependencies/G7SensorKit/fi.lproj/Localizable.strings deleted file mode 100644 index d005f6a54..000000000 --- a/Dependencies/G7SensorKit/fi.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* Button title for starting setup */ -"Continue" = "Jatka"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancel"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor expired"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor failed"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensor Start"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* Field label */ -"Glucose" = "Glucose"; - -"Last Reading" = "Last Reading"; - -"Time" = "Time"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Yhdistetty"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Yhdistetään"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* Configuration */ -"Configuration" = "Configuration"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* Button */ -"Scan for new sensor" = "Scan for new sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; diff --git a/Dependencies/G7SensorKit/fr.lproj/Localizable.strings b/Dependencies/G7SensorKit/fr.lproj/Localizable.strings deleted file mode 100644 index f29a56106..000000000 --- a/Dependencies/G7SensorKit/fr.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS peut lire les données G7 de la CGM mais vous devez toujours utiliser l'application Dexcom G7 pour associer, calibrer et gérer les capteurs."; - -/* Button title for starting setup */ -"Continue" = "Continuer"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Annuler"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Les données de glycémie ne sont pas disponibles"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Capteur est OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Le capteur est arrêté"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Capteur est en période de réchauffement"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Capteur expiré"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Capteura échoué"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Le capteur est dans un état inconnu %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Capteur démarré"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Capteur expiré"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Fin de la Période de Grâce"; - -/* Field label */ -"Glucose" = "Glycémie"; - -"Last Reading" = "Dernière lecture"; - -"Time" = "Heure"; - -"Trend" = "Tendance"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Nom"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Balayage"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Connecté"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "De liaison"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Dernière Connexion"; - -/* Configuration */ -"Configuration" = "Configuration"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Envoyer les données"; - -/* Button */ -"Scan for new sensor" = "Rechercher un nouveau capteur"; - -/* Button label for removing CGM */ -"Delete CGM" = "Supprimer CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "BAS"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HAUT"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Recherche d’un capteur"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Capteur expiré"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "L'échauffement est terminé"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "L'échauffement est terminé"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Capteura échoué"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Capteur expiré"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Période de grâce restante"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Recherche d'un\ncapteur"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Capteur\n expiré"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Capteur\na échoué"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nPerte"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Capteur\nproblème"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Capteur\nRéchauffement"; diff --git a/Dependencies/G7SensorKit/he.lproj/Localizable.strings b/Dependencies/G7SensorKit/he.lproj/Localizable.strings deleted file mode 100644 index 635c45190..000000000 --- a/Dependencies/G7SensorKit/he.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* Button title for starting setup */ -"Continue" = "Continue"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancel"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor expired"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor failed"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensor Start"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* Field label */ -"Glucose" = "Glucose"; - -"Last Reading" = "Last Reading"; - -"Time" = "Time"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* title for g7 settings connection status when connected */ -"Connected" = "מחובר"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "מתחבר"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* Configuration */ -"Configuration" = "Configuration"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* Button */ -"Scan for new sensor" = "Scan for new sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; diff --git a/Dependencies/G7SensorKit/hu.lproj/Localizable.strings b/Dependencies/G7SensorKit/hu.lproj/Localizable.strings deleted file mode 100644 index 8e190c619..000000000 --- a/Dependencies/G7SensorKit/hu.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* Button title for starting setup */ -"Continue" = "Continue"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Mégse"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor expired"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor failed"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensor Start"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* Field label */ -"Glucose" = "Glükóz"; - -"Last Reading" = "Last Reading"; - -"Time" = "Idő"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Megnevezés"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Connected"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Connecting"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* Configuration */ -"Configuration" = "Beállítások"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* Button */ -"Scan for new sensor" = "Scan for new sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "CGM kitörlése"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; diff --git a/Dependencies/G7SensorKit/it.lproj/Localizable.strings b/Dependencies/G7SensorKit/it.lproj/Localizable.strings deleted file mode 100644 index 1c5734119..000000000 --- a/Dependencies/G7SensorKit/it.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS è in grado di leggere i dati CGM di G7, ma è comunque necessario utilizzare l'App Dexcom G7 per l'accoppiamento, la calibrazione e la gestione di altri sensori."; - -/* Button title for starting setup */ -"Continue" = "Continua"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancella"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "I dati della glicemia non sono disponibili"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Il sensore è OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Il sensore è arrestato"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Il sensore è in fase di avvio"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensore scaduto"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensore fallito"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Il Sensore è in un stato %1$d sconosciuto"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Avvia sensore"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Scadenza Sensore"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Fine periodo di tolleranza"; - -/* Field label */ -"Glucose" = "Glucosio"; - -"Last Reading" = "Ultima lettura"; - -"Time" = "Tempo"; - -"Trend" = "Tendenza"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Nome"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Lettura"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Collegato"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "In collegamento"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Ultima Connessione"; - -/* Configuration */ -"Configuration" = "Impostazioni"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Carica Letture"; - -/* Button */ -"Scan for new sensor" = "Scansiona per nuovo sensore"; - -/* Button label for removing CGM */ -"Delete CGM" = "Elimina CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "BASSO"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "ALTO"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/minuto"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Ricerca del sensore in corso"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensore scaduto"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Avvio completato"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Avvio completato"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensore fallito"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Il sensore scade"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Periodo di tolleranza residuo"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Ricerca del sensore \n"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensore \n scaduto"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensore \n Fallito"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Perdita segnale \n"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Problema al sensore \n"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Riscaldamento sensore \n"; diff --git a/Dependencies/G7SensorKit/ja.lproj/Localizable.strings b/Dependencies/G7SensorKit/ja.lproj/Localizable.strings deleted file mode 100644 index 259def8e7..000000000 --- a/Dependencies/G7SensorKit/ja.lproj/Localizable.strings +++ /dev/null @@ -1,132 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* Button title for starting setup */ -"Continue" = "Continue"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancel"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor expired"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor failed"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensor Start"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* Field label */ -"Glucose" = "Glucose"; - -"Last Reading" = "Last Reading"; - -"Time" = "Time"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Connected"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Connecting"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* Configuration */ -"Configuration" = "Configuration"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* Button */ -"Scan for new sensor" = "Scan for new sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* Button text */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; diff --git a/Dependencies/G7SensorKit/nb.lproj/Localizable.strings b/Dependencies/G7SensorKit/nb.lproj/Localizable.strings deleted file mode 100644 index fd47dece6..000000000 --- a/Dependencies/G7SensorKit/nb.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS kan lese data fra Dexcom G7, men du må fremdeles bruke Dexcom G7-appen for å koble til sender, kalibrere og andre innstillinger for sensoren."; - -/* Button title for starting setup */ -"Continue" = "Fortsett"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Avbryt"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Blodsukker er utilgjengelig"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensoren er OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensoren er stoppet"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensoren varmer opp"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensoren er utløpt"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensoren feilet"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensoren har ukjent tilstand %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensorstart"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor utløper"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Slutt på utsettelsesperiode"; - -/* Field label */ -"Glucose" = "Blodsukker"; - -"Last Reading" = "Siste måling"; - -"Time" = "Tidspunkt"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Navn"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Skanner"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Tilkoblet"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Kobler til"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Siste tilkobling"; - -/* Configuration */ -"Configuration" = "Oppsett"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Last opp avlesninger"; - -/* Button */ -"Scan for new sensor" = "Søk etter ny sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Slett CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LAVT"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HØYT"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Søker etter sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensoren er utløpt"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Oppvarming fullført"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Oppvarming fullført"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensoren feilet"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor utløper"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Utsettelsesperiode som gjenstår"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Søker etter\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nUtløpt"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nFeilet"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nTapt"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nFeil"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nOppvarming"; diff --git a/Dependencies/G7SensorKit/nl.lproj/Localizable.strings b/Dependencies/G7SensorKit/nl.lproj/Localizable.strings deleted file mode 100644 index 7075fed78..000000000 --- a/Dependencies/G7SensorKit/nl.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS kan G7 CGM-gegevens lezen, maar je moet nog steeds de Dexcom G7 App gebruiken voor koppeling, kalibratie en ander sensorbeheer."; - -/* Button title for starting setup */ -"Continue" = "Vervolg"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Annuleer"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose gegevens niet beschikbaar"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is ok"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor is gestopt"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor is aan het opwarmen"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor verlopen"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor mislukt"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Senor is in onbekende status %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensor start"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor verloopt"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Einde coulance periode"; - -/* Field label */ -"Glucose" = "Glucosewaarde"; - -"Last Reading" = "Laatste stand"; - -"Time" = "Tijd"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluethooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Naam"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Aan het scannen"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Verbonden"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Verbinden"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Laatste connectie"; - -/* Configuration */ -"Configuration" = "Instellingen"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Lezingen uploaden"; - -/* Button */ -"Scan for new sensor" = "Nieuwe sensor aan het scannen"; - -/* Button label for removing CGM */ -"Delete CGM" = "Verwijder CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LAAG"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HOOG"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Sensor aan het zoeken"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor verlopen"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Opwarmen voltooid"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Opwarmen voltooid"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor mislukt"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor verloopt"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Resterende coulance periode"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Zoeken naar\nsensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nverlopen"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nmislukt"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signaal\nverlies"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nprobleem"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nopwarmen"; diff --git a/Dependencies/G7SensorKit/pl.lproj/Localizable.strings b/Dependencies/G7SensorKit/pl.lproj/Localizable.strings deleted file mode 100644 index 789376a3e..000000000 --- a/Dependencies/G7SensorKit/pl.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* Button title for starting setup */ -"Continue" = "Kontynuuj"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Anuluj"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor expired"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor failed"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensor Start"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* Field label */ -"Glucose" = "Glucose"; - -"Last Reading" = "Last Reading"; - -"Time" = "Czas"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Name"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Połączony"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Łączenie"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* Configuration */ -"Configuration" = "Configuration"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* Button */ -"Scan for new sensor" = "Scan for new sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; diff --git a/Dependencies/G7SensorKit/pt-BR.lproj/Localizable.strings b/Dependencies/G7SensorKit/pt-BR.lproj/Localizable.strings deleted file mode 100644 index f4e2108d7..000000000 --- a/Dependencies/G7SensorKit/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* Button title for starting setup */ -"Continue" = "Continuar"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancelar"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor expired"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor failed"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensor Start"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* Field label */ -"Glucose" = "Glicose"; - -"Last Reading" = "Last Reading"; - -"Time" = "Hora"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Nome"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Conectado"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Conectando"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* Configuration */ -"Configuration" = "Ajustes"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* Button */ -"Scan for new sensor" = "Scan for new sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; diff --git a/Dependencies/G7SensorKit/pt-PT.lproj/Localizable.strings b/Dependencies/G7SensorKit/pt-PT.lproj/Localizable.strings deleted file mode 100644 index bf6dfb9eb..000000000 --- a/Dependencies/G7SensorKit/pt-PT.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* Button title for starting setup */ -"Continue" = "Continue"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Cancelar"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor expired"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor failed"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensor Start"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* Field label */ -"Glucose" = "Glucose"; - -"Last Reading" = "Last Reading"; - -"Time" = "Hora"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Nome"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Connected"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Connecting"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* Configuration */ -"Configuration" = "Ajustes"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* Button */ -"Scan for new sensor" = "Scan for new sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Delete CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; diff --git a/Dependencies/G7SensorKit/ru.lproj/Localizable.strings b/Dependencies/G7SensorKit/ru.lproj/Localizable.strings deleted file mode 100644 index b480fd5d7..000000000 --- a/Dependencies/G7SensorKit/ru.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS может считывать G7 CGM данные, но Вы все равно должны использовать Dexcom G7 App для сопряжения, калибровки и управления датчиком."; - -/* Button title for starting setup */ -"Continue" = "Продолжить"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Отмена"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Данные глюкозы недоступны"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Датчик ОК"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Датчик остановлен"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Датчик прогревается"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Срок действия датчика истек"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Сбой датчика"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Датчик находится в неизвестном состоянии %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Старт датчика"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Датчик истекает"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Период отсрочки"; - -/* Field label */ -"Glucose" = "Глюкоза"; - -"Last Reading" = "Последнее считывание"; - -"Time" = "Время"; - -"Trend" = "Тенденция"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Название"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Сканирование"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Соединение установлено"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Соединяется"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Последнее подключение"; - -/* Configuration */ -"Configuration" = "Конфигурация"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Выгружать данные"; - -/* Button */ -"Scan for new sensor" = "Сканирование нового датчика"; - -/* Button label for removing CGM */ -"Delete CGM" = "Удалить CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "НИЗКИЙ"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "ВЫСОКИЙ"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/мин"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Поиск датчика"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Срок действия датчика истек"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Прогрев завершается"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Прогрев завершается"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Сбой датчика"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Датчик заканчивается"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Оставшийся период отсрочки"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Поиск\nДатчика"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Датчик\nИстек"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Датчик\nСбой"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Сигнал\nПотерян"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Датчик\nПроблема"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Датчик\nПрогрев"; diff --git a/Dependencies/G7SensorKit/sk.lproj/Localizable.strings b/Dependencies/G7SensorKit/sk.lproj/Localizable.strings deleted file mode 100644 index ce08bc035..000000000 --- a/Dependencies/G7SensorKit/sk.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS dokáže čítať dáta z G7 CGM, ale stále musíte používať aplikáciu Dexcom G7 na párovanie, kalibráciu a ďalšiu správu senzora."; - -/* Button title for starting setup */ -"Continue" = "Pokračovať"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Zrušiť"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Dáta o hladine glukózy nie sú k dispozícii"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Senzor pracuje správne"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Senzor je zastavený"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Senzor sa zahrieva"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Senzor exspiroval"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Senzor zlyhal"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Senzor je v neznámom stave %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Čas zavedenia"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Senzor exspiruje"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Dodatočná doba na výmenu senzoru končí"; - -/* Field label */ -"Glucose" = "Glykémia"; - -"Last Reading" = "Posledná hodnota"; - -"Time" = "Čas"; - -"Trend" = "Vývoj"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Názov"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Skenuje sa"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Pripojený"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Pripája sa"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Posledné spojenie"; - -/* Configuration */ -"Configuration" = "Nastavenie"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Nahrať merania"; - -/* Button */ -"Scan for new sensor" = "Načítať nový senzor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Odstrániť senzor"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "NÍZKE"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "VYSOKÉ"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Vyhľadávam nový senzor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Senzor exspiroval"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Zahrievanie senzora dokončené"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Zahrievanie senzora dokončené"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Senzor zlyhal"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Senzor exspiruje"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Zostávajúce predĺžené obdobie"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Vyhľadávam\nsenzor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Senzor\nexspiroval"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Senzor\nzlyhal"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Strata\nsignálu"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Problém\nsenzoru"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Zahrievanie\nsenzoru"; diff --git a/Dependencies/G7SensorKit/sv.lproj/Localizable.strings b/Dependencies/G7SensorKit/sv.lproj/Localizable.strings deleted file mode 100644 index aa32dbf3d..000000000 --- a/Dependencies/G7SensorKit/sv.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS kan läsa G7 CGM-värden, men du måste alltjämt använda Dexcom G7-appen för parkoppling, kalibrering samt hantering av sensorn."; - -/* Button title for starting setup */ -"Continue" = "Fortsätt"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Avbryt"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Inga blodglukosdata tillgängliga"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensorn är OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensorn har stoppats"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensorn värms upp"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensorns livslängd är slut"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensorn är felaktig"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensorstatus okänd %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensorstart"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensorns utgångsdatum"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Slut av livslängd"; - -/* Field label */ -"Glucose" = "Glukos"; - -"Last Reading" = "Senaste avläsning"; - -"Time" = "Tid"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Namn"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Skannar"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Ansluten"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Ansluter"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Senaste anslutning"; - -/* Configuration */ -"Configuration" = "Konfiguration"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Ladda upp blodsocker"; - -/* Button */ -"Scan for new sensor" = "Skanna efter ny sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Radera CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LÅGT"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HÖGT"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Söker efter sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensorns livslängd är slut"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Uppvärming av sensor"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Uppvärming av sensor"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensorn är felaktig"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensorn går ut"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Tid kvar av sensors livslängd"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Söker efter\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nUtgått"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nmisslyckades"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal-\nförlust"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nProblem"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nUppvärmning"; diff --git a/Dependencies/G7SensorKit/tr.lproj/Localizable.strings b/Dependencies/G7SensorKit/tr.lproj/Localizable.strings deleted file mode 100644 index b80812dfc..000000000 --- a/Dependencies/G7SensorKit/tr.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS, G7 CGM verilerini okuyabilir ancak yine de eşleştirme, kalibrasyon ve diğer sensör yönetimi için Dexcom G7 Uygulamasını kullanmanız gerekir."; - -/* Button title for starting setup */ -"Continue" = "Devam et"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Vazgeç"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glikoz verileri kullanılamıyor"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensör TAMAM"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensör durduruldu"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensör ısınıyor"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensör süresi doldu"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensör arızalı"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensör bilinmeyen durumda %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensörü Başlat"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensör Süre Sonu"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Yetkisiz Kullanım Sonu"; - -/* Field label */ -"Glucose" = "Glikoz"; - -"Last Reading" = "Son Okuma Değeri"; - -"Time" = "Saat"; - -"Trend" = "Eğilim"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "İsim"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Taranıyor"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Bağlandı"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Bağlanıyor"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Son Bağlantı"; - -/* Configuration */ -"Configuration" = "Yapılandırma"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Okumaları Yükle"; - -/* Button */ -"Scan for new sensor" = "Yeni sensör için tara"; - -/* Button label for removing CGM */ -"Delete CGM" = "CGM'i Sil"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "DÜŞÜK"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "YÜKSEK"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/dak"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Sensör aranıyor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensör süresi doldu"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Isınma tamamlandı"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Isınma tamamlandı"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensör arızalı"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensör süresi doluyor"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Kalan ek süre"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Sensör\nAranıyor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensör\nSüresi Doldu"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensör\nArızalı"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Sinyal\nKaybı"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensör\nSorunu"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensör\nIsınıyor"; diff --git a/Dependencies/G7SensorKit/uk.lproj/Localizable.strings b/Dependencies/G7SensorKit/uk.lproj/Localizable.strings deleted file mode 100644 index b36b92942..000000000 --- a/Dependencies/G7SensorKit/uk.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS може читати дані G7 CGM, але ви все одно повинні використовувати додаток Dexcom G7 для парування, калібрування та іншого управління сенсором."; - -/* Button title for starting setup */ -"Continue" = "Продовжити"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Відмінити"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Дані глюкози недоступні"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Сенсор підключено"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Сенсор зупинений"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Сенсор прогрівається"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Термін Сенсору закінчився"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Не вдалося встановити Сенсор"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Сенсор знаходиться в невідомому стані%1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Старт Сенсора моніторингу"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Термін дії Сенсору"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Час до блокування"; - -/* Field label */ -"Glucose" = "Глюкоза"; - -"Last Reading" = "Останнє читання"; - -"Time" = "Час"; - -"Trend" = "Тренди"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Ім’я"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Сканування"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Під'єднаний"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Під'єднання"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Останнє підключення"; - -/* Configuration */ -"Configuration" = "Налаштування"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Вивантажити читання"; - -/* Button */ -"Scan for new sensor" = "Сканувати новий Сенсор"; - -/* Button label for removing CGM */ -"Delete CGM" = "Видалити CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "НИЗЬКИЙ"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "ВИСОКИЙ"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/хв"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Пошук Сенсору"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Термін Сенсору закінчився"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Прогрів виконано"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Прогрів виконано"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Не вдалося встановити Сенсор"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Сенсор закінчується"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Період витонченості, що залишився"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Пошук\nСенсору"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Сенсор\nЗакінчився"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Сенсори\nНе вдалося"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Сигнал\nВтрата"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Сенсор\nПроблема"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Сенсор\nПрогрів"; diff --git a/Dependencies/G7SensorKit/vi.lproj/Localizable.strings b/Dependencies/G7SensorKit/vi.lproj/Localizable.strings deleted file mode 100644 index 917eec144..000000000 --- a/Dependencies/G7SensorKit/vi.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS có thể đọc dữ liệu G7 CGM tuy nhiên bạn nên dùng app của Dexcom G7 để ghép đôi, hiệu chỉnh và quản lý sensor."; - -/* Button title for starting setup */ -"Continue" = "Tiếp tục"; - -/* Button text to cancel G7 setup */ -"Cancel" = "Bỏ qua"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Dữ liệu đường huyết không có sẵn"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Cảm biến đã dừng hoạt động"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Cảm biến đang khởi động"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Cảm biến đã hết hạn"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Lỗi cảm biến"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Trạng thái cảm biến không xác định %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Khởi động Cảm biến"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Cảm biến hết hạn"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Thời gian ân huệ kết thúc"; - -/* Field label */ -"Glucose" = "Đường huyết"; - -"Last Reading" = "Kết quả đọc gần nhất"; - -"Time" = "Thời gian"; - -"Trend" = "Xu hướng Glucose"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "Tên"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Đang quét"; - -/* title for g7 settings connection status when connected */ -"Connected" = "Đã kết nối"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "Đang kết nối"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Kết nối gần đây nhất"; - -/* Configuration */ -"Configuration" = "Cấu hình"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Glucose đang tải lên"; - -/* Button */ -"Scan for new sensor" = "Scan để thay sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "Xoá CGM"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "THẤP"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "CAO"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/phút"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Đang tìm kiếm cảm biến"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Cảm biến đã hết hạn"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Khởi động hoàn tất"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Khởi động hoàn tất"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Lỗi cảm biến"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor hết hạn"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Thời gian ân huệ còn lại"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Đang tìm kiếm \n sensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\n hết hạn"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\n thất bại"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Tín hiệu\n mất"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\n có vấn đề"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\n đang khởi động"; diff --git a/Dependencies/G7SensorKit/zh-Hans.lproj/Localizable.strings b/Dependencies/G7SensorKit/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 06ecefda0..000000000 --- a/Dependencies/G7SensorKit/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,129 +0,0 @@ -/* Title on WelcomeView */ -"Dexcom G7" = "Dexcom G7"; - -/* Descriptive text on G7StartupView */ -"iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management." = "iAPS can read G7 CGM data, but you must still use the Dexcom G7 App for pairing, calibration, and other sensor management."; - -/* Button title for starting setup */ -"Continue" = "继续"; - -/* Button text to cancel G7 setup */ -"Cancel" = "取消"; - -/* Error description for unreliable state */ -"Glucose data is unavailable" = "Glucose data is unavailable"; - -/* The description of sensor algorithm state when sensor is ok. */ -"Sensor is OK" = "Sensor is OK"; - -/* The description of sensor algorithm state when sensor is stopped." */ -"Sensor is stopped" = "Sensor is stopped"; - -/* The description of sensor algorithm state when sensor is warming up. */ -"Sensor is warming up" = "Sensor is warming up"; - -/* The description of sensor algorithm state when sensor is expired. */ -"Sensor expired" = "Sensor expired"; - -/* The description of sensor algorithm state when sensor failed. */ -"Sensor failed" = "Sensor failed"; - -/* The description of sensor algorithm state when raw value is unknown. (1: missing data details) */ -"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d"; - -/* title for g7 settings row showing sensor start time */ -"Sensor Start" = "Sensor Start"; - -/* title for g7 settings row showing sensor expiration time */ -"Sensor Expiration" = "Sensor Expiration"; - -/* title for g7 settings row showing sensor grace period end time */ -"Grace Period End" = "Grace Period End"; - -/* Field label */ -"Glucose" = "葡萄糖"; - -"Last Reading" = "Last Reading"; - -"Time" = "时间"; - -"Trend" = "Trend"; - -"Bluetooth" = "Bluetooth"; - -/* title for g7 settings row showing BLE Name */ -"Name" = "设备名称"; - -/* title for g7 settings connection status when scanning */ -"Scanning" = "Scanning"; - -/* title for g7 settings connection status when connected */ -"Connected" = "已连接"; - -/* title for g7 settings connection status when connecting */ -"Connecting" = "正在连接"; - -/* title for g7 settings row showing sensor last connect time */ -"Last Connect" = "Last Connect"; - -/* Configuration */ -"Configuration" = "配置"; - -/* title for g7 config settings to upload readings */ -"Upload Readings" = "Upload Readings"; - -/* Button */ -"Scan for new sensor" = "Scan for new sensor"; - -/* Button label for removing CGM */ -"Delete CGM" = "删除CGM数据源"; - -/* No glucose value representation (3 dashes for mg/dL) */ -"– – –" = "– – –"; -/* String displayed instead of a glucose value below the CGM range */ -"LOW" = "LOW"; - -/* String displayed instead of a glucose value above the CGM range */ -"HIGH" = "HIGH"; - -/* Format string for glucose trend per minute. (1: glucose value and unit) */ -"%@/min" = "%@/min"; - -/* G7 Progress bar label when searching for sensor */ -"Searching for sensor" = "Searching for sensor"; - -/* G7 Progress bar label when sensor expired */ -"Sensor expired" = "Sensor expired"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor in warmup */ -"Warmup completes" = "Warmup completes"; - -/* G7 Progress bar label when sensor failed */ -"Sensor failed" = "Sensor failed"; - -/* G7 Progress bar label when sensor lifetime progress showing */ -"Sensor expires" = "Sensor expires"; - -/* G7 Progress bar label when sensor grace period progress showing */ -"Grace period remaining" = "Grace period remaining"; - -/* G7 Status highlight text for searching for sensor */ -"Searching for\nSensor" = "Searching for\nSensor"; - -/* G7 Status highlight text for sensor expired */ -"Sensor\nExpired" = "Sensor\nExpired"; - -/* G7 Status highlight text for signal loss */ -"Sensor\nFailed" = "Sensor\nFailed"; - -/* G7 Status highlight text for signal loss */ -"Signal\nLoss" = "Signal\nLoss"; - -/*G7 Status highlight text for sensor error */ -"Sensor\nIssue" = "Sensor\nIssue"; - -/* G7 Status highlight text for sensor warmup */ -"Sensor\nWarmup" = "Sensor\nWarmup"; diff --git a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample.xcodeproj/project.pbxproj b/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample.xcodeproj/project.pbxproj deleted file mode 100644 index 403d0eee1..000000000 --- a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample.xcodeproj/project.pbxproj +++ /dev/null @@ -1,388 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 55; - objects = { - -/* Begin PBXBuildFile section */ - 38567101272C4E39002C4DD8 /* LibreTramsmitterExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38567100272C4E39002C4DD8 /* LibreTramsmitterExampleApp.swift */; }; - 38567103272C4E39002C4DD8 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38567102272C4E39002C4DD8 /* ContentView.swift */; }; - 38567105272C4E3B002C4DD8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 38567104272C4E3B002C4DD8 /* Assets.xcassets */; }; - 38567108272C4E3B002C4DD8 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 38567107272C4E3B002C4DD8 /* Preview Assets.xcassets */; }; - 3856711B272C51A3002C4DD8 /* LibreTransmitter in Frameworks */ = {isa = PBXBuildFile; productRef = 3856711A272C51A3002C4DD8 /* LibreTransmitter */; }; - 38FEF403273AE2E300574A46 /* StateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FEF402273AE2E300574A46 /* StateModel.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 385670FD272C4E39002C4DD8 /* LibreTramsmitterExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LibreTramsmitterExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 38567100272C4E39002C4DD8 /* LibreTramsmitterExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibreTramsmitterExampleApp.swift; sourceTree = ""; }; - 38567102272C4E39002C4DD8 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; - 38567104272C4E3B002C4DD8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 38567107272C4E3B002C4DD8 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; - 38567118272C5173002C4DD8 /* LibreTransmitter */ = {isa = PBXFileReference; lastKnownFileType = folder; name = LibreTransmitter; path = ..; sourceTree = ""; }; - 3856711C272C5281002C4DD8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; - 38FEF3FF2739509400574A46 /* LibreTramsmitterExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LibreTramsmitterExample.entitlements; sourceTree = ""; }; - 38FEF402273AE2E300574A46 /* StateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateModel.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 385670FA272C4E39002C4DD8 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 3856711B272C51A3002C4DD8 /* LibreTransmitter in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 3818AA43274BFE8A00843DB3 /* Frameworks */ = { - isa = PBXGroup; - children = ( - ); - name = Frameworks; - sourceTree = ""; - }; - 385670F4272C4E39002C4DD8 = { - isa = PBXGroup; - children = ( - 385670FF272C4E39002C4DD8 /* LibreTramsmitterExample */, - 38567116272C5115002C4DD8 /* Packages */, - 385670FE272C4E39002C4DD8 /* Products */, - 3818AA43274BFE8A00843DB3 /* Frameworks */, - ); - sourceTree = ""; - }; - 385670FE272C4E39002C4DD8 /* Products */ = { - isa = PBXGroup; - children = ( - 385670FD272C4E39002C4DD8 /* LibreTramsmitterExample.app */, - ); - name = Products; - sourceTree = ""; - }; - 385670FF272C4E39002C4DD8 /* LibreTramsmitterExample */ = { - isa = PBXGroup; - children = ( - 38FEF3FF2739509400574A46 /* LibreTramsmitterExample.entitlements */, - 3856711C272C5281002C4DD8 /* Info.plist */, - 38567102272C4E39002C4DD8 /* ContentView.swift */, - 38567100272C4E39002C4DD8 /* LibreTramsmitterExampleApp.swift */, - 38567104272C4E3B002C4DD8 /* Assets.xcassets */, - 38567106272C4E3B002C4DD8 /* Preview Content */, - 38FEF402273AE2E300574A46 /* StateModel.swift */, - ); - path = LibreTramsmitterExample; - sourceTree = ""; - }; - 38567106272C4E3B002C4DD8 /* Preview Content */ = { - isa = PBXGroup; - children = ( - 38567107272C4E3B002C4DD8 /* Preview Assets.xcassets */, - ); - path = "Preview Content"; - sourceTree = ""; - }; - 38567116272C5115002C4DD8 /* Packages */ = { - isa = PBXGroup; - children = ( - 38567118272C5173002C4DD8 /* LibreTransmitter */, - ); - name = Packages; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 385670FC272C4E39002C4DD8 /* LibreTramsmitterExample */ = { - isa = PBXNativeTarget; - buildConfigurationList = 3856710B272C4E3B002C4DD8 /* Build configuration list for PBXNativeTarget "LibreTramsmitterExample" */; - buildPhases = ( - 385670F9272C4E39002C4DD8 /* Sources */, - 385670FA272C4E39002C4DD8 /* Frameworks */, - 385670FB272C4E39002C4DD8 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = LibreTramsmitterExample; - packageProductDependencies = ( - 3856711A272C51A3002C4DD8 /* LibreTransmitter */, - ); - productName = LibreTramsmitterExample; - productReference = 385670FD272C4E39002C4DD8 /* LibreTramsmitterExample.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 385670F5272C4E39002C4DD8 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1310; - LastUpgradeCheck = 1310; - TargetAttributes = { - 385670FC272C4E39002C4DD8 = { - CreatedOnToolsVersion = 13.1; - }; - }; - }; - buildConfigurationList = 385670F8272C4E39002C4DD8 /* Build configuration list for PBXProject "LibreTramsmitterExample" */; - compatibilityVersion = "Xcode 13.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 385670F4272C4E39002C4DD8; - productRefGroup = 385670FE272C4E39002C4DD8 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 385670FC272C4E39002C4DD8 /* LibreTramsmitterExample */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 385670FB272C4E39002C4DD8 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 38567108272C4E3B002C4DD8 /* Preview Assets.xcassets in Resources */, - 38567105272C4E3B002C4DD8 /* Assets.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 385670F9272C4E39002C4DD8 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 38FEF403273AE2E300574A46 /* StateModel.swift in Sources */, - 38567103272C4E39002C4DD8 /* ContentView.swift in Sources */, - 38567101272C4E39002C4DD8 /* LibreTramsmitterExampleApp.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 38567109272C4E3B002C4DD8 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = 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_DOCUMENTATION_COMMENTS = YES; - 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - 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 = 15.0; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 3856710A272C4E3B002C4DD8 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = 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_DOCUMENTATION_COMMENTS = YES; - 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - 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 = 15.0; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 3856710C272C4E3B002C4DD8 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = LibreTramsmitterExample/LibreTramsmitterExample.entitlements; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = "\"LibreTramsmitterExample/Preview Content\""; - DEVELOPMENT_TEAM = BA7ZHP4963; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = NO; - INFOPLIST_FILE = LibreTramsmitterExample/Info.plist; - INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchScreen_Generation = YES; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = ru.artpancreas.LibreTramsmitterExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 3856710D272C4E3B002C4DD8 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = LibreTramsmitterExample/LibreTramsmitterExample.entitlements; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = "\"LibreTramsmitterExample/Preview Content\""; - DEVELOPMENT_TEAM = BA7ZHP4963; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = NO; - INFOPLIST_FILE = LibreTramsmitterExample/Info.plist; - INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchScreen_Generation = YES; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = ru.artpancreas.LibreTramsmitterExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 385670F8272C4E39002C4DD8 /* Build configuration list for PBXProject "LibreTramsmitterExample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 38567109272C4E3B002C4DD8 /* Debug */, - 3856710A272C4E3B002C4DD8 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 3856710B272C4E3B002C4DD8 /* Build configuration list for PBXNativeTarget "LibreTramsmitterExample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3856710C272C4E3B002C4DD8 /* Debug */, - 3856710D272C4E3B002C4DD8 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCSwiftPackageProductDependency section */ - 3856711A272C51A3002C4DD8 /* LibreTransmitter */ = { - isa = XCSwiftPackageProductDependency; - productName = LibreTransmitter; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 385670F5272C4E39002C4DD8 /* Project object */; -} diff --git a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Assets.xcassets/AccentColor.colorset/Contents.json b/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb8789700..000000000 --- a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Assets.xcassets/AppIcon.appiconset/Contents.json b/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 9221b9bb1..000000000 --- a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Assets.xcassets/Contents.json b/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/ContentView.swift b/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/ContentView.swift deleted file mode 100644 index 92b981b8c..000000000 --- a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/ContentView.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// ContentView.swift -// LibreTramsmitterExample -// -// Created by Ivan Valkou on 29.10.2021. -// - -import SwiftUI -import LibreTransmitter -import HealthKit - -struct ContentView: View { - @StateObject var state = StateModel() - - @State var manager: LibreTransmitterManager? { - didSet { - manager?.cgmManagerDelegate = state - } - } - - @State var setupPresented = false - @State var settingsPresented = false - @AppStorage("LibreTransmitterManager.configured") var configured = false - - let unit = HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: .liter()) - - var body: some View { - VStack(spacing: 50) { - Text("\(state.currentGlucose?.glucoseDouble ?? .nan)") - Text("\(state.trend.symbol)") - - Button("Libre Transmitter") { - setupPresented = true - } - - Button("Test alert sound") { - NotificationHelper.playSoundIfNeeded() - } - } - .sheet(isPresented: $setupPresented) {} content: { - if configured, let manager = manager { - LibreTransmitterSettingsView( - manager: manager, - glucoseUnit: unit) { - self.manager = nil - configured = false - } completion: { - setupPresented = false - } - - } else { - LibreTransmitterSetupView { manager in - self.manager = manager - configured = true - } completion: { - setupPresented = false - } - } - } - .onAppear { - if configured { - manager = LibreTransmitterManager() - } - } - } -} diff --git a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Info.plist b/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Info.plist deleted file mode 100644 index 4619575c3..000000000 --- a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Info.plist +++ /dev/null @@ -1,56 +0,0 @@ - - - - - NSBluetoothAlwaysUsageDescription - Because why not - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - LSRequiresIPhoneOS - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - - UIApplicationSupportsIndirectInputEvents - - UIBackgroundModes - - bluetooth-central - bluetooth-peripheral - - UILaunchScreen - - UILaunchScreen - - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~iphone - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/LibreTramsmitterExample.entitlements b/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/LibreTramsmitterExample.entitlements deleted file mode 100644 index 1ca50cc82..000000000 --- a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/LibreTramsmitterExample.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.developer.usernotifications.time-sensitive - - - diff --git a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/LibreTramsmitterExampleApp.swift b/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/LibreTramsmitterExampleApp.swift deleted file mode 100644 index 18f0bda2f..000000000 --- a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/LibreTramsmitterExampleApp.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// LibreTramsmitterExampleApp.swift -// LibreTramsmitterExample -// -// Created by Ivan Valkou on 29.10.2021. -// - -import SwiftUI - -@main -struct LibreTramsmitterExampleApp: App { - var body: some Scene { - WindowGroup { - ContentView() - } - } -} diff --git a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Preview Content/Preview Assets.xcassets/Contents.json b/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Preview Content/Preview Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/Preview Content/Preview Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/StateModel.swift b/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/StateModel.swift deleted file mode 100644 index 44b077724..000000000 --- a/Dependencies/LibreTransmitter/LibreTramsmitterExample/LibreTramsmitterExample/StateModel.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// StateModel.swift -// LibreTramsmitterExample -// -// Created by Ivan Valkou on 09.11.2021. -// - -import SwiftUI -import LibreTransmitter - -final class StateModel: ObservableObject { - private let delegateQueue = DispatchQueue(label: "StateModel.delegateQueue") - @Published var currentGlucose: LibreGlucose? - @Published var trend: GlucoseTrend = .flat -} - -extension StateModel: LibreTransmitterManagerDelegate { - var queue: DispatchQueue { - delegateQueue - } - - func startDateToFilterNewData(for: LibreTransmitterManager) -> Date? { - Date().addingTimeInterval(-3600) - } - - func cgmManager(_ manager: LibreTransmitterManager, hasNew result: Result<[LibreGlucose], Error>) { - switch result { - - case let .success(data): - print("New data: \(data)") - DispatchQueue.main.async { - self.trend = manager.glucoseDisplay?.trendType ?? .flat - self.currentGlucose = data.first - } - case let .failure(error): - print("Error: \(error.localizedDescription)") - } - } - - func overcalibration(for: LibreTransmitterManager) -> ((Double) -> (Double))? { - nil - } -} diff --git a/Dependencies/LibreTransmitter/Package.swift b/Dependencies/LibreTransmitter/Package.swift deleted file mode 100644 index 37bfde83d..000000000 --- a/Dependencies/LibreTransmitter/Package.swift +++ /dev/null @@ -1,28 +0,0 @@ -// swift-tools-version:5.5 - -import PackageDescription - -let package = Package( - name: "LibreTransmitter", - platforms: [.iOS(.v14)], - products: [ - .library( - name: "LibreTransmitter", - targets: ["LibreTransmitter"]), - .library( - name: "RawGlucose", - targets: ["RawGlucose"]), - ], - dependencies: [], - targets: [ - .binaryTarget( - name: "RawGlucose", - path: "RawGlucose.xcframework"), - .target( - name: "LibreTransmitter", - dependencies: ["RawGlucose"], - resources: [.process("LibreTransmitterUI/Graphics")] - ) - - ] -) diff --git a/Dependencies/LibreTransmitter/README.md b/Dependencies/LibreTransmitter/README.md deleted file mode 100644 index 7e078b032..000000000 --- a/Dependencies/LibreTransmitter/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# LibreTransmitter - -A description of this package. diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/Info.plist b/Dependencies/LibreTransmitter/RawGlucose.xcframework/Info.plist deleted file mode 100644 index bef68fd7c..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/Info.plist +++ /dev/null @@ -1,40 +0,0 @@ - - - - - AvailableLibraries - - - LibraryIdentifier - ios-arm64_x86_64-simulator - LibraryPath - RawGlucose.framework - SupportedArchitectures - - arm64 - x86_64 - - SupportedPlatform - ios - SupportedPlatformVariant - simulator - - - LibraryIdentifier - ios-arm64 - LibraryPath - RawGlucose.framework - SupportedArchitectures - - arm64 - - SupportedPlatform - ios - - - CFBundlePackageType - XFWK - XCFrameworkFormatVersion - 1.0 - - diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Headers/RawGlucose-Swift.h b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Headers/RawGlucose-Swift.h deleted file mode 100644 index ed205baab..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Headers/RawGlucose-Swift.h +++ /dev/null @@ -1,212 +0,0 @@ -// Generated by Apple Swift version 5.5.1 (swiftlang-1300.0.31.4 clang-1300.0.29.6) -#ifndef RAWGLUCOSE_SWIFT_H -#define RAWGLUCOSE_SWIFT_H -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wgcc-compat" - -#if !defined(__has_include) -# define __has_include(x) 0 -#endif -#if !defined(__has_attribute) -# define __has_attribute(x) 0 -#endif -#if !defined(__has_feature) -# define __has_feature(x) 0 -#endif -#if !defined(__has_warning) -# define __has_warning(x) 0 -#endif - -#if __has_include() -# include -#endif - -#pragma clang diagnostic ignored "-Wauto-import" -#include -#include -#include -#include - -#if !defined(SWIFT_TYPEDEFS) -# define SWIFT_TYPEDEFS 1 -# if __has_include() -# include -# elif !defined(__cplusplus) -typedef uint_least16_t char16_t; -typedef uint_least32_t char32_t; -# endif -typedef float swift_float2 __attribute__((__ext_vector_type__(2))); -typedef float swift_float3 __attribute__((__ext_vector_type__(3))); -typedef float swift_float4 __attribute__((__ext_vector_type__(4))); -typedef double swift_double2 __attribute__((__ext_vector_type__(2))); -typedef double swift_double3 __attribute__((__ext_vector_type__(3))); -typedef double swift_double4 __attribute__((__ext_vector_type__(4))); -typedef int swift_int2 __attribute__((__ext_vector_type__(2))); -typedef int swift_int3 __attribute__((__ext_vector_type__(3))); -typedef int swift_int4 __attribute__((__ext_vector_type__(4))); -typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); -typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); -typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); -#endif - -#if !defined(SWIFT_PASTE) -# define SWIFT_PASTE_HELPER(x, y) x##y -# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) -#endif -#if !defined(SWIFT_METATYPE) -# define SWIFT_METATYPE(X) Class -#endif -#if !defined(SWIFT_CLASS_PROPERTY) -# if __has_feature(objc_class_property) -# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ -# else -# define SWIFT_CLASS_PROPERTY(...) -# endif -#endif - -#if __has_attribute(objc_runtime_name) -# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) -#else -# define SWIFT_RUNTIME_NAME(X) -#endif -#if __has_attribute(swift_name) -# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) -#else -# define SWIFT_COMPILE_NAME(X) -#endif -#if __has_attribute(objc_method_family) -# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) -#else -# define SWIFT_METHOD_FAMILY(X) -#endif -#if __has_attribute(noescape) -# define SWIFT_NOESCAPE __attribute__((noescape)) -#else -# define SWIFT_NOESCAPE -#endif -#if __has_attribute(ns_consumed) -# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) -#else -# define SWIFT_RELEASES_ARGUMENT -#endif -#if __has_attribute(warn_unused_result) -# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -#else -# define SWIFT_WARN_UNUSED_RESULT -#endif -#if __has_attribute(noreturn) -# define SWIFT_NORETURN __attribute__((noreturn)) -#else -# define SWIFT_NORETURN -#endif -#if !defined(SWIFT_CLASS_EXTRA) -# define SWIFT_CLASS_EXTRA -#endif -#if !defined(SWIFT_PROTOCOL_EXTRA) -# define SWIFT_PROTOCOL_EXTRA -#endif -#if !defined(SWIFT_ENUM_EXTRA) -# define SWIFT_ENUM_EXTRA -#endif -#if !defined(SWIFT_CLASS) -# if __has_attribute(objc_subclassing_restricted) -# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA -# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# else -# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# endif -#endif -#if !defined(SWIFT_RESILIENT_CLASS) -# if __has_attribute(objc_class_stub) -# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) -# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) -# else -# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) -# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) -# endif -#endif - -#if !defined(SWIFT_PROTOCOL) -# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA -# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA -#endif - -#if !defined(SWIFT_EXTENSION) -# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) -#endif - -#if !defined(OBJC_DESIGNATED_INITIALIZER) -# if __has_attribute(objc_designated_initializer) -# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) -# else -# define OBJC_DESIGNATED_INITIALIZER -# endif -#endif -#if !defined(SWIFT_ENUM_ATTR) -# if defined(__has_attribute) && __has_attribute(enum_extensibility) -# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) -# else -# define SWIFT_ENUM_ATTR(_extensibility) -# endif -#endif -#if !defined(SWIFT_ENUM) -# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type -# if __has_feature(generalized_swift_name) -# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type -# else -# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) -# endif -#endif -#if !defined(SWIFT_UNAVAILABLE) -# define SWIFT_UNAVAILABLE __attribute__((unavailable)) -#endif -#if !defined(SWIFT_UNAVAILABLE_MSG) -# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) -#endif -#if !defined(SWIFT_AVAILABILITY) -# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) -#endif -#if !defined(SWIFT_WEAK_IMPORT) -# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) -#endif -#if !defined(SWIFT_DEPRECATED) -# define SWIFT_DEPRECATED __attribute__((deprecated)) -#endif -#if !defined(SWIFT_DEPRECATED_MSG) -# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) -#endif -#if __has_feature(attribute_diagnose_if_objc) -# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) -#else -# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) -#endif -#if !defined(IBSegueAction) -# define IBSegueAction -#endif -#if __has_feature(modules) -#if __has_warning("-Watimport-in-framework-header") -#pragma clang diagnostic ignored "-Watimport-in-framework-header" -#endif -#endif - -#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" -#pragma clang diagnostic ignored "-Wduplicate-method-arg" -#if __has_warning("-Wpragma-clang-attribute") -# pragma clang diagnostic ignored "-Wpragma-clang-attribute" -#endif -#pragma clang diagnostic ignored "-Wunknown-pragmas" -#pragma clang diagnostic ignored "-Wnullability" - -#if __has_attribute(external_source_symbol) -# pragma push_macro("any") -# undef any -# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="RawGlucose",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) -# pragma pop_macro("any") -#endif - -#if __has_attribute(external_source_symbol) -# pragma clang attribute pop -#endif -#pragma clang diagnostic pop -#endif diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Headers/RawGlucose.h b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Headers/RawGlucose.h deleted file mode 100644 index 0bb475c6f..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Headers/RawGlucose.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// RawGlucose.h -// RawGlucose -// -// Created by Ivan Valkou on 29.10.2021. -// - -#import - -//! Project version number for RawGlucose. -FOUNDATION_EXPORT double RawGlucoseVersionNumber; - -//! Project version string for RawGlucose. -FOUNDATION_EXPORT const unsigned char RawGlucoseVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Info.plist b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Info.plist deleted file mode 100644 index 15d6b27bc..000000000 Binary files a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Info.plist and /dev/null differ diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64-apple-ios.swiftdoc b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64-apple-ios.swiftdoc deleted file mode 100644 index e1bbd9719..000000000 Binary files a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64-apple-ios.swiftdoc and /dev/null differ diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64-apple-ios.swiftinterface b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64-apple-ios.swiftinterface deleted file mode 100644 index 8bdb66a37..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64-apple-ios.swiftinterface +++ /dev/null @@ -1,8 +0,0 @@ -// swift-interface-format-version: 1.0 -// swift-compiler-version: Apple Swift version 5.5.1 (swiftlang-1300.0.31.4 clang-1300.0.29.6) -// swift-module-flags: -target arm64-apple-ios14.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name RawGlucose -import Foundation -@_exported import RawGlucose -import Swift -import _Concurrency -public func glucoseValueFromRaw(rawTemperature: Swift.Double, rawTemperatureAdjustment: Swift.Double, rawGlucose: Swift.Double, i1: Swift.Int, i2: Swift.Int, i3: Swift.Double, i4: Swift.Double, i5: Swift.Double, i6: Swift.Double) -> Swift.Double diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64.swiftdoc b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64.swiftdoc deleted file mode 100644 index e1bbd9719..000000000 Binary files a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64.swiftdoc and /dev/null differ diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64.swiftinterface b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64.swiftinterface deleted file mode 100644 index 8bdb66a37..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64.swiftinterface +++ /dev/null @@ -1,8 +0,0 @@ -// swift-interface-format-version: 1.0 -// swift-compiler-version: Apple Swift version 5.5.1 (swiftlang-1300.0.31.4 clang-1300.0.29.6) -// swift-module-flags: -target arm64-apple-ios14.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name RawGlucose -import Foundation -@_exported import RawGlucose -import Swift -import _Concurrency -public func glucoseValueFromRaw(rawTemperature: Swift.Double, rawTemperatureAdjustment: Swift.Double, rawGlucose: Swift.Double, i1: Swift.Int, i2: Swift.Int, i3: Swift.Double, i4: Swift.Double, i5: Swift.Double, i6: Swift.Double) -> Swift.Double diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/module.modulemap b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/module.modulemap deleted file mode 100644 index 73e07f3aa..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/Modules/module.modulemap +++ /dev/null @@ -1,11 +0,0 @@ -framework module RawGlucose { - umbrella header "RawGlucose.h" - - export * - module * { export * } -} - -module RawGlucose.Swift { - header "RawGlucose-Swift.h" - requires objc -} diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/RawGlucose b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/RawGlucose deleted file mode 100755 index 9f2bdcd45..000000000 Binary files a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/RawGlucose and /dev/null differ diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/_CodeSignature/CodeResources b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/_CodeSignature/CodeResources deleted file mode 100644 index 284af541d..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64/RawGlucose.framework/_CodeSignature/CodeResources +++ /dev/null @@ -1,201 +0,0 @@ - - - - - files - - Headers/RawGlucose-Swift.h - - TbsdmPkVid1MmO08l/+IxleHiDQ= - - Headers/RawGlucose.h - - e5N6Xw/Q6Ssus1Sfka2OdAgEwfs= - - Info.plist - - tEul9y3almjw/PjiqgW3W7uKoME= - - Modules/RawGlucose.swiftmodule/arm64-apple-ios.swiftdoc - - N3fVe2jpkhUblN1Mys8Q2Qhaa6w= - - Modules/RawGlucose.swiftmodule/arm64-apple-ios.swiftinterface - - bDo7yq/Pn9WJy96YLVD14CFqy6k= - - Modules/RawGlucose.swiftmodule/arm64-apple-ios.swiftmodule - - VJ11gvKIAReSPnvteZuJ/Zi2lzs= - - Modules/RawGlucose.swiftmodule/arm64.swiftdoc - - N3fVe2jpkhUblN1Mys8Q2Qhaa6w= - - Modules/RawGlucose.swiftmodule/arm64.swiftinterface - - bDo7yq/Pn9WJy96YLVD14CFqy6k= - - Modules/RawGlucose.swiftmodule/arm64.swiftmodule - - VJ11gvKIAReSPnvteZuJ/Zi2lzs= - - Modules/module.modulemap - - Nbavz/+JmGFVpOq9rrggRbhjo/Y= - - - files2 - - Headers/RawGlucose-Swift.h - - hash2 - - QTI1cy5YKF3DvEw55SrCA5btCBewRFi+VYIPM8VFMxg= - - - Headers/RawGlucose.h - - hash2 - - vWp1R9C9/5EBlkAhcUZ6DglPTPIL7LdzMYFDrxPPp2w= - - - Modules/RawGlucose.swiftmodule/arm64-apple-ios.swiftdoc - - hash2 - - KD1y+BgwVATnQ7wQtEbcw5J5sG2J6FDDlUSo2Mc5vbk= - - - Modules/RawGlucose.swiftmodule/arm64-apple-ios.swiftinterface - - hash2 - - zsjCd1qkk/OvTWr8aJ0L7SbzmnZA7/2pKuTHg3N9cgY= - - - Modules/RawGlucose.swiftmodule/arm64-apple-ios.swiftmodule - - hash2 - - 2Az19ev+8tlVF8RvybrcaMdD2qRfiAg2iEOK8NwNN0Q= - - - Modules/RawGlucose.swiftmodule/arm64.swiftdoc - - hash2 - - KD1y+BgwVATnQ7wQtEbcw5J5sG2J6FDDlUSo2Mc5vbk= - - - Modules/RawGlucose.swiftmodule/arm64.swiftinterface - - hash2 - - zsjCd1qkk/OvTWr8aJ0L7SbzmnZA7/2pKuTHg3N9cgY= - - - Modules/RawGlucose.swiftmodule/arm64.swiftmodule - - hash2 - - 2Az19ev+8tlVF8RvybrcaMdD2qRfiAg2iEOK8NwNN0Q= - - - Modules/module.modulemap - - hash2 - - HGSrZF6T2tksU5dqClpOIcyQITvyjJOLdm6TEvIdU7M= - - - - rules - - ^.* - - ^.*\.lproj/ - - optional - - weight - 1000 - - ^.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^Base\.lproj/ - - weight - 1010 - - ^version.plist$ - - - rules2 - - .*\.dSYM($|/) - - weight - 11 - - ^(.*/)?\.DS_Store$ - - omit - - weight - 2000 - - ^.* - - ^.*\.lproj/ - - optional - - weight - 1000 - - ^.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^Base\.lproj/ - - weight - 1010 - - ^Info\.plist$ - - omit - - weight - 20 - - ^PkgInfo$ - - omit - - weight - 20 - - ^embedded\.provisionprofile$ - - weight - 20 - - ^version\.plist$ - - weight - 20 - - - - diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Headers/RawGlucose-Swift.h b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Headers/RawGlucose-Swift.h deleted file mode 100644 index 3e33d5ed7..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Headers/RawGlucose-Swift.h +++ /dev/null @@ -1,430 +0,0 @@ -#if 0 -#elif defined(__arm64__) && __arm64__ -// Generated by Apple Swift version 5.5.1 (swiftlang-1300.0.31.4 clang-1300.0.29.6) -#ifndef RAWGLUCOSE_SWIFT_H -#define RAWGLUCOSE_SWIFT_H -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wgcc-compat" - -#if !defined(__has_include) -# define __has_include(x) 0 -#endif -#if !defined(__has_attribute) -# define __has_attribute(x) 0 -#endif -#if !defined(__has_feature) -# define __has_feature(x) 0 -#endif -#if !defined(__has_warning) -# define __has_warning(x) 0 -#endif - -#if __has_include() -# include -#endif - -#pragma clang diagnostic ignored "-Wauto-import" -#include -#include -#include -#include - -#if !defined(SWIFT_TYPEDEFS) -# define SWIFT_TYPEDEFS 1 -# if __has_include() -# include -# elif !defined(__cplusplus) -typedef uint_least16_t char16_t; -typedef uint_least32_t char32_t; -# endif -typedef float swift_float2 __attribute__((__ext_vector_type__(2))); -typedef float swift_float3 __attribute__((__ext_vector_type__(3))); -typedef float swift_float4 __attribute__((__ext_vector_type__(4))); -typedef double swift_double2 __attribute__((__ext_vector_type__(2))); -typedef double swift_double3 __attribute__((__ext_vector_type__(3))); -typedef double swift_double4 __attribute__((__ext_vector_type__(4))); -typedef int swift_int2 __attribute__((__ext_vector_type__(2))); -typedef int swift_int3 __attribute__((__ext_vector_type__(3))); -typedef int swift_int4 __attribute__((__ext_vector_type__(4))); -typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); -typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); -typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); -#endif - -#if !defined(SWIFT_PASTE) -# define SWIFT_PASTE_HELPER(x, y) x##y -# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) -#endif -#if !defined(SWIFT_METATYPE) -# define SWIFT_METATYPE(X) Class -#endif -#if !defined(SWIFT_CLASS_PROPERTY) -# if __has_feature(objc_class_property) -# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ -# else -# define SWIFT_CLASS_PROPERTY(...) -# endif -#endif - -#if __has_attribute(objc_runtime_name) -# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) -#else -# define SWIFT_RUNTIME_NAME(X) -#endif -#if __has_attribute(swift_name) -# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) -#else -# define SWIFT_COMPILE_NAME(X) -#endif -#if __has_attribute(objc_method_family) -# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) -#else -# define SWIFT_METHOD_FAMILY(X) -#endif -#if __has_attribute(noescape) -# define SWIFT_NOESCAPE __attribute__((noescape)) -#else -# define SWIFT_NOESCAPE -#endif -#if __has_attribute(ns_consumed) -# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) -#else -# define SWIFT_RELEASES_ARGUMENT -#endif -#if __has_attribute(warn_unused_result) -# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -#else -# define SWIFT_WARN_UNUSED_RESULT -#endif -#if __has_attribute(noreturn) -# define SWIFT_NORETURN __attribute__((noreturn)) -#else -# define SWIFT_NORETURN -#endif -#if !defined(SWIFT_CLASS_EXTRA) -# define SWIFT_CLASS_EXTRA -#endif -#if !defined(SWIFT_PROTOCOL_EXTRA) -# define SWIFT_PROTOCOL_EXTRA -#endif -#if !defined(SWIFT_ENUM_EXTRA) -# define SWIFT_ENUM_EXTRA -#endif -#if !defined(SWIFT_CLASS) -# if __has_attribute(objc_subclassing_restricted) -# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA -# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# else -# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# endif -#endif -#if !defined(SWIFT_RESILIENT_CLASS) -# if __has_attribute(objc_class_stub) -# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) -# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) -# else -# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) -# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) -# endif -#endif - -#if !defined(SWIFT_PROTOCOL) -# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA -# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA -#endif - -#if !defined(SWIFT_EXTENSION) -# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) -#endif - -#if !defined(OBJC_DESIGNATED_INITIALIZER) -# if __has_attribute(objc_designated_initializer) -# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) -# else -# define OBJC_DESIGNATED_INITIALIZER -# endif -#endif -#if !defined(SWIFT_ENUM_ATTR) -# if defined(__has_attribute) && __has_attribute(enum_extensibility) -# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) -# else -# define SWIFT_ENUM_ATTR(_extensibility) -# endif -#endif -#if !defined(SWIFT_ENUM) -# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type -# if __has_feature(generalized_swift_name) -# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type -# else -# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) -# endif -#endif -#if !defined(SWIFT_UNAVAILABLE) -# define SWIFT_UNAVAILABLE __attribute__((unavailable)) -#endif -#if !defined(SWIFT_UNAVAILABLE_MSG) -# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) -#endif -#if !defined(SWIFT_AVAILABILITY) -# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) -#endif -#if !defined(SWIFT_WEAK_IMPORT) -# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) -#endif -#if !defined(SWIFT_DEPRECATED) -# define SWIFT_DEPRECATED __attribute__((deprecated)) -#endif -#if !defined(SWIFT_DEPRECATED_MSG) -# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) -#endif -#if __has_feature(attribute_diagnose_if_objc) -# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) -#else -# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) -#endif -#if !defined(IBSegueAction) -# define IBSegueAction -#endif -#if __has_feature(modules) -#if __has_warning("-Watimport-in-framework-header") -#pragma clang diagnostic ignored "-Watimport-in-framework-header" -#endif -#endif - -#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" -#pragma clang diagnostic ignored "-Wduplicate-method-arg" -#if __has_warning("-Wpragma-clang-attribute") -# pragma clang diagnostic ignored "-Wpragma-clang-attribute" -#endif -#pragma clang diagnostic ignored "-Wunknown-pragmas" -#pragma clang diagnostic ignored "-Wnullability" - -#if __has_attribute(external_source_symbol) -# pragma push_macro("any") -# undef any -# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="RawGlucose",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) -# pragma pop_macro("any") -#endif - -#if __has_attribute(external_source_symbol) -# pragma clang attribute pop -#endif -#pragma clang diagnostic pop -#endif - -#elif defined(__x86_64__) && __x86_64__ -// Generated by Apple Swift version 5.5.1 (swiftlang-1300.0.31.4 clang-1300.0.29.6) -#ifndef RAWGLUCOSE_SWIFT_H -#define RAWGLUCOSE_SWIFT_H -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wgcc-compat" - -#if !defined(__has_include) -# define __has_include(x) 0 -#endif -#if !defined(__has_attribute) -# define __has_attribute(x) 0 -#endif -#if !defined(__has_feature) -# define __has_feature(x) 0 -#endif -#if !defined(__has_warning) -# define __has_warning(x) 0 -#endif - -#if __has_include() -# include -#endif - -#pragma clang diagnostic ignored "-Wauto-import" -#include -#include -#include -#include - -#if !defined(SWIFT_TYPEDEFS) -# define SWIFT_TYPEDEFS 1 -# if __has_include() -# include -# elif !defined(__cplusplus) -typedef uint_least16_t char16_t; -typedef uint_least32_t char32_t; -# endif -typedef float swift_float2 __attribute__((__ext_vector_type__(2))); -typedef float swift_float3 __attribute__((__ext_vector_type__(3))); -typedef float swift_float4 __attribute__((__ext_vector_type__(4))); -typedef double swift_double2 __attribute__((__ext_vector_type__(2))); -typedef double swift_double3 __attribute__((__ext_vector_type__(3))); -typedef double swift_double4 __attribute__((__ext_vector_type__(4))); -typedef int swift_int2 __attribute__((__ext_vector_type__(2))); -typedef int swift_int3 __attribute__((__ext_vector_type__(3))); -typedef int swift_int4 __attribute__((__ext_vector_type__(4))); -typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); -typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); -typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); -#endif - -#if !defined(SWIFT_PASTE) -# define SWIFT_PASTE_HELPER(x, y) x##y -# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) -#endif -#if !defined(SWIFT_METATYPE) -# define SWIFT_METATYPE(X) Class -#endif -#if !defined(SWIFT_CLASS_PROPERTY) -# if __has_feature(objc_class_property) -# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ -# else -# define SWIFT_CLASS_PROPERTY(...) -# endif -#endif - -#if __has_attribute(objc_runtime_name) -# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) -#else -# define SWIFT_RUNTIME_NAME(X) -#endif -#if __has_attribute(swift_name) -# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) -#else -# define SWIFT_COMPILE_NAME(X) -#endif -#if __has_attribute(objc_method_family) -# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) -#else -# define SWIFT_METHOD_FAMILY(X) -#endif -#if __has_attribute(noescape) -# define SWIFT_NOESCAPE __attribute__((noescape)) -#else -# define SWIFT_NOESCAPE -#endif -#if __has_attribute(ns_consumed) -# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) -#else -# define SWIFT_RELEASES_ARGUMENT -#endif -#if __has_attribute(warn_unused_result) -# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -#else -# define SWIFT_WARN_UNUSED_RESULT -#endif -#if __has_attribute(noreturn) -# define SWIFT_NORETURN __attribute__((noreturn)) -#else -# define SWIFT_NORETURN -#endif -#if !defined(SWIFT_CLASS_EXTRA) -# define SWIFT_CLASS_EXTRA -#endif -#if !defined(SWIFT_PROTOCOL_EXTRA) -# define SWIFT_PROTOCOL_EXTRA -#endif -#if !defined(SWIFT_ENUM_EXTRA) -# define SWIFT_ENUM_EXTRA -#endif -#if !defined(SWIFT_CLASS) -# if __has_attribute(objc_subclassing_restricted) -# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA -# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# else -# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA -# endif -#endif -#if !defined(SWIFT_RESILIENT_CLASS) -# if __has_attribute(objc_class_stub) -# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) -# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) -# else -# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) -# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) -# endif -#endif - -#if !defined(SWIFT_PROTOCOL) -# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA -# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA -#endif - -#if !defined(SWIFT_EXTENSION) -# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) -#endif - -#if !defined(OBJC_DESIGNATED_INITIALIZER) -# if __has_attribute(objc_designated_initializer) -# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) -# else -# define OBJC_DESIGNATED_INITIALIZER -# endif -#endif -#if !defined(SWIFT_ENUM_ATTR) -# if defined(__has_attribute) && __has_attribute(enum_extensibility) -# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) -# else -# define SWIFT_ENUM_ATTR(_extensibility) -# endif -#endif -#if !defined(SWIFT_ENUM) -# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type -# if __has_feature(generalized_swift_name) -# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type -# else -# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) -# endif -#endif -#if !defined(SWIFT_UNAVAILABLE) -# define SWIFT_UNAVAILABLE __attribute__((unavailable)) -#endif -#if !defined(SWIFT_UNAVAILABLE_MSG) -# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) -#endif -#if !defined(SWIFT_AVAILABILITY) -# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) -#endif -#if !defined(SWIFT_WEAK_IMPORT) -# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) -#endif -#if !defined(SWIFT_DEPRECATED) -# define SWIFT_DEPRECATED __attribute__((deprecated)) -#endif -#if !defined(SWIFT_DEPRECATED_MSG) -# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) -#endif -#if __has_feature(attribute_diagnose_if_objc) -# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) -#else -# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) -#endif -#if !defined(IBSegueAction) -# define IBSegueAction -#endif -#if __has_feature(modules) -#if __has_warning("-Watimport-in-framework-header") -#pragma clang diagnostic ignored "-Watimport-in-framework-header" -#endif -#endif - -#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" -#pragma clang diagnostic ignored "-Wduplicate-method-arg" -#if __has_warning("-Wpragma-clang-attribute") -# pragma clang diagnostic ignored "-Wpragma-clang-attribute" -#endif -#pragma clang diagnostic ignored "-Wunknown-pragmas" -#pragma clang diagnostic ignored "-Wnullability" - -#if __has_attribute(external_source_symbol) -# pragma push_macro("any") -# undef any -# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="RawGlucose",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) -# pragma pop_macro("any") -#endif - -#if __has_attribute(external_source_symbol) -# pragma clang attribute pop -#endif -#pragma clang diagnostic pop -#endif - -#endif diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Headers/RawGlucose.h b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Headers/RawGlucose.h deleted file mode 100644 index 0bb475c6f..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Headers/RawGlucose.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// RawGlucose.h -// RawGlucose -// -// Created by Ivan Valkou on 29.10.2021. -// - -#import - -//! Project version number for RawGlucose. -FOUNDATION_EXPORT double RawGlucoseVersionNumber; - -//! Project version string for RawGlucose. -FOUNDATION_EXPORT const unsigned char RawGlucoseVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Info.plist b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Info.plist deleted file mode 100644 index 0f9dc3480..000000000 Binary files a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Info.plist and /dev/null differ diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64-apple-ios-simulator.swiftdoc b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64-apple-ios-simulator.swiftdoc deleted file mode 100644 index d2b2a6a11..000000000 Binary files a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64-apple-ios-simulator.swiftdoc and /dev/null differ diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64-apple-ios-simulator.swiftinterface b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64-apple-ios-simulator.swiftinterface deleted file mode 100644 index 74af49bcd..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64-apple-ios-simulator.swiftinterface +++ /dev/null @@ -1,8 +0,0 @@ -// swift-interface-format-version: 1.0 -// swift-compiler-version: Apple Swift version 5.5.1 (swiftlang-1300.0.31.4 clang-1300.0.29.6) -// swift-module-flags: -target arm64-apple-ios14.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name RawGlucose -import Foundation -@_exported import RawGlucose -import Swift -import _Concurrency -public func glucoseValueFromRaw(rawTemperature: Swift.Double, rawTemperatureAdjustment: Swift.Double, rawGlucose: Swift.Double, i1: Swift.Int, i2: Swift.Int, i3: Swift.Double, i4: Swift.Double, i5: Swift.Double, i6: Swift.Double) -> Swift.Double diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64.swiftdoc b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64.swiftdoc deleted file mode 100644 index d2b2a6a11..000000000 Binary files a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64.swiftdoc and /dev/null differ diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64.swiftinterface b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64.swiftinterface deleted file mode 100644 index 74af49bcd..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/arm64.swiftinterface +++ /dev/null @@ -1,8 +0,0 @@ -// swift-interface-format-version: 1.0 -// swift-compiler-version: Apple Swift version 5.5.1 (swiftlang-1300.0.31.4 clang-1300.0.29.6) -// swift-module-flags: -target arm64-apple-ios14.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name RawGlucose -import Foundation -@_exported import RawGlucose -import Swift -import _Concurrency -public func glucoseValueFromRaw(rawTemperature: Swift.Double, rawTemperatureAdjustment: Swift.Double, rawGlucose: Swift.Double, i1: Swift.Int, i2: Swift.Int, i3: Swift.Double, i4: Swift.Double, i5: Swift.Double, i6: Swift.Double) -> Swift.Double diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/x86_64-apple-ios-simulator.swiftdoc b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/x86_64-apple-ios-simulator.swiftdoc deleted file mode 100644 index d961e46ed..000000000 Binary files a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/x86_64-apple-ios-simulator.swiftdoc and /dev/null differ diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/x86_64-apple-ios-simulator.swiftinterface b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/x86_64-apple-ios-simulator.swiftinterface deleted file mode 100644 index d8e268371..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +++ /dev/null @@ -1,8 +0,0 @@ -// swift-interface-format-version: 1.0 -// swift-compiler-version: Apple Swift version 5.5.1 (swiftlang-1300.0.31.4 clang-1300.0.29.6) -// swift-module-flags: -target x86_64-apple-ios14.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name RawGlucose -import Foundation -@_exported import RawGlucose -import Swift -import _Concurrency -public func glucoseValueFromRaw(rawTemperature: Swift.Double, rawTemperatureAdjustment: Swift.Double, rawGlucose: Swift.Double, i1: Swift.Int, i2: Swift.Int, i3: Swift.Double, i4: Swift.Double, i5: Swift.Double, i6: Swift.Double) -> Swift.Double diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/x86_64.swiftdoc b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/x86_64.swiftdoc deleted file mode 100644 index d961e46ed..000000000 Binary files a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/x86_64.swiftdoc and /dev/null differ diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/x86_64.swiftinterface b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/x86_64.swiftinterface deleted file mode 100644 index d8e268371..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/RawGlucose.swiftmodule/x86_64.swiftinterface +++ /dev/null @@ -1,8 +0,0 @@ -// swift-interface-format-version: 1.0 -// swift-compiler-version: Apple Swift version 5.5.1 (swiftlang-1300.0.31.4 clang-1300.0.29.6) -// swift-module-flags: -target x86_64-apple-ios14.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name RawGlucose -import Foundation -@_exported import RawGlucose -import Swift -import _Concurrency -public func glucoseValueFromRaw(rawTemperature: Swift.Double, rawTemperatureAdjustment: Swift.Double, rawGlucose: Swift.Double, i1: Swift.Int, i2: Swift.Int, i3: Swift.Double, i4: Swift.Double, i5: Swift.Double, i6: Swift.Double) -> Swift.Double diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/module.modulemap b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/module.modulemap deleted file mode 100644 index 73e07f3aa..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/Modules/module.modulemap +++ /dev/null @@ -1,11 +0,0 @@ -framework module RawGlucose { - umbrella header "RawGlucose.h" - - export * - module * { export * } -} - -module RawGlucose.Swift { - header "RawGlucose-Swift.h" - requires objc -} diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/RawGlucose b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/RawGlucose deleted file mode 100755 index c821e55cc..000000000 Binary files a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/RawGlucose and /dev/null differ diff --git a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/_CodeSignature/CodeResources b/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/_CodeSignature/CodeResources deleted file mode 100644 index c6fa7659c..000000000 --- a/Dependencies/LibreTransmitter/RawGlucose.xcframework/ios-arm64_x86_64-simulator/RawGlucose.framework/_CodeSignature/CodeResources +++ /dev/null @@ -1,267 +0,0 @@ - - - - - files - - Headers/RawGlucose-Swift.h - - NOPVTsnUQdvUXiVvlGkcrHBsYf8= - - Headers/RawGlucose.h - - e5N6Xw/Q6Ssus1Sfka2OdAgEwfs= - - Info.plist - - C822WpDoMUZHHWfCJ8tfMtklvCc= - - Modules/RawGlucose.swiftmodule/arm64-apple-ios-simulator.swiftdoc - - XVOH12u7W5mUldmztR8JA2sGUBE= - - Modules/RawGlucose.swiftmodule/arm64-apple-ios-simulator.swiftinterface - - 3G/qIi+knDm6DNBZMdut0+I0F8U= - - Modules/RawGlucose.swiftmodule/arm64-apple-ios-simulator.swiftmodule - - 8XbBt5zfUNlmyrYv31HsRH5I7Pc= - - Modules/RawGlucose.swiftmodule/arm64.swiftdoc - - XVOH12u7W5mUldmztR8JA2sGUBE= - - Modules/RawGlucose.swiftmodule/arm64.swiftinterface - - 3G/qIi+knDm6DNBZMdut0+I0F8U= - - Modules/RawGlucose.swiftmodule/arm64.swiftmodule - - 8XbBt5zfUNlmyrYv31HsRH5I7Pc= - - Modules/RawGlucose.swiftmodule/x86_64-apple-ios-simulator.swiftdoc - - YTLCQrGaBLjG2V3HCaucJ1Affak= - - Modules/RawGlucose.swiftmodule/x86_64-apple-ios-simulator.swiftinterface - - 8+AhO+0B1RfBn7TTtbJhId3or3k= - - Modules/RawGlucose.swiftmodule/x86_64-apple-ios-simulator.swiftmodule - - fBhjoSFy5wsrXWVEqv2bue3Tdho= - - Modules/RawGlucose.swiftmodule/x86_64.swiftdoc - - YTLCQrGaBLjG2V3HCaucJ1Affak= - - Modules/RawGlucose.swiftmodule/x86_64.swiftinterface - - 8+AhO+0B1RfBn7TTtbJhId3or3k= - - Modules/RawGlucose.swiftmodule/x86_64.swiftmodule - - fBhjoSFy5wsrXWVEqv2bue3Tdho= - - Modules/module.modulemap - - Nbavz/+JmGFVpOq9rrggRbhjo/Y= - - - files2 - - Headers/RawGlucose-Swift.h - - hash2 - - 05/Gxrpmj85ok9eADvswbwYSHS2GDU+dONqnxWX0YKc= - - - Headers/RawGlucose.h - - hash2 - - vWp1R9C9/5EBlkAhcUZ6DglPTPIL7LdzMYFDrxPPp2w= - - - Modules/RawGlucose.swiftmodule/arm64-apple-ios-simulator.swiftdoc - - hash2 - - R0b1kXmBK9IQpw2/AgSdiCUB3tyXVOLVYFhrcMiJTdc= - - - Modules/RawGlucose.swiftmodule/arm64-apple-ios-simulator.swiftinterface - - hash2 - - JIy4JCrP2htiXMPFm2mtQWks0BAt8xJ4N8zKSbVi4WU= - - - Modules/RawGlucose.swiftmodule/arm64-apple-ios-simulator.swiftmodule - - hash2 - - WvvLbXOvP/MljSINhZaIT3RXsDVf/dFvySSwZ2qgElg= - - - Modules/RawGlucose.swiftmodule/arm64.swiftdoc - - hash2 - - R0b1kXmBK9IQpw2/AgSdiCUB3tyXVOLVYFhrcMiJTdc= - - - Modules/RawGlucose.swiftmodule/arm64.swiftinterface - - hash2 - - JIy4JCrP2htiXMPFm2mtQWks0BAt8xJ4N8zKSbVi4WU= - - - Modules/RawGlucose.swiftmodule/arm64.swiftmodule - - hash2 - - WvvLbXOvP/MljSINhZaIT3RXsDVf/dFvySSwZ2qgElg= - - - Modules/RawGlucose.swiftmodule/x86_64-apple-ios-simulator.swiftdoc - - hash2 - - nLt/uTqHb2O8ehdLv6Pykcy9VYdbwfpAEJ7j8At6ruU= - - - Modules/RawGlucose.swiftmodule/x86_64-apple-ios-simulator.swiftinterface - - hash2 - - odDK6zWxPbRZLxn8UV8Pb3KyYW50utHNICmLKU3+B3I= - - - Modules/RawGlucose.swiftmodule/x86_64-apple-ios-simulator.swiftmodule - - hash2 - - QEolRuoZA6Gqn9VoRQId+9TRRhZAgZwIQgjHYACF9wk= - - - Modules/RawGlucose.swiftmodule/x86_64.swiftdoc - - hash2 - - nLt/uTqHb2O8ehdLv6Pykcy9VYdbwfpAEJ7j8At6ruU= - - - Modules/RawGlucose.swiftmodule/x86_64.swiftinterface - - hash2 - - odDK6zWxPbRZLxn8UV8Pb3KyYW50utHNICmLKU3+B3I= - - - Modules/RawGlucose.swiftmodule/x86_64.swiftmodule - - hash2 - - QEolRuoZA6Gqn9VoRQId+9TRRhZAgZwIQgjHYACF9wk= - - - Modules/module.modulemap - - hash2 - - HGSrZF6T2tksU5dqClpOIcyQITvyjJOLdm6TEvIdU7M= - - - - rules - - ^.* - - ^.*\.lproj/ - - optional - - weight - 1000 - - ^.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^Base\.lproj/ - - weight - 1010 - - ^version.plist$ - - - rules2 - - .*\.dSYM($|/) - - weight - 11 - - ^(.*/)?\.DS_Store$ - - omit - - weight - 2000 - - ^.* - - ^.*\.lproj/ - - optional - - weight - 1000 - - ^.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^Base\.lproj/ - - weight - 1010 - - ^Info\.plist$ - - omit - - weight - 20 - - ^PkgInfo$ - - omit - - weight - 20 - - ^embedded\.provisionprofile$ - - weight - 20 - - ^version\.plist$ - - weight - 20 - - - - diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/BluetoothSearch.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/BluetoothSearch.swift deleted file mode 100644 index b9b920b9a..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/BluetoothSearch.swift +++ /dev/null @@ -1,258 +0,0 @@ -// -// BluetoothSearch.swift -// MiaomiaoClientUI -// -// Created by Bjørn Inge Berg on 26/07/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import CoreBluetooth -import Foundation -import OSLog -import UIKit -import Combine - -struct RSSIInfo { - let bledeviceID: String - let signalStrength: Int - - var totalBars : Int { - 3 - } - - var signalBars : Int { - if signalStrength < -80 { - return 1 //near - } - - if signalStrength > -50 { - return 3 //immediate - } - - return 2 //near - } - - - -} - -public final class BluetoothSearchManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate { - - var centralManager: CBCentralManager! - - fileprivate lazy var logger = Logger(forType: Self.self) - - //fileprivate let deviceNames = SupportedDevices.allNames - //fileprivate let serviceUUIDs:[CBUUID]? = [CBUUID(string: "6E400001-B5A3-F393-E0A9-E50E24DCCA9E")] - - private var discoveredDevices = [CBPeripheral]() - - public let passThrough = PassthroughSubject() - public let passThroughMetaData = PassthroughSubject<(CBPeripheral, [String: Any]), Never>() - let throttledRSSI = GenericThrottler(identificator: \RSSIInfo.bledeviceID, interval: 5) - - - private var rescanTimerBag = Set() - - public func addDiscoveredDevice(_ device: CBPeripheral, with metadata: [String: Any], rssi: Int) { - passThrough.send(device) - passThroughMetaData.send((device, metadata)) - throttledRSSI.incoming.send(RSSIInfo(bledeviceID: device.identifier.uuidString, signalStrength: rssi)) - } - - public override init() { - super.init() - // calling readrssi on a peripheral is only supported on connected peripherals - // here we want the AllowDuplicatesKey to be true so that we get a continous feed of new rssi values for - // discovered but unconnected peripherals - // This should work, but in practice, most devices will still only be discovered once, meaning that we cannot update rssi values - // without either a new scan, or connecting to the peripheral and using .readrssi() - //centralManager = CBCentralManager(delegate: self, queue: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey : true]) - centralManager = CBCentralManager(delegate: self, queue: nil, options: nil) - // slipBuffer.delegate = self - logger.debug("BluetoothSearchManager init called ") - - // Ugly hack to be able to update rssi continously without connecting to peripheral - // Yes, this consumes extra power, but this feature is very convenient when needed, but very rarely used (only during setup) - //startTimer() - } - - public func startTimer(){ - stopTimer() - - Timer.publish(every: 10, on: .main, in: .default) - .autoconnect() - .sink( - receiveValue: { [weak self ] _ in - self?.rescan() - } - ) - .store(in: &rescanTimerBag) - } - - public func stopTimer() { - if !rescanTimerBag.isEmpty { - rescanTimerBag.forEach { cancel in - cancel.cancel() - } - } - } - - func rescan() { - if centralManager.isScanning { - centralManager.stopScan() - } - logger.debug("Rescanning") - - self.scanForCompatibleDevices() - } - - func scanForCompatibleDevices() { - - - - if centralManager.state == .poweredOn && !centralManager.isScanning { - logger.debug("Before scan for transmitter while central manager state \(String(describing: self.centralManager.state.rawValue))") - - let allServices : [CBUUID] = LibreTransmitters.all.compactMap { atype in - atype.serviceUUID.first?.value - } - - - logger.debug("Will scan for the following services: \(String(describing: allServices))") - - - // nil because miamiao1 not advertising it's services - centralManager.scanForPeripherals(withServices: nil, options:nil) - - - // Ugly hack to be able to update rssi continously without connecting to peripheral - // Yes, this consumes extra power, but this feature is very convenient when needed, but very rarely used (only during setup) - startTimer() - } - } - - func disconnectManually() { - logger.debug("did disconnect manually") - // NotificationManager.scheduleDebugNotification(message: "Timer fired in Background", wait: 3) - // _ = Timer(timeInterval: 150, repeats: false, block: {timer in NotificationManager.scheduleDebugNotification(message: "Timer fired in Background", wait: 0.5)}) - - if centralManager.isScanning { - centralManager.stopScan() - } - } - - - - // MARK: - CBCentralManagerDelegate - - public func centralManagerDidUpdateState(_ central: CBCentralManager) { - logger.debug("Central Manager did update state to \(String(describing: central.state.rawValue))") - switch central.state { - case .poweredOff, .resetting, .unauthorized, .unknown, .unsupported: - logger.debug("Central Manager was either .poweredOff, .resetting, .unauthorized, .unknown, .unsupported: \(String(describing: central.state))") - case .poweredOn: - //we don't want this to start scanning right away, but rather wait until the view has appeared - // this means that the view is responsible for calling scanForCompatibleDevices it self - //scanForCompatibleDevices() // power was switched on, while app is running -> reconnect. - break - - @unknown default: - fatalError("libre bluetooth state unhandled") - } - } - - public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) { - guard let name = peripheral.name?.lowercased() else { - logger.debug("dabear:: could not find name for device \(peripheral.identifier.uuidString)") - return - } - - if LibreTransmitters.isSupported(peripheral) { - logger.debug("dabear:: did recognize device: \(name): \(peripheral.identifier)") - self.addDiscoveredDevice(peripheral, with: advertisementData, rssi: RSSI.intValue) - //peripheral.delegate = self - //peripheral.readRSSI() - } else { - logger.debug("dabear:: did not add unknown device: \(name): \(peripheral.identifier)") - } - } - - public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { - //self.lastConnectedIdentifier = peripheral.identifier.uuidString - - } - - public func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { - logger.error("did fail to connect") - } - - public func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { - logger.debug("did didDisconnectPeripheral") - } - - // MARK: - CBPeripheralDelegate - - public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { - logger.debug("Did discover services") - if let error = error { - logger.error("Did discover services error: \(error.localizedDescription)") - } - - if let services = peripheral.services { - for service in services { - peripheral.discoverCharacteristics(nil, for: service) - - logger.debug("Did discover service: \(String(describing: service.debugDescription))") - } - } - } - - public func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { - logger.debug("Did discover characteristics for service \(String(describing: peripheral.name))") - - if let error = error { - logger.error("Did discover characteristics for service error: \(error.localizedDescription)") - } - - if let characteristics = service.characteristics { - for characteristic in characteristics { - logger.debug("Did discover characteristic: \(String(describing: characteristic.debugDescription))") - - if (characteristic.properties.intersection(.notify)) == .notify && characteristic.uuid == CBUUID(string: "6E400003-B5A3-F393-E0A9-E50E24DCCA9E") { - peripheral.setNotifyValue(true, for: characteristic) - logger.debug("Set notify value for this characteristic") - } - if characteristic.uuid == CBUUID(string: "6E400002-B5A3-F393-E0A9-E50E24DCCA9E") { - //writeCharacteristic = characteristic - } - } - } else { - logger.error("Discovered characteristics, but no characteristics listed. There must be some error.") - } - } - - - public func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) { - - //throttledRSSI.incoming.send(RSSIInfo(bledeviceID: peripheral.identifier.uuidString, signalStrength: RSSI.intValue)) - - //peripheral.readRSSI() //we keep contuing to update the rssi (only works if peripheral is already connected.... - - } - public func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { - logger.debug("Did update notification state for characteristic: \(String(describing: characteristic.debugDescription))") - } - - public func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { - logger.debug("Did update value for characteristic: \(String(describing: characteristic.debugDescription))") - } - - public func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { - logger.debug("Did Write value \(String(characteristic.value.debugDescription)) for characteristic \(String(characteristic.debugDescription))") - } - - deinit { - logger.debug("dabear:: BluetoothSearchManager deinit called") - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/CBPeripheralExtensions.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/CBPeripheralExtensions.swift deleted file mode 100644 index 220f9e337..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/CBPeripheralExtensions.swift +++ /dev/null @@ -1,84 +0,0 @@ -// -// CBPeripheralExtensions.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 19/10/2020. -// Copyright © 2020 Bjørn Inge Vikhammermo Berg. All rights reserved. -// - -import CoreBluetooth -import Foundation - -public protocol PeripheralProtocol { - var name: String? { get } - var name2: String { get } - - var asStringIdentifier: String { get } -} - -public enum Either { - case Left(A) - case Right(B) -} - -public typealias SomePeripheral = Either - -extension SomePeripheral: PeripheralProtocol, Identifiable, Hashable, Equatable { - public static func == (lhs: Either, rhs: Either) -> Bool { - lhs.asStringIdentifier == rhs.asStringIdentifier - } - - public var id: String { - actualPeripheral.asStringIdentifier - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(actualPeripheral.asStringIdentifier) - } - - private var actualPeripheral: PeripheralProtocol { - switch self { - case let .Left(real): - return real - case let .Right(mocked): - return mocked - } - } - public var name: String? { - actualPeripheral.name - } - - public var name2: String { - actualPeripheral.name2 - } - - public var asStringIdentifier: String { - actualPeripheral.asStringIdentifier - } -} - -extension CBPeripheral: PeripheralProtocol, Identifiable { - public var name2: String { - self.name ?? "" - } - - public var asStringIdentifier: String { - self.identifier.uuidString - } -} - -public class MockedPeripheral: PeripheralProtocol, Identifiable { - public var name: String? - - public var name2: String { - name ?? "unknown-device" - } - - public var asStringIdentifier: String { - name2 - } - - public init(name: String) { - self.name = name - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/GenericThrottler.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/GenericThrottler.swift deleted file mode 100644 index fe112aba2..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/GenericThrottler.swift +++ /dev/null @@ -1,111 +0,0 @@ -// -// GenericThrottler.swift -// LibreTransmitter -// -// Created by Bjørn Inge Berg on 16/08/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import Foundation -import Combine - -class GenericThrottler{ - - public var throttledPublisher : AnyPublisher { - throttledSubject.eraseToAnyPublisher() - } - //this is the where the bluetoothsearch should send its updates - public let incoming = PassthroughSubject() - - //this is what swiftui would connect to - private let throttledSubject = PassthroughSubject() - private var initiallyPublished = Set() - - private var bag = Set() - private var timerBag = Set() - - - private var newValues : [U: T] = [:] - - private var identificator : KeyPath - - private var interval: TimeInterval - - public func startTimer(){ - stopTimer() - - Timer.publish(every: interval, on: .main, in: .default) - .autoconnect() - .sink( - receiveValue: { [weak self ] _ in - //every 10 seconds, send the latest element as uniquely identified by bledeviceid - // we reset the newvalues so that we wont resend the same identifical element after 10 additional seconds - self?.newValues.forEach { el in - self?.throttledSubject.send(el.value) - } - self?.newValues = [:] - } - ) - .store(in: &timerBag) - } - - public func stopTimer() { - if !timerBag.isEmpty { - timerBag.forEach { cancel in - cancel.cancel() - } - } - } - - private func setupDebugListener() { - throttledSubject - .sink { el in - let now = Date().description - print("\(now) \t throttledPublisher got new value: \(el) ") - } - .store(in: &bag) - } - - private func setupIncoming() { - incoming - .sink { [weak self] el in - guard let self = self else { - return - } - - let id = el.self[keyPath: self.identificator] - - - let neverPublished = !self.initiallyPublished.contains(id) - if neverPublished { - self.initiallyPublished.insert(id) - //every element should be published initially - self.throttledSubject.send(el) - return - } - - self.newValues[id] = el - - } - .store(in: &bag) - } - - init(identificator : KeyPath, interval: TimeInterval) { - self.identificator = identificator - self.interval = interval - - startTimer() - setupIncoming() - - - //this cancellable would normally not be used directly, as you would consume the publisher from swiftui - //setupDebugListener() - - } - - deinit { - print("deiniting GenericThrottler") - } - - -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/LibreTransmitterMetadata.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/LibreTransmitterMetadata.swift deleted file mode 100644 index b714c6544..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/LibreTransmitterMetadata.swift +++ /dev/null @@ -1,119 +0,0 @@ -// -// MiaoMiao.swift -// LibreMonitor -// -// Created by Uwe Petersen on 02.11.18. -// Copyright © 2018 Uwe Petersen. All rights reserved. -// - -import Foundation - -public struct LibreTransmitterMetadata: CustomStringConvertible { - // hardware number - public let hardware: String - // software number - public let firmware: String - // battery level, percentage between 0 % and 100 % - public let battery: Int? - // battery level String - public let batteryString: String - - public let macAddress: String? - - public let name: String - - public let patchInfo: String? - public let uid: [UInt8]? - - init(hardware: String, firmware: String, battery: Int?, name: String, macAddress: String?, patchInfo: String?, uid: [UInt8]?) { - self.hardware = hardware - self.firmware = firmware - self.battery = battery - let batteryString = battery == nil ? "-" : "\(battery!)" - self.batteryString = batteryString - self.macAddress = macAddress - self.name = name - self.patchInfo = patchInfo - self.uid = uid - } - - public var description: String { - "Transmitter: \(name), Hardware: \(hardware), firmware: \(firmware)" + - "battery: \(batteryString), macAddress: \(String(describing: macAddress)), patchInfo: \(String(describing: patchInfo)), uid: \(String(describing: uid))" - } - - public func sensorType() -> SensorType? { - guard let patchInfo = patchInfo else { return nil } - return SensorType(patchInfo: patchInfo) - } -} - -extension String { - //https://stackoverflow.com/questions/39677330/how-does-string-substring-work-in-swift - //usage - //let s = "hello" - //s[0..<3] // "hel" - //s[3..) -> String { - let idx1 = index(startIndex, offsetBy: max(0, range.lowerBound)) - let idx2 = index(startIndex, offsetBy: min(self.count, range.upperBound)) - return String(self[idx1.. Data? { - var data = Data(capacity: count / 2) - - let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive) - regex.enumerateMatches(in: self, range: NSRange(startIndex..., in: self)) { match, _, _ in - let byteString = (self as NSString).substring(with: match!.range) - let num = UInt8(byteString, radix: 16)! - data.append(num) - } - - guard data.count > 0 else { return nil } - - return data - } -} - -public enum SensorType: String, CustomStringConvertible { - case libre1 = "DF" - case libre1A2 = "A2" - case libre2 = "9D" - case libre2C5 = "C5" - case libreUS14day = "E5" - case libreUS14dayE6 = "E6" - case libreProH = "70" - - public var description: String { - switch self { - case .libre1: - return "Libre 1" - case .libre1A2: - return "Libre 1 A2" - case .libre2, .libre2C5: - return "Libre 2" - case .libreUS14day, .libreUS14dayE6: - return "Libre US" - case .libreProH: - return "Libre PRO H" - } - } -} - -public extension SensorType { - init?(patchInfo: String) { - guard patchInfo.count > 1 else { return nil } - - let start = patchInfo[0..<2].uppercased() - - let choices: [String: SensorType] = ["DF": .libre1, "A2": .libre1A2, "9D": .libre2, "C5": .libre2, "E5": .libreUS14day, "E6": .libreUS14dayE6, "70": .libreProH] - - if let res = choices[start] { - self = res - return - } - - return nil - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/BubbleTransmitter.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/BubbleTransmitter.swift deleted file mode 100644 index 986d4687c..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/BubbleTransmitter.swift +++ /dev/null @@ -1,207 +0,0 @@ -// -// BubbleTransmitter.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 08/01/2020. -// Copyright © 2020 Bjørn Inge Berg. All rights reserved. -// - -import CoreBluetooth -import Foundation -import UIKit -import os.log - -public enum BubbleResponseType: UInt8 { - case dataPacket = 130 - case bubbleInfo = 128 // = wakeUp + device info - case noSensor = 191 - case serialNumber = 192 - case patchInfo = 193 //0xC1 - /// bubble firmware 2.6 support decrypt libre2 344 to libre1 344 - /// if firmware >= 2.6, write [0x08, 0x01, 0x00, 0x00, 0x00, 0x2B] - /// bubble will decrypt the libre2 data and return it - //we don't really support decrypteddatapacket as we like to decrypt our selves! - //case decryptedDataPacket = 136 // 0x88 -} - -extension BubbleResponseType { - var description: String { - switch self { - case .bubbleInfo: - return "bubbleinfo" - case .dataPacket: - return "datapacket" - case .noSensor: - return "nosensor" - case .serialNumber: - return "serialnumber" - case .patchInfo: - return "patchInfo" - } - } -} - -// The Bubble uses the same serviceUUID, -// writeCharachteristic and notifyCharachteristic -// as the MiaoMiao, but different byte sequences -class BubbleTransmitter: MiaoMiaoTransmitter { - override class var shortTransmitterName: String { - "bubble" - } - override class var manufacturerer: String { - "bubbledevteam" - } - - override class var smallImage: UIImage? { - UIImage(named: "bubble", in: Bundle.module, compatibleWith: nil) - } - - override static func canSupportPeripheral(_ peripheral: CBPeripheral) -> Bool { - peripheral.name?.lowercased().starts(with: "bubble") ?? false - } - - override func reset() { - rxBuffer.resetAllBytes() - } - - override class var requiresDelayedReconnect : Bool { - true - } - - private var hardware: String? = "" - private var firmware: String? = "" - private var mac: String? = "" - - private var patchInfo: String? - private var uid: [UInt8]? - - private var battery: Int? - - fileprivate lazy var bLogger = Logger(forType: Self.self) - - override class func getDeviceDetailsFromAdvertisement(advertisementData: [String: Any]?) -> String? { - let (amac, afirmware, ahardware) = Self.getDeviceDetailsFromAdvertisementInternal(advertisementData: advertisementData) - - if let amac = amac, let ahardware = ahardware, let afirmware = afirmware { - return "\(amac)\n HW:\(ahardware), FW: \(afirmware)" - } - - return nil - } - - private static func getDeviceDetailsFromAdvertisementInternal(advertisementData: [String: Any]?) -> (String?, String?, String?) { - - - - guard let data = advertisementData?["kCBAdvDataManufacturerData"] as? Data else { - return (nil, nil, nil) - } - var mac = "" - for i in 0 ..< 6 { - mac += data.subdata(in: (7 - i)..<(8 - i)).hexEncodedString().uppercased() - if i != 5 { - mac += ":" - } - } - - guard data.count >= 12 else { - return (nil, nil, nil) - } - - let fSub1 = Data(repeating: data[8], count: 1) - let fSub2 = Data(repeating: data[9], count: 1) - let firmware = Float("\(fSub1.hexEncodedString()).\(fSub2.hexEncodedString())")?.description - - let hSub1 = Data(repeating: data[10], count: 1) - let hSub2 = Data(repeating: data[11], count: 1) - - let hardware = Float("\(hSub1.hexEncodedString()).\(hSub2.hexEncodedString())")?.description - return (mac, firmware, hardware) - } - - required init(delegate: LibreTransmitterDelegate, advertisementData: [String: Any]?) { - //advertisementData is unknown for the miaomiao - - super.init(delegate: delegate, advertisementData: advertisementData) - //self.delegate = delegate - //deviceFromAdvertisementData(advertisementData: advertisementData) - (self.mac, self.firmware, self.hardware) = Self.getDeviceDetailsFromAdvertisementInternal(advertisementData: advertisementData) - } - - override func requestData(writeCharacteristics: CBCharacteristic, peripheral: CBPeripheral) { - bLogger.debug("dabear:: bubbleRequestData") - reset() - - peripheral.writeValue(Data([0x00, 0x00, 0x05]), for: writeCharacteristics, type: .withResponse) - } - override func updateValueForNotifyCharacteristics(_ value: Data, peripheral: CBPeripheral, writeCharacteristic: CBCharacteristic?) { - bLogger.debug("dabear:: bubbleDidUpdateValueForNotifyCharacteristics, firstbyte is: \(value.first.debugDescription)") - guard let firstByte = value.first, let bubbleResponseState = BubbleResponseType(rawValue: firstByte) else { - return - } - bLogger.debug("dabear:: bubble responsestate is of type \(bubbleResponseState.description)") - bLogger.debug("dabear:: bubble value is: \(value.toDebugString())") - switch bubbleResponseState { - case .bubbleInfo: - hardware = value[value.count-2].description + "." + value[value.count-1].description - firmware = value[2].description + "." + value[3].description - //let patchInfo = Data(Double(firmware)! < 1.35 ? value[3...8] : value[5...10]) - battery = Int(value[4]) - - bLogger.debug("dabear:: Got bubbledevice: \(self.metadata.debugDescription)") - if let writeCharacteristic = writeCharacteristic { - - peripheral.writeValue(Data([0x02, 0x00, 0x00, 0x00, 0x00, 0x2B]), for: writeCharacteristic, type: .withResponse) - } - case .dataPacket://, .decryptedDataPacket: - rxBuffer.append(value.suffix(from: 4)) - bLogger.debug("dabear:: aggregated datapacket is now of length: \(self.rxBuffer.count)") - if rxBuffer.count >= 352 { - handleCompleteMessage() - reset() - } - case .noSensor: - delegate?.libreTransmitterReceivedMessage(0x0000, txFlags: 0x34, payloadData: rxBuffer) - - reset() - case .serialNumber: - guard value.count >= 10 else { return } - reset() - self.uid = [UInt8](value.subdata(in: 2..<10)) - - //for historical reasons - rxBuffer.append(value.subdata(in: 2..<10)) - - case .patchInfo: - guard value.count >= 10 else { - bLogger.debug("not able to extract patchinfo") - return - } - patchInfo = value.subdata(in: 5 ..< 11).hexEncodedString().uppercased() - } - } - - private var rxBuffer = Data() - private var sensorData: SensorData? - private var metadata: LibreTransmitterMetadata? - - override func handleCompleteMessage() { - bLogger.debug("dabear:: bubbleHandleCompleteMessage") - - guard rxBuffer.count >= 352 else { - return - } - - metadata = .init(hardware: hardware ?? "unknown", firmware: firmware ?? "unknown", battery: battery ?? 100, name: Self.shortTransmitterName, macAddress: self.mac, patchInfo: patchInfo, uid: self.uid) - - let data = rxBuffer.subdata(in: 8..<352) - bLogger.debug("dabear:: bubbleHandleCompleteMessage raw data: \([UInt8](self.rxBuffer))") - sensorData = SensorData(uuid: rxBuffer.subdata(in: 0..<8), bytes: [UInt8](data), date: Date()) - - bLogger.debug("dabear:: bubble got sensordata \(self.sensorData.debugDescription) and metadata \(self.metadata.debugDescription), delegate is \(self.delegate.debugDescription)") - - if let sensorData = sensorData, let metadata = metadata { - delegate?.libreTransmitterDidUpdate(with: sensorData, and: metadata) - } - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/Libre2DirectTransmitter.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/Libre2DirectTransmitter.swift deleted file mode 100644 index 5ec85509f..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/Libre2DirectTransmitter.swift +++ /dev/null @@ -1,158 +0,0 @@ -// -// Libre2DirectTransmitter.swift - - -import CoreBluetooth -import Foundation -import os.log -import UIKit - - - - -class Libre2DirectTransmitter: LibreTransmitterProxyProtocol { - - - fileprivate lazy var logger = Logger(forType: Self.self) - - func reset() { - rxBuffer.resetAllBytes() - } - - class var manufacturerer: String { - "Abbott" - } - - class var smallImage: UIImage? { - UIImage(named: "libresensor", in: Bundle.module, compatibleWith: nil) - } - - class var shortTransmitterName: String { - "libre2" - } - - class var requiresDelayedReconnect : Bool { - false - } - - private let expectedBufferSize = 46 - static var requiresSetup = true - static var requiresPhoneNFC: Bool = true - - static var writeCharacteristic: UUIDContainer? = "F001"//0000f001-0000-1000-8000-00805f9b34fb" - static var notifyCharacteristic: UUIDContainer? = "F002"//"0000f002-0000-1000-8000-00805f9b34fb" - //static var serviceUUID: [UUIDContainer] = ["0000fde3-0000-1000-8000-00805f9b34fb"] - static var serviceUUID: [UUIDContainer] = ["FDE3"] - - weak var delegate: LibreTransmitterDelegate? - - private var rxBuffer = Data() - private var sensorData: SensorData? - private var metadata: LibreTransmitterMetadata? - - class func canSupportPeripheral(_ peripheral: CBPeripheral) -> Bool { - peripheral.name?.lowercased().starts(with: "abbott") ?? false - } - - class func getDeviceDetailsFromAdvertisement(advertisementData: [String: Any]?) -> String? { - nil - } - - required init(delegate: LibreTransmitterDelegate, advertisementData: [String: Any]?) { - //advertisementData is unknown for the miaomiao - self.delegate = delegate - } - - func requestData(writeCharacteristics: CBCharacteristic, peripheral: CBPeripheral) { - //because of timing issues, we cannot use this method on libre2 eu sensors - } - - func updateValueForNotifyCharacteristics(_ value: Data, peripheral: CBPeripheral, writeCharacteristic: CBCharacteristic?) { - rxBuffer.append(value) - - logger.debug("libre2 direct Appended value with length \(String(describing: value.count)), buffer length is: \(String(describing: self.rxBuffer.count))") - - - if rxBuffer.count == expectedBufferSize { - handleCompleteMessage() - } - - - } - - - - func didDiscoverWriteCharacteristics(_ peripheral: CBPeripheral, writeCharacteristics: CBCharacteristic) { - - guard let unlock = unlock() else{ - logger.debug("Cannot unlock sensor, aborting") - return - } - - logger.debug("Writing streaming unlock code to peripheral: \(unlock.hexEncodedString())") - peripheral.writeValue(unlock, for: writeCharacteristics, type: .withResponse) - - - } - - - - func didDiscoverNotificationCharacteristic(_ peripheral: CBPeripheral, notifyCharacteristic: CBCharacteristic) { - - logger.debug("libre2: saving notifyCharacteristic") - //peripheral.setNotifyValue(true, for: notifyCharacteristic) - logger.debug("libre2 setting notify while discovering : \(String(describing: notifyCharacteristic.debugDescription))") - peripheral.setNotifyValue(true, for: notifyCharacteristic) - } - - - private func unlock() -> Data? { - - guard var sensor = UserDefaults.standard.preSelectedSensor else { - logger.debug("impossible to unlock sensor") - return nil - } - - sensor.unlockCount = sensor.unlockCount + 1 - - UserDefaults.standard.preSelectedSensor = sensor - - let unlockPayload = Libre2.streamingUnlockPayload(sensorUID: sensor.uuid, info: sensor.patchInfo, enableTime: 42, unlockCount: UInt16(sensor.unlockCount)) - return Data(unlockPayload) - - } - - func handleCompleteMessage() { - guard rxBuffer.count >= expectedBufferSize else { - logger.debug("libre2 handle complete message with incorrect buffersize") - reset() - return - } - - guard let sensor = UserDefaults.standard.preSelectedSensor else { - logger.debug("libre2 handle complete message without sensorinfo present") - reset() - return - } - - - do { - let decryptedBLE = Data(try Libre2.decryptBLE(id: [UInt8](sensor.uuid), data: [UInt8](rxBuffer))) - let sensorUpdate = Libre2.parseBLEData(decryptedBLE) - - metadata = LibreTransmitterMetadata(hardware: "-", firmware: "-", battery: 100, name: Self.shortTransmitterName, macAddress: nil, patchInfo: sensor.patchInfo.hexEncodedString().uppercased(), uid: [UInt8](sensor.uuid)) - - delegate?.libreSensorDidUpdate(with: sensorUpdate, and: metadata!) - - print("libre2 got sensorupdate: \(String(describing: sensorUpdate))") - - } catch { - - } - - reset() - - } - - -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/LibreTransmitterProxyManager.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/LibreTransmitterProxyManager.swift deleted file mode 100644 index 26dcf5480..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/LibreTransmitterProxyManager.swift +++ /dev/null @@ -1,729 +0,0 @@ -// -// MiaoMiaoManager.swift -// LibreMonitor -// -// Created by Uwe Petersen on 10.03.18, heravily modified by Bjørn Berg. -// Copyright © 2018 Uwe Petersen. All rights reserved. -// - -import CoreBluetooth -import Foundation -import HealthKit -import os.log -import UIKit - -public enum BluetoothmanagerState: String { - case Unassigned = "Unassigned" - case Scanning = "Scanning" - case Disconnected = "Disconnected" - case DelayedReconnect = "Will soon reconnect" - case DisconnectingDueToButtonPress = "Disconnecting due to button press" - case Connecting = "Connecting" - case Connected = "Connected" - case Notifying = "Notifying" - case powerOff = "powerOff" - case UnknownDevice = "UnknownDevice" -} - -public protocol LibreTransmitterDelegate: AnyObject { - // Can happen on any queue - func libreTransmitterStateChanged(_ state: BluetoothmanagerState) - func libreTransmitterReceivedMessage(_ messageIdentifier: UInt16, txFlags: UInt8, payloadData: Data) - // Will always happen on managerQueue - func libreTransmitterDidUpdate(with sensorData: SensorData, and Device: LibreTransmitterMetadata) - func libreSensorDidUpdate(with bleData: Libre2.LibreBLEResponse, and Device: LibreTransmitterMetadata) - - func noLibreTransmitterSelected() - func libreManagerDidRestoreState(found peripherals: [CBPeripheral], connected to: CBPeripheral?) -} - -extension LibreTransmitterDelegate { - func noLibreTransmitterSelected() {} - public func libreManagerDidRestoreState(found peripherals: [CBPeripheral], connected to: CBPeripheral?) {} -} - -final class LibreTransmitterProxyManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate, LibreTransmitterDelegate { - func libreSensorDidUpdate(with bleData: Libre2.LibreBLEResponse, and Device: LibreTransmitterMetadata) { - dispatchToDelegate { manager in - manager.delegate?.libreSensorDidUpdate(with: bleData, and: Device) - } - } - - - - func libreManagerDidRestoreState(found peripherals: [CBPeripheral], connected to: CBPeripheral?) { - dispatchToDelegate { manager in - manager.delegate?.libreManagerDidRestoreState(found: peripherals, connected: to) - } - } - - func noLibreTransmitterSelected() { - dispatchToDelegate { manager in - manager.delegate?.noLibreTransmitterSelected() - } - } - - func libreTransmitterStateChanged(_ state: BluetoothmanagerState) { - - logger.debug("libreTransmitterStateChanged delegating") - dispatchToDelegate { manager in - manager.delegate?.libreTransmitterStateChanged(state) - } - } - - func libreTransmitterReceivedMessage(_ messageIdentifier: UInt16, txFlags: UInt8, payloadData: Data) { - - logger.debug("libreTransmitterReceivedMessage delegating") - dispatchToDelegate { manager in - manager.delegate?.libreTransmitterReceivedMessage(messageIdentifier, txFlags: txFlags, payloadData: payloadData) - } - } - - func libreTransmitterDidUpdate(with sensorData: SensorData, and Device: LibreTransmitterMetadata) { - self.metadata = Device - self.sensorData = sensorData - - logger.debug("libreTransmitterDidUpdate delegating") - dispatchToDelegate { manager in - manager.delegate?.libreTransmitterDidUpdate(with: sensorData, and: Device) - } - } - - // MARK: - Properties - private var wantsToTerminate = false - //private var lastConnectedIdentifier : String? - - var activePlugin: LibreTransmitterProxyProtocol? = nil { - didSet { - - logger.debug("dabear:: activePlugin changed from \(oldValue.debugDescription) to \(self.activePlugin.debugDescription)") - - } - } - - var activePluginType: LibreTransmitterProxyProtocol.Type? { - activePlugin?.staticType - } - - var shortTransmitterName: String? { - activePluginType?.shortTransmitterName - } - - - fileprivate lazy var logger = Logger(forType: Self.self) - var metadata: LibreTransmitterMetadata? - - var centralManager: CBCentralManager! - var peripheral: CBPeripheral? - // var slipBuffer = SLIPBuffer() - var writeCharacteristic: CBCharacteristic? - - var sensorData: SensorData? - - public var identifier: UUID? { - peripheral?.identifier - } - - private let managerQueue = DispatchQueue(label: "no.bjorninge.bluetoothManagerQueue", qos: .utility) - private let delegateQueue = DispatchQueue(label: "no.bjorninge.delegateQueue", qos: .utility) - - fileprivate var serviceUUIDs: [CBUUID]? { - activePluginType?.serviceUUID.map { $0.value } - } - fileprivate var writeCharachteristicUUID: CBUUID? { - activePluginType?.writeCharacteristic?.value - } - fileprivate var notifyCharacteristicUUID: CBUUID? { - activePluginType?.notifyCharacteristic?.value - } - - weak var delegate: LibreTransmitterDelegate? { - didSet { - dispatchToDelegate { manager in - // Help delegate initialize by sending current state directly after delegate assignment - manager.delegate?.libreTransmitterStateChanged(self.state) - } - } - } - - private var state: BluetoothmanagerState = .Unassigned { - didSet { - dispatchToDelegate { manager in - // Help delegate initialize by sending current state directly after delegate assignment - manager.delegate?.libreTransmitterStateChanged(self.state) - } - } - } - public var connectionStateString: String { - self.state.rawValue - } - - public func dispatchToDelegate( _ closure :@escaping (_ aself: LibreTransmitterProxyManager) -> Void ) { - delegateQueue.async { [weak self] in - if let self = self { - closure(self) - } - } - } - - // MARK: - Methods - - override init() { - super.init() - logger.debug("LibreTransmitterProxyManager called") - managerQueue.sync { - let restoreID = (bundleSeedID() ?? "Unknown") + "BluetoothRestoreIdentifierKey" - centralManager = CBCentralManager(delegate: self, queue: managerQueue, options: [CBCentralManagerOptionShowPowerAlertKey: true, CBCentralManagerOptionRestoreIdentifierKey: restoreID]) - } - } - - func scanForDevices() { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - logger.debug("Scan for bluetoothdevice while internal state= \(String(describing: self.state)), bluetoothstate=\(String(describing: self.centralManager.state))") - - guard centralManager.state == .poweredOn else { - return - } - - logger.debug("Before scan for libre bluetooth device while central manager state was \(String(describing: self.centralManager.state.rawValue)))") - - let scanForAllServices = false - - //this will search for all peripherals. Guaranteed to work - if scanForAllServices { - - logger.debug("Scanning for all services:") - centralManager.scanForPeripherals(withServices: nil, options: nil) - } else { - // This is what we should have done - // Here we optimize by scanning only for relevant services - // However, this doesn't work correctly with both miaomiao and bubble - let services = LibreTransmitters.all.getServicesForDiscovery() - logger.debug("Scanning for specific services: \(String(describing: services.map { $0.uuidString }))") - centralManager.scanForPeripherals(withServices: services, options: nil) - - } - - state = .Scanning - } - - private func reset() { - logger.debug("manager is resetting the activeplugin") - - self.activePlugin?.reset() - } - - private func connect(force forceConnect: Bool = false, advertisementData: [String: Any]?) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - logger.debug("connect while state: \(String(describing: self.state.rawValue))") - if centralManager.isScanning { - centralManager.stopScan() - } - if state == .DisconnectingDueToButtonPress && !forceConnect { - - logger.debug("Connect aborted, user has actively disconnected and a reconnect was not forced") - return - } - - if let peripheral = self.peripheral { - peripheral.delegate = self - - if activePlugin?.canSupportPeripheral(peripheral) == true { - //when reaching this part, - //we are sure the peripheral is reconnecting and therefore needs reset - - logger.debug("Connecting to known device with known plugin") - - self.reset() - - centralManager.connect(peripheral, options: nil) - state = .Connecting - } else if let plugin = LibreTransmitters.getSupportedPlugins(peripheral)?.first { - self.activePlugin = plugin.init(delegate: self, advertisementData: advertisementData) - - logger.debug("Connecting to new device with known plugin") - - //only connect to devices we can support (i.e. devices that has a suitable plugin) - centralManager.connect(peripheral, options: nil) - state = .Connecting - } else { - state = .UnknownDevice - } - } - } - - func disconnectManually() { - dispatchPrecondition(condition: .notOnQueue(managerQueue)) - logger.debug("Disconnect manually while state \(String(describing: self.state.rawValue))" ) - - managerQueue.sync { - switch self.state { - case .Connected, .Connecting, .Notifying, .Scanning: - self.state = .DisconnectingDueToButtonPress // to avoid reconnect in didDisconnetPeripheral - - self.wantsToTerminate = true - default: - break - } - - if centralManager.isScanning { - logger.debug("Stopping scan") - centralManager.stopScan() - } - if let peripheral = peripheral { - centralManager.cancelPeripheralConnection(peripheral) - } - } - } - - // MARK: - CBCentralManagerDelegate - - func centralManagerDidUpdateState(_ central: CBCentralManager) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - logger.debug("Central Manager did update state to \(String(describing: central.state.rawValue))") - - switch central.state { - case .poweredOff: - state = .powerOff - case .resetting, .unauthorized, .unknown, .unsupported: - logger.debug("Central Manager was either .poweredOff, .resetting, .unauthorized, .unknown, .unsupported: \(String(describing: central.state))") - state = .Unassigned - - if central.state == .resetting, let peripheral = self.peripheral { - logger.debug("Central Manager resetting, will cancel peripheral connection") - central.cancelPeripheralConnection(peripheral) - self.peripheral = nil - } - - if central.isScanning { - central.stopScan() - } - case .poweredOn: - - if state == .DisconnectingDueToButtonPress { - logger.debug("Central Manager was powered on but sensorstate was DisconnectingDueToButtonPress: \(String(describing: central.state))") - - return - } - - logger.debug("Central Manager was powered on") - - - //not sure if needed, but can be helpful when state is restored - if let peripheral = peripheral, delegate != nil { - // do not scan if already connected - switch peripheral.state { - case .disconnected, .disconnecting: - logger.debug("Central Manager was powered on, peripheral state is disconnecting") - self.connect(advertisementData: nil) - case .connected, .connecting: - logger.debug("Central Manager was powered on, peripheral state is connected/connecting, renewing plugin") - - // This is necessary - // Normally the connect() method would have set the correct plugin, - // however when we hit this path, it is likely a state restoration - if self.activePlugin == nil || self.activePlugin?.canSupportPeripheral(peripheral) == false { - let plugin = LibreTransmitters.getSupportedPlugins(peripheral)?.first - self.activePlugin = plugin?.init(delegate: self, advertisementData: nil) - - - logger.debug("Central Manager was powered on, peripheral state is connected/connecting, stopping scan") - if central.isScanning && peripheral.state == .connected { - central.stopScan() - } - if peripheral.delegate == nil { - logger.debug("Central Manager was powered on, peripheral delegate was nil") - - } - } - - if let serviceUUIDs = serviceUUIDs, !serviceUUIDs.isEmpty { - peripheral.discoverServices(serviceUUIDs) // good practice to just discover the services, needed - } else { - logger.debug("Central Manager was powered on, could not discover services") - - } - - default: - logger.debug("Central Manager already connected") - } - } else { - - - if let preselected = UserDefaults.standard.preSelectedDevice, - let uuid = UUID(uuidString: preselected), - let newPeripheral = centralManager.retrievePeripherals(withIdentifiers: [uuid]).first, - let plugin = LibreTransmitters.getSupportedPlugins(newPeripheral)?.first { - logger.debug("Central Manager was powered on, directly connecting to already known peripheral \(newPeripheral): \(String(describing: self.state))") - self.peripheral = newPeripheral - self.peripheral?.delegate = self - - self.activePlugin = plugin.init(delegate: self, advertisementData: nil) - - managerQueue.async { - self.state = .Connecting - self.centralManager.connect(newPeripheral, options: nil) - - } - - } else { - //state should be nassigned here - logger.debug("Central Manager was powered on, scanningfordevice: \(String(describing: self.state))") - scanForDevices() // power was switched on, while app is running -> reconnect. - - } - - - } - @unknown default: - fatalError("libre bluetooth state unhandled") - } - } - - func centralManager(_ central: CBCentralManager, willRestoreState dict: [String: Any]) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - logger.debug("Central Manager will restore state to \(String(describing: dict.debugDescription))") - - - guard self.peripheral == nil else { - logger.debug("Central Manager tried to restore state while already connected") - return - } - - guard let preselected = UserDefaults.standard.preSelectedDevice else { - logger.debug("Central Manager tried to restore state but no device was preselected") - return - } - - guard let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey] as? [CBPeripheral] else { - logger.debug("Central Manager tried to restore state but no peripheral found") - self.scanForDevices() - return - } - - defer { - self.libreManagerDidRestoreState(found: peripherals, connected: self.peripheral) - } - - let restorablePeripheral = peripherals.first(where: { $0.identifier.uuidString == preselected }) - - guard let peripheral = restorablePeripheral else { - return - } - - self.peripheral = peripheral - peripheral.delegate = self - - switch peripheral.state { - case .disconnected, .disconnecting: - logger.debug("Central Manager tried to restore state from disconnected peripheral") - state = .Disconnected - self.connect(advertisementData: nil) - case .connecting: - logger.debug("Central Manager tried to restore state from connecting peripheral") - state = .Connecting - case .connected: - logger.debug("Central Manager tried to restore state from connected peripheral, letting centralManagerDidUpdateState() do the rest of the job") - //the idea here is to let centralManagerDidUpdateState() do the heavy lifting - // after all, we did assign the periheral.delegate to self earlier - - //that means the following is not necessary: - //state = .Connected - //peripheral.discoverServices(serviceUUIDs) // good practice to just discover the services, needed - @unknown default: - fatalError("Failed due to unkown default, Uwe!") - } - } - - func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - logger.debug("Did discover peripheral while state \(String(describing: self.state.rawValue)) with name: \(String(describing: peripheral.name)), wantstoterminate?: \(self.wantsToTerminate)") - - - // Libre2: - // during setup, we find the uid by scanning via nfc - // first time connecting to a libre2 sensor via bluetooth we don't know its peripheral identifier - // but since the uid is also part of the libre 2bluetooth advertismentdata we trade uid for - - if let selectedUid = UserDefaults.standard.preSelectedUid { - logger.debug("Was asked to connect preselected libre2 by uid: \(selectedUid.hex), discovered devicename is: \(String(describing: peripheral.name))") - - guard let manufacturerData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data else { - return - } - - guard manufacturerData.count == 8 else { - return - } - - var foundUUID = manufacturerData.subdata(in: 2..<8) - foundUUID.append(contentsOf: [0x07, 0xe0]) - - guard foundUUID == selectedUid && Libre2DirectTransmitter.canSupportPeripheral(peripheral) else { - return - } - - //next time we search via bluetooth, let's identify the sensor with its bluetooth identifier - UserDefaults.standard.preSelectedUid = nil - UserDefaults.standard.preSelectedDevice = peripheral.identifier.uuidString - - logger.debug("ManufacturerData: \(manufacturerData), found uid: \(foundUUID)") - - logger.debug("Did connect to preselected \(String(describing: peripheral.name)) with identifier \(String(describing: peripheral.identifier.uuidString)) and uid \(selectedUid.hex)") - self.peripheral = peripheral - - self.connect(force: true, advertisementData: advertisementData) - - - return - - } - - if let preselected = UserDefaults.standard.preSelectedDevice { - if peripheral.identifier.uuidString == preselected { - logger.debug("Did connect to preselected \(String(describing: peripheral.name)) with identifier \(String(describing: peripheral.identifier.uuidString))") - self.peripheral = peripheral - - self.connect(force: true, advertisementData: advertisementData) - } else { - logger.info("Did not connect to \(String(describing: peripheral.name)) with identifier \(String(describing: peripheral.identifier.uuidString)), because another device with identifier \(preselected) was selected") - } - - return - } else { - self.noLibreTransmitterSelected() - } - } - - func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - logger.debug("Did connect peripheral while state \(String(describing: self.state.rawValue)) with name: \(String(describing: peripheral.name))") - if central.isScanning { - central.stopScan() - } - state = .Connected - //self.lastConnectedIdentifier = peripheral.identifier.uuidString - // Discover all Services. This might be helpful if writing is needed some time - peripheral.discoverServices(serviceUUIDs) - } - - func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - logger.debug("Did fail to connect peripheral while state: \(String(describing: self.state.rawValue))") - if let error = error { - logger.error("Did fail to connect peripheral error: \(error.localizedDescription)") - } - state = .Disconnected - - self.reconnect() - } - - private func reconnect() { - let withDelay = self.activePluginType?.requiresDelayedReconnect == true - if withDelay { - delayedReconnect() - } else { - reconnectImmediately() - } - } - - private func reconnectImmediately() { - self.connect(advertisementData: nil) - } - - private func delayedReconnect(_ seconds: Double = 7) { - state = .DelayedReconnect - - logger.debug("Will reconnect peripheral in \(String(describing: seconds)) seconds") - self.reset() - // attempt to avoid IOS killing app because of cpu usage. - // postpone connecting for x seconds - DispatchQueue.global(qos: .utility).async { [weak self] in - Thread.sleep(forTimeInterval: seconds) - self?.managerQueue.sync { - self?.connect(advertisementData: nil) - } - } - } - - func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - logger.debug("Did disconnect peripheral while state: \(String(describing: self.state.rawValue)))") - if let error = error { - logger.error("Did disconnect peripheral error: \(error.localizedDescription)") - } - - switch state { - case .DisconnectingDueToButtonPress: - state = .Disconnected - self.wantsToTerminate = true - - default: - state = .Disconnected - self.reconnect() - - // scanForMiaoMiao() - } - } - - // MARK: - CBPeripheralDelegate - - func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - logger.debug("Did discover services. is plugin nil? \((self.activePlugin == nil ? "nil" : "not nil"))") - if let error = error { - logger.error("Did discover services error: \(error.localizedDescription)") - } - - if let services = peripheral.services { - for service in services { - let toDiscover = [writeCharachteristicUUID, notifyCharacteristicUUID].compactMap { $0 } - - logger.debug("Will discover : \(String(describing: toDiscover.count)) Characteristics for service \(String(describing: service.debugDescription))") - - if !toDiscover.isEmpty { - peripheral.discoverCharacteristics(toDiscover, for: service) - - logger.debug("Did discover service: \(String(describing: service.debugDescription))") - } - } - } - } - - func didDiscoverNotificationCharacteristic(_ peripheral: CBPeripheral, notifyCharacteristic characteristic: CBCharacteristic){ - - - logger.debug("Did discover characteristic: \(String(describing: characteristic.debugDescription)) and asking activeplugin to handle it as a notification Characteristic") - - self.activePlugin?.didDiscoverNotificationCharacteristic(peripheral, notifyCharacteristic: characteristic) - - - - - } - - func didDiscoverWriteCharacteristic(_ peripheral: CBPeripheral, writeCharacteristic characteristic: CBCharacteristic){ - writeCharacteristic = characteristic - logger.debug("Did discover characteristic: \(String(describing: characteristic.debugDescription)) and asking activeplugin to handle it as a write Characteristic") - self.activePlugin?.didDiscoverWriteCharacteristics(peripheral, writeCharacteristics: characteristic) - - - } - - func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - logger.debug("Did discover characteristics for service \(String(describing: peripheral.name))") - - if let error = error { - logger.error("Did discover characteristics for service error: \(error.localizedDescription)") - } - - if let characteristics = service.characteristics { - for characteristic in characteristics { - - logger.debug("Did discover characteristic: \(String(describing: characteristic.debugDescription))") - if characteristic.properties.intersection(.notify) == .notify && characteristic.uuid == notifyCharacteristicUUID { - didDiscoverNotificationCharacteristic(peripheral, notifyCharacteristic: characteristic) - } - if characteristic.uuid == writeCharachteristicUUID { - didDiscoverWriteCharacteristic(peripheral, writeCharacteristic: characteristic) - } - } - } else { - logger.debug("Discovered characteristics, but no characteristics listed. There must be some error.") - } - } - - func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - logger.debug("Did update notification state for characteristic: \(String(describing: characteristic.debugDescription))") - - if let error = error { - logger.error("Peripheral did update notification state for characteristic: \(error.localizedDescription) with error") - } else { - self.reset() - requestData() - } - state = .Notifying - } - - private var lastNotifyUpdate: Date? - func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - let now = Date() - - // We can expect thedevices to complete well within 5 seconds for all the telegrams combined in a session - // it is therefore reasonable to expect the time between one telegram - // to the other in the same session to be well within 6 seconds - // this path will be hit when a telegram for some reason is dropped - // in a session. Or that the user disconnecting and reconnecting during a transmission - // By resetting here we ensure that the rxbuffer doesn't leak over into the next session - // Leaking over into the next session, is however not a problem for consitency as we always check the CRC's anyway - if let lastNotifyUpdate = self.lastNotifyUpdate, now > lastNotifyUpdate.addingTimeInterval(6) { - logger.debug("dabear:: there hasn't been any traffic to the \((self.activePluginType?.shortTransmitterName).debugDescription) plugin for more than 10 seconds, so we reset now") - self.reset() - } - - logger.debug("Did update value for characteristic: \(String(describing: characteristic.debugDescription))") - - self.lastNotifyUpdate = now - - if let error = error { - logger.error("Characteristic update error: \(error.localizedDescription)") - } else { - if characteristic.uuid == notifyCharacteristicUUID, let value = characteristic.value { - if self.activePlugin == nil { - logger.error("Characteristic update error: activeplugin was nil") - } - self.activePlugin?.updateValueForNotifyCharacteristics(value, peripheral: peripheral, writeCharacteristic: writeCharacteristic) - } - } - } - - func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - logger.debug("Did Write value \(String(describing: characteristic.value?.hexEncodedString())) for characteristic \(String(characteristic.debugDescription))") - self.activePlugin?.didWrite(peripheral, characteristics: characteristic) - - } - - func requestData() { - guard let peripheral = peripheral, - let writeCharacteristic = writeCharacteristic else { - return - } - self.activePlugin?.requestData(writeCharacteristics: writeCharacteristic, peripheral: peripheral) - } - - deinit { - self.activePlugin = nil - self.delegate = nil - logger.debug("dabear:: miaomiaomanager deinit called") - } -} - -extension LibreTransmitterProxyManager { - public var manufacturer: String { - activePluginType?.manufacturerer ?? "n/a" - } - - var device: HKDevice? { - HKDevice( - name: "MiaomiaoClient", - manufacturer: manufacturer, - model: nil, //latestSpikeCollector, - hardwareVersion: self.metadata?.hardware , - firmwareVersion: self.metadata?.firmware, - softwareVersion: nil, - localIdentifier: identifier?.uuidString, - udiDeviceIdentifier: nil - ) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/LibreTransmitterProxyProtocol.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/LibreTransmitterProxyProtocol.swift deleted file mode 100644 index 4ce61d996..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/LibreTransmitterProxyProtocol.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// LibreTransmitter.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 08/01/2020. -// Copyright © 2020 Bjørn Inge Berg. All rights reserved. -// - -import CoreBluetooth -import Foundation -import UIKit -public protocol LibreTransmitterProxyProtocol: AnyObject { - static var shortTransmitterName: String { get } - static var smallImage: UIImage? { get } - static var manufacturerer: String { get } - static var requiresPhoneNFC: Bool { get } - static var requiresSetup : Bool { get } - static func canSupportPeripheral(_ peripheral: CBPeripheral) -> Bool - - static var writeCharacteristic: UUIDContainer? { get set } - static var notifyCharacteristic: UUIDContainer? { get set } - static var serviceUUID: [UUIDContainer] { get set } - - var delegate: LibreTransmitterDelegate? { get set } - init(delegate: LibreTransmitterDelegate, advertisementData: [String: Any]? ) - func requestData(writeCharacteristics: CBCharacteristic, peripheral: CBPeripheral) - func updateValueForNotifyCharacteristics(_ value: Data, peripheral: CBPeripheral, writeCharacteristic: CBCharacteristic?) - func didDiscoverWriteCharacteristics(_ peripheral: CBPeripheral, writeCharacteristics: CBCharacteristic) - func didDiscoverNotificationCharacteristic(_ peripheral: CBPeripheral, notifyCharacteristic: CBCharacteristic) - func didWrite(_ peripheral: CBPeripheral, characteristics: CBCharacteristic) - - func reset() - - - - - static func getDeviceDetailsFromAdvertisement(advertisementData: [String: Any]?) -> String? - -} - -extension LibreTransmitterProxyProtocol { - func canSupportPeripheral(_ peripheral: CBPeripheral) -> Bool { - Self.canSupportPeripheral(peripheral) - } - public var staticType: LibreTransmitterProxyProtocol.Type { - Self.self - } - - func didDiscoverWriteCharacteristics(_ peripheral: CBPeripheral, writeCharacteristics: CBCharacteristic) { - - } - - func didDiscoverNotificationCharacteristic(_ peripheral: CBPeripheral, notifyCharacteristic: CBCharacteristic) { - print("Setting setNotifyValue on notifyCharacteristic") - peripheral.setNotifyValue(true, for: notifyCharacteristic) - } - - func didWrite(_ peripheral: CBPeripheral, characteristics: CBCharacteristic) { - - } - - static var requiresSetup : Bool { return false} - static var requiresPhoneNFC: Bool { return false } - - static var requiresDelayedReconnect: Bool { return false} -} - -extension Array where Array.Element == LibreTransmitterProxyProtocol.Type { - func getServicesForDiscovery() -> [CBUUID] { - self.flatMap { - return $0.serviceUUID.map { $0.value } - }.removingDuplicates() - } -} - -public enum LibreTransmitters { - public static var all: [LibreTransmitterProxyProtocol.Type] { - [MiaoMiaoTransmitter.self, BubbleTransmitter.self, Libre2DirectTransmitter.self] - } - public static func isSupported(_ peripheral: CBPeripheral) -> Bool { - getSupportedPlugins(peripheral)?.isEmpty == false - } - - public static func getSupportedPlugins(_ peripheral: CBPeripheral) -> [LibreTransmitterProxyProtocol.Type]? { - all.enumerated().compactMap { - $0.element.canSupportPeripheral(peripheral) ? $0.element : nil - } - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/MiaomiaoTransmitter.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/MiaomiaoTransmitter.swift deleted file mode 100644 index af648a1f7..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/MiaomiaoTransmitter.swift +++ /dev/null @@ -1,337 +0,0 @@ -// -// MiaomiaoTransmitter.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 01/08/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// -// How does the MiaoMiao work? -// -// 0.) Advertising -// MiaoMiao advertises with the following data: -// - key : "kCBAdvDataIsConnectable" - value : 1 -// - key : "kCBAdvDataManufacturerData" - value : <0034cb1c 53093fb4> -> This might be usable as a unique device id. -// - key : "kCBAdvDataLocalName" - value : miaomiao -// -// 1.) Services -/// The MiaoMiao has two bluetooth services, one provided for the open source community and one that is probably to be used by the Tomato app. -// a) UUID: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E -> Open Source Community -// Did discover service: -// b) UUID: 00001532-1212-EFDE-1523-785FEABCD123 -// Did discover service: -// -// 2.) Characteristics for open source service with UUID 6E400001-B5A3-F393-E0A9-E50E24DCCA9E -// -// The service contains two characheristics: -// -// a) Notify_Characteristic -// UUID: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E -// "" -// ... with properties: -// __C.CBCharacteristicProperties(rawValue: 16) -// Broadcast: [false] -// Read: [false] -// WriteWithoutResponse: [false] -// Write: [false] -// Notify: [true] -// Indicate: [false] -// AuthenticatedSignedWrites: [false] -// ExtendedProperties: [false] -// NotifyEncryptionRequired: [false] -// BroaIndicateEncryptionRequireddcast: [false] -// Service for Characteristic: [""] -// -// b) Write_Characteristic -// UUID: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E -// "" -// ... with properties: -// __C.CBCharacteristicProperties(rawValue: 12) -// Broadcast: [false] -// Read: [false] -// WriteWithoutResponse: [true] -// Write: [true] -// Notify: [false] -// Indicate: [false] -// AuthenticatedSignedWrites: [false] -// ExtendedProperties: [false] -// NotifyEncryptionRequired: [false] -// BroaIndicateEncryptionRequireddcast: [false] -// Service for Characteristic: [""] -// -// 3.) Characteristics for (possibly) Tomato app services with UUID 00001532-1212-EFDE-1523-785FEABCD123 -// -// The service contains three characteristics -// -// a) Read characteristic -// "" -// ... with properties: -// __C.CBCharacteristicProperties(rawValue: 2) -// Broadcast: [false] -// Read: [true] -// WriteWithoutResponse: [false] -// Write: [false] -// Notify: [false] -// Indicate: [false] -// AuthenticatedSignedWrites: [false] -// ExtendedProperties: [false] -// NotifyEncryptionRequired: [false] -// BroaIndicateEncryptionRequireddcast: [false] -// Service for Characteristic: [""] -// -// b) Write without respons characteristic -// Characteristic: -// "" -// ... with properties: -// __C.CBCharacteristicProperties(rawValue: 4) -// Broadcast: [false] -// Read: [false] -// WriteWithoutResponse: [true] -// Write: [false] -// Notify: [false] -// Indicate: [false] -// AuthenticatedSignedWrites: [false] -// ExtendedProperties: [false] -// NotifyEncryptionRequired: [false] -// BroaIndicateEncryptionRequireddcast: [false] -// Service for Characteristic: [""] -// -// c) Write and notify characteristic -// "" -// ... with properties: -// __C.CBCharacteristicProperties(rawValue: 24) -// Broadcast: [false] -// Read: [false] -// WriteWithoutResponse: [false] -// Write: [true] -// Notify: [true] -// Indicate: [false] -// AuthenticatedSignedWrites: [false] -// ExtendedProperties: [false] -// NotifyEncryptionRequired: [false] -// BroaIndicateEncryptionRequireddcast: [false] -// Service for Characteristic: [""] -// -// The MiaoMiao protocol -// 1.) Data -// TX: 0xF0 -// Request all the data or the sensor. The bluetooth will return the data at a certain frequency (default is every 5 minutes) after the request -// RX: -// a) Data (363 bytes): -// Pos. 0 (0x00): 0x28 + -// Pos. 1 (0x01): Len[2 bytes] + -// Pos. 3 (0x03): Index [2 bytes] (this is the minute counter of the Freestyle Libre sensor) + -// Pos. 5 (0x05): ID [8 bytes] + -// Pos. 13 (0x0D): xbattery level in percent [1 byte] (e.g. 0x64 which is 100 in decimal means 100%?) -// Pos. 14 (0x0E): firmware version [2 bytes] + -// Pos. 16 (0x10): hardware version [2 bytes] + -// Pos. 18 (0x12): FRAM data (43 x 8 bytes = 344 bytes) + -// Pos. end : 0x29 -// Example: 28 07b3 5457 db353e01 00a007e0 64 0034 0001 11b6e84f050003 875104 57540000 00 000000 00000000 0000b94b 060f1600 c0da6a80 1600c0d6 6a801600 -// 0x28 -> marks begin of data response -// 0x07b3 -> len is 1971 bytes (= 1952 for FRAM and 19 bytes for all the rest from 0x28 to 0x29, both of which are included) -// but as of 2018-03-12 only 1791 bytes are sent. -// 0x5457 -> index is 21591 -// 0xdb353e0100a007e0 -> id, can be converted to serial number -// 0x64 -> battery level (= 100%) -// 0x0034 -> firmware version -// 0x0001 -> hardware version -// 0x11b6e84f05000387 FRAM block 0x00 (sensor is expired since byte 0x04 has value 0x05) -// 0x5104575400000000 FRAM block 0x01 -// 0x0000000000000000 FRAM block 0x02 -// 0xb94b060f1600c0da FRAM block 0x03 -// ... -// 28 07b3 182b 9a8150 0100a007 e0640034 0001539d -// b) A new sensor has been detected -// 0x32 -// c) No sensor has been detected -// 0x34 -// -// 2.) Confirm to replace the sensor (if a new sensor is detected and shall be used, send this) -// TX: 0xD301 -// 3.) Confirm not to replace the sensor (if a new sensor is detected and shall not be used, send this) -// TX: 0xD300 -// 4.) Change the frequence of data transmission -// TX: 0xD1XX, where XX is the intervall time, 1 byte, e.g. 0x0A is 10 minutes -// RX: -// a) 0xD101 Success -// b) 0xD100 Fail - -import CoreBluetooth -import Foundation -import os.log -import UIKit -public enum MiaoMiaoResponseState: UInt8 { - case dataPacketReceived = 0x28 - case newSensor = 0x32 - case noSensor = 0x34 - case frequencyChangedResponse = 0xD1 -} -extension MiaoMiaoResponseState: CustomStringConvertible { - public var description: String { - switch self { - case .dataPacketReceived: - return "Data packet received" - case .newSensor: - return "New sensor detected" - case .noSensor: - return "No sensor found" - case .frequencyChangedResponse: - return "Reading intervall changed" - } - } -} - -class MiaoMiaoTransmitter: LibreTransmitterProxyProtocol { - - fileprivate lazy var logger = Logger(forType: Self.self) - - func reset() { - rxBuffer.resetAllBytes() - } - - class var manufacturerer: String { - "Tomato" - } - - class var smallImage: UIImage? { - UIImage(named: "miaomiao-small", in: Bundle.module, compatibleWith: nil) - } - - class var shortTransmitterName: String { - "miaomiao" - } - - class var requiresDelayedReconnect : Bool { - true - } - - static var writeCharacteristic: UUIDContainer? = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" - static var notifyCharacteristic: UUIDContainer? = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" - static var serviceUUID: [UUIDContainer] = ["6E400001-B5A3-F393-E0A9-E50E24DCCA9E"] - - weak var delegate: LibreTransmitterDelegate? - - private var rxBuffer = Data() - private var sensorData: SensorData? - private var metadata: LibreTransmitterMetadata? - - - - class func canSupportPeripheral(_ peripheral: CBPeripheral) -> Bool { - peripheral.name?.lowercased().starts(with: "miaomiao") ?? false - } - - class func getDeviceDetailsFromAdvertisement(advertisementData: [String: Any]?) -> String? { - nil - } - - required init(delegate: LibreTransmitterDelegate, advertisementData: [String: Any]?) { - //advertisementData is unknown for the miaomiao - self.delegate = delegate - } - - func requestData(writeCharacteristics: CBCharacteristic, peripheral: CBPeripheral) { - confirmSensor(peripheral: peripheral, writeCharacteristics: writeCharacteristics) - reset() - logger.debug("dabear: miaomiaoRequestData") - - peripheral.writeValue(Data([0xF0]), for: writeCharacteristics, type: .withResponse) - } - - func updateValueForNotifyCharacteristics(_ value: Data, peripheral: CBPeripheral, writeCharacteristic: CBCharacteristic?) { - rxBuffer.append(value) - - logger.debug("miaomiao Appended value with length \(String(describing: value.count)), buffer length is: \(String(describing: self.rxBuffer.count))") - - - - // When spreading a message over multiple telegrams, the miaomiao protocol - // does not repeat that initial byte - // firstbyte is therefore written to rxbuffer on first received telegram - // this becomes sort of a state to track which message is actually received. - // Therefore it also becomes important that once a message is fully received, the buffer is invalidated - // - guard let firstByte = rxBuffer.first, let miaoMiaoResponseState = MiaoMiaoResponseState(rawValue: firstByte) else { - reset() - logger.error("miaomiaoDidUpdateValueForNotifyCharacteristics did not undestand what to do (internal error") - return - } - - switch miaoMiaoResponseState { - case .dataPacketReceived: // 0x28: // data received, append to buffer and inform delegate if end reached - - if rxBuffer.count >= 363 { - - - delegate?.libreTransmitterReceivedMessage(0x0000, txFlags: 0x28, payloadData: rxBuffer) - - handleCompleteMessage() - reset() - } - - case .newSensor: // 0x32: // A new sensor has been detected -> acknowledge to use sensor and reset buffer - delegate?.libreTransmitterReceivedMessage(0x0000, txFlags: 0x32, payloadData: rxBuffer) - - confirmSensor(peripheral: peripheral, writeCharacteristics: writeCharacteristic) - reset() - case .noSensor: // 0x34: // No sensor has been detected -> reset buffer (and wait for new data to arrive) - - delegate?.libreTransmitterReceivedMessage(0x0000, txFlags: 0x34, payloadData: rxBuffer) - - reset() - case .frequencyChangedResponse: // 0xD1: // Success of fail for setting time intervall - - delegate?.libreTransmitterReceivedMessage(0x0000, txFlags: 0xD1, payloadData: rxBuffer) - - if value.count >= 2 { - if value[2] == 0x01 { - //success setting time interval - } else if value[2] == 0x00 { - // faioure - } else { - //"Unkown response for setting time interval." - } - } - reset() - } - } - - func handleCompleteMessage() { - guard rxBuffer.count >= 363 else { - return - } - - var patchInfo: String? - - if rxBuffer.count >= 369 { - patchInfo = Data(rxBuffer[363...368]).hexEncodedString().uppercased() - } - - logger.debug("rxbuffer length: \(self.rxBuffer.count ), patchinfo: \(String(describing: patchInfo))") - - metadata = LibreTransmitterMetadata( - hardware: String(describing: rxBuffer[16...17].hexEncodedString()), - firmware: String(describing: rxBuffer[14...15].hexEncodedString()), - battery: Int(rxBuffer[13]), - name: Self.shortTransmitterName, - macAddress: nil, - patchInfo: patchInfo, - uid: [UInt8](rxBuffer[5..<13]) ) - - sensorData = SensorData(uuid: Data(rxBuffer.subdata(in: 5..<13)), bytes: [UInt8](rxBuffer.subdata(in: 18..<362)), date: Date()) - - if let sensorData = sensorData, let metadata = metadata { - delegate?.libreTransmitterDidUpdate(with: sensorData, and: metadata) - } - } - - // Confirm (to replace) the sensor. Iif a new sensor is detected and shall be used, send this command (0xD301) - func confirmSensor(peripheral: CBPeripheral, writeCharacteristics: CBCharacteristic?) { - guard let writeCharacteristics = writeCharacteristics else { - logger.error("could not confirm sensor") - return - } - logger.debug("confirming new sensor") - peripheral.writeValue(Data([0xD3, 0x01]), for: writeCharacteristics, type: .withResponse) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/UUIDContainer.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/UUIDContainer.swift deleted file mode 100644 index 89411d4b0..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Bluetooth/Transmitter/UUIDContainer.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// UUIDContainer.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 08/01/2020. -// Copyright © 2020 Bjørn Inge Berg. All rights reserved. -// - -import CoreBluetooth -import Foundation -public struct UUIDContainer: ExpressibleByStringLiteral { - public var value: CBUUID - - init(value: CBUUID) { - self.value = value - } - public init(stringLiteral value: String) { - self.value = CBUUID(string: value) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/CollectionExtensions.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/CollectionExtensions.swift deleted file mode 100644 index d8d95151a..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/CollectionExtensions.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// CollectionExtensions.swift -// MiaomiaoClientUI -// -// Created by Bjørn Inge Berg on 26/03/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import Foundation - -extension Collection { - subscript(safe index: Index) -> Element? { - indices.contains(index) ? self[index] : nil - } -} - -extension Array where Element: Hashable { - func removingDuplicates() -> [Element] { - var addedDict = [Element: Bool]() - - return filter { - addedDict.updateValue(true, forKey: $0) == nil - } - } - - mutating func removeDuplicates() { - self = self.removingDuplicates() - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/DataExtensions.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/DataExtensions.swift deleted file mode 100644 index 9ba9488d3..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/DataExtensions.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// DataExtensions.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 22/09/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import Foundation - -extension Data { - mutating func resetAllBytes() { - self = Data() - } - - // From Stackoverflow, see https://stackoverflow.com/questions/39075043/how-to-convert-data-to-hex-string-in-swift - private static let hexAlphabet = "0123456789abcdef".unicodeScalars.map { $0 } - - public var hex: String { - return map { String(format: "%02X", $0) }.joined(separator: " ") - } - - public func hexEncodedString() -> String { - String(self.reduce(into: "".unicodeScalars, { result, value in - result.append(Data.hexAlphabet[Int(value / 16)]) - result.append(Data.hexAlphabet[Int(value % 16)]) - })) - } - - func toDebugString() -> String { - self.map { "\($0)" }.joined(separator: ", ") - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/DateExtensions.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/DateExtensions.swift deleted file mode 100644 index 86e36a690..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/DateExtensions.swift +++ /dev/null @@ -1,97 +0,0 @@ -// -// DateExtensions.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 07/03/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import Foundation - -public extension Date { - - - func rounded(on amount: Int, _ component: Calendar.Component) -> Date { - let cal = Calendar.current - let value = cal.component(component, from: self) - - // Compute nearest multiple of amount: - let roundedValue = lrint(Double(value) / Double(amount)) * amount - let newDate = cal.date(byAdding: component, value: roundedValue - value, to: self)! - - return newDate.floorAllComponents(before: component) - } - - func floorAllComponents(before component: Calendar.Component) -> Date { - // All components to round ordered by length - let components = [Calendar.Component.year, .month, .day, .hour, .minute, .second, .nanosecond] - - guard let index = components.firstIndex(of: component) else { - fatalError("Wrong component") - } - - let cal = Calendar.current - var date = self - - components.suffix(from: index + 1).forEach { roundComponent in - let value = cal.component(roundComponent, from: date) * -1 - date = cal.date(byAdding: roundComponent, value: value, to: date)! - } - - return date - } - - static var LocaleWantsAMPM: Bool { - DateFormatter.dateFormat(fromTemplate: "j", options: 0, locale: NSLocale.current)!.contains("a") - } - - func getFormattedDate(format: String) -> String { - let dateformat = DateFormatter() - dateformat.dateFormat = format - return dateformat.string(from: self) - } -} - -extension DateComponents { - func ToTimeString(wantsAMPM: Bool = Date.LocaleWantsAMPM) -> String { - //print("hour: \(self.hour) minute: \(self.minute)") - let date = Calendar.current.date(bySettingHour: self.hour ?? 0, minute: self.minute ?? 0, second: 0, of: Date())! - - let formatter = DateFormatter() - formatter.dateStyle = DateFormatter.Style.long - formatter.timeStyle = DateFormatter.Style.medium - - formatter.dateFormat = wantsAMPM ? "hh:mm a" : "HH:mm" - return formatter.string(from: date) - } -} - - -extension Array where Element == DateInterval { - // Check for intersection among the intervals in the given array and return - // the interval if found. - func intersect() -> DateInterval? { - // Algorithm: - // We will compare first two intervals. - // If an intersection is found, we will save the resultant interval - // and compare it with the next interval in the array. - // If no intersection is found at any iteration - // it means the intervals in the array are disjoint. Break the loop and return nil - // Otherwise return the last intersection. - - var previous = self.first - for (index, element) in self.enumerated() { - if index == 0 { - continue - } - - previous = previous?.intersection(with: element) - - if previous == nil { - break - } - } - - return previous - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/DoubleExtensions.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/DoubleExtensions.swift deleted file mode 100644 index bf6a83f72..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/DoubleExtensions.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// DoubleExtensions.swift -// MiaomiaoClientUI -// -// Created by Bjørn Inge Berg on 25/03/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import Foundation - -extension Double { - func roundTo(places: Int) -> Double { - let divisor = pow(10.0, Double(places)) - return (self * divisor).rounded() / divisor - } - - var twoDecimals: String { - String(format: "%.2f", self) - } - var fourDecimals: String { - String(format: "%.4f", self) - } - - enum Number { - static var formatter = NumberFormatter() - } - - -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/HashableClass.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/HashableClass.swift deleted file mode 100644 index 3818e69de..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/HashableClass.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// HashableClass.swift -// LibreTransmitterUI -// -// Created by Bjørn Inge Berg on 17/05/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -extension Hashable where Self: AnyObject { - - public func hash(into hasher: inout Hasher) { - hasher.combine(ObjectIdentifier(self)) - } -} - -extension Equatable where Self: AnyObject { - - public static func == (lhs:Self, rhs:Self) -> Bool { - return lhs === rhs - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/Notification.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/Notification.swift deleted file mode 100644 index 41b83ef7b..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/Notification.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -public extension Notification.Name { - static let newSensorDetected = Notification.Name("LibreTransmitter.newSensorDetected") -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/TimeIntervalExtensions.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/TimeIntervalExtensions.swift deleted file mode 100644 index e9a7f911b..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Extensions/TimeIntervalExtensions.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// NSTimeInterval.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - -extension TimeInterval { - static func seconds(_ seconds: Double) -> TimeInterval { - seconds - } - - static func minutes(_ minutes: Double) -> TimeInterval { - TimeInterval(minutes: minutes) - } - - static func hours(_ hours: Double) -> TimeInterval { - TimeInterval(hours: hours) - } - - init(minutes: Double) { - //self.init(minutes * 60) - let m = minutes * 60 - self.init(m) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - var minutes: Double { - self / 60.0 - } - - var hours: Double { - minutes / 60.0 - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/GlucoseSampleValue.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/GlucoseSampleValue.swift deleted file mode 100644 index f12a6ddfe..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/GlucoseSampleValue.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// GlucoseSampleValue.swift -// LoopKit -// -// Created by Nathan Racklyeft on 3/6/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -public protocol GlucoseSampleValue: GlucoseValue { - /// Uniquely identifies the source of the sample. - var provenanceIdentifier: String { get } - - /// Whether the glucose value was provided for visual consistency, rather than an actual, calibrated reading. - var isDisplayOnly: Bool { get } - - /// Whether the glucose value was entered by the user. - var wasUserEntered: Bool { get } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/GlucoseValue.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/GlucoseValue.swift deleted file mode 100644 index 59b21e553..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/GlucoseValue.swift +++ /dev/null @@ -1,91 +0,0 @@ -// -// GlucoseValue.swift -// LoopKit -// -// Created by Nathan Racklyeft on 3/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - - -import HealthKit - - -public protocol GlucoseValue: SampleValue { -} - -public struct SimpleGlucoseValue: Equatable, GlucoseValue { - public let startDate: Date - public let endDate: Date - public let quantity: HKQuantity - - public init(startDate: Date, endDate: Date? = nil, quantity: HKQuantity) { - self.startDate = startDate - self.endDate = endDate ?? startDate - self.quantity = quantity - } - - public init(_ glucoseValue: GlucoseValue) { - self.startDate = glucoseValue.startDate - self.endDate = glucoseValue.endDate - self.quantity = glucoseValue.quantity - } -} - -extension SimpleGlucoseValue: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.startDate = try container.decode(Date.self, forKey: .startDate) - self.endDate = try container.decode(Date.self, forKey: .endDate) - self.quantity = HKQuantity(unit: HKUnit(from: try container.decode(String.self, forKey: .quantityUnit)), - doubleValue: try container.decode(Double.self, forKey: .quantity)) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(startDate, forKey: .startDate) - try container.encode(endDate, forKey: .endDate) - try container.encode(quantity.doubleValue(for: .milligramsPerDeciliter), forKey: .quantity) - try container.encode(HKUnit.milligramsPerDeciliter.unitString, forKey: .quantityUnit) - } - - private enum CodingKeys: String, CodingKey { - case startDate - case endDate - case quantity - case quantityUnit - } -} - -public struct PredictedGlucoseValue: Equatable, GlucoseValue { - public let startDate: Date - public let quantity: HKQuantity - - public init(startDate: Date, quantity: HKQuantity) { - self.startDate = startDate - self.quantity = quantity - } -} - -extension PredictedGlucoseValue: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.startDate = try container.decode(Date.self, forKey: .startDate) - self.quantity = HKQuantity(unit: HKUnit(from: try container.decode(String.self, forKey: .quantityUnit)), - doubleValue: try container.decode(Double.self, forKey: .quantity)) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(startDate, forKey: .startDate) - try container.encode(quantity.doubleValue(for: .milligramsPerDeciliter), forKey: .quantity) - try container.encode(HKUnit.milligramsPerDeciliter.unitString, forKey: .quantityUnit) - } - - private enum CodingKeys: String, CodingKey { - case startDate - case quantity - case quantityUnit - } -} - -extension HKQuantitySample: GlucoseValue { } diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/HKQuantitySample+GlucoseKit.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/HKQuantitySample+GlucoseKit.swift deleted file mode 100644 index 075cfac7b..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/HKQuantitySample+GlucoseKit.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// GlucoseValue.swift -// LoopKit -// -// Created by Nathan Racklyeft on 2/19/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -let MetadataKeyGlucoseIsDisplayOnly = "com.loudnate.GlucoseKit.HKMetadataKey.GlucoseIsDisplayOnly" - - -extension HKQuantitySample: GlucoseSampleValue { - public var provenanceIdentifier: String { - return sourceRevision.source.bundleIdentifier - } - - public var isDisplayOnly: Bool { - return metadata?[MetadataKeyGlucoseIsDisplayOnly] as? Bool ?? false - } - - public var wasUserEntered: Bool { - return metadata?[HKMetadataKeyWasUserEntered] as? Bool ?? false - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/HKUnit.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/HKUnit.swift deleted file mode 100644 index 7ca8bb734..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/HKUnit.swift +++ /dev/null @@ -1,67 +0,0 @@ -// -// HKUnit.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/17/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -extension HKUnit { - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: .literUnit(with: .deci)) - }() - - static let millimolesPerLiter: HKUnit = { - return HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: .liter()) - }() - - static let internationalUnitsPerHour: HKUnit = { - return HKUnit.internationalUnit().unitDivided(by: .hour()) - }() - - static let gramsPerUnit: HKUnit = { - return HKUnit.gram().unitDivided(by: .internationalUnit()) - }() - - var foundationUnit: Unit? { - if self == HKUnit.milligramsPerDeciliter { - return UnitConcentrationMass.milligramsPerDeciliter - } - - if self == HKUnit.millimolesPerLiter { - return UnitConcentrationMass.millimolesPerLiter(withGramsPerMole: HKUnitMolarMassBloodGlucose) - } - - if self == HKUnit.gram() { - return UnitMass.grams - } - - return nil - } - - /// The smallest value expected to be visible on a chart - var chartableIncrement: Double { - if self == .milligramsPerDeciliter { - return 1 - } else { - return 1 / 25 - } - } - - var localizedShortUnitString: String { - if self == HKUnit.millimolesPerLiter { - return NSLocalizedString("mmol/L", comment: "The short unit display string for millimoles of glucose per liter") - } else if self == .milligramsPerDeciliter { - return NSLocalizedString("mg/dL", comment: "The short unit display string for milligrams of glucose per decilter") - } else if self == .internationalUnit() { - return NSLocalizedString("U", comment: "The short unit display string for international units of insulin") - } else if self == .gram() { - return NSLocalizedString("g", comment: "The short unit display string for grams") - } else { - return String(describing: self) - } - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/LocalizedString.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/LocalizedString.swift deleted file mode 100644 index efc2abfba..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/LocalizedString.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// LocalizedString.swift -// LoopKit -// -// Created by Retina15 on 8/6/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -// really needs to be a class to compile -// swiftlint:disable:next convenience_type -internal class FrameworkBundle { - static let main = Bundle(for: FrameworkBundle.self) -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: FrameworkBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: FrameworkBundle.main, comment: comment) - } -} -/* -extension DefaultStringInterpolation { - mutating func appendInterpolation(_ optional: T?) { - appendInterpolation(String(describing: optional)) - } -}*/ diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/MessagePassing.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/MessagePassing.swift deleted file mode 100644 index 777435e58..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/MessagePassing.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// MessagePassing.swift -// LibreTransmitter -// -// Created by Bjørn Inge Berg on 21/04/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import Foundation - -public func bundleSeedID() -> String? { - let queryLoad: [String: AnyObject] = [ - kSecClass as String: kSecClassGenericPassword, - kSecAttrAccount as String: "bundleSeedID" as AnyObject, - kSecAttrService as String: "" as AnyObject, - kSecReturnAttributes as String: kCFBooleanTrue - ] - - var result: AnyObject? - var status = withUnsafeMutablePointer(to: &result) { - SecItemCopyMatching(queryLoad as CFDictionary, UnsafeMutablePointer($0)) - } - - if status == errSecItemNotFound { - status = withUnsafeMutablePointer(to: &result) { - SecItemAdd(queryLoad as CFDictionary, UnsafeMutablePointer($0)) - } - } - - if status == noErr { - if let resultDict = result as? [String: Any], let accessGroup = resultDict[kSecAttrAccessGroup as String] as? String { - let components = accessGroup.components(separatedBy: ".") - return components.first - } else { - return nil - } - } else { - print("Error getting bundleSeedID to Keychain") - return nil - } -} - -public func getDynamicAppGroupForMessagePassing() -> String? { - if let seed = bundleSeedID() { - return "group.com.\(seed).Loopkit.Loop.MessagePassing" - } - return nil -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/NewGlucoseSample.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/NewGlucoseSample.swift deleted file mode 100644 index 05e440b17..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/NewGlucoseSample.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// NewGlucoseSample.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import HealthKit - - -public struct NewGlucoseSample: Equatable { - public let date: Date - public let quantity: HKQuantity - public let isDisplayOnly: Bool - public let wasUserEntered: Bool - public let syncIdentifier: String - public var syncVersion: Int - public var device: HKDevice? - - /// - Parameters: - /// - date: The date the sample was collected - /// - quantity: The glucose sample quantity - /// - isDisplayOnly: Whether the reading was shifted for visual consistency after calibration - /// - wasUserEntered: Whether the reading was entered by the user (manual) or not (device) - /// - syncIdentifier: A unique identifier representing the sample, used for de-duplication - /// - syncVersion: A version number for determining resolution in de-duplication - /// - device: The description of the device the collected the sample - public init(date: Date, quantity: HKQuantity, isDisplayOnly: Bool, wasUserEntered: Bool, syncIdentifier: String, syncVersion: Int = 1, device: HKDevice? = nil) { - self.date = date - self.quantity = quantity - self.isDisplayOnly = isDisplayOnly - self.wasUserEntered = wasUserEntered - self.syncIdentifier = syncIdentifier - self.syncVersion = syncVersion - self.device = device - } -} - - -extension NewGlucoseSample { - public var quantitySample: HKQuantitySample { - var metadata: [String: Any] = [ - HKMetadataKeySyncIdentifier: syncIdentifier, - HKMetadataKeySyncVersion: syncVersion, - ] - - if isDisplayOnly { - metadata[MetadataKeyGlucoseIsDisplayOnly] = true - } - if wasUserEntered { - metadata[HKMetadataKeyWasUserEntered] = true - } - - return HKQuantitySample( - type: HKQuantityType.quantityType(forIdentifier: .bloodGlucose)!, - quantity: quantity, - start: date, - end: date, - device: device, - metadata: metadata - ) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/NotificationHelper.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/NotificationHelper.swift deleted file mode 100644 index 78251dac4..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/NotificationHelper.swift +++ /dev/null @@ -1,350 +0,0 @@ -// -// NotificationHelper.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 30/05/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import Foundation -import HealthKit -import UserNotifications -import os.log -import UIKit - -fileprivate var logger = Logger(forType: "NotificationHelper") - -public enum NotificationHelper { - - private enum Identifiers: String { - case glucocoseNotifications = "no.bjorninge.miaomiao.glucose-notification" - case noSensorDetected = "no.bjorninge.miaomiao.nosensordetected-notification" - case tryAgainLater = "no.bjorninge.miaomiao.glucoseNotAvailableTryAgainLater-notification" - case sensorChange = "no.bjorninge.miaomiao.sensorchange-notification" - case invalidSensor = "no.bjorninge.miaomiao.invalidsensor-notification" - case lowBattery = "no.bjorninge.miaomiao.lowbattery-notification" - case sensorExpire = "no.bjorninge.miaomiao.SensorExpire-notification" - case noBridgeSelected = "no.bjorninge.miaomiao.noBridgeSelected-notification" - case bluetoothPoweredOff = "no.bjorninge.miaomiao.bluetoothPoweredOff-notification" - case invalidChecksum = "no.bjorninge.miaomiao.invalidChecksum-notification" - case calibrationOngoing = "no.bjorninge.miaomiao.calibration-notification" - case restoredState = "no.bjorninge.miaomiao.state-notification" - } - - public static func GlucoseUnitIsSupported(unit: HKUnit) -> Bool { - [HKUnit.milligramsPerDeciliter, HKUnit.millimolesPerLiter].contains(unit) - } - - public static func sendRestoredStateNotification(msg: String) { - ensureCanSendNotification { - logger.debug("dabear:: sending RestoredStateNotification") - - let content = UNMutableNotificationContent() - content.title = NSLocalizedString("State was restored", comment: "State was restored") - content.body = msg - - addRequest(identifier: .restoredState, content: content ) - } - } - - public static func sendBluetoothPowerOffNotification() { - ensureCanSendNotification { - logger.debug("dabear:: sending BluetoothPowerOffNotification") - - let content = UNMutableNotificationContent() - content.title = NSLocalizedString("Bluetooth Power Off", comment: "Bluetooth Power Off") - content.body = NSLocalizedString("Please turn on Bluetooth", comment: "Please turn on Bluetooth") - - addRequest(identifier: .bluetoothPoweredOff, content: content) - } - } - - public static func sendNoTransmitterSelectedNotification() { - ensureCanSendNotification { - logger.debug("dabear:: sending NoTransmitterSelectedNotification") - - let content = UNMutableNotificationContent() - content.title = NSLocalizedString("No Libre Transmitter Selected", comment: "No Libre Transmitter Selected") - content.body = NSLocalizedString("Delete Transmitter and start anew.", comment: "Delete Transmitter and start anew.") - - addRequest(identifier: .noBridgeSelected, content: content) - } - } - - private static func ensureCanSendGlucoseNotification(_ completion: @escaping (_ unit: HKUnit) -> Void ) { - ensureCanSendNotification { - if let glucoseUnit = UserDefaults.standard.mmGlucoseUnit, GlucoseUnitIsSupported(unit: glucoseUnit) { - completion(glucoseUnit) - } - } - } - - public static func requestNotificationPermissionsIfNeeded(){ - UNUserNotificationCenter.current().getNotificationSettings { settings in - logger.debug("settings.authorizationStatus: \(String(describing: settings.authorizationStatus.rawValue))") - if ![.authorized,.provisional].contains(settings.authorizationStatus) { - requestNotificationPermissions() - } - - } - - } - - private static func requestNotificationPermissions() { - logger.debug("requestNotificationPermissions called") - let center = UNUserNotificationCenter.current() - center.requestAuthorization(options: [.badge, .sound, .alert]) { (granted, error) in - if granted { - logger.debug("requestNotificationPermissions was granted") - } else { - logger.debug("requestNotificationPermissions failed because of error: \(String(describing: error))") - } - - } - - - } - - private static func ensureCanSendNotification(_ completion: @escaping () -> Void ) { - UNUserNotificationCenter.current().getNotificationSettings { settings in - guard settings.authorizationStatus == .authorized || settings.authorizationStatus == .provisional else { - logger.debug("dabear:: ensureCanSendNotification failed, authorization denied") - return - } - - logger.debug("dabear:: sending notification was allowed") - - completion() - } - } - - public static func sendInvalidChecksumIfDeveloper(_ sensorData: SensorData) { - if sensorData.hasValidCRCs { - return - } - - ensureCanSendNotification { - let content = UNMutableNotificationContent() - content.title = NSLocalizedString("Invalid libre checksum", comment: "Invalid libre checksum") - content.body = NSLocalizedString("Libre sensor was incorrectly read, CRCs were not valid", comment: "Libre sensor was incorrectly read, CRCs were not valid") - - addRequest(identifier: .invalidChecksum, content: content) - } - } - - private static func addRequest(identifier: Identifiers, content: UNMutableNotificationContent, deleteOld: Bool = false) { - let center = UNUserNotificationCenter.current() - //content.sound = UNNotificationSound. - let request = UNNotificationRequest(identifier: identifier.rawValue, content: content, trigger: nil) - - if deleteOld { - // Required since ios12+ have started to cache/group notifications - center.removeDeliveredNotifications(withIdentifiers: [identifier.rawValue]) - center.removePendingNotificationRequests(withIdentifiers: [identifier.rawValue]) - } - - center.add(request) { error in - if let error = error { - logger.debug("dabear:: unable to addNotificationRequest: \(error.localizedDescription)") - return - } - - logger.debug("dabear:: sending \(identifier.rawValue) notification") - } - } - - public enum CalibrationMessage: String { - case starting = "Calibrating sensor, please stand by!" - case noCalibration = "Could not calibrate sensor, check libreoopweb permissions and internet connection" - case invalidCalibrationData = "Could not calibrate sensor, invalid calibrationdata" - case success = "Success!" - } - - public static func sendCalibrationNotification(_ calibrationMessage: CalibrationMessage) { - ensureCanSendNotification { - let content = UNMutableNotificationContent() - content.sound = .default - content.title = NSLocalizedString("Extracting calibrationdata from sensor", comment: "Extracting calibrationdata from sensor") - content.body = NSLocalizedString(calibrationMessage.rawValue, comment: "calibrationMessage") - - addRequest(identifier: .calibrationOngoing, - content: content, - deleteOld: true) - } - } - - public static func sendSensorNotDetectedNotificationIfNeeded(noSensor: Bool) { - guard UserDefaults.standard.mmAlertNoSensorDetected && noSensor else { - logger.debug("Not sending noSensorDetected notification") - return - } - - sendSensorNotDetectedNotification() - } - - private static func sendSensorNotDetectedNotification() { - ensureCanSendNotification { - let content = UNMutableNotificationContent() - content.title = NSLocalizedString("No Sensor Detected", comment: "No Sensor Detected") - content.body = NSLocalizedString("This might be an intermittent problem, but please check that your transmitter is tightly secured over your sensor", comment: "This might be an intermittent problem, but please check that your transmitter is tightly secured over your sensor") - - addRequest(identifier: .noSensorDetected, content: content) - } - } - - public static func sendSensorChangeNotificationIfNeeded() { - guard UserDefaults.standard.mmAlertNewSensorDetected else { - logger.debug("not sending sendSensorChange notification ") - return - } - sendSensorChangeNotification() - } - - private static func sendSensorChangeNotification() { - ensureCanSendNotification { - let content = UNMutableNotificationContent() - content.title = NSLocalizedString("New Sensor Detected", comment: "New Sensor Detected") - content.body = NSLocalizedString("Please wait up to 30 minutes before glucose readings are available!", comment: "Please wait up to 30 minutes before glucose readings are available!") - - addRequest(identifier: .sensorChange, content: content) - //content.sound = UNNotificationSound. - - } - } - - public static func sendSensorTryAgainLaterNotification() { - ensureCanSendNotification { - let content = UNMutableNotificationContent() - content.title = NSLocalizedString("Invalid Glucose sample detected, try again later", comment: "Invalid Glucose sample detected, try again later") - content.body = NSLocalizedString("Sensor might have temporarily stopped, fallen off or is too cold or too warm", comment: "Sensor might have temporarily stopped, fallen off or is too cold or too warm") - - addRequest(identifier: .tryAgainLater, content: content) - //content.sound = UNNotificationSound. - - } - } - - - - public static func sendInvalidSensorNotificationIfNeeded(sensorData: SensorData) { - let isValid = sensorData.isLikelyLibre1FRAM && (sensorData.state == .starting || sensorData.state == .ready) - - guard UserDefaults.standard.mmAlertInvalidSensorDetected && !isValid else { - logger.debug("not sending invalidSensorDetected notification") - return - } - - sendInvalidSensorNotification(sensorData: sensorData) - } - - private static func sendInvalidSensorNotification(sensorData: SensorData) { - ensureCanSendNotification { - let content = UNMutableNotificationContent() - content.title = NSLocalizedString("Invalid Sensor Detected", comment: "Invalid Sensor Detected") - - if !sensorData.isLikelyLibre1FRAM { - content.body = NSLocalizedString("Detected sensor seems not to be a libre 1 sensor!", comment: "Detected sensor seems not to be a libre 1 sensor!") - } else if !(sensorData.state == .starting || sensorData.state == .ready) { - content.body = String(format: NSLocalizedString("Detected sensor is invalid: %@", comment: "Detected sensor is invalid: %@"), sensorData.state.description) - } - - content.sound = .default - - addRequest(identifier: .invalidSensor, content: content) - } - } - - private static var lastBatteryWarning: Date? - - public static func sendLowBatteryNotificationIfNeeded(device: LibreTransmitterMetadata) { - guard UserDefaults.standard.mmAlertLowBatteryWarning else { - logger.debug("mmAlertLowBatteryWarning toggle was not enabled, not sending low notification") - return - } - - if let battery = device.battery, battery > 20 { - logger.debug("device battery is \(battery), not sending low notification") - return - - } - - let now = Date() - //only once per mins minute - let mins = 60.0 * 120 - if let earlierplus = lastBatteryWarning?.addingTimeInterval(mins) { - if earlierplus < now { - sendLowBatteryNotification(batteryPercentage: device.batteryString, - deviceName: device.name) - lastBatteryWarning = now - } else { - logger.debug("Device battery is running low, but lastBatteryWarning Notification was sent less than 45 minutes ago, aborting. earlierplus: \(earlierplus), now: \(now)") - } - } else { - sendLowBatteryNotification(batteryPercentage: device.batteryString, - deviceName: device.name) - lastBatteryWarning = now - } - } - - private static func sendLowBatteryNotification(batteryPercentage: String, deviceName: String) { - ensureCanSendNotification { - let content = UNMutableNotificationContent() - content.title = NSLocalizedString("Low Battery", comment: "Low Battery") - content.body = String(format: NSLocalizedString("Battery is running low %@, consider charging your %@ device as soon as possible", comment: ""), batteryPercentage, deviceName) - - - content.sound = .default - - addRequest(identifier: .lowBattery, content: content) - } - } - - private static var lastSensorExpireAlert: Date? - - public static func sendSensorExpireAlertIfNeeded(minutesLeft: Double) { - guard UserDefaults.standard.mmAlertWillSoonExpire else { - logger.debug("mmAlertWillSoonExpire toggle was not enabled, not sending expiresoon alarm") - return - } - - guard TimeInterval(minutes: minutesLeft) < TimeInterval(hours: 24) else { - logger.debug("Sensor time left was more than 24 hours, not sending notification: \(minutesLeft.twoDecimals) minutes") - return - } - - let now = Date() - //only once per 6 hours - let min45 = 60.0 * 60 * 6 - - if let earlier = lastSensorExpireAlert { - if earlier.addingTimeInterval(min45) < now { - sendSensorExpireAlert(minutesLeft: minutesLeft) - lastSensorExpireAlert = now - } else { - logger.debug("Sensor is soon expiring, but lastSensorExpireAlert was sent less than 6 hours ago, so aborting") - } - } else { - sendSensorExpireAlert(minutesLeft: minutesLeft) - lastSensorExpireAlert = now - } - } - - public static func sendSensorExpireAlertIfNeeded(sensorData: SensorData) { - sendSensorExpireAlertIfNeeded(minutesLeft: Double(sensorData.minutesLeft)) - } - - private static func sendSensorExpireAlert(minutesLeft: Double) { - ensureCanSendNotification { - - let hours = minutesLeft == 0 ? 0 : round(minutesLeft/60) - - let dynamicText = hours <= 1 ? NSLocalizedString("minutes", comment: "minutes") + ": \(minutesLeft.twoDecimals)" : NSLocalizedString("hours", comment: "hours") + ": \(hours.twoDecimals)" - - let content = UNMutableNotificationContent() - content.title = NSLocalizedString("Sensor Ending Soon", comment: "Sensor Ending Soon") - content.body = String(format: NSLocalizedString("Current Sensor is Ending soon! Sensor Life left in %@", comment: ""), dynamicText) - - addRequest(identifier: .sensorExpire, content: content, deleteOld: true) - } - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/NumberFormatter.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/NumberFormatter.swift deleted file mode 100644 index 969d26f55..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/NumberFormatter.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// NSNumberFormatter.swift -// Loop -// -// Created by Nate Racklyeft on 9/5/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -extension NumberFormatter { - func string(from number: Double) -> String? { - return string(from: NSNumber(value: number)) - } - - func string(from number: Double, unit: String, style: Formatter.UnitStyle = .medium) -> String? { - guard let stringValue = string(from: number) else { - return nil - } - - let format: String - switch style { - case .long, .medium: - format = LocalizedString( - "quantity-and-unit-space", - value: "%1$@ %2$@", - comment: "Format string for combining localized numeric value and unit with a space. (1: numeric value)(2: unit)" - ) - case .short: - fallthrough - @unknown default: - format = LocalizedString( - "quantity-and-unit-tight", - value: "%1$@%2$@", - comment: "Format string for combining localized numeric value and unit without spacing. (1: numeric value)(2: unit)" - ) - } - - return String( - format: format, - stringValue, - unit - ) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/QuantityFormatter.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/QuantityFormatter.swift deleted file mode 100644 index 4bbd78922..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/QuantityFormatter.swift +++ /dev/null @@ -1,253 +0,0 @@ -// -// QuantityFormatter.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - - -/// Formats unit quantities as localized strings -open class QuantityFormatter { - - public init() { - } - - public convenience init(for unit: HKUnit) { - self.init() - setPreferredNumberFormatter(for: unit) - } - - /// The unit style determines how the unit strings are abbreviated, and spacing between the value and unit - open var unitStyle: Formatter.UnitStyle = .medium { - didSet { - if hasMeasurementFormatter { - measurementFormatter.unitStyle = unitStyle - } - - if hasMassFormatter { - massFormatter.unitStyle = unitStyle - } - } - } - - open var locale: Locale = Locale.current { - didSet { - if hasNumberFormatter { - numberFormatter.locale = locale - } - - if hasMeasurementFormatter { - measurementFormatter.locale = locale - } - } - } - - /// Updates `numberFormatter` configuration for the specified unit - /// - /// - Parameter unit: The unit - open func setPreferredNumberFormatter(for unit: HKUnit) { - numberFormatter.numberStyle = .decimal - numberFormatter.minimumFractionDigits = unit.preferredFractionDigits - numberFormatter.maximumFractionDigits = unit.maxFractionDigits - } - - private var hasNumberFormatter = false - - /// The formatter used for the quantity values - open private(set) lazy var numberFormatter: NumberFormatter = { - hasNumberFormatter = true - - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.locale = self.locale - formatter.roundingMode = .halfUp - return formatter - }() - - private var hasMeasurementFormatter = false - - /// MeasurementFormatter is used for gram measurements, mg/dL units, and mmol/L units. - /// It does not properly handle glucose measurements, as it changes unit scales: 100 mg/dL -> 1 g/L - private lazy var measurementFormatter: MeasurementFormatter = { - hasMeasurementFormatter = true - - let formatter = MeasurementFormatter() - formatter.unitOptions = [.providedUnit] - formatter.numberFormatter = self.numberFormatter - formatter.locale = self.locale - formatter.unitStyle = self.unitStyle - return formatter - }() - - private var hasMassFormatter = false - - /// MassFormatter properly creates unit strings for grams in .short/.medium style as "g", where MeasurementFormatter uses "gram"/"grams" - private lazy var massFormatter: MassFormatter = { - hasMassFormatter = true - - let formatter = MassFormatter() - formatter.numberFormatter = self.numberFormatter - formatter.unitStyle = self.unitStyle - return formatter - }() - - /// Formats a quantity and unit as a localized string - /// - /// - Parameters: - /// - quantity: The quantity - /// - unit: The unit. An exception is thrown if `quantity` is not compatible with the unit. - /// - includeUnit: Whether or not to include the unit in the returned string - /// - Returns: A localized string, or nil if `numberFormatter` is unable to format the quantity value - open func string(from quantity: HKQuantity, for unit: HKUnit, includeUnit: Bool = true) -> String? { - let value = quantity.doubleValue(for: unit) - - if !includeUnit { - return numberFormatter.string(from: value) - } - - if let foundationUnit = unit.foundationUnit, unit.usesMeasurementFormatterForMeasurement { - return measurementFormatter.string(from: Foundation.Measurement(value: value, unit: foundationUnit)) - } - - return numberFormatter.string(from: value, unit: string(from: unit, forValue: value), style: unitStyle) - } - - /// Formats a unit as a localized string - /// - /// - Parameters: - /// - unit: The unit - /// - value: An optional value for determining the plurality of the unit string - /// - Returns: A string for the unit. If no localization entry is available, the unlocalized `unitString` is returned. - open func string(from unit: HKUnit, forValue value: Double = 10) -> String { - if let string = unit.localizedUnitString(in: unitStyle, singular: abs(1.0 - value) < .ulpOfOne) { - return string - } - - if unit.usesMassFormatterForUnitString { - return massFormatter.unitString(fromValue: value, unit: HKUnit.massFormatterUnit(from: unit)) - } - - if let foundationUnit = unit.foundationUnit { - return measurementFormatter.string(from: foundationUnit) - } - - // Fallback, unlocalized - return unit.unitString - } -} - - -public extension HKUnit { - var usesMassFormatterForUnitString: Bool { - return self == .gram() - } - - var usesMeasurementFormatterForMeasurement: Bool { - return self == .gram() - } - - var preferredFractionDigits: Int { - if self == HKUnit.millimolesPerLiter || self == HKUnit.millimolesPerLiter.unitDivided(by: .internationalUnit()) { - return 1 - } else { - return 0 - } - } - - var maxFractionDigits: Int { - switch self { - case .internationalUnit(), .internationalUnitsPerHour: - return 3 - case HKUnit.gram().unitDivided(by: .internationalUnit()): - return 2 - default: - return preferredFractionDigits - } - } - - // Short localized unit string with unlocalized fallback - func shortLocalizedUnitString() -> String { - return localizedUnitString(in: .short) ?? unitString - } - - func localizedUnitString(in style: Formatter.UnitStyle, singular: Bool = false) -> String? { - if self == .internationalUnit() { - switch style { - case .short, .medium: - return LocalizedString("U", comment: "The short unit display string for international units of insulin") - case .long: - fallthrough - @unknown default: - if singular { - return LocalizedString("Unit", comment: "The long unit display string for a singular international unit of insulin") - } else { - return LocalizedString("Units", comment: "The long unit display string for international units of insulin") - } - } - } - - if self == .internationalUnitsPerHour { - switch style { - case .short, .medium: - return LocalizedString("U/hr", comment: "The short unit display string for international units of insulin per hour") - case .long: - fallthrough - @unknown default: - if singular { - return LocalizedString("Unit/hour", comment: "The long unit display string for a singular international unit of insulin per hour") - } else { - return LocalizedString("Units/hour", comment: "The long unit display string for international units of insulin per hour") - } - } - } - - if self == HKUnit.millimolesPerLiter { - switch style { - case .short, .medium: - return LocalizedString("mmol/L", comment: "The short unit display string for millimoles per liter") - case .long: - break // Fallback to the MeasurementFormatter localization - @unknown default: - break - } - } - - if self == HKUnit.milligramsPerDeciliter.unitDivided(by: HKUnit.internationalUnit()) { - switch style { - case .short, .medium: - return LocalizedString("mg/dL/U", comment: "The short unit display string for milligrams per deciliter per U") - case .long: - break // Fallback to the MeasurementFormatter localization - @unknown default: - break - } - } - - if self == HKUnit.millimolesPerLiter.unitDivided(by: HKUnit.internationalUnit()) { - switch style { - case .short, .medium: - return LocalizedString("mmol/L/U", comment: "The short unit display string for millimoles per liter per U") - case .long: - break // Fallback to the MeasurementFormatter localization - @unknown default: - break - } - } - - if self == HKUnit.gram().unitDivided(by: HKUnit.internationalUnit()) { - switch style { - case .short, .medium: - return LocalizedString("g/U", comment: "The short unit display string for grams per U") - case .long: - fallthrough - @unknown default: - break // Fallback to the MeasurementFormatter localization - } - } - - return nil - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/SampleValue.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/SampleValue.swift deleted file mode 100644 index 267e915cc..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/SampleValue.swift +++ /dev/null @@ -1,115 +0,0 @@ -// -// SampleValue.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/24/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -public protocol TimelineValue { - var startDate: Date { get } - var endDate: Date { get } -} - - -public extension TimelineValue { - var endDate: Date { - return startDate - } -} - - -public protocol SampleValue: TimelineValue { - var quantity: HKQuantity { get } -} - - -public extension Sequence where Element: TimelineValue { - /** - Returns the closest element in the sorted sequence prior to the specified date - - - parameter date: The date to use in the search - - - returns: The closest element, if any exist before the specified date - */ - func closestPrior(to date: Date) -> Iterator.Element? { - return elementsAdjacent(to: date).before - } - - /// Returns the elements immediately before and after the specified date - /// - /// - Parameter date: The date to use in the search - /// - Returns: The closest elements, if found - func elementsAdjacent(to date: Date) -> (before: Iterator.Element?, after: Iterator.Element?) { - var before: Iterator.Element? - var after: Iterator.Element? - - for value in self { - if value.startDate <= date { - before = value - } else { - after = value - break - } - } - - return (before, after) - } - - /// Returns all elements inmmediately adjacent to the specified date - /// - /// Use Sequence.elementsAdjacent(to:) if specific before/after references are necessary - /// - /// - Parameter date: The date to use in the search - /// - Returns: The closest elements, if found - func allElementsAdjacent(to date: Date) -> [Iterator.Element] { - let (before, after) = elementsAdjacent(to: date) - return [before, after].compactMap({ $0 }) - } - - /** - Returns an array of elements filtered by the specified date range. - - This behavior mimics HKQueryOptionNone, where the value must merely overlap the specified range, - not strictly exist inside of it. - - - parameter startDate: The earliest date of elements to return - - parameter endDate: The latest date of elements to return - - - returns: A new array of elements - */ - func filterDateRange(_ startDate: Date?, _ endDate: Date?) -> [Iterator.Element] { - return filter { (value) -> Bool in - if let startDate = startDate, value.endDate < startDate { - return false - } - - if let endDate = endDate, value.startDate > endDate { - return false - } - - return true - } - } -} - -public extension Sequence where Element: SampleValue { - func average(unit: HKUnit) -> HKQuantity? { - let (sum, count) = reduce(into: (sum: 0.0, count: 0)) { result, element in - result.0 += element.quantity.doubleValue(for: unit) - result.1 += 1 - } - - guard count > 0 else { - return nil - } - - let average = sum / Double(count) - - return HKQuantity(unit: unit, doubleValue: average) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/KeyChainManagerWrapper.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/KeyChainManagerWrapper.swift deleted file mode 100644 index e6fb7f16b..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/KeyChainManagerWrapper.swift +++ /dev/null @@ -1,258 +0,0 @@ -// -// KeyChainWrapper.swift -// LibreTransmitter -// -// Created by Bjørn Inge Berg on 11/07/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import Foundation -import Security - - -public enum KeychainManagerError: Error { - case add(OSStatus) - case copy(OSStatus) - case delete(OSStatus) - case unknownResult -} - - -/** - - Influenced by https://github.com/marketplacer/keychain-swift - */ -public struct KeychainManagerWrapper { - typealias Query = [String: NSObject] - - public init() { } - - var accessibility: CFString = kSecAttrAccessibleAfterFirstUnlock - - var accessGroup: String? - - static public var standard = KeychainManagerWrapper() - - public struct InternetCredentials: Equatable { - public let username: String - public let password: String - public let url: URL - - public init(username: String, password: String, url: URL) { - self.username = username - self.password = password - self.url = url - } - } - - // MARK: - Convenience methods - - private func query(by class: CFString) -> Query { - var query: Query = [kSecClass as String: `class`] - - if let accessGroup = accessGroup { - query[kSecAttrAccessGroup as String] = accessGroup as NSObject? - } - - return query - } - - - - - private func queryForInternetPassword(account: String? = nil, url: URL? = nil, label: String? = nil) -> Query { - var query = self.query(by: kSecClassInternetPassword) - - if let account = account { - query[kSecAttrAccount as String] = account as NSObject? - } - - if let url = url, let components = URLComponents(url: url, resolvingAgainstBaseURL: true) { - for (key, value) in components.keychainAttributes { - query[key] = value - } - } - - if let label = label { - query[kSecAttrLabel as String] = label as NSObject? - } - - return query - } - - private func updatedQuery(_ query: Query, withPassword password: Data) throws -> Query { - var query = query - - query[kSecValueData as String] = password as NSObject? - query[kSecAttrAccessible as String] = accessibility - - return query - } - - private func updatedQuery(_ query: Query, withPassword password: String) throws -> Query { - guard let value = password.data(using: String.Encoding.utf8) else { - throw KeychainManagerError.add(errSecDecode) - } - - return try updatedQuery(query, withPassword: value) - } - - func delete(_ query: Query) throws { - let statusCode = SecItemDelete(query as CFDictionary) - - guard statusCode == errSecSuccess || statusCode == errSecItemNotFound else { - throw KeychainManagerError.delete(statusCode) - } - } - - - - // MARK – Internet Passwords - - public func setInternetPassword(_ password: String, account: String, atURL url: URL, label: String? = nil) throws { - var query = try updatedQuery(queryForInternetPassword(account: account, url: url, label: label), withPassword: password) - - query[kSecAttrAccount as String] = account as NSObject? - - if let components = URLComponents(url: url, resolvingAgainstBaseURL: true) { - for (key, value) in components.keychainAttributes { - query[key] = value - } - } - - if let label = label { - query[kSecAttrLabel as String] = label as NSObject? - } - - let statusCode = SecItemAdd(query as CFDictionary, nil) - - guard statusCode == errSecSuccess else { - throw KeychainManagerError.add(statusCode) - } - } - - - public func replaceInternetCredentials(_ credentials: InternetCredentials?, forLabel label: String) throws { - let query = queryForInternetPassword(label: label) - - try delete(query) - - if let credentials = credentials { - try setInternetPassword(credentials.password, account: credentials.username, atURL: credentials.url, label: label) - } - } - - public func getInternetCredentials(account: String? = nil, url: URL? = nil, label: String? = nil) throws -> InternetCredentials { - var query = queryForInternetPassword(account: account, url: url, label: label) - - query[kSecReturnData as String] = kCFBooleanTrue - query[kSecReturnAttributes as String] = kCFBooleanTrue - query[kSecMatchLimit as String] = kSecMatchLimitOne - - var result: AnyObject? - - let statusCode: OSStatus = SecItemCopyMatching(query as CFDictionary, &result) - - guard statusCode == errSecSuccess else { - throw KeychainManagerError.copy(statusCode) - } - - if let result = result as? [AnyHashable: Any], let passwordData = result[kSecValueData as String] as? Data, - let password = String(data: passwordData, encoding: String.Encoding.utf8), - let url = URLComponents(keychainAttributes: result)?.url, - let username = result[kSecAttrAccount as String] as? String - { - return InternetCredentials(username: username, password: password, url: url) - } - - throw KeychainManagerError.unknownResult - } -} - - -private enum SecurityProtocol { - case http - case https - - init?(scheme: String?) { - switch scheme?.lowercased() { - case "http"?: - self = .http - case "https"?: - self = .https - default: - return nil - } - } - - init?(secAttrProtocol: CFString) { - if secAttrProtocol == kSecAttrProtocolHTTP { - self = .http - } else if secAttrProtocol == kSecAttrProtocolHTTPS { - self = .https - } else { - return nil - } - } - - var scheme: String { - switch self { - case .http: - return "http" - case .https: - return "https" - } - } - - var secAttrProtocol: CFString { - switch self { - case .http: - return kSecAttrProtocolHTTP - case .https: - return kSecAttrProtocolHTTPS - } - } -} - - -private extension URLComponents { - init?(keychainAttributes: [AnyHashable: Any]) { - self.init() - - if let secAttProtocol = keychainAttributes[kSecAttrProtocol as String] { - scheme = SecurityProtocol(secAttrProtocol: secAttProtocol as! CFString)?.scheme - } - - host = keychainAttributes[kSecAttrServer as String] as? String - - if let port = keychainAttributes[kSecAttrPort as String] as? Int, port > 0 { - self.port = port - } - - if let path = keychainAttributes[kSecAttrPath as String] as? String { - self.path = path - } - } - - var keychainAttributes: [String: NSObject] { - var query: [String: NSObject] = [:] - - if let `protocol` = SecurityProtocol(scheme: scheme) { - query[kSecAttrProtocol as String] = `protocol`.secAttrProtocol - } - - if let host = host { - query[kSecAttrServer as String] = host as NSObject - } - - if let port = port { - query[kSecAttrPort as String] = port as NSObject - } - - if !path.isEmpty { - query[kSecAttrPath as String] = path as NSObject - } - - return query - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/LogExport.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/LogExport.swift deleted file mode 100644 index ef352b50e..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/LogExport.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// LogExport.swift -// LibreTransmitter -// -// Created by Bjørn Inge Berg on 22/09/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import Foundation -import OSLog - - -@available(iOS 15, *) -fileprivate func getLogEntries() throws -> [OSLogEntryLog] { - // Open the log store. - let logStore = try OSLogStore(scope: .currentProcessIdentifier) - - // Get all the logs from the last hour. - let oneHourAgo = logStore.position(date: Date().addingTimeInterval(-3600)) - - // Fetch log objects. - let allEntries = try logStore.getEntries(at: oneHourAgo) - - // Filter the log to be relevant for our specific subsystem - // and remove other elements (signposts, etc). - return allEntries - .compactMap { $0 as? OSLogEntryLog } - //.filter { $0.subsystem == Features.logSubsystem } -} - -@available(iOS 15, *) -func getLogAsData() throws -> Data { - var data = Data() - let entries = try getLogEntries() - entries.forEach { log in - if let logstring = [log.date.ISO8601Format(), log.subsystem, log.category, "[["+log.composedMessage+"]]\r\n"] - .joined(separator: "||").data(using: .utf8, allowLossyConversion: false) { - data.append(logstring) - } - - } - return data -} - -func getLogs() throws -> Data { - var logs = Data() - if #available(iOS 15, *) { - logs = try getLogAsData() - } - return logs - -} - - -public extension Logger { - init(forType atype: Any, forSubSystem subsystem: String=Features.logSubsystem) { - self.init(subsystem: subsystem, category: String(describing: atype) ) - } - -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/UIApplication+metadata.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/UIApplication+metadata.swift deleted file mode 100644 index bbb3364f1..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/UIApplication+metadata.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// UIApplication+metadata.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 30/12/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import Foundation - -private let prefix = "no-bjorninge-mm" -enum AppMetaData { - static var allProperties: String { - Bundle.module.infoDictionary?.compactMap { - $0.key.starts(with: prefix) ? "\($0.key): \($0.value)" : nil - }.joined(separator: "\n") ?? "none" - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/UserDefaults+Alarmsettings.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/UserDefaults+Alarmsettings.swift deleted file mode 100644 index 122fbc774..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/UserDefaults+Alarmsettings.swift +++ /dev/null @@ -1,116 +0,0 @@ -// -// Userdefaults+Alarmsettings.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 20/04/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import Foundation -import HealthKit - -extension UserDefaults { - private enum Key: String { - case mmAlertLowBatteryWarning = "no.bjorninge.mmLowBatteryWarning" - case mmAlertInvalidSensorDetected = "no.bjorninge.mmInvalidSensorDetected" - case mmAlertNewSensorDetected = "no.bjorninge.mmNewSensorDetected" - case mmAlertNoSensorDetected = "no.bjorninge.mmNoSensorDetected" - case mmGlucoseUnit = "no.bjorninge.mmGlucoseUnit" - case mmAlertSensorSoonExpire = "no.bjorninge.mmAlertSensorSoonExpire" - case mmSnoozedUntil = "no.bjorninge.mmSnoozedUntil" - } - /* - case always - case lowBattery - case invalidSensorDetected - //case alarmNotifications - case newSensorDetected - case noSensorDetected - case unit - */ - public func optionalBool(forKey defaultName: String) -> Bool? { - if let value = value(forKey: defaultName) { - return value as? Bool - } - return nil - } - - var mmAlertLowBatteryWarning: Bool { - get { - optionalBool(forKey: Key.mmAlertLowBatteryWarning.rawValue) ?? true - } - set { - set(newValue, forKey: Key.mmAlertLowBatteryWarning.rawValue) - } - } - var mmAlertInvalidSensorDetected: Bool { - get { - optionalBool(forKey: Key.mmAlertInvalidSensorDetected.rawValue) ?? true - } - set { - set(newValue, forKey: Key.mmAlertInvalidSensorDetected.rawValue) - } - } - - var mmAlertNewSensorDetected: Bool { - get { - optionalBool(forKey: Key.mmAlertNewSensorDetected.rawValue) ?? true - } - set { - set(newValue, forKey: Key.mmAlertNewSensorDetected.rawValue) - } - } - - var mmAlertNoSensorDetected: Bool { - get { - optionalBool(forKey: Key.mmAlertNoSensorDetected.rawValue) ?? true - } - set { - set(newValue, forKey: Key.mmAlertNoSensorDetected.rawValue) - } - } - - var mmAlertWillSoonExpire: Bool { - get { - optionalBool(forKey: Key.mmAlertSensorSoonExpire.rawValue) ?? true - } - set { - set(newValue, forKey: Key.mmAlertSensorSoonExpire.rawValue) - } - } - - var allNotificationToggles: [Bool] { - [mmAlertLowBatteryWarning, mmAlertInvalidSensorDetected, mmAlertNewSensorDetected, mmAlertNoSensorDetected, mmAlertWillSoonExpire] - } - - //intentionally only supports mgdl and mmol - var mmGlucoseUnit: HKUnit? { - get { - if let textUnit = string(forKey: Key.mmGlucoseUnit.rawValue) { - if textUnit == "mmol" { - return HKUnit.millimolesPerLiter - } else if textUnit == "mgdl" { - return HKUnit.milligramsPerDeciliter - } - } - - return nil - } - set { - if newValue == HKUnit.milligramsPerDeciliter { - set("mgdl", forKey: Key.mmGlucoseUnit.rawValue) - } else if newValue == HKUnit.millimolesPerLiter { - set("mmol", forKey: Key.mmGlucoseUnit.rawValue) - } - } - } - - var snoozedUntil: Date? { - get { - object(forKey: Key.mmSnoozedUntil.rawValue) as? Date - } - set { - set(newValue, forKey: Key.mmSnoozedUntil.rawValue) - } - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/UserDefaults+Bluetooth.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/UserDefaults+Bluetooth.swift deleted file mode 100644 index a69caac54..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/UserDefaults+Bluetooth.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// UserDefaults+Bluetooth.swift -// MiaomiaoClientUI -// -// Created by Bjørn Inge Berg on 27/07/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import Foundation -//import MiaomiaoClient - -extension UserDefaults { - private enum Key: String { - case bluetoothDeviceUUIDString = "no.bjorninge.bluetoothDeviceUUIDString" - case libre2UiD = "no.bjorninge.libre2uid" - } - - public var preSelectedUid: Data? { - get { - return data(forKey: Key.libre2UiD.rawValue) - - } - set { - if let newValue = newValue { - set(newValue, forKey: Key.libre2UiD.rawValue) - } else { - print("Removing preSelectedUid") - removeObject(forKey: Key.libre2UiD.rawValue) - } - } - } - - public var preSelectedDevice: String? { - get { - if let astr = string(forKey: Key.bluetoothDeviceUUIDString.rawValue) { - return astr.count > 0 ? astr : nil - } - return nil - } - set { - if let newValue = newValue { - set(newValue, forKey: Key.bluetoothDeviceUUIDString.rawValue) - } else { - removeObject(forKey: Key.bluetoothDeviceUUIDString.rawValue) - } - } - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/UserDefaults+GlucoseSettings.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/UserDefaults+GlucoseSettings.swift deleted file mode 100644 index c50d87c5a..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/UserDefaults+GlucoseSettings.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// Userdefaults+Alarmsettings.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 20/04/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import Foundation -import HealthKit - -extension UserDefaults { - private enum Key: String { - case mmBackfillFromHistory = "no.bjorninge.mmBackfillFromHistory" - case mmBackfillFromTrend = "no.bjorninge.mmBackfillFromTrend" - } - - var mmBackfillFromHistory: Bool { - get { - optionalBool(forKey: Key.mmBackfillFromHistory.rawValue) ?? true - } - set { - set(newValue, forKey: Key.mmBackfillFromHistory.rawValue) - } - } - - var mmBackfillFromTrend: Bool { - get { - optionalBool(forKey: Key.mmBackfillFromTrend.rawValue) ?? false - } - set { - set(newValue, forKey: Key.mmBackfillFromTrend.rawValue) - } - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/UnfairLock.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/UnfairLock.swift deleted file mode 100644 index 974192055..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/UnfairLock.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// UnfairLock.swift -// LoopKit Example -// -// Created by Pete Schwamb on 3/22/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -// Source: http://www.russbishop.net/the-law - -import Foundation - -public class UnfairLock { - private var _lock: UnsafeMutablePointer - - public init() { - _lock = UnsafeMutablePointer.allocate(capacity: 1) - _lock.initialize(to: os_unfair_lock()) - } - - deinit { - _lock.deallocate() - } - - public func withLock(_ f: () throws -> ReturnValue) rethrows -> ReturnValue { - os_unfair_lock_lock(_lock) - defer { os_unfair_lock_unlock(_lock) } - return try f() - } - - public func assertOwned() { - os_unfair_lock_assert_owner(_lock) - } - - public func assertNotOwned() { - os_unfair_lock_assert_not_owner(_lock) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/WeakSynchronizedDelegate.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/WeakSynchronizedDelegate.swift deleted file mode 100644 index a67264995..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/WeakSynchronizedDelegate.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// WeakSynchronizedDelegate.swift -// LoopKit -// -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - -public class WeakSynchronizedDelegate { - - private let lock = UnfairLock() - private weak var _delegate: AnyObject? - private var _queue: DispatchQueue - - public init(queue: DispatchQueue = .main) { - _queue = queue - } - - public var delegate: Delegate? { - get { - return lock.withLock { - return _delegate as? Delegate - } - } - set { - lock.withLock { - _delegate = newValue as AnyObject - } - } - } - - public var queue: DispatchQueue! { - get { - return lock.withLock { - return _queue - } - } - set { - lock.withLock { - _queue = newValue ?? .main - } - } - } - - public func notify(_ block: @escaping (_ delegate: Delegate?) -> Void) { - var delegate: Delegate? - var queue: DispatchQueue! - - lock.withLock { - delegate = _delegate as? Delegate - queue = _queue - } - - queue.async { - block(delegate) - } - } - - public func notifyDelayed(by interval: TimeInterval, _ block: @escaping (_ delegate: Delegate?) -> Void) { - var delegate: Delegate? - var queue: DispatchQueue! - - lock.withLock { - delegate = _delegate as? Delegate - queue = _queue - } - - queue.asyncAfter(deadline: .now() + interval) { - block(delegate) - } - } - - public func call(_ block: (_ delegate: Delegate?) -> ReturnType) -> ReturnType { - return lock.withLock { () -> ReturnType in - var result: ReturnType! - _queue.sync { - result = block(_delegate as? Delegate) - } - return result - } - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/CompletionNotifying.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/CompletionNotifying.swift deleted file mode 100644 index 39fa06e1d..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/CompletionNotifying.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// CompletionNotifying.swift -// LoopKitUI -// -// Created by Pete Schwamb on 1/29/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - -public protocol CompletionDelegate: AnyObject { - func completionNotifyingDidComplete(_ object: CompletionNotifying) -} - -public protocol CompletionNotifying { - var completionDelegate: CompletionDelegate? { set get } -} - diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/ConcreteGlucoseDisplayable.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/ConcreteGlucoseDisplayable.swift deleted file mode 100644 index fa182f6eb..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/ConcreteGlucoseDisplayable.swift +++ /dev/null @@ -1,146 +0,0 @@ -// -// ConcreteSensorDisplayable.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 04/11/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import Foundation -import HealthKit - -public struct ConcreteGlucoseDisplayable: GlucoseDisplayable { - public var glucoseRangeCategory: GlucoseRangeCategory? - - public var isStateValid: Bool - - public var trendType: GlucoseTrend? - - public var isLocal: Bool - - public var batteries : [(name: String, percentage: Int)]? -} - -public enum GlucoseRangeCategory: Int, CaseIterable { - case belowRange - case urgentLow - case low - case normal - case high - case aboveRange -} - -public enum GlucoseTrend: Int, CaseIterable { - case upUpUp = 1 - case upUp = 2 - case up = 3 - case flat = 4 - case down = 5 - case downDown = 6 - case downDownDown = 7 - - public var symbol: String { - switch self { - case .upUpUp: - return "⇈" - case .upUp: - return "↑" - case .up: - return "↗︎" - case .flat: - return "→" - case .down: - return "↘︎" - case .downDown: - return "↓" - case .downDownDown: - return "⇊" - } - } - - public var arrows: String { - switch self { - case .upUpUp: - return "↑↑" - case .upUp: - return "↑" - case .up: - return "↗︎" - case .flat: - return "→" - case .down: - return "↘︎" - case .downDown: - return "↓" - case .downDownDown: - return "↓↓" - } - } - - public var localizedDescription: String { - switch self { - case .upUpUp: - return LocalizedString("Rising very fast", comment: "Glucose trend up-up-up") - case .upUp: - return LocalizedString("Rising fast", comment: "Glucose trend up-up") - case .up: - return LocalizedString("Rising", comment: "Glucose trend up") - case .flat: - return LocalizedString("Flat", comment: "Glucose trend flat") - case .down: - return LocalizedString("Falling", comment: "Glucose trend down") - case .downDown: - return LocalizedString("Falling fast", comment: "Glucose trend down-down") - case .downDownDown: - return LocalizedString("Falling very fast", comment: "Glucose trend down-down-down") - } - } - - public var direction: String { - switch self { - case .upUpUp: - return "DoubleUp" - case .upUp: - return "SingleUp" - case .up: - return "FortyFiveUp" - case .flat: - return "Flat" - case .down: - return "FortyFiveDown" - case .downDown: - return "SingleDown" - case .downDownDown: - return "DoubleDown" - } - } - -} - -public protocol GlucoseDisplayable { - /// Returns whether the current state is valid - var isStateValid: Bool { get } - - /// Describes the state of the sensor in the current localization - var stateDescription: String { get } - - /// Enumerates the trend of the sensor values - var trendType: GlucoseTrend? { get } - - /// Returns whether the data is from a locally-connected device - var isLocal: Bool { get } - - /// enumerates the glucose value type (e.g., normal, low, high) - var glucoseRangeCategory: GlucoseRangeCategory? { get } -} - - -extension GlucoseDisplayable { - public var stateDescription: String { - if isStateValid { - return LocalizedString("OK", comment: "Sensor state description for the valid state") - } else { - return LocalizedString("Needs Attention", comment: "Sensor state description for the non-valid state") - } - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/DeviceLogEntryType.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/DeviceLogEntryType.swift deleted file mode 100644 index 04d6b0ab8..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/DeviceLogEntryType.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// DeviceLogEntryType.swift -// LoopKit -// -// Created by Pete Schwamb on 1/13/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum DeviceLogEntryType: String { - /// Log entry related to data or commands sent to the device. - case send - /// Log entry related to data or events received from the device. - case receive - /// Log entry related to any errors from the device's SDK or the device itself. - case error - /// Log entry related to a delegate call from the device's SDK (for example, acknowledgement of receiving a command). - case delegate - /// Log entry related to a response from a delegate call (for example, acknowledgement of executing a command). - case delegateResponse - /// Log entry related to any device connection activities (e.g. scanning, connecting, disconnecting, reconnecting, etc.). - case connection -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Features.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Features.swift deleted file mode 100644 index 9ec409e30..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Features.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// Features.swift -// LibreTransmitter -// -// Created by Bjørn Inge Berg on 30/08/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import Foundation - -#if canImport(CoreNFC) -import CoreNFC -#endif - -public final class Features{ - - static public var logSubsystem = "no.bjorninge.libre" - - static var phoneNFCAvailable: Bool { - #if canImport(CoreNFC) - if NSClassFromString("NFCNDEFReaderSession") == nil { - return false - - } - - return NFCNDEFReaderSession.readingAvailable - #else - return false - #endif - } - - static var supportsLogExport: Bool { - if #available(iOS 15, *) { - return true - } - return false - } - - - - -} - diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreGlucose.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreGlucose.swift deleted file mode 100644 index ce04e40e0..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreGlucose.swift +++ /dev/null @@ -1,229 +0,0 @@ -// -// MiaomiaoClient.h -// MiaomiaoClient -// - -import Foundation -import HealthKit -import os.log - - -fileprivate var logger = Logger(forType: "LibreGlucose") - - -public struct LibreGlucose { - public let unsmoothedGlucose: Double - public var glucoseDouble: Double - public var error = [MeasurementError.OK] - public var glucose: UInt16 { - UInt16(glucoseDouble.rounded()) - } - //trend is deprecated here, it should only be calculated once in latestbackfill - //public var trend: UInt8 - public var timestamp: Date - //public let collector: String? - - public var sensorStartDate: Date? = nil - - public static func timeDifference(oldGlucose: LibreGlucose, newGlucose: LibreGlucose) -> TimeInterval { - newGlucose.startDate.timeIntervalSince(oldGlucose.startDate) - } - - public var syncId: String { - "\(Int(self.startDate.timeIntervalSince1970))\(self.unsmoothedGlucose)" - } - - public var isStateValid: Bool { - // We know that the official libre algorithm doesn't produce values - // below 39. However, both the raw sensor contents and the derived algorithm - // supports values down to 0 without issues. A bit uncertain if nightscout and loop will work with values below 1, so we restrict this to 1 - glucose >= 1 - } - - public func GetGlucoseTrend(last: Self) -> GlucoseTrend { - Self.GetGlucoseTrend(current: self, last: last) - } -} - -extension LibreGlucose: GlucoseValue { - public var startDate: Date { - timestamp - } - - public var quantity: HKQuantity { - .init(unit: .milligramsPerDeciliter, doubleValue: glucoseDouble) - } -} - -extension LibreGlucose { - public var description: String { - guard let glucoseUnit = UserDefaults.standard.mmGlucoseUnit, let formatter = LibreGlucose.dynamicFormatter, let formatted = formatter.string(from: self.quantity, for: glucoseUnit) else { - logger.debug("dabear:: glucose unit was not recognized, aborting") - return "Unknown" - } - - return formatted - } - private static var glucoseFormatterMgdl: QuantityFormatter = { - let formatter = QuantityFormatter() - formatter.setPreferredNumberFormatter(for: HKUnit.milligramsPerDeciliter) - return formatter - }() - - private static var glucoseFormatterMmol: QuantityFormatter = { - let formatter = QuantityFormatter() - formatter.setPreferredNumberFormatter(for: HKUnit.millimolesPerLiter) - return formatter - }() - - public static var dynamicFormatter: QuantityFormatter? { - guard let glucoseUnit = UserDefaults.standard.mmGlucoseUnit else { - logger.debug("dabear:: glucose unit was not recognized, aborting") - return nil - } - - return (glucoseUnit == HKUnit.milligramsPerDeciliter ? glucoseFormatterMgdl : glucoseFormatterMmol) - } - - public static func glucoseDiffDesc(oldValue: Self, newValue: Self) -> String { - guard let glucoseUnit = UserDefaults.standard.mmGlucoseUnit else { - logger.debug("dabear:: glucose unit was not recognized, aborting") - return "Unknown" - } - - var stringValue = [String]() - - var diff = newValue.glucoseDouble - oldValue.glucoseDouble - let sign = diff < 0 ? "-" : "+" - - if diff == 0 { - stringValue.append( "\(sign) 0") - } else { - diff = abs(diff) - let asObj = LibreGlucose( - unsmoothedGlucose: diff, - glucoseDouble: diff, - timestamp: Date()) - if let formatted = dynamicFormatter?.string(from: asObj.quantity, for: glucoseUnit) { - stringValue.append( "\(sign) \(formatted)") - } - } - - return stringValue.joined(separator: ",") - } -} - -extension LibreGlucose { - static func calculateSlope(current: Self, last: Self) -> Double { - if current.timestamp == last.timestamp { - return 0.0 - } - - let _curr = Double(current.timestamp.timeIntervalSince1970 * 1_000) - let _last = Double(last.timestamp.timeIntervalSince1970 * 1_000) - - return (Double(last.unsmoothedGlucose) - Double(current.unsmoothedGlucose)) / (_last - _curr) - } - - static func calculateSlopeByMinute(current: Self, last: Self) -> Double { - return calculateSlope(current: current, last: last) * 60_000 - } - - static func GetGlucoseTrend(current: Self?, last: Self?) -> GlucoseTrend { - - guard let current = current, let last = last else { - return .flat - } - - let s = calculateSlopeByMinute(current: current, last: last) - - - switch s { - case _ where s <= (-3.5): - return .downDownDown - case _ where s <= (-2): - return .downDown - case _ where s <= (-1): - return .down - case _ where s <= (1): - return .flat - case _ where s <= (2): - return .up - case _ where s <= (3.5): - return .upUp - case _ where s <= (40): - return .flat //flat is the new (tm) "unknown"! - - default: - - return .flat - } - } -} - -extension LibreGlucose { - static func fromHistoryMeasurements(_ measurements: [Measurement], nativeCalibrationData: SensorData.CalibrationInfo) -> [LibreGlucose] { - var arr = [LibreGlucose]() - - for historical in measurements { - let glucose = LibreGlucose( - //unsmoothedGlucose: historical.temperatureAlgorithmGlucose, - //glucoseDouble: historical.temperatureAlgorithmGlucose, - unsmoothedGlucose: historical.roundedGlucoseValueFromRaw2(calibrationInfo: nativeCalibrationData), - glucoseDouble: historical.roundedGlucoseValueFromRaw2(calibrationInfo: nativeCalibrationData), - error: historical.error, - timestamp: historical.date) - - if glucose.glucoseDouble > 0 { - arr.append(glucose) - } - } - - return arr - } - - static func fromTrendMeasurements(_ measurements: [Measurement], nativeCalibrationData: SensorData.CalibrationInfo, returnAll: Bool, - sensorStartDate: Date? = nil) -> [LibreGlucose] { - var arr = [LibreGlucose]() - - var shouldSmoothGlucose = true - for trend in measurements { - // trend arrows on each libreglucose value is not needed - // instead we calculate it once when latestbackfill is set, which in turn sets - // the sensordisplayable property - let glucose = LibreGlucose( - //unsmoothedGlucose: trend.temperatureAlgorithmGlucose, - unsmoothedGlucose: trend.roundedGlucoseValueFromRaw2(calibrationInfo: nativeCalibrationData), - glucoseDouble: 0.0, - error: trend.error, - timestamp: trend.date, - sensorStartDate: sensorStartDate) - // if sensor is ripped off body while transmitter is attached, values below 1 might be created - - if glucose.unsmoothedGlucose > 0 && glucose.unsmoothedGlucose <= 500 { - arr.append(glucose) - } - - // Just for expliciticity, if one of the values are 0, - // then the rest of the values should not be smoothed - if glucose.unsmoothedGlucose <= 0 { - shouldSmoothGlucose = false - } - } - - - if shouldSmoothGlucose { - arr = CalculateSmothedData5Points(origtrends: arr) - } else { - for i in 0 ..< arr.count { - arr[i].glucoseDouble = arr[i].unsmoothedGlucose - } - } - - if !returnAll, let first = arr.first { - return [first] - } - - return arr - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/Calibration.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/Calibration.swift deleted file mode 100644 index 94a764420..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/Calibration.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// Calibration.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 05/03/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import Foundation -import os.log - -private let LibreCalibrationLabel = "https://LibreCalibrationLabelNative.doesnot.exist.com" -private let LibreCalibrationUrl = URL(string: LibreCalibrationLabel)! -private let LibreUsername = "LibreUsername" - -fileprivate var logger = Logger(forType: "KeychainManagerCalibration") - -public extension KeychainManagerWrapper { - func setLibreNativeCalibrationData(_ calibrationData: SensorData.CalibrationInfo?) throws { - var credentials: InternetCredentials? = nil - if let calibrationData = calibrationData { - credentials = InternetCredentials(username: LibreUsername, password: serializeNativeAlgorithmParameters(calibrationData), url: LibreCalibrationUrl) - } - logger.debug("dabear: Setting calibrationdata to \(String(describing: calibrationData))") - try replaceInternetCredentials(credentials, forLabel: LibreCalibrationLabel) - } - - func getLibreNativeCalibrationData() -> SensorData.CalibrationInfo? { - do { // Silence all errors and return nil - let credentials = try getInternetCredentials(label: LibreCalibrationLabel) - return deserializeNativeAlgorithmParameters(text: credentials.password) - } catch { - - return nil - } - } -} - -public func calibrateSensor(sensordata: SensorData, callback: @escaping (SensorData.CalibrationInfo) -> Void) { - - let params = sensordata.calibrationData - callback(params) -} - -private func serializeNativeAlgorithmParameters(_ params: SensorData.CalibrationInfo) -> String { - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - - var aString = "" - do { - let jsonData = try encoder.encode(params) - - if let jsonString = String(data: jsonData, encoding: .utf8) { - aString = jsonString - } - } catch { - logger.debug("Could not serialize parameters: \(error.localizedDescription)") - } - return aString -} - -private func deserializeNativeAlgorithmParameters(text: String) -> SensorData.CalibrationInfo? { - if let jsonData = text.data(using: .utf8) { - let decoder = JSONDecoder() - - do { - return try decoder.decode(SensorData.CalibrationInfo.self, from: jsonData) - } catch { - logger.debug("Could not create instance: \(error.localizedDescription)") - } - } else { - logger.debug("Did not create instance") - } - return nil -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/GlucoseAlgorithm/GlucoseFromRaw.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/GlucoseAlgorithm/GlucoseFromRaw.swift deleted file mode 100644 index ccaefc891..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/GlucoseAlgorithm/GlucoseFromRaw.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// GlucoseFromRaw.swift -// - -import Foundation -import RawGlucose - -extension MeasurementProtocol { - func roundedGlucoseValueFromRaw(calibrationInfo: SensorData.CalibrationInfo) -> Int { - Int(round(glucoseValueFromRaw(calibrationInfo: calibrationInfo))) - } - - func roundedGlucoseValueFromRaw2(calibrationInfo: SensorData.CalibrationInfo) -> Double{ - round(glucoseValueFromRaw(calibrationInfo: calibrationInfo)) - } - - - func glucoseValueFromRaw(calibrationInfo: SensorData.CalibrationInfo) -> Double { - RawGlucose.glucoseValueFromRaw( - rawTemperature: Double(self.rawTemperature), - rawTemperatureAdjustment: Double(self.rawTemperatureAdjustment), - rawGlucose: Double(self.rawGlucose), - i1: calibrationInfo.i1, - i2: calibrationInfo.i2, - i3: calibrationInfo.i3, - i4: calibrationInfo.i4, - i5: calibrationInfo.i5, - i6: calibrationInfo.i6 - ) - } -} - diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/GlucoseAlgorithm/GlucoseSmoothing.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/GlucoseAlgorithm/GlucoseSmoothing.swift deleted file mode 100644 index d5561f460..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/GlucoseAlgorithm/GlucoseSmoothing.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// GlucoseSmoothing.swift -// MiaomiaoClientUI -// -// Created by Bjørn Inge Berg on 25/03/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import Foundation - -//https://github.com/NightscoutFoundation/xDrip/pull/828/files - -//private func trendToLibreGlucose(_ measurements: [Measurement]) -> [LibreGlucose]?{ - -func CalculateSmothedData5Points(origtrends: [LibreGlucose]) -> [LibreGlucose] { - // In all places in the code, there should be exactly 16 points. - // Since that might change, and I'm doing an average of 5, then in the case of less then 5 points, - // I'll only copy the data as is (to make sure there are reasonable values when the function returns). - - var trends = origtrends - //this is an adoptation, doesn't follow the original directly - if trends.count < 5 { - for i in 0 ..< trends.count { - trends[i].glucoseDouble = trends[i].unsmoothedGlucose - } - - return trends - } - for i in 0 ..< trends.count - 4 { - trends[i].glucoseDouble = (trends[i].unsmoothedGlucose + trends[i + 1].unsmoothedGlucose + trends[i + 2].unsmoothedGlucose + trends[i + 3].unsmoothedGlucose + trends[i + 4].unsmoothedGlucose) / 5 - } - trends[trends.count - 4].glucoseDouble = (trends[trends.count - 4].unsmoothedGlucose + trends[trends.count - 3].unsmoothedGlucose + trends[trends.count - 2].unsmoothedGlucose + trends[trends.count - 1].unsmoothedGlucose) / 4 - trends[trends.count - 3].glucoseDouble = (trends[trends.count - 3].unsmoothedGlucose + trends[trends.count - 2].unsmoothedGlucose + trends[trends.count - 1].unsmoothedGlucose ) / 3 - - trends[trends.count - 2].glucoseDouble = (trends[trends.count - 2].unsmoothedGlucose + trends[trends.count - 1].unsmoothedGlucose ) / 2 - - trends[trends.count - 1].glucoseDouble = trends[trends.count - 2].glucoseDouble - - return trends -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/LibreError.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/LibreError.swift deleted file mode 100644 index e42dc5dcf..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/LibreError.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// LibreError.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 05/03/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// - -import Foundation - -public enum LibreError: Error { - case noSensorData - case noCalibrationData - case invalidCalibrationData - case checksumValidationError - case expiredSensor - case invalidAutoCalibrationCredentials - case encryptedSensor - case noValidSensorData - - public var errorDescription: String { - switch self { - case .noSensorData: - return "No sensor data present" - case .noValidSensorData: - return "No valid sensor data present, but sensor is running. Maybe due to sensor being off-body?" - - case .noCalibrationData: - return "No calibration data present" - case .invalidCalibrationData: - return "invalid calibration data detected" - case .checksumValidationError: - return "Checksum Validation Error " - case .expiredSensor: - return "Sensor has expired" - case .invalidAutoCalibrationCredentials: - return "Invalid Auto Calibration Credentials" - case .encryptedSensor: - return "Encrypted or unsupported libre sensor detected." - } - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/LimitedQueue.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/LimitedQueue.swift deleted file mode 100644 index 81d9bfed4..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/LimitedQueue.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// LimitedQueue.swift -// MiaomiaoClient -// -// Created by Bjørn Inge Berg on 03/03/2020. -// Copyright © 2020 Bjørn Inge Vikhammermo Berg. All rights reserved. -// - -import Foundation - -public struct LimitedQueue: Codable { - public var array = [T]() - var limit: Int = 10 - - mutating func enqueue(_ element: T) { - while array.count >= limit { - array.removeFirst() - } - array.append(element) - } - - mutating func dequeue() -> T? { - array.isEmpty ? nil : array.removeFirst() - } -} -extension UserDefaults { - private enum Key: String { - case queuedSensorData = "no.bjorninge.queuedSensorData" - case shouldPersistSensorData = "no.bjorninge.shouldPersistSensorData" - } - - var shouldPersistSensorData: Bool { - get { - optionalBool(forKey: Key.shouldPersistSensorData.rawValue) ?? false - } - set { - set(newValue, forKey: Key.shouldPersistSensorData.rawValue) - } - } - - public var queuedSensorData: LimitedQueue? { - get { - guard let data = object(forKey: Key.queuedSensorData.rawValue) as? Data else { - return nil - } - - let decoder = JSONDecoder() - guard let q = try? decoder.decode(LimitedQueue.self, from: data) else { - return nil - } - - return q - } - set { - let encoder = JSONEncoder() - if let val = newValue, let encoded = try? encoder.encode(val) { - set(encoded, forKey: Key.queuedSensorData.rawValue) - } else { - removeObject(forKey: Key.queuedSensorData.rawValue) - } - } - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/CRC.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/CRC.swift deleted file mode 100644 index a9af4facf..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/CRC.swift +++ /dev/null @@ -1,105 +0,0 @@ -// -// CRC.swift -// LibreMonitor -// -// Created by Uwe Petersen on 26.07.16. -// Copyright © 2016 Uwe Petersen. All rights reserved. -// -// -// Part of this code is taken from -// CRC.swift -// CryptoSwift -// -// Created by Marcin Krzyzanowski on 25/08/14. -// Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved. -// - -import Foundation - -final class Crc { - /// Table of precalculated crc16 values - static let crc16table: [UInt16] = [0, 4_489, 8_978, 12_955, 17_956, 22_445, 25_910, 29_887, 35_912, 40_385, 44_890, 48_851, 51_820, 56_293, 59_774, 63_735, 4_225, 264, 13_203, 8_730, 22_181, 18_220, 30_135, 25_662, 40_137, 36_160, 49_115, 44_626, 56_045, 52_068, 63_999, 59_510, 8_450, 12_427, 528, 5_017, 26_406, 30_383, 17_460, 21_949, 44_362, 48_323, 36_440, 40_913, 60_270, 64_231, 51_324, 55_797, 12_675, 8_202, 4_753, 792, 30_631, 26_158, 21_685, 17_724, 48_587, 44_098, 40_665, 36_688, 64_495, 60_006, 55_549, 51_572, 16_900, 21_389, 24_854, 28_831, 1_056, 5_545, 10_034, 14_011, 52_812, 57_285, 60_766, 64_727, 34_920, 39_393, 43_898, 47_859, 21_125, 17_164, 29_079, 24_606, 5_281, 1_320, 14_259, 9_786, 57_037, 53_060, 64_991, 60_502, 39_145, 35_168, 48_123, 43_634, 25_350, 29_327, 16_404, 20_893, 9_506, 13_483, 1_584, 6_073, 61_262, 65_223, 52_316, 56_789, 43_370, 47_331, 35_448, 39_921, 29_575, 25_102, 20_629, 16_668, 13_731, 9_258, 5_809, 1_848, 65_487, 60_998, 56_541, 52_564, 47_595, 43_106, 39_673, 35_696, 33_800, 38_273, 42_778, 46_739, 49_708, 54_181, 57_662, 61_623, 2_112, 6_601, 11_090, 15_067, 20_068, 24_557, 28_022, 31_999, 38_025, 34_048, 47_003, 42_514, 53_933, 49_956, 61_887, 57_398, 6_337, 2_376, 15_315, 10_842, 24_293, 20_332, 32_247, 27_774, 42_250, 46_211, 34_328, 38_801, 58_158, 62_119, 49_212, 53_685, 10_562, 14_539, 2_640, 7_129, 28_518, 32_495, 19_572, 24_061, 46_475, 41_986, 38_553, 34_576, 62_383, 57_894, 53_437, 49_460, 14_787, 10_314, 6_865, 2_904, 32_743, 28_270, 23_797, 19_836, 50_700, 55_173, 58_654, 62_615, 32_808, 37_281, 41_786, 45_747, 19_012, 23_501, 26_966, 30_943, 3_168, 7_657, 12_146, 16_123, 54_925, 50_948, 62_879, 58_390, 37_033, 33_056, 46_011, 41_522, 23_237, 19_276, 31_191, 26_718, 7_393, 3_432, 16_371, 11_898, 59_150, 63_111, 50_204, 54_677, 41_258, 45_219, 33_336, 37_809, 27_462, 31_439, 18_516, 23_005, 11_618, 15_595, 3_696, 8_185, 63_375, 58_886, 54_429, 50_452, 45_483, 40_994, 37_561, 33_584, 31_687, 27_214, 22_741, 18_780, 15_843, 11_370, 7_921, 3_960] - - /// Calculates crc16. Taken from https://github.com/krzyzanowskim/CryptoSwift with modifications (reversing and byte swapping) to adjust for crc as used by Freestyle Libre - /// - /// - parameter message: Array of bytes for which the crc is to be calculated - /// - parameter seed: seed for crc - /// - /// - returns: crc16 - static func crc16(_ message: [UInt8], seed: UInt16? = nil) -> UInt16 { - var crc: UInt16 = seed != nil ? seed! : 0x0000 - - // calculate crc - for chunk in BytesSequence(chunkSize: 256, data: message) { - for b in chunk { - crc = (crc >> 8) ^ crc16table[Int((crc ^ UInt16(b)) & 0xFF)] - } - } - - // reverse the bits (modification by Uwe Petersen, 2016-06-05) - var reverseCrc = UInt16(0) - for _ in 0..<16 { - reverseCrc = reverseCrc << 1 | crc & 1 - crc >>= 1 - } - - // swap bytes and return (modification by Uwe Petersen, 2016-06-05) - return reverseCrc.byteSwapped - } - - /// Checks crc for an array of bytes. - /// - /// Assumes that the first two bytes are the crc16 of the bytes array and compares the corresponding value with the crc16 calculated over the rest of the array of bytes. - /// - /// - parameter bytes: Array of bytes with a crc in the first two bytes - /// - /// - returns: true if crc is valid - static func hasValidCrc16InFirstTwoBytes(_ bytes: [UInt8]) -> Bool { -// print(Array(bytes.dropFirst(2))) - let calculatedCrc = Crc.crc16(Array(bytes.dropFirst(2)), seed: 0xffff) - let enclosedCrc = (UInt16(bytes[0]) << 8) | UInt16(bytes[1]) - -// print(String(format: "Calculated crc is %X and enclosed crc is %x", arguments: [calculatedCrc, enclosedCrc])) - - return calculatedCrc == enclosedCrc - } - - static func hasValidCrc16InLastTwoBytes(_ bytes: [UInt8]) -> Bool { - let calculatedCrc = Crc.crc16(Array(bytes.dropLast(2)), seed: 0xffff) - let enclosedCrc = (UInt16(Array(bytes.suffix(2))[0]) << 8) | UInt16(Array(bytes.suffix(2))[1]) - - return calculatedCrc == enclosedCrc - } - - /// Returns a byte array with correct crc in first two bytes (calculated over the remaining bytes). - /// - /// In case some bytes of the original byte array are tweaked, the original crc does not match the remainaing bytes any more. This function calculates the correct crc of the bytes from byte #0x02 to the end and replaces the first two bytes with the correct crc. - /// - /// - Parameter bytes: byte array - /// - Returns: byte array with correct crc in first two bytes - static func bytesWithCorrectCRC(_ bytes: [UInt8]) -> [UInt8] { - let calculatedCrc = Crc.crc16(Array(bytes.dropFirst(2)), seed: 0xffff) - - var correctedBytes = bytes - correctedBytes[0] = UInt8(calculatedCrc >> 8) - correctedBytes[1] = UInt8(calculatedCrc & 0x00FF) - return correctedBytes - } -} - -/// Struct BytesSequence, taken from https://github.com/krzyzanowskim/CryptoSwift -struct BytesSequence: Sequence { - let chunkSize: Int - let data: [UInt8] - - func makeIterator() -> AnyIterator> { - var offset: Int = 0 - - return AnyIterator { - let end = Swift.min(self.chunkSize, self.data.count - offset) - let result = self.data[offset.. [MeasurementError]{ - errBitField == 0 ? - [MeasurementError.OK] : - MeasurementError.allErrorCodes.filter { (errBitField & $0.rawValue) != 0} - - } - - - var description: String { - String(" date: \(date), rawGlucose: \(rawGlucose), rawTemperature: \(rawTemperature), bytes: \(bytes) \n") - - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/PreLibre2.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/PreLibre2.swift deleted file mode 100644 index 9ae09b6d8..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/PreLibre2.swift +++ /dev/null @@ -1,785 +0,0 @@ -import Foundation - -public enum Libre2 { - /// Decrypts 43 blocks of Libre 2 FRAM - /// - Parameters: - /// - type: Suppurted sensor type (.libre2, .libreUS14day) - /// - id: ID/Serial of the sensor. Could be retrieved from NFC as uid. - /// - info: Sensor info. Retrieved by sending command '0xa1' via NFC. - /// - data: Encrypted FRAM data - /// - Returns: Decrypted FRAM data - static public func decryptFRAM(type: SensorType, id: [UInt8], info: [UInt8], data: [UInt8]) throws -> [UInt8] { - guard type == .libre2 || type == .libre2C5 || type == .libreUS14day || type == .libreUS14dayE6 else { - struct DecryptFRAMError: Error { - let errorDescription = "Unsupported sensor type" - } - throw DecryptFRAMError() - } - - func getArg(block: Int) -> UInt16 { - switch type { - case .libreUS14day, .libreUS14dayE6: - if block < 3 || block >= 40 { - // For header and footer it is a fixed value. - return 0xcadc - } - return UInt16(info[5], info[4]) - case .libre2, .libre2C5: - return UInt16(info[5], info[4]) ^ 0x44 - default: fatalError("Unsupported sensor type") - } - } - - var result = [UInt8]() - - for i in 0 ..< 43 { - let input = prepareVariables(id: id, x: UInt16(i), y: getArg(block: i)) - let blockKey = processCrypto(input: input) - - result.append(data[i * 8 + 0] ^ UInt8(truncatingIfNeeded: blockKey[0])) - result.append(data[i * 8 + 1] ^ UInt8(truncatingIfNeeded: blockKey[0] >> 8)) - result.append(data[i * 8 + 2] ^ UInt8(truncatingIfNeeded: blockKey[1])) - result.append(data[i * 8 + 3] ^ UInt8(truncatingIfNeeded: blockKey[1] >> 8)) - result.append(data[i * 8 + 4] ^ UInt8(truncatingIfNeeded: blockKey[2])) - result.append(data[i * 8 + 5] ^ UInt8(truncatingIfNeeded: blockKey[2] >> 8)) - result.append(data[i * 8 + 6] ^ UInt8(truncatingIfNeeded: blockKey[3])) - result.append(data[i * 8 + 7] ^ UInt8(truncatingIfNeeded: blockKey[3] >> 8)) - } - return result - } - - /// Decrypts Libre 2 BLE payload - /// - Parameters: - /// - id: ID/Serial of the sensor. Could be retrieved from NFC as uid. - /// - data: Encrypted BLE data - /// - Returns: Decrypted BLE data - static func decryptBLE(id: [UInt8], data: [UInt8]) throws -> [UInt8] { - let d = usefulFunction(id: id, x: 0x1b, y: 0x1b6a) - let x = UInt16(d[1], d[0]) ^ UInt16(d[3], d[2]) | 0x63 - let y = UInt16(data[1], data[0]) ^ 0x63 - - var key = [UInt8]() - var initialKey = processCrypto(input: prepareVariables(id: id, x: x, y: y)) - - for _ in 0 ..< 8 { - key.append(UInt8(truncatingIfNeeded: initialKey[0])) - key.append(UInt8(truncatingIfNeeded: initialKey[0] >> 8)) - key.append(UInt8(truncatingIfNeeded: initialKey[1])) - key.append(UInt8(truncatingIfNeeded: initialKey[1] >> 8)) - key.append(UInt8(truncatingIfNeeded: initialKey[2])) - key.append(UInt8(truncatingIfNeeded: initialKey[2] >> 8)) - key.append(UInt8(truncatingIfNeeded: initialKey[3])) - key.append(UInt8(truncatingIfNeeded: initialKey[3] >> 8)) - initialKey = processCrypto(input: initialKey) - } - - let result = data[2...].enumerated().map { i, value in - value ^ key[i] - } - - guard Crc.hasValidCrc16InLastTwoBytes(result) else { - struct DecryptBLEError: Error, LocalizedError { - let errorDescription = "BLE data decrytion failed" - } - throw DecryptBLEError() - } - - return result - } - - static func activateParameters(id: [UInt8]) -> Data { - let d = usefulFunction(id: id, x: 0x1b, y: 0x1b6a) - return Data([UInt8]([0x1b, d[0], d[1], d[2], d[3]])) - } -} - -public extension Libre2 { - - static func streamingUnlockPayload(sensorUID: Data, info: Data, enableTime: UInt32, unlockCount: UInt16) -> [UInt8] { - // First 4 bytes are just int32 of timestamp + unlockCount - let time = enableTime + UInt32(unlockCount) - let b: [UInt8] = [UInt8(time & 0xFF), UInt8((time >> 8) & 0xFF), UInt8((time >> 16) & 0xFF), UInt8((time >> 24) & 0xFF)] - - // Then we need data of activation command and enable command that were sent to sensor - let ad = Libre2.usefulFunction(sensorUID: sensorUID, x: 0x1b, y: 0x1b6a) - let ed = Libre2.usefulFunction(sensorUID: sensorUID, x: 0x1e, y: UInt16(enableTime & 0xFFFF) ^ UInt16(info[5], info[4])) - - let t11 = UInt16(ed[1], ed[0]) ^ UInt16(b[3], b[2]) - let t12 = UInt16(ad[1], ad[0]) - let t13 = UInt16(ed[3], ed[2]) ^ UInt16(b[1], b[0]) - let t14 = UInt16(ad[3], ad[2]) - - let t2 = Libre2.processCrypto(input: Libre2.prepareVariables(sensorUID: sensorUID, i1: t11, i2: t12, i3: t13, i4: t14)) - - // TODO extract if secret - let t31 = crc16(Data([0xc1, 0xc4, 0xc3, 0xc0, 0xd4, 0xe1, 0xe7, 0xba, UInt8(t2[0] & 0xFF), UInt8((t2[0] >> 8) & 0xFF)])).byteSwapped - let t32 = crc16(Data([UInt8(t2[1] & 0xFF), UInt8((t2[1] >> 8) & 0xFF), UInt8(t2[2] & 0xFF), UInt8((t2[2] >> 8) & 0xFF), UInt8(t2[3] & 0xFF), UInt8((t2[3] >> 8) & 0xFF)])).byteSwapped - let t33 = crc16(Data([ad[0], ad[1], ad[2], ad[3], ed[0], ed[1]])).byteSwapped - let t34 = crc16(Data([ed[2], ed[3], b[0], b[1], b[2], b[3]])).byteSwapped - - let t4 = Libre2.processCrypto(input: Libre2.prepareVariables(sensorUID: sensorUID, i1: t31, i2: t32, i3: t33, i4: t34)) - - let res = [UInt8(t4[0] & 0xFF), UInt8((t4[0] >> 8) & 0xFF), UInt8(t4[1] & 0xFF), UInt8((t4[1] >> 8) & 0xFF), UInt8(t4[2] & 0xFF), UInt8((t4[2] >> 8) & 0xFF), UInt8(t4[3] & 0xFF), UInt8((t4[3] >> 8) & 0xFF)] - - return [b[0], b[1], b[2], b[3], res[0], res[1], res[2], res[3], res[4], res[5], res[6], res[7]] - } - - static let key: [UInt16] = [0xA0C5, 0x6860, 0x0000, 0x14C6] - - static func processCrypto(input: [UInt16]) -> [UInt16] { - func op(_ value: UInt16) -> UInt16 { - // We check for last 2 bits and do the xor with specific value if bit is 1 - var res = value >> 2 // Result does not include these last 2 bits - if value & 1 != 0 { // If last bit is 1 - res = res ^ key[1] - } - - if value & 2 != 0 { // If second last bit is 1 - res = res ^ key[0] - } - - return res - } - - let r0 = op(input[0]) ^ input[3] - let r1 = op(r0) ^ input[2] - let r2 = op(r1) ^ input[1] - let r3 = op(r2) ^ input[0] - let r4 = op(r3) - let r5 = op(r4 ^ r0) - let r6 = op(r5 ^ r1) - let r7 = op(r6 ^ r2) - - let f1 = r0 ^ r4 - let f2 = r1 ^ r5 - let f3 = r2 ^ r6 - let f4 = r3 ^ r7 - - return [f4, f3, f2, f1] - } - - static func prepareVariables(sensorUID: Data, i1: UInt16, i2: UInt16, i3: UInt16, i4: UInt16) -> [UInt16] { - let s1 = UInt16(truncatingIfNeeded: UInt(UInt16(sensorUID[5], sensorUID[4])) + UInt(i1)) - let s2 = UInt16(truncatingIfNeeded: UInt(UInt16(sensorUID[3], sensorUID[2])) + UInt(i2)) - let s3 = UInt16(truncatingIfNeeded: UInt(UInt16(sensorUID[1], sensorUID[0])) + UInt(i3) + UInt(key[2])) - let s4 = UInt16(truncatingIfNeeded: UInt(i4) + UInt(key[3])) - - return [s1, s2, s3, s4] - } - - static func prepareVariables(id: [UInt8], x: UInt16, y: UInt16) -> [UInt16] { - let s1 = UInt16(truncatingIfNeeded: UInt(UInt16(id[5], id[4])) + UInt(x) + UInt(y)) - let s2 = UInt16(truncatingIfNeeded: UInt(UInt16(id[3], id[2])) + UInt(key[2])) - let s3 = UInt16(truncatingIfNeeded: UInt(UInt16(id[1], id[0])) + UInt(x) * 2) - let s4 = 0x241a ^ key[3] - - return [s1, s2, s3, s4] - } - - static func prepareVariables(sensorUID: Data, x: UInt16, y: UInt16) -> [UInt16] { - let s1 = UInt16(truncatingIfNeeded: UInt(UInt16(sensorUID[5], sensorUID[4])) + UInt(x) + UInt(y)) - let s2 = UInt16(truncatingIfNeeded: UInt(UInt16(sensorUID[3], sensorUID[2])) + UInt(key[2])) - let s3 = UInt16(truncatingIfNeeded: UInt(UInt16(sensorUID[1], sensorUID[0])) + UInt(x) * 2) - let s4 = 0x241a ^ key[3] - - return [s1, s2, s3, s4] - } - - static func usefulFunction(sensorUID: Data, x: UInt16, y: UInt16) -> [UInt8] { - let blockKey = processCrypto(input: prepareVariables(sensorUID: sensorUID, x: x, y: y)) - let low = blockKey[0] - let high = blockKey[1] - - let r1 = low ^ 0x4163 - let r2 = high ^ 0x4344 - - return [ - UInt8(truncatingIfNeeded: r1), - UInt8(truncatingIfNeeded: r1 >> 8), - UInt8(truncatingIfNeeded: r2), - UInt8(truncatingIfNeeded: r2 >> 8) - ] - } - - static func usefulFunction(id: [UInt8], x: UInt16, y: UInt16) -> [UInt8] { - let blockKey = processCrypto(input: prepareVariables(id: id, x: x, y: y)) - let low = blockKey[0] - let high = blockKey[1] - - - - let r1 = low ^ 0x4163 - let r2 = high ^ 0x4344 - return [ - UInt8(truncatingIfNeeded: r1), - UInt8(truncatingIfNeeded: r1 >> 8), - UInt8(truncatingIfNeeded: r2), - UInt8(truncatingIfNeeded: r2 >> 8) - ] - } - - typealias LibreBLEResponse = (age: Int, trend: [Measurement], history: [Measurement], crcVerified: Bool) - - static func parseBLEData(_ data: Data) -> LibreBLEResponse { - var measurementTrend: [Measurement] = [] - var measurementHistory: [Measurement] = [] - let age = Int(word(data[41], data[40])) -// let crc = Int(word(data[43], data[42])) - - let bytes = [UInt8](data) - let calculatedCrc = Crc.crc16(Array(bytes.dropLast(2)), seed: 0xffff) - let enclosedCrc = (UInt16(bytes[42]) << 8) | UInt16(bytes[43]) - - - - let delay = 2 - let ints = [0, 2, 4, 6, 7, 12, 15] - var historyCount = 0 - for i in 0 ..< 10 { - let rawSensorValue = Double(readBits(data, i * 4, 0, 0xe)) - if rawSensorValue == 0 { - continue - } - - let rawTemperature = readBits(data, i * 4, 0xe, 0xc) << 2 - var rawTemperatureAdjustment = readBits(data, i * 4, 0x1a, 0x5) << 2 - - let negativeAdjustment = readBits(data, i * 4, 0x1f, 0x1) - if negativeAdjustment != 0 { - rawTemperatureAdjustment = -rawTemperatureAdjustment - } - - var idValue = age - - if i < 7 { - idValue -= ints[i] - } else { - historyCount += 1 - idValue = ((idValue - delay) / 15) * 15 - 15 * (i - 7) - } - - let timeStamp = Date().addingTimeInterval(Double(-60 * i)) - let measurementFactory = Measurement(date: timeStamp, rawGlucose: Int(rawSensorValue), rawTemperature: rawTemperature, rawTemperatureAdjustment: rawTemperatureAdjustment, idValue: idValue) - - if i < 7 { - measurementTrend.append(measurementFactory) - } else { - measurementHistory.append(measurementFactory) - } - } - - let trend = measurementTrend.sorted(by: { $0.idValue < $1.idValue }) - let history = measurementHistory.sorted(by: { $0.idValue < $1.idValue }) - - return (age, trend, history, calculatedCrc == enclosedCrc) - } -} - -extension Libre2 { - enum Example { - static let sensorInfo: [UInt8] = [ - 157, - 8, - 48, - 1, - 115, - 23 - ] - - static let sensorId: [UInt8] = [ - 157, - 129, - 194, - 0, - 0, - 164, - 7, - 224 - ] - - static let buffer: [UInt8] = [ - 6, - 154, - 221, - 121, - 142, - 154, - 244, - 186, - 162, - 85, - 79, - 49, - 234, - 224, - 71, - 58, - 189, - 121, - 123, - 39, - 28, - 162, - 134, - 248, - 95, - 4, - 28, - 203, - 27, - 82, - 76, - 119, - 82, - 98, - 189, - 183, - 147, - 151, - 32, - 13, - 73, - 158, - 214, - 167, - 143, - 2, - 182, - 22, - 69, - 188, - 73, - 219, - 7, - 159, - 179, - 169, - 237, - 79, - 32, - 189, - 37, - 211, - 32, - 166, - 191, - 150, - 171, - 60, - 143, - 143, - 1, - 105, - 89, - 197, - 98, - 250, - 1, - 201, - 21, - 56, - 64, - 191, - 58, - 17, - 198, - 108, - 72, - 106, - 144, - 253, - 19, - 111, - 235, - 187, - 245, - 208, - 239, - 60, - 145, - 1, - 107, - 94, - 238, - 199, - 157, - 93, - 243, - 5, - 4, - 154, - 25, - 129, - 131, - 75, - 16, - 240, - 210, - 118, - 172, - 14, - 80, - 49, - 33, - 11, - 81, - 11, - 238, - 220, - 78, - 85, - 82, - 245, - 4, - 63, - 129, - 254, - 214, - 233, - 225, - 147, - 58, - 153, - 20, - 247, - 10, - 38, - 149, - 35, - 14, - 59, - 168, - 224, - 162, - 141, - 9, - 72, - 201, - 90, - 56, - 131, - 150, - 89, - 126, - 2, - 96, - 38, - 140, - 78, - 151, - 196, - 57, - 55, - 37, - 20, - 249, - 199, - 168, - 59, - 41, - 217, - 240, - 67, - 199, - 93, - 164, - 121, - 206, - 100, - 214, - 126, - 40, - 231, - 68, - 4, - 76, - 202, - 131, - 154, - 98, - 80, - 227, - 237, - 144, - 53, - 125, - 133, - 14, - 174, - 196, - 90, - 78, - 238, - 163, - 199, - 249, - 74, - 75, - 56, - 127, - 61, - 98, - 180, - 153, - 51, - 85, - 68, - 234, - 204, - 117, - 158, - 245, - 185, - 40, - 186, - 227, - 50, - 105, - 231, - 155, - 160, - 66, - 178, - 124, - 162, - 70, - 119, - 102, - 161, - 234, - 105, - 252, - 200, - 195, - 202, - 246, - 18, - 71, - 189, - 150, - 123, - 105, - 106, - 105, - 223, - 116, - 160, - 142, - 101, - 28, - 151, - 42, - 204, - 49, - 44, - 111, - 245, - 161, - 66, - 178, - 26, - 99, - 110, - 136, - 140, - 135, - 167, - 171, - 160, - 221, - 115, - 9, - 230, - 105, - 66, - 20, - 195, - 172, - 206, - 215, - 226, - 107, - 250, - 224, - 241, - 6, - 219, - 139, - 251, - 189, - 106, - 161, - 124, - 98, - 78, - 186, - 236, - 200, - 55, - 21, - 68, - 171, - 57, - 8, - 27, - 221, - 118, - 206, - 94, - 226, - 155, - 82, - 143, - 44, - 186, - 173, - 86, - 248, - 222, - 158, - 97, - 241, - 156, - 253, - 254 - ] - } - - enum Example2 { - static let sensorInfo: [UInt8] = [0x9D, 0x08, 0x30, 0x01, 0x76, 0x25] - - static let sensorId: [UInt8] = [0xDF, 0x20, 0xBE, 0x00, 0x00, 0xA4, 0x07, 0xE0] - - static let buffer: [UInt8] = [ - 0x52, 0x0B, 0xF3, 0x44, 0xDC, 0xA0, 0x43, 0x21, - 0xCC, 0x7D, 0xD7, 0x4E, 0x29, 0xE2, 0x82, 0xE3, - 0xE7, 0x04, 0xC9, 0xCF, 0x6C, 0x57, 0x2C, 0x7D, - 0xA8, 0x82, 0x10, 0xAA, 0xD7, 0x32, 0x19, 0xB3, - 0xC7, 0x9F, 0x39, 0x5F, 0xE3, 0x7A, 0x45, 0x08, - 0xB7, 0x09, 0xBC, 0x6E, 0xFA, 0xDA, 0x34, 0x07, - 0xB4, 0x65, 0x68, 0x60, 0x7E, 0xA5, 0x04, 0xE6, - 0x65, 0x65, 0x48, 0x13, 0xF8, 0x9C, 0xA7, 0xC8, - 0x70, 0xA7, 0x4D, 0x9D, 0x52, 0x35, 0x86, 0xF2, - 0x02, 0xCC, 0x9B, 0x9B, 0x74, 0x32, 0xFF, 0xC5, - 0xBF, 0xE9, 0x78, 0x1F, 0x46, 0xC2, 0xC7, 0x0B, - 0x0F, 0xB0, 0xC8, 0x54, 0x23, 0xE2, 0x0D, 0x44, - 0x97, 0x44, 0x36, 0x8F, 0xAC, 0x12, 0xAE, 0x4A, - 0x6C, 0xE1, 0x37, 0xE2, 0x46, 0x2B, 0x5C, 0x74, - 0x1B, 0x7A, 0xFE, 0x67, 0x4F, 0xCC, 0xDD, 0x95, - 0x17, 0x73, 0xB3, 0x25, 0xE9, 0xAB, 0xA6, 0x5E, - 0x70, 0xE4, 0x6C, 0xCE, 0x56, 0x8D, 0xB9, 0xE5, - 0xFE, 0xAA, 0x50, 0x36, 0x52, 0xD2, 0xC5, 0x22, - 0x24, 0x39, 0xD8, 0x63, 0x08, 0x62, 0x04, 0xAD, - 0xFA, 0x89, 0x00, 0x10, 0x72, 0xCF, 0xA9, 0xF3, - 0x47, 0x4B, 0xF5, 0x70, 0x96, 0xF2, 0x8A, 0xCA, - 0xFF, 0xEF, 0xA3, 0x9E, 0x1A, 0xEC, 0x9F, 0x4A, - 0x2F, 0xE8, 0xA9, 0xCA, 0xE6, 0xC8, 0x74, 0x46, - 0x98, 0xB2, 0xA2, 0x9E, 0x8D, 0xF0, 0xAF, 0x09, - 0xC1, 0x5B, 0x52, 0x59, 0x7E, 0x00, 0xD3, 0x3F, - 0x59, 0x41, 0x7B, 0x33, 0xEE, 0xDB, 0x40, 0x51, - 0xB2, 0x3D, 0x94, 0x82, 0xF3, 0xB2, 0xE4, 0xCA, - 0xAD, 0x3C, 0xD8, 0xC0, 0xD7, 0xD7, 0x4C, 0x51, - 0xCA, 0xA3, 0xAD, 0x26, 0x24, 0xAB, 0x10, 0xBA, - 0x61, 0x35, 0xE1, 0x7F, 0x3D, 0x3F, 0xEC, 0xB4, - 0xCF, 0xE3, 0xA2, 0x31, 0x6A, 0xE7, 0xD7, 0x36, - 0x18, 0x21, 0x5B, 0x43, 0x5A, 0x9C, 0x75, 0x7C, - 0x89, 0xE2, 0x49, 0x6C, 0xB1, 0x71, 0x6A, 0x47, - 0x6E, 0x8A, 0xE5, 0xB2, 0xC5, 0x37, 0xE9, 0xE5, - 0xDD, 0xB3, 0x12, 0x37, 0x95, 0x7A, 0xD0, 0x1F, - 0x73, 0xEB, 0xB8, 0x15, 0xF1, 0xE6, 0x5D, 0x51, - 0xFB, 0x16, 0x88, 0xA6, 0x9C, 0x17, 0xB0, 0x40, - 0x0E, 0xBB, 0xD7, 0xCA, 0x9D, 0xCD, 0x8B, 0x60, - 0x88, 0x88, 0x54, 0xFC, 0x65, 0x71, 0x43, 0xE7, - 0x51, 0xE2, 0x18, 0xEA, 0x63, 0x1D, 0x5B, 0xAA, - 0xD1, 0xD3, 0xD7, 0x08, 0xB7, 0xED, 0x87, 0xC4, - 0xB4, 0x24, 0x31, 0xE7, 0xA0, 0xE6, 0x59, 0x51, - 0x93, 0xFD, 0xA3, 0xE6, 0xBF, 0xE1, 0xF2, 0x09 - ] - } - - enum BLEExample { - static let sensorId: [UInt8] = [0x2f, 0xe7, 0xb1, 0x00, 0x00, 0xa4, 0x07, 0xe0] - static let data: [UInt8] = [ - 0xb1, - 0x94, - 0xfa, - 0xed, - 0x2c, - 0xde, - 0xa1, - 0x69, - 0x46, - 0x57, - 0xcf, - 0xd0, - 0xd8, - 0x5a, - 0xaa, - 0xf1, - 0xe2, - 0x89, - 0x1c, - 0xe9, - 0xac, - 0x82, - 0x16, - 0xfb, - 0x67, - 0xa1, - 0xd3, - 0xb6, - 0x3f, - 0x91, - 0xcd, - 0x18, - 0x4b, - 0x95, - 0x31, - 0x6c, - 0x04, - 0x5f, - 0xe1, - 0x96, - 0xc4, - 0xfd, - 0x14, - 0xfc, - 0x68, - 0xe0 - ] - } -} - - - - -fileprivate func crc16(_ data: Data) -> UInt16 { - let crc16table: [UInt16] = [0, 4489, 8978, 12955, 17956, 22445, 25910, 29887, 35912, 40385, 44890, 48851, 51820, 56293, 59774, 63735, 4225, 264, 13203, 8730, 22181, 18220, 30135, 25662, 40137, 36160, 49115, 44626, 56045, 52068, 63999, 59510, 8450, 12427, 528, 5017, 26406, 30383, 17460, 21949, 44362, 48323, 36440, 40913, 60270, 64231, 51324, 55797, 12675, 8202, 4753, 792, 30631, 26158, 21685, 17724, 48587, 44098, 40665, 36688, 64495, 60006, 55549, 51572, 16900, 21389, 24854, 28831, 1056, 5545, 10034, 14011, 52812, 57285, 60766, 64727, 34920, 39393, 43898, 47859, 21125, 17164, 29079, 24606, 5281, 1320, 14259, 9786, 57037, 53060, 64991, 60502, 39145, 35168, 48123, 43634, 25350, 29327, 16404, 20893, 9506, 13483, 1584, 6073, 61262, 65223, 52316, 56789, 43370, 47331, 35448, 39921, 29575, 25102, 20629, 16668, 13731, 9258, 5809, 1848, 65487, 60998, 56541, 52564, 47595, 43106, 39673, 35696, 33800, 38273, 42778, 46739, 49708, 54181, 57662, 61623, 2112, 6601, 11090, 15067, 20068, 24557, 28022, 31999, 38025, 34048, 47003, 42514, 53933, 49956, 61887, 57398, 6337, 2376, 15315, 10842, 24293, 20332, 32247, 27774, 42250, 46211, 34328, 38801, 58158, 62119, 49212, 53685, 10562, 14539, 2640, 7129, 28518, 32495, 19572, 24061, 46475, 41986, 38553, 34576, 62383, 57894, 53437, 49460, 14787, 10314, 6865, 2904, 32743, 28270, 23797, 19836, 50700, 55173, 58654, 62615, 32808, 37281, 41786, 45747, 19012, 23501, 26966, 30943, 3168, 7657, 12146, 16123, 54925, 50948, 62879, 58390, 37033, 33056, 46011, 41522, 23237, 19276, 31191, 26718, 7393, 3432, 16371, 11898, 59150, 63111, 50204, 54677, 41258, 45219, 33336, 37809, 27462, 31439, 18516, 23005, 11618, 15595, 3696, 8185, 63375, 58886, 54429, 50452, 45483, 40994, 37561, 33584, 31687, 27214, 22741, 18780, 15843, 11370, 7921, 3960] - var crc = data.reduce(UInt16(0xFFFF)) { ($0 >> 8) ^ crc16table[Int(($0 ^ UInt16($1)) & 0xFF)] } - var reverseCrc = UInt16(0) - for _ in 0 ..< 16 { - reverseCrc = reverseCrc << 1 | crc & 1 - crc >>= 1 - } - return reverseCrc.byteSwapped -} - -fileprivate func word(_ high: UInt8, _ low: UInt8) -> UInt64 { - return (UInt64(high) << 8) + UInt64(low & 0xff) -} - -fileprivate func readBits(_ buffer: Data, _ byteOffset: Int, _ bitOffset: Int, _ bitCount: Int) -> Int { - guard bitCount != 0 else { - return 0 - } - var res = 0 - for i in 0 ..< bitCount { - let totalBitOffset = byteOffset * 8 + bitOffset + i - let byte = Int(floor(Float(totalBitOffset) / 8)) - let bit = totalBitOffset % 8 - if totalBitOffset >= 0 && ((Int(buffer[byte]) >> bit) & 0x1) == 1 { - res = res | (1 << i) - } - } - return res -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/Sensor.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/Sensor.swift deleted file mode 100644 index 83d39595c..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/Sensor.swift +++ /dev/null @@ -1,179 +0,0 @@ -import Foundation - -public extension UserDefaults { - private enum Key: String { - case sensor = "no.bjorninge.libre2sensor" - case calibrationMapping = "no.bjorninge.libre2sensor-calibrationmapping" - - - } - - var preSelectedSensor: Sensor? { - get { - - if let sensor = object(forKey: Key.sensor.rawValue) as? Data { - let decoder = JSONDecoder() - return try? decoder.decode(Sensor.self, from: sensor) - } - - return nil - - } - set { - if let newValue = newValue { - let encoder = JSONEncoder() - if let encoded = try? encoder.encode(newValue) { - set(encoded, forKey: Key.sensor.rawValue) - } - } else { - removeObject(forKey: Key.sensor.rawValue) - } - } - } - - var calibrationMapping : CalibrationToSensorMapping? { - get { - if let sensor = object(forKey: Key.calibrationMapping.rawValue) as? Data { - let decoder = JSONDecoder() - return try? decoder.decode(CalibrationToSensorMapping.self, from: sensor) - } - - return nil - - } - set { - if let newValue = newValue { - let encoder = JSONEncoder() - if let encoded = try? encoder.encode(newValue) { - set(encoded, forKey: Key.calibrationMapping.rawValue) - } - } else { - removeObject(forKey: Key.calibrationMapping.rawValue) - } - } - } -} - -public struct CalibrationToSensorMapping: Codable { - public let uuid: Data - public let reverseFooterCRC: Int - - public init(uuid: Data, reverseFooterCRC: Int) { - self.uuid = uuid - self.reverseFooterCRC = reverseFooterCRC - } -} - - -public struct Sensor: Codable { - public let uuid: Data - public let patchInfo: Data - // public let calibrationInfo: SensorData.CalibrationInfo - - //public let family: SensorFamily - //public let type: SensorType - //public let region: SensorRegion - //public let serial: String? - //public var state: SensorState - public var age: Int? = nil - public var maxAge: Int - // public var lifetime: Int - - public var unlockCount: Int - - /* - public var unlockCount: Int { - get { - return UserDefaults.standard.integer(forKey: Key.sensorUnlockCount.rawValue) - } - set { - UserDefaults.standard.setValue(newValue, forKey: Key.sensorUnlockCount.rawValue) - } - }*/ - - /* - public var elapsedLifetime: Int? { - get { - if let remainingLifetime = remainingLifetime { - return max(0, lifetime - remainingLifetime) - } - - return nil - } - } - - public var remainingLifetime: Int? { - get { - if let age = age { - return max(0, lifetime - age) - } - - return nil - } - } */ - - public init(uuid: Data, patchInfo: Data, maxAge:Int, unlockCount: Int = 0) { - self.uuid = uuid - self.patchInfo = patchInfo - - //self.family = SensorFamily(patchInfo: patchInfo) - //self.type = SensorType(patchInfo: patchInfo) - //self.region = SensorRegion(patchInfo: patchInfo) - //self.serial = sensorSerialNumber(sensorUID: self.uuid, sensorFamily: self.family) - //self.state = SensorState(fram: fram) - //self.lifetime = Int(fram[327]) << 8 + Int(fram[326]) - self.unlockCount = 0 - self.maxAge = maxAge - //self.calibrationInfo = calibrationInfo - } - - public var description: String { - return [ - "uuid: (\(uuid.hex))", - "patchInfo: (\(patchInfo.hex))", - //"calibrationInfo: (\(calibrationInfo.description))", - //"family: \(family.description)", - //"type: \(type.description)", - //"region: \(region.description)", - //"serial: \(serial ?? "Unknown")", - //"state: \(state.description)", - //"lifetime: \(lifetime.inTime)", - ].joined(separator: ", ") - } -} - -fileprivate enum Key: String, CaseIterable { - case sensorUnlockCount = "libre-direct.settings.sensor.unlockCount" -} - -/* -fileprivate func sensorSerialNumber(sensorUID: Data, sensorFamily: SensorFamily) -> String? { - let lookupTable = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "T", "U", "V", "W", "X", "Y", "Z"] - - guard sensorUID.count == 8 else { - return nil - } - - let bytes = Array(sensorUID.reversed().suffix(6)) - var fiveBitsArray = [UInt8]() - fiveBitsArray.append(bytes[0] >> 3) - fiveBitsArray.append(bytes[0] << 2 + bytes[1] >> 6) - - fiveBitsArray.append(bytes[1] >> 1) - fiveBitsArray.append(bytes[1] << 4 + bytes[2] >> 4) - - fiveBitsArray.append(bytes[2] << 1 + bytes[3] >> 7) - - fiveBitsArray.append(bytes[3] >> 2) - fiveBitsArray.append(bytes[3] << 3 + bytes[4] >> 5) - - fiveBitsArray.append(bytes[4]) - - fiveBitsArray.append(bytes[5] >> 3) - fiveBitsArray.append(bytes[5] << 2) - - return fiveBitsArray.reduce("\(sensorFamily.rawValue)", { - $0 + lookupTable[Int(0x1F & $1)] - }) -} - */ diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/SensorData.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/SensorData.swift deleted file mode 100644 index d2d499e01..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/SensorData.swift +++ /dev/null @@ -1,473 +0,0 @@ -// -// SensorData -// LibreMonitor -// -// Created by Uwe Petersen on 26.07.16. -// Copyright © 2016 Uwe Petersen. All rights reserved. -// - -import Foundation - -/// Structure for data from Freestyle Libre sensor -/// To be initialized with the bytes as read via nfc. Provides all derived data. -public struct SensorData: Codable { - /// Parameters for the temperature compensation algorithm - //let temperatureAlgorithmParameterSet: TemperatureAlgorithmParameters? - - private var headerRange = 0..<24 // 24 bytes, i.e. 3 blocks a 8 bytes - private var bodyRange = 24..<320 // 296 bytes, i.e. 37 blocks a 8 bytes - private var footerRange = 320..<344 // 24 bytes, i.e. 3 blocks a 8 bytes - - /// The uid of the sensor - let uuid: Data - /// The serial number of the sensor - let serialNumber: String - /// Number of bytes of sensor data to be used (read only), i.e. 344 bytes (24 for header, 296 for body and 24 for footer) - private var numberOfBytes = 344 // Header and body and footer of Freestyle Libre data (i.e. 40 blocks of 8 bytes) - /// Array of 344 bytes as read via nfc - var bytes: [UInt8] - /// Subarray of 24 header bytes - var header: [UInt8] { - Array(bytes[headerRange]) - } - /// Subarray of 296 body bytes - var body: [UInt8] { - Array(bytes[bodyRange]) - } - /// Subarray of 24 footer bytes - var footer: [UInt8] { - Array(bytes[footerRange]) - } - /// Date when data was read from sensor - let date: Date - /// Minutes (approx) since start of sensor - var minutesSinceStart: Int { - Int(body[293]) << 8 + Int(body[292]) - } - /// Maximum time in Minutes he sensor can be worn before it expires - public var maxMinutesWearTime: Int { - Int(footer[7]) << 8 + Int(footer[6]) - } - /// Index on the next block of trend data that the sensor will measure and store - var nextTrendBlock: Int { - Int(body[2]) - } - /// Index on the next block of history data that the sensor will create from trend data and store - var nextHistoryBlock: Int { - Int(body[3]) - } - /// true if all crc's are valid - var hasValidCRCs: Bool { - hasValidHeaderCRC && hasValidBodyCRC && hasValidFooterCRC - } - /// true if the header crc, stored in the first two header bytes, is equal to the calculated crc - var hasValidHeaderCRC: Bool { - Crc.hasValidCrc16InFirstTwoBytes(header) - } - /// true if the body crc, stored in the first two body bytes, is equal to the calculated crc - var hasValidBodyCRC: Bool { - Crc.hasValidCrc16InFirstTwoBytes(body) - } - /// true if the footer crc, stored in the first two footer bytes, is equal to the calculated crc - var hasValidFooterCRC: Bool { - Crc.hasValidCrc16InFirstTwoBytes(footer) - } - /// Footer crc needed for checking integrity of SwiftLibreOOPWeb response - var footerCrc: UInt16 { - Crc.crc16(Array(footer.dropFirst(2)), seed: 0xffff) - } - - // the amount of minutes left before this sensor expires - var minutesLeft: Int { - maxMinutesWearTime - minutesSinceStart - } - - //once the sensor has ended we don't know the exact date anymore - var sensorEndTime: Date? { - if minutesLeft <= 0 { - return nil - } - - return self.date.addingTimeInterval(TimeInterval(minutes: Double(self.minutesLeft))) - } - - var sensorStartTime: Date? { - self.date.addingTimeInterval(-1*TimeInterval(minutes: Double(self.minutesSinceStart))) - } - - /// Sensor state (ready, failure, starting etc.) - var state: SensorState { - SensorState(stateByte: header[4]) - } - - //all libre1 and 2 sensors will pass this, once decrypted - var isLikelyLibre1FRAM: Bool { - if bytes.count > 23 { - let subset = bytes[9...23] - return !subset.contains(where: { $0 > 0 }) - } - return false - } - - var reverseFooterCRC: UInt16? { - let b0 = UInt16(self.footer[1]) - let b1 = UInt16(self.footer[0]) - return (b0 << 8) | UInt16(b1) - } - - mutating func decrypt(patchInfo: String, uid: [UInt8]) { - guard let info = patchInfo.hexadecimal(), let sensorType = SensorType(patchInfo: patchInfo) else { - return - } - - //var decrypted2 = Libre2.decryptFRAM(sensorId: uid, sensorInfo: [UInt8](info), FRAMData: self.bytes) - - do { - self.bytes = try Libre2.decryptFRAM(type: sensorType, id: uid, info: [UInt8](info), data: self.bytes) - } catch { - return - } - } - - enum CalibrationInfoCodingKeys: CodingKey { - case i1 - case i2 - case i3 - case i4 - case i5 - case i6 - case isValidForFooterWithReverseCRCs - - } - - public class CalibrationInfo: Codable, CustomStringConvertible, ObservableObject { - public required init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CalibrationInfoCodingKeys.self) - i1 = try container.decode(Int.self, forKey: .i1) - i2 = try container.decode(Int.self, forKey: .i2) - i3 = try container.decode(Double.self, forKey: .i3) - i4 = try container.decode(Double.self, forKey: .i4) - i5 = try container.decode(Double.self, forKey: .i5) - i6 = try container.decode(Double.self, forKey: .i6) - isValidForFooterWithReverseCRCs = try container.decode(Int.self, forKey: .isValidForFooterWithReverseCRCs) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CalibrationInfoCodingKeys.self) - try container.encode(i1, forKey: .i1) - try container.encode(i2, forKey: .i2) - try container.encode(i3, forKey: .i3) - try container.encode(i4, forKey: .i4) - try container.encode(i5, forKey: .i5) - try container.encode(i6, forKey: .i6) - try container.encode(isValidForFooterWithReverseCRCs, forKey: .isValidForFooterWithReverseCRCs) - } - public init(i1: Int, i2: Int, i3: Double, i4: Double, i5: Double, i6: Double, isValidForFooterWithReverseCRCs: Int) { - self.i1 = i1 - self.i2 = i2 - self.i3 = i3 - self.i4 = i4 - self.i5 = i5 - self.i6 = i6 - self.isValidForFooterWithReverseCRCs = isValidForFooterWithReverseCRCs - } - - @Published public var i1: Int - @Published public var i2: Int - @Published public var i3: Double - @Published public var i4: Double - @Published public var i5: Double - @Published public var i6: Double - - @Published public var isValidForFooterWithReverseCRCs: Int - - public var description: String { - "CalibrationInfo(i1: \(i1), i2: \(i2), i3: \(i3), i4: \(i4), isValidForFooterWithReverseCRCs: \(isValidForFooterWithReverseCRCs), i5: \(i5)), i6: \(i6))" - } - } - - //static func readBits(_ buffer: [UInt8], _ byteOffset: Int, _ bitOffset: Int, _ bitCount: Int) -> Int { - - public var calibrationData: CalibrationInfo { - let data = self.bytes - let i1 = Self.readBits(data, 2, 0, 3) - let i2 = Self.readBits(data, 2, 3, 0xa) - let i3 = Double(Self.readBits(data, 0x150, 0, 8)) - let i4 = Double(Self.readBits(data, 0x150, 8, 0xe)) - let negativei3 = Self.readBits(data, 0x150, 0x21, 1) != 0 - let i5 = Double(Self.readBits(data, 0x150, 0x28, 0xc) << 2) - let i6 = Double(Self.readBits(data, 0x150, 0x34, 0xc) << 2) - - return CalibrationInfo(i1: i1, i2: i2, i3: negativei3 ? -i3 : i3, i4: i4, i5: i5, i6: i6, isValidForFooterWithReverseCRCs: Int(self.footerCrc.byteSwapped)) - } - - fileprivate var aday = 86_400.0 //in seconds - - var humanReadableSensorAge: String { - let days = TimeInterval(minutesSinceStart * 60) / aday - return String(format: "%.2f", days) + NSLocalizedString(" day(s)", comment: "Sensor day(s)") - } - - var humanReadableTimeLeft: String { - let days = TimeInterval(minutesLeft * 60) / aday - return String(format: "%.2f", days) + NSLocalizedString(" day(s)", comment: "Sensor day(s)") - } - - var toJson: String { - "[" + self.bytes.map { String(format: "0x%02x", $0) }.joined(separator: ", ") + "]" - } - var toEcmaStatement: String { - "var someFRAM=" + self.toJson + ";" - } - - public init?(bytes: [UInt8], date: Date = Date()) { - self.init(uuid: Data(), bytes: bytes, date: date) - } - public init?(uuid: Data, bytes: [UInt8], date: Date = Date()) { - guard bytes.count == numberOfBytes else { - return nil - } - self.bytes = bytes - // we don't actually know when this reading was done, only that - // it was produced within the last minute - self.date = date.rounded(on: 1, .minute) - - self.uuid = uuid - - self.serialNumber = SensorSerialNumber(withUID: uuid)?.serialNumber ?? "-" - - // we disable this check as we might be dealing with an encrypted libre2 sensor - /* - - guard 0 <= nextTrendBlock && nextTrendBlock < 16 && 0 <= nextHistoryBlock && nextHistoryBlock < 32 else { - return nil - } - */ - } - - /// Get array of 16 trend glucose measurements. - /// Each array is sorted such that the most recent value is at index 0 and corresponds to the time when the sensor was read, i.e. self.date. The following measurements are each one more minute behind, i.e. -1 minute, -2 mintes, -3 minutes, ... -15 minutes. - /// - /// - parameter offset: offset in mg/dl that is added (NOT IN USE FOR DERIVEDALGO) - /// - parameter slope: slope in (mg/dl)/ raw (NOT IN USE FOR DERIVEDALGO) - /// - /// - returns: Array of Measurements - func trendMeasurements(_ offset: Double = 0.0, slope: Double = 0.1) -> [Measurement] { - var measurements = [Measurement]() - // Trend data is stored in body from byte 4 to byte 4+96=100 in units of 6 bytes. Index on data such that most recent block is first. - for blockIndex in 0...15 { - var index = 4 + (nextTrendBlock - 1 - blockIndex) * 6 // runs backwards - if index < 4 { - index += 96 // if end of ring buffer is reached shift to beginning of ring buffer - } - let range = index.. (date: Date, counter: Int) { - // Calculate correct date for the most recent history value. - // date.addingTimeInterval( 60.0 * -Double( (minutesSinceStart - 3) % 15 + 3 ) ) - let nextHistoryIndexCalculatedFromMinutesCounter = ( (minutesSinceStart - 3) / 15 ) % 32 - let delay = (minutesSinceStart - 3) % 15 + 3 // in minutes - if nextHistoryIndexCalculatedFromMinutesCounter == nextHistoryBlock { - // Case when history index is incremented togehter with minutesSinceStart (in sync) - // print("delay: \(delay), minutesSinceStart: \(minutesSinceStart), result: \(minutesSinceStart-delay)") - return (date: date.addingTimeInterval( 60.0 * -Double(delay) ), counter: minutesSinceStart - delay) - } else { - // Case when history index is incremented before minutesSinceStart (and they are async) - // print("delay: \(delay), minutesSinceStart: \(minutesSinceStart), result: \(minutesSinceStart-delay-15)") - return (date: date.addingTimeInterval( 60.0 * -Double(delay - 15)), counter: minutesSinceStart - delay) - } - } - - /// Get date of most recent history value. - /// History values are updated every 15 minutes. Their corresponding time from start of the sensor in minutes is 15, 30, 45, 60, ..., but the value is delivered three minutes later, i.e. at the minutes 18, 33, 48, 63, ... and so on. So for instance if the current time in minutes (since start of sensor) is 67, the most recent value is 7 minutes old. This can be calculated from the minutes since start. Unfortunately sometimes the history index is incremented earlier than the minutes counter and they are not in sync. This has to be corrected. - /// - /// - Returns: the date of the most recent history value - func dateOfMostRecentHistoryValue() -> Date { - // Calculate correct date for the most recent history value. - // date.addingTimeInterval( 60.0 * -Double( (minutesSinceStart - 3) % 15 + 3 ) ) - let nextHistoryIndexCalculatedFromMinutesCounter = ( (minutesSinceStart - 3) / 15 ) % 32 - let delay = (minutesSinceStart - 3) % 15 + 3 // in minutes - if nextHistoryIndexCalculatedFromMinutesCounter == nextHistoryBlock { - // Case when history index is incremented togehter with minutesSinceStart (in sync) - // print("delay: \(delay), minutesSinceStart: \(minutesSinceStart), result: \(minutesSinceStart-delay)") - return date.addingTimeInterval( 60.0 * -Double(delay) ) - } else { - // Case when history index is incremented before minutesSinceStart (and they are async) - // print("delay: \(delay), minutesSinceStart: \(minutesSinceStart), result: \(minutesSinceStart-delay-15)") - return date.addingTimeInterval( 60.0 * -Double(delay - 15)) - } - } - -// func currentTime() -> Int { -// -// let quotientBy16 = minutesSinceStart / 16 -// let nominalMinutesSinceStart = nextTrendBlock + quotientBy16 * 16 -// let correctedQuotientBy16 = minutesSinceStart <= nominalMinutesSinceStart ? quotientBy16 - 1 : quotientBy16 -// let currentTime = nextTrendBlock + correctedQuotientBy16 * 16 -// -// let mostRecentHistoryCounter = (currentTime / 15) * 15 -// -// print("currentTime: \(currentTime), mostRecentHistoryCounter: \(mostRecentHistoryCounter)") -// return currentTime -// } - - /// Get array of 32 history glucose measurements. - /// Each array is sorted such that the most recent value is at index 0. This most recent value corresponds to -(minutesSinceStart - 3) % 15 + 3. The following measurements are each 15 more minutes behind, i.e. -15 minutes behind, -30 minutes, -45 minutes, ... . - /// - /// - parameter offset: offset in mg/dl that is added - /// - parameter slope: slope in (mg/dl)/ raw - /// - /// - returns: Array of Measurements - func historyMeasurements(_ offset: Double = 0.0, slope: Double = 0.1) -> [Measurement] { - var measurements = [Measurement]() - // History data is stored in body from byte 100 to byte 100+192-1=291 in units of 6 bytes. Index on data such that most recent block is first. - for blockIndex in 0..<32 { - var index = 100 + (nextHistoryBlock - 1 - blockIndex) * 6 // runs backwards - if index < 100 { - index += 192 // if end of ring buffer is reached shift to beginning of ring buffer - } - - let range = index.. String { - Data(bytes).base64EncodedString() - } - - /// Returns a new array of 344 bytes of FRAM with correct crc for header, body and footer. - /// - /// Usefull, if some bytes are modified in order to investigate how the OOP algorithm handles this modification. - /// - Returns: 344 bytes of FRAM with correct crcs - func bytesWithCorrectCRC() -> [UInt8] { - Crc.bytesWithCorrectCRC(header) + Crc.bytesWithCorrectCRC(body) + Crc.bytesWithCorrectCRC(footer) - } - - - - -} - - - -extension SensorData { - /// Reads Libredata in bits converts and the result to int - /// - /// Makes it possible to read for example 7 bits from a 1 byte (8 bit) buffer. - /// Can be used to read both FRAM and Libre2 Bluetooth buffer data . Buffer is expected to be unencrypted - /// - Returns: bits from buffer - static func readBits(_ buffer: [UInt8], _ byteOffset: Int, _ bitOffset: Int, _ bitCount: Int) -> Int { - guard bitCount != 0 else { - return 0 - } - var res = 0 - for i in stride(from: 0, to: bitCount, by: 1) { - let totalBitOffset = byteOffset * 8 + bitOffset + i - let abyte = Int(floor(Float(totalBitOffset) / 8)) - let abit = totalBitOffset % 8 - if totalBitOffset >= 0 && ((buffer[abyte] >> abit) & 0x1) == 1 { - res = res | (1 << i) - } - } - return res - } - - static func writeBits(_ buffer: [UInt8], _ byteOffset: Int, _ bitOffset: Int, _ bitCount: Int, _ value: Int) -> [UInt8] { - var res = buffer; // Make a copy - for i in stride(from: 0, to: bitCount, by: 1) { - let totalBitOffset = byteOffset * 8 + bitOffset + i - let byte = Int(floor(Double(totalBitOffset) / 8)) - let bit = totalBitOffset % 8 - let bitValue = (value >> i) & 0x1 - res[byte] = (res[byte] & ~(1 << bit) | (UInt8(bitValue) << bit)) - } - return res - } -} - -public extension SensorData { - - private func average(_ input: [Double]) -> Double { - return input.reduce(0, +) / Double(input.count) - } - - private func multiply(_ a: [Double], _ b: [Double]) -> [Double] { - return zip(a, b).map(*) - } - //https://github.com/raywenderlich/swift-algorithm-club/blob/master/Linear%20Regression/LinearRegression.playground/Contents.swift - private func linearRegression(_ xs: [Double], _ ys: [Double]) -> (Double) -> Double { - let sum1 = average(multiply(xs, ys)) - average(xs) * average(ys) - let sum2 = average(multiply(xs, xs)) - pow(average(xs), 2) - let slope = sum1 / sum2 - let intercept = average(ys) - slope * average(xs) - return { x in intercept + slope * x } - } - - /// Uses trend data to predict a measurement 10 minutes into the future - /// - /// This makes it possible to better align glucose data from the intertestual fluid with actual blood sugar values, - /// Intertestual fluid lags about 10 to 15 minutes (for most people) behind blood sugar values measuretd by a finger stick - /// - /// - Returns: a predicted measurement 10 minutes into the future, or the most recent glucose value if such prediction is impossible. If no reading exists, this will return nil - /// - - internal func predictBloodSugar(_ minutes: Double = 10) -> Measurement? { - - let trends = self.trendMeasurements()//.filter { !$0.error.contains(.SENSOR_SIGNAL_LOW)} - - - guard trends.count > 15 else { - return trends.first - } - - guard let mostRecent = trends.first else { - return nil - } - - let sorted = trends.sorted{ $0.date < $1.date} - - //keep the recent raw temperatures, we don't want to apply linear regression to them - let mostRecentTemperature = mostRecent.rawTemperature - let mostRecentAdjustment = mostRecent.rawTemperatureAdjustment - let mostRecentDate = mostRecent.date - let futureDate = mostRecentDate.addingTimeInterval(60*minutes) - - - let glucoseAge = sorted.compactMap { measurement in - Double(measurement.date.timeIntervalSince1970) - } - - let rawGlucoseValues = sorted.compactMap { measurement in - Double(measurement.rawGlucose) - } - - let glucosePrediction = linearRegression(glucoseAge, rawGlucoseValues)(futureDate.timeIntervalSince1970) - - let predicted = Measurement(date: futureDate, - rawGlucose: Int(glucosePrediction.rounded()), - rawTemperature: mostRecentTemperature, - rawTemperatureAdjustment: mostRecentAdjustment) - return predicted - - - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/SensorSerialNumber.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/SensorSerialNumber.swift deleted file mode 100644 index 656a5cd81..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/SensorSerialNumber.swift +++ /dev/null @@ -1,107 +0,0 @@ -// -// FreestyleLibreSensor.swift -// LibreMonitor -// -// Created by Uwe Petersen on 01.04.18. -// Copyright © 2018 Uwe Petersen. All rights reserved. -// - -import Foundation - -public struct SensorSerialNumber: CustomStringConvertible { - let uid: Data - - fileprivate let lookupTable = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "T", "U", "V", "W", "X", "Y", "Z"] - - init?(withUID uid: Data) { - guard uid.count == 8 else { return nil } - self.uid = uid - } - - // MARK: - computed properties - - var serialNumber: String { - // The serial number of the sensor can be derived from its uid. - // - // The numbers an letters of the serial number are coded a compressed scheme that uses only 32 numbers and letters, - // by omitting the letters B, I, O and S. This information is stored in consecutive units of five bits. - // - // The encoding thus is as follows: - // index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 - // char: 0 1 2 3 4 5 6 7 8 9 A (B) C D E F G H (I) J K L M N (O) P Q R (S) T U V W X Y Z - // - // Example: 75 ce 86 00 00 a0 07 e0 - // Uid is E0 07 A0 00 00 25 90 5E, and the corresponding serial number is "0M00009DHCR" - // \ / \ / - // -+- -----+-------- - // | | - // | +-- This part encodes the serial number, see below - // +-- Standard first two bytes, where 0x07 is the code for "Texas Instruments Tag-it™", see https://en.wikipedia.org/wiki/ISO/IEC_15693 - // - // 1.) Convert the part without E007, i.e. A0 00 00 25 90 5E to binary representation - // - // A 0 0 0 0 0 2 5 9 0 5 E - // 1010 0000 0000 0000 0000 0000 0010 0101 1001 0000 0101 1110 - // - // 2.) Split this binary array in units of five bits length from the beginning and pad with two zeros at the end and - // calculate the corresponding integer and retreive the corresponding char from the table above - // - // Byte # 0 1 2 3 4 5 - // Bit # 8765 4321 8765 4321 8765 4321 8765 4321 8765 4321 8765 4321 - // - // +-- 1010 0000 0000 0000 0000 0000 0010 0101 1001 0000 0101 1110 + 00 - // | \ /\ /\ /\ / \ /\ /\ /\ / \ /\ / - // +-> 10100 00000 00000 00000 00000 01001 01100 10000 01011 11000 - // | | | | | | | | | | - // | | | | | | | | | +- = 24 -> "R" (Byte 6) << 2 Mask 0x1F - // | | | | | | | | +-------- = 11 -> "C" (Byte 5) >> 3 Mask 0x1F - // | | | | | | | +--------------- = 16 -> "H" (Byte 4) Mask 0x1F - // | | | | | | +---------------------- = 12 -> "D" (Byte 3) << 2 + (Byte 4) >> 5 Mask 0x1F - // | | | | | +----------------------------- = 9 -> "9" (Byte 3) >> 2 Mask 0x1F - // | | | | +------------------------------------ = 0 -> "0" (Byte 2) << 1 + (Byte 3) >> 7 Mask 0x1F - // | | | +------------------------------------------- = 0 -> "0" (Byte 1) << 4 + (Byte 2) >> 4 Mask 0x1F - // | | +-------------------------------------------------- = 0 -> "0" (Byte 1) >> 1 Mask 0x1F - // | +--------------------------------------------------------- = 0 -> "0" (Byte 0) << 2 + (Byte 1) >> 6 Mask 0x1F - // +---------------------------------------------------------------- = 20 -> "M" (byte 0) >> 3 Mask 0x1F - // - // - // 3.) Prepend "0" at the beginning an thus receive "0M00009DHCR" - - guard uid.count == 8 else { return "invalid uid" } - - let bytes = Array(uid.reversed().suffix(6)) // 5E 90 25 00 00 A0 07 E0" -> E0 07 A0 00 00 25 90 5E -> A0 00 00 25 90 5E - - // A0 00 00 25 90 5E -> "M00009DHCR" - var fiveBitsArray = [UInt8]() // Mask later with 0x1F to use only five bits - - fiveBitsArray.append( bytes[0] >> 3 ) - fiveBitsArray.append( bytes[0] << 2 + bytes[1] >> 6 ) - fiveBitsArray.append( bytes[1] >> 1 ) - fiveBitsArray.append( bytes[1] << 4 + bytes[2] >> 4 ) - fiveBitsArray.append( bytes[2] << 1 + bytes[3] >> 7 ) - fiveBitsArray.append( bytes[3] >> 2 ) - fiveBitsArray.append( bytes[3] << 3 + bytes[4] >> 5 ) - fiveBitsArray.append( bytes[4] ) - fiveBitsArray.append( bytes[5] >> 3 ) - fiveBitsArray.append( bytes[5] << 2 ) - - let serialNumber = fiveBitsArray.reduce("0", { // prepend with "0" according to step 3.) - $0 + lookupTable[ Int(0x1F & $1) ] // Mask with 0x1F to only take the five relevant bits - }) - return serialNumber - } - - var uidString: String { - Data(self.uid).hexEncodedString() - } - - var prettyUidString: String { - let stringArray = self.uid.map({ String(format: "%02X", $0) }) - return stringArray.dropFirst().reduce(stringArray.first!, { $0 + ":" + $1 }) - } - - // MARK: - CustomStringConvertible Protocoll - public var description: String { - "Uid is \(prettyUidString) and derived serial number is \(serialNumber)" - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/SensorState.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/SensorState.swift deleted file mode 100644 index 467c3b87d..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreSensor/SensorContents/SensorState.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// SensorState.swift -// LibreMonitor -// -// Created by Uwe Petersen on 31.07.16. -// Copyright © 2016 Uwe Petersen. All rights reserved. -// - -import Foundation - -/// State of the freestyle libre sensor -/// -/// - notYetStarted: 0x01 sensor not yet started -/// - starting: 0x02 sensor is in the starting phase -/// - ready: 0x03 sensor is ready, i.e. in normal operation mode -/// - stateFour: 0x04 state with yet unknown meaning -/// - expired: 0x05 sensor is expired -/// - failure: 0x06 sensor has an error -/// - unknown: any other state -enum SensorState { - case notYetStarted - case starting - case ready - case expired - case shutdown - case failure - case unknown - - init() { - self = .unknown - } - init(stateByte: UInt8) { - switch stateByte { - case 01: - self = .notYetStarted - case 02: - self = .starting - case 03: - self = .ready - case 04: - self = .expired - case 05: - self = .shutdown - case 06: - self = .failure - default: - self = .unknown - } - } - - var description: String { - switch self { - case .notYetStarted: - return "Sensor not yet startet" - case .starting: - return "Sensor in starting phase" - case .ready: - return "Sensor is ready" - case .expired: - return "Sensor is expired" - case .shutdown: - return "Sensor is shut down" - case .failure: - return "Sensor has failure" - default: - return "Unknown sensor state" - } - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterManager.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterManager.swift deleted file mode 100644 index 1c456b4b6..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterManager.swift +++ /dev/null @@ -1,868 +0,0 @@ -// -// LibreTransmitterManager.swift -// Created by Bjørn Inge Berg on 25/02/2019. -// Copyright © 2019 Bjørn Inge Berg. All rights reserved. -// -import Foundation -import UserNotifications -import Combine -import UIKit -import CoreBluetooth -import HealthKit -import os.log - -public protocol LibreTransmitterManagerDelegate: AnyObject { - var queue: DispatchQueue { get } - - func startDateToFilterNewData(for: LibreTransmitterManager) -> Date? - - func cgmManager(_:LibreTransmitterManager, hasNew result: Result<[LibreGlucose], Error>) - - func overcalibration(for: LibreTransmitterManager) -> ((Double) -> (Double))? -} - -public final class LibreTransmitterManager: LibreTransmitterDelegate { - - public typealias GlucoseArrayWithPrediction = (glucose:[LibreGlucose], prediction:[LibreGlucose]) - public lazy var logger = Logger(forType: Self.self) - - - public let isOnboarded = true // No distinction between created and onboarded - public var hasValidSensorSession: Bool { - lastConnected != nil - } - - public var glucoseDisplay: GlucoseDisplayable? - public var trend: GlucoseTrend? - - - public func libreManagerDidRestoreState(found peripherals: [CBPeripheral], connected to: CBPeripheral?) { - let devicename = to?.name ?? "no device" - let id = to?.identifier.uuidString ?? "null" - let msg = String(format: NSLocalizedString("Bluetooth State restored (APS restarted?). Found %d peripherals, and connected to %@ with identifier %@", comment: "Restored state message"), peripherals.count, devicename, id) - - NotificationHelper.sendRestoredStateNotification(msg: msg) - } - - public var batteryLevel: Double? { - let batt = self.proxy?.metadata?.battery - logger.debug("dabear:: LibreTransmitterManager was asked to return battery: \(batt.debugDescription)") - //convert from 8% -> 0.8 - if let battery = proxy?.metadata?.battery { - return Double(battery) / 100 - } - - return nil - } - - - - public var cgmManagerDelegate: LibreTransmitterManagerDelegate? { - get { - return delegate.delegate - } - set { - delegate.delegate = newValue - } - } - - public var delegateQueue: DispatchQueue! { - get { - return delegate.queue - } - set { - delegate.queue = newValue - } - } - - public let delegate = WeakSynchronizedDelegate() - - public var managedDataInterval: TimeInterval? - - - private func getPersistedSensorDataForDebug() -> String { - guard let data = UserDefaults.standard.queuedSensorData else { - return "nil" - } - - let c = self.calibrationData?.description ?? "no calibrationdata" - return data.array.map { - "SensorData(uuid: \"0123\".data(using: .ascii)!, bytes: \($0.bytes))!" - } - .joined(separator: ",\n") - + ",\n Calibrationdata: \(c)" - } - - public var debugDescription: String { - - return [ - "## LibreTransmitterManager", - "Testdata: foo", - "lastConnected: \(String(describing: lastConnected))", - "Connection state: \(connectionState)", - "Sensor state: \(sensorStateDescription)", - "transmitterbattery: \(batteryString)", - "SensorData: \(getPersistedSensorDataForDebug())", - "Metainfo::\n\(AppMetaData.allProperties)", - "" - ].joined(separator: "\n") - } - - public private(set) var lastConnected: Date? - - public private(set) var latestPrediction: LibreGlucose? - public private(set) var latestBackfill: LibreGlucose? { - willSet(newValue) { - guard let newValue = newValue else { - return - } - - var trend: GlucoseTrend? - let oldValue = latestBackfill - - logger.debug("dabear:: latestBackfill set, newvalue is \(newValue.description)") - - if let oldValue = oldValue { - // the idea here is to use the diff between the old and the new glucose to calculate slope and direction, rather than using trend from the glucose value. - // this is because the old and new glucose values represent earlier readouts, while the trend buffer contains somewhat more jumpy (noisy) values. - let timediff = LibreGlucose.timeDifference(oldGlucose: oldValue, newGlucose: newValue) - logger.debug("dabear:: timediff is \(timediff)") - let oldIsRecentEnough = timediff <= TimeInterval.minutes(15) - - trend = oldIsRecentEnough ? newValue.GetGlucoseTrend(last: oldValue) : nil - - var batteries : [(name: String, percentage: Int)]? - if let metaData = metaData, let battery = battery { - batteries = [(name: metaData.name, percentage: battery)] - } - - self.glucoseDisplay = ConcreteGlucoseDisplayable(isStateValid: newValue.isStateValid, trendType: trend, isLocal: true, batteries: batteries) - } else { - //could consider setting this to ConcreteSensorDisplayable with trendtype GlucoseTrend.flat, but that would be kinda lying - self.glucoseDisplay = nil - } - } - - } - - static public var managerIdentifier : String { - Self.className - } - - static public let localizedTitle = LocalizedString("Libre Bluetooth", comment: "Title for the CGMManager option") - - - - public init() { - lastConnected = nil - //let isui = (self is CGMManagerUI) - //self.miaomiaoService = MiaomiaoService(keychainManager: keychain) - logger.debug("dabear: LibreTransmitterManager will be created now") - //proxy = MiaoMiaoBluetoothManager() - proxy?.delegate = self - } - - public func disconnect() { - logger.debug("dabear:: LibreTransmitterManager disconnect called") - - proxy?.disconnectManually() - proxy?.delegate = nil - } - - deinit { - logger.debug("dabear:: LibreTransmitterManager deinit called") - //cleanup any references to events to this class - disconnect() - } - - //lazy because we don't want to scan immediately - private lazy var proxy: LibreTransmitterProxyManager? = LibreTransmitterProxyManager() - - /* - These properties are mostly useful for swiftui - */ - public var transmitterInfoObservable = TransmitterInfo() - public var sensorInfoObservable = SensorInfo() - public var glucoseInfoObservable = GlucoseInfo() - - - - var longDateFormatter : DateFormatter = ({ - let df = DateFormatter() - df.dateStyle = .long - df.timeStyle = .long - df.doesRelativeDateFormatting = true - return df - })() - - var dateFormatter : DateFormatter = ({ - let df = DateFormatter() - df.dateStyle = .long - df.timeStyle = .full - df.locale = Locale.current - return df - })() - - - //when was the libre2 direct ble update last received? - var lastDirectUpdate : Date? = nil - - private var countTimesWithoutData: Int = 0 - - -} - - -// MARK: - Convenience functions -extension LibreTransmitterManager { - func setObservables(sensorData: SensorData?, bleData: Libre2.LibreBLEResponse?, metaData: LibreTransmitterMetadata?) { - logger.debug("dabear:: setObservables called") - DispatchQueue.main.async { - - - if let metaData=metaData { - self.logger.debug("dabear::will set transmitterInfoObservable") - self.transmitterInfoObservable.battery = metaData.batteryString - self.transmitterInfoObservable.hardware = metaData.hardware - self.transmitterInfoObservable.firmware = metaData.firmware - self.transmitterInfoObservable.sensorType = metaData.sensorType()?.description ?? "Unknown" - self.transmitterInfoObservable.transmitterIdentifier = metaData.macAddress ?? UserDefaults.standard.preSelectedDevice ?? "Unknown" - - - } - - self.transmitterInfoObservable.connectionState = self.proxy?.connectionStateString ?? "n/a" - self.transmitterInfoObservable.transmitterType = self.proxy?.shortTransmitterName ?? "Unknown" - - if let sensorData = sensorData { - self.logger.debug("dabear::will set sensorInfoObservable") - self.sensorInfoObservable.sensorAge = sensorData.humanReadableSensorAge - self.sensorInfoObservable.sensorAgeLeft = sensorData.humanReadableTimeLeft - - self.sensorInfoObservable.sensorState = sensorData.state.description - self.sensorInfoObservable.sensorSerial = sensorData.serialNumber - - self.glucoseInfoObservable.checksum = String(sensorData.footerCrc.byteSwapped) - - - - if let sensorEndTime = sensorData.sensorEndTime { - self.sensorInfoObservable.sensorEndTime = self.dateFormatter.string(from: sensorEndTime ) - - } else { - self.sensorInfoObservable.sensorEndTime = "Unknown or ended" - - } - - } else if let bleData = bleData, let sensor = UserDefaults.standard.preSelectedSensor { - let aday = 86_400.0 //in seconds - var humanReadableSensorAge: String { - let days = TimeInterval(bleData.age * 60) / aday - return String(format: "%.2f", days) + NSLocalizedString(" day(s)", comment: "Sensor day(s)") - } - - - var maxMinutesWearTime : Int{ - sensor.maxAge - } - - var minutesLeft: Int { - maxMinutesWearTime - bleData.age - } - - - var humanReadableTimeLeft: String { - let days = TimeInterval(minutesLeft * 60) / aday - return String(format: "%.2f", days) + NSLocalizedString(" day(s)", comment: "Sensor day(s)") - } - - //once the sensor has ended we don't know the exact date anymore - var sensorEndTime: Date? { - if minutesLeft <= 0 { - return nil - } - - // we can assume that the libre2 direct bluetooth packet is received immediately - // after the sensor has been done a new measurement, so using Date() should be fine here - return Date().addingTimeInterval(TimeInterval(minutes: Double(minutesLeft))) - } - - self.sensorInfoObservable.sensorAge = humanReadableSensorAge - self.sensorInfoObservable.sensorAgeLeft = humanReadableTimeLeft - self.sensorInfoObservable.sensorState = "Operational" - self.sensorInfoObservable.sensorState = "Operational" - self.sensorInfoObservable.sensorSerial = SensorSerialNumber(withUID: sensor.uuid)?.serialNumber ?? "-" - - if let mapping = UserDefaults.standard.calibrationMapping, - let calibration = self.calibrationData , - mapping.uuid == sensor.uuid && calibration.isValidForFooterWithReverseCRCs == mapping.reverseFooterCRC { - self.glucoseInfoObservable.checksum = "\(mapping.reverseFooterCRC)" - } - - if let sensorEndTime = sensorEndTime { - self.sensorInfoObservable.sensorEndTime = self.dateFormatter.string(from: sensorEndTime ) - - } else { - self.sensorInfoObservable.sensorEndTime = "Unknown or ended" - - } - - } - - let formatter = QuantityFormatter() - let preferredUnit = UserDefaults.standard.mmGlucoseUnit ?? .millimolesPerLiter - - - if let d = self.latestBackfill { - self.logger.debug("dabear::will set glucoseInfoObservable") - - formatter.setPreferredNumberFormatter(for: .millimolesPerLiter) - self.glucoseInfoObservable.glucoseMMOL = formatter.string(from: d.quantity, for: .millimolesPerLiter) ?? "-" - - - formatter.setPreferredNumberFormatter(for: .milligramsPerDeciliter) - self.glucoseInfoObservable.glucoseMGDL = formatter.string(from: d.quantity, for: .milligramsPerDeciliter) ?? "-" - - //backward compat - if preferredUnit == .millimolesPerLiter { - self.glucoseInfoObservable.glucose = self.glucoseInfoObservable.glucoseMMOL - } else if preferredUnit == .milligramsPerDeciliter { - self.glucoseInfoObservable.glucose = self.glucoseInfoObservable.glucoseMGDL - } - - - - self.glucoseInfoObservable.date = self.longDateFormatter.string(from: d.timestamp) - } - - if let d = self.latestPrediction { - formatter.setPreferredNumberFormatter(for: .millimolesPerLiter) - self.glucoseInfoObservable.predictionMMOL = formatter.string(from: d.quantity, for: .millimolesPerLiter) ?? "-" - - - formatter.setPreferredNumberFormatter(for: .milligramsPerDeciliter) - self.glucoseInfoObservable.predictionMGDL = formatter.string(from: d.quantity, for: .milligramsPerDeciliter) ?? "-" - self.glucoseInfoObservable.predictionDate = self.longDateFormatter.string(from: d.timestamp) - - - } - - - - - - } - - - } - - func getStartDateForFilter() -> Date?{ - var startDate: Date? - - self.delegateQueue.sync { - startDate = self.cgmManagerDelegate?.startDateToFilterNewData(for: self) ?? self.latestBackfill?.startDate - } - - // add one second to startdate to make this an exclusive (non overlapping) match - return startDate?.addingTimeInterval(1) - } - - func glucosesToSamplesFilter(_ array: [LibreGlucose], startDate: Date?) -> [LibreGlucose] { - array - .filterDateRange(startDate, nil) - .filter { $0.isStateValid } - .compactMap { $0 } - } - - public var calibrationData: SensorData.CalibrationInfo? { - KeychainManagerWrapper.standard.getLibreNativeCalibrationData() - } -} - - -// MARK: - Direct bluetooth updates -extension LibreTransmitterManager { - - public func libreSensorDidUpdate(with bleData: Libre2.LibreBLEResponse, and device: LibreTransmitterMetadata) { - self.logger.debug("dabear:: got sensordata: \(String(describing: bleData))") - let typeDesc = device.sensorType().debugDescription - - let now = Date() - //only once per mins minute - let mins = 4.5 - if let earlierplus = lastDirectUpdate?.addingTimeInterval(mins * 60), earlierplus >= now { - logger.debug("last ble update was less than \(mins) minutes ago, aborting loop update") - return - } - - logger.debug("Directly connected to libresensor of type \(typeDesc). Details: \(device.description)") - - guard let mapping = UserDefaults.standard.calibrationMapping, - let calibrationData = calibrationData, - let sensor = UserDefaults.standard.preSelectedSensor else { - logger.error("calibrationdata, sensor uid or mapping missing, could not continue") - self.delegateQueue.async { - self.cgmManagerDelegate?.cgmManager(self, hasNew: .failure(LibreError.noCalibrationData)) - } - return - } - - guard mapping.reverseFooterCRC == calibrationData.isValidForFooterWithReverseCRCs && - mapping.uuid == sensor.uuid else { - logger.error("Calibrationdata was not correct for these bluetooth packets. This is a fatal error, we cannot calibrate without re-pairing") - self.delegateQueue.async { - self.cgmManagerDelegate?.cgmManager(self, hasNew: .failure(LibreError.noCalibrationData)) - } - return - } - - guard bleData.crcVerified else { - self.delegateQueue.async { - self.cgmManagerDelegate?.cgmManager(self, hasNew: .failure(LibreError.checksumValidationError)) - } - - logger.debug("did not get bledata with valid crcs") - return - } - - if sensor.maxAge > 0 { - let minutesLeft = Double(sensor.maxAge - bleData.age) - NotificationHelper.sendSensorExpireAlertIfNeeded(minutesLeft: minutesLeft) - - } - - let sensorStartDate = Date().addingTimeInterval(-1 * TimeInterval(minutes: Double(bleData.age))) - NSLog("Libre age \(bleData.age), Start Date calculated: \(sensorStartDate)") - -// let device = self.proxy?.device - - - - let sortedTrends = bleData.trend.sorted{ $0.date > $1.date} - - let glucose = LibreGlucose.fromTrendMeasurements(sortedTrends, nativeCalibrationData: calibrationData, returnAll: UserDefaults.standard.mmBackfillFromTrend, sensorStartDate: sensorStartDate) - //glucose += LibreGlucose.fromHistoryMeasurements(bleData.history, nativeCalibrationData: calibrationData) - // while libre2 fram scans contains historymeasurements for the last 8 hours, - // history from bledata contains just a couple of data points, so we don't bother - /*if UserDefaults.standard.mmBackfillFromHistory { - let sortedHistory = bleData.history.sorted{ $0.date > $1.date} - glucose += LibreGlucose.fromHistoryMeasurements(sortedHistory, nativeCalibrationData: calibrationData) - }*/ - - var newGlucose = glucosesToSamplesFilter(glucose, startDate: getStartDateForFilter()) - - if newGlucose.isEmpty { - self.countTimesWithoutData &+= 1 - } else { - self.latestBackfill = glucose.max { $0.startDate < $1.startDate } - self.logger.debug("dabear:: latestbackfill set to \(self.latestBackfill.debugDescription)") - self.countTimesWithoutData = 0 - } - - //todo: predictions also for libre2 bluetooth data - //self.latestPrediction = prediction?.first - var predictions: [LibreGlucose] = [] - - overcalibrate(entries: &newGlucose, prediction: &predictions) - - self.setObservables(sensorData: nil, bleData: bleData, metaData: device) - - self.logger.debug("dabear:: handleGoodReading returned with \(newGlucose.count) entries") - self.delegateQueue.async { - var result: Result<[LibreGlucose], Error> - // If several readings from a valid and running sensor come out empty, - // we have (with a large degree of confidence) a sensor that has been - // ripped off the body - if self.countTimesWithoutData > 1 { - result = .failure(LibreError.noValidSensorData) - } else { - result = .success(newGlucose) - } - self.cgmManagerDelegate?.cgmManager(self, hasNew: result) - } - - lastDirectUpdate = Date() - - } -} - -// MARK: - Bluetooth transmitter data -extension LibreTransmitterManager { - - public func noLibreTransmitterSelected() { - NotificationHelper.sendNoTransmitterSelectedNotification() - } - - public func libreTransmitterDidUpdate(with sensorData: SensorData, and device: LibreTransmitterMetadata) { - - self.logger.debug("dabear:: got sensordata: \(String(describing: sensorData)), bytescount: \( sensorData.bytes.count), bytes: \(sensorData.bytes)") - var sensorData = sensorData - - NotificationHelper.sendLowBatteryNotificationIfNeeded(device: device) - self.setObservables(sensorData: sensorData, bleData: nil, metaData: device) - - if !sensorData.isLikelyLibre1FRAM { - if let patchInfo = device.patchInfo, let sensorType = SensorType(patchInfo: patchInfo) { - let needsDecryption = [SensorType.libre2, .libreUS14day].contains(sensorType) - if needsDecryption, let uid = device.uid { - sensorData.decrypt(patchInfo: patchInfo, uid: uid) - } - } else { - logger.debug("Sensor type was incorrect, and no decryption of sensor was possible") - self.cgmManagerDelegate?.cgmManager(self, hasNew: .failure(LibreError.encryptedSensor)) - return - } - } - - let typeDesc = device.sensorType().debugDescription - - logger.debug("Transmitter connected to libresensor of type \(typeDesc). Details: \(device.description)") - - tryPersistSensorData(with: sensorData) - - NotificationHelper.sendInvalidSensorNotificationIfNeeded(sensorData: sensorData) - NotificationHelper.sendInvalidChecksumIfDeveloper(sensorData) - - - - guard sensorData.hasValidCRCs else { - self.delegateQueue.async { - self.cgmManagerDelegate?.cgmManager(self, hasNew: .failure(LibreError.checksumValidationError)) - } - - logger.debug("did not get sensordata with valid crcs") - return - } - - NotificationHelper.sendSensorExpireAlertIfNeeded(sensorData: sensorData) - - guard sensorData.state == .ready || sensorData.state == .starting else { - logger.debug("dabear:: got sensordata with valid crcs, but sensor is either expired or failed") - self.delegateQueue.async { - self.cgmManagerDelegate?.cgmManager(self, hasNew: .failure(LibreError.expiredSensor)) - } - return - } - - logger.debug("dabear:: got sensordata with valid crcs, sensor was ready") -// self.lastValidSensorData = sensorData - - - self.handleGoodReading(data: sensorData) { [weak self] error, glucoseArrayWithPrediction in - guard let self = self else { - print("dabear:: handleGoodReading could not lock on self, aborting") - return - } - if let error = error { - self.logger.error("dabear:: handleGoodReading returned with error: \(error.errorDescription)") - self.delegateQueue.async { - self.cgmManagerDelegate?.cgmManager(self, hasNew: .failure(error)) - } - return - } - - - guard let glucose = glucoseArrayWithPrediction?.glucose else { - self.logger.debug("dabear:: handleGoodReading returned with no data") - self.delegateQueue.async { - self.cgmManagerDelegate?.cgmManager(self, hasNew: .success([])) - } - return - } - - let prediction = glucoseArrayWithPrediction?.prediction - - - -// let device = self.proxy?.device - let newGlucose = self.glucosesToSamplesFilter(glucose, startDate: self.getStartDateForFilter()) - - - - if newGlucose.isEmpty { - self.countTimesWithoutData &+= 1 - } else { - self.latestBackfill = glucose.max { $0.startDate < $1.startDate } - self.logger.debug("dabear:: latestbackfill set to \(self.latestBackfill.debugDescription)") - self.countTimesWithoutData = 0 - } - - self.latestPrediction = prediction?.first - - //must be inside this handler as setobservables "depend" on latestbackfill - self.setObservables(sensorData: sensorData, bleData: nil, metaData: nil) - - self.logger.debug("dabear:: handleGoodReading returned with \(newGlucose.count) entries") - self.delegateQueue.async { - var result: Result<[LibreGlucose], Error> - // If several readings from a valid and running sensor come out empty, - // we have (with a large degree of confidence) a sensor that has been - // ripped off the body - if self.countTimesWithoutData > 1 { - result = .failure(LibreError.noValidSensorData) - } else { - result = .success(newGlucose) - } - self.cgmManagerDelegate?.cgmManager(self, hasNew: result) - } - } - - } - private func readingToGlucose(_ data: SensorData, calibration: SensorData.CalibrationInfo) -> GlucoseArrayWithPrediction { - - var entries: [LibreGlucose] = [] - var prediction: [LibreGlucose] = [] - - let predictGlucose = true - - // Increase to up to 15 to move closer to real blood sugar - // The cost is slightly more noise on consecutive readings - let glucosePredictionMinutes : Double = 10 - - if predictGlucose { - // We cheat here by forcing the loop to think that the predicted glucose value is the current blood sugar value. - logger.debug("Predicting glucose value") - if let predicted = data.predictBloodSugar(glucosePredictionMinutes){ - let currentBg = predicted.roundedGlucoseValueFromRaw2(calibrationInfo: calibration) - let bgDate = predicted.date.addingTimeInterval(60 * -glucosePredictionMinutes) - - prediction.append(LibreGlucose(unsmoothedGlucose: currentBg, glucoseDouble: currentBg, timestamp: bgDate)) - logger.debug("Predicted glucose (not used) was: \(currentBg)") - } else { - logger.debug("Tried to predict glucose value but failed!") - } - - } - - let trends = data.trendMeasurements() - let firstTrend = trends.first?.roundedGlucoseValueFromRaw2(calibrationInfo: calibration) - logger.debug("first trend was: \(String(describing: firstTrend))") - entries = LibreGlucose.fromTrendMeasurements(trends, nativeCalibrationData: calibration, returnAll: UserDefaults.standard.mmBackfillFromTrend) - - if UserDefaults.standard.mmBackfillFromHistory { - let history = data.historyMeasurements() - entries += LibreGlucose.fromHistoryMeasurements(history, nativeCalibrationData: calibration) - } - - overcalibrate(entries: &entries, prediction: &prediction) - - return (glucose: entries, prediction: prediction) - } - - private func overcalibrate(entries: inout [LibreGlucose], prediction: inout [LibreGlucose]) { - // overcalibrate - var overcalibration: ((Double) -> (Double))? = nil - delegateQueue.sync { overcalibration = cgmManagerDelegate?.overcalibration(for: self) } - - if let overcalibration = overcalibration { - func overcalibrate(entries: [LibreGlucose]) -> [LibreGlucose] { - entries.map { entry in - var entry = entry - entry.glucoseDouble = overcalibration(entry.glucoseDouble) - return entry - } - } - - entries = overcalibrate(entries: entries) - prediction = overcalibrate(entries: prediction) - } - } - - public func handleGoodReading(data: SensorData?, _ callback: @escaping (LibreError?, GlucoseArrayWithPrediction?) -> Void) { - //only care about the once per minute readings here, historical data will not be considered - guard let data = data else { - callback(.noSensorData, nil) - return - } - - - if let calibrationdata = calibrationData { - logger.debug("dabear:: calibrationdata loaded") - - if calibrationdata.isValidForFooterWithReverseCRCs == data.footerCrc.byteSwapped { - logger.debug("dabear:: calibrationdata correct for this sensor, returning last values") - - callback(nil, readingToGlucose(data, calibration: calibrationdata)) - return - } else { - logger.debug("dabear:: calibrationdata incorrect for this sensor, calibrationdata.isValidForFooterWithReverseCRCs: \(calibrationdata.isValidForFooterWithReverseCRCs), data.footerCrc.byteSwapped: \(data.footerCrc.byteSwapped)") - } - } else { - logger.debug("dabear:: calibrationdata was nil") - } - - calibrateSensor(sensordata: data) { [weak self] calibrationparams in - do { - try KeychainManagerWrapper.standard.setLibreNativeCalibrationData(calibrationparams) - } catch { - NotificationHelper.sendCalibrationNotification(.invalidCalibrationData) - callback(.invalidCalibrationData, nil) - return - } - //here we assume success, data is not changed, - //and we trust that the remote endpoint returns correct data for the sensor - NotificationHelper.sendCalibrationNotification(.success) - callback(nil, self?.readingToGlucose(data, calibration: calibrationparams)) - } - } - - //will be called on utility queue - public func libreTransmitterStateChanged(_ state: BluetoothmanagerState) { - DispatchQueue.main.async { - self.transmitterInfoObservable.connectionState = self.proxy?.connectionStateString ?? "n/a" - self.transmitterInfoObservable.transmitterType = self.proxy?.shortTransmitterName ?? "Unknown" - } - switch state { - case .Connected: - lastConnected = Date() - case .powerOff: - NotificationHelper.sendBluetoothPowerOffNotification() - default: - break - } - return - } - - //will be called on utility queue - public func libreTransmitterReceivedMessage(_ messageIdentifier: UInt16, txFlags: UInt8, payloadData: Data) { - guard let packet = MiaoMiaoResponseState(rawValue: txFlags) else { - // Incomplete package? - // this would only happen if delegate is called manually with an unknown txFlags value - // this was the case for readouts that were not yet complete - // but that was commented out in MiaoMiaoManager.swift, see comment there: - // "dabear-edit: don't notify on incomplete readouts" - logger.debug("dabear:: incomplete package or unknown response state") - return - } - - switch packet { - case .newSensor: - logger.debug("dabear:: new libresensor detected") - NotificationHelper.sendSensorChangeNotificationIfNeeded() - NotificationCenter.default.post(name: .newSensorDetected, object: nil) - case .noSensor: - logger.debug("dabear:: no libresensor detected") - NotificationHelper.sendSensorNotDetectedNotificationIfNeeded(noSensor: true) - case .frequencyChangedResponse: - logger.debug("dabear:: transmitter readout interval has changed!") - - default: - //we don't care about the rest! - break - } - - return - } - - func tryPersistSensorData(with sensorData: SensorData) { - guard UserDefaults.standard.shouldPersistSensorData else { - return - } - - //yeah, we really really need to persist any changes right away - var data = UserDefaults.standard.queuedSensorData ?? LimitedQueue() - data.enqueue(sensorData) - UserDefaults.standard.queuedSensorData = data - } -} - -// MARK: - conventience properties to access the enclosed proxy's properties -extension LibreTransmitterManager { - public var device: HKDevice? { - //proxy?.OnQueue_device - proxy?.device - } - - static var className: String { - String(describing: Self.self) - } - //cannot be called from managerQueue - public var identifier: String { - //proxy?.OnQueue_identifer?.uuidString ?? "n/a" - proxy?.identifier?.uuidString ?? "n/a" - } - - public var metaData: LibreTransmitterMetadata? { - //proxy?.OnQueue_metadata - proxy?.metadata - } - - //cannot be called from managerQueue - public var connectionState: String { - //proxy?.connectionStateString ?? "n/a" - proxy?.connectionStateString ?? "n/a" - } - //cannot be called from managerQueue - public var sensorSerialNumber: String { - //proxy?.OnQueue_sensorData?.serialNumber ?? "n/a" - proxy?.sensorData?.serialNumber ?? "n/a" - } - - public var sensorStartDate: Date? { - proxy?.sensorData?.sensorStartTime - } - - - //cannot be called from managerQueue - public var sensorAge: String { - //proxy?.OnQueue_sensorData?.humanReadableSensorAge ?? "n/a" - proxy?.sensorData?.humanReadableSensorAge ?? "n/a" - } - - public var sensorEndTime : String { - if let endtime = proxy?.sensorData?.sensorEndTime { - let mydf = DateFormatter() - mydf.dateStyle = .long - mydf.timeStyle = .full - mydf.locale = Locale.current - return mydf.string(from: endtime) - } - return "Unknown or Ended" - } - - public var sensorTimeLeft: String { - //proxy?.OnQueue_sensorData?.humanReadableSensorAge ?? "n/a" - proxy?.sensorData?.humanReadableTimeLeft ?? "n/a" - } - - //cannot be called from managerQueue - public var sensorFooterChecksums: String { - //(proxy?.OnQueue_sensorData?.footerCrc.byteSwapped).map(String.init) - (proxy?.sensorData?.footerCrc.byteSwapped).map(String.init) - - ?? "n/a" - } - - - - //cannot be called from managerQueue - public var sensorStateDescription: String { - //proxy?.OnQueue_sensorData?.state.description ?? "n/a" - proxy?.sensorData?.state.description ?? "n/a" - } - //cannot be called from managerQueue - public var firmwareVersion: String { - proxy?.metadata?.firmware ?? "n/a" - } - - //cannot be called from managerQueue - public var hardwareVersion: String { - proxy?.metadata?.hardware ?? "n/a" - } - - //cannot be called from managerQueue - public var batteryString: String { - proxy?.metadata?.batteryString ?? "n/a" - } - - public var battery: Int? { - proxy?.metadata?.battery - } - - public func getDeviceType() -> String { - proxy?.shortTransmitterName ?? "Unknown" - } - public func getSmallImage() -> UIImage? { - proxy?.activePluginType?.smallImage ?? UIImage(named: "libresensor", in: Bundle.module, compatibleWith: nil) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Controllers/LibreTransmitterSetupViewController.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Controllers/LibreTransmitterSetupViewController.swift deleted file mode 100644 index ca451d745..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Controllers/LibreTransmitterSetupViewController.swift +++ /dev/null @@ -1,115 +0,0 @@ -// -// MiaomiaoClientSetupViewController.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Combine -import SwiftUI -import UIKit -import os.log -import HealthKit - -public protocol CGMManagerSetupViewController { - var setupDelegate: CGMManagerSetupViewControllerDelegate? { get set } -} - -public protocol CGMManagerSetupViewControllerDelegate: AnyObject { - func cgmManagerSetupViewController(_ cgmManagerSetupViewController: CGMManagerSetupViewController, didSetUpCGMManager cgmManager: LibreTransmitterManager) -} - -class LibreTransmitterSetupViewController: UINavigationController, - CGMManagerSetupViewController, - - CompletionNotifying { - - weak var setupDelegate: CGMManagerSetupViewControllerDelegate? - weak var completionDelegate: CompletionDelegate? - - var modeSelection: UIHostingController! - - fileprivate var logger = Logger.init(subsystem: "no.bjorninge.libre", category: "LibreTransmitterSetupViewController") - lazy var cgmManager: LibreTransmitterManager? = LibreTransmitterManager() - - - init() { - SelectionState.shared.selectedStringIdentifier = UserDefaults.standard.preSelectedDevice - - let cancelNotifier = GenericObservableObject() - let saveNotifier = GenericObservableObject() - - modeSelection = UIHostingController(rootView: ModeSelectionView(cancelNotifier: cancelNotifier, saveNotifier: saveNotifier)) - - - super.init(rootViewController: modeSelection) - - - cancelNotifier.listenOnce { [weak self] in - self?.cancel() - } - - saveNotifier.listenOnce { [weak self] in - self?.save() - } - - } - - override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { - super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) - } - - deinit { - logger.debug("dabear LibreTransmitterSetupViewController() deinit was called") - //cgmManager = nil - } - - @available(*, unavailable) - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - @objc - private func cancel() { - completionDelegate?.completionNotifyingDidComplete(self) - - } - - @objc - private func save() { - - let hasNewDevice = SelectionState.shared.selectedStringIdentifier != UserDefaults.standard.preSelectedDevice - if hasNewDevice, let newDevice = SelectionState.shared.selectedStringIdentifier { - logger.debug("dabear: Setupcontroller will set new device to \(newDevice)") - UserDefaults.standard.preSelectedDevice = newDevice - SelectionState.shared.selectedUID = nil - UserDefaults.standard.preSelectedUid = nil - - } else if let newUID = SelectionState.shared.selectedUID { - // this one is only temporary, - // as we don't know the bluetooth identifier during nfc setup - logger.debug("dabear: Setupcontroller will set new libre2 device to \(newUID)") - - UserDefaults.standard.preSelectedUid = newUID - SelectionState.shared.selectedUID = nil - UserDefaults.standard.preSelectedDevice = nil - - - } else { - - //this cannot really happen unless you are a developer and have previously - // stored both preSelectedDevice and selectedUID ! - } - - if let cgmManager = cgmManager { - logger.debug("dabear: Setupcontroller Saving from setup") - setupDelegate?.cgmManagerSetupViewController(self, didSetUpCGMManager: cgmManager) - - } else { - logger.debug("dabear: Setupcontroller not Saving from setup") - } - - - completionDelegate?.completionNotifyingDidComplete(self) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/bubble.png b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/bubble.png deleted file mode 100644 index bfb323c26..000000000 Binary files a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/bubble.png and /dev/null differ diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/ic_bubble_mini_3-2.png b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/ic_bubble_mini_3-2.png deleted file mode 100644 index 280b58eb1..000000000 Binary files a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/ic_bubble_mini_3-2.png and /dev/null differ diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-down-arrow-50.png b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-down-arrow-50.png deleted file mode 100644 index 404412d10..000000000 Binary files a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-down-arrow-50.png and /dev/null differ diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-drop-down-arrow-50.png b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-drop-down-arrow-50.png deleted file mode 100644 index fe8055166..000000000 Binary files a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-drop-down-arrow-50.png and /dev/null differ diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-schedule-50.png b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-schedule-50.png deleted file mode 100644 index 397103da7..000000000 Binary files a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-schedule-50.png and /dev/null differ diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-slide-up-50.png b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-slide-up-50.png deleted file mode 100644 index 3ec8682e9..000000000 Binary files a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-slide-up-50.png and /dev/null differ diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-up-50.png b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-up-50.png deleted file mode 100644 index e02e5d5db..000000000 Binary files a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/icons8-up-50.png and /dev/null differ diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/libresensor.png b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/libresensor.png deleted file mode 100644 index a9e8ee286..000000000 Binary files a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/libresensor.png and /dev/null differ diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/miaomiao-small.png b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/miaomiao-small.png deleted file mode 100644 index d4fba9331..000000000 Binary files a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Graphics/miaomiao-small.png and /dev/null differ diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/LibreTransmitterManager+UI.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/LibreTransmitterManager+UI.swift deleted file mode 100644 index 8f62ac055..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/LibreTransmitterManager+UI.swift +++ /dev/null @@ -1,111 +0,0 @@ -import UIKit -import SwiftUI -import HealthKit - -public struct LibreTransmitterSetupView: UIViewControllerRepresentable { - public class Coordinator: CompletionDelegate, CGMManagerSetupViewControllerDelegate { - let completion: (() -> Void)? - let setup: ((LibreTransmitterManager) -> Void)? - - public func cgmManagerSetupViewController(_ cgmManagerSetupViewController: CGMManagerSetupViewController, didSetUpCGMManager cgmManager: LibreTransmitterManager) { - setup?(cgmManager) - } - - public func completionNotifyingDidComplete(_ object: CompletionNotifying) { - completion?() - } - - init(completion: (() -> Void)?, setup: ((LibreTransmitterManager) -> Void)?) { - self.completion = completion - self.setup = setup - } - } - - private let setup: ((LibreTransmitterManager) -> Void)? - private let completion: (() -> Void)? - - public init(setup: ((LibreTransmitterManager) -> Void)? = nil , completion: (() -> Void)? = nil) { - self.setup = setup - self.completion = completion - } - - public func makeUIViewController(context: Context) -> UIViewController { - let controller = LibreTransmitterSetupViewController() - controller.completionDelegate = context.coordinator - controller.setupDelegate = context.coordinator - return controller - } - - public func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} - - public func makeCoordinator() -> Coordinator { - Coordinator(completion: completion, setup: setup) - } -} - -public struct LibreTransmitterSettingsView: UIViewControllerRepresentable { - public class Coordinator: CompletionDelegate { - let completion: (() -> Void)? - let delete: (() -> Void)? - - public func completionNotifyingDidComplete(_ object: CompletionNotifying) { - completion?() - } - - init(completion: (() -> Void)?, delete: (() -> Void)?) { - self.completion = completion - self.delete = delete - } - } - - private weak var manager: LibreTransmitterManager! - private let glucoseUnit: HKUnit - private let delete: (() -> Void)? - private let completion: (() -> Void)? - - public init(manager: LibreTransmitterManager, glucoseUnit: HKUnit, delete: (() -> Void)? = nil , completion: (() -> Void)? = nil) { - self.manager = manager - self.glucoseUnit = glucoseUnit - self.delete = delete - self.completion = completion - } - - public func makeUIViewController(context: Context) -> UIViewController { - let doneNotifier = GenericObservableObject() - let wantToTerminateNotifier = GenericObservableObject() - - let settings = SettingsView.asHostedViewController( - glucoseUnit: glucoseUnit, - //displayGlucoseUnitObservable: displayGlucoseUnitObservable, - notifyComplete: doneNotifier, - notifyDelete: wantToTerminateNotifier, - transmitterInfoObservable: manager.transmitterInfoObservable, - sensorInfoObervable: manager.sensorInfoObservable, - glucoseInfoObservable: manager.glucoseInfoObservable - ) - - let nav = SettingsNavigationViewController(rootViewController: settings) - nav.navigationItem.title = NSLocalizedString("Libre Bluetooth", comment: "Libre Bluetooth") - nav.completionDelegate = context.coordinator - - doneNotifier.listenOnce { [weak nav] in - nav?.notifyComplete() - } - - wantToTerminateNotifier.listenOnce { [weak nav] in - manager.logger.debug("CGM wants to terminate") - manager.disconnect() - UserDefaults.standard.preSelectedDevice = nil - context.coordinator.delete?() - nav?.notifyComplete() - } - - return nav - } - - public func makeCoordinator() -> Coordinator { - Coordinator(completion: completion, delete: delete) - } - - public func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/SensorPairing/SensorPairing.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/SensorPairing/SensorPairing.swift deleted file mode 100644 index 795a0fcee..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/SensorPairing/SensorPairing.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// SensorPairing.swift -// LibreDirect -// -// Created by Reimar Metzen on 06.07.21. -// -import Foundation -import Combine - -class SensorPairingInfo : ObservableObject { - @Published private(set) var uuid: Data - @Published private(set) var patchInfo: Data - @Published private(set) var fram: Data - @Published private(set) var streamingEnabled: Bool - - public init(uuid: Data=Data(), patchInfo:Data=Data(), fram:Data=Data(), streamingEnabled: Bool = false) { - self.uuid = uuid - self.patchInfo = patchInfo - self.fram = fram - self.streamingEnabled = streamingEnabled - } - - var sensorData : SensorData? { - SensorData(bytes: [UInt8](self.fram)) - } - - var calibrationData : SensorData.CalibrationInfo? { - sensorData?.calibrationData - } - - - - -} - -protocol SensorPairingProtocol { - func pairSensor() -> AnyPublisher -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/SensorPairing/SensorPairingService.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/SensorPairing/SensorPairingService.swift deleted file mode 100644 index cee8b099b..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/SensorPairing/SensorPairingService.swift +++ /dev/null @@ -1,332 +0,0 @@ -// -// SensorPairingService.swift -// LibreDirect -// -// Created by Reimar Metzen on 06.07.21. -// - -#if canImport(CoreNFC) - -import Foundation -import Combine -import CoreNFC - -class SensorPairingService: NSObject, NFCTagReaderSessionDelegate, SensorPairingProtocol { - private var session: NFCTagReaderSession? - private var readingsSubject = PassthroughSubject() - - private let nfcQueue = DispatchQueue(label: "libre-direct.nfc-queue") - private let accessQueue = DispatchQueue(label: "libre-direct.nfc-access-queue") - - private let unlockCode: UInt32 = 42 //42 - - @discardableResult func pairSensor() -> AnyPublisher { - if NFCTagReaderSession.readingAvailable { - accessQueue.async { - self.session = NFCTagReaderSession(pollingOption: .iso15693, delegate: self, queue: self.nfcQueue) - self.session?.alertMessage = LocalizedString("Hold the top of your iPhone near the sensor to pair", comment: "") - self.session?.begin() - } - } - - return readingsSubject.eraseToAnyPublisher() - } - - public var publisher : AnyPublisher { - readingsSubject.eraseToAnyPublisher() - } - - private func sendUpdate(_ info: SensorPairingInfo) { - DispatchQueue.main.async { [weak self] in - self?.readingsSubject.send(info) - } - } - - internal func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) { - } - - internal func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) { - } - - internal func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) { - guard let firstTag = tags.first else { return } - guard case .iso15693(let tag) = firstTag else { return } - - let blocks = 43 - let requestBlocks = 3 - - let requests = Int(ceil(Double(blocks) / Double(requestBlocks))) - let remainder = blocks % requestBlocks - var dataArray = [Data](repeating: Data(), count: blocks) - - session.connect(to: firstTag) { error in - if error != nil { - return - } - - tag.getSystemInfo(requestFlags: [.address, .highDataRate]) { result in - switch result { - case .failure(_): - return - case .success(_): - tag.customCommand(requestFlags: .highDataRate, customCommandCode: 0xA1, customRequestParameters: Data()) { response, error in - - for i in 0 ..< requests { - tag.readMultipleBlocks( - requestFlags: [.highDataRate, .address], - blockRange: NSRange(UInt8(i * requestBlocks) ... UInt8(i * requestBlocks + (i == requests - 1 ? (remainder == 0 ? requestBlocks : remainder) : requestBlocks) - (requestBlocks > 1 ? 1 : 0))) - ) { blockArray, error in - if error != nil { - if i != requests - 1 { return } - } else { - for j in 0 ..< blockArray.count { - dataArray[i * requestBlocks + j] = blockArray[j] - } - } - - if i == requests - 1 { - var fram = Data() - - for (_, data) in dataArray.enumerated() { - if data.count > 0 { - fram.append(data) - } - } - - // get sensorUID and patchInfo and send to delegate - let sensorUID = Data(tag.identifier.reversed()) - let patchInfo = response - - // patchInfo should have length 6, which sometimes is not the case, as there are occuring crashes in nfcCommand and Libre2BLEUtilities.streamingUnlockPayload - guard patchInfo.count >= 6 else { - return - } - - - let subCmd: Subcommand = .enableStreaming - let cmd = self.nfcCommand(subCmd, unlockCode: self.unlockCode, patchInfo: patchInfo, sensorUID: sensorUID) - - tag.customCommand(requestFlags: .highDataRate, customCommandCode: Int(cmd.code), customRequestParameters: cmd.parameters) { response, error in - var streamingEnabled = false - - if subCmd == .enableStreaming && response.count == 6 { - streamingEnabled = true - } - - session.invalidate() - - - let patchHex = patchInfo.hexEncodedString() - let sensorType = SensorType(patchInfo: patchHex) - - print("got patchhex: \(patchHex) and sensorType: \(String(describing: sensorType))") - - - guard sensorUID.count == 8 && patchInfo.count == 6 && fram.count == 344 else { - //self.readingsSubject.send(completion: .failure(LibreError.noSensorData)) - return - } - - - if let sensorType = sensorType { - do { - let decryptedBytes = try Libre2.decryptFRAM(type: sensorType, id: [UInt8](sensorUID), info: [UInt8](patchInfo), data: [UInt8](fram)) - - self.sendUpdate(SensorPairingInfo(uuid: sensorUID, patchInfo: patchInfo, fram: Data(decryptedBytes), streamingEnabled: streamingEnabled)) - - return - } catch { - print("problem decrypting") - } - - self.sendUpdate(SensorPairingInfo(uuid: sensorUID, patchInfo: patchInfo, fram: fram, streamingEnabled: streamingEnabled)) - - } - } - - - } - } - } - } - } - } - } - } - - private func readRaw(_ address: UInt16, _ bytes: Int, buffer: Data = Data(), tag: NFCISO15693Tag, handler: @escaping (UInt16, Data, Error?) -> Void) { - var buffer = buffer - let addressToRead = address + UInt16(buffer.count) - - var remainingBytes = bytes - let bytesToRead = remainingBytes > 24 ? 24 : bytes - - var remainingWords = bytes / 2 - if bytes % 2 == 1 || (bytes % 2 == 0 && addressToRead % 2 == 1) { remainingWords += 1 } - let wordsToRead = UInt8(remainingWords > 12 ? 12 : remainingWords) // real limit is 15 - - // this is for libre 2 only, ignoring other libre types - let readRawCommand = NFCCommand(code: 0xB3, parameters: Data([UInt8(addressToRead & 0x00FF), UInt8(addressToRead >> 8), wordsToRead])) - - tag.customCommand(requestFlags: .highDataRate, customCommandCode: Int(readRawCommand.code), customRequestParameters: readRawCommand.parameters) { response, error in - var data = response - - if error != nil { - remainingBytes = 0 - } else { - if addressToRead % 2 == 1 { data = data.subdata(in: 1 ..< data.count) } - if data.count - Int(bytesToRead) == 1 { data = data.subdata(in: 0 ..< data.count - 1) } - } - - buffer += data - remainingBytes -= data.count - - if remainingBytes == 0 { - handler(address, buffer, error) - } else { - self.readRaw(address, remainingBytes, buffer: buffer, tag: tag) { address, data, error in handler(address, data, error) } - } - } - } - - private func writeRaw(_ address: UInt16, _ data: Data, tag: NFCISO15693Tag, handler: @escaping (UInt16, Data, Error?) -> Void) { - let backdoor = "deadbeef".utf8 - - tag.customCommand(requestFlags: .highDataRate, customCommandCode: 0xA4, customRequestParameters: Data(backdoor)) { - response, error in - - let addressToRead = (address / 8) * 8 - let startOffset = Int(address % 8) - let endAddressToRead = ((Int(address) + data.count - 1) / 8) * 8 + 7 - let blocksToRead = (endAddressToRead - Int(addressToRead)) / 8 + 1 - - self.readRaw(addressToRead, blocksToRead * 8, tag: tag) { readAddress, readData, error in - if error != nil { - handler(address, data, error) - return - } - - var bytesToWrite = readData - bytesToWrite.replaceSubrange(startOffset ..< startOffset + data.count, with: data) - - let startBlock = Int(addressToRead / 8) - let blocks = bytesToWrite.count / 8 - - if address < 0xF860 { // lower than FRAM blocks - for i in 0 ..< blocks { - let blockToWrite = bytesToWrite[i * 8 ... i * 8 + 7] - - // FIXME: doesn't work as the custom commands C1 or A5 for other chips - tag.extendedWriteSingleBlock(requestFlags: .highDataRate, blockNumber: startBlock + i, dataBlock: blockToWrite) { error in - if error != nil { - if i != blocks - 1 { return } - } - - if i == blocks - 1 { - tag.customCommand(requestFlags: .highDataRate, customCommandCode: 0xA2, customRequestParameters: Data(backdoor)) { response, error in - handler(address, data, error) - } - } - } - } - - } else { // address >= 0xF860: write to FRAM blocks - let requestBlocks = 2 // 3 doesn't work - let requests = Int(ceil(Double(blocks) / Double(requestBlocks))) - let remainder = blocks % requestBlocks - var blocksToWrite = [Data](repeating: Data(), count: blocks) - - for i in 0 ..< blocks { - blocksToWrite[i] = Data(bytesToWrite[i * 8 ... i * 8 + 7]) - } - - for i in 0 ..< requests { - let startIndex = startBlock - 0xF860 / 8 + i * requestBlocks - let endIndex = startIndex + (i == requests - 1 ? (remainder == 0 ? requestBlocks : remainder) : requestBlocks) - (requestBlocks > 1 ? 1 : 0) - let blockRange = NSRange(UInt8(startIndex) ... UInt8(endIndex)) - - var dataBlocks = [Data]() - for j in startIndex ... endIndex { dataBlocks.append(blocksToWrite[j - startIndex]) } - - // TODO: write to 16-bit addresses as the custom cummand C4 for other chips - tag.writeMultipleBlocks(requestFlags: [.highDataRate, .address], blockRange: blockRange, dataBlocks: dataBlocks) { error in // TEST - if error != nil { - if i != requests - 1 { return } - } - - if i == requests - 1 { - // Lock - tag.customCommand(requestFlags: .highDataRate, customCommandCode: 0xA2, customRequestParameters: Data(backdoor)) { - response, error in - - handler(address, data, error) - } - } - } - } - } - } - } - } - - private func nfcCommand(_ code: Subcommand, unlockCode: UInt32, patchInfo: Data, sensorUID: Data) -> NFCCommand { - var b: [UInt8] = [] - var y: UInt16 - - if code == .enableStreaming { - // Enables Bluetooth on Libre 2. Returns peripheral MAC address to connect to. - // unlockCode could be any 32 bit value. The unlockCode and sensor Uid / patchInfo - // will have also to be provided to the login function when connecting to peripheral. - b = [UInt8(unlockCode & 0xFF), UInt8((unlockCode >> 8) & 0xFF), UInt8((unlockCode >> 16) & 0xFF), UInt8((unlockCode >> 24) & 0xFF)] - y = UInt16(patchInfo[4...5]) ^ UInt16(b[1], b[0]) - } else { - y = 0x1b6a - } - - let d = Libre2.usefulFunction(id: [UInt8](sensorUID), x: UInt16(code.rawValue), y: y) - - var parameters = Data([code.rawValue]) - - if code == .enableStreaming { - parameters += b - } - - parameters += d - - return NFCCommand(code: 0xA1, parameters: parameters) - } -} - -extension UInt16 { - init(_ high: UInt8, _ low: UInt8) { - self = UInt16(high) << 8 + UInt16(low) - } - - init(_ data: Data) { - self = UInt16(data[data.startIndex + 1]) << 8 + UInt16(data[data.startIndex]) - } -} - -fileprivate struct NFCCommand { - let code: UInt8 - let parameters: Data -} - -fileprivate enum Subcommand: UInt8, CustomStringConvertible { - case activate = 0x1b - case enableStreaming = 0x1e - case unknown0x1a = 0x1a - case unknown0x1c = 0x1c - case unknown0x1d = 0x1d - case unknown0x1f = 0x1f - - var description: String { - switch self { - case .activate: return "activate" - case .enableStreaming: return "enable BLE streaming" - default: return "[unknown: 0x\(String(format: "%x", rawValue))]" - } - } -} - -#endif diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/CalibrationEditView.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/CalibrationEditView.swift deleted file mode 100644 index 655f462e4..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/CalibrationEditView.swift +++ /dev/null @@ -1,135 +0,0 @@ -// -// CalibrationEditView.swift -// LibreTransmitterUI -// -// Created by Bjørn Inge Berg on 24/03/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import SwiftUI -import Combine - -struct CalibrationEditView: View { - typealias Params = SensorData.CalibrationInfo - - - - @State private var isPressed = false - - @State private var presentableStatus: StatusMessage? - - public var isReadOnly : Bool { - if debugMode { - return false - } - - return !hasExistingParams - } - - - @ObservedObject fileprivate var formstate = FormErrorState.shared - - - - - var saveButtonSection: some View{ - Section { - Button(action: { - print("calibrationsaving in progress") - - - self.isPressed.toggle() - - if formstate.hasAnyError { - presentableStatus = StatusMessage(title: "Could not save", message:"Some of the fields was not correctly entered") - return - } - - if false && isReadOnly { - presentableStatus = StatusMessage(title: "Could not save", message:"Calibration parameters are readonly and cannot be saved") - return - } - - do { - try KeychainManagerWrapper.standard.setLibreNativeCalibrationData(newParams) - print("calibrationsaving completed") - - presentableStatus = StatusMessage(title: "OK", message: "Calibrations saved!") - } catch { - print("error: \(error.localizedDescription)") - presentableStatus = StatusMessage(title: "Calibration error", message:"Calibrations could not be saved, Check that footer crc is non-zero and that all values have sane defaults") - } - - - }, label: { - Text("Save") - - }).buttonStyle(BlueButtonStyle()) - .alert(item: $presentableStatus) { status in - Alert(title: Text(status.title), message: Text(status.message) , dismissButton: .default(Text("Got it!"))) - } - - } - } - - var calibrationInputsSection : some View{ - Section { - NumericTextField(description: "i1", showDescription: true, numericValue: $newParams.i1, isReadOnly: isReadOnly) - NumericTextField(description: "i2", showDescription: true, numericValue: $newParams.i2, isReadOnly: isReadOnly) - NumericTextField(description: "i3", showDescription: true, numericValue: $newParams.i3, isReadOnly: isReadOnly) - NumericTextField(description: "i4", showDescription: true, numericValue: $newParams.i4, isReadOnly: isReadOnly) - NumericTextField(description: "i5", showDescription: true, numericValue: $newParams.i5, isReadOnly: isReadOnly) - NumericTextField(description: "i6", showDescription: true, numericValue: $newParams.i6, isReadOnly: isReadOnly) - } - } - - var validForSection : some View { - Section { - Text("Valid for footer: \(newParams.isValidForFooterWithReverseCRCs)") - - } - } - - var body: some View { - List { - calibrationInputsSection - validForSection - saveButtonSection - } - .listStyle(InsetGroupedListStyle()) - .navigationBarTitle("Calibration Edit") - } - - @ObservedObject private var newParams: Params - - private var debugMode = false - private var hasExistingParams = false - - public init(debugMode:Bool=false) { - self.debugMode = debugMode - - - if let params = KeychainManagerWrapper.standard.getLibreNativeCalibrationData() { - hasExistingParams = true - self.newParams = params - } else { - hasExistingParams = false - self.newParams = Params(i1: 1,i2: 2,i3: 3,i4: 4,i5: 5,i6: 5,isValidForFooterWithReverseCRCs: 1337) - } - - } - - - - - -} - -struct CalibrationEditView_Previews: PreviewProvider { - static var previews: some View { - //var testData = FormState.shared - //testData.childStates["i1"] = true - CalibrationEditView(debugMode: true) - - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/GlucoseSettingsView.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/GlucoseSettingsView.swift deleted file mode 100644 index 5eedf243d..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/GlucoseSettingsView.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// GlucoseSettingsView.swift -// LibreTransmitterUI -// -// Created by Bjørn Inge Berg on 26/05/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import SwiftUI -import Combine -import HealthKit - -struct GlucoseSettingsView: View { - - - @State private var presentableStatus: StatusMessage? - - - private var glucoseUnit: HKUnit - - public init(glucoseUnit: HKUnit) { - if let savedGlucoseUnit = UserDefaults.standard.mmGlucoseUnit { - self.glucoseUnit = savedGlucoseUnit - } else { - self.glucoseUnit = glucoseUnit - UserDefaults.standard.mmGlucoseUnit = glucoseUnit - } - - - - } - - @AppStorage("no.bjorninge.mmBackfillFromHistory") var mmBackfillFromHistory: Bool = true - @AppStorage("no.bjorninge.mmBackfillFromTrend") var mmBackfillFromTrend: Bool = false - @AppStorage("no.bjorninge.shouldPersistSensorData") var shouldPersistSensorData: Bool = false - - - - var body: some View { - List { - - Section(header: Text("Backfill options"), footer:Text("Backfilling from trend is currently not well supported by Loop") ) { - Toggle("Backfill from history", isOn:$mmBackfillFromHistory) - Toggle("Backfill from trend", isOn: $mmBackfillFromTrend) - } - - Section(header: Text("Debug options"), footer: Text("Adds a lot of data to the Issue Report ")) { - Toggle("Persist sensordata", isOn:$shouldPersistSensorData) - } - - } - .listStyle(InsetGroupedListStyle()) - .alert(item: $presentableStatus) { status in - Alert(title: Text(status.title), message: Text(status.message) , dismissButton: .default(Text("Got it!"))) - } - .navigationBarTitle("Glucose Settings") - - } - - - - -} - - -struct GlucoseSettingsView_Previews: PreviewProvider { - static var previews: some View { - GlucoseSettingsView(glucoseUnit: HKUnit.millimolesPerLiter) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/NotificationSettingsView.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/NotificationSettingsView.swift deleted file mode 100644 index b7c54ba28..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/NotificationSettingsView.swift +++ /dev/null @@ -1,129 +0,0 @@ -// -// NotificationSettingsView.swift -// LibreTransmitterUI -// -// Created by Bjørn Inge Berg on 27/05/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import SwiftUI -import Combine -import HealthKit - - -struct NotificationSettingsView: View { - - - - @State private var presentableStatus: StatusMessage? - - - private var glucoseUnit: HKUnit - - private let glucoseSegments = [HKUnit.millimolesPerLiter, HKUnit.milligramsPerDeciliter] - private lazy var glucoseSegmentStrings = self.glucoseSegments.map({ $0.localizedShortUnitString }) - - public init(glucoseUnit: HKUnit) { - if let savedGlucoseUnit = UserDefaults.standard.mmGlucoseUnit { - self.glucoseUnit = savedGlucoseUnit - } else { - self.glucoseUnit = glucoseUnit - UserDefaults.standard.mmGlucoseUnit = glucoseUnit - } - - - } - - - private enum Key: String { - case mmAlertLowBatteryWarning = "no.bjorninge.mmLowBatteryWarning" - case mmAlertInvalidSensorDetected = "no.bjorninge.mmInvalidSensorDetected" - //case mmAlertalarmNotifications - case mmAlertNewSensorDetected = "no.bjorninge.mmNewSensorDetected" - case mmAlertNoSensorDetected = "no.bjorninge.mmNoSensorDetected" - - case mmAlertSensorSoonExpire = "no.bjorninge.mmAlertSensorSoonExpire" - - //handle specially: - case mmGlucoseUnit = "no.bjorninge.mmGlucoseUnit" - } - - @AppStorage(Key.mmAlertLowBatteryWarning.rawValue) var mmAlertLowBatteryWarning: Bool = true - @AppStorage(Key.mmAlertInvalidSensorDetected.rawValue) var mmAlertInvalidSensorDetected: Bool = true - @AppStorage(Key.mmAlertNewSensorDetected.rawValue) var mmAlertNewSensorDetected: Bool = true - @AppStorage(Key.mmAlertNoSensorDetected.rawValue) var mmAlertNoSensorDetected: Bool = true - @AppStorage(Key.mmAlertSensorSoonExpire.rawValue) var mmAlertSensorSoonExpire: Bool = true - - //especially handled mostly for backward compat - @AppStorage(Key.mmGlucoseUnit.rawValue) var mmGlucoseUnit: String = "" - - - @State var notifyErrorState = FormErrorState() - - @State private var favoriteGlucoseUnit = 0 - - static let formatter = NumberFormatter() - - var additionalNotificationsSection : some View { - Section(header: Text("Additional notification types")) { - Toggle("Low battery", isOn:$mmAlertLowBatteryWarning) - Toggle("Invalid sensor", isOn:$mmAlertInvalidSensorDetected) - Toggle("Sensor change", isOn:$mmAlertNewSensorDetected) - Toggle("Sensor not found", isOn:$mmAlertNoSensorDetected) - Toggle("Sensor expires soon", isOn:$mmAlertSensorSoonExpire) - - } - } - - var miscSection : some View { - Section(header: Text("Misc")) { - HStack { - Text("Unit override") - Picker(selection: $favoriteGlucoseUnit, label: Text("Unit override")) { - Text(HKUnit.millimolesPerLiter.localizedShortUnitString).tag(0) - Text(HKUnit.milligramsPerDeciliter.localizedShortUnitString).tag(1) - } - .pickerStyle(SegmentedPickerStyle()) - .clipped() - } - } - } - - var body: some View { - List { - additionalNotificationsSection - - miscSection - .onAppear { - favoriteGlucoseUnit = glucoseSegments.firstIndex(of: glucoseUnit) ?? 0 - } - .onChange(of: favoriteGlucoseUnit){ newValue in - let newUnit = glucoseSegments[newValue] - if newUnit == HKUnit.milligramsPerDeciliter { - mmGlucoseUnit = "mgdl" - } else if newUnit == HKUnit.millimolesPerLiter { - mmGlucoseUnit = "mmol" - } - } - - } - .listStyle(InsetGroupedListStyle()) - .alert(item: $presentableStatus) { status in - Alert(title: Text(status.title), message: Text(status.message) , dismissButton: .default(Text("Got it!"))) - } - - .navigationBarTitle("Notification Settings") - - } - - - - -} - - -struct NotificationSettingsView_Previews: PreviewProvider { - static var previews: some View { - NotificationSettingsView(glucoseUnit: HKUnit.millimolesPerLiter) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/SettingsView.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/SettingsView.swift deleted file mode 100644 index 06af3ad0d..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/SettingsView.swift +++ /dev/null @@ -1,401 +0,0 @@ -// -// SettingsOverview.swift -// LibreTransmitterUI -// -// Created by Bjørn Inge Berg on 12/06/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import SwiftUI -import HealthKit -import UniformTypeIdentifiers - - -public struct SettingsItem: View { - @State var title: String = "" // we don't want this to change after it is set - @Binding var detail: String - - init(title: String, detail: Binding) { - self.title = title - self._detail = detail - } - - //basically allows caller to set a static string without having to use .constant - init(title: String, detail: String) { - self.title = title - self._detail = Binding(get: { - detail - }, set: { newVal in - //pass - }) - } - - public var body: some View { - HStack { - Text(NSLocalizedString(title, comment: "Item title")) - Spacer() - Text(detail).font(.subheadline) - } - - } -} - - -private class FactoryCalibrationInfo : ObservableObject, Equatable, Hashable{ - @Published var i1 = "" - @Published var i2 = "" - @Published var i3 = "" - @Published var i4 = "" - @Published var i5 = "" - @Published var i6 = "" - @Published var validForFooter = "" - - - // For swiftuis stateobject to be able to compare two objects for equality, - // we must exclude the publishers them selves in the comparison - - static func ==(lhs: FactoryCalibrationInfo, rhs: FactoryCalibrationInfo) -> Bool { - lhs.i1 == rhs.i1 && lhs.i2 == rhs.i2 && - lhs.i3 == rhs.i3 && lhs.i4 == rhs.i4 && - lhs.i5 == rhs.i5 && lhs.i6 == rhs.i6 && - lhs.validForFooter == rhs.validForFooter - - } - - //todo: consider using cgmmanagers observable directly - static func loadState() -> FactoryCalibrationInfo{ - - let newState = FactoryCalibrationInfo() - - // User editable calibrationdata: keychain.getLibreNativeCalibrationData() - // Default Calibrationdata stored in sensor: cgmManager?.calibrationData - - //do not change this, there is UI support for editing calibrationdata anyway - guard let c = KeychainManagerWrapper.standard.getLibreNativeCalibrationData() else { - return newState - } - - newState.i1 = String(c.i1) - newState.i2 = String(c.i2) - newState.i3 = String(c.i3) - newState.i4 = String(c.i4) - newState.i5 = String(c.i5) - newState.i6 = String(c.i6) - newState.validForFooter = String(c.isValidForFooterWithReverseCRCs) - - return newState - } - -} - -class SettingsModel : ObservableObject { - @Published fileprivate var factoryCalibrationInfos = [FactoryCalibrationInfo()] - -} - -struct SettingsView: View { - //@ObservedObject private var displayGlucoseUnitObservable: DisplayGlucoseUnitObservable - @ObservedObject private var transmitterInfo: LibreTransmitter.TransmitterInfo - @ObservedObject private var sensorInfo: LibreTransmitter.SensorInfo - - @ObservedObject private var glucoseMeasurement: LibreTransmitter.GlucoseInfo - - - @ObservedObject private var notifyComplete: GenericObservableObject - @ObservedObject private var notifyDelete: GenericObservableObject - - //most of the settings are now retrieved from the cgmmanager observables instead - @StateObject var model = SettingsModel() - @State private var presentableStatus: StatusMessage? - - @State private var showingDestructQuestion = false - @State private var showingExporter = false - //@Environment(\.presentationMode) var presentationMode - - - static func asHostedViewController( - glucoseUnit: HKUnit, - //displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, - notifyComplete: GenericObservableObject, - notifyDelete: GenericObservableObject, - transmitterInfoObservable:LibreTransmitter.TransmitterInfo, - sensorInfoObervable: LibreTransmitter.SensorInfo, - glucoseInfoObservable: LibreTransmitter.GlucoseInfo) -> UIHostingController { - UIHostingController(rootView: self.init( - //displayGlucoseUnitObservable: displayGlucoseUnitObservable, - transmitterInfo: transmitterInfoObservable, sensorInfo: sensorInfoObervable, glucoseMeasurement: glucoseInfoObservable, notifyComplete: notifyComplete, notifyDelete: notifyDelete, glucoseUnit: glucoseUnit - - )) - } - - - - - - /*private var glucoseUnit: HKUnit { - displayGlucoseUnitObservable.displayGlucoseUnit - }*/ - private var glucoseUnit: HKUnit { - didSet { - - UserDefaults.standard.mmGlucoseUnit = glucoseUnit - } - } - - static let formatter = NumberFormatter() - - // no navigationview necessary when running inside a uihostingcontroller - // uihostingcontroller seems to add a navigationview for us, causing problems if we - // also add one herer - var body: some View { - overview - //.navigationViewStyle(StackNavigationViewStyle()) - .navigationBarTitle(Text("Libre Bluetooth"), displayMode: .inline) - .navigationBarItems(leading: dismissButton) - .onAppear{ - print("dabear:: settingsview appeared") - //While loop does this request on our behalf, freeaps does not - NotificationHelper.requestNotificationPermissionsIfNeeded() - - //only override savedglucose unit if we haven't saved this locally before - if UserDefaults.standard.mmGlucoseUnit == nil { - UserDefaults.standard.mmGlucoseUnit = glucoseUnit - } - // Yes we load factory calibrationdata every time the view appears - // I know this is bad, but the calibrationdata is stored in - // the keychain and there is no simple way of wrapping the keychain - // as an observable in swiftui without bringing in large third party - // dependencies or hand crafting it, which would be error prone - - let newFactoryInfo = FactoryCalibrationInfo.loadState() - - if newFactoryInfo != self.model.factoryCalibrationInfos.first{ - print("dabear:: factoryinfo was new") - - self.model.factoryCalibrationInfos.removeAll() - self.model.factoryCalibrationInfos.append(newFactoryInfo) - - } - - } - - } - - var measurementSection : some View { - Section(header: Text("Last measurement")) { - if glucoseUnit == .millimolesPerLiter { - SettingsItem(title: "Glucose", detail: $glucoseMeasurement.glucoseMMOL) - } else if glucoseUnit == .milligramsPerDeciliter { - SettingsItem(title: "Glucose", detail: $glucoseMeasurement.glucoseMGDL) - } - - SettingsItem(title: "Date", detail: $glucoseMeasurement.date ) - SettingsItem(title: "Sensor Footer checksum", detail: $glucoseMeasurement.checksum ) - } - } - - var predictionSection : some View { - Section(header: Text("Last Blood Sugar prediction")) { - if glucoseUnit == .millimolesPerLiter { - SettingsItem(title: "CurrentBG", detail: $glucoseMeasurement.predictionMMOL) - } else if glucoseUnit == .milligramsPerDeciliter { - SettingsItem(title: "Glucose", detail: $glucoseMeasurement.predictionMGDL) - } - - SettingsItem(title: "Date", detail: $glucoseMeasurement.predictionDate ) - - } - } - - var sensorInfoSection : some View { - Section(header: Text("Sensor Info")) { - SettingsItem(title: "Sensor Age", detail: $sensorInfo.sensorAge ) - SettingsItem(title: "Sensor Age Left", detail: $sensorInfo.sensorAgeLeft ) - SettingsItem(title: "Sensor Endtime", detail: $sensorInfo.sensorEndTime ) - SettingsItem(title: "Sensor State", detail: $sensorInfo.sensorState ) - SettingsItem(title: "Sensor Serial", detail: $sensorInfo.sensorSerial ) - } - } - - - var transmitterInfoSection: some View { - Section(header: Text("Transmitter Info")) { - if !transmitterInfo.battery.isEmpty { - SettingsItem(title: "Battery", detail: $transmitterInfo.battery ) - } - SettingsItem(title: "Hardware", detail: $transmitterInfo.hardware ) - SettingsItem(title: "Firmware", detail: $transmitterInfo.firmware ) - SettingsItem(title: "Connection State", detail: $transmitterInfo.connectionState ) - SettingsItem(title: "Transmitter Type", detail: $transmitterInfo.transmitterType ) - SettingsItem(title: "Mac", detail: $transmitterInfo.transmitterIdentifier ) - SettingsItem(title: "Sensor Type", detail: $transmitterInfo.sensorType ) - } - } - - var factoryCalibrationSection: some View { - Section(header: Text("Factory Calibration Parameters")) { - ForEach(self.model.factoryCalibrationInfos, id: \.self) { factoryCalibrationInfo in - - SettingsItem(title: "i1", detail: factoryCalibrationInfo.i1 ) - SettingsItem(title: "i2", detail: factoryCalibrationInfo.i2 ) - SettingsItem(title: "i3", detail: factoryCalibrationInfo.i3 ) - SettingsItem(title: "i4", detail: factoryCalibrationInfo.i4 ) - SettingsItem(title: "i5", detail: factoryCalibrationInfo.i5 ) - SettingsItem(title: "i6", detail: factoryCalibrationInfo.i6 ) - SettingsItem(title: "Valid for footer", detail: factoryCalibrationInfo.validForFooter ) - } - - - ZStack { - NavigationLink(destination: CalibrationEditView()) { - Button("Edit calibrations") { - print("edit calibration clicked") - } - } - - } - - } - } - - - - private var dismissButton: some View { - Button( action: { - // This should be enough - //self.presentationMode.wrappedValue.dismiss() - - //but since Loop uses uihostingcontroller wrapped in cgmviewcontroller we need - // to notify the parent to close the cgmviewcontrollers navigation - notifyComplete.notify() - }) { - Text("Close") - } - } - - - var destructSection: some View { - Section { - Button("Delete CGM") { - showingDestructQuestion = true - }.foregroundColor(.red) - .alert(isPresented: $showingDestructQuestion) { - Alert( - title: Text("Are you sure you want to remove this cgm from loop?"), - message: Text("There is no undo"), - primaryButton: .destructive(Text("Delete")) { - - notifyDelete.notify() - }, - secondaryButton: .cancel() - ) - } - - } - } - - //todo: replace sub with navigationlinks - var advancedSection: some View { - Section(header: Text("Advanced")) { - ZStack { - NavigationLink(destination: GlucoseSettingsView(glucoseUnit: self.glucoseUnit)) { - SettingsItem(title: "Glucose Settings", detail: .constant("")) - } - } - - ZStack { - NavigationLink(destination: NotificationSettingsView(glucoseUnit: self.glucoseUnit)) { - SettingsItem(title: "Notifications", detail: .constant("")) - } - } - } - } - - var logExportSection : some View { - Section { - Button("Export logs") { - if Features.supportsLogExport { - showingExporter = true - } else { - presentableStatus = StatusMessage(title: "Export not available", message: "Log export requires ios 15") - } - }.foregroundColor(.blue) - - } - } - - var overview: some View { - List { - measurementSection -// if !glucoseMeasurement.predictionDate.isEmpty{ -// predictionSection -// } - advancedSection - sensorInfoSection - transmitterInfoSection -// factoryCalibrationSection - - //disable for now due to null byte document issues - if true { - logExportSection - } - - destructSection - - } - .fileExporter(isPresented: $showingExporter, document: LogsAsTextFile(), contentType: .plainText) { result in - switch result { - case .success(let url): - print("Saved to \(url)") - case .failure(let error): - print(error.localizedDescription) - } - } - .listStyle(InsetGroupedListStyle()) - .alert(item: $presentableStatus) { status in - Alert(title: Text(status.title), message: Text(status.message) , dismissButton: .default(Text("Got it!"))) - } - - - } - - - - -} - -struct LogsAsTextFile: FileDocument { - // tell the system we support only plain text - static var readableContentTypes = [UTType.plainText] - - // a simple initializer that creates new, empty documents - init() { - } - - // this initializer loads data that has been saved previously - init(configuration: ReadConfiguration) throws { - } - - // this will be called when the system wants to write our data to disk - func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper { - var data = Data() - do { - data = try getLogs() - } catch { - data.append("No logs available".data(using: .utf8, allowLossyConversion: false)!) - } - - let wrapper = FileWrapper(regularFileWithContents: data) - let today = Date().getFormattedDate(format: "yyyy-MM-dd") - wrapper.preferredFilename = "libretransmitterlogs-\(today).txt" - return wrapper - - } -} - - -struct SettingsOverview_Previews: PreviewProvider { - static var previews: some View { - NotificationSettingsView(glucoseUnit: HKUnit.millimolesPerLiter) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Setup/BluetoothSelection.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Setup/BluetoothSelection.swift deleted file mode 100644 index dd9dfdcb3..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Setup/BluetoothSelection.swift +++ /dev/null @@ -1,402 +0,0 @@ -// -// BluetoothSelection.swift -// MiaomiaoClientUI -// -// Created by Bjørn Inge Berg on 17/10/2020. -// Copyright © 2020 Bjørn Inge Vikhammermo Berg. All rights reserved. -// - -import Combine -import CoreBluetooth -import SwiftUI - -private struct Defaults { - static let rowBackground = Color(UIColor.secondarySystemGroupedBackground) - static let selectedRowBackground = Color.orange.opacity(0.2) - static let background = Color(UIColor.systemGroupedBackground) -} - -//https://www.objc.io/blog/2020/02/18/a-signal-strength-indicator/ -struct SignalStrengthIndicator: View { - @Binding var bars : Int - var totalBars: Int = 5 - var body: some View { - HStack { - ForEach(0.. Divided { - return Divided(amount: amount, shape: self) - } -} - -struct Divided: Shape { - var amount: CGFloat // Should be in range 0...1 - var shape: S - func path(in rect: CGRect) -> Path { - shape.path(in: rect.divided(atDistance: amount * rect.height, from: .maxYEdge).slice) - } -} - - - -private struct ListFooter: View { - var devicesCount = 0 - var body: some View { - Text(String(format:NSLocalizedString("Found devices: %d", comment: "Found devices"), devicesCount)) - } -} - -private struct DeviceItem: View { - var device: SomePeripheral - @Binding var rssi: RSSIInfo? - var details1: String - var details2: String? - var details3: String? - - var requiresPhoneNFC : Bool - var requiresSetup: Bool - - @State private var presentableStatus: StatusMessage? - - @ObservedObject var selection: SelectionState = .shared - - func getDeviceImage(_ device: SomePeripheral) -> Image { - var image: UIImage! - switch device { - case let .Left(realDevice): - image = LibreTransmitters.getSupportedPlugins(realDevice)?.first?.smallImage - - case .Right: - image = LibreTransmitters.all.randomElement()?.smallImage - } - - return image == nil ? Image(systemName: "exclamationmark.triangle") : Image(uiImage: image) - } - - func getRowBackground(device: SomePeripheral) -> Color { - selection.selectedStringIdentifier == device.asStringIdentifier ? - Defaults.selectedRowBackground : Defaults.rowBackground - } - - init(device: SomePeripheral, requiresSetup: Bool, requiresPhoneNFC: Bool, details: String, rssi: Binding) { - self.device = device - self._rssi = rssi - self.requiresPhoneNFC = requiresPhoneNFC - self.requiresSetup = requiresSetup - - details1 = device.name ?? "UnknownDevice" - let split = details.split(separator: "\n") - - if split.count >= 2 { - details2 = String(split[0]) - details3 = String(split[1]) - } else { - details2 = details - } - } - - @State var isShowingSetup = false - - - - var body : some View { - //todo: make a generic setup protocol and views, but we don't plan to support other - // sensors than the libre2 directly via bluetooth. - /*if requiresSetup { - NavigationLink(destination: Libre2DirectSetup(device: device), isActive: $isShowingSetup) { - list - } - - } else { - list - } */ - //we hide libre2 devices from this view, because we have a new parentview (modeselection) that calls Libre2DirectSetup() directly - if !requiresSetup { - list - } - } - - var list : some View { - HStack { - getDeviceImage(device) - .frame(width: 100, height: 50, alignment: .leading) - - VStack(alignment: .leading) { - Text("\(details1)") - .font(.system(size: 20, weight: .medium, design: .default)) - if let details2 = details2 { - Text("\(details2)") - } - if let details3 = details3 { - Text("\(details3)") - } - - - } - Spacer() - VStack(alignment: .center, spacing: /*@START_MENU_TOKEN@*/nil/*@END_MENU_TOKEN@*/, content: { - if let rssi = rssi { - SignalStrengthIndicator(bars: .constant(rssi.signalBars), totalBars: rssi.totalBars) - .frame(width: 40, height: 40, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/) - } - }) - - - } - .alert(item: $presentableStatus) { status in - Alert(title: Text(status.title), message: Text(status.message) , dismissButton: .default(Text("Got it!"))) - } - .listRowBackground(getRowBackground(device: device)) - .onTapGesture { - print("dabear:: tapped \(device.asStringIdentifier)") - - if requiresPhoneNFC && !Features.phoneNFCAvailable { - //cannot select, show gui somehow - presentableStatus = StatusMessage(title: "Not availble", message: "The device selected is not available due to lack of NFC support on your phone") - isShowingSetup = false - print("dabear:: tapped \(device.asStringIdentifier) but it requires nfc, not available") - return - } - - if requiresSetup { - print("dabear:: tapped \(device.asStringIdentifier) but it requires setup, so aborting") - isShowingSetup = true - - return - } - - print("dabear:: tapped and set \(device.asStringIdentifier) as new identifier") - selection.selectedStringIdentifier = device.asStringIdentifier - } - } -} - -// Decided to use shared instance instead of .environmentObject() -class SelectionState: ObservableObject { - @Published var selectedStringIdentifier: String? = "" - - @Published var selectedUID: Data? = nil - - - static var shared = SelectionState() -} - -struct BluetoothSelection: View { - @ObservedObject var selection: SelectionState = .shared - @ObservedObject public var cancelNotifier: GenericObservableObject - @ObservedObject public var saveNotifier: GenericObservableObject - - public func getNewDeviceId () -> String? { - selection.selectedStringIdentifier - } - - - - private var searcher: BluetoothSearchManager! - - /*static func asHostedViewController() -> UIHostingController { - UIHostingController(rootView: self.init()) - }*/ - - // Should contain all discovered and compatible devices - // This list is expected to contain 10 or 20 items at the most - @State var allDevices = [SomePeripheral]() - @State var deviceDetails = [String: String]() - @State var deviceRequiresPhoneNFC = [String: Bool]() - @State var deviceRequiresSetup = [String: Bool]() - @State var rssi = [String: RSSIInfo]() - - var nullPubliser: Empty! - var debugMode = false - - - var cancelButton: some View { - Button("Cancel"){ - print("cancel button pressed") - cancelNotifier.notify() - - }//.accentColor(.red) - } - - var saveButton: some View { - Button("Save"){ - print("Save button pressed") - saveNotifier.notify() - - - }.disabled(selection.selectedStringIdentifier?.isEmpty ?? true) - } - - - init(debugMode: Bool = false, cancelNotifier: GenericObservableObject, saveNotifier: GenericObservableObject) { - self.debugMode = debugMode - self.cancelNotifier = cancelNotifier - self.saveNotifier = saveNotifier - - if self.debugMode { - allDevices = Self.getMockData() - nullPubliser = Empty() - - } else { - self.searcher = BluetoothSearchManager() - } - - - - LibreTransmitter.NotificationHelper.requestNotificationPermissionsIfNeeded() - - - } - - public mutating func stopScan(_ removeSearcher: Bool = false) { - self.searcher?.disconnectManually() - if removeSearcher { - self.searcher = nil - } - } - - var headerSection: some View { - Section { - Text("Select the third party transmitter you want to connect to") - .listRowBackground(Defaults.background) - .padding(.top) - HStack { - Image(systemName: "link.circle") - Text("Libre Transmitters") - } - } - } - var list : some View { - List { - headerSection - - Section { - ForEach(allDevices) { device in - if debugMode { - let randomRSSI = RSSIInfo(bledeviceID: device.asStringIdentifier, signalStrength: -90 + (1...70).randomElement()!) - let requiresPhoneNFC = Bool.random() - DeviceItem(device: device, requiresSetup: false, requiresPhoneNFC: requiresPhoneNFC, details: "mockdatamockdata mockdata mockdata\nmockdata2 nmockdata2", rssi: .constant(randomRSSI)) - } else { - let requiresPhoneNFC = deviceRequiresPhoneNFC[device.asStringIdentifier, default: false] - - let requiresSetup = deviceRequiresSetup[device.asStringIdentifier, default: false] - let rssigetter = Binding(get: { - rssi[device.asStringIdentifier] - }, set: { newVal in - //not ever needed - }) - - DeviceItem(device: device, requiresSetup: requiresSetup, requiresPhoneNFC: requiresPhoneNFC , details: deviceDetails[device.asStringIdentifier]!, rssi: rssigetter) - } - - - - } - } - Section { - ListFooter(devicesCount: allDevices.count) - } - } - .onAppear { - //devices = Self.getMockData() - if debugMode { - allDevices = Self.getMockData() - } else { - print("dabear:: asking searcher to search!") - self.searcher?.scanForCompatibleDevices() - } - } - .onDisappear { - if !self.debugMode { - print("dabear:: asking searcher to stop searching!") - self.searcher?.stopTimer() - self.searcher?.disconnectManually() - - - } - } - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: cancelButton, trailing: saveButton) - } - - func receiveRSSI(_ rssi: RSSIInfo) { - let now = Date().description - print("\(now) got rssi \(rssi.signalStrength) for bluetoothdevice \(rssi.bledeviceID)") - self.rssi[rssi.bledeviceID] = rssi - - } - - - - var body: some View { - if debugMode { - list - .onReceive(nullPubliser) { _ in - print("nullpublisher received element!?") - //allDevices.append(SomePeripheral.Left(device)) - } - } else { - list - .onReceive(searcher.passThroughMetaData) { newDevice, advertisement in - print("received searcher passthrough") - - let alreadyAdded = allDevices.contains { existingDevice -> Bool in - existingDevice.asStringIdentifier == newDevice.asStringIdentifier - } - if !alreadyAdded { - if let pluginForDevice = LibreTransmitters.getSupportedPlugins(newDevice)?.first { - - deviceRequiresPhoneNFC[newDevice.asStringIdentifier] = pluginForDevice.requiresPhoneNFC - deviceRequiresSetup[newDevice.asStringIdentifier] = pluginForDevice.requiresSetup - - if let parsedAdvertisement = pluginForDevice.getDeviceDetailsFromAdvertisement(advertisementData: advertisement) { - - deviceDetails[newDevice.asStringIdentifier] = parsedAdvertisement - } else { - deviceDetails[newDevice.asStringIdentifier] = "" - } - - - } else { - deviceDetails[newDevice.asStringIdentifier] = newDevice.asStringIdentifier - } - - - - allDevices.append(SomePeripheral.Left(newDevice)) - } - } - .onReceive(searcher.throttledRSSI.throttledPublisher, perform: receiveRSSI) - } - - - } -} - -extension BluetoothSelection { - static func getMockData() -> [SomePeripheral] { - [ - SomePeripheral.Right(MockedPeripheral(name: "device1")), - SomePeripheral.Right(MockedPeripheral(name: "device2")), - SomePeripheral.Right(MockedPeripheral(name: "device3")), - SomePeripheral.Right(MockedPeripheral(name: "device4")) - ] - } -} - -struct BluetoothSelection_Previews: PreviewProvider { - static var previews: some View { - let testData = SelectionState.shared - testData.selectedStringIdentifier = "device4" - - return BluetoothSelection(debugMode: true, cancelNotifier: GenericObservableObject(), saveNotifier: GenericObservableObject()) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Setup/Libre2DirectSetup.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Setup/Libre2DirectSetup.swift deleted file mode 100644 index 32834cd0a..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Setup/Libre2DirectSetup.swift +++ /dev/null @@ -1,167 +0,0 @@ -// -// Libre2DirectSetup.swift -// LibreTransmitterUI -// -// Created by Bjørn Inge Berg on 30/08/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import SwiftUI - -#if canImport(CoreNFC) - - -struct Libre2DirectSetup: View { - - - @State private var presentableStatus: StatusMessage? - @State private var showPairingInfo = false - - @State private var service = SensorPairingService() - - - @State private var pairingInfo = SensorPairingInfo() - - - @ObservedObject public var cancelNotifier: GenericObservableObject - @ObservedObject public var saveNotifier: GenericObservableObject - - - func pairSensor() { - if !Features.phoneNFCAvailable { - presentableStatus = StatusMessage(title: "Phone NFC required!", message: "Your phone or app is not enabled for NFC communications, which is needed to pair to libre2 sensors") - return - } - print("Asked to pair sensor! phoneNFCAvailable: \(Features.phoneNFCAvailable)") - showPairingInfo = false - - service.pairSensor() - - } - - func receivePairingInfo(_ info: SensorPairingInfo){ - - print("Received Pairinginfo: \(String(describing: info))") - - pairingInfo = info - - showPairingInfo = true - - - //calibrationdata must always be extracted from the full nfc scan - if let calibrationData = info.calibrationData { - do { - try KeychainManagerWrapper.standard.setLibreNativeCalibrationData(calibrationData) - } catch { - NotificationHelper.sendCalibrationNotification(.invalidCalibrationData) - return - } - //here we assume success, data is not changed, - //and we trust that the remote endpoint returns correct data for the sensor - - NotificationHelper.sendCalibrationNotification(.success) - - - UserDefaults.standard.calibrationMapping = CalibrationToSensorMapping(uuid: info.uuid, reverseFooterCRC: calibrationData.isValidForFooterWithReverseCRCs) - - } - - - let max = info.sensorData?.maxMinutesWearTime ?? 0 - - let sensor = Sensor(uuid: info.uuid, patchInfo: info.patchInfo, maxAge: max) - UserDefaults.standard.preSelectedSensor = sensor - - SelectionState.shared.selectedUID = pairingInfo.uuid - - print("dabear:: paried and set selected UID to: \(String(describing: SelectionState.shared.selectedUID?.hex))") - saveNotifier.notify() - - - - - } - - var cancelButton: some View { - Button("Cancel"){ - print("cancel button pressed") - cancelNotifier.notify() - - }//.accentColor(.red) - } - - var pairButtonSection : some View { - Section { - Button("Pair Sensor & connect") { - pairSensor() - }.buttonStyle(BlueButtonStyle()) - } - } - - var pairingDescriptionSection: some View { - Section(header: Text("About the Process")){ - Text("Please make sure that your Libre 2 sensor is already activated and finished warming up. If you have other apps connecting to the sensor via bluetooth, these need to be shut down or uninstalled. \n\n You can only have one app communicating with the sensor via bluetooth. Then press the \"pariring and connection\" button below to start the process. Please note that the bluetooth connection might take up to a couple of minutes before it starts working.") - .padding() - } - } - var pairingInfoSection: some View { - Section(header: Text("Pairinginfo")){ - if showPairingInfo { - - SettingsItem(title: "UUID", detail: Binding(get: { - pairingInfo.uuid.hex - }, set: { newValue in - //not used - })) - - SettingsItem(title: "PatchInfo", detail: Binding(get: { - pairingInfo.patchInfo.hex - }, set: { newValue in - //not used - })) - - SettingsItem(title: "Calibrationinfo", detail: Binding(get: { - if let c = pairingInfo.calibrationData { - return"\(c.i1),\(c.i2), \(c.i3), \(c.i4), \(c.i5), \(c.i6)" - - } - return "Unknown" - }, set: { newValue in - //not used - })) - - } else { - Text("Not paired yet") - } - - } - } - - - - - var body: some View { - List { - pairingDescriptionSection - pairButtonSection - - //pairingInfoSection - - } - .listStyle(InsetGroupedListStyle()) - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: cancelButton) // the pair button does the save process for us! //, trailing: saveButton) - .onReceive(service.publisher, perform: receivePairingInfo) - .alert(item: $presentableStatus) { status in - Alert(title: Text(status.title), message: Text(status.message) , dismissButton: .default(Text("Got it!"))) - } - } -} - -struct Libre2DirectSetup_Previews: PreviewProvider { - static var previews: some View { - Libre2DirectSetup(cancelNotifier: GenericObservableObject(), saveNotifier: GenericObservableObject()) - } -} - -#endif diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Setup/ModeSelectionView.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Setup/ModeSelectionView.swift deleted file mode 100644 index c3826dce7..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Setup/ModeSelectionView.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// ModeSelectionView.swift -// LibreTransmitterUI -// -// Created by Bjørn Inge Berg on 02/09/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import SwiftUI - -struct ModeSelectionView: View { - - @ObservedObject public var cancelNotifier: GenericObservableObject - @ObservedObject public var saveNotifier: GenericObservableObject - - var modeSelectSection : some View { - Section(header: Text("Modes")) { - - #if canImport(CoreNFC) - ZStack { - NavigationLink(destination: Libre2DirectSetup(cancelNotifier: cancelNotifier, saveNotifier: saveNotifier)) { - SettingsItem(title: NSLocalizedString("Libre 2 Direct", comment: "Libre 2 Direct"), detail: .constant("")) - .padding(.top, 30) - .padding(.bottom, 30) - } - } - #endif - - ZStack { - NavigationLink(destination: BluetoothSelection(cancelNotifier: cancelNotifier, saveNotifier: saveNotifier)) { - SettingsItem(title: NSLocalizedString("Bluetooth Transmitters", comment: "Bluetooth Transmitters"), detail: .constant("")) - .padding(.top, 30) - .padding(.bottom, 30) - } - } - - - } - } - - var cancelButton: some View { - Button("Cancel"){ - print("cancel button pressed") - cancelNotifier.notify() - - }//.accentColor(.red) - } - - var body: some View { - //no navview needed when embedded into a hostingcontroller - //NavigationView{ - List { - modeSelectSection - } - .listStyle(InsetGroupedListStyle()) - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: cancelButton) - - - } -} - - - -struct ModeSelectionView_Previews: PreviewProvider { - static var previews: some View { - ModeSelectionView(cancelNotifier: GenericObservableObject(), saveNotifier: GenericObservableObject()) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Styles/BlueButtonStyle.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Styles/BlueButtonStyle.swift deleted file mode 100644 index d19cd42e9..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Styles/BlueButtonStyle.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// BlueButtonStyle.swift -// LibreTransmitterUI -// -// Created by Bjørn Inge Berg on 28/04/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import SwiftUI - -struct BlueButtonStyle: ButtonStyle { - - func makeBody(configuration: Self.Configuration) -> some View { - - configuration.label - .font(.headline) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) - .contentShape(Rectangle()) - .padding() - .foregroundColor(configuration.isPressed ? Color.white.opacity(0.5) : Color.white) - .background(configuration.isPressed ? Color.blue.opacity(0.5) : Color.blue) - .cornerRadius(10) - - - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Styles/ErrorTextFieldStyle.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Styles/ErrorTextFieldStyle.swift deleted file mode 100644 index da4eafea9..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Styles/ErrorTextFieldStyle.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// ErrorTextFieldStyle.swift -// LibreTransmitterUI -// -// Created by Bjørn Inge Berg on 28/04/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import SwiftUI - -private struct ErrorTextFieldStyle : TextFieldStyle { - public func _body(configuration: TextField) -> some View { - configuration - .background( - RoundedRectangle(cornerRadius: 10, style: .continuous) - .stroke(Color.red, lineWidth: 3)) - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/EnumeratedForEach.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/EnumeratedForEach.swift deleted file mode 100644 index 669006691..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/EnumeratedForEach.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// EnumeratedForEach.swift -// LibreTransmitterUI -// -// Created by Bjørn Inge Berg on 17/05/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import SwiftUI - -struct EnumeratedForEach: View { - let data: [ItemType] - let content: (Int, ItemType) -> ContentView - - init(_ data: [ItemType], @ViewBuilder content: @escaping (Int, ItemType) -> ContentView) { - self.data = data - self.content = content - } - - var body: some View { - ForEach(Array(self.data.enumerated()), id: \.offset) { idx, item in - self.content(idx, item) - } - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/GenericObservableObject.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/GenericObservableObject.swift deleted file mode 100644 index ce31f18e2..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/GenericObservableObject.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// GenericObservableObject.swift -// LibreTransmitterUI -// -// Created by Bjørn Inge Berg on 10/07/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import Foundation -import Combine - -class GenericObservableObject : ObservableObject { - private var cancellables = Set() - - - func notify(){ - objectWillChange.send() - } - - @discardableResult func listenOnce(listener: @escaping () -> Void) -> Self{ - objectWillChange - .sink { [weak self]_ in - listener() - self?.cancellables.removeAll() - - } - .store(in: &cancellables) - return self - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/NumericTextField.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/NumericTextField.swift deleted file mode 100644 index a8038e881..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/NumericTextField.swift +++ /dev/null @@ -1,195 +0,0 @@ -// -// NumericTextField.swift -// LibreTransmitterUI -// -// Created by Bjørn Inge Berg on 23/05/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import SwiftUI -import Combine - -// Decided to use shared instance instead of .environmentObject() -class FormErrorState: ObservableObject { - @Published var childrenErrorStatus: [String:Bool] = [:] - - var hasAnyError : Bool { - !childrenErrorStatus.isEmpty && childrenErrorStatus.values.contains(true) - } - - static var shared = FormErrorState() -} - -fileprivate var valueNumberFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.locale = Locale.current - formatter.minimumFractionDigits = 1 - - return formatter -}() - -fileprivate var intNumberFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .none - formatter.locale = Locale.current - formatter.minimumFractionDigits = 1 - formatter.maximumFractionDigits = 0 - - return formatter -}() - - - - - - - -public struct NumericTextField: View { - - - - static func localeTextToDouble(_ text: String) -> Double? { - valueNumberFormatter.number(from: text)?.doubleValue - } - static func doubleToLocateText(_ dbl: Double) -> String? { - valueNumberFormatter.string(from: dbl as NSNumber) - } - - static func localeTextToInt(_ text: String) -> Int? { - intNumberFormatter.number(from: text)?.intValue - } - static func intToLocateText(_ dbl: Double) -> String? { - intNumberFormatter.string(from: dbl as NSNumber) - } - - @State private(set) var hasError = false { - didSet { - if oldValue != hasError { - formstate.childrenErrorStatus[description] = hasError - } - } - } - - @ObservedObject var formstate : FormErrorState = .shared - - - var textField: some View { - - TextField(description, text: $numericString) - .onReceive(Just(numericString)) { value in - - print("onreceive called") - - - guard let newValue = Self.localeTextToDouble(value) else { - print("onreceive guard failed") - hasError = true - - return - } - - let isInteger = newValue.truncatingRemainder(dividingBy: 1.0) == 0.0 - - if requiresIntegerValue && !isInteger { - //consider this or coloring view to indicate error - //self.numericString = "\(numericValue)" - hasError = true - return - - } - - if self.numericValue != newValue { - self.numericValue = newValue - } - - hasError = false - - - - } - .onAppear { - if requiresIntegerValue { - self.numericString = Self.intToLocateText(numericValue) ?? "unknown" - } else { - self.numericString = Self.doubleToLocateText(numericValue) ?? "unknown" - } - } - .textFieldStyle(RoundedBorderTextFieldStyle()) - .disableAutocorrection(true) - .keyboardType(.decimalPad) - .border(Color(UIColor.separator)) - .disabled(isReadOnly) - - - - } - - var textFieldWithError : some View{ - textField - .overlay( - VStack { - if hasError { - Rectangle() - .stroke(Color.red, lineWidth: 1) - } else { - EmptyView() - } - - } - ) - } - - public var body: some View { - HStack { - if showDescription { - Text("\(description)") - } - textFieldWithError - } - .padding(1) - - } - - init(description: String, showDescription: Bool, numericValue: Binding, isReadOnly:Bool=false, formErrorState:FormErrorState?=nil ) { - self.description = description - self._numericValue = numericValue - self.requiresIntegerValue = false - self.isReadOnly = isReadOnly - self.showDescription = showDescription - if let formErrorState = formErrorState { - self.formstate = formErrorState - } - } - - - init(description: String, showDescription: Bool, numericValue wrapper: Binding, isReadOnly:Bool=false , formErrorState:FormErrorState?=nil ) { - self.description = description - self.requiresIntegerValue = true - self.isReadOnly = isReadOnly - self.showDescription = showDescription - - if let formErrorState = formErrorState { - self.formstate = formErrorState - } - - - //allows an int to behave as a double, should be just fine in most cases (that we care about) - let bd = Binding(get: { Double(wrapper.wrappedValue) }, - set: { wrapper.wrappedValue = Int($0) }) - self._numericValue = bd - - - } - - var description: String - var showDescription: Bool - var isReadOnly: Bool = false - - var requiresIntegerValue = false - //numericvalue assumes that all ints can be encoded as doubles, which might not be true always though. - @Binding var numericValue: Double - @State private var numericString: String = "" - - -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/StatusMessage.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/StatusMessage.swift deleted file mode 100644 index bf5662acb..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/StatusMessage.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// StatusMessage.swift -// LibreTransmitterUI -// -// Created by Bjørn Inge Berg on 23/05/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import SwiftUI - -struct StatusMessage: Identifiable { - var id: String { title } - let title: String - let message: String -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/ViewExtensions.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/ViewExtensions.swift deleted file mode 100644 index 7e072780a..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Utilities/ViewExtensions.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// ViewExtensions.swift -// LibreTransmitterUI -// -// Created by Bjørn Inge Berg on 03/07/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import SwiftUI - -#if canImport(UIKit) -extension View { - func hideKeyboard() { - UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) - } -} -#endif diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/OSLog.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/OSLog.swift deleted file mode 100644 index 0be435696..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/OSLog.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// OSLog.swift -// LibreTransmitter -// -// Created by Nathaniel Hamming on 2019-12-19. -// Copyright © 2019 Mark Wilson. All rights reserved. -// - -import os.log - - -extension OSLog { - convenience init(category: String) { - self.init(subsystem: "com.loopkit.LibreTransmitter", category: category) - } - - func debug(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .debug, args) - } - - func info(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .info, args) - } - - func `default`(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .default, args) - } - - func error(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .error, args) - } - - private func log(_ message: StaticString, type: OSLogType, _ args: [CVarArg]) { - switch args.count { - case 0: - os_log(message, log: self, type: type) - case 1: - os_log(message, log: self, type: type, args[0]) - case 2: - os_log(message, log: self, type: type, args[0], args[1]) - case 3: - os_log(message, log: self, type: type, args[0], args[1], args[2]) - case 4: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3]) - case 5: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4]) - default: - os_log(message, log: self, type: type, args) - } - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Observables/GlucoseInfo.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Observables/GlucoseInfo.swift deleted file mode 100644 index 95510d313..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Observables/GlucoseInfo.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// GlucoseInfo.swift -// LibreTransmitter -// -// Created by Bjørn Inge Berg on 02/07/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import Foundation - -public class GlucoseInfo : ObservableObject, Equatable, Hashable{ - - @Published public var glucose = "" //dynamic based users preference - @Published public var glucoseMMOL = "" - @Published public var glucoseMGDL = "" - @Published public var date = "" - @Published public var checksum = "" - //@Published var entryErrors = "" - - @Published public var prediction = "" - @Published public var predictionMMOL = "" - @Published public var predictionMGDL = "" - @Published public var predictionDate = "" - - public static func ==(lhs: GlucoseInfo, rhs: GlucoseInfo) -> Bool { - lhs.glucose == rhs.glucose && lhs.date == rhs.date && - lhs.checksum == rhs.checksum && lhs.prediction == rhs.prediction && lhs.predictionDate == rhs.predictionDate - - } -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Observables/SensorInfo.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Observables/SensorInfo.swift deleted file mode 100644 index 54f30b2ec..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Observables/SensorInfo.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// SensorInfo.swift -// LibreTransmitter -// -// Created by Bjørn Inge Berg on 02/07/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import Foundation -public class SensorInfo : ObservableObject, Equatable, Hashable{ - @Published public var sensorAge = "" - @Published public var sensorAgeLeft = "" - @Published public var sensorEndTime = "" - @Published public var sensorState = "" - @Published public var sensorSerial = "" - - public static func ==(lhs: SensorInfo, rhs: SensorInfo) -> Bool { - lhs.sensorAge == rhs.sensorAge && lhs.sensorAgeLeft == rhs.sensorAgeLeft && - lhs.sensorEndTime == rhs.sensorEndTime && lhs.sensorState == rhs.sensorState && - lhs.sensorSerial == rhs.sensorSerial - - } - -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Observables/TransmitterInfo.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Observables/TransmitterInfo.swift deleted file mode 100644 index 9bf8a828f..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/Observables/TransmitterInfo.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// TransmitterInfo.swift -// LibreTransmitter -// -// Created by Bjørn Inge Berg on 02/07/2021. -// Copyright © 2021 Mark Wilson. All rights reserved. -// - -import SwiftUI - -public class TransmitterInfo : ObservableObject, Equatable, Hashable{ - @Published public var battery = "" - @Published public var hardware = "" - @Published public var firmware = "" - @Published public var connectionState = "" - @Published public var transmitterType = "" - @Published public var transmitterIdentifier = "" //either mac or apple proprietary identifere - @Published public var sensorType = "" - - public static func ==(lhs: TransmitterInfo, rhs: TransmitterInfo) -> Bool { - lhs.battery == rhs.battery && lhs.hardware == rhs.hardware && - lhs.firmware == rhs.firmware && lhs.connectionState == rhs.connectionState && - lhs.transmitterType == rhs.transmitterType && lhs.transmitterIdentifier == rhs.transmitterIdentifier && - lhs.sensorType == rhs.sensorType - - } - -} diff --git a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/SettingsNavigationViewController.swift b/Dependencies/LibreTransmitter/Sources/LibreTransmitter/SettingsNavigationViewController.swift deleted file mode 100644 index 85ff86d21..000000000 --- a/Dependencies/LibreTransmitter/Sources/LibreTransmitter/SettingsNavigationViewController.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// SettingsNavigationViewController.swift -// LoopKitUI -// -// Created by Pete Schwamb on 1/29/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit - -open class SettingsNavigationViewController: UINavigationController, CompletionNotifying { - - open weak var completionDelegate: CompletionDelegate? - - open func notifyComplete() { - completionDelegate?.completionNotifyingDidComplete(self) - } - -} diff --git a/Dependencies/LoopKit/.circleci/config.yml b/Dependencies/LoopKit/.circleci/config.yml deleted file mode 100644 index e8e97343c..000000000 --- a/Dependencies/LoopKit/.circleci/config.yml +++ /dev/null @@ -1,38 +0,0 @@ -version: 2.1 - -# -# Variables -# - -project_directory: &project_directory ~/project - -# -# Jobs -# - -jobs: - test: - working_directory: *project_directory - macos: - xcode: 14.2.0 - steps: - - checkout - - run: - name: Test - command: | - set -o pipefail && xcodebuild -project LoopKit.xcodeproj -scheme Shared build -destination 'name=iPhone 14' test | xcpretty - - run: - name: Build Swift Package - command: | - swift build -v -Xswiftc "-sdk" -Xswiftc "`xcrun --sdk iphonesimulator --show-sdk-path`" -Xswiftc "-target" -Xswiftc "x86_64-apple-ios15.0-simulator" | xcpretty - - store_test_results: - path: test_output -# -# Workflows -# - -workflows: - version: 2.1 - build_and_test: - jobs: - - test diff --git a/Dependencies/LoopKit/.gitignore b/Dependencies/LoopKit/.gitignore deleted file mode 100644 index 8caea4ccd..000000000 --- a/Dependencies/LoopKit/.gitignore +++ /dev/null @@ -1,69 +0,0 @@ -# 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 - -## Other -*.xccheckout -*.moved-aside -*.xcuserstate -*.xcscmblueprint - -## Obj-C/Swift specific -*.hmap -*.ipa - -## 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/ -.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/ - -# Carthage -# -# Add this line if you want to avoid checking in source code from Carthage dependencies. -Carthage/Checkouts -Carthage/Build - -# 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://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md - -fastlane/report.xml -fastlane/screenshots - -# Sensitive details about remote backup -RemoteSettings.plist - -.DS_Store - -Carthage/ diff --git a/Dependencies/LoopKit/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/Dependencies/LoopKit/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/Dependencies/LoopKit/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Dependencies/LoopKit/.travis.yml b/Dependencies/LoopKit/.travis.yml deleted file mode 100644 index dfc1de05e..000000000 --- a/Dependencies/LoopKit/.travis.yml +++ /dev/null @@ -1,6 +0,0 @@ -language: objective-c -osx_image: xcode12.5 - -script: - - set -o pipefail && xcodebuild -project LoopKit.xcodeproj -scheme Shared build -destination 'name=iPhone 8' test | xcpretty - - set -o pipefail && xcodebuild -project LoopKit.xcodeproj -scheme "LoopKit Example" build -destination 'name=iPhone 8' CODE_SIGNING_ALLOWED=NO | xcpretty diff --git a/Dependencies/LoopKit/CODE_OF_CONDUCT.md b/Dependencies/LoopKit/CODE_OF_CONDUCT.md deleted file mode 100644 index 8079e4550..000000000 --- a/Dependencies/LoopKit/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,72 +0,0 @@ -# Code of Conduct - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or -advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the maintaner [via email](mailto:loudnate@gmail.com). All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ \ No newline at end of file diff --git a/Dependencies/LoopKit/LICENSE b/Dependencies/LoopKit/LICENSE deleted file mode 100644 index e83480923..000000000 --- a/Dependencies/LoopKit/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Nathan Racklyeft -Copyright (c) 2016 LoopKit Authors - -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. \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKit Example/AppDelegate.swift b/Dependencies/LoopKit/LoopKit Example/AppDelegate.swift deleted file mode 100644 index 6bf3bf1be..000000000 --- a/Dependencies/LoopKit/LoopKit Example/AppDelegate.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// AppDelegate.swift -// LoopKit Example -// -// Created by Nathan Racklyeft on 2/24/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate { - - var window: UIWindow? - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - return true - } - - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - -} - diff --git a/Dependencies/LoopKit/LoopKit Example/Assets.xcassets/AppIcon.appiconset/Contents.json b/Dependencies/LoopKit/LoopKit Example/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d8db8d65f..000000000 --- a/Dependencies/LoopKit/LoopKit Example/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x" - }, - { - "idiom" : "ios-marketing", - "size" : "1024x1024", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKit Example/Assets.xcassets/Contents.json b/Dependencies/LoopKit/LoopKit Example/Assets.xcassets/Contents.json deleted file mode 100644 index da4a164c9..000000000 --- a/Dependencies/LoopKit/LoopKit Example/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKit Example/Base.lproj/LaunchScreen.storyboard b/Dependencies/LoopKit/LoopKit Example/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index fc810a630..000000000 --- a/Dependencies/LoopKit/LoopKit Example/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKit Example/Base.lproj/Main.storyboard b/Dependencies/LoopKit/LoopKit Example/Base.lproj/Main.storyboard deleted file mode 100644 index a4802fec3..000000000 --- a/Dependencies/LoopKit/LoopKit Example/Base.lproj/Main.storyboard +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKit Example/Extensions/HKUnit.swift b/Dependencies/LoopKit/LoopKit Example/Extensions/HKUnit.swift deleted file mode 100644 index a5f77cdd0..000000000 --- a/Dependencies/LoopKit/LoopKit Example/Extensions/HKUnit.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// HKUnit.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/17/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -extension HKUnit { - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: .literUnit(with: .deci)) - }() - - static let millimolesPerLiter: HKUnit = { - return HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: .liter()) - }() - - static let milligramsPerDeciliterPerMinute: HKUnit = { - return HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) - }() - - static let millimolesPerLiterPerMinute: HKUnit = { - return HKUnit.millimolesPerLiter.unitDivided(by: .minute()) - }() - - static let internationalUnitsPerHour: HKUnit = { - return HKUnit.internationalUnit().unitDivided(by: .hour()) - }() - - static let gramsPerUnit: HKUnit = { - return HKUnit.gram().unitDivided(by: .internationalUnit()) - }() - - var foundationUnit: Unit? { - if self == HKUnit.milligramsPerDeciliter { - return UnitConcentrationMass.milligramsPerDeciliter - } - - if self == HKUnit.millimolesPerLiter { - return UnitConcentrationMass.millimolesPerLiter(withGramsPerMole: HKUnitMolarMassBloodGlucose) - } - - if self == HKUnit.gram() { - return UnitMass.grams - } - - return nil - } - - /// The smallest value expected to be visible on a chart - var chartableIncrement: Double { - if self == .milligramsPerDeciliter { - return 1 - } else { - return 1 / 25 - } - } -} diff --git a/Dependencies/LoopKit/LoopKit Example/Extensions/IdentifiableClass.swift b/Dependencies/LoopKit/LoopKit Example/Extensions/IdentifiableClass.swift deleted file mode 100644 index d0bf7f297..000000000 --- a/Dependencies/LoopKit/LoopKit Example/Extensions/IdentifiableClass.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// IdentifiableClass.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -protocol IdentifiableClass: AnyObject { - static var className: String { get } -} - - -extension IdentifiableClass { - static var className: String { - return NSStringFromClass(self).components(separatedBy: ".").last! - } -} diff --git a/Dependencies/LoopKit/LoopKit Example/Extensions/LegacyInsulinDeliveryTableViewController.swift b/Dependencies/LoopKit/LoopKit Example/Extensions/LegacyInsulinDeliveryTableViewController.swift deleted file mode 100644 index 64f8b7c30..000000000 --- a/Dependencies/LoopKit/LoopKit Example/Extensions/LegacyInsulinDeliveryTableViewController.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// LegacyInsulinDeliveryTableViewController.swift -// LoopKit -// -// Created by Nate Racklyeft on 7/13/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import LoopKitUI - - -extension LegacyInsulinDeliveryTableViewController: IdentifiableClass { } diff --git a/Dependencies/LoopKit/LoopKit Example/Extensions/NSUserDefaults.swift b/Dependencies/LoopKit/LoopKit Example/Extensions/NSUserDefaults.swift deleted file mode 100644 index 998183ed7..000000000 --- a/Dependencies/LoopKit/LoopKit Example/Extensions/NSUserDefaults.swift +++ /dev/null @@ -1,205 +0,0 @@ -// -// NSUserDefaults.swift -// LoopKit -// -// Created by Nathan Racklyeft on 3/18/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import LoopKit - - -extension UserDefaults { - private enum Key: String { - case BasalRateSchedule = "com.LoopKitExample.BasalRateSchedule" - case CarbRatioSchedule = "com.LoopKitExample.CarbRatioSchedule" - case InsulinActionDuration = "com.LoopKitExample.InsulinActionDuration" - case InsulinSensitivitySchedule = "com.LoopKitExample.InsulinSensitivitySchedule" - case GlucoseTargetRangeSchedule = "com.LoopKitExample.GlucoseTargetRangeSchedule" - case PreMealTargetRange = "com.LoopKitExample.PreMealTargetRange" - case LegacyWorkoutTargetRange = "com.LoopKitExample.LegacyWorkoutTargetRange" - case MaximumBasalRatePerHour = "com.LoopKitExample.MaximumBasalRatePerHour" - case MaximumBolus = "com.LoopKitExample.MaximumBolus" - case PumpID = "com.LoopKitExample.PumpID" - case PumpTimeZone = "com.LoopKitExample.PumpTimeZone" - case TransmitterID = "com.LoopKitExample.TransmitterID" - case TransmitterStartTime = "com.LoopKitExample.TransmitterStartTime" - } - - var basalRateSchedule: BasalRateSchedule? { - get { - if let rawValue = dictionary(forKey: Key.BasalRateSchedule.rawValue) { - return BasalRateSchedule(rawValue: rawValue) - } else { - return nil - } - } - set { - set(newValue?.rawValue, forKey: Key.BasalRateSchedule.rawValue) - } - } - - var carbRatioSchedule: CarbRatioSchedule? { - get { - if let rawValue = dictionary(forKey: Key.CarbRatioSchedule.rawValue) { - return CarbRatioSchedule(rawValue: rawValue) - } else { - return nil - } - } - set { - set(newValue?.rawValue, forKey: Key.CarbRatioSchedule.rawValue) - } - } - - var insulinActionDuration: TimeInterval? { - get { - let value = double(forKey: Key.InsulinActionDuration.rawValue) - - return value > 0 ? value : TimeInterval(hours: 4) - } - set { - if let insulinActionDuration = newValue { - set(insulinActionDuration, forKey: Key.InsulinActionDuration.rawValue) - } else { - removeObject(forKey: Key.InsulinActionDuration.rawValue) - } - } - } - - var insulinSensitivitySchedule: InsulinSensitivitySchedule? { - get { - if let rawValue = dictionary(forKey: Key.InsulinSensitivitySchedule.rawValue) { - return InsulinSensitivitySchedule(rawValue: rawValue) - } else { - return nil - } - } - set { - set(newValue?.rawValue, forKey: Key.InsulinSensitivitySchedule.rawValue) - } - } - - var glucoseTargetRangeSchedule: GlucoseRangeSchedule? { - get { - if let rawValue = dictionary(forKey: Key.GlucoseTargetRangeSchedule.rawValue) { - return GlucoseRangeSchedule(rawValue: rawValue) - } else { - return nil - } - } - set { - set(newValue?.rawValue, forKey: Key.GlucoseTargetRangeSchedule.rawValue) - } - } - - var preMealTargetRange: DoubleRange? { - get { - if let rawValue = array(forKey: Key.PreMealTargetRange.rawValue) as? DoubleRange.RawValue { - return DoubleRange(rawValue: rawValue) - } else { - return nil - } - } - - set { - set(newValue?.rawValue, forKey: Key.PreMealTargetRange.rawValue) - } - } - - - var legacyWorkoutTargetRange: DoubleRange? { - get { - if let rawValue = array(forKey: Key.LegacyWorkoutTargetRange.rawValue) as? DoubleRange.RawValue { - return DoubleRange(rawValue: rawValue) - } else { - return nil - } - } - - set { - set(newValue?.rawValue, forKey: Key.LegacyWorkoutTargetRange.rawValue) - } - } - - var maximumBasalRatePerHour: Double? { - get { - let value = double(forKey: Key.MaximumBasalRatePerHour.rawValue) - - return value > 0 ? value : nil - } - set { - if let maximumBasalRatePerHour = newValue { - set(maximumBasalRatePerHour, forKey: Key.MaximumBasalRatePerHour.rawValue) - } else { - removeObject(forKey: Key.MaximumBasalRatePerHour.rawValue) - } - } - } - - var maximumBolus: Double? { - get { - let value = double(forKey: Key.MaximumBolus.rawValue) - - return value > 0 ? value : nil - } - set { - if let maximumBolus = newValue { - set(maximumBolus, forKey: Key.MaximumBolus.rawValue) - } else { - removeObject(forKey: Key.MaximumBolus.rawValue) - } - } - } - - var pumpID: String? { - get { - return string(forKey: Key.PumpID.rawValue) ?? "123456" - } - set { - set(newValue, forKey: Key.PumpID.rawValue) - } - } - - var pumpTimeZone: TimeZone? { - get { - if let offset = object(forKey: Key.PumpTimeZone.rawValue) as? NSNumber { - return TimeZone(secondsFromGMT: offset.intValue) - } else { - return nil - } - } set { - if let value = newValue { - set(NSNumber(value: value.secondsFromGMT()), forKey: Key.PumpTimeZone.rawValue) - } else { - removeObject(forKey: Key.PumpTimeZone.rawValue) - } - } - } - - var transmitterStartTime: TimeInterval? { - get { - let value = double(forKey: Key.TransmitterStartTime.rawValue) - - return value > 0 ? value : nil - } - set { - if let value = newValue { - set(value, forKey: Key.TransmitterStartTime.rawValue) - } else { - removeObject(forKey: Key.TransmitterStartTime.rawValue) - } - } - } - - var transmitterID: String? { - get { - return string(forKey: Key.TransmitterID.rawValue) - } - set { - set(newValue, forKey: Key.TransmitterID.rawValue) - } - } - -} diff --git a/Dependencies/LoopKit/LoopKit Example/Extensions/TimeInterval.swift b/Dependencies/LoopKit/LoopKit Example/Extensions/TimeInterval.swift deleted file mode 100644 index a568b77b8..000000000 --- a/Dependencies/LoopKit/LoopKit Example/Extensions/TimeInterval.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// NSTimeInterval.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension TimeInterval { - static func minutes(_ minutes: Double) -> TimeInterval { - return self.init(minutes: minutes) - } - - static func hours(_ hours: Double) -> TimeInterval { - return self.init(hours: hours) - } - - init(minutes: Double) { - self.init(minutes * 60) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - var minutes: Double { - return self / 60.0 - } - - var hours: Double { - return minutes / 60.0 - } -} diff --git a/Dependencies/LoopKit/LoopKit Example/Info.plist b/Dependencies/LoopKit/LoopKit Example/Info.plist deleted file mode 100644 index ffb4e1a1e..000000000 --- a/Dependencies/LoopKit/LoopKit Example/Info.plist +++ /dev/null @@ -1,62 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 3.0 - CFBundleSignature - ???? - CFBundleVersion - 2 - LSRequiresIPhoneOS - - NSHealthShareUsageDescription - Meal data from the Health database is used to determine glucose effects. Glucose data from the Health database is used for graphing and momentum calculation. - NSHealthUpdateUsageDescription - Carbohydrate meal data entered in the app is stored in the Health database. Glucose data is stored securely in HealthKit. - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - healthkit - - UIStatusBarTintParameters - - UINavigationBar - - Style - UIBarStyleDefault - Translucent - - - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Dependencies/LoopKit/LoopKit Example/LoopKitExample.entitlements b/Dependencies/LoopKit/LoopKit Example/LoopKitExample.entitlements deleted file mode 100644 index e10f4302d..000000000 --- a/Dependencies/LoopKit/LoopKit Example/LoopKitExample.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.developer.healthkit - - - diff --git a/Dependencies/LoopKit/LoopKit Example/Managers/DeviceDataManager.swift b/Dependencies/LoopKit/LoopKit Example/Managers/DeviceDataManager.swift deleted file mode 100644 index 08af1f06c..000000000 --- a/Dependencies/LoopKit/LoopKit Example/Managers/DeviceDataManager.swift +++ /dev/null @@ -1,114 +0,0 @@ -// -// DeviceDataManager.swift -// LoopKit -// -// Created by Nathan Racklyeft on 3/18/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit -import LoopKit - - -class DeviceDataManager { - - init() { - let healthStore = HKHealthStore() - let cacheStore = PersistenceController(directoryURL: FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!) - - carbStore = CarbStore( - healthStore: healthStore, - cacheStore: cacheStore, - cacheLength: .hours(24), - defaultAbsorptionTimes: (fast: .minutes(30), medium: .hours(3), slow: .hours(5)), - observationInterval: .hours(24), - carbRatioSchedule: carbRatioSchedule, - insulinSensitivitySchedule: insulinSensitivitySchedule, - provenanceIdentifier: HKSource.default().bundleIdentifier - ) - doseStore = DoseStore( - healthStore: healthStore, - cacheStore: cacheStore, - insulinModelProvider: PresetInsulinModelProvider(defaultRapidActingModel: ExponentialInsulinModelPreset.rapidActingAdult), - longestEffectDuration: ExponentialInsulinModelPreset.rapidActingAdult.effectDuration, - basalProfile: basalRateSchedule, - insulinSensitivitySchedule: insulinSensitivitySchedule, - provenanceIdentifier: HKSource.default().bundleIdentifier - ) - glucoseStore = GlucoseStore(healthStore: healthStore, - cacheStore: cacheStore, - provenanceIdentifier: HKSource.default().bundleIdentifier) - } - - // Data stores - - let carbStore: CarbStore! - - let doseStore: DoseStore - - let glucoseStore: GlucoseStore! - - // Settings - - var basalRateSchedule = UserDefaults.standard.basalRateSchedule { - didSet { - UserDefaults.standard.basalRateSchedule = basalRateSchedule - - doseStore.basalProfile = basalRateSchedule - } - } - - var carbRatioSchedule = UserDefaults.standard.carbRatioSchedule { - didSet { - UserDefaults.standard.carbRatioSchedule = carbRatioSchedule - - carbStore?.carbRatioSchedule = carbRatioSchedule - } - } - - var insulinSensitivitySchedule = UserDefaults.standard.insulinSensitivitySchedule { - didSet { - UserDefaults.standard.insulinSensitivitySchedule = insulinSensitivitySchedule - - carbStore?.insulinSensitivitySchedule = insulinSensitivitySchedule - doseStore.insulinSensitivitySchedule = insulinSensitivitySchedule - } - } - - var glucoseTargetRangeSchedule = UserDefaults.standard.glucoseTargetRangeSchedule { - didSet { - UserDefaults.standard.glucoseTargetRangeSchedule = glucoseTargetRangeSchedule - } - } - - public var preMealTargetRange: DoubleRange? = UserDefaults.standard.preMealTargetRange { - didSet { - UserDefaults.standard.preMealTargetRange = preMealTargetRange - } - } - - public var legacyWorkoutTargetRange: DoubleRange? = UserDefaults.standard.legacyWorkoutTargetRange { - didSet { - UserDefaults.standard.legacyWorkoutTargetRange = legacyWorkoutTargetRange - } - } - - var pumpID = UserDefaults.standard.pumpID { - didSet { - UserDefaults.standard.pumpID = pumpID - - if pumpID != oldValue { - doseStore.resetPumpData() - } - } - } - - // MARK: CarbStoreDelegate - - func carbStoreHasUpdatedCarbData(_ carbStore: CarbStore) {} - - func carbStore(_ carbStore: CarbStore, didError error: CarbStore.CarbStoreError) { - print("carbstore error: \(error)") - } -} diff --git a/Dependencies/LoopKit/LoopKit Example/MasterViewController.swift b/Dependencies/LoopKit/LoopKit Example/MasterViewController.swift deleted file mode 100644 index b31904949..000000000 --- a/Dependencies/LoopKit/LoopKit Example/MasterViewController.swift +++ /dev/null @@ -1,386 +0,0 @@ -// -// MasterViewController.swift -// LoopKit Example -// -// Created by Nathan Racklyeft on 2/24/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import LoopKit -import LoopKitUI -import HealthKit - - -class MasterViewController: UITableViewController { - - private var dataManager: DeviceDataManager? - - override func viewDidLoad() { - super.viewDidLoad() - - if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] == nil { - dataManager = DeviceDataManager() - } - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - guard let dataManager = dataManager else { - return - } - - let sampleTypes = Set([ - dataManager.glucoseStore.sampleType, - dataManager.carbStore.sampleType, - dataManager.doseStore.sampleType, - ].compactMap { $0 }) - - if dataManager.glucoseStore.authorizationRequired || - dataManager.carbStore.authorizationRequired || - dataManager.doseStore.authorizationRequired - { - dataManager.carbStore.healthStore.requestAuthorization(toShare: sampleTypes, read: sampleTypes) { (success, error) in - if success { - // Call the individual authorization methods to trigger query creation - dataManager.carbStore.authorize({ _ in }) - dataManager.doseStore.insulinDeliveryStore.authorize(toShare: true, { _ in }) - dataManager.glucoseStore.authorize({ _ in }) - } - } - } - } - - // MARK: - Data Source - - private enum Section: Int, CaseIterable { - case data - case configuration - } - - private enum DataRow: Int, CaseIterable { - case carbs = 0 - case reservoir - case diagnostic - case generate - case reset - } - - private enum ConfigurationRow: Int, CaseIterable { - case basalRate - case carbRatio - case correctionRange - case insulinSensitivity - case pumpID - } - - // MARK: UITableViewDataSource - - override func numberOfSections(in tableView: UITableView) -> Int { - return Section.allCases.count - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch Section(rawValue: section)! { - case .configuration: - return ConfigurationRow.allCases.count - case .data: - return DataRow.allCases.count - } - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) - - switch Section(rawValue: indexPath.section)! { - case .configuration: - switch ConfigurationRow(rawValue: indexPath.row)! { - case .basalRate: - cell.textLabel?.text = NSLocalizedString("Basal Rates", comment: "The title text for the basal rate schedule") - case .carbRatio: - cell.textLabel?.text = NSLocalizedString("Carb Ratios", comment: "The title of the carb ratios schedule screen") - case .correctionRange: - cell.textLabel?.text = NSLocalizedString("Correction Range", comment: "The title text for the glucose correction range schedule") - case .insulinSensitivity: - cell.textLabel?.text = NSLocalizedString("Insulin Sensitivity", comment: "The title text for the insulin sensitivity schedule") - case .pumpID: - cell.textLabel?.text = NSLocalizedString("Pump ID", comment: "The title text for the pump ID") - } - case .data: - switch DataRow(rawValue: indexPath.row)! { - case .carbs: - cell.textLabel?.text = NSLocalizedString("Carbs", comment: "The title for the cell navigating to the carbs screen") - case .reservoir: - cell.textLabel?.text = NSLocalizedString("Reservoir", comment: "The title for the cell navigating to the reservoir screen") - case .diagnostic: - cell.textLabel?.text = NSLocalizedString("Diagnostic", comment: "The title for the cell displaying diagnostic data") - case .generate: - cell.textLabel?.text = NSLocalizedString("Generate Data", comment: "The title for the cell displaying data generation") - case .reset: - cell.textLabel?.text = NSLocalizedString("Reset", comment: "Title for the cell resetting the data manager") - } - } - - return cell - } - - // MARK: - UITableViewDelegate - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let sender = tableView.cellForRow(at: indexPath) - - switch Section(rawValue: indexPath.section)! { - case .configuration: - let row = ConfigurationRow(rawValue: indexPath.row)! - switch row { -// case .basalRate: -// -// // x22 with max basal rate of 5U/hr -// let pulsesPerUnit = 20 -// let basalRates = (1...100).map { Double($0) / Double(pulsesPerUnit) } -// -// // full x23 rates -// let rateGroup1 = ((1...39).map { Double($0) / Double(40) }) -// let rateGroup2 = ((20...199).map { Double($0) / Double(20) }) -// let rateGroup3 = ((100...350).map { Double($0) / Double(10) }) -// let basalRates = rateGroup1 + rateGroup2 + rateGroup3 - -// let scheduleVC = BasalScheduleTableViewController(allowedBasalRates: basalRates, maximumScheduleItemCount: 5, minimumTimeInterval: .minutes(30)) -// -// if let profile = dataManager?.basalRateSchedule { -// scheduleVC.timeZone = profile.timeZone -// -// -// scheduleVC.scheduleItems = profile.items -// } -// scheduleVC.delegate = self -// scheduleVC.title = sender?.textLabel?.text -// scheduleVC.syncSource = self -// -// show(scheduleVC, sender: sender) - case .carbRatio: - let scheduleVC = DailyQuantityScheduleTableViewController() - - scheduleVC.delegate = self - scheduleVC.title = NSLocalizedString("Carb Ratios", comment: "The title of the carb ratios schedule screen") - scheduleVC.unit = .gram() - - if let schedule = dataManager?.carbRatioSchedule { - scheduleVC.timeZone = schedule.timeZone - scheduleVC.scheduleItems = schedule.items - scheduleVC.unit = schedule.unit - } - - show(scheduleVC, sender: sender) - case .correctionRange: - var therapySettings = TherapySettings() - therapySettings.glucoseTargetRangeSchedule = self.dataManager?.glucoseTargetRangeSchedule - let therapySettingsViewModel = TherapySettingsViewModel(therapySettings: therapySettings) - - let view = CorrectionRangeScheduleEditor(mode: .settings, therapySettingsViewModel: therapySettingsViewModel, didSave: { - self.dataManager?.glucoseTargetRangeSchedule = therapySettingsViewModel.therapySettings.glucoseTargetRangeSchedule - self.navigationController?.popToViewController(self, animated: true) - }) - .environmentObject(DisplayGlucoseUnitObservable(displayGlucoseUnit: .milligramsPerDeciliter)) - - let scheduleVC = DismissibleHostingController(rootView: view, dismissalMode: .pop(to: type(of: self)), isModalInPresentation: false) - show(scheduleVC, sender: sender) - case .insulinSensitivity: - let unit = dataManager?.insulinSensitivitySchedule?.unit ?? dataManager?.glucoseStore.preferredUnit ?? HKUnit.milligramsPerDeciliter - let scheduleVC = InsulinSensitivityScheduleViewController(allowedValues: unit.allowedSensitivityValues, unit: unit) - - scheduleVC.unit = unit - scheduleVC.delegate = self - scheduleVC.insulinSensitivityScheduleStorageDelegate = self - scheduleVC.schedule = dataManager?.insulinSensitivitySchedule - scheduleVC.title = NSLocalizedString("Insulin Sensitivity", comment: "The title of the insulin sensitivity schedule screen") - show(scheduleVC, sender: sender) - - case .pumpID: - let textFieldVC = TextFieldTableViewController() - -// textFieldVC.delegate = self - textFieldVC.title = sender?.textLabel?.text - textFieldVC.placeholder = NSLocalizedString("Enter the 6-digit pump ID", comment: "The placeholder text instructing users how to enter a pump ID") - textFieldVC.value = dataManager?.pumpID - textFieldVC.keyboardType = .numberPad - textFieldVC.contextHelp = NSLocalizedString("The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N).", comment: "Instructions on where to find the pump ID on a Minimed pump") - - show(textFieldVC, sender: sender) - default: - break - } - case .data: - switch DataRow(rawValue: indexPath.row)! { - case .carbs: - //performSegue(withIdentifier: CarbEntryTableViewController.className, sender: sender) - break - case .reservoir: - performSegue(withIdentifier: LegacyInsulinDeliveryTableViewController.className, sender: sender) - case .diagnostic: - let vc = CommandResponseViewController(command: { [weak self] (completionHandler) -> String in - let group = DispatchGroup() - - guard let dataManager = self?.dataManager else { - completionHandler("") - return "nil" - } - - var doseStoreResponse = "" - group.enter() - dataManager.doseStore.generateDiagnosticReport { (report) in - doseStoreResponse = report - group.leave() - } - - var carbStoreResponse = "" - if let carbStore = dataManager.carbStore { - group.enter() - carbStore.generateDiagnosticReport { (report) in - carbStoreResponse = report - group.leave() - } - } - - var glucoseStoreResponse = "" - group.enter() - dataManager.glucoseStore.generateDiagnosticReport { (report) in - glucoseStoreResponse = report - group.leave() - } - - group.notify(queue: DispatchQueue.main) { - completionHandler([ - doseStoreResponse, - carbStoreResponse, - glucoseStoreResponse - ].joined(separator: "\n\n")) - } - - return "…" - }) - vc.title = "Diagnostic" - - show(vc, sender: sender) - case .generate: - let vc = CommandResponseViewController(command: { [weak self] (completionHandler) -> String in - guard let dataManager = self?.dataManager else { - completionHandler("") - return "dataManager is nil" - } - - let group = DispatchGroup() - - var unitVolume = 150.0 - - reservoir: for index in sequence(first: TimeInterval(hours: -6), next: { $0 + .minutes(5) }) { - guard index < 0 else { - break reservoir - } - - unitVolume -= (drand48() * 2.0) - - group.enter() - dataManager.doseStore.addReservoirValue(unitVolume, at: Date(timeIntervalSinceNow: index)) { (_, _, _, error) in - group.leave() - } - } - - group.enter() - dataManager.glucoseStore.addGlucoseSamples([NewGlucoseSample(date: Date(), quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 101), condition: nil, trend: nil, trendRate: nil, isDisplayOnly: false, wasUserEntered: false, syncIdentifier: UUID().uuidString)], completion: { (result) in - group.leave() - }) - - group.notify(queue: .main) { - completionHandler("Completed") - } - - return "Generating…" - }) - vc.title = sender?.textLabel?.text - - show(vc, sender: sender) - case .reset: - dataManager = nil - tableView.reloadData() - } - } - } - - // MARK: - Segues - - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - super.prepare(for: segue, sender: sender) - - var targetViewController = segue.destination - - if let navVC = targetViewController as? UINavigationController, let topViewController = navVC.topViewController { - targetViewController = topViewController - } - - switch targetViewController { - case let vc as LegacyInsulinDeliveryTableViewController: - vc.doseStore = dataManager?.doseStore - default: - break - } - } -} - - -extension MasterViewController: DailyValueScheduleTableViewControllerDelegate { - func dailyValueScheduleTableViewControllerWillFinishUpdating(_ controller: DailyValueScheduleTableViewController) { - if let indexPath = tableView.indexPathForSelectedRow { - switch Section(rawValue: indexPath.section)! { - case .configuration: - switch ConfigurationRow(rawValue: indexPath.row)! { -// case .basalRate: -// if let controller = controller as? BasalScheduleTableViewController { -// dataManager?.basalRateSchedule = BasalRateSchedule(dailyItems: controller.scheduleItems, timeZone: controller.timeZone) -// } - default: - break - } - - tableView.reloadRows(at: [indexPath], with: .none) - default: - break - } - } - } -} - - -extension MasterViewController: InsulinSensitivityScheduleStorageDelegate { - func saveSchedule(_ schedule: InsulinSensitivitySchedule, for viewController: InsulinSensitivityScheduleViewController, completion: @escaping (SaveInsulinSensitivityScheduleResult) -> Void) { - self.dataManager?.insulinSensitivitySchedule = schedule - completion(.success) - } -} - -private extension HKUnit { - var allowedSensitivityValues: [Double] { - if self == HKUnit.milligramsPerDeciliter { - return (10...500).map { Double($0) } - } - - if self == HKUnit.millimolesPerLiter { - return (6...270).map { Double($0) / 10.0 } - } - - return [] - } - - var allowedCorrectionRangeValues: [Double] { - if self == HKUnit.milligramsPerDeciliter { - return (60...180).map { Double($0) } - } - - if self == HKUnit.millimolesPerLiter { - return (33...100).map { Double($0) / 10.0 } - } - - return [] - } -} diff --git a/Dependencies/LoopKit/LoopKit Example/ar.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/ar.lproj/Localizable.strings deleted file mode 100644 index d6379bd41..000000000 --- a/Dependencies/LoopKit/LoopKit Example/ar.lproj/Localizable.strings +++ /dev/null @@ -1,21 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "الضخ المستمر"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "معاملات الكارب"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Carbs"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "نطاق التصحيح"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Enter the 6-digit pump ID"; - -/* The title text for the pump ID */ -"Pump ID" = "Pump ID"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "الخزان"; - diff --git a/Dependencies/LoopKit/LoopKit Example/ar.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/ar.lproj/Main.strings deleted file mode 100644 index bc7d8efb8..000000000 --- a/Dependencies/LoopKit/LoopKit Example/ar.lproj/Main.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "عنوان"; - diff --git a/Dependencies/LoopKit/LoopKit Example/cs.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/cs.lproj/Localizable.strings deleted file mode 100644 index 08727bede..000000000 --- a/Dependencies/LoopKit/LoopKit Example/cs.lproj/Localizable.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Úrovně bazálu"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Zadejte 6místné ID pumpy"; - -/* The title text for the pump ID */ -"Pump ID" = "ID pumpy"; - diff --git a/Dependencies/LoopKit/LoopKit Example/da.lproj/InfoPlist.strings b/Dependencies/LoopKit/LoopKit Example/da.lproj/InfoPlist.strings deleted file mode 100644 index 81b74517f..000000000 --- a/Dependencies/LoopKit/LoopKit Example/da.lproj/InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle name */ -"CFBundleName" = "Eksempel på LoopKit"; - -/* Privacy - Health Share Usage Description */ -"NSHealthShareUsageDescription" = "Måltidsdata fra Apple Health-databasen bruges til at bestemme effekten på blodsukkeret. Blodsukkerdata fra Apple Health-databasen bruges til graftegning og momentum beregnings"; - -/* Privacy - Health Update Usage Description */ -"NSHealthUpdateUsageDescription" = "Kulhydrater indtastet i Loop gemmes i Health databasen. Blodsukker lagres sikkert i HealthKit."; - diff --git a/Dependencies/LoopKit/LoopKit Example/da.lproj/LaunchScreen.strings b/Dependencies/LoopKit/LoopKit Example/da.lproj/LaunchScreen.strings deleted file mode 100644 index 8b1378917..000000000 --- a/Dependencies/LoopKit/LoopKit Example/da.lproj/LaunchScreen.strings +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Dependencies/LoopKit/LoopKit Example/da.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/da.lproj/Localizable.strings deleted file mode 100644 index 0da3a5a5e..000000000 --- a/Dependencies/LoopKit/LoopKit Example/da.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basalrater"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Kulhydratforhold"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Kulhydrater"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Korrektionsområde"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Diagnostik"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Indtast det 6-cifrede pumpe ID"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Genererer data"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Insulinfølsomhed"; - -/* The title text for the pump ID */ -"Pump ID" = "Pumpe ID"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Reservoir"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Nulstil"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Synkroniser med pumpe"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "Pumpe ID kan findes trykt på bagsiden, eller nær bunden på STATUS/Esc skærmen. Det er den rent numeriske del af serienummeret (vist som SN eller S/N)"; - diff --git a/Dependencies/LoopKit/LoopKit Example/da.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/da.lproj/Main.strings deleted file mode 100644 index 87e302e73..000000000 --- a/Dependencies/LoopKit/LoopKit Example/da.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "UI Tests"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Titel"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "UI Tests"; - diff --git a/Dependencies/LoopKit/LoopKit Example/de.lproj/InfoPlist.strings b/Dependencies/LoopKit/LoopKit Example/de.lproj/InfoPlist.strings deleted file mode 100644 index 124cf4b88..000000000 --- a/Dependencies/LoopKit/LoopKit Example/de.lproj/InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle name */ -"CFBundleName" = "LoopKit-Beispiel"; - -/* Privacy - Health Share Usage Description */ -"NSHealthShareUsageDescription" = "Mahlzeitendaten aus HealthKit werden verwendet, um Blutzuckereffekte zu bestimmen. Blutzuckerdaten aus HealthKit werden für die grafische Darstellung und Momentum-Berechnung verwendet."; - -/* Privacy - Health Update Usage Description */ -"NSHealthUpdateUsageDescription" = "In die App eingegebene Daten zu Mahlzeiten werden in HealthKit gespeichert. Blutzuckerwerte werden sicher in HealthKit gespeichert."; - diff --git a/Dependencies/LoopKit/LoopKit Example/de.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/de.lproj/Localizable.strings deleted file mode 100644 index 74b299a5b..000000000 --- a/Dependencies/LoopKit/LoopKit Example/de.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basalrate"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "KH-Verhältnis"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "KH"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Korrekturbereich"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Diagnosedaten"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Geben Sie die 6-stellige Pumpen-ID ein"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Erzeuge Daten"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Insulinempfindlichkeit"; - -/* The title text for the pump ID */ -"Pump ID" = "Pumpen-ID"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Reservoir"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Reset"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Mit der Pumpe synchronisieren"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "Die Pumpen-ID finden Sie auf der Rückseite oder am unteren Rand des STATUS / Esc-Bildschirms. Dies ist der streng numerische Teil der Seriennummer (gezeigt als SN oder S/N)."; - diff --git a/Dependencies/LoopKit/LoopKit Example/de.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/de.lproj/Main.strings deleted file mode 100644 index b81b54651..000000000 --- a/Dependencies/LoopKit/LoopKit Example/de.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "UI-Tests"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Titel"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "UI-Tests"; - diff --git a/Dependencies/LoopKit/LoopKit Example/en.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/en.lproj/Localizable.strings deleted file mode 100644 index 087db1a52..000000000 --- a/Dependencies/LoopKit/LoopKit Example/en.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basal Rates"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Carb Ratios"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Carbs"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Correction Range"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Diagnostic"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Enter the 6-digit pump ID"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Generate Data"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Insulin Sensitivity"; - -/* The title text for the pump ID */ -"Pump ID" = "Pump ID"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Reservoir"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Reset"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Sync With Pump"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)."; - diff --git a/Dependencies/LoopKit/LoopKit Example/es.lproj/InfoPlist.strings b/Dependencies/LoopKit/LoopKit Example/es.lproj/InfoPlist.strings deleted file mode 100644 index a79de59db..000000000 --- a/Dependencies/LoopKit/LoopKit Example/es.lproj/InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle name */ -"CFBundleName" = "Ejemplo de LoopKit"; - -/* Privacy - Health Share Usage Description */ -"NSHealthShareUsageDescription" = "Datos de alimentos de Salud se utiliza para determinar los efectos en el nivel de glucosa. Datos de glucosa de Salud se utilizan para graficar y determinar cálculos de momento."; - -/* Privacy - Health Update Usage Description */ -"NSHealthUpdateUsageDescription" = "Datos de alimentos ingresados en la aplicación son almacenados en la base de datos de Salud. Los datos de glucosa se almacenan de manera segura en Kit de Salud."; - diff --git a/Dependencies/LoopKit/LoopKit Example/es.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/es.lproj/Localizable.strings deleted file mode 100644 index 467e4fca5..000000000 --- a/Dependencies/LoopKit/LoopKit Example/es.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Tasas basales"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Ratios de carbohidratos"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Carbohidratos"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Rango de Corrección"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Diagnóstico"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Ingrese ID de 6 dígitios de la microinfusora"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Generar Datos"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Sensibilidad a la insulina"; - -/* The title text for the pump ID */ -"Pump ID" = "ID de Bomba"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Reservorio"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Reiniciar"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Sincronizar con la Microinfusora"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "El ID de microinfusora puede encontrarse en la parte trasera o cerca de la parte inferior de la pantalla STATUS/Esc. Es la parte estrictamente numérica del número de serie mostrado como SN o S/N"; - diff --git a/Dependencies/LoopKit/LoopKit Example/es.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/es.lproj/Main.strings deleted file mode 100644 index 8bbae80b8..000000000 --- a/Dependencies/LoopKit/LoopKit Example/es.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "Pruebas de UI"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Título"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "Pruebas de UI"; - diff --git a/Dependencies/LoopKit/LoopKit Example/fi.lproj/InfoPlist.strings b/Dependencies/LoopKit/LoopKit Example/fi.lproj/InfoPlist.strings deleted file mode 100644 index 0e4ae92b8..000000000 --- a/Dependencies/LoopKit/LoopKit Example/fi.lproj/InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle name */ -"CFBundleName" = "LoopKit-esimerkki"; - -/* Privacy - Health Share Usage Description */ -"NSHealthShareUsageDescription" = "Terveys-sovelluksen ateriatietoja käytetään glukoosivaikutusten määrittämiseen. Terveys-sovelluksen glukoositietoja käytetään graafeissa ja laskelmissa."; - -/* Privacy - Health Update Usage Description */ -"NSHealthUpdateUsageDescription" = "Sovelluksen kautta tallennetut hiilihydraattitiedot tallennetaan Terveys-tietokantaan. Glukoositieto tallennetaan turvallisesti HealthKitiin."; - diff --git a/Dependencies/LoopKit/LoopKit Example/fi.lproj/LaunchScreen.strings b/Dependencies/LoopKit/LoopKit Example/fi.lproj/LaunchScreen.strings deleted file mode 100644 index 8b1378917..000000000 --- a/Dependencies/LoopKit/LoopKit Example/fi.lproj/LaunchScreen.strings +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Dependencies/LoopKit/LoopKit Example/fi.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/fi.lproj/Localizable.strings deleted file mode 100644 index bb2e65b99..000000000 --- a/Dependencies/LoopKit/LoopKit Example/fi.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basaalitasot"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Hiilihydraattisuhteet"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Hiilihydraatit"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Korjausalue"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Diagnostiikka"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Syötä 6-numeroinen pumpun tunniste"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Luo tiedot"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Insuliiniherkkyys"; - -/* The title text for the pump ID */ -"Pump ID" = "Pumpun tunniste"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Säiliö"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Nollaa"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Synkronoi pumpun kanssa"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "Pumpun tunniste löytyy pumpun takaosasta tai STATUS/Esc-valikon loppuosasta. Se on pelkästään numeroita sisältävä osa sarjanumerosta (SN tai S/N)."; - diff --git a/Dependencies/LoopKit/LoopKit Example/fi.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/fi.lproj/Main.strings deleted file mode 100644 index 8d5a826f8..000000000 --- a/Dependencies/LoopKit/LoopKit Example/fi.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "UI Tests"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Title"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "UI Tests"; - diff --git a/Dependencies/LoopKit/LoopKit Example/fr.lproj/InfoPlist.strings b/Dependencies/LoopKit/LoopKit Example/fr.lproj/InfoPlist.strings deleted file mode 100644 index 84c8cd981..000000000 --- a/Dependencies/LoopKit/LoopKit Example/fr.lproj/InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle name */ -"CFBundleName" = "Exemple de LoopKit"; - -/* Privacy - Health Share Usage Description */ -"NSHealthShareUsageDescription" = "Les données sur les repas provenant de la base de données Santé sont utilisées pour déterminer les effets sur la glycémie . Les données sur la glycémie de la base de données Health sont utilisées pour le calcul graphique et le calcul du momentum."; - -/* Privacy - Health Update Usage Description */ -"NSHealthUpdateUsageDescription" = "Les données sur les apports de repas glucidiques saisies dans l'application sont stockées dans la base de données Santé d'Apple. Les données de glycémie extraites du CGM sont stockées de manière sécurisée dans HealthKit."; - diff --git a/Dependencies/LoopKit/LoopKit Example/fr.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/fr.lproj/Localizable.strings deleted file mode 100644 index 0fcf76e3d..000000000 --- a/Dependencies/LoopKit/LoopKit Example/fr.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Débits basaux"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Ratios Insuline-Glucides"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Glucides"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Plage de correction"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Diagnostique"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Entrée l’ID de pompe de 6 chiffres"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Générer les données"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Facteur de sensibilité à l’insuline"; - -/* The title text for the pump ID */ -"Pump ID" = "ID de la pompe"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Réservoir"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Réinitialiser"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Synchroniser avec la pompe"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "L'ID de la pompe se trouve imprimé au dos ou près du bas de l'écran STATUS/Esc. Il s'agit de la partie uniquement numérique du numéro de série (indiquée par SN ou S/N)."; - diff --git a/Dependencies/LoopKit/LoopKit Example/fr.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/fr.lproj/Main.strings deleted file mode 100644 index 8d5a826f8..000000000 --- a/Dependencies/LoopKit/LoopKit Example/fr.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "UI Tests"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Title"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "UI Tests"; - diff --git a/Dependencies/LoopKit/LoopKit Example/he.lproj/LaunchScreen.strings b/Dependencies/LoopKit/LoopKit Example/he.lproj/LaunchScreen.strings deleted file mode 100644 index 8b1378917..000000000 --- a/Dependencies/LoopKit/LoopKit Example/he.lproj/LaunchScreen.strings +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Dependencies/LoopKit/LoopKit Example/he.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/he.lproj/Localizable.strings deleted file mode 100644 index 4fbff9555..000000000 --- a/Dependencies/LoopKit/LoopKit Example/he.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basal Rates"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Carb Ratios"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Carbs"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Correction Range"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Diagnostic"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "הזן את מספר זיהוי המשאבה בן 6 הספרות"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Generate Data"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Insulin Sensitivity"; - -/* The title text for the pump ID */ -"Pump ID" = "מספר זיהוי המשאבה"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Reservoir"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Reset"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Sync With Pump"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "מספר זיהוי המשאבה מודפס על החלק האחורי או קרוב לחלק התחתון של המסך STATUS/Esc. רק הספרות של מספר הסידורי נצרכות (מופיעה כ- SN או S/N)."; - diff --git a/Dependencies/LoopKit/LoopKit Example/he.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/he.lproj/Main.strings deleted file mode 100644 index 8d5a826f8..000000000 --- a/Dependencies/LoopKit/LoopKit Example/he.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "UI Tests"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Title"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "UI Tests"; - diff --git a/Dependencies/LoopKit/LoopKit Example/it.lproj/InfoPlist.strings b/Dependencies/LoopKit/LoopKit Example/it.lproj/InfoPlist.strings deleted file mode 100644 index 4d34b1f59..000000000 --- a/Dependencies/LoopKit/LoopKit Example/it.lproj/InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle name */ -"CFBundleName" = "Esempio di LoopKit"; - -/* Privacy - Health Share Usage Description */ -"NSHealthShareUsageDescription" = "I dati sui pasti contenuti nel database della app Apple Salute vengono utilizzati per determinare gli effetti sulla glicemia. Inoltre i dati del glucosio contenuti nel database di Apple Salute vengono utilizzati per il calcolo del grafico e le variazioni glicemiche."; - -/* Privacy - Health Update Usage Description */ -"NSHealthUpdateUsageDescription" = "I dati dei carboidrati relativi ai pasti inseriti nell'app vengono archiviati nel database Salute. I dati delle glicemie vengono archiviati in modo sicuro in Salute."; - diff --git a/Dependencies/LoopKit/LoopKit Example/it.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/it.lproj/Localizable.strings deleted file mode 100644 index 65cc4a337..000000000 --- a/Dependencies/LoopKit/LoopKit Example/it.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Velocità basali"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Rapporti carboidrati"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Carb."; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Intervallo Glicemico"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Dati diagnostici"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Inserire 6-cifre ID micro"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Genera dati"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Sensibilità insulinica"; - -/* The title text for the pump ID */ -"Pump ID" = "ID microinfusore"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Serbatoio"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Ripristina"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Sincronizza con la pompa"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "L'ID della pompa si trova stampato sul retro o in fondo alla schermata STATO/Esc. È la parte strettamente numerica del numero di serie (indicato come SN o S/N)."; - diff --git a/Dependencies/LoopKit/LoopKit Example/it.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/it.lproj/Main.strings deleted file mode 100644 index 0768c382c..000000000 --- a/Dependencies/LoopKit/LoopKit Example/it.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "Test dell'interfaccia utente"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Titolo"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "Test dell'interfaccia utente"; - diff --git a/Dependencies/LoopKit/LoopKit Example/ja.lproj/LaunchScreen.strings b/Dependencies/LoopKit/LoopKit Example/ja.lproj/LaunchScreen.strings deleted file mode 100644 index 8b1378917..000000000 --- a/Dependencies/LoopKit/LoopKit Example/ja.lproj/LaunchScreen.strings +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Dependencies/LoopKit/LoopKit Example/ja.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/ja.lproj/Localizable.strings deleted file mode 100644 index 4b1a9977e..000000000 --- a/Dependencies/LoopKit/LoopKit Example/ja.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "基礎レート"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Carb Ratios"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "カーボ"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "ターゲット範囲"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "診断"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "6桁のポンプ ID"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "データ生成"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Insulin Sensitivity"; - -/* The title text for the pump ID */ -"Pump ID" = "ポンプ ID"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Reservoir"; - -/* Title for the cell resetting the data manager */ -"Reset" = "リセット"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "ポンプと同期する"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "ポンプIDは、ポンプの裏面か、STATUS/Esc画面の下方に表示されています。シリアル番号の数字の部分です。(SNまたはS/Nで表示)"; - diff --git a/Dependencies/LoopKit/LoopKit Example/ja.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/ja.lproj/Main.strings deleted file mode 100644 index 8d5a826f8..000000000 --- a/Dependencies/LoopKit/LoopKit Example/ja.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "UI Tests"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Title"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "UI Tests"; - diff --git a/Dependencies/LoopKit/LoopKit Example/nb.lproj/InfoPlist.strings b/Dependencies/LoopKit/LoopKit Example/nb.lproj/InfoPlist.strings deleted file mode 100644 index 9a6f7bb68..000000000 --- a/Dependencies/LoopKit/LoopKit Example/nb.lproj/InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle name */ -"CFBundleName" = "LoopKit-eksempel"; - -/* Privacy - Health Share Usage Description */ -"NSHealthShareUsageDescription" = "Måltidsdata fra helsedatabasen brukes til å bestemme glukoseeffekter. Glukosedata fra helsedatabasen brukes til grafer og momentumberegning."; - -/* Privacy - Health Update Usage Description */ -"NSHealthUpdateUsageDescription" = "Karbohydratmåltidsdata som legges inn i appen, lagres i Helsedatabasen. Glukosedata lagres sikkert i HealthKit."; - diff --git a/Dependencies/LoopKit/LoopKit Example/nb.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/nb.lproj/Localizable.strings deleted file mode 100644 index 4f4137a8c..000000000 --- a/Dependencies/LoopKit/LoopKit Example/nb.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basal-satser"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Karb forhold"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Karbohydrater"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Korreksjonsområde"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Diagnostikk"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Skriv 6-siffret pumpe-ID"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Generer data"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Insulinfølsomhet"; - -/* The title text for the pump ID */ -"Pump ID" = "Pumpe ID"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Reservoar"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Nullstille"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Synkroniser med pumpe"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "Pumpe-ID finner du trykt på baksiden eller nær bunnen av STATUS/Esc-skjermen. Det er den numeriske delen av serienummeret (vist som SN eller S/N)."; - diff --git a/Dependencies/LoopKit/LoopKit Example/nb.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/nb.lproj/Main.strings deleted file mode 100644 index be772d0a0..000000000 --- a/Dependencies/LoopKit/LoopKit Example/nb.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "UI Tester"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Tittel"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "UI Tester"; - diff --git a/Dependencies/LoopKit/LoopKit Example/nl.lproj/InfoPlist.strings b/Dependencies/LoopKit/LoopKit Example/nl.lproj/InfoPlist.strings deleted file mode 100644 index 20fab0fc1..000000000 --- a/Dependencies/LoopKit/LoopKit Example/nl.lproj/InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle name */ -"CFBundleName" = "LoopKit Voorbeeld"; - -/* Privacy - Health Share Usage Description */ -"NSHealthShareUsageDescription" = "Maaltijdgegevens uit de database Gezondheid worden gebruikt om glucoseëffecten te bepalen. Glucosegegevens uit de database Gezondheid worden gebruikt voor grafieken en het berekenen van trendlijnen."; - -/* Privacy - Health Update Usage Description */ -"NSHealthUpdateUsageDescription" = "Maaltijdkoolhydraten die worden ingevoerd in de app worden opgeslagen in de database Gezondheid. Glucosegegevens worden veilig opgeslagen in HealthKit."; - diff --git a/Dependencies/LoopKit/LoopKit Example/nl.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/nl.lproj/Localizable.strings deleted file mode 100644 index 90aa0ed94..000000000 --- a/Dependencies/LoopKit/LoopKit Example/nl.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basaalsnelheden"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Koolhydraatratio's"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Koolhydraten"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Correctiebereik"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Diagnose"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Voer het 6-cijferige pompserienummer in"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Genereer Gegevens"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Insulinegevoeligheid"; - -/* The title text for the pump ID */ -"Pump ID" = "Pompserienummer"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Reservoir"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Reset"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Synchroniseer met pomp"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "Het pompserienummer vindt je op de achterkant of onderaan het STATUS/Esc-scherm. Het is het strikt numerieke deel van het serienummer (weergegeven als SN of S/N)."; - diff --git a/Dependencies/LoopKit/LoopKit Example/nl.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/nl.lproj/Main.strings deleted file mode 100644 index 239c3d06c..000000000 --- a/Dependencies/LoopKit/LoopKit Example/nl.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "UI Testen"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Titel"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "UI Testen"; - diff --git a/Dependencies/LoopKit/LoopKit Example/pl.lproj/InfoPlist.strings b/Dependencies/LoopKit/LoopKit Example/pl.lproj/InfoPlist.strings deleted file mode 100644 index 5fabb05e2..000000000 --- a/Dependencies/LoopKit/LoopKit Example/pl.lproj/InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle name */ -"CFBundleName" = "LoopKit Example"; - -/* Privacy - Health Share Usage Description */ -"NSHealthShareUsageDescription" = "Dane o posiłkach z bazy danych aplikacji Zdrowie są używane do ustalania wpływu na poziom glukozy. Dane o poziomie glukozy z bazy danych aplikacji Apple Zdrowie są używane do tworzenia wykresu i obliczania momentum."; - -/* Privacy - Health Update Usage Description */ -"NSHealthUpdateUsageDescription" = "Dane dotyczące posiłków zawierających węglowodany wprowadzone w aplikacji są przechowywane w bazie danych aplikacji Zdrowie. Dane dotyczące glukozy są bezpiecznie przechowywane w Zdrowie Kit."; - diff --git a/Dependencies/LoopKit/LoopKit Example/pl.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/pl.lproj/Localizable.strings deleted file mode 100644 index 1e0620ec9..000000000 --- a/Dependencies/LoopKit/LoopKit Example/pl.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Dawka Podstawowa (Baza)"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Współczynniki węglowodanowe"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Węglowodany"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Zakres docelowy"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Diagnostyka"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Wprowadź 6-cyfrowy numer pompy"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Generuj dane"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Insulinowrażliwość"; - -/* The title text for the pump ID */ -"Pump ID" = "ID pompy"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Zbiorniczek"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Resetuj"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Synchronizuj z pompą"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)."; - diff --git a/Dependencies/LoopKit/LoopKit Example/pl.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/pl.lproj/Main.strings deleted file mode 100644 index 818547568..000000000 --- a/Dependencies/LoopKit/LoopKit Example/pl.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "Testy interfejsu użytkownika"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Title"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "Testy interfejsu użytkownika"; - diff --git a/Dependencies/LoopKit/LoopKit Example/pt-BR.lproj/LaunchScreen.strings b/Dependencies/LoopKit/LoopKit Example/pt-BR.lproj/LaunchScreen.strings deleted file mode 100644 index 8b1378917..000000000 --- a/Dependencies/LoopKit/LoopKit Example/pt-BR.lproj/LaunchScreen.strings +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Dependencies/LoopKit/LoopKit Example/pt-BR.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/pt-BR.lproj/Localizable.strings deleted file mode 100644 index 5acc3e2c0..000000000 --- a/Dependencies/LoopKit/LoopKit Example/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Taxas Basais"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Taxas de Carbs"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Carbs"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Faixa de Correção"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Diagnóstico"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Digite o ID da bomba de 6 dígitos"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Gerar Dados"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Sensibilidade a Insulina"; - -/* The title text for the pump ID */ -"Pump ID" = "ID da Bomba"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Reservoir"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Restabelecer"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Sincronizar com a Bomba"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "O ID da bomba pode ser encontrado impresso na parte traseira ou na parte inferior da tela STATUS/Esc. É a parte estritamente numérica do número de série (mostrado como SN ou S/N)."; - diff --git a/Dependencies/LoopKit/LoopKit Example/pt-BR.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/pt-BR.lproj/Main.strings deleted file mode 100644 index 8d5a826f8..000000000 --- a/Dependencies/LoopKit/LoopKit Example/pt-BR.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "UI Tests"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Title"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "UI Tests"; - diff --git a/Dependencies/LoopKit/LoopKit Example/ro.lproj/InfoPlist.strings b/Dependencies/LoopKit/LoopKit Example/ro.lproj/InfoPlist.strings deleted file mode 100644 index 23a9cd988..000000000 --- a/Dependencies/LoopKit/LoopKit Example/ro.lproj/InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle name */ -"CFBundleName" = "Exemplu de LoopKit"; - -/* Privacy - Health Share Usage Description */ -"NSHealthShareUsageDescription" = "Datele mesei din baza de date Health sunt folosite pentru a determina efectele glicemiei. Datele despre glicemie din baza de date Health sunt folosite pentru grafice și calcularea impulsului."; - -/* Privacy - Health Update Usage Description */ -"NSHealthUpdateUsageDescription" = "Carbohidrații introduși în aplicație sunt stocați în baza de date Health. Glicemiile sunt stocate în mod confidențial în HealthKit."; - diff --git a/Dependencies/LoopKit/LoopKit Example/ro.lproj/LaunchScreen.strings b/Dependencies/LoopKit/LoopKit Example/ro.lproj/LaunchScreen.strings deleted file mode 100644 index 8b1378917..000000000 --- a/Dependencies/LoopKit/LoopKit Example/ro.lproj/LaunchScreen.strings +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Dependencies/LoopKit/LoopKit Example/ro.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/ro.lproj/Localizable.strings deleted file mode 100644 index fee3aead2..000000000 --- a/Dependencies/LoopKit/LoopKit Example/ro.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Rate bazale"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Raport carbohidrați/insulină"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Carbohidrați"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Interval țintă pentru corecție"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Diagnostic"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Introduceți ID-ul de pompă din 6 cifre"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Generează date"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Factor de sensibilitate la insulină"; - -/* The title text for the pump ID */ -"Pump ID" = "ID pompă"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Rezervor"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Resetare"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Sincronizează cu pompa"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "ID-ul pompei poate fi găsit pe spate sau în partea inferioară a ecranului STATUS/Esc. Este format strict din porțiunea numerică a numărului serial (afișat ca SN sau S/N)."; - diff --git a/Dependencies/LoopKit/LoopKit Example/ro.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/ro.lproj/Main.strings deleted file mode 100644 index 8d5a826f8..000000000 --- a/Dependencies/LoopKit/LoopKit Example/ro.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "UI Tests"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Title"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "UI Tests"; - diff --git a/Dependencies/LoopKit/LoopKit Example/ru.lproj/InfoPlist.strings b/Dependencies/LoopKit/LoopKit Example/ru.lproj/InfoPlist.strings deleted file mode 100644 index 630548987..000000000 --- a/Dependencies/LoopKit/LoopKit Example/ru.lproj/InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle name */ -"CFBundleName" = "Пример LoopKit"; - -/* Privacy - Health Share Usage Description */ -"NSHealthShareUsageDescription" = "Данные о приеме пищи из базы данных Health используются для определения влияния глюкозы. Данные о глюкозе из базы данных Health используются для построения графиков и расчетов."; - -/* Privacy - Health Update Usage Description */ -"NSHealthUpdateUsageDescription" = "Данные об углеводах, введенные в приложение, сохраняются в базе данных Health. Данные о глюкозе надежно хранятся в HealthKit."; - diff --git a/Dependencies/LoopKit/LoopKit Example/ru.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/ru.lproj/Localizable.strings deleted file mode 100644 index c94ef2c32..000000000 --- a/Dependencies/LoopKit/LoopKit Example/ru.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Скорости базала"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Соотношения углеводов"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Углеводы"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Диапазон коррекции"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Диагностика"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Ввести 6-значный ID помпы"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Генерировать данные"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Чувствительность к инсулину"; - -/* The title text for the pump ID */ -"Pump ID" = "Идентификатор ID помпы"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Reservoir"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Сброс"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Синхронизация с помпой"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "Регион помпы находится на ее задней стенке как часть номера модели (REF), например MMT-551NAB или MMT-515LWWS. Если номер модели содержит \"NA\" or \"CA\", то регион - Северная Америка. Если это \"WW\", тогда регион - остальной мир."; - diff --git a/Dependencies/LoopKit/LoopKit Example/ru.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/ru.lproj/Main.strings deleted file mode 100644 index c916275d1..000000000 --- a/Dependencies/LoopKit/LoopKit Example/ru.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "Тесты пользовательского интерфейса"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Title"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "Тесты пользовательского интерфейса"; - diff --git a/Dependencies/LoopKit/LoopKit Example/sk.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/sk.lproj/Localizable.strings deleted file mode 100644 index 106ebc27c..000000000 --- a/Dependencies/LoopKit/LoopKit Example/sk.lproj/Localizable.strings +++ /dev/null @@ -1,18 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Bazálne dávky"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Inzulínovo sacharidový pomer"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Zadajte 6-miestne ID pumpy"; - -/* The title text for the pump ID */ -"Pump ID" = "ID pumpy"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Rezervoár"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Resetovať"; - diff --git a/Dependencies/LoopKit/LoopKit Example/sk.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/sk.lproj/Main.strings deleted file mode 100644 index 542ce77eb..000000000 --- a/Dependencies/LoopKit/LoopKit Example/sk.lproj/Main.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Názov"; - diff --git a/Dependencies/LoopKit/LoopKit Example/sv.lproj/InfoPlist.strings b/Dependencies/LoopKit/LoopKit Example/sv.lproj/InfoPlist.strings deleted file mode 100644 index 2b6426fab..000000000 --- a/Dependencies/LoopKit/LoopKit Example/sv.lproj/InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle name */ -"CFBundleName" = "LoopKit Example"; - -/* Privacy - Health Share Usage Description */ -"NSHealthShareUsageDescription" = "Kolhydratdata från Apple Health-databasen används för att avgöra glukoseffekt. Blodglukosvärden från Apple Health-databasen används i diagram och för beräkning av förändring."; - -/* Privacy - Health Update Usage Description */ -"NSHealthUpdateUsageDescription" = "Kolhydratvärden inmatade i appen lagras i Apple Health-databasen. Blodglukosvärden lagras säkert i HealthKit."; - diff --git a/Dependencies/LoopKit/LoopKit Example/sv.lproj/LaunchScreen.strings b/Dependencies/LoopKit/LoopKit Example/sv.lproj/LaunchScreen.strings deleted file mode 100644 index 8b1378917..000000000 --- a/Dependencies/LoopKit/LoopKit Example/sv.lproj/LaunchScreen.strings +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Dependencies/LoopKit/LoopKit Example/sv.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/sv.lproj/Localizable.strings deleted file mode 100644 index d1ad2be15..000000000 --- a/Dependencies/LoopKit/LoopKit Example/sv.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basaldoser"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Insulinkvoter"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Kolhydrater"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Målvärde"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Diagnostisk"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Ange 6-siffrigt pump-ID"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Generera data"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Insulinkänslighet"; - -/* The title text for the pump ID */ -"Pump ID" = "Pump-ID"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Reservoar"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Återställ"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Synka med pump"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "Ditt pump-ID står tryckt på baksidan, eller nästan längst ner på status/Esc-menyn. Det är den numeriska delen av serienumret (visad som SN eller S/N). "; - diff --git a/Dependencies/LoopKit/LoopKit Example/sv.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/sv.lproj/Main.strings deleted file mode 100644 index 8d5a826f8..000000000 --- a/Dependencies/LoopKit/LoopKit Example/sv.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "UI Tests"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Title"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "UI Tests"; - diff --git a/Dependencies/LoopKit/LoopKit Example/tr.lproj/InfoPlist.strings b/Dependencies/LoopKit/LoopKit Example/tr.lproj/InfoPlist.strings deleted file mode 100644 index 32c154cf1..000000000 --- a/Dependencies/LoopKit/LoopKit Example/tr.lproj/InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle name */ -"CFBundleName" = "LoopKit Örneği"; - -/* Privacy - Health Share Usage Description */ -"NSHealthShareUsageDescription" = "Sağlık veri tabanından alınan yemek verileri, KŞ etkilerini belirlemek için kullanılır. Sağlık veri tabanından alınan KŞ verileri, grafik ve momentum hesaplaması için kullanılır."; - -/* Privacy - Health Update Usage Description */ -"NSHealthUpdateUsageDescription" = "Uygulamaya girilen karbonhidrat yemek verileri Sağlık veritabanında saklanır. KŞ verileri HealthKit'te güvenli bir şekilde saklanır."; - diff --git a/Dependencies/LoopKit/LoopKit Example/tr.lproj/LaunchScreen.strings b/Dependencies/LoopKit/LoopKit Example/tr.lproj/LaunchScreen.strings deleted file mode 100644 index 8b1378917..000000000 --- a/Dependencies/LoopKit/LoopKit Example/tr.lproj/LaunchScreen.strings +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Dependencies/LoopKit/LoopKit Example/tr.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/tr.lproj/Localizable.strings deleted file mode 100644 index 51f3c1f6c..000000000 --- a/Dependencies/LoopKit/LoopKit Example/tr.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Bazal Oranlar"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Karbonhidrat Oranları"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Karb"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Düzeltme Aralığı"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Teşhis"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "6 haneli pompa kimliğini girin"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Veri Oluştur"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "İnsulin Duyarlılığı"; - -/* The title text for the pump ID */ -"Pump ID" = "Pompa Kimliği"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Rezervuar"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Sıfırla"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Pompa ile Senkronize Et"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "Pompa kimliğini, pompanın arkasında veya Durum/Esc ekranında bulabilirsiniz. Seri numarasının tam olarak sayısal kısmıdır (SN veya S/N olarak gösterilir)."; - diff --git a/Dependencies/LoopKit/LoopKit Example/tr.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/tr.lproj/Main.strings deleted file mode 100644 index 84f58a8dd..000000000 --- a/Dependencies/LoopKit/LoopKit Example/tr.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "UI Tests"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Başlık"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "UI Tests"; - diff --git a/Dependencies/LoopKit/LoopKit Example/vi.lproj/LaunchScreen.strings b/Dependencies/LoopKit/LoopKit Example/vi.lproj/LaunchScreen.strings deleted file mode 100644 index 8b1378917..000000000 --- a/Dependencies/LoopKit/LoopKit Example/vi.lproj/LaunchScreen.strings +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Dependencies/LoopKit/LoopKit Example/vi.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/vi.lproj/Localizable.strings deleted file mode 100644 index f31ff64b5..000000000 --- a/Dependencies/LoopKit/LoopKit Example/vi.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "Lịch biểu tiêm liều nền"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "Carb Ratios"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "Carbs"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "Phạm vi liều Bổ sung"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "Chuẩn đoán"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Nhập 6 số ID của bơm"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "Xuất bản dữ liệu"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "Độ nhạy Insulin"; - -/* The title text for the pump ID */ -"Pump ID" = "Số ID của bơm"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "Reservoir"; - -/* Title for the cell resetting the data manager */ -"Reset" = "Khôi phục lại"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "Đồng hóa dữ liệu với bơm"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "Số ID của bơm có thể nhìn thấy phía sau của bơm hay gần mục STATUS/Esc. Đây là phần số của số seri (bắt đầu bằng SN hay S/N)."; - diff --git a/Dependencies/LoopKit/LoopKit Example/vi.lproj/Main.strings b/Dependencies/LoopKit/LoopKit Example/vi.lproj/Main.strings deleted file mode 100644 index 8d5a826f8..000000000 --- a/Dependencies/LoopKit/LoopKit Example/vi.lproj/Main.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Class = "UITableViewController"; title = "UI Tests"; ObjectID = "7bK-jq-Zjz"; */ -"7bK-jq-Zjz.title" = "UI Tests"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "Arm-wq-HPj"; */ -"Arm-wq-HPj.text" = "Title"; - -/* Class = "UINavigationController"; title = "UI Tests"; ObjectID = "RMx-3f-FxP"; */ -"RMx-3f-FxP.title" = "UI Tests"; - diff --git a/Dependencies/LoopKit/LoopKit Example/zh-Hans.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit Example/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 2e60c62f6..000000000 --- a/Dependencies/LoopKit/LoopKit Example/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* The title text for the basal rate schedule */ -"Basal Rates" = "基础率"; - -/* The title of the carb ratios schedule screen */ -"Carb Ratios" = "碳水化合物系数"; - -/* The title for the cell navigating to the carbs screen */ -"Carbs" = "碳水化合物"; - -/* The title text for the glucose correction range schedule */ -"Correction Range" = "修正范围"; - -/* The title for the cell displaying diagnostic data */ -"Diagnostic" = "诊断"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "输入六位数字的泵ID"; - -/* The title for the cell displaying data generation */ -"Generate Data" = "创建日期"; - -/* The title of the insulin sensitivity schedule screen - The title text for the insulin sensitivity schedule */ -"Insulin Sensitivity" = "胰岛素敏感系数"; - -/* The title text for the pump ID */ -"Pump ID" = "胰岛素泵序列号"; - -/* The title for the cell navigating to the reservoir screen */ -"Reservoir" = "胰岛素容量"; - -/* Title for the cell resetting the data manager */ -"Reset" = "重置"; - -/* Title of button to sync basal profile from pump */ -"Sync With Pump" = "同步到胰岛素"; - -/* Instructions on where to find the pump ID on a Minimed pump */ -"The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)." = "The pump ID can be found printed on the back, or near the bottom of the STATUS/Esc screen. It is the strictly numerical portion of the serial number (shown as SN or S/N)."; - diff --git a/Dependencies/LoopKit/LoopKit.xcodeproj/project.pbxproj b/Dependencies/LoopKit/LoopKit.xcodeproj/project.pbxproj deleted file mode 100644 index b88d32f23..000000000 --- a/Dependencies/LoopKit/LoopKit.xcodeproj/project.pbxproj +++ /dev/null @@ -1,5515 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXBuildFile section */ - 14B33265293ED44C009B8746 /* GlucoseRangeSchedule+SafeBounds.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14B33264293ED44C009B8746 /* GlucoseRangeSchedule+SafeBounds.swift */; }; - 1D096BFA24C242300078B6B5 /* CheckmarkListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D096BF924C242300078B6B5 /* CheckmarkListItem.swift */; }; - 1D096C0224C24C220078B6B5 /* InsulinModelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D096BFF24C24C220078B6B5 /* InsulinModelProvider.swift */; }; - 1D096C0324C24C220078B6B5 /* ExponentialInsulinModelPreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D096C0024C24C220078B6B5 /* ExponentialInsulinModelPreset.swift */; }; - 1D096C0524C624F70078B6B5 /* InsulinModelSettings+LoopKitUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D096C0424C624F70078B6B5 /* InsulinModelSettings+LoopKitUI.swift */; }; - 1D0E708526BDE3BB00AECF0D /* HKDeviceCodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D0E708426BDE3BB00AECF0D /* HKDeviceCodableTests.swift */; }; - 1D1065E4282DAEE500026A70 /* VideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1065E2282DAEE500026A70 /* VideoView.swift */; }; - 1D1065E5282DAEE500026A70 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1065E3282DAEE500026A70 /* WebView.swift */; }; - 1D1065E7282DC3BB00026A70 /* PopoverLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1065E6282DC3BB00026A70 /* PopoverLink.swift */; }; - 1D1065E9282DC54700026A70 /* VideoPlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1065E8282DC54700026A70 /* VideoPlayView.swift */; }; - 1D1438B825633E2100BE8F06 /* GlucoseTherapySettingInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1438B725633E2100BE8F06 /* GlucoseTherapySettingInformationView.swift */; }; - 1D1A019E24B678BF0077D86E /* TherapySettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1A019D24B678BF0077D86E /* TherapySettingsView.swift */; }; - 1D1FCE2324BD13A2000300A8 /* CorrectionRangeOverridesExpandableSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1FCE2224BD13A2000300A8 /* CorrectionRangeOverridesExpandableSetting.swift */; }; - 1D1FCE2524BD42EF000300A8 /* TherapySettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1FCE2424BD42EF000300A8 /* TherapySettingsViewModel.swift */; }; - 1D1FCE2724BE4DE2000300A8 /* CorrectionRangeOverrides.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1FCE2624BE4DE2000300A8 /* CorrectionRangeOverrides.swift */; }; - 1D1FCE2924BE4F11000300A8 /* TherapySetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1FCE2824BE4F11000300A8 /* TherapySetting.swift */; }; - 1D1FCE2B24BE704A000300A8 /* TherapySetting+Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1FCE2A24BE704A000300A8 /* TherapySetting+Settings.swift */; }; - 1D24A8D524C896E100AB8DB9 /* Prescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D24A8D424C896E100AB8DB9 /* Prescription.swift */; }; - 1D25C22E246A2A1A00E87FA0 /* critical.caf in Resources */ = {isa = PBXBuildFile; fileRef = 1D25C22D246A2A1A00E87FA0 /* critical.caf */; }; - 1D3E2973276031F80041F460 /* ResizeablePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D3E2972276031F80041F460 /* ResizeablePicker.swift */; }; - 1D498E4724D892B0000627F2 /* Environment+Authenticate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D498E4624D892B0000627F2 /* Environment+Authenticate.swift */; }; - 1D60355E24D39ED10095DC2A /* Environment+AppName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D60355D24D39ED10095DC2A /* Environment+AppName.swift */; }; - 1D63DEA326E94FDF00F46FA5 /* VersionUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D63DEA226E94FDF00F46FA5 /* VersionUpdate.swift */; }; - 1D640FF724525228008F9755 /* sub.caf in Resources */ = {isa = PBXBuildFile; fileRef = 1D640FF524524284008F9755 /* sub.caf */; }; - 1D67E79D2563001800A82ED6 /* InformationScreens.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1D67E79C2563001800A82ED6 /* InformationScreens.xcassets */; }; - 1D6EAB9124C12C090081249D /* PumpSupportedIncrements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6EAB9024C12C090081249D /* PumpSupportedIncrements.swift */; }; - 1D70C40D26F01D9F00C62570 /* VersionCheckServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D70C40C26F01D9F00C62570 /* VersionCheckServiceTests.swift */; }; - 1D70F80226C1BEB700D5BE96 /* CoreDataMigrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D70F80126C1BEB700D5BE96 /* CoreDataMigrationTests.swift */; }; - 1D841AAD24577EE10069DBFF /* AlertSoundPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D841AAC24577EE10069DBFF /* AlertSoundPlayer.swift */; }; - 1D97A33C256F11E00042737E /* View+InsetGroupedListStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D97A33B256F11E00042737E /* View+InsetGroupedListStyle.swift */; }; - 1DA649AB2445174400F61E75 /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DA649AA2445174400F61E75 /* Alert.swift */; }; - 1DABAD3A2453615200ACF708 /* IssueAlertTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DABAD392453615200ACF708 /* IssueAlertTableViewController.swift */; }; - 1DC64C7C24BF6BFD004A63A1 /* CorrectionRangeOverridesExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DC64C7B24BF6BFD004A63A1 /* CorrectionRangeOverridesExtension.swift */; }; - 1DC64C7E24BF6EBC004A63A1 /* DeliveryLimits.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DC64C7D24BF6EBC004A63A1 /* DeliveryLimits.swift */; }; - 1DC9240F2575EF9A004F132A /* QuantityFormatter+Guardrails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DC9240E2575EF9A004F132A /* QuantityFormatter+Guardrails.swift */; }; - 1DD1964E248AE88000420876 /* HorizontalSizeClassOverride.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DD1964D248AE88000420876 /* HorizontalSizeClassOverride.swift */; }; - 1DD3DEB624451C3300BD8E40 /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DA649AA2445174400F61E75 /* Alert.swift */; }; - 1DD65CFF26C476890085CC64 /* Model.sqlite.v1.original in Resources */ = {isa = PBXBuildFile; fileRef = 1DD65CFE26C476880085CC64 /* Model.sqlite.v1.original */; }; - 1DD9CE9926B8CC2A008B4A46 /* HKDevice+Encodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DD9CE9826B8CC2A008B4A46 /* HKDevice+Encodable.swift */; }; - 1DD9CE9A26B8CF4A008B4A46 /* HKDevice+Encodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DD9CE9826B8CC2A008B4A46 /* HKDevice+Encodable.swift */; }; - 1DE35E7A24ABEC720086F9AE /* DeviceManagerUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE35E7924ABEC720086F9AE /* DeviceManagerUI.swift */; }; - 1DEE227724A676A300693C32 /* HKHealthStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437AFF1E203A763F008C4892 /* HKHealthStoreMock.swift */; }; - 1DEE229D24A676A300693C32 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D8FDCB1C728FDF0073BE78 /* LoopKit.framework */; }; - 1DFB99D6245CB2E900DCC8C9 /* AlertTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DFB99D5245CB2E900DCC8C9 /* AlertTests.swift */; }; - 1DFFB988271740EE0075AEAA /* MockSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DFFB987271740EE0075AEAA /* MockSupport.swift */; }; - 1F5DAB2D2118CE9300048054 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1F5DAB2B2118CE9300048054 /* Localizable.strings */; }; - 1FE58796211D12CE004F24ED /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7D68A9E31FE0A3D300522C49 /* Localizable.strings */; }; - 430157FA1C7EC03B00B64B63 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430157F91C7EC03B00B64B63 /* AppDelegate.swift */; }; - 430157FC1C7EC03B00B64B63 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430157FB1C7EC03B00B64B63 /* MasterViewController.swift */; }; - 430158011C7EC03B00B64B63 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 430157FF1C7EC03B00B64B63 /* Main.storyboard */; }; - 430158031C7EC03B00B64B63 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 430158021C7EC03B00B64B63 /* Assets.xcassets */; }; - 430158061C7EC03B00B64B63 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 430158041C7EC03B00B64B63 /* LaunchScreen.storyboard */; }; - 430158191C7ECB5E00B64B63 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D8FDCB1C728FDF0073BE78 /* LoopKit.framework */; }; - 4301581A1C7ECB5E00B64B63 /* LoopKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 43D8FDCB1C728FDF0073BE78 /* LoopKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 4301582D1C7ECD7A00B64B63 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4301582C1C7ECD7A00B64B63 /* HealthKit.framework */; }; - 43026D642132404900A332E2 /* ice_minus_flat_carb_effect_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43026D632132404900A332E2 /* ice_minus_flat_carb_effect_output.json */; }; - 4302F4DF1D4E607B00F0FCAF /* LegacyInsulinDeliveryTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4302F4DE1D4E607B00F0FCAF /* LegacyInsulinDeliveryTableViewController.swift */; }; - 4322B76C202F9ECD0002837D /* CarbMathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE411C7291900073BE78 /* CarbMathTests.swift */; }; - 4322B76D202F9EF20002837D /* GlucoseMathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE991C7293D00073BE78 /* GlucoseMathTests.swift */; }; - 4322B76E202FA26B0002837D /* GlucoseMath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE861C72934C0073BE78 /* GlucoseMath.swift */; }; - 4322B76F202FA26F0002837D /* GlucoseSampleValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43971A3F1C8CABFF0013154F /* GlucoseSampleValue.swift */; }; - 4322B770202FA26F0002837D /* GlucoseStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE871C72934C0073BE78 /* GlucoseStore.swift */; }; - 4322B771202FA26F0002837D /* HKQuantitySample+GlucoseKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FADDFA1C89679200DDE013 /* HKQuantitySample+GlucoseKit.swift */; }; - 4322B772202FA2790002837D /* AbsorbedCarbValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4378B64C1ED61C22000AE785 /* AbsorbedCarbValue.swift */; }; - 4322B773202FA2790002837D /* CarbEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE4A1C7291BD0073BE78 /* CarbEntry.swift */; }; - 4322B774202FA2790002837D /* CarbMath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE4B1C7291BD0073BE78 /* CarbMath.swift */; }; - 4322B775202FA2790002837D /* CarbStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4378B6501ED62D8D000AE785 /* CarbStatus.swift */; }; - 4322B776202FA2790002837D /* CarbStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE4C1C7291BD0073BE78 /* CarbStore.swift */; }; - 4322B777202FA2790002837D /* CarbValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4378B64E1ED61C64000AE785 /* CarbValue.swift */; }; - 4322B778202FA2790002837D /* HKQuantitySample+CarbKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE4D1C7291BD0073BE78 /* HKQuantitySample+CarbKit.swift */; }; - 4322B779202FA2790002837D /* NewCarbEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE5B1C7291D80073BE78 /* NewCarbEntry.swift */; }; - 4322B77A202FA2790002837D /* NSUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4346D1FB1C79481E00ABAFE3 /* NSUserDefaults.swift */; }; - 4322B77B202FA2790002837D /* StoredCarbEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE4E1C7291BD0073BE78 /* StoredCarbEntry.swift */; }; - 4322B77D202FA2AF0002837D /* NewPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4302F4EA1D50670500F0FCAF /* NewPumpEvent.swift */; }; - 4322B77E202FA2AF0002837D /* PersistedPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4302F4EC1D5068CE00F0FCAF /* PersistedPumpEvent.swift */; }; - 4322B77F202FA2AF0002837D /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FEE21C7294D50073BE78 /* PersistenceController.swift */; }; - 4322B780202FA2AF0002837D /* PumpEvent+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43DFE27B1CB1D6A600EFBE95 /* PumpEvent+CoreDataClass.swift */; }; - 4322B781202FA2AF0002837D /* PumpEvent+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43DFE27C1CB1D6A600EFBE95 /* PumpEvent+CoreDataProperties.swift */; }; - 4322B782202FA2AF0002837D /* PumpEventType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43DFE27F1CB1E12D00EFBE95 /* PumpEventType.swift */; }; - 4322B783202FA2AF0002837D /* Reservoir.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FEE31C7294D50073BE78 /* Reservoir.swift */; }; - 4322B784202FA2AF0002837D /* Reservoir+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FEE41C7294D50073BE78 /* Reservoir+CoreDataProperties.swift */; }; - 4322B785202FA2AF0002837D /* ReservoirValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4302F4E81D5066F400F0FCAF /* ReservoirValue.swift */; }; - 4322B786202FA2AF0002837D /* WalshInsulinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1DB55B01F2E95FD00C483A2 /* WalshInsulinModel.swift */; }; - 4322B787202FA2B30002837D /* DoseEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FEDC1C7294D50073BE78 /* DoseEntry.swift */; }; - 4322B788202FA2B30002837D /* DoseStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FEDD1C7294D50073BE78 /* DoseStore.swift */; }; - 4322B789202FA2B30002837D /* DoseType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A0670E1F23CAC700E9E90F /* DoseType.swift */; }; - 4322B78A202FA2B30002837D /* DoseUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C094451CAA1E98001F6403 /* DoseUnit.swift */; }; - 4322B78B202FA2B30002837D /* ExponentialInsulinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1DB55B21F2E964400C483A2 /* ExponentialInsulinModel.swift */; }; - 4322B78C202FA2B30002837D /* HKQuantitySample+InsulinKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437B064D1F2EB35800D95237 /* HKQuantitySample+InsulinKit.swift */; }; - 4322B78D202FA2B30002837D /* InsulinDeliveryStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 438207701F2AE9A300886C13 /* InsulinDeliveryStore.swift */; }; - 4322B78E202FA2B30002837D /* InsulinMath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FEDF1C7294D50073BE78 /* InsulinMath.swift */; }; - 4322B78F202FA2B30002837D /* InsulinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12EE16B1F2964B3007DB9F1 /* InsulinModel.swift */; }; - 4322B790202FA2B30002837D /* InsulinValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43DFE2811CB1FB8500EFBE95 /* InsulinValue.swift */; }; - 4322B792202FA3CC0002837D /* carb_effect_from_history_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FE441C7291A60073BE78 /* carb_effect_from_history_input.json */; }; - 4322B793202FA3CC0002837D /* carb_effect_from_history_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FE451C7291A60073BE78 /* carb_effect_from_history_output.json */; }; - 4322B794202FA3CC0002837D /* carb_entry_input.json in Resources */ = {isa = PBXBuildFile; fileRef = C17F4CB21EE9B6DF005079B1 /* carb_entry_input.json */; }; - 4322B795202FA3CC0002837D /* carbs_on_board_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FE461C7291A60073BE78 /* carbs_on_board_output.json */; }; - 4322B796202FA3CC0002837D /* grouped_by_overlapping_absorption_times_border_case_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43EBE44C1EAC7F0C0073A0B5 /* grouped_by_overlapping_absorption_times_border_case_input.json */; }; - 4322B797202FA3CC0002837D /* grouped_by_overlapping_absorption_times_border_case_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43EBE44B1EAC7F0C0073A0B5 /* grouped_by_overlapping_absorption_times_border_case_output.json */; }; - 4322B798202FA3CC0002837D /* grouped_by_overlapping_absorption_times_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43EBE4471EAC77290073A0B5 /* grouped_by_overlapping_absorption_times_input.json */; }; - 4322B799202FA3CC0002837D /* grouped_by_overlapping_absorption_times_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43EBE4481EAC77290073A0B5 /* grouped_by_overlapping_absorption_times_output.json */; }; - 4322B79A202FA3CC0002837D /* ice_1_hour_input.json in Resources */ = {isa = PBXBuildFile; fileRef = C1CBF61B1EEA2A1E001E4851 /* ice_1_hour_input.json */; }; - 4322B79B202FA3CC0002837D /* ice_1_hour_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 439BCD8F1EEDD2AD00100EAA /* ice_1_hour_output.json */; }; - 4322B79C202FA3CC0002837D /* ice_35_min_input.json in Resources */ = {isa = PBXBuildFile; fileRef = C1110E981EE98CF5009BB852 /* ice_35_min_input.json */; }; - 4322B79D202FA3CC0002837D /* ice_35_min_none_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 439BCD8D1EEDD22900100EAA /* ice_35_min_none_output.json */; }; - 4322B79E202FA3CC0002837D /* ice_35_min_partial_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 4359E74F1EED04330022EF0C /* ice_35_min_partial_output.json */; }; - 4322B79F202FA3CC0002837D /* ice_slow_absorption_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 439BCD911EEDD33F00100EAA /* ice_slow_absorption_output.json */; }; - 4322B7A0202FA3CC0002837D /* ice_slow_absorption.json in Resources */ = {isa = PBXBuildFile; fileRef = C13E6D291EEB1CB9006F5880 /* ice_slow_absorption.json */; }; - 4322B7A1202FA3D20002837D /* momentum_effect_bouncing_glucose_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FE9C1C7293FA0073BE78 /* momentum_effect_bouncing_glucose_input.json */; }; - 4322B7A2202FA3D20002837D /* momentum_effect_bouncing_glucose_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FE9D1C7293FA0073BE78 /* momentum_effect_bouncing_glucose_output.json */; }; - 4322B7A3202FA3D20002837D /* momentum_effect_display_only_glucose_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43971A411C8CAEF20013154F /* momentum_effect_display_only_glucose_input.json */; }; - 4322B7A4202FA3D20002837D /* momentum_effect_duplicate_glucose_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 4303C48B1E29DD4200ADEDC8 /* momentum_effect_duplicate_glucose_input.json */; }; - 4322B7A5202FA3D20002837D /* momentum_effect_falling_glucose_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FE9E1C7293FA0073BE78 /* momentum_effect_falling_glucose_input.json */; }; - 4322B7A6202FA3D20002837D /* momentum_effect_falling_glucose_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FE9F1C7293FA0073BE78 /* momentum_effect_falling_glucose_output.json */; }; - 4322B7A7202FA3D20002837D /* momentum_effect_incomplete_glucose_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43DC87B51C8A9567005BC30D /* momentum_effect_incomplete_glucose_input.json */; }; - 4322B7A8202FA3D20002837D /* momentum_effect_mixed_provenance_glucose_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43C27D921E3C4E7D00613CE1 /* momentum_effect_mixed_provenance_glucose_input.json */; }; - 4322B7A9202FA3D20002837D /* momentum_effect_rising_glucose_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FEA01C7293FA0073BE78 /* momentum_effect_rising_glucose_input.json */; }; - 4322B7AA202FA3D20002837D /* momentum_effect_rising_glucose_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FEA11C7293FA0073BE78 /* momentum_effect_rising_glucose_output.json */; }; - 4322B7AB202FA3D20002837D /* momentum_effect_stable_glucose_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FEA21C7293FA0073BE78 /* momentum_effect_stable_glucose_input.json */; }; - 4322B7AC202FA3D20002837D /* momentum_effect_stable_glucose_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FEA31C7293FA0073BE78 /* momentum_effect_stable_glucose_output.json */; }; - 432762741D60505F0083215A /* HKQuantitySample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432762731D60505F0083215A /* HKQuantitySample.swift */; }; - 432CF86720D76AB90066B889 /* SettingsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432CF86620D76AB90066B889 /* SettingsTableViewCell.swift */; }; - 432CF86920D76B320066B889 /* SetupButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432CF86820D76B320066B889 /* SetupButton.swift */; }; - 432CF86B20D76B9C0066B889 /* SetupIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432CF86A20D76B9C0066B889 /* SetupIndicatorView.swift */; }; - 432CF86D20D76C470066B889 /* SwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432CF86C20D76C470066B889 /* SwitchTableViewCell.swift */; }; - 432CF86F20D76CCF0066B889 /* GlucoseTrend.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432CF86E20D76CCF0066B889 /* GlucoseTrend.swift */; }; - 432CF87120D76D5A0066B889 /* GlucoseDisplayable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432CF87020D76D5A0066B889 /* GlucoseDisplayable.swift */; }; - 432CF87320D774220066B889 /* PumpManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432CF87220D774220066B889 /* PumpManager.swift */; }; - 433BC7A720523DB7000B1200 /* NewGlucoseSample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433BC7A620523DB7000B1200 /* NewGlucoseSample.swift */; }; - 433BC7AA20538D4C000B1200 /* CachedGlucoseObject+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433BC7A820538D4C000B1200 /* CachedGlucoseObject+CoreDataClass.swift */; }; - 433BC7AB20538D4C000B1200 /* CachedGlucoseObject+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433BC7A920538D4C000B1200 /* CachedGlucoseObject+CoreDataProperties.swift */; }; - 433BC7AD20538FCA000B1200 /* StoredGlucoseSample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433BC7AC20538FCA000B1200 /* StoredGlucoseSample.swift */; }; - 434113AA20F171CB00D05747 /* CachedInsulinDeliveryObject+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434113A820F171CB00D05747 /* CachedInsulinDeliveryObject+CoreDataClass.swift */; }; - 434113AB20F171CB00D05747 /* CachedInsulinDeliveryObject+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434113A920F171CB00D05747 /* CachedInsulinDeliveryObject+CoreDataProperties.swift */; }; - 434113AD20F287DC00D05747 /* NSManagedObjectContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434113AC20F287DC00D05747 /* NSManagedObjectContext.swift */; }; - 434113B320F2890800D05747 /* PersistenceControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434113B220F2890800D05747 /* PersistenceControllerTests.swift */; }; - 434113B520F2BDB500D05747 /* CachedInsulinDeliveryObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434113B420F2BDB500D05747 /* CachedInsulinDeliveryObjectTests.swift */; }; - 434113B820F2BDE800D05747 /* PersistenceControllerTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434113B720F2BDE800D05747 /* PersistenceControllerTestCase.swift */; }; - 434113BC20F2C56100D05747 /* CachedGlucoseObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434113BB20F2C56100D05747 /* CachedGlucoseObjectTests.swift */; }; - 434113BE20F2C72000D05747 /* CachedCarbObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434113BD20F2C72000D05747 /* CachedCarbObjectTests.swift */; }; - 4343951F205EED1F0056DC37 /* counteraction_effect_falling_glucose_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 4343951E205EED1F0056DC37 /* counteraction_effect_falling_glucose_output.json */; }; - 43439521205F2D910056DC37 /* counteraction_effect_falling_glucose_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43439520205F2D910056DC37 /* counteraction_effect_falling_glucose_input.json */; }; - 434C5F9C2098352500B2FD1A /* QuantityFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434C5F9B2098352500B2FD1A /* QuantityFormatter.swift */; }; - 434C5FA0209ABD4700B2FD1A /* QuantityFormatterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434C5F9F209ABD4700B2FD1A /* QuantityFormatterTests.swift */; }; - 4352A73C20DECF0700CAC200 /* CGMManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4352A73B20DECF0600CAC200 /* CGMManager.swift */; }; - 4353D16F203D104F007B4ECD /* CarbStoreError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4353D16E203D104F007B4ECD /* CarbStoreError.swift */; }; - 4353D170203D3E5C007B4ECD /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4301582C1C7ECD7A00B64B63 /* HealthKit.framework */; }; - 4353D173203D3E7E007B4ECD /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4353D172203D3E7E007B4ECD /* CoreData.framework */; }; - 435D2925205F3A670026F401 /* counteraction_effect_falling_glucose_almost_duplicates_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 435D2924205F3A670026F401 /* counteraction_effect_falling_glucose_almost_duplicates_input.json */; }; - 435D2928205F3C760026F401 /* counteraction_effect_falling_glucose_double_entries._input.json in Resources */ = {isa = PBXBuildFile; fileRef = 435D2926205F3C750026F401 /* counteraction_effect_falling_glucose_double_entries._input.json */; }; - 435D2929205F3C760026F401 /* momentum_effect_rising_glucose_double_entries_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 435D2927205F3C750026F401 /* momentum_effect_rising_glucose_double_entries_input.json */; }; - 435D292B205F46180026F401 /* counteraction_effect_falling_glucose_almost_duplicates_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 435D292A205F46180026F401 /* counteraction_effect_falling_glucose_almost_duplicates_output.json */; }; - 435D292D205F48750026F401 /* counteraction_effect_falling_glucose_insulin.json in Resources */ = {isa = PBXBuildFile; fileRef = 435D292C205F48750026F401 /* counteraction_effect_falling_glucose_insulin.json */; }; - 435F355E1C9CD16A00C204D2 /* NSUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435F355D1C9CD16A00C204D2 /* NSUserDefaults.swift */; }; - 435F35611C9CD25F00C204D2 /* DeviceDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435F35601C9CD25F00C204D2 /* DeviceDataManager.swift */; }; - 4369F08F208859E6000E3E45 /* PaddedTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4369F08E208859E6000E3E45 /* PaddedTextField.swift */; }; - 4369F092208B0DFF000E3E45 /* DateAndDurationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4369F091208B0DFF000E3E45 /* DateAndDurationTableViewCell.swift */; }; - 4369F094208BA001000E3E45 /* TextButtonTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4369F093208BA001000E3E45 /* TextButtonTableViewCell.swift */; }; - 437874B5202FDD1200A3D8B9 /* DoseStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A067121F245A2F00E9E90F /* DoseStoreTests.swift */; }; - 437874B6202FDD1500A3D8B9 /* InsulinMathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FEC81C7294640073BE78 /* InsulinMathTests.swift */; }; - 437874B7202FDD2D00A3D8B9 /* basal_dose.json in Resources */ = {isa = PBXBuildFile; fileRef = 43B99B051C74552300D050F5 /* basal_dose.json */; }; - 437874B8202FDD2D00A3D8B9 /* bolus_dose.json in Resources */ = {isa = PBXBuildFile; fileRef = 43B99AFB1C744CE300D050F5 /* bolus_dose.json */; }; - 437874B9202FDD2D00A3D8B9 /* doses_overlay_basal_profile_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 4333931E1F32E31C009466DC /* doses_overlay_basal_profile_output.json */; }; - 437874BA202FDD2D00A3D8B9 /* effect_from_basal_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43B99B071C74553900D050F5 /* effect_from_basal_output.json */; }; - 437874BB202FDD2D00A3D8B9 /* effect_from_bolus_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43B99AFD1C744E5F00D050F5 /* effect_from_bolus_output.json */; }; - 437874BC202FDD2D00A3D8B9 /* effect_from_history_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43B99AFF1C7450EE00D050F5 /* effect_from_history_output.json */; }; - 437874BD202FDD2D00A3D8B9 /* iob_from_bolus_120min_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43CE7CE11CA9EA1A003CC1B0 /* iob_from_bolus_120min_output.json */; }; - 437874BE202FDD2D00A3D8B9 /* iob_from_bolus_180min_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43CE7CE31CA9EB1E003CC1B0 /* iob_from_bolus_180min_output.json */; }; - 437874BF202FDD2D00A3D8B9 /* iob_from_bolus_240min_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43CE7CDF1CA9E8B0003CC1B0 /* iob_from_bolus_240min_output.json */; }; - 437874C0202FDD2D00A3D8B9 /* iob_from_bolus_300min_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43CE7CE51CA9EBD2003CC1B0 /* iob_from_bolus_300min_output.json */; }; - 437874C1202FDD2D00A3D8B9 /* iob_from_bolus_312min_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43CE7CE71CA9EC1F003CC1B0 /* iob_from_bolus_312min_output.json */; }; - 437874C2202FDD2D00A3D8B9 /* iob_from_bolus_360min_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43CE7CE91CA9EC50003CC1B0 /* iob_from_bolus_360min_output.json */; }; - 437874C3202FDD2D00A3D8B9 /* iob_from_bolus_420min_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43CE7CEB1CA9EC88003CC1B0 /* iob_from_bolus_420min_output.json */; }; - 437874C4202FDD2D00A3D8B9 /* iob_from_bolus_exponential_output.json in Resources */ = {isa = PBXBuildFile; fileRef = C1DB55B61F2EACD500C483A2 /* iob_from_bolus_exponential_output.json */; }; - 437874C5202FDD2D00A3D8B9 /* iob_from_doses_exponential_output.json in Resources */ = {isa = PBXBuildFile; fileRef = C1DB55B41F2EA6EA00C483A2 /* iob_from_doses_exponential_output.json */; }; - 437874C6202FDD2D00A3D8B9 /* iob_from_doses_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FECE1C7294B80073BE78 /* iob_from_doses_output.json */; }; - 437874C7202FDD2D00A3D8B9 /* iob_from_reservoir_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FECF1C7294B80073BE78 /* iob_from_reservoir_output.json */; }; - 437874C8202FDD2D00A3D8B9 /* normalize_edge_case_doses_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43CE7CED1CA9F2CF003CC1B0 /* normalize_edge_case_doses_input.json */; }; - 437874C9202FDD2D00A3D8B9 /* normalize_edge_case_doses_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43CE7CEF1CA9F32C003CC1B0 /* normalize_edge_case_doses_output.json */; }; - 437874CA202FDD2D00A3D8B9 /* normalized_doses.json in Resources */ = {isa = PBXBuildFile; fileRef = 43B99B011C7451E500D050F5 /* normalized_doses.json */; }; - 437874CB202FDD2D00A3D8B9 /* normalized_reservoir_history_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FED01C7294B80073BE78 /* normalized_reservoir_history_output.json */; }; - 437874CC202FDD2D00A3D8B9 /* reconcile_history_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 434872781CB6256500E55D75 /* reconcile_history_input.json */; }; - 437874CD202FDD2D00A3D8B9 /* reconcile_history_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 4348727C1CB626E500E55D75 /* reconcile_history_output.json */; }; - 437874CE202FDD2D00A3D8B9 /* reconcile_resume_before_rewind_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43BDD7E71F804ED5005BA15C /* reconcile_resume_before_rewind_input.json */; }; - 437874CF202FDD2D00A3D8B9 /* reconcile_resume_before_rewind_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43BDD7E91F8050C3005BA15C /* reconcile_resume_before_rewind_output.json */; }; - 437874D0202FDD2D00A3D8B9 /* reservoir_history_with_continuity_holes.json in Resources */ = {isa = PBXBuildFile; fileRef = 434FB6471D70096A007B9C70 /* reservoir_history_with_continuity_holes.json */; }; - 437874D1202FDD2D00A3D8B9 /* reservoir_history_with_rewind_and_prime_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FED11C7294B80073BE78 /* reservoir_history_with_rewind_and_prime_input.json */; }; - 437874D2202FDD2D00A3D8B9 /* reservoir_history_with_rewind_and_prime_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FED21C7294B80073BE78 /* reservoir_history_with_rewind_and_prime_output.json */; }; - 437874D3202FDD2D00A3D8B9 /* short_basal_dose.json in Resources */ = {isa = PBXBuildFile; fileRef = 43B99B031C74538D00D050F5 /* short_basal_dose.json */; }; - 437874D4202FDD2D00A3D8B9 /* suspend_dose_reconciled_normalized_iob.json in Resources */ = {isa = PBXBuildFile; fileRef = 4378B6441ED55F8C000AE785 /* suspend_dose_reconciled_normalized_iob.json */; }; - 437874D5202FDD2D00A3D8B9 /* suspend_dose_reconciled_normalized.json in Resources */ = {isa = PBXBuildFile; fileRef = 4378B6451ED55F8C000AE785 /* suspend_dose_reconciled_normalized.json */; }; - 437874D6202FDD2D00A3D8B9 /* suspend_dose_reconciled.json in Resources */ = {isa = PBXBuildFile; fileRef = 4378B6461ED55F8C000AE785 /* suspend_dose_reconciled.json */; }; - 437874D7202FDD2D00A3D8B9 /* suspend_dose.json in Resources */ = {isa = PBXBuildFile; fileRef = 4378B6421ED55E81000AE785 /* suspend_dose.json */; }; - 4378B64B1ED61965000AE785 /* GlucoseEffectVelocity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4378B64A1ED61965000AE785 /* GlucoseEffectVelocity.swift */; }; - 4379CFE321102A4100AADC79 /* DeviceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4379CFE221102A4100AADC79 /* DeviceManager.swift */; }; - 437AFEED2036A156008C4892 /* CachedCarbObject+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437AFEE92036A156008C4892 /* CachedCarbObject+CoreDataClass.swift */; }; - 437AFEEE2036A156008C4892 /* CachedCarbObject+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437AFEEA2036A156008C4892 /* CachedCarbObject+CoreDataProperties.swift */; }; - 437AFF1D203A45DB008C4892 /* CacheStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437AFF1C203A45DB008C4892 /* CacheStore.swift */; }; - 437AFF1F203A763F008C4892 /* HKHealthStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437AFF1E203A763F008C4892 /* HKHealthStoreMock.swift */; }; - 437AFF21203AA740008C4892 /* NSManagedObjectContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437AFF20203AA740008C4892 /* NSManagedObjectContext.swift */; }; - 437AFF24203BE402008C4892 /* HKHealthStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437AFF23203BE402008C4892 /* HKHealthStore.swift */; }; - 439706E922D2E94800C81566 /* BoundSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 439706E822D2E94800C81566 /* BoundSwitchTableViewCell.swift */; }; - 43A8EC3C210CEEA500A81379 /* CGMManagerUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A8EC3B210CEEA500A81379 /* CGMManagerUI.swift */; }; - 43AF1FB21C926CDD00EA2F3D /* HKQuantity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43AF1FB11C926CDD00EA2F3D /* HKQuantity.swift */; }; - 43B17C89208EEC0B00AC27E9 /* HealthStoreUnitCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43B17C88208EEC0B00AC27E9 /* HealthStoreUnitCache.swift */; }; - 43BA7158201E484D0058961E /* LoopKitUI.h in Headers */ = {isa = PBXBuildFile; fileRef = 43BA7156201E484D0058961E /* LoopKitUI.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43BA715B201E484D0058961E /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43BA7154201E484D0058961E /* LoopKitUI.framework */; }; - 43BA715C201E484D0058961E /* LoopKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 43BA7154201E484D0058961E /* LoopKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 43BA7162201E490D0058961E /* ErrorBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FEEF1C7294E90073BE78 /* ErrorBackgroundView.swift */; }; - 43BA7164201E49130058961E /* InsulinKit.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FEED1C7294E90073BE78 /* InsulinKit.storyboard */; }; - 43BA716C201E49220058961E /* CustomInputTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432711371EDE826A00171F6A /* CustomInputTextField.swift */; }; - 43BA716D201E49220058961E /* DatePickerTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE591C7291D80073BE78 /* DatePickerTableViewCell.swift */; }; - 43BA716E201E49220058961E /* DecimalTextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE5A1C7291D80073BE78 /* DecimalTextFieldTableViewCell.swift */; }; - 43BA716F201E49220058961E /* FoodEmojiDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4359E74D1EEA1FBC0022EF0C /* FoodEmojiDataSource.swift */; }; - 43BA7170201E49220058961E /* FoodTypeShortcutCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433D705D1EFB29700004EB9F /* FoodTypeShortcutCell.swift */; }; - 43BA7173201E492E0058961E /* DateAndDurationTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 434A01CF1F019D9100938125 /* DateAndDurationTableViewCell.xib */; }; - 43BA717D201EE7090058961E /* GlucoseRangeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE071C7290530073BE78 /* GlucoseRangeTableViewCell.swift */; }; - 43BA717E201EE7090058961E /* CommandResponseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434FB6491D712158007B9C70 /* CommandResponseViewController.swift */; }; - 43BA717F201EE7090058961E /* GlucoseRangeOverrideTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43177D0B1D3734040006E908 /* GlucoseRangeOverrideTableViewCell.swift */; }; - 43BA7180201EE7090058961E /* SingleValueScheduleTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE0C1C7290530073BE78 /* SingleValueScheduleTableViewController.swift */; }; - 43BA7181201EE7090058961E /* RepeatingScheduleValueTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE0A1C7290530073BE78 /* RepeatingScheduleValueTableViewCell.swift */; }; - 43BA7182201EE7090058961E /* TextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434FF1F01CF29451000DB779 /* TextFieldTableViewCell.swift */; }; - 43BA7183201EE7090058961E /* DailyQuantityScheduleTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE041C7290530073BE78 /* DailyQuantityScheduleTableViewController.swift */; }; - 43BA7184201EE7090058961E /* TextFieldTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434FF1F31CF294A9000DB779 /* TextFieldTableViewController.swift */; }; - 43BA7185201EE7090058961E /* DailyValueScheduleTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE051C7290530073BE78 /* DailyValueScheduleTableViewController.swift */; }; - 43BA7187201EE7090058961E /* GlucoseRangeScheduleTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE061C7290530073BE78 /* GlucoseRangeScheduleTableViewController.swift */; }; - 43BA7192202039950058961E /* RepeatingScheduleValueTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FE0B1C7290530073BE78 /* RepeatingScheduleValueTableViewCell.xib */; }; - 43BA7193202039A30058961E /* TextFieldTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 434FF1EF1CF29451000DB779 /* TextFieldTableViewCell.xib */; }; - 43BA7194202039A90058961E /* GlucoseRangeTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FE081C7290530073BE78 /* GlucoseRangeTableViewCell.xib */; }; - 43BA7195202039B00058961E /* GlucoseRangeOverrideTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43177D071D37306D0006E908 /* GlucoseRangeOverrideTableViewCell.xib */; }; - 43BA719620203C750058961E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 43177D091D3732C70006E908 /* Assets.xcassets */; }; - 43C9805A212BDEE4003B5D17 /* ice_minus_carb_effect_with_gaps_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43C98059212BDEE4003B5D17 /* ice_minus_carb_effect_with_gaps_output.json */; }; - 43C9805C212D216A003B5D17 /* GlucoseChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C9805B212D216A003B5D17 /* GlucoseChange.swift */; }; - 43CACE0E2247F89100F90AF5 /* WeakSynchronizedSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CACE0D2247F89100F90AF5 /* WeakSynchronizedSet.swift */; }; - 43CB51B2211EB1A400DB9B4A /* NSUserActivity+CarbKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CB51B0211EB16C00DB9B4A /* NSUserActivity+CarbKit.swift */; }; - 43D8FDCF1C728FDF0073BE78 /* LoopKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 43D8FDCE1C728FDF0073BE78 /* LoopKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43D8FDD61C728FDF0073BE78 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D8FDCB1C728FDF0073BE78 /* LoopKit.framework */; }; - 43D8FDDB1C728FDF0073BE78 /* LoopKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDDA1C728FDF0073BE78 /* LoopKitTests.swift */; }; - 43D8FDF41C7290350073BE78 /* BasalRateSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDE51C7290340073BE78 /* BasalRateSchedule.swift */; }; - 43D8FDF51C7290350073BE78 /* CarbRatioSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDE61C7290350073BE78 /* CarbRatioSchedule.swift */; }; - 43D8FDF61C7290350073BE78 /* DailyQuantitySchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDE71C7290350073BE78 /* DailyQuantitySchedule.swift */; }; - 43D8FDF71C7290350073BE78 /* DailyValueSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDE81C7290350073BE78 /* DailyValueSchedule.swift */; }; - 43D8FDF81C7290350073BE78 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDE91C7290350073BE78 /* Double.swift */; }; - 43D8FDF91C7290350073BE78 /* GlucoseEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDEA1C7290350073BE78 /* GlucoseEffect.swift */; }; - 43D8FDFA1C7290350073BE78 /* GlucoseRangeSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDEB1C7290350073BE78 /* GlucoseRangeSchedule.swift */; }; - 43D8FDFB1C7290350073BE78 /* GlucoseSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDEC1C7290350073BE78 /* GlucoseSchedule.swift */; }; - 43D8FDFC1C7290350073BE78 /* HealthKitSampleStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDED1C7290350073BE78 /* HealthKitSampleStore.swift */; }; - 43D8FDFE1C7290350073BE78 /* LoopMath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDEF1C7290350073BE78 /* LoopMath.swift */; }; - 43D8FDFF1C7290350073BE78 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDF01C7290350073BE78 /* Date.swift */; }; - 43D8FE021C7290350073BE78 /* SampleValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDF31C7290350073BE78 /* SampleValue.swift */; }; - 43D8FE1D1C72906E0073BE78 /* BasalRateScheduleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE1A1C72906E0073BE78 /* BasalRateScheduleTests.swift */; }; - 43D8FE1E1C72906E0073BE78 /* NSDateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE1B1C72906E0073BE78 /* NSDateTests.swift */; }; - 43D8FE1F1C72906E0073BE78 /* QuantityScheduleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE1C1C72906E0073BE78 /* QuantityScheduleTests.swift */; }; - 43D8FE691C7292B00073BE78 /* read_carb_ratios.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FE661C7292950073BE78 /* read_carb_ratios.json */; }; - 43D8FEF71C7295500073BE78 /* basal.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D8FEF41C7295490073BE78 /* basal.json */; }; - 43D9888B1C87E47800DA4467 /* GlucoseValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D9888A1C87E47800DA4467 /* GlucoseValue.swift */; }; - 43D9888D1C87EBE400DA4467 /* LoopMathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D9888C1C87EBE400DA4467 /* LoopMathTests.swift */; }; - 43D988A11C87FFA300DA4467 /* glucose_from_effects_no_momentum_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D988921C87FFA300DA4467 /* glucose_from_effects_no_momentum_output.json */; }; - 43D988A21C87FFA300DA4467 /* glucose_from_effects_momentum_up_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D988931C87FFA300DA4467 /* glucose_from_effects_momentum_up_output.json */; }; - 43D988A31C87FFA300DA4467 /* glucose_from_effects_momentum_up_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D988941C87FFA300DA4467 /* glucose_from_effects_momentum_up_input.json */; }; - 43D988A41C87FFA300DA4467 /* glucose_from_effects_momentum_flat_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D988951C87FFA300DA4467 /* glucose_from_effects_momentum_flat_output.json */; }; - 43D988A51C87FFA300DA4467 /* glucose_from_effects_momentum_flat_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D988961C87FFA300DA4467 /* glucose_from_effects_momentum_flat_input.json */; }; - 43D988A61C87FFA300DA4467 /* glucose_from_effects_momentum_flat_glucose_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D988971C87FFA300DA4467 /* glucose_from_effects_momentum_flat_glucose_input.json */; }; - 43D988A71C87FFA300DA4467 /* glucose_from_effects_momentum_down_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D988981C87FFA300DA4467 /* glucose_from_effects_momentum_down_output.json */; }; - 43D988A81C87FFA300DA4467 /* glucose_from_effects_momentum_down_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D988991C87FFA300DA4467 /* glucose_from_effects_momentum_down_input.json */; }; - 43D988A91C87FFA300DA4467 /* glucose_from_effects_momentum_blend_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D9889A1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_output.json */; }; - 43D988AA1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_momentum_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D9889B1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_momentum_input.json */; }; - 43D988AB1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_insulin_effect_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D9889C1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_insulin_effect_input.json */; }; - 43D988AC1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_glucose_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D9889D1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_glucose_input.json */; }; - 43D988AD1C87FFA300DA4467 /* glucose_from_effects_insulin_effect_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D9889E1C87FFA300DA4467 /* glucose_from_effects_insulin_effect_input.json */; }; - 43D988AE1C87FFA300DA4467 /* glucose_from_effects_glucose_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D9889F1C87FFA300DA4467 /* glucose_from_effects_glucose_input.json */; }; - 43D988AF1C87FFA300DA4467 /* glucose_from_effects_carb_effect_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43D988A01C87FFA300DA4467 /* glucose_from_effects_carb_effect_input.json */; }; - 43DC87B81C8AD058005BC30D /* glucose_from_effects_non_zero_glucose_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43DC87B71C8AD058005BC30D /* glucose_from_effects_non_zero_glucose_input.json */; }; - 43DC87BB1C8AD0ED005BC30D /* glucose_from_effects_non_zero_insulin_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43DC87B91C8AD0ED005BC30D /* glucose_from_effects_non_zero_insulin_input.json */; }; - 43DC87BC1C8AD0ED005BC30D /* glucose_from_effects_non_zero_carb_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 43DC87BA1C8AD0ED005BC30D /* glucose_from_effects_non_zero_carb_input.json */; }; - 43DC87BE1C8AD41D005BC30D /* glucose_from_effects_non_zero_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 43DC87BD1C8AD41D005BC30D /* glucose_from_effects_non_zero_output.json */; }; - 43F5034B21051FCE009FA89A /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F5034A21051FCD009FA89A /* KeychainManager.swift */; }; - 43F5034D210599CC009FA89A /* AuthenticationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F5034C210599CC009FA89A /* AuthenticationViewController.swift */; }; - 43F5034F210599DF009FA89A /* ValidatingIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F5034E210599DF009FA89A /* ValidatingIndicatorView.swift */; }; - 43F5035721059A8A009FA89A /* ServiceCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F5035521059A8A009FA89A /* ServiceCredential.swift */; }; - 43F5035A21059AF7009FA89A /* AuthenticationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F5035821059AF7009FA89A /* AuthenticationTableViewCell.swift */; }; - 43F5035B21059AF7009FA89A /* AuthenticationTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43F5035921059AF7009FA89A /* AuthenticationTableViewCell.xib */; }; - 43F503632106C761009FA89A /* ServiceAuthenticationUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F503622106C761009FA89A /* ServiceAuthenticationUI.swift */; }; - 43F503642106C78C009FA89A /* ServiceAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F5035421059A8A009FA89A /* ServiceAuthentication.swift */; }; - 43F89C9F22BDFB10006BB54E /* UIActivityIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F89C9E22BDFB10006BB54E /* UIActivityIndicatorView.swift */; }; - 43FB60E320DCB9E0002B996B /* PumpManagerUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FB60E220DCB9E0002B996B /* PumpManagerUI.swift */; }; - 43FB60E520DCBA02002B996B /* SetupTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FB60E420DCBA02002B996B /* SetupTableViewController.swift */; }; - 43FB60E720DCBC55002B996B /* RadioSelectionTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FB60E620DCBC55002B996B /* RadioSelectionTableViewController.swift */; }; - 43FB60E920DCBE64002B996B /* PumpManagerStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FB60E820DCBE64002B996B /* PumpManagerStatus.swift */; }; - 43FB610720DDF19B002B996B /* PumpManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FB610620DDF19B002B996B /* PumpManagerError.swift */; }; - 4B67E2CB289B4EDB002D92AF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4B67E2C9289B4EDB002D92AF /* InfoPlist.strings */; }; - 7D68A9AE1FE0A3D000522C49 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7D68A9B01FE0A3D000522C49 /* Localizable.strings */; }; - 8907E35921A9D0EC00335852 /* GlucoseEntryTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8907E35821A9D0EC00335852 /* GlucoseEntryTableViewController.swift */; }; - 89186C0524BEC9CA0003D0F3 /* SegmentedControlTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89186C0424BEC9CA0003D0F3 /* SegmentedControlTableViewCell.swift */; }; - 89186C0724BF7FC70003D0F3 /* Guardrail+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89186C0624BF7FC70003D0F3 /* Guardrail+UI.swift */; }; - 89186C0B24BFD6DB0003D0F3 /* DurationPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89186C0A24BFD6DB0003D0F3 /* DurationPicker.swift */; }; - 891A3FD12249948A00378B27 /* TemporaryScheduleOverrideHistoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A3FD02249948A00378B27 /* TemporaryScheduleOverrideHistoryTests.swift */; }; - 891A3FD32249990900378B27 /* DailyValueSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A3FD22249990900378B27 /* DailyValueSchedule.swift */; }; - 891A3FD5224B047200378B27 /* DailyQuantitySchedule+Override.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A3FD4224B047200378B27 /* DailyQuantitySchedule+Override.swift */; }; - 891A3FD7224BE62100378B27 /* DailyValueScheduleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A3FD6224BE62100378B27 /* DailyValueScheduleTests.swift */; }; - 891A3FD9224BEB4600378B27 /* EGPSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A3FD8224BEB4500378B27 /* EGPSchedule.swift */; }; - 891A3FDB224BEC0D00378B27 /* CarbSensitivitySchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A3FDA224BEC0D00378B27 /* CarbSensitivitySchedule.swift */; }; - 892155132245C516009112BC /* SegmentedGaugeBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892155122245C516009112BC /* SegmentedGaugeBarView.swift */; }; - 892155152245C57E009112BC /* SegmentedGaugeBarLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892155142245C57E009112BC /* SegmentedGaugeBarLayer.swift */; }; - 892155182245FBEF009112BC /* InsulinSensitivityScalingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892155162245FBEF009112BC /* InsulinSensitivityScalingTableViewCell.swift */; }; - 892155192245FBEF009112BC /* InsulinSensitivityScalingTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 892155172245FBEF009112BC /* InsulinSensitivityScalingTableViewCell.xib */; }; - 892A5D28222EF567008961AB /* (null) in Sources */ = {isa = PBXBuildFile; }; - 892A5D2E222EF69A008961AB /* MockHUDProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5D2D222EF69A008961AB /* MockHUDProvider.swift */; }; - 892A5D46222F03CB008961AB /* LoopTestingKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 892A5D36222F03CB008961AB /* LoopTestingKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 892A5D49222F03CC008961AB /* LoopTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 892A5D34222F03CB008961AB /* LoopTestingKit.framework */; }; - 892A5D4A222F03CC008961AB /* LoopTestingKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 892A5D34222F03CB008961AB /* LoopTestingKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 892A5D52222F03DB008961AB /* TestingDeviceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5D51222F03DB008961AB /* TestingDeviceManager.swift */; }; - 892A5D54222F03F9008961AB /* TestingPumpManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5D53222F03F9008961AB /* TestingPumpManager.swift */; }; - 892A5D56222F0414008961AB /* TestingCGMManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5D55222F0414008961AB /* TestingCGMManager.swift */; }; - 892A5D57222F04E2008961AB /* LoopTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 892A5D34222F03CB008961AB /* LoopTestingKit.framework */; }; - 892A5D5C222F1210008961AB /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D8FDCB1C728FDF0073BE78 /* LoopKit.framework */; }; - 892A5D9A2231E0E4008961AB /* SettingsNavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5D992231E0E3008961AB /* SettingsNavigationViewController.swift */; }; - 892A5D9C2231E118008961AB /* UIAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5D9B2231E118008961AB /* UIAlertController.swift */; }; - 892A5D9E2231E122008961AB /* StateColorPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5D9D2231E122008961AB /* StateColorPalette.swift */; }; - 892A5DA02231E130008961AB /* CompletionNotifying.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5D9F2231E12F008961AB /* CompletionNotifying.swift */; }; - 892A5DA22231E137008961AB /* HUDProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5DA12231E136008961AB /* HUDProvider.swift */; }; - 892A5DAE2231E185008961AB /* HUDAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 892A5DAD2231E185008961AB /* HUDAssets.xcassets */; }; - 892A5DB22231E191008961AB /* LoadingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5DAF2231E191008961AB /* LoadingTableViewCell.swift */; }; - 892A5DB32231E191008961AB /* LevelHUDView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5DB02231E191008961AB /* LevelHUDView.swift */; }; - 892A5DB42231E191008961AB /* LevelMaskView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5DB12231E191008961AB /* LevelMaskView.swift */; }; - 892A5DB72231E1A0008961AB /* ReservoirVolumeHUDView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 892A5DB52231E19F008961AB /* ReservoirVolumeHUDView.xib */; }; - 892A5DB82231E1A0008961AB /* ReservoirVolumeHUDView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5DB62231E19F008961AB /* ReservoirVolumeHUDView.swift */; }; - 892ADE002446C858007CE08C /* Card.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892ADDFF2446C858007CE08C /* Card.swift */; }; - 893C9F8C2447DBD900CD4185 /* CardBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893C9F8B2447DBD900CD4185 /* CardBuilder.swift */; }; - 895FE06E22011E9A00FCF18A /* OverrideEmojiDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895FE06C22011E9900FCF18A /* OverrideEmojiDataSource.swift */; }; - 895FE06F22011E9A00FCF18A /* OverrideSelectionViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 895FE06D22011E9A00FCF18A /* OverrideSelectionViewController.storyboard */; }; - 895FE07122011EDD00FCF18A /* EmojiInputController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 895FE07022011EDD00FCF18A /* EmojiInputController.storyboard */; }; - 895FE07F22011F0C00FCF18A /* DoubleRangeTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 895FE07222011F0B00FCF18A /* DoubleRangeTableViewCell.xib */; }; - 895FE08022011F0C00FCF18A /* EmojiDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895FE07322011F0B00FCF18A /* EmojiDataSource.swift */; }; - 895FE08122011F0C00FCF18A /* OverridePresetCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895FE07422011F0B00FCF18A /* OverridePresetCollectionViewCell.swift */; }; - 895FE08222011F0C00FCF18A /* LabeledTextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895FE07522011F0B00FCF18A /* LabeledTextFieldTableViewCell.swift */; }; - 895FE08322011F0C00FCF18A /* OverrideSelectionFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895FE07622011F0B00FCF18A /* OverrideSelectionFooterView.swift */; }; - 895FE08622011F0C00FCF18A /* DecimalTextFieldTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 895FE07922011F0B00FCF18A /* DecimalTextFieldTableViewCell.xib */; }; - 895FE08722011F0C00FCF18A /* EmojiInputCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895FE07A22011F0C00FCF18A /* EmojiInputCell.swift */; }; - 895FE08822011F0C00FCF18A /* DoubleRangeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895FE07B22011F0C00FCF18A /* DoubleRangeTableViewCell.swift */; }; - 895FE08922011F0C00FCF18A /* OverrideSelectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895FE07C22011F0C00FCF18A /* OverrideSelectionHeaderView.swift */; }; - 895FE08A22011F0C00FCF18A /* LabeledTextFieldTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 895FE07D22011F0C00FCF18A /* LabeledTextFieldTableViewCell.xib */; }; - 895FE08B22011F0C00FCF18A /* EmojiInputHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895FE07E22011F0C00FCF18A /* EmojiInputHeaderView.swift */; }; - 895FE09022011F4800FCF18A /* OverrideSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895FE08C22011F4800FCF18A /* OverrideSelectionViewController.swift */; }; - 895FE09122011F4800FCF18A /* AddEditOverrideTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895FE08D22011F4800FCF18A /* AddEditOverrideTableViewController.swift */; }; - 895FE09322011F4800FCF18A /* EmojiInputController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895FE08F22011F4800FCF18A /* EmojiInputController.swift */; }; - 89627B16244115A400BEB424 /* CardList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89627B15244115A400BEB424 /* CardList.swift */; }; - 89627B182441168900BEB424 /* ConfigurationPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89627B172441168900BEB424 /* ConfigurationPage.swift */; }; - 89653C802473527100E1BAA5 /* FractionalQuantityPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89653C7F2473527100E1BAA5 /* FractionalQuantityPicker.swift */; }; - 89653C822473592600E1BAA5 /* CarbRatioScheduleEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89653C812473592600E1BAA5 /* CarbRatioScheduleEditor.swift */; }; - 89653C8424738D2B00E1BAA5 /* BasalRateScheduleEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89653C8324738D2B00E1BAA5 /* BasalRateScheduleEditor.swift */; }; - 8974AFC022120D7A0043F01B /* TemporaryScheduleOverrideTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8974AFBF22120D7A0043F01B /* TemporaryScheduleOverrideTests.swift */; }; - 898B4E75246CCAB50053C484 /* Binding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 898B4E74246CCAB50053C484 /* Binding.swift */; }; - 898B4E77246DAE280053C484 /* GlucoseRangePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 898B4E76246DAE280053C484 /* GlucoseRangePicker.swift */; }; - 898B4E7B246DC6A70053C484 /* CorrectionRangeScheduleEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 898B4E7A246DC6A70053C484 /* CorrectionRangeScheduleEditor.swift */; }; - 898B4E7E246DEB920053C484 /* GuardrailConstrainedQuantityRangeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 898B4E7D246DEB920053C484 /* GuardrailConstrainedQuantityRangeView.swift */; }; - 898C896D24D4BF75002FA994 /* FloatingPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 898C896C24D4BF75002FA994 /* FloatingPoint.swift */; }; - 898C897124D4C0E4002FA994 /* GuardrailTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 898C897024D4C0E4002FA994 /* GuardrailTests.swift */; }; - 898E6E5D2241783C0019E459 /* SetConstrainedScheduleEntryTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5D63222F6B13008961AB /* SetConstrainedScheduleEntryTableViewCell.swift */; }; - 898E6E67224179310019E459 /* BaseHUDView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 898E6E64224179300019E459 /* BaseHUDView.swift */; }; - 898E6E68224179310019E459 /* BatteryLevelHUDView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 898E6E65224179300019E459 /* BatteryLevelHUDView.xib */; }; - 898E6E69224179310019E459 /* BatteryLevelHUDView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 898E6E66224179300019E459 /* BatteryLevelHUDView.swift */; }; - 898E6E6C224194060019E459 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 898E6E6B224194050019E459 /* UIColor.swift */; }; - 898E6E6E2241ED9F0019E459 /* SuspendResumeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 898E6E6D2241ED9F0019E459 /* SuspendResumeTableViewCell.swift */; }; - 898E6E702241EDB70019E459 /* PercentageTextFieldTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 898E6E6F2241EDB70019E459 /* PercentageTextFieldTableViewController.swift */; }; - 898E6E722241EDC10019E459 /* DateAndDurationTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 898E6E712241EDC10019E459 /* DateAndDurationTableViewController.swift */; }; - 899012C1246F1D8F007B88BA /* ExpandableSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 899012C0246F1D8F007B88BA /* ExpandableSetting.swift */; }; - 89904032245B5CA500F1C0A2 /* Deletable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89904031245B5CA500F1C0A2 /* Deletable.swift */; }; - 8992426521EC138000EA512B /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8992426421EC138000EA512B /* UIColor.swift */; }; - 8997B4F523727E8A00061132 /* CustomOverrideCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8997B4F423727E8A00061132 /* CustomOverrideCollectionViewCell.swift */; }; - 89AC9DCB24529927004A6B8A /* QuantityPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AC9DCA24529927004A6B8A /* QuantityPicker.swift */; }; - 89AC9DCD24529D9B004A6B8A /* TimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AC9DCC24529D9B004A6B8A /* TimePicker.swift */; }; - 89ADE129226BDB280067222B /* TestingScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89ADE128226BDB280067222B /* TestingScenario.swift */; }; - 89ADE12B226BDB730067222B /* DateRelativeCarbEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89ADE12A226BDB730067222B /* DateRelativeCarbEntry.swift */; }; - 89ADE12D226BDD190067222B /* DateRelativeBasalEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89ADE12C226BDD190067222B /* DateRelativeBasalEntry.swift */; }; - 89ADE12F226BDED40067222B /* DateRelativeBolusEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89ADE12E226BDED40067222B /* DateRelativeBolusEntry.swift */; }; - 89ADE134226BF0490067222B /* TestingScenarioInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89ADE133226BF0490067222B /* TestingScenarioInstance.swift */; }; - 89ADE136226BF0BE0067222B /* DateRelativeGlucoseSample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89ADE135226BF0BE0067222B /* DateRelativeGlucoseSample.swift */; }; - 89AE2226228BC54C00BDFD85 /* TemporaryScheduleOverridePreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AE221F228BC54C00BDFD85 /* TemporaryScheduleOverridePreset.swift */; }; - 89AE2227228BC54C00BDFD85 /* TemporaryScheduleOverride.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AE2223228BC54C00BDFD85 /* TemporaryScheduleOverride.swift */; }; - 89AE2228228BC54C00BDFD85 /* TemporaryScheduleOverrideSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AE2224228BC54C00BDFD85 /* TemporaryScheduleOverrideSettings.swift */; }; - 89AE2229228BC54C00BDFD85 /* TemporaryScheduleOverrideHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AE2225228BC54C00BDFD85 /* TemporaryScheduleOverrideHistory.swift */; }; - 89AE222B228BC56A00BDFD85 /* WeakSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AE222A228BC56A00BDFD85 /* WeakSet.swift */; }; - 89AE222C228BC66E00BDFD85 /* Locked.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AC792E224C781200B8E9BA /* Locked.swift */; }; - 89AE222D228BC66E00BDFD85 /* Locked.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AC792E224C781200B8E9BA /* Locked.swift */; }; - 89AE222E228BC68000BDFD85 /* DoseProgressReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AC792C224C781100B8E9BA /* DoseProgressReporter.swift */; }; - 89AE222F228BC68000BDFD85 /* DoseProgressTimerEstimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AC792D224C781100B8E9BA /* DoseProgressTimerEstimator.swift */; }; - 89AE2230228BC68100BDFD85 /* DoseProgressReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AC792C224C781100B8E9BA /* DoseProgressReporter.swift */; }; - 89AE2231228BC68100BDFD85 /* DoseProgressTimerEstimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AC792D224C781100B8E9BA /* DoseProgressTimerEstimator.swift */; }; - 89AE2232228BC68600BDFD85 /* UnfairLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1ABE38D2245CFCD00570E82 /* UnfairLock.swift */; }; - 89AE2233228BC6A500BDFD85 /* MockDoseProgressEstimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AC7934224C783500B8E9BA /* MockDoseProgressEstimator.swift */; }; - 89AE2235228BCAAB00BDFD85 /* CarbSensitivitySchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A3FDA224BEC0D00378B27 /* CarbSensitivitySchedule.swift */; }; - 89AE2236228BCAAB00BDFD85 /* DailyQuantitySchedule+Override.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A3FD4224B047200378B27 /* DailyQuantitySchedule+Override.swift */; }; - 89AE2237228BCAAB00BDFD85 /* EGPSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A3FD8224BEB4500378B27 /* EGPSchedule.swift */; }; - 89AE2238228BCAAB00BDFD85 /* TemporaryScheduleOverride.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AE2223228BC54C00BDFD85 /* TemporaryScheduleOverride.swift */; }; - 89AE2239228BCAAB00BDFD85 /* TemporaryScheduleOverrideHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AE2225228BC54C00BDFD85 /* TemporaryScheduleOverrideHistory.swift */; }; - 89AE223A228BCAAB00BDFD85 /* TemporaryScheduleOverridePreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AE221F228BC54C00BDFD85 /* TemporaryScheduleOverridePreset.swift */; }; - 89AE223B228BCAAB00BDFD85 /* TemporaryScheduleOverrideSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AE2224228BC54C00BDFD85 /* TemporaryScheduleOverrideSettings.swift */; }; - 89AE223C228BCAAB00BDFD85 /* WeakSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AE222A228BC56A00BDFD85 /* WeakSet.swift */; }; - 89AE223E228BD3C400BDFD85 /* SetConstrainedScheduleEntryTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 892A5D62222F6B13008961AB /* SetConstrainedScheduleEntryTableViewCell.xib */; }; - 89AF78C02447E285002B4FCC /* CardStackBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AF78BF2447E285002B4FCC /* CardStackBuilder.swift */; }; - 89AF78C22447E353002B4FCC /* Splat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AF78C12447E353002B4FCC /* Splat.swift */; }; - 89AF78C624482269002B4FCC /* ActionButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AF78C524482268002B4FCC /* ActionButtonStyle.swift */; }; - 89B0B2AA2453C0AB0063D4A7 /* GuardrailConstraintedQuantityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89B0B2A92453C0AB0063D4A7 /* GuardrailConstraintedQuantityView.swift */; }; - 89BE75C124649C2E00B145D9 /* ModalHeaderButtonBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89BE75C024649C2E00B145D9 /* ModalHeaderButtonBar.swift */; }; - 89BE75C324649C4C00B145D9 /* RoundedCorners.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89BE75C224649C4C00B145D9 /* RoundedCorners.swift */; }; - 89BE75C524649C8100B145D9 /* NewScheduleItemEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89BE75C424649C8100B145D9 /* NewScheduleItemEditor.swift */; }; - 89BE75C72464B4A900B145D9 /* Environment+Dismiss.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89BE75C62464B4A900B145D9 /* Environment+Dismiss.swift */; }; - 89BE75CB2464BC2000B145D9 /* AlertContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89BE75CA2464BC2000B145D9 /* AlertContent.swift */; }; - 89CA2B38226D4456004D9350 /* DateRelativeQuantity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CA2B37226D4456004D9350 /* DateRelativeQuantity.swift */; }; - 89CAB36B24C9EC25009EE3CE /* DismissibleKeyboardTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CAB36A24C9EC25009EE3CE /* DismissibleKeyboardTextField.swift */; }; - 89CAB36D24C9EC98009EE3CE /* Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CAB36C24C9EC98009EE3CE /* Keyboard.swift */; }; - 89CAB36F24C9ECCA009EE3CE /* View+KeyboardAware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CAB36E24C9ECCA009EE3CE /* View+KeyboardAware.swift */; }; - 89CAB37124CB4DEC009EE3CE /* WarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CAB37024CB4DEC009EE3CE /* WarningView.swift */; }; - 89CC35D42403450E008FB633 /* ThumbView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CC35D32403450E008FB633 /* ThumbView.swift */; }; - 89D2048221CC7BD8001238CC /* MockKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 89D2047421CC7BD7001238CC /* MockKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 89D2048921CC7BF7001238CC /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4301582C1C7ECD7A00B64B63 /* HealthKit.framework */; }; - 89D2049F21CC7C13001238CC /* MockKitUI.h in Headers */ = {isa = PBXBuildFile; fileRef = 89D2049121CC7C13001238CC /* MockKitUI.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 89D204A621CC7C55001238CC /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D8FDCB1C728FDF0073BE78 /* LoopKit.framework */; }; - 89D204A721CC7C5C001238CC /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43BA7154201E484D0058961E /* LoopKitUI.framework */; }; - 89D204A821CC7C60001238CC /* MockKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 89D2047221CC7BD7001238CC /* MockKit.framework */; }; - 89D204A921CC7C8F001238CC /* MockPumpManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AB9EC621A4774500351324 /* MockPumpManager.swift */; }; - 89D204AA21CC7C8F001238CC /* MockGlucoseProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CCD4F721A8D5500068C3FB /* MockGlucoseProvider.swift */; }; - 89D204AB21CC7C8F001238CC /* MockCGMDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CCD4F121A87D340068C3FB /* MockCGMDataSource.swift */; }; - 89D204AC21CC7C8F001238CC /* MockCGMManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AB9EC821A4BC2400351324 /* MockCGMManager.swift */; }; - 89D204B221CC7D93001238CC /* Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89DC540C21B75AE7005A1CE0 /* Collection.swift */; }; - 89D204B421CC7E74001238CC /* MockCGMManager+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CCD4F321A8A2B30068C3FB /* MockCGMManager+UI.swift */; }; - 89D204B521CC7E74001238CC /* MockPumpManager+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AB9ECA21A4C36200351324 /* MockPumpManager+UI.swift */; }; - 89D204BA21CC7F34001238CC /* MockPumpManagerSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AB9ED521A4DE5F00351324 /* MockPumpManagerSettingsViewController.swift */; }; - 89D204BB21CC7F34001238CC /* MockCGMManagerSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CCD4F521A8A6A60068C3FB /* MockCGMManagerSettingsViewController.swift */; }; - 89D204BC21CC7F34001238CC /* SineCurveParametersTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8907E35A21A9D1B200335852 /* SineCurveParametersTableViewController.swift */; }; - 89D204BD21CC7F34001238CC /* RandomOutlierTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892F481A21AB2964004D313D /* RandomOutlierTableViewController.swift */; }; - 89D204BE21CC7F34001238CC /* GlucoseTrendTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89D2046B21C83C3F001238CC /* GlucoseTrendTableViewController.swift */; }; - 89D204D221CC837A001238CC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 89D204D121CC837A001238CC /* Assets.xcassets */; }; - 89E7E61024D11AB600591386 /* OrientationLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89E7E60F24D11AB600591386 /* OrientationLock.swift */; }; - 89F6E30D2449713600CB9E15 /* CardStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F6E30C2449713600CB9E15 /* CardStack.swift */; }; - 89F6E30F244A1A5D00CB9E15 /* Guardrail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F6E30E244A1A5D00CB9E15 /* Guardrail.swift */; }; - 89F6E311244A1AAB00CB9E15 /* SettingDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F6E310244A1AAB00CB9E15 /* SettingDescription.swift */; }; - 89F6E314244A1AB600CB9E15 /* GuardrailWarning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F6E312244A1AB500CB9E15 /* GuardrailWarning.swift */; }; - 89F6E315244A1AB600CB9E15 /* GlucoseValuePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F6E313244A1AB600CB9E15 /* GlucoseValuePicker.swift */; }; - 89FC688F245A2D680075CF59 /* InsulinSensitivityScheduleEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89FC688A245A2D670075CF59 /* InsulinSensitivityScheduleEditor.swift */; }; - 89FC6890245A2D680075CF59 /* QuantityScheduleEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89FC688B245A2D670075CF59 /* QuantityScheduleEditor.swift */; }; - 89FC6891245A2D680075CF59 /* ScheduleItemPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89FC688C245A2D680075CF59 /* ScheduleItemPicker.swift */; }; - 89FC6892245A2D680075CF59 /* ScheduleEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89FC688D245A2D680075CF59 /* ScheduleEditor.swift */; }; - 89FC6893245A2D680075CF59 /* ScheduleItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89FC688E245A2D680075CF59 /* ScheduleItemView.swift */; }; - 9E78433F236653F00016C583 /* ice_35_min_none_piecewiselinear_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 9E78433E236653F00016C583 /* ice_35_min_none_piecewiselinear_output.json */; }; - 9E784341236656770016C583 /* ice_35_min_partial_piecewiselinear_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 9E784340236656770016C583 /* ice_35_min_partial_piecewiselinear_output.json */; }; - 9E784343236659BD0016C583 /* ice_slow_absorption_piecewiselinear_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 9E784342236659BD0016C583 /* ice_slow_absorption_piecewiselinear_output.json */; }; - 9E78434523665B5A0016C583 /* ice_35_min_partial_piecewiselinear_adaptiverate_output.json in Resources */ = {isa = PBXBuildFile; fileRef = 9E78434423665B5A0016C583 /* ice_35_min_partial_piecewiselinear_adaptiverate_output.json */; }; - A9012EB225BA3861000813AD /* SetupUIResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9012EB125BA3861000813AD /* SetupUIResult.swift */; }; - A91263872790B45300C6C950 /* NewPumpEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91263862790B45300C6C950 /* NewPumpEventTests.swift */; }; - A912BE29245B9CD500CBE199 /* SettingsObject+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = A912BE28245B9CD500CBE199 /* SettingsObject+CoreDataClass.swift */; }; - A912BE2B245B9E8600CBE199 /* SettingsObject+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = A912BE2A245B9E8600CBE199 /* SettingsObject+CoreDataProperties.swift */; }; - A912BE2D245B9F9800CBE199 /* SettingsObject+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = A912BE28245B9CD500CBE199 /* SettingsObject+CoreDataClass.swift */; }; - A914472527BF04170054A39D /* normalize_edge_case_doses_mutable_input.json in Resources */ = {isa = PBXBuildFile; fileRef = A914472427BF04170054A39D /* normalize_edge_case_doses_mutable_input.json */; }; - A914472727BF044C0054A39D /* normalize_edge_case_doses_mutable_output.json in Resources */ = {isa = PBXBuildFile; fileRef = A914472627BF044C0054A39D /* normalize_edge_case_doses_mutable_output.json */; }; - A919889C2354E5EB00B75EEE /* SettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A919889B2354E5EB00B75EEE /* SettingsStore.swift */; }; - A919889F2355016B00B75EEE /* DosingDecisionStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A919889E2355016B00B75EEE /* DosingDecisionStore.swift */; }; - A932803B2798D63B0091D0A1 /* SyncAlertObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = A932803A2798D63B0091D0A1 /* SyncAlertObject.swift */; }; - A932803C2798D63B0091D0A1 /* SyncAlertObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = A932803A2798D63B0091D0A1 /* SyncAlertObject.swift */; }; - A933DB8824BF956F009B417A /* CriticalEventLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = A933DB8724BF956F009B417A /* CriticalEventLog.swift */; }; - A933DB8924BF97CC009B417A /* CriticalEventLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = A933DB8724BF956F009B417A /* CriticalEventLog.swift */; }; - A935094426E2FAB70030B60D /* GlucoseCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = A935094326E2FAB70030B60D /* GlucoseCondition.swift */; }; - A935094526E2FAB70030B60D /* GlucoseCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = A935094326E2FAB70030B60D /* GlucoseCondition.swift */; }; - A935793B29A2570400246DED /* CarbAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A935793629A2570300246DED /* CarbAction.swift */; }; - A935793C29A2570400246DED /* OverrideCancelAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A935793729A2570300246DED /* OverrideCancelAction.swift */; }; - A935793D29A2570400246DED /* OverrideAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A935793829A2570400246DED /* OverrideAction.swift */; }; - A935793E29A2570400246DED /* BolusAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A935793929A2570400246DED /* BolusAction.swift */; }; - A935793F29A2570400246DED /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = A935793A29A2570400246DED /* Action.swift */; }; - A93761C125ED670200F6BE43 /* BluetoothProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93761C025ED670200F6BE43 /* BluetoothProvider.swift */; }; - A93761C225ED670200F6BE43 /* BluetoothProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93761C025ED670200F6BE43 /* BluetoothProvider.swift */; }; - A93CA899278D08CC003B5A01 /* PumpAlarmType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CA898278D08CC003B5A01 /* PumpAlarmType.swift */; }; - A93CA89A278D08CC003B5A01 /* PumpAlarmType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CA898278D08CC003B5A01 /* PumpAlarmType.swift */; }; - A9498D6F23386C0B00DAA9B9 /* TempBasalRecommendation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9498D6E23386C0B00DAA9B9 /* TempBasalRecommendation.swift */; }; - A9498D7023386C0B00DAA9B9 /* TempBasalRecommendation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9498D6E23386C0B00DAA9B9 /* TempBasalRecommendation.swift */; }; - A9498D7823386C3300DAA9B9 /* LoggingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9498D7123386C3200DAA9B9 /* LoggingService.swift */; }; - A9498D7C23386C3300DAA9B9 /* AnalyticsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9498D7323386C3200DAA9B9 /* AnalyticsService.swift */; }; - A9498D7E23386C3300DAA9B9 /* GlucoseThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9498D7423386C3200DAA9B9 /* GlucoseThreshold.swift */; }; - A9498D7F23386C3300DAA9B9 /* GlucoseThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9498D7423386C3200DAA9B9 /* GlucoseThreshold.swift */; }; - A9498D8023386C3300DAA9B9 /* RemoteDataService.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9498D7523386C3300DAA9B9 /* RemoteDataService.swift */; }; - A9498D8223386C3300DAA9B9 /* Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9498D7623386C3300DAA9B9 /* Service.swift */; }; - A9498D8823386CAF00DAA9B9 /* ServiceNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9498D8623386CAF00DAA9B9 /* ServiceNavigationController.swift */; }; - A9498D8B23386CC700DAA9B9 /* ServiceUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9498D8A23386CC700DAA9B9 /* ServiceUI.swift */; }; - A9498D8D23386CD800DAA9B9 /* MockService.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9498D8C23386CD700DAA9B9 /* MockService.swift */; }; - A9498D8F23386CE800DAA9B9 /* MockServiceTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9498D8E23386CE800DAA9B9 /* MockServiceTableViewController.swift */; }; - A9498D9123386D0800DAA9B9 /* MockService+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9498D9023386D0800DAA9B9 /* MockService+UI.swift */; }; - A95A1D7F2460BBC70079378D /* DosingDecisionObject+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95A1D7E2460BBC70079378D /* DosingDecisionObject+CoreDataClass.swift */; }; - A95A1D802460BBC70079378D /* DosingDecisionObject+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95A1D7E2460BBC70079378D /* DosingDecisionObject+CoreDataClass.swift */; }; - A95A1D822460BBDC0079378D /* DosingDecisionObject+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95A1D812460BBDC0079378D /* DosingDecisionObject+CoreDataProperties.swift */; }; - A95A1D852460CAD50079378D /* CarbValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95A1D842460CAD50079378D /* CarbValueTests.swift */; }; - A95A1D872460F1250079378D /* GlucoseValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95A1D862460F1250079378D /* GlucoseValueTests.swift */; }; - A95A1D892460F8930079378D /* PumpManagerStatusTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95A1D882460F8930079378D /* PumpManagerStatusTests.swift */; }; - A95A1D8B2460FD620079378D /* BolusRecommendationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95A1D8A2460FD620079378D /* BolusRecommendationTests.swift */; }; - A95A1D8D246101760079378D /* DoseEntryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95A1D8C246101760079378D /* DoseEntryTests.swift */; }; - A963B278252CE2510062AA12 /* StoredCarbEntryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A963B277252CE2510062AA12 /* StoredCarbEntryTests.swift */; }; - A9672B5326E80C060025B0CD /* NewGlucoseSampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9672B5226E80C060025B0CD /* NewGlucoseSampleTests.swift */; }; - A967D94924F99B6A00CDDF8A /* OutputStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = A967D94824F99B6A00CDDF8A /* OutputStream.swift */; }; - A967D94A24F99B6A00CDDF8A /* OutputStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = A967D94824F99B6A00CDDF8A /* OutputStream.swift */; }; - A96E6C3727B35BC600F81A5B /* AnyCodableEquatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A96E6C3627B35BC600F81A5B /* AnyCodableEquatable.swift */; }; - A96E6C3827B35BC600F81A5B /* AnyCodableEquatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A96E6C3627B35BC600F81A5B /* AnyCodableEquatable.swift */; }; - A971C89F23C68B030099BEFC /* GlucoseStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A971C89E23C68B030099BEFC /* GlucoseStoreTests.swift */; }; - A971C8A223C6B17D0099BEFC /* SettingsStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A971C8A123C6B17D0099BEFC /* SettingsStoreTests.swift */; }; - A971C8A423C6B1890099BEFC /* DosingDecisionStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A971C8A323C6B1890099BEFC /* DosingDecisionStoreTests.swift */; }; - A985464B251442010099C1A6 /* OutputStreamTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A985464A251442010099C1A6 /* OutputStreamTests.swift */; }; - A985464F251449FE0099C1A6 /* NotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = A985464E251449FE0099C1A6 /* NotificationSettings.swift */; }; - A985465125144ABA0099C1A6 /* NotificationSettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A985465025144ABA0099C1A6 /* NotificationSettingsTests.swift */; }; - A987CD4624A5893500439ADC /* JSONStreamEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = A987CD4524A5893500439ADC /* JSONStreamEncoder.swift */; }; - A987CD4724A5893500439ADC /* JSONStreamEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = A987CD4524A5893500439ADC /* JSONStreamEncoder.swift */; }; - A98ED5FB25312E3200FD8F70 /* HKObserverQueryMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E7035E25001EA500DAB534 /* HKObserverQueryMock.swift */; }; - A98ED5FC25312ED100FD8F70 /* HKAnchoredObjectQueryMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E703612500390B00DAB534 /* HKAnchoredObjectQueryMock.swift */; }; - A98ED5FE253132A400FD8F70 /* CarbStoreHKQueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98ED5FD253132A400FD8F70 /* CarbStoreHKQueryTests.swift */; }; - A994B884254241B10039B108 /* InsulinDeliveryStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A994B883254241B10039B108 /* InsulinDeliveryStoreTests.swift */; }; - A99C7373233990D400C80963 /* TempBasalRecommendationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A99C7372233990D400C80963 /* TempBasalRecommendationTests.swift */; }; - A99C73772339A67A00C80963 /* GlucoseThresholdTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A99C73762339A67A00C80963 /* GlucoseThresholdTests.swift */; }; - A99C73792339ACDC00C80963 /* ServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A99C73782339ACDC00C80963 /* ServiceTests.swift */; }; - A9A53E2C2714E5BC0050C0B1 /* CodableDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A53E2B2714E5BC0050C0B1 /* CodableDevice.swift */; }; - A9A53E2D2714E5BC0050C0B1 /* CodableDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A53E2B2714E5BC0050C0B1 /* CodableDevice.swift */; }; - A9B0D97E273313EB00D96D93 /* CGMManagerStatusTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B0D97D273313EB00D96D93 /* CGMManagerStatusTests.swift */; }; - A9BD318224F4548900994B83 /* Modelv3EntityMigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BD318124F4548900994B83 /* Modelv3EntityMigrationPolicy.swift */; }; - A9BD318324F4548900994B83 /* Modelv3EntityMigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BD318124F4548900994B83 /* Modelv3EntityMigrationPolicy.swift */; }; - A9BFA03E245CCCB9001E4AE3 /* DailyQuantityScheduleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BFA03D245CCCB9001E4AE3 /* DailyQuantityScheduleTests.swift */; }; - A9CE912324CA033A00302A40 /* InsulinModelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D096BFF24C24C220078B6B5 /* InsulinModelProvider.swift */; }; - A9CFCA8F2582F9FA00A04932 /* OnboardingUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CFCA8E2582F9FA00A04932 /* OnboardingUI.swift */; }; - A9CFCAA52582FA0400A04932 /* SupportUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CFCAA42582FA0400A04932 /* SupportUI.swift */; }; - A9DCF2CA25B0F38000C89088 /* LoopUIColorPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DCF2C925B0F38000C89088 /* LoopUIColorPalette.swift */; }; - A9DF02C324F6EEE400B7C988 /* DeviceLogEntryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DF02C224F6EEE400B7C988 /* DeviceLogEntryTests.swift */; }; - A9DF02C524F6FA5100B7C988 /* PumpEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DF02C424F6FA5100B7C988 /* PumpEventTests.swift */; }; - A9DF02C924F724D900B7C988 /* CriticalEventLogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DF02C824F724D900B7C988 /* CriticalEventLogTests.swift */; }; - A9DF02CF24F732FC00B7C988 /* JSONStreamEncoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DF02CE24F732FC00B7C988 /* JSONStreamEncoderTests.swift */; }; - A9DF02D124F7449E00B7C988 /* PersistentDeviceLogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DF02D024F7449E00B7C988 /* PersistentDeviceLogTests.swift */; }; - A9DF02D224F748BF00B7C988 /* CriticalEventLogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DF02C824F724D900B7C988 /* CriticalEventLogTests.swift */; }; - A9DF02D324F762DC00B7C988 /* CarbStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437AFF192039F149008C4892 /* CarbStoreTests.swift */; }; - A9E068112534D87800BDAB59 /* StoredGlucoseSampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E068102534D87800BDAB59 /* StoredGlucoseSampleTests.swift */; }; - A9E068162534EB8200BDAB59 /* CachedGlucoseObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E068152534EB8200BDAB59 /* CachedGlucoseObjectTests.swift */; }; - A9E0681825350ECC00BDAB59 /* GlucoseStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E0681725350ECC00BDAB59 /* GlucoseStoreTests.swift */; }; - A9E1E6A924E1B6700073CA39 /* SyncCarbObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E1E6A824E1B6700073CA39 /* SyncCarbObject.swift */; }; - A9E1E6AA24E1B7C10073CA39 /* SyncCarbObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E1E6A824E1B6700073CA39 /* SyncCarbObject.swift */; }; - A9E1E6AC24E1D7EC0073CA39 /* PersistenceControllerTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434113B720F2BDE800D05747 /* PersistenceControllerTestCase.swift */; }; - A9E1E6AD24E1D8590073CA39 /* CacheStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437AFF1C203A45DB008C4892 /* CacheStore.swift */; }; - A9E1E6AE24E1D8860073CA39 /* NSManagedObjectContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437AFF20203AA740008C4892 /* NSManagedObjectContext.swift */; }; - A9E6758222713F4700E25293 /* LoopNotificationCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1814B83225B9ED5008D2D8E /* LoopNotificationCategory.swift */; }; - A9E6758422713F4700E25293 /* NewCarbEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE5B1C7291D80073BE78 /* NewCarbEntry.swift */; }; - A9E6758522713F4700E25293 /* GlucoseMath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE861C72934C0073BE78 /* GlucoseMath.swift */; }; - A9E6758722713F4700E25293 /* CarbEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE4A1C7291BD0073BE78 /* CarbEntry.swift */; }; - A9E6758822713F4700E25293 /* HealthKitSampleStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDED1C7290350073BE78 /* HealthKitSampleStore.swift */; }; - A9E6758C22713F4700E25293 /* DoseType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A0670E1F23CAC700E9E90F /* DoseType.swift */; }; - A9E6758D22713F4700E25293 /* CachedCarbObject+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437AFEE92036A156008C4892 /* CachedCarbObject+CoreDataClass.swift */; }; - A9E6758E22713F4700E25293 /* DailyValueSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDE81C7290350073BE78 /* DailyValueSchedule.swift */; }; - A9E6758F22713F4700E25293 /* NewPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4302F4EA1D50670500F0FCAF /* NewPumpEvent.swift */; }; - A9E6759022713F4700E25293 /* CachedInsulinDeliveryObject+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434113A820F171CB00D05747 /* CachedInsulinDeliveryObject+CoreDataClass.swift */; }; - A9E6759122713F4700E25293 /* GlucoseTrend.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432CF86E20D76CCF0066B889 /* GlucoseTrend.swift */; }; - A9E6759222713F4700E25293 /* PumpManagerStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FB60E820DCBE64002B996B /* PumpManagerStatus.swift */; }; - A9E6759322713F4700E25293 /* CarbMath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE4B1C7291BD0073BE78 /* CarbMath.swift */; }; - A9E6759522713F4700E25293 /* ExponentialInsulinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1DB55B21F2E964400C483A2 /* ExponentialInsulinModel.swift */; }; - A9E6759722713F4700E25293 /* DailyQuantitySchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDE71C7290350073BE78 /* DailyQuantitySchedule.swift */; }; - A9E6759822713F4700E25293 /* CarbRatioSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDE61C7290350073BE78 /* CarbRatioSchedule.swift */; }; - A9E6759922713F4700E25293 /* GlucoseSampleValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43971A3F1C8CABFF0013154F /* GlucoseSampleValue.swift */; }; - A9E6759A22713F4700E25293 /* GlucoseDisplayable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432CF87020D76D5A0066B889 /* GlucoseDisplayable.swift */; }; - A9E6759B22713F4700E25293 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FEE21C7294D50073BE78 /* PersistenceController.swift */; }; - A9E6759C22713F4700E25293 /* InsulinDeliveryStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 438207701F2AE9A300886C13 /* InsulinDeliveryStore.swift */; }; - A9E6759D22713F4700E25293 /* DeviceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4379CFE221102A4100AADC79 /* DeviceManager.swift */; }; - A9E6759E22713F4700E25293 /* DoseUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C094451CAA1E98001F6403 /* DoseUnit.swift */; }; - A9E675A022713F4700E25293 /* HKQuantitySample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432762731D60505F0083215A /* HKQuantitySample.swift */; }; - A9E675A122713F4700E25293 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDE91C7290350073BE78 /* Double.swift */; }; - A9E675A222713F4700E25293 /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F5034A21051FCD009FA89A /* KeychainManager.swift */; }; - A9E675A322713F4700E25293 /* PumpManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432CF87220D774220066B889 /* PumpManager.swift */; }; - A9E675A422713F4700E25293 /* SampleValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDF31C7290350073BE78 /* SampleValue.swift */; }; - A9E675A522713F4700E25293 /* GlucoseValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D9888A1C87E47800DA4467 /* GlucoseValue.swift */; }; - A9E675A622713F4700E25293 /* BasalRateSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDE51C7290340073BE78 /* BasalRateSchedule.swift */; }; - A9E675A722713F4700E25293 /* DoseStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FEDD1C7294D50073BE78 /* DoseStore.swift */; }; - A9E675A922713F4700E25293 /* PumpEvent+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43DFE27C1CB1D6A600EFBE95 /* PumpEvent+CoreDataProperties.swift */; }; - A9E675AA22713F4700E25293 /* ReservoirValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4302F4E81D5066F400F0FCAF /* ReservoirValue.swift */; }; - A9E675AB22713F4700E25293 /* HKHealthStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437AFF23203BE402008C4892 /* HKHealthStore.swift */; }; - A9E675AC22713F4700E25293 /* Reservoir.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FEE31C7294D50073BE78 /* Reservoir.swift */; }; - A9E675AE22713F4700E25293 /* CarbValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4378B64E1ED61C64000AE785 /* CarbValue.swift */; }; - A9E675AF22713F4700E25293 /* PumpEventType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43DFE27F1CB1E12D00EFBE95 /* PumpEventType.swift */; }; - A9E675B222713F4700E25293 /* GlucoseRangeSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDEB1C7290350073BE78 /* GlucoseRangeSchedule.swift */; }; - A9E675B322713F4700E25293 /* PersistedPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4302F4EC1D5068CE00F0FCAF /* PersistedPumpEvent.swift */; }; - A9E675B422713F4700E25293 /* CachedCarbObject+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437AFEEA2036A156008C4892 /* CachedCarbObject+CoreDataProperties.swift */; }; - A9E675B522713F4700E25293 /* AbsorbedCarbValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4378B64C1ED61C22000AE785 /* AbsorbedCarbValue.swift */; }; - A9E675B722713F4700E25293 /* NSManagedObjectContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434113AC20F287DC00D05747 /* NSManagedObjectContext.swift */; }; - A9E675B822713F4700E25293 /* StoredCarbEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE4E1C7291BD0073BE78 /* StoredCarbEntry.swift */; }; - A9E675BA22713F4700E25293 /* InsulinValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43DFE2811CB1FB8500EFBE95 /* InsulinValue.swift */; }; - A9E675BD22713F4700E25293 /* HKQuantitySample+InsulinKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437B064D1F2EB35800D95237 /* HKQuantitySample+InsulinKit.swift */; }; - A9E675BE22713F4700E25293 /* InsulinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12EE16B1F2964B3007DB9F1 /* InsulinModel.swift */; }; - A9E675BF22713F4700E25293 /* QuantityFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434C5F9B2098352500B2FD1A /* QuantityFormatter.swift */; }; - A9E675C022713F4700E25293 /* ServiceAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F5035421059A8A009FA89A /* ServiceAuthentication.swift */; }; - A9E675C122713F4700E25293 /* NewGlucoseSample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433BC7A620523DB7000B1200 /* NewGlucoseSample.swift */; }; - A9E675C222713F4700E25293 /* InsulinMath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FEDF1C7294D50073BE78 /* InsulinMath.swift */; }; - A9E675C322713F4700E25293 /* UnfairLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1ABE38D2245CFCD00570E82 /* UnfairLock.swift */; }; - A9E675C422713F4700E25293 /* HealthStoreUnitCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43B17C88208EEC0B00AC27E9 /* HealthStoreUnitCache.swift */; }; - A9E675C622713F4700E25293 /* CarbStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4378B6501ED62D8D000AE785 /* CarbStatus.swift */; }; - A9E675C722713F4700E25293 /* DoseEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FEDC1C7294D50073BE78 /* DoseEntry.swift */; }; - A9E675C822713F4700E25293 /* NSUserActivity+CarbKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CB51B0211EB16C00DB9B4A /* NSUserActivity+CarbKit.swift */; }; - A9E675C922713F4700E25293 /* CachedInsulinDeliveryObject+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434113A920F171CB00D05747 /* CachedInsulinDeliveryObject+CoreDataProperties.swift */; }; - A9E675CB22713F4700E25293 /* StoredGlucoseSample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433BC7AC20538FCA000B1200 /* StoredGlucoseSample.swift */; }; - A9E675CC22713F4700E25293 /* GlucoseEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDEA1C7290350073BE78 /* GlucoseEffect.swift */; }; - A9E675CD22713F4700E25293 /* WeakSynchronizedSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CACE0D2247F89100F90AF5 /* WeakSynchronizedSet.swift */; }; - A9E675CE22713F4700E25293 /* LoopMath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDEF1C7290350073BE78 /* LoopMath.swift */; }; - A9E675CF22713F4700E25293 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDF01C7290350073BE78 /* Date.swift */; }; - A9E675D022713F4700E25293 /* GlucoseChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C9805B212D216A003B5D17 /* GlucoseChange.swift */; }; - A9E675D122713F4700E25293 /* GlucoseSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FDEC1C7290350073BE78 /* GlucoseSchedule.swift */; }; - A9E675D222713F4700E25293 /* NSUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4346D1FB1C79481E00ABAFE3 /* NSUserDefaults.swift */; }; - A9E675D322713F4700E25293 /* CarbStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE4C1C7291BD0073BE78 /* CarbStore.swift */; }; - A9E675D422713F4700E25293 /* CachedGlucoseObject+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433BC7A820538D4C000B1200 /* CachedGlucoseObject+CoreDataClass.swift */; }; - A9E675D522713F4700E25293 /* WalshInsulinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1DB55B01F2E95FD00C483A2 /* WalshInsulinModel.swift */; }; - A9E675D622713F4700E25293 /* GlucoseEffectVelocity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4378B64A1ED61965000AE785 /* GlucoseEffectVelocity.swift */; }; - A9E675D722713F4700E25293 /* PumpEvent+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43DFE27B1CB1D6A600EFBE95 /* PumpEvent+CoreDataClass.swift */; }; - A9E675D922713F4700E25293 /* Reservoir+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FEE41C7294D50073BE78 /* Reservoir+CoreDataProperties.swift */; }; - A9E675DA22713F4700E25293 /* HKQuantitySample+CarbKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE4D1C7291BD0073BE78 /* HKQuantitySample+CarbKit.swift */; }; - A9E675DB22713F4700E25293 /* HKQuantitySample+GlucoseKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FADDFA1C89679200DDE013 /* HKQuantitySample+GlucoseKit.swift */; }; - A9E675DC22713F4700E25293 /* CachedGlucoseObject+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433BC7A920538D4C000B1200 /* CachedGlucoseObject+CoreDataProperties.swift */; }; - A9E675DD22713F4700E25293 /* PumpManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FB610620DDF19B002B996B /* PumpManagerError.swift */; }; - A9E675E022713F4700E25293 /* GlucoseStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D8FE871C72934C0073BE78 /* GlucoseStore.swift */; }; - A9E675E122713F4700E25293 /* WeakSynchronizedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1814B8B226371DF008D2D8E /* WeakSynchronizedDelegate.swift */; }; - A9E675E222713F4700E25293 /* CGMManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4352A73B20DECF0600CAC200 /* CGMManager.swift */; }; - A9E675E322713F4700E25293 /* CarbStoreError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4353D16E203D104F007B4ECD /* CarbStoreError.swift */; }; - A9E675E422713F4700E25293 /* HKQuantity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43AF1FB11C926CDD00EA2F3D /* HKQuantity.swift */; }; - A9E675E922713F4700E25293 /* LoopKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 43D8FDCE1C728FDF0073BE78 /* LoopKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; - A9E675EC22713F4700E25293 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1F5DAB2B2118CE9300048054 /* Localizable.strings */; }; - A9E675F3227140D800E25293 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9E675F2227140D800E25293 /* CoreData.framework */; }; - A9E675F5227140DD00E25293 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9E675F4227140DD00E25293 /* HealthKit.framework */; }; - A9FD046F24E310D00040F203 /* HKObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FD046E24E310D00040F203 /* HKObject.swift */; }; - A9FD047024E310DD0040F203 /* HKObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FD046E24E310D00040F203 /* HKObject.swift */; }; - B4001CF028CBC200002FB414 /* SingleSelectionCheckList.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4001CEF28CBC200002FB414 /* SingleSelectionCheckList.swift */; }; - B40C43912707408400F5D86C /* DeliveryLimits.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DC64C7D24BF6EBC004A63A1 /* DeliveryLimits.swift */; }; - B40D07CA251BD89D00C1C6D7 /* DateAndDurationSteppableTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B40D07C8251BD89D00C1C6D7 /* DateAndDurationSteppableTableViewCell.xib */; }; - B40D07CB251BD89D00C1C6D7 /* DateAndDurationSteppableTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40D07C9251BD89D00C1C6D7 /* DateAndDurationSteppableTableViewCell.swift */; }; - B4102D3224ABB068005D460B /* DeviceLifecycleProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4102D3124ABB068005D460B /* DeviceLifecycleProgress.swift */; }; - B4102D3324ABB0D8005D460B /* DeviceLifecycleProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4102D3124ABB068005D460B /* DeviceLifecycleProgress.swift */; }; - B41A60AF23D1DB5B00636320 /* TableViewTitleLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B41A60AE23D1DB5B00636320 /* TableViewTitleLabel.swift */; }; - B41A60B223D1DBC700636320 /* UIFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = B41A60B123D1DBC700636320 /* UIFont.swift */; }; - B429D66C24BF7204003E1B4A /* GlucoseTrend.swift in Sources */ = {isa = PBXBuildFile; fileRef = B429D66B24BF7204003E1B4A /* GlucoseTrend.swift */; }; - B429D66E24BF7255003E1B4A /* UIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B429D66D24BF7255003E1B4A /* UIImage.swift */; }; - B42A7472235885B600247B03 /* LoopNotificationUserInfoKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = B42A7471235885B600247B03 /* LoopNotificationUserInfoKey.swift */; }; - B42C950E24A3BD4B00857C73 /* MeasurementFrequencyTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B42C950C24A3BD4B00857C73 /* MeasurementFrequencyTableViewController.swift */; }; - B42C951924A508CE00857C73 /* DeviceStatusHighlight.swift in Sources */ = {isa = PBXBuildFile; fileRef = B42C94FD24A2A2B000857C73 /* DeviceStatusHighlight.swift */; }; - B42C951B24A63B8100857C73 /* DeviceStatusHighlight.swift in Sources */ = {isa = PBXBuildFile; fileRef = B42C94FD24A2A2B000857C73 /* DeviceStatusHighlight.swift */; }; - B43DA43F24D49AA400CAFF4E /* GuidanceColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43DA43E24D49AA400CAFF4E /* GuidanceColors.swift */; }; - B43DA44224D9CD8500CAFF4E /* Environment+Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = B45AF6EF24D4355A00EEAA4D /* Environment+Colors.swift */; }; - B455F31825FBEC5F000ED456 /* SuspendThresholdEditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B455F2A125FBE985000ED456 /* SuspendThresholdEditorViewModel.swift */; }; - B455F35625FC0284000ED456 /* CorrectionRangeOverridesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B455F35525FC0284000ED456 /* CorrectionRangeOverridesTests.swift */; }; - B455F3A425FF7FF0000ED456 /* CorrectionRangeOverridesEditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B455F3A325FF7FF0000ED456 /* CorrectionRangeOverridesEditorViewModel.swift */; }; - B455F48125FF9A8B000ED456 /* InsulinSensitivityScheduleEditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B455F48025FF9A8B000ED456 /* InsulinSensitivityScheduleEditorViewModel.swift */; }; - B455F4D32600DA0B000ED456 /* GlucoseRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = B455F4D22600DA0B000ED456 /* GlucoseRange.swift */; }; - B455F4DF2600E0A8000ED456 /* GlucoseRangeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B455F4DE2600E0A8000ED456 /* GlucoseRangeTests.swift */; }; - B455F4FE2600E5EE000ED456 /* GlucoseRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = B455F4D22600DA0B000ED456 /* GlucoseRange.swift */; }; - B45774352562CCC6004B9466 /* SupportedRangeTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B45774342562CCC6004B9466 /* SupportedRangeTableViewController.swift */; }; - B46B62A723FEFE4D001E69BA /* InstructionList.swift in Sources */ = {isa = PBXBuildFile; fileRef = B46B62A623FEFE4D001E69BA /* InstructionList.swift */; }; - B46B62A923FF05F8001E69BA /* LabeledNumberInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = B46B62A823FF05F8001E69BA /* LabeledNumberInput.swift */; }; - B46B62AB23FF0822001E69BA /* LabeledValueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B46B62AA23FF0822001E69BA /* LabeledValueView.swift */; }; - B46B62AD23FF0A87001E69BA /* LabeledDateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B46B62AC23FF0A87001E69BA /* LabeledDateView.swift */; }; - B46B62AF23FF0BF6001E69BA /* SectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B46B62AE23FF0BF6001E69BA /* SectionHeader.swift */; }; - B46B62B123FF0CA6001E69BA /* DescriptiveText.swift in Sources */ = {isa = PBXBuildFile; fileRef = B46B62B023FF0CA6001E69BA /* DescriptiveText.swift */; }; - B46B62B323FF0E62001E69BA /* SelectableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B46B62B223FF0E62001E69BA /* SelectableLabel.swift */; }; - B46E095725F7E5910025A04D /* GlucoseRangeScheduleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B46E095625F7E5910025A04D /* GlucoseRangeScheduleTests.swift */; }; - B46E096D25F80D6C0025A04D /* OverrideTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B46E096C25F80D6C0025A04D /* OverrideTests.swift */; }; - B46FA3F3253F00DC00D993E2 /* momentum_effect_impossible_rising_glucose_output.json in Resources */ = {isa = PBXBuildFile; fileRef = B46FA3F1253F00DC00D993E2 /* momentum_effect_impossible_rising_glucose_output.json */; }; - B46FA3F4253F00DD00D993E2 /* momentum_effect_impossible_rising_glucose_input.json in Resources */ = {isa = PBXBuildFile; fileRef = B46FA3F2253F00DC00D993E2 /* momentum_effect_impossible_rising_glucose_input.json */; }; - B47ECFD625DC22D20024A54D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B47ECFD525DC22D20024A54D /* Assets.xcassets */; }; - B4A2AAB1240830A30066563F /* LabeledTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4A2AAB0240830A30066563F /* LabeledTextField.swift */; }; - B4A2AAB3240832350066563F /* MultipleSelectionList.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4A2AAB2240832350066563F /* MultipleSelectionList.swift */; }; - B4B7C1612603F241007379F6 /* InsulinSensitivityScheduleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B7C1602603F241007379F6 /* InsulinSensitivityScheduleTests.swift */; }; - B4B7C1772603F5F6007379F6 /* HKUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B7C1762603F5F6007379F6 /* HKUnitTests.swift */; }; - B4B7C1BC2604E3FC007379F6 /* CorrectionRangeScheduleEditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B7C1BB2604E3FC007379F6 /* CorrectionRangeScheduleEditorViewModel.swift */; }; - B4B85FCD24A2312000A296A3 /* GlucoseRangeCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B85FCC24A2312000A296A3 /* GlucoseRangeCategory.swift */; }; - B4B85FD024A2318A00A296A3 /* GlucoseRangeCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B85FCC24A2312000A296A3 /* GlucoseRangeCategory.swift */; }; - B4C004D12416961300B40429 /* GuidePage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4C004B3241085DB00B40429 /* GuidePage.swift */; }; - B4C004D22416961300B40429 /* GuideNavigationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4C004B4241085DC00B40429 /* GuideNavigationButton.swift */; }; - B4C004D32416961300B40429 /* ActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4C004B2241085DB00B40429 /* ActionButton.swift */; }; - B4CEE2A5256E912A0093111B /* DoseProgressTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4CEE2A4256E91290093111B /* DoseProgressTests.swift */; }; - B4CEE2E3257129780093111B /* UnfinalizedDoseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4CEE2E2257129780093111B /* UnfinalizedDoseTests.swift */; }; - B4CEE2E5257129780093111B /* MockKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 89D2047221CC7BD7001238CC /* MockKit.framework */; }; - B4D3D4AD25B8A94E0085BA0F /* DisplayGlucoseUnitObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B1162D25AF3A40006428DE /* DisplayGlucoseUnitObserver.swift */; }; - B4D4C20D25F95A8700DA809D /* DisplayGlucoseUnitObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4D4C20C25F95A8700DA809D /* DisplayGlucoseUnitObservable.swift */; }; - C109240F286A4AD500FAD2B8 /* AutomaticDosingStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C109240E286A4AD500FAD2B8 /* AutomaticDosingStrategy.swift */; }; - C1092410286A4ADB00FAD2B8 /* AutomaticDosingStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C109240E286A4AD500FAD2B8 /* AutomaticDosingStrategy.swift */; }; - C140DFFF260276BF000A4FF7 /* ManualBolusRecommendation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C140DFFE260276BF000A4FF7 /* ManualBolusRecommendation.swift */; }; - C140E0522602908A000A4FF7 /* SettingsPresentationMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = C140E0512602908A000A4FF7 /* SettingsPresentationMode.swift */; }; - C1475B33264C30800040C7B1 /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43BA7154201E484D0058961E /* LoopKitUI.framework */; }; - C14A7E7E295F43AB00CD87B4 /* ConfigurationPageScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14A7E7D295F43AB00CD87B4 /* ConfigurationPageScrollView.swift */; }; - C15E994429C67866004AB926 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4B67E2CC289B4EDB002D92AF /* Localizable.strings */; }; - C15E994629C6790A004AB926 /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = C15E994529C6790A004AB926 /* LocalizedString.swift */; }; - C164A56022F14C73000E3FA5 /* UnfinalizedDose.swift in Sources */ = {isa = PBXBuildFile; fileRef = C164A55F22F14C73000E3FA5 /* UnfinalizedDose.swift */; }; - C164A56422F21081000E3FA5 /* MockPumpManagerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C164A56322F21081000E3FA5 /* MockPumpManagerState.swift */; }; - C168CA7A280DD00F002BD2A7 /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = C168CA77280DD00F002BD2A7 /* Model.xcdatamodeld */; }; - C16DA83F22E8D88F008624C2 /* LoopPluginBundleKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = C16DA83E22E8D88F008624C2 /* LoopPluginBundleKey.swift */; }; - C16DA84522E9330A008624C2 /* LoopUIPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = C16DA84422E9330A008624C2 /* LoopUIPlugin.swift */; }; - C17F39C123CD24A000FA1113 /* DeviceLog.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = C17F39BF23CD24A000FA1113 /* DeviceLog.xcdatamodeld */; }; - C17F39C723CD256000FA1113 /* PersistentDeviceLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F39C623CD256000FA1113 /* PersistentDeviceLog.swift */; }; - C17F39C923CD269200FA1113 /* DeviceLogEntryType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F39C823CD269200FA1113 /* DeviceLogEntryType.swift */; }; - C17F39CA23CD2D2000FA1113 /* PersistentDeviceLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F39C623CD256000FA1113 /* PersistentDeviceLog.swift */; }; - C17F39CB23CD2D2F00FA1113 /* DeviceLogEntryType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F39C823CD269200FA1113 /* DeviceLogEntryType.swift */; }; - C17F39CC23CD2D3E00FA1113 /* DeviceLog.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = C17F39BF23CD24A000FA1113 /* DeviceLog.xcdatamodeld */; }; - C17F39D023CE34B100FA1113 /* StoredDeviceLogEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F39CF23CE34B100FA1113 /* StoredDeviceLogEntry.swift */; }; - C17F39D123CE34FD00FA1113 /* StoredDeviceLogEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17F39CF23CE34B100FA1113 /* StoredDeviceLogEntry.swift */; }; - C1814B84225B9ED5008D2D8E /* LoopNotificationCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1814B83225B9ED5008D2D8E /* LoopNotificationCategory.swift */; }; - C1814B8C226371DF008D2D8E /* WeakSynchronizedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1814B8B226371DF008D2D8E /* WeakSynchronizedDelegate.swift */; }; - C187337E29B9481500519CDF /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187337D29B9481500519CDF /* LocalizedString.swift */; }; - C187338A29B9486200519CDF /* Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187337F29B9486100519CDF /* Collection.swift */; }; - C187338B29B9486200519CDF /* Comparable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338029B9486100519CDF /* Comparable.swift */; }; - C187338C29B9486200519CDF /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338129B9486100519CDF /* HKUnit.swift */; }; - C187338D29B9486200519CDF /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338229B9486200519CDF /* TimeInterval.swift */; }; - C187338E29B9486200519CDF /* ClosedRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338329B9486200519CDF /* ClosedRange.swift */; }; - C187338F29B9486200519CDF /* NumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338429B9486200519CDF /* NumberFormatter.swift */; }; - C187339029B9486200519CDF /* Guardrail+Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338529B9486200519CDF /* Guardrail+Settings.swift */; }; - C187339129B9486200519CDF /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338629B9486200519CDF /* Data.swift */; }; - C187339229B9486200519CDF /* MutableCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338729B9486200519CDF /* MutableCollection.swift */; }; - C187339329B9486200519CDF /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338829B9486200519CDF /* OSLog.swift */; }; - C187339429B9486200519CDF /* DateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338929B9486200519CDF /* DateFormatter.swift */; }; - C187339829B9488300519CDF /* Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187339529B9488300519CDF /* Sequence.swift */; }; - C187339929B9488300519CDF /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187339629B9488300519CDF /* TimeZone.swift */; }; - C187339A29B9488300519CDF /* UUID.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187339729B9488300519CDF /* UUID.swift */; }; - C187339C29B948D800519CDF /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187339B29B948D800519CDF /* Data.swift */; }; - C187339E29B948F200519CDF /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187339D29B948F200519CDF /* HKUnit.swift */; }; - C18733AA29B9492300519CDF /* NumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187339F29B9492200519CDF /* NumberFormatter.swift */; }; - C18733AB29B9492300519CDF /* UITableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733A029B9492200519CDF /* UITableViewCell.swift */; }; - C18733AC29B9492300519CDF /* UITextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733A129B9492200519CDF /* UITextField.swift */; }; - C18733AD29B9492300519CDF /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733A229B9492200519CDF /* TimeZone.swift */; }; - C18733AE29B9492300519CDF /* NSTimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733A329B9492200519CDF /* NSTimeInterval.swift */; }; - C18733AF29B9492300519CDF /* Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733A429B9492200519CDF /* Collection.swift */; }; - C18733B029B9492300519CDF /* NibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733A529B9492200519CDF /* NibLoadable.swift */; }; - C18733B129B9492300519CDF /* Math.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733A629B9492300519CDF /* Math.swift */; }; - C18733B229B9492300519CDF /* Comparable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733A729B9492300519CDF /* Comparable.swift */; }; - C18733B329B9492300519CDF /* IdentifiableClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733A829B9492300519CDF /* IdentifiableClass.swift */; }; - C18733B429B9492300519CDF /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733A929B9492300519CDF /* HKUnit.swift */; }; - C18733B629B9495400519CDF /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733B529B9495400519CDF /* LocalizedString.swift */; }; - C18733B829B949FF00519CDF /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733B729B949FF00519CDF /* Data.swift */; }; - C18733BC29B94A3700519CDF /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733B929B94A3700519CDF /* HKUnit.swift */; }; - C18733BD29B94A3700519CDF /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733BA29B94A3700519CDF /* TimeInterval.swift */; }; - C18733BE29B94A3700519CDF /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733BB29B94A3700519CDF /* TimeZone.swift */; }; - C18733C529B94A6400519CDF /* NumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733BF29B94A6300519CDF /* NumberFormatter.swift */; }; - C18733C629B94A6400519CDF /* Comparable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733C029B94A6300519CDF /* Comparable.swift */; }; - C18733C729B94A6400519CDF /* IdentifiableClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733C129B94A6300519CDF /* IdentifiableClass.swift */; }; - C18733C829B94A6400519CDF /* NibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733C229B94A6300519CDF /* NibLoadable.swift */; }; - C18733C929B94A6400519CDF /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733C329B94A6300519CDF /* TimeInterval.swift */; }; - C18733CA29B94A6400519CDF /* UITableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733C429B94A6300519CDF /* UITableViewCell.swift */; }; - C18733CC29B94A7A00519CDF /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733CB29B94A7A00519CDF /* LocalizedString.swift */; }; - C18733CE29B94B1700519CDF /* IdentifiableClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733CD29B94B1700519CDF /* IdentifiableClass.swift */; }; - C18733D029B94B3300519CDF /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733CF29B94B3300519CDF /* TimeInterval.swift */; }; - C18733D229B94B8E00519CDF /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18733D129B94B8E00519CDF /* HKUnit.swift */; }; - C188B83422CC16AC0051760A /* InsulinSensitivityScheduleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C188B83322CC16AC0051760A /* InsulinSensitivityScheduleViewController.swift */; }; - C191D26325B3815000C26C0B /* AutomaticDoseRecommendation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C191D26225B3815000C26C0B /* AutomaticDoseRecommendation.swift */; }; - C1A174EC23DEAD670034DF11 /* DeviceLogEntry+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F8403723DB84B700673141 /* DeviceLogEntry+CoreDataClass.swift */; }; - C1A174ED23DEAD6A0034DF11 /* DeviceLogEntry+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F8403823DB84B700673141 /* DeviceLogEntry+CoreDataProperties.swift */; }; - C1BECA93285902F5008075C4 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D8FDCB1C728FDF0073BE78 /* LoopKit.framework */; }; - C1CAB9E926A3254800A57273 /* StoredInsulinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CAB9E826A3254800A57273 /* StoredInsulinModel.swift */; }; - C1CB895925C8E7D900782BAC /* Modelv1v4.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = C1E84B8425C62FB100623C08 /* Modelv1v4.xcmappingmodel */; }; - C1CCF1062858F07A0035389C /* SwiftCharts in Frameworks */ = {isa = PBXBuildFile; productRef = C1CCF1052858F07A0035389C /* SwiftCharts */; }; - C1CCF1082858F1E10035389C /* SwiftCharts in Frameworks */ = {isa = PBXBuildFile; productRef = C1CCF1072858F1E10035389C /* SwiftCharts */; }; - C1CEBFD229BA9D43007FD8A3 /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338229B9486200519CDF /* TimeInterval.swift */; }; - C1CEBFD329BA9D4F007FD8A3 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338829B9486200519CDF /* OSLog.swift */; }; - C1CEBFD429BA9D57007FD8A3 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338129B9486100519CDF /* HKUnit.swift */; }; - C1CEBFD529BA9D62007FD8A3 /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187337D29B9481500519CDF /* LocalizedString.swift */; }; - C1CEBFD629BA9D6C007FD8A3 /* Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187337F29B9486100519CDF /* Collection.swift */; }; - C1CEBFD729BA9D73007FD8A3 /* MutableCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338729B9486200519CDF /* MutableCollection.swift */; }; - C1CEBFD829BA9D7A007FD8A3 /* Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187339529B9488300519CDF /* Sequence.swift */; }; - C1CEBFD929BA9D81007FD8A3 /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187339629B9488300519CDF /* TimeZone.swift */; }; - C1CEBFDA29BA9D88007FD8A3 /* ClosedRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338329B9486200519CDF /* ClosedRange.swift */; }; - C1CEBFDB29BA9D8F007FD8A3 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338629B9486200519CDF /* Data.swift */; }; - C1CEBFDC29BA9D9D007FD8A3 /* NumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187338429B9486200519CDF /* NumberFormatter.swift */; }; - C1D56376296B3F5E00BA15EC /* reservoir_for_iob_missing.json in Resources */ = {isa = PBXBuildFile; fileRef = C1D56375296B3F5E00BA15EC /* reservoir_for_iob_missing.json */; }; - C1D7162129C75DC700B5AB3B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C1D7162329C75DC700B5AB3B /* Localizable.strings */; }; - C1DD512B259FD8A600DE27AE /* InsulinTypeChooser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1742345259CD3ED00399C9D /* InsulinTypeChooser.swift */; }; - C1DD517825A016E700DE27AE /* InsulinTypeSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1DD515A259FE3AB00DE27AE /* InsulinTypeSetting.swift */; }; - C1DE4C2125A253BD007065F8 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1DE4C2025A253BD007065F8 /* Color.swift */; }; - C1E0EEF624EB26D800086510 /* DeliveryUncertaintyRecoveryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E0EEF524EB26D800086510 /* DeliveryUncertaintyRecoveryView.swift */; }; - C1E4B305242E98E900E70CCB /* ProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E4B303242E98E900E70CCB /* ProgressView.swift */; }; - C1E4B306242E98E900E70CCB /* ProgressIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E4B304242E98E900E70CCB /* ProgressIndicatorView.swift */; }; - C1E4B308242E995200E70CCB /* ActivityIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E4B307242E995200E70CCB /* ActivityIndicator.swift */; }; - C1E4B30A242E99A800E70CCB /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E4B309242E99A800E70CCB /* Image.swift */; }; - C1E7035D24FFFA5C00DAB534 /* CollectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E7035C24FFFA5C00DAB534 /* CollectionTests.swift */; }; - C1E84B8525C62FB100623C08 /* Modelv1v4.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = C1E84B8425C62FB100623C08 /* Modelv1v4.xcmappingmodel */; }; - C1E94D3B28170DAC00262A6E /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = C168CA77280DD00F002BD2A7 /* Model.xcdatamodeld */; }; - C1F8403923DB84B700673141 /* DeviceLogEntry+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F8403723DB84B700673141 /* DeviceLogEntry+CoreDataClass.swift */; }; - C1F8403A23DB84B700673141 /* DeviceLogEntry+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F8403823DB84B700673141 /* DeviceLogEntry+CoreDataProperties.swift */; }; - C1FAC06328C7B0A100754AE2 /* reservoir_iob_test.json in Resources */ = {isa = PBXBuildFile; fileRef = C1FAC06228C7B0A100754AE2 /* reservoir_iob_test.json */; }; - C1FAEC1D264AD6B400A3250B /* DeviceStatusBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1FAEC1C264AD6B400A3250B /* DeviceStatusBadge.swift */; }; - C1FAEC1F264AE12700A3250B /* UIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B47ECF8725DC20810024A54D /* UIImage.swift */; }; - C1FAEC21264AEEA300A3250B /* UIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1FAEC20264AEEA300A3250B /* UIImage.swift */; }; - E9077D2724ACD59F0066A88D /* InformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9077D2624ACD59F0066A88D /* InformationView.swift */; }; - E9077D2A24ACDE2C0066A88D /* CorrectionRangeInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9077D2924ACDE2C0066A88D /* CorrectionRangeInformationView.swift */; }; - E9086B2924B39EDC0062F5C8 /* ChartsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9086B2824B39EDC0062F5C8 /* ChartsTableViewController.swift */; }; - E9086B2D24B3A4AC0062F5C8 /* ChartsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9086B2C24B3A4AC0062F5C8 /* ChartsManager.swift */; }; - E9086B2F24B3A5080062F5C8 /* ChartColorPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9086B2E24B3A5080062F5C8 /* ChartColorPalette.swift */; }; - E9086B3124B3A7270062F5C8 /* ChartTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9086B3024B3A7270062F5C8 /* ChartTableViewCell.swift */; }; - E9086B3524B3A8820062F5C8 /* ChartContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9086B3424B3A8820062F5C8 /* ChartContainerView.swift */; }; - E9086B3924B3CB4B0062F5C8 /* TherapySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9086B3824B3CB4B0062F5C8 /* TherapySettings.swift */; }; - E9086B4524B53CC50062F5C8 /* GlucoseChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9086B4424B53CC50062F5C8 /* GlucoseChart.swift */; }; - E9086B4824B5405E0062F5C8 /* ChartAxisValueDoubleUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9086B4724B5405E0062F5C8 /* ChartAxisValueDoubleUnit.swift */; }; - E9086B4A24B540B70062F5C8 /* DateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9086B4924B540B70062F5C8 /* DateFormatter.swift */; }; - E916F56924AD32F000BE3547 /* CorrectionRangeOverridesEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E916F56824AD32F000BE3547 /* CorrectionRangeOverridesEditor.swift */; }; - E916F56F24AE2FFE00BE3547 /* CorrectionRangeOverrideInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E916F56E24AE2FFE00BE3547 /* CorrectionRangeOverrideInformationView.swift */; }; - E93BA06624A39DBC00C5D7E6 /* DismissibleHostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93BA06524A39DBC00C5D7E6 /* DismissibleHostingController.swift */; }; - E93C86A024C8F6E00073089B /* InsulinModelSelection.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93C869F24C8F6E00073089B /* InsulinModelSelection.swift */; }; - E93C86A224C8F7550073089B /* InsulinModelChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93C86A124C8F7550073089B /* InsulinModelChart.swift */; }; - E93C86A424C8F79C0073089B /* ChartLineModel+LoopKitUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93C86A324C8F79C0073089B /* ChartLineModel+LoopKitUI.swift */; }; - E93C86A624C8F7D90073089B /* ChartSettings+LoopKitUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93C86A524C8F7D90073089B /* ChartSettings+LoopKitUI.swift */; }; - E93C86A824C8F7F70073089B /* InsulinModelChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93C86A724C8F7F60073089B /* InsulinModelChartView.swift */; }; - E93C86B024CF7C470073089B /* TherapySettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93C86AF24CF7C470073089B /* TherapySettingsTests.swift */; }; - E93C86B224D080E00073089B /* CarbRatioInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93C86B124D080E00073089B /* CarbRatioInformationView.swift */; }; - E93C86B624D08CAD0073089B /* InsulinSensitivityInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93C86B524D08CAD0073089B /* InsulinSensitivityInformationView.swift */; }; - E93E865A24DC744300FF40C8 /* effect_from_basal_output_exponential.json in Resources */ = {isa = PBXBuildFile; fileRef = E93E865924DC744300FF40C8 /* effect_from_basal_output_exponential.json */; }; - E93E865C24DC75EF00FF40C8 /* basal_dose_with_expired.json in Resources */ = {isa = PBXBuildFile; fileRef = E93E865B24DC75EF00FF40C8 /* basal_dose_with_expired.json */; }; - E93E865E24DC797A00FF40C8 /* basal_dose_with_delivered.json in Resources */ = {isa = PBXBuildFile; fileRef = E93E865D24DC797A00FF40C8 /* basal_dose_with_delivered.json */; }; - E93E866024DC82A600FF40C8 /* dose_history_with_delivered_units.json in Resources */ = {isa = PBXBuildFile; fileRef = E93E865F24DC82A500FF40C8 /* dose_history_with_delivered_units.json */; }; - E93E866224DC87AE00FF40C8 /* effect_from_history_exponential_delivered_units_output.json in Resources */ = {isa = PBXBuildFile; fileRef = E93E866124DC87AE00FF40C8 /* effect_from_history_exponential_delivered_units_output.json */; }; - E93E866424DCFB6D00FF40C8 /* OverrideHistoryCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93E866324DCFB6D00FF40C8 /* OverrideHistoryCollectionViewCell.swift */; }; - E93E866A24DD05FA00FF40C8 /* OverrideSelectionHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93E866924DD05FA00FF40C8 /* OverrideSelectionHistory.swift */; }; - E94141CE24C8F2950096C326 /* ExponentialInsulinModelPreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D096C0024C24C220078B6B5 /* ExponentialInsulinModelPreset.swift */; }; - E94141D024C8F31C0096C326 /* DeliveryLimitsEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E94141CF24C8F31C0096C326 /* DeliveryLimitsEditor.swift */; }; - E949E38924AFC82F00024DA0 /* DeliveryLimitsInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E949E38824AFC82F00024DA0 /* DeliveryLimitsInformationView.swift */; }; - E949E38F24B3711E00024DA0 /* InsulinModelInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E949E38E24B3711E00024DA0 /* InsulinModelInformationView.swift */; }; - E96175AE24B7BE38008E5080 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = E96175AD24B7BE38008E5080 /* Dictionary.swift */; }; - E96DCB5824AEF50F007117BC /* SuspendThresholdInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E96DCB5724AEF50F007117BC /* SuspendThresholdInformationView.swift */; }; - E96DCB5A24AF74AC007117BC /* SuspendThresholdEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E96DCB5924AF74AC007117BC /* SuspendThresholdEditor.swift */; }; - E96DCB5E24AF7DC7007117BC /* BasalRatesInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E96DCB5D24AF7DC7007117BC /* BasalRatesInformationView.swift */; }; - E99A132E2557548300D3F5B3 /* SegmentedGaugeBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E99A132D2557548300D3F5B3 /* SegmentedGaugeBar.swift */; }; - E9A6D0E828DBCF5800DFF9D9 /* LoopNotificationUserInfoKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = B42A7471235885B600247B03 /* LoopNotificationUserInfoKey.swift */; }; - E9C58A6E24DA65E400487A17 /* HistoricalOverrideDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9C58A6D24DA65E400487A17 /* HistoricalOverrideDetailView.swift */; }; - E9DFB92C24E634E800468917 /* ExpandablePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9DFB92B24E634E800468917 /* ExpandablePicker.swift */; }; - E9DFB92E24E8A75C00468917 /* iob_from_multiple_curves_output.json in Resources */ = {isa = PBXBuildFile; fileRef = E9DFB92D24E8A75C00468917 /* iob_from_multiple_curves_output.json */; }; - E9DFB93024E8CA8500468917 /* LegacyInsulinDeliveryTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9DFB92F24E8CA8500468917 /* LegacyInsulinDeliveryTableViewController.swift */; }; - E9DFB93524E8CD5800468917 /* LegacyInsulinDeliveryTableViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E9DFB93324E8CD5800468917 /* LegacyInsulinDeliveryTableViewController.storyboard */; }; - E9E5E56524D362E900B5DFFE /* dynamic_glucose_effect_none_observed_output.json in Resources */ = {isa = PBXBuildFile; fileRef = E9E5E56124D362E800B5DFFE /* dynamic_glucose_effect_none_observed_output.json */; }; - E9E5E56624D362E900B5DFFE /* dynamic_glucose_effect_never_fully_observed_output.json in Resources */ = {isa = PBXBuildFile; fileRef = E9E5E56224D362E800B5DFFE /* dynamic_glucose_effect_never_fully_observed_output.json */; }; - E9E5E56724D362E900B5DFFE /* dynamic_glucose_effect_partially_observed_output.json in Resources */ = {isa = PBXBuildFile; fileRef = E9E5E56324D362E800B5DFFE /* dynamic_glucose_effect_partially_observed_output.json */; }; - E9E5E56824D362E900B5DFFE /* dynamic_glucose_effect_fully_observed_output.json in Resources */ = {isa = PBXBuildFile; fileRef = E9E5E56424D362E900B5DFFE /* dynamic_glucose_effect_fully_observed_output.json */; }; - E9E5E56A24D5CCE800B5DFFE /* OverrideViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E5E56924D5CCE800B5DFFE /* OverrideViewCell.swift */; }; - E9F54F5E25802D5E0034795E /* InsulinType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9F54F5D25802D5E0034795E /* InsulinType.swift */; }; - E9F54FBA258052130034795E /* InsulinType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9F54F5D25802D5E0034795E /* InsulinType.swift */; }; - E9F54FC62581C50D0034795E /* ExpandableDatePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9F54FC52581C50C0034795E /* ExpandableDatePicker.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 1DEE226A24A676A300693C32 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 43D8FDCA1C728FDF0073BE78; - remoteInfo = LoopKit; - }; - 1DEE230324A6774900693C32 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 430157F61C7EC03B00B64B63; - remoteInfo = "LoopKit Example"; - }; - 4301581B1C7ECB5E00B64B63 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 43D8FDCA1C728FDF0073BE78; - remoteInfo = LoopKit; - }; - 43BA7159201E484D0058961E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 43BA7153201E484D0058961E; - remoteInfo = LoopKitUI; - }; - 43CACE0F22483AC500F90AF5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 89D2047121CC7BD7001238CC; - remoteInfo = MockKit; - }; - 43CACE1122483AC500F90AF5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 89D2048E21CC7C12001238CC; - remoteInfo = MockKitUI; - }; - 43CACE1322483B6100F90AF5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 43D8FDCA1C728FDF0073BE78; - remoteInfo = LoopKit; - }; - 43CACE1522483B6100F90AF5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 892A5D33222F03CB008961AB; - remoteInfo = LoopTestingKit; - }; - 43CACE1722483B7200F90AF5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 43D8FDCA1C728FDF0073BE78; - remoteInfo = LoopKit; - }; - 43D8FDD71C728FDF0073BE78 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 43D8FDCA1C728FDF0073BE78; - remoteInfo = LoopKit; - }; - 892A5D47222F03CB008961AB /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 892A5D33222F03CB008961AB; - remoteInfo = LoopTestingKit; - }; - A9E6757A22713C3F00E25293 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 43BA7153201E484D0058961E; - remoteInfo = LoopKitUI; - }; - A9E6757C22713C3F00E25293 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 89D2047121CC7BD7001238CC; - remoteInfo = MockKit; - }; - B4CEE2E6257129780093111B /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 89D2047121CC7BD7001238CC; - remoteInfo = MockKit; - }; - C1BECA95285902F5008075C4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 43D8FDCA1C728FDF0073BE78; - remoteInfo = LoopKit; - }; - C1E0280B264C47C900EC4DF1 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 43D8FDC21C728FDF0073BE78 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 43BA7153201E484D0058961E; - remoteInfo = LoopKitUI; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 4301581D1C7ECB5E00B64B63 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 892A5D4A222F03CC008961AB /* LoopTestingKit.framework in Embed Frameworks */, - 4301581A1C7ECB5E00B64B63 /* LoopKit.framework in Embed Frameworks */, - 43BA715C201E484D0058961E /* LoopKitUI.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; - C1CCF10A2858F1E10035389C /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 14B33264293ED44C009B8746 /* GlucoseRangeSchedule+SafeBounds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GlucoseRangeSchedule+SafeBounds.swift"; sourceTree = ""; }; - 193F1E422B44C1EE00525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/InsulinKit.strings; sourceTree = ""; }; - 193F1E432B44C1EE00525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - 193F1E442B44C1EF00525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; - 193F1E452B44C1EF00525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; - 1D096BF924C242300078B6B5 /* CheckmarkListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckmarkListItem.swift; sourceTree = ""; }; - 1D096BFF24C24C220078B6B5 /* InsulinModelProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsulinModelProvider.swift; sourceTree = ""; }; - 1D096C0024C24C220078B6B5 /* ExponentialInsulinModelPreset.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExponentialInsulinModelPreset.swift; sourceTree = ""; }; - 1D096C0424C624F70078B6B5 /* InsulinModelSettings+LoopKitUI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "InsulinModelSettings+LoopKitUI.swift"; sourceTree = ""; }; - 1D0E708426BDE3BB00AECF0D /* HKDeviceCodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HKDeviceCodableTests.swift; sourceTree = ""; }; - 1D1065E2282DAEE500026A70 /* VideoView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoView.swift; sourceTree = ""; }; - 1D1065E3282DAEE500026A70 /* WebView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = ""; }; - 1D1065E6282DC3BB00026A70 /* PopoverLink.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PopoverLink.swift; sourceTree = ""; }; - 1D1065E8282DC54700026A70 /* VideoPlayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayView.swift; sourceTree = ""; }; - 1D1438B725633E2100BE8F06 /* GlucoseTherapySettingInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseTherapySettingInformationView.swift; sourceTree = ""; }; - 1D1A019D24B678BF0077D86E /* TherapySettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TherapySettingsView.swift; sourceTree = ""; }; - 1D1FCE2224BD13A2000300A8 /* CorrectionRangeOverridesExpandableSetting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CorrectionRangeOverridesExpandableSetting.swift; sourceTree = ""; }; - 1D1FCE2424BD42EF000300A8 /* TherapySettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TherapySettingsViewModel.swift; sourceTree = ""; }; - 1D1FCE2624BE4DE2000300A8 /* CorrectionRangeOverrides.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CorrectionRangeOverrides.swift; sourceTree = ""; }; - 1D1FCE2824BE4F11000300A8 /* TherapySetting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TherapySetting.swift; sourceTree = ""; }; - 1D1FCE2A24BE704A000300A8 /* TherapySetting+Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TherapySetting+Settings.swift"; sourceTree = ""; }; - 1D24A8D424C896E100AB8DB9 /* Prescription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Prescription.swift; sourceTree = ""; }; - 1D25C22D246A2A1A00E87FA0 /* critical.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = critical.caf; sourceTree = ""; }; - 1D3E2972276031F80041F460 /* ResizeablePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResizeablePicker.swift; sourceTree = ""; }; - 1D498E4624D892B0000627F2 /* Environment+Authenticate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Environment+Authenticate.swift"; sourceTree = ""; }; - 1D60355D24D39ED10095DC2A /* Environment+AppName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Environment+AppName.swift"; sourceTree = ""; }; - 1D63DEA226E94FDF00F46FA5 /* VersionUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionUpdate.swift; sourceTree = ""; }; - 1D640FF524524284008F9755 /* sub.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = sub.caf; sourceTree = ""; }; - 1D67E79C2563001800A82ED6 /* InformationScreens.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = InformationScreens.xcassets; sourceTree = ""; }; - 1D6EAB9024C12C090081249D /* PumpSupportedIncrements.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpSupportedIncrements.swift; sourceTree = ""; }; - 1D70C40C26F01D9F00C62570 /* VersionCheckServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionCheckServiceTests.swift; sourceTree = ""; }; - 1D70F80126C1BEB700D5BE96 /* CoreDataMigrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataMigrationTests.swift; sourceTree = ""; }; - 1D841AAC24577EE10069DBFF /* AlertSoundPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertSoundPlayer.swift; sourceTree = ""; }; - 1D97A33B256F11E00042737E /* View+InsetGroupedListStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+InsetGroupedListStyle.swift"; sourceTree = ""; }; - 1DA649AA2445174400F61E75 /* Alert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = ""; }; - 1DABAD392453615200ACF708 /* IssueAlertTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssueAlertTableViewController.swift; sourceTree = ""; }; - 1DC64C7B24BF6BFD004A63A1 /* CorrectionRangeOverridesExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CorrectionRangeOverridesExtension.swift; sourceTree = ""; }; - 1DC64C7D24BF6EBC004A63A1 /* DeliveryLimits.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeliveryLimits.swift; sourceTree = ""; }; - 1DC9240E2575EF9A004F132A /* QuantityFormatter+Guardrails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "QuantityFormatter+Guardrails.swift"; sourceTree = ""; }; - 1DD1964D248AE88000420876 /* HorizontalSizeClassOverride.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalSizeClassOverride.swift; sourceTree = ""; }; - 1DD65CFE26C476880085CC64 /* Model.sqlite.v1.original */ = {isa = PBXFileReference; lastKnownFileType = file; path = Model.sqlite.v1.original; sourceTree = ""; }; - 1DD9CE9826B8CC2A008B4A46 /* HKDevice+Encodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HKDevice+Encodable.swift"; sourceTree = ""; }; - 1DE35E7924ABEC720086F9AE /* DeviceManagerUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceManagerUI.swift; sourceTree = ""; }; - 1DEE230124A676A300693C32 /* LoopKitHostedTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LoopKitHostedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 1DEE230224A676A300693C32 /* LoopKitHostedTests.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = LoopKitHostedTests.plist; sourceTree = ""; }; - 1DFB99D5245CB2E900DCC8C9 /* AlertTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertTests.swift; sourceTree = ""; }; - 1DFFB987271740EE0075AEAA /* MockSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockSupport.swift; sourceTree = ""; }; - 1F50C322212B20D300C18FAB /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InsulinKit.strings; sourceTree = ""; }; - 1F50C324212B20D300C18FAB /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - 1F50C326212B20D400C18FAB /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - 1F50C329212B20D400C18FAB /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB2C2118CE9300048054 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB322118D2A700048054 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB372118D5A200048054 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InsulinKit.strings; sourceTree = ""; }; - 1F5DAB392118D5A200048054 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB3B2118D5A300048054 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB3E2118D5A300048054 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB402118D5D500048054 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB442118F14600048054 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InsulinKit.strings; sourceTree = ""; }; - 1F5DAB462118F14600048054 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB482118F14700048054 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB4B2118F14700048054 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB4D2118F18E00048054 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB542118F2C700048054 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InsulinKit.strings"; sourceTree = ""; }; - 1F5DAB562118F2C700048054 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - 1F5DAB582118F2C700048054 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - 1F5DAB5B2118F2C700048054 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - 1F5DAB602118F33000048054 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InsulinKit.strings; sourceTree = ""; }; - 1F5DAB622118F33000048054 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB642118F33000048054 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB672118F33100048054 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB6C2118F3C200048054 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InsulinKit.strings; sourceTree = ""; }; - 1F5DAB6E2118F3C200048054 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB702118F3C200048054 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB732118F3C300048054 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB782118F3FB00048054 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/InsulinKit.strings; sourceTree = ""; }; - 1F5DAB7A2118F3FB00048054 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB7C2118F3FC00048054 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - 1F5DAB7F2118F3FC00048054 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - 1FE58790211CFBB7004F24ED /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; - 1FE58794211D0967004F24ED /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; - 430157F71C7EC03B00B64B63 /* LoopKit Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "LoopKit Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 430157F91C7EC03B00B64B63 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 430157FB1C7EC03B00B64B63 /* MasterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = MasterViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; - 430158001C7EC03B00B64B63 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 430158021C7EC03B00B64B63 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 430158051C7EC03B00B64B63 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 430158071C7EC03B00B64B63 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 4301582A1C7ECCEF00B64B63 /* LoopKitExample.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = LoopKitExample.entitlements; sourceTree = ""; }; - 4301582C1C7ECD7A00B64B63 /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; }; - 43026D632132404900A332E2 /* ice_minus_flat_carb_effect_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ice_minus_flat_carb_effect_output.json; sourceTree = ""; }; - 4302F4DE1D4E607B00F0FCAF /* LegacyInsulinDeliveryTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyInsulinDeliveryTableViewController.swift; sourceTree = ""; }; - 4302F4E81D5066F400F0FCAF /* ReservoirValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReservoirValue.swift; sourceTree = ""; }; - 4302F4EA1D50670500F0FCAF /* NewPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewPumpEvent.swift; sourceTree = ""; }; - 4302F4EC1D5068CE00F0FCAF /* PersistedPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersistedPumpEvent.swift; sourceTree = ""; }; - 4303C48B1E29DD4200ADEDC8 /* momentum_effect_duplicate_glucose_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_duplicate_glucose_input.json; sourceTree = ""; }; - 43177D071D37306D0006E908 /* GlucoseRangeOverrideTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = GlucoseRangeOverrideTableViewCell.xib; sourceTree = ""; }; - 43177D091D3732C70006E908 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 43177D0B1D3734040006E908 /* GlucoseRangeOverrideTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseRangeOverrideTableViewCell.swift; sourceTree = ""; }; - 432711371EDE826A00171F6A /* CustomInputTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomInputTextField.swift; sourceTree = ""; }; - 432762731D60505F0083215A /* HKQuantitySample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKQuantitySample.swift; sourceTree = ""; }; - 432CF86620D76AB90066B889 /* SettingsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewCell.swift; sourceTree = ""; }; - 432CF86820D76B320066B889 /* SetupButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupButton.swift; sourceTree = ""; }; - 432CF86A20D76B9C0066B889 /* SetupIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupIndicatorView.swift; sourceTree = ""; }; - 432CF86C20D76C470066B889 /* SwitchTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitchTableViewCell.swift; sourceTree = ""; }; - 432CF86E20D76CCF0066B889 /* GlucoseTrend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseTrend.swift; sourceTree = ""; }; - 432CF87020D76D5A0066B889 /* GlucoseDisplayable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseDisplayable.swift; sourceTree = ""; }; - 432CF87220D774220066B889 /* PumpManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpManager.swift; sourceTree = ""; }; - 4333931E1F32E31C009466DC /* doses_overlay_basal_profile_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = doses_overlay_basal_profile_output.json; sourceTree = ""; }; - 433BC7A620523DB7000B1200 /* NewGlucoseSample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewGlucoseSample.swift; sourceTree = ""; }; - 433BC7A820538D4C000B1200 /* CachedGlucoseObject+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CachedGlucoseObject+CoreDataClass.swift"; sourceTree = ""; }; - 433BC7A920538D4C000B1200 /* CachedGlucoseObject+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CachedGlucoseObject+CoreDataProperties.swift"; sourceTree = ""; }; - 433BC7AC20538FCA000B1200 /* StoredGlucoseSample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredGlucoseSample.swift; sourceTree = ""; }; - 433D705D1EFB29700004EB9F /* FoodTypeShortcutCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FoodTypeShortcutCell.swift; sourceTree = ""; }; - 434113A820F171CB00D05747 /* CachedInsulinDeliveryObject+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CachedInsulinDeliveryObject+CoreDataClass.swift"; sourceTree = ""; }; - 434113A920F171CB00D05747 /* CachedInsulinDeliveryObject+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CachedInsulinDeliveryObject+CoreDataProperties.swift"; sourceTree = ""; }; - 434113AC20F287DC00D05747 /* NSManagedObjectContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSManagedObjectContext.swift; sourceTree = ""; }; - 434113B220F2890800D05747 /* PersistenceControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistenceControllerTests.swift; sourceTree = ""; }; - 434113B420F2BDB500D05747 /* CachedInsulinDeliveryObjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedInsulinDeliveryObjectTests.swift; sourceTree = ""; }; - 434113B720F2BDE800D05747 /* PersistenceControllerTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistenceControllerTestCase.swift; sourceTree = ""; }; - 434113BB20F2C56100D05747 /* CachedGlucoseObjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedGlucoseObjectTests.swift; sourceTree = ""; }; - 434113BD20F2C72000D05747 /* CachedCarbObjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedCarbObjectTests.swift; sourceTree = ""; }; - 4343951E205EED1F0056DC37 /* counteraction_effect_falling_glucose_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = counteraction_effect_falling_glucose_output.json; sourceTree = ""; }; - 43439520205F2D910056DC37 /* counteraction_effect_falling_glucose_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = counteraction_effect_falling_glucose_input.json; sourceTree = ""; }; - 4346D1FB1C79481E00ABAFE3 /* NSUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSUserDefaults.swift; sourceTree = ""; }; - 434872781CB6256500E55D75 /* reconcile_history_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = reconcile_history_input.json; sourceTree = ""; }; - 4348727C1CB626E500E55D75 /* reconcile_history_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = reconcile_history_output.json; sourceTree = ""; }; - 434A01CF1F019D9100938125 /* DateAndDurationTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DateAndDurationTableViewCell.xib; sourceTree = ""; }; - 434C5F9B2098352500B2FD1A /* QuantityFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuantityFormatter.swift; sourceTree = ""; }; - 434C5F9F209ABD4700B2FD1A /* QuantityFormatterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuantityFormatterTests.swift; sourceTree = ""; }; - 434FB6471D70096A007B9C70 /* reservoir_history_with_continuity_holes.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = reservoir_history_with_continuity_holes.json; sourceTree = ""; }; - 434FB6491D712158007B9C70 /* CommandResponseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommandResponseViewController.swift; sourceTree = ""; }; - 434FF1EF1CF29451000DB779 /* TextFieldTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TextFieldTableViewCell.xib; sourceTree = ""; }; - 434FF1F01CF29451000DB779 /* TextFieldTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldTableViewCell.swift; sourceTree = ""; }; - 434FF1F31CF294A9000DB779 /* TextFieldTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldTableViewController.swift; sourceTree = ""; }; - 4352A73B20DECF0600CAC200 /* CGMManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGMManager.swift; sourceTree = ""; }; - 4353D16E203D104F007B4ECD /* CarbStoreError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbStoreError.swift; sourceTree = ""; }; - 4353D172203D3E7E007B4ECD /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; - 4359E74D1EEA1FBC0022EF0C /* FoodEmojiDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FoodEmojiDataSource.swift; sourceTree = ""; }; - 4359E74F1EED04330022EF0C /* ice_35_min_partial_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ice_35_min_partial_output.json; sourceTree = ""; }; - 435D2924205F3A670026F401 /* counteraction_effect_falling_glucose_almost_duplicates_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = counteraction_effect_falling_glucose_almost_duplicates_input.json; sourceTree = ""; }; - 435D2926205F3C750026F401 /* counteraction_effect_falling_glucose_double_entries._input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = counteraction_effect_falling_glucose_double_entries._input.json; sourceTree = ""; }; - 435D2927205F3C750026F401 /* momentum_effect_rising_glucose_double_entries_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_rising_glucose_double_entries_input.json; sourceTree = ""; }; - 435D292A205F46180026F401 /* counteraction_effect_falling_glucose_almost_duplicates_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = counteraction_effect_falling_glucose_almost_duplicates_output.json; sourceTree = ""; }; - 435D292C205F48750026F401 /* counteraction_effect_falling_glucose_insulin.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = counteraction_effect_falling_glucose_insulin.json; sourceTree = ""; }; - 435F355D1C9CD16A00C204D2 /* NSUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSUserDefaults.swift; sourceTree = ""; }; - 435F35601C9CD25F00C204D2 /* DeviceDataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceDataManager.swift; sourceTree = ""; }; - 4369F08E208859E6000E3E45 /* PaddedTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaddedTextField.swift; sourceTree = ""; }; - 4369F091208B0DFF000E3E45 /* DateAndDurationTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateAndDurationTableViewCell.swift; sourceTree = ""; }; - 4369F093208BA001000E3E45 /* TextButtonTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextButtonTableViewCell.swift; sourceTree = ""; }; - 4378B6421ED55E81000AE785 /* suspend_dose.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = suspend_dose.json; sourceTree = ""; }; - 4378B6441ED55F8C000AE785 /* suspend_dose_reconciled_normalized_iob.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = suspend_dose_reconciled_normalized_iob.json; sourceTree = ""; }; - 4378B6451ED55F8C000AE785 /* suspend_dose_reconciled_normalized.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = suspend_dose_reconciled_normalized.json; sourceTree = ""; }; - 4378B6461ED55F8C000AE785 /* suspend_dose_reconciled.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = suspend_dose_reconciled.json; sourceTree = ""; }; - 4378B64A1ED61965000AE785 /* GlucoseEffectVelocity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseEffectVelocity.swift; sourceTree = ""; }; - 4378B64C1ED61C22000AE785 /* AbsorbedCarbValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AbsorbedCarbValue.swift; sourceTree = ""; }; - 4378B64E1ED61C64000AE785 /* CarbValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarbValue.swift; sourceTree = ""; }; - 4378B6501ED62D8D000AE785 /* CarbStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarbStatus.swift; sourceTree = ""; }; - 4379CFE221102A4100AADC79 /* DeviceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceManager.swift; sourceTree = ""; }; - 437AFEE92036A156008C4892 /* CachedCarbObject+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CachedCarbObject+CoreDataClass.swift"; sourceTree = ""; }; - 437AFEEA2036A156008C4892 /* CachedCarbObject+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CachedCarbObject+CoreDataProperties.swift"; sourceTree = ""; }; - 437AFF192039F149008C4892 /* CarbStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbStoreTests.swift; sourceTree = ""; }; - 437AFF1C203A45DB008C4892 /* CacheStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheStore.swift; sourceTree = ""; }; - 437AFF1E203A763F008C4892 /* HKHealthStoreMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HKHealthStoreMock.swift; sourceTree = ""; }; - 437AFF20203AA740008C4892 /* NSManagedObjectContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSManagedObjectContext.swift; sourceTree = ""; }; - 437AFF23203BE402008C4892 /* HKHealthStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HKHealthStore.swift; sourceTree = ""; }; - 437B064D1F2EB35800D95237 /* HKQuantitySample+InsulinKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HKQuantitySample+InsulinKit.swift"; sourceTree = ""; }; - 438207701F2AE9A300886C13 /* InsulinDeliveryStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinDeliveryStore.swift; sourceTree = ""; }; - 439706E822D2E94800C81566 /* BoundSwitchTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoundSwitchTableViewCell.swift; sourceTree = ""; }; - 43971A3F1C8CABFF0013154F /* GlucoseSampleValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseSampleValue.swift; sourceTree = ""; }; - 43971A411C8CAEF20013154F /* momentum_effect_display_only_glucose_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_display_only_glucose_input.json; sourceTree = ""; }; - 439BCD8D1EEDD22900100EAA /* ice_35_min_none_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ice_35_min_none_output.json; sourceTree = ""; }; - 439BCD8F1EEDD2AD00100EAA /* ice_1_hour_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ice_1_hour_output.json; sourceTree = ""; }; - 439BCD911EEDD33F00100EAA /* ice_slow_absorption_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ice_slow_absorption_output.json; sourceTree = ""; }; - 43A0670E1F23CAC700E9E90F /* DoseType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoseType.swift; sourceTree = ""; }; - 43A067121F245A2F00E9E90F /* DoseStoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoseStoreTests.swift; sourceTree = ""; }; - 43A8EC3B210CEEA500A81379 /* CGMManagerUI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGMManagerUI.swift; sourceTree = ""; }; - 43AF1FB11C926CDD00EA2F3D /* HKQuantity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKQuantity.swift; sourceTree = ""; }; - 43B17C88208EEC0B00AC27E9 /* HealthStoreUnitCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HealthStoreUnitCache.swift; sourceTree = ""; }; - 43B99AFB1C744CE300D050F5 /* bolus_dose.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = bolus_dose.json; sourceTree = ""; }; - 43B99AFD1C744E5F00D050F5 /* effect_from_bolus_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = effect_from_bolus_output.json; sourceTree = ""; }; - 43B99AFF1C7450EE00D050F5 /* effect_from_history_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = effect_from_history_output.json; sourceTree = ""; }; - 43B99B011C7451E500D050F5 /* normalized_doses.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = normalized_doses.json; sourceTree = ""; }; - 43B99B031C74538D00D050F5 /* short_basal_dose.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = short_basal_dose.json; sourceTree = ""; }; - 43B99B051C74552300D050F5 /* basal_dose.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = basal_dose.json; sourceTree = ""; }; - 43B99B071C74553900D050F5 /* effect_from_basal_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = effect_from_basal_output.json; sourceTree = ""; }; - 43BA7154201E484D0058961E /* LoopKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LoopKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 43BA7156201E484D0058961E /* LoopKitUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LoopKitUI.h; sourceTree = ""; }; - 43BA7157201E484D0058961E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 43BDD7E71F804ED5005BA15C /* reconcile_resume_before_rewind_input.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = reconcile_resume_before_rewind_input.json; sourceTree = ""; }; - 43BDD7E91F8050C3005BA15C /* reconcile_resume_before_rewind_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = reconcile_resume_before_rewind_output.json; sourceTree = ""; }; - 43C094451CAA1E98001F6403 /* DoseUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoseUnit.swift; sourceTree = ""; }; - 43C27D921E3C4E7D00613CE1 /* momentum_effect_mixed_provenance_glucose_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_mixed_provenance_glucose_input.json; sourceTree = ""; }; - 43C98059212BDEE4003B5D17 /* ice_minus_carb_effect_with_gaps_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ice_minus_carb_effect_with_gaps_output.json; sourceTree = ""; }; - 43C9805B212D216A003B5D17 /* GlucoseChange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseChange.swift; sourceTree = ""; }; - 43CACE0D2247F89100F90AF5 /* WeakSynchronizedSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakSynchronizedSet.swift; sourceTree = ""; }; - 43CB51B0211EB16C00DB9B4A /* NSUserActivity+CarbKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSUserActivity+CarbKit.swift"; sourceTree = ""; }; - 43CE7CDF1CA9E8B0003CC1B0 /* iob_from_bolus_240min_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = iob_from_bolus_240min_output.json; sourceTree = ""; }; - 43CE7CE11CA9EA1A003CC1B0 /* iob_from_bolus_120min_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = iob_from_bolus_120min_output.json; sourceTree = ""; }; - 43CE7CE31CA9EB1E003CC1B0 /* iob_from_bolus_180min_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = iob_from_bolus_180min_output.json; sourceTree = ""; }; - 43CE7CE51CA9EBD2003CC1B0 /* iob_from_bolus_300min_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = iob_from_bolus_300min_output.json; sourceTree = ""; }; - 43CE7CE71CA9EC1F003CC1B0 /* iob_from_bolus_312min_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = iob_from_bolus_312min_output.json; sourceTree = ""; }; - 43CE7CE91CA9EC50003CC1B0 /* iob_from_bolus_360min_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = iob_from_bolus_360min_output.json; sourceTree = ""; }; - 43CE7CEB1CA9EC88003CC1B0 /* iob_from_bolus_420min_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = iob_from_bolus_420min_output.json; sourceTree = ""; }; - 43CE7CED1CA9F2CF003CC1B0 /* normalize_edge_case_doses_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = normalize_edge_case_doses_input.json; sourceTree = ""; }; - 43CE7CEF1CA9F32C003CC1B0 /* normalize_edge_case_doses_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = normalize_edge_case_doses_output.json; sourceTree = ""; }; - 43D8FDCB1C728FDF0073BE78 /* LoopKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LoopKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 43D8FDCE1C728FDF0073BE78 /* LoopKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LoopKit.h; sourceTree = ""; }; - 43D8FDD01C728FDF0073BE78 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 43D8FDD51C728FDF0073BE78 /* LoopKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LoopKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 43D8FDDA1C728FDF0073BE78 /* LoopKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopKitTests.swift; sourceTree = ""; }; - 43D8FDDC1C728FDF0073BE78 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 43D8FDE51C7290340073BE78 /* BasalRateSchedule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasalRateSchedule.swift; sourceTree = ""; }; - 43D8FDE61C7290350073BE78 /* CarbRatioSchedule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarbRatioSchedule.swift; sourceTree = ""; }; - 43D8FDE71C7290350073BE78 /* DailyQuantitySchedule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DailyQuantitySchedule.swift; sourceTree = ""; }; - 43D8FDE81C7290350073BE78 /* DailyValueSchedule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DailyValueSchedule.swift; sourceTree = ""; }; - 43D8FDE91C7290350073BE78 /* Double.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = ""; }; - 43D8FDEA1C7290350073BE78 /* GlucoseEffect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseEffect.swift; sourceTree = ""; }; - 43D8FDEB1C7290350073BE78 /* GlucoseRangeSchedule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseRangeSchedule.swift; sourceTree = ""; }; - 43D8FDEC1C7290350073BE78 /* GlucoseSchedule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseSchedule.swift; sourceTree = ""; }; - 43D8FDED1C7290350073BE78 /* HealthKitSampleStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HealthKitSampleStore.swift; sourceTree = ""; }; - 43D8FDEF1C7290350073BE78 /* LoopMath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoopMath.swift; sourceTree = ""; }; - 43D8FDF01C7290350073BE78 /* Date.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = ""; }; - 43D8FDF31C7290350073BE78 /* SampleValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SampleValue.swift; sourceTree = ""; }; - 43D8FE041C7290530073BE78 /* DailyQuantityScheduleTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DailyQuantityScheduleTableViewController.swift; sourceTree = ""; }; - 43D8FE051C7290530073BE78 /* DailyValueScheduleTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = DailyValueScheduleTableViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; - 43D8FE061C7290530073BE78 /* GlucoseRangeScheduleTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = GlucoseRangeScheduleTableViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; - 43D8FE071C7290530073BE78 /* GlucoseRangeTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseRangeTableViewCell.swift; sourceTree = ""; }; - 43D8FE081C7290530073BE78 /* GlucoseRangeTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = GlucoseRangeTableViewCell.xib; sourceTree = ""; }; - 43D8FE0A1C7290530073BE78 /* RepeatingScheduleValueTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepeatingScheduleValueTableViewCell.swift; sourceTree = ""; }; - 43D8FE0B1C7290530073BE78 /* RepeatingScheduleValueTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RepeatingScheduleValueTableViewCell.xib; sourceTree = ""; }; - 43D8FE0C1C7290530073BE78 /* SingleValueScheduleTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = SingleValueScheduleTableViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; - 43D8FE1A1C72906E0073BE78 /* BasalRateScheduleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasalRateScheduleTests.swift; sourceTree = ""; }; - 43D8FE1B1C72906E0073BE78 /* NSDateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDateTests.swift; sourceTree = ""; }; - 43D8FE1C1C72906E0073BE78 /* QuantityScheduleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuantityScheduleTests.swift; sourceTree = ""; }; - 43D8FE411C7291900073BE78 /* CarbMathTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarbMathTests.swift; sourceTree = ""; }; - 43D8FE441C7291A60073BE78 /* carb_effect_from_history_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = carb_effect_from_history_input.json; sourceTree = ""; }; - 43D8FE451C7291A60073BE78 /* carb_effect_from_history_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = carb_effect_from_history_output.json; sourceTree = ""; }; - 43D8FE461C7291A60073BE78 /* carbs_on_board_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = carbs_on_board_output.json; sourceTree = ""; }; - 43D8FE4A1C7291BD0073BE78 /* CarbEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarbEntry.swift; sourceTree = ""; }; - 43D8FE4B1C7291BD0073BE78 /* CarbMath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarbMath.swift; sourceTree = ""; }; - 43D8FE4C1C7291BD0073BE78 /* CarbStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarbStore.swift; sourceTree = ""; }; - 43D8FE4D1C7291BD0073BE78 /* HKQuantitySample+CarbKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HKQuantitySample+CarbKit.swift"; sourceTree = ""; }; - 43D8FE4E1C7291BD0073BE78 /* StoredCarbEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoredCarbEntry.swift; sourceTree = ""; }; - 43D8FE591C7291D80073BE78 /* DatePickerTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatePickerTableViewCell.swift; sourceTree = ""; }; - 43D8FE5A1C7291D80073BE78 /* DecimalTextFieldTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecimalTextFieldTableViewCell.swift; sourceTree = ""; }; - 43D8FE5B1C7291D80073BE78 /* NewCarbEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewCarbEntry.swift; sourceTree = ""; }; - 43D8FE661C7292950073BE78 /* read_carb_ratios.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = read_carb_ratios.json; sourceTree = ""; }; - 43D8FE861C72934C0073BE78 /* GlucoseMath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseMath.swift; sourceTree = ""; }; - 43D8FE871C72934C0073BE78 /* GlucoseStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseStore.swift; sourceTree = ""; }; - 43D8FE991C7293D00073BE78 /* GlucoseMathTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseMathTests.swift; sourceTree = ""; }; - 43D8FE9C1C7293FA0073BE78 /* momentum_effect_bouncing_glucose_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_bouncing_glucose_input.json; sourceTree = ""; }; - 43D8FE9D1C7293FA0073BE78 /* momentum_effect_bouncing_glucose_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_bouncing_glucose_output.json; sourceTree = ""; }; - 43D8FE9E1C7293FA0073BE78 /* momentum_effect_falling_glucose_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_falling_glucose_input.json; sourceTree = ""; }; - 43D8FE9F1C7293FA0073BE78 /* momentum_effect_falling_glucose_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_falling_glucose_output.json; sourceTree = ""; }; - 43D8FEA01C7293FA0073BE78 /* momentum_effect_rising_glucose_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_rising_glucose_input.json; sourceTree = ""; }; - 43D8FEA11C7293FA0073BE78 /* momentum_effect_rising_glucose_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_rising_glucose_output.json; sourceTree = ""; }; - 43D8FEA21C7293FA0073BE78 /* momentum_effect_stable_glucose_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_stable_glucose_input.json; sourceTree = ""; }; - 43D8FEA31C7293FA0073BE78 /* momentum_effect_stable_glucose_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_stable_glucose_output.json; sourceTree = ""; }; - 43D8FEC81C7294640073BE78 /* InsulinMathTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsulinMathTests.swift; sourceTree = ""; }; - 43D8FECE1C7294B80073BE78 /* iob_from_doses_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = iob_from_doses_output.json; sourceTree = ""; }; - 43D8FECF1C7294B80073BE78 /* iob_from_reservoir_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = iob_from_reservoir_output.json; sourceTree = ""; }; - 43D8FED01C7294B80073BE78 /* normalized_reservoir_history_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = normalized_reservoir_history_output.json; sourceTree = ""; }; - 43D8FED11C7294B80073BE78 /* reservoir_history_with_rewind_and_prime_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = reservoir_history_with_rewind_and_prime_input.json; sourceTree = ""; }; - 43D8FED21C7294B80073BE78 /* reservoir_history_with_rewind_and_prime_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = reservoir_history_with_rewind_and_prime_output.json; sourceTree = ""; }; - 43D8FEDC1C7294D50073BE78 /* DoseEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoseEntry.swift; sourceTree = ""; }; - 43D8FEDD1C7294D50073BE78 /* DoseStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoseStore.swift; sourceTree = ""; }; - 43D8FEDF1C7294D50073BE78 /* InsulinMath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsulinMath.swift; sourceTree = ""; }; - 43D8FEE21C7294D50073BE78 /* PersistenceController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersistenceController.swift; sourceTree = ""; }; - 43D8FEE31C7294D50073BE78 /* Reservoir.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reservoir.swift; sourceTree = ""; }; - 43D8FEE41C7294D50073BE78 /* Reservoir+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Reservoir+CoreDataProperties.swift"; sourceTree = ""; }; - 43D8FEEE1C7294E90073BE78 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/InsulinKit.storyboard; sourceTree = ""; }; - 43D8FEEF1C7294E90073BE78 /* ErrorBackgroundView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorBackgroundView.swift; sourceTree = ""; }; - 43D8FEF41C7295490073BE78 /* basal.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = basal.json; sourceTree = ""; }; - 43D9888A1C87E47800DA4467 /* GlucoseValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseValue.swift; sourceTree = ""; }; - 43D9888C1C87EBE400DA4467 /* LoopMathTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoopMathTests.swift; sourceTree = ""; }; - 43D988921C87FFA300DA4467 /* glucose_from_effects_no_momentum_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_no_momentum_output.json; sourceTree = ""; }; - 43D988931C87FFA300DA4467 /* glucose_from_effects_momentum_up_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_momentum_up_output.json; sourceTree = ""; }; - 43D988941C87FFA300DA4467 /* glucose_from_effects_momentum_up_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_momentum_up_input.json; sourceTree = ""; }; - 43D988951C87FFA300DA4467 /* glucose_from_effects_momentum_flat_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_momentum_flat_output.json; sourceTree = ""; }; - 43D988961C87FFA300DA4467 /* glucose_from_effects_momentum_flat_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_momentum_flat_input.json; sourceTree = ""; }; - 43D988971C87FFA300DA4467 /* glucose_from_effects_momentum_flat_glucose_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_momentum_flat_glucose_input.json; sourceTree = ""; }; - 43D988981C87FFA300DA4467 /* glucose_from_effects_momentum_down_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_momentum_down_output.json; sourceTree = ""; }; - 43D988991C87FFA300DA4467 /* glucose_from_effects_momentum_down_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_momentum_down_input.json; sourceTree = ""; }; - 43D9889A1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_momentum_blend_output.json; sourceTree = ""; }; - 43D9889B1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_momentum_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_momentum_blend_momentum_input.json; sourceTree = ""; }; - 43D9889C1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_insulin_effect_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_momentum_blend_insulin_effect_input.json; sourceTree = ""; }; - 43D9889D1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_glucose_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_momentum_blend_glucose_input.json; sourceTree = ""; }; - 43D9889E1C87FFA300DA4467 /* glucose_from_effects_insulin_effect_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_insulin_effect_input.json; sourceTree = ""; }; - 43D9889F1C87FFA300DA4467 /* glucose_from_effects_glucose_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_glucose_input.json; sourceTree = ""; }; - 43D988A01C87FFA300DA4467 /* glucose_from_effects_carb_effect_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_carb_effect_input.json; sourceTree = ""; }; - 43DC87B51C8A9567005BC30D /* momentum_effect_incomplete_glucose_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_incomplete_glucose_input.json; sourceTree = ""; }; - 43DC87B71C8AD058005BC30D /* glucose_from_effects_non_zero_glucose_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_non_zero_glucose_input.json; sourceTree = ""; }; - 43DC87B91C8AD0ED005BC30D /* glucose_from_effects_non_zero_insulin_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_non_zero_insulin_input.json; sourceTree = ""; }; - 43DC87BA1C8AD0ED005BC30D /* glucose_from_effects_non_zero_carb_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_non_zero_carb_input.json; sourceTree = ""; }; - 43DC87BD1C8AD41D005BC30D /* glucose_from_effects_non_zero_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = glucose_from_effects_non_zero_output.json; sourceTree = ""; }; - 43DFE27B1CB1D6A600EFBE95 /* PumpEvent+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PumpEvent+CoreDataClass.swift"; sourceTree = ""; }; - 43DFE27C1CB1D6A600EFBE95 /* PumpEvent+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PumpEvent+CoreDataProperties.swift"; sourceTree = ""; }; - 43DFE27F1CB1E12D00EFBE95 /* PumpEventType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpEventType.swift; sourceTree = ""; }; - 43DFE2811CB1FB8500EFBE95 /* InsulinValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsulinValue.swift; sourceTree = ""; }; - 43EBE4471EAC77290073A0B5 /* grouped_by_overlapping_absorption_times_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = grouped_by_overlapping_absorption_times_input.json; sourceTree = ""; }; - 43EBE4481EAC77290073A0B5 /* grouped_by_overlapping_absorption_times_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = grouped_by_overlapping_absorption_times_output.json; sourceTree = ""; }; - 43EBE44B1EAC7F0C0073A0B5 /* grouped_by_overlapping_absorption_times_border_case_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = grouped_by_overlapping_absorption_times_border_case_output.json; sourceTree = ""; }; - 43EBE44C1EAC7F0C0073A0B5 /* grouped_by_overlapping_absorption_times_border_case_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = grouped_by_overlapping_absorption_times_border_case_input.json; sourceTree = ""; }; - 43F5034A21051FCD009FA89A /* KeychainManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainManager.swift; sourceTree = ""; }; - 43F5034C210599CC009FA89A /* AuthenticationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationViewController.swift; sourceTree = ""; }; - 43F5034E210599DF009FA89A /* ValidatingIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidatingIndicatorView.swift; sourceTree = ""; }; - 43F5035421059A8A009FA89A /* ServiceAuthentication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceAuthentication.swift; sourceTree = ""; }; - 43F5035521059A8A009FA89A /* ServiceCredential.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceCredential.swift; sourceTree = ""; }; - 43F5035821059AF7009FA89A /* AuthenticationTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationTableViewCell.swift; sourceTree = ""; }; - 43F5035921059AF7009FA89A /* AuthenticationTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AuthenticationTableViewCell.xib; sourceTree = ""; }; - 43F503622106C761009FA89A /* ServiceAuthenticationUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceAuthenticationUI.swift; sourceTree = ""; }; - 43F89C9E22BDFB10006BB54E /* UIActivityIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIActivityIndicatorView.swift; sourceTree = ""; }; - 43FADDFA1C89679200DDE013 /* HKQuantitySample+GlucoseKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HKQuantitySample+GlucoseKit.swift"; sourceTree = ""; }; - 43FB60E220DCB9E0002B996B /* PumpManagerUI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpManagerUI.swift; sourceTree = ""; }; - 43FB60E420DCBA02002B996B /* SetupTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetupTableViewController.swift; sourceTree = ""; }; - 43FB60E620DCBC55002B996B /* RadioSelectionTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSelectionTableViewController.swift; sourceTree = ""; }; - 43FB60E820DCBE64002B996B /* PumpManagerStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpManagerStatus.swift; sourceTree = ""; }; - 43FB610620DDF19B002B996B /* PumpManagerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpManagerError.swift; sourceTree = ""; }; - 4B67E2CA289B4EDB002D92AF /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = ""; }; - 4B67E2CD289B4EDB002D92AF /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - 7D68A9AF1FE0A3D000522C49 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - 7D68A9CA1FE0A3D200522C49 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InsulinKit.strings; sourceTree = ""; }; - 7D68A9E21FE0A3D300522C49 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - 7D68AAB91FE31A2800522C49 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InsulinKit.strings; sourceTree = ""; }; - 7D68AABC1FE31BE700522C49 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - 7D68AAC61FE31BE900522C49 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - 8907E35821A9D0EC00335852 /* GlucoseEntryTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseEntryTableViewController.swift; sourceTree = ""; }; - 8907E35A21A9D1B200335852 /* SineCurveParametersTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SineCurveParametersTableViewController.swift; sourceTree = ""; }; - 89186C0424BEC9CA0003D0F3 /* SegmentedControlTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentedControlTableViewCell.swift; sourceTree = ""; }; - 89186C0624BF7FC70003D0F3 /* Guardrail+UI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Guardrail+UI.swift"; sourceTree = ""; }; - 89186C0A24BFD6DB0003D0F3 /* DurationPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DurationPicker.swift; sourceTree = ""; }; - 891A3FD02249948A00378B27 /* TemporaryScheduleOverrideHistoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemporaryScheduleOverrideHistoryTests.swift; sourceTree = ""; }; - 891A3FD22249990900378B27 /* DailyValueSchedule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyValueSchedule.swift; sourceTree = ""; }; - 891A3FD4224B047200378B27 /* DailyQuantitySchedule+Override.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DailyQuantitySchedule+Override.swift"; sourceTree = ""; }; - 891A3FD6224BE62100378B27 /* DailyValueScheduleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyValueScheduleTests.swift; sourceTree = ""; }; - 891A3FD8224BEB4500378B27 /* EGPSchedule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EGPSchedule.swift; sourceTree = ""; }; - 891A3FDA224BEC0D00378B27 /* CarbSensitivitySchedule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbSensitivitySchedule.swift; sourceTree = ""; }; - 892155122245C516009112BC /* SegmentedGaugeBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentedGaugeBarView.swift; sourceTree = ""; }; - 892155142245C57E009112BC /* SegmentedGaugeBarLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentedGaugeBarLayer.swift; sourceTree = ""; }; - 892155162245FBEF009112BC /* InsulinSensitivityScalingTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinSensitivityScalingTableViewCell.swift; sourceTree = ""; }; - 892155172245FBEF009112BC /* InsulinSensitivityScalingTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = InsulinSensitivityScalingTableViewCell.xib; sourceTree = ""; }; - 892A5D2D222EF69A008961AB /* MockHUDProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockHUDProvider.swift; sourceTree = ""; }; - 892A5D34222F03CB008961AB /* LoopTestingKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LoopTestingKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 892A5D36222F03CB008961AB /* LoopTestingKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LoopTestingKit.h; sourceTree = ""; }; - 892A5D37222F03CB008961AB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 892A5D51222F03DB008961AB /* TestingDeviceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestingDeviceManager.swift; sourceTree = ""; }; - 892A5D53222F03F9008961AB /* TestingPumpManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestingPumpManager.swift; sourceTree = ""; }; - 892A5D55222F0414008961AB /* TestingCGMManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestingCGMManager.swift; sourceTree = ""; }; - 892A5D62222F6B13008961AB /* SetConstrainedScheduleEntryTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SetConstrainedScheduleEntryTableViewCell.xib; sourceTree = ""; }; - 892A5D63222F6B13008961AB /* SetConstrainedScheduleEntryTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetConstrainedScheduleEntryTableViewCell.swift; sourceTree = ""; }; - 892A5D992231E0E3008961AB /* SettingsNavigationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsNavigationViewController.swift; sourceTree = ""; }; - 892A5D9B2231E118008961AB /* UIAlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIAlertController.swift; sourceTree = ""; }; - 892A5D9D2231E122008961AB /* StateColorPalette.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateColorPalette.swift; sourceTree = ""; }; - 892A5D9F2231E12F008961AB /* CompletionNotifying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompletionNotifying.swift; sourceTree = ""; }; - 892A5DA12231E136008961AB /* HUDProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HUDProvider.swift; sourceTree = ""; }; - 892A5DAD2231E185008961AB /* HUDAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = HUDAssets.xcassets; sourceTree = ""; }; - 892A5DAF2231E191008961AB /* LoadingTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingTableViewCell.swift; sourceTree = ""; }; - 892A5DB02231E191008961AB /* LevelHUDView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LevelHUDView.swift; sourceTree = ""; }; - 892A5DB12231E191008961AB /* LevelMaskView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LevelMaskView.swift; sourceTree = ""; }; - 892A5DB52231E19F008961AB /* ReservoirVolumeHUDView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ReservoirVolumeHUDView.xib; sourceTree = ""; }; - 892A5DB62231E19F008961AB /* ReservoirVolumeHUDView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReservoirVolumeHUDView.swift; sourceTree = ""; }; - 892ADDFF2446C858007CE08C /* Card.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Card.swift; sourceTree = ""; }; - 892F481A21AB2964004D313D /* RandomOutlierTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RandomOutlierTableViewController.swift; sourceTree = ""; }; - 893C9F8B2447DBD900CD4185 /* CardBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardBuilder.swift; sourceTree = ""; }; - 895695F521AA413B00828067 /* DateAndDurationTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateAndDurationTableViewController.swift; sourceTree = ""; }; - 895FE06C22011E9900FCF18A /* OverrideEmojiDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverrideEmojiDataSource.swift; sourceTree = ""; }; - 895FE06D22011E9A00FCF18A /* OverrideSelectionViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = OverrideSelectionViewController.storyboard; sourceTree = ""; }; - 895FE07022011EDD00FCF18A /* EmojiInputController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = EmojiInputController.storyboard; sourceTree = ""; }; - 895FE07222011F0B00FCF18A /* DoubleRangeTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DoubleRangeTableViewCell.xib; sourceTree = ""; }; - 895FE07322011F0B00FCF18A /* EmojiDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmojiDataSource.swift; sourceTree = ""; }; - 895FE07422011F0B00FCF18A /* OverridePresetCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverridePresetCollectionViewCell.swift; sourceTree = ""; }; - 895FE07522011F0B00FCF18A /* LabeledTextFieldTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LabeledTextFieldTableViewCell.swift; sourceTree = ""; }; - 895FE07622011F0B00FCF18A /* OverrideSelectionFooterView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverrideSelectionFooterView.swift; sourceTree = ""; }; - 895FE07922011F0B00FCF18A /* DecimalTextFieldTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DecimalTextFieldTableViewCell.xib; sourceTree = ""; }; - 895FE07A22011F0C00FCF18A /* EmojiInputCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmojiInputCell.swift; sourceTree = ""; }; - 895FE07B22011F0C00FCF18A /* DoubleRangeTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoubleRangeTableViewCell.swift; sourceTree = ""; }; - 895FE07C22011F0C00FCF18A /* OverrideSelectionHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverrideSelectionHeaderView.swift; sourceTree = ""; }; - 895FE07D22011F0C00FCF18A /* LabeledTextFieldTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LabeledTextFieldTableViewCell.xib; sourceTree = ""; }; - 895FE07E22011F0C00FCF18A /* EmojiInputHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmojiInputHeaderView.swift; sourceTree = ""; }; - 895FE08C22011F4800FCF18A /* OverrideSelectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverrideSelectionViewController.swift; sourceTree = ""; }; - 895FE08D22011F4800FCF18A /* AddEditOverrideTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddEditOverrideTableViewController.swift; sourceTree = ""; }; - 895FE08F22011F4800FCF18A /* EmojiInputController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmojiInputController.swift; sourceTree = ""; }; - 89627B15244115A400BEB424 /* CardList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardList.swift; sourceTree = ""; }; - 89627B172441168900BEB424 /* ConfigurationPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationPage.swift; sourceTree = ""; }; - 89653C7F2473527100E1BAA5 /* FractionalQuantityPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FractionalQuantityPicker.swift; sourceTree = ""; }; - 89653C812473592600E1BAA5 /* CarbRatioScheduleEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbRatioScheduleEditor.swift; sourceTree = ""; }; - 89653C8324738D2B00E1BAA5 /* BasalRateScheduleEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasalRateScheduleEditor.swift; sourceTree = ""; }; - 8974AFBF22120D7A0043F01B /* TemporaryScheduleOverrideTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemporaryScheduleOverrideTests.swift; sourceTree = ""; }; - 898B4E74246CCAB50053C484 /* Binding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Binding.swift; sourceTree = ""; }; - 898B4E76246DAE280053C484 /* GlucoseRangePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseRangePicker.swift; sourceTree = ""; }; - 898B4E7A246DC6A70053C484 /* CorrectionRangeScheduleEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CorrectionRangeScheduleEditor.swift; sourceTree = ""; }; - 898B4E7D246DEB920053C484 /* GuardrailConstrainedQuantityRangeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuardrailConstrainedQuantityRangeView.swift; sourceTree = ""; }; - 898C896C24D4BF75002FA994 /* FloatingPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPoint.swift; sourceTree = ""; }; - 898C897024D4C0E4002FA994 /* GuardrailTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuardrailTests.swift; sourceTree = ""; }; - 898E6E64224179300019E459 /* BaseHUDView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseHUDView.swift; sourceTree = ""; }; - 898E6E65224179300019E459 /* BatteryLevelHUDView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BatteryLevelHUDView.xib; sourceTree = ""; }; - 898E6E66224179300019E459 /* BatteryLevelHUDView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatteryLevelHUDView.swift; sourceTree = ""; }; - 898E6E6B224194050019E459 /* UIColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; }; - 898E6E6D2241ED9F0019E459 /* SuspendResumeTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SuspendResumeTableViewCell.swift; sourceTree = ""; }; - 898E6E6F2241EDB70019E459 /* PercentageTextFieldTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PercentageTextFieldTableViewController.swift; sourceTree = ""; }; - 898E6E712241EDC10019E459 /* DateAndDurationTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateAndDurationTableViewController.swift; sourceTree = ""; }; - 899012C0246F1D8F007B88BA /* ExpandableSetting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableSetting.swift; sourceTree = ""; }; - 89904031245B5CA500F1C0A2 /* Deletable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Deletable.swift; sourceTree = ""; }; - 8992426421EC138000EA512B /* UIColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; }; - 8997B4F423727E8A00061132 /* CustomOverrideCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomOverrideCollectionViewCell.swift; sourceTree = ""; }; - 89AB9EC621A4774500351324 /* MockPumpManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPumpManager.swift; sourceTree = ""; }; - 89AB9EC821A4BC2400351324 /* MockCGMManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCGMManager.swift; sourceTree = ""; }; - 89AB9ECA21A4C36200351324 /* MockPumpManager+UI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MockPumpManager+UI.swift"; sourceTree = ""; }; - 89AB9ED521A4DE5F00351324 /* MockPumpManagerSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPumpManagerSettingsViewController.swift; sourceTree = ""; }; - 89AC792C224C781100B8E9BA /* DoseProgressReporter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoseProgressReporter.swift; sourceTree = ""; }; - 89AC792D224C781100B8E9BA /* DoseProgressTimerEstimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoseProgressTimerEstimator.swift; sourceTree = ""; }; - 89AC792E224C781200B8E9BA /* Locked.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Locked.swift; sourceTree = ""; }; - 89AC7934224C783500B8E9BA /* MockDoseProgressEstimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockDoseProgressEstimator.swift; sourceTree = ""; }; - 89AC9DCA24529927004A6B8A /* QuantityPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuantityPicker.swift; sourceTree = ""; }; - 89AC9DCC24529D9B004A6B8A /* TimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TimePicker.swift; path = CardList/TimePicker.swift; sourceTree = ""; }; - 89ADE128226BDB280067222B /* TestingScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestingScenario.swift; sourceTree = ""; }; - 89ADE12A226BDB730067222B /* DateRelativeCarbEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateRelativeCarbEntry.swift; sourceTree = ""; }; - 89ADE12C226BDD190067222B /* DateRelativeBasalEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateRelativeBasalEntry.swift; sourceTree = ""; }; - 89ADE12E226BDED40067222B /* DateRelativeBolusEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateRelativeBolusEntry.swift; sourceTree = ""; }; - 89ADE133226BF0490067222B /* TestingScenarioInstance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestingScenarioInstance.swift; sourceTree = ""; }; - 89ADE135226BF0BE0067222B /* DateRelativeGlucoseSample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateRelativeGlucoseSample.swift; sourceTree = ""; }; - 89AE221F228BC54C00BDFD85 /* TemporaryScheduleOverridePreset.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemporaryScheduleOverridePreset.swift; sourceTree = ""; }; - 89AE2223228BC54C00BDFD85 /* TemporaryScheduleOverride.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemporaryScheduleOverride.swift; sourceTree = ""; }; - 89AE2224228BC54C00BDFD85 /* TemporaryScheduleOverrideSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemporaryScheduleOverrideSettings.swift; sourceTree = ""; }; - 89AE2225228BC54C00BDFD85 /* TemporaryScheduleOverrideHistory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemporaryScheduleOverrideHistory.swift; sourceTree = ""; }; - 89AE222A228BC56A00BDFD85 /* WeakSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeakSet.swift; sourceTree = ""; }; - 89AF78BF2447E285002B4FCC /* CardStackBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardStackBuilder.swift; sourceTree = ""; }; - 89AF78C12447E353002B4FCC /* Splat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Splat.swift; sourceTree = ""; }; - 89AF78C524482268002B4FCC /* ActionButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionButtonStyle.swift; sourceTree = ""; }; - 89B0B2A92453C0AB0063D4A7 /* GuardrailConstraintedQuantityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuardrailConstraintedQuantityView.swift; sourceTree = ""; }; - 89BE75C024649C2E00B145D9 /* ModalHeaderButtonBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalHeaderButtonBar.swift; sourceTree = ""; }; - 89BE75C224649C4C00B145D9 /* RoundedCorners.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedCorners.swift; sourceTree = ""; }; - 89BE75C424649C8100B145D9 /* NewScheduleItemEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewScheduleItemEditor.swift; sourceTree = ""; }; - 89BE75C62464B4A900B145D9 /* Environment+Dismiss.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Environment+Dismiss.swift"; sourceTree = ""; }; - 89BE75CA2464BC2000B145D9 /* AlertContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertContent.swift; sourceTree = ""; }; - 89CA2B37226D4456004D9350 /* DateRelativeQuantity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateRelativeQuantity.swift; sourceTree = ""; }; - 89CAB36A24C9EC25009EE3CE /* DismissibleKeyboardTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DismissibleKeyboardTextField.swift; sourceTree = ""; }; - 89CAB36C24C9EC98009EE3CE /* Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keyboard.swift; sourceTree = ""; }; - 89CAB36E24C9ECCA009EE3CE /* View+KeyboardAware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+KeyboardAware.swift"; sourceTree = ""; }; - 89CAB37024CB4DEC009EE3CE /* WarningView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WarningView.swift; sourceTree = ""; }; - 89CC35D32403450E008FB633 /* ThumbView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbView.swift; sourceTree = ""; }; - 89CCD4F121A87D340068C3FB /* MockCGMDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCGMDataSource.swift; sourceTree = ""; }; - 89CCD4F321A8A2B30068C3FB /* MockCGMManager+UI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MockCGMManager+UI.swift"; sourceTree = ""; }; - 89CCD4F521A8A6A60068C3FB /* MockCGMManagerSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCGMManagerSettingsViewController.swift; sourceTree = ""; }; - 89CCD4F721A8D5500068C3FB /* MockGlucoseProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockGlucoseProvider.swift; sourceTree = ""; }; - 89CCD4F921A911510068C3FB /* PercentageTextFieldTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PercentageTextFieldTableViewController.swift; sourceTree = ""; }; - 89D2046B21C83C3F001238CC /* GlucoseTrendTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseTrendTableViewController.swift; sourceTree = ""; }; - 89D2047221CC7BD7001238CC /* MockKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MockKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 89D2047421CC7BD7001238CC /* MockKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockKit.h; sourceTree = ""; }; - 89D2047521CC7BD7001238CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 89D2048F21CC7C12001238CC /* MockKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MockKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 89D2049121CC7C13001238CC /* MockKitUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockKitUI.h; sourceTree = ""; }; - 89D2049221CC7C13001238CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 89D204D121CC837A001238CC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 89DC540C21B75AE7005A1CE0 /* Collection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = ""; }; - 89E7E60F24D11AB600591386 /* OrientationLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrientationLock.swift; sourceTree = ""; }; - 89F6E30C2449713600CB9E15 /* CardStack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardStack.swift; sourceTree = ""; }; - 89F6E30E244A1A5D00CB9E15 /* Guardrail.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Guardrail.swift; sourceTree = ""; }; - 89F6E310244A1AAB00CB9E15 /* SettingDescription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingDescription.swift; sourceTree = ""; }; - 89F6E312244A1AB500CB9E15 /* GuardrailWarning.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GuardrailWarning.swift; sourceTree = ""; }; - 89F6E313244A1AB600CB9E15 /* GlucoseValuePicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseValuePicker.swift; sourceTree = ""; }; - 89FC688A245A2D670075CF59 /* InsulinSensitivityScheduleEditor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsulinSensitivityScheduleEditor.swift; sourceTree = ""; }; - 89FC688B245A2D670075CF59 /* QuantityScheduleEditor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuantityScheduleEditor.swift; sourceTree = ""; }; - 89FC688C245A2D680075CF59 /* ScheduleItemPicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScheduleItemPicker.swift; sourceTree = ""; }; - 89FC688D245A2D680075CF59 /* ScheduleEditor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScheduleEditor.swift; sourceTree = ""; }; - 89FC688E245A2D680075CF59 /* ScheduleItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScheduleItemView.swift; sourceTree = ""; }; - 9E78433E236653F00016C583 /* ice_35_min_none_piecewiselinear_output.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ice_35_min_none_piecewiselinear_output.json; sourceTree = ""; }; - 9E784340236656770016C583 /* ice_35_min_partial_piecewiselinear_output.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ice_35_min_partial_piecewiselinear_output.json; sourceTree = ""; }; - 9E784342236659BD0016C583 /* ice_slow_absorption_piecewiselinear_output.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ice_slow_absorption_piecewiselinear_output.json; sourceTree = ""; }; - 9E78434423665B5A0016C583 /* ice_35_min_partial_piecewiselinear_adaptiverate_output.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ice_35_min_partial_piecewiselinear_adaptiverate_output.json; sourceTree = ""; }; - A9012EB125BA3861000813AD /* SetupUIResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupUIResult.swift; sourceTree = ""; }; - A91263862790B45300C6C950 /* NewPumpEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPumpEventTests.swift; sourceTree = ""; }; - A912BE28245B9CD500CBE199 /* SettingsObject+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SettingsObject+CoreDataClass.swift"; sourceTree = ""; }; - A912BE2A245B9E8600CBE199 /* SettingsObject+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SettingsObject+CoreDataProperties.swift"; sourceTree = ""; }; - A914472427BF04170054A39D /* normalize_edge_case_doses_mutable_input.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = normalize_edge_case_doses_mutable_input.json; sourceTree = ""; }; - A914472627BF044C0054A39D /* normalize_edge_case_doses_mutable_output.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = normalize_edge_case_doses_mutable_output.json; sourceTree = ""; }; - A919889B2354E5EB00B75EEE /* SettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsStore.swift; sourceTree = ""; }; - A919889E2355016B00B75EEE /* DosingDecisionStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DosingDecisionStore.swift; sourceTree = ""; }; - A932803A2798D63B0091D0A1 /* SyncAlertObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncAlertObject.swift; sourceTree = ""; }; - A933DB8724BF956F009B417A /* CriticalEventLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CriticalEventLog.swift; sourceTree = ""; }; - A935094326E2FAB70030B60D /* GlucoseCondition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseCondition.swift; sourceTree = ""; }; - A935793629A2570300246DED /* CarbAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarbAction.swift; sourceTree = ""; }; - A935793729A2570300246DED /* OverrideCancelAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverrideCancelAction.swift; sourceTree = ""; }; - A935793829A2570400246DED /* OverrideAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverrideAction.swift; sourceTree = ""; }; - A935793929A2570400246DED /* BolusAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusAction.swift; sourceTree = ""; }; - A935793A29A2570400246DED /* Action.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Action.swift; sourceTree = ""; }; - A93761C025ED670200F6BE43 /* BluetoothProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothProvider.swift; sourceTree = ""; }; - A93CA898278D08CC003B5A01 /* PumpAlarmType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpAlarmType.swift; sourceTree = ""; }; - A9498D6E23386C0B00DAA9B9 /* TempBasalRecommendation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TempBasalRecommendation.swift; sourceTree = ""; }; - A9498D7123386C3200DAA9B9 /* LoggingService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggingService.swift; sourceTree = ""; }; - A9498D7323386C3200DAA9B9 /* AnalyticsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnalyticsService.swift; sourceTree = ""; }; - A9498D7423386C3200DAA9B9 /* GlucoseThreshold.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseThreshold.swift; sourceTree = ""; }; - A9498D7523386C3300DAA9B9 /* RemoteDataService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteDataService.swift; sourceTree = ""; }; - A9498D7623386C3300DAA9B9 /* Service.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Service.swift; sourceTree = ""; }; - A9498D8623386CAF00DAA9B9 /* ServiceNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceNavigationController.swift; sourceTree = ""; }; - A9498D8A23386CC700DAA9B9 /* ServiceUI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceUI.swift; sourceTree = ""; }; - A9498D8C23386CD700DAA9B9 /* MockService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockService.swift; sourceTree = ""; }; - A9498D8E23386CE800DAA9B9 /* MockServiceTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockServiceTableViewController.swift; sourceTree = ""; }; - A9498D9023386D0800DAA9B9 /* MockService+UI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MockService+UI.swift"; sourceTree = ""; }; - A95A1D7E2460BBC70079378D /* DosingDecisionObject+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DosingDecisionObject+CoreDataClass.swift"; sourceTree = ""; }; - A95A1D812460BBDC0079378D /* DosingDecisionObject+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DosingDecisionObject+CoreDataProperties.swift"; sourceTree = ""; }; - A95A1D842460CAD50079378D /* CarbValueTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbValueTests.swift; sourceTree = ""; }; - A95A1D862460F1250079378D /* GlucoseValueTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseValueTests.swift; sourceTree = ""; }; - A95A1D882460F8930079378D /* PumpManagerStatusTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpManagerStatusTests.swift; sourceTree = ""; }; - A95A1D8A2460FD620079378D /* BolusRecommendationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusRecommendationTests.swift; sourceTree = ""; }; - A95A1D8C246101760079378D /* DoseEntryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoseEntryTests.swift; sourceTree = ""; }; - A963B277252CE2510062AA12 /* StoredCarbEntryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredCarbEntryTests.swift; sourceTree = ""; }; - A9672B5226E80C060025B0CD /* NewGlucoseSampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewGlucoseSampleTests.swift; sourceTree = ""; }; - A967D94824F99B6A00CDDF8A /* OutputStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutputStream.swift; sourceTree = ""; }; - A96E6C3627B35BC600F81A5B /* AnyCodableEquatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyCodableEquatable.swift; sourceTree = ""; }; - A971C89E23C68B030099BEFC /* GlucoseStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseStoreTests.swift; sourceTree = ""; }; - A971C8A123C6B17D0099BEFC /* SettingsStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsStoreTests.swift; sourceTree = ""; }; - A971C8A323C6B1890099BEFC /* DosingDecisionStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DosingDecisionStoreTests.swift; sourceTree = ""; }; - A985464A251442010099C1A6 /* OutputStreamTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutputStreamTests.swift; sourceTree = ""; }; - A985464E251449FE0099C1A6 /* NotificationSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettings.swift; sourceTree = ""; }; - A985465025144ABA0099C1A6 /* NotificationSettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsTests.swift; sourceTree = ""; }; - A987CD4524A5893500439ADC /* JSONStreamEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONStreamEncoder.swift; sourceTree = ""; }; - A98ED5FD253132A400FD8F70 /* CarbStoreHKQueryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbStoreHKQueryTests.swift; sourceTree = ""; }; - A994B883254241B10039B108 /* InsulinDeliveryStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinDeliveryStoreTests.swift; sourceTree = ""; }; - A99C7372233990D400C80963 /* TempBasalRecommendationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TempBasalRecommendationTests.swift; sourceTree = ""; }; - A99C73762339A67A00C80963 /* GlucoseThresholdTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseThresholdTests.swift; sourceTree = ""; }; - A99C73782339ACDC00C80963 /* ServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceTests.swift; sourceTree = ""; }; - A9A53E2B2714E5BC0050C0B1 /* CodableDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableDevice.swift; sourceTree = ""; }; - A9B0D97D273313EB00D96D93 /* CGMManagerStatusTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGMManagerStatusTests.swift; sourceTree = ""; }; - A9BD318124F4548900994B83 /* Modelv3EntityMigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modelv3EntityMigrationPolicy.swift; sourceTree = ""; }; - A9BFA03D245CCCB9001E4AE3 /* DailyQuantityScheduleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyQuantityScheduleTests.swift; sourceTree = ""; }; - A9CFCA8E2582F9FA00A04932 /* OnboardingUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingUI.swift; sourceTree = ""; }; - A9CFCAA42582FA0400A04932 /* SupportUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportUI.swift; sourceTree = ""; }; - A9DCF2C925B0F38000C89088 /* LoopUIColorPalette.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopUIColorPalette.swift; sourceTree = ""; }; - A9DF02C224F6EEE400B7C988 /* DeviceLogEntryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLogEntryTests.swift; sourceTree = ""; }; - A9DF02C424F6FA5100B7C988 /* PumpEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpEventTests.swift; sourceTree = ""; }; - A9DF02C824F724D900B7C988 /* CriticalEventLogTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CriticalEventLogTests.swift; sourceTree = ""; }; - A9DF02CE24F732FC00B7C988 /* JSONStreamEncoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONStreamEncoderTests.swift; sourceTree = ""; }; - A9DF02D024F7449E00B7C988 /* PersistentDeviceLogTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentDeviceLogTests.swift; sourceTree = ""; }; - A9E068102534D87800BDAB59 /* StoredGlucoseSampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredGlucoseSampleTests.swift; sourceTree = ""; }; - A9E068152534EB8200BDAB59 /* CachedGlucoseObjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedGlucoseObjectTests.swift; sourceTree = ""; }; - A9E0681725350ECC00BDAB59 /* GlucoseStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseStoreTests.swift; sourceTree = ""; }; - A9E1E6A824E1B6700073CA39 /* SyncCarbObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncCarbObject.swift; sourceTree = ""; }; - A9E675F022713F4700E25293 /* LoopKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LoopKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - A9E675F2227140D800E25293 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS.sdk/System/Library/Frameworks/CoreData.framework; sourceTree = DEVELOPER_DIR; }; - A9E675F4227140DD00E25293 /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS.sdk/System/Library/Frameworks/HealthKit.framework; sourceTree = DEVELOPER_DIR; }; - A9FD046E24E310D00040F203 /* HKObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HKObject.swift; sourceTree = ""; }; - B4001CEF28CBC200002FB414 /* SingleSelectionCheckList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleSelectionCheckList.swift; sourceTree = ""; }; - B40D07C8251BD89D00C1C6D7 /* DateAndDurationSteppableTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DateAndDurationSteppableTableViewCell.xib; sourceTree = ""; }; - B40D07C9251BD89D00C1C6D7 /* DateAndDurationSteppableTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateAndDurationSteppableTableViewCell.swift; sourceTree = ""; }; - B4102D3124ABB068005D460B /* DeviceLifecycleProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLifecycleProgress.swift; sourceTree = ""; }; - B41A60AE23D1DB5B00636320 /* TableViewTitleLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewTitleLabel.swift; sourceTree = ""; }; - B41A60B123D1DBC700636320 /* UIFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIFont.swift; sourceTree = ""; }; - B429D66B24BF7204003E1B4A /* GlucoseTrend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseTrend.swift; sourceTree = ""; }; - B429D66D24BF7255003E1B4A /* UIImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImage.swift; sourceTree = ""; }; - B42A7471235885B600247B03 /* LoopNotificationUserInfoKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopNotificationUserInfoKey.swift; sourceTree = ""; }; - B42C94FD24A2A2B000857C73 /* DeviceStatusHighlight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceStatusHighlight.swift; sourceTree = ""; }; - B42C950C24A3BD4B00857C73 /* MeasurementFrequencyTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeasurementFrequencyTableViewController.swift; sourceTree = ""; }; - B43DA43E24D49AA400CAFF4E /* GuidanceColors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuidanceColors.swift; sourceTree = ""; }; - B455F2A125FBE985000ED456 /* SuspendThresholdEditorViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SuspendThresholdEditorViewModel.swift; path = LoopKitUI/ViewModels/SuspendThresholdEditorViewModel.swift; sourceTree = SOURCE_ROOT; }; - B455F35525FC0284000ED456 /* CorrectionRangeOverridesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CorrectionRangeOverridesTests.swift; sourceTree = ""; }; - B455F3A325FF7FF0000ED456 /* CorrectionRangeOverridesEditorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CorrectionRangeOverridesEditorViewModel.swift; sourceTree = ""; }; - B455F48025FF9A8B000ED456 /* InsulinSensitivityScheduleEditorViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsulinSensitivityScheduleEditorViewModel.swift; sourceTree = ""; }; - B455F4D22600DA0B000ED456 /* GlucoseRange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseRange.swift; sourceTree = ""; }; - B455F4DE2600E0A8000ED456 /* GlucoseRangeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseRangeTests.swift; sourceTree = ""; }; - B45774342562CCC6004B9466 /* SupportedRangeTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportedRangeTableViewController.swift; sourceTree = ""; }; - B45AF6EF24D4355A00EEAA4D /* Environment+Colors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Environment+Colors.swift"; sourceTree = ""; }; - B46B62A623FEFE4D001E69BA /* InstructionList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstructionList.swift; sourceTree = ""; }; - B46B62A823FF05F8001E69BA /* LabeledNumberInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabeledNumberInput.swift; sourceTree = ""; }; - B46B62AA23FF0822001E69BA /* LabeledValueView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabeledValueView.swift; sourceTree = ""; }; - B46B62AC23FF0A87001E69BA /* LabeledDateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabeledDateView.swift; sourceTree = ""; }; - B46B62AE23FF0BF6001E69BA /* SectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeader.swift; sourceTree = ""; }; - B46B62B023FF0CA6001E69BA /* DescriptiveText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DescriptiveText.swift; sourceTree = ""; }; - B46B62B223FF0E62001E69BA /* SelectableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectableLabel.swift; sourceTree = ""; }; - B46E095625F7E5910025A04D /* GlucoseRangeScheduleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseRangeScheduleTests.swift; sourceTree = ""; }; - B46E096C25F80D6C0025A04D /* OverrideTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideTests.swift; sourceTree = ""; }; - B46FA3F1253F00DC00D993E2 /* momentum_effect_impossible_rising_glucose_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_impossible_rising_glucose_output.json; sourceTree = ""; }; - B46FA3F2253F00DC00D993E2 /* momentum_effect_impossible_rising_glucose_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = momentum_effect_impossible_rising_glucose_input.json; sourceTree = ""; }; - B47ECF8725DC20810024A54D /* UIImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImage.swift; sourceTree = ""; }; - B47ECFD525DC22D20024A54D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - B4A2AAB0240830A30066563F /* LabeledTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabeledTextField.swift; sourceTree = ""; }; - B4A2AAB2240832350066563F /* MultipleSelectionList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultipleSelectionList.swift; sourceTree = ""; }; - B4B1162D25AF3A40006428DE /* DisplayGlucoseUnitObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayGlucoseUnitObserver.swift; sourceTree = ""; }; - B4B7C1602603F241007379F6 /* InsulinSensitivityScheduleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinSensitivityScheduleTests.swift; sourceTree = ""; }; - B4B7C1762603F5F6007379F6 /* HKUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HKUnitTests.swift; sourceTree = ""; }; - B4B7C1BB2604E3FC007379F6 /* CorrectionRangeScheduleEditorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CorrectionRangeScheduleEditorViewModel.swift; sourceTree = ""; }; - B4B85FCC24A2312000A296A3 /* GlucoseRangeCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseRangeCategory.swift; sourceTree = ""; }; - B4C004B2241085DB00B40429 /* ActionButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionButton.swift; sourceTree = ""; }; - B4C004B3241085DB00B40429 /* GuidePage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GuidePage.swift; sourceTree = ""; }; - B4C004B4241085DC00B40429 /* GuideNavigationButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GuideNavigationButton.swift; sourceTree = ""; }; - B4CEE2A4256E91290093111B /* DoseProgressTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoseProgressTests.swift; sourceTree = ""; }; - B4CEE2E0257129780093111B /* MockKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MockKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - B4CEE2E2257129780093111B /* UnfinalizedDoseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnfinalizedDoseTests.swift; sourceTree = ""; }; - B4CEE2E4257129780093111B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - B4D4C20C25F95A8700DA809D /* DisplayGlucoseUnitObservable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayGlucoseUnitObservable.swift; sourceTree = ""; }; - C10340F329C786E900FE5BA1 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - C104B64A2981EE3B003A9235 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Main.strings; sourceTree = ""; }; - C104B64B2981EE3B003A9235 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = ""; }; - C109240E286A4AD500FAD2B8 /* AutomaticDosingStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutomaticDosingStrategy.swift; sourceTree = ""; }; - C10B8078297E498E00446CDD /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - C10BD98429C7867600FE2BDC /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - C1110E981EE98CF5009BB852 /* ice_35_min_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ice_35_min_input.json; sourceTree = ""; }; - C121D8D329C7866D00DA0520 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - C121D8D429C7866D00DA0520 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - C122DF0129BBFAAE00321F8D /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Main.strings; sourceTree = ""; }; - C122DF0229BBFAAE00321F8D /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = ""; }; - C12D11D229C7867E000B215F /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - C12EE16B1F2964B3007DB9F1 /* InsulinModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsulinModel.swift; sourceTree = ""; }; - C1330679297E49730067A05C /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - C133067A297E49730067A05C /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - C133067B297E49730067A05C /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - C133067C297E49730067A05C /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - C13493B4297E498700D87305 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - C13493B5297E498700D87305 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - C13493B6297E498700D87305 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - C13493B7297E498700D87305 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - C1394BA6297E49630042F1A9 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - C13E6D291EEB1CB9006F5880 /* ice_slow_absorption.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ice_slow_absorption.json; sourceTree = ""; }; - C13F89C4297E495B00C71398 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - C140DFFE260276BF000A4FF7 /* ManualBolusRecommendation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManualBolusRecommendation.swift; sourceTree = ""; }; - C140E0512602908A000A4FF7 /* SettingsPresentationMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsPresentationMode.swift; sourceTree = ""; }; - C14690CF297E497A00124A99 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - C1469E02297E498100042439 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - C14A7E7D295F43AB00CD87B4 /* ConfigurationPageScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationPageScrollView.swift; sourceTree = ""; }; - C14C0AD02981EE35001B758E /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/InfoPlist.strings; sourceTree = ""; }; - C14C46E82981EE3F00E20BEF /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Main.strings; sourceTree = ""; }; - C14C46E92981EE3F00E20BEF /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/InfoPlist.strings; sourceTree = ""; }; - C15A582429C7866600D3A5A1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Main.strings; sourceTree = ""; }; - C15A582529C7866600D3A5A1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; - C15A582629C7866600D3A5A1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; - C15A582729C7866600D3A5A1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/InsulinKit.strings; sourceTree = ""; }; - C15A582829C7866600D3A5A1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - C15A582929C7866600D3A5A1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; - C15A582A29C7866600D3A5A1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; - C15A582B29C7866600D3A5A1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; - C15C115029C814F300EBAC55 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - C15E994529C6790A004AB926 /* LocalizedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedString.swift; sourceTree = ""; }; - C161742B297E494D007C2E5F /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - C161742C297E494D007C2E5F /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - C161742D297E494D007C2E5F /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - C161742E297E494D007C2E5F /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - C161E8F9297E495300E22BDD /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - C161E8FA297E495300E22BDD /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - C161E8FB297E495300E22BDD /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - C161E8FC297E495300E22BDD /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - C164A55F22F14C73000E3FA5 /* UnfinalizedDose.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnfinalizedDose.swift; sourceTree = ""; }; - C164A56322F21081000E3FA5 /* MockPumpManagerState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPumpManagerState.swift; sourceTree = ""; }; - C16528FF2981EE40000B130A /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Main.strings; sourceTree = ""; }; - C16529002981EE40000B130A /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = ""; }; - C168CA78280DD00F002BD2A7 /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = ""; }; - C168CA79280DD00F002BD2A7 /* Modelv4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Modelv4.xcdatamodel; sourceTree = ""; }; - C16DA83E22E8D88F008624C2 /* LoopPluginBundleKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopPluginBundleKey.swift; sourceTree = ""; }; - C16DA84422E9330A008624C2 /* LoopUIPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopUIPlugin.swift; sourceTree = ""; }; - C16DFA45297E494500D56397 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - C1742345259CD3ED00399C9D /* InsulinTypeChooser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinTypeChooser.swift; sourceTree = ""; }; - C1790E6D297E493600683E3B /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - C17F39C023CD24A000FA1113 /* DeviceCommsLog.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = DeviceCommsLog.xcdatamodel; sourceTree = ""; }; - C17F39C623CD256000FA1113 /* PersistentDeviceLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentDeviceLog.swift; sourceTree = ""; }; - C17F39C823CD269200FA1113 /* DeviceLogEntryType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLogEntryType.swift; sourceTree = ""; }; - C17F39CF23CE34B100FA1113 /* StoredDeviceLogEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredDeviceLogEntry.swift; sourceTree = ""; }; - C17F4CB21EE9B6DF005079B1 /* carb_entry_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = carb_entry_input.json; sourceTree = ""; }; - C1814B83225B9ED5008D2D8E /* LoopNotificationCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopNotificationCategory.swift; sourceTree = ""; }; - C1814B8B226371DF008D2D8E /* WeakSynchronizedDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakSynchronizedDelegate.swift; sourceTree = ""; }; - C1821688297E55A7001EB097 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Main.strings; sourceTree = ""; }; - C1821689297E55A7001EB097 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; - C183FDD3297E493D003B16ED /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/InfoPlist.strings; sourceTree = ""; }; - C183FDD4297E493D003B16ED /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - C183FDD5297E493D003B16ED /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - C183FDD6297E493D003B16ED /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - C183FDD7297E493D003B16ED /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - C187337D29B9481500519CDF /* LocalizedString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizedString.swift; sourceTree = ""; }; - C187337F29B9486100519CDF /* Collection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = ""; }; - C187338029B9486100519CDF /* Comparable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comparable.swift; sourceTree = ""; }; - C187338129B9486100519CDF /* HKUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKUnit.swift; sourceTree = ""; }; - C187338229B9486200519CDF /* TimeInterval.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeInterval.swift; sourceTree = ""; }; - C187338329B9486200519CDF /* ClosedRange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosedRange.swift; sourceTree = ""; }; - C187338429B9486200519CDF /* NumberFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberFormatter.swift; sourceTree = ""; }; - C187338529B9486200519CDF /* Guardrail+Settings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Guardrail+Settings.swift"; sourceTree = ""; }; - C187338629B9486200519CDF /* Data.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; }; - C187338729B9486200519CDF /* MutableCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MutableCollection.swift; sourceTree = ""; }; - C187338829B9486200519CDF /* OSLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; - C187338929B9486200519CDF /* DateFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateFormatter.swift; sourceTree = ""; }; - C187339529B9488300519CDF /* Sequence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sequence.swift; sourceTree = ""; }; - C187339629B9488300519CDF /* TimeZone.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeZone.swift; sourceTree = ""; }; - C187339729B9488300519CDF /* UUID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UUID.swift; sourceTree = ""; }; - C187339B29B948D800519CDF /* Data.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; }; - C187339D29B948F200519CDF /* HKUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKUnit.swift; sourceTree = ""; }; - C187339F29B9492200519CDF /* NumberFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberFormatter.swift; sourceTree = ""; }; - C18733A029B9492200519CDF /* UITableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITableViewCell.swift; sourceTree = ""; }; - C18733A129B9492200519CDF /* UITextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITextField.swift; sourceTree = ""; }; - C18733A229B9492200519CDF /* TimeZone.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeZone.swift; sourceTree = ""; }; - C18733A329B9492200519CDF /* NSTimeInterval.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSTimeInterval.swift; sourceTree = ""; }; - C18733A429B9492200519CDF /* Collection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = ""; }; - C18733A529B9492200519CDF /* NibLoadable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NibLoadable.swift; sourceTree = ""; }; - C18733A629B9492300519CDF /* Math.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Math.swift; sourceTree = ""; }; - C18733A729B9492300519CDF /* Comparable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comparable.swift; sourceTree = ""; }; - C18733A829B9492300519CDF /* IdentifiableClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentifiableClass.swift; sourceTree = ""; }; - C18733A929B9492300519CDF /* HKUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKUnit.swift; sourceTree = ""; }; - C18733B529B9495400519CDF /* LocalizedString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizedString.swift; sourceTree = ""; }; - C18733B729B949FF00519CDF /* Data.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; }; - C18733B929B94A3700519CDF /* HKUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKUnit.swift; sourceTree = ""; }; - C18733BA29B94A3700519CDF /* TimeInterval.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeInterval.swift; sourceTree = ""; }; - C18733BB29B94A3700519CDF /* TimeZone.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeZone.swift; sourceTree = ""; }; - C18733BF29B94A6300519CDF /* NumberFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberFormatter.swift; sourceTree = ""; }; - C18733C029B94A6300519CDF /* Comparable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comparable.swift; sourceTree = ""; }; - C18733C129B94A6300519CDF /* IdentifiableClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentifiableClass.swift; sourceTree = ""; }; - C18733C229B94A6300519CDF /* NibLoadable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NibLoadable.swift; sourceTree = ""; }; - C18733C329B94A6300519CDF /* TimeInterval.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeInterval.swift; sourceTree = ""; }; - C18733C429B94A6300519CDF /* UITableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITableViewCell.swift; sourceTree = ""; }; - C18733CB29B94A7A00519CDF /* LocalizedString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizedString.swift; sourceTree = ""; }; - C18733CD29B94B1700519CDF /* IdentifiableClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentifiableClass.swift; sourceTree = ""; }; - C18733CF29B94B3300519CDF /* TimeInterval.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeInterval.swift; sourceTree = ""; }; - C18733D129B94B8E00519CDF /* HKUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKUnit.swift; sourceTree = ""; }; - C188B83322CC16AC0051760A /* InsulinSensitivityScheduleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinSensitivityScheduleViewController.swift; sourceTree = ""; }; - C18E73FD29C7870A0031245F /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - C191D26225B3815000C26C0B /* AutomaticDoseRecommendation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutomaticDoseRecommendation.swift; sourceTree = ""; }; - C192C60529C78711001EFEA6 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - C19951DA29C786C8001983C9 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - C19E387F298638CE00851444 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - C1A1C7A529C786D1001A0FA5 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - C1A4ED662981EE36008F4B1A /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Main.strings; sourceTree = ""; }; - C1AA4E0F2981EE4400888F32 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/InfoPlist.strings; sourceTree = ""; }; - C1ABE38D2245CFCD00570E82 /* UnfairLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnfairLock.swift; sourceTree = ""; }; - C1B0CFDB29C786BF0045B04D /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - C1B2679E2995824000BCB7C1 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = ""; }; - C1B761F229C786D90098916A /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - C1BCB5BA298309C4001C50FF /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Main.strings; sourceTree = ""; }; - C1BCB5BB298309C4001C50FF /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = ""; }; - C1C685F929C786B70002E063 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - C1CAB9E826A3254800A57273 /* StoredInsulinModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoredInsulinModel.swift; sourceTree = ""; }; - C1CBF61B1EEA2A1E001E4851 /* ice_1_hour_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ice_1_hour_input.json; sourceTree = ""; }; - C1D107B7297E499D008905A6 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - C1D107B8297E499D008905A6 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - C1D107B9297E499D008905A6 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - C1D107BA297E499D008905A6 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - C1D56375296B3F5E00BA15EC /* reservoir_for_iob_missing.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = reservoir_for_iob_missing.json; sourceTree = ""; }; - C1D7162229C75DC700B5AB3B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - C1D7162429C75E3B00B5AB3B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - C1D7162529C75E9000B5AB3B /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - C1D7162629C75E9F00B5AB3B /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; - C1D7162729C75EBD00B5AB3B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - C1D7162829C75ECE00B5AB3B /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - C1D7162929C75EE200B5AB3B /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - C1D72CFD2981EE4600EE0982 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = ""; }; - C1DB5556297E499500EB1DCE /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - C1DB55B01F2E95FD00C483A2 /* WalshInsulinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalshInsulinModel.swift; sourceTree = ""; }; - C1DB55B21F2E964400C483A2 /* ExponentialInsulinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExponentialInsulinModel.swift; sourceTree = ""; }; - C1DB55B41F2EA6EA00C483A2 /* iob_from_doses_exponential_output.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = iob_from_doses_exponential_output.json; sourceTree = ""; }; - C1DB55B61F2EACD500C483A2 /* iob_from_bolus_exponential_output.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = iob_from_bolus_exponential_output.json; sourceTree = ""; }; - C1DD515A259FE3AB00DE27AE /* InsulinTypeSetting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinTypeSetting.swift; sourceTree = ""; }; - C1DE4C2025A253BD007065F8 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; - C1E0EEF524EB26D800086510 /* DeliveryUncertaintyRecoveryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeliveryUncertaintyRecoveryView.swift; sourceTree = ""; }; - C1E4B303242E98E900E70CCB /* ProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressView.swift; sourceTree = ""; }; - C1E4B304242E98E900E70CCB /* ProgressIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressIndicatorView.swift; sourceTree = ""; }; - C1E4B307242E995200E70CCB /* ActivityIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivityIndicator.swift; sourceTree = ""; }; - C1E4B309242E99A800E70CCB /* Image.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Image.swift; sourceTree = ""; }; - C1E50005297E492E0018FA21 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - C1E50006297E492E0018FA21 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - C1E50007297E492E0018FA21 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - C1E50008297E492E0018FA21 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - C1E5A6DF29C7870100703C90 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - C1E5F20D29C786A100BC686C /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - C1E693D129C786E200410918 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - C1E7035C24FFFA5C00DAB534 /* CollectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionTests.swift; sourceTree = ""; }; - C1E7035E25001EA500DAB534 /* HKObserverQueryMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HKObserverQueryMock.swift; sourceTree = ""; }; - C1E703612500390B00DAB534 /* HKAnchoredObjectQueryMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HKAnchoredObjectQueryMock.swift; sourceTree = ""; }; - C1E84B8425C62FB100623C08 /* Modelv1v4.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = Modelv1v4.xcmappingmodel; sourceTree = ""; }; - C1F490012995821600C8BD69 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Main.strings; sourceTree = ""; }; - C1F490022995821600C8BD69 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InfoPlist.strings; sourceTree = ""; }; - C1F4FD5A29C7869800D7ACBC /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - C1F8403723DB84B700673141 /* DeviceLogEntry+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DeviceLogEntry+CoreDataClass.swift"; sourceTree = ""; }; - C1F8403823DB84B700673141 /* DeviceLogEntry+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DeviceLogEntry+CoreDataProperties.swift"; sourceTree = ""; }; - C1FAB5C329C786B000D25073 /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = ""; }; - C1FAB5C429C786B000D25073 /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = ""; }; - C1FAC06228C7B0A100754AE2 /* reservoir_iob_test.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = reservoir_iob_test.json; sourceTree = ""; }; - C1FAEC1C264AD6B400A3250B /* DeviceStatusBadge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceStatusBadge.swift; sourceTree = ""; }; - C1FAEC20264AEEA300A3250B /* UIImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImage.swift; sourceTree = ""; }; - C1FC393029C786F20003C587 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - C1FC9C6329C78690005D2515 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - C1FDCC0429C786F90056E652 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Main.strings; sourceTree = ""; }; - C1FDCC0529C786F90056E652 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1FDCC0629C786F90056E652 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1FDCC0729C786F90056E652 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/InsulinKit.strings; sourceTree = ""; }; - C1FDCC0829C786F90056E652 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - C1FDCC0929C786F90056E652 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1FDCC0A29C786F90056E652 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1FDCC0B29C786F90056E652 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1FF3D4E29C786A900BDC1EC /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; - E9077D2624ACD59F0066A88D /* InformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InformationView.swift; sourceTree = ""; }; - E9077D2924ACDE2C0066A88D /* CorrectionRangeInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CorrectionRangeInformationView.swift; sourceTree = ""; }; - E9086B2824B39EDC0062F5C8 /* ChartsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartsTableViewController.swift; sourceTree = ""; }; - E9086B2C24B3A4AC0062F5C8 /* ChartsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartsManager.swift; sourceTree = ""; }; - E9086B2E24B3A5080062F5C8 /* ChartColorPalette.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartColorPalette.swift; sourceTree = ""; }; - E9086B3024B3A7270062F5C8 /* ChartTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartTableViewCell.swift; sourceTree = ""; }; - E9086B3424B3A8820062F5C8 /* ChartContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartContainerView.swift; sourceTree = ""; }; - E9086B3824B3CB4B0062F5C8 /* TherapySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TherapySettings.swift; sourceTree = ""; }; - E9086B4424B53CC50062F5C8 /* GlucoseChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseChart.swift; sourceTree = ""; }; - E9086B4724B5405E0062F5C8 /* ChartAxisValueDoubleUnit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartAxisValueDoubleUnit.swift; sourceTree = ""; }; - E9086B4924B540B70062F5C8 /* DateFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateFormatter.swift; sourceTree = ""; }; - E916F56824AD32F000BE3547 /* CorrectionRangeOverridesEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CorrectionRangeOverridesEditor.swift; sourceTree = ""; }; - E916F56E24AE2FFE00BE3547 /* CorrectionRangeOverrideInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CorrectionRangeOverrideInformationView.swift; sourceTree = ""; }; - E93BA06524A39DBC00C5D7E6 /* DismissibleHostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DismissibleHostingController.swift; sourceTree = ""; }; - E93C869F24C8F6E00073089B /* InsulinModelSelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinModelSelection.swift; sourceTree = ""; }; - E93C86A124C8F7550073089B /* InsulinModelChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinModelChart.swift; sourceTree = ""; }; - E93C86A324C8F79C0073089B /* ChartLineModel+LoopKitUI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ChartLineModel+LoopKitUI.swift"; sourceTree = ""; }; - E93C86A524C8F7D90073089B /* ChartSettings+LoopKitUI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ChartSettings+LoopKitUI.swift"; sourceTree = ""; }; - E93C86A724C8F7F60073089B /* InsulinModelChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsulinModelChartView.swift; sourceTree = ""; }; - E93C86AF24CF7C470073089B /* TherapySettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TherapySettingsTests.swift; sourceTree = ""; }; - E93C86B124D080E00073089B /* CarbRatioInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbRatioInformationView.swift; sourceTree = ""; }; - E93C86B524D08CAD0073089B /* InsulinSensitivityInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinSensitivityInformationView.swift; sourceTree = ""; }; - E93E865924DC744300FF40C8 /* effect_from_basal_output_exponential.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = effect_from_basal_output_exponential.json; sourceTree = ""; }; - E93E865B24DC75EF00FF40C8 /* basal_dose_with_expired.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = basal_dose_with_expired.json; sourceTree = ""; }; - E93E865D24DC797A00FF40C8 /* basal_dose_with_delivered.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = basal_dose_with_delivered.json; sourceTree = ""; }; - E93E865F24DC82A500FF40C8 /* dose_history_with_delivered_units.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = dose_history_with_delivered_units.json; sourceTree = ""; }; - E93E866124DC87AE00FF40C8 /* effect_from_history_exponential_delivered_units_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = effect_from_history_exponential_delivered_units_output.json; sourceTree = ""; }; - E93E866324DCFB6D00FF40C8 /* OverrideHistoryCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideHistoryCollectionViewCell.swift; sourceTree = ""; }; - E93E866924DD05FA00FF40C8 /* OverrideSelectionHistory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverrideSelectionHistory.swift; sourceTree = ""; }; - E94141CF24C8F31C0096C326 /* DeliveryLimitsEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeliveryLimitsEditor.swift; sourceTree = ""; }; - E949E38824AFC82F00024DA0 /* DeliveryLimitsInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeliveryLimitsInformationView.swift; sourceTree = ""; }; - E949E38E24B3711E00024DA0 /* InsulinModelInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinModelInformationView.swift; sourceTree = ""; }; - E96175AD24B7BE38008E5080 /* Dictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = ""; }; - E96DCB5724AEF50F007117BC /* SuspendThresholdInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuspendThresholdInformationView.swift; sourceTree = ""; }; - E96DCB5924AF74AC007117BC /* SuspendThresholdEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuspendThresholdEditor.swift; sourceTree = ""; }; - E96DCB5D24AF7DC7007117BC /* BasalRatesInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasalRatesInformationView.swift; sourceTree = ""; }; - E99A132D2557548300D3F5B3 /* SegmentedGaugeBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentedGaugeBar.swift; sourceTree = ""; }; - E9C58A6D24DA65E400487A17 /* HistoricalOverrideDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoricalOverrideDetailView.swift; sourceTree = ""; }; - E9DFB92B24E634E800468917 /* ExpandablePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandablePicker.swift; sourceTree = ""; }; - E9DFB92D24E8A75C00468917 /* iob_from_multiple_curves_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = iob_from_multiple_curves_output.json; sourceTree = ""; }; - E9DFB92F24E8CA8500468917 /* LegacyInsulinDeliveryTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyInsulinDeliveryTableViewController.swift; sourceTree = ""; }; - E9DFB93424E8CD5800468917 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LegacyInsulinDeliveryTableViewController.storyboard; sourceTree = ""; }; - E9DFB93724E8CD7400468917 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - E9DFB93924E8CD7800468917 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/LegacyInsulinDeliveryTableViewController.strings"; sourceTree = ""; }; - E9DFB93B24E8CD7A00468917 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - E9DFB93D24E8CD7B00468917 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - E9DFB93F24E8CD7C00468917 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - E9DFB94124E8CD7D00468917 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - E9DFB94324E8CD8100468917 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - E9DFB94524E8CD8300468917 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - E9DFB94724E8CD8400468917 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - E9DFB94924E8CD8600468917 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - E9E5E56124D362E800B5DFFE /* dynamic_glucose_effect_none_observed_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = dynamic_glucose_effect_none_observed_output.json; sourceTree = ""; }; - E9E5E56224D362E800B5DFFE /* dynamic_glucose_effect_never_fully_observed_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = dynamic_glucose_effect_never_fully_observed_output.json; sourceTree = ""; }; - E9E5E56324D362E800B5DFFE /* dynamic_glucose_effect_partially_observed_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = dynamic_glucose_effect_partially_observed_output.json; sourceTree = ""; }; - E9E5E56424D362E900B5DFFE /* dynamic_glucose_effect_fully_observed_output.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = dynamic_glucose_effect_fully_observed_output.json; sourceTree = ""; }; - E9E5E56924D5CCE800B5DFFE /* OverrideViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideViewCell.swift; sourceTree = ""; }; - E9F54F5D25802D5E0034795E /* InsulinType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinType.swift; sourceTree = ""; }; - E9F54FC52581C50C0034795E /* ExpandableDatePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableDatePicker.swift; sourceTree = ""; }; - F5E0BDE427E1D8950033557E /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/LaunchScreen.strings; sourceTree = ""; }; - F5E0BDE527E1D8C20033557E /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Main.strings; sourceTree = ""; }; - F5E0BDE727E1D8C20033557E /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/InsulinKit.strings; sourceTree = ""; }; - F5E0BDE827E1D8C20033557E /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - F5E0BDE927E1D9590033557E /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/LaunchScreen.strings; sourceTree = ""; }; - F5E0BDEA27E1D9590033557E /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Main.strings; sourceTree = ""; }; - F5E0BDEC27E1D9870033557E /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/InsulinKit.strings; sourceTree = ""; }; - F5E0BDED27E1D9870033557E /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - F5E0BDEE27E1D9EB0033557E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/LaunchScreen.strings; sourceTree = ""; }; - F5E0BDEF27E1D9EB0033557E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Main.strings; sourceTree = ""; }; - F5E0BDF127E1D9EB0033557E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/InsulinKit.strings; sourceTree = ""; }; - F5E0BDF227E1D9EC0033557E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - F5E0BDF327E1D9EC0033557E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; - F5E0BDF427E1D9EC0033557E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; - F5E0BDF527E1D9EC0033557E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; - F5E0BDF627E1D9F90033557E /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/LaunchScreen.strings; sourceTree = ""; }; - F5E0BDF727E1DA260033557E /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Main.strings; sourceTree = ""; }; - F5E0BDF927E1DA260033557E /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InsulinKit.strings; sourceTree = ""; }; - F5E0BDFA27E1DA260033557E /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - F5E0BDFB27E1DAA00033557E /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/LaunchScreen.strings"; sourceTree = ""; }; - F5E0BDFC27E1DACD0033557E /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Main.strings"; sourceTree = ""; }; - F5E0BDFE27E1DACE0033557E /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/InsulinKit.strings"; sourceTree = ""; }; - F5E0BDFF27E1DACE0033557E /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/LegacyInsulinDeliveryTableViewController.strings"; sourceTree = ""; }; - F5E0BE0027E1DB350033557E /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/LaunchScreen.strings; sourceTree = ""; }; - F5E0BE0127E1DB620033557E /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Main.strings; sourceTree = ""; }; - F5E0BE0327E1DB620033557E /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/InsulinKit.strings; sourceTree = ""; }; - F5E0BE0427E1DB620033557E /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - F5E0BE0527E1DB760033557E /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/LaunchScreen.strings; sourceTree = ""; }; - F5E0BE0627E1DBA40033557E /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Main.strings; sourceTree = ""; }; - F5E0BE0827E1DBA40033557E /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InsulinKit.strings; sourceTree = ""; }; - F5E0BE0927E1DBA40033557E /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - F5E0BE0A27E1DC480033557E /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/LaunchScreen.strings; sourceTree = ""; }; - F5E0BE0B27E1DC480033557E /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Main.strings; sourceTree = ""; }; - F5E0BE0D27E1DC490033557E /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InsulinKit.strings; sourceTree = ""; }; - F5E0BE0E27E1DC490033557E /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; - F5E0BE0F27E1DC490033557E /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - F5E0BE1027E1DC490033557E /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - F5E0BE1127E1DC490033557E /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - F5E0BE1227E1DC9C0033557E /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/LaunchScreen.strings; sourceTree = ""; }; - F5E0BE1327E1DCC90033557E /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Main.strings; sourceTree = ""; }; - F5E0BE1527E1DCC90033557E /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/InsulinKit.strings; sourceTree = ""; }; - F5E0BE1627E1DCC90033557E /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/LegacyInsulinDeliveryTableViewController.strings; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 1DEE229C24A676A300693C32 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 1DEE229D24A676A300693C32 /* LoopKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 430157F41C7EC03B00B64B63 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C1CCF1062858F07A0035389C /* SwiftCharts in Frameworks */, - 892A5D49222F03CC008961AB /* LoopTestingKit.framework in Frameworks */, - 4301582D1C7ECD7A00B64B63 /* HealthKit.framework in Frameworks */, - 430158191C7ECB5E00B64B63 /* LoopKit.framework in Frameworks */, - 43BA715B201E484D0058961E /* LoopKitUI.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43BA7150201E484D0058961E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C1CCF1082858F1E10035389C /* SwiftCharts in Frameworks */, - C1BECA93285902F5008075C4 /* LoopKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43D8FDC71C728FDF0073BE78 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 4353D173203D3E7E007B4ECD /* CoreData.framework in Frameworks */, - 4353D170203D3E5C007B4ECD /* HealthKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43D8FDD21C728FDF0073BE78 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 43D8FDD61C728FDF0073BE78 /* LoopKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 892A5D31222F03CB008961AB /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 892A5D5C222F1210008961AB /* LoopKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 89D2046F21CC7BD7001238CC /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C1475B33264C30800040C7B1 /* LoopKitUI.framework in Frameworks */, - 892A5D57222F04E2008961AB /* LoopTestingKit.framework in Frameworks */, - 89D204A621CC7C55001238CC /* LoopKit.framework in Frameworks */, - 89D2048921CC7BF7001238CC /* HealthKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 89D2048C21CC7C12001238CC /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 89D204A821CC7C60001238CC /* MockKit.framework in Frameworks */, - 89D204A721CC7C5C001238CC /* LoopKitUI.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A9E675E522713F4700E25293 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - A9E675F3227140D800E25293 /* CoreData.framework in Frameworks */, - A9E675F5227140DD00E25293 /* HealthKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - B4CEE2DD257129780093111B /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - B4CEE2E5257129780093111B /* MockKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 1D096BFD24C24C140078B6B5 /* Insulin */ = { - isa = PBXGroup; - children = ( - 1D096C0024C24C220078B6B5 /* ExponentialInsulinModelPreset.swift */, - 1D096BFF24C24C220078B6B5 /* InsulinModelProvider.swift */, - ); - path = Insulin; - sourceTree = ""; - }; - 1D63DEA126E94F6B00F46FA5 /* Service */ = { - isa = PBXGroup; - children = ( - A98FF28F29A25699005739A5 /* Remote */, - A9498D7323386C3200DAA9B9 /* AnalyticsService.swift */, - A9498D7123386C3200DAA9B9 /* LoggingService.swift */, - A9498D7523386C3300DAA9B9 /* RemoteDataService.swift */, - A9498D7623386C3300DAA9B9 /* Service.swift */, - ); - path = Service; - sourceTree = ""; - }; - 1D640FF424524274008F9755 /* Sounds */ = { - isa = PBXGroup; - children = ( - 1D25C22D246A2A1A00E87FA0 /* critical.caf */, - 1D640FF524524284008F9755 /* sub.caf */, - ); - path = Sounds; - sourceTree = ""; - }; - 1D70F7FA26C1BE6100D5BE96 /* TestCoreData */ = { - isa = PBXGroup; - children = ( - 1DD65CFE26C476880085CC64 /* Model.sqlite.v1.original */, - ); - path = TestCoreData; - sourceTree = ""; - }; - 1DEE230524A6960400693C32 /* LoopKitHostedTests */ = { - isa = PBXGroup; - children = ( - 1D70F7FA26C1BE6100D5BE96 /* TestCoreData */, - A9E068142534EB6B00BDAB59 /* Persistence */, - 1DEE230224A676A300693C32 /* LoopKitHostedTests.plist */, - A98ED5FD253132A400FD8F70 /* CarbStoreHKQueryTests.swift */, - 1D70F80126C1BEB700D5BE96 /* CoreDataMigrationTests.swift */, - A9E0681725350ECC00BDAB59 /* GlucoseStoreTests.swift */, - C1E703612500390B00DAB534 /* HKAnchoredObjectQueryMock.swift */, - C1E7035E25001EA500DAB534 /* HKObserverQueryMock.swift */, - A994B883254241B10039B108 /* InsulinDeliveryStoreTests.swift */, - ); - path = LoopKitHostedTests; - sourceTree = ""; - }; - 430157F81C7EC03B00B64B63 /* LoopKit Example */ = { - isa = PBXGroup; - children = ( - 7D68A9B01FE0A3D000522C49 /* Localizable.strings */, - 435F355F1C9CD23D00C204D2 /* Managers */, - 435F355C1C9CD14E00C204D2 /* Extensions */, - 4301582A1C7ECCEF00B64B63 /* LoopKitExample.entitlements */, - 430158071C7EC03B00B64B63 /* Info.plist */, - 4B67E2C9289B4EDB002D92AF /* InfoPlist.strings */, - 430157F91C7EC03B00B64B63 /* AppDelegate.swift */, - 430157FB1C7EC03B00B64B63 /* MasterViewController.swift */, - 430158021C7EC03B00B64B63 /* Assets.xcassets */, - 430158041C7EC03B00B64B63 /* LaunchScreen.storyboard */, - 430157FF1C7EC03B00B64B63 /* Main.storyboard */, - ); - path = "LoopKit Example"; - sourceTree = ""; - }; - 432CF86320D769070066B889 /* View Controllers */ = { - isa = PBXGroup; - children = ( - 895FE08D22011F4800FCF18A /* AddEditOverrideTableViewController.swift */, - 43F5034C210599CC009FA89A /* AuthenticationViewController.swift */, - 434FB6491D712158007B9C70 /* CommandResponseViewController.swift */, - 43D8FE041C7290530073BE78 /* DailyQuantityScheduleTableViewController.swift */, - 43D8FE051C7290530073BE78 /* DailyValueScheduleTableViewController.swift */, - 898E6E712241EDC10019E459 /* DateAndDurationTableViewController.swift */, - 895FE08F22011F4800FCF18A /* EmojiInputController.swift */, - 8907E35821A9D0EC00335852 /* GlucoseEntryTableViewController.swift */, - 43D8FE061C7290530073BE78 /* GlucoseRangeScheduleTableViewController.swift */, - C188B83322CC16AC0051760A /* InsulinSensitivityScheduleViewController.swift */, - 895FE08C22011F4800FCF18A /* OverrideSelectionViewController.swift */, - 898E6E6F2241EDB70019E459 /* PercentageTextFieldTableViewController.swift */, - 43FB60E620DCBC55002B996B /* RadioSelectionTableViewController.swift */, - A9498D8623386CAF00DAA9B9 /* ServiceNavigationController.swift */, - 892A5D992231E0E3008961AB /* SettingsNavigationViewController.swift */, - 43FB60E420DCBA02002B996B /* SetupTableViewController.swift */, - 43D8FE0C1C7290530073BE78 /* SingleValueScheduleTableViewController.swift */, - 434FF1F31CF294A9000DB779 /* TextFieldTableViewController.swift */, - 89CCD4F921A911510068C3FB /* PercentageTextFieldTableViewController.swift */, - 895695F521AA413B00828067 /* DateAndDurationTableViewController.swift */, - E93BA06524A39DBC00C5D7E6 /* DismissibleHostingController.swift */, - E9086B2824B39EDC0062F5C8 /* ChartsTableViewController.swift */, - E9086B2C24B3A4AC0062F5C8 /* ChartsManager.swift */, - E9C58A6D24DA65E400487A17 /* HistoricalOverrideDetailView.swift */, - ); - path = "View Controllers"; - sourceTree = ""; - }; - 434113B620F2BDB900D05747 /* Persistence */ = { - isa = PBXGroup; - children = ( - 434113BD20F2C72000D05747 /* CachedCarbObjectTests.swift */, - 434113BB20F2C56100D05747 /* CachedGlucoseObjectTests.swift */, - 434113B420F2BDB500D05747 /* CachedInsulinDeliveryObjectTests.swift */, - A9DF02C224F6EEE400B7C988 /* DeviceLogEntryTests.swift */, - 434113B220F2890800D05747 /* PersistenceControllerTests.swift */, - 434113B720F2BDE800D05747 /* PersistenceControllerTestCase.swift */, - A9DF02C424F6FA5100B7C988 /* PumpEventTests.swift */, - ); - path = Persistence; - sourceTree = ""; - }; - 435F355C1C9CD14E00C204D2 /* Extensions */ = { - isa = PBXGroup; - children = ( - C18733D129B94B8E00519CDF /* HKUnit.swift */, - C18733CF29B94B3300519CDF /* TimeInterval.swift */, - C18733CD29B94B1700519CDF /* IdentifiableClass.swift */, - 4302F4DE1D4E607B00F0FCAF /* LegacyInsulinDeliveryTableViewController.swift */, - 435F355D1C9CD16A00C204D2 /* NSUserDefaults.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 435F355F1C9CD23D00C204D2 /* Managers */ = { - isa = PBXGroup; - children = ( - 435F35601C9CD25F00C204D2 /* DeviceDataManager.swift */, - ); - path = Managers; - sourceTree = ""; - }; - 4369F090208B0D68000E3E45 /* Views */ = { - isa = PBXGroup; - children = ( - B4C004B2241085DB00B40429 /* ActionButton.swift */, - 89AF78C524482268002B4FCC /* ActionButtonStyle.swift */, - C1E4B307242E995200E70CCB /* ActivityIndicator.swift */, - 89BE75CA2464BC2000B145D9 /* AlertContent.swift */, - 43F5035821059AF7009FA89A /* AuthenticationTableViewCell.swift */, - 43F5035921059AF7009FA89A /* AuthenticationTableViewCell.xib */, - 898E6E64224179300019E459 /* BaseHUDView.swift */, - 898E6E66224179300019E459 /* BatteryLevelHUDView.swift */, - 898E6E65224179300019E459 /* BatteryLevelHUDView.xib */, - 893C9F8A2447DBC100CD4185 /* CardList */, - E9086B3424B3A8820062F5C8 /* ChartContainerView.swift */, - E9086B3024B3A7270062F5C8 /* ChartTableViewCell.swift */, - 1D096BF924C242300078B6B5 /* CheckmarkListItem.swift */, - 89627B172441168900BEB424 /* ConfigurationPage.swift */, - C14A7E7D295F43AB00CD87B4 /* ConfigurationPageScrollView.swift */, - 8997B4F423727E8A00061132 /* CustomOverrideCollectionViewCell.swift */, - 43D8FE591C7291D80073BE78 /* DatePickerTableViewCell.swift */, - 895FE07922011F0B00FCF18A /* DecimalTextFieldTableViewCell.xib */, - 89904031245B5CA500F1C0A2 /* Deletable.swift */, - B46B62B023FF0CA6001E69BA /* DescriptiveText.swift */, - 89CAB36A24C9EC25009EE3CE /* DismissibleKeyboardTextField.swift */, - 895FE07B22011F0C00FCF18A /* DoubleRangeTableViewCell.swift */, - 895FE07222011F0B00FCF18A /* DoubleRangeTableViewCell.xib */, - 89186C0A24BFD6DB0003D0F3 /* DurationPicker.swift */, - 895FE07322011F0B00FCF18A /* EmojiDataSource.swift */, - 895FE07A22011F0C00FCF18A /* EmojiInputCell.swift */, - 895FE07E22011F0C00FCF18A /* EmojiInputHeaderView.swift */, - E9F54FC52581C50C0034795E /* ExpandableDatePicker.swift */, - E9DFB92B24E634E800468917 /* ExpandablePicker.swift */, - 899012C0246F1D8F007B88BA /* ExpandableSetting.swift */, - 89653C7F2473527100E1BAA5 /* FractionalQuantityPicker.swift */, - 43177D0B1D3734040006E908 /* GlucoseRangeOverrideTableViewCell.swift */, - 43177D071D37306D0006E908 /* GlucoseRangeOverrideTableViewCell.xib */, - 898B4E76246DAE280053C484 /* GlucoseRangePicker.swift */, - 43D8FE071C7290530073BE78 /* GlucoseRangeTableViewCell.swift */, - 43D8FE081C7290530073BE78 /* GlucoseRangeTableViewCell.xib */, - 89F6E313244A1AB600CB9E15 /* GlucoseValuePicker.swift */, - 898B4E7D246DEB920053C484 /* GuardrailConstrainedQuantityRangeView.swift */, - 89B0B2A92453C0AB0063D4A7 /* GuardrailConstraintedQuantityView.swift */, - 89F6E312244A1AB500CB9E15 /* GuardrailWarning.swift */, - B4C004B4241085DC00B40429 /* GuideNavigationButton.swift */, - B4C004B3241085DB00B40429 /* GuidePage.swift */, - 892A5DAD2231E185008961AB /* HUDAssets.xcassets */, - E9077D2824ACD5AA0066A88D /* Information Screens */, - B46B62A623FEFE4D001E69BA /* InstructionList.swift */, - 892155162245FBEF009112BC /* InsulinSensitivityScalingTableViewCell.swift */, - 892155172245FBEF009112BC /* InsulinSensitivityScalingTableViewCell.xib */, - C1742345259CD3ED00399C9D /* InsulinTypeChooser.swift */, - C1DD515A259FE3AB00DE27AE /* InsulinTypeSetting.swift */, - B46B62AC23FF0A87001E69BA /* LabeledDateView.swift */, - B46B62A823FF05F8001E69BA /* LabeledNumberInput.swift */, - B4A2AAB0240830A30066563F /* LabeledTextField.swift */, - 895FE07522011F0B00FCF18A /* LabeledTextFieldTableViewCell.swift */, - 895FE07D22011F0C00FCF18A /* LabeledTextFieldTableViewCell.xib */, - B46B62AA23FF0822001E69BA /* LabeledValueView.swift */, - 892A5DB02231E191008961AB /* LevelHUDView.swift */, - 892A5DB12231E191008961AB /* LevelMaskView.swift */, - 892A5DAF2231E191008961AB /* LoadingTableViewCell.swift */, - 89BE75C024649C2E00B145D9 /* ModalHeaderButtonBar.swift */, - B4A2AAB2240832350066563F /* MultipleSelectionList.swift */, - 89BE75C424649C8100B145D9 /* NewScheduleItemEditor.swift */, - E93E866324DCFB6D00FF40C8 /* OverrideHistoryCollectionViewCell.swift */, - 895FE07422011F0B00FCF18A /* OverridePresetCollectionViewCell.swift */, - 895FE07622011F0B00FCF18A /* OverrideSelectionFooterView.swift */, - 895FE07C22011F0C00FCF18A /* OverrideSelectionHeaderView.swift */, - E93E866924DD05FA00FF40C8 /* OverrideSelectionHistory.swift */, - E9E5E56924D5CCE800B5DFFE /* OverrideViewCell.swift */, - 4369F08E208859E6000E3E45 /* PaddedTextField.swift */, - 1D1065E6282DC3BB00026A70 /* PopoverLink.swift */, - C1E4B304242E98E900E70CCB /* ProgressIndicatorView.swift */, - C1E4B303242E98E900E70CCB /* ProgressView.swift */, - 89AC9DCA24529927004A6B8A /* QuantityPicker.swift */, - 89FC688B245A2D670075CF59 /* QuantityScheduleEditor.swift */, - 43D8FE0A1C7290530073BE78 /* RepeatingScheduleValueTableViewCell.swift */, - 43D8FE0B1C7290530073BE78 /* RepeatingScheduleValueTableViewCell.xib */, - 892A5DB62231E19F008961AB /* ReservoirVolumeHUDView.swift */, - 892A5DB52231E19F008961AB /* ReservoirVolumeHUDView.xib */, - 89BE75C224649C4C00B145D9 /* RoundedCorners.swift */, - 89FC688D245A2D680075CF59 /* ScheduleEditor.swift */, - 89FC688C245A2D680075CF59 /* ScheduleItemPicker.swift */, - 89FC688E245A2D680075CF59 /* ScheduleItemView.swift */, - B46B62AE23FF0BF6001E69BA /* SectionHeader.swift */, - 89186C0424BEC9CA0003D0F3 /* SegmentedControlTableViewCell.swift */, - E99A132D2557548300D3F5B3 /* SegmentedGaugeBar.swift */, - 892155142245C57E009112BC /* SegmentedGaugeBarLayer.swift */, - 892155122245C516009112BC /* SegmentedGaugeBarView.swift */, - B46B62B223FF0E62001E69BA /* SelectableLabel.swift */, - 892A5D63222F6B13008961AB /* SetConstrainedScheduleEntryTableViewCell.swift */, - 892A5D62222F6B13008961AB /* SetConstrainedScheduleEntryTableViewCell.xib */, - 89F6E310244A1AAB00CB9E15 /* SettingDescription.swift */, - E916F56724AD31F900BE3547 /* Settings Editors */, - 432CF86620D76AB90066B889 /* SettingsTableViewCell.swift */, - 432CF86820D76B320066B889 /* SetupButton.swift */, - 432CF86A20D76B9C0066B889 /* SetupIndicatorView.swift */, - 1D3E2972276031F80041F460 /* ResizeablePicker.swift */, - B4001CEF28CBC200002FB414 /* SingleSelectionCheckList.swift */, - 898E6E6D2241ED9F0019E459 /* SuspendResumeTableViewCell.swift */, - 432CF86C20D76C470066B889 /* SwitchTableViewCell.swift */, - B41A60AE23D1DB5B00636320 /* TableViewTitleLabel.swift */, - 4369F093208BA001000E3E45 /* TextButtonTableViewCell.swift */, - 434FF1F01CF29451000DB779 /* TextFieldTableViewCell.swift */, - 434FF1EF1CF29451000DB779 /* TextFieldTableViewCell.xib */, - 89CC35D32403450E008FB633 /* ThumbView.swift */, - 89AC9DCC24529D9B004A6B8A /* TimePicker.swift */, - 43F5034E210599DF009FA89A /* ValidatingIndicatorView.swift */, - 1D1065E8282DC54700026A70 /* VideoPlayView.swift */, - 1D1065E2282DAEE500026A70 /* VideoView.swift */, - 89CAB37024CB4DEC009EE3CE /* WarningView.swift */, - 1D1065E3282DAEE500026A70 /* WebView.swift */, - ); - path = Views; - sourceTree = ""; - }; - 437874B4202FDC8300A3D8B9 /* Persistence */ = { - isa = PBXGroup; - children = ( - C168CA77280DD00F002BD2A7 /* Model.xcdatamodeld */, - C1E84B8425C62FB100623C08 /* Modelv1v4.xcmappingmodel */, - A9BD318124F4548900994B83 /* Modelv3EntityMigrationPolicy.swift */, - 434113AC20F287DC00D05747 /* NSManagedObjectContext.swift */, - 43D8FEE21C7294D50073BE78 /* PersistenceController.swift */, - ); - path = Persistence; - sourceTree = ""; - }; - 437AFF1B203A45CF008C4892 /* Extensions */ = { - isa = PBXGroup; - children = ( - 437AFF1C203A45DB008C4892 /* CacheStore.swift */, - 437AFF1E203A763F008C4892 /* HKHealthStoreMock.swift */, - 437AFF20203AA740008C4892 /* NSManagedObjectContext.swift */, - 891A3FD22249990900378B27 /* DailyValueSchedule.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 437AFF22203BE382008C4892 /* Extensions */ = { - isa = PBXGroup; - children = ( - C187338329B9486200519CDF /* ClosedRange.swift */, - C187337F29B9486100519CDF /* Collection.swift */, - C187338029B9486100519CDF /* Comparable.swift */, - C187338629B9486200519CDF /* Data.swift */, - 43D8FDF01C7290350073BE78 /* Date.swift */, - C187338929B9486200519CDF /* DateFormatter.swift */, - 43D8FDE91C7290350073BE78 /* Double.swift */, - 898C896C24D4BF75002FA994 /* FloatingPoint.swift */, - C187338529B9486200519CDF /* Guardrail+Settings.swift */, - 437AFF23203BE402008C4892 /* HKHealthStore.swift */, - A9FD046E24E310D00040F203 /* HKObject.swift */, - 43AF1FB11C926CDD00EA2F3D /* HKQuantity.swift */, - 432762731D60505F0083215A /* HKQuantitySample.swift */, - C187338129B9486100519CDF /* HKUnit.swift */, - C187338729B9486200519CDF /* MutableCollection.swift */, - 43CB51B0211EB16C00DB9B4A /* NSUserActivity+CarbKit.swift */, - C187338429B9486200519CDF /* NumberFormatter.swift */, - C187338829B9486200519CDF /* OSLog.swift */, - A967D94824F99B6A00CDDF8A /* OutputStream.swift */, - C187339529B9488300519CDF /* Sequence.swift */, - C187338229B9486200519CDF /* TimeInterval.swift */, - C187339629B9488300519CDF /* TimeZone.swift */, - C187339729B9488300519CDF /* UUID.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 439706E722D2E8EE00C81566 /* Views */ = { - isa = PBXGroup; - children = ( - 439706E822D2E94800C81566 /* BoundSwitchTableViewCell.swift */, - C1E0EEF524EB26D800086510 /* DeliveryUncertaintyRecoveryView.swift */, - ); - path = Views; - sourceTree = ""; - }; - 43BA7155201E484D0058961E /* LoopKitUI */ = { - isa = PBXGroup; - children = ( - C1CEBFDE29BB72EA007FD8A3 /* Resources */, - C18733B529B9495400519CDF /* LocalizedString.swift */, - E9086B4624B5404D0062F5C8 /* Models */, - E9086B4324B53CB40062F5C8 /* Charts */, - B41A60B023D1DBB700636320 /* Extensions */, - 43BA7160201E48910058961E /* CarbKit */, - 43A8EC3B210CEEA500A81379 /* CGMManagerUI.swift */, - 892A5D9F2231E12F008961AB /* CompletionNotifying.swift */, - 1DE35E7924ABEC720086F9AE /* DeviceManagerUI.swift */, - C1FAEC1C264AD6B400A3250B /* DeviceStatusBadge.swift */, - B4B1162D25AF3A40006428DE /* DisplayGlucoseUnitObserver.swift */, - 892A5DA12231E136008961AB /* HUDProvider.swift */, - 43BA7157201E484D0058961E /* Info.plist */, - 1D096C0424C624F70078B6B5 /* InsulinModelSettings+LoopKitUI.swift */, - 43BA7161201E48EB0058961E /* InsulinKit */, - 43BA7156201E484D0058961E /* LoopKitUI.h */, - C16DA84422E9330A008624C2 /* LoopUIPlugin.swift */, - A9DCF2C925B0F38000C89088 /* LoopUIColorPalette.swift */, - A9CFCA8E2582F9FA00A04932 /* OnboardingUI.swift */, - 895FE06C22011E9900FCF18A /* OverrideEmojiDataSource.swift */, - 43FB60E220DCB9E0002B996B /* PumpManagerUI.swift */, - 43F503622106C761009FA89A /* ServiceAuthenticationUI.swift */, - 43F5035521059A8A009FA89A /* ServiceCredential.swift */, - A9498D8A23386CC700DAA9B9 /* ServiceUI.swift */, - 892A5D9D2231E122008961AB /* StateColorPalette.swift */, - A9CFCAA42582FA0400A04932 /* SupportUI.swift */, - 43F89C9E22BDFB10006BB54E /* UIActivityIndicatorView.swift */, - 892A5D9B2231E118008961AB /* UIAlertController.swift */, - 898E6E6B224194050019E459 /* UIColor.swift */, - A9012EB125BA3861000813AD /* SetupUIResult.swift */, - 1DD1964D248AE88000420876 /* HorizontalSizeClassOverride.swift */, - 432CF86320D769070066B889 /* View Controllers */, - B4D4C20B25F95A6700DA809D /* ViewModels */, - 4369F090208B0D68000E3E45 /* Views */, - E9086B2E24B3A5080062F5C8 /* ChartColorPalette.swift */, - ); - path = LoopKitUI; - sourceTree = ""; - }; - 43BA7160201E48910058961E /* CarbKit */ = { - isa = PBXGroup; - children = ( - 432711371EDE826A00171F6A /* CustomInputTextField.swift */, - B40D07C9251BD89D00C1C6D7 /* DateAndDurationSteppableTableViewCell.swift */, - B40D07C8251BD89D00C1C6D7 /* DateAndDurationSteppableTableViewCell.xib */, - 434A01CF1F019D9100938125 /* DateAndDurationTableViewCell.xib */, - 4369F091208B0DFF000E3E45 /* DateAndDurationTableViewCell.swift */, - 43D8FE5A1C7291D80073BE78 /* DecimalTextFieldTableViewCell.swift */, - 4359E74D1EEA1FBC0022EF0C /* FoodEmojiDataSource.swift */, - 433D705D1EFB29700004EB9F /* FoodTypeShortcutCell.swift */, - ); - path = CarbKit; - sourceTree = ""; - }; - 43BA7161201E48EB0058961E /* InsulinKit */ = { - isa = PBXGroup; - children = ( - 43D8FEEF1C7294E90073BE78 /* ErrorBackgroundView.swift */, - E9DFB92F24E8CA8500468917 /* LegacyInsulinDeliveryTableViewController.swift */, - ); - path = InsulinKit; - sourceTree = ""; - }; - 43BA718D202020140058961E /* Frameworks */ = { - isa = PBXGroup; - children = ( - A9E675F4227140DD00E25293 /* HealthKit.framework */, - 4353D172203D3E7E007B4ECD /* CoreData.framework */, - A9E675F2227140D800E25293 /* CoreData.framework */, - 4301582C1C7ECD7A00B64B63 /* HealthKit.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 43D8FDC11C728FDF0073BE78 = { - isa = PBXGroup; - children = ( - 43D8FDCD1C728FDF0073BE78 /* LoopKit */, - 430157F81C7EC03B00B64B63 /* LoopKit Example */, - 1DEE230524A6960400693C32 /* LoopKitHostedTests */, - 43D8FDD91C728FDF0073BE78 /* LoopKitTests */, - 43BA7155201E484D0058961E /* LoopKitUI */, - 89D2047321CC7BD7001238CC /* MockKit */, - 89D2049021CC7C13001238CC /* MockKitUI */, - 892A5D35222F03CB008961AB /* LoopTestingKit */, - B4CEE2E1257129780093111B /* MockKitTests */, - 43BA718D202020140058961E /* Frameworks */, - 43D8FDCC1C728FDF0073BE78 /* Products */, - ); - sourceTree = ""; - }; - 43D8FDCC1C728FDF0073BE78 /* Products */ = { - isa = PBXGroup; - children = ( - 43D8FDCB1C728FDF0073BE78 /* LoopKit.framework */, - 43D8FDD51C728FDF0073BE78 /* LoopKitTests.xctest */, - 430157F71C7EC03B00B64B63 /* LoopKit Example.app */, - 43BA7154201E484D0058961E /* LoopKitUI.framework */, - 89D2047221CC7BD7001238CC /* MockKit.framework */, - 89D2048F21CC7C12001238CC /* MockKitUI.framework */, - 892A5D34222F03CB008961AB /* LoopTestingKit.framework */, - A9E675F022713F4700E25293 /* LoopKit.framework */, - 1DEE230124A676A300693C32 /* LoopKitHostedTests.xctest */, - B4CEE2E0257129780093111B /* MockKitTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 43D8FDCD1C728FDF0073BE78 /* LoopKit */ = { - isa = PBXGroup; - children = ( - 1DA649AA2445174400F61E75 /* Alert.swift */, - A96E6C3627B35BC600F81A5B /* AnyCodableEquatable.swift */, - C109240E286A4AD500FAD2B8 /* AutomaticDosingStrategy.swift */, - 43D8FDE51C7290340073BE78 /* BasalRateSchedule.swift */, - A93761C025ED670200F6BE43 /* BluetoothProvider.swift */, - 43D8FE2B1C72914D0073BE78 /* CarbKit */, - 43D8FDE61C7290350073BE78 /* CarbRatioSchedule.swift */, - 891A3FDA224BEC0D00378B27 /* CarbSensitivitySchedule.swift */, - 1D1FCE2624BE4DE2000300A8 /* CorrectionRangeOverrides.swift */, - A933DB8724BF956F009B417A /* CriticalEventLog.swift */, - 43D8FDE71C7290350073BE78 /* DailyQuantitySchedule.swift */, - 891A3FD4224B047200378B27 /* DailyQuantitySchedule+Override.swift */, - 43D8FDE81C7290350073BE78 /* DailyValueSchedule.swift */, - 1DC64C7D24BF6EBC004A63A1 /* DeliveryLimits.swift */, - C17F39BD23CD239000FA1113 /* DeviceManager */, - A95A1D7E2460BBC70079378D /* DosingDecisionObject+CoreDataClass.swift */, - A95A1D812460BBDC0079378D /* DosingDecisionObject+CoreDataProperties.swift */, - A919889E2355016B00B75EEE /* DosingDecisionStore.swift */, - 891A3FD8224BEB4500378B27 /* EGPSchedule.swift */, - 437AFF22203BE382008C4892 /* Extensions */, - 43C9805B212D216A003B5D17 /* GlucoseChange.swift */, - 43D8FDEA1C7290350073BE78 /* GlucoseEffect.swift */, - 4378B64A1ED61965000AE785 /* GlucoseEffectVelocity.swift */, - 43D8FE701C7293070073BE78 /* GlucoseKit */, - B455F4D22600DA0B000ED456 /* GlucoseRange.swift */, - 43D8FDEB1C7290350073BE78 /* GlucoseRangeSchedule.swift */, - 14B33264293ED44C009B8746 /* GlucoseRangeSchedule+SafeBounds.swift */, - 43D8FDEC1C7290350073BE78 /* GlucoseSchedule.swift */, - A9498D7423386C3200DAA9B9 /* GlucoseThreshold.swift */, - 43D9888A1C87E47800DA4467 /* GlucoseValue.swift */, - 89F6E30E244A1A5D00CB9E15 /* Guardrail.swift */, - 43D8FDED1C7290350073BE78 /* HealthKitSampleStore.swift */, - 43B17C88208EEC0B00AC27E9 /* HealthStoreUnitCache.swift */, - 43D8FDD01C728FDF0073BE78 /* Info.plist */, - 1D096BFD24C24C140078B6B5 /* Insulin */, - 43D8FEB21C7294520073BE78 /* InsulinKit */, - A987CD4524A5893500439ADC /* JSONStreamEncoder.swift */, - 43F5034A21051FCD009FA89A /* KeychainManager.swift */, - C187337D29B9481500519CDF /* LocalizedString.swift */, - 89AC792E224C781200B8E9BA /* Locked.swift */, - 43D8FDCE1C728FDF0073BE78 /* LoopKit.h */, - 43D8FDEF1C7290350073BE78 /* LoopMath.swift */, - C16DA83E22E8D88F008624C2 /* LoopPluginBundleKey.swift */, - B42A74702358858D00247B03 /* Notification */, - A985464E251449FE0099C1A6 /* NotificationSettings.swift */, - 437874B4202FDC8300A3D8B9 /* Persistence */, - 1D24A8D424C896E100AB8DB9 /* Prescription.swift */, - 434C5F9B2098352500B2FD1A /* QuantityFormatter.swift */, - C1CEBFDD29BB6C84007FD8A3 /* Resources */, - 43D8FDF31C7290350073BE78 /* SampleValue.swift */, - 1D63DEA126E94F6B00F46FA5 /* Service */, - 43F5035421059A8A009FA89A /* ServiceAuthentication.swift */, - A912BE28245B9CD500CBE199 /* SettingsObject+CoreDataClass.swift */, - A912BE2A245B9E8600CBE199 /* SettingsObject+CoreDataProperties.swift */, - A919889B2354E5EB00B75EEE /* SettingsStore.swift */, - C1CAB9E826A3254800A57273 /* StoredInsulinModel.swift */, - A932803A2798D63B0091D0A1 /* SyncAlertObject.swift */, - 89AE2223228BC54C00BDFD85 /* TemporaryScheduleOverride.swift */, - 89AE2225228BC54C00BDFD85 /* TemporaryScheduleOverrideHistory.swift */, - 89AE221F228BC54C00BDFD85 /* TemporaryScheduleOverridePreset.swift */, - 89AE2224228BC54C00BDFD85 /* TemporaryScheduleOverrideSettings.swift */, - 1D1FCE2824BE4F11000300A8 /* TherapySetting.swift */, - E9086B3824B3CB4B0062F5C8 /* TherapySettings.swift */, - C1ABE38D2245CFCD00570E82 /* UnfairLock.swift */, - 1D63DEA226E94FDF00F46FA5 /* VersionUpdate.swift */, - 89AE222A228BC56A00BDFD85 /* WeakSet.swift */, - C1814B8B226371DF008D2D8E /* WeakSynchronizedDelegate.swift */, - 43CACE0D2247F89100F90AF5 /* WeakSynchronizedSet.swift */, - ); - path = LoopKit; - sourceTree = ""; - }; - 43D8FDD91C728FDF0073BE78 /* LoopKitTests */ = { - isa = PBXGroup; - children = ( - 43D8FDDC1C728FDF0073BE78 /* Info.plist */, - 1DFB99D5245CB2E900DCC8C9 /* AlertTests.swift */, - 43D8FE1A1C72906E0073BE78 /* BasalRateScheduleTests.swift */, - A95A1D8A2460FD620079378D /* BolusRecommendationTests.swift */, - 43D8FE411C7291900073BE78 /* CarbMathTests.swift */, - 437AFF192039F149008C4892 /* CarbStoreTests.swift */, - A95A1D842460CAD50079378D /* CarbValueTests.swift */, - A9B0D97D273313EB00D96D93 /* CGMManagerStatusTests.swift */, - C1E7035C24FFFA5C00DAB534 /* CollectionTests.swift */, - B455F35525FC0284000ED456 /* CorrectionRangeOverridesTests.swift */, - A9DF02C824F724D900B7C988 /* CriticalEventLogTests.swift */, - A9BFA03D245CCCB9001E4AE3 /* DailyQuantityScheduleTests.swift */, - 891A3FD6224BE62100378B27 /* DailyValueScheduleTests.swift */, - A95A1D8C246101760079378D /* DoseEntryTests.swift */, - B4CEE2A4256E91290093111B /* DoseProgressTests.swift */, - 43A067121F245A2F00E9E90F /* DoseStoreTests.swift */, - A971C8A323C6B1890099BEFC /* DosingDecisionStoreTests.swift */, - 43D8FE991C7293D00073BE78 /* GlucoseMathTests.swift */, - B46E095625F7E5910025A04D /* GlucoseRangeScheduleTests.swift */, - B455F4DE2600E0A8000ED456 /* GlucoseRangeTests.swift */, - A971C89E23C68B030099BEFC /* GlucoseStoreTests.swift */, - A99C73762339A67A00C80963 /* GlucoseThresholdTests.swift */, - A95A1D862460F1250079378D /* GlucoseValueTests.swift */, - 898C897024D4C0E4002FA994 /* GuardrailTests.swift */, - 1D0E708426BDE3BB00AECF0D /* HKDeviceCodableTests.swift */, - B4B7C1762603F5F6007379F6 /* HKUnitTests.swift */, - 43D8FEC81C7294640073BE78 /* InsulinMathTests.swift */, - B4B7C1602603F241007379F6 /* InsulinSensitivityScheduleTests.swift */, - A9DF02CE24F732FC00B7C988 /* JSONStreamEncoderTests.swift */, - 43D8FDDA1C728FDF0073BE78 /* LoopKitTests.swift */, - 43D9888C1C87EBE400DA4467 /* LoopMathTests.swift */, - A9672B5226E80C060025B0CD /* NewGlucoseSampleTests.swift */, - A91263862790B45300C6C950 /* NewPumpEventTests.swift */, - A985465025144ABA0099C1A6 /* NotificationSettingsTests.swift */, - 43D8FE1B1C72906E0073BE78 /* NSDateTests.swift */, - A985464A251442010099C1A6 /* OutputStreamTests.swift */, - B46E096C25F80D6C0025A04D /* OverrideTests.swift */, - A9DF02D024F7449E00B7C988 /* PersistentDeviceLogTests.swift */, - A95A1D882460F8930079378D /* PumpManagerStatusTests.swift */, - 434C5F9F209ABD4700B2FD1A /* QuantityFormatterTests.swift */, - 43D8FE1C1C72906E0073BE78 /* QuantityScheduleTests.swift */, - A99C73782339ACDC00C80963 /* ServiceTests.swift */, - A971C8A123C6B17D0099BEFC /* SettingsStoreTests.swift */, - A963B277252CE2510062AA12 /* StoredCarbEntryTests.swift */, - A9E068102534D87800BDAB59 /* StoredGlucoseSampleTests.swift */, - A99C7372233990D400C80963 /* TempBasalRecommendationTests.swift */, - 891A3FD02249948A00378B27 /* TemporaryScheduleOverrideHistoryTests.swift */, - 8974AFBF22120D7A0043F01B /* TemporaryScheduleOverrideTests.swift */, - E93C86AF24CF7C470073089B /* TherapySettingsTests.swift */, - 1D70C40C26F01D9F00C62570 /* VersionCheckServiceTests.swift */, - 437AFF1B203A45CF008C4892 /* Extensions */, - 43D988911C87FEFF00DA4467 /* Fixtures */, - 434113B620F2BDB900D05747 /* Persistence */, - ); - path = LoopKitTests; - sourceTree = ""; - }; - 43D8FE2B1C72914D0073BE78 /* CarbKit */ = { - isa = PBXGroup; - children = ( - 4378B64C1ED61C22000AE785 /* AbsorbedCarbValue.swift */, - 437AFEE92036A156008C4892 /* CachedCarbObject+CoreDataClass.swift */, - 437AFEEA2036A156008C4892 /* CachedCarbObject+CoreDataProperties.swift */, - 43D8FE4A1C7291BD0073BE78 /* CarbEntry.swift */, - 43D8FE4B1C7291BD0073BE78 /* CarbMath.swift */, - 4378B6501ED62D8D000AE785 /* CarbStatus.swift */, - 43D8FE4C1C7291BD0073BE78 /* CarbStore.swift */, - 4353D16E203D104F007B4ECD /* CarbStoreError.swift */, - 4378B64E1ED61C64000AE785 /* CarbValue.swift */, - 43D8FE4D1C7291BD0073BE78 /* HKQuantitySample+CarbKit.swift */, - 43D8FE5B1C7291D80073BE78 /* NewCarbEntry.swift */, - 4346D1FB1C79481E00ABAFE3 /* NSUserDefaults.swift */, - 43D8FE4E1C7291BD0073BE78 /* StoredCarbEntry.swift */, - A9E1E6A824E1B6700073CA39 /* SyncCarbObject.swift */, - ); - path = CarbKit; - sourceTree = ""; - }; - 43D8FE431C7291930073BE78 /* CarbKit */ = { - isa = PBXGroup; - children = ( - E9E5E56424D362E900B5DFFE /* dynamic_glucose_effect_fully_observed_output.json */, - E9E5E56224D362E800B5DFFE /* dynamic_glucose_effect_never_fully_observed_output.json */, - E9E5E56124D362E800B5DFFE /* dynamic_glucose_effect_none_observed_output.json */, - E9E5E56324D362E800B5DFFE /* dynamic_glucose_effect_partially_observed_output.json */, - 43D8FE441C7291A60073BE78 /* carb_effect_from_history_input.json */, - 43D8FE451C7291A60073BE78 /* carb_effect_from_history_output.json */, - C17F4CB21EE9B6DF005079B1 /* carb_entry_input.json */, - 43D8FE461C7291A60073BE78 /* carbs_on_board_output.json */, - 43EBE44C1EAC7F0C0073A0B5 /* grouped_by_overlapping_absorption_times_border_case_input.json */, - 43EBE44B1EAC7F0C0073A0B5 /* grouped_by_overlapping_absorption_times_border_case_output.json */, - 43EBE4471EAC77290073A0B5 /* grouped_by_overlapping_absorption_times_input.json */, - 43EBE4481EAC77290073A0B5 /* grouped_by_overlapping_absorption_times_output.json */, - C1CBF61B1EEA2A1E001E4851 /* ice_1_hour_input.json */, - 439BCD8F1EEDD2AD00100EAA /* ice_1_hour_output.json */, - C1110E981EE98CF5009BB852 /* ice_35_min_input.json */, - 439BCD8D1EEDD22900100EAA /* ice_35_min_none_output.json */, - 4359E74F1EED04330022EF0C /* ice_35_min_partial_output.json */, - 439BCD911EEDD33F00100EAA /* ice_slow_absorption_output.json */, - C13E6D291EEB1CB9006F5880 /* ice_slow_absorption.json */, - 9E78433E236653F00016C583 /* ice_35_min_none_piecewiselinear_output.json */, - 9E784340236656770016C583 /* ice_35_min_partial_piecewiselinear_output.json */, - 9E784342236659BD0016C583 /* ice_slow_absorption_piecewiselinear_output.json */, - 9E78434423665B5A0016C583 /* ice_35_min_partial_piecewiselinear_adaptiverate_output.json */, - ); - path = CarbKit; - sourceTree = ""; - }; - 43D8FE701C7293070073BE78 /* GlucoseKit */ = { - isa = PBXGroup; - children = ( - 433BC7A820538D4C000B1200 /* CachedGlucoseObject+CoreDataClass.swift */, - 433BC7A920538D4C000B1200 /* CachedGlucoseObject+CoreDataProperties.swift */, - A935094326E2FAB70030B60D /* GlucoseCondition.swift */, - 432CF87020D76D5A0066B889 /* GlucoseDisplayable.swift */, - 43D8FE861C72934C0073BE78 /* GlucoseMath.swift */, - B4B85FCC24A2312000A296A3 /* GlucoseRangeCategory.swift */, - 43971A3F1C8CABFF0013154F /* GlucoseSampleValue.swift */, - 43D8FE871C72934C0073BE78 /* GlucoseStore.swift */, - 432CF86E20D76CCF0066B889 /* GlucoseTrend.swift */, - 1DD9CE9826B8CC2A008B4A46 /* HKDevice+Encodable.swift */, - 43FADDFA1C89679200DDE013 /* HKQuantitySample+GlucoseKit.swift */, - 433BC7A620523DB7000B1200 /* NewGlucoseSample.swift */, - 433BC7AC20538FCA000B1200 /* StoredGlucoseSample.swift */, - ); - path = GlucoseKit; - sourceTree = ""; - }; - 43D8FE9B1C7293EB0073BE78 /* GlucoseKit */ = { - isa = PBXGroup; - children = ( - 435D2924205F3A670026F401 /* counteraction_effect_falling_glucose_almost_duplicates_input.json */, - 435D292A205F46180026F401 /* counteraction_effect_falling_glucose_almost_duplicates_output.json */, - 435D2926205F3C750026F401 /* counteraction_effect_falling_glucose_double_entries._input.json */, - 43439520205F2D910056DC37 /* counteraction_effect_falling_glucose_input.json */, - 435D292C205F48750026F401 /* counteraction_effect_falling_glucose_insulin.json */, - 4343951E205EED1F0056DC37 /* counteraction_effect_falling_glucose_output.json */, - 43D8FE9C1C7293FA0073BE78 /* momentum_effect_bouncing_glucose_input.json */, - 43D8FE9D1C7293FA0073BE78 /* momentum_effect_bouncing_glucose_output.json */, - 43971A411C8CAEF20013154F /* momentum_effect_display_only_glucose_input.json */, - 4303C48B1E29DD4200ADEDC8 /* momentum_effect_duplicate_glucose_input.json */, - 43D8FE9E1C7293FA0073BE78 /* momentum_effect_falling_glucose_input.json */, - 43D8FE9F1C7293FA0073BE78 /* momentum_effect_falling_glucose_output.json */, - B46FA3F2253F00DC00D993E2 /* momentum_effect_impossible_rising_glucose_input.json */, - B46FA3F1253F00DC00D993E2 /* momentum_effect_impossible_rising_glucose_output.json */, - 43DC87B51C8A9567005BC30D /* momentum_effect_incomplete_glucose_input.json */, - 43C27D921E3C4E7D00613CE1 /* momentum_effect_mixed_provenance_glucose_input.json */, - 435D2927205F3C750026F401 /* momentum_effect_rising_glucose_double_entries_input.json */, - 43D8FEA01C7293FA0073BE78 /* momentum_effect_rising_glucose_input.json */, - 43D8FEA11C7293FA0073BE78 /* momentum_effect_rising_glucose_output.json */, - 43D8FEA21C7293FA0073BE78 /* momentum_effect_stable_glucose_input.json */, - 43D8FEA31C7293FA0073BE78 /* momentum_effect_stable_glucose_output.json */, - ); - path = GlucoseKit; - sourceTree = ""; - }; - 43D8FEB21C7294520073BE78 /* InsulinKit */ = { - isa = PBXGroup; - children = ( - C191D26225B3815000C26C0B /* AutomaticDoseRecommendation.swift */, - 434113A820F171CB00D05747 /* CachedInsulinDeliveryObject+CoreDataClass.swift */, - 434113A920F171CB00D05747 /* CachedInsulinDeliveryObject+CoreDataProperties.swift */, - 43D8FEDC1C7294D50073BE78 /* DoseEntry.swift */, - 43D8FEDD1C7294D50073BE78 /* DoseStore.swift */, - 43A0670E1F23CAC700E9E90F /* DoseType.swift */, - 43C094451CAA1E98001F6403 /* DoseUnit.swift */, - C1DB55B21F2E964400C483A2 /* ExponentialInsulinModel.swift */, - 437B064D1F2EB35800D95237 /* HKQuantitySample+InsulinKit.swift */, - 438207701F2AE9A300886C13 /* InsulinDeliveryStore.swift */, - 43D8FEDF1C7294D50073BE78 /* InsulinMath.swift */, - C12EE16B1F2964B3007DB9F1 /* InsulinModel.swift */, - E9F54F5D25802D5E0034795E /* InsulinType.swift */, - 43DFE2811CB1FB8500EFBE95 /* InsulinValue.swift */, - C140DFFE260276BF000A4FF7 /* ManualBolusRecommendation.swift */, - 4302F4EA1D50670500F0FCAF /* NewPumpEvent.swift */, - 4302F4EC1D5068CE00F0FCAF /* PersistedPumpEvent.swift */, - A93CA898278D08CC003B5A01 /* PumpAlarmType.swift */, - 43DFE27B1CB1D6A600EFBE95 /* PumpEvent+CoreDataClass.swift */, - 43DFE27C1CB1D6A600EFBE95 /* PumpEvent+CoreDataProperties.swift */, - 43DFE27F1CB1E12D00EFBE95 /* PumpEventType.swift */, - 43D8FEE31C7294D50073BE78 /* Reservoir.swift */, - 43D8FEE41C7294D50073BE78 /* Reservoir+CoreDataProperties.swift */, - 4302F4E81D5066F400F0FCAF /* ReservoirValue.swift */, - A9498D6E23386C0B00DAA9B9 /* TempBasalRecommendation.swift */, - C1DB55B01F2E95FD00C483A2 /* WalshInsulinModel.swift */, - ); - path = InsulinKit; - sourceTree = ""; - }; - 43D8FECA1C7294670073BE78 /* InsulinKit */ = { - isa = PBXGroup; - children = ( - E93E865F24DC82A500FF40C8 /* dose_history_with_delivered_units.json */, - E93E865B24DC75EF00FF40C8 /* basal_dose_with_expired.json */, - E93E865D24DC797A00FF40C8 /* basal_dose_with_delivered.json */, - 43B99B051C74552300D050F5 /* basal_dose.json */, - 43B99AFB1C744CE300D050F5 /* bolus_dose.json */, - 4333931E1F32E31C009466DC /* doses_overlay_basal_profile_output.json */, - E93E865924DC744300FF40C8 /* effect_from_basal_output_exponential.json */, - 43B99B071C74553900D050F5 /* effect_from_basal_output.json */, - E93E866124DC87AE00FF40C8 /* effect_from_history_exponential_delivered_units_output.json */, - 43B99AFD1C744E5F00D050F5 /* effect_from_bolus_output.json */, - 43B99AFF1C7450EE00D050F5 /* effect_from_history_output.json */, - 43CE7CE11CA9EA1A003CC1B0 /* iob_from_bolus_120min_output.json */, - 43CE7CE31CA9EB1E003CC1B0 /* iob_from_bolus_180min_output.json */, - E9DFB92D24E8A75C00468917 /* iob_from_multiple_curves_output.json */, - 43CE7CDF1CA9E8B0003CC1B0 /* iob_from_bolus_240min_output.json */, - 43CE7CE51CA9EBD2003CC1B0 /* iob_from_bolus_300min_output.json */, - 43CE7CE71CA9EC1F003CC1B0 /* iob_from_bolus_312min_output.json */, - 43CE7CE91CA9EC50003CC1B0 /* iob_from_bolus_360min_output.json */, - 43CE7CEB1CA9EC88003CC1B0 /* iob_from_bolus_420min_output.json */, - C1DB55B61F2EACD500C483A2 /* iob_from_bolus_exponential_output.json */, - C1DB55B41F2EA6EA00C483A2 /* iob_from_doses_exponential_output.json */, - 43D8FECE1C7294B80073BE78 /* iob_from_doses_output.json */, - 43D8FECF1C7294B80073BE78 /* iob_from_reservoir_output.json */, - 43CE7CED1CA9F2CF003CC1B0 /* normalize_edge_case_doses_input.json */, - 43CE7CEF1CA9F32C003CC1B0 /* normalize_edge_case_doses_output.json */, - A914472427BF04170054A39D /* normalize_edge_case_doses_mutable_input.json */, - A914472627BF044C0054A39D /* normalize_edge_case_doses_mutable_output.json */, - 43B99B011C7451E500D050F5 /* normalized_doses.json */, - 43D8FED01C7294B80073BE78 /* normalized_reservoir_history_output.json */, - 434872781CB6256500E55D75 /* reconcile_history_input.json */, - 4348727C1CB626E500E55D75 /* reconcile_history_output.json */, - 43BDD7E71F804ED5005BA15C /* reconcile_resume_before_rewind_input.json */, - 43BDD7E91F8050C3005BA15C /* reconcile_resume_before_rewind_output.json */, - 434FB6471D70096A007B9C70 /* reservoir_history_with_continuity_holes.json */, - 43D8FED11C7294B80073BE78 /* reservoir_history_with_rewind_and_prime_input.json */, - 43D8FED21C7294B80073BE78 /* reservoir_history_with_rewind_and_prime_output.json */, - C1FAC06228C7B0A100754AE2 /* reservoir_iob_test.json */, - 43B99B031C74538D00D050F5 /* short_basal_dose.json */, - 4378B6441ED55F8C000AE785 /* suspend_dose_reconciled_normalized_iob.json */, - 4378B6451ED55F8C000AE785 /* suspend_dose_reconciled_normalized.json */, - 4378B6461ED55F8C000AE785 /* suspend_dose_reconciled.json */, - 4378B6421ED55E81000AE785 /* suspend_dose.json */, - C1D56375296B3F5E00BA15EC /* reservoir_for_iob_missing.json */, - ); - path = InsulinKit; - sourceTree = ""; - }; - 43D988911C87FEFF00DA4467 /* Fixtures */ = { - isa = PBXGroup; - children = ( - 43D8FE431C7291930073BE78 /* CarbKit */, - 43D8FE9B1C7293EB0073BE78 /* GlucoseKit */, - 43D8FECA1C7294670073BE78 /* InsulinKit */, - 43D8FEF41C7295490073BE78 /* basal.json */, - 43DC87BD1C8AD41D005BC30D /* glucose_from_effects_non_zero_output.json */, - 43DC87B91C8AD0ED005BC30D /* glucose_from_effects_non_zero_insulin_input.json */, - 43DC87BA1C8AD0ED005BC30D /* glucose_from_effects_non_zero_carb_input.json */, - 43DC87B71C8AD058005BC30D /* glucose_from_effects_non_zero_glucose_input.json */, - 43D988921C87FFA300DA4467 /* glucose_from_effects_no_momentum_output.json */, - 43D988931C87FFA300DA4467 /* glucose_from_effects_momentum_up_output.json */, - 43D988941C87FFA300DA4467 /* glucose_from_effects_momentum_up_input.json */, - 43D988951C87FFA300DA4467 /* glucose_from_effects_momentum_flat_output.json */, - 43D988961C87FFA300DA4467 /* glucose_from_effects_momentum_flat_input.json */, - 43D988971C87FFA300DA4467 /* glucose_from_effects_momentum_flat_glucose_input.json */, - 43D988981C87FFA300DA4467 /* glucose_from_effects_momentum_down_output.json */, - 43D988991C87FFA300DA4467 /* glucose_from_effects_momentum_down_input.json */, - 43D9889A1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_output.json */, - 43D9889B1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_momentum_input.json */, - 43D9889C1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_insulin_effect_input.json */, - 43D9889D1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_glucose_input.json */, - 43D9889E1C87FFA300DA4467 /* glucose_from_effects_insulin_effect_input.json */, - 43D9889F1C87FFA300DA4467 /* glucose_from_effects_glucose_input.json */, - 43D988A01C87FFA300DA4467 /* glucose_from_effects_carb_effect_input.json */, - 43C98059212BDEE4003B5D17 /* ice_minus_carb_effect_with_gaps_output.json */, - 43026D632132404900A332E2 /* ice_minus_flat_carb_effect_output.json */, - 43D8FE661C7292950073BE78 /* read_carb_ratios.json */, - ); - path = Fixtures; - sourceTree = ""; - }; - 892A5D35222F03CB008961AB /* LoopTestingKit */ = { - isa = PBXGroup; - children = ( - C187339B29B948D800519CDF /* Data.swift */, - 89ADE12C226BDD190067222B /* DateRelativeBasalEntry.swift */, - 89ADE12E226BDED40067222B /* DateRelativeBolusEntry.swift */, - 89ADE12A226BDB730067222B /* DateRelativeCarbEntry.swift */, - 89ADE135226BF0BE0067222B /* DateRelativeGlucoseSample.swift */, - 89CA2B37226D4456004D9350 /* DateRelativeQuantity.swift */, - C187339D29B948F200519CDF /* HKUnit.swift */, - 892A5D37222F03CB008961AB /* Info.plist */, - 892A5D36222F03CB008961AB /* LoopTestingKit.h */, - 892A5D55222F0414008961AB /* TestingCGMManager.swift */, - 892A5D51222F03DB008961AB /* TestingDeviceManager.swift */, - 892A5D53222F03F9008961AB /* TestingPumpManager.swift */, - 89ADE128226BDB280067222B /* TestingScenario.swift */, - 89ADE133226BF0490067222B /* TestingScenarioInstance.swift */, - ); - path = LoopTestingKit; - sourceTree = ""; - }; - 893C9F8A2447DBC100CD4185 /* CardList */ = { - isa = PBXGroup; - children = ( - 892ADDFF2446C858007CE08C /* Card.swift */, - 893C9F8B2447DBD900CD4185 /* CardBuilder.swift */, - 89627B15244115A400BEB424 /* CardList.swift */, - 89F6E30C2449713600CB9E15 /* CardStack.swift */, - 89AF78BF2447E285002B4FCC /* CardStackBuilder.swift */, - 89AF78C12447E353002B4FCC /* Splat.swift */, - ); - path = CardList; - sourceTree = ""; - }; - 8992426321EC137900EA512B /* Extensions */ = { - isa = PBXGroup; - children = ( - C18733C029B94A6300519CDF /* Comparable.swift */, - C18733C129B94A6300519CDF /* IdentifiableClass.swift */, - C18733C229B94A6300519CDF /* NibLoadable.swift */, - C18733BF29B94A6300519CDF /* NumberFormatter.swift */, - C18733C329B94A6300519CDF /* TimeInterval.swift */, - 8992426421EC138000EA512B /* UIColor.swift */, - C1FAEC20264AEEA300A3250B /* UIImage.swift */, - C18733C429B94A6300519CDF /* UITableViewCell.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 89D2047321CC7BD7001238CC /* MockKit */ = { - isa = PBXGroup; - children = ( - C1CEBFDF29BB731E007FD8A3 /* Resources */, - 89D204AD21CC7D2B001238CC /* Extensions */, - 89D2047521CC7BD7001238CC /* Info.plist */, - 89CCD4F121A87D340068C3FB /* MockCGMDataSource.swift */, - 89AB9EC821A4BC2400351324 /* MockCGMManager.swift */, - 89AC7934224C783500B8E9BA /* MockDoseProgressEstimator.swift */, - 89CCD4F721A8D5500068C3FB /* MockGlucoseProvider.swift */, - 89D2047421CC7BD7001238CC /* MockKit.h */, - 89AB9EC621A4774500351324 /* MockPumpManager.swift */, - C164A56322F21081000E3FA5 /* MockPumpManagerState.swift */, - A9498D8C23386CD700DAA9B9 /* MockService.swift */, - C164A55F22F14C73000E3FA5 /* UnfinalizedDose.swift */, - C15E994529C6790A004AB926 /* LocalizedString.swift */, - ); - path = MockKit; - sourceTree = ""; - }; - 89D2049021CC7C13001238CC /* MockKitUI */ = { - isa = PBXGroup; - children = ( - C18733CB29B94A7A00519CDF /* LocalizedString.swift */, - C1CEBFE029BB7342007FD8A3 /* Resources */, - 8992426321EC137900EA512B /* Extensions */, - 89D204B621CC7E77001238CC /* View Controllers */, - 439706E722D2E8EE00C81566 /* Views */, - A9498D9023386D0800DAA9B9 /* MockService+UI.swift */, - 89AB9ECA21A4C36200351324 /* MockPumpManager+UI.swift */, - 89CCD4F321A8A2B30068C3FB /* MockCGMManager+UI.swift */, - 892A5D2D222EF69A008961AB /* MockHUDProvider.swift */, - 1DFFB987271740EE0075AEAA /* MockSupport.swift */, - 89D2049121CC7C13001238CC /* MockKitUI.h */, - 89D2049221CC7C13001238CC /* Info.plist */, - ); - path = MockKitUI; - sourceTree = ""; - }; - 89D204AD21CC7D2B001238CC /* Extensions */ = { - isa = PBXGroup; - children = ( - 89DC540C21B75AE7005A1CE0 /* Collection.swift */, - C18733B929B94A3700519CDF /* HKUnit.swift */, - C18733BA29B94A3700519CDF /* TimeInterval.swift */, - C18733BB29B94A3700519CDF /* TimeZone.swift */, - B47ECF8725DC20810024A54D /* UIImage.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 89D204B621CC7E77001238CC /* View Controllers */ = { - isa = PBXGroup; - children = ( - 89D2046B21C83C3F001238CC /* GlucoseTrendTableViewController.swift */, - 1DABAD392453615200ACF708 /* IssueAlertTableViewController.swift */, - B42C950C24A3BD4B00857C73 /* MeasurementFrequencyTableViewController.swift */, - 89CCD4F521A8A6A60068C3FB /* MockCGMManagerSettingsViewController.swift */, - 89AB9ED521A4DE5F00351324 /* MockPumpManagerSettingsViewController.swift */, - A9498D8E23386CE800DAA9B9 /* MockServiceTableViewController.swift */, - 892F481A21AB2964004D313D /* RandomOutlierTableViewController.swift */, - 8907E35A21A9D1B200335852 /* SineCurveParametersTableViewController.swift */, - B45774342562CCC6004B9466 /* SupportedRangeTableViewController.swift */, - ); - path = "View Controllers"; - sourceTree = ""; - }; - A935793529A256F800246DED /* Actions */ = { - isa = PBXGroup; - children = ( - A935793A29A2570400246DED /* Action.swift */, - A935793929A2570400246DED /* BolusAction.swift */, - A935793629A2570300246DED /* CarbAction.swift */, - A935793829A2570400246DED /* OverrideAction.swift */, - A935793729A2570300246DED /* OverrideCancelAction.swift */, - ); - path = Actions; - sourceTree = ""; - }; - A98FF28F29A25699005739A5 /* Remote */ = { - isa = PBXGroup; - children = ( - A935793529A256F800246DED /* Actions */, - ); - path = Remote; - sourceTree = ""; - }; - A9E068142534EB6B00BDAB59 /* Persistence */ = { - isa = PBXGroup; - children = ( - A9E068152534EB8200BDAB59 /* CachedGlucoseObjectTests.swift */, - ); - path = Persistence; - sourceTree = ""; - }; - B41A60B023D1DBB700636320 /* Extensions */ = { - isa = PBXGroup; - children = ( - C18733B729B949FF00519CDF /* Data.swift */, - 898B4E74246CCAB50053C484 /* Binding.swift */, - E93C86A324C8F79C0073089B /* ChartLineModel+LoopKitUI.swift */, - E93C86A524C8F7D90073089B /* ChartSettings+LoopKitUI.swift */, - C18733A429B9492200519CDF /* Collection.swift */, - C1DE4C2025A253BD007065F8 /* Color.swift */, - C18733A729B9492300519CDF /* Comparable.swift */, - E9086B4924B540B70062F5C8 /* DateFormatter.swift */, - E96175AD24B7BE38008E5080 /* Dictionary.swift */, - 1D60355D24D39ED10095DC2A /* Environment+AppName.swift */, - 1D498E4624D892B0000627F2 /* Environment+Authenticate.swift */, - B45AF6EF24D4355A00EEAA4D /* Environment+Colors.swift */, - 89BE75C62464B4A900B145D9 /* Environment+Dismiss.swift */, - B429D66B24BF7204003E1B4A /* GlucoseTrend.swift */, - 89186C0624BF7FC70003D0F3 /* Guardrail+UI.swift */, - C18733A929B9492300519CDF /* HKUnit.swift */, - C18733A829B9492300519CDF /* IdentifiableClass.swift */, - C1E4B309242E99A800E70CCB /* Image.swift */, - 89CAB36C24C9EC98009EE3CE /* Keyboard.swift */, - C18733A629B9492300519CDF /* Math.swift */, - C18733A529B9492200519CDF /* NibLoadable.swift */, - C18733A329B9492200519CDF /* NSTimeInterval.swift */, - C187339F29B9492200519CDF /* NumberFormatter.swift */, - 89E7E60F24D11AB600591386 /* OrientationLock.swift */, - 1DC9240E2575EF9A004F132A /* QuantityFormatter+Guardrails.swift */, - C18733A229B9492200519CDF /* TimeZone.swift */, - B41A60B123D1DBC700636320 /* UIFont.swift */, - B429D66D24BF7255003E1B4A /* UIImage.swift */, - C18733A029B9492200519CDF /* UITableViewCell.swift */, - C18733A129B9492200519CDF /* UITextField.swift */, - 1D97A33B256F11E00042737E /* View+InsetGroupedListStyle.swift */, - 89CAB36E24C9ECCA009EE3CE /* View+KeyboardAware.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - B42A74702358858D00247B03 /* Notification */ = { - isa = PBXGroup; - children = ( - C1814B83225B9ED5008D2D8E /* LoopNotificationCategory.swift */, - B42A7471235885B600247B03 /* LoopNotificationUserInfoKey.swift */, - ); - path = Notification; - sourceTree = ""; - }; - B4CEE2E1257129780093111B /* MockKitTests */ = { - isa = PBXGroup; - children = ( - B4CEE2E2257129780093111B /* UnfinalizedDoseTests.swift */, - B4CEE2E4257129780093111B /* Info.plist */, - ); - path = MockKitTests; - sourceTree = ""; - }; - B4D4C20B25F95A6700DA809D /* ViewModels */ = { - isa = PBXGroup; - children = ( - B455F3A325FF7FF0000ED456 /* CorrectionRangeOverridesEditorViewModel.swift */, - B4B7C1BB2604E3FC007379F6 /* CorrectionRangeScheduleEditorViewModel.swift */, - B4D4C20C25F95A8700DA809D /* DisplayGlucoseUnitObservable.swift */, - B455F48025FF9A8B000ED456 /* InsulinSensitivityScheduleEditorViewModel.swift */, - B455F2A125FBE985000ED456 /* SuspendThresholdEditorViewModel.swift */, - 1D1FCE2424BD42EF000300A8 /* TherapySettingsViewModel.swift */, - ); - path = ViewModels; - sourceTree = ""; - }; - C17F39BD23CD239000FA1113 /* DeviceManager */ = { - isa = PBXGroup; - children = ( - C17F39BE23CD248000FA1113 /* DeviceLog */, - 1D841AAC24577EE10069DBFF /* AlertSoundPlayer.swift */, - 4352A73B20DECF0600CAC200 /* CGMManager.swift */, - A9A53E2B2714E5BC0050C0B1 /* CodableDevice.swift */, - B4102D3124ABB068005D460B /* DeviceLifecycleProgress.swift */, - 4379CFE221102A4100AADC79 /* DeviceManager.swift */, - B42C94FD24A2A2B000857C73 /* DeviceStatusHighlight.swift */, - 89AC792C224C781100B8E9BA /* DoseProgressReporter.swift */, - 89AC792D224C781100B8E9BA /* DoseProgressTimerEstimator.swift */, - 432CF87220D774220066B889 /* PumpManager.swift */, - 43FB610620DDF19B002B996B /* PumpManagerError.swift */, - 43FB60E820DCBE64002B996B /* PumpManagerStatus.swift */, - ); - path = DeviceManager; - sourceTree = ""; - }; - C17F39BE23CD248000FA1113 /* DeviceLog */ = { - isa = PBXGroup; - children = ( - C1F8403723DB84B700673141 /* DeviceLogEntry+CoreDataClass.swift */, - C1F8403823DB84B700673141 /* DeviceLogEntry+CoreDataProperties.swift */, - C17F39BF23CD24A000FA1113 /* DeviceLog.xcdatamodeld */, - C17F39C823CD269200FA1113 /* DeviceLogEntryType.swift */, - C17F39C623CD256000FA1113 /* PersistentDeviceLog.swift */, - C17F39CF23CE34B100FA1113 /* StoredDeviceLogEntry.swift */, - ); - path = DeviceLog; - sourceTree = ""; - }; - C1CEBFDD29BB6C84007FD8A3 /* Resources */ = { - isa = PBXGroup; - children = ( - 1F5DAB2B2118CE9300048054 /* Localizable.strings */, - ); - path = Resources; - sourceTree = ""; - }; - C1CEBFDE29BB72EA007FD8A3 /* Resources */ = { - isa = PBXGroup; - children = ( - 895FE07022011EDD00FCF18A /* EmojiInputController.storyboard */, - 43D8FEED1C7294E90073BE78 /* InsulinKit.storyboard */, - E9DFB93324E8CD5800468917 /* LegacyInsulinDeliveryTableViewController.storyboard */, - 7D68A9E31FE0A3D300522C49 /* Localizable.strings */, - 895FE06D22011E9A00FCF18A /* OverrideSelectionViewController.storyboard */, - 43177D091D3732C70006E908 /* Assets.xcassets */, - ); - path = Resources; - sourceTree = ""; - }; - C1CEBFDF29BB731E007FD8A3 /* Resources */ = { - isa = PBXGroup; - children = ( - B47ECFD525DC22D20024A54D /* Assets.xcassets */, - 1D640FF424524274008F9755 /* Sounds */, - 4B67E2CC289B4EDB002D92AF /* Localizable.strings */, - ); - path = Resources; - sourceTree = ""; - }; - C1CEBFE029BB7342007FD8A3 /* Resources */ = { - isa = PBXGroup; - children = ( - 89D204D121CC837A001238CC /* Assets.xcassets */, - C1D7162329C75DC700B5AB3B /* Localizable.strings */, - ); - path = Resources; - sourceTree = ""; - }; - E9077D2824ACD5AA0066A88D /* Information Screens */ = { - isa = PBXGroup; - children = ( - 1D67E79C2563001800A82ED6 /* InformationScreens.xcassets */, - E96DCB5D24AF7DC7007117BC /* BasalRatesInformationView.swift */, - E93C86B124D080E00073089B /* CarbRatioInformationView.swift */, - E9077D2924ACDE2C0066A88D /* CorrectionRangeInformationView.swift */, - E916F56E24AE2FFE00BE3547 /* CorrectionRangeOverrideInformationView.swift */, - E949E38824AFC82F00024DA0 /* DeliveryLimitsInformationView.swift */, - E9077D2624ACD59F0066A88D /* InformationView.swift */, - E949E38E24B3711E00024DA0 /* InsulinModelInformationView.swift */, - E93C86B524D08CAD0073089B /* InsulinSensitivityInformationView.swift */, - E96DCB5724AEF50F007117BC /* SuspendThresholdInformationView.swift */, - 1D1438B725633E2100BE8F06 /* GlucoseTherapySettingInformationView.swift */, - ); - path = "Information Screens"; - sourceTree = ""; - }; - E9086B4324B53CB40062F5C8 /* Charts */ = { - isa = PBXGroup; - children = ( - E9086B4424B53CC50062F5C8 /* GlucoseChart.swift */, - E93C86A124C8F7550073089B /* InsulinModelChart.swift */, - ); - path = Charts; - sourceTree = ""; - }; - E9086B4624B5404D0062F5C8 /* Models */ = { - isa = PBXGroup; - children = ( - E9086B4724B5405E0062F5C8 /* ChartAxisValueDoubleUnit.swift */, - B43DA43E24D49AA400CAFF4E /* GuidanceColors.swift */, - ); - path = Models; - sourceTree = ""; - }; - E916F56724AD31F900BE3547 /* Settings Editors */ = { - isa = PBXGroup; - children = ( - 89653C8324738D2B00E1BAA5 /* BasalRateScheduleEditor.swift */, - 89653C812473592600E1BAA5 /* CarbRatioScheduleEditor.swift */, - E916F56824AD32F000BE3547 /* CorrectionRangeOverridesEditor.swift */, - 1D1FCE2224BD13A2000300A8 /* CorrectionRangeOverridesExpandableSetting.swift */, - 1DC64C7B24BF6BFD004A63A1 /* CorrectionRangeOverridesExtension.swift */, - 898B4E7A246DC6A70053C484 /* CorrectionRangeScheduleEditor.swift */, - E94141CF24C8F31C0096C326 /* DeliveryLimitsEditor.swift */, - E93C86A724C8F7F60073089B /* InsulinModelChartView.swift */, - E93C869F24C8F6E00073089B /* InsulinModelSelection.swift */, - 89FC688A245A2D670075CF59 /* InsulinSensitivityScheduleEditor.swift */, - 1D6EAB9024C12C090081249D /* PumpSupportedIncrements.swift */, - C140E0512602908A000A4FF7 /* SettingsPresentationMode.swift */, - E96DCB5924AF74AC007117BC /* SuspendThresholdEditor.swift */, - 1D1FCE2A24BE704A000300A8 /* TherapySetting+Settings.swift */, - 1D1A019D24B678BF0077D86E /* TherapySettingsView.swift */, - ); - path = "Settings Editors"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 43BA7151201E484D0058961E /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 43BA7158201E484D0058961E /* LoopKitUI.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43D8FDC81C728FDF0073BE78 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 43D8FDCF1C728FDF0073BE78 /* LoopKit.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 892A5D2F222F03CB008961AB /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 892A5D46222F03CB008961AB /* LoopTestingKit.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 89D2046D21CC7BD7001238CC /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 89D2048221CC7BD8001238CC /* MockKit.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 89D2048A21CC7C12001238CC /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 89D2049F21CC7C13001238CC /* MockKitUI.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A9E675E822713F4700E25293 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - A9E675E922713F4700E25293 /* LoopKit.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 1DEE226824A676A300693C32 /* LoopKitHostedTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1DEE22FE24A676A300693C32 /* Build configuration list for PBXNativeTarget "LoopKitHostedTests" */; - buildPhases = ( - 1DEE226B24A676A300693C32 /* Sources */, - 1DEE229C24A676A300693C32 /* Frameworks */, - 1DEE229E24A676A300693C32 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 1DEE226924A676A300693C32 /* PBXTargetDependency */, - 1DEE230424A6774900693C32 /* PBXTargetDependency */, - ); - name = LoopKitHostedTests; - productName = LoopKitTests; - productReference = 1DEE230124A676A300693C32 /* LoopKitHostedTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 430157F61C7EC03B00B64B63 /* LoopKit Example */ = { - isa = PBXNativeTarget; - buildConfigurationList = 430158171C7EC03B00B64B63 /* Build configuration list for PBXNativeTarget "LoopKit Example" */; - buildPhases = ( - 430157F31C7EC03B00B64B63 /* Sources */, - 430157F41C7EC03B00B64B63 /* Frameworks */, - 430157F51C7EC03B00B64B63 /* Resources */, - 4301581D1C7ECB5E00B64B63 /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 4301581C1C7ECB5E00B64B63 /* PBXTargetDependency */, - 43BA715A201E484D0058961E /* PBXTargetDependency */, - 892A5D48222F03CB008961AB /* PBXTargetDependency */, - 43CACE1022483AC500F90AF5 /* PBXTargetDependency */, - 43CACE1222483AC500F90AF5 /* PBXTargetDependency */, - ); - name = "LoopKit Example"; - packageProductDependencies = ( - C1CCF1052858F07A0035389C /* SwiftCharts */, - ); - productName = "LoopKit Example"; - productReference = 430157F71C7EC03B00B64B63 /* LoopKit Example.app */; - productType = "com.apple.product-type.application"; - }; - 43BA7153201E484D0058961E /* LoopKitUI */ = { - isa = PBXNativeTarget; - buildConfigurationList = 43BA715F201E484D0058961E /* Build configuration list for PBXNativeTarget "LoopKitUI" */; - buildPhases = ( - 43BA7151201E484D0058961E /* Headers */, - 43BA714F201E484D0058961E /* Sources */, - 43BA7150201E484D0058961E /* Frameworks */, - 43BA7152201E484D0058961E /* Resources */, - C1CCF10A2858F1E10035389C /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - C1BECA96285902F5008075C4 /* PBXTargetDependency */, - ); - name = LoopKitUI; - packageProductDependencies = ( - C1CCF1072858F1E10035389C /* SwiftCharts */, - ); - productName = LoopKitUI; - productReference = 43BA7154201E484D0058961E /* LoopKitUI.framework */; - productType = "com.apple.product-type.framework"; - }; - 43D8FDCA1C728FDF0073BE78 /* LoopKit */ = { - isa = PBXNativeTarget; - buildConfigurationList = 43D8FDDF1C728FDF0073BE78 /* Build configuration list for PBXNativeTarget "LoopKit" */; - buildPhases = ( - 43D8FDC81C728FDF0073BE78 /* Headers */, - 43D8FDC61C728FDF0073BE78 /* Sources */, - 43D8FDC71C728FDF0073BE78 /* Frameworks */, - 43D8FDC91C728FDF0073BE78 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = LoopKit; - productName = LoopKit; - productReference = 43D8FDCB1C728FDF0073BE78 /* LoopKit.framework */; - productType = "com.apple.product-type.framework"; - }; - 43D8FDD41C728FDF0073BE78 /* LoopKitTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 43D8FDE21C728FDF0073BE78 /* Build configuration list for PBXNativeTarget "LoopKitTests" */; - buildPhases = ( - 43D8FDD11C728FDF0073BE78 /* Sources */, - 43D8FDD21C728FDF0073BE78 /* Frameworks */, - 43D8FDD31C728FDF0073BE78 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 43D8FDD81C728FDF0073BE78 /* PBXTargetDependency */, - ); - name = LoopKitTests; - productName = LoopKitTests; - productReference = 43D8FDD51C728FDF0073BE78 /* LoopKitTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 892A5D33222F03CB008961AB /* LoopTestingKit */ = { - isa = PBXNativeTarget; - buildConfigurationList = 89AE2220228BC54C00BDFD85 /* Build configuration list for PBXNativeTarget "LoopTestingKit" */; - buildPhases = ( - 892A5D2F222F03CB008961AB /* Headers */, - 892A5D30222F03CB008961AB /* Sources */, - 892A5D31222F03CB008961AB /* Frameworks */, - 892A5D32222F03CB008961AB /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 43CACE1822483B7200F90AF5 /* PBXTargetDependency */, - ); - name = LoopTestingKit; - productName = LoopTestingKit; - productReference = 892A5D34222F03CB008961AB /* LoopTestingKit.framework */; - productType = "com.apple.product-type.framework"; - }; - 89D2047121CC7BD7001238CC /* MockKit */ = { - isa = PBXNativeTarget; - buildConfigurationList = 89AE2221228BC54C00BDFD85 /* Build configuration list for PBXNativeTarget "MockKit" */; - buildPhases = ( - 89D2046D21CC7BD7001238CC /* Headers */, - 89D2046E21CC7BD7001238CC /* Sources */, - 89D2046F21CC7BD7001238CC /* Frameworks */, - 89D2047021CC7BD7001238CC /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - C1E0280C264C47C900EC4DF1 /* PBXTargetDependency */, - 43CACE1422483B6100F90AF5 /* PBXTargetDependency */, - 43CACE1622483B6100F90AF5 /* PBXTargetDependency */, - ); - name = MockKit; - productName = MockKit; - productReference = 89D2047221CC7BD7001238CC /* MockKit.framework */; - productType = "com.apple.product-type.framework"; - }; - 89D2048E21CC7C12001238CC /* MockKitUI */ = { - isa = PBXNativeTarget; - buildConfigurationList = 89AE2222228BC54C00BDFD85 /* Build configuration list for PBXNativeTarget "MockKitUI" */; - buildPhases = ( - 89D2048A21CC7C12001238CC /* Headers */, - 89D2048B21CC7C12001238CC /* Sources */, - 89D2048C21CC7C12001238CC /* Frameworks */, - 89D2048D21CC7C12001238CC /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - A9E6757D22713C3F00E25293 /* PBXTargetDependency */, - A9E6757B22713C3F00E25293 /* PBXTargetDependency */, - ); - name = MockKitUI; - productName = MockKitUI; - productReference = 89D2048F21CC7C12001238CC /* MockKitUI.framework */; - productType = "com.apple.product-type.framework"; - }; - A9E6758022713F4700E25293 /* LoopKit-watchOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = A9E675ED22713F4700E25293 /* Build configuration list for PBXNativeTarget "LoopKit-watchOS" */; - buildPhases = ( - A9E675E822713F4700E25293 /* Headers */, - A9E6758122713F4700E25293 /* Sources */, - A9E675E522713F4700E25293 /* Frameworks */, - A9E675EA22713F4700E25293 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "LoopKit-watchOS"; - productName = LoopKit; - productReference = A9E675F022713F4700E25293 /* LoopKit.framework */; - productType = "com.apple.product-type.framework"; - }; - B4CEE2DF257129780093111B /* MockKitTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = B4CEE2EA257129780093111B /* Build configuration list for PBXNativeTarget "MockKitTests" */; - buildPhases = ( - B4CEE2DC257129780093111B /* Sources */, - B4CEE2DD257129780093111B /* Frameworks */, - B4CEE2DE257129780093111B /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - B4CEE2E7257129780093111B /* PBXTargetDependency */, - ); - name = MockKitTests; - productName = MockKitTests; - productReference = B4CEE2E0257129780093111B /* MockKitTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 43D8FDC21C728FDF0073BE78 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 1210; - LastUpgradeCheck = 1220; - ORGANIZATIONNAME = "LoopKit Authors"; - TargetAttributes = { - 1DEE226824A676A300693C32 = { - TestTargetID = 430157F61C7EC03B00B64B63; - }; - 430157F61C7EC03B00B64B63 = { - CreatedOnToolsVersion = 7.2.1; - LastSwiftMigration = 1020; - SystemCapabilities = { - com.apple.HealthKit = { - enabled = 1; - }; - }; - }; - 43BA7153201E484D0058961E = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1020; - ProvisioningStyle = Automatic; - }; - 43D8FDCA1C728FDF0073BE78 = { - CreatedOnToolsVersion = 7.2.1; - LastSwiftMigration = 1020; - ProvisioningStyle = Automatic; - }; - 43D8FDD41C728FDF0073BE78 = { - CreatedOnToolsVersion = 7.2.1; - LastSwiftMigration = 1020; - }; - 892A5D33222F03CB008961AB = { - CreatedOnToolsVersion = 10.1; - LastSwiftMigration = 1020; - ProvisioningStyle = Automatic; - }; - 89D2047121CC7BD7001238CC = { - CreatedOnToolsVersion = 10.0; - LastSwiftMigration = 1020; - ProvisioningStyle = Automatic; - }; - 89D2048E21CC7C12001238CC = { - CreatedOnToolsVersion = 10.0; - LastSwiftMigration = 1020; - ProvisioningStyle = Automatic; - }; - A9E6758022713F4700E25293 = { - LastSwiftMigration = 1020; - ProvisioningStyle = Automatic; - }; - B4CEE2DF257129780093111B = { - CreatedOnToolsVersion = 12.1; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = 43D8FDC51C728FDF0073BE78 /* Build configuration list for PBXProject "LoopKit" */; - compatibilityVersion = "Xcode 8.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - es, - de, - fr, - "zh-Hans", - it, - nl, - nb, - pl, - ru, - da, - fi, - he, - ja, - "pt-BR", - ro, - sv, - tr, - vi, - cs, - ar, - hi, - sk, - hu, - ); - mainGroup = 43D8FDC11C728FDF0073BE78; - packageReferences = ( - C1CCF1042858F07A0035389C /* XCRemoteSwiftPackageReference "SwiftCharts" */, - ); - productRefGroup = 43D8FDCC1C728FDF0073BE78 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 430157F61C7EC03B00B64B63 /* LoopKit Example */, - 43D8FDCA1C728FDF0073BE78 /* LoopKit */, - A9E6758022713F4700E25293 /* LoopKit-watchOS */, - 43D8FDD41C728FDF0073BE78 /* LoopKitTests */, - 1DEE226824A676A300693C32 /* LoopKitHostedTests */, - 43BA7153201E484D0058961E /* LoopKitUI */, - 89D2047121CC7BD7001238CC /* MockKit */, - B4CEE2DF257129780093111B /* MockKitTests */, - 89D2048E21CC7C12001238CC /* MockKitUI */, - 892A5D33222F03CB008961AB /* LoopTestingKit */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 1DEE229E24A676A300693C32 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 1DD65CFF26C476890085CC64 /* Model.sqlite.v1.original in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 430157F51C7EC03B00B64B63 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7D68A9AE1FE0A3D000522C49 /* Localizable.strings in Resources */, - 430158061C7EC03B00B64B63 /* LaunchScreen.storyboard in Resources */, - 430158031C7EC03B00B64B63 /* Assets.xcassets in Resources */, - 430158011C7EC03B00B64B63 /* Main.storyboard in Resources */, - 4B67E2CB289B4EDB002D92AF /* InfoPlist.strings in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43BA7152201E484D0058961E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 43BA7194202039A90058961E /* GlucoseRangeTableViewCell.xib in Resources */, - B40D07CA251BD89D00C1C6D7 /* DateAndDurationSteppableTableViewCell.xib in Resources */, - E9DFB93524E8CD5800468917 /* LegacyInsulinDeliveryTableViewController.storyboard in Resources */, - 895FE07122011EDD00FCF18A /* EmojiInputController.storyboard in Resources */, - 892A5DAE2231E185008961AB /* HUDAssets.xcassets in Resources */, - 43BA7173201E492E0058961E /* DateAndDurationTableViewCell.xib in Resources */, - 1D67E79D2563001800A82ED6 /* InformationScreens.xcassets in Resources */, - 43BA7164201E49130058961E /* InsulinKit.storyboard in Resources */, - 895FE08A22011F0C00FCF18A /* LabeledTextFieldTableViewCell.xib in Resources */, - 892155192245FBEF009112BC /* InsulinSensitivityScalingTableViewCell.xib in Resources */, - 43BA7195202039B00058961E /* GlucoseRangeOverrideTableViewCell.xib in Resources */, - 895FE07F22011F0C00FCF18A /* DoubleRangeTableViewCell.xib in Resources */, - 1FE58796211D12CE004F24ED /* Localizable.strings in Resources */, - 892A5DB72231E1A0008961AB /* ReservoirVolumeHUDView.xib in Resources */, - 898E6E68224179310019E459 /* BatteryLevelHUDView.xib in Resources */, - 895FE06F22011E9A00FCF18A /* OverrideSelectionViewController.storyboard in Resources */, - 43BA7193202039A30058961E /* TextFieldTableViewCell.xib in Resources */, - 895FE08622011F0C00FCF18A /* DecimalTextFieldTableViewCell.xib in Resources */, - 43BA719620203C750058961E /* Assets.xcassets in Resources */, - 89AE223E228BD3C400BDFD85 /* SetConstrainedScheduleEntryTableViewCell.xib in Resources */, - 43BA7192202039950058961E /* RepeatingScheduleValueTableViewCell.xib in Resources */, - 43F5035B21059AF7009FA89A /* AuthenticationTableViewCell.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43D8FDC91C728FDF0073BE78 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 1F5DAB2D2118CE9300048054 /* Localizable.strings in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43D8FDD31C728FDF0073BE78 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 4322B795202FA3CC0002837D /* carbs_on_board_output.json in Resources */, - B46FA3F4253F00DD00D993E2 /* momentum_effect_impossible_rising_glucose_input.json in Resources */, - 4322B7A0202FA3CC0002837D /* ice_slow_absorption.json in Resources */, - 437874BE202FDD2D00A3D8B9 /* iob_from_bolus_180min_output.json in Resources */, - 4322B7A6202FA3D20002837D /* momentum_effect_falling_glucose_output.json in Resources */, - C1D56376296B3F5E00BA15EC /* reservoir_for_iob_missing.json in Resources */, - 437874C0202FDD2D00A3D8B9 /* iob_from_bolus_300min_output.json in Resources */, - 4322B7A8202FA3D20002837D /* momentum_effect_mixed_provenance_glucose_input.json in Resources */, - 435D2929205F3C760026F401 /* momentum_effect_rising_glucose_double_entries_input.json in Resources */, - 4322B7AB202FA3D20002837D /* momentum_effect_stable_glucose_input.json in Resources */, - E9DFB92E24E8A75C00468917 /* iob_from_multiple_curves_output.json in Resources */, - 43D988A61C87FFA300DA4467 /* glucose_from_effects_momentum_flat_glucose_input.json in Resources */, - 9E784341236656770016C583 /* ice_35_min_partial_piecewiselinear_output.json in Resources */, - 437874D5202FDD2D00A3D8B9 /* suspend_dose_reconciled_normalized.json in Resources */, - 435D2925205F3A670026F401 /* counteraction_effect_falling_glucose_almost_duplicates_input.json in Resources */, - 437874CD202FDD2D00A3D8B9 /* reconcile_history_output.json in Resources */, - 4322B7A2202FA3D20002837D /* momentum_effect_bouncing_glucose_output.json in Resources */, - 4322B7A4202FA3D20002837D /* momentum_effect_duplicate_glucose_input.json in Resources */, - 4322B79F202FA3CC0002837D /* ice_slow_absorption_output.json in Resources */, - 43DC87BE1C8AD41D005BC30D /* glucose_from_effects_non_zero_output.json in Resources */, - 4322B79B202FA3CC0002837D /* ice_1_hour_output.json in Resources */, - 43DC87B81C8AD058005BC30D /* glucose_from_effects_non_zero_glucose_input.json in Resources */, - 437874D1202FDD2D00A3D8B9 /* reservoir_history_with_rewind_and_prime_input.json in Resources */, - 43C9805A212BDEE4003B5D17 /* ice_minus_carb_effect_with_gaps_output.json in Resources */, - 4322B797202FA3CC0002837D /* grouped_by_overlapping_absorption_times_border_case_output.json in Resources */, - 437874CA202FDD2D00A3D8B9 /* normalized_doses.json in Resources */, - 4322B7A7202FA3D20002837D /* momentum_effect_incomplete_glucose_input.json in Resources */, - 437874D7202FDD2D00A3D8B9 /* suspend_dose.json in Resources */, - 437874D4202FDD2D00A3D8B9 /* suspend_dose_reconciled_normalized_iob.json in Resources */, - 43D988AD1C87FFA300DA4467 /* glucose_from_effects_insulin_effect_input.json in Resources */, - 4322B7A9202FA3D20002837D /* momentum_effect_rising_glucose_input.json in Resources */, - 437874BD202FDD2D00A3D8B9 /* iob_from_bolus_120min_output.json in Resources */, - 437874D2202FDD2D00A3D8B9 /* reservoir_history_with_rewind_and_prime_output.json in Resources */, - 437874BF202FDD2D00A3D8B9 /* iob_from_bolus_240min_output.json in Resources */, - 437874D0202FDD2D00A3D8B9 /* reservoir_history_with_continuity_holes.json in Resources */, - 4322B7A3202FA3D20002837D /* momentum_effect_display_only_glucose_input.json in Resources */, - 437874CB202FDD2D00A3D8B9 /* normalized_reservoir_history_output.json in Resources */, - 435D2928205F3C760026F401 /* counteraction_effect_falling_glucose_double_entries._input.json in Resources */, - 437874B9202FDD2D00A3D8B9 /* doses_overlay_basal_profile_output.json in Resources */, - 4322B79C202FA3CC0002837D /* ice_35_min_input.json in Resources */, - E93E865A24DC744300FF40C8 /* effect_from_basal_output_exponential.json in Resources */, - 43D988AC1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_glucose_input.json in Resources */, - 43DC87BC1C8AD0ED005BC30D /* glucose_from_effects_non_zero_carb_input.json in Resources */, - 4322B79A202FA3CC0002837D /* ice_1_hour_input.json in Resources */, - 437874C8202FDD2D00A3D8B9 /* normalize_edge_case_doses_input.json in Resources */, - 437874B7202FDD2D00A3D8B9 /* basal_dose.json in Resources */, - 4322B799202FA3CC0002837D /* grouped_by_overlapping_absorption_times_output.json in Resources */, - 435D292D205F48750026F401 /* counteraction_effect_falling_glucose_insulin.json in Resources */, - 437874D3202FDD2D00A3D8B9 /* short_basal_dose.json in Resources */, - C1FAC06328C7B0A100754AE2 /* reservoir_iob_test.json in Resources */, - 437874C6202FDD2D00A3D8B9 /* iob_from_doses_output.json in Resources */, - 437874D6202FDD2D00A3D8B9 /* suspend_dose_reconciled.json in Resources */, - 4343951F205EED1F0056DC37 /* counteraction_effect_falling_glucose_output.json in Resources */, - 43D988AE1C87FFA300DA4467 /* glucose_from_effects_glucose_input.json in Resources */, - 9E78433F236653F00016C583 /* ice_35_min_none_piecewiselinear_output.json in Resources */, - 4322B7AA202FA3D20002837D /* momentum_effect_rising_glucose_output.json in Resources */, - 437874C3202FDD2D00A3D8B9 /* iob_from_bolus_420min_output.json in Resources */, - 437874C5202FDD2D00A3D8B9 /* iob_from_doses_exponential_output.json in Resources */, - 437874C2202FDD2D00A3D8B9 /* iob_from_bolus_360min_output.json in Resources */, - 43026D642132404900A332E2 /* ice_minus_flat_carb_effect_output.json in Resources */, - 9E784343236659BD0016C583 /* ice_slow_absorption_piecewiselinear_output.json in Resources */, - 43DC87BB1C8AD0ED005BC30D /* glucose_from_effects_non_zero_insulin_input.json in Resources */, - 4322B7A1202FA3D20002837D /* momentum_effect_bouncing_glucose_input.json in Resources */, - 43D988A91C87FFA300DA4467 /* glucose_from_effects_momentum_blend_output.json in Resources */, - 437874CF202FDD2D00A3D8B9 /* reconcile_resume_before_rewind_output.json in Resources */, - 4322B7A5202FA3D20002837D /* momentum_effect_falling_glucose_input.json in Resources */, - 4322B796202FA3CC0002837D /* grouped_by_overlapping_absorption_times_border_case_input.json in Resources */, - 437874BA202FDD2D00A3D8B9 /* effect_from_basal_output.json in Resources */, - 4322B798202FA3CC0002837D /* grouped_by_overlapping_absorption_times_input.json in Resources */, - E93E866024DC82A600FF40C8 /* dose_history_with_delivered_units.json in Resources */, - 437874C9202FDD2D00A3D8B9 /* normalize_edge_case_doses_output.json in Resources */, - 43D988A11C87FFA300DA4467 /* glucose_from_effects_no_momentum_output.json in Resources */, - 43D988A81C87FFA300DA4467 /* glucose_from_effects_momentum_down_input.json in Resources */, - E93E865E24DC797A00FF40C8 /* basal_dose_with_delivered.json in Resources */, - 437874BB202FDD2D00A3D8B9 /* effect_from_bolus_output.json in Resources */, - 437874CC202FDD2D00A3D8B9 /* reconcile_history_input.json in Resources */, - 43D988AA1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_momentum_input.json in Resources */, - 43439521205F2D910056DC37 /* counteraction_effect_falling_glucose_input.json in Resources */, - 4322B792202FA3CC0002837D /* carb_effect_from_history_input.json in Resources */, - E93E865C24DC75EF00FF40C8 /* basal_dose_with_expired.json in Resources */, - E9E5E56724D362E900B5DFFE /* dynamic_glucose_effect_partially_observed_output.json in Resources */, - 43D988A41C87FFA300DA4467 /* glucose_from_effects_momentum_flat_output.json in Resources */, - E93E866224DC87AE00FF40C8 /* effect_from_history_exponential_delivered_units_output.json in Resources */, - 437874C1202FDD2D00A3D8B9 /* iob_from_bolus_312min_output.json in Resources */, - 43D988AF1C87FFA300DA4467 /* glucose_from_effects_carb_effect_input.json in Resources */, - A914472527BF04170054A39D /* normalize_edge_case_doses_mutable_input.json in Resources */, - 4322B793202FA3CC0002837D /* carb_effect_from_history_output.json in Resources */, - 43D988A51C87FFA300DA4467 /* glucose_from_effects_momentum_flat_input.json in Resources */, - 43D988A21C87FFA300DA4467 /* glucose_from_effects_momentum_up_output.json in Resources */, - 43D988A71C87FFA300DA4467 /* glucose_from_effects_momentum_down_output.json in Resources */, - E9E5E56624D362E900B5DFFE /* dynamic_glucose_effect_never_fully_observed_output.json in Resources */, - 43D8FE691C7292B00073BE78 /* read_carb_ratios.json in Resources */, - 43D988AB1C87FFA300DA4467 /* glucose_from_effects_momentum_blend_insulin_effect_input.json in Resources */, - A914472727BF044C0054A39D /* normalize_edge_case_doses_mutable_output.json in Resources */, - E9E5E56524D362E900B5DFFE /* dynamic_glucose_effect_none_observed_output.json in Resources */, - 437874C4202FDD2D00A3D8B9 /* iob_from_bolus_exponential_output.json in Resources */, - 437874CE202FDD2D00A3D8B9 /* reconcile_resume_before_rewind_input.json in Resources */, - 4322B79E202FA3CC0002837D /* ice_35_min_partial_output.json in Resources */, - 435D292B205F46180026F401 /* counteraction_effect_falling_glucose_almost_duplicates_output.json in Resources */, - B46FA3F3253F00DC00D993E2 /* momentum_effect_impossible_rising_glucose_output.json in Resources */, - E9E5E56824D362E900B5DFFE /* dynamic_glucose_effect_fully_observed_output.json in Resources */, - 4322B7AC202FA3D20002837D /* momentum_effect_stable_glucose_output.json in Resources */, - 437874BC202FDD2D00A3D8B9 /* effect_from_history_output.json in Resources */, - 437874C7202FDD2D00A3D8B9 /* iob_from_reservoir_output.json in Resources */, - 4322B794202FA3CC0002837D /* carb_entry_input.json in Resources */, - 437874B8202FDD2D00A3D8B9 /* bolus_dose.json in Resources */, - 43D8FEF71C7295500073BE78 /* basal.json in Resources */, - 4322B79D202FA3CC0002837D /* ice_35_min_none_output.json in Resources */, - 9E78434523665B5A0016C583 /* ice_35_min_partial_piecewiselinear_adaptiverate_output.json in Resources */, - 43D988A31C87FFA300DA4467 /* glucose_from_effects_momentum_up_input.json in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 892A5D32222F03CB008961AB /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 89D2047021CC7BD7001238CC /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 1D640FF724525228008F9755 /* sub.caf in Resources */, - C15E994429C67866004AB926 /* Localizable.strings in Resources */, - B47ECFD625DC22D20024A54D /* Assets.xcassets in Resources */, - 1D25C22E246A2A1A00E87FA0 /* critical.caf in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 89D2048D21CC7C12001238CC /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 89D204D221CC837A001238CC /* Assets.xcassets in Resources */, - C1D7162129C75DC700B5AB3B /* Localizable.strings in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A9E675EA22713F4700E25293 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - A9E675EC22713F4700E25293 /* Localizable.strings in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - B4CEE2DE257129780093111B /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 1DEE226B24A676A300693C32 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - A98ED5FC25312ED100FD8F70 /* HKAnchoredObjectQueryMock.swift in Sources */, - A9E1E6AC24E1D7EC0073CA39 /* PersistenceControllerTestCase.swift in Sources */, - A98ED5FE253132A400FD8F70 /* CarbStoreHKQueryTests.swift in Sources */, - A9DF02D224F748BF00B7C988 /* CriticalEventLogTests.swift in Sources */, - A9E068162534EB8200BDAB59 /* CachedGlucoseObjectTests.swift in Sources */, - 1DEE227724A676A300693C32 /* HKHealthStoreMock.swift in Sources */, - A9E1E6AD24E1D8590073CA39 /* CacheStore.swift in Sources */, - A994B884254241B10039B108 /* InsulinDeliveryStoreTests.swift in Sources */, - A9E0681825350ECC00BDAB59 /* GlucoseStoreTests.swift in Sources */, - A9E1E6AE24E1D8860073CA39 /* NSManagedObjectContext.swift in Sources */, - 1D70F80226C1BEB700D5BE96 /* CoreDataMigrationTests.swift in Sources */, - A98ED5FB25312E3200FD8F70 /* HKObserverQueryMock.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 430157F31C7EC03B00B64B63 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C18733D029B94B3300519CDF /* TimeInterval.swift in Sources */, - 4302F4DF1D4E607B00F0FCAF /* LegacyInsulinDeliveryTableViewController.swift in Sources */, - C18733D229B94B8E00519CDF /* HKUnit.swift in Sources */, - 430157FC1C7EC03B00B64B63 /* MasterViewController.swift in Sources */, - C18733CE29B94B1700519CDF /* IdentifiableClass.swift in Sources */, - 430157FA1C7EC03B00B64B63 /* AppDelegate.swift in Sources */, - 435F355E1C9CD16A00C204D2 /* NSUserDefaults.swift in Sources */, - 435F35611C9CD25F00C204D2 /* DeviceDataManager.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43BA714F201E484D0058961E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 1D1438B825633E2100BE8F06 /* GlucoseTherapySettingInformationView.swift in Sources */, - 1D1065E7282DC3BB00026A70 /* PopoverLink.swift in Sources */, - 898E6E6E2241ED9F0019E459 /* SuspendResumeTableViewCell.swift in Sources */, - B4C004D12416961300B40429 /* GuidePage.swift in Sources */, - C18733B129B9492300519CDF /* Math.swift in Sources */, - 898B4E7E246DEB920053C484 /* GuardrailConstrainedQuantityRangeView.swift in Sources */, - C18733AB29B9492300519CDF /* UITableViewCell.swift in Sources */, - E93E866A24DD05FA00FF40C8 /* OverrideSelectionHistory.swift in Sources */, - 898E6E69224179310019E459 /* BatteryLevelHUDView.swift in Sources */, - 89E7E61024D11AB600591386 /* OrientationLock.swift in Sources */, - 89B0B2AA2453C0AB0063D4A7 /* GuardrailConstraintedQuantityView.swift in Sources */, - 898B4E75246CCAB50053C484 /* Binding.swift in Sources */, - 892155182245FBEF009112BC /* InsulinSensitivityScalingTableViewCell.swift in Sources */, - C18733AE29B9492300519CDF /* NSTimeInterval.swift in Sources */, - 892155132245C516009112BC /* SegmentedGaugeBarView.swift in Sources */, - E9077D2A24ACDE2C0066A88D /* CorrectionRangeInformationView.swift in Sources */, - 1D498E4724D892B0000627F2 /* Environment+Authenticate.swift in Sources */, - B4A2AAB3240832350066563F /* MultipleSelectionList.swift in Sources */, - B46B62AB23FF0822001E69BA /* LabeledValueView.swift in Sources */, - 43FB60E720DCBC55002B996B /* RadioSelectionTableViewController.swift in Sources */, - 43BA7182201EE7090058961E /* TextFieldTableViewCell.swift in Sources */, - 89F6E314244A1AB600CB9E15 /* GuardrailWarning.swift in Sources */, - B46B62A723FEFE4D001E69BA /* InstructionList.swift in Sources */, - C1FAEC1D264AD6B400A3250B /* DeviceStatusBadge.swift in Sources */, - 8907E35921A9D0EC00335852 /* GlucoseEntryTableViewController.swift in Sources */, - 43F5034D210599CC009FA89A /* AuthenticationViewController.swift in Sources */, - B4C004D32416961300B40429 /* ActionButton.swift in Sources */, - 895FE08922011F0C00FCF18A /* OverrideSelectionHeaderView.swift in Sources */, - C14A7E7E295F43AB00CD87B4 /* ConfigurationPageScrollView.swift in Sources */, - 89653C802473527100E1BAA5 /* FractionalQuantityPicker.swift in Sources */, - 1D97A33C256F11E00042737E /* View+InsetGroupedListStyle.swift in Sources */, - 898E6E67224179310019E459 /* BaseHUDView.swift in Sources */, - 43F5034F210599DF009FA89A /* ValidatingIndicatorView.swift in Sources */, - 1D1065E5282DAEE500026A70 /* WebView.swift in Sources */, - C1E4B308242E995200E70CCB /* ActivityIndicator.swift in Sources */, - B4001CF028CBC200002FB414 /* SingleSelectionCheckList.swift in Sources */, - 89FC6891245A2D680075CF59 /* ScheduleItemPicker.swift in Sources */, - 1D1FCE2524BD42EF000300A8 /* TherapySettingsViewModel.swift in Sources */, - 43F5035A21059AF7009FA89A /* AuthenticationTableViewCell.swift in Sources */, - E916F56924AD32F000BE3547 /* CorrectionRangeOverridesEditor.swift in Sources */, - C18733B029B9492300519CDF /* NibLoadable.swift in Sources */, - C1E4B30A242E99A800E70CCB /* Image.swift in Sources */, - B4A2AAB1240830A30066563F /* LabeledTextField.swift in Sources */, - B429D66E24BF7255003E1B4A /* UIImage.swift in Sources */, - B46B62A923FF05F8001E69BA /* LabeledNumberInput.swift in Sources */, - 892155152245C57E009112BC /* SegmentedGaugeBarLayer.swift in Sources */, - C1DD512B259FD8A600DE27AE /* InsulinTypeChooser.swift in Sources */, - E9086B2D24B3A4AC0062F5C8 /* ChartsManager.swift in Sources */, - E9086B4824B5405E0062F5C8 /* ChartAxisValueDoubleUnit.swift in Sources */, - B429D66C24BF7204003E1B4A /* GlucoseTrend.swift in Sources */, - 432CF86720D76AB90066B889 /* SettingsTableViewCell.swift in Sources */, - 898B4E7B246DC6A70053C484 /* CorrectionRangeScheduleEditor.swift in Sources */, - E9E5E56A24D5CCE800B5DFFE /* OverrideViewCell.swift in Sources */, - 892A5DB42231E191008961AB /* LevelMaskView.swift in Sources */, - 892A5DA02231E130008961AB /* CompletionNotifying.swift in Sources */, - E93C86A424C8F79C0073089B /* ChartLineModel+LoopKitUI.swift in Sources */, - E949E38F24B3711E00024DA0 /* InsulinModelInformationView.swift in Sources */, - 895FE08B22011F0C00FCF18A /* EmojiInputHeaderView.swift in Sources */, - 43BA7170201E49220058961E /* FoodTypeShortcutCell.swift in Sources */, - 895FE08322011F0C00FCF18A /* OverrideSelectionFooterView.swift in Sources */, - 89AF78C22447E353002B4FCC /* Splat.swift in Sources */, - 893C9F8C2447DBD900CD4185 /* CardBuilder.swift in Sources */, - B4D4C20D25F95A8700DA809D /* DisplayGlucoseUnitObservable.swift in Sources */, - 89BE75C524649C8100B145D9 /* NewScheduleItemEditor.swift in Sources */, - 89CAB36F24C9ECCA009EE3CE /* View+KeyboardAware.swift in Sources */, - E9086B2F24B3A5080062F5C8 /* ChartColorPalette.swift in Sources */, - 89653C822473592600E1BAA5 /* CarbRatioScheduleEditor.swift in Sources */, - 1D1FCE2B24BE704A000300A8 /* TherapySetting+Settings.swift in Sources */, - 4369F08F208859E6000E3E45 /* PaddedTextField.swift in Sources */, - A9498D8823386CAF00DAA9B9 /* ServiceNavigationController.swift in Sources */, - 892A5D9E2231E122008961AB /* StateColorPalette.swift in Sources */, - 895FE08022011F0C00FCF18A /* EmojiDataSource.swift in Sources */, - 1D3E2973276031F80041F460 /* ResizeablePicker.swift in Sources */, - 432CF86920D76B320066B889 /* SetupButton.swift in Sources */, - E9DFB93024E8CA8500468917 /* LegacyInsulinDeliveryTableViewController.swift in Sources */, - C1DE4C2125A253BD007065F8 /* Color.swift in Sources */, - 898E6E702241EDB70019E459 /* PercentageTextFieldTableViewController.swift in Sources */, - 89CAB36D24C9EC98009EE3CE /* Keyboard.swift in Sources */, - 89186C0724BF7FC70003D0F3 /* Guardrail+UI.swift in Sources */, - 43FB60E520DCBA02002B996B /* SetupTableViewController.swift in Sources */, - 43BA7180201EE7090058961E /* SingleValueScheduleTableViewController.swift in Sources */, - E9DFB92C24E634E800468917 /* ExpandablePicker.swift in Sources */, - 898E6E5D2241783C0019E459 /* SetConstrainedScheduleEntryTableViewCell.swift in Sources */, - 89FC688F245A2D680075CF59 /* InsulinSensitivityScheduleEditor.swift in Sources */, - E96DCB5E24AF7DC7007117BC /* BasalRatesInformationView.swift in Sources */, - 895FE09322011F4800FCF18A /* EmojiInputController.swift in Sources */, - 43BA717E201EE7090058961E /* CommandResponseViewController.swift in Sources */, - C188B83422CC16AC0051760A /* InsulinSensitivityScheduleViewController.swift in Sources */, - 895FE08822011F0C00FCF18A /* DoubleRangeTableViewCell.swift in Sources */, - E9086B2924B39EDC0062F5C8 /* ChartsTableViewController.swift in Sources */, - 43BA7187201EE7090058961E /* GlucoseRangeScheduleTableViewController.swift in Sources */, - B46B62AF23FF0BF6001E69BA /* SectionHeader.swift in Sources */, - 43BA7183201EE7090058961E /* DailyQuantityScheduleTableViewController.swift in Sources */, - 1D1FCE2324BD13A2000300A8 /* CorrectionRangeOverridesExpandableSetting.swift in Sources */, - E93BA06624A39DBC00C5D7E6 /* DismissibleHostingController.swift in Sources */, - 43F503632106C761009FA89A /* ServiceAuthenticationUI.swift in Sources */, - 1D6EAB9124C12C090081249D /* PumpSupportedIncrements.swift in Sources */, - 899012C1246F1D8F007B88BA /* ExpandableSetting.swift in Sources */, - 89FC6890245A2D680075CF59 /* QuantityScheduleEditor.swift in Sources */, - 432CF86B20D76B9C0066B889 /* SetupIndicatorView.swift in Sources */, - 898E6E722241EDC10019E459 /* DateAndDurationTableViewController.swift in Sources */, - B455F48125FF9A8B000ED456 /* InsulinSensitivityScheduleEditorViewModel.swift in Sources */, - 43BA716D201E49220058961E /* DatePickerTableViewCell.swift in Sources */, - E9C58A6E24DA65E400487A17 /* HistoricalOverrideDetailView.swift in Sources */, - 895FE08222011F0C00FCF18A /* LabeledTextFieldTableViewCell.swift in Sources */, - B43DA44224D9CD8500CAFF4E /* Environment+Colors.swift in Sources */, - 892A5DB22231E191008961AB /* LoadingTableViewCell.swift in Sources */, - B4D3D4AD25B8A94E0085BA0F /* DisplayGlucoseUnitObserver.swift in Sources */, - E96DCB5A24AF74AC007117BC /* SuspendThresholdEditor.swift in Sources */, - E96DCB5824AEF50F007117BC /* SuspendThresholdInformationView.swift in Sources */, - C140E0522602908A000A4FF7 /* SettingsPresentationMode.swift in Sources */, - 4369F094208BA001000E3E45 /* TextButtonTableViewCell.swift in Sources */, - A9CFCAA52582FA0400A04932 /* SupportUI.swift in Sources */, - 89AC9DCD24529D9B004A6B8A /* TimePicker.swift in Sources */, - A9498D8B23386CC700DAA9B9 /* ServiceUI.swift in Sources */, - E96175AE24B7BE38008E5080 /* Dictionary.swift in Sources */, - 1D096C0524C624F70078B6B5 /* InsulinModelSettings+LoopKitUI.swift in Sources */, - 892A5DB82231E1A0008961AB /* ReservoirVolumeHUDView.swift in Sources */, - 43BA716C201E49220058961E /* CustomInputTextField.swift in Sources */, - B46B62B323FF0E62001E69BA /* SelectableLabel.swift in Sources */, - 89FC6893245A2D680075CF59 /* ScheduleItemView.swift in Sources */, - 43BA716F201E49220058961E /* FoodEmojiDataSource.swift in Sources */, - E9077D2724ACD59F0066A88D /* InformationView.swift in Sources */, - E94141D024C8F31C0096C326 /* DeliveryLimitsEditor.swift in Sources */, - C18733AD29B9492300519CDF /* TimeZone.swift in Sources */, - 43F89C9F22BDFB10006BB54E /* UIActivityIndicatorView.swift in Sources */, - C1DD517825A016E700DE27AE /* InsulinTypeSetting.swift in Sources */, - 892ADE002446C858007CE08C /* Card.swift in Sources */, - 89653C8424738D2B00E1BAA5 /* BasalRateScheduleEditor.swift in Sources */, - C18733B229B9492300519CDF /* Comparable.swift in Sources */, - B4B7C1BC2604E3FC007379F6 /* CorrectionRangeScheduleEditorViewModel.swift in Sources */, - 898B4E77246DAE280053C484 /* GlucoseRangePicker.swift in Sources */, - 432CF86D20D76C470066B889 /* SwitchTableViewCell.swift in Sources */, - E93C86A824C8F7F70073089B /* InsulinModelChartView.swift in Sources */, - E93C86B224D080E00073089B /* CarbRatioInformationView.swift in Sources */, - 89F6E30D2449713600CB9E15 /* CardStack.swift in Sources */, - 89BE75C324649C4C00B145D9 /* RoundedCorners.swift in Sources */, - C1E4B306242E98E900E70CCB /* ProgressIndicatorView.swift in Sources */, - 4369F092208B0DFF000E3E45 /* DateAndDurationTableViewCell.swift in Sources */, - E9086B3524B3A8820062F5C8 /* ChartContainerView.swift in Sources */, - 89AF78C624482269002B4FCC /* ActionButtonStyle.swift in Sources */, - 1D60355E24D39ED10095DC2A /* Environment+AppName.swift in Sources */, - 8997B4F523727E8A00061132 /* CustomOverrideCollectionViewCell.swift in Sources */, - 1DD1964E248AE88000420876 /* HorizontalSizeClassOverride.swift in Sources */, - 892A5D9C2231E118008961AB /* UIAlertController.swift in Sources */, - 43BA7181201EE7090058961E /* RepeatingScheduleValueTableViewCell.swift in Sources */, - C18733B629B9495400519CDF /* LocalizedString.swift in Sources */, - 1DC64C7C24BF6BFD004A63A1 /* CorrectionRangeOverridesExtension.swift in Sources */, - 43BA716E201E49220058961E /* DecimalTextFieldTableViewCell.swift in Sources */, - 895FE08722011F0C00FCF18A /* EmojiInputCell.swift in Sources */, - 89627B182441168900BEB424 /* ConfigurationPage.swift in Sources */, - 43A8EC3C210CEEA500A81379 /* CGMManagerUI.swift in Sources */, - 89FC6892245A2D680075CF59 /* ScheduleEditor.swift in Sources */, - 89CAB37124CB4DEC009EE3CE /* WarningView.swift in Sources */, - A9CFCA8F2582F9FA00A04932 /* OnboardingUI.swift in Sources */, - E916F56F24AE2FFE00BE3547 /* CorrectionRangeOverrideInformationView.swift in Sources */, - 89BE75C124649C2E00B145D9 /* ModalHeaderButtonBar.swift in Sources */, - A9012EB225BA3861000813AD /* SetupUIResult.swift in Sources */, - 89186C0524BEC9CA0003D0F3 /* SegmentedControlTableViewCell.swift in Sources */, - 89F6E315244A1AB600CB9E15 /* GlucoseValuePicker.swift in Sources */, - E9086B3124B3A7270062F5C8 /* ChartTableViewCell.swift in Sources */, - E93E866424DCFB6D00FF40C8 /* OverrideHistoryCollectionViewCell.swift in Sources */, - 895FE08122011F0C00FCF18A /* OverridePresetCollectionViewCell.swift in Sources */, - 43FB60E320DCB9E0002B996B /* PumpManagerUI.swift in Sources */, - 89186C0B24BFD6DB0003D0F3 /* DurationPicker.swift in Sources */, - 89BE75C72464B4A900B145D9 /* Environment+Dismiss.swift in Sources */, - 43BA717F201EE7090058961E /* GlucoseRangeOverrideTableViewCell.swift in Sources */, - 895FE09022011F4800FCF18A /* OverrideSelectionViewController.swift in Sources */, - 89904032245B5CA500F1C0A2 /* Deletable.swift in Sources */, - 43F5035721059A8A009FA89A /* ServiceCredential.swift in Sources */, - E93C86A224C8F7550073089B /* InsulinModelChart.swift in Sources */, - E93C86B624D08CAD0073089B /* InsulinSensitivityInformationView.swift in Sources */, - C18733AF29B9492300519CDF /* Collection.swift in Sources */, - 892A5DA22231E137008961AB /* HUDProvider.swift in Sources */, - 898E6E6C224194060019E459 /* UIColor.swift in Sources */, - 43BA717D201EE7090058961E /* GlucoseRangeTableViewCell.swift in Sources */, - B455F3A425FF7FF0000ED456 /* CorrectionRangeOverridesEditorViewModel.swift in Sources */, - 89BE75CB2464BC2000B145D9 /* AlertContent.swift in Sources */, - 43BA7184201EE7090058961E /* TextFieldTableViewController.swift in Sources */, - 1D1A019E24B678BF0077D86E /* TherapySettingsView.swift in Sources */, - E93C86A024C8F6E00073089B /* InsulinModelSelection.swift in Sources */, - 895FE09122011F4800FCF18A /* AddEditOverrideTableViewController.swift in Sources */, - C1E4B305242E98E900E70CCB /* ProgressView.swift in Sources */, - C16DA84522E9330A008624C2 /* LoopUIPlugin.swift in Sources */, - E93C86A624C8F7D90073089B /* ChartSettings+LoopKitUI.swift in Sources */, - B46B62AD23FF0A87001E69BA /* LabeledDateView.swift in Sources */, - 895FE06E22011E9A00FCF18A /* OverrideEmojiDataSource.swift in Sources */, - B43DA43F24D49AA400CAFF4E /* GuidanceColors.swift in Sources */, - 89AF78C02447E285002B4FCC /* CardStackBuilder.swift in Sources */, - E9F54FC62581C50D0034795E /* ExpandableDatePicker.swift in Sources */, - 43BA7185201EE7090058961E /* DailyValueScheduleTableViewController.swift in Sources */, - C18733B829B949FF00519CDF /* Data.swift in Sources */, - 1D1065E4282DAEE500026A70 /* VideoView.swift in Sources */, - 1D1065E9282DC54700026A70 /* VideoPlayView.swift in Sources */, - E99A132E2557548300D3F5B3 /* SegmentedGaugeBar.swift in Sources */, - B455F31825FBEC5F000ED456 /* SuspendThresholdEditorViewModel.swift in Sources */, - 892A5DB32231E191008961AB /* LevelHUDView.swift in Sources */, - B41A60B223D1DBC700636320 /* UIFont.swift in Sources */, - B41A60AF23D1DB5B00636320 /* TableViewTitleLabel.swift in Sources */, - C18733B329B9492300519CDF /* IdentifiableClass.swift in Sources */, - C18733AC29B9492300519CDF /* UITextField.swift in Sources */, - 89CC35D42403450E008FB633 /* ThumbView.swift in Sources */, - 43BA7162201E490D0058961E /* ErrorBackgroundView.swift in Sources */, - 892A5D9A2231E0E4008961AB /* SettingsNavigationViewController.swift in Sources */, - B46B62B123FF0CA6001E69BA /* DescriptiveText.swift in Sources */, - B40D07CB251BD89D00C1C6D7 /* DateAndDurationSteppableTableViewCell.swift in Sources */, - E949E38924AFC82F00024DA0 /* DeliveryLimitsInformationView.swift in Sources */, - 1DC9240F2575EF9A004F132A /* QuantityFormatter+Guardrails.swift in Sources */, - C18733B429B9492300519CDF /* HKUnit.swift in Sources */, - 89CAB36B24C9EC25009EE3CE /* DismissibleKeyboardTextField.swift in Sources */, - E9086B4A24B540B70062F5C8 /* DateFormatter.swift in Sources */, - 89AC9DCB24529927004A6B8A /* QuantityPicker.swift in Sources */, - 1D096BFA24C242300078B6B5 /* CheckmarkListItem.swift in Sources */, - A9DCF2CA25B0F38000C89088 /* LoopUIColorPalette.swift in Sources */, - E9086B4524B53CC50062F5C8 /* GlucoseChart.swift in Sources */, - B4C004D22416961300B40429 /* GuideNavigationButton.swift in Sources */, - 89627B16244115A400BEB424 /* CardList.swift in Sources */, - C18733AA29B9492300519CDF /* NumberFormatter.swift in Sources */, - 89F6E311244A1AAB00CB9E15 /* SettingDescription.swift in Sources */, - 1DE35E7A24ABEC720086F9AE /* DeviceManagerUI.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43D8FDC61C728FDF0073BE78 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - B4102D3224ABB068005D460B /* DeviceLifecycleProgress.swift in Sources */, - C17F39C923CD269200FA1113 /* DeviceLogEntryType.swift in Sources */, - C1814B84225B9ED5008D2D8E /* LoopNotificationCategory.swift in Sources */, - E9F54F5E25802D5E0034795E /* InsulinType.swift in Sources */, - C17F39C123CD24A000FA1113 /* DeviceLog.xcdatamodeld in Sources */, - B42C951924A508CE00857C73 /* DeviceStatusHighlight.swift in Sources */, - 4322B779202FA2790002837D /* NewCarbEntry.swift in Sources */, - 4322B76E202FA26B0002837D /* GlucoseMath.swift in Sources */, - B455F4D32600DA0B000ED456 /* GlucoseRange.swift in Sources */, - 891A3FDB224BEC0D00378B27 /* CarbSensitivitySchedule.swift in Sources */, - 4322B773202FA2790002837D /* CarbEntry.swift in Sources */, - C1E84B8525C62FB100623C08 /* Modelv1v4.xcmappingmodel in Sources */, - 43D8FDFC1C7290350073BE78 /* HealthKitSampleStore.swift in Sources */, - A9498D7E23386C3300DAA9B9 /* GlucoseThreshold.swift in Sources */, - 4322B789202FA2B30002837D /* DoseType.swift in Sources */, - C17F39C723CD256000FA1113 /* PersistentDeviceLog.swift in Sources */, - C187338D29B9486200519CDF /* TimeInterval.swift in Sources */, - 437AFEED2036A156008C4892 /* CachedCarbObject+CoreDataClass.swift in Sources */, - 43D8FDF71C7290350073BE78 /* DailyValueSchedule.swift in Sources */, - 4322B77D202FA2AF0002837D /* NewPumpEvent.swift in Sources */, - A935793F29A2570400246DED /* Action.swift in Sources */, - 434113AA20F171CB00D05747 /* CachedInsulinDeliveryObject+CoreDataClass.swift in Sources */, - C140DFFF260276BF000A4FF7 /* ManualBolusRecommendation.swift in Sources */, - 432CF86F20D76CCF0066B889 /* GlucoseTrend.swift in Sources */, - 43FB60E920DCBE64002B996B /* PumpManagerStatus.swift in Sources */, - 4322B774202FA2790002837D /* CarbMath.swift in Sources */, - 4322B78B202FA2B30002837D /* ExponentialInsulinModel.swift in Sources */, - E9086B3924B3CB4B0062F5C8 /* TherapySettings.swift in Sources */, - 89AE222F228BC68000BDFD85 /* DoseProgressTimerEstimator.swift in Sources */, - 43D8FDF61C7290350073BE78 /* DailyQuantitySchedule.swift in Sources */, - 43D8FDF51C7290350073BE78 /* CarbRatioSchedule.swift in Sources */, - 4322B76F202FA26F0002837D /* GlucoseSampleValue.swift in Sources */, - 89AE222C228BC66E00BDFD85 /* Locked.swift in Sources */, - A935793C29A2570400246DED /* OverrideCancelAction.swift in Sources */, - 432CF87120D76D5A0066B889 /* GlucoseDisplayable.swift in Sources */, - A919889F2355016B00B75EEE /* DosingDecisionStore.swift in Sources */, - A9BD318224F4548900994B83 /* Modelv3EntityMigrationPolicy.swift in Sources */, - 4322B77F202FA2AF0002837D /* PersistenceController.swift in Sources */, - 4322B78D202FA2B30002837D /* InsulinDeliveryStore.swift in Sources */, - A9498D8023386C3300DAA9B9 /* RemoteDataService.swift in Sources */, - 4379CFE321102A4100AADC79 /* DeviceManager.swift in Sources */, - 4322B78A202FA2B30002837D /* DoseUnit.swift in Sources */, - C187339029B9486200519CDF /* Guardrail+Settings.swift in Sources */, - A95A1D7F2460BBC70079378D /* DosingDecisionObject+CoreDataClass.swift in Sources */, - 432762741D60505F0083215A /* HKQuantitySample.swift in Sources */, - 43D8FDF81C7290350073BE78 /* Double.swift in Sources */, - A95A1D822460BBDC0079378D /* DosingDecisionObject+CoreDataProperties.swift in Sources */, - 898C896D24D4BF75002FA994 /* FloatingPoint.swift in Sources */, - 43F5034B21051FCE009FA89A /* KeychainManager.swift in Sources */, - 891A3FD5224B047200378B27 /* DailyQuantitySchedule+Override.swift in Sources */, - 432CF87320D774220066B889 /* PumpManager.swift in Sources */, - 43D8FE021C7290350073BE78 /* SampleValue.swift in Sources */, - 43D9888B1C87E47800DA4467 /* GlucoseValue.swift in Sources */, - A967D94924F99B6A00CDDF8A /* OutputStream.swift in Sources */, - 43D8FDF41C7290350073BE78 /* BasalRateSchedule.swift in Sources */, - A935793B29A2570400246DED /* CarbAction.swift in Sources */, - 4322B788202FA2B30002837D /* DoseStore.swift in Sources */, - A9498D6F23386C0B00DAA9B9 /* TempBasalRecommendation.swift in Sources */, - C187338E29B9486200519CDF /* ClosedRange.swift in Sources */, - A93CA899278D08CC003B5A01 /* PumpAlarmType.swift in Sources */, - 4322B781202FA2AF0002837D /* PumpEvent+CoreDataProperties.swift in Sources */, - A9498D8223386C3300DAA9B9 /* Service.swift in Sources */, - C187338F29B9486200519CDF /* NumberFormatter.swift in Sources */, - 4322B785202FA2AF0002837D /* ReservoirValue.swift in Sources */, - 891A3FD9224BEB4600378B27 /* EGPSchedule.swift in Sources */, - A935793D29A2570400246DED /* OverrideAction.swift in Sources */, - 89AE2229228BC54C00BDFD85 /* TemporaryScheduleOverrideHistory.swift in Sources */, - C187338B29B9486200519CDF /* Comparable.swift in Sources */, - 437AFF24203BE402008C4892 /* HKHealthStore.swift in Sources */, - 89AE222B228BC56A00BDFD85 /* WeakSet.swift in Sources */, - A9498D7C23386C3300DAA9B9 /* AnalyticsService.swift in Sources */, - 1D24A8D524C896E100AB8DB9 /* Prescription.swift in Sources */, - C109240F286A4AD500FAD2B8 /* AutomaticDosingStrategy.swift in Sources */, - 4322B783202FA2AF0002837D /* Reservoir.swift in Sources */, - 1DA649AB2445174400F61E75 /* Alert.swift in Sources */, - 4322B777202FA2790002837D /* CarbValue.swift in Sources */, - 4322B782202FA2AF0002837D /* PumpEventType.swift in Sources */, - 89AE2228228BC54C00BDFD85 /* TemporaryScheduleOverrideSettings.swift in Sources */, - 43D8FDFA1C7290350073BE78 /* GlucoseRangeSchedule.swift in Sources */, - 4322B77E202FA2AF0002837D /* PersistedPumpEvent.swift in Sources */, - 437AFEEE2036A156008C4892 /* CachedCarbObject+CoreDataProperties.swift in Sources */, - 4322B772202FA2790002837D /* AbsorbedCarbValue.swift in Sources */, - 434113AD20F287DC00D05747 /* NSManagedObjectContext.swift in Sources */, - C187339829B9488300519CDF /* Sequence.swift in Sources */, - 4322B77B202FA2790002837D /* StoredCarbEntry.swift in Sources */, - 4322B790202FA2B30002837D /* InsulinValue.swift in Sources */, - 4322B78C202FA2B30002837D /* HKQuantitySample+InsulinKit.swift in Sources */, - C187339229B9486200519CDF /* MutableCollection.swift in Sources */, - 89AE2226228BC54C00BDFD85 /* TemporaryScheduleOverridePreset.swift in Sources */, - 4322B78F202FA2B30002837D /* InsulinModel.swift in Sources */, - 1D096C0324C24C220078B6B5 /* ExponentialInsulinModelPreset.swift in Sources */, - 434C5F9C2098352500B2FD1A /* QuantityFormatter.swift in Sources */, - 43F503642106C78C009FA89A /* ServiceAuthentication.swift in Sources */, - A93761C125ED670200F6BE43 /* BluetoothProvider.swift in Sources */, - 433BC7A720523DB7000B1200 /* NewGlucoseSample.swift in Sources */, - 4322B78E202FA2B30002837D /* InsulinMath.swift in Sources */, - C17F39D023CE34B100FA1113 /* StoredDeviceLogEntry.swift in Sources */, - 43B17C89208EEC0B00AC27E9 /* HealthStoreUnitCache.swift in Sources */, - A912BE29245B9CD500CBE199 /* SettingsObject+CoreDataClass.swift in Sources */, - 89AE222E228BC68000BDFD85 /* DoseProgressReporter.swift in Sources */, - 1DD9CE9926B8CC2A008B4A46 /* HKDevice+Encodable.swift in Sources */, - 4322B775202FA2790002837D /* CarbStatus.swift in Sources */, - 4322B787202FA2B30002837D /* DoseEntry.swift in Sources */, - 43CB51B2211EB1A400DB9B4A /* NSUserActivity+CarbKit.swift in Sources */, - C187338C29B9486200519CDF /* HKUnit.swift in Sources */, - 434113AB20F171CB00D05747 /* CachedInsulinDeliveryObject+CoreDataProperties.swift in Sources */, - A9E1E6A924E1B6700073CA39 /* SyncCarbObject.swift in Sources */, - A96E6C3727B35BC600F81A5B /* AnyCodableEquatable.swift in Sources */, - A9A53E2C2714E5BC0050C0B1 /* CodableDevice.swift in Sources */, - A933DB8824BF956F009B417A /* CriticalEventLog.swift in Sources */, - C16DA83F22E8D88F008624C2 /* LoopPluginBundleKey.swift in Sources */, - C1F8403923DB84B700673141 /* DeviceLogEntry+CoreDataClass.swift in Sources */, - A935094426E2FAB70030B60D /* GlucoseCondition.swift in Sources */, - 433BC7AD20538FCA000B1200 /* StoredGlucoseSample.swift in Sources */, - 43D8FDF91C7290350073BE78 /* GlucoseEffect.swift in Sources */, - A932803B2798D63B0091D0A1 /* SyncAlertObject.swift in Sources */, - 1D841AAD24577EE10069DBFF /* AlertSoundPlayer.swift in Sources */, - C187339A29B9488300519CDF /* UUID.swift in Sources */, - C1CAB9E926A3254800A57273 /* StoredInsulinModel.swift in Sources */, - 43CACE0E2247F89100F90AF5 /* WeakSynchronizedSet.swift in Sources */, - A912BE2B245B9E8600CBE199 /* SettingsObject+CoreDataProperties.swift in Sources */, - 1D63DEA326E94FDF00F46FA5 /* VersionUpdate.swift in Sources */, - 43D8FDFE1C7290350073BE78 /* LoopMath.swift in Sources */, - 43D8FDFF1C7290350073BE78 /* Date.swift in Sources */, - C191D26325B3815000C26C0B /* AutomaticDoseRecommendation.swift in Sources */, - C187339429B9486200519CDF /* DateFormatter.swift in Sources */, - A919889C2354E5EB00B75EEE /* SettingsStore.swift in Sources */, - C187338A29B9486200519CDF /* Collection.swift in Sources */, - B42A7472235885B600247B03 /* LoopNotificationUserInfoKey.swift in Sources */, - B4B85FCD24A2312000A296A3 /* GlucoseRangeCategory.swift in Sources */, - 43C9805C212D216A003B5D17 /* GlucoseChange.swift in Sources */, - 14B33265293ED44C009B8746 /* GlucoseRangeSchedule+SafeBounds.swift in Sources */, - 43D8FDFB1C7290350073BE78 /* GlucoseSchedule.swift in Sources */, - 4322B77A202FA2790002837D /* NSUserDefaults.swift in Sources */, - 4322B776202FA2790002837D /* CarbStore.swift in Sources */, - C1F8403A23DB84B700673141 /* DeviceLogEntry+CoreDataProperties.swift in Sources */, - A987CD4624A5893500439ADC /* JSONStreamEncoder.swift in Sources */, - A9498D7823386C3300DAA9B9 /* LoggingService.swift in Sources */, - 1D096C0224C24C220078B6B5 /* InsulinModelProvider.swift in Sources */, - 433BC7AA20538D4C000B1200 /* CachedGlucoseObject+CoreDataClass.swift in Sources */, - 4322B786202FA2AF0002837D /* WalshInsulinModel.swift in Sources */, - 4378B64B1ED61965000AE785 /* GlucoseEffectVelocity.swift in Sources */, - 4322B780202FA2AF0002837D /* PumpEvent+CoreDataClass.swift in Sources */, - 89AE2227228BC54C00BDFD85 /* TemporaryScheduleOverride.swift in Sources */, - 4322B784202FA2AF0002837D /* Reservoir+CoreDataProperties.swift in Sources */, - 4322B778202FA2790002837D /* HKQuantitySample+CarbKit.swift in Sources */, - 4322B771202FA26F0002837D /* HKQuantitySample+GlucoseKit.swift in Sources */, - 433BC7AB20538D4C000B1200 /* CachedGlucoseObject+CoreDataProperties.swift in Sources */, - A935793E29A2570400246DED /* BolusAction.swift in Sources */, - C187339929B9488300519CDF /* TimeZone.swift in Sources */, - C187339329B9486200519CDF /* OSLog.swift in Sources */, - 43FB610720DDF19B002B996B /* PumpManagerError.swift in Sources */, - 89AE2232228BC68600BDFD85 /* UnfairLock.swift in Sources */, - A9FD046F24E310D00040F203 /* HKObject.swift in Sources */, - 1DC64C7E24BF6EBC004A63A1 /* DeliveryLimits.swift in Sources */, - C168CA7A280DD00F002BD2A7 /* Model.xcdatamodeld in Sources */, - 4322B770202FA26F0002837D /* GlucoseStore.swift in Sources */, - C1814B8C226371DF008D2D8E /* WeakSynchronizedDelegate.swift in Sources */, - C187339129B9486200519CDF /* Data.swift in Sources */, - 1D1FCE2724BE4DE2000300A8 /* CorrectionRangeOverrides.swift in Sources */, - 1D1FCE2924BE4F11000300A8 /* TherapySetting.swift in Sources */, - 4352A73C20DECF0700CAC200 /* CGMManager.swift in Sources */, - 4353D16F203D104F007B4ECD /* CarbStoreError.swift in Sources */, - 43AF1FB21C926CDD00EA2F3D /* HKQuantity.swift in Sources */, - 89F6E30F244A1A5D00CB9E15 /* Guardrail.swift in Sources */, - A985464F251449FE0099C1A6 /* NotificationSettings.swift in Sources */, - C187337E29B9481500519CDF /* LocalizedString.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43D8FDD11C728FDF0073BE78 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 434113B820F2BDE800D05747 /* PersistenceControllerTestCase.swift in Sources */, - 437874B6202FDD1500A3D8B9 /* InsulinMathTests.swift in Sources */, - B4B7C1612603F241007379F6 /* InsulinSensitivityScheduleTests.swift in Sources */, - A95A1D8B2460FD620079378D /* BolusRecommendationTests.swift in Sources */, - A99C7373233990D400C80963 /* TempBasalRecommendationTests.swift in Sources */, - A971C89F23C68B030099BEFC /* GlucoseStoreTests.swift in Sources */, - A971C8A423C6B1890099BEFC /* DosingDecisionStoreTests.swift in Sources */, - 437AFF21203AA740008C4892 /* NSManagedObjectContext.swift in Sources */, - A95A1D852460CAD50079378D /* CarbValueTests.swift in Sources */, - 437AFF1F203A763F008C4892 /* HKHealthStoreMock.swift in Sources */, - A99C73792339ACDC00C80963 /* ServiceTests.swift in Sources */, - 891A3FD32249990900378B27 /* DailyValueSchedule.swift in Sources */, - 434C5FA0209ABD4700B2FD1A /* QuantityFormatterTests.swift in Sources */, - A95A1D892460F8930079378D /* PumpManagerStatusTests.swift in Sources */, - B4CEE2A5256E912A0093111B /* DoseProgressTests.swift in Sources */, - A963B278252CE2510062AA12 /* StoredCarbEntryTests.swift in Sources */, - B46E096D25F80D6C0025A04D /* OverrideTests.swift in Sources */, - A95A1D8D246101760079378D /* DoseEntryTests.swift in Sources */, - 43D8FE1E1C72906E0073BE78 /* NSDateTests.swift in Sources */, - 1D0E708526BDE3BB00AECF0D /* HKDeviceCodableTests.swift in Sources */, - 43D9888D1C87EBE400DA4467 /* LoopMathTests.swift in Sources */, - A9DF02D324F762DC00B7C988 /* CarbStoreTests.swift in Sources */, - 437874B5202FDD1200A3D8B9 /* DoseStoreTests.swift in Sources */, - A985465125144ABA0099C1A6 /* NotificationSettingsTests.swift in Sources */, - B455F4DF2600E0A8000ED456 /* GlucoseRangeTests.swift in Sources */, - 4322B76C202F9ECD0002837D /* CarbMathTests.swift in Sources */, - 1D70C40D26F01D9F00C62570 /* VersionCheckServiceTests.swift in Sources */, - 434113B520F2BDB500D05747 /* CachedInsulinDeliveryObjectTests.swift in Sources */, - 43D8FE1F1C72906E0073BE78 /* QuantityScheduleTests.swift in Sources */, - 43D8FE1D1C72906E0073BE78 /* BasalRateScheduleTests.swift in Sources */, - 434113B320F2890800D05747 /* PersistenceControllerTests.swift in Sources */, - 434113BE20F2C72000D05747 /* CachedCarbObjectTests.swift in Sources */, - A9DF02D124F7449E00B7C988 /* PersistentDeviceLogTests.swift in Sources */, - A9DF02C524F6FA5100B7C988 /* PumpEventTests.swift in Sources */, - A985464B251442010099C1A6 /* OutputStreamTests.swift in Sources */, - A971C8A223C6B17D0099BEFC /* SettingsStoreTests.swift in Sources */, - C1E7035D24FFFA5C00DAB534 /* CollectionTests.swift in Sources */, - 1DFB99D6245CB2E900DCC8C9 /* AlertTests.swift in Sources */, - B455F35625FC0284000ED456 /* CorrectionRangeOverridesTests.swift in Sources */, - 898C897124D4C0E4002FA994 /* GuardrailTests.swift in Sources */, - A9DF02CF24F732FC00B7C988 /* JSONStreamEncoderTests.swift in Sources */, - 4322B76D202F9EF20002837D /* GlucoseMathTests.swift in Sources */, - A9672B5326E80C060025B0CD /* NewGlucoseSampleTests.swift in Sources */, - 43D8FDDB1C728FDF0073BE78 /* LoopKitTests.swift in Sources */, - A9E068112534D87800BDAB59 /* StoredGlucoseSampleTests.swift in Sources */, - B4B7C1772603F5F6007379F6 /* HKUnitTests.swift in Sources */, - A9DF02C924F724D900B7C988 /* CriticalEventLogTests.swift in Sources */, - 8974AFC022120D7A0043F01B /* TemporaryScheduleOverrideTests.swift in Sources */, - A91263872790B45300C6C950 /* NewPumpEventTests.swift in Sources */, - 437AFF1D203A45DB008C4892 /* CacheStore.swift in Sources */, - A9B0D97E273313EB00D96D93 /* CGMManagerStatusTests.swift in Sources */, - 891A3FD12249948A00378B27 /* TemporaryScheduleOverrideHistoryTests.swift in Sources */, - A9BFA03E245CCCB9001E4AE3 /* DailyQuantityScheduleTests.swift in Sources */, - A99C73772339A67A00C80963 /* GlucoseThresholdTests.swift in Sources */, - 434113BC20F2C56100D05747 /* CachedGlucoseObjectTests.swift in Sources */, - E93C86B024CF7C470073089B /* TherapySettingsTests.swift in Sources */, - A95A1D872460F1250079378D /* GlucoseValueTests.swift in Sources */, - B46E095725F7E5910025A04D /* GlucoseRangeScheduleTests.swift in Sources */, - A9DF02C324F6EEE400B7C988 /* DeviceLogEntryTests.swift in Sources */, - 891A3FD7224BE62100378B27 /* DailyValueScheduleTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 892A5D30222F03CB008961AB /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 892A5D54222F03F9008961AB /* TestingPumpManager.swift in Sources */, - 89ADE12F226BDED40067222B /* DateRelativeBolusEntry.swift in Sources */, - C187339E29B948F200519CDF /* HKUnit.swift in Sources */, - 89CA2B38226D4456004D9350 /* DateRelativeQuantity.swift in Sources */, - 89ADE12D226BDD190067222B /* DateRelativeBasalEntry.swift in Sources */, - C187339C29B948D800519CDF /* Data.swift in Sources */, - 89ADE134226BF0490067222B /* TestingScenarioInstance.swift in Sources */, - 892A5D52222F03DB008961AB /* TestingDeviceManager.swift in Sources */, - 89ADE129226BDB280067222B /* TestingScenario.swift in Sources */, - 89ADE12B226BDB730067222B /* DateRelativeCarbEntry.swift in Sources */, - 89ADE136226BF0BE0067222B /* DateRelativeGlucoseSample.swift in Sources */, - 892A5D56222F0414008961AB /* TestingCGMManager.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 89D2046E21CC7BD7001238CC /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C164A56422F21081000E3FA5 /* MockPumpManagerState.swift in Sources */, - C18733BD29B94A3700519CDF /* TimeInterval.swift in Sources */, - C164A56022F14C73000E3FA5 /* UnfinalizedDose.swift in Sources */, - 89D204A921CC7C8F001238CC /* MockPumpManager.swift in Sources */, - C18733BC29B94A3700519CDF /* HKUnit.swift in Sources */, - C1FAEC1F264AE12700A3250B /* UIImage.swift in Sources */, - A9498D8D23386CD800DAA9B9 /* MockService.swift in Sources */, - 89D204AA21CC7C8F001238CC /* MockGlucoseProvider.swift in Sources */, - 89AE2233228BC6A500BDFD85 /* MockDoseProgressEstimator.swift in Sources */, - 89D204AB21CC7C8F001238CC /* MockCGMDataSource.swift in Sources */, - C15E994629C6790A004AB926 /* LocalizedString.swift in Sources */, - 89D204B221CC7D93001238CC /* Collection.swift in Sources */, - 89D204AC21CC7C8F001238CC /* MockCGMManager.swift in Sources */, - C18733BE29B94A3700519CDF /* TimeZone.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 89D2048B21CC7C12001238CC /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 892A5D2E222EF69A008961AB /* MockHUDProvider.swift in Sources */, - C18733C929B94A6400519CDF /* TimeInterval.swift in Sources */, - C18733C529B94A6400519CDF /* NumberFormatter.swift in Sources */, - 439706E922D2E94800C81566 /* BoundSwitchTableViewCell.swift in Sources */, - 89D204B421CC7E74001238CC /* MockCGMManager+UI.swift in Sources */, - 89D204B521CC7E74001238CC /* MockPumpManager+UI.swift in Sources */, - 1DFFB988271740EE0075AEAA /* MockSupport.swift in Sources */, - A9498D8F23386CE800DAA9B9 /* MockServiceTableViewController.swift in Sources */, - 89D204BE21CC7F34001238CC /* GlucoseTrendTableViewController.swift in Sources */, - C18733C829B94A6400519CDF /* NibLoadable.swift in Sources */, - C18733CA29B94A6400519CDF /* UITableViewCell.swift in Sources */, - 8992426521EC138000EA512B /* UIColor.swift in Sources */, - C18733C629B94A6400519CDF /* Comparable.swift in Sources */, - 89D204BA21CC7F34001238CC /* MockPumpManagerSettingsViewController.swift in Sources */, - C18733CC29B94A7A00519CDF /* LocalizedString.swift in Sources */, - 89D204BC21CC7F34001238CC /* SineCurveParametersTableViewController.swift in Sources */, - C1FAEC21264AEEA300A3250B /* UIImage.swift in Sources */, - 89D204BD21CC7F34001238CC /* RandomOutlierTableViewController.swift in Sources */, - B42C950E24A3BD4B00857C73 /* MeasurementFrequencyTableViewController.swift in Sources */, - B45774352562CCC6004B9466 /* SupportedRangeTableViewController.swift in Sources */, - 892A5D28222EF567008961AB /* (null) in Sources */, - C1E0EEF624EB26D800086510 /* DeliveryUncertaintyRecoveryView.swift in Sources */, - 89D204BB21CC7F34001238CC /* MockCGMManagerSettingsViewController.swift in Sources */, - 1DABAD3A2453615200ACF708 /* IssueAlertTableViewController.swift in Sources */, - C18733C729B94A6400519CDF /* IdentifiableClass.swift in Sources */, - A9498D9123386D0800DAA9B9 /* MockService+UI.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A9E6758122713F4700E25293 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C1CB895925C8E7D900782BAC /* Modelv1v4.xcmappingmodel in Sources */, - 89AE2235228BCAAB00BDFD85 /* CarbSensitivitySchedule.swift in Sources */, - 89AE2236228BCAAB00BDFD85 /* DailyQuantitySchedule+Override.swift in Sources */, - 89AE2237228BCAAB00BDFD85 /* EGPSchedule.swift in Sources */, - A933DB8924BF97CC009B417A /* CriticalEventLog.swift in Sources */, - 89AE2238228BCAAB00BDFD85 /* TemporaryScheduleOverride.swift in Sources */, - 89AE2239228BCAAB00BDFD85 /* TemporaryScheduleOverrideHistory.swift in Sources */, - 89AE223A228BCAAB00BDFD85 /* TemporaryScheduleOverridePreset.swift in Sources */, - 89AE223B228BCAAB00BDFD85 /* TemporaryScheduleOverrideSettings.swift in Sources */, - A987CD4724A5893500439ADC /* JSONStreamEncoder.swift in Sources */, - C1CEBFD929BA9D81007FD8A3 /* TimeZone.swift in Sources */, - 89AE223C228BCAAB00BDFD85 /* WeakSet.swift in Sources */, - A9E6758222713F4700E25293 /* LoopNotificationCategory.swift in Sources */, - C1CEBFDA29BA9D88007FD8A3 /* ClosedRange.swift in Sources */, - A9E1E6AA24E1B7C10073CA39 /* SyncCarbObject.swift in Sources */, - A9E6758422713F4700E25293 /* NewCarbEntry.swift in Sources */, - A9E6758522713F4700E25293 /* GlucoseMath.swift in Sources */, - A9E6758722713F4700E25293 /* CarbEntry.swift in Sources */, - A9E6758822713F4700E25293 /* HealthKitSampleStore.swift in Sources */, - C17F39CC23CD2D3E00FA1113 /* DeviceLog.xcdatamodeld in Sources */, - A93CA89A278D08CC003B5A01 /* PumpAlarmType.swift in Sources */, - C1CEBFDC29BA9D9D007FD8A3 /* NumberFormatter.swift in Sources */, - A9E6758C22713F4700E25293 /* DoseType.swift in Sources */, - A9E6758D22713F4700E25293 /* CachedCarbObject+CoreDataClass.swift in Sources */, - 1DD9CE9A26B8CF4A008B4A46 /* HKDevice+Encodable.swift in Sources */, - A9E6758E22713F4700E25293 /* DailyValueSchedule.swift in Sources */, - A9E6758F22713F4700E25293 /* NewPumpEvent.swift in Sources */, - A9CE912324CA033A00302A40 /* InsulinModelProvider.swift in Sources */, - A9E6759022713F4700E25293 /* CachedInsulinDeliveryObject+CoreDataClass.swift in Sources */, - C1CEBFD429BA9D57007FD8A3 /* HKUnit.swift in Sources */, - A9E6759122713F4700E25293 /* GlucoseTrend.swift in Sources */, - A9E6759222713F4700E25293 /* PumpManagerStatus.swift in Sources */, - A9E6759322713F4700E25293 /* CarbMath.swift in Sources */, - A9E6759522713F4700E25293 /* ExponentialInsulinModel.swift in Sources */, - B4102D3324ABB0D8005D460B /* DeviceLifecycleProgress.swift in Sources */, - A9E6759722713F4700E25293 /* DailyQuantitySchedule.swift in Sources */, - C1A174EC23DEAD670034DF11 /* DeviceLogEntry+CoreDataClass.swift in Sources */, - A9E6759822713F4700E25293 /* CarbRatioSchedule.swift in Sources */, - A9E6759922713F4700E25293 /* GlucoseSampleValue.swift in Sources */, - A9E6759A22713F4700E25293 /* GlucoseDisplayable.swift in Sources */, - A9E6759B22713F4700E25293 /* PersistenceController.swift in Sources */, - B4B85FD024A2318A00A296A3 /* GlucoseRangeCategory.swift in Sources */, - A9E6759C22713F4700E25293 /* InsulinDeliveryStore.swift in Sources */, - A9E6759D22713F4700E25293 /* DeviceManager.swift in Sources */, - A9E6759E22713F4700E25293 /* DoseUnit.swift in Sources */, - C17F39D123CE34FD00FA1113 /* StoredDeviceLogEntry.swift in Sources */, - A9E675A022713F4700E25293 /* HKQuantitySample.swift in Sources */, - C1CEBFD329BA9D4F007FD8A3 /* OSLog.swift in Sources */, - A9E675A122713F4700E25293 /* Double.swift in Sources */, - A9E675A222713F4700E25293 /* KeychainManager.swift in Sources */, - A9E675A322713F4700E25293 /* PumpManager.swift in Sources */, - A9FD047024E310DD0040F203 /* HKObject.swift in Sources */, - A9E675A422713F4700E25293 /* SampleValue.swift in Sources */, - C1CEBFD829BA9D7A007FD8A3 /* Sequence.swift in Sources */, - A9E675A522713F4700E25293 /* GlucoseValue.swift in Sources */, - A9E675A622713F4700E25293 /* BasalRateSchedule.swift in Sources */, - A9E675A722713F4700E25293 /* DoseStore.swift in Sources */, - A9E675A922713F4700E25293 /* PumpEvent+CoreDataProperties.swift in Sources */, - A9E675AA22713F4700E25293 /* ReservoirValue.swift in Sources */, - A93761C225ED670200F6BE43 /* BluetoothProvider.swift in Sources */, - A9E675AB22713F4700E25293 /* HKHealthStore.swift in Sources */, - A9E675AC22713F4700E25293 /* Reservoir.swift in Sources */, - C1092410286A4ADB00FAD2B8 /* AutomaticDosingStrategy.swift in Sources */, - A9E675AE22713F4700E25293 /* CarbValue.swift in Sources */, - C17F39CB23CD2D2F00FA1113 /* DeviceLogEntryType.swift in Sources */, - A9E675AF22713F4700E25293 /* PumpEventType.swift in Sources */, - C1A174ED23DEAD6A0034DF11 /* DeviceLogEntry+CoreDataProperties.swift in Sources */, - A9E675B222713F4700E25293 /* GlucoseRangeSchedule.swift in Sources */, - A9E675B322713F4700E25293 /* PersistedPumpEvent.swift in Sources */, - 89AE2231228BC68100BDFD85 /* DoseProgressTimerEstimator.swift in Sources */, - A9E675B422713F4700E25293 /* CachedCarbObject+CoreDataProperties.swift in Sources */, - A9E675B522713F4700E25293 /* AbsorbedCarbValue.swift in Sources */, - B455F4FE2600E5EE000ED456 /* GlucoseRange.swift in Sources */, - A9E675B722713F4700E25293 /* NSManagedObjectContext.swift in Sources */, - A9E675B822713F4700E25293 /* StoredCarbEntry.swift in Sources */, - C1CEBFD629BA9D6C007FD8A3 /* Collection.swift in Sources */, - A9E675BA22713F4700E25293 /* InsulinValue.swift in Sources */, - A95A1D802460BBC70079378D /* DosingDecisionObject+CoreDataClass.swift in Sources */, - 89AE2230228BC68100BDFD85 /* DoseProgressReporter.swift in Sources */, - A9E675BD22713F4700E25293 /* HKQuantitySample+InsulinKit.swift in Sources */, - C17F39CA23CD2D2000FA1113 /* PersistentDeviceLog.swift in Sources */, - E9A6D0E828DBCF5800DFF9D9 /* LoopNotificationUserInfoKey.swift in Sources */, - A9E675BE22713F4700E25293 /* InsulinModel.swift in Sources */, - 89AE222D228BC66E00BDFD85 /* Locked.swift in Sources */, - A9E675BF22713F4700E25293 /* QuantityFormatter.swift in Sources */, - A9E675C022713F4700E25293 /* ServiceAuthentication.swift in Sources */, - A9E675C122713F4700E25293 /* NewGlucoseSample.swift in Sources */, - A9E675C222713F4700E25293 /* InsulinMath.swift in Sources */, - C1CEBFD729BA9D73007FD8A3 /* MutableCollection.swift in Sources */, - A9E675C322713F4700E25293 /* UnfairLock.swift in Sources */, - 1DD3DEB624451C3300BD8E40 /* Alert.swift in Sources */, - A9E675C422713F4700E25293 /* HealthStoreUnitCache.swift in Sources */, - A9E675C622713F4700E25293 /* CarbStatus.swift in Sources */, - B42C951B24A63B8100857C73 /* DeviceStatusHighlight.swift in Sources */, - A935094526E2FAB70030B60D /* GlucoseCondition.swift in Sources */, - A932803C2798D63B0091D0A1 /* SyncAlertObject.swift in Sources */, - A9498D7023386C0B00DAA9B9 /* TempBasalRecommendation.swift in Sources */, - A9E675C722713F4700E25293 /* DoseEntry.swift in Sources */, - A9E675C822713F4700E25293 /* NSUserActivity+CarbKit.swift in Sources */, - C1CEBFD229BA9D43007FD8A3 /* TimeInterval.swift in Sources */, - A9E675C922713F4700E25293 /* CachedInsulinDeliveryObject+CoreDataProperties.swift in Sources */, - C1CEBFD529BA9D62007FD8A3 /* LocalizedString.swift in Sources */, - A967D94A24F99B6A00CDDF8A /* OutputStream.swift in Sources */, - A9E675CB22713F4700E25293 /* StoredGlucoseSample.swift in Sources */, - A9E675CC22713F4700E25293 /* GlucoseEffect.swift in Sources */, - A9E675CD22713F4700E25293 /* WeakSynchronizedSet.swift in Sources */, - A9E675CE22713F4700E25293 /* LoopMath.swift in Sources */, - C1CEBFDB29BA9D8F007FD8A3 /* Data.swift in Sources */, - A9E675CF22713F4700E25293 /* Date.swift in Sources */, - A9E675D022713F4700E25293 /* GlucoseChange.swift in Sources */, - A9E675D122713F4700E25293 /* GlucoseSchedule.swift in Sources */, - A9E675D222713F4700E25293 /* NSUserDefaults.swift in Sources */, - A9E675D322713F4700E25293 /* CarbStore.swift in Sources */, - A9E675D422713F4700E25293 /* CachedGlucoseObject+CoreDataClass.swift in Sources */, - E94141CE24C8F2950096C326 /* ExponentialInsulinModelPreset.swift in Sources */, - A9498D7F23386C3300DAA9B9 /* GlucoseThreshold.swift in Sources */, - C1E94D3B28170DAC00262A6E /* Model.xcdatamodeld in Sources */, - A9E675D522713F4700E25293 /* WalshInsulinModel.swift in Sources */, - A9A53E2D2714E5BC0050C0B1 /* CodableDevice.swift in Sources */, - A9E675D622713F4700E25293 /* GlucoseEffectVelocity.swift in Sources */, - B40C43912707408400F5D86C /* DeliveryLimits.swift in Sources */, - A9E675D722713F4700E25293 /* PumpEvent+CoreDataClass.swift in Sources */, - A9E675D922713F4700E25293 /* Reservoir+CoreDataProperties.swift in Sources */, - E9F54FBA258052130034795E /* InsulinType.swift in Sources */, - A96E6C3827B35BC600F81A5B /* AnyCodableEquatable.swift in Sources */, - A9E675DA22713F4700E25293 /* HKQuantitySample+CarbKit.swift in Sources */, - A9E675DB22713F4700E25293 /* HKQuantitySample+GlucoseKit.swift in Sources */, - A9E675DC22713F4700E25293 /* CachedGlucoseObject+CoreDataProperties.swift in Sources */, - A9E675DD22713F4700E25293 /* PumpManagerError.swift in Sources */, - A9E675E022713F4700E25293 /* GlucoseStore.swift in Sources */, - A912BE2D245B9F9800CBE199 /* SettingsObject+CoreDataClass.swift in Sources */, - A9E675E122713F4700E25293 /* WeakSynchronizedDelegate.swift in Sources */, - A9E675E222713F4700E25293 /* CGMManager.swift in Sources */, - A9E675E322713F4700E25293 /* CarbStoreError.swift in Sources */, - A9E675E422713F4700E25293 /* HKQuantity.swift in Sources */, - A9BD318324F4548900994B83 /* Modelv3EntityMigrationPolicy.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - B4CEE2DC257129780093111B /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - B4CEE2E3257129780093111B /* UnfinalizedDoseTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 1DEE226924A676A300693C32 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 43D8FDCA1C728FDF0073BE78 /* LoopKit */; - targetProxy = 1DEE226A24A676A300693C32 /* PBXContainerItemProxy */; - }; - 1DEE230424A6774900693C32 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 430157F61C7EC03B00B64B63 /* LoopKit Example */; - targetProxy = 1DEE230324A6774900693C32 /* PBXContainerItemProxy */; - }; - 4301581C1C7ECB5E00B64B63 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 43D8FDCA1C728FDF0073BE78 /* LoopKit */; - targetProxy = 4301581B1C7ECB5E00B64B63 /* PBXContainerItemProxy */; - }; - 43BA715A201E484D0058961E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 43BA7153201E484D0058961E /* LoopKitUI */; - targetProxy = 43BA7159201E484D0058961E /* PBXContainerItemProxy */; - }; - 43CACE1022483AC500F90AF5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 89D2047121CC7BD7001238CC /* MockKit */; - targetProxy = 43CACE0F22483AC500F90AF5 /* PBXContainerItemProxy */; - }; - 43CACE1222483AC500F90AF5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 89D2048E21CC7C12001238CC /* MockKitUI */; - targetProxy = 43CACE1122483AC500F90AF5 /* PBXContainerItemProxy */; - }; - 43CACE1422483B6100F90AF5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 43D8FDCA1C728FDF0073BE78 /* LoopKit */; - targetProxy = 43CACE1322483B6100F90AF5 /* PBXContainerItemProxy */; - }; - 43CACE1622483B6100F90AF5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 892A5D33222F03CB008961AB /* LoopTestingKit */; - targetProxy = 43CACE1522483B6100F90AF5 /* PBXContainerItemProxy */; - }; - 43CACE1822483B7200F90AF5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 43D8FDCA1C728FDF0073BE78 /* LoopKit */; - targetProxy = 43CACE1722483B7200F90AF5 /* PBXContainerItemProxy */; - }; - 43D8FDD81C728FDF0073BE78 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 43D8FDCA1C728FDF0073BE78 /* LoopKit */; - targetProxy = 43D8FDD71C728FDF0073BE78 /* PBXContainerItemProxy */; - }; - 892A5D48222F03CB008961AB /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 892A5D33222F03CB008961AB /* LoopTestingKit */; - targetProxy = 892A5D47222F03CB008961AB /* PBXContainerItemProxy */; - }; - A9E6757B22713C3F00E25293 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 43BA7153201E484D0058961E /* LoopKitUI */; - targetProxy = A9E6757A22713C3F00E25293 /* PBXContainerItemProxy */; - }; - A9E6757D22713C3F00E25293 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 89D2047121CC7BD7001238CC /* MockKit */; - targetProxy = A9E6757C22713C3F00E25293 /* PBXContainerItemProxy */; - }; - B4CEE2E7257129780093111B /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 89D2047121CC7BD7001238CC /* MockKit */; - targetProxy = B4CEE2E6257129780093111B /* PBXContainerItemProxy */; - }; - C1BECA96285902F5008075C4 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 43D8FDCA1C728FDF0073BE78 /* LoopKit */; - targetProxy = C1BECA95285902F5008075C4 /* PBXContainerItemProxy */; - }; - C1E0280C264C47C900EC4DF1 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 43BA7153201E484D0058961E /* LoopKitUI */; - targetProxy = C1E0280B264C47C900EC4DF1 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 1F5DAB2B2118CE9300048054 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 1F5DAB2C2118CE9300048054 /* es */, - 1F5DAB322118D2A700048054 /* ru */, - 1F5DAB392118D5A200048054 /* de */, - 1F5DAB462118F14600048054 /* fr */, - 1F5DAB4D2118F18E00048054 /* en */, - 1F5DAB562118F2C700048054 /* zh-Hans */, - 1F5DAB622118F33000048054 /* it */, - 1F5DAB6E2118F3C200048054 /* nl */, - 1F5DAB7A2118F3FB00048054 /* nb */, - 1FE58794211D0967004F24ED /* Base */, - 1F50C324212B20D300C18FAB /* pl */, - F5E0BDF327E1D9EC0033557E /* he */, - F5E0BE0F27E1DC490033557E /* tr */, - C1E50006297E492E0018FA21 /* ro */, - C183FDD5297E493D003B16ED /* fi */, - C161742C297E494D007C2E5F /* vi */, - C161E8FA297E495300E22BDD /* pt-BR */, - C133067A297E49730067A05C /* sv */, - C13493B5297E498700D87305 /* da */, - C1D107B8297E499D008905A6 /* ja */, - C1D7162929C75EE200B5AB3B /* cs */, - C15A582629C7866600D3A5A1 /* ar */, - C1FDCC0629C786F90056E652 /* sk */, - 193F1E442B44C1EF00525770 /* hu */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - 430157FF1C7EC03B00B64B63 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 430158001C7EC03B00B64B63 /* Base */, - F5E0BDE527E1D8C20033557E /* da */, - F5E0BDEA27E1D9590033557E /* fi */, - F5E0BDEF27E1D9EB0033557E /* he */, - F5E0BDF727E1DA260033557E /* ja */, - F5E0BDFC27E1DACD0033557E /* pt-BR */, - F5E0BE0127E1DB620033557E /* ro */, - F5E0BE0627E1DBA40033557E /* sv */, - F5E0BE0B27E1DC480033557E /* tr */, - F5E0BE1327E1DCC90033557E /* vi */, - C1821688297E55A7001EB097 /* es */, - C1A4ED662981EE36008F4B1A /* de */, - C104B64A2981EE3B003A9235 /* fr */, - C14C46E82981EE3F00E20BEF /* nb */, - C16528FF2981EE40000B130A /* nl */, - C1BCB5BA298309C4001C50FF /* it */, - C1F490012995821600C8BD69 /* pl */, - C122DF0129BBFAAE00321F8D /* ru */, - C15A582429C7866600D3A5A1 /* ar */, - C1FDCC0429C786F90056E652 /* sk */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 430158041C7EC03B00B64B63 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 430158051C7EC03B00B64B63 /* Base */, - F5E0BDE427E1D8950033557E /* da */, - F5E0BDE927E1D9590033557E /* fi */, - F5E0BDEE27E1D9EB0033557E /* he */, - F5E0BDF627E1D9F90033557E /* ja */, - F5E0BDFB27E1DAA00033557E /* pt-BR */, - F5E0BE0027E1DB350033557E /* ro */, - F5E0BE0527E1DB760033557E /* sv */, - F5E0BE0A27E1DC480033557E /* tr */, - F5E0BE1227E1DC9C0033557E /* vi */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; - 43D8FEED1C7294E90073BE78 /* InsulinKit.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 43D8FEEE1C7294E90073BE78 /* Base */, - 7D68A9CA1FE0A3D200522C49 /* es */, - 7D68AAB91FE31A2800522C49 /* ru */, - 1F5DAB372118D5A200048054 /* de */, - 1F5DAB442118F14600048054 /* fr */, - 1F5DAB542118F2C700048054 /* zh-Hans */, - 1F5DAB602118F33000048054 /* it */, - 1F5DAB6C2118F3C200048054 /* nl */, - 1F5DAB782118F3FB00048054 /* nb */, - 1F50C322212B20D300C18FAB /* pl */, - F5E0BDE727E1D8C20033557E /* da */, - F5E0BDEC27E1D9870033557E /* fi */, - F5E0BDF127E1D9EB0033557E /* he */, - F5E0BDF927E1DA260033557E /* ja */, - F5E0BDFE27E1DACE0033557E /* pt-BR */, - F5E0BE0327E1DB620033557E /* ro */, - F5E0BE0827E1DBA40033557E /* sv */, - F5E0BE0D27E1DC490033557E /* tr */, - F5E0BE1527E1DCC90033557E /* vi */, - C15A582729C7866600D3A5A1 /* ar */, - C1FDCC0729C786F90056E652 /* sk */, - 193F1E422B44C1EE00525770 /* hu */, - ); - name = InsulinKit.storyboard; - sourceTree = ""; - }; - 4B67E2C9289B4EDB002D92AF /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 4B67E2CA289B4EDB002D92AF /* de */, - C183FDD3297E493D003B16ED /* fi */, - C1821689297E55A7001EB097 /* es */, - C14C0AD02981EE35001B758E /* da */, - C104B64B2981EE3B003A9235 /* fr */, - C14C46E92981EE3F00E20BEF /* nb */, - C16529002981EE40000B130A /* nl */, - C1AA4E0F2981EE4400888F32 /* ro */, - C1D72CFD2981EE4600EE0982 /* sv */, - C1BCB5BB298309C4001C50FF /* it */, - C1F490022995821600C8BD69 /* pl */, - C1B2679E2995824000BCB7C1 /* tr */, - C122DF0229BBFAAE00321F8D /* ru */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; - 4B67E2CC289B4EDB002D92AF /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 4B67E2CD289B4EDB002D92AF /* de */, - C1E50008297E492E0018FA21 /* ro */, - C1790E6D297E493600683E3B /* nl */, - C183FDD7297E493D003B16ED /* fi */, - C16DFA45297E494500D56397 /* fr */, - C161742E297E494D007C2E5F /* vi */, - C161E8FC297E495300E22BDD /* pt-BR */, - C13F89C4297E495B00C71398 /* ru */, - C1394BA6297E49630042F1A9 /* pl */, - C133067C297E49730067A05C /* sv */, - C14690CF297E497A00124A99 /* it */, - C1469E02297E498100042439 /* nb */, - C13493B7297E498700D87305 /* da */, - C10B8078297E498E00446CDD /* es */, - C1DB5556297E499500EB1DCE /* zh-Hans */, - C1D107BA297E499D008905A6 /* ja */, - C19E387F298638CE00851444 /* tr */, - C1D7162429C75E3B00B5AB3B /* en */, - C1D7162529C75E9000B5AB3B /* cs */, - C1D7162629C75E9F00B5AB3B /* he */, - C15A582A29C7866600D3A5A1 /* ar */, - C1FDCC0A29C786F90056E652 /* sk */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - 7D68A9B01FE0A3D000522C49 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 7D68A9AF1FE0A3D000522C49 /* es */, - 7D68AABC1FE31BE700522C49 /* ru */, - 1F5DAB3B2118D5A300048054 /* de */, - 1F5DAB402118D5D500048054 /* en */, - 1F5DAB482118F14700048054 /* fr */, - 1F5DAB582118F2C700048054 /* zh-Hans */, - 1F5DAB642118F33000048054 /* it */, - 1F5DAB702118F3C200048054 /* nl */, - 1F5DAB7C2118F3FC00048054 /* nb */, - 1F50C326212B20D400C18FAB /* pl */, - F5E0BDF427E1D9EC0033557E /* he */, - F5E0BE1027E1DC490033557E /* tr */, - C1E50005297E492E0018FA21 /* ro */, - C183FDD4297E493D003B16ED /* fi */, - C161742B297E494D007C2E5F /* vi */, - C161E8F9297E495300E22BDD /* pt-BR */, - C1330679297E49730067A05C /* sv */, - C13493B4297E498700D87305 /* da */, - C1D107B7297E499D008905A6 /* ja */, - C15A582529C7866600D3A5A1 /* ar */, - C121D8D329C7866D00DA0520 /* cs */, - C1FDCC0529C786F90056E652 /* sk */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - 7D68A9E31FE0A3D300522C49 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 7D68A9E21FE0A3D300522C49 /* es */, - 7D68AAC61FE31BE900522C49 /* ru */, - 1F5DAB3E2118D5A300048054 /* de */, - 1F5DAB4B2118F14700048054 /* fr */, - 1F5DAB5B2118F2C700048054 /* zh-Hans */, - 1F5DAB672118F33100048054 /* it */, - 1F5DAB732118F3C300048054 /* nl */, - 1F5DAB7F2118F3FC00048054 /* nb */, - 1FE58790211CFBB7004F24ED /* Base */, - 1F50C329212B20D400C18FAB /* pl */, - F5E0BDF527E1D9EC0033557E /* he */, - F5E0BE1127E1DC490033557E /* tr */, - C1E50007297E492E0018FA21 /* ro */, - C183FDD6297E493D003B16ED /* fi */, - C161742D297E494D007C2E5F /* vi */, - C161E8FB297E495300E22BDD /* pt-BR */, - C133067B297E49730067A05C /* sv */, - C13493B6297E498700D87305 /* da */, - C1D107B9297E499D008905A6 /* ja */, - C1D7162729C75EBD00B5AB3B /* en */, - C1D7162829C75ECE00B5AB3B /* cs */, - C15A582929C7866600D3A5A1 /* ar */, - C1FAB5C329C786B000D25073 /* hi */, - C1FDCC0929C786F90056E652 /* sk */, - 193F1E452B44C1EF00525770 /* hu */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - C1D7162329C75DC700B5AB3B /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - C1D7162229C75DC700B5AB3B /* en */, - C15A582B29C7866600D3A5A1 /* ar */, - C121D8D429C7866D00DA0520 /* cs */, - C10BD98429C7867600FE2BDC /* da */, - C12D11D229C7867E000B215F /* de */, - C1FC9C6329C78690005D2515 /* es */, - C1F4FD5A29C7869800D7ACBC /* fi */, - C1E5F20D29C786A100BC686C /* fr */, - C1FF3D4E29C786A900BDC1EC /* he */, - C1FAB5C429C786B000D25073 /* hi */, - C1C685F929C786B70002E063 /* it */, - C1B0CFDB29C786BF0045B04D /* ja */, - C19951DA29C786C8001983C9 /* nb */, - C1A1C7A529C786D1001A0FA5 /* nl */, - C1B761F229C786D90098916A /* pl */, - C1E693D129C786E200410918 /* pt-BR */, - C10340F329C786E900FE5BA1 /* ro */, - C1FC393029C786F20003C587 /* ru */, - C1FDCC0B29C786F90056E652 /* sk */, - C1E5A6DF29C7870100703C90 /* sv */, - C18E73FD29C7870A0031245F /* tr */, - C192C60529C78711001EFEA6 /* vi */, - C15C115029C814F300EBAC55 /* zh-Hans */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - E9DFB93324E8CD5800468917 /* LegacyInsulinDeliveryTableViewController.storyboard */ = { - isa = PBXVariantGroup; - children = ( - E9DFB93424E8CD5800468917 /* Base */, - E9DFB93724E8CD7400468917 /* en */, - E9DFB93924E8CD7800468917 /* zh-Hans */, - E9DFB93B24E8CD7A00468917 /* nl */, - E9DFB93D24E8CD7B00468917 /* fr */, - E9DFB93F24E8CD7C00468917 /* de */, - E9DFB94124E8CD7D00468917 /* it */, - E9DFB94324E8CD8100468917 /* nb */, - E9DFB94524E8CD8300468917 /* pl */, - E9DFB94724E8CD8400468917 /* ru */, - E9DFB94924E8CD8600468917 /* es */, - F5E0BDE827E1D8C20033557E /* da */, - F5E0BDED27E1D9870033557E /* fi */, - F5E0BDF227E1D9EC0033557E /* he */, - F5E0BDFA27E1DA260033557E /* ja */, - F5E0BDFF27E1DACE0033557E /* pt-BR */, - F5E0BE0427E1DB620033557E /* ro */, - F5E0BE0927E1DBA40033557E /* sv */, - F5E0BE0E27E1DC490033557E /* tr */, - F5E0BE1627E1DCC90033557E /* vi */, - C15A582829C7866600D3A5A1 /* ar */, - C1FDCC0829C786F90056E652 /* sk */, - 193F1E432B44C1EE00525770 /* hu */, - ); - name = LegacyInsulinDeliveryTableViewController.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 1DEE22FF24A676A300693C32 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = LoopKitHostedTests/LoopKitHostedTests.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopKitHostedTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LoopKit Example.app/LoopKit Example"; - }; - name = Debug; - }; - 1DEE230024A676A300693C32 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = LoopKitHostedTests/LoopKitHostedTests.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopKitHostedTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LoopKit Example.app/LoopKit Example"; - }; - name = Release; - }; - 430158131C7EC03B00B64B63 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = "LoopKit Example/LoopKitExample.entitlements"; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DEVELOPMENT_TEAM = UY678SP37Q; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = "LoopKit Example/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.LoopKitExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - SWIFT_EMIT_LOC_STRINGS = YES; - }; - name = Debug; - }; - 430158141C7EC03B00B64B63 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = "LoopKit Example/LoopKitExample.entitlements"; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DEVELOPMENT_TEAM = UY678SP37Q; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = "LoopKit Example/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.LoopKitExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - SWIFT_EMIT_LOC_STRINGS = YES; - }; - name = Release; - }; - 43BA715D201E484D0058961E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 41; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 41; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = LoopKitUI/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopKitUI; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - }; - name = Debug; - }; - 43BA715E201E484D0058961E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 41; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 41; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = LoopKitUI/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopKitUI; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - }; - name = Release; - }; - 43D8FDDD1C728FDF0073BE78 /* 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - 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; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 41; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - 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 = 15.1; - LOCALIZED_STRING_MACRO_NAMES = ( - NSLocalizedString, - CFLocalizedString, - LocalizedString, - ); - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - WATCHOS_DEPLOYMENT_TARGET = 4.0; - }; - name = Debug; - }; - 43D8FDDE1C728FDF0073BE78 /* 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - 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; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 41; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - 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 = 15.1; - LOCALIZED_STRING_MACRO_NAMES = ( - NSLocalizedString, - CFLocalizedString, - LocalizedString, - ); - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - WATCHOS_DEPLOYMENT_TARGET = 4.0; - }; - name = Release; - }; - 43D8FDE01C728FDF0073BE78 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - CODE_SIGN_STYLE = Automatic; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 41; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = LoopKit/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopKit; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 43D8FDE11C728FDF0073BE78 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - CODE_SIGN_STYLE = Automatic; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 41; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = LoopKit/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopKit; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 43D8FDE31C728FDF0073BE78 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = LoopKitTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopKitTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 43D8FDE41C728FDF0073BE78 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = LoopKitTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopKitTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 89AE2219228BC50900BDFD85 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - COPY_PHASE_STRIP = NO; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - INFOPLIST_FILE = MockKit/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.MockKit; - PRODUCT_NAME = MockKit; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 89AE221A228BC50900BDFD85 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = LoopTestingKit/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.MockKit; - PRODUCT_NAME = MockKit; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 89AE221B228BC50900BDFD85 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - COPY_PHASE_STRIP = NO; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = MockKit/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.MockKitUI; - PRODUCT_NAME = MockKitUI; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_INSTALL_OBJC_HEADER = NO; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 89AE221C228BC50900BDFD85 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = MockKit/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.MockKitUI; - PRODUCT_NAME = MockKitUI; - SKIP_INSTALL = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 89AE221D228BC50900BDFD85 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - COPY_PHASE_STRIP = NO; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = MockKitUI/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopTestingKit; - PRODUCT_NAME = LoopTestingKit; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 89AE221E228BC50900BDFD85 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = MockKitUI/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopTestingKit; - PRODUCT_NAME = LoopTestingKit; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - A9E675EE22713F4700E25293 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Automatic; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 41; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = LoopKit/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopKit; - PRODUCT_NAME = LoopKit; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = watchos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "watchos watchsimulator"; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - TARGETED_DEVICE_FAMILY = 4; - }; - name = Debug; - }; - A9E675EF22713F4700E25293 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Automatic; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 41; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = LoopKit/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopKit; - PRODUCT_NAME = LoopKit; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = watchos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "watchos watchsimulator"; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - TARGETED_DEVICE_FAMILY = 4; - }; - name = Release; - }; - C16C6E022576B4B7003052EF /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - INFOPLIST_FILE = MockKitTests/Info.plist; - PRODUCT_NAME = MockKitTests; - }; - name = Debug; - }; - C16C6E032576B4B7003052EF /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - INFOPLIST_FILE = MockKitTests/Info.plist; - PRODUCT_NAME = MockKitTests; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 1DEE22FE24A676A300693C32 /* Build configuration list for PBXNativeTarget "LoopKitHostedTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1DEE22FF24A676A300693C32 /* Debug */, - 1DEE230024A676A300693C32 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 430158171C7EC03B00B64B63 /* Build configuration list for PBXNativeTarget "LoopKit Example" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 430158131C7EC03B00B64B63 /* Debug */, - 430158141C7EC03B00B64B63 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 43BA715F201E484D0058961E /* Build configuration list for PBXNativeTarget "LoopKitUI" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 43BA715D201E484D0058961E /* Debug */, - 43BA715E201E484D0058961E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 43D8FDC51C728FDF0073BE78 /* Build configuration list for PBXProject "LoopKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 43D8FDDD1C728FDF0073BE78 /* Debug */, - 43D8FDDE1C728FDF0073BE78 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 43D8FDDF1C728FDF0073BE78 /* Build configuration list for PBXNativeTarget "LoopKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 43D8FDE01C728FDF0073BE78 /* Debug */, - 43D8FDE11C728FDF0073BE78 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 43D8FDE21C728FDF0073BE78 /* Build configuration list for PBXNativeTarget "LoopKitTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 43D8FDE31C728FDF0073BE78 /* Debug */, - 43D8FDE41C728FDF0073BE78 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 89AE2220228BC54C00BDFD85 /* Build configuration list for PBXNativeTarget "LoopTestingKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 89AE221D228BC50900BDFD85 /* Debug */, - 89AE221E228BC50900BDFD85 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 89AE2221228BC54C00BDFD85 /* Build configuration list for PBXNativeTarget "MockKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 89AE2219228BC50900BDFD85 /* Debug */, - 89AE221A228BC50900BDFD85 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 89AE2222228BC54C00BDFD85 /* Build configuration list for PBXNativeTarget "MockKitUI" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 89AE221B228BC50900BDFD85 /* Debug */, - 89AE221C228BC50900BDFD85 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - A9E675ED22713F4700E25293 /* Build configuration list for PBXNativeTarget "LoopKit-watchOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - A9E675EE22713F4700E25293 /* Debug */, - A9E675EF22713F4700E25293 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - B4CEE2EA257129780093111B /* Build configuration list for PBXNativeTarget "MockKitTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C16C6E022576B4B7003052EF /* Debug */, - C16C6E032576B4B7003052EF /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - C1CCF1042858F07A0035389C /* XCRemoteSwiftPackageReference "SwiftCharts" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ivanschuetz/SwiftCharts"; - requirement = { - branch = master; - kind = branch; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - C1CCF1052858F07A0035389C /* SwiftCharts */ = { - isa = XCSwiftPackageProductDependency; - package = C1CCF1042858F07A0035389C /* XCRemoteSwiftPackageReference "SwiftCharts" */; - productName = SwiftCharts; - }; - C1CCF1072858F1E10035389C /* SwiftCharts */ = { - isa = XCSwiftPackageProductDependency; - package = C1CCF1042858F07A0035389C /* XCRemoteSwiftPackageReference "SwiftCharts" */; - productName = SwiftCharts; - }; -/* End XCSwiftPackageProductDependency section */ - -/* Begin XCVersionGroup section */ - C168CA77280DD00F002BD2A7 /* Model.xcdatamodeld */ = { - isa = XCVersionGroup; - children = ( - C168CA78280DD00F002BD2A7 /* Model.xcdatamodel */, - C168CA79280DD00F002BD2A7 /* Modelv4.xcdatamodel */, - ); - currentVersion = C168CA79280DD00F002BD2A7 /* Modelv4.xcdatamodel */; - path = Model.xcdatamodeld; - sourceTree = ""; - versionGroupType = wrapper.xcdatamodel; - }; - C17F39BF23CD24A000FA1113 /* DeviceLog.xcdatamodeld */ = { - isa = XCVersionGroup; - children = ( - C17F39C023CD24A000FA1113 /* DeviceCommsLog.xcdatamodel */, - ); - currentVersion = C17F39C023CD24A000FA1113 /* DeviceCommsLog.xcdatamodel */; - path = DeviceLog.xcdatamodeld; - sourceTree = ""; - versionGroupType = wrapper.xcdatamodel; - }; -/* End XCVersionGroup section */ - }; - rootObject = 43D8FDC21C728FDF0073BE78 /* Project object */; -} diff --git a/Dependencies/LoopKit/LoopKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Dependencies/LoopKit/LoopKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/Dependencies/LoopKit/LoopKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Dependencies/LoopKit/LoopKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dependencies/LoopKit/LoopKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Dependencies/LoopKit/LoopKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Dependencies/LoopKit/LoopKit.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Dependencies/LoopKit/LoopKit.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index 08de0be8d..000000000 --- a/Dependencies/LoopKit/LoopKit.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded - - - diff --git a/Dependencies/LoopKit/LoopKit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Dependencies/LoopKit/LoopKit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index 9ef3909da..000000000 --- a/Dependencies/LoopKit/LoopKit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,14 +0,0 @@ -{ - "pins" : [ - { - "identity" : "swiftcharts", - "kind" : "remoteSourceControl", - "location" : "https://github.com/ivanschuetz/SwiftCharts", - "state" : { - "branch" : "master", - "revision" : "3d011f67eccb1ffa622fbfccb1348eed80309ae8" - } - } - ], - "version" : 2 -} diff --git a/Dependencies/LoopKit/LoopKit/Alert.swift b/Dependencies/LoopKit/LoopKit/Alert.swift deleted file mode 100644 index 12b7f0546..000000000 --- a/Dependencies/LoopKit/LoopKit/Alert.swift +++ /dev/null @@ -1,268 +0,0 @@ -// -// Alert.swift -// LoopKit -// -// Created by Rick Pasetto on 4/8/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - -/// Protocol that describes any class that issues and retract Alerts. -public protocol AlertIssuer: AnyObject { - /// Issue (post) the given alert, according to its trigger schedule. - func issueAlert(_ alert: Alert) - /// Retract any alerts with the given identifier. This includes both pending and delivered alerts. - func retractAlert(identifier: Alert.Identifier) -} - -/// Protocol that describes something that can deal with a user's response to an alert. -public protocol AlertResponder: AnyObject { - /// Acknowledge alerts with a given type identifier. If the alert fails to clear, an error should be passed to the completion handler, indicating the cause of failure. - func acknowledgeAlert(alertIdentifier: Alert.AlertIdentifier, completion: @escaping (Error?) -> Void) -> Void -} - -public struct PersistedAlert: Equatable { - public let alert: Alert - public let issuedDate: Date - public let retractedDate: Date? - public let acknowledgedDate: Date? - public init(alert: Alert, issuedDate: Date, retractedDate: Date?, acknowledgedDate: Date?) { - self.alert = alert - self.issuedDate = issuedDate - self.retractedDate = retractedDate - self.acknowledgedDate = acknowledgedDate - } -} - -/// Protocol for recording and looking up alerts persisted in storage -public protocol PersistedAlertStore { - /// Determine if an alert is already issued for a given `Alert.Identifier`. - func doesIssuedAlertExist(identifier: Alert.Identifier, completion: @escaping (Swift.Result) -> Void) - - /// Look up all issued, but unretracted, alerts for a given `managerIdentifier`. This is useful for an Alert issuer to see what alerts are extant (outstanding). - /// NOTE: the completion function may be called on a different queue than the caller. Callers must be prepared for this. - func lookupAllUnretracted(managerIdentifier: String, completion: @escaping (Swift.Result<[PersistedAlert], Error>) -> Void) - - /// Look up all issued, but unretracted, and unacknowledged, alerts for a given `managerIdentifier`. This is useful for an Alert issuer to see what alerts are extant (outstanding). - /// NOTE: the completion function may be called on a different queue than the caller. Callers must be prepared for this. - func lookupAllUnacknowledgedUnretracted(managerIdentifier: String, completion: @escaping (Swift.Result<[PersistedAlert], Error>) -> Void) - - /// Records an alert that occurred (likely in the past) but is already retracted. This alert will never be presented to the user by an AlertPresenter. Such a retracted alert has the same date for issued and retracted dates, and there is no acknowledged date - func recordRetractedAlert(_ alert: Alert, at date: Date) -} - -/// Structure that represents an Alert that is issued from a Device. -public struct Alert: Equatable { - /// Representation of an alert Trigger - public enum Trigger: Equatable { - /// Trigger the alert immediately - case immediate - /// Delay triggering the alert by `interval`, but issue it only once. - case delayed(interval: TimeInterval) - /// Delay triggering the alert by `repeatInterval`, and repeat at that interval until cancelled or unscheduled. - case repeating(repeatInterval: TimeInterval) - } - /// The interruption level of the alert. Note that these follow the same definitions as defined by https://developer.apple.com/documentation/usernotifications/unnotificationinterruptionlevel - /// Handlers will determine how that is manifested. - public enum InterruptionLevel: String { - /// The system presents the notification immediately, lights up the screen, and can play a sound. These alerts may be deferred if the user chooses. - case active - /// The system presents the notification immediately, lights up the screen, and can play a sound. These alerts may not be deferred. - case timeSensitive - /// The system makes every attempt at alerting the user, including (possibly) ignoring the mute switch, or the user's notification settings. - case critical - } - /// Content of the alert, either for foreground or background alerts - public struct Content: Equatable { - public let title: String - public let body: String - // TODO: when we have more complicated actions. For now, all we have is "acknowledge". -// let actions: [UserAlertAction] - public let acknowledgeActionButtonLabel: String - public init(title: String, body: String, acknowledgeActionButtonLabel: String) { - self.title = title - self.body = body - self.acknowledgeActionButtonLabel = acknowledgeActionButtonLabel - } - } - public struct Identifier: Equatable, Hashable { - /// Unique device manager identifier from whence the alert came, and to which alert acknowledgements should be directed. - public let managerIdentifier: String - /// Per-alert-type identifier, for instance to group alert types. This is the identifier that will be used to acknowledge the alert. - public let alertIdentifier: AlertIdentifier - public init(managerIdentifier: String, alertIdentifier: AlertIdentifier) { - self.managerIdentifier = managerIdentifier - self.alertIdentifier = alertIdentifier - } - /// An opaque value for this tuple for unique identification of the alert across devices. - public var value: String { - return "\(managerIdentifier).\(alertIdentifier)" - } - } - /// This type represents a per-alert-type identifier, but not necessarily unique across devices. Each device may have its own Swift type for this, - /// so conversion to String is the most convenient, but aliasing the type is helpful because it is not just "any String". - public typealias AlertIdentifier = String - - /// Alert content to show while app is in the foreground. If nil, there shall be no alert while app is in the foreground. - public let foregroundContent: Content? - /// Alert content to show while app is in the background. - public let backgroundContent: Content - /// Trigger for the alert. - public let trigger: Trigger - /// Interruption level for the alert. See `InterruptionLevel` above. - public let interruptionLevel: InterruptionLevel - - /// An alert's "identifier" is a tuple of `managerIdentifier` and `alertIdentifier`. It's purpose is to uniquely identify an alert so we can - /// find which device issued it, and send acknowledgment of that alert to the proper device manager. - public let identifier: Identifier - - /// Representation of a "sound" (or other sound-like action, like vibrate) to perform when the alert is issued. - public enum Sound: Equatable { - case vibrate - case sound(name: String) - } - public let sound: Sound? - - /// Any metadata for the alert used to customize the alert content - public typealias MetadataValue = AnyCodableEquatable - public typealias Metadata = [String: MetadataValue] - public let metadata: Metadata? - - public init(identifier: Identifier, - foregroundContent: Content?, - backgroundContent: Content, - trigger: Trigger, - interruptionLevel: InterruptionLevel = .timeSensitive, - sound: Sound? = nil, - metadata: Metadata? = nil) - { - self.identifier = identifier - self.foregroundContent = foregroundContent - self.backgroundContent = backgroundContent - self.trigger = trigger - self.interruptionLevel = interruptionLevel - self.sound = sound - self.metadata = metadata - } -} - -public extension Alert.Sound { - var filename: String? { - switch self { - case .sound(let name): return name - case .vibrate: return nil - } - } -} - -public protocol AlertSoundVendor { - // Get the base URL for where to find all the vendor's sounds. It is under here that all of the sound files should be. - // Returns nil if the vendor has no sounds. - func getSoundBaseURL() -> URL? - // Get all the sounds for this vendor. Returns an empty array if the vendor has no sounds. - func getSounds() -> [Alert.Sound] -} - -// MARK: Codable implementations - -extension Alert: Codable { } -extension Alert.Content: Codable { } -extension Alert.Identifier: Codable { } -extension Alert.InterruptionLevel: Codable { } -// These Codable implementations of enums with associated values cannot be synthesized (yet) in Swift. -// The code below follows a pattern described by https://medium.com/@hllmandel/codable-enum-with-associated-values-swift-4-e7d75d6f4370 -extension Alert.Trigger: Codable { - private enum CodingKeys: String, CodingKey { - case immediate, delayed, repeating - } - private struct Delayed: Codable { - let delayInterval: TimeInterval - } - private struct Repeating: Codable { - let repeatInterval: TimeInterval - } - public init(from decoder: Decoder) throws { - if let singleValue = try? decoder.singleValueContainer().decode(CodingKeys.RawValue.self) { - switch singleValue { - case CodingKeys.immediate.rawValue: - self = .immediate - default: - throw decoder.enumDecodingError - } - } else { - let container = try decoder.container(keyedBy: CodingKeys.self) - if let delayInterval = try? container.decode(Delayed.self, forKey: .delayed) { - self = .delayed(interval: delayInterval.delayInterval) - } else if let repeatInterval = try? container.decode(Repeating.self, forKey: .repeating) { - self = .repeating(repeatInterval: repeatInterval.repeatInterval) - } else { - throw decoder.enumDecodingError - } - } - } - - public func encode(to encoder: Encoder) throws { - switch self { - case .immediate: - var container = encoder.singleValueContainer() - try container.encode(CodingKeys.immediate.rawValue) - case .delayed(let interval): - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(Delayed(delayInterval: interval), forKey: .delayed) - case .repeating(let repeatInterval): - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(Repeating(repeatInterval: repeatInterval), forKey: .repeating) - } - } -} - -extension Alert.Sound: Codable { - private enum CodingKeys: String, CodingKey { - case vibrate, sound - } - private struct SoundName: Codable { - let name: String - } - public init(from decoder: Decoder) throws { - if let singleValue = try? decoder.singleValueContainer().decode(CodingKeys.RawValue.self) { - switch singleValue { - case CodingKeys.vibrate.rawValue: - self = .vibrate - default: - throw decoder.enumDecodingError - } - } else { - let container = try decoder.container(keyedBy: CodingKeys.self) - if let name = try? container.decode(SoundName.self, forKey: .sound) { - self = .sound(name: name.name); return - } else { - throw decoder.enumDecodingError - } - } - } - - public func encode(to encoder: Encoder) throws { - switch self { - case .vibrate: - var container = encoder.singleValueContainer() - try container.encode(CodingKeys.vibrate.rawValue) - case .sound(let name): - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(SoundName(name: name), forKey: .sound) - } - } -} - -public extension Alert.Metadata { - init(dict: [String: E]) { - self = dict.mapValues { Alert.MetadataValue($0) } - } -} - -extension Decoder { - var enumDecodingError: DecodingError { - return DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "invalid enumeration")) - } -} - diff --git a/Dependencies/LoopKit/LoopKit/AnyCodableEquatable.swift b/Dependencies/LoopKit/LoopKit/AnyCodableEquatable.swift deleted file mode 100644 index fea410633..000000000 --- a/Dependencies/LoopKit/LoopKit/AnyCodableEquatable.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// AnyCodableEquatable.swift -// LoopKit -// -// Created by Darin Krauss on 2/8/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct AnyCodableEquatable: Codable, Equatable { - public enum Error: Swift.Error { - case unknownType - } - - public let wrapped: Any - private let equals: (Self) -> Bool - - public init(_ wrapped: T) { - self.wrapped = wrapped - self.equals = { $0.wrapped as? T == wrapped } - } - - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - if let value = try? container.decode(String.self) { - self.init(value) - } else if let value = try? container.decode(Int.self) { - self.init(value) - } else if let value = try? container.decode(Double.self) { - self.init(value) - } else if let value = try? container.decode(Bool.self) { - self.init(value) - } else { - throw Error.unknownType - } - } - - public func encode(to encoder: Encoder) throws { - try (wrapped as? Encodable)?.encode(to: encoder) - } - - public static func ==(lhs: AnyCodableEquatable, rhs: AnyCodableEquatable) -> Bool { - return lhs.equals(rhs) - } -} diff --git a/Dependencies/LoopKit/LoopKit/AutomaticDosingStrategy.swift b/Dependencies/LoopKit/LoopKit/AutomaticDosingStrategy.swift deleted file mode 100644 index d9b7dc5b7..000000000 --- a/Dependencies/LoopKit/LoopKit/AutomaticDosingStrategy.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// DosingStrategy.swift -// LoopKit -// -// Created by Pete Schwamb on 6/27/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - - -public enum AutomaticDosingStrategy: Int, CaseIterable, Codable { - case tempBasalOnly - case automaticBolus -} diff --git a/Dependencies/LoopKit/LoopKit/BasalRateSchedule.swift b/Dependencies/LoopKit/LoopKit/BasalRateSchedule.swift deleted file mode 100644 index d126e672c..000000000 --- a/Dependencies/LoopKit/LoopKit/BasalRateSchedule.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// BasalRateSchedule.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/12/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public typealias BasalRateSchedule = DailyValueSchedule - -public struct BasalScheduleValidationResult { - let scheduleError: Error? - let itemErrors: [(index: Int, error: Error)] -} - - -public extension DailyValueSchedule where T == Double { - /** - Calculates the total basal delivery for a day - - - returns: The total basal delivery - */ - func total() -> Double { - var total: Double = 0 - - for (index, item) in items.enumerated() { - var endTime = maxTimeInterval - - if index < items.endIndex - 1 { - endTime = items[index + 1].startTime - } - - total += (endTime - item.startTime).hours * item.value - } - - return total - } -} diff --git a/Dependencies/LoopKit/LoopKit/BluetoothProvider.swift b/Dependencies/LoopKit/LoopKit/BluetoothProvider.swift deleted file mode 100644 index 2d6f85c77..000000000 --- a/Dependencies/LoopKit/LoopKit/BluetoothProvider.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// BluetoothProvider.swift -// LoopKit -// -// Created by Darin Krauss on 3/1/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum BluetoothAuthorization: Int { - /// User has not yet made a choice regarding whether the application may use Bluetooth. - case notDetermined - - /// This application is not authorized to use Bluetooth. The user cannot change this application’s status, - case restricted - - /// User has explicitly denied this application from using Bluetooth. - case denied - - /// User has authorized this application to use Bluetooth. - case authorized -} - -public enum BluetoothState: Int { - /// State unknown, update imminent. - case unknown - - /// The connection with the system service was momentarily lost, update imminent. - case resetting - - /// The platform doesn't support the Bluetooth Low Energy Central/Client role. - case unsupported - - /// The application is not authorized to use the Bluetooth Low Energy role. - case unauthorized - - /// Bluetooth is currently powered off. - case poweredOff - - /// Bluetooth is currently powered on and available to use. - case poweredOn -} - -public protocol BluetoothObserver: AnyObject { - /// Informs the observer that the Bluetooth state has changed to the given value. - /// - /// - Parameters: - /// - state: The latest Bluetooth state. - func bluetoothDidUpdateState(_ state: BluetoothState) -} - -public protocol BluetoothProvider: AnyObject { - /// The current Bluetooth authorization. - var bluetoothAuthorization: BluetoothAuthorization { get } - - /// The current Bluetooth state. If Bluetooth has not been authorized then returns .unknown. - var bluetoothState: BluetoothState { get } - - /// Authorize Bluetooth. Should only be invoked if bluetoothAuthorization is .notDetermined. - /// - /// - Parameters: - /// - completion: Invoked when Bluetooth authorization is complete along with the resulting authorization. - func authorizeBluetooth(_ completion: @escaping (BluetoothAuthorization) -> Void) - - /// Start observing Bluetooth changes. - /// - /// - Parameters: - /// - observer: The observer observing Bluetooth changes. - /// - queue: The Dispatch queue upon which to notify the observer of Bluetooth changes. - func addBluetoothObserver(_ observer: BluetoothObserver, queue: DispatchQueue) - - /// Stop observing Bluetooth changes. - /// - /// - Parameters: - /// - observer: The observer observing Bluetooth changes. - func removeBluetoothObserver(_ observer: BluetoothObserver) -} diff --git a/Dependencies/LoopKit/LoopKit/CarbKit/AbsorbedCarbValue.swift b/Dependencies/LoopKit/LoopKit/CarbKit/AbsorbedCarbValue.swift deleted file mode 100644 index bbe78f234..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbKit/AbsorbedCarbValue.swift +++ /dev/null @@ -1,80 +0,0 @@ -// -// AbsorbedCarbValue.swift -// LoopKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - - -/// A quantity of carbs absorbed over a given date interval -public struct AbsorbedCarbValue: SampleValue { - /// The quantity of carbs absorbed - public let observed: HKQuantity - /// The quantity of carbs absorbed, clamped to the original prediction - public let clamped: HKQuantity - /// The quantity of carbs entered as eaten - public let total: HKQuantity - /// The quantity of carbs expected to still absorb - public let remaining: HKQuantity - /// The dates over which absorption was observed - public let observedDate: DateInterval - - /// The predicted time for the remaining carbs to absorb - public let estimatedTimeRemaining: TimeInterval - - // Total predicted absorption time for this carb entry - public var estimatedDate: DateInterval { - return DateInterval(start: observedDate.start, duration: observedDate.duration + estimatedTimeRemaining) - } - - /// The amount of time required to absorb observed carbs - public let timeToAbsorbObservedCarbs: TimeInterval - - /// Whether absorption is still in-progress - public var isActive: Bool { - return estimatedTimeRemaining > 0 - } - - public var observedProgress: HKQuantity { - let gram = HKUnit.gram() - let totalGrams = total.doubleValue(for: gram) - let percent = HKUnit.percent() - - guard totalGrams > 0 else { - return HKQuantity(unit: percent, doubleValue: 0) - } - - return HKQuantity( - unit: percent, - doubleValue: observed.doubleValue(for: gram) / totalGrams - ) - } - - public var clampedProgress: HKQuantity { - let gram = HKUnit.gram() - let totalGrams = total.doubleValue(for: gram) - let percent = HKUnit.percent() - - guard totalGrams > 0 else { - return HKQuantity(unit: percent, doubleValue: 0) - } - - return HKQuantity( - unit: percent, - doubleValue: clamped.doubleValue(for: gram) / totalGrams - ) - } - - // MARK: SampleValue - - public var quantity: HKQuantity { - return clamped - } - - public var startDate: Date { - return estimatedDate.start - } -} diff --git a/Dependencies/LoopKit/LoopKit/CarbKit/CachedCarbObject+CoreDataClass.swift b/Dependencies/LoopKit/LoopKit/CarbKit/CachedCarbObject+CoreDataClass.swift deleted file mode 100644 index c7372d914..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbKit/CachedCarbObject+CoreDataClass.swift +++ /dev/null @@ -1,259 +0,0 @@ -// -// CachedCarbObject+CoreDataClass.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// -// - -import Foundation -import CoreData -import HealthKit - -class CachedCarbObject: NSManagedObject { - var absorptionTime: TimeInterval? { - get { - willAccessValue(forKey: "absorptionTime") - defer { didAccessValue(forKey: "absorptionTime") } - return primitiveAbsorptionTime?.doubleValue - } - set { - willChangeValue(forKey: "absorptionTime") - defer { didChangeValue(forKey: "absorptionTime") } - primitiveAbsorptionTime = newValue != nil ? NSNumber(value: newValue!) : nil - } - } - - var syncVersion: Int? { - get { - willAccessValue(forKey: "syncVersion") - defer { didAccessValue(forKey: "syncVersion") } - return primitiveSyncVersion?.intValue - } - set { - willChangeValue(forKey: "syncVersion") - defer { didChangeValue(forKey: "syncVersion") } - primitiveSyncVersion = newValue != nil ? NSNumber(value: newValue!) : nil - } - } - - var operation: Operation { - get { - willAccessValue(forKey: "operation") - defer { didAccessValue(forKey: "operation") } - return Operation(rawValue: primitiveOperation.intValue)! - } - set { - willChangeValue(forKey: "operation") - defer { didChangeValue(forKey: "operation") } - primitiveOperation = NSNumber(value: newValue.rawValue) - } - } - - override func awakeFromInsert() { - super.awakeFromInsert() - setPrimitiveValue(managedObjectContext!.anchorKey!, forKey: "anchorKey") - } -} - -// MARK: - Helpers - -extension CachedCarbObject { - var quantity: HKQuantity { HKQuantity(unit: .gram(), doubleValue: grams) } -} - -// MARK: - Operations - -extension CachedCarbObject { - - // Loop - func create(from entry: NewCarbEntry, provenanceIdentifier: String, syncIdentifier: String, syncVersion: Int = 1, on date: Date = Date()) { - self.absorptionTime = entry.absorptionTime - self.createdByCurrentApp = true - self.foodType = entry.foodType - self.grams = entry.quantity.doubleValue(for: .gram()) - self.startDate = entry.startDate - self.uuid = nil - - self.provenanceIdentifier = provenanceIdentifier - self.syncIdentifier = syncIdentifier - self.syncVersion = syncVersion - - self.userCreatedDate = entry.date - self.userUpdatedDate = nil - self.userDeletedDate = nil - - self.operation = .create - self.addedDate = date - self.supercededDate = nil - } - - // HealthKit - func create(from sample: HKQuantitySample, on date: Date = Date()) { - self.absorptionTime = sample.absorptionTime - self.createdByCurrentApp = sample.createdByCurrentApp - self.foodType = sample.foodType - self.grams = sample.quantity.doubleValue(for: .gram()) - self.startDate = sample.startDate - self.uuid = sample.uuid - - self.provenanceIdentifier = sample.provenanceIdentifier - self.syncIdentifier = sample.syncIdentifier - self.syncVersion = sample.syncVersion - - self.userCreatedDate = sample.userCreatedDate - self.userUpdatedDate = nil - self.userDeletedDate = nil - - self.operation = .create - self.addedDate = date - self.supercededDate = nil - } - - // Loop - func update(from entry: NewCarbEntry, replacing object: CachedCarbObject, on date: Date = Date()) { - precondition(object.createdByCurrentApp) - precondition(object.syncIdentifier != nil) - precondition(object.syncVersion != nil) - - self.absorptionTime = entry.absorptionTime - self.createdByCurrentApp = object.createdByCurrentApp - self.foodType = entry.foodType - self.grams = entry.quantity.doubleValue(for: .gram()) - self.startDate = entry.startDate - self.uuid = nil - - self.provenanceIdentifier = object.provenanceIdentifier - self.syncIdentifier = object.syncIdentifier - self.syncVersion = object.syncVersion.map { $0 + 1 } - - self.userCreatedDate = object.userCreatedDate - self.userUpdatedDate = entry.date - self.userDeletedDate = nil - - self.operation = .update - self.addedDate = date - self.supercededDate = nil - } - - // HealthKit - func update(from sample: HKQuantitySample, replacing object: CachedCarbObject, on date: Date = Date()) { -// precondition(!object.createdByCurrentApp) -// precondition(sample.createdByCurrentApp == object.createdByCurrentApp) -// precondition(sample.provenanceIdentifier == object.provenanceIdentifier) -// precondition(object.syncIdentifier != nil) -// precondition(sample.syncIdentifier == object.syncIdentifier) - - self.absorptionTime = sample.absorptionTime - self.createdByCurrentApp = sample.createdByCurrentApp - self.foodType = sample.foodType - self.grams = sample.quantity.doubleValue(for: .gram()) - self.startDate = sample.startDate - self.uuid = sample.uuid - - self.provenanceIdentifier = sample.provenanceIdentifier - self.syncIdentifier = sample.syncIdentifier - self.syncVersion = sample.syncVersion - - self.userCreatedDate = object.userCreatedDate - self.userUpdatedDate = sample.userUpdatedDate - self.userDeletedDate = nil - - self.operation = .update - self.addedDate = date - self.supercededDate = nil - } - - // Either - func delete(from object: CachedCarbObject, on date: Date = Date()) { - self.absorptionTime = object.absorptionTime - self.createdByCurrentApp = object.createdByCurrentApp - self.foodType = object.foodType - self.grams = object.grams - self.startDate = object.startDate - self.uuid = object.uuid - - self.provenanceIdentifier = object.provenanceIdentifier - self.syncIdentifier = object.syncIdentifier - self.syncVersion = object.syncVersion - - self.userCreatedDate = object.userCreatedDate - self.userUpdatedDate = object.userUpdatedDate - self.userDeletedDate = object.createdByCurrentApp ? date : nil // Cannot know actual user deleted data from other app - - self.operation = .delete - self.addedDate = date - self.supercededDate = nil - } -} - -// MARK: - Watch Synchronization - -extension CachedCarbObject { - func update(from object: SyncCarbObject) { - self.absorptionTime = object.absorptionTime - self.createdByCurrentApp = object.createdByCurrentApp - self.foodType = object.foodType - self.grams = object.grams - self.startDate = object.startDate - self.uuid = object.uuid - - self.provenanceIdentifier = object.provenanceIdentifier - self.syncIdentifier = object.syncIdentifier - self.syncVersion = object.syncVersion - - self.userCreatedDate = object.userCreatedDate - self.userUpdatedDate = object.userUpdatedDate - self.userDeletedDate = object.userDeletedDate - - self.operation = object.operation - self.addedDate = object.addedDate - self.supercededDate = object.supercededDate - } -} - -// MARK: - HealthKit Synchronization - -extension CachedCarbObject { - var quantitySample: HKQuantitySample { - var metadata = [String: Any]() - - metadata[HKMetadataKeyFoodType] = foodType - metadata[MetadataKeyAbsorptionTime] = absorptionTime - - metadata[HKMetadataKeySyncIdentifier] = syncIdentifier - metadata[HKMetadataKeySyncVersion] = syncVersion - - metadata[MetadataKeyUserCreatedDate] = userCreatedDate - metadata[MetadataKeyUserUpdatedDate] = userUpdatedDate - - return HKQuantitySample( - type: HKObjectType.quantityType(forIdentifier: .dietaryCarbohydrates)!, - quantity: quantity, - start: startDate, - end: startDate, - metadata: metadata - ) - } -} - -// MARK: - DEPRECATED - Used only for migration - -extension CachedCarbObject { - func create(from entry: StoredCarbEntry) { - self.absorptionTime = entry.absorptionTime - self.createdByCurrentApp = entry.createdByCurrentApp - self.foodType = entry.foodType - self.grams = entry.quantity.doubleValue(for: .gram()) - self.startDate = entry.startDate - self.uuid = entry.uuid - - self.provenanceIdentifier = entry.provenanceIdentifier - self.syncIdentifier = entry.syncIdentifier - self.syncVersion = entry.syncVersion - - self.operation = .create - self.addedDate = nil - self.supercededDate = nil - } -} diff --git a/Dependencies/LoopKit/LoopKit/CarbKit/CachedCarbObject+CoreDataProperties.swift b/Dependencies/LoopKit/LoopKit/CarbKit/CachedCarbObject+CoreDataProperties.swift deleted file mode 100644 index 64a50c5ea..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbKit/CachedCarbObject+CoreDataProperties.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// CachedCarbObject+CoreDataProperties.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// -// - -import Foundation -import CoreData - - -extension CachedCarbObject { - - @nonobjc public class func fetchRequest() -> NSFetchRequest { - return NSFetchRequest(entityName: "CachedCarbObject") - } - - @NSManaged public var primitiveAbsorptionTime: NSNumber? - @NSManaged public var createdByCurrentApp: Bool - @NSManaged public var foodType: String? - @NSManaged public var grams: Double - @NSManaged public var startDate: Date - @NSManaged public var uuid: UUID? - @NSManaged public var provenanceIdentifier: String - @NSManaged public var syncIdentifier: String? - @NSManaged public var primitiveSyncVersion: NSNumber? - @NSManaged public var userCreatedDate: Date? - @NSManaged public var userUpdatedDate: Date? - @NSManaged public var userDeletedDate: Date? - @NSManaged public var primitiveOperation: NSNumber - @NSManaged public var addedDate: Date? - @NSManaged public var supercededDate: Date? - @NSManaged public var anchorKey: Int64 - -} - -extension CachedCarbObject: Encodable { - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encodeIfPresent(absorptionTime, forKey: .absorptionTime) - try container.encode(createdByCurrentApp, forKey: .createdByCurrentApp) - try container.encodeIfPresent(foodType, forKey: .foodType) - try container.encode(grams, forKey: .grams) - try container.encode(startDate, forKey: .startDate) - try container.encodeIfPresent(uuid, forKey: .uuid) - try container.encode(provenanceIdentifier, forKey: .provenanceIdentifier) - try container.encodeIfPresent(syncIdentifier, forKey: .syncIdentifier) - try container.encodeIfPresent(syncVersion, forKey: .syncVersion) - try container.encodeIfPresent(userCreatedDate, forKey: .userCreatedDate) - try container.encodeIfPresent(userUpdatedDate, forKey: .userUpdatedDate) - try container.encodeIfPresent(userDeletedDate, forKey: .userDeletedDate) - try container.encodeIfPresent(operation, forKey: .operation) - try container.encodeIfPresent(addedDate, forKey: .addedDate) - try container.encodeIfPresent(supercededDate, forKey: .supercededDate) - try container.encode(anchorKey, forKey: .anchorKey) - } - - private enum CodingKeys: String, CodingKey { - case absorptionTime - case createdByCurrentApp - case foodType - case grams - case startDate - case uuid - case provenanceIdentifier - case syncIdentifier - case syncVersion - case userCreatedDate - case userUpdatedDate - case userDeletedDate - case operation - case addedDate - case supercededDate - case anchorKey - } -} diff --git a/Dependencies/LoopKit/LoopKit/CarbKit/CarbEntry.swift b/Dependencies/LoopKit/LoopKit/CarbKit/CarbEntry.swift deleted file mode 100644 index d96a8d3a2..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbKit/CarbEntry.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// CarbEntry.swift -// CarbKit -// -// Created by Nathan Racklyeft on 1/3/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public protocol CarbEntry: SampleValue { - var absorptionTime: TimeInterval? { get } -} diff --git a/Dependencies/LoopKit/LoopKit/CarbKit/CarbMath.swift b/Dependencies/LoopKit/LoopKit/CarbKit/CarbMath.swift deleted file mode 100644 index 8d941b2f7..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbKit/CarbMath.swift +++ /dev/null @@ -1,902 +0,0 @@ -// -// CarbMath.swift -// CarbKit -// -// Created by Nathan Racklyeft on 1/16/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -struct CarbModelSettings { - var absorptionModel: CarbAbsorptionComputable - var initialAbsorptionTimeOverrun: Double - var adaptiveAbsorptionRateEnabled: Bool - var adaptiveRateStandbyIntervalFraction: Double - - init(absorptionModel: CarbAbsorptionComputable, initialAbsorptionTimeOverrun: Double, adaptiveAbsorptionRateEnabled: Bool, adaptiveRateStandbyIntervalFraction: Double = 0.2) { - self.absorptionModel = absorptionModel - self.initialAbsorptionTimeOverrun = initialAbsorptionTimeOverrun - self.adaptiveAbsorptionRateEnabled = adaptiveAbsorptionRateEnabled - self.adaptiveRateStandbyIntervalFraction = adaptiveRateStandbyIntervalFraction - } -} - -protocol CarbAbsorptionComputable { - /// Returns the percentage of total carbohydrates absorbed as blood glucose at a specified interval after eating. - /// - /// - Parameters: - /// - percentTime: The percentage of the total absorption time - /// - Returns: The percentage of the total carbohydrates that have been absorbed as blood glucose - func percentAbsorptionAtPercentTime(_ percentTime: Double) -> Double - - /// Returns the percent of total absorption time for a percentage of total carbohydrates absorbed - /// - /// The is the inverse of perecentAbsorptionAtPercentTime( :percentTime: ) - /// - /// - Parameters: - /// - percentAbsorption: The percentage of the total carbohydrates that have been absorbed as blood glucose - /// - Returns: The percentage of the absorption time needed to absorb the percentage of the total carbohydrates - func percentTimeAtPercentAbsorption(_ percentAbsorption: Double) -> Double - - /// Returns the total absorption time for a percentage of total carbohydrates absorbed as blood glucose at a specified interval after eating. - /// - /// - Parameters: - /// - percentAbsorption: The percentage of the total carbohydrates that have been absorbed as blood glucose - /// - time: The interval after the carbohydrates were eaten - /// - Returns: The total time of carbohydrates absorption - func absorptionTime(forPercentAbsorption percentAbsorption: Double, atTime time: TimeInterval) -> TimeInterval - - /// Returns the number of total carbohydrates absorbed as blood glucose at a specified interval after eating - /// - /// - Parameters: - /// - total: The total number of carbohydrates eaten - /// - time: The interval after carbohydrates were eaten - /// - absorptionTime: The total time of carbohydrates absorption - /// - Returns: The number of total carbohydrates that have been absorbed as blood glucose - func absorbedCarbs(of total: Double, atTime time: TimeInterval, absorptionTime: TimeInterval) -> Double - - /// Returns the number of total carbohydrates not yet absorbed as blood glucose at a specified interval after eating - /// - /// - Parameters: - /// - total: The total number of carbs eaten - /// - time: The interval after carbohydrates were eaten - /// - absorptionTime: The total time of carb absorption - /// - Returns: The number of total carbohydrates that have not yet been absorbed as blood glucose - func unabsorbedCarbs(of total: Double, atTime time: TimeInterval, absorptionTime: TimeInterval) -> Double - - /// Returns the normalized rate of carbohydrates absorption at a specified percentage of the absorption time - /// - /// - Parameters: - /// - percentTime: The percentage of absorption time elapsed since the carbohydrates were eaten - /// - Returns: The percentage absorption rate at the percentage of absorption time - func percentRateAtPercentTime(_ percentTime: Double) -> Double -} - - -extension CarbAbsorptionComputable { - func absorbedCarbs(of total: Double, atTime time: TimeInterval, absorptionTime: TimeInterval) -> Double { - let percentTime = time / absorptionTime - return total * percentAbsorptionAtPercentTime(percentTime) - } - - func unabsorbedCarbs(of total: Double, atTime time: TimeInterval, absorptionTime: TimeInterval) -> Double { - let percentTime = time / absorptionTime - return total * (1.0 - percentAbsorptionAtPercentTime(percentTime)) - } - - func absorptionTime(forPercentAbsorption percentAbsorption: Double, atTime time: TimeInterval) -> TimeInterval { - let percentTime = max(percentTimeAtPercentAbsorption(percentAbsorption), .ulpOfOne) - return time / percentTime - } - - func timeToAbsorb(forPercentAbsorbed percentAbsorption: Double, totalAbsorptionTime: TimeInterval) -> TimeInterval { - let percentTime = percentTimeAtPercentAbsorption(percentAbsorption) - return percentTime * totalAbsorptionTime - } - -} - - -// MARK: - Parabolic absorption as described by Scheiner -// This is the integral approximation of the Scheiner GI curve found in Think Like a Pancreas, Fig 7-8, which first appeared in [GlucoDyn](https://github.com/kenstack/GlucoDyn) -struct ParabolicAbsorption: CarbAbsorptionComputable { - func percentAbsorptionAtPercentTime(_ percentTime: Double) -> Double { - switch percentTime { - case let t where t <= 0.0: - return 0.0 - case let t where t <= 0.5: - return 2.0 * pow(t, 2) - case let t where t < 1.0: - return -1.0 + 2.0 * t * (2.0 - t) - default: - return 1.0 - } - } - - func percentTimeAtPercentAbsorption(_ percentAbsorption: Double) -> Double { - switch percentAbsorption { - case let a where a <= 0: - return 0.0 - case let a where a <= 0.5: - return sqrt(0.5 * a) - case let a where a < 1.0: - return 1.0 - sqrt(0.5 * (1.0 - a)) - default: - return 1.0 - } - } - - func percentRateAtPercentTime(_ percentTime: Double) -> Double { - switch percentTime { - case let t where t > 0 && t <= 0.5: - return 4.0 * t - case let t where t > 0.5 && t < 1.0: - return 4.0 - 4.0 * t - default: - return 0.0 - } - } -} - - -// MARK: - Linear absorption as a factor of reported duration -struct LinearAbsorption: CarbAbsorptionComputable { - func percentAbsorptionAtPercentTime(_ percentTime: Double) -> Double { - switch percentTime { - case let t where t <= 0.0: - return 0.0 - case let t where t < 1.0: - return t - default: - return 1.0 - } - } - - func percentTimeAtPercentAbsorption(_ percentAbsorption: Double) -> Double { - switch percentAbsorption { - case let a where a <= 0.0: - return 0.0 - case let a where a < 1.0: - return a - default: - return 1.0 - } - } - - func percentRateAtPercentTime(_ percentTime: Double) -> Double { - switch percentTime { - case let t where t > 0.0 && t <= 1.0: - return 1.0 - default: - return 0.0 - } - } -} - -// MARK: - Piecewise linear absorption as a factor of reported duration -/// Nonlinear carb absorption model where absorption rate increases linearly from zero to a maximum value at a fraction of absorption time equal to percentEndOfRise, then remains constant until a fraction of absorption time equal to percentStartOfFall, and then decreases linearly to zero at the end of absorption time -/// - Parameters: -/// - percentEndOfRise: the percentage of absorption time when absorption rate reaches maximum, must be strictly between 0 and 1 -/// - percentStartOfFall: the percentage of absorption time when absorption rate starts to decay, must be stritctly between 0 and 1 and greater than percentEndOfRise -struct PiecewiseLinearAbsorption: CarbAbsorptionComputable { - - let percentEndOfRise = 0.15 - let percentStartOfFall = 0.5 - var scale: Double { - return 2.0 / (1.0 + percentStartOfFall - percentEndOfRise) - } - - func percentAbsorptionAtPercentTime(_ percentTime: Double) -> Double { - switch percentTime { - case let t where t <= 0.0: - return 0.0 - case let t where t < percentEndOfRise: - return 0.5 * scale * pow(t, 2.0) / percentEndOfRise - case let t where t >= percentEndOfRise && t < percentStartOfFall: - return scale * (t - 0.5 * percentEndOfRise) - case let t where t >= percentStartOfFall && t < 1.0: - return scale * (percentStartOfFall - 0.5 * percentEndOfRise + - (t - percentStartOfFall) * (1.0 - 0.5 * (t - percentStartOfFall) / (1.0 - percentStartOfFall))) - default: - return 1.0 - } - } - - func percentTimeAtPercentAbsorption(_ percentAbsorption: Double) -> Double { - switch percentAbsorption { - case let a where a <= 0: - return 0.0 - case let a where a > 0.0 && a < 0.5 * scale * percentEndOfRise: - return sqrt(2.0 * percentEndOfRise * a / scale) - case let a where a >= 0.5 * scale * percentEndOfRise && a < scale * (percentStartOfFall - 0.5 * percentEndOfRise): - return 0.5 * percentEndOfRise + a / scale - case let a where a >= scale * (percentStartOfFall - 0.5 * percentEndOfRise) && a < 1.0: - return 1.0 - sqrt((1.0 - percentStartOfFall) * - (1.0 + percentStartOfFall - percentEndOfRise) * (1.0 - a)) - default: - return 1.0 - } - } - - func percentRateAtPercentTime(_ percentTime: Double) -> Double { - switch percentTime { - case let t where t > 0 && t < percentEndOfRise: - return scale * t / percentEndOfRise - case let t where t >= percentEndOfRise && t < percentStartOfFall: - return scale - case let t where t >= percentStartOfFall && t < 1.0: - return scale * ((1.0 - t) / (1.0 - percentStartOfFall)) - default: - return 0.0 - } - } -} - -extension CarbEntry { - - func carbsOnBoard(at date: Date, defaultAbsorptionTime: TimeInterval, delay: TimeInterval, absorptionModel: CarbAbsorptionComputable) -> Double { - let time = date.timeIntervalSince(startDate) - let value: Double - - if time >= 0 { - value = absorptionModel.unabsorbedCarbs(of: quantity.doubleValue(for: HKUnit.gram()), atTime: time - delay, absorptionTime: absorptionTime ?? defaultAbsorptionTime) - } else { - value = 0 - } - - return value - } - - // g - func absorbedCarbs( - at date: Date, - absorptionTime: TimeInterval, - delay: TimeInterval, - absorptionModel: CarbAbsorptionComputable - ) -> Double { - let time = date.timeIntervalSince(startDate) - - return absorptionModel.absorbedCarbs( - of: quantity.doubleValue(for: .gram()), - atTime: time - delay, - absorptionTime: absorptionTime - ) - } - - // mg/dL / g * g - fileprivate func glucoseEffect( - at date: Date, - carbRatio: HKQuantity, - insulinSensitivity: HKQuantity, - defaultAbsorptionTime: TimeInterval, - delay: TimeInterval, - absorptionModel: CarbAbsorptionComputable - ) -> Double { - return insulinSensitivity.doubleValue(for: HKUnit.milligramsPerDeciliter) / carbRatio.doubleValue(for: .gram()) * absorbedCarbs(at: date, absorptionTime: absorptionTime ?? defaultAbsorptionTime, delay: delay, absorptionModel: absorptionModel) - } - - fileprivate func estimatedAbsorptionTime(forAbsorbedCarbs carbs: Double, at date: Date, absorptionModel: CarbAbsorptionComputable) -> TimeInterval { - let time = date.timeIntervalSince(startDate) - - return max(time, absorptionModel.absorptionTime(forPercentAbsorption: carbs / quantity.doubleValue(for: .gram()), atTime: time)) - } -} - -extension Collection where Element: CarbEntry { - fileprivate func simulationDateRange( - from start: Date? = nil, - to end: Date? = nil, - defaultAbsorptionTime: TimeInterval, - delay: TimeInterval, - delta: TimeInterval - ) -> (start: Date, end: Date)? { - guard count > 0 else { - return nil - } - - if let start = start, let end = end { - return (start: start.dateFlooredToTimeInterval(delta), end: end.dateCeiledToTimeInterval(delta)) - } else { - var minDate = first!.startDate - var maxDate = minDate - - for sample in self { - if sample.startDate < minDate { - minDate = sample.startDate - } - - let endDate = sample.endDate.addingTimeInterval(sample.absorptionTime ?? defaultAbsorptionTime).addingTimeInterval(delay) - if endDate > maxDate { - maxDate = endDate - } - } - - return ( - start: (start ?? minDate).dateFlooredToTimeInterval(delta), - end: (end ?? maxDate).dateCeiledToTimeInterval(delta) - ) - } - } - - /// Creates groups of entries that have overlapping absorption date intervals - /// - /// - Parameters: - /// - defaultAbsorptionTime: The default absorption time value, if not set on the entry - /// - Returns: An array of arrays representing groups of entries, in chronological order by entry startDate - func groupedByOverlappingAbsorptionTimes( - defaultAbsorptionTime: TimeInterval - ) -> [[Iterator.Element]] { - var batches: [[Iterator.Element]] = [] - - for entry in sorted(by: { $0.startDate < $1.startDate }) { - if let lastEntry = batches.last?.last, - lastEntry.startDate.addingTimeInterval(lastEntry.absorptionTime ?? defaultAbsorptionTime) > entry.startDate - { - batches[batches.count - 1].append(entry) - } else { - batches.append([entry]) - } - } - - return batches - } - - func carbsOnBoard( - from start: Date? = nil, - to end: Date? = nil, - defaultAbsorptionTime: TimeInterval, - absorptionModel: CarbAbsorptionComputable, - delay: TimeInterval = TimeInterval(minutes: 10), - delta: TimeInterval = TimeInterval(minutes: 5) - ) -> [CarbValue] { - guard let (startDate, endDate) = simulationDateRange(from: start, to: end, defaultAbsorptionTime: defaultAbsorptionTime, delay: delay, delta: delta) else { - return [] - } - - var date = startDate - var values = [CarbValue]() - - repeat { - let value = reduce(0.0) { (value, entry) -> Double in - return value + entry.carbsOnBoard(at: date, defaultAbsorptionTime: defaultAbsorptionTime, delay: delay, absorptionModel: absorptionModel) - } - - values.append(CarbValue(startDate: date, quantity: HKQuantity(unit: HKUnit.gram(), doubleValue: value))) - date = date.addingTimeInterval(delta) - } while date <= endDate - - return values - } - - func glucoseEffects( - from start: Date? = nil, - to end: Date? = nil, - carbRatios: CarbRatioSchedule, - insulinSensitivities: InsulinSensitivitySchedule, - defaultAbsorptionTime: TimeInterval, - absorptionModel: CarbAbsorptionComputable, - delay: TimeInterval = TimeInterval(minutes: 10), - delta: TimeInterval = TimeInterval(minutes: 5) - ) -> [GlucoseEffect] { - guard let (startDate, endDate) = simulationDateRange(from: start, to: end, defaultAbsorptionTime: defaultAbsorptionTime, delay: delay, delta: delta) else { - return [] - } - - var date = startDate - var values = [GlucoseEffect]() - let unit = HKUnit.milligramsPerDeciliter - - repeat { - let value = reduce(0.0) { (value, entry) -> Double in - return value + entry.glucoseEffect( - at: date, - carbRatio: carbRatios.quantity(at: entry.startDate), - insulinSensitivity: insulinSensitivities.quantity(at: entry.startDate), - defaultAbsorptionTime: defaultAbsorptionTime, - delay: delay, - absorptionModel: absorptionModel - ) - } - - values.append(GlucoseEffect(startDate: date, quantity: HKQuantity(unit: unit, doubleValue: value))) - date = date.addingTimeInterval(delta) - } while date <= endDate - - return values - } - - var totalCarbs: CarbValue? { - guard count > 0 else { - return nil - } - - let unit = HKUnit.gram() - var startDate = Date.distantFuture - var totalGrams: Double = 0 - - for entry in self { - totalGrams += entry.quantity.doubleValue(for: unit) - - if entry.startDate < startDate { - startDate = entry.startDate - } - } - - return CarbValue(startDate: startDate, quantity: HKQuantity(unit: unit, doubleValue: totalGrams)) - } -} - - -// MARK: - Dyanamic absorption overrides -extension Collection { - func dynamicCarbsOnBoard( - from start: Date? = nil, - to end: Date? = nil, - defaultAbsorptionTime: TimeInterval, - absorptionModel: CarbAbsorptionComputable, - delay: TimeInterval = TimeInterval(minutes: 10), - delta: TimeInterval = TimeInterval(minutes: 5) - ) -> [CarbValue] where Element == CarbStatus { - guard let (startDate, endDate) = simulationDateRange(from: start, to: end, defaultAbsorptionTime: defaultAbsorptionTime, delay: delay, delta: delta) else { - return [] - } - - var date = startDate - var values = [CarbValue]() - - repeat { - let value = reduce(0.0) { (value, entry) -> Double in - return value + entry.dynamicCarbsOnBoard( - at: date, - defaultAbsorptionTime: defaultAbsorptionTime, - delay: delay, - delta: delta, - absorptionModel: absorptionModel - ) - } - - values.append(CarbValue(startDate: date, quantity: HKQuantity(unit: HKUnit.gram(), doubleValue: value))) - date = date.addingTimeInterval(delta) - } while date <= endDate - - return values - } - - func dynamicGlucoseEffects( - from start: Date? = nil, - to end: Date? = nil, - carbRatios: CarbRatioSchedule, - insulinSensitivities: InsulinSensitivitySchedule, - defaultAbsorptionTime: TimeInterval, - absorptionModel: CarbAbsorptionComputable, - delay: TimeInterval = TimeInterval(minutes: 10), - delta: TimeInterval = TimeInterval(minutes: 5) - ) -> [GlucoseEffect] where Element == CarbStatus { - guard let (startDate, endDate) = simulationDateRange(from: start, to: end, defaultAbsorptionTime: defaultAbsorptionTime, delay: delay, delta: delta) else { - return [] - } - - var date = startDate - var values = [GlucoseEffect]() - let mgdL = HKUnit.milligramsPerDeciliter - let gram = HKUnit.gram() - - repeat { - let value = reduce(0.0) { (value, entry) -> Double in - let csf = insulinSensitivities.quantity(at: entry.startDate).doubleValue(for: mgdL) / carbRatios.quantity(at: entry.startDate).doubleValue(for: gram) - - return value + csf * entry.dynamicAbsorbedCarbs( - at: date, - absorptionTime: entry.absorptionTime ?? defaultAbsorptionTime, - delay: delay, - delta: delta, - absorptionModel: absorptionModel - ) - } - - values.append(GlucoseEffect(startDate: date, quantity: HKQuantity(unit: mgdL, doubleValue: value))) - date = date.addingTimeInterval(delta) - } while date <= endDate - - return values - } - - /// The quantity of carbs expected to still absorb at the last date of absorption - public func getClampedCarbsOnBoard() -> CarbValue? where Element == CarbStatus { - guard let firstAbsorption = first?.absorption else { - return nil - } - - let gram = HKUnit.gram() - var maxObservedEndDate = firstAbsorption.observedDate.end - var remainingTotalGrams: Double = 0 - - for entry in self { - guard let absorption = entry.absorption else { - continue - } - - maxObservedEndDate = Swift.max(maxObservedEndDate, absorption.observedDate.end) - remainingTotalGrams += absorption.remaining.doubleValue(for: gram) - } - - return CarbValue(startDate: maxObservedEndDate, quantity: HKQuantity(unit: gram, doubleValue: remainingTotalGrams)) - } -} - - -/// Aggregates and computes data about the absorption of a CarbEntry to create a CarbStatus value. -/// -/// There are three key components managed by this builder: -/// - The entry data as reported by the user -/// - The observed data as calculated from glucose changes relative to insulin curves -/// - The minimum/maximum amounts of absorption used to clamp our observation data within reasonable bounds -fileprivate class CarbStatusBuilder { - - // MARK: Model settings - - private var absorptionModel: CarbAbsorptionComputable - - private var adaptiveAbsorptionRateEnabled: Bool - - private var adaptiveRateStandbyIntervalFraction: Double - - private var adaptiveRateStandbyInterval: TimeInterval { - return initialAbsorptionTime * adaptiveRateStandbyIntervalFraction - } - - // MARK: User-entered data - - /// The carb entry input - let entry: T - - /// The unit used for carb values - let carbUnit: HKUnit - - /// The total grams entered for this entry - let entryGrams: Double - - /// The total glucose effect expected for this entry, in glucose units - let entryEffect: Double - - /// The carbohydrate-sensitivity factor for this entry, in glucose units per gram - let carbohydrateSensitivityFactor: Double - - /// The absorption time for this entry before any absorption is observed - let initialAbsorptionTime: TimeInterval - - // MARK: Minimum/maximum bounding factors - - /// The maximum absorption time allowed for this entry, determining the minimum absorption rate - let maxAbsorptionTime: TimeInterval - - /// An amount of time to wait after the entry date before minimum absorption is assumed to begin - let delay: TimeInterval - - /// The maximum end date allowed for this entry's absorption - let maxEndDate: Date - - /// The last date we have effects observed, or "now" in real-time analysis. - private let lastEffectDate: Date - - /// The minimum-required carb absorption rate for this entry, in g/s - var minAbsorptionRate: Double { - return entryGrams / maxAbsorptionTime - } - - /// The minimum amount of carbs we assume must have absorbed at the last observation date - private var minPredictedGrams: Double { - // We incorporate a delay when calculating minimum absorption values - let time = lastEffectDate.timeIntervalSince(entry.startDate) - delay - return absorptionModel.absorbedCarbs(of: entryGrams, atTime: time, absorptionTime: maxAbsorptionTime) - } - - // MARK: Incremental observation - - /// The date at which we observe all the carbs were absorbed. or nil if carb absorption has not finished - private var observedCompletionDate: Date? - - /// The total observed effect for each entry, in glucose units - private(set) var observedEffect: Double = 0 - - /// The timeline of absorption amounts credited to this carb entry, in grams, for computation of historical COB and effect history - private(set) var observedTimeline: [CarbValue] = [] - - /// The amount of carbs we've observed absorbing - private var observedGrams: Double { - return observedEffect / carbohydrateSensitivityFactor - } - - /// The amount of effect remaining until 100% of entry absorption is observed - var remainingEffect: Double { - return max(entryEffect - observedEffect, 0) - } - - /// The dates over which we observed absorption, from start until 100% or last observed effect. - private var observedAbsorptionDates: DateInterval { - return DateInterval(start: entry.startDate, end: observedCompletionDate ?? lastEffectDate) - } - - - // MARK: Clamped results - - /// The number of carbs absorbed, suitable for use in calculations. - /// This is bounded by minimumPredictedGrams and the entry total. - private var clampedGrams: Double { - let minPredictedGrams = self.minPredictedGrams - - return min(entryGrams, max(minPredictedGrams, observedGrams)) - } - - private var percentAbsorbed: Double { - return clampedGrams / entryGrams - } - - /// The amount of time needed to absorb observed grams - private var timeToAbsorbObservedCarbs: TimeInterval { - let time = lastEffectDate.timeIntervalSince(entry.startDate) - delay - guard time > 0 else { - return 0.0 - } - var timeToAbsorb: TimeInterval - if adaptiveAbsorptionRateEnabled && time > adaptiveRateStandbyInterval { - // If adaptive absorption rate is enabled, and if the time since start of absorption is greater than the standby interval, the time to absorb observed carbs equals the obervation time - timeToAbsorb = time - } else { - // If adaptive absorption rate is disabled, or if the time since start of absorption is less than the standby interval, the time to absorb observed carbs is calculated based on the absorption model - timeToAbsorb = absorptionModel.timeToAbsorb(forPercentAbsorbed: percentAbsorbed, totalAbsorptionTime: initialAbsorptionTime) - } - return min(timeToAbsorb, maxAbsorptionTime) - } - - /// The amount of time needed for the remaining entry grams to absorb - private var estimatedTimeRemaining: TimeInterval { - let time = lastEffectDate.timeIntervalSince(entry.startDate) - delay - guard time > 0 else { - return initialAbsorptionTime - } - let notToExceedTimeRemaining = max(maxAbsorptionTime - time, 0.0) - guard notToExceedTimeRemaining > 0 else { - return 0.0 - } - var dynamicTimeRemaining: TimeInterval - if adaptiveAbsorptionRateEnabled && time > adaptiveRateStandbyInterval { - // If adaptive absorption rate is enabled, and if the time since start of absorption is greater than the standby interval, the remaining time is estimated assuming the observed relative absorption rate persists for the remaining carbs - let dynamicAbsorptionTime = absorptionModel.absorptionTime(forPercentAbsorption: percentAbsorbed, atTime: time) - dynamicTimeRemaining = dynamicAbsorptionTime - time - } else { - // If adaptive absorption rate is disabled, or if the time since start of absorption is less than the standby interval, the remaining time is estimated assuming the modeled absorption rate - dynamicTimeRemaining = initialAbsorptionTime - timeToAbsorbObservedCarbs - } - // time remaining must not extend beyond the maximum absorption time - return min(dynamicTimeRemaining, notToExceedTimeRemaining) - } - - /// The timeline of observed absorption, if greater than the minimum required absorption. - private var clampedTimeline: [CarbValue]? { - return observedGrams >= minPredictedGrams ? observedTimeline : nil - } - - /// Configures a new builder - /// - /// - Parameters: - /// - entry: The carb entry input - /// - carbUnit: The unit used for carb values - /// - carbohydrateSensitivityFactor: The carbohydrate-sensitivity factor for the entry, in glucose units per gram - /// - initialAbsorptionTime: The absorption initially assigned to this entry before any absorption is observed - /// - maxAbsorptionTime: The maximum absorption time allowed for this entry, determining the minimum absorption rate - /// - delay: An amount of time to wait after the entry date before minimum absorption is assumed to begin - /// - lastEffectDate: The last recorded date of effect observation, used to initialize absorption at model defined rate - /// - initialObservedEffect: The initial amount of observed effect, in glucose units. Defaults to 0 - /// - absorptionModel: The absorption model to use when computing remaining absorption - /// - adaptiveAbsorptionRateEnabled: Whether the remaining absorption rate changes based in observed absorption rate - /// - adaptiveRateStandbyIntervalFraction: The delay, specified as a fraction of total absorption time, before the absorption rate will change based on observed absorption rate. Only used if adaptiveAbsorptionRateEnabled is true. - init(entry: T, carbUnit: HKUnit, carbohydrateSensitivityFactor: Double, initialAbsorptionTime: TimeInterval, maxAbsorptionTime: TimeInterval, delay: TimeInterval, lastEffectDate: Date?, absorptionModel: CarbAbsorptionComputable, adaptiveAbsorptionRateEnabled: Bool, adaptiveRateStandbyIntervalFraction: Double, initialObservedEffect: Double = 0) { - self.entry = entry - self.carbUnit = carbUnit - self.carbohydrateSensitivityFactor = carbohydrateSensitivityFactor - self.initialAbsorptionTime = initialAbsorptionTime - self.maxAbsorptionTime = maxAbsorptionTime - self.delay = delay - self.observedEffect = initialObservedEffect - self.absorptionModel = absorptionModel - self.adaptiveAbsorptionRateEnabled = adaptiveAbsorptionRateEnabled - self.adaptiveRateStandbyIntervalFraction = adaptiveRateStandbyIntervalFraction - self.entryGrams = entry.quantity.doubleValue(for: carbUnit) - self.entryEffect = entryGrams * carbohydrateSensitivityFactor - self.maxEndDate = entry.startDate.addingTimeInterval(maxAbsorptionTime + delay) - self.lastEffectDate = min( - maxEndDate, - Swift.max(lastEffectDate ?? entry.startDate, entry.startDate) - ) - - } - - /// Increments the builder state with the next glucose effect. - /// - /// This function should only be called with values in ascending date order. - /// - /// - Parameters: - /// - effect: The effect value, in glucose units corresponding to `carbohydrateSensitivityFactor` - /// - start: The start date of the effect - /// - end: The end date of the effect - func addNextEffect(_ effect: Double, start: Date, end: Date) { - guard start >= entry.startDate else { - return - } - - observedEffect += effect - - if observedCompletionDate == nil { - // Continue recording the timeline until 100% of the carbs have been observed - observedTimeline.append(CarbValue( - startDate: start, - endDate: end, - quantity: HKQuantity( - unit: carbUnit, - doubleValue: effect / carbohydrateSensitivityFactor - ) - )) - - // Once 100% of the carbs are observed, track the endDate - if observedEffect + Double(Float.ulpOfOne) >= entryEffect { - observedCompletionDate = end - } - } - } - - /// The resulting CarbStatus value - var result: CarbStatus { - let absorption = AbsorbedCarbValue( - observed: HKQuantity(unit: carbUnit, doubleValue: observedGrams), - clamped: HKQuantity(unit: carbUnit, doubleValue: clampedGrams), - total: entry.quantity, - remaining: HKQuantity(unit: carbUnit, doubleValue: entryGrams - clampedGrams), - observedDate: observedAbsorptionDates, - estimatedTimeRemaining: estimatedTimeRemaining, - timeToAbsorbObservedCarbs: timeToAbsorbObservedCarbs - ) - - return CarbStatus( - entry: entry, - absorption: absorption, - observedTimeline: clampedTimeline - ) - } - - func absorptionRateAtTime(t: TimeInterval) -> Double { - let dynamicAbsorptionTime = min(observedAbsorptionDates.duration + estimatedTimeRemaining, maxAbsorptionTime) - guard dynamicAbsorptionTime > 0 else { - return 0.0 - } - // time t nomalized to absorption time - let percentTime = t / dynamicAbsorptionTime - let averageAbsorptionRate = entryGrams / dynamicAbsorptionTime - return averageAbsorptionRate * absorptionModel.percentRateAtPercentTime(percentTime) - } - -} - - -// MARK: - Sorted collections of CarbEntries -extension Collection where Element: CarbEntry { - /// Maps a sorted timeline of carb entries to the observed absorbed carbohydrates for each, from a timeline of glucose effect velocities. - /// - /// This makes some important assumptions: - /// - insulin effects, used with glucose to calculate counteraction, are "correct" - /// - carbs are absorbed completely in the order they were eaten without mixing or overlapping effects - /// - /// - Parameters: - /// - effectVelocities: A timeline of glucose effect velocities, ordered by start date - /// - carbRatio: The schedule of carb ratios, in grams per unit - /// - insulinSensitivity: The schedule of insulin sensitivities, in units of insulin per glucose-unit - /// - absorptionTimeOverrun: A multiplier for determining the minimum absorption time from the specified absorption time - /// - defaultAbsorptionTime: The absorption time to use for unspecified carb entries - /// - delay: The time to delay the dose effect - /// - Returns: A new array of `CarbStatus` values describing the absorbed carb quantities - func map( - to effectVelocities: [GlucoseEffectVelocity], - carbRatio: CarbRatioSchedule?, - insulinSensitivity: InsulinSensitivitySchedule?, - absorptionTimeOverrun: Double, - defaultAbsorptionTime: TimeInterval, - delay: TimeInterval, - initialAbsorptionTimeOverrun: Double, - absorptionModel: CarbAbsorptionComputable, - adaptiveAbsorptionRateEnabled: Bool, - adaptiveRateStandbyIntervalFraction: Double - ) -> [CarbStatus] { - guard count > 0 else { - // TODO: Apply unmatched effects to meal prediction - return [] - } - - guard let carbRatios = carbRatio, let insulinSensitivities = insulinSensitivity else { - return map { (entry) in - CarbStatus(entry: entry, absorption: nil, observedTimeline: nil) - } - } - - // for computation - let glucoseUnit = HKUnit.milligramsPerDeciliter - let carbUnit = HKUnit.gram() - - let builders: [CarbStatusBuilder] = map { (entry) in - let carbRatio = carbRatios.quantity(at: entry.startDate) - let insulinSensitivity = insulinSensitivities.quantity(at: entry.startDate) - let initialAbsorptionTimeOverrun = initialAbsorptionTimeOverrun - - return CarbStatusBuilder( - entry: entry, - carbUnit: carbUnit, - carbohydrateSensitivityFactor: insulinSensitivity.doubleValue(for: glucoseUnit) / carbRatio.doubleValue(for: carbUnit), - initialAbsorptionTime: (entry.absorptionTime ?? defaultAbsorptionTime) * initialAbsorptionTimeOverrun, - maxAbsorptionTime: (entry.absorptionTime ?? defaultAbsorptionTime) * absorptionTimeOverrun, - delay: delay, - lastEffectDate: effectVelocities.last?.endDate, - absorptionModel: absorptionModel, - adaptiveAbsorptionRateEnabled: adaptiveAbsorptionRateEnabled, - adaptiveRateStandbyIntervalFraction: adaptiveRateStandbyIntervalFraction - ) - } - - for dxEffect in effectVelocities { - guard dxEffect.endDate > dxEffect.startDate else { - assertionFailure() - continue - } - - // calculate instantanous absorption rate for all active entries - - // Apply effect to all active entries - - // Select only the entries whose dates overlap the current date interval. - // These are not necessarily contiguous as maxEndDate varies between entries - let activeBuilders = builders.filter { (builder) -> Bool in - return dxEffect.startDate < builder.maxEndDate && dxEffect.startDate >= builder.entry.startDate - } - - // Ignore velocities < 0 when estimating carb absorption. - // These are most likely the result of insulin absorption increases such as - // during activity - var effectValue = Swift.max(0, dxEffect.effect.quantity.doubleValue(for: glucoseUnit)) - - // Sum the current absorption rates of each active entry to determine how to split the active effects - var totalRate = activeBuilders.reduce(0) { (totalRate, builder) -> Double in - let effectTime = dxEffect.startDate.timeIntervalSince(builder.entry.startDate) - let absorptionRateAtEffectTime = builder.absorptionRateAtTime(t: effectTime) - return totalRate + absorptionRateAtEffectTime - } - - for builder in activeBuilders { - // Apply a portion of the effect to this entry - let effectTime = dxEffect.startDate.timeIntervalSince(builder.entry.startDate) - let absorptionRateAtEffectTime = builder.absorptionRateAtTime(t: effectTime) - // If total rate is zero, assign zero to partial effect - var partialEffectValue: Double = 0.0 - if totalRate > 0 { - partialEffectValue = Swift.min(builder.remainingEffect, (absorptionRateAtEffectTime / totalRate) * effectValue) - totalRate -= absorptionRateAtEffectTime - effectValue -= partialEffectValue - } - - builder.addNextEffect(partialEffectValue, start: dxEffect.startDate, end: dxEffect.endDate) - - // If there's still remainder effects with no additional entries to account them to, count them as overrun on the final entry - if effectValue > Double(Float.ulpOfOne) && builder === activeBuilders.last! { - builder.addNextEffect(effectValue, start: dxEffect.startDate, end: dxEffect.endDate) - } - } - - // We have remaining effect and no activeBuilders (otherwise we would have applied the effect to the last one) - if effectValue > Double(Float.ulpOfOne) { - // TODO: Track "phantom meals" - } - } - - return builders.map { $0.result } - } -} diff --git a/Dependencies/LoopKit/LoopKit/CarbKit/CarbStatus.swift b/Dependencies/LoopKit/LoopKit/CarbKit/CarbStatus.swift deleted file mode 100644 index c3acf2df1..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbKit/CarbStatus.swift +++ /dev/null @@ -1,130 +0,0 @@ -// -// CarbStatus.swift -// LoopKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - - -public struct CarbStatus { - /// Details entered by the user - public let entry: T - - /// The last-computed absorption of the carbs - public let absorption: AbsorbedCarbValue? - - /// The timeline of observed carb absorption. Nil if observed absorption is less than the modeled minimum - public let observedTimeline: [CarbValue]? -} - - -// Masquerade as a carb entry, substituting AbsorbedCarbValue's interpretation of absorption time -extension CarbStatus: SampleValue { - public var quantity: HKQuantity { - return entry.quantity - } - - public var startDate: Date { - return entry.startDate - } -} - - -extension CarbStatus: CarbEntry { - public var absorptionTime: TimeInterval? { - return absorption?.estimatedDate.duration ?? entry.absorptionTime - } -} - - -extension CarbStatus { - - func dynamicCarbsOnBoard(at date: Date, defaultAbsorptionTime: TimeInterval, delay: TimeInterval, delta: TimeInterval, absorptionModel: CarbAbsorptionComputable) -> Double { - guard date >= startDate - delta, - let absorption = absorption - else { - // We have to have absorption info for dynamic calculation - return entry.carbsOnBoard(at: date, defaultAbsorptionTime: defaultAbsorptionTime, delay: delay, absorptionModel: absorptionModel) - } - - let unit = HKUnit.gram() - - guard let observedTimeline = observedTimeline, let observationEnd = observedTimeline.last?.endDate else { - // Less than minimum observed or observation not yet started; calc based on modeled absorption rate - let total = absorption.total.doubleValue(for: unit) - let time = date.timeIntervalSince(startDate) - delay - let absorptionTime = absorption.estimatedDate.duration - return absorptionModel.unabsorbedCarbs(of: total, atTime: time, absorptionTime: absorptionTime) - } - - guard date <= observationEnd else { - // Predicted absorption for remaining carbs, post-observation - let effectiveTime = date.timeIntervalSince(observationEnd) + absorption.timeToAbsorbObservedCarbs - let effectiveAbsorptionTime = absorption.timeToAbsorbObservedCarbs + absorption.estimatedTimeRemaining - let total = absorption.total.doubleValue(for: unit) - let unabsorbedAtEffectiveTime = absorptionModel.unabsorbedCarbs(of: total, atTime: effectiveTime, absorptionTime: effectiveAbsorptionTime) - let unabsorbedCarbs = max(unabsorbedAtEffectiveTime, 0.0) - return unabsorbedCarbs - } - - // Observed absorption - // TODO: This creates an O(n^2) situation for COB timelines - let total = entry.quantity.doubleValue(for: unit) - return max(observedTimeline.filter({ $0.endDate <= date }).reduce(total) { (total, value) -> Double in - return total - value.quantity.doubleValue(for: unit) - }, 0) - } - - func dynamicAbsorbedCarbs(at date: Date, absorptionTime: TimeInterval, delay: TimeInterval, delta: TimeInterval, absorptionModel: CarbAbsorptionComputable) -> Double { - guard date >= startDate, - let absorption = absorption - else { - // We have to have absorption info for dynamic calculation - return entry.absorbedCarbs(at: date, absorptionTime: absorptionTime, delay: delay, absorptionModel: absorptionModel) - } - - let unit = HKUnit.gram() - - guard let observedTimeline = observedTimeline, let observationEnd = observedTimeline.last?.endDate else { - // Less than minimum observed or observation not yet started; calc based on modeled absorption rate - let total = absorption.total.doubleValue(for: unit) - let time = date.timeIntervalSince(startDate) - delay - let absorptionTime = absorption.estimatedDate.duration - return absorptionModel.absorbedCarbs(of: total, atTime: time, absorptionTime: absorptionTime) - } - - guard date <= observationEnd else { - // Predicted absorption for remaining carbs, post-observation - let effectiveTime = date.timeIntervalSince(observationEnd) + absorption.timeToAbsorbObservedCarbs - let effectiveAbsorptionTime = absorption.timeToAbsorbObservedCarbs + absorption.estimatedTimeRemaining - let total = absorption.total.doubleValue(for: unit) - let absorbedAtEffectiveTime = absorptionModel.absorbedCarbs(of: total, atTime: effectiveTime, absorptionTime: effectiveAbsorptionTime) - let absorbedCarbs = min(absorbedAtEffectiveTime, total) - return absorbedCarbs - } - - // Observed absorption - // TODO: This creates an O(n^2) situation for carb effect timelines - var sum: Double = 0 - var beforeDate = observedTimeline.filter { (value) -> Bool in - value.startDate.addingTimeInterval(delta) <= date - } - - // Apply only a portion of the value if it extends past the final value - if let last = beforeDate.popLast() { - let observationInterval = DateInterval(start: last.startDate, end: last.endDate) - if observationInterval.duration > 0, - let calculationInterval = DateInterval(start: last.startDate, end: date).intersection(with: observationInterval) - { - sum += calculationInterval.duration / observationInterval.duration * last.quantity.doubleValue(for: unit) - } - } - - return min(beforeDate.reduce(sum) { (sum, value) -> Double in - return sum + value.quantity.doubleValue(for: unit) - }, quantity.doubleValue(for: unit)) - } -} diff --git a/Dependencies/LoopKit/LoopKit/CarbKit/CarbStore.swift b/Dependencies/LoopKit/LoopKit/CarbKit/CarbStore.swift deleted file mode 100644 index 806ec56ab..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbKit/CarbStore.swift +++ /dev/null @@ -1,1481 +0,0 @@ -// -// CarbStore.swift -// CarbKit -// -// Created by Nathan Racklyeft on 1/3/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import CoreData -import HealthKit -import os.log - - -public enum CarbStoreResult { - case success(T) - case failure(CarbStore.CarbStoreError) -} - -public enum CarbAbsorptionModel { - case linear - case nonlinear - case adaptiveRateNonlinear -} - -public protocol CarbStoreDelegate: AnyObject { - - /** - Informs the delegate that the carb store has updated carb data. - - - Parameter carbStore: The carb store that has updated carb data. - */ - func carbStoreHasUpdatedCarbData(_ carbStore: CarbStore) - - /** - Informs the delegate that an internal error occurred. - - - parameter carbStore: The carb store - - parameter error: The error describing the issue - */ - func carbStore(_ carbStore: CarbStore, didError error: CarbStore.CarbStoreError) - -} - -/** - Manages storage, retrieval, and calculation of carbohydrate data. - - There are two tiers of storage: - - * Persistant cache, stored in Core Data, used to ensure access if the app is suspended and re-launched while the Health database - is protected and to provide data for upload to remote data services. Backfilled from HealthKit data up to observation interval. - ``` - 0 [max(cacheLength, observationInterval, defaultAbsorptionTimes.slow * 2)] - |––––––––––––| - ``` - * HealthKit data, managed by the current application and persisted indefinitely - ``` - 0 - |––––––––––––––––––---> - ``` - */ -public final class CarbStore: HealthKitSampleStore { - - /// Notification posted when carb entries were changed, either via add/replace/delete methods or from HealthKit - public static let carbEntriesDidChange = NSNotification.Name(rawValue: "com.loopkit.CarbStore.carbEntriesDidChange") - - public typealias DefaultAbsorptionTimes = (fast: TimeInterval, medium: TimeInterval, slow: TimeInterval) - - public enum CarbStoreError: Error { - // The store isn't correctly configured for the requested operation - case notConfigured - // The health store request returned an error - case healthStoreError(Error) - // The core data request returned an error - case coreDataError(Error) - // The requested sample can't be modified by this store - case unauthorized - // No data was found to match the specified request - case noData - - init?(error: PersistenceController.PersistenceControllerError?) { - guard let error = error, case .coreDataError(let coreDataError) = error else { - return nil - } - self = .coreDataError(coreDataError as Error) - } - } - - private let carbType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.dietaryCarbohydrates)! - - /// The preferred unit. iOS currently only supports grams for dietary carbohydrates. - public override var preferredUnit: HKUnit! { - return super.preferredUnit - } - - /// A history of recently applied schedule overrides. - private let overrideHistory: TemporaryScheduleOverrideHistory? - - /// Carbohydrate-to-insulin ratio - public var carbRatioSchedule: CarbRatioSchedule? { - get { - return lockedCarbRatioSchedule.value - } - set { - lockedCarbRatioSchedule.value = newValue - } - } - private let lockedCarbRatioSchedule: Locked - - /// The carb ratio schedule, applying recent overrides relative to the current moment in time. - public var carbRatioScheduleApplyingOverrideHistory: CarbRatioSchedule? { - if let carbRatioSchedule = carbRatioSchedule { - return overrideHistory?.resolvingRecentCarbRatioSchedule(carbRatioSchedule) - } else { - return nil - } - } - - /// A trio of default carbohydrate absorption times. Defaults to 2, 3, and 4 hours. - public let defaultAbsorptionTimes: DefaultAbsorptionTimes - - /// Insulin-to-glucose sensitivity - public var insulinSensitivitySchedule: InsulinSensitivitySchedule? { - get { - return lockedInsulinSensitivitySchedule.value - } - set { - lockedInsulinSensitivitySchedule.value = newValue - } - } - private let lockedInsulinSensitivitySchedule: Locked - - /// The insulin sensitivity schedule, applying recent overrides relative to the current moment in time. - public var insulinSensitivityScheduleApplyingOverrideHistory: InsulinSensitivitySchedule? { - if let insulinSensitivitySchedule = insulinSensitivitySchedule { - return overrideHistory?.resolvingRecentInsulinSensitivitySchedule(insulinSensitivitySchedule) - } else { - return nil - } - } - - /// The computed carbohydrate sensitivity schedule based on the insulin sensitivity and carb ratio schedules. - public var carbSensitivitySchedule: CarbSensitivitySchedule? { - guard let insulinSensitivitySchedule = insulinSensitivitySchedule, let carbRatioSchedule = carbRatioSchedule else { - return nil - } - return .carbSensitivitySchedule(insulinSensitivitySchedule: insulinSensitivitySchedule, carbRatioSchedule: carbRatioSchedule) - } - - /// The expected delay in the appearance of glucose effects, accounting for both digestion and sensor lag - public let delay: TimeInterval - - /// The interval between effect values to use for the calculated timelines. - public let delta: TimeInterval - - /// The factor by which the entered absorption time can be extended to accomodate slower-than-expected absorption - public let absorptionTimeOverrun: Double - - /// Carb absorption model - public let carbAbsorptionModel: CarbAbsorptionModel - - /// The interval of carb data to keep in cache - public let cacheLength: TimeInterval - - /// The interval to observe HealthKit data to populate the cache - public let observationInterval: TimeInterval - - private let storeEntriesToHealthKit: Bool - - private let cacheStore: PersistenceController - - /// The sync version used for new samples written to HealthKit - /// Choose a lower or higher sync version if the same sample might be written twice (e.g. from an extension and from an app) for deterministic conflict resolution - public let syncVersion: Int - - public weak var delegate: CarbStoreDelegate? - - private let queue = DispatchQueue(label: "com.loopkit.CarbStore.queue", qos: .utility) - - private let log = OSLog(category: "CarbStore") - - static let healthKitQueryAnchorMetadataKey = "com.loopkit.CarbStore.hkQueryAnchor" - - var settings = CarbModelSettings(absorptionModel: PiecewiseLinearAbsorption(), initialAbsorptionTimeOverrun: 1.5, adaptiveAbsorptionRateEnabled: false) - - private let provenanceIdentifier: String - - /** - Initializes a new instance of the store. - - - returns: A new instance of the store - */ - public init( - healthStore: HKHealthStore, - observeHealthKitSamplesFromOtherApps: Bool = true, - storeEntriesToHealthKit: Bool = true, - cacheStore: PersistenceController, - cacheLength: TimeInterval, - defaultAbsorptionTimes: DefaultAbsorptionTimes, - observationInterval: TimeInterval, - carbRatioSchedule: CarbRatioSchedule? = nil, - insulinSensitivitySchedule: InsulinSensitivitySchedule? = nil, - overrideHistory: TemporaryScheduleOverrideHistory? = nil, - syncVersion: Int = 1, - absorptionTimeOverrun: Double = 1.5, - calculationDelta: TimeInterval = 5 /* minutes */ * 60, - effectDelay: TimeInterval = 10 /* minutes */ * 60, - carbAbsorptionModel: CarbAbsorptionModel = .nonlinear, - provenanceIdentifier: String, - test_currentDate: Date? = nil - ) { - self.storeEntriesToHealthKit = storeEntriesToHealthKit - self.cacheStore = cacheStore - self.defaultAbsorptionTimes = defaultAbsorptionTimes - self.lockedCarbRatioSchedule = Locked(carbRatioSchedule) - self.lockedInsulinSensitivitySchedule = Locked(insulinSensitivitySchedule) - self.overrideHistory = overrideHistory - self.syncVersion = syncVersion - self.absorptionTimeOverrun = absorptionTimeOverrun - self.delta = calculationDelta - self.delay = effectDelay - self.cacheLength = cacheLength - self.observationInterval = observationInterval - self.carbAbsorptionModel = carbAbsorptionModel - self.provenanceIdentifier = provenanceIdentifier - - let observationEnabled = observationInterval > 0 - - super.init(healthStore: healthStore, - observeHealthKitSamplesFromCurrentApp: true, - observeHealthKitSamplesFromOtherApps: observeHealthKitSamplesFromOtherApps, - type: carbType, - observationStart: (test_currentDate ?? Date()).addingTimeInterval(-self.observationInterval), - observationEnabled: observationEnabled, - test_currentDate: test_currentDate) - - // Carb model settings based on the selected absorption model - switch self.carbAbsorptionModel { - case .linear: - self.settings = CarbModelSettings(absorptionModel: LinearAbsorption(), initialAbsorptionTimeOverrun: absorptionTimeOverrun, adaptiveAbsorptionRateEnabled: false) - case .nonlinear: - self.settings = CarbModelSettings(absorptionModel: PiecewiseLinearAbsorption(), initialAbsorptionTimeOverrun: absorptionTimeOverrun, adaptiveAbsorptionRateEnabled: false) - case .adaptiveRateNonlinear: - self.settings = CarbModelSettings(absorptionModel: PiecewiseLinearAbsorption(), initialAbsorptionTimeOverrun: 1.0, adaptiveAbsorptionRateEnabled: true, adaptiveRateStandbyIntervalFraction: 0.2) - } - - cacheStore.onReady { (error) in - guard error == nil else { - return - } - - cacheStore.fetchAnchor(key: CarbStore.healthKitQueryAnchorMetadataKey) { (anchor) in - self.queue.async { - self.setInitialQueryAnchor(anchor) - self.migrateLegacyCarbEntryKeys() - } - } - } - } - - // Migrate modifiedCarbEntries and deletedCarbEntryIDs - private func migrateLegacyCarbEntryKeys() { - cacheStore.managedObjectContext.performAndWait { - var changed = false - - for entry in UserDefaults.standard.modifiedCarbEntries ?? [] { - let object = CachedCarbObject(context: self.cacheStore.managedObjectContext) - object.create(from: entry) - changed = true - } - - // Note: We no longer migrate UserDefaults.standard.deletedCarbEntryIds since we don't have a startDate (only - // external ID) and CachedCarbObject requires a starDate. This only prevents a deleted carb entry that was previously - // uploaded to Nightscout, but not yet deleted from Nightscout, from being deleted in Nightscout. - - if changed { - self.cacheStore.save() - } - } - - UserDefaults.standard.purgeLegacyCarbEntryKeys() - } - - // MARK: - HealthKitSampleStore - - override func storeQueryAnchor(_ anchor: HKQueryAnchor) { - cacheStore.storeAnchor(anchor, key: CarbStore.healthKitQueryAnchorMetadataKey) - } - - override func processResults(from query: HKAnchoredObjectQuery, added: [HKSample], deleted: [HKDeletedObject], anchor: HKQueryAnchor, completion: @escaping (Bool) -> Void) { - queue.async { - var changed = false - var error: CarbStoreError? - - self.cacheStore.managedObjectContext.performAndWait { - do { - let date = Date() - - // Add new samples - if let samples = added as? [HKQuantitySample] { - for sample in samples { - if try self.addCarbEntry(for: sample, on: date) { - self.log.debug("Saved sample %@ into cache from HKAnchoredObjectQuery", sample.uuid.uuidString) - changed = true - } else { - self.log.default("Sample %@ from HKAnchoredObjectQuery already present in cache", sample.uuid.uuidString) - } - } - } - - // Delete deleted samples - for sample in deleted { - if try self.deleteCarbEntry(for: sample.uuid, on: date) { - self.log.debug("Deleted sample %@ from cache from HKAnchoredObjectQuery", sample.uuid.uuidString) - changed = true - } - } - - guard changed else { - return - } - - error = CarbStoreError(error: self.cacheStore.save()) - } catch let coreDataError { - error = .coreDataError(coreDataError) - } - } - - if let error = error { - self.delegate?.carbStore(self, didError: error) - completion(false) - return - } - - if !changed { - completion(true) - return - } - - self.handleUpdatedCarbData() - completion(true) - } - } -} - -// MARK: - Fetching - -extension CarbStore { - /// Retrieves carb entries within the specified date range - /// - /// - Parameters: - /// - start: The earliest date of values to retrieve - /// - end: The latest date of values to retrieve, if provided - /// - completion: A closure called once the values have been retrieved - /// - result: An array of carb entries, in chronological order by startDate, or error - public func getCarbEntries(start: Date? = nil, end: Date? = nil, completion: @escaping (_ result: CarbStoreResult<[StoredCarbEntry]>) -> Void) { - queue.async { - completion(self.getCarbEntries(start: start, end: end)) - } - } - - /// Retrieves carb entries within the specified date range - /// - /// - Parameters: - /// - start: The earliest date of values to retrieve - /// - end: The latest date of values to retrieve, if provided - /// - Returns: An array of carb entries, in chronological order by startDate, or error - private func getCarbEntries(start: Date? = nil, end: Date? = nil) -> CarbStoreResult<[StoredCarbEntry]> { - dispatchPrecondition(condition: .onQueue(queue)) - - var entries: [StoredCarbEntry] = [] - var error: CarbStoreError? - - cacheStore.managedObjectContext.performAndWait { - do { - entries = try self.getActiveCachedCarbObjects(start: start, end: end).map { StoredCarbEntry(managedObject: $0) } - } catch let coreDataError { - error = .coreDataError(coreDataError) - } - } - - if let error = error { - return .failure(error) - } - - return .success(entries) - } - - /// Retrieves active (not superceded, non-delete operation) cached carb objects within the specified date range - /// - /// - Parameters: - /// - start: The earliest date of values to retrieve - /// - end: The latest date of values to retrieve, if provided - /// - Returns: An array of cached carb objects - private func getActiveCachedCarbObjects(start: Date? = nil, end: Date? = nil) throws -> [CachedCarbObject] { - dispatchPrecondition(condition: .onQueue(queue)) - - var predicates = [NSPredicate(format: "operation != %d", Operation.delete.rawValue), - NSPredicate(format: "supercededDate == NIL")] - if let start = start { - predicates.append(NSPredicate(format: "startDate >= %@", start as NSDate)) - } - if let end = end { - predicates.append(NSPredicate(format: "startDate < %@", end as NSDate)) - } - - let request: NSFetchRequest = CachedCarbObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates) - request.sortDescriptors = [NSSortDescriptor(key: "startDate", ascending: true)] - - return try self.cacheStore.managedObjectContext.fetch(request) - } - - /// Retrieves carb entries from HealthKit within the specified date range and interprets their - /// absorption status based on the provided glucose effect - /// - /// - Parameters: - /// - start: The earliest date of values to retrieve - /// - end: The latest date of values to retrieve, if provided - /// - effectVelocities: A timeline of glucose effect velocities, ordered by start date - /// - completion: A closure calld once the values have been retrieved - /// - result: An array of carb entries, in chronological order by startDate - public func getCarbStatus( - start: Date, - end: Date? = nil, - effectVelocities: [GlucoseEffectVelocity]? = nil, - completion: @escaping (_ result: CarbStoreResult<[CarbStatus]>) -> Void - ) { - getCarbEntries(start: start, end: end) { (result) in - switch result { - case .success(let entries): - let status = entries.map( - to: effectVelocities ?? [], - carbRatio: self.carbRatioScheduleApplyingOverrideHistory, - insulinSensitivity: self.insulinSensitivityScheduleApplyingOverrideHistory, - absorptionTimeOverrun: self.absorptionTimeOverrun, - defaultAbsorptionTime: self.defaultAbsorptionTimes.medium, - delay: self.delay, - initialAbsorptionTimeOverrun: self.settings.initialAbsorptionTimeOverrun, - absorptionModel: self.settings.absorptionModel, - adaptiveAbsorptionRateEnabled: self.settings.adaptiveAbsorptionRateEnabled, - adaptiveRateStandbyIntervalFraction: self.settings.adaptiveRateStandbyIntervalFraction - ) - - completion(.success(status)) - case .failure(let error): - completion(.failure(error)) - } - } - } -} - -// MARK: - Modification - -extension CarbStore { - public func addCarbEntry(_ entry: NewCarbEntry, completion: @escaping (_ result: CarbStoreResult) -> Void) { - queue.async { - var storedEntry: StoredCarbEntry? - var error: CarbStoreError? - - self.cacheStore.managedObjectContext.performAndWait { - do { - let syncIdentifier = try self.cacheStore.managedObjectContext.generateUniqueSyncIdentifier() - - let newObject = CachedCarbObject(context: self.cacheStore.managedObjectContext) - newObject.create(from: entry, - provenanceIdentifier: self.provenanceIdentifier, - syncIdentifier: syncIdentifier, - syncVersion: self.syncVersion) - - if let saveError = CarbStoreError(error: self.cacheStore.save()) { - error = saveError - return - } - - self.saveEntryToHealthKit(newObject) - - storedEntry = StoredCarbEntry(managedObject: newObject) - } catch let coreDataError { - error = .coreDataError(coreDataError) - } - } - - if let error = error { - completion(.failure(error)) - return - } - - completion(.success(storedEntry!)) - - self.handleUpdatedCarbData() - } - } - - public func replaceCarbEntry(_ oldEntry: StoredCarbEntry, withEntry newEntry: NewCarbEntry, completion: @escaping (_ result: CarbStoreResult) -> Void) { - guard oldEntry.createdByCurrentApp else { - completion(.failure(.unauthorized)) - return - } - - queue.async { - var storedEntry: StoredCarbEntry? - var error: CarbStoreError? - - self.cacheStore.managedObjectContext.performAndWait { - do { - guard let oldObject = try self.cacheStore.managedObjectContext.cachedCarbObjectFromStoredCarbEntry(oldEntry) else { - error = .noData - return - } - - // Use same date for superceding old object and adding new object - let date = Date() - - oldObject.supercededDate = date - - let newObject = CachedCarbObject(context: self.cacheStore.managedObjectContext) - newObject.update(from: newEntry, replacing: oldObject, on: date) - - if let saveError = CarbStoreError(error: self.cacheStore.save()) { - error = saveError - return - } - - self.saveEntryToHealthKit(newObject) - - storedEntry = StoredCarbEntry(managedObject: newObject) - } catch let coreDataError { - error = .coreDataError(coreDataError) - } - } - - if let error = error { - completion(.failure(error)) - return - } - - completion(.success(storedEntry!)) - - self.handleUpdatedCarbData() - } - } - - private func saveEntryToHealthKit(_ object: CachedCarbObject) { - dispatchPrecondition(condition: .onQueue(queue)) - - guard storeEntriesToHealthKit else { - return - } - - let quantitySample = object.quantitySample - var error: Error? - - // Save object to HealthKit, log any errors, but do not fail - let dispatchGroup = DispatchGroup() - dispatchGroup.enter() - self.healthStore.save(quantitySample) { (_, healthKitError) in - error = healthKitError - dispatchGroup.leave() - } - dispatchGroup.wait() - - if let error = error { - self.log.error("Error saving HealthKit object: %@", String(describing: error)) - return - } - - // Update Core Data with the change, log any errors, but do not fail - object.uuid = quantitySample.uuid - if let error = self.cacheStore.save() { - self.log.error("Error updating CachedCarbObject after saving HealthKit object: %@", String(describing: error)) - object.uuid = nil - } - } - - public func deleteCarbEntry(_ oldEntry: StoredCarbEntry, completion: @escaping (_ result: CarbStoreResult) -> Void) { - guard oldEntry.createdByCurrentApp else { - completion(.failure(.unauthorized)) - return - } - - queue.async { - var error: CarbStoreError? - - self.cacheStore.managedObjectContext.performAndWait { - do { - guard let oldObject = try self.cacheStore.managedObjectContext.cachedCarbObjectFromStoredCarbEntry(oldEntry) else { - error = .noData - return - } - - // Use same date for superceding old object and adding new object; also used for userDeletedDate - let date = Date() - - oldObject.supercededDate = date - - let newObject = CachedCarbObject(context: self.cacheStore.managedObjectContext) - newObject.delete(from: oldObject, on: date) - - if let saveError = CarbStoreError(error: self.cacheStore.save()) { - error = saveError - return - } - - self.deleteObjectFromHealthKit(newObject) - } catch let coreDataError { - error = .coreDataError(coreDataError) - } - } - - if let error = error { - completion(.failure(error)) - return - } - - completion(.success(true)) - - self.handleUpdatedCarbData() - } - } - - private func deleteObjectFromHealthKit(_ object: CachedCarbObject) { - dispatchPrecondition(condition: .onQueue(queue)) - - // If the object does not have a UUID, then it was never saved to HealthKit, so no need to delete - guard object.uuid != nil else { - return - } - - var error: Error? - - // Delete object from HealthKit, log any errors, but do not fail - let dispatchGroup = DispatchGroup() - dispatchGroup.enter() - self.healthStore.deleteObjects(of: self.carbType, predicate: HKQuery.predicateForObject(with: object.uuid!)) { (_, _, healthKitError) in - error = healthKitError - dispatchGroup.leave() - } - dispatchGroup.wait() - - if let error = error { - self.log.error("Error deleting HealthKit object: %@", String(describing: error)) - return - } - - // Update Core Data with the change, log any errors, but do not fail - object.uuid = nil - if let error = self.cacheStore.save() { - self.log.error("Error updating CachedCarbObject after deleting HealthKit object: %@", String(describing: error)) - } - } - - private func addCarbEntry(for sample: HKQuantitySample, on date: Date) throws -> Bool { - dispatchPrecondition(condition: .onQueue(queue)) - - // Are there any objects matching the UUID? - let request: NSFetchRequest = CachedCarbObject.fetchRequest() - request.predicate = NSPredicate(format: "uuid == %@", sample.uuid as NSUUID) - request.fetchLimit = 1 - - let count = try cacheStore.managedObjectContext.count(for: request) - guard count == 0 else { - return false - } - - // Find all objects being replaced - let replacedObjects = try fetchRelatedCarbObjects(for: sample) - - // Mark all objects as superceded, as necessary - replacedObjects.filter({ $0.supercededDate == nil }).forEach({ $0.supercededDate = date }) - - // Add an object (create or update) for this UUID - let object = CachedCarbObject(context: cacheStore.managedObjectContext) - if let replacedObject = replacedObjects.last { - object.update(from: sample, replacing: replacedObject, on: date) - } else { - object.create(from: sample, on: date) - } - - return true - } - - private func deleteCarbEntry(for uuid: UUID, on date: Date) throws -> Bool { - dispatchPrecondition(condition: .onQueue(queue)) - - // Fetch objects matching the UUID, if none found, then nothing to delete, sorted by last seen anchor key - let request: NSFetchRequest = CachedCarbObject.fetchRequest() - request.predicate = NSPredicate(format: "uuid == %@", uuid as NSUUID) - request.sortDescriptors = [NSSortDescriptor(key: "anchorKey", ascending: true)] - - let objects = try cacheStore.managedObjectContext.fetch(request) - guard !objects.isEmpty else { - return false - } - - // Find all unsuperceded create/update objects, if none found, then nothing to delete - let supercededObjects = objects.filter { $0.operation != .delete && $0.supercededDate == nil } - guard !supercededObjects.isEmpty else { - return false - } - - // Mark as superceded - supercededObjects.forEach { $0.supercededDate = date } - - // If we don't yet have a delete object, then add one - if !objects.contains(where: { $0.operation == .delete }), let supercededObject = supercededObjects.last { - let object = CachedCarbObject(context: cacheStore.managedObjectContext) - object.delete(from: supercededObject, on: date) - } - - return true - } - - // Fetch all objects that are different versions of the specified sample, using sync identifier - private func fetchRelatedCarbObjects(for sample: HKQuantitySample) throws -> [CachedCarbObject] { - dispatchPrecondition(condition: .onQueue(queue)) - - guard let syncIdentifier = sample.syncIdentifier else { - return [] - } - - let request: NSFetchRequest = CachedCarbObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format: "provenanceIdentifier == %@", sample.provenanceIdentifier), - NSPredicate(format: "syncIdentifier == %@", syncIdentifier)]) - request.sortDescriptors = [NSSortDescriptor(key: "anchorKey", ascending: true)] - - return try cacheStore.managedObjectContext.fetch(request) - } -} - -// MARK: - Watch Synchronization - -extension CarbStore { - - /// Get carb objects in main app to deliver to Watch extension - public func getSyncCarbObjects(start: Date? = nil, end: Date? = nil, completion: @escaping (_ result: CarbStoreResult<[SyncCarbObject]>) -> Void) { - queue.async { - var objects: [SyncCarbObject] = [] - var error: CarbStoreError? - - self.cacheStore.managedObjectContext.performAndWait { - do { - objects = try self.getActiveCachedCarbObjects(start: start, end: end).map { SyncCarbObject(managedObject: $0) } - } catch let coreDataError { - error = .coreDataError(coreDataError) - } - } - - if let error = error { - completion(.failure(error)) - return - } - - completion(.success(objects)) - } - } - - /// Store carb objects in Watch extension - public func setSyncCarbObjects(_ objects: [SyncCarbObject], completion: @escaping (CarbStoreError?) -> Void) { - queue.async { - if let error = self.purgeCachedCarbObjectsUnconditionally() { - completion(error) - return - } - - var error: CarbStoreError? - - self.cacheStore.managedObjectContext.performAndWait { - guard !objects.isEmpty else { - return - } - - objects.forEach { - let object = CachedCarbObject(context: self.cacheStore.managedObjectContext) - object.update(from: $0) - } - - error = CarbStoreError(error: self.cacheStore.save()) - } - - completion(error) - - self.handleUpdatedCarbData() - } - } -} - -// MARK: - Cache management - -extension CarbStore { - public var earliestCacheDate: Date { - return currentDate(timeIntervalSinceNow: -cacheLength) - } - - private func purgeExpiredCachedCarbObjects() { - purgeCachedCarbObjects(before: earliestCacheDate) - } - - @discardableResult - private func purgeCachedCarbObjects(before date: Date) -> CarbStoreError? { - dispatchPrecondition(condition: .onQueue(queue)) - - var error: CarbStoreError? - - cacheStore.managedObjectContext.performAndWait { - do { - // Fetch all candidate objects for purge - let request: NSFetchRequest = CachedCarbObject.fetchRequest() - request.predicate = NSPredicate(format: "startDate < %@", date as NSDate) - - let objects = try self.cacheStore.managedObjectContext.fetch(request) - - // Objects can only be purged if all related objects can be purged - let purgedObjects = try objects.filter { try self.areAllRelatedObjectsPurgable(to: $0, before: date) } - guard !purgedObjects.isEmpty else { - return - } - - // Actually purge - purgedObjects.forEach { self.cacheStore.managedObjectContext.delete($0) } - - if let saveError = CarbStoreError(error: self.cacheStore.save()) { - error = saveError - return - } - - self.log.info("Purged %d CachedCarbObjects", purgedObjects.count) - } catch let coreDataError { - error = .coreDataError(coreDataError) - } - } - - if let error = error { - self.log.error("Unable to purge CachedCarbObjects: %{public}@", String(describing: error)) - return error - } - - return nil - } - - public func purgeCachedCarbObjectsUnconditionally(before date: Date, completion: @escaping (CarbStoreError?) -> Void) { - queue.async { - if let error = self.purgeCachedCarbObjectsUnconditionally(before: date) { - completion(error) - return - } - - self.handleUpdatedCarbData() - completion(nil) - } - } - - private func purgeCachedCarbObjectsUnconditionally(before date: Date? = nil) -> CarbStoreError? { - dispatchPrecondition(condition: .onQueue(queue)) - - var error: CarbStoreError? - - cacheStore.managedObjectContext.performAndWait { - do { - let request: NSFetchRequest = CachedCarbObject.fetchRequest() - if let date = date { - request.predicate = NSPredicate(format: "startDate < %@", date as NSDate) - } - let count = try self.cacheStore.managedObjectContext.deleteObjects(matching: request) - self.log.info("Purged all %d CachedCarbObjects", count) - } catch let coreDataError { - self.log.error("Unable to purge all CachedCarbObjects: %{public}@", String(describing: coreDataError)) - error = .coreDataError(coreDataError) - } - } - - return error - } - - private func handleUpdatedCarbData() { - dispatchPrecondition(condition: .onQueue(queue)) - - purgeExpiredCachedCarbObjects() - - NotificationCenter.default.post(name: CarbStore.carbEntriesDidChange, object: self) - delegate?.carbStoreHasUpdatedCarbData(self) - } - - private func areAllRelatedObjectsPurgable(to object: CachedCarbObject, before date: Date) throws -> Bool { - dispatchPrecondition(condition: .onQueue(queue)) - - // If no sync identifier, then there are no related objects - guard let syncIdentifier = object.syncIdentifier else { - return true - } - - // Count any that are NOT purgable - let request: NSFetchRequest = CachedCarbObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format: "provenanceIdentifier == %@", object.provenanceIdentifier), - NSPredicate(format: "syncIdentifier == %@", syncIdentifier), - NSPredicate(format: "startDate >= %@", date as NSDate)]) - request.fetchLimit = 1 - - return try cacheStore.managedObjectContext.count(for: request) == 0 - } -} - -// MARK: - Math - -extension CarbStore { - /// The longest expected absorption time interval for carbohydrates. Defaults to 8 hours. - public var maximumAbsorptionTimeInterval: TimeInterval { - return defaultAbsorptionTimes.slow * 2 - } - - /// Retrieves the single carbs on-board value occuring just prior or equal to the specified date - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - Parameters: - /// - date: The date of the value to retrieve - /// - effectVelocities: A timeline of glucose effect velocities, ordered by start date - /// - completion: A closure called once the value has been retrieved - /// - result: The carbs on-board value - public func carbsOnBoard(at date: Date, effectVelocities: [GlucoseEffectVelocity]? = nil, completion: @escaping (_ result: CarbStoreResult) -> Void) { - getCarbsOnBoardValues(start: date.addingTimeInterval(-delta), end: date, effectVelocities: effectVelocities) { (result) in - switch result { - case .failure(let error): - completion(.failure(error)) - case .success(let values): - guard let value = values.closestPrior(to: date) else { - // If we have no cob values in the store, and did not encounter an error, return 0 - completion(.success(CarbValue(startDate: date, quantity: HKQuantity(unit: .gram(), doubleValue: 0)))) - return - } - completion(.success(value)) - } - } - } - - /// Retrieves a timeline of unabsorbed carbohydrates - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - Parameters: - /// - start: The earliest date of values to retrieve - /// - end: The latest date of values to retrieve, if provided - /// - effectVelocities: A timeline of glucose effect velocities, ordered by start date - /// - completion: A closure called once the values have been retrieved - /// - values: A timeline of carb values, in chronological order - public func getCarbsOnBoardValues(start: Date, end: Date? = nil, effectVelocities: [GlucoseEffectVelocity]? = nil, completion: @escaping (_ result: CarbStoreResult<[CarbValue]>) -> Void) { - // To know COB at the requested start date, we need to fetch samples that might still be absorbing - let foodStart = start.addingTimeInterval(-maximumAbsorptionTimeInterval) - getCarbEntries(start: foodStart, end: end) { (result) in - switch result { - case .failure(let error): - completion(.failure(error)) - case .success(let entries): - let carbsOnBoard = self.carbsOnBoard(from: entries, startingAt: start, endingAt: end, effectVelocities: effectVelocities) - completion(.success(carbsOnBoard)) - } - } - } - - /// Computes a timeline of unabsorbed carbohydrates - /// - Parameters: - /// - start: The earliest date of values to retrieve - /// - end: The latest date of values to retrieve, if provided - /// - effectVelocities: A timeline of glucose effect velocities, ordered by start date - /// - Returns: A timeline of unabsorbed carbohydrates - public func carbsOnBoard( - from samples: [Sample], - startingAt start: Date, - endingAt end: Date? = nil, - effectVelocities: [GlucoseEffectVelocity]? = nil - ) -> [CarbValue] { - if let velocities = effectVelocities, - let carbRatioSchedule = carbRatioScheduleApplyingOverrideHistory, - let insulinSensitivitySchedule = insulinSensitivityScheduleApplyingOverrideHistory - { - return samples.map( - to: velocities, - carbRatio: carbRatioSchedule, - insulinSensitivity: insulinSensitivitySchedule, - absorptionTimeOverrun: absorptionTimeOverrun, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: delay, - initialAbsorptionTimeOverrun: settings.initialAbsorptionTimeOverrun, - absorptionModel: settings.absorptionModel, - adaptiveAbsorptionRateEnabled: settings.adaptiveAbsorptionRateEnabled, - adaptiveRateStandbyIntervalFraction: settings.adaptiveRateStandbyIntervalFraction - ).dynamicCarbsOnBoard( - from: start, - to: end, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: settings.absorptionModel, - delay: delay, - delta: delta - ) - } else { - return samples.carbsOnBoard( - from: start, - to: end, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: settings.absorptionModel, - delay: delay, - delta: delta - ) - } - } - - /// Computes the single carbs on-board value occuring just prior or equal to the specified date - /// - Parameters: - /// - date: The date of the value to retrieve - /// - effectVelocities: A timeline of glucose effect velocities, ordered by start date - /// - Returns: The carbs on-board value - public func carbsOnBoard( - from samples: [Sample], - at date: Date, - effectVelocities: [GlucoseEffectVelocity]? = nil - ) throws -> CarbValue { - let values = carbsOnBoard(from: samples, startingAt: date.addingTimeInterval(-delta), endingAt: date, effectVelocities: effectVelocities) - - guard let value = values.closestPrior(to: date) else { - throw CarbStoreError.noData - } - - return value - } - - - /// Retrieves a timeline of effect on blood glucose from carbohydrates - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - Parameters: - /// - start: The earliest date of effects to retrieve - /// - end: The latest date of effects to retrieve, if provided - /// - effectVelocities: A timeline of glucose effect velocities, ordered by start date - /// - completion: A closure called once the effects have been retrieved - /// - result: An array of effects, in chronological order - public func getGlucoseEffects(start: Date, end: Date? = nil, effectVelocities: [GlucoseEffectVelocity]? = nil, completion: @escaping(_ result: CarbStoreResult<(entries: [StoredCarbEntry], effects: [GlucoseEffect])>) -> Void) { - queue.async { - guard self.carbRatioSchedule != nil, self.insulinSensitivitySchedule != nil else { - completion(.failure(.notConfigured)) - return - } - - // To know glucose effects at the requested start date, we need to fetch samples that might still be absorbing - let foodStart = start.addingTimeInterval(-self.maximumAbsorptionTimeInterval) - - self.getCarbEntries(start: foodStart, end: end) { (result) in - switch result { - case .failure(let error): - completion(.failure(error)) - case .success(let entries): - do { - let effects = try self.glucoseEffects(of: entries, startingAt: start, endingAt: end, effectVelocities: effectVelocities) - completion(.success((entries: entries, effects: effects))) - } catch let error as CarbStoreError { - completion(.failure(error)) - } catch { - fatalError() - } - } - } - } - } - - /// Computes a timeline of effects on blood glucose from carbohydrates - /// - Parameters: - /// - start: The earliest date of effects to retrieve - /// - end: The latest date of effects to retrieve, if provided - /// - effectVelocities: A timeline of glucose effect velocities, ordered by start date - public func glucoseEffects( - of samples: [Sample], - startingAt start: Date, - endingAt end: Date? = nil, - effectVelocities: [GlucoseEffectVelocity]? = nil - ) throws -> [GlucoseEffect] { - guard - let carbRatioSchedule = carbRatioScheduleApplyingOverrideHistory, - let insulinSensitivitySchedule = insulinSensitivityScheduleApplyingOverrideHistory - else { - throw CarbStoreError.notConfigured - } - - if let effectVelocities = effectVelocities { - return samples.map( - to: effectVelocities, - carbRatio: carbRatioSchedule, - insulinSensitivity: insulinSensitivitySchedule, - absorptionTimeOverrun: absorptionTimeOverrun, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: delay, - initialAbsorptionTimeOverrun: settings.initialAbsorptionTimeOverrun, - absorptionModel: settings.absorptionModel, - adaptiveAbsorptionRateEnabled: settings.adaptiveAbsorptionRateEnabled, - adaptiveRateStandbyIntervalFraction: settings.adaptiveRateStandbyIntervalFraction - ).dynamicGlucoseEffects( - from: start, - to: end, - carbRatios: carbRatioSchedule, - insulinSensitivities: insulinSensitivitySchedule, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: settings.absorptionModel, - delay: delay, - delta: delta - ) - } else { - return samples.glucoseEffects( - from: start, - to: end, - carbRatios: carbRatioSchedule, - insulinSensitivities: insulinSensitivitySchedule, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: settings.absorptionModel, - delay: delay, - delta: delta - ) - } - } - - /// Retrieves the total number of recorded carbohydrates for the specified period. - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - Parameters: - /// - start: The earliest date of samples to include. - /// - completion: A closure called once the value has been retrieved. - /// - result: The total carbs recorded and the date of the first sample - public func getTotalCarbs(since start: Date, completion: @escaping (_ result: CarbStoreResult) -> Void) { - getCarbEntries(start: start) { (result) in - switch result { - case .success(let samples): - let total = samples.totalCarbs ?? CarbValue( - startDate: start, - quantity: HKQuantity(unit: .gram(), doubleValue: 0) - ) - - completion(.success(total)) - case .failure(let error): - completion(.failure(error)) - } - } - } -} - -// MARK: - Remote Data Service Query - -extension CarbStore { - public struct QueryAnchor: Equatable, RawRepresentable { - public typealias RawValue = [String: Any] - - internal var anchorKey: Int64 - - public init() { - self.anchorKey = 0 - } - - public init?(rawValue: RawValue) { - guard let anchorKey = (rawValue["anchorKey"] ?? rawValue["storedModificationCounter"]) as? Int64 else { // Backwards compatibility with storedModificationCounter - return nil - } - self.anchorKey = anchorKey - } - - public var rawValue: RawValue { - var rawValue: RawValue = [:] - rawValue["anchorKey"] = anchorKey - return rawValue - } - } - - public enum CarbQueryResult { - case success(QueryAnchor, [SyncCarbObject], [SyncCarbObject], [SyncCarbObject]) - case failure(Error) - } - - public func executeCarbQuery(fromQueryAnchor queryAnchor: QueryAnchor?, limit: Int, completion: @escaping (CarbQueryResult) -> Void) { - queue.async { - var queryAnchor = queryAnchor ?? QueryAnchor() - var queryCreatedResult = [SyncCarbObject]() - var queryUpdatedResult = [SyncCarbObject]() - var queryDeletedResult = [SyncCarbObject]() - var queryError: Error? - - guard limit > 0 else { - completion(.success(queryAnchor, [], [], [])) - return - } - - self.cacheStore.managedObjectContext.performAndWait { - let storedRequest: NSFetchRequest = CachedCarbObject.fetchRequest() - storedRequest.predicate = NSPredicate(format: "anchorKey > %d", queryAnchor.anchorKey) - storedRequest.sortDescriptors = [NSSortDescriptor(key: "anchorKey", ascending: true)] - storedRequest.fetchLimit = limit - - do { - let stored = try self.cacheStore.managedObjectContext.fetch(storedRequest) - if let anchorKey = stored.max(by: { $0.anchorKey < $1.anchorKey })?.anchorKey { - queryAnchor.anchorKey = anchorKey - } - stored.map({ SyncCarbObject(managedObject: $0) }).forEach { - switch $0.operation { - case .create: - queryCreatedResult.append($0) - case .update: - queryUpdatedResult.append($0) - case .delete: - queryDeletedResult.append($0) - } - } - - } catch let coreDataError { - queryError = coreDataError - return - } - } - - if let queryError = queryError { - completion(.failure(queryError)) - return - } - - completion(.success(queryAnchor, queryCreatedResult, queryUpdatedResult, queryDeletedResult)) - } - } -} - -// MARK: - Critical Event Log Export - -extension CarbStore: CriticalEventLog { - private var exportProgressUnitCountPerObject: Int64 { 1 } - private var exportFetchLimit: Int { Int(criticalEventLogExportProgressUnitCountPerFetch / exportProgressUnitCountPerObject) } - - public var exportName: String { "Carbs.json" } - - public func exportProgressTotalUnitCount(startDate: Date, endDate: Date? = nil) -> Result { - var result: Result? - - self.cacheStore.managedObjectContext.performAndWait { - do { - let request: NSFetchRequest = CachedCarbObject.fetchRequest() - request.predicate = self.exportDatePredicate(startDate: startDate, endDate: endDate) - - let objectCount = try self.cacheStore.managedObjectContext.count(for: request) - result = .success(Int64(objectCount) * exportProgressUnitCountPerObject) - } catch let error { - result = .failure(error) - } - } - - return result! - } - - public func export(startDate: Date, endDate: Date, to stream: OutputStream, progress: Progress) -> Error? { - let encoder = JSONStreamEncoder(stream: stream) - var anchorKey: Int64 = 0 - var fetching = true - var error: Error? - - while fetching && error == nil { - self.cacheStore.managedObjectContext.performAndWait { - do { - guard !progress.isCancelled else { - throw CriticalEventLogError.cancelled - } - - let request: NSFetchRequest = CachedCarbObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format: "anchorKey > %d", anchorKey), - self.exportDatePredicate(startDate: startDate, endDate: endDate)]) - request.sortDescriptors = [NSSortDescriptor(key: "anchorKey", ascending: true)] - request.fetchLimit = self.exportFetchLimit - - let objects = try self.cacheStore.managedObjectContext.fetch(request) - if objects.isEmpty { - fetching = false - return - } - - try encoder.encode(objects) - - anchorKey = objects.last!.anchorKey - - progress.completedUnitCount += Int64(objects.count) * exportProgressUnitCountPerObject - } catch let fetchError { - error = fetchError - } - } - } - - if let closeError = encoder.close(), error == nil { - error = closeError - } - - return error - } - - private func exportDatePredicate(startDate: Date, endDate: Date? = nil) -> NSPredicate { - var addedDatePredicate = NSPredicate(format: "addedDate >= %@", startDate as NSDate) - var supercededDatePredicate = NSPredicate(format: "supercededDate >= %@", startDate as NSDate) - if let endDate = endDate { - addedDatePredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [addedDatePredicate, NSPredicate(format: "addedDate < %@", endDate as NSDate)]) - supercededDatePredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [supercededDatePredicate, NSPredicate(format: "supercededDate < %@", endDate as NSDate)]) - } - return NSCompoundPredicate(orPredicateWithSubpredicates: [addedDatePredicate, supercededDatePredicate]) - } -} - -// MARK: - Core Data (Bulk) - TEST ONLY - -extension CarbStore { - public func addNewCarbEntries(entries: [NewCarbEntry], completion: @escaping (Error?) -> Void) { - guard !entries.isEmpty else { - completion(nil) - return - } - - queue.async { - var error: Error? - - self.cacheStore.managedObjectContext.performAndWait { - do { - for entry in entries { - let syncIdentifier = try self.cacheStore.managedObjectContext.generateUniqueSyncIdentifier() - - let object = CachedCarbObject(context: self.cacheStore.managedObjectContext) - object.create(from: entry, - provenanceIdentifier: self.provenanceIdentifier, - syncIdentifier: syncIdentifier, - on: entry.date) - } - error = self.cacheStore.save() - } catch let coreDataError { - error = coreDataError - } - } - - guard error == nil else { - completion(error) - return - } - - self.log.info("Added %d CachedCarbObjects", entries.count) - self.delegate?.carbStoreHasUpdatedCarbData(self) - completion(nil) - } - } -} - -// MARK: - Issue Report - -extension CarbStore { - /// Generates a diagnostic report about the current state - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - parameter completionHandler: A closure called once the report has been generated. The closure takes a single argument of the report string. - public func generateDiagnosticReport(_ completionHandler: @escaping (_ report: String) -> Void) { - queue.async { - - var carbAbsorptionModel: String - switch self.carbAbsorptionModel { - case .linear: - carbAbsorptionModel = "Linear" - case .nonlinear: - carbAbsorptionModel = "Nonlinear" - case .adaptiveRateNonlinear: - carbAbsorptionModel = "Nonlinear with Adaptive Rate for Remaining Carbs" - } - - var report: [String] = [ - "## CarbStore", - "", - "* carbRatioSchedule: \(self.carbRatioSchedule?.debugDescription ?? "")", - "* carbRatioScheduleApplyingOverrideHistory: \(self.carbRatioScheduleApplyingOverrideHistory?.debugDescription ?? "nil")", - "* cacheLength: \(self.cacheLength)", - "* defaultAbsorptionTimes: \(self.defaultAbsorptionTimes)", - "* observationInterval: \(self.observationInterval)", - "* insulinSensitivitySchedule: \(self.insulinSensitivitySchedule?.debugDescription ?? "")", - "* insulinSensitivityScheduleApplyingOverrideHistory: \(self.insulinSensitivityScheduleApplyingOverrideHistory?.debugDescription ?? "nil")", - "* overrideHistory: \(self.overrideHistory.map(String.init(describing:)) ?? "nil")", - "* carbSensitivitySchedule: \(self.carbSensitivitySchedule?.debugDescription ?? "nil")", - "* delay: \(self.delay)", - "* delta: \(self.delta)", - "* absorptionTimeOverrun: \(self.absorptionTimeOverrun)", - "* carbAbsorptionModel: \(carbAbsorptionModel)", - "* Carb absorption model settings: \(self.settings)", - super.debugDescription, - "", - "cachedCarbEntries:" - ] - - switch self.getCarbEntries() { - case .failure(let error): - report.append("Error: \(error)") - case .success(let entries): - report.append("[") - report.append("\tStoredCarbEntry(uuid, provenanceIdentifier, syncIdentifier, syncVersion, startDate, quantity, foodType, absorptionTime, createdByCurrentApp, userCreatedDate, userUpdatedDate)") - report.append(entries.map({ (entry) -> String in - return [ - "\t", - entry.uuid?.uuidString ?? "", - entry.provenanceIdentifier, - entry.syncIdentifier ?? "", - entry.syncVersion != nil ? String(describing: entry.syncVersion) : "", - String(describing: entry.startDate), - String(describing: entry.quantity), - entry.foodType ?? "", - String(describing: entry.absorptionTime ?? self.defaultAbsorptionTimes.medium), - String(describing: entry.createdByCurrentApp), - entry.userCreatedDate != nil ? String(describing: entry.userCreatedDate) : "", - entry.userUpdatedDate != nil ? String(describing: entry.userUpdatedDate) : "", - ].joined(separator: ", ") - }).joined(separator: "\n")) - report.append("]") - report.append("") - } - - completionHandler(report.joined(separator: "\n")) - } - } -} - -// MARK: - NSManagedObjectContext - -fileprivate extension NSManagedObjectContext { - func generateUniqueSyncIdentifier() throws -> String { - while true { - let syncIdentifier = UUID().uuidString - - let request: NSFetchRequest = CachedCarbObject.fetchRequest() - request.predicate = NSPredicate(format: "syncIdentifier == %@", syncIdentifier) - request.fetchLimit = 1 - - if try count(for: request) == 0 { - return syncIdentifier - } - } - } - - func cachedCarbObjectFromStoredCarbEntry(_ entry: StoredCarbEntry) throws -> CachedCarbObject? { - guard entry.createdByCurrentApp, let syncIdentifier = entry.syncIdentifier, let syncVersion = entry.syncVersion else { - return nil - } - - let request: NSFetchRequest = CachedCarbObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [ - NSPredicate(format: "createdByCurrentApp == YES"), - NSPredicate(format: "syncIdentifier == %@", syncIdentifier), - NSPredicate(format: "syncVersion == %d", syncVersion), - NSPredicate(format: "operation != %d", Operation.delete.rawValue), - NSPredicate(format: "supercededDate == NIL") - ]) - request.fetchLimit = 1 - - if let object = try fetch(request).first { - return object - } - - return try cachedCarbObjectFromStoredCarbEntryDEPRECATED(entry) - } - - // DEPRECATED: Fallback for pre-syncIdentifier entries, just has UUID from HealthKit - func cachedCarbObjectFromStoredCarbEntryDEPRECATED(_ entry: StoredCarbEntry) throws -> CachedCarbObject? { - guard entry.createdByCurrentApp, let uuid = entry.uuid else { - return nil - } - - let request: NSFetchRequest = CachedCarbObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [ - NSPredicate(format: "createdByCurrentApp == YES"), - NSPredicate(format: "uuid == %@", uuid as NSUUID), - NSPredicate(format: "operation != %d", Operation.delete.rawValue), - NSPredicate(format: "supercededDate == NIL") - ]) - request.fetchLimit = 1 - - if let object = try fetch(request).first { - return object - } - - return nil - } -} diff --git a/Dependencies/LoopKit/LoopKit/CarbKit/CarbStoreError.swift b/Dependencies/LoopKit/LoopKit/CarbKit/CarbStoreError.swift deleted file mode 100644 index 60bc4320d..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbKit/CarbStoreError.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// CarbStoreError.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension CarbStore.CarbStoreError: LocalizedError { - public var errorDescription: String? { - switch self { - case .unauthorized: - return LocalizedString("com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription", value: "Authorization Denied", comment: "The description of an error returned when attempting to delete a sample not shared by the current app") - case .notConfigured: - return nil - case .healthStoreError(let error): - return error.localizedDescription - case .coreDataError(let error): - return error.localizedDescription - case .noData: - return LocalizedString("No values found", comment: "Describes an error for no data found in a CarbStore request") - } - } - - public var recoverySuggestion: String? { - switch self { - case .unauthorized: - return LocalizedString("com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion", value: "This sample can be deleted from the Health app", comment: "The error recovery suggestion when attempting to delete a sample not shared by the current app") - case .notConfigured: - return nil - case .healthStoreError: - return nil - case .coreDataError: - return nil - case .noData: - return LocalizedString("Ensure carb data exists for the specified date", comment: "Recovery suggestion for a no data error") - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/CarbKit/CarbValue.swift b/Dependencies/LoopKit/LoopKit/CarbKit/CarbValue.swift deleted file mode 100644 index 94d59a3ed..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbKit/CarbValue.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// CarbValue.swift -// LoopKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - - -public struct CarbValue: SampleValue { - public let startDate: Date - public let endDate: Date - public var quantity: HKQuantity - - public init(startDate: Date, endDate: Date? = nil, quantity: HKQuantity) { - self.startDate = startDate - self.endDate = endDate ?? startDate - self.quantity = quantity - } -} - -extension CarbValue: Equatable {} - -extension CarbValue: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.startDate = try container.decode(Date.self, forKey: .startDate) - self.endDate = try container.decode(Date.self, forKey: .endDate) - self.quantity = HKQuantity(unit: HKUnit(from: try container.decode(String.self, forKey: .quantityUnit)), - doubleValue: try container.decode(Double.self, forKey: .quantity)) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(startDate, forKey: .startDate) - try container.encode(endDate, forKey: .endDate) - try container.encode(quantity.doubleValue(for: .gram()), forKey: .quantity) - try container.encode(HKUnit.gram().unitString, forKey: .quantityUnit) - } - - private enum CodingKeys: String, CodingKey { - case startDate - case endDate - case quantity - case quantityUnit - } -} diff --git a/Dependencies/LoopKit/LoopKit/CarbKit/HKQuantitySample+CarbKit.swift b/Dependencies/LoopKit/LoopKit/CarbKit/HKQuantitySample+CarbKit.swift deleted file mode 100644 index 40d498c45..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbKit/HKQuantitySample+CarbKit.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// HKQuantitySample.swift -// CarbKit -// -// Created by Nathan Racklyeft on 1/10/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -let LegacyMetadataKeyAbsorptionTime = "com.loudnate.CarbKit.HKMetadataKey.AbsorptionTimeMinutes" -let MetadataKeyAbsorptionTime = "com.loopkit.AbsorptionTime" -let MetadataKeyUserCreatedDate = "com.loopkit.CarbKit.HKMetadataKey.UserCreatedDate" -let MetadataKeyUserUpdatedDate = "com.loopkit.CarbKit.HKMetadataKey.UserUpdatedDate" - -extension HKQuantitySample { - public var foodType: String? { - return metadata?[HKMetadataKeyFoodType] as? String - } - - public var absorptionTime: TimeInterval? { - return metadata?[MetadataKeyAbsorptionTime] as? TimeInterval - ?? metadata?[LegacyMetadataKeyAbsorptionTime] as? TimeInterval - } - - public var createdByCurrentApp: Bool { - return sourceRevision.source == HKSource.default() - } - - public var userCreatedDate: Date? { - return metadata?[MetadataKeyUserCreatedDate] as? Date - } - - public var userUpdatedDate: Date? { - return metadata?[MetadataKeyUserUpdatedDate] as? Date - } -} diff --git a/Dependencies/LoopKit/LoopKit/CarbKit/NSUserDefaults.swift b/Dependencies/LoopKit/LoopKit/CarbKit/NSUserDefaults.swift deleted file mode 100644 index fd0dfe740..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbKit/NSUserDefaults.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// NSUserDefaults.swift -// LoopKit -// -// Created by Nathan Racklyeft on 2/20/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension UserDefaults { - private enum Key: String { - case CarbEntryCache = "com.loudnate.CarbKit.CarbEntryCache" - case ModifiedCarbEntries = "com.loudnate.CarbKit.ModifiedCarbEntries" - case DeletedCarbEntryIds = "com.loudnate.CarbKit.DeletedCarbEntryIds" - } - - func purgeLegacyCarbEntryKeys() { - removeObject(forKey: Key.CarbEntryCache.rawValue) - removeObject(forKey: Key.ModifiedCarbEntries.rawValue) - removeObject(forKey: Key.DeletedCarbEntryIds.rawValue) - } - - var modifiedCarbEntries: [StoredCarbEntry]? { - get { - if let rawValue = array(forKey: Key.ModifiedCarbEntries.rawValue) as? [StoredCarbEntry.RawValue] { - return rawValue.compactMap { StoredCarbEntry(rawValue: $0) } - } else { - return nil - } - } - } - - var deletedCarbEntryIds: [String]? { - get { - return array(forKey: Key.DeletedCarbEntryIds.rawValue) as? [String] - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/CarbKit/NewCarbEntry.swift b/Dependencies/LoopKit/LoopKit/CarbKit/NewCarbEntry.swift deleted file mode 100644 index 1570668d4..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbKit/NewCarbEntry.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// NewCarbEntry.swift -// CarbKit -// -// Created by Nathan Racklyeft on 1/15/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -public struct NewCarbEntry: CarbEntry, Equatable, RawRepresentable { - public typealias RawValue = [String: Any] - - public let date: Date - public let quantity: HKQuantity - public let startDate: Date - public let foodType: String? - public let absorptionTime: TimeInterval? - - public init(date: Date = Date(), quantity: HKQuantity, startDate: Date, foodType: String?, absorptionTime: TimeInterval?) { - self.date = date - self.quantity = quantity - self.startDate = startDate - self.foodType = foodType - self.absorptionTime = absorptionTime - } - - public init?(rawValue: RawValue) { - guard - let date = rawValue["date"] as? Date, - let grams = rawValue["grams"] as? Double, - let startDate = rawValue["startDate"] as? Date - else { - return nil - } - - self.init( - date: date, - quantity: HKQuantity(unit: .gram(), doubleValue: grams), - startDate: startDate, - foodType: rawValue["foodType"] as? String, - absorptionTime: rawValue["absorptionTime"] as? TimeInterval - ) - } - - public var rawValue: RawValue { - var rawValue: RawValue = [ - "date": date, - "grams": quantity.doubleValue(for: .gram()), - "startDate": startDate - ] - - rawValue["foodType"] = foodType - rawValue["absorptionTime"] = absorptionTime - - return rawValue - } -} diff --git a/Dependencies/LoopKit/LoopKit/CarbKit/StoredCarbEntry.swift b/Dependencies/LoopKit/LoopKit/CarbKit/StoredCarbEntry.swift deleted file mode 100644 index 529bee641..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbKit/StoredCarbEntry.swift +++ /dev/null @@ -1,169 +0,0 @@ -// -// StoredCarbEntry.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/22/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit -import CoreData - -public struct StoredCarbEntry: CarbEntry, Equatable { - - public let uuid: UUID? - - // MARK: - HealthKit Sync Support - - public let provenanceIdentifier: String - public let syncIdentifier: String? - public let syncVersion: Int? - - // MARK: - SampleValue - - public let startDate: Date - public let quantity: HKQuantity - - // MARK: - CarbEntry - - public let foodType: String? - public let absorptionTime: TimeInterval? - public let createdByCurrentApp: Bool - - // MARK: - User dates - - public let userCreatedDate: Date? - public let userUpdatedDate: Date? - - public init( - uuid: UUID?, - provenanceIdentifier: String, - syncIdentifier: String?, - syncVersion: Int?, - startDate: Date, - quantity: HKQuantity, - foodType: String?, - absorptionTime: TimeInterval?, - createdByCurrentApp: Bool, - userCreatedDate: Date?, - userUpdatedDate: Date? - ) { - self.uuid = uuid - self.provenanceIdentifier = provenanceIdentifier - self.syncIdentifier = syncIdentifier - self.syncVersion = syncVersion - self.startDate = startDate - self.quantity = quantity - self.foodType = foodType - self.absorptionTime = absorptionTime - self.createdByCurrentApp = createdByCurrentApp - self.userCreatedDate = userCreatedDate - self.userUpdatedDate = userUpdatedDate - } -} - -extension StoredCarbEntry { - init(managedObject: CachedCarbObject) { - self.init( - uuid: managedObject.uuid, - provenanceIdentifier: managedObject.provenanceIdentifier, - syncIdentifier: managedObject.syncIdentifier, - syncVersion: managedObject.syncVersion, - startDate: managedObject.startDate, - quantity: managedObject.quantity, - foodType: managedObject.foodType, - absorptionTime: managedObject.absorptionTime, - createdByCurrentApp: managedObject.createdByCurrentApp, - userCreatedDate: managedObject.userCreatedDate, - userUpdatedDate: managedObject.userUpdatedDate - ) - } -} - -extension StoredCarbEntry: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.init(uuid: try container.decodeIfPresent(UUID.self, forKey: .uuid), - provenanceIdentifier: try container.decode(String.self, forKey: .provenanceIdentifier), - syncIdentifier: try container.decodeIfPresent(String.self, forKey: .syncIdentifier), - syncVersion: try container.decodeIfPresent(Int.self, forKey: .syncVersion), - startDate: try container.decode(Date.self, forKey: .startDate), - quantity: HKQuantity(unit: .gram(), doubleValue: try container.decode(Double.self, forKey: .quantity)), - foodType: try container.decodeIfPresent(String.self, forKey: .foodType), - absorptionTime: try container.decodeIfPresent(TimeInterval.self, forKey: .absorptionTime), - createdByCurrentApp: try container.decode(Bool.self, forKey: .createdByCurrentApp), - userCreatedDate: try container.decodeIfPresent(Date.self, forKey: .userCreatedDate), - userUpdatedDate: try container.decodeIfPresent(Date.self, forKey: .userUpdatedDate) - ) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encodeIfPresent(uuid, forKey: .uuid) - try container.encode(provenanceIdentifier, forKey: .provenanceIdentifier) - try container.encodeIfPresent(syncIdentifier, forKey: .syncIdentifier) - try container.encodeIfPresent(syncVersion, forKey: .syncVersion) - try container.encode(startDate, forKey: .startDate) - try container.encode(quantity.doubleValue(for: .gram()), forKey: .quantity) - try container.encodeIfPresent(foodType, forKey: .foodType) - try container.encodeIfPresent(absorptionTime, forKey: .absorptionTime) - try container.encode(createdByCurrentApp, forKey: .createdByCurrentApp) - try container.encodeIfPresent(userCreatedDate, forKey: .userCreatedDate) - try container.encodeIfPresent(userUpdatedDate, forKey: .userUpdatedDate) - } - - private enum CodingKeys: String, CodingKey { - case uuid - case provenanceIdentifier - case syncIdentifier - case syncVersion - case startDate - case quantity - case foodType - case absorptionTime - case createdByCurrentApp - case userCreatedDate - case userUpdatedDate - } -} - -// MARK: - DEPRECATED - Used only for migration - -extension StoredCarbEntry { - typealias RawValue = [String: Any] - - init?(rawValue: RawValue) { - guard let - sampleUUIDString = rawValue["sampleUUID"] as? String, - let uuid = UUID(uuidString: sampleUUIDString), - let startDate = rawValue["startDate"] as? Date, - let unitString = rawValue["unitString"] as? String, - let value = rawValue["value"] as? Double, - let createdByCurrentApp = rawValue["createdByCurrentApp"] as? Bool else - { - return nil - } - - var syncIdentifier: String? - var syncVersion: Int? - - if let externalID = rawValue["externalId"] as? String { - syncIdentifier = externalID - syncVersion = 1 - } - - self.init( - uuid: uuid, - provenanceIdentifier: createdByCurrentApp ? HKSource.default().bundleIdentifier : "", - syncIdentifier: syncIdentifier, - syncVersion: syncVersion, - startDate: startDate, - quantity: HKQuantity(unit: HKUnit(from: unitString), doubleValue: value), - foodType: rawValue["foodType"] as? String, - absorptionTime: rawValue["absorptionTime"] as? TimeInterval, - createdByCurrentApp: createdByCurrentApp, - userCreatedDate: nil, - userUpdatedDate: nil - ) - } -} diff --git a/Dependencies/LoopKit/LoopKit/CarbKit/SyncCarbObject.swift b/Dependencies/LoopKit/LoopKit/CarbKit/SyncCarbObject.swift deleted file mode 100644 index 2870cf2e7..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbKit/SyncCarbObject.swift +++ /dev/null @@ -1,88 +0,0 @@ -// -// SyncCarbObject.swift -// LoopKit -// -// Created by Darin Krauss on 8/10/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - -public enum Operation: Int, CaseIterable, Codable { - case create - case update - case delete -} - -public struct SyncCarbObject: Codable, Equatable { - public let absorptionTime: TimeInterval? - public let createdByCurrentApp: Bool - public let foodType: String? - public let grams: Double - public let startDate: Date - public let uuid: UUID? - public let provenanceIdentifier: String - public let syncIdentifier: String? - public let syncVersion: Int? - public let userCreatedDate: Date? - public let userUpdatedDate: Date? - public let userDeletedDate: Date? - public let operation: Operation - public let addedDate: Date? - public let supercededDate: Date? - - public init(absorptionTime: TimeInterval?, - createdByCurrentApp: Bool, - foodType: String?, - grams: Double, - startDate: Date, - uuid: UUID?, - provenanceIdentifier: String, - syncIdentifier: String?, - syncVersion: Int?, - userCreatedDate: Date?, - userUpdatedDate: Date?, - userDeletedDate: Date?, - operation: Operation, - addedDate: Date?, - supercededDate: Date?) { - self.absorptionTime = absorptionTime - self.createdByCurrentApp = createdByCurrentApp - self.foodType = foodType - self.grams = grams - self.startDate = startDate - self.uuid = uuid - self.provenanceIdentifier = provenanceIdentifier - self.syncIdentifier = syncIdentifier - self.syncVersion = syncVersion - self.userCreatedDate = userCreatedDate - self.userUpdatedDate = userUpdatedDate - self.userDeletedDate = userDeletedDate - self.operation = operation - self.addedDate = addedDate - self.supercededDate = supercededDate - } - - public var quantity: HKQuantity { HKQuantity(unit: .gram(), doubleValue: grams) } -} - -extension SyncCarbObject { - init(managedObject: CachedCarbObject) { - self.init(absorptionTime: managedObject.absorptionTime, - createdByCurrentApp: managedObject.createdByCurrentApp, - foodType: managedObject.foodType, - grams: managedObject.grams, - startDate: managedObject.startDate, - uuid: managedObject.uuid, - provenanceIdentifier: managedObject.provenanceIdentifier, - syncIdentifier: managedObject.syncIdentifier, - syncVersion: managedObject.syncVersion, - userCreatedDate: managedObject.userCreatedDate, - userUpdatedDate: managedObject.userUpdatedDate, - userDeletedDate: managedObject.userDeletedDate, - operation: managedObject.operation, - addedDate: managedObject.addedDate, - supercededDate: managedObject.supercededDate) - } -} diff --git a/Dependencies/LoopKit/LoopKit/CarbRatioSchedule.swift b/Dependencies/LoopKit/LoopKit/CarbRatioSchedule.swift deleted file mode 100644 index 0965eb7fe..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbRatioSchedule.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// CarbRatioSchedule.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/12/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -public typealias CarbRatioSchedule = SingleQuantitySchedule diff --git a/Dependencies/LoopKit/LoopKit/CarbSensitivitySchedule.swift b/Dependencies/LoopKit/LoopKit/CarbSensitivitySchedule.swift deleted file mode 100644 index 10b68a2ef..000000000 --- a/Dependencies/LoopKit/LoopKit/CarbSensitivitySchedule.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// CarbSensitivitySchedule.swift -// LoopKit -// -// Created by Michael Pangburn on 3/27/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -public typealias CarbSensitivitySchedule = SingleQuantitySchedule - -extension /* CarbSensitivitySchedule */ DailyQuantitySchedule where T == Double { - public static func carbSensitivitySchedule(insulinSensitivitySchedule: InsulinSensitivitySchedule, carbRatioSchedule: CarbRatioSchedule) -> CarbSensitivitySchedule { - return insulinSensitivitySchedule / carbRatioSchedule - } -} diff --git a/Dependencies/LoopKit/LoopKit/CorrectionRangeOverrides.swift b/Dependencies/LoopKit/LoopKit/CorrectionRangeOverrides.swift deleted file mode 100644 index 5f8c1ea19..000000000 --- a/Dependencies/LoopKit/LoopKit/CorrectionRangeOverrides.swift +++ /dev/null @@ -1,113 +0,0 @@ -// -// CorrectionRangeOverrides.swift -// LoopKit -// -// Created by Rick Pasetto on 7/14/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import HealthKit -import Foundation - -public struct CorrectionRangeOverrides: Equatable { - public enum Preset: Hashable, CaseIterable { - case preMeal - case workout - } - - public var ranges: [Preset: ClosedRange] - - public init(preMeal: DoubleRange?, workout: DoubleRange?, unit: HKUnit) { - ranges = [:] - ranges[.preMeal] = preMeal?.quantityRange(for: unit) - ranges[.workout] = workout?.quantityRange(for: unit) - } - - public init(preMeal: GlucoseRange?, workout: GlucoseRange?) { - ranges = [:] - ranges[.preMeal] = preMeal?.quantityRange - ranges[.workout] = workout?.quantityRange - } - - public init(preMeal: ClosedRange?, workout: ClosedRange?) { - ranges = [:] - ranges[.preMeal] = preMeal - ranges[.workout] = workout - } - - public var preMeal: ClosedRange? { ranges[.preMeal] } - public var workout: ClosedRange? { ranges[.workout] } -} - -public extension CorrectionRangeOverrides.Preset { - var title: String { - switch self { - case .preMeal: - return LocalizedString("Pre-Meal", comment: "Title for pre-meal mode") - case .workout: - return LocalizedString("Workout", comment: "Title for workout mode") - } - } - - var therapySetting: TherapySetting { - switch self { - case .preMeal: return .preMealCorrectionRangeOverride - case .workout: return .workoutCorrectionRangeOverride - } - } -} - -extension CorrectionRangeOverrides: Codable { - fileprivate var codingGlucoseUnit: HKUnit { - return .milligramsPerDeciliter - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let preMealGlucoseRange = try container.decodeIfPresent(GlucoseRange.self, forKey: .preMealRange) - let workoutGlucoseRange = try container.decodeIfPresent(GlucoseRange.self, forKey: .workoutRange) - - self.ranges = [:] - self.ranges[.preMeal] = preMealGlucoseRange?.quantityRange - self.ranges[.workout] = workoutGlucoseRange?.quantityRange - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - let preMealGlucoseRange = preMeal?.glucoseRange(for: codingGlucoseUnit) - let workoutGlucoseRange = workout?.glucoseRange(for: codingGlucoseUnit) - try container.encodeIfPresent(preMealGlucoseRange, forKey: .preMealRange) - try container.encodeIfPresent(workoutGlucoseRange, forKey: .workoutRange) - } - - private enum CodingKeys: String, CodingKey { - case preMealRange - case workoutRange - case bloodGlucoseUnit - } -} - -extension CorrectionRangeOverrides: RawRepresentable { - public typealias RawValue = [String: Any] - - public init?(rawValue: RawValue) { - ranges = [:] - if let rawPreMealTargetRange = rawValue["preMealTargetRange"] as? GlucoseRange.RawValue { - ranges[.preMeal] = GlucoseRange(rawValue: rawPreMealTargetRange)?.quantityRange - } - - if let rawWorkoutTargetRange = rawValue["workoutTargetRange"] as? GlucoseRange.RawValue { - ranges[.workout] = GlucoseRange(rawValue: rawWorkoutTargetRange)?.quantityRange - } - } - - public var rawValue: RawValue { - var raw: RawValue = [:] - let preMealTargetGlucoseRange = preMeal?.glucoseRange(for: codingGlucoseUnit) - let workoutTargetGlucoseRange = workout?.glucoseRange(for: codingGlucoseUnit) - raw["preMealTargetRange"] = preMealTargetGlucoseRange?.rawValue - raw["workoutTargetRange"] = workoutTargetGlucoseRange?.rawValue - - return raw - } -} diff --git a/Dependencies/LoopKit/LoopKit/CriticalEventLog.swift b/Dependencies/LoopKit/LoopKit/CriticalEventLog.swift deleted file mode 100644 index 71a6e449d..000000000 --- a/Dependencies/LoopKit/LoopKit/CriticalEventLog.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// CriticalEventLog.swift -// LoopKit -// -// Created by Darin Krauss on 7/15/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - -public protocol CriticalEventLog { - - /// The name for the critical event log export. - var exportName: String { get } - - /// Calculate the progress total unit count for the critical event log export for the specified date range. - /// - /// - Parameters: - /// - startDate: The start date for the critical events to export. - /// - endDate: The end date for the critical events to export. Optional. If not specified, default to now. - /// - Returns: An progress total unit count, or an error. - func exportProgressTotalUnitCount(startDate: Date, endDate: Date?) -> Result - - /// Export the critical event log for the specified date range. - /// - /// - Parameters: - /// - startDate: The start date for the critical events to export. - /// - endDate: The end date for the critical events to export. - /// - stream: The output stream to write the critical event log to. Typically writes JSON UTF-8 text. - /// - progressor: The estimated duration progress to use to check if cancelled and report progress. - /// - Returns: Any error that occurs during the export, or nil if successful. - func export(startDate: Date, endDate: Date, to stream: OutputStream, progress: Progress) -> Error? -} - -public enum CriticalEventLogError: Error { - - /// The export was cancelled either by the user or the OS. - case cancelled -} - -public let criticalEventLogExportProgressUnitCountPerFetch: Int64 = 250 diff --git a/Dependencies/LoopKit/LoopKit/DailyQuantitySchedule+Override.swift b/Dependencies/LoopKit/LoopKit/DailyQuantitySchedule+Override.swift deleted file mode 100644 index 7af3abea2..000000000 --- a/Dependencies/LoopKit/LoopKit/DailyQuantitySchedule+Override.swift +++ /dev/null @@ -1,180 +0,0 @@ -// -// DailyQuantitySchedule+Override.swift -// LoopKit -// -// Created by Michael Pangburn on 3/26/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import HealthKit - - -extension GlucoseRangeSchedule { - public func applyingOverride(_ override: TemporaryScheduleOverride) -> GlucoseRangeSchedule { - guard let targetRange = override.settings.targetRange else { - return self - } - - let doubleRange = targetRange.doubleRange(for: unit) - let rangeOverride = GlucoseRangeSchedule.Override(value: doubleRange, start: override.startDate, end: override.scheduledEndDate) - return GlucoseRangeSchedule(rangeSchedule: rangeSchedule, override: rangeOverride) - } -} - -extension /* BasalRateSchedule */ DailyValueSchedule where T == Double { - func applyingBasalRateMultiplier( - from override: TemporaryScheduleOverride, - relativeTo date: Date = Date() - ) -> BasalRateSchedule { - return applyingOverride(override, relativeTo: date, multiplier: \.basalRateMultiplier) - } -} - -extension /* InsulinSensitivitySchedule */ DailyQuantitySchedule where T == Double { - func applyingSensitivityMultiplier( - from override: TemporaryScheduleOverride, - relativeTo date: Date = Date() - ) -> InsulinSensitivitySchedule { - return DailyQuantitySchedule( - unit: unit, - valueSchedule: valueSchedule.applyingOverride( - override, - relativeTo: date, - multiplier: \.insulinSensitivityMultiplier - ) - ) - } -} - -extension /* CarbRatioSchedule */ DailyQuantitySchedule where T == Double { - func applyingCarbRatioMultiplier( - from override: TemporaryScheduleOverride, - relativeTo date: Date = Date() - ) -> CarbRatioSchedule { - return DailyQuantitySchedule( - unit: unit, - valueSchedule: valueSchedule.applyingOverride( - override, - relativeTo: date, - multiplier: \.carbRatioMultiplier - ) - ) - } -} - -extension DailyValueSchedule where T == Double { - fileprivate func applyingOverride( - _ override: TemporaryScheduleOverride, - relativeTo date: Date, - multiplier multiplierKeyPath: KeyPath - ) -> DailyValueSchedule { - guard let multiplier = override.settings[keyPath: multiplierKeyPath] else { - return self - } - return applyingOverride( - during: override.activeInterval, - relativeTo: date, - updatingOverridenValuesWith: { $0 * multiplier } - ) - } -} - -extension DailyValueSchedule { - fileprivate func applyingOverride( - during activeInterval: DateInterval, - relativeTo referenceDate: Date, - updatingOverridenValuesWith update: (T) -> T - ) -> DailyValueSchedule { - guard let activeInterval = clampingToAffectedInterval(activeInterval, relativeTo: referenceDate) else { - // Override has no effect relative to the reference date - return self - } - - let overrideStartOffset = scheduleOffset(for: activeInterval.start) - let overrideEndOffset = scheduleOffset(for: activeInterval.end) - guard overrideStartOffset != overrideEndOffset else { - // Full schedule overridden - return DailyValueSchedule( - dailyItems: items.map { item in RepeatingScheduleValue(startTime: item.startTime, value: update(item.value)) }, - timeZone: timeZone - )! - } - - let overrideCrossesMidnight = overrideStartOffset > overrideEndOffset - let scheduleItemsIncludingOverride = scheduleItemsPaddedToClosedInterval - .adjacentPairs() - .flatMap { item, nextItem -> [RepeatingScheduleValue] in - let overriddenItemValue = update(item.value) - let overriddenItem = RepeatingScheduleValue(startTime: item.startTime, value: overriddenItemValue) - let overrideStart = RepeatingScheduleValue(startTime: overrideStartOffset, value: overriddenItemValue) - let overrideEnd = RepeatingScheduleValue(startTime: overrideEndOffset, value: item.value) - - let scheduleItemInterval = item.startTime.. DateInterval? { - let relevantPeriodStart = referenceDate.addingTimeInterval(-repeatInterval) - let relevantPeriodEnd = referenceDate.addingTimeInterval(repeatInterval) - - guard - interval.end > relevantPeriodStart, - interval.start < relevantPeriodEnd - else { - return nil - } - - let startDate = max(interval.start, relevantPeriodStart) - let endDate = min(interval.end, relevantPeriodEnd) - let affectedInterval = DateInterval(start: startDate, end: endDate) - return affectedInterval - } - - /// Pads the schedule with an extra item to form a closed interval. - private var scheduleItemsPaddedToClosedInterval: [RepeatingScheduleValue] { - guard let lastItem = items.last else { - assertionFailure("Schedule can never be empty") - return [] - } - let lastItemStartingAtDayEnd = RepeatingScheduleValue(startTime: maxTimeInterval, value: lastItem.value) - return items + [lastItemStartingAtDayEnd] - } -} - diff --git a/Dependencies/LoopKit/LoopKit/DailyQuantitySchedule.swift b/Dependencies/LoopKit/LoopKit/DailyQuantitySchedule.swift deleted file mode 100644 index ccb51d368..000000000 --- a/Dependencies/LoopKit/LoopKit/DailyQuantitySchedule.swift +++ /dev/null @@ -1,203 +0,0 @@ -// -// DailyQuantitySchedule.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/12/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -public struct DailyQuantitySchedule: DailySchedule { - public typealias RawValue = [String: Any] - public let unit: HKUnit - var valueSchedule: DailyValueSchedule - - public init?(unit: HKUnit, dailyItems: [RepeatingScheduleValue], timeZone: TimeZone? = nil) { - guard let valueSchedule = DailyValueSchedule(dailyItems: dailyItems, timeZone: timeZone) else { - return nil - } - - self.unit = unit - self.valueSchedule = valueSchedule - } - - init(unit: HKUnit, valueSchedule: DailyValueSchedule) { - self.unit = unit - self.valueSchedule = valueSchedule - } - - public init?(rawValue: RawValue) { - guard let rawUnit = rawValue["unit"] as? String, - let valueSchedule = DailyValueSchedule(rawValue: rawValue) - else - { - return nil - } - - self.unit = HKUnit(from: rawUnit) - self.valueSchedule = valueSchedule - } - - public var items: [RepeatingScheduleValue] { - return valueSchedule.items - } - - public var timeZone: TimeZone { - get { - return valueSchedule.timeZone - } - set { - valueSchedule.timeZone = newValue - } - } - - public var rawValue: RawValue { - var rawValue = valueSchedule.rawValue - - rawValue["unit"] = unit.unitString - - return rawValue - } - - public func between(start startDate: Date, end endDate: Date) -> [AbsoluteScheduleValue] { - return valueSchedule.between(start: startDate, end: endDate) - } - - public func value(at time: Date) -> T { - return valueSchedule.value(at: time) - } -} - -extension DailyQuantitySchedule: Codable where T: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.unit = HKUnit(from: try container.decode(String.self, forKey: .unit)) - self.valueSchedule = try container.decode(DailyValueSchedule.self, forKey: .valueSchedule) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(unit.unitString, forKey: .unit) - try container.encode(valueSchedule, forKey: .valueSchedule) - } - - private enum CodingKeys: String, CodingKey { - case unit - case valueSchedule - } -} - -extension DailyQuantitySchedule: CustomDebugStringConvertible { - public var debugDescription: String { - return String(reflecting: rawValue) - } -} - - -public typealias SingleQuantitySchedule = DailyQuantitySchedule - - -public extension DailyQuantitySchedule where T == Double { - func quantity(at time: Date) -> HKQuantity { - return HKQuantity(unit: unit, doubleValue: valueSchedule.value(at: time)) - } - - func averageValue() -> Double { - var total: Double = 0 - - for (index, item) in valueSchedule.items.enumerated() { - var endTime = valueSchedule.maxTimeInterval - - if index < valueSchedule.items.endIndex - 1 { - endTime = valueSchedule.items[index + 1].startTime - } - - total += (endTime - item.startTime) * item.value - } - - return total / valueSchedule.repeatInterval - } - - func averageQuantity() -> HKQuantity { - return HKQuantity(unit: unit, doubleValue: averageValue()) - } - - func lowestValue() -> Double? { - return valueSchedule.items.min(by: { $0.value < $1.value } )?.value - } - - var quantities: [RepeatingScheduleValue] { - return self.items.map { - RepeatingScheduleValue(startTime: $0.startTime, - value: HKQuantity(unit: unit, doubleValue: $0.value)) - } - } - - func quantities(using unit: HKUnit) -> [RepeatingScheduleValue] { - return self.items.map { - RepeatingScheduleValue(startTime: $0.startTime, - value: HKQuantity(unit: unit, doubleValue: $0.value)) - } - } - - init?(unit: HKUnit, - dailyQuantities: [RepeatingScheduleValue], - timeZone: TimeZone? = nil) - { - guard let valueSchedule = DailyValueSchedule( - dailyItems: dailyQuantities.map { - RepeatingScheduleValue(startTime: $0.startTime, value: $0.value.doubleValue(for: unit)) - }, - timeZone: timeZone) else - { - return nil - } - - self.unit = unit - self.valueSchedule = valueSchedule - } -} - -public extension DailyQuantitySchedule where T == DoubleRange { - init?(unit: HKUnit, - dailyQuantities: [RepeatingScheduleValue>], - timeZone: TimeZone? = nil) - { - guard let valueSchedule = DailyValueSchedule( - dailyItems: dailyQuantities.map { - RepeatingScheduleValue(startTime: $0.startTime, value: $0.value.doubleRange(for: unit)) - }, - timeZone: timeZone) else - { - return nil - } - - self.unit = unit - self.valueSchedule = valueSchedule - } -} - -extension DailyQuantitySchedule: Equatable where T: Equatable { - public static func == (lhs: DailyQuantitySchedule, rhs: DailyQuantitySchedule) -> Bool { - return lhs.valueSchedule == rhs.valueSchedule && lhs.unit.unitString == rhs.unit.unitString - } -} - -extension DailyQuantitySchedule where T: Numeric { - public static func * (lhs: DailyQuantitySchedule, rhs: DailyQuantitySchedule) -> DailyQuantitySchedule { - let unit = lhs.unit.unitMultiplied(by: rhs.unit) - let schedule = DailyValueSchedule.zip(lhs.valueSchedule, rhs.valueSchedule).map(*) - return DailyQuantitySchedule(unit: unit, valueSchedule: schedule) - } -} - -extension DailyQuantitySchedule where T: FloatingPoint { - public static func / (lhs: DailyQuantitySchedule, rhs: DailyQuantitySchedule) -> DailyQuantitySchedule { - let unit = lhs.unit.unitDivided(by: rhs.unit) - let schedule = DailyValueSchedule.zip(lhs.valueSchedule, rhs.valueSchedule).map(/) - return DailyQuantitySchedule(unit: unit, valueSchedule: schedule) - } -} diff --git a/Dependencies/LoopKit/LoopKit/DailyValueSchedule.swift b/Dependencies/LoopKit/LoopKit/DailyValueSchedule.swift deleted file mode 100644 index 2438261d5..000000000 --- a/Dependencies/LoopKit/LoopKit/DailyValueSchedule.swift +++ /dev/null @@ -1,275 +0,0 @@ -// -// QuantitySchedule.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/18/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -public struct RepeatingScheduleValue { - public var startTime: TimeInterval - public var value: T - - public init(startTime: TimeInterval, value: T) { - self.startTime = startTime - self.value = value - } - - public func map(_ transform: (T) -> U) -> RepeatingScheduleValue { - return RepeatingScheduleValue(startTime: startTime, value: transform(value)) - } -} - -extension RepeatingScheduleValue: Equatable where T: Equatable { - public static func == (lhs: RepeatingScheduleValue, rhs: RepeatingScheduleValue) -> Bool { - return abs(lhs.startTime - rhs.startTime) < .ulpOfOne && lhs.value == rhs.value - } -} - -extension RepeatingScheduleValue: Hashable where T: Hashable {} - -public struct AbsoluteScheduleValue: TimelineValue { - public let startDate: Date - public let endDate: Date - public let value: T -} - -extension AbsoluteScheduleValue: Equatable where T: Equatable {} - -extension RepeatingScheduleValue: RawRepresentable where T: RawRepresentable { - public typealias RawValue = [String: Any] - - public init?(rawValue: RawValue) { - guard let startTime = rawValue["startTime"] as? Double, - let rawValue = rawValue["value"] as? T.RawValue, - let value = T(rawValue: rawValue) else - { - return nil - } - - self.init(startTime: startTime, value: value) - } - - public var rawValue: RawValue { - return [ - "startTime": startTime, - "value": value.rawValue - ] - } -} - -extension RepeatingScheduleValue: Codable where T: Codable {} - -public protocol DailySchedule { - associatedtype T - - var items: [RepeatingScheduleValue] { get } - - var timeZone: TimeZone { get set } - - func between(start startDate: Date, end endDate: Date) -> [AbsoluteScheduleValue] - - func value(at time: Date) -> T -} - - -public extension DailySchedule { - func value(at time: Date) -> T { - return between(start: time, end: time).first!.value - } -} - -extension DailySchedule where T: Comparable { - public func valueRange() -> ClosedRange { - items.range(of: { $0.value })! - } -} - -public struct DailyValueSchedule: DailySchedule { - let referenceTimeInterval: TimeInterval - let repeatInterval: TimeInterval - - public let items: [RepeatingScheduleValue] - public var timeZone: TimeZone - - public init?(dailyItems: [RepeatingScheduleValue], timeZone: TimeZone? = nil) { - self.repeatInterval = TimeInterval(hours: 24) - self.items = dailyItems.sorted { $0.startTime < $1.startTime } - self.timeZone = timeZone ?? TimeZone.currentFixed - - guard let firstItem = self.items.first else { - return nil - } - - referenceTimeInterval = firstItem.startTime - } - - var maxTimeInterval: TimeInterval { - return referenceTimeInterval + repeatInterval - } - - /** - Returns the time interval for a given date normalized to the span of the schedule items - - - parameter date: The date to convert - */ - func scheduleOffset(for date: Date) -> TimeInterval { - // The time interval since a reference date in the specified time zone - let interval = date.timeIntervalSinceReferenceDate + TimeInterval(timeZone.secondsFromGMT(for: date)) - - // The offset of the time interval since the last occurence of the reference time + n * repeatIntervals. - // If the repeat interval was 1 day, this is the fractional amount of time since the most recent repeat interval starting at the reference time - return ((interval - referenceTimeInterval).truncatingRemainder(dividingBy: repeatInterval)) + referenceTimeInterval - } - - /** - Returns a slice of schedule items that occur between two dates - - - parameter startDate: The start date of the range - - parameter endDate: The end date of the range - - - returns: A slice of `ScheduleItem` values - */ - public func between(start startDate: Date, end endDate: Date) -> [AbsoluteScheduleValue] { - guard startDate <= endDate else { - return [] - } - - let startOffset = scheduleOffset(for: startDate) - let endOffset = startOffset + endDate.timeIntervalSince(startDate) - - guard endOffset <= maxTimeInterval else { - let boundaryDate = startDate.addingTimeInterval(maxTimeInterval - startOffset) - - return between(start: startDate, end: boundaryDate) + between(start: boundaryDate, end: endDate) - } - - var startIndex = 0 - var endIndex = items.count - - for (index, item) in items.enumerated() { - if startOffset >= item.startTime { - startIndex = index - } - if endOffset < item.startTime { - endIndex = index - break - } - } - - let referenceDate = startDate.addingTimeInterval(-startOffset) - - return (startIndex..(_ transform: (T) -> U) -> DailyValueSchedule { - return DailyValueSchedule( - dailyItems: items.map { $0.map(transform) }, - timeZone: timeZone - )! - } - - public static func zip(_ lhs: DailyValueSchedule, _ rhs: DailyValueSchedule) -> DailyValueSchedule where T == (L, R) { - precondition(lhs.timeZone == rhs.timeZone) - - var (leftCursor, rightCursor) = (lhs.items.startIndex, rhs.items.startIndex) - var alignedItems: [RepeatingScheduleValue<(L, R)>] = [] - repeat { - let (leftItem, rightItem) = (lhs.items[leftCursor], rhs.items[rightCursor]) - let alignedItem = RepeatingScheduleValue( - startTime: max(leftItem.startTime, rightItem.startTime), - value: (leftItem.value, rightItem.value) - ) - alignedItems.append(alignedItem) - - let nextLeftStartTime = leftCursor == lhs.items.endIndex - 1 ? nil : lhs.items[leftCursor + 1].startTime - let nextRightStartTime = rightCursor == rhs.items.endIndex - 1 ? nil : rhs.items[rightCursor + 1].startTime - switch (nextLeftStartTime, nextRightStartTime) { - case (.some(let leftStart), .some(let rightStart)): - if leftStart < rightStart { - leftCursor += 1 - } else if rightStart < leftStart { - rightCursor += 1 - } else { - leftCursor += 1 - rightCursor += 1 - } - case (.some, .none): - leftCursor += 1 - case (.none, .some): - rightCursor += 1 - case (.none, .none): - leftCursor += 1 - rightCursor += 1 - } - } while leftCursor < lhs.items.endIndex && rightCursor < rhs.items.endIndex - - return DailyValueSchedule(dailyItems: alignedItems, timeZone: lhs.timeZone)! - } -} - - -extension DailyValueSchedule: RawRepresentable, CustomDebugStringConvertible where T: RawRepresentable { - public typealias RawValue = [String: Any] - public init?(rawValue: RawValue) { - guard let rawItems = rawValue["items"] as? [RepeatingScheduleValue.RawValue] else { - return nil - } - - var timeZone: TimeZone? - - if let offset = rawValue["timeZone"] as? Int { - timeZone = TimeZone(secondsFromGMT: offset) - } - - let validScheduleItems = rawItems.compactMap(RepeatingScheduleValue.init(rawValue:)) - guard validScheduleItems.count == rawItems.count else { - return nil - } - self.init(dailyItems: validScheduleItems, timeZone: timeZone) - } - - public var rawValue: RawValue { - let rawItems = items.map { $0.rawValue } - - return [ - "timeZone": timeZone.secondsFromGMT(), - "items": rawItems - ] - } - - public var debugDescription: String { - return String(reflecting: rawValue) - } -} - -extension DailyValueSchedule: Codable where T: Codable {} - -extension DailyValueSchedule: Equatable where T: Equatable {} - -extension RepeatingScheduleValue { - public static func == (lhs: RepeatingScheduleValue, rhs: RepeatingScheduleValue) -> Bool where T == (L, R) { - return lhs.startTime == rhs.startTime && lhs.value == rhs.value - } -} - -extension DailyValueSchedule { - public static func == (lhs: DailyValueSchedule, rhs: DailyValueSchedule) -> Bool where T == (L, R) { - return lhs.timeZone == rhs.timeZone - && lhs.items.count == rhs.items.count - && Swift.zip(lhs.items, rhs.items).allSatisfy(==) - } -} diff --git a/Dependencies/LoopKit/LoopKit/DeliveryLimits.swift b/Dependencies/LoopKit/LoopKit/DeliveryLimits.swift deleted file mode 100644 index 28a6a591b..000000000 --- a/Dependencies/LoopKit/LoopKit/DeliveryLimits.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// DeliveryLimits.swift -// LoopKit -// -// Created by Rick Pasetto on 7/15/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import HealthKit - -public struct DeliveryLimits: Equatable { - public enum Setting: Equatable { - case maximumBasalRate - case maximumBolus - } - - private var settings: [Setting: HKQuantity] - - public init(maximumBasalRate: HKQuantity?, maximumBolus: HKQuantity?) { - settings = [:] - settings[.maximumBasalRate] = maximumBasalRate - settings[.maximumBolus] = maximumBolus - } - - public var maximumBasalRate: HKQuantity? { - get { settings[.maximumBasalRate] } - set { settings[.maximumBasalRate] = newValue } - } - - public var maximumBolus: HKQuantity? { - get { settings[.maximumBolus] } - set { settings[.maximumBolus] = newValue } - } -} - -public extension DeliveryLimits.Setting { - // The following comes from https://tidepool.atlassian.net/browse/IFU-24 - var title: String { - switch self { - case .maximumBasalRate: - return LocalizedString("Maximum Basal Rate", comment: "Title text for maximum basal rate configuration") - case .maximumBolus: - return LocalizedString("Maximum Bolus", comment: "Title text for maximum bolus configuration") - } - } - - func localizedDescriptiveText(appName: String) -> String { - switch self { - case .maximumBasalRate: - return String(format: LocalizedString("Maximum Basal Rate is the highest temporary basal rate %1$@ is allowed to set.", comment: "Descriptive text for maximum basal rate (1: app name)"), appName) - case .maximumBolus: - return LocalizedString("Maximum Bolus is the highest bolus amount you can deliver at one time to cover carbs or bring down high glucose.", comment: "Descriptive text for maximum bolus") - } - } -} - diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/AlertSoundPlayer.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/AlertSoundPlayer.swift deleted file mode 100644 index e7690b57a..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/AlertSoundPlayer.swift +++ /dev/null @@ -1,101 +0,0 @@ -// -// AlertSoundPlayer.swift -// Loop -// -// Created by Rick Pasetto on 4/27/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -#if os(watchOS) -import WatchKit -#else -import AudioToolbox -#endif -import AVFoundation -import os.log - -public protocol AlertSoundPlayer { - func vibrate() - func play(url: URL) - func stopAll() -} - -public class DeviceAVSoundPlayer: AlertSoundPlayer { - private let log = OSLog(category: "DeviceAVSoundPlayer") - private let baseURL: URL? - private var delegate: Delegate! - private var players = [AVAudioPlayer]() - - @objc class Delegate: NSObject, AVAudioPlayerDelegate { - weak var parent: DeviceAVSoundPlayer? - init(parent: DeviceAVSoundPlayer) { self.parent = parent } - func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { - parent?.players.removeAll { $0 == player } - } - } - - public init(baseURL: URL? = nil) { - self.baseURL = baseURL - self.delegate = Delegate(parent: self) - } - - enum Error: Swift.Error { - case playFailed - } - - public func vibrate() { - #if os(watchOS) - WKInterfaceDevice.current().play(.notification) - #else - AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate)) - #endif - } - - public func play(url: URL) { - DispatchQueue.main.async { - do { - let soundEffect = try AVAudioPlayer(contentsOf: url) - soundEffect.delegate = self.delegate - // The AVAudioPlayer has to remain around until the sound completes playing, which is why we hold - // onto it until it completes. - self.players.append(soundEffect) - if !soundEffect.play() { - self.log.default("couldn't play sound (app may be in the background): %@", url.absoluteString) - } - } catch { - self.log.error("couldn't play sound %@: %@", url.absoluteString, String(describing: error)) - } - } - } - - public func stopAll() { - DispatchQueue.main.async { - for soundEffect in self.players { - soundEffect.stop() - } - } - } -} - -public extension DeviceAVSoundPlayer { - - func playAlert(sound: Alert.Sound) { - switch sound { - case .vibrate: - vibrate() - default: - if let baseURL = baseURL { - if let name = sound.filename { - self.stopAll() - self.play(url: baseURL.appendingPathComponent(name)) - } else { - log.default("No file to play for %@", "\(sound)") - vibrate() - } - } else { - log.error("No base URL, could not play %@", sound.filename ?? "") - vibrate() - } - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/CGMManager.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/CGMManager.swift deleted file mode 100644 index d39786bba..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/CGMManager.swift +++ /dev/null @@ -1,193 +0,0 @@ -// -// CGMManager.swift -// Loop -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import HealthKit - -/// Describes the result of CGM manager operations to fetch and report sensor readings. -/// -/// - noData: No new data was available or retrieved -/// - unreliableData: New glucose data was received, but is not reliable enough to use for therapy -/// - newData: New glucose data was received and stored -/// - error: An error occurred while receiving or store data -public enum CGMReadingResult { - case noData - case unreliableData - case newData([NewGlucoseSample]) - case error(Error) -} - -public struct CGMManagerStatus: Equatable { - // Return false if no sensor active, or in a state where no future data is expected without user intervention - public var hasValidSensorSession: Bool - - public var lastCommunicationDate: Date? - - public var device: HKDevice? - - public init(hasValidSensorSession: Bool, lastCommunicationDate: Date? = nil, device: HKDevice?) { - self.hasValidSensorSession = hasValidSensorSession - self.lastCommunicationDate = lastCommunicationDate - self.device = device - } -} - -extension CGMManagerStatus: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.hasValidSensorSession = try container.decode(Bool.self, forKey: .hasValidSensorSession) - self.lastCommunicationDate = try container.decodeIfPresent(Date.self, forKey: .lastCommunicationDate) - self.device = try container.decodeIfPresent(CodableDevice.self, forKey: .device)?.device - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(hasValidSensorSession, forKey: .hasValidSensorSession) - try container.encodeIfPresent(lastCommunicationDate, forKey: .lastCommunicationDate) - try container.encodeIfPresent(device.map { CodableDevice($0) }, forKey: .device) - } - - private enum CodingKeys: String, CodingKey { - case hasValidSensorSession - case lastCommunicationDate - case device - } -} - -public protocol CGMManagerStatusObserver: AnyObject { - /// Notifies observers of changes in CGMManagerStatus - /// - /// - Parameter manager: The manager instance - /// - Parameter status: The new, updated status. Status includes properties associated with the manager, transmitter, or sensor, - /// that are not part of an individual sensor reading. - func cgmManager(_ manager: CGMManager, didUpdate status: CGMManagerStatus) -} - -public protocol CGMManagerDelegate: DeviceManagerDelegate, CGMManagerStatusObserver { - /// Asks the delegate for a date with which to filter incoming glucose data - /// - /// - Parameter manager: The manager instance - /// - Returns: The date data occuring on or after which should be kept - func startDateToFilterNewData(for manager: CGMManager) -> Date? - - /// Informs the delegate that the device has updated with a new result - /// - /// - Parameters: - /// - manager: The manager instance - /// - result: The result of the update - func cgmManager(_ manager: CGMManager, hasNew readingResult: CGMReadingResult) -> Void - - /// Informs the delegate that the manager is deactivating and should be deleted - /// - /// - Parameter manager: The manager instance - func cgmManagerWantsDeletion(_ manager: CGMManager) - - /// Informs the delegate that the manager has updated its state and should be persisted. - /// - /// - Parameter manager: The manager instance - func cgmManagerDidUpdateState(_ manager: CGMManager) - - /// Asks the delegate for credential store prefix to avoid namespace conflicts - /// - /// - Parameter manager: The manager instance - /// - Returns: The unique prefix for the credential store - func credentialStoragePrefix(for manager: CGMManager) -> String -} - - -public protocol CGMManager: DeviceManager { - var cgmManagerDelegate: CGMManagerDelegate? { get set } - - var appURL: URL? { get } - - /// Whether the device is capable of waking the app - var providesBLEHeartbeat: Bool { get } - - /// The length of time to keep samples in HealthKit before removal. Return nil to never remove samples. - var managedDataInterval: TimeInterval? { get } - - /// The length of time to delay until storing samples into HealthKit. Return 0 for no delay. - static var healthKitStorageDelay: TimeInterval { get } - - var shouldSyncToRemoteService: Bool { get } - - var glucoseDisplay: GlucoseDisplayable? { get } - - /// The current status of the cgm manager - var cgmManagerStatus: CGMManagerStatus { get } - - /// The queue on which CGMManagerDelegate methods are called - /// Setting to nil resets to a default provided by the manager - var delegateQueue: DispatchQueue! { get set } - - - /// Implementations of this function must call the `completion` block, with the appropriate `CGMReadingResult` - /// according to the current available data. - /// - If there is new unreliable data, return `.unreliableData` - /// - If there is no new data and the current data is unreliable, return `.unreliableData` - /// - If there is new reliable data, return `.newData` with the data samples - /// - If there is no new data and the current data is reliable, return `.noData` - /// - If there is an error, return `.error` with the appropriate error. - /// - /// - Parameters: - /// - completion: A closure called when operation has completed - func fetchNewDataIfNeeded(_ completion: @escaping (CGMReadingResult) -> Void) -> Void - - /// Adds an observer of changes in CGMManagerStatus - /// - /// Observers are held by weak reference. - /// - /// - Parameters: - /// - observer: The observing object - /// - queue: The queue on which the observer methods should be called - func addStatusObserver(_ observer: CGMManagerStatusObserver, queue: DispatchQueue) - - /// Removes an observer of changes in CGMManagerStatus - /// - /// Since observers are held weakly, calling this method is not required when the observer is deallocated - /// - /// - Parameter observer: The observing object - func removeStatusObserver(_ observer: CGMManagerStatusObserver) - - /// Requests that the manager completes its deletion process - /// - /// - Parameter completion: Action to take after the CGM manager is deleted - func delete(completion: @escaping () -> Void) -} - - -public extension CGMManager { - var appURL: URL? { - return nil - } - - /// Default is no delay to store samples in HealthKit - static var healthKitStorageDelay: TimeInterval { 0 } - - /// Convenience wrapper for notifying the delegate of deletion on the delegate queue - /// - /// - Parameters: - /// - completion: A closure called from the delegate queue after the delegate is called - func notifyDelegateOfDeletion(completion: @escaping () -> Void) { - delegateQueue.async { - self.cgmManagerDelegate?.cgmManagerWantsDeletion(self) - completion() - } - } - - func addStatusObserver(_ observer: CGMManagerStatusObserver, queue: DispatchQueue) { - // optional since a CGM manager may not support status observers - } - - func removeStatusObserver(_ observer: CGMManagerStatusObserver) { - // optional since a CGM manager may not support status observers - } - - /// Override this default behaviour if the CGM Manager needs to complete tasks before being deleted - func delete(completion: @escaping () -> Void) { - notifyDelegateOfDeletion(completion: completion) - } -} diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/CodableDevice.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/CodableDevice.swift deleted file mode 100644 index 137b6a974..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/CodableDevice.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// CodableDevice.swift -// LoopKit -// -// Created by Darin Krauss on 10/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import HealthKit - -struct CodableDevice: Codable { - let name: String? - let manufacturer: String? - let model: String? - let hardwareVersion: String? - let firmwareVersion: String? - let softwareVersion: String? - let localIdentifier: String? - let udiDeviceIdentifier: String? - - init(_ device: HKDevice) { - self.name = device.name - self.manufacturer = device.manufacturer - self.model = device.model - self.hardwareVersion = device.hardwareVersion - self.firmwareVersion = device.firmwareVersion - self.softwareVersion = device.softwareVersion - self.localIdentifier = device.localIdentifier - self.udiDeviceIdentifier = device.udiDeviceIdentifier - } - - var device: HKDevice { - return HKDevice(name: name, - manufacturer: manufacturer, - model: model, - hardwareVersion: hardwareVersion, - firmwareVersion: firmwareVersion, - softwareVersion: softwareVersion, - localIdentifier: localIdentifier, - udiDeviceIdentifier: udiDeviceIdentifier) - } -} - diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLifecycleProgress.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLifecycleProgress.swift deleted file mode 100644 index eab257ee1..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLifecycleProgress.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// DeviceLifecycleProgress.swift -// LoopKit -// -// Created by Nathaniel Hamming on 2020-06-30. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - -public protocol DeviceLifecycleProgress { - /// the percent complete of the progress for this device status. Expects a value between 0.0 and 1.0 - var percentComplete: Double { get } - - /// the status of the progress to provide guidance as to how to present the progress - var progressState: DeviceLifecycleProgressState { get } -} - -public enum DeviceLifecycleProgressState: String, Codable { - case critical - case dimmed - case normalCGM - case normalPump - case warning -} diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/DeviceLog.xcdatamodeld/DeviceCommsLog.xcdatamodel/contents b/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/DeviceLog.xcdatamodeld/DeviceCommsLog.xcdatamodel/contents deleted file mode 100644 index 248bf13ab..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/DeviceLog.xcdatamodeld/DeviceCommsLog.xcdatamodel/contents +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/DeviceLogEntry+CoreDataClass.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/DeviceLogEntry+CoreDataClass.swift deleted file mode 100644 index bfb36b975..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/DeviceLogEntry+CoreDataClass.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// DeviceLogEntry+CoreDataClass.swift -// LoopKit -// -// Created by Pete Schwamb on 1/13/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// -// - -import Foundation -import CoreData - -class DeviceLogEntry: NSManagedObject { - - var type: DeviceLogEntryType? { - get { - willAccessValue(forKey: "type") - defer { didAccessValue(forKey: "type") } - guard let primitiveType = primitiveType else { - return nil - } - return DeviceLogEntryType(rawValue: primitiveType) - } - set { - willChangeValue(forKey: "type") - defer { didChangeValue(forKey: "type") } - primitiveType = newValue?.rawValue - } - } - - var hasUpdatedModificationCounter: Bool { changedValues().keys.contains("modificationCounter") } - - func updateModificationCounter() { setPrimitiveValue(managedObjectContext!.modificationCounter!, forKey: "modificationCounter") } - - override func awakeFromInsert() { - super.awakeFromInsert() - updateModificationCounter() - } - - override func willSave() { - if isUpdated && !hasUpdatedModificationCounter { - updateModificationCounter() - } - super.willSave() - } -} diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/DeviceLogEntry+CoreDataProperties.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/DeviceLogEntry+CoreDataProperties.swift deleted file mode 100644 index 8174d694e..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/DeviceLogEntry+CoreDataProperties.swift +++ /dev/null @@ -1,58 +0,0 @@ -// -// DeviceLogEntry+CoreDataProperties.swift -// LoopKit -// -// Created by Pete Schwamb on 1/13/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// -// - -import Foundation -import CoreData - - -extension DeviceLogEntry { - - @nonobjc public class func fetchRequest() -> NSFetchRequest { - return NSFetchRequest(entityName: "Entry") - } - - @NSManaged public var primitiveType: String? - @NSManaged public var managerIdentifier: String? - @NSManaged public var deviceIdentifier: String? - @NSManaged public var message: String? - @NSManaged public var timestamp: Date? - @NSManaged public var modificationCounter: Int64 - -} - -extension DeviceLogEntry: Encodable { - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encodeIfPresent(type?.rawValue, forKey: .type) - try container.encodeIfPresent(managerIdentifier, forKey: .managerIdentifier) - try container.encodeIfPresent(deviceIdentifier, forKey: .deviceIdentifier) - try container.encodeIfPresent(message, forKey: .message) - try container.encodeIfPresent(timestamp, forKey: .timestamp) - try container.encode(modificationCounter, forKey: .modificationCounter) - } - - private enum CodingKeys: String, CodingKey { - case type - case managerIdentifier - case deviceIdentifier - case message - case timestamp - case modificationCounter - } -} - -extension DeviceLogEntry { - func update(from entry: StoredDeviceLogEntry) { - type = entry.type - managerIdentifier = entry.managerIdentifier - deviceIdentifier = entry.deviceIdentifier - message = entry.message - timestamp = entry.timestamp - } -} diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/DeviceLogEntryType.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/DeviceLogEntryType.swift deleted file mode 100644 index 04d6b0ab8..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/DeviceLogEntryType.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// DeviceLogEntryType.swift -// LoopKit -// -// Created by Pete Schwamb on 1/13/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum DeviceLogEntryType: String { - /// Log entry related to data or commands sent to the device. - case send - /// Log entry related to data or events received from the device. - case receive - /// Log entry related to any errors from the device's SDK or the device itself. - case error - /// Log entry related to a delegate call from the device's SDK (for example, acknowledgement of receiving a command). - case delegate - /// Log entry related to a response from a delegate call (for example, acknowledgement of executing a command). - case delegateResponse - /// Log entry related to any device connection activities (e.g. scanning, connecting, disconnecting, reconnecting, etc.). - case connection -} diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/PersistentDeviceLog.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/PersistentDeviceLog.swift deleted file mode 100644 index 8875b7d46..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/PersistentDeviceLog.swift +++ /dev/null @@ -1,239 +0,0 @@ -// -// PersistentDeviceLog.swift -// LoopKit -// -// Created by Pete Schwamb on 1/13/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation -import CoreData -import os.log - - -// Using a framework specific class will search the framework's bundle for model files. -class PersistentContainer: NSPersistentContainer { } - -public class PersistentDeviceLog { - - private let storageFile: URL - - private let managedObjectContext: NSManagedObjectContext - - private let persistentContainer: NSPersistentContainer - - private let maxEntryAge: TimeInterval - - public var earliestLogEntryDate: Date { - return Date(timeIntervalSinceNow: -maxEntryAge) - } - - private let log = OSLog(category: "PersistentDeviceLog") - - public init(storageFile: URL, maxEntryAge: TimeInterval = TimeInterval(7 * 24 * 60 * 60)) { - self.storageFile = storageFile - self.maxEntryAge = maxEntryAge - - managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) - managedObjectContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy - managedObjectContext.automaticallyMergesChangesFromParent = true - - let storeDescription = NSPersistentStoreDescription(url: storageFile) - persistentContainer = PersistentContainer(name: "DeviceLog") - persistentContainer.persistentStoreDescriptions = [storeDescription] - persistentContainer.loadPersistentStores { description, error in - if let error = error { - fatalError("Unable to load persistent stores: \(error)") - } - } - managedObjectContext.persistentStoreCoordinator = persistentContainer.persistentStoreCoordinator - } - - public func log(managerIdentifier: String, deviceIdentifier: String?, type: DeviceLogEntryType, message: String, completion: ((Error?) -> Void)? = nil) { - // Grab timestamp at time of log, in case managedObjectContext is busy - let timestamp = Date() - - managedObjectContext.perform { - let entry = DeviceLogEntry(context: self.managedObjectContext) - entry.managerIdentifier = managerIdentifier - entry.deviceIdentifier = deviceIdentifier - entry.type = type - entry.message = message - entry.timestamp = timestamp - do { - try self.managedObjectContext.save() - if type == .error { - self.log.error("%{public}@ (%{public}@) %{public}@", String(describing: type), deviceIdentifier ?? "", message) - } else { - self.log.default("%{public}@ (%{public}@) %{public}@", String(describing: type), deviceIdentifier ?? "", message) - } - completion?(nil) - } catch let error { - self.log.error("Could not store device log entry %{public}@", String(describing: error)) - completion?(error) - } - } - } - - public func getLogEntries(startDate: Date, endDate: Date? = nil, completion: @escaping (_ result: Result<[StoredDeviceLogEntry], Error>) -> Void) { - - managedObjectContext.perform { - var predicate: NSPredicate = NSPredicate(format: "timestamp >= %@", startDate as NSDate) - if let endDate = endDate { - let endFilter = NSPredicate(format: "timestamp < %@", endDate as NSDate) - predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, endFilter]) - } - - let request: NSFetchRequest = DeviceLogEntry.fetchRequest() - request.predicate = predicate - request.sortDescriptors = [NSSortDescriptor(key: "timestamp", ascending: true)] - - do { - let entries = try self.managedObjectContext.fetch(request) - completion(.success(entries.map { StoredDeviceLogEntry(managedObject: $0) } )) - self.purgeExpiredLogEntries() - } catch let error { - completion(.failure(error)) - } - } - } - - // Should only be called from managed object context queue - private func purgeExpiredLogEntries() { - let predicate = NSPredicate(format: "timestamp < %@", earliestLogEntryDate as NSDate) - - do { - let fetchRequest: NSFetchRequest = DeviceLogEntry.fetchRequest() - fetchRequest.predicate = predicate - let count = try managedObjectContext.deleteObjects(matching: fetchRequest) - log.info("Deleted %d DeviceLogEntries", count) - } catch let error { - log.error("Could not purge expired log entry %{public}@", String(describing: error)) - } - } - - public func purgeLogEntries(before date: Date, completion: ((Error?) -> Void)? = nil) { - var purgeError: Error? - - managedObjectContext.performAndWait { - do { - let count = try managedObjectContext.purgeObjects(of: DeviceLogEntry.self, matching: NSPredicate(format: "timestamp < %@", date as NSDate)) - log.info("Purged %d DeviceLogEntries", count) - } catch let error { - log.error("Unable to purge DeviceLogEntries: %{public}@", String(describing: error)) - purgeError = error - } - } - - completion?(purgeError) - } -} - -// MARK: - Critical Event Log Export - -extension PersistentDeviceLog: CriticalEventLog { - private var exportProgressUnitCountPerObject: Int64 { 1 } - private var exportFetchLimit: Int { Int(criticalEventLogExportProgressUnitCountPerFetch / exportProgressUnitCountPerObject) } - - public var exportName: String { "DeviceLog.json" } - - public func exportProgressTotalUnitCount(startDate: Date, endDate: Date? = nil) -> Result { - var result: Result? - - self.managedObjectContext.performAndWait { - do { - let request: NSFetchRequest = DeviceLogEntry.fetchRequest() - request.predicate = self.exportDatePredicate(startDate: startDate, endDate: endDate) - - let objectCount = try self.managedObjectContext.count(for: request) - result = .success(Int64(objectCount) * exportProgressUnitCountPerObject) - } catch let error { - result = .failure(error) - } - } - - return result! - } - - public func export(startDate: Date, endDate: Date, to stream: OutputStream, progress: Progress) -> Error? { - let encoder = JSONStreamEncoder(stream: stream) - var modificationCounter: Int64 = 0 - var fetching = true - var error: Error? - - while fetching && error == nil { - self.managedObjectContext.performAndWait { - do { - guard !progress.isCancelled else { - throw CriticalEventLogError.cancelled - } - - let request: NSFetchRequest = DeviceLogEntry.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format: "modificationCounter > %d", modificationCounter), - self.exportDatePredicate(startDate: startDate, endDate: endDate)]) - request.sortDescriptors = [NSSortDescriptor(key: "modificationCounter", ascending: true)] - request.fetchLimit = self.exportFetchLimit - - let objects = try self.managedObjectContext.fetch(request) - if objects.isEmpty { - fetching = false - return - } - - try encoder.encode(objects) - - modificationCounter = objects.last!.modificationCounter - - progress.completedUnitCount += Int64(objects.count) * exportProgressUnitCountPerObject - } catch let fetchError { - error = fetchError - } - } - } - - if let closeError = encoder.close(), error == nil { - error = closeError - } - - return error - } - - private func exportDatePredicate(startDate: Date, endDate: Date? = nil) -> NSPredicate { - var predicate = NSPredicate(format: "timestamp >= %@", startDate as NSDate) - if let endDate = endDate { - predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSPredicate(format: "timestamp < %@", endDate as NSDate)]) - } - return predicate - } -} - -// MARK: - Core Data (Bulk) - TEST ONLY - -extension PersistentDeviceLog { - public func addStoredDeviceLogEntries(entries: [StoredDeviceLogEntry]) -> Error? { - guard !entries.isEmpty else { - return nil - } - - var error: Error? - - self.managedObjectContext.performAndWait { - for entry in entries { - let object = DeviceLogEntry(context: self.managedObjectContext) - object.update(from: entry) - } - do { - try self.managedObjectContext.save() - } catch let saveError { - error = saveError - } - } - - guard error == nil else { - return error - } - - self.log.info("Added %d StoredDeviceLogEntries", entries.count) - return nil - } -} diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/StoredDeviceLogEntry.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/StoredDeviceLogEntry.swift deleted file mode 100644 index 186bf0053..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceLog/StoredDeviceLogEntry.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// StoredDeviceLogEntry.swift -// LoopKit -// -// Created by Pete Schwamb on 1/14/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct StoredDeviceLogEntry { - public let type: DeviceLogEntryType - public let managerIdentifier: String - public let deviceIdentifier: String? - public let message: String - public let timestamp: Date - - public init( - type: DeviceLogEntryType, - managerIdentifier: String, - deviceIdentifier: String?, - message: String, - timestamp: Date - ) { - self.type = type - self.managerIdentifier = managerIdentifier - self.deviceIdentifier = deviceIdentifier - self.message = message - self.timestamp = timestamp - } - - - init(managedObject: DeviceLogEntry) { - self.init( - type: managedObject.type!, - managerIdentifier: managedObject.managerIdentifier!, - deviceIdentifier: managedObject.deviceIdentifier, - message: managedObject.message!, - timestamp: managedObject.timestamp! - ) - } -} diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceManager.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceManager.swift deleted file mode 100644 index 761f9f3bc..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceManager.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// DeviceManager.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import UserNotifications - -public protocol DeviceManagerDelegate: AlertIssuer, PersistedAlertStore { - // This will be called from an unspecified queue - func deviceManager(_ manager: DeviceManager, logEventForDeviceIdentifier deviceIdentifier: String?, type: DeviceLogEntryType, message: String, completion: ((Error?) -> Void)?) -} - -public protocol DeviceManager: CustomDebugStringConvertible, AlertResponder, AlertSoundVendor { - typealias RawStateValue = [String: Any] - - /// A unique identifier for this manager - var managerIdentifier: String { get } - - /// A title describing this manager - var localizedTitle: String { get } - - /// Initializes the manager with its previously-saved state - /// - /// Return nil if the saved state is invalid to prevent restoration - /// - /// - Parameter rawState: The last state - init?(rawState: RawStateValue) - - /// The current, serializable state of the manager - var rawState: RawStateValue { get } - - /// Is the device manager onboarded and ready for use? - var isOnboarded: Bool { get } -} diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceStatusHighlight.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceStatusHighlight.swift deleted file mode 100644 index 817f0bdef..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/DeviceStatusHighlight.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// DeviceStatusHighlight.swift -// LoopKit -// -// Created by Nathaniel Hamming on 2020-06-23. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -public protocol DeviceStatusHighlight: Codable { - /// a localized message from the device - var localizedMessage: String { get } - - /// the system name of the icon related to the message - var imageName: String { get } - - /// the state of the status highlight (guides presentation) - var state: DeviceStatusHighlightState { get } -} - -public typealias DeviceStatusHighlightState = DeviceStatusElementState - -public enum DeviceStatusElementState: String, Codable { - case critical - case normalCGM - case normalPump - case warning -} diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/DoseProgressReporter.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/DoseProgressReporter.swift deleted file mode 100644 index a232c3190..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/DoseProgressReporter.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// DoseProgressReporter.swift -// LoopKit -// -// Created by Pete Schwamb on 3/12/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - - -public struct DoseProgress { - public let deliveredUnits: Double - public let percentComplete: Double - - public var isComplete: Bool { - return percentComplete >= 1.0 || fabs(percentComplete - 1.0) <= Double.ulpOfOne - } - - public init(deliveredUnits: Double, percentComplete: Double) { - self.deliveredUnits = deliveredUnits - self.percentComplete = percentComplete - } -} - -public protocol DoseProgressObserver: AnyObject { - func doseProgressReporterDidUpdate(_ doseProgressReporter: DoseProgressReporter) -} - -public protocol DoseProgressReporter: AnyObject { - var progress: DoseProgress { get } - - func addObserver(_ observer: DoseProgressObserver) - - func removeObserver(_ observer: DoseProgressObserver) -} diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/DoseProgressTimerEstimator.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/DoseProgressTimerEstimator.swift deleted file mode 100644 index 406358457..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/DoseProgressTimerEstimator.swift +++ /dev/null @@ -1,94 +0,0 @@ -// -// DoseProgressTimerEstimator.swift -// LoopKit -// -// Created by Pete Schwamb on 3/23/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - - -open class DoseProgressTimerEstimator: DoseProgressReporter { - - private let lock = UnfairLock() - - private var observers = WeakSet() - - var timer: DispatchSourceTimer? - - let reportingQueue: DispatchQueue - - public init(reportingQueue: DispatchQueue) { - self.reportingQueue = reportingQueue - } - - open var progress: DoseProgress { - fatalError("progress must be implemented in subclasse") - } - - public func addObserver(_ observer: DoseProgressObserver) { - lock.withLock { - let firstObserver = observers.isEmpty - observers.insert(observer) - if firstObserver { - start() - } - } - } - - public func removeObserver(_ observer: DoseProgressObserver) { - lock.withLock { - observers.remove(observer) - if observers.isEmpty { - stop() - } - } - } - - public func notify() { - let observersCopy = lock.withLock { observers } - - for observer in observersCopy { - observer.doseProgressReporterDidUpdate(self) - } - - if progress.isComplete { - lock.withLock { stop() } - } - } - - private func start() { - guard self.timer == nil, !progress.isComplete else { - return - } - - let (delay, repeating) = timerParameters() - - let timer = DispatchSource.makeTimerSource(queue: reportingQueue) - timer.schedule(deadline: .now() + delay, repeating: repeating) - timer.setEventHandler(handler: { [weak self] in - self?.notify() - }) - self.timer = timer - timer.resume() - } - - open func timerParameters() -> (delay: TimeInterval, repeating: TimeInterval) { - fatalError("timerParameters must be been implemented in subclasse") - } - - private func stop() { - guard let timer = timer else { - return - } - - timer.setEventHandler {} - timer.cancel() - self.timer = nil - } - - deinit { - lock.withLock { stop() } - } -} diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/PumpManager.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/PumpManager.swift deleted file mode 100644 index 0dab476aa..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/PumpManager.swift +++ /dev/null @@ -1,254 +0,0 @@ -// -// PumpManager.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - -public enum PumpManagerResult { - case success(T) - case failure(PumpManagerError) -} - -public protocol PumpManagerStatusObserver: AnyObject { - func pumpManager(_ pumpManager: PumpManager, didUpdate status: PumpManagerStatus, oldStatus: PumpManagerStatus) -} - -public enum BolusActivationType: String, Codable { - case manualNoRecommendation - case manualRecommendationAccepted - case manualRecommendationChanged - case automatic - - public var isAutomatic: Bool { - self == .automatic - } - - static public func activationTypeFor(recommendedAmount: Double?, bolusAmount: Double) -> BolusActivationType { - guard let recommendedAmount = recommendedAmount else { return .manualNoRecommendation } - return recommendedAmount =~ bolusAmount ? .manualRecommendationAccepted : .manualRecommendationChanged - } -} - -public protocol PumpManagerDelegate: DeviceManagerDelegate, PumpManagerStatusObserver { - func pumpManagerBLEHeartbeatDidFire(_ pumpManager: PumpManager) - - /// Queries the delegate as to whether Loop requires the pump to provide its own periodic scheduling - /// via BLE. - /// This is the companion to `PumpManager.setMustProvideBLEHeartbeat(_:)` - func pumpManagerMustProvideBLEHeartbeat(_ pumpManager: PumpManager) -> Bool - - /// Informs the delegate that the manager is deactivating and should be deleted - func pumpManagerWillDeactivate(_ pumpManager: PumpManager) - - /// Informs the delegate that the hardware this PumpManager has been reporting for has been replaced. - func pumpManagerPumpWasReplaced(_ pumpManager: PumpManager) - - /// Triggered when pump model changes. With a more formalized setup flow (which requires a successful model fetch), - /// this delegate method could go away. - func pumpManager(_ pumpManager: PumpManager, didUpdatePumpRecordsBasalProfileStartEvents pumpRecordsBasalProfileStartEvents: Bool) - - /// Reports an error that should be surfaced to the user - func pumpManager(_ pumpManager: PumpManager, didError error: PumpManagerError) - - /// This should be called any time the PumpManager synchronizes with the pump, even if there are no new doses in the log, as changes to lastReconciliation - /// indicate we can trust insulin delivery status up until that point, even if there are no new doses. - /// For pumps whose only source of dosing adjustments is Loop, lastReconciliation should be reflective of the last time we received telemetry from the pump. - /// For pumps with a user interface and dosing history capabilities, lastReconciliation should be reflective of the last time we reconciled fully with pump history, and know - /// that we have accounted for any external doses. It is possible for the pump to report reservoir data beyond the date of lastReconciliation, and Loop can use it for - /// calculating IOB. - func pumpManager(_ pumpManager: PumpManager, hasNewPumpEvents events: [NewPumpEvent], lastReconciliation: Date?, completion: @escaping (_ error: Error?) -> Void) - - func pumpManager(_ pumpManager: PumpManager, didReadReservoirValue units: Double, at date: Date, completion: @escaping (_ result: Result<(newValue: ReservoirValue, lastValue: ReservoirValue?, areStoredValuesContinuous: Bool), Error>) -> Void) - - func pumpManager(_ pumpManager: PumpManager, didAdjustPumpClockBy adjustment: TimeInterval) - - func pumpManagerDidUpdateState(_ pumpManager: PumpManager) - - func startDateToFilterNewPumpEvents(for manager: PumpManager) -> Date - - /// Indicates the system time offset from a trusted time source. If the return value is added to the system time, the result is the trusted time source value. If the trusted time source is earlier than the system time, the return value is negative. - var detectedSystemTimeOffset: TimeInterval { get } -} - - -public protocol PumpManager: DeviceManager { - /// The maximum number of scheduled basal rates in a single day supported by the pump. Used during onboarding by therapy settings. - static var onboardingMaximumBasalScheduleEntryCount: Int { get } - - /// All user-selectable basal rates, in Units per Hour. Must be non-empty. Used during onboarding by therapy settings. - static var onboardingSupportedBasalRates: [Double] { get } - - /// All user-selectable bolus volumes, in Units. Must be non-empty. Used during onboarding by therapy settings. - static var onboardingSupportedBolusVolumes: [Double] { get } - - /// All user-selectable maximum bolus volumes, in Units. Must be non-empty. Used during onboarding by therapy settings. - static var onboardingSupportedMaximumBolusVolumes: [Double] { get } - - /// The queue on which PumpManagerDelegate methods are called - /// Setting to nil resets to a default provided by the manager - var delegateQueue: DispatchQueue! { get set } - - /// Rounds a basal rate in U/hr to a rate supported by this pump. - /// - /// - Parameters: - /// - unitsPerHour: A desired rate of delivery in Units per Hour - /// - Returns: The rounded rate of delivery in Units per Hour. The rate returned should not be larger than the passed in rate. - func roundToSupportedBasalRate(unitsPerHour: Double) -> Double - - /// Rounds a bolus volume in Units to a volume supported by this pump. - /// - /// - Parameters: - /// - units: A desired volume of delivery in Units - /// - Returns: The rounded bolus volume in Units. The volume returned should not be larger than the passed in rate. - func roundToSupportedBolusVolume(units: Double) -> Double - - /// All user-selectable basal rates, in Units per Hour. Must be non-empty. - var supportedBasalRates: [Double] { get } - - /// All user-selectable bolus volumes, in Units. Must be non-empty. - var supportedBolusVolumes: [Double] { get } - - /// All user-selectable bolus volumes for setting the maximum allowed bolus, in Units. Must be non-empty. - var supportedMaximumBolusVolumes: [Double] { get } - - /// The maximum number of scheduled basal rates in a single day supported by the pump - var maximumBasalScheduleEntryCount: Int { get } - - /// The basal schedule duration increment, beginning at midnight, supported by the pump - var minimumBasalScheduleEntryDuration: TimeInterval { get } - - /// The primary client receiving notifications about the pump lifecycle - /// All delegate methods are called on `delegateQueue` - var pumpManagerDelegate: PumpManagerDelegate? { get set } - - /// Whether the PumpManager provides DoseEntry values for scheduled basal delivery. If false, Loop will use the basal schedule to infer normal basal delivery during times not overridden by: - /// - Temporary basal delivery - /// - Suspend/Resume pairs - /// - Rewind/Prime pairs - var pumpRecordsBasalProfileStartEvents: Bool { get } - - /// The maximum reservoir volume of the pump - var pumpReservoirCapacity: Double { get } - - /// The time of the last sync with the pump's event history, or reservoir, or last status check if pump does not provide history. - var lastSync: Date? { get } - - /// The most-recent status - var status: PumpManagerStatus { get } - - /// Adds an observer of changes in PumpManagerStatus - /// - /// Observers are held by weak reference. - /// - /// - Parameters: - /// - observer: The observing object - /// - queue: The queue on which the observer methods should be called - func addStatusObserver(_ observer: PumpManagerStatusObserver, queue: DispatchQueue) - - /// Removes an observer of changes in PumpManagerStatus - /// - /// Since observers are held weakly, calling this method is not required when the observer is deallocated - /// - /// - Parameter observer: The observing object - func removeStatusObserver(_ observer: PumpManagerStatusObserver) - - /// Ensure that the pump's data (reservoir/events) is up to date. If not, fetch it. - /// The PumpManager should call the completion block with the date of last sync with the pump, nil if no sync has occurred - func ensureCurrentPumpData(completion: ((_ lastSync: Date?) -> Void)?) - - /// Loop calls this method when the current environment requires the pump to provide its own periodic - /// scheduling via BLE. - /// The manager may choose to still enable its own heartbeat even if `mustProvideBLEHeartbeat` is false - func setMustProvideBLEHeartbeat(_ mustProvideBLEHeartbeat: Bool) - - /// Returns a dose estimator for the current bolus, if one is in progress - func createBolusProgressReporter(reportingOn dispatchQueue: DispatchQueue) -> DoseProgressReporter? - - /// Returns the estimated time for the bolus amount to be delivered - func estimatedDuration(toBolus units: Double) -> TimeInterval - - /// Send a bolus command and handle the result - /// - /// - Parameters: - /// - units: The number of units to deliver - /// - automatic: Whether the dose was triggered automatically as opposed to commanded by user - /// - completion: A closure called after the command is complete - /// - error: An optional error describing why the command failed - func enactBolus(units: Double, activationType: BolusActivationType, completion: @escaping (_ error: PumpManagerError?) -> Void) - - /// Cancels the current, in progress, bolus. - /// - /// - Parameters: - /// - completion: A closure called after the command is complete - /// - result: A DoseEntry containing the actual delivery amount of the canceled bolus, nil if canceled bolus information is not available, or an error describing why the command failed. - func cancelBolus(completion: @escaping (_ result: PumpManagerResult) -> Void) - - /// Send a temporary basal rate command and handle the result - /// - /// - Parameters: - /// - unitsPerHour: The temporary basal rate to set - /// - duration: The duration of the temporary basal rate. If you pass in a duration of 0, that cancels any currently running Temp Basal - /// - completion: A closure called after the command is complete - /// - error: An optional error describing why the command failed - func enactTempBasal(unitsPerHour: Double, for duration: TimeInterval, completion: @escaping (_ error: PumpManagerError?) -> Void) - - /// Send a command to the pump to suspend delivery - /// - /// - Parameters: - /// - completion: A closure called after the command is complete - /// - error: An error describing why the command failed - func suspendDelivery(completion: @escaping (_ error: Error?) -> Void) - - /// Send a command to the pump to resume delivery - /// - /// - Parameters: - /// - completion: A closure called after the command is complete - /// - error: An error describing why the command failed - func resumeDelivery(completion: @escaping (_ error: Error?) -> Void) - - /// Sync the schedule of basal rates to the pump, annotating the result with the proper time zone. - /// - /// - Precondition: - /// - `scheduleItems` must not be empty. - /// - /// - Parameters: - /// - scheduleItems: The items comprising the basal rate schedule - /// - completion: A closure called after the command is complete - /// - result: A BasalRateSchedule or an error describing why the command failed - func syncBasalRateSchedule(items scheduleItems: [RepeatingScheduleValue], completion: @escaping (_ result: Result) -> Void) - - /// Sync the delivery limits for basal rate and bolus. If the pump does not support setting max bolus or max basal rates, the completion should be called with success including the provided delivery limits. - /// - /// - Parameters: - /// - deliveryLimits: The delivery limits - /// - completion: A closure called after the command is complete - /// - result: The delivery limits set or an error describing why the command failed - func syncDeliveryLimits(limits deliveryLimits: DeliveryLimits, completion: @escaping (_ result: Result) -> Void) -} - - -public extension PumpManager { - func roundToSupportedBasalRate(unitsPerHour: Double) -> Double { - return supportedBasalRates.filter({$0 <= unitsPerHour}).max() ?? 0 - } - - func roundToSupportedBolusVolume(units: Double) -> Double { - return supportedBolusVolumes.filter({$0 <= units}).max() ?? 0 - } - - /// Convenience wrapper for notifying the delegate of deactivation on the delegate queue - /// - /// - Parameters: - /// - completion: A closure called from the delegate queue after the delegate is called - func notifyDelegateOfDeactivation(completion: @escaping () -> Void) { - delegateQueue.async { - self.pumpManagerDelegate?.pumpManagerWillDeactivate(self) - completion() - } - } - -} diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/PumpManagerError.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/PumpManagerError.swift deleted file mode 100644 index 7dfde2a30..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/PumpManagerError.swift +++ /dev/null @@ -1,88 +0,0 @@ -// -// PumpManagerError.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum PumpManagerError: Error { - /// The manager isn't configured correctly - case configuration(LocalizedError?) - - /// The device connection failed - case connection(LocalizedError?) - - /// The device is connected, but communication failed - case communication(LocalizedError?) - - /// The device is in an error state - case deviceState(LocalizedError?) - - /// A command issued to the pump was sent, but we do not know if the pump received it - case uncertainDelivery -} - - -extension PumpManagerError: LocalizedError { - public var errorDescription: String? { - switch self { - case .communication(let error): - return error?.errorDescription ?? LocalizedString("Communication Failure", comment: "Generic pump error description") - case .configuration(let error): - return error?.errorDescription ?? LocalizedString("Invalid Configuration", comment: "Generic pump error description") - case .connection(let error): - return error?.errorDescription ?? LocalizedString("Connection Failure", comment: "Generic pump error description") - case .deviceState(let error): - return error?.errorDescription ?? LocalizedString("Device Refused", comment: "Generic pump error description") - case .uncertainDelivery: - return LocalizedString("Uncertain Delivery", comment: "Error description for uncertain delivery") - } - } - - public var failureReason: String? { - switch self { - case .communication(let error): - return error?.failureReason - case .configuration(let error): - return error?.failureReason - case .connection(let error): - return error?.failureReason - case .deviceState(let error): - return error?.failureReason - case .uncertainDelivery: - return LocalizedString("Communications interrupted during insulin delivery command.", comment: "Failure reason for uncertain delivery") - } - } - - public var recoverySuggestion: String? { - switch self { - case .communication(let error): - return error?.recoverySuggestion - case .configuration(let error): - return error?.recoverySuggestion - case .connection(let error): - return error?.recoverySuggestion - case .deviceState(let error): - return error?.recoverySuggestion - case .uncertainDelivery: - return LocalizedString("Make sure your pump is within communication range of your phone.", comment: "Recovery suggestion for uncertain delivery") - } - } - - public var helpAnchor: String? { - switch self { - case .communication(let error): - return error?.helpAnchor - case .configuration(let error): - return error?.helpAnchor - case .connection(let error): - return error?.helpAnchor - case .deviceState(let error): - return error?.helpAnchor - case .uncertainDelivery: - return nil - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/DeviceManager/PumpManagerStatus.swift b/Dependencies/LoopKit/LoopKit/DeviceManager/PumpManagerStatus.swift deleted file mode 100644 index 634fe2af6..000000000 --- a/Dependencies/LoopKit/LoopKit/DeviceManager/PumpManagerStatus.swift +++ /dev/null @@ -1,273 +0,0 @@ -// -// PumpManagerStatus.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - -public struct PumpStatusHighlight: DeviceStatusHighlight, Equatable { - public var localizedMessage: String - - public var imageName: String - - public var state: DeviceStatusHighlightState - - public init(localizedMessage: String, imageName: String, state: DeviceStatusHighlightState) { - self.localizedMessage = localizedMessage - self.imageName = imageName - self.state = state - } -} - -public struct PumpLifecycleProgress: DeviceLifecycleProgress, Equatable { - public var percentComplete: Double - - public var progressState: DeviceLifecycleProgressState - - public init(percentComplete: Double, progressState: DeviceLifecycleProgressState) { - self.percentComplete = percentComplete - self.progressState = progressState - } -} - -public struct PumpManagerStatus: Equatable { - - public enum BasalDeliveryState: Equatable { - case active(_ at: Date) - case initiatingTempBasal - case tempBasal(_ dose: DoseEntry) - case cancelingTempBasal - case suspending - case suspended(_ at: Date) - case resuming - - public var isSuspended: Bool { - if case .suspended = self { - return true - } - return false - } - } - - public enum BolusState: Equatable { - case noBolus - case initiating - case inProgress(_ dose: DoseEntry) - case canceling - } - - public let timeZone: TimeZone - public let device: HKDevice - public var pumpBatteryChargeRemaining: Double? - public var basalDeliveryState: BasalDeliveryState? - public var bolusState: BolusState - - /// The type of insulin this pump is delivering, nil if pump is in a state where insulin type is unknown; i.e. between reservoirs, or pod changes - public var insulinType: InsulinType? - - public var deliveryIsUncertain: Bool - - public init( - timeZone: TimeZone, - device: HKDevice, - pumpBatteryChargeRemaining: Double?, - basalDeliveryState: BasalDeliveryState?, - bolusState: BolusState, - insulinType: InsulinType?, - deliveryIsUncertain: Bool = false - ) { - self.timeZone = timeZone - self.device = device - self.pumpBatteryChargeRemaining = pumpBatteryChargeRemaining - self.basalDeliveryState = basalDeliveryState - self.bolusState = bolusState - self.insulinType = insulinType - self.deliveryIsUncertain = deliveryIsUncertain - } -} - -extension PumpManagerStatus: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.timeZone = try container.decode(TimeZone.self, forKey: .timeZone) - self.device = try container.decode(CodableDevice.self, forKey: .device).device - self.pumpBatteryChargeRemaining = try container.decodeIfPresent(Double.self, forKey: .pumpBatteryChargeRemaining) - self.basalDeliveryState = try container.decodeIfPresent(BasalDeliveryState.self, forKey: .basalDeliveryState) - self.bolusState = try container.decode(BolusState.self, forKey: .bolusState) - self.insulinType = try container.decodeIfPresent(InsulinType.self, forKey: .insulinType) - self.deliveryIsUncertain = try container.decode(Bool.self, forKey: .deliveryIsUncertain) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(timeZone, forKey: .timeZone) - try container.encode(CodableDevice(device), forKey: .device) - try container.encodeIfPresent(pumpBatteryChargeRemaining, forKey: .pumpBatteryChargeRemaining) - try container.encodeIfPresent(basalDeliveryState, forKey: .basalDeliveryState) - try container.encode(bolusState, forKey: .bolusState) - try container.encodeIfPresent(insulinType, forKey: .insulinType) - try container.encode(deliveryIsUncertain, forKey: .deliveryIsUncertain) - } - - private enum CodingKeys: String, CodingKey { - case timeZone - case device - case pumpBatteryChargeRemaining - case basalDeliveryState - case bolusState - case insulinType - case deliveryIsUncertain - } -} - -extension PumpManagerStatus.BasalDeliveryState: Codable { - public init(from decoder: Decoder) throws { - if let string = try? decoder.singleValueContainer().decode(String.self) { - switch string { - case CodableKeys.initiatingTempBasal.rawValue: - self = .initiatingTempBasal - case CodableKeys.cancelingTempBasal.rawValue: - self = .cancelingTempBasal - case CodableKeys.suspending.rawValue: - self = .suspending - case CodableKeys.resuming.rawValue: - self = .resuming - default: - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "invalid enumeration")) - } - } else { - let container = try decoder.container(keyedBy: CodableKeys.self) - if let active = try container.decodeIfPresent(Active.self, forKey: .active) { - self = .active(active.at) - } else if let tempBasal = try container.decodeIfPresent(TempBasal.self, forKey: .tempBasal) { - self = .tempBasal(tempBasal.dose) - } else if let suspended = try container.decodeIfPresent(Suspended.self, forKey: .suspended) { - self = .suspended(suspended.at) - } else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "invalid enumeration")) - } - } - } - - public func encode(to encoder: Encoder) throws { - switch self { - case .active(let at): - var container = encoder.container(keyedBy: CodableKeys.self) - try container.encode(Active(at: at), forKey: .active) - case .initiatingTempBasal: - var container = encoder.singleValueContainer() - try container.encode(CodableKeys.initiatingTempBasal.rawValue) - case .tempBasal(let dose): - var container = encoder.container(keyedBy: CodableKeys.self) - try container.encode(TempBasal(dose: dose), forKey: .tempBasal) - case .cancelingTempBasal: - var container = encoder.singleValueContainer() - try container.encode(CodableKeys.cancelingTempBasal.rawValue) - case .suspending: - var container = encoder.singleValueContainer() - try container.encode(CodableKeys.suspending.rawValue) - case .suspended(let at): - var container = encoder.container(keyedBy: CodableKeys.self) - try container.encode(Suspended(at: at), forKey: .suspended) - case .resuming: - var container = encoder.singleValueContainer() - try container.encode(CodableKeys.resuming.rawValue) - } - } - - private struct Active: Codable { - let at: Date - } - - private struct TempBasal: Codable { - let dose: DoseEntry - } - - private struct Suspended: Codable { - let at: Date - } - - private enum CodableKeys: String, CodingKey { - case active - case initiatingTempBasal - case tempBasal - case cancelingTempBasal - case suspending - case suspended - case resuming - } -} - -extension PumpManagerStatus.BolusState: Codable { - public init(from decoder: Decoder) throws { - if let string = try? decoder.singleValueContainer().decode(String.self) { - switch string { - case CodableKeys.noBolus.rawValue, "none": // included for backward compatibility. BolusState.none -> BolusState.noBolus - self = .noBolus - case CodableKeys.initiating.rawValue: - self = .initiating - case CodableKeys.canceling.rawValue: - self = .canceling - default: - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "invalid enumeration")) - } - } else { - let container = try decoder.container(keyedBy: CodableKeys.self) - if let inProgress = try container.decodeIfPresent(InProgress.self, forKey: .inProgress) { - self = .inProgress(inProgress.dose) - } else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "invalid enumeration")) - } - } - } - - public func encode(to encoder: Encoder) throws { - switch self { - case .noBolus: - var container = encoder.singleValueContainer() - try container.encode(CodableKeys.noBolus.rawValue) - case .initiating: - var container = encoder.singleValueContainer() - try container.encode(CodableKeys.initiating.rawValue) - case .inProgress(let dose): - var container = encoder.container(keyedBy: CodableKeys.self) - try container.encode(InProgress(dose: dose), forKey: .inProgress) - case .canceling: - var container = encoder.singleValueContainer() - try container.encode(CodableKeys.canceling.rawValue) - } - } - - private struct InProgress: Codable { - let dose: DoseEntry - } - - private enum CodableKeys: String, CodingKey { - case noBolus - case initiating - case inProgress - case canceling - } -} - -extension PumpStatusHighlight: Codable { } - -extension PumpLifecycleProgress: Codable { } - -extension PumpManagerStatus: CustomDebugStringConvertible { - public var debugDescription: String { - return """ - ## PumpManagerStatus - * timeZone: \(timeZone) - * device: \(device) - * pumpBatteryChargeRemaining: \(pumpBatteryChargeRemaining as Any) - * basalDeliveryState: \(basalDeliveryState as Any) - * bolusState: \(bolusState) - * insulinType: \(insulinType as Any) - * deliveryIsUncertain: \(deliveryIsUncertain) - """ - } -} diff --git a/Dependencies/LoopKit/LoopKit/DosingDecisionObject+CoreDataClass.swift b/Dependencies/LoopKit/LoopKit/DosingDecisionObject+CoreDataClass.swift deleted file mode 100644 index 8804b2713..000000000 --- a/Dependencies/LoopKit/LoopKit/DosingDecisionObject+CoreDataClass.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// DosingDecisionObject+CoreDataClass.swift -// LoopKit -// -// Created by Darin Krauss on 5/4/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import CoreData - -class DosingDecisionObject: NSManagedObject { - var hasUpdatedModificationCounter: Bool { changedValues().keys.contains("modificationCounter") } - - func updateModificationCounter() { setPrimitiveValue(managedObjectContext!.modificationCounter!, forKey: "modificationCounter") } - - public override func awakeFromInsert() { - super.awakeFromInsert() - updateModificationCounter() - } - - public override func willSave() { - if isUpdated && !hasUpdatedModificationCounter { - updateModificationCounter() - } - super.willSave() - } -} diff --git a/Dependencies/LoopKit/LoopKit/DosingDecisionObject+CoreDataProperties.swift b/Dependencies/LoopKit/LoopKit/DosingDecisionObject+CoreDataProperties.swift deleted file mode 100644 index a65fad7e1..000000000 --- a/Dependencies/LoopKit/LoopKit/DosingDecisionObject+CoreDataProperties.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// DosingDecisionObject+CoreDataProperties.swift -// LoopKit -// -// Created by Darin Krauss on 5/4/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation -import CoreData - -extension DosingDecisionObject { - @nonobjc public class func fetchRequest() -> NSFetchRequest { - return NSFetchRequest(entityName: "DosingDecisionObject") - } - - @NSManaged public var data: Data - @NSManaged public var date: Date - @NSManaged public var modificationCounter: Int64 -} - -extension DosingDecisionObject: Encodable { - func encode(to encoder: Encoder) throws { - try EncodableDosingDecisionObject(self).encode(to: encoder) - } -} - -fileprivate struct EncodableDosingDecisionObject: Encodable { - var data: StoredDosingDecision - var date: Date - var modificationCounter: Int64 - - init(_ object: DosingDecisionObject) throws { - self.data = try PropertyListDecoder().decode(StoredDosingDecision.self, from: object.data) - self.date = object.date - self.modificationCounter = object.modificationCounter - } -} diff --git a/Dependencies/LoopKit/LoopKit/DosingDecisionStore.swift b/Dependencies/LoopKit/LoopKit/DosingDecisionStore.swift deleted file mode 100644 index 92e473c99..000000000 --- a/Dependencies/LoopKit/LoopKit/DosingDecisionStore.swift +++ /dev/null @@ -1,553 +0,0 @@ -// -// DosingDecisionStore.swift -// LoopKit -// -// Created by Darin Krauss on 10/14/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import os.log -import Foundation -import CoreData - -public protocol DosingDecisionStoreDelegate: AnyObject { - /** - Informs the delegate that the dosing decision store has updated dosing decision data. - - - Parameter dosingDecisionStore: The dosing decision store that has updated dosing decision data. - */ - func dosingDecisionStoreHasUpdatedDosingDecisionData(_ dosingDecisionStore: DosingDecisionStore) -} - -public class DosingDecisionStore { - public weak var delegate: DosingDecisionStoreDelegate? - - private let store: PersistenceController - private let expireAfter: TimeInterval - private let dataAccessQueue = DispatchQueue(label: "com.loopkit.DosingDecisionStore.dataAccessQueue", qos: .utility) - public let log = OSLog(category: "DosingDecisionStore") - - public init(store: PersistenceController, expireAfter: TimeInterval) { - self.store = store - self.expireAfter = expireAfter - } - - public func storeDosingDecision(_ dosingDecision: StoredDosingDecision, completion: @escaping () -> Void) { - dataAccessQueue.async { - if let data = self.encodeDosingDecision(dosingDecision) { - self.store.managedObjectContext.performAndWait { - let object = DosingDecisionObject(context: self.store.managedObjectContext) - object.data = data - object.date = dosingDecision.date - self.store.save() - } - } - - self.purgeExpiredDosingDecisions() - completion() - } - } - - public var expireDate: Date { - return Date(timeIntervalSinceNow: -expireAfter) - } - - private func purgeExpiredDosingDecisions() { - purgeDosingDecisionObjects(before: expireDate) - } - - public func purgeDosingDecisions(before date: Date, completion: @escaping (Error?) -> Void) { - dataAccessQueue.async { - self.purgeDosingDecisionObjects(before: date, completion: completion) - } - } - - private func purgeDosingDecisionObjects(before date: Date, completion: ((Error?) -> Void)? = nil) { - dispatchPrecondition(condition: .onQueue(dataAccessQueue)) - - var purgeError: Error? - - store.managedObjectContext.performAndWait { - do { - let count = try self.store.managedObjectContext.purgeObjects(of: DosingDecisionObject.self, matching: NSPredicate(format: "date < %@", date as NSDate)) - self.log.info("Purged %d DosingDecisionObjects", count) - } catch let error { - self.log.error("Unable to purge DosingDecisionObjects: %{public}@", String(describing: error)) - purgeError = error - } - } - - if let purgeError = purgeError { - completion?(purgeError) - return - } - - delegate?.dosingDecisionStoreHasUpdatedDosingDecisionData(self) - completion?(nil) - } - - private static var encoder: PropertyListEncoder = { - let encoder = PropertyListEncoder() - encoder.outputFormat = .binary - return encoder - }() - - private func encodeDosingDecision(_ dosingDecision: StoredDosingDecision) -> Data? { - do { - return try Self.encoder.encode(dosingDecision) - } catch let error { - self.log.error("Error encoding StoredDosingDecision: %@", String(describing: error)) - return nil - } - } - - private static var decoder = PropertyListDecoder() - - private func decodeDosingDecision(fromData data: Data) -> StoredDosingDecision? { - do { - return try Self.decoder.decode(StoredDosingDecision.self, from: data) - } catch let error { - self.log.error("Error decoding StoredDosingDecision: %@", String(describing: error)) - return nil - } - } -} - -extension DosingDecisionStore { - public struct QueryAnchor: Equatable, RawRepresentable { - public typealias RawValue = [String: Any] - - internal var modificationCounter: Int64 - - public init() { - self.modificationCounter = 0 - } - - public init?(rawValue: RawValue) { - guard let modificationCounter = rawValue["modificationCounter"] as? Int64 else { - return nil - } - self.modificationCounter = modificationCounter - } - - public var rawValue: RawValue { - var rawValue: RawValue = [:] - rawValue["modificationCounter"] = modificationCounter - return rawValue - } - } - - public enum DosingDecisionQueryResult { - case success(QueryAnchor, [StoredDosingDecision]) - case failure(Error) - } - - public func executeDosingDecisionQuery(fromQueryAnchor queryAnchor: QueryAnchor?, limit: Int, completion: @escaping (DosingDecisionQueryResult) -> Void) { - dataAccessQueue.async { - var queryAnchor = queryAnchor ?? QueryAnchor() - var queryResult = [StoredDosingDecisionData]() - var queryError: Error? - - guard limit > 0 else { - completion(.success(queryAnchor, [])) - return - } - - let enqueueTime = DispatchTime.now() - - self.store.managedObjectContext.performAndWait { - let startTime = DispatchTime.now() - - defer { - let endTime = DispatchTime.now() - let queueWait = Double(startTime.uptimeNanoseconds - enqueueTime.uptimeNanoseconds) / 1_000_000_000 - let fetchWait = Double(endTime.uptimeNanoseconds - startTime.uptimeNanoseconds) / 1_000_000_000 - self.log.debug("executeDosingDecisionQuery (anchor = %{public}@: queueWait(%.03f), fetch(%.03f)", String(describing: queryAnchor), queueWait, fetchWait) - } - - let storedRequest: NSFetchRequest = DosingDecisionObject.fetchRequest() - - storedRequest.predicate = NSPredicate(format: "modificationCounter > %d", queryAnchor.modificationCounter) - storedRequest.sortDescriptors = [NSSortDescriptor(key: "modificationCounter", ascending: true)] - storedRequest.fetchLimit = limit - - do { - let stored = try self.store.managedObjectContext.fetch(storedRequest) - if let modificationCounter = stored.max(by: { $0.modificationCounter < $1.modificationCounter })?.modificationCounter { - queryAnchor.modificationCounter = modificationCounter - } - queryResult.append(contentsOf: stored.compactMap { StoredDosingDecisionData(date: $0.date, data: $0.data) }) - } catch let error { - queryError = error - return - } - } - - if let queryError = queryError { - completion(.failure(queryError)) - return - } - - // Decoding a large number of dosing decision can be very CPU intensive and may take considerable wall clock time. - // Do not block DosingDecisionStore dataAccessQueue. Perform work and callback in global utility queue. - DispatchQueue.global(qos: .utility).async { - completion(.success(queryAnchor, queryResult.compactMap { self.decodeDosingDecision(fromData: $0.data) })) - } - } - } -} - -public struct StoredDosingDecisionData { - public let date: Date - public let data: Data - - public init(date: Date, data: Data) { - self.date = date - self.data = data - } -} - -public typealias HistoricalGlucoseValue = PredictedGlucoseValue - -public struct StoredDosingDecision { - public var date: Date - public var controllerTimeZone: TimeZone - public var reason: String - public var settings: Settings? - public var scheduleOverride: TemporaryScheduleOverride? - public var controllerStatus: ControllerStatus? - public var pumpManagerStatus: PumpManagerStatus? - public var pumpStatusHighlight: StoredDeviceHighlight? - public var cgmManagerStatus: CGMManagerStatus? - public var lastReservoirValue: LastReservoirValue? - public var historicalGlucose: [HistoricalGlucoseValue]? - public var originalCarbEntry: StoredCarbEntry? - public var carbEntry: StoredCarbEntry? - public var manualGlucoseSample: StoredGlucoseSample? - public var carbsOnBoard: CarbValue? - public var insulinOnBoard: InsulinValue? - public var glucoseTargetRangeSchedule: GlucoseRangeSchedule? - public var predictedGlucose: [PredictedGlucoseValue]? - public var automaticDoseRecommendation: AutomaticDoseRecommendation? - public var manualBolusRecommendation: ManualBolusRecommendationWithDate? - public var manualBolusRequested: Double? - public var warnings: [Issue] - public var errors: [Issue] - public var syncIdentifier: UUID - - public init(date: Date = Date(), - controllerTimeZone: TimeZone = TimeZone.current, - reason: String, - settings: Settings? = nil, - scheduleOverride: TemporaryScheduleOverride? = nil, - controllerStatus: ControllerStatus? = nil, - pumpManagerStatus: PumpManagerStatus? = nil, - pumpStatusHighlight: StoredDeviceHighlight? = nil, - cgmManagerStatus: CGMManagerStatus? = nil, - lastReservoirValue: LastReservoirValue? = nil, - historicalGlucose: [HistoricalGlucoseValue]? = nil, - originalCarbEntry: StoredCarbEntry? = nil, - carbEntry: StoredCarbEntry? = nil, - manualGlucoseSample: StoredGlucoseSample? = nil, - carbsOnBoard: CarbValue? = nil, - insulinOnBoard: InsulinValue? = nil, - glucoseTargetRangeSchedule: GlucoseRangeSchedule? = nil, - predictedGlucose: [PredictedGlucoseValue]? = nil, - automaticDoseRecommendation: AutomaticDoseRecommendation? = nil, - manualBolusRecommendation: ManualBolusRecommendationWithDate? = nil, - manualBolusRequested: Double? = nil, - warnings: [Issue] = [], - errors: [Issue] = [], - syncIdentifier: UUID = UUID()) { - self.date = date - self.controllerTimeZone = controllerTimeZone - self.reason = reason - self.settings = settings - self.scheduleOverride = scheduleOverride - self.controllerStatus = controllerStatus - self.pumpManagerStatus = pumpManagerStatus - self.pumpStatusHighlight = pumpStatusHighlight - self.cgmManagerStatus = cgmManagerStatus - self.lastReservoirValue = lastReservoirValue - self.historicalGlucose = historicalGlucose - self.originalCarbEntry = originalCarbEntry - self.carbEntry = carbEntry - self.manualGlucoseSample = manualGlucoseSample - self.carbsOnBoard = carbsOnBoard - self.insulinOnBoard = insulinOnBoard - self.glucoseTargetRangeSchedule = glucoseTargetRangeSchedule - self.predictedGlucose = predictedGlucose - self.automaticDoseRecommendation = automaticDoseRecommendation - self.manualBolusRecommendation = manualBolusRecommendation - self.manualBolusRequested = manualBolusRequested - self.warnings = warnings - self.errors = errors - self.syncIdentifier = syncIdentifier - } - - public struct Settings: Codable, Equatable { - public let syncIdentifier: UUID - - public init(syncIdentifier: UUID) { - self.syncIdentifier = syncIdentifier - } - } - - public struct ControllerStatus: Codable, Equatable { - public enum BatteryState: String, Codable { - case unknown - case unplugged - case charging - case full - } - - public let batteryState: BatteryState? - public let batteryLevel: Float? - - public init(batteryState: BatteryState? = nil, batteryLevel: Float? = nil) { - self.batteryState = batteryState - self.batteryLevel = batteryLevel - } - } - - public struct LastReservoirValue: Codable { - public let startDate: Date - public let unitVolume: Double - - public init(startDate: Date, unitVolume: Double) { - self.startDate = startDate - self.unitVolume = unitVolume - } - } - - public struct Issue: Codable, Equatable { - public let id: String - public let details: [String: String]? - - public init(id: String, details: [String: String]? = nil) { - self.id = id - self.details = details?.isEmpty == false ? details : nil - } - } - - public struct StoredDeviceHighlight: Codable, Equatable, DeviceStatusHighlight { - public var localizedMessage: String - public var imageName: String - public var state: DeviceStatusHighlightState - - public init(localizedMessage: String, imageName: String, state: DeviceStatusHighlightState) { - self.localizedMessage = localizedMessage - self.imageName = imageName - self.state = state - } - } -} - -public struct ManualBolusRecommendationWithDate: Codable { - public let recommendation: ManualBolusRecommendation - public let date: Date - - public init(recommendation: ManualBolusRecommendation, date: Date) { - self.recommendation = recommendation - self.date = date - } -} - -extension StoredDosingDecision: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.init(date: try container.decode(Date.self, forKey: .date), - controllerTimeZone: try container.decode(TimeZone.self, forKey: .controllerTimeZone), - reason: try container.decode(String.self, forKey: .reason), - settings: try container.decodeIfPresent(Settings.self, forKey: .settings), - scheduleOverride: try container.decodeIfPresent(TemporaryScheduleOverride.self, forKey: .scheduleOverride), - controllerStatus: try container.decodeIfPresent(ControllerStatus.self, forKey: .controllerStatus), - pumpManagerStatus: try container.decodeIfPresent(PumpManagerStatus.self, forKey: .pumpManagerStatus), - pumpStatusHighlight: try container.decodeIfPresent(StoredDeviceHighlight.self, forKey: .pumpStatusHighlight), - cgmManagerStatus: try container.decodeIfPresent(CGMManagerStatus.self, forKey: .cgmManagerStatus), - lastReservoirValue: try container.decodeIfPresent(LastReservoirValue.self, forKey: .lastReservoirValue), - historicalGlucose: try container.decodeIfPresent([HistoricalGlucoseValue].self, forKey: .historicalGlucose), - originalCarbEntry: try container.decodeIfPresent(StoredCarbEntry.self, forKey: .originalCarbEntry), - carbEntry: try container.decodeIfPresent(StoredCarbEntry.self, forKey: .carbEntry), - manualGlucoseSample: try container.decodeIfPresent(StoredGlucoseSample.self, forKey: .manualGlucoseSample), - carbsOnBoard: try container.decodeIfPresent(CarbValue.self, forKey: .carbsOnBoard), - insulinOnBoard: try container.decodeIfPresent(InsulinValue.self, forKey: .insulinOnBoard), - glucoseTargetRangeSchedule: try container.decodeIfPresent(GlucoseRangeSchedule.self, forKey: .glucoseTargetRangeSchedule), - predictedGlucose: try container.decodeIfPresent([PredictedGlucoseValue].self, forKey: .predictedGlucose), - automaticDoseRecommendation: try container.decodeIfPresent(AutomaticDoseRecommendation.self, forKey: .automaticDoseRecommendation), - manualBolusRecommendation: try container.decodeIfPresent(ManualBolusRecommendationWithDate.self, forKey: .manualBolusRecommendation), - manualBolusRequested: try container.decodeIfPresent(Double.self, forKey: .manualBolusRequested), - warnings: try container.decodeIfPresent([Issue].self, forKey: .warnings) ?? [], - errors: try container.decodeIfPresent([Issue].self, forKey: .errors) ?? [], - syncIdentifier: try container.decode(UUID.self, forKey: .syncIdentifier)) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(date, forKey: .date) - try container.encode(controllerTimeZone, forKey: .controllerTimeZone) - try container.encode(reason, forKey: .reason) - try container.encodeIfPresent(settings, forKey: .settings) - try container.encodeIfPresent(scheduleOverride, forKey: .scheduleOverride) - try container.encodeIfPresent(controllerStatus, forKey: .controllerStatus) - try container.encodeIfPresent(pumpManagerStatus, forKey: .pumpManagerStatus) - try container.encodeIfPresent(pumpStatusHighlight, forKey: .pumpStatusHighlight) - try container.encodeIfPresent(cgmManagerStatus, forKey: .cgmManagerStatus) - try container.encodeIfPresent(lastReservoirValue, forKey: .lastReservoirValue) - try container.encodeIfPresent(historicalGlucose, forKey: .historicalGlucose) - try container.encodeIfPresent(originalCarbEntry, forKey: .originalCarbEntry) - try container.encodeIfPresent(carbEntry, forKey: .carbEntry) - try container.encodeIfPresent(manualGlucoseSample, forKey: .manualGlucoseSample) - try container.encodeIfPresent(carbsOnBoard, forKey: .carbsOnBoard) - try container.encodeIfPresent(insulinOnBoard, forKey: .insulinOnBoard) - try container.encodeIfPresent(glucoseTargetRangeSchedule, forKey: .glucoseTargetRangeSchedule) - try container.encodeIfPresent(predictedGlucose, forKey: .predictedGlucose) - try container.encodeIfPresent(automaticDoseRecommendation, forKey: .automaticDoseRecommendation) - try container.encodeIfPresent(manualBolusRecommendation, forKey: .manualBolusRecommendation) - try container.encodeIfPresent(manualBolusRequested, forKey: .manualBolusRequested) - try container.encodeIfPresent(!warnings.isEmpty ? warnings : nil, forKey: .warnings) - try container.encodeIfPresent(!errors.isEmpty ? errors : nil, forKey: .errors) - try container.encode(syncIdentifier, forKey: .syncIdentifier) - } - - private enum CodingKeys: String, CodingKey { - case date - case controllerTimeZone - case reason - case settings - case scheduleOverride - case controllerStatus - case pumpManagerStatus - case pumpStatusHighlight - case cgmManagerStatus - case lastReservoirValue - case historicalGlucose - case originalCarbEntry - case carbEntry - case manualGlucoseSample - case carbsOnBoard - case insulinOnBoard - case glucoseTargetRangeSchedule - case predictedGlucose - case automaticDoseRecommendation - case manualBolusRecommendation - case manualBolusRequested - case warnings - case errors - case syncIdentifier - } -} - -// MARK: - Critical Event Log Export - -extension DosingDecisionStore: CriticalEventLog { - private var exportProgressUnitCountPerObject: Int64 { 33 } - private var exportFetchLimit: Int { Int(criticalEventLogExportProgressUnitCountPerFetch / exportProgressUnitCountPerObject) } - - public var exportName: String { "DosingDecisions.json" } - - public func exportProgressTotalUnitCount(startDate: Date, endDate: Date? = nil) -> Result { - var result: Result? - - self.store.managedObjectContext.performAndWait { - do { - let request: NSFetchRequest = DosingDecisionObject.fetchRequest() - request.predicate = self.exportDatePredicate(startDate: startDate, endDate: endDate) - - let objectCount = try self.store.managedObjectContext.count(for: request) - result = .success(Int64(objectCount) * exportProgressUnitCountPerObject) - } catch let error { - result = .failure(error) - } - } - - return result! - } - - public func export(startDate: Date, endDate: Date, to stream: OutputStream, progress: Progress) -> Error? { - let encoder = JSONStreamEncoder(stream: stream) - var modificationCounter: Int64 = 0 - var fetching = true - var error: Error? - - while fetching && error == nil { - self.store.managedObjectContext.performAndWait { - do { - guard !progress.isCancelled else { - throw CriticalEventLogError.cancelled - } - - let request: NSFetchRequest = DosingDecisionObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format: "modificationCounter > %d", modificationCounter), - self.exportDatePredicate(startDate: startDate, endDate: endDate)]) - request.sortDescriptors = [NSSortDescriptor(key: "modificationCounter", ascending: true)] - request.fetchLimit = self.exportFetchLimit - - let objects = try self.store.managedObjectContext.fetch(request) - if objects.isEmpty { - fetching = false - return - } - - try encoder.encode(objects) - - modificationCounter = objects.last!.modificationCounter - - progress.completedUnitCount += Int64(objects.count) * exportProgressUnitCountPerObject - } catch let fetchError { - error = fetchError - } - } - } - - if let closeError = encoder.close(), error == nil { - error = closeError - } - - return error - } - - private func exportDatePredicate(startDate: Date, endDate: Date? = nil) -> NSPredicate { - var predicate = NSPredicate(format: "date >= %@", startDate as NSDate) - if let endDate = endDate { - predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSPredicate(format: "date < %@", endDate as NSDate)]) - } - return predicate - } -} - -// MARK: - Core Data (Bulk) - TEST ONLY - -extension DosingDecisionStore { - public func addStoredDosingDecisions(dosingDecisions: [StoredDosingDecision], completion: @escaping (Error?) -> Void) { - guard !dosingDecisions.isEmpty else { - completion(nil) - return - } - - dataAccessQueue.async { - var error: Error? - - self.store.managedObjectContext.performAndWait { - for dosingDecision in dosingDecisions { - guard let data = self.encodeDosingDecision(dosingDecision) else { - continue - } - let object = DosingDecisionObject(context: self.store.managedObjectContext) - object.data = data - object.date = dosingDecision.date - } - error = self.store.save() - } - - guard error == nil else { - completion(error) - return - } - - self.log.info("Added %d DosingDecisionObjects", dosingDecisions.count) - self.delegate?.dosingDecisionStoreHasUpdatedDosingDecisionData(self) - completion(nil) - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/EGPSchedule.swift b/Dependencies/LoopKit/LoopKit/EGPSchedule.swift deleted file mode 100644 index 95d4e5cdf..000000000 --- a/Dependencies/LoopKit/LoopKit/EGPSchedule.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// EGPSchedule.swift -// LoopKit -// -// Created by Michael Pangburn on 3/27/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -public typealias EGPSchedule = SingleQuantitySchedule - -extension /* EGPSchedule */ DailyQuantitySchedule where T == Double { - public static func egpSchedule(basalSchedule: BasalRateSchedule, insulinSensitivitySchedule: InsulinSensitivitySchedule) -> EGPSchedule { - let basalScheduleWithUnit = DailyQuantitySchedule(unit: .internationalUnitsPerHour, valueSchedule: basalSchedule) - return basalScheduleWithUnit * insulinSensitivitySchedule - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/ClosedRange.swift b/Dependencies/LoopKit/LoopKit/Extensions/ClosedRange.swift deleted file mode 100644 index 7042e97c6..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/ClosedRange.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// ClosedRange.swift -// LoopKit -// -// Created by Michael Pangburn on 6/23/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -extension ClosedRange { - func expandedToInclude(_ value: Bound) -> ClosedRange { - if value < lowerBound { - return value...upperBound - } else if value > upperBound { - return lowerBound...value - } else { - return self - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/Collection.swift b/Dependencies/LoopKit/LoopKit/Extensions/Collection.swift deleted file mode 100644 index c37a84c4e..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/Collection.swift +++ /dev/null @@ -1,98 +0,0 @@ -// -// Collection.swift -// LoopKit -// -// Created by Michael Pangburn on 2/14/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -/// Returns the cartesian product of a sequence and a collection. -/// -/// O(1), but O(_n_*_m_) on iteration. -/// - Note: Don't mind the scary return type; it's just a lazy sequence. -func product(_ s: S, _ c: C) -> LazySequence>>> { - return s.lazy.flatMap { first in - c.lazy.map { second in - (first, second) - } - } -} - -extension Collection { - /// Returns a sequence containing adjacent pairs of elements in the ordered collection. - func adjacentPairs() -> Zip2Sequence { - return zip(self, dropFirst()) - } -} - -extension Collection { - func chunked(into size: Int) -> [SubSequence] { - precondition(size > 0, "Chunk size must be greater than zero") - var start = startIndex - return stride(from: 0, to: count, by: size).map {_ in - let end = index(start, offsetBy: size, limitedBy: endIndex) ?? endIndex - defer { start = end } - return self[start.. LazyMapSequence>>>, (Element, Element)> { - return product(indices, indices).filter(<).map { - (self[$0], self[$1]) - } - } -} - -extension RangeReplaceableCollection where Index: Hashable { - /// Removes the elements at all of the given indices. - /// - /// O(_n_*_m_) - mutating func removeAll(at indices: S) where S.Element == Index { - let arranged = Set(indices).sorted(by: >) - for index in arranged { - remove(at: index) - } - } -} - -// Source: https://github.com/apple/swift/blob/master/stdlib/public/core/CollectionAlgorithms.swift#L476 -extension Collection { - /// Returns the index of the first element in the collection that matches - /// the predicate. - /// - /// The collection must already be partitioned according to the predicate. - /// That is, there should be an index `i` where for every element in - /// `collection[.. Bool - ) rethrows -> Index { - var n = count - var l = startIndex - - while n > 0 { - let half = n / 2 - let mid = index(l, offsetBy: half) - if try predicate(self[mid]) { - n = half - } else { - l = index(after: mid) - n -= half + 1 - } - } - return l - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/Comparable.swift b/Dependencies/LoopKit/LoopKit/Extensions/Comparable.swift deleted file mode 100644 index 8ffc4dcaa..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/Comparable.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// Comparable.swift -// LoopKit -// -// Created by Michael Pangburn on 11/20/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -extension Comparable { - func clamped(to range: ClosedRange) -> Self { - if self < range.lowerBound { - return range.lowerBound - } else if self > range.upperBound { - return range.upperBound - } else { - return self - } - } - - mutating func clamp(to range: ClosedRange) { - self = clamped(to: range) - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/Data.swift b/Dependencies/LoopKit/LoopKit/Extensions/Data.swift deleted file mode 100644 index e92db3921..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/Data.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// NSData.swift -// LoopKit -// -// Created by Nate Racklyeft on 8/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -// String conversion methods, adapted from https://stackoverflow.com/questions/40276322/hex-binary-string-conversion-in-swift/40278391#40278391 -extension Data { - init?(hexadecimalString: String) { - self.init(capacity: hexadecimalString.utf16.count / 2) - - // Convert 0 ... 9, a ... f, A ...F to their decimal value, - // return nil for all other input characters - func decodeNibble(u: UInt16) -> UInt8? { - switch u { - case 0x30 ... 0x39: // '0'-'9' - return UInt8(u - 0x30) - case 0x41 ... 0x46: // 'A'-'F' - return UInt8(u - 0x41 + 10) // 10 since 'A' is 10, not 0 - case 0x61 ... 0x66: // 'a'-'f' - return UInt8(u - 0x61 + 10) // 10 since 'a' is 10, not 0 - default: - return nil - } - } - - var even = true - var byte: UInt8 = 0 - for c in hexadecimalString.utf16 { - guard let val = decodeNibble(u: c) else { return nil } - if even { - byte = val << 4 - } else { - byte += val - self.append(byte) - } - even = !even - } - guard even else { return nil } - } - - var hexadecimalString: String { - return map { String(format: "%02hhx", $0) }.joined() - } -} - -extension Data { - static func newPumpEventIdentifier() -> Data { - return Data(UUID().uuidString.utf8) - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/Date.swift b/Dependencies/LoopKit/LoopKit/Extensions/Date.swift deleted file mode 100644 index e2fe98674..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/Date.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// NSDate.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/17/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public extension Date { - func dateFlooredToTimeInterval(_ interval: TimeInterval) -> Date { - if interval == 0 { - return self - } - - return Date(timeIntervalSinceReferenceDate: floor(self.timeIntervalSinceReferenceDate / interval) * interval) - } - - func dateCeiledToTimeInterval(_ interval: TimeInterval) -> Date { - if interval == 0 { - return self - } - - return Date(timeIntervalSinceReferenceDate: ceil(self.timeIntervalSinceReferenceDate / interval) * interval) - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/DateFormatter.swift b/Dependencies/LoopKit/LoopKit/Extensions/DateFormatter.swift deleted file mode 100644 index 7a35adc10..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/DateFormatter.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// NSDateFormatter.swift -// Naterade -// -// Created by Nathan Racklyeft on 11/25/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -// MARK: - Extensions useful in parsing fixture dates -extension ISO8601DateFormatter { - static func localTimeDate(timeZone: TimeZone = .currentFixed) -> Self { - let formatter = self.init() - - formatter.formatOptions = .withInternetDateTime - formatter.formatOptions.subtract(.withTimeZone) - formatter.timeZone = timeZone - - return formatter - } -} - - -extension DateFormatter { - static var descriptionFormatter: DateFormatter { - let formatter = self.init() - formatter.dateFormat = "yyyy-MM-dd HH:mm:ssZZZZZ" - - return formatter - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/Double.swift b/Dependencies/LoopKit/LoopKit/Extensions/Double.swift deleted file mode 100644 index 349c65a22..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/Double.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// Double.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/12/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - -extension Double: RawRepresentable { - public typealias RawValue = Double - - public init?(rawValue: RawValue) { - self = rawValue - } - - public var rawValue: RawValue { - return self - } -} - -infix operator =~ : ComparisonPrecedence - - extension Double { - static func =~ (lhs: Double, rhs: Double) -> Bool { - return fabs(lhs - rhs) < Double.ulpOfOne - } - } diff --git a/Dependencies/LoopKit/LoopKit/Extensions/FloatingPoint.swift b/Dependencies/LoopKit/LoopKit/Extensions/FloatingPoint.swift deleted file mode 100644 index 41d23a510..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/FloatingPoint.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// FloatingPoint.swift -// LoopKit -// -// Created by Michael Pangburn on 7/30/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension Double { - public func matchingOrTruncatedValue(from supportedValues: [Double], withinDecimalPlaces precision: Int) -> Double { - let nearestSupportedValue = roundedToNearest(of: supportedValues) - return abs(nearestSupportedValue - self) <= pow(10.0, Double(-precision)) - ? nearestSupportedValue - : truncating(toOneOf: supportedValues) - } -} - -extension FloatingPoint { - /// Precondition: - `supportedValues` is sorted in ascending order. - public func roundedToNearest(of supportedValues: [Self]) -> Self { - guard !supportedValues.isEmpty else { - return self - } - - let splitPoint = supportedValues.partitioningIndex(where: { $0 > self }) - switch splitPoint { - case supportedValues.startIndex: - return supportedValues.first! - case supportedValues.endIndex: - return supportedValues.last! - default: - let (lesser, greater) = (supportedValues[splitPoint - 1], supportedValues[splitPoint]) - return (self - lesser) <= (greater - self) ? lesser : greater - } - } - - /// Precondition: - `supportedValues` is sorted in ascending order. - public func truncating(toOneOf supportedValues: [Self]) -> Self { - guard !supportedValues.isEmpty else { - return self - } - - let splitPoint = supportedValues.partitioningIndex(where: { $0 > self }) - return splitPoint == supportedValues.startIndex - ? supportedValues.first! - : supportedValues[splitPoint - 1] - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/Guardrail+Settings.swift b/Dependencies/LoopKit/LoopKit/Extensions/Guardrail+Settings.swift deleted file mode 100644 index 2a5bf6f9d..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/Guardrail+Settings.swift +++ /dev/null @@ -1,175 +0,0 @@ -// -// Guardrail+Settings.swift -// LoopKit -// -// Created by Rick Pasetto on 7/14/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import HealthKit - -public extension Guardrail where Value == HKQuantity { - static let suspendThreshold = Guardrail(absoluteBounds: 67...110, recommendedBounds: 74...80, unit: .milligramsPerDeciliter, startingSuggestion: 80) - - static func maxSuspendThresholdValue(correctionRangeSchedule: GlucoseRangeSchedule?, preMealTargetRange: ClosedRange?, workoutTargetRange: ClosedRange?) -> HKQuantity { - - return [ - suspendThreshold.absoluteBounds.upperBound, - correctionRangeSchedule?.minLowerBound(), - preMealTargetRange?.lowerBound, - workoutTargetRange?.lowerBound - ] - .compactMap { $0 } - .min()! - } - - static let correctionRange = Guardrail(absoluteBounds: 87...180, recommendedBounds: 100...115, unit: .milligramsPerDeciliter, startingSuggestion: 100) - - static func minCorrectionRangeValue(suspendThreshold: GlucoseThreshold?) -> HKQuantity { - return [ - correctionRange.absoluteBounds.lowerBound, - suspendThreshold?.quantity - ] - .compactMap { $0 } - .max()! - } - - // Static "unconstrained" constant values before applying constraints - static let unconstrainedWorkoutCorrectionRange = Guardrail( - absoluteBounds: correctionRange.absoluteBounds.lowerBound.doubleValue(for: .milligramsPerDeciliter)...250, - recommendedBounds: correctionRange.recommendedBounds.lowerBound.doubleValue(for: .milligramsPerDeciliter)...180, - unit: .milligramsPerDeciliter) - - fileprivate static func workoutCorrectionRange(correctionRangeScheduleRange: ClosedRange, - suspendThreshold: GlucoseThreshold?) -> Guardrail { - let absoluteLowerBound = [ - unconstrainedWorkoutCorrectionRange.absoluteBounds.lowerBound, - suspendThreshold?.quantity - ] - .compactMap { $0 } - .max()! - let recommmendedLowerBound = max(absoluteLowerBound, correctionRangeScheduleRange.upperBound) - return Guardrail( - absoluteBounds: absoluteLowerBound...unconstrainedWorkoutCorrectionRange.absoluteBounds.upperBound, - recommendedBounds: recommmendedLowerBound...unconstrainedWorkoutCorrectionRange.recommendedBounds.upperBound - ) - } - - static let premealCorrectionRangeMaximum = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 130.0) - - fileprivate static func preMealCorrectionRange(correctionRangeScheduleRange: ClosedRange, - suspendThreshold: GlucoseThreshold?) -> Guardrail { - let absoluteLowerBound = suspendThreshold?.quantity ?? Guardrail.suspendThreshold.absoluteBounds.lowerBound - return Guardrail( - absoluteBounds: absoluteLowerBound...premealCorrectionRangeMaximum, - recommendedBounds: absoluteLowerBound...min(max(absoluteLowerBound, correctionRangeScheduleRange.lowerBound), premealCorrectionRangeMaximum) - ) - } - - static func correctionRangeOverride(for preset: CorrectionRangeOverrides.Preset, - correctionRangeScheduleRange: ClosedRange, - suspendThreshold: GlucoseThreshold?) -> Guardrail { - - switch preset { - case .workout: - return workoutCorrectionRange(correctionRangeScheduleRange: correctionRangeScheduleRange, suspendThreshold: suspendThreshold) - case .preMeal: - return preMealCorrectionRange(correctionRangeScheduleRange: correctionRangeScheduleRange, suspendThreshold: suspendThreshold) - } - } - - static let insulinSensitivity = Guardrail( - absoluteBounds: 10...500, - recommendedBounds: 16...399, - unit: HKUnit.milligramsPerDeciliter.unitDivided(by: .internationalUnit()), - startingSuggestion: 50 - ) - - static let carbRatio = Guardrail( - absoluteBounds: 2...150, - recommendedBounds: 4...28, - unit: .gramsPerUnit, - startingSuggestion: 15 - ) - - static func basalRate(supportedBasalRates: [Double]) -> Guardrail { - let scheduledBasalRateAbsoluteRange = 0.0...30.0 - let allowedBasalRates = supportedBasalRates.filter { scheduledBasalRateAbsoluteRange.contains($0) } - return Guardrail( - absoluteBounds: allowedBasalRates.first!...allowedBasalRates.last!, - recommendedBounds: allowedBasalRates.first!...allowedBasalRates.last!, - unit: .internationalUnitsPerHour, - startingSuggestion: allowedBasalRates.first! - ) - } - - static func maximumBasalRate( - supportedBasalRates: [Double], - scheduledBasalRange: ClosedRange?, - lowestCarbRatio: Double?, - maximumBasalRatePrecision decimalPlaces: Int = 3 - ) -> Guardrail { - - let maximumUpperBound = 70.0 / (lowestCarbRatio ?? carbRatio.absoluteBounds.lowerBound.doubleValue(for: .gramsPerUnit)) - let absoluteUpperBound = maximumUpperBound.matchingOrTruncatedValue(from: supportedBasalRates, withinDecimalPlaces: decimalPlaces) - - let recommendedHighScheduledBasalScaleFactor = 6.4 - let recommendedLowScheduledBasalScaleFactor = 2.1 - - let recommendedLowerBound: Double - let recommendedUpperBound: Double - if let highestScheduledBasalRate = scheduledBasalRange?.upperBound { - recommendedLowerBound = (recommendedLowScheduledBasalScaleFactor * highestScheduledBasalRate).matchingOrTruncatedValue(from: supportedBasalRates, withinDecimalPlaces: decimalPlaces) - recommendedUpperBound = (recommendedHighScheduledBasalScaleFactor * highestScheduledBasalRate).matchingOrTruncatedValue(from: supportedBasalRates, withinDecimalPlaces: decimalPlaces) - - let absoluteBounds = highestScheduledBasalRate...max(absoluteUpperBound, recommendedUpperBound) - let recommendedBounds = (recommendedLowerBound...recommendedUpperBound).clamped(to: absoluteBounds) - return Guardrail( - absoluteBounds: absoluteBounds, - recommendedBounds: recommendedBounds, - unit: .internationalUnitsPerHour - ) - - } else { - let bounds = supportedBasalRates.drop { $0 <= 0 }.first!...absoluteUpperBound - return Guardrail( - absoluteBounds: bounds, - recommendedBounds: bounds, - unit: .internationalUnitsPerHour, - startingSuggestion: 3.clamped(to: bounds) - ) - } - } - - static func selectableMaxBasalRates(supportedBasalRates: [Double], - scheduledBasalRange: ClosedRange?, - lowestCarbRatio: Double?, - maximumBasalRatePrecision decimalPlaces: Int = 3) -> [Double] { - let basalGuardrail = Guardrail.maximumBasalRate(supportedBasalRates: supportedBasalRates, scheduledBasalRange: scheduledBasalRange, lowestCarbRatio: lowestCarbRatio) - let maximumScheduledBasalRate = scheduledBasalRange?.upperBound ?? -Double.infinity - return supportedBasalRates - .drop { $0 < maximumScheduledBasalRate } - .filter { basalGuardrail.absoluteBounds.contains(HKQuantity(unit: .internationalUnitsPerHour, doubleValue: $0)) } - } - - static func maximumBolus(supportedBolusVolumes: [Double]) -> Guardrail { - let maxBolusThresholdUnits: Double = 30 - let maxBolusWarningThresholdUnits: Double = 20 - let supportedBolusVolumes = supportedBolusVolumes.filter { $0 > 0 && $0 <= maxBolusThresholdUnits } - let recommendedUpperBound = supportedBolusVolumes.last { $0 < maxBolusWarningThresholdUnits } - let recommendedBounds = supportedBolusVolumes.dropFirst().first!...recommendedUpperBound! - return Guardrail( - absoluteBounds: supportedBolusVolumes.first!...supportedBolusVolumes.last!, - recommendedBounds: recommendedBounds, - unit: .internationalUnit(), - startingSuggestion: 5.clamped(to: recommendedBounds) - ) - } - - static func selectableBolusVolumes(supportedBolusVolumes: [Double]) -> [Double] { - let guardrail = Guardrail.maximumBolus(supportedBolusVolumes: supportedBolusVolumes) - return supportedBolusVolumes.filter { - guardrail.absoluteBounds.contains(HKQuantity(unit: .internationalUnit(), doubleValue: $0)) - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/HKHealthStore.swift b/Dependencies/LoopKit/LoopKit/Extensions/HKHealthStore.swift deleted file mode 100644 index b7d3febc1..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/HKHealthStore.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// HKHealthStore.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import HealthKit - - -protocol HKSampleQueryTestable { - func executeSampleQuery( - for type: HKSampleType, - matching predicate: NSPredicate, - limit: Int, - sortDescriptors: [NSSortDescriptor]?, - resultsHandler: @escaping (_ query: HKSampleQuery, _ results: [HKSample]?, _ error: Error?) -> Void - ) -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/HKObject.swift b/Dependencies/LoopKit/LoopKit/Extensions/HKObject.swift deleted file mode 100644 index 37d7a2505..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/HKObject.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// HKObject.swift -// LoopKit -// -// Created by Darin Krauss on 8/11/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import HealthKit - -extension HKObject { - public var syncIdentifier: String? { metadata?[HKMetadataKeySyncIdentifier] as? String } - public var syncVersion: Int? { metadata?[HKMetadataKeySyncVersion] as? Int } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/HKQuantity.swift b/Dependencies/LoopKit/LoopKit/Extensions/HKQuantity.swift deleted file mode 100644 index 160e7f3bc..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/HKQuantity.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// HKQuantity.swift -// LoopKit -// -// Created by Nathan Racklyeft on 3/10/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -extension HKQuantity: Comparable { } - - -public func <(lhs: HKQuantity, rhs: HKQuantity) -> Bool { - return lhs.compare(rhs) == .orderedAscending -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/HKQuantitySample.swift b/Dependencies/LoopKit/LoopKit/Extensions/HKQuantitySample.swift deleted file mode 100644 index d19f6d500..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/HKQuantitySample.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// HKQuantitySample.swift -// LoopKit -// -// Created by Nate Racklyeft on 8/14/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -extension HKQuantitySample: SampleValue { } diff --git a/Dependencies/LoopKit/LoopKit/Extensions/HKUnit.swift b/Dependencies/LoopKit/LoopKit/Extensions/HKUnit.swift deleted file mode 100644 index a5f77cdd0..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/HKUnit.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// HKUnit.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/17/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -extension HKUnit { - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: .literUnit(with: .deci)) - }() - - static let millimolesPerLiter: HKUnit = { - return HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: .liter()) - }() - - static let milligramsPerDeciliterPerMinute: HKUnit = { - return HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) - }() - - static let millimolesPerLiterPerMinute: HKUnit = { - return HKUnit.millimolesPerLiter.unitDivided(by: .minute()) - }() - - static let internationalUnitsPerHour: HKUnit = { - return HKUnit.internationalUnit().unitDivided(by: .hour()) - }() - - static let gramsPerUnit: HKUnit = { - return HKUnit.gram().unitDivided(by: .internationalUnit()) - }() - - var foundationUnit: Unit? { - if self == HKUnit.milligramsPerDeciliter { - return UnitConcentrationMass.milligramsPerDeciliter - } - - if self == HKUnit.millimolesPerLiter { - return UnitConcentrationMass.millimolesPerLiter(withGramsPerMole: HKUnitMolarMassBloodGlucose) - } - - if self == HKUnit.gram() { - return UnitMass.grams - } - - return nil - } - - /// The smallest value expected to be visible on a chart - var chartableIncrement: Double { - if self == .milligramsPerDeciliter { - return 1 - } else { - return 1 / 25 - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/MutableCollection.swift b/Dependencies/LoopKit/LoopKit/Extensions/MutableCollection.swift deleted file mode 100644 index fbf3ebf8d..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/MutableCollection.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// MutableCollection.swift -// LoopKit Example -// -// Created by Michael Pangburn on 4/21/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -extension MutableCollection { - public mutating func mutateEach(_ body: (inout Element) throws -> Void) rethrows { - var index = startIndex - while index != endIndex { - try body(&self[index]) - formIndex(after: &index) - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/NSUserActivity+CarbKit.swift b/Dependencies/LoopKit/LoopKit/Extensions/NSUserActivity+CarbKit.swift deleted file mode 100644 index 1a7743acc..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/NSUserActivity+CarbKit.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// NSUserActivity+CarbKit.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - - -// FIXME: this class should be in Loop now that the carb entry flow is there -/// Conveniences for activity handoff and restoration of creating a carb entry -extension NSUserActivity { - public static let newCarbEntryActivityType = "NewCarbEntry" - - public static let newCarbEntryUserInfoKey = "NewCarbEntry" - public static let carbEntryIsMissedMealUserInfoKey = "CarbEntryIsMissedMeal" - - public class func forNewCarbEntry() -> NSUserActivity { - let activity = NSUserActivity(activityType: newCarbEntryActivityType) - activity.requiredUserInfoKeys = [] - return activity - } - - public func update(from entry: NewCarbEntry?, isMissedMeal: Bool = false) { - if let rawValue = entry?.rawValue { - addUserInfoEntries(from: [ - NSUserActivity.newCarbEntryUserInfoKey: rawValue, - NSUserActivity.carbEntryIsMissedMealUserInfoKey: isMissedMeal - ]) - } else { - userInfo = nil - } - } - - public var newCarbEntry: NewCarbEntry? { - guard let rawValue = userInfo?[NSUserActivity.newCarbEntryUserInfoKey] as? NewCarbEntry.RawValue else { - return nil - } - - return NewCarbEntry(rawValue: rawValue) - } - - public var entryisMissedMeal: Bool { - guard newCarbEntry != nil else { - return false - } - - return userInfo?[NSUserActivity.carbEntryIsMissedMealUserInfoKey] as? Bool ?? false - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/NumberFormatter.swift b/Dependencies/LoopKit/LoopKit/Extensions/NumberFormatter.swift deleted file mode 100644 index 6d9d3ab78..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/NumberFormatter.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// NSNumberFormatter.swift -// Loop -// -// Created by Nate Racklyeft on 9/5/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -extension NumberFormatter { - func string(from number: Double) -> String? { - return string(from: NSNumber(value: number)) - } - - func string(from number: Double, unit: String, style: Formatter.UnitStyle = .medium, avoidLineBreaking: Bool = true) -> String? { - guard let stringValue = string(from: number) else { - return nil - } - - let separator: String - switch style { - case .long: - separator = " " - case .medium: - separator = avoidLineBreaking ? .nonBreakingSpace : " " - case .short: - fallthrough - @unknown default: - separator = avoidLineBreaking ? .wordJoiner : "" - } - - let unit = avoidLineBreaking ? unit.replacingOccurrences(of: "/", with: "\(String.wordJoiner)/\(String.wordJoiner)") : unit - - return String( - format: LocalizedString("%1$@%2$@%3$@", comment: "String format for value with units (1: value, 2: separator, 3: units)"), - stringValue, - separator, - unit - ) - } -} - -public extension String { - static let nonBreakingSpace = "\u{00a0}" - static let wordJoiner = "\u{2060}" -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/OSLog.swift b/Dependencies/LoopKit/LoopKit/Extensions/OSLog.swift deleted file mode 100644 index ac86a5b73..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/OSLog.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// OSLog.swift -// Loop -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import os.log - - -extension OSLog { - convenience init(category: String) { - self.init(subsystem: "com.loopkit.LoopKit", category: category) - } - - func debug(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .debug, args) - } - - func info(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .info, args) - } - - func `default`(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .default, args) - } - - func error(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .error, args) - } - - private func log(_ message: StaticString, type: OSLogType, _ args: [CVarArg]) { - switch args.count { - case 0: - os_log(message, log: self, type: type) - case 1: - os_log(message, log: self, type: type, args[0]) - case 2: - os_log(message, log: self, type: type, args[0], args[1]) - case 3: - os_log(message, log: self, type: type, args[0], args[1], args[2]) - case 4: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3]) - case 5: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4]) - default: - os_log(message, log: self, type: type, args) - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/OutputStream.swift b/Dependencies/LoopKit/LoopKit/Extensions/OutputStream.swift deleted file mode 100644 index ff7f0c17f..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/OutputStream.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// OutputStream.swift -// LoopKit -// -// Created by Darin Krauss on 8/28/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension OutputStream { - func write(_ string: String) throws { - if let streamError = streamError { - throw streamError - } - let bytes = [UInt8](string.utf8) - write(bytes, maxLength: bytes.count) - if let streamError = streamError { - throw streamError - } - } - - func write(_ data: Data) throws { - if let streamError = streamError { - throw streamError - } - if data.isEmpty { - return - } - _ = data.withUnsafeBytes { (unsafeRawBuffer: UnsafeRawBufferPointer) -> UInt8 in - if let unsafe = unsafeRawBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) { - write(unsafe, maxLength: unsafeRawBuffer.count) - } - return 0 - } - if let streamError = streamError { - throw streamError - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/Sequence.swift b/Dependencies/LoopKit/LoopKit/Extensions/Sequence.swift deleted file mode 100644 index 190976c0e..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/Sequence.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// Sequence.swift -// LoopKit -// -// Created by Michael Pangburn on 6/23/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -extension Sequence { - func range(of metricForElement: (Element) throws -> Metric) rethrows -> ClosedRange? { - try lazy.map(metricForElement).reduce(nil) { range, metric in - if let range = range { - return range.expandedToInclude(metric) - } else { - return metric...metric - } - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/TimeInterval.swift b/Dependencies/LoopKit/LoopKit/Extensions/TimeInterval.swift deleted file mode 100644 index a568b77b8..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/TimeInterval.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// NSTimeInterval.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension TimeInterval { - static func minutes(_ minutes: Double) -> TimeInterval { - return self.init(minutes: minutes) - } - - static func hours(_ hours: Double) -> TimeInterval { - return self.init(hours: hours) - } - - init(minutes: Double) { - self.init(minutes * 60) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - var minutes: Double { - return self / 60.0 - } - - var hours: Double { - return minutes / 60.0 - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/TimeZone.swift b/Dependencies/LoopKit/LoopKit/Extensions/TimeZone.swift deleted file mode 100644 index 4b912b912..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/TimeZone.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// TimeZone.swift -// LoopKit -// -// Created by Nate Racklyeft on 10/2/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - - -extension TimeZone { - static var currentFixed: TimeZone { - return TimeZone(secondsFromGMT: TimeZone.current.secondsFromGMT())! - } -} diff --git a/Dependencies/LoopKit/LoopKit/Extensions/UUID.swift b/Dependencies/LoopKit/LoopKit/Extensions/UUID.swift deleted file mode 100644 index ee61eca54..000000000 --- a/Dependencies/LoopKit/LoopKit/Extensions/UUID.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// UUID.swift -// LoopKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - - -extension UUID { - var data: Data { - return withUnsafePointer(to: uuid) { - return Data(bytes: $0, count: MemoryLayout.size(ofValue: uuid)) - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseChange.swift b/Dependencies/LoopKit/LoopKit/GlucoseChange.swift deleted file mode 100644 index 6b8edce05..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseChange.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// GlucoseChange.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import HealthKit - - -public struct GlucoseChange: SampleValue, Equatable { - public var startDate: Date - public var endDate: Date - public var quantity: HKQuantity -} - - -extension GlucoseChange { - mutating public func append(_ effect: GlucoseEffect) { - startDate = min(effect.startDate, startDate) - endDate = max(effect.endDate, endDate) - quantity = HKQuantity( - unit: .milligramsPerDeciliter, - doubleValue: quantity.doubleValue(for: .milligramsPerDeciliter) + effect.quantity.doubleValue(for: .milligramsPerDeciliter) - ) - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseEffect.swift b/Dependencies/LoopKit/LoopKit/GlucoseEffect.swift deleted file mode 100644 index e7cac4069..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseEffect.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// GlucoseEffect.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/24/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -public struct GlucoseEffect: GlucoseValue, Equatable { - public let startDate: Date - public let quantity: HKQuantity - - public init(startDate: Date, quantity: HKQuantity) { - self.startDate = startDate - self.quantity = quantity - } -} - - -extension GlucoseEffect: Comparable { - public static func <(lhs: GlucoseEffect, rhs: GlucoseEffect) -> Bool { - return lhs.startDate < rhs.startDate - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseEffectVelocity.swift b/Dependencies/LoopKit/LoopKit/GlucoseEffectVelocity.swift deleted file mode 100644 index eb39a24be..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseEffectVelocity.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// GlucoseEffectVelocity.swift -// LoopKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - - -/// The first-derivative of GlucoseEffect, blood glucose over time. -public struct GlucoseEffectVelocity: SampleValue { - public let startDate: Date - public let endDate: Date - public let quantity: HKQuantity - - public init(startDate: Date, endDate: Date, quantity: HKQuantity) { - self.startDate = startDate - self.endDate = endDate - self.quantity = quantity - } -} - - -extension GlucoseEffectVelocity { - static let perSecondUnit = HKUnit.milligramsPerDeciliter.unitDivided(by: .second()) - - /// The integration of the velocity span - public var effect: GlucoseEffect { - let duration = endDate.timeIntervalSince(startDate) - let velocityPerSecond = quantity.doubleValue(for: GlucoseEffectVelocity.perSecondUnit) - - return GlucoseEffect( - startDate: endDate, - quantity: HKQuantity( - unit: .milligramsPerDeciliter, - doubleValue: velocityPerSecond * duration - ) - ) - } - - /// The integration of the velocity span from `start` to `end` - public func effect(from start: Date, to end: Date) -> GlucoseEffect? { - guard - start <= end, - startDate <= start, - end <= endDate - else { - return nil - } - - let duration = end.timeIntervalSince(start) - let velocityPerSecond = quantity.doubleValue(for: GlucoseEffectVelocity.perSecondUnit) - - return GlucoseEffect( - startDate: end, - quantity: HKQuantity( - unit: .milligramsPerDeciliter, - doubleValue: velocityPerSecond * duration - ) - ) - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseKit/CachedGlucoseObject+CoreDataClass.swift b/Dependencies/LoopKit/LoopKit/GlucoseKit/CachedGlucoseObject+CoreDataClass.swift deleted file mode 100644 index c5d0066f4..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseKit/CachedGlucoseObject+CoreDataClass.swift +++ /dev/null @@ -1,201 +0,0 @@ -// -// CachedGlucoseObject+CoreDataClass.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// -// - -import Foundation -import CoreData -import HealthKit - - -class CachedGlucoseObject: NSManagedObject { - var syncVersion: Int? { - get { - willAccessValue(forKey: "syncVersion") - defer { didAccessValue(forKey: "syncVersion") } - return primitiveSyncVersion?.intValue - } - set { - willChangeValue(forKey: "syncVersion") - defer { didChangeValue(forKey: "syncVersion") } - primitiveSyncVersion = newValue.map { NSNumber(value: $0) } - } - } - - var device: HKDevice? { - get { - willAccessValue(forKey: "device") - defer { didAccessValue(forKey: "device") } - return primitiveDevice.flatMap { try? NSKeyedUnarchiver.unarchivedObject(ofClass: HKDevice.self, from: $0) } - } - set { - willChangeValue(forKey: "device") - defer { didChangeValue(forKey: "device") } - primitiveDevice = newValue.flatMap { try? NSKeyedArchiver.archivedData(withRootObject: $0, requiringSecureCoding: false) } - } - } - - var condition: GlucoseCondition? { - get { - willAccessValue(forKey: "condition") - defer { didAccessValue(forKey: "condition") } - return primitiveCondition.flatMap { GlucoseCondition(rawValue: $0) } - } - set { - willChangeValue(forKey: "condition") - defer { didChangeValue(forKey: "condition") } - primitiveCondition = newValue.map { $0.rawValue } - } - } - - var trend: GlucoseTrend? { - get { - willAccessValue(forKey: "trend") - defer { didAccessValue(forKey: "trend") } - return primitiveTrend.flatMap { GlucoseTrend(rawValue: $0.intValue) } - } - set { - willChangeValue(forKey: "trend") - defer { didChangeValue(forKey: "trend") } - primitiveTrend = newValue.map { NSNumber(value: $0.rawValue) } - } - } - - var hasUpdatedModificationCounter: Bool { changedValues().keys.contains("modificationCounter") } - - func updateModificationCounter() { setPrimitiveValue(managedObjectContext!.modificationCounter!, forKey: "modificationCounter") } - - override func awakeFromInsert() { - super.awakeFromInsert() - updateModificationCounter() - } - - override func willSave() { - if isUpdated && !hasUpdatedModificationCounter { - updateModificationCounter() - } - super.willSave() - } -} - -// MARK: - Helpers - -extension CachedGlucoseObject { - var quantity: HKQuantity { HKQuantity(unit: HKUnit(from: unitString), doubleValue: value) } - - var quantitySample: HKQuantitySample { - var metadata: [String: Any] = [:] - metadata[HKMetadataKeySyncIdentifier] = syncIdentifier - metadata[HKMetadataKeySyncVersion] = syncVersion - if isDisplayOnly { - metadata[MetadataKeyGlucoseIsDisplayOnly] = true - } - if wasUserEntered { - metadata[HKMetadataKeyWasUserEntered] = true - } - metadata[MetadataKeyGlucoseCondition] = condition?.rawValue - metadata[MetadataKeyGlucoseTrend] = trend?.symbol - metadata[MetadataKeyGlucoseTrendRateUnit] = trendRateUnit - metadata[MetadataKeyGlucoseTrendRateValue] = trendRateValue - - return HKQuantitySample( - type: HKQuantityType.quantityType(forIdentifier: .bloodGlucose)!, - quantity: quantity, - start: startDate, - end: startDate, - device: device, - metadata: metadata - ) - } - - var trendRate: HKQuantity? { - get { - guard let trendRateUnit = trendRateUnit, let trendRateValue = trendRateValue else { - return nil - } - return HKQuantity(unit: HKUnit(from: trendRateUnit), doubleValue: trendRateValue.doubleValue) - } - - set { - if let newValue = newValue { - let unit = HKUnit(from: unitString).unitDivided(by: .minute()) - trendRateUnit = unit.unitString - trendRateValue = NSNumber(value: newValue.doubleValue(for: unit)) - } else { - trendRateUnit = nil - trendRateValue = nil - } - } - } -} - -// MARK: - Operations - -extension CachedGlucoseObject { - - /// Creates (initializes) a `CachedGlucoseObject` from a new CGM sample from Loop. - /// - parameters: - /// - sample: A new glucose (CGM) sample to copy data from. - /// - provenanceIdentifier: A string uniquely identifying the provenance (origin) of the sample. - /// - healthKitStorageDelay: The amount of time (seconds) to delay writing this sample to HealthKit. A `nil` here means this sample is not eligible (i.e. authorized) to be written to HealthKit. - func create(from sample: NewGlucoseSample, provenanceIdentifier: String, healthKitStorageDelay: TimeInterval?) { - self.uuid = nil - self.provenanceIdentifier = provenanceIdentifier - self.syncIdentifier = sample.syncIdentifier - self.syncVersion = sample.syncVersion - self.value = sample.quantity.doubleValue(for: .milligramsPerDeciliter) - self.unitString = HKUnit.milligramsPerDeciliter.unitString - self.startDate = sample.date - self.isDisplayOnly = sample.isDisplayOnly - self.wasUserEntered = sample.wasUserEntered - self.device = sample.device - self.condition = sample.condition - self.trend = sample.trend - self.trendRate = sample.trendRate - self.healthKitEligibleDate = healthKitStorageDelay.map { sample.date.addingTimeInterval($0) } - } - - // HealthKit - func create(from sample: HKQuantitySample) { - self.uuid = sample.uuid - self.provenanceIdentifier = sample.provenanceIdentifier - self.syncIdentifier = sample.syncIdentifier - self.syncVersion = sample.syncVersion - self.value = sample.quantity.doubleValue(for: .milligramsPerDeciliter) - self.unitString = HKUnit.milligramsPerDeciliter.unitString - self.startDate = sample.startDate - self.isDisplayOnly = sample.isDisplayOnly - self.wasUserEntered = sample.wasUserEntered - self.device = sample.device - self.condition = sample.condition - self.trend = sample.trend - self.trendRate = sample.trendRate - // The assumption here is that if this is created from a HKQuantitySample, it is coming out of HealthKit, and - // therefore does not need to be written to HealthKit. - self.healthKitEligibleDate = nil - } -} - -// MARK: - Watch Synchronization - -extension CachedGlucoseObject { - func update(from sample: StoredGlucoseSample) { - self.uuid = sample.uuid - self.provenanceIdentifier = sample.provenanceIdentifier - self.syncIdentifier = sample.syncIdentifier - self.syncVersion = sample.syncVersion - self.value = sample.quantity.doubleValue(for: .milligramsPerDeciliter) - self.unitString = HKUnit.milligramsPerDeciliter.unitString - self.startDate = sample.startDate - self.isDisplayOnly = sample.isDisplayOnly - self.wasUserEntered = sample.wasUserEntered - self.device = sample.device - self.condition = sample.condition - self.trend = sample.trend - self.trendRate = sample.trendRate - self.healthKitEligibleDate = sample.healthKitEligibleDate - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseKit/CachedGlucoseObject+CoreDataProperties.swift b/Dependencies/LoopKit/LoopKit/GlucoseKit/CachedGlucoseObject+CoreDataProperties.swift deleted file mode 100644 index dc4eba61e..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseKit/CachedGlucoseObject+CoreDataProperties.swift +++ /dev/null @@ -1,84 +0,0 @@ -// -// CachedGlucoseObject+CoreDataProperties.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// -// - -import Foundation -import CoreData -import HealthKit - - -extension CachedGlucoseObject { - - @nonobjc public class func fetchRequest() -> NSFetchRequest { - return NSFetchRequest(entityName: "CachedGlucoseObject") - } - - /// This is the UUID provided from HealthKit. Nil if not (yet) stored in HealthKit. Note: it is _not_ a unique identifier for this object. - @NSManaged public var uuid: UUID? - @NSManaged public var provenanceIdentifier: String - @NSManaged public var syncIdentifier: String? - @NSManaged public var primitiveSyncVersion: NSNumber? - @NSManaged public var value: Double - @NSManaged public var unitString: String - @NSManaged public var startDate: Date - @NSManaged public var isDisplayOnly: Bool - @NSManaged public var wasUserEntered: Bool - @NSManaged public var modificationCounter: Int64 - @NSManaged public var primitiveDevice: Data? - @NSManaged public var primitiveCondition: String? - @NSManaged public var primitiveTrend: NSNumber? - @NSManaged public var trendRateUnit: String? - @NSManaged public var trendRateValue: NSNumber? - /// This is the date when this object is eligible for writing to HealthKit. For example, if it is required to delay writing - /// data to HealthKit, this date will be in the future. If the date is in the past, then it is written to HealthKit as soon as possible, - /// and this value is set to `nil`. A `nil` value either means that this object has already been written to HealthKit, or it is - /// not eligible for HealthKit in the first place (for example, if a user has denied permissions at the time the sample was taken). - @NSManaged public var healthKitEligibleDate: Date? -} - -extension CachedGlucoseObject: Encodable { - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encodeIfPresent(uuid, forKey: .uuid) - try container.encode(provenanceIdentifier, forKey: .provenanceIdentifier) - try container.encodeIfPresent(syncIdentifier, forKey: .syncIdentifier) - try container.encodeIfPresent(syncVersion, forKey: .syncVersion) - try container.encode(value, forKey: .value) - try container.encode(unitString, forKey: .unitString) - try container.encode(startDate, forKey: .startDate) - try container.encode(isDisplayOnly, forKey: .isDisplayOnly) - try container.encode(wasUserEntered, forKey: .wasUserEntered) - try container.encode(modificationCounter, forKey: .modificationCounter) - try container.encodeIfPresent(device, forKey: .device) - try container.encodeIfPresent(condition, forKey: .condition) - try container.encodeIfPresent(trend, forKey: .trend) - try container.encodeIfPresent(trendRateUnit, forKey: .trendRateUnit) - try container.encodeIfPresent(trendRateValue?.doubleValue, forKey: .trendRateValue) - try container.encodeIfPresent(healthKitEligibleDate, forKey: .healthKitEligibleDate) - } - - private enum CodingKeys: String, CodingKey { - case uuid - case provenanceIdentifier - case syncIdentifier - case syncVersion - case value - case unitString - case startDate - case isDisplayOnly - case wasUserEntered - case modificationCounter - case device - case condition - case trend - case trendRateUnit - case trendRateValue - case healthKitEligibleDate - } -} - -extension GlucoseTrend: Codable {} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseCondition.swift b/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseCondition.swift deleted file mode 100644 index 6659718fa..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseCondition.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// GlucoseCondition.swift -// LoopKit -// -// Created by Darin Krauss on 9/3/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -public enum GlucoseCondition: String, Codable { - case belowRange - case aboveRange -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseDisplayable.swift b/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseDisplayable.swift deleted file mode 100644 index ec5025f76..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseDisplayable.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// GlucoseDisplayable.swift -// Loop -// -// Created by Nate Racklyeft on 8/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - -public protocol GlucoseDisplayable { - /// Returns whether the current state is valid - var isStateValid: Bool { get } - - /// Describes the state of the sensor in the current localization - var stateDescription: String { get } - - /// Enumerates the trend of the sensor values - var trendType: GlucoseTrend? { get } - - /// The trend rate of the sensor values, if available - var trendRate: HKQuantity? { get } - - /// Returns whether the data is from a locally-connected device - var isLocal: Bool { get } - - /// enumerates the glucose value type (e.g., normal, low, high) - var glucoseRangeCategory: GlucoseRangeCategory? { get } -} - - -extension GlucoseDisplayable { - public var stateDescription: String { - if isStateValid { - return LocalizedString("OK", comment: "Sensor state description for the valid state") - } else { - return LocalizedString("Needs Attention", comment: "Sensor state description for the non-valid state") - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseMath.swift b/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseMath.swift deleted file mode 100644 index 27e911dac..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseMath.swift +++ /dev/null @@ -1,219 +0,0 @@ -// -// GlucoseMath.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/24/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -fileprivate extension Collection where Element == (x: Double, y: Double) { - /** - Calculates slope and intercept using linear regression - - This implementation is not suited for large datasets. - - - parameter points: An array of tuples containing x and y values - - - returns: A tuple of slope and intercept values - */ - func linearRegression() -> (slope: Double, intercept: Double) { - var sumX = 0.0 - var sumY = 0.0 - var sumXY = 0.0 - var sumX² = 0.0 - var sumY² = 0.0 - let count = Double(self.count) - - for point in self { - sumX += point.x - sumY += point.y - sumXY += (point.x * point.y) - sumX² += (point.x * point.x) - sumY² += (point.y * point.y) - } - - let slope = ((count * sumXY) - (sumX * sumY)) / ((count * sumX²) - (sumX * sumX)) - let intercept = (sumY * sumX² - (sumX * sumXY)) / (count * sumX² - (sumX * sumX)) - - return (slope: slope, intercept: intercept) - } -} - - -extension BidirectionalCollection where Element: GlucoseSampleValue, Index == Int { - - /// Whether the collection contains no calibration entries - /// Runtime: O(n) - var isCalibrated: Bool { - return filter({ $0.isDisplayOnly }).count == 0 - } - - /// Filters a timeline of glucose samples to only include those after the last calibration. - func filterAfterCalibration() -> [Element] { - var postCalibration = true - - return reversed().filter({ (sample) in - if sample.isDisplayOnly { - postCalibration = false - } - - return postCalibration - }).reversed() - } - - /// Whether the collection can be considered continuous - /// - /// - Parameters: - /// - interval: The interval between readings, on average, used to determine if we have a contiguous set of values - /// - Returns: True if the samples are continuous - func isContinuous(within interval: TimeInterval = TimeInterval(minutes: 5)) -> Bool { - if let first = first, - let last = last, - // Ensure that the entries are contiguous - abs(first.startDate.timeIntervalSince(last.startDate)) < interval * TimeInterval(count) - { - return true - } - - return false - } - - /// Calculates the short-term predicted momentum effect using linear regression - /// - /// - Parameters: - /// - duration: The duration of the effects - /// - delta: The time differential for the returned values - /// - velocityMaximum: The limit on how fast the momentum effect can rise. Defaults to 4 mg/dL/min based on physiological rates - /// - Returns: An array of glucose effects - func linearMomentumEffect( - duration: TimeInterval = TimeInterval(minutes: 30), - delta: TimeInterval = TimeInterval(minutes: 5), - velocityMaximum: HKQuantity = HKQuantity(unit: HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()), doubleValue: 4.0) - ) -> [GlucoseEffect] { - guard - self.count > 2, // Linear regression isn't much use without 3 or more entries. - isContinuous() && isCalibrated && hasSingleProvenance, - let firstSample = self.first, - let lastSample = self.last, - let (startDate, endDate) = LoopMath.simulationDateRangeForSamples([lastSample], duration: duration, delta: delta) - else { - return [] - } - - /// Choose a unit to use during raw value calculation - let unit = HKUnit.milligramsPerDeciliter - - let (slope: slope, intercept: _) = self.map { ( - x: $0.startDate.timeIntervalSince(firstSample.startDate), - y: $0.quantity.doubleValue(for: unit) - ) }.linearRegression() - - guard slope.isFinite else { - return [] - } - - let limitedSlope = Swift.min(slope, velocityMaximum.doubleValue(for: unit.unitDivided(by: .second()))) - - var date = startDate - var values = [GlucoseEffect]() - - repeat { - let value = Swift.max(0, date.timeIntervalSince(lastSample.startDate)) * limitedSlope - let momentumEffect = GlucoseEffect(startDate: date, quantity: HKQuantity(unit: unit, doubleValue: value)) - - values.append(momentumEffect) - date = date.addingTimeInterval(delta) - } while date <= endDate - - return values - } -} - - -extension Collection where Element: GlucoseSampleValue, Index == Int { - /// Whether the collection is all from the same source. - /// Runtime: O(n) - var hasSingleProvenance: Bool { - let firstProvenance = self.first?.provenanceIdentifier - - for sample in self { - if sample.provenanceIdentifier != firstProvenance { - return false - } - } - - return true - } - - /// Calculates a timeline of effect velocity (glucose/time) observed in glucose readings that counteract the specified effects. - /// - /// - Parameter effects: Glucose effects to be countered, in chronological order - /// - Returns: An array of velocities describing the change in glucose samples compared to the specified effects - func counteractionEffects(to effects: [GlucoseEffect]) -> [GlucoseEffectVelocity] { - let mgdL = HKUnit.milligramsPerDeciliter - let velocityUnit = GlucoseEffectVelocity.perSecondUnit - var velocities = [GlucoseEffectVelocity]() - - var effectIndex = 0 - var startGlucose: Element! = self.first - - for endGlucose in self.dropFirst() { - // Find a valid change in glucose, requiring identical provenance and no calibration - let glucoseChange = endGlucose.quantity.doubleValue(for: mgdL) - startGlucose.quantity.doubleValue(for: mgdL) - let timeInterval = endGlucose.startDate.timeIntervalSince(startGlucose.startDate) - - guard timeInterval > .minutes(4) else { - continue - } - - defer { - startGlucose = endGlucose - } - - guard startGlucose.provenanceIdentifier == endGlucose.provenanceIdentifier, - !startGlucose.isDisplayOnly, !endGlucose.isDisplayOnly - else { - continue - } - - // Compare that to a change in insulin effects - guard effects.count > effectIndex else { - break - } - - var startEffect: GlucoseEffect? - var endEffect: GlucoseEffect? - - for effect in effects[effectIndex..= startGlucose.startDate { - startEffect = effect - } else if endEffect == nil && effect.startDate >= endGlucose.startDate { - endEffect = effect - break - } - - effectIndex += 1 - } - - guard let startEffectValue = startEffect?.quantity.doubleValue(for: mgdL), - let endEffectValue = endEffect?.quantity.doubleValue(for: mgdL) - else { - break - } - - let effectChange = endEffectValue - startEffectValue - let discrepancy = glucoseChange - effectChange - - let averageVelocity = HKQuantity(unit: velocityUnit, doubleValue: discrepancy / timeInterval) - let effect = GlucoseEffectVelocity(startDate: startGlucose.startDate, endDate: endGlucose.startDate, quantity: averageVelocity) - - velocities.append(effect) - } - - return velocities - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseRangeCategory.swift b/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseRangeCategory.swift deleted file mode 100644 index a51625844..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseRangeCategory.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// GlucoseRangeCategory.swift -// LoopKit -// -// Created by Nathaniel Hamming on 2020-06-23. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum GlucoseRangeCategory: Int, CaseIterable { - case belowRange - case urgentLow - case low - case normal - case high - case aboveRange -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseSampleValue.swift b/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseSampleValue.swift deleted file mode 100644 index 6a8d2e52f..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseSampleValue.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// GlucoseSampleValue.swift -// LoopKit -// -// Created by Nathan Racklyeft on 3/6/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - -public protocol GlucoseSampleValue: GlucoseValue { - /// Uniquely identifies the source of the sample. - var provenanceIdentifier: String { get } - - /// Whether the glucose value was provided for visual consistency, rather than an actual, calibrated reading. - var isDisplayOnly: Bool { get } - - /// Whether the glucose value was entered by the user. - var wasUserEntered: Bool { get } - - /// Any condition applied to the sample. - var condition: GlucoseCondition? { get } - - /// The trend rate of the sample. - var trendRate: HKQuantity? { get } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseStore.swift b/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseStore.swift deleted file mode 100644 index 8c0289e57..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseStore.swift +++ /dev/null @@ -1,912 +0,0 @@ -// -// GlucoseStore.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/24/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import CoreData -import HealthKit -import os.log - -public protocol GlucoseStoreDelegate: AnyObject { - - /** - Informs the delegate that the glucose store has updated glucose data. - - - Parameter glucoseStore: The glucose store that has updated glucose data. - */ - func glucoseStoreHasUpdatedGlucoseData(_ glucoseStore: GlucoseStore) - -} - -/** - Manages storage, retrieval, and calculation of glucose data. - - There are three tiers of storage: - - * Persistant cache, stored in Core Data, used to ensure access if the app is suspended and re-launched while the Health database - * is protected and to provide data for upload to remote data services. Backfilled from HealthKit data up to observation interval. -``` - 0 [max(cacheLength, momentumDataInterval, observationInterval)] - |––––| -``` - * HealthKit data, managed by the current application -``` - 0 [managedDataInterval?] - |––––––––––––| -``` - * HealthKit data, managed by the manufacturer's application -``` - [managedDataInterval?] [maxPurgeInterval] - |–––––––––---> -``` - */ -public final class GlucoseStore: HealthKitSampleStore { - - /// Notification posted when glucose samples were changed, either via direct add or from HealthKit - public static let glucoseSamplesDidChange = NSNotification.Name(rawValue: "com.loopkit.GlucoseStore.glucoseSamplesDidChange") - - public weak var delegate: GlucoseStoreDelegate? - - private let glucoseType = HKQuantityType.quantityType(forIdentifier: .bloodGlucose)! - - /// The oldest interval to include when purging managed data - private let maxPurgeInterval: TimeInterval = TimeInterval(hours: 24) * 7 - - /// The interval before which glucose values should be purged from HealthKit. If nil, glucose values are not purged. - public var managedDataInterval: TimeInterval? { - get { - return lockedManagedDataInterval.value - } - set { - lockedManagedDataInterval.value = newValue - } - } - private let lockedManagedDataInterval = Locked(nil) - - /// The interval of glucose data to keep in cache - public let cacheLength: TimeInterval - - /// The interval of glucose data to use for momentum calculation - public let momentumDataInterval: TimeInterval - - /// The interval to observe HealthKit data to populate the cache - public let observationInterval: TimeInterval - - private let queue = DispatchQueue(label: "com.loopkit.GlucoseStore.queue", qos: .utility) - - private let log = OSLog(category: "GlucoseStore") - - /// The most-recent glucose value. - public private(set) var latestGlucose: GlucoseSampleValue? { - get { - return lockedLatestGlucose.value - } - set { - lockedLatestGlucose.value = newValue - } - } - private let lockedLatestGlucose = Locked(nil) - - private let storeSamplesToHealthKit: Bool - - private let cacheStore: PersistenceController - - private let provenanceIdentifier: String - - public var healthKitStorageDelay: TimeInterval = 0 - - // If HealthKit sharing is not authorized, `nil` will prevent later storage - var healthKitStorageDelayIfAllowed: TimeInterval? { storeSamplesToHealthKit && sharingAuthorized ? healthKitStorageDelay : nil } - - static let healthKitQueryAnchorMetadataKey = "com.loopkit.GlucoseStore.hkQueryAnchor" - - public init( - healthStore: HKHealthStore, - observeHealthKitSamplesFromOtherApps: Bool = true, - storeSamplesToHealthKit: Bool = true, - cacheStore: PersistenceController, - observationEnabled: Bool = true, - cacheLength: TimeInterval = 60 /* minutes */ * 60 /* seconds */, - momentumDataInterval: TimeInterval = 15 /* minutes */ * 60 /* seconds */, - observationInterval: TimeInterval? = nil, - provenanceIdentifier: String - ) { - let cacheLength = max(cacheLength, momentumDataInterval, observationInterval ?? 0) - - self.cacheStore = cacheStore - self.momentumDataInterval = momentumDataInterval - - self.storeSamplesToHealthKit = storeSamplesToHealthKit - self.cacheLength = cacheLength - self.observationInterval = observationInterval ?? cacheLength - self.provenanceIdentifier = provenanceIdentifier - - super.init(healthStore: healthStore, - observeHealthKitSamplesFromCurrentApp: true, - observeHealthKitSamplesFromOtherApps: observeHealthKitSamplesFromOtherApps, - type: glucoseType, - observationStart: Date(timeIntervalSinceNow: -self.observationInterval), - observationEnabled: observationEnabled) - - cacheStore.onReady { (error) in - guard error == nil else { - return - } - - cacheStore.fetchAnchor(key: GlucoseStore.healthKitQueryAnchorMetadataKey) { (anchor) in - self.queue.async { - self.setInitialQueryAnchor(anchor) - - self.updateLatestGlucose() - } - } - } - } - - // MARK: - HealthKitSampleStore - - override func storeQueryAnchor(_ anchor: HKQueryAnchor) { - cacheStore.storeAnchor(anchor, key: GlucoseStore.healthKitQueryAnchorMetadataKey) - } - - override func processResults(from query: HKAnchoredObjectQuery, added: [HKSample], deleted: [HKDeletedObject], anchor: HKQueryAnchor, completion: @escaping (Bool) -> Void) { - queue.async { - var changed = false - var error: Error? - - self.cacheStore.managedObjectContext.performAndWait { - do { - // Add new samples - if let samples = added as? [HKQuantitySample] { - for sample in samples { - if try self.addGlucoseSample(for: sample) { - self.log.debug("Saved sample %@ into cache from HKAnchoredObjectQuery", sample.uuid.uuidString) - changed = true - } else { - self.log.default("Sample %@ from HKAnchoredObjectQuery already present in cache", sample.uuid.uuidString) - } - } - } - - // Delete deleted samples - let count = try self.deleteGlucoseSamples(withUUIDs: deleted.map { $0.uuid }) - if count > 0 { - self.log.debug("Deleted %d samples from cache from HKAnchoredObjectQuery", count) - changed = true - } - - guard changed else { - return - } - - error = self.cacheStore.save() - } catch let coreDataError { - error = coreDataError - } - } - - guard error == nil else { - completion(false) - return - } - - if !changed { - completion(true) - return - } - - // Purge expired managed data from HealthKit - if let newestStartDate = added.map({ $0.startDate }).max() { - self.purgeExpiredManagedDataFromHealthKit(before: newestStartDate) - } - - self.handleUpdatedGlucoseData() - completion(true) - } - } -} - -// MARK: - Fetching - -extension GlucoseStore { - /// Retrieves glucose samples within the specified date range. - /// - /// - Parameters: - /// - start: The earliest date of glucose samples to retrieve, if provided. - /// - end: The latest date of glucose samples to retrieve, if provided. - /// - completion: A closure called once the glucose samples have been retrieved. - /// - result: An array of glucose samples, in chronological order by startDate, or error. - public func getGlucoseSamples(start: Date? = nil, end: Date? = nil, completion: @escaping (_ result: Result<[StoredGlucoseSample], Error>) -> Void) { - queue.async { - completion(self.getGlucoseSamples(start: start, end: end)) - } - } - - private func getGlucoseSamples(start: Date? = nil, end: Date? = nil) -> Result<[StoredGlucoseSample], Error> { - dispatchPrecondition(condition: .onQueue(queue)) - - var samples: [StoredGlucoseSample] = [] - var error: Error? - - cacheStore.managedObjectContext.performAndWait { - do { - samples = try self.getCachedGlucoseObjects(start: start, end: end).map { StoredGlucoseSample(managedObject: $0) } - } catch let coreDataError { - error = coreDataError - } - } - - if let error = error { - return .failure(error) - } - - return .success(samples) - } - - private func getCachedGlucoseObjects(start: Date? = nil, end: Date? = nil) throws -> [CachedGlucoseObject] { - dispatchPrecondition(condition: .onQueue(queue)) - - var predicates: [NSPredicate] = [] - if let start = start { - predicates.append(NSPredicate(format: "startDate >= %@", start as NSDate)) - } - if let end = end { - predicates.append(NSPredicate(format: "startDate < %@", end as NSDate)) - } - - let request: NSFetchRequest = CachedGlucoseObject.fetchRequest() - request.predicate = (predicates.count > 1) ? NSCompoundPredicate(andPredicateWithSubpredicates: predicates) : predicates.first - request.sortDescriptors = [NSSortDescriptor(key: "startDate", ascending: true)] - - return try self.cacheStore.managedObjectContext.fetch(request) - } - - private func updateLatestGlucose() { - dispatchPrecondition(condition: .onQueue(queue)) - - cacheStore.managedObjectContext.performAndWait { - var latestGlucose: StoredGlucoseSample? - - do { - let request: NSFetchRequest = CachedGlucoseObject.fetchRequest() - request.sortDescriptors = [NSSortDescriptor(key: "startDate", ascending: false)] - request.fetchLimit = 1 - - let objects = try self.cacheStore.managedObjectContext.fetch(request) - latestGlucose = objects.first.map { StoredGlucoseSample(managedObject: $0) } - } catch let error { - self.log.error("Unable to fetch latest glucose object: %@", String(describing: error)) - } - - self.latestGlucose = latestGlucose - } - } -} - -// MARK: - Modification - -extension GlucoseStore { - /// Add glucose samples to store. - /// - /// - Parameters: - /// - samples: The new glucose samples to add to the store. - /// - completion: A closure called once the glucose samples have been stored. - /// - result: An array of glucose samples that were stored, or error. - public func addGlucoseSamples(_ samples: [NewGlucoseSample], completion: @escaping (_ result: Result<[StoredGlucoseSample], Error>) -> Void) { - guard !samples.isEmpty else { - completion(.success([])) - return - } - - queue.async { - var storedSamples: [StoredGlucoseSample] = [] - var error: Error? - - self.cacheStore.managedObjectContext.performAndWait { - do { - // Filter samples to ensure no duplicate sync identifiers nor existing sample with matching sync identifier for our provenance identifier - var syncIdentifiers = Set() - let samples: [NewGlucoseSample] = try samples.compactMap { sample in - guard syncIdentifiers.insert(sample.syncIdentifier).inserted else { - self.log.default("Skipping adding glucose sample due to duplicate sync identifier: %{public}@", sample.syncIdentifier) - return nil - } - - let request: NSFetchRequest = CachedGlucoseObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format: "provenanceIdentifier == %@", self.provenanceIdentifier), - NSPredicate(format: "syncIdentifier == %@", sample.syncIdentifier)]) - request.fetchLimit = 1 - - guard try self.cacheStore.managedObjectContext.count(for: request) == 0 else { - self.log.default("Skipping adding glucose sample due to existing cached sync identifier: %{public}@", sample.syncIdentifier) - return nil - } - - return sample - } - guard !samples.isEmpty else { - return - } - - let objects: [CachedGlucoseObject] = samples.map { sample in - let object = CachedGlucoseObject(context: self.cacheStore.managedObjectContext) - object.create(from: sample, - provenanceIdentifier: self.provenanceIdentifier, - healthKitStorageDelay: self.healthKitStorageDelayIfAllowed) - return object - } - - error = self.cacheStore.save() - guard error == nil else { - return - } - - storedSamples = objects.map { StoredGlucoseSample(managedObject: $0) } - } catch let coreDataError { - error = coreDataError - } - } - - if let error = error { - completion(.failure(error)) - return - } - - self.handleUpdatedGlucoseData() - completion(.success(storedSamples)) - } - } - - private func saveSamplesToHealthKit() { - dispatchPrecondition(condition: .onQueue(queue)) - var error: Error? - - guard storeSamplesToHealthKit else { - return - } - - cacheStore.managedObjectContext.performAndWait { - do { - let request: NSFetchRequest = CachedGlucoseObject.fetchRequest() - request.predicate = NSPredicate(format: "healthKitEligibleDate <= %@", Date() as NSDate) - request.sortDescriptors = [NSSortDescriptor(key: "modificationCounter", ascending: true)] // Maintains modificationCounter order - - let objects = try self.cacheStore.managedObjectContext.fetch(request) - guard !objects.isEmpty else { - return - } - - if objects.contains(where: { $0.uuid != nil }) { - self.log.error("Found CachedGlucoseObjects with non-nil uuid. Should never happen, but HealthKit should be able to resolve it.") - // Note: UUIDs will be overwritten below, but since the syncIdentifiers will match then HealthKit can resolve correctly via replacement - } - - let quantitySamples = objects.map { $0.quantitySample } - - let dispatchGroup = DispatchGroup() - dispatchGroup.enter() - self.healthStore.save(quantitySamples) { (_, healthKitError) in - error = healthKitError - dispatchGroup.leave() - } - dispatchGroup.wait() - - // If there is an error writing to HealthKit, then do not persist uuids and retry later - guard error == nil else { - return - } - - for (object, quantitySample) in zip(objects, quantitySamples) { - object.uuid = quantitySample.uuid - object.healthKitEligibleDate = nil - object.updateModificationCounter() // Maintains modificationCounter order - } - - error = self.cacheStore.save() - guard error == nil else { - return - } - - self.log.default("Stored %d eligible glucose samples to HealthKit", objects.count) - } catch let coreDataError { - error = coreDataError - } - } - - if let error = error { - self.log.error("Error saving samples to HealthKit: %{public}@", String(describing: error)) - } - } - - private func addGlucoseSample(for sample: HKQuantitySample) throws -> Bool { - dispatchPrecondition(condition: .onQueue(queue)) - - // Are there any objects matching the UUID? - let request: NSFetchRequest = CachedGlucoseObject.fetchRequest() - request.predicate = NSPredicate(format: "uuid == %@", sample.uuid as NSUUID) - request.fetchLimit = 1 - - let count = try cacheStore.managedObjectContext.count(for: request) - guard count == 0 else { - return false - } - - // Add an object for this UUID - let object = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object.create(from: sample) - - return true - } - - private func deleteGlucoseSamples(withUUIDs uuids: [UUID], batchSize: Int = 500) throws -> Int { - dispatchPrecondition(condition: .onQueue(queue)) - - var count = 0 - for batch in uuids.chunked(into: batchSize) { - let predicate = NSPredicate(format: "uuid IN %@", batch.map { $0 as NSUUID }) - count += try cacheStore.managedObjectContext.purgeObjects(of: CachedGlucoseObject.self, matching: predicate) - } - return count - } - - /// - /// - Parameters: - /// - since: Only consider glucose valid after or at this date - /// - Returns: The latest CGM glucose, if available in the time period specified - public func getLatestCGMGlucose(since: Date, completion: @escaping (_ result: Result) -> Void) { - queue.async { - self.cacheStore.managedObjectContext.performAndWait { - let request: NSFetchRequest = CachedGlucoseObject.fetchRequest() - request.predicate = NSPredicate(format: "startDate >= %@ AND wasUserEntered == NO", since as NSDate) - request.sortDescriptors = [NSSortDescriptor(key: "startDate", ascending: false)] - request.fetchLimit = 1 - - do { - let objects = try self.cacheStore.managedObjectContext.fetch(request) - let samples = objects.map { StoredGlucoseSample(managedObject: $0) } - completion(.success(samples.first)) - } catch let error { - self.log.error("Error in getLatestCGMGlucose: %@", String(describing: error)) - completion(.failure(error)) - } - } - } - } -} - -// MARK: - Watch Synchronization - -extension GlucoseStore { - - /// Get glucose samples in main app to deliver to Watch extension - public func getSyncGlucoseSamples(start: Date? = nil, end: Date? = nil, completion: @escaping (_ result: Result<[StoredGlucoseSample], Error>) -> Void) { - queue.async { - var samples: [StoredGlucoseSample] = [] - var error: Error? - - self.cacheStore.managedObjectContext.performAndWait { - do { - samples = try self.getCachedGlucoseObjects(start: start, end: end).map { StoredGlucoseSample(managedObject: $0) } - } catch let coreDataError { - error = coreDataError - } - } - - if let error = error { - completion(.failure(error)) - return - } - - completion(.success(samples)) - } - } - - /// Store glucose samples in Watch extension - public func setSyncGlucoseSamples(_ objects: [StoredGlucoseSample], completion: @escaping (Error?) -> Void) { - queue.async { - var error: Error? - - self.cacheStore.managedObjectContext.performAndWait { - guard !objects.isEmpty else { - return - } - - objects.forEach { - let object = CachedGlucoseObject(context: self.cacheStore.managedObjectContext) - object.update(from: $0) - } - - error = self.cacheStore.save() - } - - if let error = error { - completion(error) - return - } - - self.handleUpdatedGlucoseData() - completion(nil) - } - } -} - -// MARK: - Cache Management - -extension GlucoseStore { - public var earliestCacheDate: Date { - return Date(timeIntervalSinceNow: -cacheLength) - } - - /// Purge all glucose samples from the glucose store and HealthKit (matching the specified device predicate). - /// - /// - Parameters: - /// - healthKitPredicate: The predicate to use in matching HealthKit glucose objects. - /// - completion: The completion handler returning any error. - public func purgeAllGlucoseSamples(healthKitPredicate: NSPredicate, completion: @escaping (Error?) -> Void) { - queue.async { - let storeError = self.purgeCachedGlucoseObjects() - self.healthStore.deleteObjects(of: self.glucoseType, predicate: healthKitPredicate) { _, _, healthKitError in - self.queue.async { - if let error = storeError ?? healthKitError { - completion(error) - return - } - - self.handleUpdatedGlucoseData() - completion(nil) - } - } - } - } - - private func purgeExpiredCachedGlucoseObjects() { - purgeCachedGlucoseObjects(before: earliestCacheDate) - } - - /// Purge cached glucose objects from the glucose store. - /// - /// - Parameters: - /// - date: Purge cached glucose objects with start date before this date. - /// - completion: The completion handler returning any error. - public func purgeCachedGlucoseObjects(before date: Date? = nil, completion: @escaping (Error?) -> Void) { - queue.async { - if let error = self.purgeCachedGlucoseObjects(before: date) { - completion(error) - return - } - self.handleUpdatedGlucoseData() - completion(nil) - } - } - - @discardableResult - private func purgeCachedGlucoseObjects(before date: Date? = nil) -> Error? { - dispatchPrecondition(condition: .onQueue(queue)) - - var error: Error? - - cacheStore.managedObjectContext.performAndWait { - do { - var predicate: NSPredicate? - if let date = date { - predicate = NSPredicate(format: "startDate < %@", date as NSDate) - } - let count = try cacheStore.managedObjectContext.purgeObjects(of: CachedGlucoseObject.self, matching: predicate) - self.log.default("Purged %d CachedGlucoseObjects", count) - } catch let coreDataError { - self.log.error("Unable to purge CachedGlucoseObjects: %{public}@", String(describing: error)) - error = coreDataError - } - } - - return error - } - - private func purgeExpiredManagedDataFromHealthKit(before date: Date) { - dispatchPrecondition(condition: .onQueue(queue)) - - guard let managedDataInterval = managedDataInterval else { - return - } - - let end = min(Date(timeIntervalSinceNow: -managedDataInterval), date) - let predicate = HKQuery.predicateForSamples(withStart: Date(timeIntervalSinceNow: -maxPurgeInterval), end: end) - healthStore.deleteObjects(of: glucoseType, predicate: predicate) { (success, count, error) -> Void in - // error is expected and ignored if protected data is unavailable - if success { - self.log.debug("Successfully purged %d HealthKit objects older than %{public}@", count, String(describing: end)) - } - } - } - - private func handleUpdatedGlucoseData() { - dispatchPrecondition(condition: .onQueue(queue)) - - self.purgeExpiredCachedGlucoseObjects() - self.updateLatestGlucose() - self.saveSamplesToHealthKit() - - NotificationCenter.default.post(name: GlucoseStore.glucoseSamplesDidChange, object: self) - delegate?.glucoseStoreHasUpdatedGlucoseData(self) - } -} - -// MARK: - Math - -extension GlucoseStore { - /// Calculates the momentum effect for recent glucose values. - /// - /// The duration of effect data returned is determined by the `momentumDataInterval`, and the delta between data points is 5 minutes. - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - Parameters: - /// - completion: A closure called once the calculation has completed. - /// - result: The calculated effect values, or an empty array if the glucose data isn't suitable for momentum calculation, or error. - public func getRecentMomentumEffect(_ completion: @escaping (_ result: Result<[GlucoseEffect], Error>) -> Void) { - getGlucoseSamples(start: Date(timeIntervalSinceNow: -momentumDataInterval)) { (result) in - switch result { - case .failure(let error): - completion(.failure(error)) - case .success(let samples): - let effects = samples.linearMomentumEffect( - duration: self.momentumDataInterval, - delta: TimeInterval(minutes: 5) - ) - completion(.success(effects)) - } - } - } - - /// Calculates a timeline of effect velocity (glucose/time) observed in glucose that counteract the specified effects. - /// - /// - Parameters: - /// - start: The earliest date of glucose samples to include. - /// - end: The latest date of glucose samples to include, if provided. - /// - effects: Glucose effects to be countered, in chronological order, and counteraction effects calculated. - /// - completion: A closure called once the glucose samples have been retrieved and counteraction effects calculated. - /// - result: An array of glucose effect velocities describing the change in glucose samples compared to the specified glucose effects, or error. - public func getCounteractionEffects(start: Date, end: Date? = nil, to effects: [GlucoseEffect], _ completion: @escaping (_ result: Result<[GlucoseEffectVelocity], Error>) -> Void) { - getGlucoseSamples(start: start, end: end) { (result) in - switch result { - case .failure(let error): - completion(.failure(error)) - case .success(let samples): - completion(.success(self.counteractionEffects(for: samples, to: effects))) - } - } - } - - /// Calculates a timeline of effect velocity (glucose/time) observed in glucose that counteract the specified effects. - /// - /// - Parameter: - /// - samples: The observed timeline of samples. - /// - effects: An array of velocities describing the change in glucose samples compared to the specified effects - public func counteractionEffects(for samples: [Sample], to effects: [GlucoseEffect]) -> [GlucoseEffectVelocity] { - samples.counteractionEffects(to: effects) - } -} - -// MARK: - Remote Data Service Query - -extension GlucoseStore { - public struct QueryAnchor: Equatable, RawRepresentable { - public typealias RawValue = [String: Any] - - internal var modificationCounter: Int64 - - public init() { - self.modificationCounter = 0 - } - - public init?(rawValue: RawValue) { - guard let modificationCounter = rawValue["modificationCounter"] as? Int64 else { - return nil - } - self.modificationCounter = modificationCounter - } - - public var rawValue: RawValue { - var rawValue: RawValue = [:] - rawValue["modificationCounter"] = modificationCounter - return rawValue - } - } - - public enum GlucoseQueryResult { - case success(QueryAnchor, [StoredGlucoseSample]) - case failure(Error) - } - - public func executeGlucoseQuery(fromQueryAnchor queryAnchor: QueryAnchor?, limit: Int, completion: @escaping (GlucoseQueryResult) -> Void) { - queue.async { - var queryAnchor = queryAnchor ?? QueryAnchor() - var queryResult = [StoredGlucoseSample]() - var queryError: Error? - - guard limit > 0 else { - completion(.success(queryAnchor, [])) - return - } - - self.cacheStore.managedObjectContext.performAndWait { - let storedRequest: NSFetchRequest = CachedGlucoseObject.fetchRequest() - - storedRequest.predicate = NSPredicate(format: "modificationCounter > %d", queryAnchor.modificationCounter) - storedRequest.sortDescriptors = [NSSortDescriptor(key: "modificationCounter", ascending: true)] - storedRequest.fetchLimit = limit - - do { - let stored = try self.cacheStore.managedObjectContext.fetch(storedRequest) - if let modificationCounter = stored.max(by: { $0.modificationCounter < $1.modificationCounter })?.modificationCounter { - queryAnchor.modificationCounter = modificationCounter - } - queryResult.append(contentsOf: stored.compactMap { StoredGlucoseSample(managedObject: $0) }) - } catch let error { - queryError = error - return - } - } - - if let queryError = queryError { - completion(.failure(queryError)) - return - } - - completion(.success(queryAnchor, queryResult)) - } - } -} - -// MARK: - Critical Event Log Export - -extension GlucoseStore: CriticalEventLog { - private var exportProgressUnitCountPerObject: Int64 { 1 } - private var exportFetchLimit: Int { Int(criticalEventLogExportProgressUnitCountPerFetch / exportProgressUnitCountPerObject) } - - public var exportName: String { "Glucose.json" } - - public func exportProgressTotalUnitCount(startDate: Date, endDate: Date? = nil) -> Result { - var result: Result? - - self.cacheStore.managedObjectContext.performAndWait { - do { - let request: NSFetchRequest = CachedGlucoseObject.fetchRequest() - request.predicate = self.exportDatePredicate(startDate: startDate, endDate: endDate) - - let objectCount = try self.cacheStore.managedObjectContext.count(for: request) - result = .success(Int64(objectCount) * exportProgressUnitCountPerObject) - } catch let error { - result = .failure(error) - } - } - - return result! - } - - public func export(startDate: Date, endDate: Date, to stream: OutputStream, progress: Progress) -> Error? { - let encoder = JSONStreamEncoder(stream: stream) - var modificationCounter: Int64 = 0 - var fetching = true - var error: Error? - - while fetching && error == nil { - self.cacheStore.managedObjectContext.performAndWait { - do { - guard !progress.isCancelled else { - throw CriticalEventLogError.cancelled - } - - let request: NSFetchRequest = CachedGlucoseObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format: "modificationCounter > %d", modificationCounter), - self.exportDatePredicate(startDate: startDate, endDate: endDate)]) - request.sortDescriptors = [NSSortDescriptor(key: "modificationCounter", ascending: true)] - request.fetchLimit = self.exportFetchLimit - - let objects = try self.cacheStore.managedObjectContext.fetch(request) - if objects.isEmpty { - fetching = false - return - } - - try encoder.encode(objects) - - modificationCounter = objects.last!.modificationCounter - - progress.completedUnitCount += Int64(objects.count) * exportProgressUnitCountPerObject - } catch let fetchError { - error = fetchError - } - } - } - - if let closeError = encoder.close(), error == nil { - error = closeError - } - - return error - } - - private func exportDatePredicate(startDate: Date, endDate: Date? = nil) -> NSPredicate { - var predicate = NSPredicate(format: "startDate >= %@", startDate as NSDate) - if let endDate = endDate { - predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSPredicate(format: "startDate < %@", endDate as NSDate)]) - } - return predicate - } -} - -// MARK: - Core Data (Bulk) - TEST ONLY - -extension GlucoseStore { - public func addNewGlucoseSamples(samples: [NewGlucoseSample], completion: @escaping (Error?) -> Void) { - guard !samples.isEmpty else { - completion(nil) - return - } - - queue.async { - var error: Error? - - self.cacheStore.managedObjectContext.performAndWait { - for sample in samples { - let object = CachedGlucoseObject(context: self.cacheStore.managedObjectContext) - object.create(from: sample, provenanceIdentifier: self.provenanceIdentifier, healthKitStorageDelay: self.healthKitStorageDelayIfAllowed) - } - error = self.cacheStore.save() - } - - guard error == nil else { - completion(error) - return - } - - self.log.info("Added %d CachedGlucoseObjects", samples.count) - self.delegate?.glucoseStoreHasUpdatedGlucoseData(self) - completion(nil) - } - } -} - -// MARK: - Issue Report - -extension GlucoseStore { - /// Generates a diagnostic report about the current state. - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - parameter completionHandler: A closure called once the report has been generated. The closure takes a single argument of the report string. - public func generateDiagnosticReport(_ completionHandler: @escaping (_ report: String) -> Void) { - queue.async { - var report: [String] = [ - "## GlucoseStore", - "", - "* latestGlucoseValue: \(String(reflecting: self.latestGlucose))", - "* managedDataInterval: \(self.managedDataInterval ?? 0)", - "* cacheLength: \(self.cacheLength)", - "* momentumDataInterval: \(self.momentumDataInterval)", - "* observationInterval: \(self.observationInterval)", - super.debugDescription, - "", - "### cachedGlucoseSamples", - ] - - switch self.getGlucoseSamples(start: Date(timeIntervalSinceNow: -.hours(24))) { - case .failure(let error): - report.append("Error: \(error)") - case .success(let samples): - for sample in samples { - report.append(String(describing: sample)) - } - } - - report.append("") - - completionHandler(report.joined(separator: "\n")) - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseTrend.swift b/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseTrend.swift deleted file mode 100644 index 729eb0c4b..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseKit/GlucoseTrend.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// GlucoseTrend.swift -// Loop -// -// Created by Nate Racklyeft on 8/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public enum GlucoseTrend: Int, CaseIterable { - case upUpUp = 1 - case upUp = 2 - case up = 3 - case flat = 4 - case down = 5 - case downDown = 6 - case downDownDown = 7 - - public var symbol: String { - switch self { - case .upUpUp: - return "⇈" - case .upUp: - return "↑" - case .up: - return "↗︎" - case .flat: - return "→" - case .down: - return "↘︎" - case .downDown: - return "↓" - case .downDownDown: - return "⇊" - } - } - - public var arrows: String { - switch self { - case .upUpUp: - return "↑↑" - case .upUp: - return "↑" - case .up: - return "↗︎" - case .flat: - return "→" - case .down: - return "↘︎" - case .downDown: - return "↓" - case .downDownDown: - return "↓↓" - } - } - - public var localizedDescription: String { - switch self { - case .upUpUp: - return LocalizedString("Rising very fast", comment: "Glucose trend up-up-up") - case .upUp: - return LocalizedString("Rising fast", comment: "Glucose trend up-up") - case .up: - return LocalizedString("Rising", comment: "Glucose trend up") - case .flat: - return LocalizedString("Flat", comment: "Glucose trend flat") - case .down: - return LocalizedString("Falling", comment: "Glucose trend down") - case .downDown: - return LocalizedString("Falling fast", comment: "Glucose trend down-down") - case .downDownDown: - return LocalizedString("Falling very fast", comment: "Glucose trend down-down-down") - } - } -} - -extension GlucoseTrend { - public init?(symbol: String) { - switch symbol { - case "↑↑": - self = .upUpUp - case "↑": - self = .upUp - case "↗︎": - self = .up - case "→": - self = .flat - case "↘︎": - self = .down - case "↓": - self = .downDown - case "↓↓": - self = .downDownDown - default: - return nil - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseKit/HKDevice+Encodable.swift b/Dependencies/LoopKit/LoopKit/GlucoseKit/HKDevice+Encodable.swift deleted file mode 100644 index fa8249372..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseKit/HKDevice+Encodable.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// HKDevice+Encodable.swift -// LoopKit -// -// Created by Rick Pasetto on 8/2/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - -extension HKDevice: Encodable { - private enum CodingKeys: String, CodingKey { - case name, manufacturer, model, hardwareVersion, firmwareVersion, softwareVersion, localIdentifier, udiDeviceIdentifier - } - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encodeIfPresent(name, forKey: .name) - try container.encodeIfPresent(manufacturer, forKey: .manufacturer) - try container.encodeIfPresent(model, forKey: .model) - try container.encodeIfPresent(hardwareVersion, forKey: .hardwareVersion) - try container.encodeIfPresent(firmwareVersion, forKey: .firmwareVersion) - try container.encodeIfPresent(softwareVersion, forKey: .softwareVersion) - try container.encodeIfPresent(localIdentifier, forKey: .localIdentifier) - try container.encodeIfPresent(udiDeviceIdentifier, forKey: .udiDeviceIdentifier) - } - - // Swift won't let us implement Decodable for HKDevice, but we can at least implement deserialization "by hand" - // by trying both Plist and JSON -- not very efficient, but gets the job done. - public convenience init(from data: Data) throws { - var props = try? PropertyListSerialization.propertyList(from: data, format: nil) as? [String: Any] - if props == nil { - props = try? JSONSerialization.jsonObject(with: data) as? [String: Any] - } - guard let props = props else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "Invalid data")) - } - self.init(from: props) - } - - convenience init(from props: [String: Any]) { - self.init(name: props[CodingKeys.name.rawValue] as! String?, - manufacturer: props[CodingKeys.manufacturer.rawValue] as! String?, - model: props[CodingKeys.model.rawValue] as! String?, - hardwareVersion: props[CodingKeys.hardwareVersion.rawValue] as! String?, - firmwareVersion: props[CodingKeys.firmwareVersion.rawValue] as! String?, - softwareVersion: props[CodingKeys.softwareVersion.rawValue] as! String?, - localIdentifier: props[CodingKeys.localIdentifier.rawValue] as! String?, - udiDeviceIdentifier: props[CodingKeys.udiDeviceIdentifier.rawValue] as! String?) - } - -} - - diff --git a/Dependencies/LoopKit/LoopKit/GlucoseKit/HKQuantitySample+GlucoseKit.swift b/Dependencies/LoopKit/LoopKit/GlucoseKit/HKQuantitySample+GlucoseKit.swift deleted file mode 100644 index 15344fc22..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseKit/HKQuantitySample+GlucoseKit.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// GlucoseValue.swift -// LoopKit -// -// Created by Nathan Racklyeft on 2/19/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -let MetadataKeyGlucoseIsDisplayOnly = "com.loudnate.GlucoseKit.HKMetadataKey.GlucoseIsDisplayOnly" -let MetadataKeyGlucoseCondition = "com.LoopKit.GlucoseKit.HKMetadataKey.GlucoseCondition" -let MetadataKeyGlucoseTrend = "com.LoopKit.GlucoseKit.HKMetadataKey.GlucoseTrend" -let MetadataKeyGlucoseTrendRateUnit = "com.LoopKit.GlucoseKit.HKMetadataKey.GlucoseTrendRateUnit" -let MetadataKeyGlucoseTrendRateValue = "com.LoopKit.GlucoseKit.HKMetadataKey.GlucoseTrendRateValue" - - -extension HKQuantitySample: GlucoseSampleValue { - public var provenanceIdentifier: String { - return sourceRevision.source.bundleIdentifier - } - - public var isDisplayOnly: Bool { - return metadata?[MetadataKeyGlucoseIsDisplayOnly] as? Bool ?? false - } - - public var wasUserEntered: Bool { - return metadata?[HKMetadataKeyWasUserEntered] as? Bool ?? false - } - - public var condition: GlucoseCondition? { - guard let rawCondition = metadata?[MetadataKeyGlucoseCondition] as? String else { - return nil - } - return GlucoseCondition(rawValue: rawCondition) - } - - public var trend: GlucoseTrend? { - guard let symbol = metadata?[MetadataKeyGlucoseTrend] as? String else { - return nil - } - return GlucoseTrend(symbol: symbol) - } - - public var trendRate: HKQuantity? { - guard let unit = metadata?[MetadataKeyGlucoseTrendRateUnit] as? String, - let value = metadata?[MetadataKeyGlucoseTrendRateValue] as? Double else { - return nil - } - return HKQuantity(unit: HKUnit(from: unit), doubleValue: value) - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseKit/NewGlucoseSample.swift b/Dependencies/LoopKit/LoopKit/GlucoseKit/NewGlucoseSample.swift deleted file mode 100644 index 365fd6220..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseKit/NewGlucoseSample.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// NewGlucoseSample.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import HealthKit - - -public struct NewGlucoseSample: Equatable { - public let date: Date - public let quantity: HKQuantity - public let condition: GlucoseCondition? - public let trend: GlucoseTrend? - public let trendRate: HKQuantity? - public let isDisplayOnly: Bool - public let wasUserEntered: Bool - public let syncIdentifier: String - public var syncVersion: Int - public let device: HKDevice? - - /// - Parameters: - /// - date: The date the sample was collected - /// - quantity: The glucose sample quantity - /// - trend: The glucose sample's trend. A value of `nil` means no trend is available. - /// - isDisplayOnly: Whether the reading was shifted for visual consistency after calibration - /// - wasUserEntered: Whether the reading was entered by the user (manual) or not (device) - /// - syncIdentifier: A unique identifier representing the sample, used for de-duplication - /// - syncVersion: A version number for determining resolution in de-duplication - /// - device: The description of the device the collected the sample - public init(date: Date, - quantity: HKQuantity, - condition: GlucoseCondition?, - trend: GlucoseTrend?, - trendRate: HKQuantity?, - isDisplayOnly: Bool, - wasUserEntered: Bool, - syncIdentifier: String, - syncVersion: Int = 1, - device: HKDevice? = nil) { - self.date = date - self.quantity = quantity - self.condition = condition - self.trend = trend - self.trendRate = trendRate - self.isDisplayOnly = isDisplayOnly - self.wasUserEntered = wasUserEntered - self.syncIdentifier = syncIdentifier - self.syncVersion = syncVersion - self.device = device - } -} - - -extension NewGlucoseSample { - public var quantitySample: HKQuantitySample { - var metadata: [String: Any] = [ - HKMetadataKeySyncIdentifier: syncIdentifier, - HKMetadataKeySyncVersion: syncVersion, - ] - - metadata[MetadataKeyGlucoseCondition] = condition?.rawValue - metadata[MetadataKeyGlucoseTrend] = trend?.symbol - if let trendRate = trendRate { - metadata[MetadataKeyGlucoseTrendRateUnit] = HKUnit.milligramsPerDeciliterPerMinute.unitString - metadata[MetadataKeyGlucoseTrendRateValue] = trendRate.doubleValue(for: .milligramsPerDeciliterPerMinute) - } - if isDisplayOnly { - metadata[MetadataKeyGlucoseIsDisplayOnly] = true - } - if wasUserEntered { - metadata[HKMetadataKeyWasUserEntered] = true - } - - return HKQuantitySample( - type: HKQuantityType.quantityType(forIdentifier: .bloodGlucose)!, - quantity: quantity, - start: date, - end: date, - device: device, - metadata: metadata - ) - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseKit/StoredGlucoseSample.swift b/Dependencies/LoopKit/LoopKit/GlucoseKit/StoredGlucoseSample.swift deleted file mode 100644 index a3a21d5cc..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseKit/StoredGlucoseSample.swift +++ /dev/null @@ -1,150 +0,0 @@ -// -// StoredGlucoseSample.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import HealthKit - -public struct StoredGlucoseSample: GlucoseSampleValue, Equatable { - public let uuid: UUID? // Note this is the UUID from HealthKit. Nil if not (yet) stored in HealthKit. - - // MARK: - HealthKit Sync Support - - public let provenanceIdentifier: String - public let syncIdentifier: String? - public let syncVersion: Int? - public let device: HKDevice? - public let healthKitEligibleDate: Date? - - // MARK: - SampleValue - - public let startDate: Date - public let quantity: HKQuantity - - // MARK: - GlucoseSampleValue - - public let isDisplayOnly: Bool - public let wasUserEntered: Bool - public let condition: GlucoseCondition? - public let trend: GlucoseTrend? - public let trendRate: HKQuantity? - - public init(sample: HKQuantitySample) { - self.init( - uuid: sample.uuid, - provenanceIdentifier: sample.provenanceIdentifier, - syncIdentifier: sample.syncIdentifier, - syncVersion: sample.syncVersion, - startDate: sample.startDate, - quantity: sample.quantity, - condition: sample.condition, - trend: sample.trend, - trendRate: sample.trendRate, - isDisplayOnly: sample.isDisplayOnly, - wasUserEntered: sample.wasUserEntered, - device: sample.device, - healthKitEligibleDate: nil) - } - - public init( - uuid: UUID?, - provenanceIdentifier: String, - syncIdentifier: String?, - syncVersion: Int?, - startDate: Date, - quantity: HKQuantity, - condition: GlucoseCondition?, - trend: GlucoseTrend?, - trendRate: HKQuantity?, - isDisplayOnly: Bool, - wasUserEntered: Bool, - device: HKDevice?, - healthKitEligibleDate: Date?) { - self.uuid = uuid - self.provenanceIdentifier = provenanceIdentifier - self.syncIdentifier = syncIdentifier - self.syncVersion = syncVersion - self.startDate = startDate - self.quantity = quantity - self.condition = condition - self.trend = trend - self.trendRate = trendRate - self.isDisplayOnly = isDisplayOnly - self.wasUserEntered = wasUserEntered - self.device = device - self.healthKitEligibleDate = healthKitEligibleDate - } -} - -extension StoredGlucoseSample { - init(managedObject: CachedGlucoseObject) { - self.init( - uuid: managedObject.uuid, - provenanceIdentifier: managedObject.provenanceIdentifier, - syncIdentifier: managedObject.syncIdentifier, - syncVersion: managedObject.syncVersion, - startDate: managedObject.startDate, - quantity: managedObject.quantity, - condition: managedObject.condition, - trend: managedObject.trend, - trendRate: managedObject.trendRate, - isDisplayOnly: managedObject.isDisplayOnly, - wasUserEntered: managedObject.wasUserEntered, - device: managedObject.device, - healthKitEligibleDate: managedObject.healthKitEligibleDate) - } -} - -extension StoredGlucoseSample: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.init(uuid: try container.decodeIfPresent(UUID.self, forKey: .uuid), - provenanceIdentifier: try container.decode(String.self, forKey: .provenanceIdentifier), - syncIdentifier: try container.decodeIfPresent(String.self, forKey: .syncIdentifier), - syncVersion: try container.decodeIfPresent(Int.self, forKey: .syncVersion), - startDate: try container.decode(Date.self, forKey: .startDate), - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: try container.decode(Double.self, forKey: .quantity)), - condition: try container.decodeIfPresent(GlucoseCondition.self, forKey: .condition), - trend: try container.decodeIfPresent(GlucoseTrend.self, forKey: .trend), - trendRate: try container.decodeIfPresent(Double.self, forKey: .trendRate).map { HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: $0) }, - isDisplayOnly: try container.decode(Bool.self, forKey: .isDisplayOnly), - wasUserEntered: try container.decode(Bool.self, forKey: .wasUserEntered), - device: try container.decodeIfPresent(CodableDevice.self, forKey: .device).map { $0.device }, - healthKitEligibleDate: try container.decodeIfPresent(Date.self, forKey: .healthKitEligibleDate)) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encodeIfPresent(uuid, forKey: .uuid) - try container.encode(provenanceIdentifier, forKey: .provenanceIdentifier) - try container.encodeIfPresent(syncIdentifier, forKey: .syncIdentifier) - try container.encodeIfPresent(syncVersion, forKey: .syncVersion) - try container.encode(startDate, forKey: .startDate) - try container.encode(quantity.doubleValue(for: .milligramsPerDeciliter), forKey: .quantity) - try container.encodeIfPresent(condition, forKey: .condition) - try container.encodeIfPresent(trend, forKey: .trend) - try container.encodeIfPresent(trendRate?.doubleValue(for: .milligramsPerDeciliterPerMinute), forKey: .trendRate) - try container.encode(isDisplayOnly, forKey: .isDisplayOnly) - try container.encode(wasUserEntered, forKey: .wasUserEntered) - try container.encodeIfPresent(device.map { CodableDevice($0) }, forKey: .device) - try container.encodeIfPresent(healthKitEligibleDate, forKey: .healthKitEligibleDate) - } - - private enum CodingKeys: String, CodingKey { - case uuid - case provenanceIdentifier - case syncIdentifier - case syncVersion - case startDate - case quantity - case condition - case trend - case trendRate - case isDisplayOnly - case wasUserEntered - case device - case healthKitEligibleDate - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseRange.swift b/Dependencies/LoopKit/LoopKit/GlucoseRange.swift deleted file mode 100644 index b086e2537..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseRange.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// GlucoseRange.swift -// LoopKit -// -// Created by Nathaniel Hamming on 2021-03-16. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - -public struct GlucoseRange { - public let range: DoubleRange - public let unit: HKUnit - - public init(minValue: Double, maxValue: Double, unit: HKUnit) { - self.init(range: DoubleRange(minValue: minValue, maxValue: maxValue), unit: unit) - } - - public init(range: DoubleRange, unit: HKUnit) { - precondition(unit == .milligramsPerDeciliter || unit == .millimolesPerLiter) - self.range = range - self.unit = unit - } - - public var isZero: Bool { - return abs(range.minValue) < .ulpOfOne && abs(range.maxValue) < .ulpOfOne - } - - public var quantityRange: ClosedRange { - range.quantityRange(for: unit) - } -} - -extension GlucoseRange: Hashable {} - -extension GlucoseRange: Equatable {} - -extension GlucoseRange: RawRepresentable { - public typealias RawValue = [String:Any] - - public init?(rawValue: RawValue) { - guard let rawRange = rawValue["range"] as? DoubleRange.RawValue, - let range = DoubleRange(rawValue: rawRange), - let bloodGlucoseUnit = rawValue["bloodGlucoseUnit"] as? String else - { - return nil - } - self.range = range - self.unit = HKUnit(from: bloodGlucoseUnit) - } - - public var rawValue: RawValue { - return [ - "range": range.rawValue, - "bloodGlucoseUnit": unit.unitString - ] - } -} - -extension GlucoseRange: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - unit = HKUnit(from: try container.decode(String.self, forKey: .bloodGlucoseUnit)) - range = try container.decode(DoubleRange.self, forKey: .range) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(range, forKey: .range) - try container.encode(unit.unitString, forKey: .bloodGlucoseUnit) - } - - private enum CodingKeys: String, CodingKey { - case bloodGlucoseUnit - case range - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseRangeSchedule+SafeBounds.swift b/Dependencies/LoopKit/LoopKit/GlucoseRangeSchedule+SafeBounds.swift deleted file mode 100644 index cdc0b494f..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseRangeSchedule+SafeBounds.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// GlucoseRangeSchedule+SafeBounds.swift -// LoopKit -// -// Created by Noah Brauner on 12/5/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - -extension GlucoseRangeSchedule { - public func safeSchedule(with suspendThreshold: HKQuantity?) -> GlucoseRangeSchedule? { - let minGlucoseValue = [ - suspendThreshold?.doubleValue(for: self.unit), - Guardrail.correctionRange.absoluteBounds.lowerBound.doubleValue(for: self.unit) - ] - .compactMap({ $0 }) - .max()! - - let maxGlucoseValue = Guardrail.correctionRange.absoluteBounds.upperBound.doubleValue(for: self.unit) - - func safeGlucoseValue(_ initialValue: Double) -> Double { - return max(minGlucoseValue, min(maxGlucoseValue, initialValue)) - } - - let filteredItems = rangeSchedule.valueSchedule.items.map { scheduleValue in - let newScheduleValue = DoubleRange(minValue: safeGlucoseValue(scheduleValue.value.minValue), maxValue: safeGlucoseValue(scheduleValue.value.maxValue)) - return RepeatingScheduleValue(startTime: scheduleValue.startTime, value: newScheduleValue) - } - guard let filteredRangeSchedule = DailyQuantitySchedule(unit: rangeSchedule.unit, dailyItems: filteredItems) else { - return nil - } - return GlucoseRangeSchedule(rangeSchedule: filteredRangeSchedule, override: self.override) - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseRangeSchedule.swift b/Dependencies/LoopKit/LoopKit/GlucoseRangeSchedule.swift deleted file mode 100644 index f467d9d17..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseRangeSchedule.swift +++ /dev/null @@ -1,238 +0,0 @@ -// -// GlucoseRangeSchedule.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/13/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -public struct DoubleRange { - public let minValue: Double - public let maxValue: Double - - public init(minValue: Double, maxValue: Double) { - self.minValue = minValue - self.maxValue = maxValue - } - - public var isZero: Bool { - return abs(minValue) < .ulpOfOne && abs(maxValue) < .ulpOfOne - } -} - - -extension DoubleRange: RawRepresentable { - public typealias RawValue = [Double] - - public init?(rawValue: RawValue) { - guard rawValue.count == 2 else { - return nil - } - - minValue = rawValue[0] - maxValue = rawValue[1] - } - - public var rawValue: RawValue { - return [minValue, maxValue] - } -} - -extension DoubleRange: Equatable { - public static func ==(lhs: DoubleRange, rhs: DoubleRange) -> Bool { - return abs(lhs.minValue - rhs.minValue) < .ulpOfOne && - abs(lhs.maxValue - rhs.maxValue) < .ulpOfOne - } -} - -extension DoubleRange: Hashable {} - -extension DoubleRange: Codable {} - -/// Defines a daily schedule of glucose ranges -public struct GlucoseRangeSchedule: DailySchedule, Equatable { - public typealias RawValue = [String: Any] - - /// A time-based value overriding the rangeSchedule - public struct Override: Equatable { - - public let start: Date - public let end: Date - public let value: DoubleRange - - /// Initializes a new override - /// - /// - Parameters: - /// - value: The value to return when active - /// - start: The date at which the override starts - /// - end: The date at which the override ends, or nil for an indefinite override - public init(value: DoubleRange, start: Date, end: Date? = nil) { - self.value = value - self.start = start - self.end = end ?? .distantFuture - } - - public var activeDates: DateInterval { - return DateInterval(start: start, end: end) - } - - public func isActive(at date: Date = Date()) -> Bool { - return activeDates.contains(date) && !value.isZero - } - } - - /// An enabled override of the range schedule; only "active" between start and end, but when - /// active, it overrides the entire schedule. Not persisted - public private(set) var override: Override? - - var rangeSchedule: DailyQuantitySchedule - - public init(rangeSchedule: DailyQuantitySchedule, override: Override? = nil) { - self.rangeSchedule = rangeSchedule - self.override = override - } - - public init?(unit: HKUnit, dailyItems: [RepeatingScheduleValue], timeZone: TimeZone? = nil) { - guard let rangeSchedule = DailyQuantitySchedule(unit: unit, dailyItems: dailyItems, timeZone: timeZone) else { - return nil - } - - self.rangeSchedule = rangeSchedule - } - - public init?(rawValue: RawValue) { - guard let rangeSchedule = DailyQuantitySchedule(rawValue: rawValue) else { - return nil - } - - self.rangeSchedule = rangeSchedule - } - - public func between(start startDate: Date, end endDate: Date) -> [AbsoluteScheduleValue] { - return rangeSchedule.between(start: startDate, end: endDate) - } - - public func quantityBetween(start: Date, end: Date) -> [AbsoluteScheduleValue>] { - var quantitySchedule = [AbsoluteScheduleValue>]() - - for schedule in between(start: start, end: end) { - quantitySchedule.append(AbsoluteScheduleValue( - startDate: schedule.startDate, - endDate: schedule.endDate, - value: schedule.value.quantityRange(for: unit) - )) - } - - return quantitySchedule - } - - /// Returns the underlying values in `unit` - /// Consider using quantity(at:) instead - public func value(at time: Date) -> DoubleRange { - if let override = override, time >= override.start && Date() < override.end { - return override.value - } - - return rangeSchedule.value(at: time) - } - - public func quantityRange(at time: Date) -> ClosedRange { - return value(at: time).quantityRange(for: unit) - } - - public var items: [RepeatingScheduleValue] { - return rangeSchedule.items - } - - public var quantityRanges: [RepeatingScheduleValue>] { - return self.items.map { - RepeatingScheduleValue>(startTime: $0.startTime, - value: $0.value.quantityRange(for: unit)) - } - } - - public var timeZone: TimeZone { - get { - return rangeSchedule.timeZone - } - set { - rangeSchedule.timeZone = newValue - } - } - - public var unit: HKUnit { - return rangeSchedule.unit - } - - public var rawValue: RawValue { - return rangeSchedule.rawValue - } - - public func minLowerBound() -> HKQuantity { - let minDoubleValue = items.lazy.map { $0.value.minValue }.min()! - return HKQuantity(unit: unit, doubleValue: minDoubleValue) - } - - public func scheduleRange() -> ClosedRange { - let minDoubleValue = items.lazy.map { $0.value.minValue }.min()! - let lowerBound = HKQuantity(unit: unit, doubleValue: minDoubleValue) - - let maxDoubleValue = items.lazy.map { $0.value.maxValue }.max()! - let upperBound = HKQuantity(unit: unit, doubleValue: maxDoubleValue) - - return lowerBound...upperBound - } - - private func convertTo(unit: HKUnit) -> GlucoseRangeSchedule? { - guard unit != self.unit else { - return self - } - - let convertedDailyItems: [RepeatingScheduleValue] = rangeSchedule.items.map { - RepeatingScheduleValue(startTime: $0.startTime, - value: $0.value.quantityRange(for: self.unit).doubleRange(for: unit) - ) - } - - return GlucoseRangeSchedule(unit: unit, - dailyItems: convertedDailyItems, - timeZone: timeZone) - } - - public func schedule(for glucoseUnit: HKUnit) -> GlucoseRangeSchedule? { - precondition(glucoseUnit == .millimolesPerLiter || glucoseUnit == .milligramsPerDeciliter) - return self.convertTo(unit: glucoseUnit) - } -} - -extension GlucoseRangeSchedule: Codable {} - -extension GlucoseRangeSchedule.Override: Codable {} - -extension DoubleRange { - public func quantityRange(for unit: HKUnit) -> ClosedRange { - let lowerBound = HKQuantity(unit: unit, doubleValue: minValue) - let upperBound = HKQuantity(unit: unit, doubleValue: maxValue) - return lowerBound...upperBound - } -} - -extension ClosedRange where Bound == HKQuantity { - public func doubleRange(for unit: HKUnit) -> DoubleRange { - return DoubleRange(minValue: lowerBound.doubleValue(for: unit), maxValue: upperBound.doubleValue(for: unit)) - } - - public func glucoseRange(for unit: HKUnit) -> GlucoseRange { - GlucoseRange(range: self.doubleRange(for: unit), unit: unit) - } -} - -public extension DoubleRange { - init(_ val: ClosedRange) { - self.init(minValue: val.lowerBound, maxValue: val.upperBound) - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseSchedule.swift b/Dependencies/LoopKit/LoopKit/GlucoseSchedule.swift deleted file mode 100644 index 47c3da0dd..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseSchedule.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// GlucoseSchedule.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/12/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - -public typealias GlucoseSchedule = SingleQuantitySchedule - -public typealias InsulinSensitivitySchedule = GlucoseSchedule - -public extension InsulinSensitivitySchedule { - private func convertTo(unit: HKUnit) -> InsulinSensitivitySchedule? { - guard unit != self.unit else { - return self - } - - let convertedDailyItems: [RepeatingScheduleValue] = self.items.map { - RepeatingScheduleValue(startTime: $0.startTime, - value: HKQuantity(unit: self.unit, doubleValue: $0.value).doubleValue(for: unit) - ) - } - - return InsulinSensitivitySchedule(unit: unit, - dailyItems: convertedDailyItems, - timeZone: timeZone) - } - - func schedule(for glucoseUnit: HKUnit) -> InsulinSensitivitySchedule? { - // InsulinSensitivitySchedule stores only the glucose unit. - precondition(glucoseUnit == .millimolesPerLiter || glucoseUnit == .milligramsPerDeciliter) - return self.convertTo(unit: glucoseUnit) - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseThreshold.swift b/Dependencies/LoopKit/LoopKit/GlucoseThreshold.swift deleted file mode 100644 index 3c47aa615..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseThreshold.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// GlucoseThreshold.swift -// Loop -// -// Created by Pete Schwamb on 1/1/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - -public struct GlucoseThreshold: Equatable, RawRepresentable { - public typealias RawValue = [String: Any] - - public let value: Double - public let unit: HKUnit - - public var quantity: HKQuantity { - return HKQuantity(unit: unit, doubleValue: value) - } - - public init(unit: HKUnit, value: Double) { - self.value = value - self.unit = unit - } - - public init?(rawValue: RawValue) { - guard let unitsStr = rawValue["units"] as? String, let value = rawValue["value"] as? Double else { - return nil - } - self.unit = HKUnit(from: unitsStr) - self.value = value - } - - public var rawValue: RawValue { - return [ - "value": value, - "units": unit.unitString - ] - } - - public func convertTo(unit: HKUnit) -> GlucoseThreshold { - guard unit != self.unit else { - return self - } - - let convertedValue = self.quantity.doubleValue(for: unit) - - return GlucoseThreshold(unit: unit, - value: convertedValue) - } -} - -extension GlucoseThreshold: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.value = try container.decode(Double.self, forKey: .value) - self.unit = HKUnit(from: try container.decode(String.self, forKey: .unit)) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(value, forKey: .value) - try container.encode(unit.unitString, forKey: .unit) - } - - private enum CodingKeys: String, CodingKey { - case value - case unit - } -} diff --git a/Dependencies/LoopKit/LoopKit/GlucoseValue.swift b/Dependencies/LoopKit/LoopKit/GlucoseValue.swift deleted file mode 100644 index 59b21e553..000000000 --- a/Dependencies/LoopKit/LoopKit/GlucoseValue.swift +++ /dev/null @@ -1,91 +0,0 @@ -// -// GlucoseValue.swift -// LoopKit -// -// Created by Nathan Racklyeft on 3/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - - -import HealthKit - - -public protocol GlucoseValue: SampleValue { -} - -public struct SimpleGlucoseValue: Equatable, GlucoseValue { - public let startDate: Date - public let endDate: Date - public let quantity: HKQuantity - - public init(startDate: Date, endDate: Date? = nil, quantity: HKQuantity) { - self.startDate = startDate - self.endDate = endDate ?? startDate - self.quantity = quantity - } - - public init(_ glucoseValue: GlucoseValue) { - self.startDate = glucoseValue.startDate - self.endDate = glucoseValue.endDate - self.quantity = glucoseValue.quantity - } -} - -extension SimpleGlucoseValue: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.startDate = try container.decode(Date.self, forKey: .startDate) - self.endDate = try container.decode(Date.self, forKey: .endDate) - self.quantity = HKQuantity(unit: HKUnit(from: try container.decode(String.self, forKey: .quantityUnit)), - doubleValue: try container.decode(Double.self, forKey: .quantity)) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(startDate, forKey: .startDate) - try container.encode(endDate, forKey: .endDate) - try container.encode(quantity.doubleValue(for: .milligramsPerDeciliter), forKey: .quantity) - try container.encode(HKUnit.milligramsPerDeciliter.unitString, forKey: .quantityUnit) - } - - private enum CodingKeys: String, CodingKey { - case startDate - case endDate - case quantity - case quantityUnit - } -} - -public struct PredictedGlucoseValue: Equatable, GlucoseValue { - public let startDate: Date - public let quantity: HKQuantity - - public init(startDate: Date, quantity: HKQuantity) { - self.startDate = startDate - self.quantity = quantity - } -} - -extension PredictedGlucoseValue: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.startDate = try container.decode(Date.self, forKey: .startDate) - self.quantity = HKQuantity(unit: HKUnit(from: try container.decode(String.self, forKey: .quantityUnit)), - doubleValue: try container.decode(Double.self, forKey: .quantity)) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(startDate, forKey: .startDate) - try container.encode(quantity.doubleValue(for: .milligramsPerDeciliter), forKey: .quantity) - try container.encode(HKUnit.milligramsPerDeciliter.unitString, forKey: .quantityUnit) - } - - private enum CodingKeys: String, CodingKey { - case startDate - case quantity - case quantityUnit - } -} - -extension HKQuantitySample: GlucoseValue { } diff --git a/Dependencies/LoopKit/LoopKit/Guardrail.swift b/Dependencies/LoopKit/LoopKit/Guardrail.swift deleted file mode 100644 index 471f1c2c4..000000000 --- a/Dependencies/LoopKit/LoopKit/Guardrail.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// Guardrail.swift -// LoopKit -// -// Created by Michael Pangburn on 4/10/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import HealthKit - - -public enum SafetyClassification: Equatable { - public enum Threshold: Equatable { - case minimum - case belowRecommended - case aboveRecommended - case maximum - } - - case withinRecommendedRange - case outsideRecommendedRange(Threshold) -} - -public struct Guardrail { - public let absoluteBounds: ClosedRange - public let recommendedBounds: ClosedRange - public let startingSuggestion: Value? - - public init(absoluteBounds: ClosedRange, recommendedBounds: ClosedRange, startingSuggestion: Value? = nil) { - precondition(absoluteBounds.lowerBound <= recommendedBounds.lowerBound, "The minimum value must be less than or equal to the smallest recommended value") - precondition(absoluteBounds.upperBound >= recommendedBounds.upperBound, "The maximum value must be greater than or equal to the greatest recommended value") - if let startingSuggestion = startingSuggestion { - precondition(recommendedBounds.contains(startingSuggestion)) - } - self.absoluteBounds = absoluteBounds - self.recommendedBounds = recommendedBounds - self.startingSuggestion = startingSuggestion - } - - public func classification(for value: Value) -> SafetyClassification { - switch value { - case ...absoluteBounds.lowerBound where absoluteBounds.lowerBound != recommendedBounds.lowerBound: - return .outsideRecommendedRange(.minimum) - case .. StrideThrough { - stride(from: absoluteBounds.lowerBound, through: absoluteBounds.upperBound, by: increment) - } -} - -extension Guardrail where Value == HKQuantity { - public init(absoluteBounds: ClosedRange, recommendedBounds: ClosedRange, unit: HKUnit, startingSuggestion: Double? = nil) { - let absoluteBoundsWithUnit = HKQuantity(unit: unit, doubleValue: absoluteBounds.lowerBound)...HKQuantity(unit: unit, doubleValue: absoluteBounds.upperBound) - let recommendedBoundsWithUnit = HKQuantity(unit: unit, doubleValue: recommendedBounds.lowerBound)...HKQuantity(unit: unit, doubleValue: recommendedBounds.upperBound) - let startingSuggestionQuantity: HKQuantity? - if let startingSuggestion = startingSuggestion { - startingSuggestionQuantity = HKQuantity(unit: unit, doubleValue: startingSuggestion) - } else { - startingSuggestionQuantity = nil - } - self.init(absoluteBounds: absoluteBoundsWithUnit, recommendedBounds: recommendedBoundsWithUnit, startingSuggestion: startingSuggestionQuantity) - } - - public func allQuantities(stridingBy increment: HKQuantity, unit: HKUnit) -> [HKQuantity] { - allValues(stridingBy: increment, unit: unit) - .map { HKQuantity(unit: unit, doubleValue: $0) } - } - - public func allValues(stridingBy increment: HKQuantity, unit: HKUnit) -> [Double] { - Array(stride( - from: absoluteBounds.lowerBound.doubleValue(for: unit, withRounding: true), - through: absoluteBounds.upperBound.doubleValue(for: unit, withRounding: true), - by: increment.doubleValue(for: unit, withRounding: true) - )) - } -} diff --git a/Dependencies/LoopKit/LoopKit/HealthKitSampleStore.swift b/Dependencies/LoopKit/LoopKit/HealthKitSampleStore.swift deleted file mode 100644 index 979bf3364..000000000 --- a/Dependencies/LoopKit/LoopKit/HealthKitSampleStore.swift +++ /dev/null @@ -1,571 +0,0 @@ -// -// HealthKitSampleStore.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/24/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit -import os.log - - -extension Notification.Name { - public static let StoreAuthorizationStatusDidChange = Notification.Name(rawValue: "com.loudnate.LoopKit.AuthorizationStatusDidChangeNotification") -} - - -public enum HealthKitSampleStoreResult { - case success(T) - case failure(HealthKitSampleStore.StoreError) -} - - -public class HealthKitSampleStore { - - public enum StoreError: Error { - case authorizationDenied - case healthKitError(HKError) - } - - /// The sample type managed by this store - public let sampleType: HKSampleType - - /// The health store used for underlying queries - public let healthStore: HKHealthStore - - /// Whether the store should fetch data that was written to HealthKit from current app - private let observeHealthKitSamplesFromCurrentApp: Bool - - /// Whether the store should fetch data that was written to HealthKit from other apps - private let observeHealthKitSamplesFromOtherApps: Bool - - /// Whether the store is observing changes to types - public let observationEnabled: Bool - - /// For unit testing only. - internal var testQueryStore: HKSampleQueryTestable? - - /// Current date. Will return the unit-test configured date if set, or the current date otherwise. - internal var currentDate: Date { - test_currentDate ?? Date() - } - - /// Allows for controlling uses of the system date in unit testing - internal var test_currentDate: Date? - - internal func currentDate(timeIntervalSinceNow: TimeInterval = 0) -> Date { - return currentDate.addingTimeInterval(timeIntervalSinceNow) - } - - /// Declaring this as a var allows unit test to inject a mock for HKObserverQuery - internal var createObserverQuery: (HKSampleType, NSPredicate?, @escaping (HKObserverQuery, @escaping HKObserverQueryCompletionHandler, Error?) -> Void) -> HKObserverQuery = { (sampleType, predicate, updateHandler) in - return HKObserverQuery(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler) - } - - /// Allows unit test to inject a mock for HKAnchoredObjectQuery - internal var createAnchoredObjectQuery: (HKSampleType, NSPredicate?, HKQueryAnchor?, Int, @escaping (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, Error?) -> Void) -> HKAnchoredObjectQuery = { (sampleType, predicate, anchor, limit, resultsHandler) in - return HKAnchoredObjectQuery(type: sampleType, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: resultsHandler) - } - - private let log: OSLog - - public init( - healthStore: HKHealthStore, - observeHealthKitSamplesFromCurrentApp: Bool = true, - observeHealthKitSamplesFromOtherApps: Bool = true, - type: HKSampleType, - observationStart: Date, - observationEnabled: Bool, - test_currentDate: Date? = nil - ) { - self.healthStore = healthStore - self.observeHealthKitSamplesFromCurrentApp = observeHealthKitSamplesFromCurrentApp - self.observeHealthKitSamplesFromOtherApps = observeHealthKitSamplesFromOtherApps - self.sampleType = type - self.observationStart = observationStart - self.observationEnabled = observationEnabled - self.test_currentDate = test_currentDate - self.lockedQueryState = Locked(QueryState(anchorState: .uninitialized, authorizationDetermined: false)) - - self.log = OSLog(category: String(describing: Swift.type(of: self))) - } - - deinit { - if let query = observerQuery { - healthStore.stop(query) - } - observerQuery = nil - } - - // MARK: - Authorization - - /// Requests authorization from HealthKit to share and read the sample type. - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - Parameters: - /// - toShare: Whether to request write authorization. Defaults to true. - /// - read: Whether to request read authorization. Defaults to true. - /// - completion: A closure called after the authorization is completed - /// - result: The authorization result - public func authorize(toShare: Bool = true, read: Bool = true, _ completion: @escaping (_ result: HealthKitSampleStoreResult) -> Void) { - healthStore.requestAuthorization(toShare: toShare ? [sampleType] : [], read: read ? [sampleType] : []) { (completed, error) -> Void in - if completed { - self.mutateQueryState { state in - state.authorizationDetermined = true - } - completion(.success(true)) - } else { - let authError: StoreError - - if let error = error { - authError = .healthKitError(HKError(_nsError: error as NSError)) - } else { - authError = .authorizationDenied - } - - completion(.failure(authError)) - } - - // Do not remove this log: it actually triggers a query by calling preferredUnit, and can update the cache - // And trigger a unit change notification after authorization happens. - self.log.default("Checking units after authorization: %{public}@", String(describing: self.preferredUnit)) - } - } - - // MARK: - Query support - - /// The active observer query - internal var observerQuery: HKObserverQuery? { - didSet { - if let query = oldValue { - healthStore.stop(query) - } - - if let query = observerQuery { - log.debug("Executing observerQuery %@", query) - healthStore.execute(query) - } - } - } - - /// The earliest sample date for which additions and deletions are observed - public internal(set) var observationStart: Date { - didSet { - // If we are now looking farther back, then reset the query - if oldValue > observationStart { - log.default("observationStart changed: creating HK query") - createQuery(from: "observartionStart") - } - } - } - - private enum QueryAnchorState: Equatable { - case uninitialized - case initializationComplete(HKQueryAnchor?) - - var anchor: HKQueryAnchor? { - switch self { - case .uninitialized: - return nil - case.initializationComplete(let anchor): - return anchor - } - } - } - - /// The last-retreived anchor from an anchored object query - internal var queryAnchor: HKQueryAnchor? { - get { - if case .initializationComplete(let anchor) = queryState.anchorState { - return anchor - } else { - return nil - } - } - set { - mutateQueryState { state in - state.anchorState = .initializationComplete(newValue) - state.authorizationDetermined = !authorizationRequired - } - } - } - - private struct QueryState: Equatable { - var anchorState: QueryAnchorState - var authorizationDetermined: Bool - - // ObserverQuery will fail if HKAuthorizationStatus is undetermined - var readyToQuery: Bool { - return anchorState != .uninitialized && authorizationDetermined - } - } - - private let lockedQueryState: Locked - - private var queryState: QueryState { - return lockedQueryState.value - } - - @discardableResult - private func mutateQueryState(_ changes: (_ state: inout QueryState) -> Void) -> QueryState { - return setQueryStateWithResult({ (state) -> QueryState in - changes(&state) - return state - }) - } - - private func setQueryStateWithResult(_ changes: (_ state: inout QueryState) -> ReturnType) -> ReturnType { - var oldValue: QueryState! - var returnType: ReturnType! - let newValue = lockedQueryState.mutate { (state) in - oldValue = state - returnType = changes(&state) - } - - guard oldValue != newValue else { - return returnType - } - - if let anchor = newValue.anchorState.anchor, anchor != oldValue.anchorState.anchor { - storeQueryAnchor(anchor) - } - - if !oldValue.readyToQuery && newValue.readyToQuery { - createQuery(from: "main") - } - - if !oldValue.authorizationDetermined && newValue.authorizationDetermined { - NotificationCenter.default.post(name: .StoreAuthorizationStatusDidChange, object: self) - } - - return returnType - } - - - // Observation will not start until this is called. Pass nil to receive all the matching samples and recently deleted objects - func setInitialQueryAnchor(_ anchor: HKQueryAnchor?) { - queryAnchor = anchor - } - - func storeQueryAnchor(_ anchor: HKQueryAnchor) { - // Subclasses should override - } - - /// Called in response to an update by the observer query - /// - /// - Parameters: - /// - query: The query which triggered the update - /// - error: An error during the update, if one occurred - internal final func observerQueryHandler(query: HKObserverQuery, observerQueryCompletionHandler: @escaping HKObserverQueryCompletionHandler, error: Error?) { - - if let error = error { - log.error("Observer query %{public}@ notified of error: %{public}@", query, String(describing: error)) - observerQueryCompletionHandler() - return - } - - log.default("%{public}@ notified with changes. Fetching from: %{public}@", query, queryAnchor.map(String.init(describing:)) ?? "0") - executeAnchorQuery(observerQuery: query, observerQueryCompletionHandler: observerQueryCompletionHandler) - } - - internal final func executeAnchorQuery(observerQuery: HKObserverQuery, observerQueryCompletionHandler: @escaping HKObserverQueryCompletionHandler) { - - let batchSize = 500 - - let anchoredObjectQuery = createAnchoredObjectQuery(sampleType, observerQuery.predicate, queryAnchor, batchSize) { [weak self] (query, newSamples, deletedSamples, anchor, error) in - - guard let self else { - return - } - - if let error = error { - self.log.error("HKQuery: Error from anchoredObjectQuery: anchor: %{public}@ error: %{public}@", String(describing: anchor), String(describing: error)) - observerQueryCompletionHandler() - return - } - - guard let newSamples else { - self.log.error("HKQuery: Error from anchoredObjectQuery: newSamples is nil") - observerQueryCompletionHandler() - return - } - - guard let deletedSamples else { - self.log.error("HKQuery: Error from anchoredObjectQuery: deletedSamples is nil") - observerQueryCompletionHandler() - return - } - - guard let anchor = anchor else { - self.log.error("HKQuery: anchoredObjectQueryResultsHandler called with no anchor") - observerQueryCompletionHandler() - return - } - - self.log.default("AnchorQuery results new: %{public}d deleted: %{public}d anchor: %{public}@", newSamples.count, deletedSamples.count, anchor.description) - - guard anchor != self.queryAnchor else { - self.log.default("Skipping processing results from anchored object query, as anchor was already processed") - observerQueryCompletionHandler() - return - } - - self.processResults(from: query, added: newSamples, deleted: deletedSamples, anchor: anchor) { (success) in - if success { - // Do not advance anchor if we failed to update local cache - self.queryAnchor = anchor - - if newSamples.count + deletedSamples.count >= batchSize { - self.executeAnchorQuery(observerQuery: observerQuery, observerQueryCompletionHandler: observerQueryCompletionHandler) - } else { - observerQueryCompletionHandler() - } - } else { - observerQueryCompletionHandler() - } - } - } - - log.default("HKQuery: Executing anchored object query") - healthStore.execute(anchoredObjectQuery) - } - - /// Called in response to new results from an anchored object query - /// - /// - Parameters: - /// - query: The executed query - /// - added: An array of samples added - /// - deleted: An array of samples deleted - /// - error: An error from the query, if one occurred - internal func processResults(from query: HKAnchoredObjectQuery, added: [HKSample], deleted: [HKDeletedObject], anchor: HKQueryAnchor, completion: @escaping (Bool) -> Void) { - // To be overridden - completion(true) - } - - /// The preferred unit for the sample type - /// - /// The unit may be nil if the health store times out while fetching or the sample type is unsupported - public var preferredUnit: HKUnit? { - let identifier = HKQuantityTypeIdentifier(rawValue: sampleType.identifier) - return HealthStoreUnitCache.unitCache(for: healthStore).preferredUnit(for: identifier) - } -} - - -// MARK: - Unit Test Support -extension HealthKitSampleStore: HKSampleQueryTestable { - func executeSampleQuery( - for type: HKSampleType, - matching predicate: NSPredicate, - limit: Int = HKObjectQueryNoLimit, - sortDescriptors: [NSSortDescriptor]? = nil, - resultsHandler: @escaping (HKSampleQuery, [HKSample]?, Error?) -> Void - ) { - if let tester = testQueryStore { - tester.executeSampleQuery(for: type, matching: predicate, limit: limit, sortDescriptors: sortDescriptors, resultsHandler: resultsHandler) - } else { - let query = HKSampleQuery(sampleType: type, predicate: predicate, limit: limit, sortDescriptors: sortDescriptors, resultsHandler: resultsHandler) - healthStore.execute(query) - } - } -} - - -// MARK: - Query -extension HealthKitSampleStore { - internal func predicateForSamples(withStart startDate: Date?, end endDate: Date?, options: HKQueryOptions = []) -> NSPredicate? { - guard observeHealthKitSamplesFromCurrentApp || observeHealthKitSamplesFromOtherApps else { - return nil - } - - // Initial predicate is just the date range - var predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: options) - - // If we don't want samples from the current app, then only query samples NOT from the default HKSource - if !observeHealthKitSamplesFromCurrentApp { - predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSCompoundPredicate(notPredicateWithSubpredicate: HKQuery.predicateForObjects(from: HKSource.default()))]) - - // Othewrise, if we don't want samples from other apps, then only query samples from the default HKSource - } else if !observeHealthKitSamplesFromOtherApps { - predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, HKQuery.predicateForObjects(from: HKSource.default())]) - } - - return predicate - } -} - - -// MARK: - Observation -extension HealthKitSampleStore { - internal func createQuery(from: String) { - log.debug("%@ [from: %@]", #function, from) - log.debug("%@ [sampleType: %@]", #function, sampleType) - log.debug("%@ [observationEnabled: %d]", #function, observationEnabled) - log.debug("%@ [observeHealthKitSamplesFromCurrentApp: %d]", #function, observeHealthKitSamplesFromCurrentApp) - log.debug("%@ [observeHealthKitSamplesFromOtherApps: %d]", #function, observeHealthKitSamplesFromOtherApps) - log.debug("%@ [observationStart: %@]", #function, String(describing: observationStart)) - - guard observationEnabled else { - return - } - - guard let predicate = predicateForSamples(withStart: observationStart, end: nil) else { - return - } - - // Assigning observerQuery here starts the query - observerQuery = createObserverQuery(sampleType, predicate) { [weak self] (query, completionHandler, error) in - // This is the HKObserverQueryCompletionHandler - self?.observerQueryHandler(query: query, observerQueryCompletionHandler: completionHandler, error: error) - } - - enableBackgroundDelivery { (result) in - switch result { - case .failure(let error): - self.log.error("Error enabling background delivery: %@", error.localizedDescription) - case .success: - self.log.default("Enabled background delivery for %{public}@", self.sampleType) - } - } - } - - - /// Enables the immediate background delivery of updates to samples from HealthKit. - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - Parameter completion: A closure called after the request is completed - /// - Parameter result: A boolean indicating the new background delivery state - private func enableBackgroundDelivery(_ completion: @escaping (_ result: HealthKitSampleStoreResult) -> Void) { - #if os(iOS) - healthStore.enableBackgroundDelivery(for: sampleType, frequency: .immediate) { (enabled, error) in - if let error = error { - completion(.failure(.healthKitError(HKError(_nsError: error as NSError)))) - } else if enabled { - completion(.success(true)) - } else { - assertionFailure() - } - } - #endif - } - - /// Disables the immediate background delivery of updates to samples from HealthKit. - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - Parameter completion: A closure called after the request is completed - /// - Parameter result: A boolean indicating the new background delivery state - private func disableBackgroundDelivery(_ completion: @escaping (_ result: HealthKitSampleStoreResult) -> Void) { - #if os(iOS) - healthStore.disableBackgroundDelivery(for: sampleType) { (disabled, error) in - if let error = error { - completion(.failure(.healthKitError(HKError(_nsError: error as NSError)))) - } else if disabled { - completion(.success(false)) - } else { - assertionFailure() - } - } - #endif - } -} - - -// MARK: - HKHealthStore helpers -extension HealthKitSampleStore { - - /// True if the user has explicitly authorized access to any required share types - public var sharingAuthorized: Bool { - return healthStore.authorizationStatus(for: sampleType) == .sharingAuthorized - } - - /// True if the user has explicitly denied access to any required share types - public var sharingDenied: Bool { - return healthStore.authorizationStatus(for: sampleType) == .sharingDenied - } - - /// True if the store requires authorization - public var authorizationRequired: Bool { - return healthStore.authorizationStatus(for: sampleType) == .notDetermined - } - - /** - Queries the preferred unit for the authorized share types. If more than one unit is retrieved, - then the completion contains just one of them. - - - parameter completion: A closure called after the query is completed. This closure takes two arguments: - - unit: The retrieved unit - - error: An error object explaining why the retrieval was unsuccessful - */ - @available(*, deprecated, message: "Use HealthKitSampleStore.getter:preferredUnit instead") - public func preferredUnit(_ completion: @escaping (_ unit: HKUnit?, _ error: Error?) -> Void) { - preferredUnit { result in - switch result { - case .success(let unit): - completion(unit, nil) - case .failure(let error): - completion(nil, error) - } - } - } - - /// Queries the preferred unit for the sample type. - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - Parameter completion: A closure called after the query is completed - /// - Parameter result: The query result - @available(*, deprecated, message: "Use HealthKitSampleStore.getter:preferredUnit instead") - private func preferredUnit(_ completion: @escaping (_ result: HealthKitSampleStoreResult) -> Void) { - let quantityTypes = [self.sampleType].compactMap { (sampleType) -> HKQuantityType? in - return sampleType as? HKQuantityType - } - - self.healthStore.preferredUnits(for: Set(quantityTypes)) { (quantityToUnit, error) -> Void in - if let error = error { - completion(.failure(.healthKitError(HKError(_nsError: error as NSError)))) - } else if let unit = quantityToUnit.values.first { - completion(.success(unit)) - } else { - assertionFailure() - } - } - } -} - - -extension HealthKitSampleStore: CustomDebugStringConvertible { - public var debugDescription: String { - return """ - * observerQuery: \(String(describing: observerQuery)) - * observationStart: \(observationStart) - * observationEnabled: \(observationEnabled) - * authorizationRequired: \(authorizationRequired) - """ - } -} - - -extension HealthKitSampleStore.StoreError: LocalizedError { - public var errorDescription: String? { - switch self { - case .authorizationDenied: - return LocalizedString("Authorization Denied", comment: "The error description describing when Health sharing was denied") - case .healthKitError(let error): - return error.localizedDescription - } - } - - public var recoverySuggestion: String? { - switch self { - case .authorizationDenied: - return LocalizedString("Please re-enable sharing in Health", comment: "The error recovery suggestion when Health sharing was denied") - case .healthKitError(let error): - return error.errorUserInfo[NSLocalizedRecoverySuggestionErrorKey] as? String - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/HealthStoreUnitCache.swift b/Dependencies/LoopKit/LoopKit/HealthStoreUnitCache.swift deleted file mode 100644 index 913860123..000000000 --- a/Dependencies/LoopKit/LoopKit/HealthStoreUnitCache.swift +++ /dev/null @@ -1,119 +0,0 @@ -// -// HealthStoreUnitCache.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import HealthKit -import os.log - -public extension Notification.Name { - // used to avoid potential timing issues since a unit change triggers a cache refresh and all stores pull the current unit from the cache - static let HealthStorePreferredGlucoseUnitDidChange = Notification.Name(rawValue: "com.loopKit.notification.HealthStorePreferredGlucoseUnitDidChange") -} - -public class HealthStoreUnitCache { - private static var cacheCache = NSMapTable.weakToStrongObjects() - - public let healthStore: HKHealthStore - - private static let fixedUnits: [HKQuantityTypeIdentifier: HKUnit] = [ - .dietaryCarbohydrates: .gram(), - .insulinDelivery: .internationalUnit() - ] - - private var unitCache = Locked([HKQuantityTypeIdentifier: HKUnit]()) - - private var userPreferencesChangeObserver: Any? - - private init(healthStore: HKHealthStore) { - self.healthStore = healthStore - - userPreferencesChangeObserver = NotificationCenter.default.addObserver(forName: .HKUserPreferencesDidChange, object: healthStore, queue: nil, using: { [weak self] _ in - DispatchQueue.global().async { - self?.updateCachedUnits() - } - }) - } - - public class func unitCache(for healthStore: HKHealthStore) -> HealthStoreUnitCache { - if let cache = cacheCache.object(forKey: healthStore) { - return cache - } - - let cache = HealthStoreUnitCache(healthStore: healthStore) - cacheCache.setObject(cache, forKey: healthStore) - return cache - } - - public func preferredUnit(for quantityTypeIdentifier: HKQuantityTypeIdentifier) -> HKUnit? { - if let unit = HealthStoreUnitCache.fixedUnits[quantityTypeIdentifier] { - return unit - } - - if let unit = unitCache.value[quantityTypeIdentifier] { - return unit - } - - return getHealthStoreUnitAndUpdateCache(for: quantityTypeIdentifier) - } - - @discardableResult private func getHealthStoreUnitAndUpdateCache(for quantityTypeIdentifier: HKQuantityTypeIdentifier) -> HKUnit? { - guard let quantityType = HKQuantityType.quantityType(forIdentifier: quantityTypeIdentifier) else { - return nil - } - - var unit: HKUnit? - let semaphore = DispatchSemaphore(value: 0) - - healthStore.preferredUnits(for: [quantityType]) { (results, error) in - if let error = error { - // This is a common/expected case when protected data is unavailable - OSLog(category: "HealthStoreUnitCache").info("Error fetching unit for %{public}@: %{public}@", quantityTypeIdentifier.rawValue, String(describing: error)) - } - - unit = results[quantityType] - - self.updateCache(for: quantityTypeIdentifier, with: unit) - - semaphore.signal() - } - - _ = semaphore.wait(timeout: .now() + .seconds(3)) - return unit - } - - private func updateCachedUnits() { - let quantityTypeIdentifiers = unitCache.value.keys - for quantityTypeIdentifier in quantityTypeIdentifiers { - self.getHealthStoreUnitAndUpdateCache(for: quantityTypeIdentifier) - } - } - - private func updateCache(for quantityTypeIdentifier: HKQuantityTypeIdentifier, with unit: HKUnit?) { - _ = self.unitCache.mutate({ (cache) in - guard unit != cache[quantityTypeIdentifier] else { - return - } - - cache[quantityTypeIdentifier] = unit - switch quantityTypeIdentifier { - case .bloodGlucose: - // currently only changes to glucose unit is reported - DispatchQueue.main.async { - NotificationCenter.default.post(name: .HealthStorePreferredGlucoseUnitDidChange, object: self.healthStore) - } - default: - break - } - }) - } - - deinit { - if let observer = userPreferencesChangeObserver { - NotificationCenter.default.removeObserver(observer) - } - } -} - diff --git a/Dependencies/LoopKit/LoopKit/Info.plist b/Dependencies/LoopKit/LoopKit/Info.plist deleted file mode 100644 index f9b44a004..000000000 --- a/Dependencies/LoopKit/LoopKit/Info.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.0 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHealthShareUsageDescription - Meal data from the Health database is used to determine glucose effects. Glucose data is retrieved from HealthKit for graphing and analysis. - NSHealthUpdateUsageDescription - Carbohydrate meal data entered in the app is stored in the Health database. Glucose data is stored securely in HealthKit. - NSPrincipalClass - - - diff --git a/Dependencies/LoopKit/LoopKit/Insulin/ExponentialInsulinModelPreset.swift b/Dependencies/LoopKit/LoopKit/Insulin/ExponentialInsulinModelPreset.swift deleted file mode 100644 index df2b51e21..000000000 --- a/Dependencies/LoopKit/LoopKit/Insulin/ExponentialInsulinModelPreset.swift +++ /dev/null @@ -1,86 +0,0 @@ -// -// ExponentialInsulinModelPreset.swift -// LoopKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum ExponentialInsulinModelPreset: String, Codable { - case rapidActingAdult - case rapidActingChild - case fiasp - case lyumjev - case afrezza -} - - -// MARK: - Model generation -extension ExponentialInsulinModelPreset { - public var actionDuration: TimeInterval { - switch self { - case .rapidActingAdult: - return .minutes(360) - case .rapidActingChild: - return .minutes(360) - case .fiasp: - return .minutes(360) - case .lyumjev: - return .minutes(360) - case .afrezza: - return .minutes(300) - } - } - - public var peakActivity: TimeInterval { - switch self { - case .rapidActingAdult: - return .minutes(75) - case .rapidActingChild: - return .minutes(65) - case .fiasp: - return .minutes(55) - case .lyumjev: - return .minutes(55) - case.afrezza: - return .minutes(29) - } - } - - public var delay: TimeInterval { - switch self { - case .rapidActingAdult: - return .minutes(10) - case .rapidActingChild: - return .minutes(10) - case .fiasp: - return .minutes(10) - case .lyumjev: - return .minutes(10) - case.afrezza: - return .minutes(10) - } - } - - var model: InsulinModel { - return ExponentialInsulinModel(actionDuration: actionDuration, peakActivityTime: peakActivity, delay: delay) - } -} - - -extension ExponentialInsulinModelPreset: InsulinModel { - public var effectDuration: TimeInterval { - return model.effectDuration - } - - public func percentEffectRemaining(at time: TimeInterval) -> Double { - return model.percentEffectRemaining(at: time) - } -} - -extension ExponentialInsulinModelPreset: CustomDebugStringConvertible { - public var debugDescription: String { - return "\(self.rawValue)(\(String(reflecting: model))" - } -} diff --git a/Dependencies/LoopKit/LoopKit/Insulin/InsulinModelProvider.swift b/Dependencies/LoopKit/LoopKit/Insulin/InsulinModelProvider.swift deleted file mode 100644 index f99aca822..000000000 --- a/Dependencies/LoopKit/LoopKit/Insulin/InsulinModelProvider.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// InsulinModelProvider.swift -// LoopKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -public protocol InsulinModelProvider { - func model(for type: InsulinType?) -> InsulinModel -} - -public struct PresetInsulinModelProvider: InsulinModelProvider { - var defaultRapidActingModel: InsulinModel? - - public init(defaultRapidActingModel: InsulinModel?) { - self.defaultRapidActingModel = defaultRapidActingModel - } - - public func model(for type: InsulinType?) -> InsulinModel { - switch type { - case .fiasp: - return ExponentialInsulinModelPreset.fiasp - case .lyumjev: - return ExponentialInsulinModelPreset.lyumjev - case .afrezza: - return ExponentialInsulinModelPreset.afrezza - default: - return defaultRapidActingModel ?? ExponentialInsulinModelPreset.rapidActingAdult - } - } -} - -// Provides a fixed model, ignoring insulin type -public struct StaticInsulinModelProvider: InsulinModelProvider { - var model: InsulinModel - - public init(_ model: InsulinModel) { - self.model = model - } - - public func model(for type: InsulinType?) -> InsulinModel { - return model - } -} - - diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/AutomaticDoseRecommendation.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/AutomaticDoseRecommendation.swift deleted file mode 100644 index 1d290a6d9..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/AutomaticDoseRecommendation.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// AutomaticDoseRecommendation.swift -// LoopKit -// -// Created by Pete Schwamb on 1/16/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct AutomaticDoseRecommendation: Equatable { - public let basalAdjustment: TempBasalRecommendation? - public let bolusUnits: Double? - - public init(basalAdjustment: TempBasalRecommendation?, bolusUnits: Double? = nil) { - self.basalAdjustment = basalAdjustment - self.bolusUnits = bolusUnits - } -} - -extension AutomaticDoseRecommendation: Codable {} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/CachedInsulinDeliveryObject+CoreDataClass.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/CachedInsulinDeliveryObject+CoreDataClass.swift deleted file mode 100644 index 6cde4f50b..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/CachedInsulinDeliveryObject+CoreDataClass.swift +++ /dev/null @@ -1,258 +0,0 @@ -// -// CachedInsulinDeliveryObject+CoreDataClass.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// -// - -import Foundation -import CoreData -import HealthKit - -class CachedInsulinDeliveryObject: NSManagedObject { - var reason: HKInsulinDeliveryReason! { - get { - willAccessValue(forKey: "reason") - defer { didAccessValue(forKey: "reason") } - - guard let value = primitiveReason?.intValue else { - return nil - } - - return HKInsulinDeliveryReason(rawValue: value) - } - set { - willChangeValue(forKey: "reason") - defer { didChangeValue(forKey: "reason") } - - guard let value = newValue?.rawValue else { - primitiveReason = nil - return - } - - primitiveReason = NSNumber(value: value) - } - } - - var scheduledBasalRate: HKQuantity? { - get { - willAccessValue(forKey: "scheduledBasalRate") - defer { didAccessValue(forKey: "scheduledBasalRate") } - - guard let rate = primitiveScheduledBasalRate else { - return nil - } - - return HKQuantity(unit: DoseEntry.unitsPerHour, doubleValue: rate.doubleValue) - } - set { - willChangeValue(forKey: "scheduledBasalRate") - defer { didChangeValue(forKey: "scheduledBasalRate") } - - guard let rate = newValue?.doubleValue(for: DoseEntry.unitsPerHour) else { - primitiveScheduledBasalRate = nil - return - } - - primitiveScheduledBasalRate = NSNumber(value: rate) - } - } - - var programmedTempBasalRate: HKQuantity? { - get { - willAccessValue(forKey: "programmedTempBasalRate") - defer { didAccessValue(forKey: "programmedTempBasalRate") } - - guard let rate = primitiveProgrammedTempBasalRate else { - return nil - } - - return HKQuantity(unit: DoseEntry.unitsPerHour, doubleValue: rate.doubleValue) - } - set { - willChangeValue(forKey: "programmedTempBasalRate") - defer { didChangeValue(forKey: "programmedTempBasalRate") } - - guard let rate = newValue?.doubleValue(for: DoseEntry.unitsPerHour) else { - primitiveProgrammedTempBasalRate = nil - return - } - - primitiveProgrammedTempBasalRate = NSNumber(value: rate) - } - } - - var insulinType: InsulinType? { - get { - willAccessValue(forKey: "insulinType") - defer { didAccessValue(forKey: "insulinType") } - guard let type = primitiveInsulinType else { - return nil - } - return InsulinType(rawValue: type.intValue) - } - set { - willChangeValue(forKey: "insulinType") - defer { didChangeValue(forKey: "insulinType") } - primitiveInsulinType = newValue != nil ? NSNumber(value: newValue!.rawValue) : nil - } - } - - var automaticallyIssued: Bool? { - get { - willAccessValue(forKey: "automaticallyIssued") - defer { didAccessValue(forKey: "automaticallyIssued") } - return primitiveAutomaticallyIssued?.boolValue - } - set { - willChangeValue(forKey: "automaticallyIssued") - defer { didChangeValue(forKey: "automaticallyIssued") } - primitiveAutomaticallyIssued = newValue != nil ? NSNumber(booleanLiteral: newValue!) : nil - } - } - - var hasUpdatedModificationCounter: Bool { changedValues().keys.contains("modificationCounter") } - - func updateModificationCounter() { setPrimitiveValue(managedObjectContext!.modificationCounter!, forKey: "modificationCounter") } - - public override func awakeFromInsert() { - super.awakeFromInsert() - updateModificationCounter() - createdAt = Date() - } - - public override func willSave() { - if isUpdated && !hasUpdatedModificationCounter { - updateModificationCounter() - } - super.willSave() - } -} - -// MARK: - Helpers - -extension CachedInsulinDeliveryObject { - var dose: DoseEntry! { - let type: DoseType - - switch reason! { - case .basal: - if isSuspend { - type = .suspend - } else if programmedTempBasalRate != nil { - type = .tempBasal - } else { - type = .basal - } - case .bolus: - type = .bolus - @unknown default: - fatalError("CachedInsulinDeliveryObject has unexpected reason value: \(String(describing: reason))") - } - - let doseValue: Double - let unit: DoseUnit - let deliveredUnits: Double? - - if let programmedRate = programmedTempBasalRate { - doseValue = programmedRate.doubleValue(for: .internationalUnitsPerHour) - unit = .unitsPerHour - deliveredUnits = value - } else { - doseValue = value - unit = .units - deliveredUnits = nil - } - - return DoseEntry( - type: type, - startDate: startDate, - endDate: endDate, - value: doseValue, - unit: unit, - deliveredUnits: !isMutable ? deliveredUnits : nil, - description: nil, - syncIdentifier: syncIdentifier, - scheduledBasalRate: scheduledBasalRate, - insulinType: insulinType, - automatic: automaticallyIssued, - manuallyEntered: manuallyEntered, - isMutable: isMutable, - wasProgrammedByPumpUI: wasProgrammedByPumpUI - ) - } -} - -extension CachedInsulinDeliveryObject { - func create(fromExisting sample: HKQuantitySample, on date: Date = Date()) { - self.uuid = sample.uuid - self.provenanceIdentifier = sample.provenanceIdentifier - self.hasLoopKitOrigin = sample.hasLoopKitOrigin - self.startDate = sample.startDate - self.endDate = sample.endDate - self.syncIdentifier = sample.syncIdentifier ?? sample.uuid.uuidString // External doses might not have a syncIdentifier, so use the UUID - self.value = sample.quantity.doubleValue(for: .internationalUnit()) - self.scheduledBasalRate = sample.scheduledBasalRate - self.programmedTempBasalRate = sample.programmedTempBasalRate - self.insulinType = sample.insulinType - self.automaticallyIssued = sample.automaticallyIssued - self.manuallyEntered = sample.manuallyEntered - self.isSuspend = sample.isSuspend - self.reason = sample.insulinDeliveryReason - self.createdAt = date - } -} - -extension CachedInsulinDeliveryObject { - func create(from entry: DoseEntry, by provenanceIdentifier: String, at date: Date) { - assert(entry.type != .resume) - - self.uuid = nil - self.provenanceIdentifier = provenanceIdentifier - self.hasLoopKitOrigin = true - self.startDate = entry.startDate - self.endDate = entry.endDate - self.syncIdentifier = entry.syncIdentifier - self.value = entry.unitsInDeliverableIncrements - self.scheduledBasalRate = entry.scheduledBasalRate - self.programmedTempBasalRate = (entry.type == .tempBasal) ? HKQuantity(unit: .internationalUnitsPerHour, doubleValue: entry.unitsPerHour) : nil - self.reason = (entry.type == .bolus) ? .bolus : .basal - self.createdAt = date - self.deletedAt = nil - self.insulinType = entry.insulinType - self.automaticallyIssued = entry.automatic - self.manuallyEntered = entry.manuallyEntered - self.isSuspend = (entry.type == .suspend) - self.isMutable = entry.isMutable - self.wasProgrammedByPumpUI = entry.wasProgrammedByPumpUI - updateModificationCounter() // Maintains modificationCounter order - } - - func update(from entry: DoseEntry) { - assert(entry.type != .resume) - // startDate can change when doses split by basal schedule changes are later split by - // override enactments/cancels. - //assert(entry.startDate == startDate) - assert(entry.syncIdentifier == syncIdentifier) - if !isMutable { - assertionFailure("Attempt to update un-mutable dose: \(self) with \(entry)") - } - - self.startDate = entry.startDate - self.endDate = entry.endDate - self.syncIdentifier = entry.syncIdentifier - self.value = entry.unitsInDeliverableIncrements - self.scheduledBasalRate = entry.scheduledBasalRate - self.programmedTempBasalRate = (entry.type == .tempBasal) ? HKQuantity(unit: .internationalUnitsPerHour, doubleValue: entry.unitsPerHour) : nil - self.reason = (entry.type == .bolus) ? .bolus : .basal - self.deletedAt = nil - self.insulinType = entry.insulinType - self.automaticallyIssued = entry.automatic - self.manuallyEntered = entry.manuallyEntered - self.isSuspend = (entry.type == .suspend) - self.isMutable = entry.isMutable - self.wasProgrammedByPumpUI = entry.wasProgrammedByPumpUI - updateModificationCounter() // Maintains modificationCounter order - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/CachedInsulinDeliveryObject+CoreDataProperties.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/CachedInsulinDeliveryObject+CoreDataProperties.swift deleted file mode 100644 index 56a2f880b..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/CachedInsulinDeliveryObject+CoreDataProperties.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// CachedInsulinDeliveryObject+CoreDataProperties.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// -// - -import Foundation -import CoreData - - -extension CachedInsulinDeliveryObject { - - @nonobjc public class func fetchRequest() -> NSFetchRequest { - return NSFetchRequest(entityName: "CachedInsulinDeliveryObject") - } - - @NSManaged public var uuid: UUID? - @NSManaged public var provenanceIdentifier: String - @NSManaged public var hasLoopKitOrigin: Bool - @NSManaged public var startDate: Date - @NSManaged public var endDate: Date - @NSManaged public var syncIdentifier: String? - @NSManaged public var value: Double - @NSManaged public var primitiveScheduledBasalRate: NSNumber? - @NSManaged public var primitiveProgrammedTempBasalRate: NSNumber? - @NSManaged public var primitiveReason: NSNumber? - @NSManaged public var createdAt: Date - @NSManaged public var deletedAt: Date? - @NSManaged public var primitiveInsulinType: NSNumber? - @NSManaged public var primitiveAutomaticallyIssued: NSNumber? - @NSManaged public var manuallyEntered: Bool - @NSManaged public var isSuspend: Bool - @NSManaged public var isMutable: Bool - @NSManaged public var modificationCounter: Int64 - @NSManaged public var wasProgrammedByPumpUI: Bool -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/DoseEntry.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/DoseEntry.swift deleted file mode 100644 index 48958c703..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/DoseEntry.swift +++ /dev/null @@ -1,272 +0,0 @@ -// -// DoseEntry.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/31/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -public struct DoseEntry: TimelineValue, Equatable { - public let type: DoseType - public let startDate: Date - public let endDate: Date - internal let value: Double - public let unit: DoseUnit - public let deliveredUnits: Double? - public let description: String? - public let insulinType: InsulinType? - public let automatic: Bool? - public let manuallyEntered: Bool - public internal(set) var syncIdentifier: String? - public let isMutable: Bool - public let wasProgrammedByPumpUI: Bool - - /// The scheduled basal rate during this dose entry - public internal(set) var scheduledBasalRate: HKQuantity? - - public init(suspendDate: Date, automatic: Bool? = nil, isMutable: Bool = false, wasProgrammedByPumpUI: Bool = false) { - self.init(type: .suspend, startDate: suspendDate, value: 0, unit: .units, automatic: automatic, isMutable: isMutable, wasProgrammedByPumpUI: wasProgrammedByPumpUI) - } - - public init(resumeDate: Date, insulinType: InsulinType? = nil, automatic: Bool? = nil, isMutable: Bool = false, wasProgrammedByPumpUI: Bool = false) { - self.init(type: .resume, startDate: resumeDate, value: 0, unit: .units, insulinType: insulinType, automatic: automatic, isMutable: isMutable, wasProgrammedByPumpUI: wasProgrammedByPumpUI) - } - - // If the insulin model field is nil, it's assumed that the model is the type of insulin the pump dispenses - public init(type: DoseType, startDate: Date, endDate: Date? = nil, value: Double, unit: DoseUnit, deliveredUnits: Double? = nil, description: String? = nil, syncIdentifier: String? = nil, scheduledBasalRate: HKQuantity? = nil, insulinType: InsulinType? = nil, automatic: Bool? = nil, manuallyEntered: Bool = false, isMutable: Bool = false, wasProgrammedByPumpUI: Bool = false) { - self.type = type - self.startDate = startDate - self.endDate = endDate ?? startDate - self.value = value - self.unit = unit - self.deliveredUnits = deliveredUnits - self.description = description - self.syncIdentifier = syncIdentifier - self.scheduledBasalRate = scheduledBasalRate - self.insulinType = insulinType - self.automatic = automatic - self.manuallyEntered = manuallyEntered - self.isMutable = isMutable - self.wasProgrammedByPumpUI = wasProgrammedByPumpUI - } -} - - -extension DoseEntry { - public static var units = HKUnit.internationalUnit() - - public static let unitsPerHour = HKUnit.internationalUnit().unitDivided(by: .hour()) - - private var hours: Double { - return endDate.timeIntervalSince(startDate).hours - } - - public var programmedUnits: Double { - switch unit { - case .units: - return value - case .unitsPerHour: - return value * hours - } - } - - public var unitsPerHour: Double { - switch unit { - case .units: - let hours = self.hours - guard hours != 0 else { - return 0 - } - - return value / hours - case .unitsPerHour: - return value - } - } - - /// The number of units delivered, net the basal rate scheduled during that time, which can be used to compute insulin on-board and glucose effects - public var netBasalUnits: Double { - switch type { - case .bolus: - return deliveredUnits ?? programmedUnits - case .basal: - return 0 - case .resume, .suspend, .tempBasal: - break - } - - guard hours > 0 else { - return 0 - } - - let scheduledUnitsPerHour: Double - if let basalRate = scheduledBasalRate { - scheduledUnitsPerHour = basalRate.doubleValue(for: DoseEntry.unitsPerHour) - } else { - scheduledUnitsPerHour = 0 - } - - let scheduledUnits = scheduledUnitsPerHour * hours - return unitsInDeliverableIncrements - scheduledUnits - } - - /// The rate of delivery, net the basal rate scheduled during that time, which can be used to compute insulin on-board and glucose effects - public var netBasalUnitsPerHour: Double { - switch type { - case .basal: - return 0 - case .bolus: - return self.unitsPerHour - default: - break - } - - guard let basalRate = scheduledBasalRate else { - return 0 - } - - let unitsPerHour = self.unitsPerHour - basalRate.doubleValue(for: DoseEntry.unitsPerHour) - - guard abs(unitsPerHour) > .ulpOfOne else { - return 0 - } - - return unitsPerHour - } - - /// The smallest increment per unit of hourly basal delivery - /// TODO: Is this 40 for x23 models? (yes - PS 7/26/2019) - /// MinimedPumpmanager will be updated to report deliveredUnits, so this will end up not being used. - private static let minimumMinimedIncrementPerUnit: Double = 20 - - /// Returns the delivered units, or rounds to nearest deliverable (mdt) increment - public var unitsInDeliverableIncrements: Double { - guard case .unitsPerHour = unit else { - return deliveredUnits ?? programmedUnits - } - - return deliveredUnits ?? round(programmedUnits * DoseEntry.minimumMinimedIncrementPerUnit) / DoseEntry.minimumMinimedIncrementPerUnit - } -} - -extension DoseEntry: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.type = try container.decode(DoseType.self, forKey: .type) - self.startDate = try container.decode(Date.self, forKey: .startDate) - self.endDate = try container.decode(Date.self, forKey: .endDate) - self.value = try container.decode(Double.self, forKey: .value) - self.unit = try container.decode(DoseUnit.self, forKey: .unit) - self.deliveredUnits = try container.decodeIfPresent(Double.self, forKey: .deliveredUnits) - self.description = try container.decodeIfPresent(String.self, forKey: .description) - self.syncIdentifier = try container.decodeIfPresent(String.self, forKey: .syncIdentifier) - self.insulinType = try container.decodeIfPresent(InsulinType.self, forKey: .insulinType) - if let scheduledBasalRate = try container.decodeIfPresent(Double.self, forKey: .scheduledBasalRate), - let scheduledBasalRateUnit = try container.decodeIfPresent(String.self, forKey: .scheduledBasalRateUnit) { - self.scheduledBasalRate = HKQuantity(unit: HKUnit(from: scheduledBasalRateUnit), doubleValue: scheduledBasalRate) - } - self.automatic = try container.decodeIfPresent(Bool.self, forKey: .automatic) - self.manuallyEntered = try container.decodeIfPresent(Bool.self, forKey: .manuallyEntered) ?? false - self.isMutable = try container.decodeIfPresent(Bool.self, forKey: .isMutable) ?? false - self.wasProgrammedByPumpUI = try container.decodeIfPresent(Bool.self, forKey: .wasProgrammedByPumpUI) ?? false - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(type, forKey: .type) - try container.encode(startDate, forKey: .startDate) - try container.encode(endDate, forKey: .endDate) - try container.encode(value, forKey: .value) - try container.encode(unit, forKey: .unit) - try container.encodeIfPresent(deliveredUnits, forKey: .deliveredUnits) - try container.encodeIfPresent(description, forKey: .description) - try container.encodeIfPresent(syncIdentifier, forKey: .syncIdentifier) - try container.encodeIfPresent(insulinType, forKey: .insulinType) - if let scheduledBasalRate = scheduledBasalRate { - try container.encode(scheduledBasalRate.doubleValue(for: DoseEntry.unitsPerHour), forKey: .scheduledBasalRate) - try container.encode(DoseEntry.unitsPerHour.unitString, forKey: .scheduledBasalRateUnit) - } - try container.encodeIfPresent(automatic, forKey: .automatic) - try container.encode(manuallyEntered, forKey: .manuallyEntered) - try container.encode(isMutable, forKey: .isMutable) - try container.encode(wasProgrammedByPumpUI, forKey: .wasProgrammedByPumpUI) - } - - private enum CodingKeys: String, CodingKey { - case type - case startDate - case endDate - case value - case unit - case deliveredUnits - case description - case syncIdentifier - case scheduledBasalRate - case scheduledBasalRateUnit - case insulinType - case automatic - case manuallyEntered - case isMutable - case wasProgrammedByPumpUI - } -} - -extension DoseEntry: RawRepresentable { - public typealias RawValue = [String: Any] - - public init?(rawValue: [String: Any]) { - guard let rawType = rawValue["type"] as? DoseType.RawValue, - let type = DoseType(rawValue: rawType), - let startDate = rawValue["startDate"] as? Date, - let endDate = rawValue["endDate"] as? Date, - let value = rawValue["value"] as? Double, - let rawUnit = rawValue["unit"] as? DoseUnit.RawValue, - let unit = DoseUnit(rawValue: rawUnit), - let manuallyEntered = rawValue["manuallyEntered"] as? Bool - else { - return nil - } - - self.type = type - self.startDate = startDate - self.endDate = endDate - self.value = value - self.unit = unit - self.manuallyEntered = manuallyEntered - - self.deliveredUnits = rawValue["deliveredUnits"] as? Double - self.description = rawValue["description"] as? String - self.insulinType = (rawValue["insulinType"] as? InsulinType.RawValue).flatMap { InsulinType(rawValue: $0) } - self.automatic = rawValue["automatic"] as? Bool - self.syncIdentifier = rawValue["syncIdentifier"] as? String - self.scheduledBasalRate = (rawValue["scheduledBasalRate"] as? Double).flatMap { HKQuantity(unit: .internationalUnitsPerHour, doubleValue: $0) } - self.isMutable = rawValue["isMutable"] as? Bool ?? false - self.wasProgrammedByPumpUI = rawValue["wasProgrammedByPumpUI"] as? Bool ?? false - } - - public var rawValue: [String: Any] { - var rawValue: [String: Any] = [ - "type": type.rawValue, - "startDate": startDate, - "endDate": endDate, - "value": value, - "unit": unit.rawValue, - "manuallyEntered": manuallyEntered, - "isMutable": isMutable, - "wasProgrammedByPumpUI": wasProgrammedByPumpUI - ] - - rawValue["deliveredUnits"] = deliveredUnits - rawValue["description"] = description - rawValue["insulinType"] = insulinType?.rawValue - rawValue["automatic"] = automatic - rawValue["syncIdentifier"] = syncIdentifier - rawValue["scheduledBasalRate"] = scheduledBasalRate?.doubleValue(for: .internationalUnitsPerHour) - - return rawValue - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/DoseStore.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/DoseStore.swift deleted file mode 100644 index 7494c49c9..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/DoseStore.swift +++ /dev/null @@ -1,1680 +0,0 @@ -// -// DoseStore.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/27/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import CoreData -import HealthKit -import os.log - -public protocol DoseStoreDelegate: AnyObject { - - /** - Informs the delegate that the dose store has updated pump event data. - - - Parameter doseStore: The dose store that has updated pump event data. - */ - func doseStoreHasUpdatedPumpEventData(_ doseStore: DoseStore) - -} - -public enum DoseStoreResult { - case success(T) - case failure(DoseStore.DoseStoreError) -} - -/** - Manages storage, retrieval, and calculation of insulin pump delivery data. - - Pump data are stored in the following tiers: - - * In-memory cache, used for IOB and insulin effect calculation - ``` - 0 [1.5 * insulinActionDuration] - |––––––––––––––––––––—————————––| - ``` - * On-disk Core Data store, unprotected - ``` - 0 [24 hours] - |––––––––––––––––––––––—————————| - ``` - * HealthKit data, managed by the current application and persisted indefinitely - ``` - 0 - |––––––––––––––––––––––——————————————> - ``` - - Private members should be assumed to not be thread-safe, and access should be contained to within blocks submitted to `persistenceStore.managedObjectContext`, which executes them on a private, serial queue. - */ -public final class DoseStore { - - /// Notification posted when data was modifed. - public static let valuesDidChange = NSNotification.Name(rawValue: "com.loopkit.DoseStore.valuesDidChange") - - public enum DoseStoreError: Error { - case configurationError - case initializationError(description: String, recoverySuggestion: String?) - case persistenceError(description: String, recoverySuggestion: String?) - case fetchError(description: String, recoverySuggestion: String?) - - init?(error: PersistenceController.PersistenceControllerError?) { - if let error = error { - self = .persistenceError(description: String(describing: error), recoverySuggestion: error.recoverySuggestion) - } else { - return nil - } - } - } - - public weak var delegate: DoseStoreDelegate? - - private let log = OSLog(category: "DoseStore") - - public var longestEffectDuration: TimeInterval - - public var insulinModelProvider: InsulinModelProvider { - get { - return lockedInsulinModelProvider.value - } - set { - lockedInsulinModelProvider.value = newValue - - persistenceController.managedObjectContext.perform { - self.pumpEventQueryAfterDate = max(self.pumpEventQueryAfterDate, self.cacheStartDate) - - self.validateReservoirContinuity() - } - } - } - private let lockedInsulinModelProvider: Locked - - /// A history of recently applied schedule overrides. - private let overrideHistory: TemporaryScheduleOverrideHistory? - - public var basalProfile: BasalRateSchedule? { - get { - return lockedBasalProfile.value - } - set { - lockedBasalProfile.value = newValue - - persistenceController.managedObjectContext.perform { - self.clearReservoirNormalizedDoseCache() - } - } - } - private let lockedBasalProfile: Locked - - /// The basal profile, applying recent overrides relative to the current moment in time. - public var basalProfileApplyingOverrideHistory: BasalRateSchedule? { - if let basalProfile = basalProfile { - return overrideHistory?.resolvingRecentBasalSchedule(basalProfile) ?? basalProfile - } else { - return nil - } - } - - public var insulinSensitivitySchedule: InsulinSensitivitySchedule? { - get { - return lockedInsulinSensitivitySchedule.value - } - set { - lockedInsulinSensitivitySchedule.value = newValue - } - } - private let lockedInsulinSensitivitySchedule: Locked - - /// The insulin sensitivity schedule, applying recent overrides relative to the current moment in time. - public var insulinSensitivityScheduleApplyingOverrideHistory: InsulinSensitivitySchedule? { - if let insulinSensitivitySchedule = insulinSensitivitySchedule { - return overrideHistory?.resolvingRecentInsulinSensitivitySchedule(insulinSensitivitySchedule) - } else { - return nil - } - } - - /// The computed EGP schedule based on the basal profile and insulin sensitivity schedule. - public var egpSchedule: EGPSchedule? { - guard let basalProfile = basalProfile, let insulinSensitivitySchedule = insulinSensitivitySchedule else { - return nil - } - return .egpSchedule(basalSchedule: basalProfile, insulinSensitivitySchedule: insulinSensitivitySchedule) - } - - public let insulinDeliveryStore: InsulinDeliveryStore - - /// The HealthKit sample type managed by this store - public var sampleType: HKSampleType { - return insulinDeliveryStore.sampleType - } - - /// True if the store requires authorization - public var authorizationRequired: Bool { - return insulinDeliveryStore.authorizationRequired - } - - /// True if the user has explicitly denied access to any required share types - public var sharingDenied: Bool { - return insulinDeliveryStore.sharingDenied - } - - /// The representation of the insulin pump for Health storage - public var device: HKDevice? { - get { - return lockedDevice.value - } - set { - lockedDevice.value = newValue - } - } - private let lockedDevice = Locked(nil) - - /// Whether the pump generates events indicating the start of a scheduled basal rate after it had been interrupted. - public var pumpRecordsBasalProfileStartEvents: Bool = false - - /// The sync version used for new samples written to HealthKit - /// Choose a lower or higher sync version if the same sample might be written twice (e.g. from an extension and from an app) for deterministic conflict resolution - public let syncVersion: Int - - /// Window for retrieving historical doses that might be used to reconcile current events - private let pumpEventReconciliationWindow = TimeInterval(hours: 24) - - - // MARK: - - - /// Initializes and configures a new store - /// - /// - Parameters: - /// - healthStore: The HealthKit store for reading & writing insulin delivery - /// - observeHealthKitSamplesFromOtherApps: Whether or not this Store should read HealthKit data written by other apps - /// - storeSamplesToHealthKit: Whether or not this Store should store samples in HealthKit - /// - cacheStore: The cache store for reading & writing short-term intermediate data - /// - observationEnabled: Whether the store should observe changes from HealthKit - /// - cacheLength: Maximum age of data to keep in the store. - /// - insulinModelProvider: A factory for producing insulin models based on insulin type - /// - longestEffectDuration: This determines the oldest age of doses to be retrieved for calculating glucose effects - /// - basalProfile: The daily schedule of basal insulin rates - /// - insulinSensitivitySchedule: The daily schedule of insulin sensitivity (ISF) - /// - overrideHistory: A history of overrides to be used when calculating glucose effects - /// - syncVersion: A version number for determining resolution in de-duplication - /// - lastPumpEventsReconciliation: The date the PumpManger last reconciled with the pump - /// - provenanceIdentifier: An id to store with new doses, indicating the provenance of the dose, usually the app's bundle identifier. - /// - readyCallback: A closure that will be called after initialization. - /// - test_currentDate: Used for testing to mock current time - public init( - healthStore: HKHealthStore, - observeHealthKitSamplesFromOtherApps: Bool = true, - storeSamplesToHealthKit: Bool = true, - cacheStore: PersistenceController, - observationEnabled: Bool = true, - cacheLength: TimeInterval = 24 /* hours */ * 60 /* minutes */ * 60 /* seconds */, - insulinModelProvider: InsulinModelProvider, - longestEffectDuration: TimeInterval, - basalProfile: BasalRateSchedule?, - insulinSensitivitySchedule: InsulinSensitivitySchedule?, - overrideHistory: TemporaryScheduleOverrideHistory? = nil, - syncVersion: Int = 1, - lastPumpEventsReconciliation: Date? = nil, - provenanceIdentifier: String, - onReady: ((DoseStoreError?) -> Void)? = nil, - test_currentDate: Date? = nil - ) { - self.insulinDeliveryStore = InsulinDeliveryStore( - healthStore: healthStore, - observeHealthKitSamplesFromOtherApps: observeHealthKitSamplesFromOtherApps, - storeSamplesToHealthKit: storeSamplesToHealthKit, - cacheStore: cacheStore, - observationEnabled: observationEnabled, - cacheLength: cacheLength, - provenanceIdentifier: provenanceIdentifier, - test_currentDate: test_currentDate - ) - self.lockedInsulinSensitivitySchedule = Locked(insulinSensitivitySchedule) - self.lockedInsulinModelProvider = Locked(insulinModelProvider) - self.longestEffectDuration = longestEffectDuration - self.lockedBasalProfile = Locked(basalProfile) - self.overrideHistory = overrideHistory - self.persistenceController = cacheStore - self.cacheLength = cacheLength - self.syncVersion = syncVersion - self.lockedLastPumpEventsReconciliation = Locked(lastPumpEventsReconciliation) - - self.pumpEventQueryAfterDate = cacheStartDate - - persistenceController.onReady { (error) -> Void in - guard error == nil else { - onReady?(.init(error: error)) - return - } - - self.persistenceController.managedObjectContext.perform { - // Find the newest PumpEvent date we have - let request: NSFetchRequest = PumpEvent.fetchRequest() - request.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false)] - request.predicate = NSPredicate(format: "mutable != true") - request.fetchLimit = 1 - - if let events = try? self.persistenceController.managedObjectContext.fetch(request), let lastEvent = events.first { - self.pumpEventQueryAfterDate = lastEvent.date - } - - // Validate the state of the stored reservoir data. - self.validateReservoirContinuity() - - onReady?(nil) - } - } - } - - /// Clears all pump data from the on-disk store. - /// - /// Calling this method may result in data loss, as there is no check to ensure data has been synced first. - /// - /// - Parameter completion: A closure to call after the reset has completed - public func resetPumpData(completion: ((_ error: DoseStoreError?) -> Void)? = nil) { - log.info("Resetting all cached pump data") - deleteAllPumpEvents { (error) in - self.deleteAllReservoirValues { (error) in - completion?(error) - } - } - } - - private let persistenceController: PersistenceController - - private let cacheLength: TimeInterval - - private var purgeableValuesPredicate: NSPredicate { - return NSPredicate(format: "date < %@", cacheStartDate as NSDate) - } - - /// The maximum length of time to keep data around. - /// Dose data is unprotected on disk, and should only remain persisted long enough to support dosing algorithms and until its persisted by the delegate. - public var cacheStartDate: Date { - return currentDate(timeIntervalSinceNow: -cacheLength) - } - - private var recentStartDate: Date { - return Calendar.current.date(byAdding: .day, value: -1, to: currentDate())! - } - - internal func currentDate(timeIntervalSinceNow: TimeInterval = 0) -> Date { - return insulinDeliveryStore.currentDate(timeIntervalSinceNow: timeIntervalSinceNow) - } - - // MARK: - Reservoir Data - - /// The last-created reservoir object. - private var lastStoredReservoirValue: StoredReservoirValue? { - get { - return lockedLastStoredReservoirValue.value - } - set { - lockedLastStoredReservoirValue.value = newValue - } - } - private let lockedLastStoredReservoirValue = Locked(nil) - - // The last-saved reservoir value - public var lastReservoirValue: ReservoirValue? { - return lastStoredReservoirValue - } - - /// An incremental cache of temp basal doses based on reservoir records, used to avoid repeated work. - /// - /// *Access should be isolated to a managed object context block* - private var recentReservoirNormalizedDoseEntriesCache: [DoseEntry]? - - /** - *This method should only be called from within a managed object context block.* - */ - private func clearReservoirNormalizedDoseCache() { - recentReservoirNormalizedDoseEntriesCache = nil - } - - /// Whether the current recent state of the stored reservoir data is considered - /// continuous and reliable for the derivation of insulin effects - /// - /// *Access should be isolated to a managed object context block* - private var areReservoirValuesValid = false - - - // MARK: - Pump Event Data - - /// The earliest event date that should included in subsequent queries for pump event data. - public private(set) var pumpEventQueryAfterDate: Date { - get { - return lockedPumpEventQueryAfterDate.value - } - set { - lockedPumpEventQueryAfterDate.value = newValue - } - } - private let lockedPumpEventQueryAfterDate = Locked(.distantPast) - - /// The last time the PumpManager reconciled events with the pump. - public private(set) var lastPumpEventsReconciliation: Date? { - get { - return lockedLastPumpEventsReconciliation.value - } - set { - lockedLastPumpEventsReconciliation.value = newValue - } - } - private let lockedLastPumpEventsReconciliation: Locked - - public var lastAddedPumpData: Date { - return [lastReservoirValue?.startDate, lastPumpEventsReconciliation].compactMap { $0 }.max() ?? .distantPast - } - - /// The date of the most recent pump prime event, if known. - /// - /// *Access should be isolated to a managed object context block* - private var lastRecordedPrimeEventDate: Date? { - get { - if _lastRecordedPrimeEventDate == nil { - if let pumpEvents = try? self.getPumpEventObjects( - matching: NSPredicate(format: "type = %@", PumpEventType.prime.rawValue), - chronological: false, - limit: 1 - ), - let firstEvent = pumpEvents.first - { - _lastRecordedPrimeEventDate = firstEvent.date - } else { - _lastRecordedPrimeEventDate = .distantPast - } - } - - return _lastRecordedPrimeEventDate - } - set { - _lastRecordedPrimeEventDate = newValue - } - } - private var _lastRecordedPrimeEventDate: Date? - -} - - -// MARK: - Reservoir Operations -extension DoseStore { - /// Validates the current reservoir data for reliability in glucose effect calculation at the specified date - /// - /// *This method should only be called from within a managed object context block.* - /// - /// - Parameter date: The date to base the continuity calculation on. Defaults to now. - /// - Returns: The array of reservoir data used in the calculation - @discardableResult - private func validateReservoirContinuity(at date: Date? = nil) -> [Reservoir] { - let date = date ?? currentDate() - - // Consider any entries longer than 30 minutes, or with a value of 0, to be unreliable - let maximumInterval = TimeInterval(minutes: 30) - - let continuityStartDate = date.addingTimeInterval(-longestEffectDuration) - - if let recentReservoirObjects = try? self.getReservoirObjects(since: continuityStartDate - maximumInterval), - let oldestRelevantReservoirObject = recentReservoirObjects.last - { - // Verify reservoir timestamps are continuous - let areReservoirValuesContinuous = recentReservoirObjects.reversed().isContinuous( - from: continuityStartDate, - to: date, - within: maximumInterval - ) - - // also make sure prime events don't exist withing the insulin action duration - let primeEventExistsWithinInsulinActionDuration = (lastRecordedPrimeEventDate ?? .distantPast) >= oldestRelevantReservoirObject.startDate - - self.areReservoirValuesValid = areReservoirValuesContinuous && !primeEventExistsWithinInsulinActionDuration - self.lastStoredReservoirValue = recentReservoirObjects.first?.storedReservoirValue - - return recentReservoirObjects - } - - self.areReservoirValuesValid = false - self.lastStoredReservoirValue = nil - return [] - } - - /** - Adds and persists a new reservoir value - - - parameter unitVolume: The reservoir volume, in units - - parameter date: The date of the volume reading - - parameter completion: A closure called after the value was saved. This closure takes three arguments: - - value: The new reservoir value, if it was saved - - previousValue: The last new reservoir value - - areStoredValuesContinous: Whether the current recent state of the stored reservoir data is considered continuous and reliable for deriving insulin effects after addition of this new value. - - error: An error object explaining why the value could not be saved - */ - public func addReservoirValue(_ unitVolume: Double, at date: Date, completion: @escaping (_ value: ReservoirValue?, _ previousValue: ReservoirValue?, _ areStoredValuesContinuous: Bool, _ error: DoseStoreError?) -> Void) { - persistenceController.managedObjectContext.perform { - // Perform some sanity checking of the new value against the most recent value. - if let previousValue = self.lastReservoirValue { - let isOutOfOrder = previousValue.endDate > date - let isSameDate = previousValue.endDate == date - let isConflicting = isSameDate && previousValue.unitVolume != unitVolume - if isOutOfOrder || isConflicting { - self.log.error("Added inconsistent reservoir value of %{public}.3fU at %{public}@ after %{public}.3fU at %{public}@. Resetting.", unitVolume, String(describing: date), previousValue.unitVolume, String(describing: previousValue.endDate)) - - // If we're violating consistency of the previous value, reset. - do { - try self.purgeReservoirObjects() - self.clearReservoirNormalizedDoseCache() - self.validateReservoirContinuity() - } catch let error { - self.log.error("Error purging reservoir objects: %{public}@", String(describing: error)) - completion(nil, nil, false, DoseStoreError(error: error as? PersistenceController.PersistenceControllerError)) - return - } - // If no error on purge, continue with creation - } else if isSameDate && previousValue.unitVolume == unitVolume { - // Ignore duplicate adds - self.log.error("Added duplicate reservoir value at %{public}@", String(describing: date)) - completion(nil, previousValue, self.areReservoirValuesValid, nil) - return - } - } - - let reservoir = Reservoir(context: self.persistenceController.managedObjectContext) - - reservoir.volume = unitVolume - reservoir.date = date - - let previousValue = self.lastStoredReservoirValue - if let basalProfile = self.basalProfileApplyingOverrideHistory { - var newValues: [StoredReservoirValue] = [] - - if let previousValue = previousValue { - newValues.append(previousValue) - } - - newValues.append(reservoir.storedReservoirValue) - - let newDoseEntries = newValues.doseEntries - - if self.recentReservoirNormalizedDoseEntriesCache != nil { - self.recentReservoirNormalizedDoseEntriesCache = self.recentReservoirNormalizedDoseEntriesCache!.filterDateRange(self.recentStartDate, nil) - - self.recentReservoirNormalizedDoseEntriesCache! += newDoseEntries.annotated(with: basalProfile) - } - } - - // Remove reservoir objects older than our cache length - try? self.purgeReservoirObjects(matching: self.purgeableValuesPredicate) - // Trigger a re-evaluation of continuity and update self.lastStoredReservoirValue - self.validateReservoirContinuity() - - self.persistenceController.save { (error) -> Void in - var saveError: DoseStoreError? - - if let error = error { - saveError = DoseStoreError(error: error) - } - - completion( - reservoir.storedReservoirValue, - previousValue, - self.areReservoirValuesValid, - saveError - ) - - NotificationCenter.default.post(name: DoseStore.valuesDidChange, object: self) - } - } - } - - /// Retrieves reservoir values since the given date. - /// - /// - Parameters: - /// - startDate: The earliest reservoir record date to include - /// - limit: An optional limit to the number of values returned - /// - completion: A closure called after retrieval - /// - result: An array of reservoir values in reverse-chronological order - public func getReservoirValues(since startDate: Date, limit: Int? = nil, completion: @escaping (_ result: DoseStoreResult<[ReservoirValue]>) -> Void) { - persistenceController.managedObjectContext.perform { - do { - let values = try self.getReservoirObjects(since: startDate, limit: limit).map { $0.storedReservoirValue } - - completion(.success(values)) - } catch let error as DoseStoreError { - completion(.failure(error)) - } catch { - assertionFailure() - } - } - } - - /// *This method should only be called from within a managed object context block.* - /// - /// - Parameters: - /// - startDate: The earliest reservoir record date to include - /// - limit: An optional limit to the number of objects returned - /// - Returns: An array of reservoir managed objects, in reverse-chronological order - /// - Throws: An error describing the failure to fetch objects - private func getReservoirObjects(since startDate: Date, limit: Int? = nil) throws -> [Reservoir] { - let request: NSFetchRequest = Reservoir.fetchRequest() - request.predicate = NSPredicate(format: "date >= %@", startDate as NSDate) - request.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false)] - - if let limit = limit { - request.fetchLimit = limit - } - - do { - return try persistenceController.managedObjectContext.fetch(request) - } catch let fetchError as NSError { - throw DoseStoreError.fetchError(description: fetchError.localizedDescription, recoverySuggestion: fetchError.localizedRecoverySuggestion) - } - } - - /// Retrieves normalized dose values derived from reservoir readings - /// - /// *This method should only be called from within a managed object context block.* - /// - /// - Parameters: - /// - start: The earliest date of entries to include - /// - end: The latest date of entries to include, defaulting to the distant future. - /// - Returns: An array of normalized entries - /// - Throws: A DoseStoreError describing a failure - private func getNormalizedReservoirDoseEntries(start: Date, end: Date? = nil) throws -> [DoseEntry] { - if let normalizedDoses = self.recentReservoirNormalizedDoseEntriesCache, let firstDoseDate = normalizedDoses.first?.startDate, firstDoseDate <= start { - return normalizedDoses.filterDateRange(start, end) - } else { - guard let basalProfile = self.basalProfileApplyingOverrideHistory else { - throw DoseStoreError.configurationError - } - - // Attempt to get the reading before "start", so we can build those doses that have an end date after "start", but a start date before "start" - // Any extra doses will be filtered out below, via filterDateRange - let doses = try self.getReservoirObjects(since: start.addingTimeInterval(-.minutes(10))).reversed().doseEntries - - let normalizedDoses = doses.annotated(with: basalProfile) - self.recentReservoirNormalizedDoseEntriesCache = normalizedDoses - return normalizedDoses.filterDateRange(start, end) - } - } - - /** - Deletes a persisted reservoir value - - - parameter value: The value to delete - - parameter completion: A closure called after the value was deleted. This closure takes two arguments: - - parameter deletedValues: An array of removed values - - parameter error: An error object explaining why the value could not be deleted - */ - public func deleteReservoirValue(_ value: ReservoirValue, completion: @escaping (_ deletedValues: [ReservoirValue], _ error: DoseStoreError?) -> Void) { - persistenceController.managedObjectContext.perform { - var deletedObjects = [ReservoirValue]() - if let storedValue = value as? StoredReservoirValue, - let objectID = self.persistenceController.managedObjectContext.persistentStoreCoordinator?.managedObjectID(forURIRepresentation: storedValue.objectIDURL), - let object = try? self.persistenceController.managedObjectContext.existingObject(with: objectID) - { - self.persistenceController.managedObjectContext.delete(object) - deletedObjects.append(storedValue) - self.validateReservoirContinuity() - } - - self.persistenceController.save { (error) in - self.clearReservoirNormalizedDoseCache() - completion(deletedObjects, DoseStoreError(error: error)) - NotificationCenter.default.post(name: DoseStore.valuesDidChange, object: self) - } - } - } - - /// Deletes all persisted reservoir values - /// - /// - Parameter completion: A closure called after all the values are deleted. This closure takes a single argument: - /// - Parameter error: An error explaining why the deletion failed - public func deleteAllReservoirValues(_ completion: @escaping (_ error: DoseStoreError?) -> Void) { - persistenceController.managedObjectContext.perform { - do { - self.log.info("Deleting all reservoir values") - try self.purgeReservoirObjects() - - self.persistenceController.save { (error) in - self.clearReservoirNormalizedDoseCache() - self.validateReservoirContinuity() - - completion(DoseStoreError(error: error)) - NotificationCenter.default.post(name: DoseStore.valuesDidChange, object: self) - } - } catch let error as PersistenceController.PersistenceControllerError { - completion(DoseStoreError(error: error)) - } catch { - assertionFailure() - } - } - } - - /** - Removes reservoir objects older than the recency predicate, and re-evaluates the continuity of the remaining objects - - *This method should only be called from within a managed object context block.* - - - throws: PersistenceController.PersistenceControllerError.coreDataError if the delete request failed - */ - private func purgeReservoirObjects(matching predicate: NSPredicate? = nil) throws { - let fetchRequest = NSFetchRequest(entityName: Reservoir.entity().name!) - fetchRequest.predicate = predicate - - let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) - deleteRequest.resultType = .resultTypeObjectIDs - - do { - if let result = try persistenceController.managedObjectContext.execute(deleteRequest) as? NSBatchDeleteResult, - let objectIDs = result.result as? [NSManagedObjectID], - objectIDs.count > 0 - { - let changes = [NSDeletedObjectsKey: objectIDs] - NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [persistenceController.managedObjectContext]) - self.validateReservoirContinuity() - } - } catch let error as NSError { - throw PersistenceController.PersistenceControllerError.coreDataError(error) - } - } -} - - -// MARK: - Pump Event Operations -extension DoseStore { - /** - Adds and persists new pump events. - - Events are deduplicated by a unique constraint on `NewPumpEvent.getter:raw`. - - - parameter events: An array of new pump events. Pump events should have end times reflective of when delivery is actually expected to be finished, as doses that end prior to a reservoir reading are ignored when reservoir data is being used. - - parameter lastReconciliation: The date that pump events were most recently reconciled against recorded pump history. Pump events are assumed to be reflective of delivery up until this point in time. If reservoir values are recorded after this time, they may be used to supplement event based delivery. - - parameter completion: A closure called after the events are saved. The closure takes a single argument: - - parameter error: An error object explaining why the events could not be saved. - */ - public func addPumpEvents(_ events: [NewPumpEvent], lastReconciliation: Date?, completion: @escaping (_ error: DoseStoreError?) -> Void) { - lastPumpEventsReconciliation = lastReconciliation - - guard events.count > 0 else { - completion(nil) - return - } - - for event in events { - if let dose = event.dose { - self.log.debug("Add %@, isMutable=%@", String(describing: dose), String(describing: event.dose?.isMutable)) - } - } - - persistenceController.managedObjectContext.perform { - var lastFinalDate: Date? - var firstMutableDate: Date? - var primeValueAdded = false - - // Remove any stored mutable pumpEvents; any that are still valid should be included in events - do { - try self.purgePumpEventObjects(matching: NSPredicate(format: "mutable == YES")) - } catch let error { - completion(DoseStoreError(error: .coreDataError(error as NSError))) - return - } - - // Remove old doses - self.purgePumpEventObjects(before: self.cacheStartDate, completion: { error in - if let error = error { - self.log.error("Error purging PumpEvent objects: %{public}@", String(describing: error)) - } - }) - - // There is no guarantee of event ordering, so we must search the entire array to find key date boundaries. - - for event in events { - if case .prime? = event.type { - primeValueAdded = true - } - - let isMutable = event.dose?.isMutable == true - let wasProgrammedByPumpUI = event.dose?.wasProgrammedByPumpUI ?? false - if isMutable { - firstMutableDate = min(event.date, firstMutableDate ?? event.date) - } else { - lastFinalDate = max(event.date, lastFinalDate ?? event.date) - } - - let object = PumpEvent(context: self.persistenceController.managedObjectContext) - - object.date = event.date - object.raw = event.raw - object.title = event.title - object.type = event.type - object.mutable = isMutable - object.dose = event.dose - object.alarmType = event.alarmType - object.wasProgrammedByPumpUI = wasProgrammedByPumpUI - } - - // Only change pumpEventQueryAfterDate if we received new finalized records. - if let finalDate = lastFinalDate { - if let mutableDate = firstMutableDate, mutableDate < finalDate { - self.pumpEventQueryAfterDate = mutableDate - } else { - self.pumpEventQueryAfterDate = finalDate - } - } - - if primeValueAdded { - self.lastRecordedPrimeEventDate = nil - self.validateReservoirContinuity() - } - - self.persistenceController.save { (error) -> Void in - self.syncPumpEventsToInsulinDeliveryStore(resolveMutable: true) { _ in - completion(DoseStoreError(error: error)) - self.delegate?.doseStoreHasUpdatedPumpEventData(self) - NotificationCenter.default.post(name: DoseStore.valuesDidChange, object: self) - } - } - } - } - - public func deletePumpEvent(_ event: PersistedPumpEvent, completion: @escaping (_ error: DoseStoreError?) -> Void) { - persistenceController.managedObjectContext.perform { - - if let objectID = self.persistenceController.managedObjectContext.persistentStoreCoordinator?.managedObjectID(forURIRepresentation: event.objectIDURL), - let object = try? self.persistenceController.managedObjectContext.existingObject(with: objectID) - { - self.persistenceController.managedObjectContext.delete(object) - } - - // Reset the latest query date to the newest PumpEvent - let request: NSFetchRequest = PumpEvent.fetchRequest() - request.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false)] - request.predicate = NSPredicate(format: "mutable != true") - request.fetchLimit = 1 - - if let events = try? self.persistenceController.managedObjectContext.fetch(request), - let lastEvent = events.first - { - self.pumpEventQueryAfterDate = lastEvent.date - } else { - self.pumpEventQueryAfterDate = self.cacheStartDate - } - - self.persistenceController.save { (error) in - completion(DoseStoreError(error: error)) - NotificationCenter.default.post(name: DoseStore.valuesDidChange, object: self) - - self.lastRecordedPrimeEventDate = nil - self.validateReservoirContinuity() - } - } - } - - /// Deletes all persisted pump events - /// - /// - Parameter completion: A closure called after all the events are deleted. This closure takes a single argument: - /// - Parameter error: An error explaining why the deletion failed - public func deleteAllPumpEvents(_ completion: @escaping (_ error: DoseStoreError?) -> Void) { - syncPumpEventsToInsulinDeliveryStore { (error) in - if let error = error { - self.log.error("Error performing final sync to insulin delivery store before deleteAllPumpEvents: %{public}@", String(describing: error)) - } - - self.persistenceController.managedObjectContext.perform { - do { - self.log.info("Deleting all pump events") - try self.purgePumpEventObjects() - - self.persistenceController.save { (error) in - self.pumpEventQueryAfterDate = self.cacheStartDate - self.lastPumpEventsReconciliation = nil - self.lastRecordedPrimeEventDate = nil - - completion(DoseStoreError(error: error)) - NotificationCenter.default.post(name: DoseStore.valuesDidChange, object: self) - } - } catch let error as PersistenceController.PersistenceControllerError { - completion(DoseStoreError(error: error)) - } catch { - assertionFailure() - } - } - } - } - - /** - Adds and persists doses. Doses *cannot* be mutable. - - parameter doses: An array of dose entries to add. - - parameter completion: A closure called after the doses are saved. The closure takes a single argument: - - parameter error: An error object explaining why the doses could not be saved. - */ - public func addDoses(_ doses: [DoseEntry], from device: HKDevice?, completion: @escaping (_ error: Error?) -> Void) { - assert(!doses.contains(where: { $0.isMutable })) - guard doses.count > 0 else { - completion(nil) - return - } - - self.persistenceController.save { (error) -> Void in - if let error = error { - self.log.error("Error saving: %{public}@", String(describing: error)) - } - self.insulinDeliveryStore.addDoseEntries(doses, from: device, syncVersion: self.syncVersion) { (result) in - switch result { - case .success: - completion(nil) - self.syncPumpEventsToInsulinDeliveryStore { error in - completion(error) - NotificationCenter.default.post(name: DoseStore.valuesDidChange, object: self) - } - case .failure(let error): - self.log.error("Error adding dose: %{public}@", String(describing: error)) - completion(error) - } - } - } - } - - /// Deletes one particular manually entered dose from the store - /// - /// - Parameter dose: Dose to delete. - /// - Parameter completion: A closure called after the event deleted. This closure takes a single argument: - /// - Parameter success: True if dose was successfully deleted - public func deleteDose(_ dose: DoseEntry, completion: @escaping (_ error: DoseStoreError?) -> Void) { - guard let syncIdentifier = dose.syncIdentifier else { - self.log.error("Unable to delete PersistedManualEntryDose: no syncIdentifier") - completion(DoseStoreError.fetchError(description: "Unable to delete dose: syncIdentifier is missing", recoverySuggestion: "File an issue report in Github")) - return - } - insulinDeliveryStore.deleteDose(bySyncIdentifier: syncIdentifier) { (error) in - if let error = error { - completion(DoseStoreError.persistenceError(description: error, recoverySuggestion: nil)) - } else { - completion(nil) - NotificationCenter.default.post(name: DoseStore.valuesDidChange, object: self) - } - } - } - - /// Deletes all manually entered doses - /// - /// - Parameter completion: A closure called after all the events are deleted. This closure takes a single argument: - /// - Parameter error: An error explaining why the deletion failed - public func deleteAllManuallyEnteredDoses(since startDate: Date, _ completion: @escaping (_ error: DoseStoreError?) -> Void) { - self.log.info("Deleting all manually entered doses since %{public}@", String(describing: startDate)) - insulinDeliveryStore.deleteAllManuallyEnteredDoses(since: startDate) { error in - completion(error) - NotificationCenter.default.post(name: DoseStore.valuesDidChange, object: self) - } - } - - /// Attempts to store doses from pump events to insulin delivery store - private func syncPumpEventsToInsulinDeliveryStore(after start: Date? = nil, resolveMutable: Bool = false, completion: @escaping (_ error: Error?) -> Void) { - insulinDeliveryStore.getLastImmutableBasalEndDate { (result) in - switch result { - case .success(let date): - // Limit the query behavior to 24 hours - let date = max(date, self.recentStartDate) - self.savePumpEventsToInsulinDeliveryStore(after: start ?? date, resolveMutable: resolveMutable, completion: completion) - case .failure(let error): - completion(error) - } - } - } - - /// Processes and saves dose events on or after the given date to insulin delivery store - /// - /// - Parameters: - /// - start: The date on and after which to include doses - /// - resolveMutable: Resolve mutable dose entries during saving - /// - completion: A closure called on completion - /// - error: An error if one ocurred during processing or saving - private func savePumpEventsToInsulinDeliveryStore(after start: Date, resolveMutable: Bool, completion: @escaping (_ error: Error?) -> Void) { - getPumpEventDoseEntriesForSavingToInsulinDeliveryStore(startingAt: start) { (result) in - switch result { - case .success(let doses): - guard doses.count > 0 else { - completion(nil) - return - } - - for dose in doses { - self.log.debug("Adding dose to insulin delivery store: %@", String(describing: dose)) - } - - self.insulinDeliveryStore.addDoseEntries(doses, from: self.device, syncVersion: self.syncVersion, resolveMutable: resolveMutable) { (result) in - switch result { - case .success: - completion(nil) - case .failure(let error): - self.log.error("Error adding doses: %{public}@", String(describing: error)) - completion(error) - } - } - case .failure(let error): - completion(error) - } - } - } - - /// Fetches a timeline of doses, filling in gaps between delivery changes with the scheduled basal delivery - /// if the pump doesn't already handle this - /// - /// - Parameters: - /// - start: The date on and after which to include doses - /// - completion: A closure called on completion - /// - result: The doses along with schedule basal - private func getPumpEventDoseEntriesForSavingToInsulinDeliveryStore(startingAt: Date, completion: @escaping (_ result: DoseStoreResult<[DoseEntry]>) -> Void) { - // Can't store to insulin delivery store if we don't know end of reconciled range, or if we already have doses after the end - guard let endingAt = lastPumpEventsReconciliation, endingAt > startingAt else { - completion(.success([])) - return - } - - self.persistenceController.managedObjectContext.perform { - let doses: [DoseEntry] - do { - doses = try self.getNormalizedPumpEventDoseEntriesForSavingToInsulinDeliveryStore(basalStart: startingAt, end: self.currentDate()) - } catch let error as DoseStoreError { - self.log.error("Error while fetching doses to add to insulin delivery store: %{public}@", String(describing: error)) - completion(.failure(error)) - return - } catch { - assertionFailure() - return - } - - guard !doses.isEmpty else - { - completion(.success([])) - return - } - - guard let basalSchedule = self.basalProfileApplyingOverrideHistory else { - self.log.error("Can't save %d doses to insulin delivery store because no basal profile is configured", doses.count) - completion(.failure(DoseStoreError.configurationError)) - return - } - - self.log.debug("Overlaying basal schedule for %d doses starting at %@", doses.count, String(describing: startingAt)) - let reconciledDoses = doses.overlayBasalSchedule(basalSchedule, startingAt: startingAt, insertingBasalEntries: !self.pumpRecordsBasalProfileStartEvents) - completion(.success(reconciledDoses)) - } - } - - /// Fetches manually entered doses. - /// - /// - Parameter startDate: The earliest dose startDate to include - /// - Returns: An array of manually entered dose managed objects, in reverse-chronological order, or an error describing the failure to fetch objects - public func getManuallyEnteredDoses(since startDate: Date, completion: @escaping (_ result: DoseStoreResult<[DoseEntry]>) -> Void) { - insulinDeliveryStore.getManuallyEnteredDoses(since: startDate, chronological: false, completion: completion) - } - - /// Retrieves pump event values since the given date. - /// - /// - Parameters: - /// - startDate: The earliest pump event date to include - /// - completion: A closure called after retrieval - /// - result: An array of pump event values in reverse-chronological order - public func getPumpEventValues(since startDate: Date, completion: @escaping (_ result: DoseStoreResult<[PersistedPumpEvent]>) -> Void) { - persistenceController.managedObjectContext.perform { - do { - let events = try self.getPumpEventObjects(since: startDate).map { $0.persistedPumpEvent } - - completion(.success(events)) - } catch let error as DoseStoreError { - completion(.failure(error)) - } catch { - assertionFailure() - } - } - } - - /// *This method should only be called from within a managed object context block.* - /// - /// - Parameter startDate: The earliest pump event date to include - /// - Returns: An array of pump event managed objects, in reverse-chronological order - /// - Throws: An error describing the failure to fetch objects - private func getPumpEventObjects(since startDate: Date) throws -> [PumpEvent] { - return try getPumpEventObjects( - matching: NSPredicate(format: "date >= %@", startDate as NSDate), - chronological: false - ) - } - - /// *This method should only be called from within a managed object context block.* - /// - /// Objects are ordered by date using the DoseType sort ordering as a tiebreaker for stability - /// - /// - Parameters: - /// - predicate: The predicate to apply to the objects - /// - chronological: Whether to return the objects in chronological or reverse-chronological order - /// - Returns: An array of pump events in the specified order by date - /// - Throws: An error describing the failure to fetch objects - private func getPumpEventObjects(matching predicate: NSPredicate, chronological: Bool, limit: Int? = nil) throws -> [PumpEvent] { - let request: NSFetchRequest = PumpEvent.fetchRequest() - request.predicate = predicate - request.sortDescriptors = [NSSortDescriptor(key: "date", ascending: chronological)] - - if let limit = limit { - request.fetchLimit = limit - } - - do { - return try persistenceController.managedObjectContext.fetch(request).sorted(by: { (lhs, rhs) -> Bool in - let (first, second) = chronological ? (lhs, rhs) : (rhs, lhs) - - if first.startDate == second.startDate, - let firstType = first.type, let secondType = second.type - { - return firstType.sortOrder < secondType.sortOrder - } else { - return first.startDate < second.startDate - } - }) - } catch let fetchError as NSError { - throw DoseStoreError.fetchError(description: fetchError.localizedDescription, recoverySuggestion: fetchError.localizedRecoverySuggestion) - } - } - - /// *This method should only be called from within a managed object context block.* - /// - /// - Parameters: - /// - start: The earliest dose end date to include - /// - end: The latest dose start date to include - /// - Returns: An array of doses from pump events - /// - Throws: An error describing the failure to fetch objects - private func getNormalizedPumpEventDoseEntries(start: Date, end: Date? = nil) throws -> [DoseEntry] { - guard let basalProfile = self.basalProfileApplyingOverrideHistory else { - throw DoseStoreError.configurationError - } - - let queryStart = start.addingTimeInterval(-pumpEventReconciliationWindow) - - let doses = try getPumpEventObjects( - matching: NSPredicate(format: "date >= %@ && doseType != nil", queryStart as NSDate), - chronological: true - ).compactMap({ $0.dose }) - let normalizedDoses = doses.reconciled().annotated(with: basalProfile) - - return normalizedDoses.filterDateRange(start, end) - } - - /// *This method should only be called from within a managed object context block.* - /// - /// - Returns: An array of doses from pump events that were marked mutable - /// - Throws: An error describing the failure to fetch objects - private func getNormalizedMutablePumpEventDoseEntries(start: Date) throws -> [DoseEntry] { - guard let basalProfile = self.basalProfileApplyingOverrideHistory else { - throw DoseStoreError.configurationError - } - - let doses = try getPumpEventObjects( - matching: NSPredicate(format: "mutable == true && doseType != nil"), - chronological: true - ).compactMap({ $0.dose }) - let normalizedDoses = doses.filterDateRange(start, nil).reconciled().annotated(with: basalProfile) - return normalizedDoses.map { $0.trimmed(from: start) } - } - - - /// *This method should only be called from within a managed object context block.* - /// - /// - Parameters: - /// - basalStart: The earliest basal dose start date to include - /// - end: The latest dose end date to include - /// - Returns: An array of doses from pump events - /// - Throws: An error describing the failure to fetch objects - private func getNormalizedPumpEventDoseEntriesForSavingToInsulinDeliveryStore(basalStart: Date, end: Date) throws -> [DoseEntry] { - guard let basalProfile = self.basalProfileApplyingOverrideHistory else { - throw DoseStoreError.configurationError - } - - self.log.info("Fetching Pumpevents between %{public}@ and %{public}@ for saving to InsulinDeliveryStore", String(describing: basalStart), String(describing: end)) - - // Make sure we look far back enough to have prior temp basal records to reconcile - // resumption of temp basal after suspend/resume. - let queryStart = basalStart.addingTimeInterval(-pumpEventReconciliationWindow) - - let afterBasalStart = NSPredicate(format: "date >= %@ && doseType != nil", queryStart as NSDate) - let allBoluses = NSPredicate(format: "date >= %@ && doseType == %@", recentStartDate as NSDate, DoseType.bolus.rawValue) - - let doses = try getPumpEventObjects( - matching: NSCompoundPredicate(orPredicateWithSubpredicates: [afterBasalStart, allBoluses]), - chronological: true - ).compactMap({ $0.dose }) - // Ignore any doses which have not yet ended by the specified date. - // Also, since we are retrieving dosing history older than basalStart for - // reconciliation purposes, we need to filter that out after reconciliation. - let normalizedDoses = doses.reconciled().filter({ $0.endDate <= end || $0.isMutable }).annotated(with: basalProfile).filter({ $0.startDate >= basalStart || $0.type == .bolus }) - - return normalizedDoses - } - - public func purgePumpEventObjects(before date: Date, completion: (Error?) -> Void) { - do { - let count = try purgePumpEventObjects(matching: NSPredicate(format: "date < %@", date as NSDate)) - self.log.info("Purged %d PumpEvents", count) - completion(nil) - } catch let error { - self.log.error("Unable to purge PumpEvents: %{public}@", String(describing: error)) - completion(error) - } - } - - /** - Removes uploaded pump event objects older than the recency predicate - - *This method should only be called from within a managed object context block.* - - - throws: A core data exception if the delete request failed - */ - @discardableResult - private func purgePumpEventObjects(matching predicate: NSPredicate? = nil) throws -> Int { - let fetchRequest = NSFetchRequest(entityName: PumpEvent.entity().name!) - fetchRequest.predicate = predicate - - let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) - deleteRequest.resultType = .resultTypeObjectIDs - - if let result = try persistenceController.managedObjectContext.execute(deleteRequest) as? NSBatchDeleteResult, - let objectIDs = result.result as? [NSManagedObjectID], - objectIDs.count > 0 - { - let changes = [NSDeletedObjectsKey: objectIDs] - NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [persistenceController.managedObjectContext]) - persistenceController.managedObjectContext.refreshAllObjects() - return objectIDs.count - } - - return 0 - } -} - - -extension DoseStore { - /// Retrieves dose entries normalized to the current basal schedule, for visualization purposes. - /// - /// Doses are derived from pump events if they've been updated within the last 15 minutes or reservoir data is incomplete. - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - Parameters: - /// - start: The earliest endDate of entries to retrieve - /// - end: The latest startDate of entries to retrieve, if provided - /// - completion: A closure called once the entries have been retrieved - /// - result: An array of dose entries, in chronological order by startDate - public func getNormalizedDoseEntries(start: Date, end: Date? = nil, completion: @escaping (_ result: DoseStoreResult<[DoseEntry]>) -> Void) { - insulinDeliveryStore.getDoseEntries(start: start, end: end, includeMutable: true) { (result) in - switch result { - case .failure(let error): - completion(.failure(.persistenceError(description: error.localizedDescription, recoverySuggestion: nil))) - case .success(let insulinDeliveryDoses): - let filteredStart = max(self.lastPumpEventsReconciliation ?? start, start) - - self.persistenceController.managedObjectContext.perform { - do { - let doses: [DoseEntry] - - // Reservoir data is used only if it's continuous and the pumpmanager hasn't reconciled since the last reservoir reading - if self.areReservoirValuesValid, let reservoirEndDate = self.lastStoredReservoirValue?.startDate, reservoirEndDate > self.lastPumpEventsReconciliation ?? .distantPast { - let reservoirDoses = try self.getNormalizedReservoirDoseEntries(start: filteredStart, end: end) - let endOfReservoirData = self.lastStoredReservoirValue?.endDate ?? .distantPast - let startOfReservoirData = reservoirDoses.first?.startDate ?? filteredStart - let mutableDoses = try self.getNormalizedMutablePumpEventDoseEntries(start: endOfReservoirData) - doses = insulinDeliveryDoses.map({ $0.trimmed(to: startOfReservoirData) }) + reservoirDoses + mutableDoses.map({ $0.trimmed(from: endOfReservoirData) }) - } else { - // Deduplicates doses by syncIdentifier - doses = insulinDeliveryDoses.appendedUnion(with: try self.getNormalizedPumpEventDoseEntries(start: filteredStart, end: end)) - } - completion(.success(doses)) - } catch let error as DoseStoreError { - completion(.failure(error)) - } catch { - assertionFailure() - } - } - } - } - } - - /// Retrieves the maximum insulin on-board value from the two timeline values nearest to the specified date - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - Parameters: - /// - date: The date of the value to retrieve - /// - completion: A closure called once the value has been retrieved - /// - result: The insulin on-board value - public func insulinOnBoard(at date: Date, completion: @escaping (_ result: DoseStoreResult) -> Void) { - getInsulinOnBoardValues(start: date.addingTimeInterval(.minutes(-5)), end: date.addingTimeInterval(.minutes(5))) { (result) -> Void in - switch result { - case .failure(let error): - completion(.failure(error)) - case .success(let values): - let closest = values.allElementsAdjacent(to: date) - - // Return the larger of the two bounding values, for the scenario when a bolus - // was scheduled between the two values; we want to return the later, larger value - guard let maxValue = closest.max(by: { return $0.value < $1.value }) else { - // If we have no iob values in the store, and did not encounter an error, return 0 - completion(.success(InsulinValue(startDate: date, value: 0))) - return - } - - completion(.success(maxValue)) - } - } - } - - /// Retrieves a timeline of unabsorbed insulin values. - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - Parameters: - /// - start: The earliest date of values to retrieve - /// - end: The latest date of values to retrieve, if provided - /// - basalDosingEnd: The date at which continuing doses should be assumed to be cancelled - /// - completion: A closure called once the values have been retrieved - /// - result: An array of insulin values, in chronological order - public func getInsulinOnBoardValues(start: Date, end: Date? = nil, basalDosingEnd: Date? = nil, completion: @escaping (_ result: DoseStoreResult<[InsulinValue]>) -> Void) { - - // To properly know IOB at startDate, we need to go back another DIA hours - let doseStart = start.addingTimeInterval(-longestEffectDuration) - getNormalizedDoseEntries(start: doseStart, end: end) { (result) in - switch result { - case .failure(let error): - completion(.failure(error)) - case .success(let doses): - let trimmedDoses = doses.map { $0.trimmed(to: basalDosingEnd) } - let insulinOnBoard = trimmedDoses.insulinOnBoard(insulinModelProvider: self.insulinModelProvider, longestEffectDuration: self.longestEffectDuration) - completion(.success(insulinOnBoard.filterDateRange(start, end))) - } - } - } - - /// Retrieves a timeline of effect on blood glucose from doses - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - Parameters: - /// - start: The earliest date of effects to retrieve - /// - end: The latest date of effects to retrieve, if provided - /// - basalDosingEnd: The date at which continuing doses should be assumed to be cancelled - /// - completion: A closure called once the effects have been retrieved - /// - result: An array of effects, in chronological order - public func getGlucoseEffects(start: Date, end: Date? = nil, basalDosingEnd: Date? = Date(), completion: @escaping (_ result: DoseStoreResult<[GlucoseEffect]>) -> Void) { - guard let insulinSensitivitySchedule = self.insulinSensitivityScheduleApplyingOverrideHistory else { - completion(.failure(.configurationError)) - return - } - - // To properly know glucose effects at startDate, we need to go back another DIA hours - let doseStart = start.addingTimeInterval(-longestEffectDuration) - getNormalizedDoseEntries(start: doseStart, end: end) { (result) in - switch result { - case .failure(let error): - completion(.failure(error)) - case .success(let doses): - let trimmedDoses = doses.map { (dose) -> DoseEntry in - guard dose.type != .bolus else { - return dose - } - return dose.trimmed(to: basalDosingEnd) - } - - let glucoseEffects = trimmedDoses.glucoseEffects(insulinModelProvider: self.insulinModelProvider, longestEffectDuration: self.longestEffectDuration, insulinSensitivity: insulinSensitivitySchedule) - completion(.success(glucoseEffects.filterDateRange(start, end))) - } - } - } - - /// Retrieves the estimated total number of units delivered since the specified date. - /// - /// - Parameters: - /// - startDate: The date after which delivery should be calculated - /// - completion: A closure called once the total has been retrieved with arguments: - /// - result: The total units delivered and the date of the first dose - public func getTotalUnitsDelivered(since startDate: Date, completion: @escaping (_ result: DoseStoreResult) -> Void) { - persistenceController.managedObjectContext.perform { - - self.getNormalizedDoseEntries(start: startDate) { (result) in - switch result { - case .success(let doses): - let trimmedDoses = doses.map { $0.trimmed(from: startDate, to: self.currentDate())} - let result = InsulinValue( - startDate: startDate, - value: trimmedDoses.totalDelivery - ) - - completion(.success(result)) - case .failure(let error): - completion(.failure(error)) - } - } - } - } -} - -extension DoseStore { - /// Generates a diagnostic report about the current state - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - parameter completion: The closure takes a single argument of the report string. - public func generateDiagnosticReport(_ completion: @escaping (_ report: String) -> Void) { - var report: [String] = [ - "## DoseStore", - "", - "* insulinModelProvider: \(String(reflecting: insulinModelProvider))", - "* basalProfile: \(basalProfile?.debugDescription ?? "")", - "* basalProfileApplyingOverrideHistory \(basalProfileApplyingOverrideHistory?.debugDescription ?? "nil")", - "* insulinSensitivitySchedule: \(insulinSensitivitySchedule?.debugDescription ?? "")", - "* insulinSensitivityScheduleApplyingOverrideHistory \(insulinSensitivityScheduleApplyingOverrideHistory?.debugDescription ?? "nil")", - "* overrideHistory: \(overrideHistory.map(String.init(describing:)) ?? "nil")", - "* egpSchedule: \(egpSchedule?.debugDescription ?? "nil")", - "* areReservoirValuesValid: \(areReservoirValuesValid)", - "* lastPumpEventsReconciliation: \(String(describing: lastPumpEventsReconciliation))", - "* lastStoredReservoirValue: \(String(describing: lastStoredReservoirValue))", - "* pumpEventQueryAfterDate: \(pumpEventQueryAfterDate)", - "* lastRecordedPrimeEventDate: \(String(describing: lastRecordedPrimeEventDate))", - "* pumpRecordsBasalProfileStartEvents: \(pumpRecordsBasalProfileStartEvents)", - "* device: \(String(describing: device))", - ] - - insulinOnBoard(at: currentDate()) { (result) in - report.append("") - - switch result { - case .failure(let error): - report.append("* insulinOnBoard: \(error)") - case .success(let value): - report.append("* insulinOnBoard: \(String(describing: value))") - } - - let historyStart = Date().addingTimeInterval(-.hours(24)) - - self.getReservoirValues(since: historyStart) { (result) in - report.append("") - report.append("### getReservoirValues") - - switch result { - case .failure(let error): - report.append("Error: \(error)") - case .success(let values): - report.append("") - report.append("* Reservoir(startDate, unitVolume)") - for value in values { - report.append("* \(value.startDate), \(value.unitVolume)") - } - } - - self.getPumpEventValues(since: historyStart) { (result) in - report.append("") - report.append("### getPumpEventValues") - - var firstPumpEventDate = self.cacheStartDate - - switch result { - case .failure(let error): - report.append("Error: \(error)") - case .success(let values): - report.append("") - - if let firstEvent = values.last { - firstPumpEventDate = firstEvent.date - } - - for value in values { - report.append("* \(value)") - } - } - - self.getNormalizedDoseEntries(start: firstPumpEventDate) { (result) in - report.append("") - report.append("### getNormalizedDoseEntries") - - switch result { - case .failure(let error): - report.append("Error: \(error)") - case .success(let entries): - report.append("") - for entry in entries { - report.append("* \(entry)") - } - } - - self.getPumpEventDoseEntriesForSavingToInsulinDeliveryStore(startingAt: firstPumpEventDate, completion: { (result) in - - report.append("") - report.append("### getPumpEventDoseEntriesForSavingToInsulinDeliveryStore") - - switch result { - case .failure(let error): - report.append("Error: \(error)") - case .success(let entries): - report.append("") - for entry in entries { - report.append("* \(entry)") - } - } - - self.getManuallyEnteredDoses(since: firstPumpEventDate) { (result) in - report.append("") - report.append("### getManuallyEnteredDoses") - - switch result { - case .failure(let error): - report.append("Error: \(error)") - case .success(let entries): - report.append("") - for entry in entries { - report.append("* \(entry)") - } - } - - self.insulinDeliveryStore.generateDiagnosticReport { (result) in - report.append("") - report.append(result) - - report.append("") - completion(report.joined(separator: "\n")) - } - } - }) - } - } - } - } - } -} - -extension DoseStore { - - public struct QueryAnchor: Equatable, RawRepresentable { - - public typealias RawValue = [String: Any] - - internal var modificationCounter: Int64 - - public init() { - self.modificationCounter = 0 - } - - public init?(rawValue: RawValue) { - guard let modificationCounter = rawValue["modificationCounter"] as? Int64 else { - return nil - } - self.modificationCounter = modificationCounter - } - - public var rawValue: RawValue { - var rawValue: RawValue = [:] - rawValue["modificationCounter"] = modificationCounter - return rawValue - } - } - - public enum PumpEventQueryResult { - case success(QueryAnchor, [PersistedPumpEvent]) - case failure(Error) - } - - public func executePumpEventQuery(fromQueryAnchor queryAnchor: QueryAnchor?, limit: Int, completion: @escaping (PumpEventQueryResult) -> Void) { - var queryAnchor = queryAnchor ?? QueryAnchor() - var queryResult = [PersistedPumpEvent]() - var queryError: Error? - - guard limit > 0 else { - completion(.success(queryAnchor, [])) - return - } - - persistenceController.managedObjectContext.performAndWait { - let storedRequest: NSFetchRequest = PumpEvent.fetchRequest() - - storedRequest.predicate = NSPredicate(format: "modificationCounter > %d", queryAnchor.modificationCounter) - storedRequest.sortDescriptors = [NSSortDescriptor(key: "modificationCounter", ascending: true)] - storedRequest.fetchLimit = limit - - do { - let stored = try self.persistenceController.managedObjectContext.fetch(storedRequest) - if let modificationCounter = stored.max(by: { $0.modificationCounter < $1.modificationCounter })?.modificationCounter { - queryAnchor.modificationCounter = modificationCounter - } - queryResult.append(contentsOf: stored.compactMap { $0.persistedPumpEvent }) - } catch let error { - queryError = error - } - } - - if let queryError = queryError { - completion(.failure(queryError)) - return - } - - completion(.success(queryAnchor, queryResult)) - } -} - -// MARK: - Critical Event Log Export - -extension DoseStore: CriticalEventLog { - private var exportProgressUnitCountPerObject: Int64 { 1 } - private var exportFetchLimit: Int { Int(criticalEventLogExportProgressUnitCountPerFetch / exportProgressUnitCountPerObject) } - - public var exportName: String { "Doses.json" } - - public func exportProgressTotalUnitCount(startDate: Date, endDate: Date? = nil) -> Result { - var result: Result? - - self.persistenceController.managedObjectContext.performAndWait { - do { - let request: NSFetchRequest = PumpEvent.fetchRequest() - request.predicate = self.exportDatePredicate(startDate: startDate, endDate: endDate) - - let objectCount = try self.persistenceController.managedObjectContext.count(for: request) - result = .success(Int64(objectCount) * exportProgressUnitCountPerObject) - } catch let error { - result = .failure(error) - } - } - - return result! - } - - public func export(startDate: Date, endDate: Date, to stream: OutputStream, progress: Progress) -> Error? { - let encoder = JSONStreamEncoder(stream: stream) - var modificationCounter: Int64 = 0 - var fetching = true - var error: Error? - - while fetching && error == nil { - self.persistenceController.managedObjectContext.performAndWait { - do { - guard !progress.isCancelled else { - throw CriticalEventLogError.cancelled - } - - let request: NSFetchRequest = PumpEvent.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format: "modificationCounter > %d", modificationCounter), - self.exportDatePredicate(startDate: startDate, endDate: endDate)]) - request.sortDescriptors = [NSSortDescriptor(key: "modificationCounter", ascending: true)] - request.fetchLimit = self.exportFetchLimit - - let objects = try self.persistenceController.managedObjectContext.fetch(request) - if objects.isEmpty { - fetching = false - return - } - - try encoder.encode(objects) - - modificationCounter = objects.last!.modificationCounter - - progress.completedUnitCount += Int64(objects.count) * exportProgressUnitCountPerObject - } catch let fetchError { - error = fetchError - } - } - } - - if let closeError = encoder.close(), error == nil { - error = closeError - } - - return error - } - - private func exportDatePredicate(startDate: Date, endDate: Date? = nil) -> NSPredicate { - var predicate = NSPredicate(format: "date >= %@", startDate as NSDate) - if let endDate = endDate { - predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSPredicate(format: "date < %@", endDate as NSDate)]) - } - return predicate - } -} - -// MARK: - Core Data (Bulk) - TEST ONLY - -extension DoseStore { - public func addPumpEvents(events: [PersistedPumpEvent]) -> Error? { - guard !events.isEmpty, !events.contains(where: { $0.dose?.isMutable == true }) else { - return nil - } - - var error: Error? - - let dispatchGroup = DispatchGroup() - dispatchGroup.enter() - self.persistenceController.managedObjectContext.perform { - for event in events { - let object = PumpEvent(context: self.persistenceController.managedObjectContext) - object.update(from: event) - } - self.persistenceController.save { saveError in - guard saveError == nil else { - error = saveError - dispatchGroup.leave() - return - } - self.syncPumpEventsToInsulinDeliveryStore(after: events.compactMap { $0.date }.min()) { syncError in - error = syncError - dispatchGroup.leave() - } - } - } - dispatchGroup.wait() - - guard error == nil else { - return error - } - - self.log.info("Added %d PumpEvents", events.count) - self.delegate?.doseStoreHasUpdatedPumpEventData(self) - return nil - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/DoseType.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/DoseType.swift deleted file mode 100644 index 3c6a83f48..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/DoseType.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// DoseType.swift -// LoopKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation - - -/// A general set of ways insulin can be delivered by a pump -public enum DoseType: String, CaseIterable { - case basal - case bolus - case resume - case suspend - case tempBasal - - public var localizedDescription: String { - switch self { - case .basal: - return LocalizedString("Basal", comment: "Title for basal dose type") - case .bolus: - return LocalizedString("Bolus", comment: "Title for bolus dose type") - case .tempBasal: - return LocalizedString("Temp Basal", comment: "Title for temp basal dose type") - case .suspend: - return LocalizedString("Suspended", comment: "Title for suspend dose type") - case .resume: - return LocalizedString("Resumed", comment: "Title for resume dose type") - } - } -} - -extension DoseType: Codable {} - -/// Compatibility transform to PumpEventType -extension DoseType { - public init?(pumpEventType: PumpEventType) { - switch pumpEventType { - case .basal: - self = .basal - case .bolus: - self = .bolus - case .resume: - self = .resume - case .suspend: - self = .suspend - case .tempBasal: - self = .tempBasal - case .alarm, .alarmClear, .prime, .rewind: - return nil - } - } - - public var pumpEventType: PumpEventType { - switch self { - case .basal: - return .basal - case .bolus: - return .bolus - case .resume: - return .resume - case .suspend: - return .suspend - case .tempBasal: - return .tempBasal - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/DoseUnit.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/DoseUnit.swift deleted file mode 100644 index b15eca6b2..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/DoseUnit.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// DoseUnit.swift -// LoopKit -// -// Created by Nathan Racklyeft on 3/28/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public enum DoseUnit: String { - case unitsPerHour = "U/hour" - case units = "U" -} - -extension DoseUnit: Codable {} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/ExponentialInsulinModel.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/ExponentialInsulinModel.swift deleted file mode 100644 index 75e54515e..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/ExponentialInsulinModel.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// ExponentialInsulinModel.swift -// InsulinKit -// -// Created by Pete Schwamb on 7/30/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct ExponentialInsulinModel { - public let actionDuration: TimeInterval - public let peakActivityTime: TimeInterval - public let delay: TimeInterval - - // Precomputed terms - fileprivate let τ: Double - fileprivate let a: Double - fileprivate let S: Double - - /// Configures a new exponential insulin model - /// - /// - Parameters: - /// - actionDuration: The total duration of insulin activity, excluding delay - /// - peakActivityTime: The time of the peak of insulin activity from dose. - /// - delay: The time to delay the dose effect - public init(actionDuration: TimeInterval, peakActivityTime: TimeInterval, delay: TimeInterval = 600) { - self.actionDuration = actionDuration - self.peakActivityTime = peakActivityTime - self.delay = delay - - self.τ = peakActivityTime * (1 - peakActivityTime / actionDuration) / (1 - 2 * peakActivityTime / actionDuration) - self.a = 2 * τ / actionDuration - self.S = 1 / (1 - a + (1 + a) * exp(-actionDuration / τ)) - } -} - -extension ExponentialInsulinModel: InsulinModel { - public var effectDuration: TimeInterval { - return self.actionDuration + self.delay - } - - /// Returns the percentage of total insulin effect remaining at a specified interval after delivery; - /// also known as Insulin On Board (IOB). - /// - /// This is a configurable exponential model as described here: https://github.com/LoopKit/Loop/issues/388#issuecomment-317938473 - /// Allows us to specify time of peak activity, as well as duration, and provides activity and IOB decay functions - /// Many thanks to Dragan Maksimovic (@dm61) for creating such a flexible way of adjusting an insulin curve - /// for use in closed loop systems. - /// - /// - Parameter time: The interval after insulin delivery - /// - Returns: The percentage of total insulin effect remaining - - public func percentEffectRemaining(at time: TimeInterval) -> Double { - let timeAfterDelay = time - delay - switch timeAfterDelay { - case let t where t <= 0: - return 1 - case let t where t >= actionDuration: - return 0 - default: - let t = timeAfterDelay - return 1 - S * (1 - a) * - ((pow(t, 2) / (τ * actionDuration * (1 - a)) - t / τ - 1) * exp(-t / τ) + 1) - } - } -} - -extension ExponentialInsulinModel: CustomDebugStringConvertible { - public var debugDescription: String { - return "ExponentialInsulinModel(actionDuration: \(actionDuration), peakActivityTime: \(peakActivityTime), delay: \(delay)" - } -} - -#if swift(>=4) -extension ExponentialInsulinModel: Decodable { - enum CodingKeys: String, CodingKey { - case actionDuration - case peakActivityTime - case delay - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let actionDuration: Double = try container.decode(Double.self, forKey: .actionDuration) - let peakActivityTime: Double = try container.decode(Double.self, forKey: .peakActivityTime) - let delay: Double = try container.decode(TimeInterval.self, forKey: .delay) - - self.init(actionDuration: actionDuration, peakActivityTime: peakActivityTime, delay: delay) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(actionDuration, forKey: .actionDuration) - try container.encode(peakActivityTime, forKey: .peakActivityTime) - try container.encode(delay, forKey: .delay) - } -} -#endif diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/HKQuantitySample+InsulinKit.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/HKQuantitySample+InsulinKit.swift deleted file mode 100644 index e0538eb6a..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/HKQuantitySample+InsulinKit.swift +++ /dev/null @@ -1,243 +0,0 @@ -// -// HKQuantitySample+InsulinKit.swift -// InsulinKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import HealthKit - - -/// Defines the scheduled basal insulin rate during the time of the basal delivery sample -let MetadataKeyScheduledBasalRate = "com.loopkit.InsulinKit.MetadataKeyScheduledBasalRate" - -/// Defines the programmed rate for a temporary basal dose -let MetadataKeyProgrammedTempBasalRate = "com.loopkit.InsulinKit.MetadataKeyProgrammedTempBasalRate" - -/// A crude determination of whether a sample was written by LoopKit, in the case of multiple LoopKit-enabled app versions on the same phone. -let MetadataKeyHasLoopKitOrigin = "HasLoopKitOrigin" - -/// Defines the insulin curve type to use to evaluate the dose's activity -let MetadataKeyInsulinType = "com.loopkit.InsulinKit.MetadataKeyInsulinType" - -/// Flag indicated whether this dose was manually entered -let MetadataKeyManuallyEntered = "com.loopkit.InsulinKit.MetadataKeyManuallyEntered" - -/// Flag indicating whether this dose was issued automatically or if a user issued it manually. -let MetadataKeyAutomaticallyIssued = "com.loopkit.InsulinKit.MetadataKeyAutomaticallyIssued" - -/// Flag indicating whether this dose is a suspend -let MetadataKeyIsSuspend = "com.loopkit.InsulinKit.MetadataKeyIsSuspend" - -extension HKQuantitySample { - convenience init?(type: HKQuantityType, unit: HKUnit, dose: DoseEntry, device: HKDevice?, provenanceIdentifier: String, syncVersion: Int = 1) { - let units = dose.unitsInDeliverableIncrements - - guard let syncIdentifier = dose.syncIdentifier else { - return nil - } - - var metadata: [String: Any] = [ - HKMetadataKeySyncVersion: syncVersion, - HKMetadataKeySyncIdentifier: syncIdentifier, - MetadataKeyHasLoopKitOrigin: true, - MetadataKeyManuallyEntered: dose.manuallyEntered - ] - - switch dose.type { - case .basal, .tempBasal, .suspend: - // Ignore 0-duration basal entries - guard dose.endDate.timeIntervalSince(dose.startDate) > .ulpOfOne else { - return nil - } - - metadata[HKMetadataKeyInsulinDeliveryReason] = HKInsulinDeliveryReason.basal.rawValue - - if let basalRate = dose.scheduledBasalRate { - metadata[MetadataKeyScheduledBasalRate] = basalRate - } - - if dose.type == .tempBasal { - metadata[MetadataKeyProgrammedTempBasalRate] = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: dose.unitsPerHour) - } - - metadata[MetadataKeyIsSuspend] = dose.type == .suspend - case .bolus: - // Ignore 0-unit bolus entries - guard units > .ulpOfOne else { - return nil - } - - metadata[HKMetadataKeyInsulinDeliveryReason] = HKInsulinDeliveryReason.bolus.rawValue - case .resume: - return nil - } - - if let insulinType = dose.insulinType { - metadata[MetadataKeyInsulinType] = insulinType.healthKitRepresentation - } - - if let automatic = dose.automatic { - metadata[MetadataKeyAutomaticallyIssued] = automatic - } - - self.init( - type: type, - quantity: HKQuantity(unit: unit, doubleValue: units), - start: dose.startDate, - end: dose.endDate, - device: device, - metadata: metadata - ) - } - - var hasLoopKitOrigin: Bool { - guard let hasLoopKitOrigin = metadata?[MetadataKeyHasLoopKitOrigin] as? Bool else { - return false - } - - return hasLoopKitOrigin - } - - var insulinDeliveryReason: HKInsulinDeliveryReason? { - guard let reason = metadata?[HKMetadataKeyInsulinDeliveryReason] as? HKInsulinDeliveryReason.RawValue else { - return nil - } - - return HKInsulinDeliveryReason(rawValue: reason) - } - - var scheduledBasalRate: HKQuantity? { - return metadata?[MetadataKeyScheduledBasalRate] as? HKQuantity - } - - var programmedTempBasalRate: HKQuantity? { - return metadata?[MetadataKeyProgrammedTempBasalRate] as? HKQuantity - } - - var isSuspend: Bool { - return metadata?[MetadataKeyIsSuspend] as? Bool ?? false - } - - var manuallyEntered: Bool { - return metadata?[MetadataKeyManuallyEntered] as? Bool ?? false - } - - var automaticallyIssued: Bool? { - return metadata?[MetadataKeyAutomaticallyIssued] as? Bool - } - - var insulinType: InsulinType? { - guard let rawType = metadata?[MetadataKeyInsulinType] as? String else { - return nil - } - - return InsulinType(healthKitRepresentation: rawType) - } - - /// Returns a DoseEntry representation of the sample. - /// Doses are not normalized, nor should they be assumed reconciled. - var dose: DoseEntry? { - guard let reason = insulinDeliveryReason else { - return nil - } - - let type: DoseType - - switch reason { - case .basal: - if isSuspend { - type = .suspend - } else if programmedTempBasalRate != nil { - type = .tempBasal - } else { - type = .basal - } - - // We can't properly trust non-LoopKit-provided basal insulin - guard hasLoopKitOrigin else { - return nil - } - case .bolus: - type = .bolus - @unknown default: - return nil - } - - let value: Double - let unit: DoseUnit - let deliveredUnits: Double? - - if let programmedRate = programmedTempBasalRate { - value = programmedRate.doubleValue(for: .internationalUnitsPerHour) - unit = .unitsPerHour - deliveredUnits = quantity.doubleValue(for: .internationalUnit()) - } else { - value = quantity.doubleValue(for: .internationalUnit()) - unit = .units - deliveredUnits = nil - } - - return DoseEntry( - type: type, - startDate: startDate, - endDate: endDate, - value: value, - unit: unit, - deliveredUnits: deliveredUnits, - description: nil, - syncIdentifier: syncIdentifier, - scheduledBasalRate: scheduledBasalRate, - insulinType: insulinType, - automatic: automaticallyIssued, - manuallyEntered: manuallyEntered - ) - } -} - -enum InsulinTypeHealthKitRepresentation: String { - case novolog = "Novolog" - case humalog = "Humalog" - case apidra = "Apidra" - case fiasp = "Fiasp" - case lyumjev = "Lyumjev" - case afrezza = "Afrezza" -} - -extension InsulinType { - var healthKitRepresentation: String { - switch self { - case .novolog: - return InsulinTypeHealthKitRepresentation.novolog.rawValue - case .humalog: - return InsulinTypeHealthKitRepresentation.humalog.rawValue - case .apidra: - return InsulinTypeHealthKitRepresentation.apidra.rawValue - case .fiasp: - return InsulinTypeHealthKitRepresentation.fiasp.rawValue - case .lyumjev: - return InsulinTypeHealthKitRepresentation.lyumjev.rawValue - case .afrezza: - return InsulinTypeHealthKitRepresentation.afrezza.rawValue - } - } - - init?(healthKitRepresentation: String) { - switch healthKitRepresentation { - case InsulinTypeHealthKitRepresentation.novolog.rawValue: - self = .novolog - case InsulinTypeHealthKitRepresentation.humalog.rawValue: - self = .humalog - case InsulinTypeHealthKitRepresentation.apidra.rawValue: - self = .apidra - case InsulinTypeHealthKitRepresentation.fiasp.rawValue: - self = .fiasp - case InsulinTypeHealthKitRepresentation.lyumjev.rawValue: - self = .lyumjev - case InsulinTypeHealthKitRepresentation.afrezza.rawValue: - self = .afrezza - default: - return nil - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinDeliveryStore.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinDeliveryStore.swift deleted file mode 100644 index 7156c12ab..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinDeliveryStore.swift +++ /dev/null @@ -1,794 +0,0 @@ -// -// InsulinDeliveryStore.swift -// InsulinKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import HealthKit -import CoreData -import os.log - -public protocol InsulinDeliveryStoreDelegate: AnyObject { - - /** - Informs the delegate that the insulin delivery store has updated dose data. - - - Parameter insulinDeliveryStore: The insulin delivery store that has updated dose data. - */ - func insulinDeliveryStoreHasUpdatedDoseData(_ insulinDeliveryStore: InsulinDeliveryStore) - -} - -/// Manages insulin dose data in Core Data and optionally reads insulin dose data from HealthKit. -/// -/// Scheduled doses (e.g. a bolus or temporary basal) shouldn't be written to this store until they've -/// been delivered into the patient, which means its common for this store data to slightly lag -/// behind the dose data used for algorithmic calculation. -/// -/// This store data isn't a substitute for an insulin pump's diagnostic event history, but doses fetched -/// from this store can reduce the amount of repeated communication with an insulin pump. -public class InsulinDeliveryStore: HealthKitSampleStore { - - /// Notification posted when dose entries were changed, either via direct add or from HealthKit - public static let doseEntriesDidChange = NSNotification.Name(rawValue: "com.loopkit.InsulinDeliveryStore.doseEntriesDidChange") - - private let insulinQuantityType = HKQuantityType.quantityType(forIdentifier: .insulinDelivery)! - - private let queue = DispatchQueue(label: "com.loopkit.InsulinDeliveryStore.queue", qos: .utility) - - private let log = OSLog(category: "InsulinDeliveryStore") - - /// The most-recent end date for an immutable basal dose entry written by LoopKit - /// Should only be accessed on queue - private var lastImmutableBasalEndDate: Date? { - didSet { - test_lastImmutableBasalEndDateDidSet?() - } - } - - internal var test_lastImmutableBasalEndDateDidSet: (() -> Void)? - - public weak var delegate: InsulinDeliveryStoreDelegate? - - /// The interval of insulin delivery data to keep in cache - public let cacheLength: TimeInterval - - private let storeSamplesToHealthKit: Bool - - private let cacheStore: PersistenceController - - private let provenanceIdentifier: String - - static let healthKitQueryAnchorMetadataKey = "com.loopkit.InsulinDeliveryStore.hkQueryAnchor" - - public init( - healthStore: HKHealthStore, - observeHealthKitSamplesFromOtherApps: Bool = true, - storeSamplesToHealthKit: Bool = true, - cacheStore: PersistenceController, - observationEnabled: Bool = true, - cacheLength: TimeInterval = 24 /* hours */ * 60 /* minutes */ * 60 /* seconds */, - provenanceIdentifier: String, - test_currentDate: Date? = nil - ) { - self.storeSamplesToHealthKit = storeSamplesToHealthKit - self.cacheStore = cacheStore - self.cacheLength = cacheLength - self.provenanceIdentifier = provenanceIdentifier - - // Only observe HK driven changes from last 24 hours - let observationStartOffset = min(cacheLength, .hours(24)) - - super.init( - healthStore: healthStore, - observeHealthKitSamplesFromCurrentApp: true, - observeHealthKitSamplesFromOtherApps: observeHealthKitSamplesFromOtherApps, - type: insulinQuantityType, - observationStart: (test_currentDate ?? Date()).addingTimeInterval(-observationStartOffset), - observationEnabled: observationEnabled, - test_currentDate: test_currentDate - ) - - cacheStore.onReady { (error) in - guard error == nil else { - return - } - - self.queue.sync { - self.updateLastImmutableBasalEndDate() - } - - cacheStore.fetchAnchor(key: InsulinDeliveryStore.healthKitQueryAnchorMetadataKey) { (anchor) in - self.queue.async { - self.setInitialQueryAnchor(anchor) - } - } - } - } - - // MARK: - HealthKitSampleStore - - override func storeQueryAnchor(_ anchor: HKQueryAnchor) { - cacheStore.storeAnchor(anchor, key: InsulinDeliveryStore.healthKitQueryAnchorMetadataKey) - self.log.default("stored query anchor %{public}@", String(describing: anchor)) - } - - override func processResults(from query: HKAnchoredObjectQuery, added: [HKSample], deleted: [HKDeletedObject], anchor: HKQueryAnchor, completion: @escaping (Bool) -> Void) { - queue.async { - var changed = false - var error: Error? - - self.cacheStore.managedObjectContext.performAndWait { - do { - // Add new samples - if let samples = added as? [HKQuantitySample] { - for sample in samples { - if try self.addDoseEntry(for: sample) { - self.log.debug("Saved sample %@ into cache from HKAnchoredObjectQuery", sample.uuid.uuidString) - changed = true - } else { - self.log.default("Sample %@ from HKAnchoredObjectQuery already present in cache", sample.uuid.uuidString) - } - } - } - - // Delete deleted samples - let count = try self.deleteDoseEntries(withUUIDs: deleted.map { $0.uuid }) - if count > 0 { - self.log.debug("Deleted %d samples from cache from HKAnchoredObjectQuery", count) - changed = true - } - - guard changed else { - return - } - - error = self.cacheStore.save() - } catch let coreDataError { - error = coreDataError - } - } - - guard error == nil else { - completion(false) - return - } - - guard changed else { - completion(true) - return - } - - self.handleUpdatedDoseData() - self.delegate?.insulinDeliveryStoreHasUpdatedDoseData(self) - - completion(true) - } - } -} - -// MARK: - Fetching - -extension InsulinDeliveryStore { - /// Retrieves dose entries within the specified date range. - /// - /// - Parameters: - /// - start: The earliest date of dose entries to retrieve, if provided. - /// - end: The latest date of dose entries to retrieve, if provided. - /// - includeMutable: Whether to include mutable dose entries or not. Defaults to false. - /// - completion: A closure called once the dose entries have been retrieved. - /// - result: An array of dose entries, in chronological order by startDate, or error. - public func getDoseEntries(start: Date? = nil, end: Date? = nil, includeMutable: Bool = false, completion: @escaping (_ result: Result<[DoseEntry], Error>) -> Void) { - queue.async { - completion(self.getDoseEntries(start: start, end: end, includeMutable: includeMutable)) - } - } - - private func getDoseEntries(start: Date? = nil, end: Date? = nil, includeMutable: Bool = false) -> Result<[DoseEntry], Error> { - dispatchPrecondition(condition: .onQueue(queue)) - - var entries: [DoseEntry] = [] - var error: Error? - - cacheStore.managedObjectContext.performAndWait { - do { - entries = try self.getCachedInsulinDeliveryObjects(start: start, end: end, includeMutable: includeMutable).map { $0.dose } - } catch let coreDataError { - error = coreDataError - } - } - - if let error = error { - self.log.error("Error getting CachedInsulinDeliveryObjects: %{public}@", String(describing: error)) - return .failure(error) - } - - return .success(entries) - } - - private func getCachedInsulinDeliveryObjects(start: Date? = nil, end: Date? = nil, includeMutable: Bool = false) throws -> [CachedInsulinDeliveryObject] { - dispatchPrecondition(condition: .onQueue(queue)) - - // Match all doses whose start OR end dates fall in the start and end date range, if specified. Therefore, we ensure the - // dose end date is AFTER the start date, if specified, and the dose start date is BEFORE the end date, if specified. - var predicates = [NSPredicate(format: "deletedAt == NIL")] - if let start = start { - predicates.append(NSPredicate(format: "endDate >= %@", start as NSDate)) - } - if let end = end { - predicates.append(NSPredicate(format: "startDate <= %@", end as NSDate)) // Note: Using <= rather than < to match previous behavior - } - if !includeMutable { - predicates.append(NSPredicate(format: "isMutable == NO")) - } - - let request: NSFetchRequest = CachedInsulinDeliveryObject.fetchRequest() - request.predicate = (predicates.count > 1) ? NSCompoundPredicate(andPredicateWithSubpredicates: predicates) : predicates.first - request.sortDescriptors = [NSSortDescriptor(key: "startDate", ascending: true)] - - return try self.cacheStore.managedObjectContext.fetch(request) - } - - /// Fetches manually entered doses. - /// - /// - Parameters: - /// - startDate: The earliest dose startDate to include. - /// - chronological: Whether to return the objects in chronological or reverse-chronological order. - /// - limit: The maximum number of manually entered dose entries to return. - /// - Returns: An array of manually entered dose dose entries in the specified order by date. - public func getManuallyEnteredDoses(since startDate: Date, chronological: Bool = true, limit: Int? = nil, completion: @escaping (_ result: DoseStoreResult<[DoseEntry]>) -> Void) { - queue.async { - var doses: [DoseEntry] = [] - var error: DoseStore.DoseStoreError? - - self.cacheStore.managedObjectContext.performAndWait { - let predicates = [NSPredicate(format: "deletedAt == NIL"), - NSPredicate(format: "startDate >= %@", startDate as NSDate), - NSPredicate(format: "manuallyEntered == YES")] - - let request: NSFetchRequest = CachedInsulinDeliveryObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates) - request.sortDescriptors = [NSSortDescriptor(key: "startDate", ascending: chronological)] - if let limit = limit { - request.fetchLimit = limit - } - - do { - doses = try self.cacheStore.managedObjectContext.fetch(request).compactMap{ $0.dose } - } catch let fetchError as NSError { - error = .fetchError(description: fetchError.localizedDescription, recoverySuggestion: fetchError.localizedRecoverySuggestion) - } catch { - assertionFailure() - } - } - - if let error = error { - completion(.failure(error)) - } - - completion(.success(doses)) - } - } - - /// Returns the end date of the most recent basal dose entry. - /// - /// - Parameters: - /// - completion: A closure called when the date has been retrieved with date. - /// - result: The date, or error. - func getLastImmutableBasalEndDate(_ completion: @escaping (_ result: Result) -> Void) { - queue.async { - switch self.lastImmutableBasalEndDate { - case .some(let date): - completion(.success(date)) - case .none: - // TODO: send a proper error - completion(.failure(DoseStore.DoseStoreError.initializationError(description: "lastImmutableBasalEndDate has not been set", recoverySuggestion: "Avoid accessing InsulinDeliveryStore until initialization is complete"))) - } - } - } - - private func updateLastImmutableBasalEndDate() { - dispatchPrecondition(condition: .onQueue(queue)) - - var endDate: Date? - - cacheStore.managedObjectContext.performAndWait { - let request: NSFetchRequest = CachedInsulinDeliveryObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format: "deletedAt == NIL"), - NSPredicate(format: "reason == %d", HKInsulinDeliveryReason.basal.rawValue), - NSPredicate(format: "hasLoopKitOrigin == YES"), - NSPredicate(format: "isMutable == NO")]) - request.sortDescriptors = [NSSortDescriptor(key: "endDate", ascending: false)] - request.fetchLimit = 1 - - do { - let objects = try self.cacheStore.managedObjectContext.fetch(request) - - endDate = objects.first?.endDate - } catch let error { - self.log.error("Unable to fetch latest insulin delivery objects: %@", String(describing: error)) - } - } - - self.lastImmutableBasalEndDate = endDate ?? .distantPast - } -} - -// MARK: - Modification - -extension InsulinDeliveryStore { - /// Add dose entries to store. - /// - /// - Parameters: - /// - entries: The new dose entries to add to the store. - /// - device: The optional device used for the new dose entries. - /// - syncVersion: The sync version used for the new dose entries. - /// - resolveMutable: Whether to update or delete any pre-existing mutable dose entries based upon any matching incoming mutable dose entries. Any previously stored mutable doses that are not also included in entries will be marked as deleted. - /// - completion: A closure called once the dose entries have been stored. - /// - result: Success or error. - func addDoseEntries(_ entries: [DoseEntry], from device: HKDevice?, syncVersion: Int, resolveMutable: Bool = false, completion: @escaping (_ result: Result) -> Void) { - guard !entries.isEmpty else { - completion(.success(())) - return - } - - queue.async { - var changed = false - var error: Error? - - self.cacheStore.managedObjectContext.performAndWait { - do { - let now = self.currentDate() - var mutableObjects: [CachedInsulinDeliveryObject] = [] - - // If we are resolving mutable objects, then fetch all non-deleted mutable objects and initially mark as deleted - // If an incoming entry matches via syncIdentifier, then update and mark as NOT deleted - if resolveMutable { - let request: NSFetchRequest = CachedInsulinDeliveryObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format: "deletedAt == NIL"), - NSPredicate(format: "isMutable == YES")]) - mutableObjects = try self.cacheStore.managedObjectContext.fetch(request) - mutableObjects.forEach { $0.deletedAt = now } - } - - let resolvedSampleObjects: [(HKQuantitySample, CachedInsulinDeliveryObject)] = entries.compactMap { entry in - guard entry.syncIdentifier != nil else { - self.log.error("Ignored adding dose entry without sync identifier: %{public}@", String(reflecting: entry)) - return nil - } - - guard let quantitySample = HKQuantitySample(type: self.insulinQuantityType, - unit: HKUnit.internationalUnit(), - dose: entry, - device: device, - provenanceIdentifier: self.provenanceIdentifier, - syncVersion: syncVersion) - else { - self.log.error("Failure to create HKQuantitySample from DoseEntry: %{public}@", String(describing: entry)) - return nil - } - - // If we have a mutable object that matches this sync identifier, then update, it will mark as NOT deleted - if let object = mutableObjects.first(where: { $0.provenanceIdentifier == self.provenanceIdentifier && $0.syncIdentifier == entry.syncIdentifier }) { - self.log.debug("Update: %{public}@", String(describing: entry)) - object.update(from: entry) - return (quantitySample, object) - - // Otherwise, add new object - } else { - let object = CachedInsulinDeliveryObject(context: self.cacheStore.managedObjectContext) - object.create(from: entry, by: self.provenanceIdentifier, at: now) - self.log.debug("Add: %{public}@", String(describing: entry)) - return (quantitySample, object) - } - } - - for dose in mutableObjects { - if dose.deletedAt != nil { - self.log.debug("Delete: %{public}@", String(describing: dose)) - } - } - - changed = !mutableObjects.isEmpty || !resolvedSampleObjects.isEmpty - guard changed else { - return - } - - error = self.cacheStore.save() - if error != nil { - return - } - - // Only save immutable objects to HealthKit - self.saveEntriesToHealthKit(resolvedSampleObjects.filter { !$0.1.isMutable && !$0.1.isFault }) - } catch let coreDataError { - error = coreDataError - } - } - - if let error = error { - completion(.failure(error)) - return - } - - guard changed else { - completion(.success(())) - return - } - - self.handleUpdatedDoseData() - self.delegate?.insulinDeliveryStoreHasUpdatedDoseData(self) - - completion(.success(())) - } - } - - private func saveEntriesToHealthKit(_ sampleObjects: [(HKQuantitySample, CachedInsulinDeliveryObject)]) { - dispatchPrecondition(condition: .onQueue(queue)) - - guard storeSamplesToHealthKit, !sampleObjects.isEmpty else { - return - } - - var error: Error? - - // Save objects to HealthKit, log any errors, but do not fail - let dispatchGroup = DispatchGroup() - dispatchGroup.enter() - self.healthStore.save(sampleObjects.map { (sample, _) in sample }) { (_, healthKitError) in - error = healthKitError - dispatchGroup.leave() - } - dispatchGroup.wait() - - if let error = error { - self.log.error("Error saving HealthKit objects: %@", String(describing: error)) - return - } - - // Update Core Data with the changes, log any errors, but do not fail - sampleObjects.forEach { (sample, object) in object.uuid = sample.uuid } - if let error = self.cacheStore.save() { - self.log.error("Error updating CachedInsulinDeliveryObjects after saving HealthKit objects: %@", String(describing: error)) - sampleObjects.forEach { (_, object) in object.uuid = nil } - } - } - - private func addDoseEntry(for sample: HKQuantitySample) throws -> Bool { - dispatchPrecondition(condition: .onQueue(queue)) - - // Is entire sample before earliest cache date? - guard sample.endDate >= earliestCacheDate else { - return false - } - - // Are there any objects matching the UUID? - let request: NSFetchRequest = CachedInsulinDeliveryObject.fetchRequest() - request.predicate = NSPredicate(format: "uuid == %@", sample.uuid as NSUUID) - request.fetchLimit = 1 - - let count = try cacheStore.managedObjectContext.count(for: request) - guard count == 0 else { - return false - } - - // Add an object for this UUID - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.create(fromExisting: sample, on: self.currentDate()) - - return true - } - - func deleteDose(bySyncIdentifier syncIdentifier: String, _ completion: @escaping (String?) -> Void) { - queue.async { - var errorString: String? = nil - self.cacheStore.managedObjectContext.performAndWait { - do { - let request: NSFetchRequest = CachedInsulinDeliveryObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format: "deletedAt == NIL"), - NSPredicate(format: "syncIdentifier == %@", syncIdentifier)]) - request.fetchBatchSize = 100 - let objects = try self.cacheStore.managedObjectContext.fetch(request) - if !objects.isEmpty { - let deletedAt = self.currentDate() - for object in objects { - object.deletedAt = deletedAt - } - self.cacheStore.save() - } - - let healthKitPredicate = HKQuery.predicateForObjects(withMetadataKey: HKMetadataKeySyncIdentifier, allowedValues: [syncIdentifier]) - self.healthStore.deleteObjects(of: self.insulinQuantityType, predicate: healthKitPredicate) - { success, deletedObjectCount, error in - if let error = error { - self.log.error("Unable to delete dose from Health: %@", error.localizedDescription) - } - } - } catch let error { - errorString = "Error deleting CachedInsulinDeliveryObject: " + error.localizedDescription - return - } - } - self.handleUpdatedDoseData() - self.delegate?.insulinDeliveryStoreHasUpdatedDoseData(self) - completion(errorString) - } - } - - func deleteDose(with uuidToDelete: UUID, _ completion: @escaping (String?) -> Void) { - queue.async { - var errorString: String? = nil - self.cacheStore.managedObjectContext.performAndWait { - do { - let count = try self.deleteDoseEntries(withUUIDs: [uuidToDelete]) - guard count > 0 else { - errorString = "Cannot find CachedInsulinDeliveryObject to delete" - return - } - self.cacheStore.save() - } catch let error { - errorString = "Error deleting CachedInsulinDeliveryObject: " + error.localizedDescription - return - } - } - self.handleUpdatedDoseData() - self.delegate?.insulinDeliveryStoreHasUpdatedDoseData(self) - completion(errorString) - } - } - - private func deleteDoseEntries(withUUIDs uuids: [UUID], batchSize: Int = 500) throws -> Int { - dispatchPrecondition(condition: .onQueue(queue)) - - let deletedAt = self.currentDate() - - var count = 0 - for batch in uuids.chunked(into: batchSize) { - let request: NSFetchRequest = CachedInsulinDeliveryObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format: "deletedAt == NIL"), - NSPredicate(format: "uuid IN %@", batch.map { $0 as NSUUID })]) - let objects = try self.cacheStore.managedObjectContext.fetch(request) - for object in objects { - object.deletedAt = deletedAt - } - count += objects.count - } - return count - } - - public func deleteAllManuallyEnteredDoses(since startDate: Date, _ completion: @escaping (_ error: DoseStore.DoseStoreError?) -> Void) { - queue.async { - var doseStoreError: DoseStore.DoseStoreError? - self.cacheStore.managedObjectContext.performAndWait { - do { - let request: NSFetchRequest = CachedInsulinDeliveryObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format: "deletedAt == NIL"), - NSPredicate(format: "startDate >= %@", startDate as NSDate), - NSPredicate(format: "manuallyEntered == YES")]) - request.fetchBatchSize = 100 - let objects = try self.cacheStore.managedObjectContext.fetch(request) - if !objects.isEmpty { - let deletedAt = self.currentDate() - for object in objects { - object.deletedAt = deletedAt - } - doseStoreError = DoseStore.DoseStoreError(error: self.cacheStore.save()) - } - } - catch let error as NSError { - doseStoreError = DoseStore.DoseStoreError(error: .coreDataError(error)) - } - } - self.handleUpdatedDoseData() - self.delegate?.insulinDeliveryStoreHasUpdatedDoseData(self) - completion(doseStoreError) - } - } -} - -// MARK: - Cache Management - -extension InsulinDeliveryStore { - var earliestCacheDate: Date { - return currentDate(timeIntervalSinceNow: -cacheLength) - } - - /// Purge all dose entries from the insulin delivery store and HealthKit (matching the specified device predicate). - /// - /// - Parameters: - /// - healthKitPredicate: The HealthKit device predicate to match HealthKit insulin samples. - /// - completion: The completion handler returning any error. - public func purgeAllDoseEntries(healthKitPredicate: NSPredicate, completion: @escaping (Error?) -> Void) { - queue.async { - let storeError = self.purgeCachedInsulinDeliveryObjects(matching: nil) - self.healthStore.deleteObjects(of: self.insulinQuantityType, predicate: healthKitPredicate) { _, _, healthKitError in - self.queue.async { - self.handleUpdatedDoseData() - completion(storeError ?? healthKitError) - } - } - } - } - - private func purgeExpiredCachedInsulinDeliveryObjects() { - purgeCachedInsulinDeliveryObjects(before: earliestCacheDate) - } - - /// Purge cached insulin delivery objects from the insulin delivery store. - /// - /// - Parameters: - /// - date: Purge cached insulin delivery objects with start date before this date. - /// - completion: The completion handler returning any error. - public func purgeCachedInsulinDeliveryObjects(before date: Date? = nil, completion: @escaping (Error?) -> Void) { - queue.async { - if let error = self.purgeCachedInsulinDeliveryObjects(before: date) { - completion(error) - return - } - self.handleUpdatedDoseData() - completion(nil) - } - } - - @discardableResult - private func purgeCachedInsulinDeliveryObjects(before date: Date? = nil) -> Error? { - return purgeCachedInsulinDeliveryObjects(matching: date.map { NSPredicate(format: "endDate < %@", $0 as NSDate) }) - } - - private func purgeCachedInsulinDeliveryObjects(matching predicate: NSPredicate? = nil) -> Error? { - dispatchPrecondition(condition: .onQueue(queue)) - - var error: Error? - - cacheStore.managedObjectContext.performAndWait { - do { - let count = try cacheStore.managedObjectContext.purgeObjects(of: CachedInsulinDeliveryObject.self, matching: predicate) - if count > 0 { - self.log.default("Purged %d CachedInsulinDeliveryObjects", count) - } - } catch let coreDataError { - self.log.error("Unable to purge CachedInsulinDeliveryObjects: %{public}@", String(describing: error)) - error = coreDataError - } - } - - return error - } - - private func handleUpdatedDoseData() { - dispatchPrecondition(condition: .onQueue(queue)) - - self.purgeExpiredCachedInsulinDeliveryObjects() - self.updateLastImmutableBasalEndDate() - - NotificationCenter.default.post(name: InsulinDeliveryStore.doseEntriesDidChange, object: self) - } -} - -// MARK: - Issue Report - -extension InsulinDeliveryStore { - /// Generates a diagnostic report about the current state - /// - /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. - /// - /// - parameter completion: The closure takes a single argument of the report string. - public func generateDiagnosticReport(_ completion: @escaping (_ report: String) -> Void) { - self.queue.async { - var report: [String] = [ - "### InsulinDeliveryStore", - "* cacheLength: \(self.cacheLength)", - super.debugDescription, - "* lastImmutableBasalEndDate: \(String(describing: self.lastImmutableBasalEndDate))", - "", - "#### cachedDoseEntries", - ] - - switch self.getDoseEntries(start: Date(timeIntervalSinceNow: -.hours(24)), includeMutable: true) { - case .failure(let error): - report.append("Error: \(error)") - case .success(let entries): - for entry in entries { - report.append(String(describing: entry)) - } - } - - report.append("") - completion(report.joined(separator: "\n")) - } - } -} - -// MARK: - Query - -extension InsulinDeliveryStore { - - public struct QueryAnchor: Equatable, RawRepresentable { - - public typealias RawValue = [String: Any] - - internal var modificationCounter: Int64 - - public init() { - self.modificationCounter = 0 - } - - public init?(rawValue: RawValue) { - guard let modificationCounter = rawValue["modificationCounter"] as? Int64 else { - return nil - } - self.modificationCounter = modificationCounter - } - - public var rawValue: RawValue { - var rawValue: RawValue = [:] - rawValue["modificationCounter"] = modificationCounter - return rawValue - } - } - - public enum DoseQueryResult { - case success(QueryAnchor, [DoseEntry], [DoseEntry]) - case failure(Error) - } - - public func executeDoseQuery(fromQueryAnchor queryAnchor: QueryAnchor?, limit: Int, completion: @escaping (DoseQueryResult) -> Void) { - queue.async { - var queryAnchor = queryAnchor ?? QueryAnchor() - var queryCreatedResult = [DoseEntry]() - var queryDeletedResult = [DoseEntry]() - var queryError: Error? - - guard limit > 0 else { - completion(.success(queryAnchor, [], [])) - return - } - - self.cacheStore.managedObjectContext.performAndWait { - let storedRequest: NSFetchRequest = CachedInsulinDeliveryObject.fetchRequest() - - storedRequest.predicate = NSPredicate(format: "modificationCounter > %d", queryAnchor.modificationCounter) - storedRequest.sortDescriptors = [NSSortDescriptor(key: "modificationCounter", ascending: true)] - storedRequest.fetchLimit = limit - - do { - let stored = try self.cacheStore.managedObjectContext.fetch(storedRequest) - if let modificationCounter = stored.max(by: { $0.modificationCounter < $1.modificationCounter })?.modificationCounter { - queryAnchor.modificationCounter = modificationCounter - } - queryCreatedResult.append(contentsOf: stored.filter({ $0.deletedAt == nil }).compactMap { $0.dose }) - queryDeletedResult.append(contentsOf: stored.filter({ $0.deletedAt != nil }).compactMap { $0.dose }) - } catch let error { - queryError = error - } - } - - if let queryError = queryError { - completion(.failure(queryError)) - return - } - - completion(.success(queryAnchor, queryCreatedResult, queryDeletedResult)) - } - } -} - -// MARK: - Unit Testing - -extension InsulinDeliveryStore { - public var test_lastImmutableBasalEndDate: Date? { - get { - var date: Date? - queue.sync { - date = self.lastImmutableBasalEndDate - } - return date - } - set { - queue.sync { - self.lastImmutableBasalEndDate = newValue - } - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinMath.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinMath.swift deleted file mode 100644 index 29c7053c4..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinMath.swift +++ /dev/null @@ -1,695 +0,0 @@ -// -// InsulinMath.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/30/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -extension DoseEntry { - private func continuousDeliveryInsulinOnBoard(at date: Date, model: InsulinModel, delta: TimeInterval) -> Double { - let doseDuration = endDate.timeIntervalSince(startDate) // t1 - let time = date.timeIntervalSince(startDate) - var iob: Double = 0 - var doseDate = TimeInterval(0) // i - - repeat { - let segment: Double - - if doseDuration > 0 { - segment = max(0, min(doseDate + delta, doseDuration) - doseDate) / doseDuration - } else { - segment = 1 - } - - iob += segment * model.percentEffectRemaining(at: time - doseDate) - doseDate += delta - } while doseDate <= min(floor((time + model.delay) / delta) * delta, doseDuration) - - return iob - } - - func insulinOnBoard(at date: Date, model: InsulinModel, delta: TimeInterval) -> Double { - let time = date.timeIntervalSince(startDate) - guard time >= 0 else { - return 0 - } - - // Consider doses within the delta time window as momentary - if endDate.timeIntervalSince(startDate) <= 1.05 * delta { - return netBasalUnits * model.percentEffectRemaining(at: time) - } else { - return netBasalUnits * continuousDeliveryInsulinOnBoard(at: date, model: model, delta: delta) - } - } - - private func continuousDeliveryGlucoseEffect(at date: Date, model: InsulinModel, delta: TimeInterval) -> Double { - let doseDuration = endDate.timeIntervalSince(startDate) // t1 - let time = date.timeIntervalSince(startDate) - var value: Double = 0 - var doseDate = TimeInterval(0) // i - - repeat { - let segment: Double - - if doseDuration > 0 { - segment = max(0, min(doseDate + delta, doseDuration) - doseDate) / doseDuration - } else { - segment = 1 - } - - value += segment * (1.0 - model.percentEffectRemaining(at: time - doseDate)) - doseDate += delta - } while doseDate <= min(floor((time + model.delay) / delta) * delta, doseDuration) - - return value - } - - func glucoseEffect(at date: Date, model: InsulinModel, insulinSensitivity: Double, delta: TimeInterval) -> Double { - let time = date.timeIntervalSince(startDate) - - guard time >= 0 else { - return 0 - } - - // Consider doses within the delta time window as momentary - if endDate.timeIntervalSince(startDate) <= 1.05 * delta { - return netBasalUnits * -insulinSensitivity * (1.0 - model.percentEffectRemaining(at: time)) - } else { - return netBasalUnits * -insulinSensitivity * continuousDeliveryGlucoseEffect(at: date, model: model, delta: delta) - } - } - - func trimmed(from start: Date? = nil, to end: Date? = nil, syncIdentifier: String? = nil) -> DoseEntry { - - let originalDuration = endDate.timeIntervalSince(startDate) - - let startDate = max(start ?? .distantPast, self.startDate) - let endDate = max(startDate, min(end ?? .distantFuture, self.endDate)) - - var trimmedDeliveredUnits: Double? = deliveredUnits - var trimmedValue: Double = value - - if originalDuration > .ulpOfOne && (startDate > self.startDate || endDate < self.endDate) { - let updatedActualDelivery = unitsInDeliverableIncrements * (endDate.timeIntervalSince(startDate) / originalDuration) - if deliveredUnits != nil { - trimmedDeliveredUnits = updatedActualDelivery - } - if case .units = unit { - trimmedValue = updatedActualDelivery - } - } - - return DoseEntry( - type: type, - startDate: startDate, - endDate: endDate, - value: trimmedValue, - unit: unit, - deliveredUnits: trimmedDeliveredUnits, - description: description, - syncIdentifier: syncIdentifier, - scheduledBasalRate: scheduledBasalRate, - insulinType: insulinType, - automatic: automatic, - isMutable: isMutable, - wasProgrammedByPumpUI: wasProgrammedByPumpUI - ) - } -} - - -/** - It takes a MM x22 pump about 40s to deliver 1 Unit while bolusing - See: http://www.healthline.com/diabetesmine/ask-dmine-speed-insulin-pumps#3 - - The x23 and newer pumps can deliver at 2x, 3x, and 4x that speed, targeting - a maximum 5-minute delivery for all boluses (8U - 25U) - - A basal rate of 30 U/hour (near-max) would deliver an additional 0.5 U/min. - */ -private let MaximumReservoirDropPerMinute = 6.5 - - -extension Collection where Element: ReservoirValue { - /** - Converts a continuous, chronological sequence of reservoir values to a sequence of doses - - This is an O(n) operation. - - - returns: An array of doses - */ - var doseEntries: [DoseEntry] { - var doses: [DoseEntry] = [] - var previousValue: Element? - - let numberFormatter = NumberFormatter() - numberFormatter.numberStyle = .decimal - numberFormatter.maximumFractionDigits = 3 - - for value in self { - if let previousValue = previousValue { - let volumeDrop = previousValue.unitVolume - value.unitVolume - let duration = value.startDate.timeIntervalSince(previousValue.startDate) - - if duration > 0 && 0 <= volumeDrop && volumeDrop <= MaximumReservoirDropPerMinute * duration.minutes { - doses.append(DoseEntry( - type: .tempBasal, - startDate: previousValue.startDate, - endDate: value.startDate, - value: volumeDrop, - unit: .units - )) - } - } - - previousValue = value - } - - return doses - } - - /** - Whether a span of chronological reservoir values is considered continuous and therefore reliable. - - Reservoir values of 0 are automatically considered unreliable due to the assumption that an unknown amount of insulin can be delivered after the 0 marker. - - - parameter startDate: The beginning of the interval in which to validate continuity - - parameter endDate: The end of the interval in which to validate continuity - - parameter maximumDuration: The maximum interval to consider reliable for a reservoir-derived dose - - - returns: Whether the reservoir values meet the critera for continuity - */ - func isContinuous(from start: Date?, to end: Date, within maximumDuration: TimeInterval) -> Bool { - guard let firstValue = self.first else { - return false - } - - // The first value has to be at least as old as the start date, as a reference point. - let startDate = start ?? firstValue.endDate - guard firstValue.endDate <= startDate else { - return false - } - - var lastValue = firstValue - - for value in self { - defer { - lastValue = value - } - - // Volume and interval validation only applies for values in the specified range, - guard value.endDate >= startDate && value.startDate <= end else { - continue - } - - // We can't trust 0. What else was delivered? - guard value.unitVolume > 0 else { - return false - } - - // Rises in reservoir volume indicate a rewind + prime, and primes - // can be easily confused with boluses. - // Small rises (1 U) can be ignored as they're indicative of a mixed-precision sequence. - guard value.unitVolume <= lastValue.unitVolume + 1 else { - return false - } - - // Ensure no more than the maximum interval has passed - guard value.startDate.timeIntervalSince(lastValue.endDate) <= maximumDuration else { - return false - } - } - - return true - } -} - - -extension DoseEntry { - /// Annotates a dose with the context of the scheduled basal rate - /// - /// If the dose crosses a schedule boundary, it will be split into multiple doses so each dose has a - /// single scheduled basal rate. - /// - /// - Parameter basalSchedule: The basal rate schedule to apply - /// - Returns: An array of annotated doses - fileprivate func annotated(with basalSchedule: BasalRateSchedule) -> [DoseEntry] { - switch type { - case .tempBasal, .suspend, .resume: - guard scheduledBasalRate == nil else { - return [self] - } - break - case .basal, .bolus: - return [self] - } - - var doses: [DoseEntry] = [] - let basalItems = basalSchedule.between(start: startDate, end: endDate) - - for (index, basalItem) in basalItems.enumerated() { - let startDate: Date - let endDate: Date - - // If we're splitting into multiple entries, keep the syncIdentifier unique - var syncIdentifier = self.syncIdentifier - if syncIdentifier != nil, basalItems.count > 1 { - syncIdentifier! += " \(index + 1)/\(basalItems.count)" - } - - if index == 0 { - startDate = self.startDate - } else { - startDate = basalItem.startDate - } - - if index == basalItems.count - 1 { - endDate = self.endDate - } else { - endDate = basalItems[index + 1].startDate - } - - var dose = trimmed(from: startDate, to: endDate, syncIdentifier: syncIdentifier) - - dose.scheduledBasalRate = HKQuantity(unit: DoseEntry.unitsPerHour, doubleValue: basalItem.value) - - doses.append(dose) - } - - return doses - } - - /// Annotates a dose with the specified insulin type. - /// - /// - Parameter insulinType: The insulin type to annotate the dose with. - /// - Returns: A dose annotated with the insulin model - public func annotated(with insulinType: InsulinType) -> DoseEntry { - return DoseEntry( - type: type, - startDate: startDate, - endDate: endDate, - value: value, - unit: unit, - deliveredUnits: deliveredUnits, - description: description, - syncIdentifier: syncIdentifier, - scheduledBasalRate: scheduledBasalRate, - insulinType: insulinType, - automatic: automatic, - isMutable: isMutable, - wasProgrammedByPumpUI: wasProgrammedByPumpUI - ) - } -} - -extension DoseEntry { - /// Calculates the timeline of glucose effects for a temp basal dose - /// Use case: predict glucose effects of zero temping - /// - /// - Parameters: - /// - insulinModelProvider: A factory that can provide an insulin model given an insulin type - /// - longestEffectDuration: The longest duration that a dose could be active. - /// - defaultInsulinModelSetting: The model of insulin activity over time - /// - insulinSensitivity: The schedule of glucose effect per unit of insulin - /// - basalRateSchedule: The schedule of basal rates - /// - Returns: An array of glucose effects for the duration of the temp basal dose plus the duration of insulin action - public func tempBasalGlucoseEffects( - insulinModelProvider: InsulinModelProvider, - longestEffectDuration: TimeInterval, - insulinSensitivity: InsulinSensitivitySchedule, - basalRateSchedule: BasalRateSchedule - ) -> [GlucoseEffect] { - - guard case .tempBasal = type else { - return [] - } - - let netTempBasalDoses = self.annotated(with: basalRateSchedule) - - return netTempBasalDoses.glucoseEffects(insulinModelProvider: insulinModelProvider, longestEffectDuration: longestEffectDuration, insulinSensitivity: insulinSensitivity) - } - - fileprivate var resolvingDelivery: DoseEntry { - guard !isMutable, deliveredUnits == nil else { - return self - } - - let resolvedUnits: Double - - if case .units = unit { - resolvedUnits = value - } else { - switch type { - case .tempBasal: - resolvedUnits = unitsInDeliverableIncrements - case .basal: - resolvedUnits = programmedUnits - default: - return self - } - } - return DoseEntry(type: type, startDate: startDate, endDate: endDate, value: value, unit: unit, deliveredUnits: resolvedUnits, description: description, syncIdentifier: syncIdentifier, scheduledBasalRate: scheduledBasalRate, insulinType: insulinType, automatic: automatic, isMutable: isMutable, wasProgrammedByPumpUI: wasProgrammedByPumpUI) - } -} - -extension Collection where Element == DoseEntry { - - /** - Maps a timeline of dose entries with overlapping start and end dates to a timeline of doses that represents actual insulin delivery. - - - returns: An array of reconciled insulin delivery history, as TempBasal and Bolus records - */ - func reconciled() -> [DoseEntry] { - - var reconciled: [DoseEntry] = [] - - var lastSuspend: DoseEntry? - var lastBasal: DoseEntry? - - for dose in self { - switch dose.type { - case .bolus: - reconciled.append(dose) - case .basal, .tempBasal: - if lastSuspend == nil, let last = lastBasal { - let endDate = Swift.min(last.endDate, dose.startDate) - - // Ignore 0-duration doses - if endDate > last.startDate { - reconciled.append(last.trimmed(from: nil, to: endDate, syncIdentifier: last.syncIdentifier)) - } - } else if let suspend = lastSuspend, dose.type == .tempBasal { - // Handle missing resume. Basal following suspend, with no resume. - reconciled.append(DoseEntry( - type: suspend.type, - startDate: suspend.startDate, - endDate: dose.startDate, - value: suspend.value, - unit: suspend.unit, - description: suspend.description ?? dose.description, - syncIdentifier: suspend.syncIdentifier, - insulinType: suspend.insulinType, - automatic: suspend.automatic, - isMutable: suspend.isMutable, - wasProgrammedByPumpUI: suspend.wasProgrammedByPumpUI - )) - lastSuspend = nil - } - - lastBasal = dose - case .resume: - if let suspend = lastSuspend { - - reconciled.append(DoseEntry( - type: suspend.type, - startDate: suspend.startDate, - endDate: dose.startDate, - value: suspend.value, - unit: suspend.unit, - description: suspend.description ?? dose.description, - syncIdentifier: suspend.syncIdentifier, - insulinType: suspend.insulinType, - automatic: suspend.automatic, - isMutable: suspend.isMutable, - wasProgrammedByPumpUI: suspend.wasProgrammedByPumpUI - )) - - lastSuspend = nil - - // Continue temp basals that may have started before suspending - if let last = lastBasal { - if last.endDate > dose.endDate { - lastBasal = DoseEntry( - type: last.type, - startDate: dose.endDate, - endDate: last.endDate, - value: last.value, - unit: last.unit, - description: last.description, - // We intentionally use the resume's identifier, as the basal entry has already been entered - syncIdentifier: dose.syncIdentifier, - insulinType: last.insulinType, - automatic: last.automatic, - isMutable: last.isMutable, - wasProgrammedByPumpUI: last.wasProgrammedByPumpUI - ) - } else { - lastBasal = nil - } - } - } - case .suspend: - if let last = lastBasal { - - reconciled.append(DoseEntry( - type: last.type, - startDate: last.startDate, - endDate: Swift.min(last.endDate, dose.startDate), - value: last.value, - unit: last.unit, - description: last.description, - syncIdentifier: last.syncIdentifier, - insulinType: last.insulinType, - automatic: last.automatic, - isMutable: last.isMutable, - wasProgrammedByPumpUI: last.wasProgrammedByPumpUI - )) - - if last.endDate <= dose.startDate { - lastBasal = nil - } - } - - lastSuspend = dose - } - } - - if let suspend = lastSuspend { - reconciled.append(suspend) - } else if let last = lastBasal, last.endDate > last.startDate { - reconciled.append(last) - } - - return reconciled.map { $0.resolvingDelivery } - } - - /// Annotates a sequence of dose entries with the configured basal rate schedule. - /// - /// Doses which cross time boundaries in the basal rate schedule are split into multiple entries. - /// - /// - Parameter basalSchedule: The basal rate schedule - /// - Returns: An array of annotated dose entries - func annotated(with basalSchedule: BasalRateSchedule) -> [DoseEntry] { - var annotatedDoses: [DoseEntry] = [] - - for dose in self { - annotatedDoses += dose.annotated(with: basalSchedule) - } - - return annotatedDoses - } - - /** - Calculates the total insulin delivery for a collection of doses - - - returns: The total insulin insulin, in Units - */ - var totalDelivery: Double { - return reduce(0) { (total, dose) -> Double in - return total + dose.unitsInDeliverableIncrements - } - } - - /** - Calculates the timeline of insulin remaining for a collection of doses - - - parameter insulinModelProvider: A factory that can provide an insulin model given an insulin type - - parameter longestEffectDuration: The longest duration that a dose could be active. - - parameter start: The date to start the timeline - - parameter end: The date to end the timeline - - parameter delta: The differential between timeline entries - - - returns: A sequence of insulin amount remaining - */ - func insulinOnBoard( - insulinModelProvider: InsulinModelProvider, - longestEffectDuration: TimeInterval, - from start: Date? = nil, - to end: Date? = nil, - delta: TimeInterval = TimeInterval(minutes: 5) - ) -> [InsulinValue] { - guard let (start, end) = LoopMath.simulationDateRangeForSamples(self, from: start, to: end, duration: longestEffectDuration, delta: delta) else { - return [] - } - - var date = start - var values = [InsulinValue]() - - repeat { - let value = reduce(0) { (value, dose) -> Double in - return value + dose.insulinOnBoard(at: date, model: insulinModelProvider.model(for: dose.insulinType), delta: delta) - } - - values.append(InsulinValue(startDate: date, value: value)) - date = date.addingTimeInterval(delta) - } while date <= end - - return values - } - - /// Calculates the timeline of glucose effects for a collection of doses - /// - /// - Parameters: - /// - insulinModelProvider: A factory that can provide an insulin model given an insulin type - /// - longestEffectDuration: The longest duration that a dose could be active. - /// - insulinSensitivity: The schedule of glucose effect per unit of insulin - /// - start: The earliest date of effects to return - /// - end: The latest date of effects to return - /// - delta: The interval between returned effects - /// - Returns: An array of glucose effects for the duration of the doses - public func glucoseEffects( - insulinModelProvider: InsulinModelProvider, - longestEffectDuration: TimeInterval, - insulinSensitivity: InsulinSensitivitySchedule, - from start: Date? = nil, - to end: Date? = nil, - delta: TimeInterval = TimeInterval(/* minutes: */60 * 5) - ) -> [GlucoseEffect] { - guard let (start, end) = LoopMath.simulationDateRangeForSamples(self.filter({ entry in - entry.netBasalUnits != 0 - }), from: start, to: end, duration: longestEffectDuration, delta: delta) else { - return [] - } - - var date = start - var values = [GlucoseEffect]() - let unit = HKUnit.milligramsPerDeciliter - - repeat { - let value = reduce(0) { (value, dose) -> Double in - return value + dose.glucoseEffect(at: date, model: insulinModelProvider.model(for: dose.insulinType), insulinSensitivity: insulinSensitivity.quantity(at: dose.startDate).doubleValue(for: unit), delta: delta) - } - - values.append(GlucoseEffect(startDate: date, quantity: HKQuantity(unit: unit, doubleValue: value))) - date = date.addingTimeInterval(delta) - } while date <= end - - return values - } - - /// Applies the current basal schedule to a collection of reconciled doses in chronological order - /// - /// The scheduled basal rate is associated doses that override it, for later derivation of net delivery - /// - /// - Parameters: - /// - basalSchedule: The active basal schedule during the dose delivery - /// - start: The earliest date to apply the basal schedule - /// - end: The latest date to include. Doses must end before this time to be included. - /// - insertingBasalEntries: Whether basal doses should be created from the schedule. Pass true only for pump models that do not report their basal rates in event history. - /// - Returns: An array of doses, - func overlayBasalSchedule(_ basalSchedule: BasalRateSchedule, startingAt start: Date, endingAt end: Date = .distantFuture, insertingBasalEntries: Bool) -> [DoseEntry] { - let dateFormatter = ISO8601DateFormatter() // GMT-based ISO formatting - var newEntries = [DoseEntry]() - var lastBasal: DoseEntry? - - if insertingBasalEntries { - // Create a placeholder entry at our start date, so we know the correct duration of the - // inserted basal entries - lastBasal = DoseEntry(resumeDate: start, automatic: true) - } - - for dose in self { - switch dose.type { - case .tempBasal, .basal, .suspend: - // Only include entries if they have ended by the end date, since they may be cancelled - guard dose.endDate <= end else { - continue - } - - if let lastBasal = lastBasal { - if insertingBasalEntries { - // For older pumps which don't report the start/end of scheduled basal delivery, - // generate a basal entry from the specified schedule. - for scheduled in basalSchedule.between(start: lastBasal.endDate, end: dose.startDate) { - // Generate a unique identifier based on the start/end timestamps - let start = Swift.max(lastBasal.endDate, scheduled.startDate) - let end = Swift.min(dose.startDate, scheduled.endDate) - - guard end.timeIntervalSince(start) > .ulpOfOne else { - continue - } - - let syncIdentifier = "BasalRateSchedule \(dateFormatter.string(from: start)) \(dateFormatter.string(from: end))" - - newEntries.append(DoseEntry( - type: .basal, - startDate: start, - endDate: end, - value: scheduled.value, - unit: .unitsPerHour, - syncIdentifier: syncIdentifier, - scheduledBasalRate: HKQuantity(unit: .internationalUnitsPerHour, doubleValue: scheduled.value), - insulinType: lastBasal.insulinType, - automatic: lastBasal.automatic - )) - } - } - } - - lastBasal = dose - - // Only include the last basal entry if has ended by our end date - if let lastBasal = lastBasal { - newEntries.append(lastBasal) - } - case .resume: - assertionFailure("No resume events should be present in reconciled doses") - case .bolus: - newEntries.append(dose) - } - } - - return newEntries - } - - /// Creates an array of DoseEntry values by unioning another array, de-duplicating by syncIdentifier - /// - /// - Parameter otherDoses: An array of doses to union - /// - Returns: A new array of doses - func appendedUnion(with otherDoses: [DoseEntry]) -> [DoseEntry] { - var union: [DoseEntry] = [] - var syncIdentifiers: Set = [] - - for dose in (self + otherDoses) { - if let syncIdentifier = dose.syncIdentifier { - let (inserted, _) = syncIdentifiers.insert(syncIdentifier) - if !inserted { - continue - } - } - - union.append(dose) - } - - return union - } -} - - -extension BidirectionalCollection where Element == DoseEntry { - /// The endDate of the last basal dose in the collection - var lastBasalEndDate: Date? { - for dose in self.reversed() { - if dose.type == .basal || dose.type == .tempBasal || dose.type == .resume { - return dose.endDate - } - } - - return nil - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinModel.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinModel.swift deleted file mode 100644 index 00eca9913..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinModel.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// InsulinModel.swift -// LoopKit -// -// Created by Pete Schwamb on 7/26/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation - - -public protocol InsulinModel: CustomDebugStringConvertible { - - /// Returns the percentage of total insulin effect remaining at a specified interval after delivery; also known as Insulin On Board (IOB). - /// Return value is within the range of 0-1 - /// - /// - Parameters: - /// - time: The interval after insulin delivery - func percentEffectRemaining(at time: TimeInterval) -> Double - - /// The expected duration, including any effect delay, of an insulin dose, from the time of the dose - var effectDuration: TimeInterval { get } - - /// The time after the dose where the effect becomes non-zero - var delay: TimeInterval { get } -} - - diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinType.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinType.swift deleted file mode 100644 index c75a73b23..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinType.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// InsulinType.swift -// LoopKit -// -// Created by Anna Quinlan on 12/8/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum InsulinType: Int, Codable, CaseIterable { - case novolog - case humalog - case apidra - case fiasp - case lyumjev - case afrezza - - public var title: String { - switch self { - case .novolog: - return LocalizedString("Novolog (insulin aspart)", comment: "Title for Novolog insulin type") - case .humalog: - return LocalizedString("Humalog (insulin lispro)", comment: "Title for Humalog insulin type") - case .apidra: - return LocalizedString("Apidra (insulin glulisine)", comment: "Title for Apidra insulin type") - case .fiasp: - return LocalizedString("Fiasp", comment: "Title for Fiasp insulin type") - case .lyumjev: - return LocalizedString("Lyumjev", comment: "Title for Lyumjev insulin type") - case .afrezza: - return LocalizedString("Afrezza", comment: "Title for Afrezza insulin type") - } - } - - public var brandName: String { - switch self { - case .novolog: - return LocalizedString("Novolog", comment: "Brand name for novolog insulin type") - case .humalog: - return LocalizedString("Humalog", comment: "Brand name for humalog insulin type") - case .apidra: - return LocalizedString("Apidra", comment: "Brand name for apidra insulin type") - case .fiasp: - return LocalizedString("Fiasp", comment: "Brand name for fiasp insulin type") - case .lyumjev: - return LocalizedString("Lyumjev", comment: "Brand name for lyumjev insulin type") - case .afrezza: - return LocalizedString("Afrezza", comment: "Brand name for afrezza insulin type") - } - } - - public var description: String { - switch self { - case .novolog: - return LocalizedString("NovoLog (insulin aspart) is a rapid-acting insulin made by Novo Nordisk", comment: "Description for novolog insulin type") - case .humalog: - return LocalizedString("Humalog (insulin lispro) is a rapid-acting insulin made by Eli Lilly", comment: "Description for humalog insulin type") - case .apidra: - return LocalizedString("Apidra (insulin glulisine) is a rapid-acting insulin made by Sanofi-aventis ", comment: "Description for apidra insulin type") - case .fiasp: - return LocalizedString("Fiasp is a mealtime insulin aspart formulation with the addition of nicotinamide (vitamin B3) made by Novo Nordisk", comment: "Description for fiasp insulin type") - case .lyumjev: - return LocalizedString("Lyumjev is a mealtime insulin lispro formulation with the addition of citrate and treprostinil made by Eli Lilly", comment: "Description for lyumjev insulin type") - case .afrezza: - return LocalizedString("Afrezza is an ultra rapid-acting mealtime insulin that is breathed in through your lungs using an oral inhaler and made by MannKind", comment: "Description for afrezza insulin type") - } - } - - public var pumpAdministerable: Bool { - switch self { - case .afrezza: - return false - default: - return true - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinValue.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinValue.swift deleted file mode 100644 index 1fba5d829..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/InsulinValue.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// InsulinValue.swift -// LoopKit -// -// Created by Nathan Racklyeft on 4/3/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public struct InsulinValue: TimelineValue, Equatable { - public let startDate: Date - public let value: Double - - public init(startDate: Date, value: Double) { - self.startDate = startDate - self.value = value - } -} - -extension InsulinValue: Codable {} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/ManualBolusRecommendation.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/ManualBolusRecommendation.swift deleted file mode 100644 index 7989853cd..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/ManualBolusRecommendation.swift +++ /dev/null @@ -1,102 +0,0 @@ -// -// ManualBolusRecommendation.swift -// LoopKit -// -// Created by Pete Schwamb on 1/2/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - -public enum BolusRecommendationNotice { - case glucoseBelowSuspendThreshold(minGlucose: GlucoseValue) - case currentGlucoseBelowTarget(glucose: GlucoseValue) - case predictedGlucoseBelowTarget(minGlucose: GlucoseValue) - case predictedGlucoseInRange - case allGlucoseBelowTarget(minGlucose: GlucoseValue) -} - -extension BolusRecommendationNotice: Codable { - public init(from decoder: Decoder) throws { - if let string = try? decoder.singleValueContainer().decode(String.self) { - switch string { - case CodableKeys.predictedGlucoseInRange.rawValue: - self = .predictedGlucoseInRange - default: - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "invalid enumeration")) - } - } else { - let container = try decoder.container(keyedBy: CodableKeys.self) - if let glucoseBelowSuspendThreshold = try container.decodeIfPresent(GlucoseBelowSuspendThreshold.self, forKey: .glucoseBelowSuspendThreshold) { - self = .glucoseBelowSuspendThreshold(minGlucose: glucoseBelowSuspendThreshold.minGlucose) - } else if let currentGlucoseBelowTarget = try container.decodeIfPresent(CurrentGlucoseBelowTarget.self, forKey: .currentGlucoseBelowTarget) { - self = .currentGlucoseBelowTarget(glucose: currentGlucoseBelowTarget.glucose) - } else if let predictedGlucoseBelowTarget = try container.decodeIfPresent(PredictedGlucoseBelowTarget.self, forKey: .predictedGlucoseBelowTarget) { - self = .predictedGlucoseBelowTarget(minGlucose: predictedGlucoseBelowTarget.minGlucose) - } else if let allGlucoseBelowTarget = try container.decodeIfPresent(AllGlucoseBelowTarget.self, forKey: .allGlucoseBelowTarget) { - self = .allGlucoseBelowTarget(minGlucose: allGlucoseBelowTarget.minGlucose) - } else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "invalid enumeration")) - } - } - } - - public func encode(to encoder: Encoder) throws { - switch self { - case .glucoseBelowSuspendThreshold(let minGlucose): - var container = encoder.container(keyedBy: CodableKeys.self) - try container.encode(GlucoseBelowSuspendThreshold(minGlucose: SimpleGlucoseValue(minGlucose)), forKey: .glucoseBelowSuspendThreshold) - case .currentGlucoseBelowTarget(let glucose): - var container = encoder.container(keyedBy: CodableKeys.self) - try container.encode(CurrentGlucoseBelowTarget(glucose: SimpleGlucoseValue(glucose)), forKey: .currentGlucoseBelowTarget) - case .predictedGlucoseBelowTarget(let minGlucose): - var container = encoder.container(keyedBy: CodableKeys.self) - try container.encode(PredictedGlucoseBelowTarget(minGlucose: SimpleGlucoseValue(minGlucose)), forKey: .predictedGlucoseBelowTarget) - case .predictedGlucoseInRange: - var container = encoder.singleValueContainer() - try container.encode(CodableKeys.predictedGlucoseInRange.rawValue) - case .allGlucoseBelowTarget(minGlucose: let minGlucose): - var container = encoder.container(keyedBy: CodableKeys.self) - try container.encode(AllGlucoseBelowTarget(minGlucose: SimpleGlucoseValue(minGlucose)), forKey: .allGlucoseBelowTarget) - } - } - - private struct GlucoseBelowSuspendThreshold: Codable { - let minGlucose: SimpleGlucoseValue - } - - private struct CurrentGlucoseBelowTarget: Codable { - let glucose: SimpleGlucoseValue - } - - private struct PredictedGlucoseBelowTarget: Codable { - let minGlucose: SimpleGlucoseValue - } - - private struct AllGlucoseBelowTarget: Codable { - let minGlucose: SimpleGlucoseValue - } - - private enum CodableKeys: String, CodingKey { - case glucoseBelowSuspendThreshold - case currentGlucoseBelowTarget - case predictedGlucoseBelowTarget - case predictedGlucoseInRange - case allGlucoseBelowTarget - } -} - -public struct ManualBolusRecommendation { - public let amount: Double - public let pendingInsulin: Double - public var notice: BolusRecommendationNotice? - - public init(amount: Double, pendingInsulin: Double, notice: BolusRecommendationNotice? = nil) { - self.amount = amount - self.pendingInsulin = pendingInsulin - self.notice = notice - } -} - -extension ManualBolusRecommendation: Codable {} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/NewPumpEvent.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/NewPumpEvent.swift deleted file mode 100644 index 0fca3378a..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/NewPumpEvent.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// NewPumpEvent.swift -// LoopKit -// -// Created by Nate Racklyeft on 8/1/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public struct NewPumpEvent: Equatable { - /// The date of the event - public let date: Date - /// The insulin dose described by the event, if applicable - public let dose: DoseEntry? - /// The opaque raw data representing the event - public let raw: Data - /// The type of pump event - public let type: PumpEventType? - /// A human-readable title to describe the event - public let title: String - /// The type of alarm, only valid if type == .alarm - public let alarmType: PumpAlarmType? - - public init(date: Date, dose: DoseEntry?, raw: Data, title: String, type: PumpEventType? = nil, alarmType: PumpAlarmType? = nil) { - self.date = date - self.raw = raw - self.title = title - - var dose = dose - // Use the raw data as the unique identifier for the dose - dose?.syncIdentifier = raw.hexadecimalString - self.dose = dose - - // Try to use the dose's type if no explicit type was set - self.type = type ?? dose?.type.pumpEventType - - self.alarmType = alarmType - } -} - -extension NewPumpEvent: RawRepresentable { - public typealias RawValue = [String: Any] - - public init?(rawValue: [String: Any]) { - guard let date = rawValue["date"] as? Date, - let raw = rawValue["raw"] as? Data, - let title = rawValue["title"] as? String - else { - return nil - } - - self.date = date - self.raw = raw - self.title = title - - self.dose = (rawValue["dose"] as? DoseEntry.RawValue).flatMap { DoseEntry(rawValue: $0) } - self.type = (rawValue["type"] as? PumpEventType.RawValue).flatMap { PumpEventType(rawValue: $0) } - self.alarmType = (rawValue["alarmType"] as? PumpAlarmType.RawValue).flatMap { PumpAlarmType(rawValue: $0) } - } - - public var rawValue: [String: Any] { - var rawValue: [String: Any] = [ - "date": date, - "raw": raw, - "title": title - ] - - rawValue["dose"] = dose?.rawValue - rawValue["type"] = type?.rawValue - rawValue["alarmType"] = alarmType?.rawValue - - return rawValue - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/PersistedPumpEvent.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/PersistedPumpEvent.swift deleted file mode 100644 index 22a1f627f..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/PersistedPumpEvent.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// PersistedPumpEvent.swift -// LoopKit -// -// Created by Nate Racklyeft on 8/1/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public struct PersistedPumpEvent { - /// The date of the event - public let date: Date - /// The date the event was persisted - public let persistedDate: Date - /// The insulin dose described by the event, if applicable - public let dose: DoseEntry? - /// Whether the event has been successfully uploaded - public let isUploaded: Bool - /// The NSManagedObject identifier of the event used by the store - public let objectIDURL: URL - /// The opaque raw data representing the event - public let raw: Data? - /// A human-readable short description of the event - public let title: String? - /// The type of pump event - public let type: PumpEventType? - /// Whether the pump event is marked mutable - public let automatic: Bool? - /// The type of alarm, only valid if type == .alarm - public let alarmType: PumpAlarmType? - - public init(date: Date, - persistedDate: Date, - dose: DoseEntry?, - isUploaded: Bool, - objectIDURL: URL, - raw: Data?, - title: String?, - type: PumpEventType?, - automatic: Bool? = nil, - alarmType: PumpAlarmType? = nil) { - self.date = date - self.persistedDate = persistedDate - self.dose = dose - self.isUploaded = isUploaded - self.objectIDURL = objectIDURL - self.raw = raw - self.title = title - self.type = type - self.automatic = automatic - self.alarmType = alarmType - } -} - - -extension PumpEvent { - var persistedPumpEvent: PersistedPumpEvent { - return PersistedPumpEvent( - date: date, - persistedDate: createdAt, - dose: dose, - isUploaded: isUploaded, - objectIDURL: objectID.uriRepresentation(), - raw: raw, - title: title, - type: type, - automatic: automatic, - alarmType: alarmType - ) - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/PumpAlarmType.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/PumpAlarmType.swift deleted file mode 100644 index 4318cb480..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/PumpAlarmType.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// PumpAlarmType.swift -// LoopKit -// -// Created by Darin Krauss on 1/10/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum PumpAlarmType: Equatable, Codable { - case autoOff - case lowInsulin - case lowPower - case noDelivery - case noInsulin - case noPower - case occlusion - case other(_ details: String) -} - -extension PumpAlarmType: RawRepresentable { - public typealias RawValue = String - - public init(rawValue: String) { - switch rawValue { - case "autoOff": - self = .autoOff - case "lowInsulin": - self = .lowInsulin - case "lowPower": - self = .lowPower - case "noDelivery": - self = .noDelivery - case "noInsulin": - self = .noInsulin - case "noPower": - self = .noPower - case "occlusion": - self = .occlusion - default: - self = .other(rawValue) - } - } - - public var rawValue: String { - switch self { - case .autoOff: - return "autoOff" - case .lowInsulin: - return "lowInsulin" - case .lowPower: - return "lowPower" - case .noDelivery: - return "noDelivery" - case .noInsulin: - return "noInsulin" - case .noPower: - return "noPower" - case .occlusion: - return "occlusion" - case .other(let details): - return details - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/PumpEvent+CoreDataClass.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/PumpEvent+CoreDataClass.swift deleted file mode 100644 index 15437a7f0..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/PumpEvent+CoreDataClass.swift +++ /dev/null @@ -1,250 +0,0 @@ -// -// PumpEvent.swift -// LoopKit -// -// Created by Nathan Racklyeft on 3/28/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import CoreData - - -class PumpEvent: NSManagedObject { - - var doseType: DoseType? { - get { - willAccessValue(forKey: "doseType") - defer { didAccessValue(forKey: "doseType") } - return DoseType(rawValue: primitiveDoseType ?? "") - } - set { - willChangeValue(forKey: "doseType") - defer { didChangeValue(forKey: "doseType") } - primitiveDoseType = newValue?.rawValue - } - } - - var duration: TimeInterval! { - get { - willAccessValue(forKey: "duration") - defer { didAccessValue(forKey: "duration") } - return primitiveDuration?.doubleValue - } - set { - willChangeValue(forKey: "duration") - defer { didChangeValue(forKey: "duration") } - primitiveDuration = newValue != nil ? NSNumber(value: newValue) : nil - } - } - - var unit: DoseUnit? { - get { - willAccessValue(forKey: "unit") - defer { didAccessValue(forKey: "unit") } - return DoseUnit(rawValue: primitiveUnit ?? "") - } - set { - willChangeValue(forKey: "unit") - defer { didChangeValue(forKey: "unit") } - primitiveUnit = newValue?.rawValue - } - } - - var insulinType: InsulinType? { - get { - willAccessValue(forKey: "insulinType") - defer { didAccessValue(forKey: "insulinType") } - guard let type = primitiveInsulinType else { - return nil - } - return InsulinType(rawValue: type.intValue) - } - set { - willChangeValue(forKey: "insulinType") - defer { didChangeValue(forKey: "insulinType") } - primitiveInsulinType = newValue != nil ? NSNumber(value: newValue!.rawValue) : nil - } - } - - var type: PumpEventType? { - get { - willAccessValue(forKey: "type") - defer { didAccessValue(forKey: "type") } - return PumpEventType(rawValue: primitiveType ?? "") - } - set { - willChangeValue(forKey: "type") - defer { didChangeValue(forKey: "type") } - primitiveType = newValue?.rawValue - } - } - - var uploaded: Bool { - get { - willAccessValue(forKey: "uploaded") - defer { didAccessValue(forKey: "uploaded") } - return primitiveUploaded?.boolValue ?? false - } - set { - willChangeValue(forKey: "uploaded") - defer { didChangeValue(forKey: "uploaded") } - primitiveUploaded = NSNumber(value: newValue) - } - } - - var value: Double? { - get { - willAccessValue(forKey: "value") - defer { didAccessValue(forKey: "value") } - return primitiveValue?.doubleValue - } - set { - willChangeValue(forKey: "value") - defer { didChangeValue(forKey: "value") } - primitiveValue = newValue != nil ? NSNumber(value: newValue!) : nil - } - } - - var automatic: Bool? { - get { - willAccessValue(forKey: "automatic") - defer { didAccessValue(forKey: "automatic") } - return primitiveAutomatic?.boolValue - } - set { - willChangeValue(forKey: "automatic") - defer { didChangeValue(forKey: "automatic") } - primitiveAutomatic = newValue != nil ? NSNumber(booleanLiteral: newValue!) : nil - } - } - - var deliveredUnits: Double? { - get { - willAccessValue(forKey: "deliveredUnits") - defer { didAccessValue(forKey: "deliveredUnits") } - return primitiveDeliveredUnits?.doubleValue - } - set { - willChangeValue(forKey: "deliveredUnits") - defer { didChangeValue(forKey: "deliveredUnits") } - primitiveDeliveredUnits = newValue != nil ? NSNumber(value: newValue!) : nil - } - } - - var alarmType: PumpAlarmType? { - get { - willAccessValue(forKey: "alarmType") - defer { didAccessValue(forKey: "alarmType") } - return primitiveAlarmType.map { PumpAlarmType(rawValue: $0) } - } - set { - willChangeValue(forKey: "alarmType") - defer { didChangeValue(forKey: "alarmType") } - primitiveAlarmType = newValue?.rawValue - } - } - - var hasUpdatedModificationCounter: Bool { changedValues().keys.contains("modificationCounter") } - - func updateModificationCounter() { setPrimitiveValue(managedObjectContext!.modificationCounter!, forKey: "modificationCounter") } - - public override func awakeFromInsert() { - super.awakeFromInsert() - updateModificationCounter() - createdAt = Date() - } - - public override func willSave() { - if isUpdated && !hasUpdatedModificationCounter { - updateModificationCounter() - } - super.willSave() - } - -} - - -extension PumpEvent: TimelineValue { - var startDate: Date { - get { - return date - } - set { - date = newValue - } - } - - var endDate: Date { - get { - return date.addingTimeInterval(duration) - } - set { - duration = newValue.timeIntervalSince(startDate) - } - } -} - - -extension PumpEvent { - var dose: DoseEntry? { - get { - // To handle migration, we're requiring any dose to also have a PumpEventType - guard let type = type, let value = value, let unit = unit else { - return nil - } - - return DoseEntry( - type: doseType ?? DoseType(pumpEventType: type)!, - startDate: startDate, - endDate: endDate, - value: value, - unit: unit, - deliveredUnits: deliveredUnits, - syncIdentifier: syncIdentifier, - insulinType: insulinType, - automatic: automatic, - isMutable: mutable, - wasProgrammedByPumpUI: wasProgrammedByPumpUI - ) - } - set { - guard let entry = newValue else { - return - } - - doseType = entry.type - startDate = entry.startDate - endDate = entry.endDate - value = entry.value - unit = entry.unit - deliveredUnits = entry.deliveredUnits - insulinType = entry.insulinType - automatic = entry.automatic - mutable = entry.isMutable - wasProgrammedByPumpUI = entry.wasProgrammedByPumpUI - } - } - - var syncIdentifier: String? { - return raw?.hexadecimalString - } - - var isUploaded: Bool { - return uploaded - } -} - -extension PumpEvent { - func update(from event: PersistedPumpEvent) { - createdAt = event.persistedDate - date = event.date - type = event.type - uploaded = event.isUploaded - raw = event.raw - title = event.title - dose = event.dose - automatic = event.automatic - alarmType = event.alarmType - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/PumpEvent+CoreDataProperties.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/PumpEvent+CoreDataProperties.swift deleted file mode 100644 index 55e86d90f..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/PumpEvent+CoreDataProperties.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// PumpEvent+CoreDataProperties.swift -// LoopKit -// -// Created by Nate Racklyeft on 8/1/16. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation -import CoreData - - -extension PumpEvent { - - @nonobjc class func fetchRequest() -> NSFetchRequest { - return NSFetchRequest(entityName: "PumpEvent") - } - - @NSManaged var createdAt: Date! - @NSManaged var date: Date! - @NSManaged var primitiveDoseType: String? - @NSManaged var primitiveDuration: NSNumber? - @NSManaged var primitiveType: String? - @NSManaged var primitiveUnit: String? - @NSManaged var primitiveUploaded: NSNumber? - @NSManaged var primitiveValue: NSNumber? - @NSManaged var primitiveDeliveredUnits: NSNumber? - @NSManaged var mutable: Bool - @NSManaged var raw: Data? - @NSManaged var title: String? - @NSManaged var primitiveInsulinType: NSNumber? - @NSManaged var primitiveAutomatic: NSNumber? - @NSManaged var primitiveAlarmType: String? - @NSManaged var modificationCounter: Int64 - @NSManaged var wasProgrammedByPumpUI: Bool -} - -extension PumpEvent: Encodable { - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(createdAt, forKey: .createdAt) - try container.encode(date, forKey: .date) - try container.encodeIfPresent(doseType?.rawValue, forKey: .doseType) - try container.encode(duration, forKey: .duration) - try container.encodeIfPresent(type?.rawValue, forKey: .type) - try container.encodeIfPresent(unit?.rawValue, forKey: .unit) - try container.encode(uploaded, forKey: .uploaded) - try container.encodeIfPresent(value, forKey: .value) - try container.encodeIfPresent(deliveredUnits, forKey: .deliveredUnits) - try container.encode(mutable, forKey: .mutable) - try container.encodeIfPresent(raw?.base64EncodedString(), forKey: .raw) - try container.encodeIfPresent(title, forKey: .title) - try container.encodeIfPresent(insulinType, forKey: .insulinType) - try container.encodeIfPresent(automatic, forKey: .automatic) - try container.encodeIfPresent(alarmType?.rawValue, forKey: .alarmType) - try container.encode(modificationCounter, forKey: .modificationCounter) - try container.encode(wasProgrammedByPumpUI, forKey: .wasProgrammedByPumpUI) - } - - private enum CodingKeys: String, CodingKey { - case createdAt - case date - case doseType - case duration - case type - case unit - case uploaded - case value - case deliveredUnits - case mutable - case raw - case title - case insulinType - case automatic - case alarmType - case modificationCounter - case wasProgrammedByPumpUI - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/PumpEventType.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/PumpEventType.swift deleted file mode 100644 index 80138b3ed..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/PumpEventType.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// PumpEventType.swift -// LoopKit -// -// Created by Nathan Racklyeft on 3/28/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -/// A subset of pump event types, with raw values matching decocare's strings -public enum PumpEventType: String, CaseIterable { - case alarm = "AlarmPump" - case alarmClear = "ClearAlarm" - case basal = "BasalProfileStart" - case bolus = "Bolus" - case prime = "Prime" - case resume = "PumpResume" - case rewind = "Rewind" - case suspend = "PumpSuspend" - case tempBasal = "TempBasal" -} - - -extension PumpEventType { - /// Provides an ordering between types used for stable, chronological sorting for doses that share the same date. - var sortOrder: Int { - switch self { - case .bolus: - return 1 - // An alarm should happen before a clear - case .alarm: - return 2 - case .alarmClear: - return 3 - // A rewind should happen before a prime - case .rewind: - return 4 - case .prime: - return 5 - // A suspend should always happen before a resume - case .suspend: - return 6 - // A resume should happen before basal delivery begins - case .resume: - return 7 - // A 0-second temporary basal cancelation should happen before schedule basal delivery - case .tempBasal: - return 8 - case .basal: - return 9 - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/Reservoir+CoreDataProperties.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/Reservoir+CoreDataProperties.swift deleted file mode 100644 index 779a1f8ab..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/Reservoir+CoreDataProperties.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// Reservoir+CoreDataProperties.swift -// LoopKit -// -// Created by Nathan Racklyeft on 1/30/16. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation -import CoreData - - -extension Reservoir { - - @nonobjc class func fetchRequest() -> NSFetchRequest { - return NSFetchRequest(entityName: "Reservoir") - } - - @NSManaged var createdAt: Date! - @NSManaged var date: Date! - @NSManaged var primitiveVolume: NSNumber? - @NSManaged var raw: Data? - -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/Reservoir.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/Reservoir.swift deleted file mode 100644 index 6427e47b4..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/Reservoir.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// Reservoir.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/29/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import CoreData - - -class Reservoir: NSManagedObject { - - var volume: Double! { - get { - willAccessValue(forKey: "volume") - defer { didAccessValue(forKey: "volume") } - return primitiveVolume?.doubleValue - } - set { - willChangeValue(forKey: "volume") - defer { didChangeValue(forKey: "volume") } - primitiveVolume = newValue != nil ? NSNumber(value: newValue) : nil - } - } - - override func awakeFromInsert() { - super.awakeFromInsert() - - createdAt = Date() - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/ReservoirValue.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/ReservoirValue.swift deleted file mode 100644 index a5cd09fcb..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/ReservoirValue.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// ReservoirValue.swift -// LoopKit -// -// Created by Nate Racklyeft on 8/1/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import CoreData - - -public protocol ReservoirValue: TimelineValue { - var startDate: Date { get } - var unitVolume: Double { get } -} - - -struct StoredReservoirValue: ReservoirValue { - let startDate: Date - let unitVolume: Double - let objectIDURL: URL -} - - -extension Reservoir: ReservoirValue { - var startDate: Date { - return date - } - - var unitVolume: Double { - return volume - } - - var storedReservoirValue: StoredReservoirValue { - return StoredReservoirValue(startDate: startDate, unitVolume: unitVolume, objectIDURL: objectID.uriRepresentation()) - } -} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/TempBasalRecommendation.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/TempBasalRecommendation.swift deleted file mode 100644 index 8029b0285..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/TempBasalRecommendation.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// TempBasalRecommendation.swift -// LoopKit -// -// Created by Darin Krauss on 5/21/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct TempBasalRecommendation: Equatable { - public let unitsPerHour: Double - public let duration: TimeInterval - - /// A special command which cancels any existing temp basals - public static var cancel: TempBasalRecommendation { - return self.init(unitsPerHour: 0, duration: 0) - } - - public init(unitsPerHour: Double, duration: TimeInterval) { - self.unitsPerHour = unitsPerHour - self.duration = duration - } -} - -extension TempBasalRecommendation: Codable {} diff --git a/Dependencies/LoopKit/LoopKit/InsulinKit/WalshInsulinModel.swift b/Dependencies/LoopKit/LoopKit/InsulinKit/WalshInsulinModel.swift deleted file mode 100644 index 086bb20f6..000000000 --- a/Dependencies/LoopKit/LoopKit/InsulinKit/WalshInsulinModel.swift +++ /dev/null @@ -1,124 +0,0 @@ -// -// WalshInsulinModel.swift -// InsulinKit -// -// Created by Pete Schwamb on 7/30/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct WalshInsulinModel { - public let actionDuration: TimeInterval - public let delay: TimeInterval - - public init(actionDuration: TimeInterval, delay: TimeInterval = 600) { - self.actionDuration = actionDuration - self.delay = delay - } -} - -extension WalshInsulinModel: InsulinModel { - public var effectDuration: TimeInterval { - return self.actionDuration + self.delay - } - - /// Returns the percentage of total insulin effect remaining at a specified interval after delivery; - /// also known as Insulin On Board (IOB). - /// - /// These are 4th-order polynomial fits of John Walsh's IOB curve plots, and they first appeared in GlucoDyn. - /// - /// See: https:github.com/kenstack/GlucoDyn - /// - /// - Parameter time: The interval after insulin delivery - /// - Returns: The percentage of total insulin effect remaining - public func percentEffectRemaining(at time: TimeInterval) -> Double { - let timeAfterDelay = time - delay - switch timeAfterDelay { - case let t where t <= 0: - return 1 - case let t where t >= actionDuration: - return 0 - default: - // We only have Walsh models for a few discrete action durations, so we scale other action durations appropriately to the nearest one. - let nearestModeledDuration: TimeInterval - - switch actionDuration { - case let x where x < TimeInterval(hours: 3): - nearestModeledDuration = TimeInterval(hours: 3) - case let x where x > TimeInterval(hours: 6): - nearestModeledDuration = TimeInterval(hours: 6) - default: - nearestModeledDuration = TimeInterval(hours: round(actionDuration.hours)) - } - - let minutes = timeAfterDelay.minutes * nearestModeledDuration / actionDuration - - switch nearestModeledDuration { - case TimeInterval(hours: 3): - return -3.2030e-9 * pow(minutes, 4) + 1.354e-6 * pow(minutes, 3) - 1.759e-4 * pow(minutes, 2) + 9.255e-4 * minutes + 0.99951 - case TimeInterval(hours: 4): - return -3.310e-10 * pow(minutes, 4) + 2.530e-7 * pow(minutes, 3) - 5.510e-5 * pow(minutes, 2) - 9.086e-4 * minutes + 0.99950 - case TimeInterval(hours: 5): - return -2.950e-10 * pow(minutes, 4) + 2.320e-7 * pow(minutes, 3) - 5.550e-5 * pow(minutes, 2) + 4.490e-4 * minutes + 0.99300 - case TimeInterval(hours: 6): - return -1.493e-10 * pow(minutes, 4) + 1.413e-7 * pow(minutes, 3) - 4.095e-5 * pow(minutes, 2) + 6.365e-4 * minutes + 0.99700 - default: - assertionFailure() - return 0 - } - } - } -} - -extension WalshInsulinModel: CustomDebugStringConvertible { - public var debugDescription: String { - return "WalshInsulinModel(actionDuration: \(actionDuration), delay: \(delay))" - } -} - -extension WalshInsulinModel: Equatable { - public static func ==(lhs: WalshInsulinModel, rhs: WalshInsulinModel) -> Bool { - return abs(lhs.actionDuration - rhs.actionDuration) < .ulpOfOne - } -} - -#if swift(>=4) -extension WalshInsulinModel: Codable { - enum CodingKeys: String, CodingKey { - case actionDuration - case delay - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let actionDuration: Double = try container.decode(Double.self, forKey: .actionDuration) - let delay: Double = try container.decode(TimeInterval.self, forKey: .delay) - - self.init(actionDuration: actionDuration, delay: delay) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(actionDuration, forKey: .actionDuration) - try container.encode(delay, forKey: .delay) - } - -} -#endif - -extension WalshInsulinModel: RawRepresentable { - public typealias RawValue = [String: Any] - - public init?(rawValue: RawValue) { - guard let duration = rawValue["actionDuration"] as? TimeInterval else { - return nil - } - - self.init(actionDuration: duration) - } - - public var rawValue: [String : Any] { - return ["actionDuration": self.actionDuration] - } -} diff --git a/Dependencies/LoopKit/LoopKit/JSONStreamEncoder.swift b/Dependencies/LoopKit/LoopKit/JSONStreamEncoder.swift deleted file mode 100644 index 5d474f03d..000000000 --- a/Dependencies/LoopKit/LoopKit/JSONStreamEncoder.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// JSONStreamEncoder.swift -// LoopKit -// -// Created by Darin Krauss on 6/25/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum JSONStreamEncoderError: Error { - case encoderClosed -} - -public class JSONStreamEncoder { - private let stream: OutputStream - private var encoded: Bool - private var closed: Bool - - public init(stream: OutputStream) { - self.stream = stream - self.encoded = false - self.closed = false - } - - public func close() -> Error? { - guard !closed else { - return nil - } - - self.closed = true - - do { - try stream.write(encoded ? "\n]" : "[]") - } catch let error { - return error - } - - return nil - } - - public func encode(_ values: T) throws where T: Collection, T.Element: Encodable { - guard !closed else { - throw JSONStreamEncoderError.encoderClosed - } - - for value in values { - try stream.write(encoded ? ",\n" : "[\n") - try stream.write(try Self.encoder.encode(value)) - encoded = true - } - } - - private static var encoder: JSONEncoder = { - let encoder = JSONEncoder() - if #available(watchOSApplicationExtension 6.0, *) { - encoder.outputFormatting = [.sortedKeys, .withoutEscapingSlashes] - } else { - encoder.outputFormatting = [.sortedKeys] - } - encoder.dateEncodingStrategy = .custom { (date, encoder) in - var encoder = encoder.singleValueContainer() - try encoder.encode(dateFormatter.string(from: date)) - } - return encoder - }() - - private static let dateFormatter: ISO8601DateFormatter = { - var dateFormatter = ISO8601DateFormatter() - dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] - return dateFormatter - }() -} diff --git a/Dependencies/LoopKit/LoopKit/KeychainManager.swift b/Dependencies/LoopKit/LoopKit/KeychainManager.swift deleted file mode 100644 index 89e5b14ff..000000000 --- a/Dependencies/LoopKit/LoopKit/KeychainManager.swift +++ /dev/null @@ -1,352 +0,0 @@ -// -// KeychainManager.swift -// Loop -// -// Created by Nate Racklyeft on 6/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import Security - - -public enum KeychainManagerError: Error { - case add(OSStatus) - case copy(OSStatus) - case delete(OSStatus) - case unknownResult -} - - -/** - - Influenced by https://github.com/marketplacer/keychain-swift - */ -public struct KeychainManager { - typealias Query = [String: NSObject] - - public init() { } - - var accessibility: CFString = kSecAttrAccessibleAfterFirstUnlock - - var accessGroup: String? - - public struct InternetCredentials: Equatable { - public let username: String - public let password: String - public let url: URL - - public init(username: String, password: String, url: URL) { - self.username = username - self.password = password - self.url = url - } - } - - // MARK: - Convenience methods - - private func query(by class: CFString) -> Query { - var query: Query = [kSecClass as String: `class`] - - if let accessGroup = accessGroup { - query[kSecAttrAccessGroup as String] = accessGroup as NSObject? - } - - return query - } - - private func queryForGenericPassword(by service: String) -> Query { - var query = self.query(by: kSecClassGenericPassword) - - query[kSecAttrService as String] = service as NSObject? - - return query - } - - private func queryForInternetPassword(account: String? = nil, url: URL? = nil, label: String? = nil) -> Query { - var query = self.query(by: kSecClassInternetPassword) - - if let account = account { - query[kSecAttrAccount as String] = account as NSObject? - } - - if let url = url, let components = URLComponents(url: url, resolvingAgainstBaseURL: true) { - for (key, value) in components.keychainAttributes { - query[key] = value - } - } - - if let label = label { - query[kSecAttrLabel as String] = label as NSObject? - } - - return query - } - - private func updatedQuery(_ query: Query, withPassword password: Data) throws -> Query { - var query = query - - query[kSecValueData as String] = password as NSObject? - query[kSecAttrAccessible as String] = accessibility - - return query - } - - private func updatedQuery(_ query: Query, withPassword password: String) throws -> Query { - guard let value = password.data(using: String.Encoding.utf8) else { - throw KeychainManagerError.add(errSecDecode) - } - - return try updatedQuery(query, withPassword: value) - } - - func delete(_ query: Query) throws { - let statusCode = SecItemDelete(query as CFDictionary) - - guard statusCode == errSecSuccess || statusCode == errSecItemNotFound else { - throw KeychainManagerError.delete(statusCode) - } - } - - // MARK: – Generic Passwords - - public func deleteGenericPassword(forService service: String) throws { - try delete(queryForGenericPassword(by: service)) - } - - public func replaceGenericPassword(_ password: String?, forService service: String) throws { - var query = queryForGenericPassword(by: service) - - try delete(query) - - guard let password = password else { - return - } - - query = try updatedQuery(query, withPassword: password) - - let statusCode = SecItemAdd(query as CFDictionary, nil) - - guard statusCode == errSecSuccess else { - throw KeychainManagerError.add(statusCode) - } - } - - public func replaceGenericPassword(_ password: Data?, forService service: String) throws { - var query = queryForGenericPassword(by: service) - - try delete(query) - - guard let password = password else { - return - } - - query = try updatedQuery(query, withPassword: password) - - let statusCode = SecItemAdd(query as CFDictionary, nil) - - guard statusCode == errSecSuccess else { - throw KeychainManagerError.add(statusCode) - } - } - - public func getGenericPasswordForServiceAsData(_ service: String) throws -> Data { - var query = queryForGenericPassword(by: service) - - query[kSecReturnData as String] = kCFBooleanTrue - query[kSecMatchLimit as String] = kSecMatchLimitOne - - var result: AnyObject? - - let statusCode = SecItemCopyMatching(query as CFDictionary, &result) - - guard statusCode == errSecSuccess else { - throw KeychainManagerError.copy(statusCode) - } - - guard let passwordData = result as? Data else { - throw KeychainManagerError.unknownResult - } - - return passwordData - } - - public func getGenericPasswordForService(_ service: String) throws -> String { - let passwordData = try getGenericPasswordForServiceAsData(service) - - guard let password = String(data: passwordData, encoding: String.Encoding.utf8) else { - throw KeychainManagerError.unknownResult - } - - return password - } - - // MARK – Internet Passwords - - public func setInternetPassword(_ password: String, account: String, atURL url: URL, label: String? = nil) throws { - var query = try updatedQuery(queryForInternetPassword(account: account, url: url, label: label), withPassword: password) - - query[kSecAttrAccount as String] = account as NSObject? - - if let components = URLComponents(url: url, resolvingAgainstBaseURL: true) { - for (key, value) in components.keychainAttributes { - query[key] = value - } - } - - if let label = label { - query[kSecAttrLabel as String] = label as NSObject? - } - - let statusCode = SecItemAdd(query as CFDictionary, nil) - - guard statusCode == errSecSuccess else { - throw KeychainManagerError.add(statusCode) - } - } - - public func replaceInternetCredentials(_ credentials: InternetCredentials?, forAccount account: String) throws { - let query = queryForInternetPassword(account: account) - - try delete(query) - - if let credentials = credentials { - try setInternetPassword(credentials.password, account: credentials.username, atURL: credentials.url) - } - } - - public func replaceInternetCredentials(_ credentials: InternetCredentials?, forLabel label: String) throws { - let query = queryForInternetPassword(label: label) - - try delete(query) - - if let credentials = credentials { - try setInternetPassword(credentials.password, account: credentials.username, atURL: credentials.url, label: label) - } - } - - public func replaceInternetCredentials(_ credentials: InternetCredentials?, forURL url: URL) throws { - let query = queryForInternetPassword(url: url) - - try delete(query) - - if let credentials = credentials { - try setInternetPassword(credentials.password, account: credentials.username, atURL: credentials.url) - } - } - - public func getInternetCredentials(account: String? = nil, url: URL? = nil, label: String? = nil) throws -> InternetCredentials { - var query = queryForInternetPassword(account: account, url: url, label: label) - - query[kSecReturnData as String] = kCFBooleanTrue - query[kSecReturnAttributes as String] = kCFBooleanTrue - query[kSecMatchLimit as String] = kSecMatchLimitOne - - var result: AnyObject? - - let statusCode: OSStatus = SecItemCopyMatching(query as CFDictionary, &result) - - guard statusCode == errSecSuccess else { - throw KeychainManagerError.copy(statusCode) - } - - if let result = result as? [AnyHashable: Any], let passwordData = result[kSecValueData as String] as? Data, - let password = String(data: passwordData, encoding: String.Encoding.utf8), - let url = URLComponents(keychainAttributes: result)?.url, - let username = result[kSecAttrAccount as String] as? String - { - return InternetCredentials(username: username, password: password, url: url) - } - - throw KeychainManagerError.unknownResult - } -} - - -private enum SecurityProtocol { - case http - case https - - init?(scheme: String?) { - switch scheme?.lowercased() { - case "http"?: - self = .http - case "https"?: - self = .https - default: - return nil - } - } - - init?(secAttrProtocol: CFString) { - if secAttrProtocol == kSecAttrProtocolHTTP { - self = .http - } else if secAttrProtocol == kSecAttrProtocolHTTPS { - self = .https - } else { - return nil - } - } - - var scheme: String { - switch self { - case .http: - return "http" - case .https: - return "https" - } - } - - var secAttrProtocol: CFString { - switch self { - case .http: - return kSecAttrProtocolHTTP - case .https: - return kSecAttrProtocolHTTPS - } - } -} - - -private extension URLComponents { - init?(keychainAttributes: [AnyHashable: Any]) { - self.init() - - if let secAttProtocol = keychainAttributes[kSecAttrProtocol as String] { - scheme = SecurityProtocol(secAttrProtocol: secAttProtocol as! CFString)?.scheme - } - - host = keychainAttributes[kSecAttrServer as String] as? String - - if let port = keychainAttributes[kSecAttrPort as String] as? Int, port > 0 { - self.port = port - } - - if let path = keychainAttributes[kSecAttrPath as String] as? String { - self.path = path - } - } - - var keychainAttributes: [String: NSObject] { - var query: [String: NSObject] = [:] - - if let `protocol` = SecurityProtocol(scheme: scheme) { - query[kSecAttrProtocol as String] = `protocol`.secAttrProtocol - } - - if let host = host { - query[kSecAttrServer as String] = host as NSObject - } - - if let port = port { - query[kSecAttrPort as String] = port as NSObject - } - - if !path.isEmpty { - query[kSecAttrPath as String] = path as NSObject - } - - return query - } -} - diff --git a/Dependencies/LoopKit/LoopKit/LocalizedString.swift b/Dependencies/LoopKit/LoopKit/LocalizedString.swift deleted file mode 100644 index f0ecbc502..000000000 --- a/Dependencies/LoopKit/LoopKit/LocalizedString.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// LocalizedString.swift -// LoopKit -// -// Created by Retina15 on 8/6/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -class LocalBundle { - /// Returns the resource bundle associated with the current Swift module. - static var main: Bundle = { - if let mainResourceURL = Bundle(for: LocalBundle.self).resourceURL, - let bundle = Bundle(url: mainResourceURL.appendingPathComponent("LoopKit_LoopKit.bundle")) - { - return bundle - } - return Bundle(for: LocalBundle.self) - }() -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, comment: comment) - } -} diff --git a/Dependencies/LoopKit/LoopKit/Locked.swift b/Dependencies/LoopKit/LoopKit/Locked.swift deleted file mode 100644 index 4c0abc4c0..000000000 --- a/Dependencies/LoopKit/LoopKit/Locked.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// Locked.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import os.lock - - -public class Locked { - private var _lock: UnfairLock - private var _value: T - - public init(_ value: T) { - _lock = UnfairLock() - _value = value - } - - public var value: T { - get { - return _lock.withLock { _value } - } - set { - _lock.withLock { - _value = newValue - } - } - } - - @discardableResult public func mutate(_ changes: (_ value: inout T) -> Void) -> T { - return _lock.withLock { - changes(&_value) - return _value - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/LoopKit.h b/Dependencies/LoopKit/LoopKit/LoopKit.h deleted file mode 100644 index 1468febbd..000000000 --- a/Dependencies/LoopKit/LoopKit/LoopKit.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// LoopKit.h -// LoopKit -// -// Created by Nathan Racklyeft on 1/18/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -#import - -//! Project version number for LoopKit. -FOUNDATION_EXPORT double LoopKitVersionNumber; - -//! Project version string for LoopKit. -FOUNDATION_EXPORT const unsigned char LoopKitVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/LoopKit/LoopKit/LoopMath.swift b/Dependencies/LoopKit/LoopKit/LoopMath.swift deleted file mode 100644 index 2760ba1e8..000000000 --- a/Dependencies/LoopKit/LoopKit/LoopMath.swift +++ /dev/null @@ -1,329 +0,0 @@ -// -// LoopMath.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/24/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -public enum LoopMath { - static func simulationDateRangeForSamples( - _ samples: T, - from start: Date? = nil, - to end: Date? = nil, - duration: TimeInterval, - delay: TimeInterval = 0, - delta: TimeInterval - ) -> (start: Date, end: Date)? where T.Element: TimelineValue { - guard samples.count > 0 else { - return nil - } - - if let start = start, let end = end { - return (start: start.dateFlooredToTimeInterval(delta), end: end.dateCeiledToTimeInterval(delta)) - } else { - var minDate = samples.first!.startDate - var maxDate = minDate - - for sample in samples { - if sample.startDate < minDate { - minDate = sample.startDate - } - - if sample.endDate > maxDate { - maxDate = sample.endDate - } - } - - return ( - start: (start ?? minDate).dateFlooredToTimeInterval(delta), - end: (end ?? maxDate.addingTimeInterval(duration + delay)).dateCeiledToTimeInterval(delta) - ) - } - } - - /** - Calculates a range of time in `delta`-value intervals - - - parameter start: The range start date - - parameter end: The range end date - - parameter delta: The time differential for items in the returned range - - - returns: An array of dates - */ - public static func simulationDateRange( - from start: Date, - to end: Date, - delta: TimeInterval - ) -> [Date] { - let flooredStart = start.dateFlooredToTimeInterval(delta) - let ceiledEnd = end.dateCeiledToTimeInterval(delta) - - var output: [Date] = [] - var curr = flooredStart - repeat { - output.append(curr) - - let new = curr.addingTimeInterval(delta) - curr = new - } while curr <= ceiledEnd - - return output - } - - /** - Calculates a timeline of predicted glucose values from a variety of effects timelines. - - Each effect timeline: - - Is given equal weight, with the exception of the momentum effect timeline - - Can be of arbitrary size and start date - - Should be in ascending order - - Should have aligning dates with any overlapping timelines to ensure a smooth result - - - parameter startingGlucose: The starting glucose value - - parameter momentum: The momentum effect timeline determined from prior glucose values - - parameter effects: The glucose effect timelines to apply to the prediction. - - - returns: A timeline of glucose values - */ - public static func predictGlucose(startingAt startingGlucose: GlucoseValue, momentum: [GlucoseEffect] = [], effects: [GlucoseEffect]...) -> [PredictedGlucoseValue] { - return predictGlucose(startingAt: startingGlucose, momentum: momentum, effects: effects) - } - - /** - Calculates a timeline of predicted glucose values from a variety of effects timelines. - - Each effect timeline: - - Is given equal weight, with the exception of the momentum effect timeline - - Can be of arbitrary size and start date - - Should be in ascending order - - Should have aligning dates with any overlapping timelines to ensure a smooth result - - - parameter startingGlucose: The starting glucose value - - parameter momentum: The momentum effect timeline determined from prior glucose values - - parameter effects: The glucose effect timelines to apply to the prediction. - - - returns: A timeline of glucose values - */ - public static func predictGlucose(startingAt startingGlucose: GlucoseValue, momentum: [GlucoseEffect] = [], effects: [[GlucoseEffect]]) -> [PredictedGlucoseValue] { - var effectValuesAtDate: [Date: Double] = [:] - let unit = HKUnit.milligramsPerDeciliter - - for timeline in effects { - var previousEffectValue: Double = timeline.first?.quantity.doubleValue(for: unit) ?? 0 - - for effect in timeline { - let value = effect.quantity.doubleValue(for: unit) - effectValuesAtDate[effect.startDate] = (effectValuesAtDate[effect.startDate] ?? 0) + value - previousEffectValue - previousEffectValue = value - } - } - - // Blend the momentum effect linearly into the summed effect list - if momentum.count > 1 { - var previousEffectValue: Double = momentum[0].quantity.doubleValue(for: unit) - - // The blend begins delta minutes after after the last glucose (1.0) and ends at the last momentum point (0.0) - // We're assuming the first one occurs on or before the starting glucose. - let blendCount = momentum.count - 2 - - let timeDelta = momentum[1].startDate.timeIntervalSince(momentum[0].startDate) - - // The difference between the first momentum value and the starting glucose value - let momentumOffset = startingGlucose.startDate.timeIntervalSince(momentum[0].startDate) - - let blendSlope = 1.0 / Double(blendCount) - let blendOffset = momentumOffset / timeDelta * blendSlope - - for (index, effect) in momentum.enumerated() { - let value = effect.quantity.doubleValue(for: unit) - let effectValueChange = value - previousEffectValue - - let split = min(1.0, max(0.0, Double(momentum.count - index) / Double(blendCount) - blendSlope + blendOffset)) - let effectBlend = (1.0 - split) * (effectValuesAtDate[effect.startDate] ?? 0) - let momentumBlend = split * effectValueChange - - effectValuesAtDate[effect.startDate] = effectBlend + momentumBlend - - previousEffectValue = value - } - } - - let prediction = effectValuesAtDate.sorted { $0.0 < $1.0 }.reduce([PredictedGlucoseValue(startDate: startingGlucose.startDate, quantity: startingGlucose.quantity)]) { (prediction, effect) -> [PredictedGlucoseValue] in - if effect.0 > startingGlucose.startDate, let lastValue = prediction.last { - let nextValue = PredictedGlucoseValue( - startDate: effect.0, - quantity: HKQuantity(unit: unit, doubleValue: effect.1 + lastValue.quantity.doubleValue(for: unit)) - ) - return prediction + [nextValue] - } else { - return prediction - } - } - - return prediction - } -} - - -extension GlucoseValue { - /** - Calculates a timeline of glucose effects by applying a linear decay to a rate of change. - - - parameter rate: The glucose velocity - - parameter duration: The duration the effect should continue before ending - - parameter delta: The time differential for the returned values - - - returns: An array of glucose effects - */ - public func decayEffect(atRate rate: HKQuantity, for duration: TimeInterval, withDelta delta: TimeInterval = 5 * 60) -> [GlucoseEffect] { - guard let (startDate, endDate) = LoopMath.simulationDateRangeForSamples([self], duration: duration, delta: delta) else { - return [] - } - - let glucoseUnit = HKUnit.milligramsPerDeciliter - let velocityUnit = GlucoseEffectVelocity.perSecondUnit - - // The starting rate, which we will decay to 0 over the specified duration - let intercept = rate.doubleValue(for: velocityUnit) // mg/dL/s - let decayStartDate = startDate.addingTimeInterval(delta) - let slope = -intercept / (duration - delta) // mg/dL/s/s - - var values = [GlucoseEffect(startDate: startDate, quantity: quantity)] - var date = decayStartDate - var lastValue = quantity.doubleValue(for: glucoseUnit) - - repeat { - let value = lastValue + (intercept + slope * date.timeIntervalSince(decayStartDate)) * delta - values.append(GlucoseEffect(startDate: date, quantity: HKQuantity(unit: glucoseUnit, doubleValue: value))) - lastValue = value - date = date.addingTimeInterval(delta) - } while date < endDate - - return values - } -} - - -extension BidirectionalCollection where Element == GlucoseEffect { - - /// Sums adjacent glucose effects into buckets of the specified duration. - /// - /// Requires the receiver to be sorted chronologically by endDate - /// - /// - Parameter duration: The duration of each resulting summed element - /// - Returns: An array of summed effects - public func combinedSums(of duration: TimeInterval) -> [GlucoseChange] { - var sums = [GlucoseChange]() - sums.reserveCapacity(self.count) - var lastValidIndex = sums.startIndex - - for effect in reversed() { - sums.append(GlucoseChange(startDate: effect.startDate, endDate: effect.endDate, quantity: effect.quantity)) - - for sumsIndex in lastValidIndex..<(sums.endIndex - 1) { - guard sums[sumsIndex].endDate <= effect.endDate.addingTimeInterval(duration) else { - lastValidIndex += 1 - continue - } - - sums[sumsIndex].append(effect) - } - } - - return sums.reversed() - } - - /// Returns the net effect of the receiver as a GlucoseChange object - /// - /// Requires the receiver to be sorted chronologically by endDate - /// - /// - Returns: A single GlucoseChange representing the net effect - public func netEffect() -> GlucoseChange? { - guard let first = self.first, let last = self.last else { - return nil - } - - let net = last.quantity.doubleValue(for: .milligramsPerDeciliter) - first.quantity.doubleValue(for: .milligramsPerDeciliter) - - return GlucoseChange(startDate: first.startDate, endDate: last.endDate, quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: net)) - } - -} - -extension Sequence where Element: AdditiveArithmetic { - func sum() -> Element { - return reduce(.zero, +) - } -} - - -extension BidirectionalCollection where Element == GlucoseEffectVelocity { - - /// Subtracts an array of glucose effects with uniform intervals and no gaps from the collection of effect changes, which may not have uniform intervals. - /// - /// - Parameters: - /// - otherEffects: The array of glucose effects to subtract - /// - effectInterval: The time interval between elements in the otherEffects array - /// - Returns: A resulting array of glucose effects - public func subtracting(_ otherEffects: [GlucoseEffect], withUniformInterval effectInterval: TimeInterval) -> [GlucoseEffect] { - // Trim both collections to match - let otherEffects = otherEffects.filterDateRange(self.first?.endDate, nil) - let effects = self.filterDateRange(otherEffects.first?.startDate, nil) - - var subtracted: [GlucoseEffect] = [] - - var previousOtherEffectValue = otherEffects.first?.quantity.doubleValue(for: .milligramsPerDeciliter) ?? 0 // mg/dL - var effectIndex = effects.startIndex - - for otherEffect in otherEffects.dropFirst() { - guard effectIndex < effects.endIndex else { - break - } - - let otherEffectValue = otherEffect.quantity.doubleValue(for: .milligramsPerDeciliter) - let otherEffectChange = otherEffectValue - previousOtherEffectValue - previousOtherEffectValue = otherEffectValue - - let effect = effects[effectIndex] - - // Our effect array may have gaps, or have longer segments than 5 minutes. - guard effect.endDate <= otherEffect.endDate else { - continue // Move on to the next other effect - } - - effectIndex += 1 - - let effectValue = effect.quantity.doubleValue(for: GlucoseEffectVelocity.perSecondUnit) // mg/dL/s - let effectValueMatchingOtherEffectInterval = effectValue * effectInterval // mg/dL - - subtracted.append(GlucoseEffect( - startDate: effect.endDate, - quantity: HKQuantity( - unit: .milligramsPerDeciliter, - doubleValue: effectValueMatchingOtherEffectInterval - otherEffectChange - ) - )) - } - - // If we have run out of otherEffect items, we assume the otherEffectChange remains zero - for effect in effects[effectIndex.. - - - - _XCCurrentVersionName - Modelv4.xcdatamodel - - diff --git a/Dependencies/LoopKit/LoopKit/Persistence/Model.xcdatamodeld/Model.xcdatamodel/contents b/Dependencies/LoopKit/LoopKit/Persistence/Model.xcdatamodeld/Model.xcdatamodel/contents deleted file mode 100644 index 1dbd2ce73..000000000 --- a/Dependencies/LoopKit/LoopKit/Persistence/Model.xcdatamodeld/Model.xcdatamodel/contents +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKit/Persistence/Model.xcdatamodeld/Modelv4.xcdatamodel/contents b/Dependencies/LoopKit/LoopKit/Persistence/Model.xcdatamodeld/Modelv4.xcdatamodel/contents deleted file mode 100644 index 90e0eb402..000000000 --- a/Dependencies/LoopKit/LoopKit/Persistence/Model.xcdatamodeld/Modelv4.xcdatamodel/contents +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKit/Persistence/Modelv1v4.xcmappingmodel/xcmapping.xml b/Dependencies/LoopKit/LoopKit/Persistence/Modelv1v4.xcmappingmodel/xcmapping.xml deleted file mode 100644 index a3c2db070..000000000 --- a/Dependencies/LoopKit/LoopKit/Persistence/Modelv1v4.xcmappingmodel/xcmapping.xml +++ /dev/null @@ -1,707 +0,0 @@ - - - - - - 134481920 - B7872188-B623-47F1-8CDA-19B36EFB08C9 - 232 - - - - NSPersistenceFrameworkVersion - 1152 - NSStoreModelVersionHashes - - XDDevAttributeMapping - - 0plcXXRN7XHKl5CcF+fwriFmUpON3ZtcI/AfK748aWc= - - XDDevEntityMapping - - qeN1Ym3TkWN1G6dU9RfX6Kd2ccEvcDVWHpd3LpLgboI= - - XDDevMappingModel - - EqtMzvRnVZWkXwBHu4VeVGy8UyoOe+bi67KC79kphlQ= - - XDDevPropertyMapping - - XN33V44TTGY4JETlMoOB5yyTKxB+u4slvDIinv0rtGA= - - XDDevRelationshipMapping - - akYY9LhehVA/mCb4ATLWuI9XGLcjpm14wWL1oEBtIcs= - - - NSStoreModelVersionHashesDigest - +Hmc2uYZK6og+Pvx5GUJ7oW75UG4V/ksQanTjfTKUnxyGWJRMtB5tIRgVwGsrd7lz/QR57++wbvWsr6nxwyS0A== - NSStoreModelVersionHashesVersion - 3 - NSStoreModelVersionIdentifiers - - - - - - - - - syncVersion - - - - startDate - - - - value - - - - reason - - - - syncIdentifier - - - - scheduledBasalRate - - - - Reservoir - Undefined - 1 - Reservoir - 1 - - - - - - provenanceIdentifier - - - - anchorKey - - - - unit - - - - condition - - - - modificationCounter - - - - isMutable - - - - modificationCounter - - - - trendRateUnit - - - - createdAt - - - - manuallyEntered - - - - createdAt - - - - createdAt - - - - supercededDate - - - - mutable - - - - deletedAt - - - - date - - - - Undefined - 4 - SettingsObject - 1 - - - - - - trend - - - - uploaded - - - - value - - - - modificationCounter - - - - data - - - - insulinType - - - - automatic - - - - LoopKit/Persistence/Model.xcdatamodeld/Model.xcdatamodel - YnBsaXN0MDDUAAEAAgADAAQABQAGAAcAClgkdmVyc2lvblkkYXJjaGl2ZXJUJHRvcFgkb2JqZWN0 -cxIAAYagXxAPTlNLZXllZEFyY2hpdmVy0QAIAAlUcm9vdIABrxEFdgALAAwAGwA3ADgAOQBLAEwATQBOAE8AUABRAGwAbQBuAHQAdQCBAJcAmACZAJoAmwCcAJ0AngCfAKAAuQC8AMMAyQDYAOcA7ADwAPEA9QD2AQUBFAEXAGsBJwE2AToBPgFNAVMBVAFcAWsBbAF1AZEBkgGTAZQBlQGWAZcBmAGZAZoBmwGcAbEBsgG6AbsBvAHIAdwB3QHeAd8B4AHhAeIB4wHkAfMCAgIRAhUCJAIzAjQCQwJSAlMCYgJuAoACgQKCAoMChAKFAoYChwKWAqUCtALDAsQC0wLiAvEC+QMOAw8DFwMjAzcDRgNVA2QDaAN3A4YDlQOkA7MDvwPRA+AD7wP+BA0EDgQdBCwEOwRQBFEEWQRlBHkEiASXBKYEqgS5BMgE1wTmBPUFAQUTBSIFMQVABU8FXgVtBXwFkQWSBZoFpgW6BckF2AXnBesF+gYJBhgGJwY2BkIGVAZjBnIGgQaQBpEGoAavBr4G0wbUBtwG6Ab8BwsHGgcpBy0HPAdLB1oHaQd4B4QHlgelB7QHwwfSB9MH4gfxCAAIFQgWCB4IKgg+CE0IXAhrCG8IfgiNCJwIqwi6CMYI2AjnCOgI9wkGCRUJJAkzCUIJVwlYCWAJbAmACY8JngmtCbEJwAnPCd4J7Qn8CggKGgopCioKOQpIClcKWApnCnYKhQqaCpsKowqvCsMK0grhCvAK9AsDCxILIQswCz8LSwtdC2wLewuKC5kLmgupC7gLxwvcC90L5QvxDAUMFAwjDDIMNgxFDFQMYwxyDIEMjQyfDK4MvQzMDNsM6gz5DQgNHQ0eDSYNMg1GDVUNZA1zDXcNhg2VDaQNsw3CDc4N4A3vDf4ODQ4cDisOOg5JDl4OXw5nDnMOhw6WDqUOtA64DscO1g7lDvQPAw8PDyEPMA8/D04PXQ9sD3sPig+fD6APqA+0D8gP1w/mD/UP+RAIEBcQJhA1EEQQUBBiEHEQgBCPEJ4QrRC8EMsQzBDPENgQ8hDzEPkRBREbESoRLRE8EUsRUBFUEVgRWRFoEXcRehGJEZgRnBGrEboRuxHTEdQR1RHWEdcR2BHZEdoR2xHwEfER+RIFEhkSKBI3EkYSShJZEmgSdxKGEpUSoRKzEsISwxLSEuES8BLxEwATDxMeEzMTNBM8E0gTXBNrE3oTiRONE5wTqxO6E8kT2BPkE/YUBRQUFCMUMhRBFFAUXxR0FHUUfRSJFJ0UrBS7FMoUzhTdFOwU+xUKFRkVJRU3FUYVVRVkFXMVghWRFaAVtRW2Fb4VyhXeFe0V/BYLFg8WHhYtFjwWSxZaFmYWeBaHFpYWpRa0FsMW0hbhFvYW9xb/FwsXHxcuFz0XTBdQF18Xbhd9F4wXmxenF7kXyBfXF+YX9RgEGBMYIhg3GDgYQBhMGGAYbxh+GI0YkRigGK8YvhjNGNwY6Bj6GQkZGBknGTYZRRlUGWMZeBl5GYEZjRmhGbAZvxnOGdIZ4RnwGf8aDhodGikaOxpKGlkaaBp3GoYalRqkGrkauhrCGs4a4hrxGwAbDxsTGyIbMRtAG08bXhtqG3wbixuaG6kbuBvHG9Yb5Rv6G/scAxwPHCMcMhxBHFAcVBxjHHIcgRyQHJ8cqxy9HMwc2xzqHPkdCB0XHSYdOx08HUQdUB1kHXMdgh2RHZUdpB2zHcId0R3gHewd/h4NHhweKx46HkkeWB5nHmoehB6FHoselx6tHrwevx7OHt0e4R7lHuYe9R8EHwcfFh8lHykfOB9HH0gfZB9lH2YfZx9oH2kfah9rH2wfbR+CH4Mfix+XH6sfuh/JH9gf3B/rH/ogCSAYICcgMyBFIFQgYyByIIEgkCCfIK4gwyDEIMwg2CDsIPshCiEZIR0hLCE7IUohWSFoIXQhhiGVIaQhsyHCIdEh4CHvIgQiBSINIhkiLSI8IksiWiJeIm0ifCKLIpoiqSK1Isci1iLlIvQjAyMEIxMjIiMxI0YjRyNPI1sjbyN+I40jnCOgI68jviPNI9wj6yP3JAkkGCQnJDYkRSRUJGMkciSHJIgkkCScJLAkvyTOJN0k4STwJP8lDiUdJSwlOCVKJVklaCV3JYYllSWkJbMlyCXJJdEl3SXxJgAmDyYeJiImMSZAJk8mXiZtJnkmiyaaJpsmqia5Jsgm1ybmJvUnCicLJxMnHyczJ0InUSdgJ2QncyeCJ5EnoCevJ7snzSfcJ+sn+igJKBgoJyg2KEsoTChUKGAodCiDKJIooSilKLQowyjSKOEo8Cj8KQ4pHSksKTspSilZKWgpdymMKY0plSmhKbUpxCnTKeIp5in1KgQqEyoiKjEqPSpPKl4qbSp8KosqmiqpKrgqzSrOKtYq4ir2KwUrFCsjKycrNitFK1QrYytyK34rkCufK64rvSvMK9sr6iv5LA4sDywXLCMsNyxGLFUsZCxoLHcshiyVLKQssyy/LNEs4CzvLP4tDS0cLSstOi1PLVAtWC1kLXgthy2WLaUtqS24Lcct1i3lLfQuAC4SLiEuMC4/Lk4uXS5sLnsufi6YLpkuny6rLsEu0C7TLuIu8S71Lvku+i8JLxgvGy8qLzkvPS9ML1svXC9mL2cvfC99L4UvkS+lL7Qvwy/SL9Yv5S/0MAMwEjAhMC0wPzBOMF0wbDB7MIowmTCoML0wvjDGMNIw5jD1MQQxEzEXMSYxNTFEMVMxYjFuMYAxjzGeMa0xvDHLMdox6TH+Mf8yBzITMicyNjJFMlQyWDJnMnYyhTKUMqMyrzLBMtAy3zLuMv0zDDMbMyozLTNHM0gzTjNaM3AzfzOCM5EzoDOlM6kzrTOuM70zzDPPM94z7TPxNAA0DzQQNCY0JzQoNCk0KjQrNEA0QTRJNFU0aTR4NIc0ljSaNKk0uDTHNNY05TTxNQM1EjUhNTA1PzVONV01bDWBNYI1ijWWNao1uTXINdc12zXqNfk2CDYXNiY2MjZENlM2YjZxNoA2jzaeNq02wjbDNss21zbrNvo3CTcYNxw3Kzc6N0k3WDdnN3M3hTeUN6M3sjfBN9A33zfuOAM4BDgMOBg4LDg7OEo4WThdOGw4eziKOJk4qDi0OMY41TjkOPM5AjkROSA5LzlEOUU5TTlZOW05fDmLOZo5njmtObw5yznaOek59ToHOhY6JTo0OkM6UjphOnA6hTqGOo46mjquOr06zDrbOt867jr9Oww7GzsqOzY7SDtXO2Y7dTuEO5M7ojuxO8Y7xzvPO9s77zv+PA08HDwgPC88PjxNPFw8azx3PIk8mDynPLY8xTzUPOM88j0HPQg9ED0cPTA9Pz1OPV09YT1wPX89jj2dPaw9uD3KPdk96D33PgY+FT4kPjM+SD5JPlE+XT5xPoA+jz6ePqI+sT7APs8+3j7tPvk/Cz8aPyk/OD9HP1Y/ZT90P3c/kT+SP5g/pD+6P8k/zD/bP+o/7T/8QAtADkAdQCxAMEA/QE5AT0BbQFxAcUByQHpAhkCaQKlAuEDHQMtA2kDpQPhBB0EWQSJBNEFDQVJBYUFwQX9BjkGdQbJBs0G7QcdB20HqQflCCEIMQhtCKkI5QkhCV0JjQnVChEKTQqJCsULAQs9C3kLzQvRC/EMIQxxDK0M6Q0lDTUNcQ2tDekOJQ5hDpEO2Q8VD1EPjQ/JEAUQQRB9ENEQ1RD1ESURdRGxEe0SKRI5EnUSsRLtEykTZROVE90UGRRVFJEUzRUJFUUVgRWNFZ0VrRW9Fd0V6RX5Ff1UkbnVsbNcADQAOAA8AEAARABIAEwAUABUAFgAXABgAFwAaXxAPX3hkX3Jvb3RQYWNrYWdlViRjbGFzc1xfeGRfY29tbWVudHNfEBBfeGRfbW9kZWxNYW5hZ2VyXxAVX2NvbmZpZ3VyYXRpb25zQnlOYW1lXV94ZF9tb2RlbE5hbWVfEBdfbW9kZWxWZXJzaW9uSWRlbnRpZmllcoACgQV1gQVygACBBXOAAIEFdN4AHAAdAB4AHwAgACEAIgAOACMAJAAlACYAJwAoACkAKgArAAkAKQAXAC8AMAAxADIAMwApACkAF18QHFhEQnVja2V0Rm9yQ2xhc3Nlc3dhc0VuY29kZWRfEBpYREJ1Y2tldEZvclBhY2thZ2Vzc3RvcmFnZV8QHFhEQnVja2V0Rm9ySW50ZXJmYWNlc3N0b3JhZ2VfEA9feGRfb3duaW5nTW9kZWxfEB1YREJ1Y2tldEZvclBhY2thZ2Vzd2FzRW5jb2RlZFZfb3duZXJfEBtYREJ1Y2tldEZvckRhdGFUeXBlc3N0b3JhZ2VbX3Zpc2liaWxpdHlfEBlYREJ1Y2tldEZvckNsYXNzZXNzdG9yYWdlVV9uYW1lXxAfWERCdWNrZXRGb3JJbnRlcmZhY2Vzd2FzRW5jb2RlZF8QHlhEQnVja2V0Rm9yRGF0YVR5cGVzd2FzRW5jb2RlZF8QEF91bmlxdWVFbGVtZW50SUSABIEFcIEFboABgASAAIEFb4EFcRAAgAWAA4AEgASAAFBTWUVT0wA6ADsADgA8AEMASldOUy5rZXlzWk5TLm9iamVjdHOmAD0APgA/AEAAQQBCgAaAB4AIgAmACoALpgBEAEUARgBHAEgASYAMgQF1gQJ9gQOzgQQQgQT8gC5fEBtDYWNoZWRJbnN1bGluRGVsaXZlcnlPYmplY3RfEBBDYWNoZWRDYXJiT2JqZWN0WVB1bXBFdmVudF8QEURlbGV0ZWRDYXJiT2JqZWN0XxATQ2FjaGVkR2x1Y29zZU9iamVjdFlSZXNlcnZvaXLfEBAAUgBTAFQAVQAhAFYAVwAjAFgAWQAOACUAWgBbACgAXABdAF4AKQApABQAYgBjADEAKQBdAGYAPQBdAGkAagBrXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlW19pc0Fic3RyYWN0gA6ANoAEgASAAoAPgQFygASADoEBdIAGgA6BAXOADQgTAAAAAScTb1FXb3JkZXJlZNMAOgA7AA4AbwBxAEqhAHCAEKEAcoARgC5eWERfUFN0ZXJlb3R5cGXZACEAJQB2AA4AKAB3ACMAXAB4AEQAcABdAHwAFwApADEAawCAXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgAyAEIAOgDWAAIAECIAS0wA6ADsADgCCAIwASqkAgwCEAIUAhgCHAIgAiQCKAIuAE4AUgBWAFoAXgBiAGYAagBupAI0AjgCPAJAAkQCSAJMAlACVgByAIIAhgCeAKIAqgCyAL4AzgC5fEBNYRFBNQ29tcG91bmRJbmRleGVzXxAQWERfUFNLX2VsZW1lbnRJRF8QGVhEUE1VbmlxdWVuZXNzQ29uc3RyYWludHNfEBpYRF9QU0tfdmVyc2lvbkhhc2hNb2RpZmllcl8QGVhEX1BTS19mZXRjaFJlcXVlc3RzQXJyYXlfEBFYRF9QU0tfaXNBYnN0cmFjdF8QD1hEX1BTS191c2VySW5mb18QE1hEX1BTS19jbGFzc01hcHBpbmdfEBZYRF9QU0tfZW50aXR5Q2xhc3NOYW1l3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcArAAXAHIAawBrAGsAMQBrALMAgwBrAGsAFwBrVV90eXBlWF9kZWZhdWx0XF9hc3NvY2lhdGlvbltfaXNSZWFkT25seVlfaXNTdGF0aWNZX2lzVW5pcXVlWl9pc0Rlcml2ZWRaX2lzT3JkZXJlZFxfaXNDb21wb3NpdGVXX2lzTGVhZoAAgB2AAIARCAgICIAfgBMICIAACNIAOwAOALoAu6CAHtIAvQC+AL8AwFokY2xhc3NuYW1lWCRjbGFzc2VzXk5TTXV0YWJsZUFycmF5owC/AMEAwldOU0FycmF5WE5TT2JqZWN00gC9AL4AxADFXxAQWERVTUxQcm9wZXJ0eUltcKQAxgDHAMgAwl8QEFhEVU1MUHJvcGVydHlJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwByAGsAawBrADEAawCzAIQAawBrABcAa4AAgACAAIARCAgICIAfgBQICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXANoAFwByAGsAawBrADEAawCzAIUAawBrABcAa4AAgCKAAIARCAgICIAfgBUICIAACNIAOwAOAOgAu6IA6QDqgCOAJYAe0gA7AA4A7QC7oQDugCSAHlR1dWlk0gA7AA4A8gC7oQDzgCaAHl5zeW5jSWRlbnRpZmllct8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwByAGsAawBrADEAawCzAIYAawBrABcAa4AAgACAAIARCAgICIAfgBYICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXAQcAFwByAGsAawBrADEAawCzAIcAawBrABcAa4AAgCmAAIARCAgICIAfgBcICIAACNIAOwAOARUAu6CAHt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwByAGsAawBrADEAawCzAIgAawBrABcAa4AAgCuAAIARCAgICIAfgBgICIAACAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEpABcAcgBrAGsAawAxAGsAswCJAGsAawAXAGuAAIAtgACAEQgICAiAH4AZCAiAAAjTADoAOwAOATcBOABKoKCALtIAvQC+ATsBPF8QE05TTXV0YWJsZURpY3Rpb25hcnmjATsBPQDCXE5TRGljdGlvbmFyed8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXAUAAFwByAGsAawBrADEAawCzAIoAawBrABcAa4AAgDCAAIARCAgICIAfgBoICIAACNYAJQAOACgAXAAhACMBTgFPABcAawAXADGAMYAygAAIgABfEBRYREdlbmVyaWNSZWNvcmRDbGFzc9IAvQC+AVUBVl1YRFVNTENsYXNzSW1wpgFXAVgBWQFaAVsAwl1YRFVNTENsYXNzSW1wXxASWERVTUxDbGFzc2lmaWVySW1wXxARWERVTUxOYW1lc3BhY2VJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXAV4AFwByAGsAawBrADEAawCzAIsAawBrABcAa4AAgDSAAIARCAgICIAfgBsICIAACF8QHC5DYWNoZWRJbnN1bGluRGVsaXZlcnlPYmplY3TSAL0AvgFtAW5fEBJYRFVNTFN0ZXJlb3R5cGVJbXCnAW8BcAFxAXIBcwF0AMJfEBJYRFVNTFN0ZXJlb3R5cGVJbXBdWERVTUxDbGFzc0ltcF8QElhEVU1MQ2xhc3NpZmllckltcF8QEVhEVU1MTmFtZXNwYWNlSW1wXxAUWERVTUxOYW1lZEVsZW1lbnRJbXBfEA9YRFVNTEVsZW1lbnRJbXDTADoAOwAOAXYBgwBKrAF3AO4BeQF6AXsBfAF9AX4BfwGAAYEBgoA3gCSAOIA5gDqAO4A8gD2APoA/gECAQawBhAGFAYYBhwGIAYkBigGLAYwBjQGOAY+AQoBugIaAnYC1gM2A5YD+gQEWgQEtgQFEgQFbgC5fEBdwcm9ncmFtbWVkVGVtcEJhc2FsUmF0ZV8QFnNjaGVkdWxlZFRlbXBCYXNhbFJhdGVXZW5kRGF0ZV5zeW5jSWRlbnRpZmllclV2YWx1ZVZyZWFzb25fEBBoYXNMb29wS2l0T3JpZ2luWXN0YXJ0RGF0ZVljcmVhdGVkQXRfEBJzY2hlZHVsZWRCYXNhbFJhdGVfEBRwcm92ZW5hbmNlSWRlbnRpZmllct8QEgChAKIAowGdACEApQCmAZ4AIwCkAZ8ApwAOACUAqACpACgAqgAXABcAFwApAEQAawBrAacAMQBrAF0AawGrAXcAawBrAa8Aa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgAwICIBECIAOCIBtgDcICIBDCBLUwyJZ0wA6ADsADgGzAbYASqIBtAG1gEWARqIBtwG4gEeAXIAuXxASWERfUFByb3BTdGVyZW90eXBlXxASWERfUEF0dF9TdGVyZW90eXBl2QAhACUBvQAOACgBvgAjAFwBvwGEAbQAXQB8ABcAKQAxAGsBx18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYBCgEWADoA1gACABAiASNMAOgA7AA4ByQHSAEqoAcoBywHMAc0BzgHPAdAB0YBJgEqAS4BMgE2AToBPgFCoAdMB1AHVAdYB1wHYAdkB2oBRgFKAU4BVgFaAWIBZgFuALl8QG1hEX1BQU0tfaXNTdG9yZWRJblRydXRoRmlsZV8QG1hEX1BQU0tfdmVyc2lvbkhhc2hNb2RpZmllcl8QEFhEX1BQU0tfdXNlckluZm9fEBFYRF9QUFNLX2lzSW5kZXhlZF8QElhEX1BQU0tfaXNPcHRpb25hbF8QGlhEX1BQU0tfaXNTcG90bGlnaHRJbmRleGVkXxARWERfUFBTS19lbGVtZW50SURfEBNYRF9QUFNLX2lzVHJhbnNpZW503xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXAbcAawBrAGsAMQBrALMBygBrAGsAFwBrgACAK4AAgEcICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXAbcAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgEcICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcCBAAXAbcAawBrAGsAMQBrALMBzABrAGsAFwBrgACAVIAAgEcICAgIgB+ASwgIgAAI0wA6ADsADgISAhMASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcBtwBrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACARwgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwImABcBtwBrAGsAawAxAGsAswHOAGsAawAXAGuAAIBXgACARwgICAiAH4BNCAiAAAgJ3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXAbcAawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgEcICAgIgB+ATggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcCRQAXAbcAawBrAGsAMQBrALMB0ABrAGsAFwBrgACAWoAAgEcICAgIgB+ATwgIgAAIXxAWc2NoZWR1bGVkVGVtcEJhc2FsUmF0Zd8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwG3AGsAawBrADEAawCzAdEAawBrABcAa4AAgCuAAIBHCAgICIAfgFAICIAACNkAIQAlAmMADgAoAmQAIwBcAmUBhAG1AF0AfAAXACkAMQBrAm1fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAQoBGgA6ANYAAgAQIgF3TADoAOwAOAm8CdwBKpwJwAnECcgJzAnQCdQJ2gF6AX4BggGGAYoBjgGSnAngCeQJ6AnsCfAJ9An6AZYBmgGeAaIBqgGuAbIAuXxAdWERfUEF0dEtfZGVmYXVsdFZhbHVlQXNTdHJpbmdfEChYRF9QQXR0S19hbGxvd3NFeHRlcm5hbEJpbmFyeURhdGFTdG9yYWdlXxAXWERfUEF0dEtfbWluVmFsdWVTdHJpbmdfEBZYRF9QQXR0S19hdHRyaWJ1dGVUeXBlXxAXWERfUEF0dEtfbWF4VmFsdWVTdHJpbmdfEB1YRF9QQXR0S192YWx1ZVRyYW5zZm9ybWVyTmFtZV8QIFhEX1BBdHRLX3JlZ3VsYXJFeHByZXNzaW9uU3RyaW5n3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXAbgAawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgFwICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXAbgAawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgFwICAgIgB+AXwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXAbgAawBrAGsAMQBrALMCcgBrAGsAFwBrgACAAIAAgFwICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcCtgAXAbgAawBrAGsAMQBrALMCcwBrAGsAFwBrgACAaYAAgFwICAgIgB+AYQgIgAAIEQH03xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXAbgAawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgFwICAgIgB+AYggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXAbgAawBrAGsAMQBrALMCdQBrAGsAFwBrgACAAIAAgFwICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXAbgAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgFwICAgIgB+AZAgIgAAI0gC9AL4C8gLzXVhEUE1BdHRyaWJ1dGWmAvQC9QL2AvcC+ADCXVhEUE1BdHRyaWJ1dGVcWERQTVByb3BlcnR5XxAQWERVTUxQcm9wZXJ0eUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xASAKEAogCjAvoAIQClAKYC+wAjAKQC/ACnAA4AJQCoAKkAKACqABcAFwAXACkARABrAGsDBAAxAGsAXQBrAasA7gBrAGsDDABrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASADAgIgHAIgA4IgG2AJAgIgG8IEmS8HQ/TADoAOwAOAxADEwBKogG0AbWARYBGogMUAxWAcYB8gC7ZACEAJQMYAA4AKAMZACMAXAMaAYUBtABdAHwAFwApADEAawMiXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgG6ARYAOgDWAAIAECIBy0wA6ADsADgMkAy0ASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgDLgMvAzADMQMyAzMDNAM1gHOAdIB1gHeAeIB5gHqAe4Au3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXAxQAawBrAGsAMQBrALMBygBrAGsAFwBrgACAK4AAgHEICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXAxQAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgHEICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcDVwAXAxQAawBrAGsAMQBrALMBzABrAGsAFwBrgACAdoAAgHEICAgIgB+ASwgIgAAI0wA6ADsADgNlA2YASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwImABcDFABrAGsAawAxAGsAswHNAGsAawAXAGuAAIBXgACAcQgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcDFABrAGsAawAxAGsAswHOAGsAawAXAGuAAIArgACAcQgICAiAH4BNCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcDFABrAGsAawAxAGsAswHPAGsAawAXAGuAAIArgACAcQgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcDFABrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACAcQgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcDFABrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACAcQgICAiAH4BQCAiAAAjZACEAJQO0AA4AKAO1ACMAXAO2AYUBtQBdAHwAFwApADEAawO+XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgG6ARoAOgDWAAIAECIB90wA6ADsADgPAA8gASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4BkpwPJA8oDywPMA80DzgPPgH6Af4CAgIGAg4CEgIWALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwMVAGsAawBrADEAawCzAnAAawBrABcAa4AAgACAAIB8CAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwMVAGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIB8CAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwMVAGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIB8CAgICIAfgGAICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXBAAAFwMVAGsAawBrADEAawCzAnMAawBrABcAa4AAgIKAAIB8CAgICIAfgGEICIAACBEETN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwMVAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIB8CAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwMVAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIB8CAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwMVAGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAIB8CAgICIAfgGQICIAACN8QEgChAKIAowQ8ACEApQCmBD0AIwCkBD4ApwAOACUAqACpACgAqgAXABcAFwApAEQAawBrBEYAMQBrAF0AawGrAXkAawBrBE4Aa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgAwICICICIAOCIBtgDgICICHCBMAAAABCv1MPtMAOgA7AA4EUgRVAEqiAbQBtYBFgEaiBFYEV4CJgJSALtkAIQAlBFoADgAoBFsAIwBcBFwBhgG0AF0AfAAXACkAMQBrBGRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAhoBFgA6ANYAAgAQIgIrTADoAOwAOBGYEbwBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqARwBHEEcgRzBHQEdQR2BHeAi4CMgI2Aj4CQgJGAkoCTgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcEVgBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACAiQgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcEVgBrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACAiQgICAiAH4BKCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwSZABcEVgBrAGsAawAxAGsAswHMAGsAawAXAGuAAICOgACAiQgICAiAH4BLCAiAAAjTADoAOwAOBKcEqABKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwRWAGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAICJCAgICIAfgEwICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXAiYAFwRWAGsAawBrADEAawCzAc4AawBrABcAa4AAgFeAAICJCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwRWAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAICJCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwRWAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAICJCAgICIAfgE8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwRWAGsAawBrADEAawCzAdEAawBrABcAa4AAgCuAAICJCAgICIAfgFAICIAACNkAIQAlBPYADgAoBPcAIwBcBPgBhgG1AF0AfAAXACkAMQBrBQBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAhoBGgA6ANYAAgAQIgJXTADoAOwAOBQIFCgBKpwJwAnECcgJzAnQCdQJ2gF6AX4BggGGAYoBjgGSnBQsFDAUNBQ4FDwUQBRGAloCXgJiAmYCagJuAnIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXBFcAawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgJQICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXBFcAawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgJQICAgIgB+AXwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXBFcAawBrAGsAMQBrALMCcgBrAGsAFwBrgACAAIAAgJQICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcCtgAXBFcAawBrAGsAMQBrALMCcwBrAGsAFwBrgACAaYAAgJQICAgIgB+AYQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXBFcAawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgJQICAgIgB+AYggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXBFcAawBrAGsAMQBrALMCdQBrAGsAFwBrgACAAIAAgJQICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXBFcAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgJQICAgIgB+AZAgIgAAI3xASAKEAogCjBX0AIQClAKYFfgAjAKQFfwCnAA4AJQCoAKkAKACqABcAFwAXACkARABrAGsFhwAxAGsAXQBrAasBegBrAGsFjwBrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASADAgIgJ8IgA4IgG2AOQgIgJ4IEld6/WXTADoAOwAOBZMFlgBKogG0AbWARYBGogWXBZiAoICrgC7ZACEAJQWbAA4AKAWcACMAXAWdAYcBtABdAHwAFwApADEAawWlXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgJ2ARYAOgDWAAIAECICh0wA6ADsADgWnBbAASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgFsQWyBbMFtAW1BbYFtwW4gKKAo4CkgKaAp4CogKmAqoAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXBZcAawBrAGsAMQBrALMBygBrAGsAFwBrgACAK4AAgKAICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXBZcAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgKAICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcF2gAXBZcAawBrAGsAMQBrALMBzABrAGsAFwBrgACApYAAgKAICAgIgB+ASwgIgAAI0wA6ADsADgXoBekASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcFlwBrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACAoAgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcFlwBrAGsAawAxAGsAswHOAGsAawAXAGuAAIArgACAoAgICAiAH4BNCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcFlwBrAGsAawAxAGsAswHPAGsAawAXAGuAAIArgACAoAgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcFlwBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACAoAgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcFlwBrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACAoAgICAiAH4BQCAiAAAjZACEAJQY3AA4AKAY4ACMAXAY5AYcBtQBdAHwAFwApADEAawZBXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgJ2ARoAOgDWAAIAECICs0wA6ADsADgZDBksASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4BkpwZMBk0GTgZPBlAGUQZSgK2AroCvgLCAsoCzgLSALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwWYAGsAawBrADEAawCzAnAAawBrABcAa4AAgACAAICrCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwWYAGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAICrCAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwWYAGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAICrCAgICIAfgGAICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXBoMAFwWYAGsAawBrADEAawCzAnMAawBrABcAa4AAgLGAAICrCAgICIAfgGEICIAACBEDhN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwWYAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAICrCAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwWYAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAICrCAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwWYAGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAICrCAgICIAfgGQICIAACN8QEgChAKIAowa/ACEApQCmBsAAIwCkBsEApwAOACUAqACpACgAqgAXABcAFwApAEQAawBrBskAMQBrAF0AawGrAXsAawBrBtEAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgAwICIC3CIAOCIBtgDoICIC2CBJzXZd50wA6ADsADgbVBtgASqIBtAG1gEWARqIG2QbagLiAw4Au2QAhACUG3QAOACgG3gAjAFwG3wGIAbQAXQB8ABcAKQAxAGsG518QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYC1gEWADoA1gACABAiAudMAOgA7AA4G6QbyAEqoAcoBywHMAc0BzgHPAdAB0YBJgEqAS4BMgE2AToBPgFCoBvMG9Ab1BvYG9wb4BvkG+oC6gLuAvIC+gL+AwIDBgMKALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwbZAGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIC4CAgICIAfgEkICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwbZAGsAawBrADEAawCzAcsAawBrABcAa4AAgACAAIC4CAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXBxwAFwbZAGsAawBrADEAawCzAcwAawBrABcAa4AAgL2AAIC4CAgICIAfgEsICIAACNMAOgA7AA4HKgcrAEqgoIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcCJgAXBtkAawBrAGsAMQBrALMBzQBrAGsAFwBrgACAV4AAgLgICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXBtkAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgLgICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXBtkAawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgLgICAgIgB+ATggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXBtkAawBrAGsAMQBrALMB0ABrAGsAFwBrgACAAIAAgLgICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXBtkAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgLgICAgIgB+AUAgIgAAI2QAhACUHeQAOACgHegAjAFwHewGIAbUAXQB8ABcAKQAxAGsHg18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYC1gEaADoA1gACABAiAxNMAOgA7AA4HhQeNAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKcHjgePB5AHkQeSB5MHlIDFgMaAx4DIgMqAy4DMgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcG2gBrAGsAawAxAGsAswJwAGsAawAXAGuAAIAAgACAwwgICAiAH4BeCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcG2gBrAGsAawAxAGsAswJxAGsAawAXAGuAAIArgACAwwgICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcG2gBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACAwwgICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwfFABcG2gBrAGsAawAxAGsAswJzAGsAawAXAGuAAIDJgACAwwgICAiAH4BhCAiAAAgRArzfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcG2gBrAGsAawAxAGsAswJ0AGsAawAXAGuAAIAAgACAwwgICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcG2gBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACAwwgICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcG2gBrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACAwwgICAiAH4BkCAiAAAjfEBIAoQCiAKMIAQAhAKUApggCACMApAgDAKcADgAlAKgAqQAoAKoAFwAXABcAKQBEAGsAawgLADEAawBdAGsBqwF8AGsAawgTAGtfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIAMCAiAzwiADgiAbYA7CAiAzggS+Lr+/tMAOgA7AA4IFwgaAEqiAbQBtYBFgEaiCBsIHIDQgNuALtkAIQAlCB8ADgAoCCAAIwBcCCEBiQG0AF0AfAAXACkAMQBrCClfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAzYBFgA6ANYAAgAQIgNHTADoAOwAOCCsINABKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqAg1CDYINwg4CDkIOgg7CDyA0oDTgNSA1oDXgNiA2YDagC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcIGwBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACA0AgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcIGwBrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACA0AgICAiAH4BKCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwheABcIGwBrAGsAawAxAGsAswHMAGsAawAXAGuAAIDVgACA0AgICAiAH4BLCAiAAAjTADoAOwAOCGwIbQBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwgbAGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIDQCAgICIAfgEwICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwgbAGsAawBrADEAawCzAc4AawBrABcAa4AAgCuAAIDQCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwgbAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIDQCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwgbAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIDQCAgICIAfgE8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwgbAGsAawBrADEAawCzAdEAawBrABcAa4AAgCuAAIDQCAgICIAfgFAICIAACNkAIQAlCLsADgAoCLwAIwBcCL0BiQG1AF0AfAAXACkAMQBrCMVfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAzYBGgA6ANYAAgAQIgNzTADoAOwAOCMcIzwBKpwJwAnECcgJzAnQCdQJ2gF6AX4BggGGAYoBjgGSnCNAI0QjSCNMI1AjVCNaA3YDfgOCA4YDigOOA5IAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcI2gAXCBwAawBrAGsAMQBrALMCcABrAGsAFwBrgACA3oAAgNsICAgIgB+AXggIgAAIUzAuMN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwgcAGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIDbCAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwgcAGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIDbCAgICIAfgGAICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXArYAFwgcAGsAawBrADEAawCzAnMAawBrABcAa4AAgGmAAIDbCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwgcAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIDbCAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwgcAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIDbCAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwgcAGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAIDbCAgICIAfgGQICIAACN8QEgChAKIAowlDACEApQCmCUQAIwCkCUUApwAOACUAqACpACgAqgAXABcAFwApAEQAawBrCU0AMQBrAF0AawGrAX0AawBrCVUAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgAwICIDnCIAOCIBtgDwICIDmCBMAAAABF4aloNMAOgA7AA4JWQlcAEqiAbQBtYBFgEaiCV0JXoDogPOALtkAIQAlCWEADgAoCWIAIwBcCWMBigG0AF0AfAAXACkAMQBrCWtfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WA5YBFgA6ANYAAgAQIgOnTADoAOwAOCW0JdgBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqAl3CXgJeQl6CXsJfAl9CX6A6oDrgOyA7oDvgPCA8YDygC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcJXQBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACA6AgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcJXQBrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACA6AgICAiAH4BKCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwmgABcJXQBrAGsAawAxAGsAswHMAGsAawAXAGuAAIDtgACA6AgICAiAH4BLCAiAAAjTADoAOwAOCa4JrwBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwldAGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIDoCAgICIAfgEwICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwldAGsAawBrADEAawCzAc4AawBrABcAa4AAgCuAAIDoCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwldAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIDoCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwldAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIDoCAgICIAfgE8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwldAGsAawBrADEAawCzAdEAawBrABcAa4AAgCuAAIDoCAgICIAfgFAICIAACNkAIQAlCf0ADgAoCf4AIwBcCf8BigG1AF0AfAAXACkAMQBrCgdfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WA5YBGgA6ANYAAgAQIgPTTADoAOwAOCgkKEQBKpwJwAnECcgJzAnQCdQJ2gF6AX4BggGGAYoBjgGSnChIKEwoUChUKFgoXChiA9YD3gPiA+YD7gPyA/YAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcKHAAXCV4AawBrAGsAMQBrALMCcABrAGsAFwBrgACA9oAAgPMICAgIgB+AXggIgAAIUTDfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcJXgBrAGsAawAxAGsAswJxAGsAawAXAGuAAIArgACA8wgICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcJXgBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACA8wgICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwpKABcJXgBrAGsAawAxAGsAswJzAGsAawAXAGuAAID6gACA8wgICAiAH4BhCAiAAAgQZN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwleAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIDzCAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwleAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIDzCAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwleAGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAIDzCAgICIAfgGQICIAACN8QEgChAKIAowqGACEApQCmCocAIwCkCogApwAOACUAqACpACgAqgAXABcAFwApAEQAawBrCpAAMQBrAF0AawGrAX4AawBrCpgAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgAwICIEBAAiADgiAbYA9CAiA/wgS1uwAcNMAOgA7AA4KnAqfAEqiAbQBtYBFgEaiCqAKoYEBAYEBDIAu2QAhACUKpAAOACgKpQAjAFwKpgGLAbQAXQB8ABcAKQAxAGsKrl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYD+gEWADoA1gACABAiBAQLTADoAOwAOCrAKuQBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqAq6CrsKvAq9Cr4KvwrACsGBAQOBAQSBAQWBAQeBAQiBAQmBAQqBAQuALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwqgAGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIEBAQgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcKoABrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBAQEICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcK4wAXCqAAawBrAGsAMQBrALMBzABrAGsAFwBrgACBAQaAAIEBAQgICAiAH4BLCAiAAAjTADoAOwAOCvEK8gBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwqgAGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIEBAQgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcKoABrAGsAawAxAGsAswHOAGsAawAXAGuAAIArgACBAQEICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXCqAAawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQEBCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwqgAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIEBAQgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcKoABrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBAQEICAgIgB+AUAgIgAAI2QAhACULQAAOACgLQQAjAFwLQgGLAbUAXQB8ABcAKQAxAGsLSl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYD+gEaADoA1gACABAiBAQ3TADoAOwAOC0wLVABKpwJwAnECcgJzAnQCdQJ2gF6AX4BggGGAYoBjgGSnC1ULVgtXC1gLWQtaC1uBAQ6BAQ+BARCBARGBAROBARSBARWALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwqhAGsAawBrADEAawCzAnAAawBrABcAa4AAgACAAIEBDAgICAiAH4BeCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcKoQBrAGsAawAxAGsAswJxAGsAawAXAGuAAIArgACBAQwICAgIgB+AXwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXCqEAawBrAGsAMQBrALMCcgBrAGsAFwBrgACAAIAAgQEMCAgICIAfgGAICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXC4wAFwqhAGsAawBrADEAawCzAnMAawBrABcAa4AAgQESgACBAQwICAgIgB+AYQgIgAAIEQMg3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXCqEAawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgQEMCAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwqhAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIEBDAgICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcKoQBrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACBAQwICAgIgB+AZAgIgAAI3xASAKEAogCjC8gAIQClAKYLyQAjAKQLygCnAA4AJQCoAKkAKACqABcAFwAXACkARABrAGsL0gAxAGsAXQBrAasBfwBrAGsL2gBrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASADAgIgQEYCIAOCIBtgD4ICIEBFwgSlPuImNMAOgA7AA4L3gvhAEqiAbQBtYBFgEaiC+IL44EBGYEBJIAu2QAhACUL5gAOACgL5wAjAFwL6AGMAbQAXQB8ABcAKQAxAGsL8F8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEBFoBFgA6ANYAAgAQIgQEa0wA6ADsADgvyC/sASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgL/Av9C/4L/wwADAEMAgwDgQEbgQEcgQEdgQEfgQEggQEhgQEigQEjgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcL4gBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBARkICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXC+IAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQEZCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXDCUAFwviAGsAawBrADEAawCzAcwAawBrABcAa4AAgQEegACBARkICAgIgB+ASwgIgAAI0wA6ADsADgwzDDQASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcL4gBrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACBARkICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXC+IAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgQEZCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwviAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEBGQgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcL4gBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBARkICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXC+IAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQEZCAgICIAfgFAICIAACNkAIQAlDIIADgAoDIMAIwBcDIQBjAG1AF0AfAAXACkAMQBrDIxfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBARaARoAOgDWAAIAECIEBJdMAOgA7AA4MjgyWAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKcMlwyYDJkMmgybDJwMnYEBJoEBJ4EBKIEBKYEBKoEBK4EBLIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXC+MAawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgQEkCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFwvjAGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEBJAgICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcL4wBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBASQICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcGgwAXC+MAawBrAGsAMQBrALMCcwBrAGsAFwBrgACAsYAAgQEkCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFwvjAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEBJAgICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcL4wBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBASQICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXC+MAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQEkCAgICIAfgGQICIAACN8QEgChAKIAow0JACEApQCmDQoAIwCkDQsApwAOACUAqACpACgAqgAXABcAFwApAEQAawBrDRMAMQBrAF0AawGrAYAAawBrDRsAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgAwICIEBLwiADgiAbYA/CAiBAS4IElnl7mPTADoAOwAODR8NIgBKogG0AbWARYBGog0jDSSBATCBATuALtkAIQAlDScADgAoDSgAIwBcDSkBjQG0AF0AfAAXACkAMQBrDTFfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAS2ARYAOgDWAAIAECIEBMdMAOgA7AA4NMw08AEqoAcoBywHMAc0BzgHPAdAB0YBJgEqAS4BMgE2AToBPgFCoDT0NPg0/DUANQQ1CDUMNRIEBMoEBM4EBNIEBNoEBN4EBOIEBOYEBOoAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXDSMAawBrAGsAMQBrALMBygBrAGsAFwBrgACAK4AAgQEwCAgICIAfgEkICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFw0jAGsAawBrADEAawCzAcsAawBrABcAa4AAgACAAIEBMAgICAiAH4BKCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFw1mABcNIwBrAGsAawAxAGsAswHMAGsAawAXAGuAAIEBNYAAgQEwCAgICIAfgEsICIAACNMAOgA7AA4NdA11AEqgoIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXDSMAawBrAGsAMQBrALMBzQBrAGsAFwBrgACAK4AAgQEwCAgICIAfgEwICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFw0jAGsAawBrADEAawCzAc4AawBrABcAa4AAgCuAAIEBMAgICAiAH4BNCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcNIwBrAGsAawAxAGsAswHPAGsAawAXAGuAAIArgACBATAICAgIgB+ATggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXDSMAawBrAGsAMQBrALMB0ABrAGsAFwBrgACAAIAAgQEwCAgICIAfgE8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFw0jAGsAawBrADEAawCzAdEAawBrABcAa4AAgCuAAIEBMAgICAiAH4BQCAiAAAjZACEAJQ3DAA4AKA3EACMAXA3FAY0BtQBdAHwAFwApADEAaw3NXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQEtgEaADoA1gACABAiBATzTADoAOwAODc8N1wBKpwJwAnECcgJzAnQCdQJ2gF6AX4BggGGAYoBjgGSnDdgN2Q3aDdsN3A3dDd6BAT2BAT6BAT+BAUCBAUGBAUKBAUOALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFw0kAGsAawBrADEAawCzAnAAawBrABcAa4AAgACAAIEBOwgICAiAH4BeCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcNJABrAGsAawAxAGsAswJxAGsAawAXAGuAAIArgACBATsICAgIgB+AXwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXDSQAawBrAGsAMQBrALMCcgBrAGsAFwBrgACAAIAAgQE7CAgICIAfgGAICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXBoMAFw0kAGsAawBrADEAawCzAnMAawBrABcAa4AAgLGAAIEBOwgICAiAH4BhCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcNJABrAGsAawAxAGsAswJ0AGsAawAXAGuAAIAAgACBATsICAgIgB+AYggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXDSQAawBrAGsAMQBrALMCdQBrAGsAFwBrgACAAIAAgQE7CAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFw0kAGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAIEBOwgICAiAH4BkCAiAAAjfEBIAoQCiAKMOSgAhAKUApg5LACMApA5MAKcADgAlAKgAqQAoAKoAFwAXABcAKQBEAGsAaw5UADEAawBdAGsBqwGBAGsAaw5cAGtfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIAMCAiBAUYIgA4IgG2AQAgIgQFFCBJZpu9l0wA6ADsADg5gDmMASqIBtAG1gEWARqIOZA5lgQFHgQFSgC7ZACEAJQ5oAA4AKA5pACMAXA5qAY4BtABdAHwAFwApADEAaw5yXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQFEgEWADoA1gACABAiBAUjTADoAOwAODnQOfQBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqA5+Dn8OgA6BDoIOgw6EDoWBAUmBAUqBAUuBAU2BAU6BAU+BAVCBAVGALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFw5kAGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIEBRwgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcOZABrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBAUcICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcOpwAXDmQAawBrAGsAMQBrALMBzABrAGsAFwBrgACBAUyAAIEBRwgICAiAH4BLCAiAAAjTADoAOwAODrUOtgBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFw5kAGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIEBRwgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwImABcOZABrAGsAawAxAGsAswHOAGsAawAXAGuAAIBXgACBAUcICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXDmQAawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQFHCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFw5kAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIEBRwgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcOZABrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBAUcICAgIgB+AUAgIgAAI2QAhACUPBAAOACgPBQAjAFwPBgGOAbUAXQB8ABcAKQAxAGsPDl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEBRIBGgA6ANYAAgAQIgQFT0wA6ADsADg8QDxgASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4Bkpw8ZDxoPGw8cDx0PHg8fgQFUgQFVgQFWgQFXgQFYgQFZgQFagC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcOZQBrAGsAawAxAGsAswJwAGsAawAXAGuAAIAAgACBAVIICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXDmUAawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQFSCAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFw5lAGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIEBUggICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwK2ABcOZQBrAGsAawAxAGsAswJzAGsAawAXAGuAAIBpgACBAVIICAgIgB+AYQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXDmUAawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgQFSCAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFw5lAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIEBUggICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcOZQBrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACBAVIICAgIgB+AZAgIgAAI3xASAKEAogCjD4sAIQClAKYPjAAjAKQPjQCnAA4AJQCoAKkAKACqABcAFwAXACkARABrAGsPlQAxAGsAXQBrAasBggBrAGsPnQBrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASADAgIgQFdCIAOCIBtgEEICIEBXAgSjJwfVtMAOgA7AA4PoQ+kAEqiAbQBtYBFgEaiD6UPpoEBXoEBaYAu2QAhACUPqQAOACgPqgAjAFwPqwGPAbQAXQB8ABcAKQAxAGsPs18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEBW4BFgA6ANYAAgAQIgQFf0wA6ADsADg+1D74ASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgPvw/AD8EPwg/DD8QPxQ/GgQFggQFhgQFigQFkgQFlgQFmgQFngQFogC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcPpQBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBAV4ICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXD6UAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQFeCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXD+gAFw+lAGsAawBrADEAawCzAcwAawBrABcAa4AAgQFjgACBAV4ICAgIgB+ASwgIgAAI0wA6ADsADg/2D/cASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcPpQBrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACBAV4ICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXD6UAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgQFeCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFw+lAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEBXggICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcPpQBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBAV4ICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXD6UAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQFeCAgICIAfgFAICIAACNkAIQAlEEUADgAoEEYAIwBcEEcBjwG1AF0AfAAXACkAMQBrEE9fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAVuARoAOgDWAAIAECIEBatMAOgA7AA4QURBZAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKcQWhBbEFwQXRBeEF8QYIEBa4EBbIEBbYEBboEBb4EBcIEBcYAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXD6YAawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgQFpCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFw+mAGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEBaQgICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcPpgBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBAWkICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcHxQAXD6YAawBrAGsAMQBrALMCcwBrAGsAFwBrgACAyYAAgQFpCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFw+mAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEBaQgICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcPpgBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBAWkICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXD6YAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQFpCAgICIAfgGQICIAACFpkdXBsaWNhdGVz0gA7AA4QzQC7oIAe0gC9AL4Q0BDRWlhEUE1FbnRpdHmnENIQ0xDUENUQ1hDXAMJaWERQTUVudGl0eV1YRFVNTENsYXNzSW1wXxASWERVTUxDbGFzc2lmaWVySW1wXxARWERVTUxOYW1lc3BhY2VJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcN8QEBDZENoQ2xDcACEQ3RDeACMQ3xDgAA4AJRDhEOIAKABcAF0Q5AApACkAFBDoAGMAMQApAF0AZgA+AF0Q7xDwAGtfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2WADoEBi4AEgASAAoEBd4EBcoAEgA6BAXSAB4AOgQJ8gQF2CBMAAAABGb8WlNMAOgA7AA4Q9BD2AEqhAHCAEKEQ94EBeIAu2QAhACUQ+gAOACgQ+wAjAFwQ/ABFAHAAXQB8ABcAKQAxAGsRBF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEBdYAQgA6ANYAAgAQIgQF50wA6ADsADhEGERAASqkAgwCEAIUAhgCHAIgAiQCKAIuAE4AUgBWAFoAXgBiAGYAagBupEREREhETERQRFREWERcRGBEZgQF6gQF8gQF9gQGCgQGDgQGFgQGGgQGIgQGJgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFxEdABcQ9wBrAGsAawAxAGsAswCDAGsAawAXAGuAAIEBe4AAgQF4CAgICIAfgBMICIAACNIAOwAOESsAu6CAHt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxD3AGsAawBrADEAawCzAIQAawBrABcAa4AAgACAAIEBeAgICAiAH4AUCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFxE+ABcQ9wBrAGsAawAxAGsAswCFAGsAawAXAGuAAIEBfoAAgQF4CAgICIAfgBUICIAACNIAOwAOEUwAu6IRTRFOgQF/gQGAgB7SADsADhFRALuhAO6AJIAe0gA7AA4RVQC7oRFWgQGBgB5ec3luY0lkZW50aWZpZXLfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcQ9wBrAGsAawAxAGsAswCGAGsAawAXAGuAAIAAgACBAXgICAgIgB+AFggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcRagAXEPcAawBrAGsAMQBrALMAhwBrAGsAFwBrgACBAYSAAIEBeAgICAiAH4AXCAiAAAjSADsADhF4ALuggB7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcQ9wBrAGsAawAxAGsAswCIAGsAawAXAGuAAIArgACBAXgICAgIgB+AGAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcRiwAXEPcAawBrAGsAMQBrALMAiQBrAGsAFwBrgACBAYeAAIEBeAgICAiAH4AZCAiAAAjTADoAOwAOEZkRmgBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXAUAAFxD3AGsAawBrADEAawCzAIoAawBrABcAa4AAgDCAAIEBeAgICAiAH4AaCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFxGtABcQ9wBrAGsAawAxAGsAswCLAGsAawAXAGuAAIEBioAAgQF4CAgICIAfgBsICIAACF8QES5DYWNoZWRDYXJiT2JqZWN00wA6ADsADhG8EccASqoRvRG+AX8RwBHBAO4RwxHEEcURxoEBjIEBjYA+gQGOgQGPgCSBAZCBAZGBAZKBAZOqEcgRyRHKEcsRzBHNEc4RzxHQEdGBAZSBAa2BAcSBAduBAfKBAgmBAiCBAjeBAk6BAmWALltzeW5jVmVyc2lvbl8QE2NyZWF0ZWRCeUN1cnJlbnRBcHBVZ3JhbXNeYWJzb3JwdGlvblRpbWVec3luY0lkZW50aWZpZXJYZm9vZFR5cGVaZXh0ZXJuYWxJRFt1cGxvYWRTdGF0Zd8QEgChAKIAoxHcACEApQCmEd0AIwCkEd4ApwAOACUAqACpACgAqgAXABcAFwApAEUAawBrEeYAMQBrAF0AawGrEb0AawBrEe4Aa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQF1CAiBAZYIgA4IgG2BAYwICIEBlQgSzopIvNMAOgA7AA4R8hH1AEqiAbQBtYBFgEaiEfYR94EBl4EBooAu2QAhACUR+gAOACgR+wAjAFwR/BHIAbQAXQB8ABcAKQAxAGsSBF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEBlIBFgA6ANYAAgAQIgQGY0wA6ADsADhIGEg8ASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgSEBIREhISExIUEhUSFhIXgQGZgQGagQGbgQGdgQGegQGfgQGggQGhgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcR9gBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBAZcICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXEfYAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQGXCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXEjkAFxH2AGsAawBrADEAawCzAcwAawBrABcAa4AAgQGcgACBAZcICAgIgB+ASwgIgAAI0wA6ADsADhJHEkgASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcR9gBrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACBAZcICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXEfYAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgQGXCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxH2AGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEBlwgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcR9gBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBAZcICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXEfYAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQGXCAgICIAfgFAICIAACNkAIQAlEpYADgAoEpcAIwBcEpgRyAG1AF0AfAAXACkAMQBrEqBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAZSARoAOgDWAAIAECIEBo9MAOgA7AA4SohKqAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKcSqxKsEq0SrhKvErASsYEBpIEBpoEBp4EBqIEBqoEBq4EBrIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcStQAXEfcAawBrAGsAMQBrALMCcABrAGsAFwBrgACBAaWAAIEBoggICAiAH4BeCAiAAAhRMd8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxH3AGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEBoggICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcR9wBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBAaIICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcS4wAXEfcAawBrAGsAMQBrALMCcwBrAGsAFwBrgACBAamAAIEBoggICAiAH4BhCAiAAAgQyN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxH3AGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEBoggICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcR9wBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBAaIICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXEfcAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQGiCAgICIAfgGQICIAACN8QEgChAKIAoxMfACEApQCmEyAAIwCkEyEApwAOACUAqACpACgAqgAXABcAFwApAEUAawBrEykAMQBrAF0AawGrEb4AawBrEzEAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQF1CAiBAa8IgA4IgG2BAY0ICIEBrggSzQAUx9MAOgA7AA4TNRM4AEqiAbQBtYBFgEaiEzkTOoEBsIEBu4Au2QAhACUTPQAOACgTPgAjAFwTPxHJAbQAXQB8ABcAKQAxAGsTR18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEBrYBFgA6ANYAAgAQIgQGx0wA6ADsADhNJE1IASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgTUxNUE1UTVhNXE1gTWRNagQGygQGzgQG0gQG2gQG3gQG4gQG5gQG6gC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcTOQBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBAbAICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXEzkAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQGwCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXE3wAFxM5AGsAawBrADEAawCzAcwAawBrABcAa4AAgQG1gACBAbAICAgIgB+ASwgIgAAI0wA6ADsADhOKE4sASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcTOQBrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACBAbAICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXEzkAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgQGwCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxM5AGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEBsAgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcTOQBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBAbAICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXEzkAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQGwCAgICIAfgFAICIAACNkAIQAlE9kADgAoE9oAIwBcE9sRyQG1AF0AfAAXACkAMQBrE+NfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAa2ARoAOgDWAAIAECIEBvNMAOgA7AA4T5RPtAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKcT7hPvE/AT8RPyE/MT9IEBvYEBvoEBv4EBwIEBwYEBwoEBw4Au3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXEzoAawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgQG7CAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxM6AGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEBuwgICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcTOgBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBAbsICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcLjAAXEzoAawBrAGsAMQBrALMCcwBrAGsAFwBrgACBARKAAIEBuwgICAiAH4BhCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcTOgBrAGsAawAxAGsAswJ0AGsAawAXAGuAAIAAgACBAbsICAgIgB+AYggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXEzoAawBrAGsAMQBrALMCdQBrAGsAFwBrgACAAIAAgQG7CAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxM6AGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAIEBuwgICAiAH4BkCAiAAAjfEBIAoQCiAKMUYAAhAKUAphRhACMApBRiAKcADgAlAKgAqQAoAKoAFwAXABcAKQBFAGsAaxRqADEAawBdAGsBqwF/AGsAaxRyAGtfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEBdQgIgQHGCIAOCIBtgD4ICIEBxQgSnH10WdMAOgA7AA4UdhR5AEqiAbQBtYBFgEaiFHoUe4EBx4EB0oAu2QAhACUUfgAOACgUfwAjAFwUgBHKAbQAXQB8ABcAKQAxAGsUiF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEBxIBFgA6ANYAAgAQIgQHI0wA6ADsADhSKFJMASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgUlBSVFJYUlxSYFJkUmhSbgQHJgQHKgQHLgQHNgQHOgQHPgQHQgQHRgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcUegBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBAccICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXFHoAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQHHCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXFL0AFxR6AGsAawBrADEAawCzAcwAawBrABcAa4AAgQHMgACBAccICAgIgB+ASwgIgAAI0wA6ADsADhTLFMwASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcUegBrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACBAccICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXFHoAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgQHHCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxR6AGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEBxwgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcUegBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBAccICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXFHoAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQHHCAgICIAfgFAICIAACNkAIQAlFRoADgAoFRsAIwBcFRwRygG1AF0AfAAXACkAMQBrFSRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAcSARoAOgDWAAIAECIEB09MAOgA7AA4VJhUuAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKcVLxUwFTEVMhUzFTQVNYEB1IEB1YEB1oEB14EB2IEB2YEB2oAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXFHsAawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgQHSCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxR7AGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEB0ggICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcUewBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBAdIICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcGgwAXFHsAawBrAGsAMQBrALMCcwBrAGsAFwBrgACAsYAAgQHSCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxR7AGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEB0ggICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcUewBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBAdIICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXFHsAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQHSCAgICIAfgGQICIAACN8QEgChAKIAoxWhACEApQCmFaIAIwCkFaMApwAOACUAqACpACgAqgAXABcAFwApAEUAawBrFasAMQBrAF0AawGrEcAAawBrFbMAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQF1CAiBAd0IgA4IgG2BAY4ICIEB3AgStsYFYdMAOgA7AA4VtxW6AEqiAbQBtYBFgEaiFbsVvIEB3oEB6YAu2QAhACUVvwAOACgVwAAjAFwVwRHLAbQAXQB8ABcAKQAxAGsVyV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEB24BFgA6ANYAAgAQIgQHf0wA6ADsADhXLFdQASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgV1RXWFdcV2BXZFdoV2xXcgQHggQHhgQHigQHkgQHlgQHmgQHngQHogC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcVuwBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBAd4ICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXFbsAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQHeCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXFf4AFxW7AGsAawBrADEAawCzAcwAawBrABcAa4AAgQHjgACBAd4ICAgIgB+ASwgIgAAI0wA6ADsADhYMFg0ASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcVuwBrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACBAd4ICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXFbsAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgQHeCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxW7AGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEB3ggICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcVuwBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBAd4ICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXFbsAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQHeCAgICIAfgFAICIAACNkAIQAlFlsADgAoFlwAIwBcFl0RywG1AF0AfAAXACkAMQBrFmVfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAduARoAOgDWAAIAECIEB6tMAOgA7AA4WZxZvAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKcWcBZxFnIWcxZ0FnUWdoEB64EB7IEB7YEB7oEB74EB8IEB8YAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcI2gAXFbwAawBrAGsAMQBrALMCcABrAGsAFwBrgACA3oAAgQHpCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxW8AGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEB6QgICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcVvABrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBAekICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcCtgAXFbwAawBrAGsAMQBrALMCcwBrAGsAFwBrgACAaYAAgQHpCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxW8AGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEB6QgICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcVvABrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBAekICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXFbwAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQHpCAgICIAfgGQICIAACN8QEgChAKIAoxbiACEApQCmFuMAIwCkFuQApwAOACUAqACpACgAqgAXABcAFwApAEUAawBrFuwAMQBrAF0AawGrEcEAawBrFvQAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQF1CAiBAfQIgA4IgG2BAY8ICIEB8wgSaTkzOtMAOgA7AA4W+Bb7AEqiAbQBtYBFgEaiFvwW/YEB9YECAIAu2QAhACUXAAAOACgXAQAjAFwXAhHMAbQAXQB8ABcAKQAxAGsXCl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEB8oBFgA6ANYAAgAQIgQH20wA6ADsADhcMFxUASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgXFhcXFxgXGRcaFxsXHBcdgQH3gQH4gQH5gQH7gQH8gQH9gQH+gQH/gC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcW/ABrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBAfUICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXFvwAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQH1CAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXFz8AFxb8AGsAawBrADEAawCzAcwAawBrABcAa4AAgQH6gACBAfUICAgIgB+ASwgIgAAI0wA6ADsADhdNF04ASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcW/ABrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACBAfUICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcCJgAXFvwAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAV4AAgQH1CAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxb8AGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEB9QgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcW/ABrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBAfUICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXFvwAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQH1CAgICIAfgFAICIAACNkAIQAlF5wADgAoF50AIwBcF54RzAG1AF0AfAAXACkAMQBrF6ZfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAfKARoAOgDWAAIAECIECAdMAOgA7AA4XqBewAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKcXsReyF7MXtBe1F7YXt4ECAoECA4ECBIECBYECBoECB4ECCIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXFv0AawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgQIACAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxb9AGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIECAAgICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcW/QBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBAgAICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcCtgAXFv0AawBrAGsAMQBrALMCcwBrAGsAFwBrgACAaYAAgQIACAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxb9AGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIECAAgICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcW/QBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBAgAICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXFv0AawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQIACAgICIAfgGQICIAACN8QEgChAKIAoxgjACEApQCmGCQAIwCkGCUApwAOACUAqACpACgAqgAXABcAFwApAEUAawBrGC0AMQBrAF0AawGrAO4AawBrGDUAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQF1CAiBAgsIgA4IgG2AJAgIgQIKCBLJaaWs0wA6ADsADhg5GDwASqIBtAG1gEWARqIYPRg+gQIMgQIXgC7ZACEAJRhBAA4AKBhCACMAXBhDEc0BtABdAHwAFwApADEAaxhLXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQIJgEWADoA1gACABAiBAg3TADoAOwAOGE0YVgBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqBhXGFgYWRhaGFsYXBhdGF6BAg6BAg+BAhCBAhKBAhOBAhSBAhWBAhaALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxg9AGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIECDAgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcYPQBrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBAgwICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcYgAAXGD0AawBrAGsAMQBrALMBzABrAGsAFwBrgACBAhGAAIECDAgICAiAH4BLCAiAAAjTADoAOwAOGI4YjwBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxg9AGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIECDAgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwImABcYPQBrAGsAawAxAGsAswHOAGsAawAXAGuAAIBXgACBAgwICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXGD0AawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQIMCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxg9AGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIECDAgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcYPQBrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBAgwICAgIgB+AUAgIgAAI2QAhACUY3QAOACgY3gAjAFwY3xHNAbUAXQB8ABcAKQAxAGsY518QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECCYBGgA6ANYAAgAQIgQIY0wA6ADsADhjpGPEASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4BkpxjyGPMY9Bj1GPYY9xj4gQIZgQIagQIbgQIcgQIdgQIegQIfgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcYPgBrAGsAawAxAGsAswJwAGsAawAXAGuAAIAAgACBAhcICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXGD4AawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQIXCAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxg+AGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIECFwgICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwQAABcYPgBrAGsAawAxAGsAswJzAGsAawAXAGuAAICCgACBAhcICAgIgB+AYQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXGD4AawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgQIXCAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxg+AGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIECFwgICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcYPgBrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACBAhcICAgIgB+AZAgIgAAI3xASAKEAogCjGWQAIQClAKYZZQAjAKQZZgCnAA4AJQCoAKkAKACqABcAFwAXACkARQBrAGsZbgAxAGsAXQBrAasRwwBrAGsZdgBrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAXUICIECIgiADgiAbYEBkAgIgQIhCBK/OFdg0wA6ADsADhl6GX0ASqIBtAG1gEWARqIZfhl/gQIjgQIugC7ZACEAJRmCAA4AKBmDACMAXBmEEc4BtABdAHwAFwApADEAaxmMXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQIggEWADoA1gACABAiBAiTTADoAOwAOGY4ZlwBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqBmYGZkZmhmbGZwZnRmeGZ+BAiWBAiaBAieBAimBAiqBAiuBAiyBAi2ALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxl+AGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIECIwgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcZfgBrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBAiMICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcZwQAXGX4AawBrAGsAMQBrALMBzABrAGsAFwBrgACBAiiAAIECIwgICAiAH4BLCAiAAAjTADoAOwAOGc8Z0ABKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxl+AGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIECIwgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwImABcZfgBrAGsAawAxAGsAswHOAGsAawAXAGuAAIBXgACBAiMICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXGX4AawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQIjCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxl+AGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIECIwgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcZfgBrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBAiMICAgIgB+AUAgIgAAI2QAhACUaHgAOACgaHwAjAFwaIBHOAbUAXQB8ABcAKQAxAGsaKF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECIIBGgA6ANYAAgAQIgQIv0wA6ADsADhoqGjIASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4BkpxozGjQaNRo2GjcaOBo5gQIwgQIxgQIygQIzgQI0gQI1gQI2gC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcZfwBrAGsAawAxAGsAswJwAGsAawAXAGuAAIAAgACBAi4ICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXGX8AawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQIuCAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxl/AGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIECLggICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwfFABcZfwBrAGsAawAxAGsAswJzAGsAawAXAGuAAIDJgACBAi4ICAgIgB+AYQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXGX8AawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgQIuCAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxl/AGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIECLggICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcZfwBrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACBAi4ICAgIgB+AZAgIgAAI3xASAKEAogCjGqUAIQClAKYapgAjAKQapwCnAA4AJQCoAKkAKACqABcAFwAXACkARQBrAGsarwAxAGsAXQBrAasRxABrAGsatwBrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAXUICIECOQiADgiAbYEBkQgIgQI4CBJ53RZe0wA6ADsADhq7Gr4ASqIBtAG1gEWARqIavxrAgQI6gQJFgC7ZACEAJRrDAA4AKBrEACMAXBrFEc8BtABdAHwAFwApADEAaxrNXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQI3gEWADoA1gACABAiBAjvTADoAOwAOGs8a2ABKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqBrZGtoa2xrcGt0a3hrfGuCBAjyBAj2BAj6BAkCBAkGBAkKBAkOBAkSALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxq/AGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIECOggICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcavwBrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBAjoICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcbAgAXGr8AawBrAGsAMQBrALMBzABrAGsAFwBrgACBAj+AAIECOggICAiAH4BLCAiAAAjTADoAOwAOGxAbEQBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxq/AGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIECOggICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwImABcavwBrAGsAawAxAGsAswHOAGsAawAXAGuAAIBXgACBAjoICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXGr8AawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQI6CAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxq/AGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIECOggICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcavwBrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBAjoICAgIgB+AUAgIgAAI2QAhACUbXwAOACgbYAAjAFwbYRHPAbUAXQB8ABcAKQAxAGsbaV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECN4BGgA6ANYAAgAQIgQJG0wA6ADsADhtrG3MASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4Bkpxt0G3Ubdht3G3gbeRt6gQJHgQJIgQJJgQJKgQJLgQJMgQJNgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcawABrAGsAawAxAGsAswJwAGsAawAXAGuAAIAAgACBAkUICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXGsAAawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQJFCAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxrAAGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIECRQgICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwfFABcawABrAGsAawAxAGsAswJzAGsAawAXAGuAAIDJgACBAkUICAgIgB+AYQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXGsAAawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgQJFCAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxrAAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIECRQgICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcawABrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACBAkUICAgIgB+AZAgIgAAI3xASAKEAogCjG+YAIQClAKYb5wAjAKQb6ACnAA4AJQCoAKkAKACqABcAFwAXACkARQBrAGsb8AAxAGsAXQBrAasRxQBrAGsb+ABrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAXUICIECUAiADgiAbYEBkggIgQJPCBJ6nkXk0wA6ADsADhv8G/8ASqIBtAG1gEWARqIcABwBgQJRgQJcgC7ZACEAJRwEAA4AKBwFACMAXBwGEdABtABdAHwAFwApADEAaxwOXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQJOgEWADoA1gACABAiBAlLTADoAOwAOHBAcGQBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqBwaHBscHBwdHB4cHxwgHCGBAlOBAlSBAlWBAleBAliBAlmBAlqBAluALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxwAAGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIECUQgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABccAABrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBAlEICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABccQwAXHAAAawBrAGsAMQBrALMBzABrAGsAFwBrgACBAlaAAIECUQgICAiAH4BLCAiAAAjTADoAOwAOHFEcUgBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFxwAAGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIECUQgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwImABccAABrAGsAawAxAGsAswHOAGsAawAXAGuAAIBXgACBAlEICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXHAAAawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQJRCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxwAAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIECUQgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABccAABrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBAlEICAgIgB+AUAgIgAAI2QAhACUcoAAOACgcoQAjAFwcohHQAbUAXQB8ABcAKQAxAGscql8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECToBGgA6ANYAAgAQIgQJd0wA6ADsADhysHLQASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4Bkpxy1HLYctxy4HLkcuhy7gQJegQJfgQJggQJhgQJigQJjgQJkgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABccAQBrAGsAawAxAGsAswJwAGsAawAXAGuAAIAAgACBAlwICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXHAEAawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQJcCAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxwBAGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIECXAgICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwfFABccAQBrAGsAawAxAGsAswJzAGsAawAXAGuAAIDJgACBAlwICAgIgB+AYQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXHAEAawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgQJcCAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFxwBAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIECXAgICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABccAQBrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACBAlwICAgIgB+AZAgIgAAI3xASAKEAogCjHScAIQClAKYdKAAjAKQdKQCnAA4AJQCoAKkAKACqABcAFwAXACkARQBrAGsdMQAxAGsAXQBrAasRxgBrAGsdOQBrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAXUICIECZwiADgiAbYEBkwgIgQJmCBJQMEs20wA6ADsADh09HUAASqIBtAG1gEWARqIdQR1CgQJogQJzgC7ZACEAJR1FAA4AKB1GACMAXB1HEdEBtABdAHwAFwApADEAax1PXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQJlgEWADoA1gACABAiBAmnTADoAOwAOHVEdWgBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqB1bHVwdXR1eHV8dYB1hHWKBAmqBAmuBAmyBAm6BAm+BAnCBAnGBAnKALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFx1BAGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIECaAgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcdQQBrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBAmgICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcdhAAXHUEAawBrAGsAMQBrALMBzABrAGsAFwBrgACBAm2AAIECaAgICAiAH4BLCAiAAAjTADoAOwAOHZIdkwBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFx1BAGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIECaAgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcdQQBrAGsAawAxAGsAswHOAGsAawAXAGuAAIArgACBAmgICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXHUEAawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQJoCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFx1BAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIECaAgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcdQQBrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBAmgICAgIgB+AUAgIgAAI2QAhACUd4QAOACgd4gAjAFwd4xHRAbUAXQB8ABcAKQAxAGsd618QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECZYBGgA6ANYAAgAQIgQJ00wA6ADsADh3tHfUASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4Bkpx32Hfcd+B35Hfod+x38gQJ1gQJ2gQJ3gQJ4gQJ5gQJ6gQJ7gC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwocABcdQgBrAGsAawAxAGsAswJwAGsAawAXAGuAAID2gACBAnMICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXHUIAawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQJzCAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFx1CAGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIECcwgICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFxLjABcdQgBrAGsAawAxAGsAswJzAGsAawAXAGuAAIEBqYAAgQJzCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFx1CAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIECcwgICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcdQgBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBAnMICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXHUIAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQJzCAgICIAfgGQICIAACNIAOwAOHmgAu6CAHt8QEB5rHmwebR5uACEebx5wACMecR5yAA4AJR5zHnQAKABcAF0edgApACkAFB56AGMAMQApAF0AZgA/AF0egR6CAGtfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2WADoECkoAEgASAAoECf4EBcoAEgA6BAXSACIAOgQOygQJ+CBLxelUG0wA6ADsADh6GHogASqEAcIAQoR6JgQKAgC7ZACEAJR6MAA4AKB6NACMAXB6OAEYAcABdAHwAFwApADEAax6WXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQJ9gBCADoA1gACABAiBAoHTADoAOwAOHpgeogBKqQCDAIQAhQCGAIcAiACJAIoAi4ATgBSAFYAWgBeAGIAZgBqAG6keox6kHqUeph6nHqgeqR6qHquBAoKBAoSBAoWBAomBAoqBAoyBAo2BAo+BApCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXHq8AFx6JAGsAawBrADEAawCzAIMAawBrABcAa4AAgQKDgACBAoAICAgIgB+AEwgIgAAI0gA7AA4evQC7oIAe3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXHokAawBrAGsAMQBrALMAhABrAGsAFwBrgACAAIAAgQKACAgICIAfgBQICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXHtAAFx6JAGsAawBrADEAawCzAIUAawBrABcAa4AAgQKGgACBAoAICAgIgB+AFQgIgAAI0gA7AA4e3gC7oR7fgQKHgB7SADsADh7iALuhHuOBAoiAHlNyYXffEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABceiQBrAGsAawAxAGsAswCGAGsAawAXAGuAAIAAgACBAoAICAgIgB+AFggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABce9wAXHokAawBrAGsAMQBrALMAhwBrAGsAFwBrgACBAouAAIECgAgICAiAH4AXCAiAAAjSADsADh8FALuggB7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABceiQBrAGsAawAxAGsAswCIAGsAawAXAGuAAIArgACBAoAICAgIgB+AGAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcfGAAXHokAawBrAGsAMQBrALMAiQBrAGsAFwBrgACBAo6AAIECgAgICAiAH4AZCAiAAAjTADoAOwAOHyYfJwBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXAUAAFx6JAGsAawBrADEAawCzAIoAawBrABcAa4AAgDCAAIECgAgICAiAH4AaCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFx86ABceiQBrAGsAawAxAGsAswCLAGsAawAXAGuAAIECkYAAgQKACAgICIAfgBsICIAACFouUHVtcEV2ZW500wA6ADsADh9JH1YASqwfSh9LHuMfTQF8H08fUB9RH1IfUx9UAYCBApOBApSBAoiBApWAO4ECloECl4ECmIECmYECmoECm4A/rB9XH1gfWR9aH1sfXB9dH14fXx9gH2EfYoECnIECs4ECyoEC4oEC+YEDEIEDKIEDP4EDVoEDbYEDhIEDm4AuWGRvc2VUeXBlVHVuaXRUdHlwZVdtdXRhYmxlVGRhdGVVdGl0bGVYdXBsb2FkZWRYZHVyYXRpb25eZGVsaXZlcmVkVW5pdHPfEBIAoQCiAKMfbgAhAKUAph9vACMApB9wAKcADgAlAKgAqQAoAKoAFwAXABcAKQBGAGsAax94ADEAawBdAGsBqx9KAGsAax+AAGtfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIECfQgIgQKeCIAOCIBtgQKTCAiBAp0IEssfc//TADoAOwAOH4QfhwBKogG0AbWARYBGoh+IH4mBAp+BAqqALtkAIQAlH4wADgAoH40AIwBcH44fVwG0AF0AfAAXACkAMQBrH5ZfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBApyARYAOgDWAAIAECIECoNMAOgA7AA4fmB+hAEqoAcoBywHMAc0BzgHPAdAB0YBJgEqAS4BMgE2AToBPgFCoH6Ifox+kH6Ufph+nH6gfqYECoYECooECo4ECpYECpoECp4ECqIECqYAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXH4gAawBrAGsAMQBrALMBygBrAGsAFwBrgACAK4AAgQKfCAgICIAfgEkICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFx+IAGsAawBrADEAawCzAcsAawBrABcAa4AAgACAAIECnwgICAiAH4BKCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFx/LABcfiABrAGsAawAxAGsAswHMAGsAawAXAGuAAIECpIAAgQKfCAgICIAfgEsICIAACNMAOgA7AA4f2R/aAEqgoIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXH4gAawBrAGsAMQBrALMBzQBrAGsAFwBrgACAK4AAgQKfCAgICIAfgEwICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXAiYAFx+IAGsAawBrADEAawCzAc4AawBrABcAa4AAgFeAAIECnwgICAiAH4BNCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcfiABrAGsAawAxAGsAswHPAGsAawAXAGuAAIArgACBAp8ICAgIgB+ATggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXH4gAawBrAGsAMQBrALMB0ABrAGsAFwBrgACAAIAAgQKfCAgICIAfgE8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFx+IAGsAawBrADEAawCzAdEAawBrABcAa4AAgCuAAIECnwgICAiAH4BQCAiAAAjZACEAJSAoAA4AKCApACMAXCAqH1cBtQBdAHwAFwApADEAayAyXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQKcgEaADoA1gACABAiBAqvTADoAOwAOIDQgPABKpwJwAnECcgJzAnQCdQJ2gF6AX4BggGGAYoBjgGSnID0gPiA/IEAgQSBCIEOBAqyBAq2BAq6BAq+BArCBArGBArKALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFx+JAGsAawBrADEAawCzAnAAawBrABcAa4AAgACAAIECqggICAiAH4BeCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcfiQBrAGsAawAxAGsAswJxAGsAawAXAGuAAIArgACBAqoICAgIgB+AXwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXH4kAawBrAGsAMQBrALMCcgBrAGsAFwBrgACAAIAAgQKqCAgICIAfgGAICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXB8UAFx+JAGsAawBrADEAawCzAnMAawBrABcAa4AAgMmAAIECqggICAiAH4BhCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcfiQBrAGsAawAxAGsAswJ0AGsAawAXAGuAAIAAgACBAqoICAgIgB+AYggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXH4kAawBrAGsAMQBrALMCdQBrAGsAFwBrgACAAIAAgQKqCAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFx+JAGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAIECqggICAiAH4BkCAiAAAjfEBIAoQCiAKMgrwAhAKUApiCwACMApCCxAKcADgAlAKgAqQAoAKoAFwAXABcAKQBGAGsAayC5ADEAawBdAGsBqx9LAGsAayDBAGtfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIECfQgIgQK1CIAOCIBtgQKUCAiBArQIElDo+MXTADoAOwAOIMUgyABKogG0AbWARYBGoiDJIMqBAraBAsGALtkAIQAlIM0ADgAoIM4AIwBcIM8fWAG0AF0AfAAXACkAMQBrINdfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBArOARYAOgDWAAIAECIECt9MAOgA7AA4g2SDiAEqoAcoBywHMAc0BzgHPAdAB0YBJgEqAS4BMgE2AToBPgFCoIOMg5CDlIOYg5yDoIOkg6oECuIECuYECuoECvIECvYECvoECv4ECwIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXIMkAawBrAGsAMQBrALMBygBrAGsAFwBrgACAK4AAgQK2CAgICIAfgEkICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFyDJAGsAawBrADEAawCzAcsAawBrABcAa4AAgACAAIECtggICAiAH4BKCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFyEMABcgyQBrAGsAawAxAGsAswHMAGsAawAXAGuAAIECu4AAgQK2CAgICIAfgEsICIAACNMAOgA7AA4hGiEbAEqgoIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXIMkAawBrAGsAMQBrALMBzQBrAGsAFwBrgACAK4AAgQK2CAgICIAfgEwICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXAiYAFyDJAGsAawBrADEAawCzAc4AawBrABcAa4AAgFeAAIECtggICAiAH4BNCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcgyQBrAGsAawAxAGsAswHPAGsAawAXAGuAAIArgACBArYICAgIgB+ATggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXIMkAawBrAGsAMQBrALMB0ABrAGsAFwBrgACAAIAAgQK2CAgICIAfgE8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFyDJAGsAawBrADEAawCzAdEAawBrABcAa4AAgCuAAIECtggICAiAH4BQCAiAAAjZACEAJSFpAA4AKCFqACMAXCFrH1gBtQBdAHwAFwApADEAayFzXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQKzgEaADoA1gACABAiBAsLTADoAOwAOIXUhfQBKpwJwAnECcgJzAnQCdQJ2gF6AX4BggGGAYoBjgGSnIX4hfyGAIYEhgiGDIYSBAsOBAsSBAsWBAsaBAseBAsiBAsmALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFyDKAGsAawBrADEAawCzAnAAawBrABcAa4AAgACAAIECwQgICAiAH4BeCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcgygBrAGsAawAxAGsAswJxAGsAawAXAGuAAIArgACBAsEICAgIgB+AXwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXIMoAawBrAGsAMQBrALMCcgBrAGsAFwBrgACAAIAAgQLBCAgICIAfgGAICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXB8UAFyDKAGsAawBrADEAawCzAnMAawBrABcAa4AAgMmAAIECwQgICAiAH4BhCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcgygBrAGsAawAxAGsAswJ0AGsAawAXAGuAAIAAgACBAsEICAgIgB+AYggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXIMoAawBrAGsAMQBrALMCdQBrAGsAFwBrgACAAIAAgQLBCAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFyDKAGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAIECwQgICAiAH4BkCAiAAAjfEBIAoQCiAKMh8AAhAKUApiHxACMApCHyAKcADgAlAKgAqQAoAKoAFwAXABcAKQBGAGsAayH6ADEAawBdAGsBqx7jAGsAayICAGtfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIECfQgIgQLMCIAOCIBtgQKICAiBAssIEwAAAAEUEQ7I0wA6ADsADiIGIgkASqIBtAG1gEWARqIiCiILgQLNgQLYgC7ZACEAJSIOAA4AKCIPACMAXCIQH1kBtABdAHwAFwApADEAayIYXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQLKgEWADoA1gACABAiBAs7TADoAOwAOIhoiIwBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqCIkIiUiJiInIigiKSIqIiuBAs+BAtCBAtGBAtOBAtSBAtWBAtaBAteALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFyIKAGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIECzQgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABciCgBrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBAs0ICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABciTQAXIgoAawBrAGsAMQBrALMBzABrAGsAFwBrgACBAtKAAIECzQgICAiAH4BLCAiAAAjTADoAOwAOIlsiXABKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFyIKAGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIECzQgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwImABciCgBrAGsAawAxAGsAswHOAGsAawAXAGuAAIBXgACBAs0ICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXIgoAawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQLNCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFyIKAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIECzQgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABciCgBrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBAs0ICAgIgB+AUAgIgAAI2QAhACUiqgAOACgiqwAjAFwirB9ZAbUAXQB8ABcAKQAxAGsitF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECyoBGgA6ANYAAgAQIgQLZ0wA6ADsADiK2Ir4ASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4BkpyK/IsAiwSLCIsMixCLFgQLagQLbgQLcgQLdgQLfgQLggQLhgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABciCwBrAGsAawAxAGsAswJwAGsAawAXAGuAAIAAgACBAtgICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXIgsAawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQLYCAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFyILAGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIEC2AgICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFyL2ABciCwBrAGsAawAxAGsAswJzAGsAawAXAGuAAIEC3oAAgQLYCAgICIAfgGEICIAACBED6N8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFyILAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEC2AgICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABciCwBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBAtgICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXIgsAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQLYCAgICIAfgGQICIAACN8QEgChAKIAoyMyACEApQCmIzMAIwCkIzQApwAOACUAqACpACgAqgAXABcAFwApAEYAawBrIzwAMQBrAF0AawGrH00AawBrI0QAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQJ9CAiBAuQIgA4IgG2BApUICIEC4wgSZ/XSyNMAOgA7AA4jSCNLAEqiAbQBtYBFgEaiI0wjTYEC5YEC8IAu2QAhACUjUAAOACgjUQAjAFwjUh9aAbQAXQB8ABcAKQAxAGsjWl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEC4oBFgA6ANYAAgAQIgQLm0wA6ADsADiNcI2UASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgjZiNnI2gjaSNqI2sjbCNtgQLngQLogQLpgQLrgQLsgQLtgQLugQLvgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcjTABrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBAuUICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXI0wAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQLlCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXI48AFyNMAGsAawBrADEAawCzAcwAawBrABcAa4AAgQLqgACBAuUICAgIgB+ASwgIgAAI0wA6ADsADiOdI54ASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwImABcjTABrAGsAawAxAGsAswHNAGsAawAXAGuAAIBXgACBAuUICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcCJgAXI0wAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAV4AAgQLlCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFyNMAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEC5QgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcjTABrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBAuUICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXI0wAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQLlCAgICIAfgFAICIAACNkAIQAlI+wADgAoI+0AIwBcI+4fWgG1AF0AfAAXACkAMQBrI/ZfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAuKARoAOgDWAAIAECIEC8dMAOgA7AA4j+CQAAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKckASQCJAMkBCQFJAYkB4EC8oEC84EC9IEC9YEC9oEC94EC+IAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXI00AawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgQLwCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFyNNAGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEC8AgICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcjTQBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBAvAICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcHxQAXI00AawBrAGsAMQBrALMCcwBrAGsAFwBrgACAyYAAgQLwCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFyNNAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEC8AgICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcjTQBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBAvAICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXI00AawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQLwCAgICIAfgGQICIAACN8QEgChAKIAoyRzACEApQCmJHQAIwCkJHUApwAOACUAqACpACgAqgAXABcAFwApAEYAawBrJH0AMQBrAF0AawGrAXwAawBrJIUAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQJ9CAiBAvsIgA4IgG2AOwgIgQL6CBMAAAABGo6retMAOgA7AA4kiSSMAEqiAbQBtYBFgEaiJI0kjoEC/IEDB4Au2QAhACUkkQAOACgkkgAjAFwkkx9bAbQAXQB8ABcAKQAxAGskm18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEC+YBFgA6ANYAAgAQIgQL90wA6ADsADiSdJKYASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgkpySoJKkkqiSrJKwkrSSugQL+gQL/gQMAgQMCgQMDgQMEgQMFgQMGgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABckjQBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBAvwICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXJI0AawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQL8CAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXJNAAFySNAGsAawBrADEAawCzAcwAawBrABcAa4AAgQMBgACBAvwICAgIgB+ASwgIgAAI0wA6ADsADiTeJN8ASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABckjQBrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACBAvwICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcCJgAXJI0AawBrAGsAMQBrALMBzgBrAGsAFwBrgACAV4AAgQL8CAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFySNAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEC/AgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABckjQBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBAvwICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXJI0AawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQL8CAgICIAfgFAICIAACNkAIQAlJS0ADgAoJS4AIwBcJS8fWwG1AF0AfAAXACkAMQBrJTdfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAvmARoAOgDWAAIAECIEDCNMAOgA7AA4lOSVBAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKclQiVDJUQlRSVGJUclSIEDCYEDCoEDC4EDDIEDDYEDDoEDD4Au3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXJI4AawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgQMHCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFySOAGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEDBwgICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABckjgBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBAwcICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcCtgAXJI4AawBrAGsAMQBrALMCcwBrAGsAFwBrgACAaYAAgQMHCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFySOAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEDBwgICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABckjgBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBAwcICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXJI4AawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQMHCAgICIAfgGQICIAACN8QEgChAKIAoyW0ACEApQCmJbUAIwCkJbYApwAOACUAqACpACgAqgAXABcAFwApAEYAawBrJb4AMQBrAF0AawGrH08AawBrJcYAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQJ9CAiBAxIIgA4IgG2BApYICIEDEQgSmuQJ6dMAOgA7AA4lyiXNAEqiAbQBtYBFgEaiJc4lz4EDE4EDHoAu2QAhACUl0gAOACgl0wAjAFwl1B9cAbQAXQB8ABcAKQAxAGsl3F8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDEIBFgA6ANYAAgAQIgQMU0wA6ADsADiXeJecASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgl6CXpJeol6yXsJe0l7iXvgQMVgQMWgQMXgQMZgQMagQMbgQMcgQMdgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABclzgBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBAxMICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXJc4AawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQMTCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXJhEAFyXOAGsAawBrADEAawCzAcwAawBrABcAa4AAgQMYgACBAxMICAgIgB+ASwgIgAAI0wA6ADsADiYfJiAASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwImABclzgBrAGsAawAxAGsAswHNAGsAawAXAGuAAIBXgACBAxMICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXJc4AawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgQMTCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFyXOAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEDEwgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABclzgBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBAxMICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXJc4AawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQMTCAgICIAfgFAICIAACNkAIQAlJm4ADgAoJm8AIwBcJnAfXAG1AF0AfAAXACkAMQBrJnhfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAxCARoAOgDWAAIAECIEDH9MAOgA7AA4meiaCAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKcmgyaEJoUmhiaHJogmiYEDIIEDIoEDI4EDJIEDJYEDJoEDJ4Au3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcmjQAXJc8AawBrAGsAMQBrALMCcABrAGsAFwBrgACBAyGAAIEDHggICAiAH4BeCAiAAAhSTk/fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABclzwBrAGsAawAxAGsAswJxAGsAawAXAGuAAIArgACBAx4ICAgIgB+AXwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXJc8AawBrAGsAMQBrALMCcgBrAGsAFwBrgACAAIAAgQMeCAgICIAfgGAICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXC4wAFyXPAGsAawBrADEAawCzAnMAawBrABcAa4AAgQESgACBAx4ICAgIgB+AYQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXJc8AawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgQMeCAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFyXPAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIEDHggICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABclzwBrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACBAx4ICAgIgB+AZAgIgAAI3xASAKEAogCjJvYAIQClAKYm9wAjAKQm+ACnAA4AJQCoAKkAKACqABcAFwAXACkARgBrAGsnAAAxAGsAXQBrAasfUABrAGsnCABrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAn0ICIEDKgiADgiAbYEClwgIgQMpCBI8s5gH0wA6ADsADicMJw8ASqIBtAG1gEWARqInECcRgQMrgQM2gC7ZACEAJScUAA4AKCcVACMAXCcWH10BtABdAHwAFwApADEAayceXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQMogEWADoA1gACABAiBAyzTADoAOwAOJyAnKQBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqCcqJysnLCctJy4nLycwJzGBAy2BAy6BAy+BAzGBAzKBAzOBAzSBAzWALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFycQAGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIEDKwgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcnEABrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBAysICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcnUwAXJxAAawBrAGsAMQBrALMBzABrAGsAFwBrgACBAzCAAIEDKwgICAiAH4BLCAiAAAjTADoAOwAOJ2EnYgBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXAiYAFycQAGsAawBrADEAawCzAc0AawBrABcAa4AAgFeAAIEDKwgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcnEABrAGsAawAxAGsAswHOAGsAawAXAGuAAIArgACBAysICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXJxAAawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQMrCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFycQAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIEDKwgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcnEABrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBAysICAgIgB+AUAgIgAAI2QAhACUnsAAOACgnsQAjAFwnsh9dAbUAXQB8ABcAKQAxAGsnul8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDKIBGgA6ANYAAgAQIgQM30wA6ADsADie8J8QASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4BkpyfFJ8YnxyfIJ8knyifLgQM4gQM5gQM6gQM7gQM8gQM9gQM+gC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcnEQBrAGsAawAxAGsAswJwAGsAawAXAGuAAIAAgACBAzYICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXJxEAawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQM2CAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFycRAGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIEDNggICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwaDABcnEQBrAGsAawAxAGsAswJzAGsAawAXAGuAAICxgACBAzYICAgIgB+AYQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXJxEAawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgQM2CAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFycRAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIEDNggICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcnEQBrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACBAzYICAgIgB+AZAgIgAAI3xASAKEAogCjKDcAIQClAKYoOAAjAKQoOQCnAA4AJQCoAKkAKACqABcAFwAXACkARgBrAGsoQQAxAGsAXQBrAasfUQBrAGsoSQBrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAn0ICIEDQQiADgiAbYECmAgIgQNACBMAAAABDU29pNMAOgA7AA4oTShQAEqiAbQBtYBFgEaiKFEoUoEDQoEDTYAu2QAhACUoVQAOACgoVgAjAFwoVx9eAbQAXQB8ABcAKQAxAGsoX18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDP4BFgA6ANYAAgAQIgQND0wA6ADsADihhKGoASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgoayhsKG0obihvKHAocShygQNEgQNFgQNGgQNIgQNJgQNKgQNLgQNMgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcoUQBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBA0IICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXKFEAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQNCCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXKJQAFyhRAGsAawBrADEAawCzAcwAawBrABcAa4AAgQNHgACBA0IICAgIgB+ASwgIgAAI0wA6ADsADiiiKKMASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcoUQBrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACBA0IICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcCJgAXKFEAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAV4AAgQNCCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFyhRAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEDQggICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcoUQBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBA0IICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXKFEAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQNCCAgICIAfgFAICIAACNkAIQAlKPEADgAoKPIAIwBcKPMfXgG1AF0AfAAXACkAMQBrKPtfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAz+ARoAOgDWAAIAECIEDTtMAOgA7AA4o/SkFAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKcpBikHKQgpCSkKKQspDIEDT4EDUIEDUYEDUoEDU4EDVIEDVYAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXKFIAawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgQNNCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFyhSAGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEDTQgICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcoUgBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBA00ICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcHxQAXKFIAawBrAGsAMQBrALMCcwBrAGsAFwBrgACAyYAAgQNNCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFyhSAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEDTQgICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcoUgBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBA00ICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXKFIAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQNNCAgICIAfgGQICIAACN8QEgChAKIAoyl4ACEApQCmKXkAIwCkKXoApwAOACUAqACpACgAqgAXABcAFwApAEYAawBrKYIAMQBrAF0AawGrH1IAawBrKYoAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQJ9CAiBA1gIgA4IgG2BApkICIEDVwgSqPL85NMAOgA7AA4pjimRAEqiAbQBtYBFgEaiKZIpk4EDWYEDZIAu2QAhACUplgAOACgplwAjAFwpmB9fAbQAXQB8ABcAKQAxAGspoF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDVoBFgA6ANYAAgAQIgQNa0wA6ADsADimiKasASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgprCmtKa4prymwKbEpsimzgQNbgQNcgQNdgQNfgQNggQNhgQNigQNjgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcpkgBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBA1kICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXKZIAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQNZCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXKdUAFymSAGsAawBrADEAawCzAcwAawBrABcAa4AAgQNegACBA1kICAgIgB+ASwgIgAAI0wA6ADsADinjKeQASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwImABcpkgBrAGsAawAxAGsAswHNAGsAawAXAGuAAIBXgACBA1kICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXKZIAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgQNZCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFymSAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEDWQgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcpkgBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBA1kICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXKZIAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQNZCAgICIAfgFAICIAACNkAIQAlKjIADgAoKjMAIwBcKjQfXwG1AF0AfAAXACkAMQBrKjxfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBA1aARoAOgDWAAIAECIEDZdMAOgA7AA4qPipGAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKcqRypIKkkqSipLKkwqTYEDZoEDZ4EDaIEDaYEDaoEDa4EDbIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcmjQAXKZMAawBrAGsAMQBrALMCcABrAGsAFwBrgACBAyGAAIEDZAgICAiAH4BeCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcpkwBrAGsAawAxAGsAswJxAGsAawAXAGuAAIArgACBA2QICAgIgB+AXwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXKZMAawBrAGsAMQBrALMCcgBrAGsAFwBrgACAAIAAgQNkCAgICIAfgGAICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXC4wAFymTAGsAawBrADEAawCzAnMAawBrABcAa4AAgQESgACBA2QICAgIgB+AYQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXKZMAawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgQNkCAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFymTAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIEDZAgICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcpkwBrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACBA2QICAgIgB+AZAgIgAAI3xASAKEAogCjKrkAIQClAKYqugAjAKQquwCnAA4AJQCoAKkAKACqABcAFwAXACkARgBrAGsqwwAxAGsAXQBrAasfUwBrAGsqywBrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAn0ICIEDbwiADgiAbYECmggIgQNuCBJJQHTB0wA6ADsADirPKtIASqIBtAG1gEWARqIq0yrUgQNwgQN7gC7ZACEAJSrXAA4AKCrYACMAXCrZH2ABtABdAHwAFwApADEAayrhXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQNtgEWADoA1gACABAiBA3HTADoAOwAOKuMq7ABKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqCrtKu4q7yrwKvEq8irzKvSBA3KBA3OBA3SBA3aBA3eBA3iBA3mBA3qALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFyrTAGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIEDcAgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcq0wBrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBA3AICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcrFgAXKtMAawBrAGsAMQBrALMBzABrAGsAFwBrgACBA3WAAIEDcAgICAiAH4BLCAiAAAjTADoAOwAOKyQrJQBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFyrTAGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIEDcAgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcq0wBrAGsAawAxAGsAswHOAGsAawAXAGuAAIArgACBA3AICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXKtMAawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQNwCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFyrTAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIEDcAgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcq0wBrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBA3AICAgIgB+AUAgIgAAI2QAhACUrcwAOACgrdAAjAFwrdR9gAbUAXQB8ABcAKQAxAGsrfV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDbYBGgA6ANYAAgAQIgQN80wA6ADsADit/K4cASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4BkpyuIK4kriiuLK4wrjSuOgQN9gQN+gQN/gQOAgQOBgQOCgQODgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwjaABcq1ABrAGsAawAxAGsAswJwAGsAawAXAGuAAIDegACBA3sICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXKtQAawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQN7CAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXChwAFyrUAGsAawBrADEAawCzAnIAawBrABcAa4AAgPaAAIEDewgICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwK2ABcq1ABrAGsAawAxAGsAswJzAGsAawAXAGuAAIBpgACBA3sICAgIgB+AYQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXKtQAawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgQN7CAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFyrUAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIEDewgICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcq1ABrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACBA3sICAgIgB+AZAgIgAAI3xASAKEAogCjK/oAIQClAKYr+wAjAKQr/ACnAA4AJQCoAKkAKACqABcAFwAXACkARgBrAGssBAAxAGsAXQBrAasfVABrAGssDABrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAn0ICIEDhgiADgiAbYECmwgIgQOFCBIrFwtf0wA6ADsADiwQLBMASqIBtAG1gEWARqIsFCwVgQOHgQOSgC7ZACEAJSwYAA4AKCwZACMAXCwaH2EBtABdAHwAFwApADEAaywiXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQOEgEWADoA1gACABAiBA4jTADoAOwAOLCQsLQBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqCwuLC8sMCwxLDIsMyw0LDWBA4mBA4qBA4uBA42BA46BA4+BA5CBA5GALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFywUAGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIEDhwgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcsFABrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBA4cICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcsVwAXLBQAawBrAGsAMQBrALMBzABrAGsAFwBrgACBA4yAAIEDhwgICAiAH4BLCAiAAAjTADoAOwAOLGUsZgBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFywUAGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIEDhwgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwImABcsFABrAGsAawAxAGsAswHOAGsAawAXAGuAAIBXgACBA4cICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXLBQAawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQOHCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFywUAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIEDhwgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcsFABrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBA4cICAgIgB+AUAgIgAAI2QAhACUstAAOACgstQAjAFwsth9hAbUAXQB8ABcAKQAxAGssvl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDhIBGgA6ANYAAgAQIgQOT0wA6ADsADizALMgASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4BkpyzJLMosyyzMLM0szizPgQOUgQOVgQOWgQOXgQOYgQOZgQOagC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcsFQBrAGsAawAxAGsAswJwAGsAawAXAGuAAIAAgACBA5IICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXLBUAawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQOSCAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFywVAGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIEDkggICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwK2ABcsFQBrAGsAawAxAGsAswJzAGsAawAXAGuAAIBpgACBA5IICAgIgB+AYQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXLBUAawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgQOSCAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFywVAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIEDkggICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcsFQBrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACBA5IICAgIgB+AZAgIgAAI3xASAKEAogCjLTsAIQClAKYtPAAjAKQtPQCnAA4AJQCoAKkAKACqABcAFwAXACkARgBrAGstRQAxAGsAXQBrAasBgABrAGstTQBrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAn0ICIEDnQiADgiAbYA/CAiBA5wIEn8njKPTADoAOwAOLVEtVABKogG0AbWARYBGoi1VLVaBA56BA6mALtkAIQAlLVkADgAoLVoAIwBcLVsfYgG0AF0AfAAXACkAMQBrLWNfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBA5uARYAOgDWAAIAECIEDn9MAOgA7AA4tZS1uAEqoAcoBywHMAc0BzgHPAdAB0YBJgEqAS4BMgE2AToBPgFCoLW8tcC1xLXItcy10LXUtdoEDoIEDoYEDooEDpIEDpYEDpoEDp4EDqIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXLVUAawBrAGsAMQBrALMBygBrAGsAFwBrgACAK4AAgQOeCAgICIAfgEkICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFy1VAGsAawBrADEAawCzAcsAawBrABcAa4AAgACAAIEDnggICAiAH4BKCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFy2YABctVQBrAGsAawAxAGsAswHMAGsAawAXAGuAAIEDo4AAgQOeCAgICIAfgEsICIAACNMAOgA7AA4tpi2nAEqgoIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXLVUAawBrAGsAMQBrALMBzQBrAGsAFwBrgACAK4AAgQOeCAgICIAfgEwICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFy1VAGsAawBrADEAawCzAc4AawBrABcAa4AAgCuAAIEDnggICAiAH4BNCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABctVQBrAGsAawAxAGsAswHPAGsAawAXAGuAAIArgACBA54ICAgIgB+ATggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXLVUAawBrAGsAMQBrALMB0ABrAGsAFwBrgACAAIAAgQOeCAgICIAfgE8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFy1VAGsAawBrADEAawCzAdEAawBrABcAa4AAgCuAAIEDnggICAiAH4BQCAiAAAjZACEAJS31AA4AKC32ACMAXC33H2IBtQBdAHwAFwApADEAay3/XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQObgEaADoA1gACABAiBA6rTADoAOwAOLgEuCQBKpwJwAnECcgJzAnQCdQJ2gF6AX4BggGGAYoBjgGSnLgouCy4MLg0uDi4PLhCBA6uBA6yBA62BA66BA6+BA7CBA7GALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFy1WAGsAawBrADEAawCzAnAAawBrABcAa4AAgACAAIEDqQgICAiAH4BeCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABctVgBrAGsAawAxAGsAswJxAGsAawAXAGuAAIArgACBA6kICAgIgB+AXwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXLVYAawBrAGsAMQBrALMCcgBrAGsAFwBrgACAAIAAgQOpCAgICIAfgGAICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXBoMAFy1WAGsAawBrADEAawCzAnMAawBrABcAa4AAgLGAAIEDqQgICAiAH4BhCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABctVgBrAGsAawAxAGsAswJ0AGsAawAXAGuAAIAAgACBA6kICAgIgB+AYggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXLVYAawBrAGsAMQBrALMCdQBrAGsAFwBrgACAAIAAgQOpCAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFy1WAGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAIEDqQgICAiAH4BkCAiAAAjSADsADi58ALuggB7fEBAufy6ALoEuggAhLoMuhAAjLoUuhgAOACUuhy6IACgAXABdLooAKQApABQujgBjADEAKQBdAGYAQABdLpUulgBrXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlgA6BA8iABIAEgAKBA7WBAXKABIAOgQF0gAmADoEED4EDtAgShC1Fn9MAOgA7AA4umi6cAEqhAHCAEKEunYEDtoAu2QAhACUuoAAOACguoQAjAFwuogBHAHAAXQB8ABcAKQAxAGsuql8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDs4AQgA6ANYAAgAQIgQO30wA6ADsADi6sLrYASqkAgwCEAIUAhgCHAIgAiQCKAIuAE4AUgBWAFoAXgBiAGYAagBupLrcuuC65Lrouuy68Lr0uvi6/gQO4gQO6gQO7gQO/gQPAgQPCgQPDgQPFgQPGgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFy7DABcunQBrAGsAawAxAGsAswCDAGsAawAXAGuAAIEDuYAAgQO2CAgICIAfgBMICIAACNIAOwAOLtEAu6CAHt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFy6dAGsAawBrADEAawCzAIQAawBrABcAa4AAgACAAIEDtggICAiAH4AUCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFy7kABcunQBrAGsAawAxAGsAswCFAGsAawAXAGuAAIEDvIAAgQO2CAgICIAfgBUICIAACNIAOwAOLvIAu6Eu84EDvYAe0gA7AA4u9gC7oS73gQO+gB5aZXh0ZXJuYWxJRN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFy6dAGsAawBrADEAawCzAIYAawBrABcAa4AAgACAAIEDtggICAiAH4AWCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFy8LABcunQBrAGsAawAxAGsAswCHAGsAawAXAGuAAIEDwYAAgQO2CAgICIAfgBcICIAACNIAOwAOLxkAu6CAHt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFy6dAGsAawBrADEAawCzAIgAawBrABcAa4AAgCuAAIEDtggICAiAH4AYCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFy8sABcunQBrAGsAawAxAGsAswCJAGsAawAXAGuAAIEDxIAAgQO2CAgICIAfgBkICIAACNMAOgA7AA4vOi87AEqgoIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBQAAXLp0AawBrAGsAMQBrALMAigBrAGsAFwBrgACAMIAAgQO2CAgICIAfgBoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXL04AFy6dAGsAawBrADEAawCzAIsAawBrABcAa4AAgQPHgACBA7YICAgIgB+AGwgIgAAIXxASLkRlbGV0ZWRDYXJiT2JqZWN00wA6ADsADi9dL2EASqMRxi9fAX+BAZOBA8mAPqMvYi9jL2SBA8qBA+GBA/iALlpleHRlcm5hbElE3xASAKEAogCjL2gAIQClAKYvaQAjAKQvagCnAA4AJQCoAKkAKACqABcAFwAXACkARwBrAGsvcgAxAGsAXQBrAasRxgBrAGsvegBrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBA7MICIEDzAiADgiAbYEBkwgIgQPLCBMAAAABHLDToNMAOgA7AA4vfi+BAEqiAbQBtYBFgEaiL4Ivg4EDzYED2IAu2QAhACUvhgAOACgvhwAjAFwviC9iAbQAXQB8ABcAKQAxAGsvkF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDyoBFgA6ANYAAgAQIgQPO0wA6ADsADi+SL5sASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgvnC+dL54vny+gL6Evoi+jgQPPgQPQgQPRgQPTgQPUgQPVgQPWgQPXgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcvggBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBA80ICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXL4IAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQPNCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXL8UAFy+CAGsAawBrADEAawCzAcwAawBrABcAa4AAgQPSgACBA80ICAgIgB+ASwgIgAAI0wA6ADsADi/TL9QASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcvggBrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACBA80ICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXL4IAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgQPNCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFy+CAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEDzQgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcvggBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBA80ICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXL4IAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQPNCAgICIAfgFAICIAACNkAIQAlMCIADgAoMCMAIwBcMCQvYgG1AF0AfAAXACkAMQBrMCxfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBA8qARoAOgDWAAIAECIED2dMAOgA7AA4wLjA2AEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKcwNzA4MDkwOjA7MDwwPYED2oED24ED3IED3YED3oED34ED4IAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcKHAAXL4MAawBrAGsAMQBrALMCcABrAGsAFwBrgACA9oAAgQPYCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFy+DAGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIED2AgICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcvgwBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBA9gICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcS4wAXL4MAawBrAGsAMQBrALMCcwBrAGsAFwBrgACBAamAAIED2AgICAiAH4BhCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcvgwBrAGsAawAxAGsAswJ0AGsAawAXAGuAAIAAgACBA9gICAgIgB+AYggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXL4MAawBrAGsAMQBrALMCdQBrAGsAFwBrgACAAIAAgQPYCAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFy+DAGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAIED2AgICAiAH4BkCAiAAAjfEBIAoQCiAKMwqQAhAKUApjCqACMApDCrAKcADgAlAKgAqQAoAKoAFwAXABcAKQBHAGsAazCzADEAawBdAGsBqy9fAGsAazC7AGtfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEDswgIgQPjCIAOCIBtgQPJCAiBA+IIEk77a7jTADoAOwAOML8wwgBKogG0AbWARYBGojDDMMSBA+SBA++ALtkAIQAlMMcADgAoMMgAIwBcMMkvYwG0AF0AfAAXACkAMQBrMNFfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBA+GARYAOgDWAAIAECIED5dMAOgA7AA4w0zDcAEqoAcoBywHMAc0BzgHPAdAB0YBJgEqAS4BMgE2AToBPgFCoMN0w3jDfMOAw4TDiMOMw5IED5oED54ED6IED6oED64ED7IED7YED7oAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXMMMAawBrAGsAMQBrALMBygBrAGsAFwBrgACAK4AAgQPkCAgICIAfgEkICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzDDAGsAawBrADEAawCzAcsAawBrABcAa4AAgACAAIED5AgICAiAH4BKCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFzEGABcwwwBrAGsAawAxAGsAswHMAGsAawAXAGuAAIED6YAAgQPkCAgICIAfgEsICIAACNMAOgA7AA4xFDEVAEqgoIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXMMMAawBrAGsAMQBrALMBzQBrAGsAFwBrgACAK4AAgQPkCAgICIAfgEwICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzDDAGsAawBrADEAawCzAc4AawBrABcAa4AAgCuAAIED5AgICAiAH4BNCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcwwwBrAGsAawAxAGsAswHPAGsAawAXAGuAAIArgACBA+QICAgIgB+ATggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXMMMAawBrAGsAMQBrALMB0ABrAGsAFwBrgACAAIAAgQPkCAgICIAfgE8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzDDAGsAawBrADEAawCzAdEAawBrABcAa4AAgCuAAIED5AgICAiAH4BQCAiAAAjZACEAJTFjAA4AKDFkACMAXDFlL2MBtQBdAHwAFwApADEAazFtXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQPhgEaADoA1gACABAiBA/DTADoAOwAOMW8xdwBKpwJwAnECcgJzAnQCdQJ2gF6AX4BggGGAYoBjgGSnMXgxeTF6MXsxfDF9MX6BA/GBA/KBA/OBA/SBA/WBA/aBA/eALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzDEAGsAawBrADEAawCzAnAAawBrABcAa4AAgACAAIED7wgICAiAH4BeCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcwxABrAGsAawAxAGsAswJxAGsAawAXAGuAAIArgACBA+8ICAgIgB+AXwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXMMQAawBrAGsAMQBrALMCcgBrAGsAFwBrgACAAIAAgQPvCAgICIAfgGAICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXB8UAFzDEAGsAawBrADEAawCzAnMAawBrABcAa4AAgMmAAIED7wgICAiAH4BhCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcwxABrAGsAawAxAGsAswJ0AGsAawAXAGuAAIAAgACBA+8ICAgIgB+AYggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXMMQAawBrAGsAMQBrALMCdQBrAGsAFwBrgACAAIAAgQPvCAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzDEAGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAIED7wgICAiAH4BkCAiAAAjfEBIAoQCiAKMx6gAhAKUApjHrACMApDHsAKcADgAlAKgAqQAoAKoAFwAXABcAKQBHAGsAazH0ADEAawBdAGsBqwF/AGsAazH8AGtfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEDswgIgQP6CIAOCIBtgD4ICIED+QgSdJGxtdMAOgA7AA4yADIDAEqiAbQBtYBFgEaiMgQyBYED+4EEBoAu2QAhACUyCAAOACgyCQAjAFwyCi9kAbQAXQB8ABcAKQAxAGsyEl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYED+IBFgA6ANYAAgAQIgQP80wA6ADsADjIUMh0ASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKgyHjIfMiAyITIiMiMyJDIlgQP9gQP+gQP/gQQBgQQCgQQDgQQEgQQFgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcyBABrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBA/sICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXMgQAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQP7CAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXMkcAFzIEAGsAawBrADEAawCzAcwAawBrABcAa4AAgQQAgACBA/sICAgIgB+ASwgIgAAI0wA6ADsADjJVMlYASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABcyBABrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACBA/sICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXMgQAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgQP7CAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzIEAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIED+wgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcyBABrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBA/sICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXMgQAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQP7CAgICIAfgFAICIAACNkAIQAlMqQADgAoMqUAIwBcMqYvZAG1AF0AfAAXACkAMQBrMq5fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBA/iARoAOgDWAAIAECIEEB9MAOgA7AA4ysDK4AEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKcyuTK6MrsyvDK9Mr4yv4EECIEECYEECoEEC4EEDIEEDYEEDoAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXMgUAawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgQQGCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzIFAGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEEBggICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcyBQBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBBAYICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcGgwAXMgUAawBrAGsAMQBrALMCcwBrAGsAFwBrgACAsYAAgQQGCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzIFAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEEBggICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABcyBQBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBBAYICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXMgUAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQQGCAgICIAfgGQICIAACNIAOwAOMysAu6CAHt8QEDMuMy8zMDMxACEzMjMzACMzNDM1AA4AJTM2MzcAKABcAF0zOQApACkAFDM9AGMAMQApAF0AZgBBAF0zRDNFAGtfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2WADoEEJoAEgASAAoEEEoEBcoAEgA6BAXSACoAOgQT7gQQRCBJX1ZcF0wA6ADsADjNJM0sASqEAcIAQoTNMgQQTgC7ZACEAJTNPAA4AKDNQACMAXDNRAEgAcABdAHwAFwApADEAazNZXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQQQgBCADoA1gACABAiBBBTTADoAOwAOM1szZQBKqQCDAIQAhQCGAIcAiACJAIoAi4ATgBSAFYAWgBeAGIAZgBqAG6kzZjNnM2gzaTNqM2szbDNtM26BBBWBBBeBBBiBBB2BBB6BBCCBBCGBBCOBBCSALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXM3IAFzNMAGsAawBrADEAawCzAIMAawBrABcAa4AAgQQWgACBBBMICAgIgB+AEwgIgAAI0gA7AA4zgAC7oIAe3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXM0wAawBrAGsAMQBrALMAhABrAGsAFwBrgACAAIAAgQQTCAgICIAfgBQICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXM5MAFzNMAGsAawBrADEAawCzAIUAawBrABcAa4AAgQQZgACBBBMICAgIgB+AFQgIgAAI0gA7AA4zoQC7ojOiM6OBBBqBBBuAHtIAOwAOM6YAu6EA7oAkgB7SADsADjOqALuhM6uBBByAHl5zeW5jSWRlbnRpZmllct8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzNMAGsAawBrADEAawCzAIYAawBrABcAa4AAgACAAIEEEwgICAiAH4AWCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFzO/ABczTABrAGsAawAxAGsAswCHAGsAawAXAGuAAIEEH4AAgQQTCAgICIAfgBcICIAACNIAOwAOM80Au6CAHt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzNMAGsAawBrADEAawCzAIgAawBrABcAa4AAgCuAAIEEEwgICAiAH4AYCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFzPgABczTABrAGsAawAxAGsAswCJAGsAawAXAGuAAIEEIoAAgQQTCAgICIAfgBkICIAACNMAOgA7AA4z7jPvAEqgoIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBQAAXM0wAawBrAGsAMQBrALMAigBrAGsAFwBrgACAMIAAgQQTCAgICIAfgBoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXNAIAFzNMAGsAawBrADEAawCzAIsAawBrABcAa4AAgQQlgACBBBMICAgIgB+AGwgIgAAIXxAULkNhY2hlZEdsdWNvc2VPYmplY3TTADoAOwAONBE0GwBKqTQSAX80FDQVAO40FwF8EcY0GoEEJ4A+gQQogQQpgCSBBCqAO4EBk4EEK6k0HDQdNB40HzQgNCE0IjQjNCSBBCyBBEOBBFqBBHGBBIiBBJ+BBLaBBM2BBOSALltzeW5jVmVyc2lvbl1pc0Rpc3BsYXlPbmx5WnVuaXRTdHJpbmdec3luY0lkZW50aWZpZXJfEBRwcm92ZW5hbmNlSWRlbnRpZmllct8QEgChAKIAozQsACEApQCmNC0AIwCkNC4ApwAOACUAqACpACgAqgAXABcAFwApAEgAawBrNDYAMQBrAF0AawGrNBIAawBrND4Aa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQQQCAiBBC4IgA4IgG2BBCcICIEELQgTAAAAAQUDPCjTADoAOwAONEI0RQBKogG0AbWARYBGojRGNEeBBC+BBDqALtkAIQAlNEoADgAoNEsAIwBcNEw0HAG0AF0AfAAXACkAMQBrNFRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBCyARYAOgDWAAIAECIEEMNMAOgA7AA40VjRfAEqoAcoBywHMAc0BzgHPAdAB0YBJgEqAS4BMgE2AToBPgFCoNGA0YTRiNGM0ZDRlNGY0Z4EEMYEEMoEEM4EENYEENoEEN4EEOIEEOYAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXNEYAawBrAGsAMQBrALMBygBrAGsAFwBrgACAK4AAgQQvCAgICIAfgEkICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzRGAGsAawBrADEAawCzAcsAawBrABcAa4AAgACAAIEELwgICAiAH4BKCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFzSJABc0RgBrAGsAawAxAGsAswHMAGsAawAXAGuAAIEENIAAgQQvCAgICIAfgEsICIAACNMAOgA7AA40lzSYAEqgoIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXNEYAawBrAGsAMQBrALMBzQBrAGsAFwBrgACAK4AAgQQvCAgICIAfgEwICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzRGAGsAawBrADEAawCzAc4AawBrABcAa4AAgCuAAIEELwgICAiAH4BNCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc0RgBrAGsAawAxAGsAswHPAGsAawAXAGuAAIArgACBBC8ICAgIgB+ATggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXNEYAawBrAGsAMQBrALMB0ABrAGsAFwBrgACAAIAAgQQvCAgICIAfgE8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzRGAGsAawBrADEAawCzAdEAawBrABcAa4AAgCuAAIEELwgICAiAH4BQCAiAAAjZACEAJTTmAA4AKDTnACMAXDToNBwBtQBdAHwAFwApADEAazTwXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQQsgEaADoA1gACABAiBBDvTADoAOwAONPI0+gBKpwJwAnECcgJzAnQCdQJ2gF6AX4BggGGAYoBjgGSnNPs0/DT9NP40/zUANQGBBDyBBD2BBD6BBD+BBECBBEGBBEKALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXErUAFzRHAGsAawBrADEAawCzAnAAawBrABcAa4AAgQGlgACBBDoICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXNEcAawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQQ6CAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzRHAGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIEEOggICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFxLjABc0RwBrAGsAawAxAGsAswJzAGsAawAXAGuAAIEBqYAAgQQ6CAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzRHAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEEOggICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc0RwBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBBDoICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXNEcAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQQ6CAgICIAfgGQICIAACN8QEgChAKIAozVtACEApQCmNW4AIwCkNW8ApwAOACUAqACpACgAqgAXABcAFwApAEgAawBrNXcAMQBrAF0AawGrAX8AawBrNX8Aa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQQQCAiBBEUIgA4IgG2APggIgQRECBLFSrC50wA6ADsADjWDNYYASqIBtAG1gEWARqI1hzWIgQRGgQRRgC7ZACEAJTWLAA4AKDWMACMAXDWNNB0BtABdAHwAFwApADEAazWVXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQRDgEWADoA1gACABAiBBEfTADoAOwAONZc1oABKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqDWhNaI1ozWkNaU1pjWnNaiBBEiBBEmBBEqBBEyBBE2BBE6BBE+BBFCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzWHAGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIEERggICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc1hwBrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBBEYICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABc1ygAXNYcAawBrAGsAMQBrALMBzABrAGsAFwBrgACBBEuAAIEERggICAiAH4BLCAiAAAjTADoAOwAONdg12QBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXAiYAFzWHAGsAawBrADEAawCzAc0AawBrABcAa4AAgFeAAIEERggICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc1hwBrAGsAawAxAGsAswHOAGsAawAXAGuAAIArgACBBEYICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXNYcAawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQRGCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzWHAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIEERggICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc1hwBrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBBEYICAgIgB+AUAgIgAAI2QAhACU2JwAOACg2KAAjAFw2KTQdAbUAXQB8ABcAKQAxAGs2MV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEEQ4BGgA6ANYAAgAQIgQRS0wA6ADsADjYzNjsASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4BkpzY8Nj02PjY/NkA2QTZCgQRTgQRUgQRVgQRWgQRXgQRYgQRZgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc1iABrAGsAawAxAGsAswJwAGsAawAXAGuAAIAAgACBBFEICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXNYgAawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQRRCAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzWIAGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIEEUQgICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwaDABc1iABrAGsAawAxAGsAswJzAGsAawAXAGuAAICxgACBBFEICAgIgB+AYQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXNYgAawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgQRRCAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzWIAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIEEUQgICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc1iABrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACBBFEICAgIgB+AZAgIgAAI3xASAKEAogCjNq4AIQClAKY2rwAjAKQ2sACnAA4AJQCoAKkAKACqABcAFwAXACkASABrAGs2uAAxAGsAXQBrAas0FABrAGs2wABrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBBBAICIEEXAiADgiAbYEEKAgIgQRbCBJNHFQi0wA6ADsADjbENscASqIBtAG1gEWARqI2yDbJgQRdgQRogC7ZACEAJTbMAA4AKDbNACMAXDbONB4BtABdAHwAFwApADEAazbWXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQRagEWADoA1gACABAiBBF7TADoAOwAONtg24QBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqDbiNuM25DblNuY25zboNumBBF+BBGCBBGGBBGOBBGSBBGWBBGaBBGeALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzbIAGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIEEXQgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc2yABrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBBF0ICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABc3CwAXNsgAawBrAGsAMQBrALMBzABrAGsAFwBrgACBBGKAAIEEXQgICAiAH4BLCAiAAAjTADoAOwAONxk3GgBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzbIAGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIEEXQgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc2yABrAGsAawAxAGsAswHOAGsAawAXAGuAAIArgACBBF0ICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXNsgAawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQRdCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzbIAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIEEXQgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc2yABrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBBF0ICAgIgB+AUAgIgAAI2QAhACU3aAAOACg3aQAjAFw3ajQeAbUAXQB8ABcAKQAxAGs3cl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEEWoBGgA6ANYAAgAQIgQRp0wA6ADsADjd0N3wASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4Bkpzd9N343fzeAN4E3gjeDgQRqgQRrgQRsgQRtgQRugQRvgQRwgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFyaNABc2yQBrAGsAawAxAGsAswJwAGsAawAXAGuAAIEDIYAAgQRoCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzbJAGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEEaAgICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc2yQBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBBGgICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcLjAAXNskAawBrAGsAMQBrALMCcwBrAGsAFwBrgACBARKAAIEEaAgICAiAH4BhCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc2yQBrAGsAawAxAGsAswJ0AGsAawAXAGuAAIAAgACBBGgICAgIgB+AYggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXNskAawBrAGsAMQBrALMCdQBrAGsAFwBrgACAAIAAgQRoCAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzbJAGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAIEEaAgICAiAH4BkCAiAAAjfEBIAoQCiAKM37wAhAKUApjfwACMApDfxAKcADgAlAKgAqQAoAKoAFwAXABcAKQBIAGsAazf5ADEAawBdAGsBqzQVAGsAazgBAGtfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEEEAgIgQRzCIAOCIBtgQQpCAiBBHIIErVdGYXTADoAOwAOOAU4CABKogG0AbWARYBGojgJOAqBBHSBBH+ALtkAIQAlOA0ADgAoOA4AIwBcOA80HwG0AF0AfAAXACkAMQBrOBdfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBHGARYAOgDWAAIAECIEEddMAOgA7AA44GTgiAEqoAcoBywHMAc0BzgHPAdAB0YBJgEqAS4BMgE2AToBPgFCoOCM4JDglOCY4JzgoOCk4KoEEdoEEd4EEeIEEeoEEe4EEfIEEfYEEfoAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXOAkAawBrAGsAMQBrALMBygBrAGsAFwBrgACAK4AAgQR0CAgICIAfgEkICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzgJAGsAawBrADEAawCzAcsAawBrABcAa4AAgACAAIEEdAgICAiAH4BKCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFzhMABc4CQBrAGsAawAxAGsAswHMAGsAawAXAGuAAIEEeYAAgQR0CAgICIAfgEsICIAACNMAOgA7AA44WjhbAEqgoIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXOAkAawBrAGsAMQBrALMBzQBrAGsAFwBrgACAK4AAgQR0CAgICIAfgEwICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzgJAGsAawBrADEAawCzAc4AawBrABcAa4AAgCuAAIEEdAgICAiAH4BNCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc4CQBrAGsAawAxAGsAswHPAGsAawAXAGuAAIArgACBBHQICAgIgB+ATggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXOAkAawBrAGsAMQBrALMB0ABrAGsAFwBrgACAAIAAgQR0CAgICIAfgE8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzgJAGsAawBrADEAawCzAdEAawBrABcAa4AAgCuAAIEEdAgICAiAH4BQCAiAAAjZACEAJTipAA4AKDiqACMAXDirNB8BtQBdAHwAFwApADEAazizXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQRxgEaADoA1gACABAiBBIDTADoAOwAOOLU4vQBKpwJwAnECcgJzAnQCdQJ2gF6AX4BggGGAYoBjgGSnOL44vzjAOME4wjjDOMSBBIGBBIKBBIOBBISBBIWBBIaBBIeALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzgKAGsAawBrADEAawCzAnAAawBrABcAa4AAgACAAIEEfwgICAiAH4BeCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc4CgBrAGsAawAxAGsAswJxAGsAawAXAGuAAIArgACBBH8ICAgIgB+AXwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXOAoAawBrAGsAMQBrALMCcgBrAGsAFwBrgACAAIAAgQR/CAgICIAfgGAICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXB8UAFzgKAGsAawBrADEAawCzAnMAawBrABcAa4AAgMmAAIEEfwgICAiAH4BhCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc4CgBrAGsAawAxAGsAswJ0AGsAawAXAGuAAIAAgACBBH8ICAgIgB+AYggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXOAoAawBrAGsAMQBrALMCdQBrAGsAFwBrgACAAIAAgQR/CAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzgKAGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAIEEfwgICAiAH4BkCAiAAAjfEBIAoQCiAKM5MAAhAKUApjkxACMApDkyAKcADgAlAKgAqQAoAKoAFwAXABcAKQBIAGsAazk6ADEAawBdAGsBqwDuAGsAazlCAGtfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEEEAgIgQSKCIAOCIBtgCQICIEEiQgSeMtDbdMAOgA7AA45RjlJAEqiAbQBtYBFgEaiOUo5S4EEi4EEloAu2QAhACU5TgAOACg5TwAjAFw5UDQgAbQAXQB8ABcAKQAxAGs5WF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEEiIBFgA6ANYAAgAQIgQSM0wA6ADsADjlaOWMASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKg5ZDllOWY5ZzloOWk5ajlrgQSNgQSOgQSPgQSRgQSSgQSTgQSUgQSVgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc5SgBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBBIsICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXOUoAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQSLCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXOY0AFzlKAGsAawBrADEAawCzAcwAawBrABcAa4AAgQSQgACBBIsICAgIgB+ASwgIgAAI0wA6ADsADjmbOZwASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwImABc5SgBrAGsAawAxAGsAswHNAGsAawAXAGuAAIBXgACBBIsICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXOUoAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgQSLCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzlKAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEEiwgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc5SgBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBBIsICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXOUoAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQSLCAgICIAfgFAICIAACNkAIQAlOeoADgAoOesAIwBcOew0IAG1AF0AfAAXACkAMQBrOfRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBIiARoAOgDWAAIAECIEEl9MAOgA7AA459jn+AEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKc5/zoAOgE6AjoDOgQ6BYEEmIEEmYEEmoEEm4EEnIEEnYEEnoAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXOUsAawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgQSWCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzlLAGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEElggICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc5SwBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBBJYICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcEAAAXOUsAawBrAGsAMQBrALMCcwBrAGsAFwBrgACAgoAAgQSWCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzlLAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEElggICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc5SwBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBBJYICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXOUsAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQSWCAgICIAfgGQICIAACN8QEgChAKIAozpxACEApQCmOnIAIwCkOnMApwAOACUAqACpACgAqgAXABcAFwApAEgAawBrOnsAMQBrAF0AawGrNBcAawBrOoMAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQQQCAiBBKEIgA4IgG2BBCoICIEEoAgStEj1ntMAOgA7AA46hzqKAEqiAbQBtYBFgEaiOos6jIEEooEErYAu2QAhACU6jwAOACg6kAAjAFw6kTQhAbQAXQB8ABcAKQAxAGs6mV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEEn4BFgA6ANYAAgAQIgQSj0wA6ADsADjqbOqQASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKg6pTqmOqc6qDqpOqo6qzqsgQSkgQSlgQSmgQSogQSpgQSqgQSrgQSsgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc6iwBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBBKIICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXOosAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQSiCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXOs4AFzqLAGsAawBrADEAawCzAcwAawBrABcAa4AAgQSngACBBKIICAgIgB+ASwgIgAAI0wA6ADsADjrcOt0ASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwImABc6iwBrAGsAawAxAGsAswHNAGsAawAXAGuAAIBXgACBBKIICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXOosAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgQSiCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzqLAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEEoggICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc6iwBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBBKIICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXOosAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQSiCAgICIAfgFAICIAACNkAIQAlOysADgAoOywAIwBcOy00IQG1AF0AfAAXACkAMQBrOzVfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBJ+ARoAOgDWAAIAECIEErtMAOgA7AA47Nzs/AEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKc7QDtBO0I7QztEO0U7RoEEr4EEsIEEsYEEsoEEs4EEtIEEtYAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXOowAawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgQStCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzqMAGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEErQgICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc6jABrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBBK0ICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcHxQAXOowAawBrAGsAMQBrALMCcwBrAGsAFwBrgACAyYAAgQStCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzqMAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEErQgICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc6jABrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBBK0ICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXOowAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQStCAgICIAfgGQICIAACN8QEgChAKIAozuyACEApQCmO7MAIwCkO7QApwAOACUAqACpACgAqgAXABcAFwApAEgAawBrO7wAMQBrAF0AawGrAXwAawBrO8QAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQQQCAiBBLgIgA4IgG2AOwgIgQS3CBJ+04F30wA6ADsADjvIO8sASqIBtAG1gEWARqI7zDvNgQS5gQTEgC7ZACEAJTvQAA4AKDvRACMAXDvSNCIBtABdAHwAFwApADEAazvaXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQS2gEWADoA1gACABAiBBLrTADoAOwAOO9w75QBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqDvmO+c76DvpO+o76zvsO+2BBLuBBLyBBL2BBL+BBMCBBMGBBMKBBMOALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzvMAGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIEEuQgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc7zABrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBBLkICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABc8DwAXO8wAawBrAGsAMQBrALMBzABrAGsAFwBrgACBBL6AAIEEuQgICAiAH4BLCAiAAAjTADoAOwAOPB08HgBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFzvMAGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIEEuQgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc7zABrAGsAawAxAGsAswHOAGsAawAXAGuAAIArgACBBLkICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXO8wAawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQS5CAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzvMAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIEEuQgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc7zABrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBBLkICAgIgB+AUAgIgAAI2QAhACU8bAAOACg8bQAjAFw8bjQiAbUAXQB8ABcAKQAxAGs8dl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEEtoBGgA6ANYAAgAQIgQTF0wA6ADsADjx4PIAASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4BkpzyBPII8gzyEPIU8hjyHgQTGgQTHgQTIgQTJgQTKgQTLgQTMgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc7zQBrAGsAawAxAGsAswJwAGsAawAXAGuAAIAAgACBBMQICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXO80AawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQTECAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzvNAGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIEExAgICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwK2ABc7zQBrAGsAawAxAGsAswJzAGsAawAXAGuAAIBpgACBBMQICAgIgB+AYQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXO80AawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgQTECAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFzvNAGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIEExAgICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc7zQBrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACBBMQICAgIgB+AZAgIgAAI3xASAKEAogCjPPMAIQClAKY89AAjAKQ89QCnAA4AJQCoAKkAKACqABcAFwAXACkASABrAGs8/QAxAGsAXQBrAasRxgBrAGs9BQBrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBBBAICIEEzwiADgiAbYEBkwgIgQTOCBLt3AUT0wA6ADsADj0JPQwASqIBtAG1gEWARqI9DT0OgQTQgQTbgC7ZACEAJT0RAA4AKD0SACMAXD0TNCMBtABdAHwAFwApADEAaz0bXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQTNgEWADoA1gACABAiBBNHTADoAOwAOPR09JgBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqD0nPSg9KT0qPSs9LD0tPS6BBNKBBNOBBNSBBNaBBNeBBNiBBNmBBNqALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFz0NAGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIEE0AgICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc9DQBrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBBNAICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABc9UAAXPQ0AawBrAGsAMQBrALMBzABrAGsAFwBrgACBBNWAAIEE0AgICAiAH4BLCAiAAAjTADoAOwAOPV49XwBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFz0NAGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIEE0AgICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc9DQBrAGsAawAxAGsAswHOAGsAawAXAGuAAIArgACBBNAICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXPQ0AawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQTQCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFz0NAGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIEE0AgICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc9DQBrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBBNAICAgIgB+AUAgIgAAI2QAhACU9rQAOACg9rgAjAFw9rzQjAbUAXQB8ABcAKQAxAGs9t18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEEzYBGgA6ANYAAgAQIgQTc0wA6ADsADj25PcEASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4Bkpz3CPcM9xD3FPcY9xz3IgQTdgQTegQTfgQTggQThgQTigQTjgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwocABc9DgBrAGsAawAxAGsAswJwAGsAawAXAGuAAID2gACBBNsICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXPQ4AawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQTbCAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFz0OAGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIEE2wgICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFxLjABc9DgBrAGsAawAxAGsAswJzAGsAawAXAGuAAIEBqYAAgQTbCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFz0OAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEE2wgICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc9DgBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBBNsICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXPQ4AawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQTbCAgICIAfgGQICIAACN8QEgChAKIAoz40ACEApQCmPjUAIwCkPjYApwAOACUAqACpACgAqgAXABcAFwApAEgAawBrPj4AMQBrAF0AawGrNBoAawBrPkYAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQQQCAiBBOYIgA4IgG2BBCsICIEE5QgSQVjDvtMAOgA7AA4+Sj5NAEqiAbQBtYBFgEaiPk4+T4EE54EE8oAu2QAhACU+UgAOACg+UwAjAFw+VDQkAbQAXQB8ABcAKQAxAGs+XF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEE5IBFgA6ANYAAgAQIgQTo0wA6ADsADj5ePmcASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKg+aD5pPmo+az5sPm0+bj5vgQTpgQTqgQTrgQTtgQTugQTvgQTwgQTxgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc+TgBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBBOcICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXPk4AawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQTnCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXPpEAFz5OAGsAawBrADEAawCzAcwAawBrABcAa4AAgQTsgACBBOcICAgIgB+ASwgIgAAI0wA6ADsADj6fPqAASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABc+TgBrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACBBOcICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXPk4AawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgQTnCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFz5OAGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEE5wgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc+TgBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBBOcICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXPk4AawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQTnCAgICIAfgFAICIAACNkAIQAlPu4ADgAoPu8AIwBcPvA0JAG1AF0AfAAXACkAMQBrPvhfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBOSARoAOgDWAAIAECIEE89MAOgA7AA4++j8CAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKc/Az8EPwU/Bj8HPwg/CYEE9IEE9YEE9oEE94EE+IEE+YEE+oAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXPk8AawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgQTyCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAFz5PAGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEE8ggICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc+TwBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBBPIICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcHxQAXPk8AawBrAGsAMQBrALMCcwBrAGsAFwBrgACAyYAAgQTyCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAFz5PAGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEE8ggICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABc+TwBrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBBPIICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXPk8AawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQTyCAgICIAfgGQICIAACNIAOwAOP3UAu6CAHt8QED94P3k/ej97ACE/fD99ACM/fj9/AA4AJT+AP4EAKABcAF0/gwApACkAFD+HAGMAMQApAF0AZgBCAF0/jj+PAGtfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2WADoEFD4AEgASAAoEE/oEBcoAEgA6BAXSAC4AOgQVtgQT9CBKt7xe10wA6ADsADj+TP5UASqEAcIAQoT+WgQT/gC7ZACEAJT+ZAA4AKD+aACMAXD+bAEkAcABdAHwAFwApADEAaz+jXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQT8gBCADoA1gACABAiBBQDTADoAOwAOP6U/rwBKqQCDAIQAhQCGAIcAiACJAIoAi4ATgBSAFYAWgBeAGIAZgBqAG6k/sD+xP7I/sz+0P7U/tj+3P7iBBQGBBQOBBQSBBQaBBQeBBQmBBQqBBQyBBQ2ALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXP7wAFz+WAGsAawBrADEAawCzAIMAawBrABcAa4AAgQUCgACBBP8ICAgIgB+AEwgIgAAI0gA7AA4/ygC7oIAe3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXP5YAawBrAGsAMQBrALMAhABrAGsAFwBrgACAAIAAgQT/CAgICIAfgBQICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXP90AFz+WAGsAawBrADEAawCzAIUAawBrABcAa4AAgQUFgACBBP8ICAgIgB+AFQgIgAAI0gA7AA4/6wC7oIAe3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXP5YAawBrAGsAMQBrALMAhgBrAGsAFwBrgACAAIAAgQT/CAgICIAfgBYICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXP/4AFz+WAGsAawBrADEAawCzAIcAawBrABcAa4AAgQUIgACBBP8ICAgIgB+AFwgIgAAI0gA7AA5ADAC7oIAe3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXP5YAawBrAGsAMQBrALMAiABrAGsAFwBrgACAK4AAgQT/CAgICIAfgBgICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXQB8AFz+WAGsAawBrADEAawCzAIkAawBrABcAa4AAgQULgACBBP8ICAgIgB+AGQgIgAAI0wA6ADsADkAtQC4ASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwFAABc/lgBrAGsAawAxAGsAswCKAGsAawAXAGuAAIAwgACBBP8ICAgIgB+AGggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABdAQQAXP5YAawBrAGsAMQBrALMAiwBrAGsAFwBrgACBBQ6AAIEE/wgICAiAH4AbCAiAAAhaLlJlc2Vydm9pctMAOgA7AA5AUEBVAEqkH1Ae40BTAYCBApeBAoiBBRCAP6RAVkBXQFhAWYEFEYEFKIEFP4EFVoAuVnZvbHVtZd8QEgChAKIAo0BdACEApQCmQF4AIwCkQF8ApwAOACUAqACpACgAqgAXABcAFwApAEkAawBrQGcAMQBrAF0AawGrH1AAawBrQG8Aa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQT8CAiBBRMIgA4IgG2BApcICIEFEggSbuTWLNMAOgA7AA5Ac0B2AEqiAbQBtYBFgEaiQHdAeIEFFIEFH4Au2QAhACVAewAOAChAfAAjAFxAfUBWAbQAXQB8ABcAKQAxAGtAhV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEFEYBFgA6ANYAAgAQIgQUV0wA6ADsADkCHQJAASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKhAkUCSQJNAlECVQJZAl0CYgQUWgQUXgQUYgQUagQUbgQUcgQUdgQUegC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABdAdwBrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBBRQICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXQHcAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQUUCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXQLoAF0B3AGsAawBrADEAawCzAcwAawBrABcAa4AAgQUZgACBBRQICAgIgB+ASwgIgAAI0wA6ADsADkDIQMkASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABdAdwBrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACBBRQICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXQHcAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAK4AAgQUUCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAF0B3AGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEFFAgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABdAdwBrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBBRQICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXQHcAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQUUCAgICIAfgFAICIAACNkAIQAlQRcADgAoQRgAIwBcQRlAVgG1AF0AfAAXACkAMQBrQSFfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBRGARoAOgDWAAIAECIEFINMAOgA7AA5BI0ErAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKdBLEEtQS5BL0EwQTFBMoEFIYEFIoEFI4EFJIEFJYEFJoEFJ4Au3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXQHgAawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgQUfCAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAF0B4AGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEFHwgICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABdAeABrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBBR8ICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcGgwAXQHgAawBrAGsAMQBrALMCcwBrAGsAFwBrgACAsYAAgQUfCAgICIAfgGEICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAF0B4AGsAawBrADEAawCzAnQAawBrABcAa4AAgACAAIEFHwgICAiAH4BiCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABdAeABrAGsAawAxAGsAswJ1AGsAawAXAGuAAIAAgACBBR8ICAgIgB+AYwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXQHgAawBrAGsAMQBrALMCdgBrAGsAFwBrgACAAIAAgQUfCAgICIAfgGQICIAACN8QEgChAKIAo0GeACEApQCmQZ8AIwCkQaAApwAOACUAqACpACgAqgAXABcAFwApAEkAawBrQagAMQBrAF0AawGrHuMAawBrQbAAa18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQT8CAiBBSoIgA4IgG2BAogICIEFKQgSUaYQg9MAOgA7AA5BtEG3AEqiAbQBtYBFgEaiQbhBuYEFK4EFNoAu2QAhACVBvAAOAChBvQAjAFxBvkBXAbQAXQB8ABcAKQAxAGtBxl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEFKIBFgA6ANYAAgAQIgQUs0wA6ADsADkHIQdEASqgBygHLAcwBzQHOAc8B0AHRgEmASoBLgEyATYBOgE+AUKhB0kHTQdRB1UHWQddB2EHZgQUtgQUugQUvgQUxgQUygQUzgQU0gQU1gC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABdBuABrAGsAawAxAGsAswHKAGsAawAXAGuAAIArgACBBSsICAgIgB+ASQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXQbgAawBrAGsAMQBrALMBywBrAGsAFwBrgACAAIAAgQUrCAgICIAfgEoICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXQfsAF0G4AGsAawBrADEAawCzAcwAawBrABcAa4AAgQUwgACBBSsICAgIgB+ASwgIgAAI0wA6ADsADkIJQgoASqCggC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABdBuABrAGsAawAxAGsAswHNAGsAawAXAGuAAIArgACBBSsICAgIgB+ATAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcCJgAXQbgAawBrAGsAMQBrALMBzgBrAGsAFwBrgACAV4AAgQUrCAgICIAfgE0ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAF0G4AGsAawBrADEAawCzAc8AawBrABcAa4AAgCuAAIEFKwgICAiAH4BOCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABdBuABrAGsAawAxAGsAswHQAGsAawAXAGuAAIAAgACBBSsICAgIgB+ATwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXQbgAawBrAGsAMQBrALMB0QBrAGsAFwBrgACAK4AAgQUrCAgICIAfgFAICIAACNkAIQAlQlgADgAoQlkAIwBcQlpAVwG1AF0AfAAXACkAMQBrQmJfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBSiARoAOgDWAAIAECIEFN9MAOgA7AA5CZEJsAEqnAnACcQJyAnMCdAJ1AnaAXoBfgGCAYYBigGOAZKdCbUJuQm9CcEJxQnJCc4EFOIEFOYEFOoEFO4EFPIEFPYEFPoAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXQbkAawBrAGsAMQBrALMCcABrAGsAFwBrgACAAIAAgQU2CAgICIAfgF4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAF0G5AGsAawBrADEAawCzAnEAawBrABcAa4AAgCuAAIEFNggICAiAH4BfCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABdBuQBrAGsAawAxAGsAswJyAGsAawAXAGuAAIAAgACBBTYICAgIgB+AYAgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABci9gAXQbkAawBrAGsAMQBrALMCcwBrAGsAFwBrgACBAt6AAIEFNggICAiAH4BhCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABdBuQBrAGsAawAxAGsAswJ0AGsAawAXAGuAAIAAgACBBTYICAgIgB+AYggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXQbkAawBrAGsAMQBrALMCdQBrAGsAFwBrgACAAIAAgQU2CAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAF0G5AGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAIEFNggICAiAH4BkCAiAAAjfEBIAoQCiAKNC3wAhAKUApkLgACMApELhAKcADgAlAKgAqQAoAKoAFwAXABcAKQBJAGsAa0LpADEAawBdAGsBq0BTAGsAa0LxAGtfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEE/AgIgQVBCIAOCIBtgQUQCAiBBUAIEwAAAAEkV1aE0wA6ADsADkL1QvgASqIBtAG1gEWARqJC+UL6gQVCgQVNgC7ZACEAJUL9AA4AKEL+ACMAXEL/QFgBtABdAHwAFwApADEAa0MHXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQU/gEWADoA1gACABAiBBUPTADoAOwAOQwlDEgBKqAHKAcsBzAHNAc4BzwHQAdGASYBKgEuATIBNgE6AT4BQqEMTQxRDFUMWQxdDGEMZQxqBBUSBBUWBBUaBBUiBBUmBBUqBBUuBBUyALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAF0L5AGsAawBrADEAawCzAcoAawBrABcAa4AAgCuAAIEFQggICAiAH4BJCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABdC+QBrAGsAawAxAGsAswHLAGsAawAXAGuAAIAAgACBBUIICAgIgB+ASggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABdDPAAXQvkAawBrAGsAMQBrALMBzABrAGsAFwBrgACBBUeAAIEFQggICAiAH4BLCAiAAAjTADoAOwAOQ0pDSwBKoKCALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAF0L5AGsAawBrADEAawCzAc0AawBrABcAa4AAgCuAAIEFQggICAiAH4BMCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABdC+QBrAGsAawAxAGsAswHOAGsAawAXAGuAAIArgACBBUIICAgIgB+ATQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXQvkAawBrAGsAMQBrALMBzwBrAGsAFwBrgACAK4AAgQVCCAgICIAfgE4ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAF0L5AGsAawBrADEAawCzAdAAawBrABcAa4AAgACAAIEFQggICAiAH4BPCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABdC+QBrAGsAawAxAGsAswHRAGsAawAXAGuAAIArgACBBUIICAgIgB+AUAgIgAAI2QAhACVDmQAOAChDmgAjAFxDm0BYAbUAXQB8ABcAKQAxAGtDo18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEFP4BGgA6ANYAAgAQIgQVO0wA6ADsADkOlQ60ASqcCcAJxAnICcwJ0AnUCdoBegF+AYIBhgGKAY4Bkp0OuQ69DsEOxQ7JDs0O0gQVPgQVQgQVRgQVSgQVTgQVUgQVVgC7fEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABdC+gBrAGsAawAxAGsAswJwAGsAawAXAGuAAIAAgACBBU0ICAgIgB+AXggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXQvoAawBrAGsAMQBrALMCcQBrAGsAFwBrgACAK4AAgQVNCAgICIAfgF8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAF0L6AGsAawBrADEAawCzAnIAawBrABcAa4AAgACAAIEFTQgICAiAH4BgCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwK2ABdC+gBrAGsAawAxAGsAswJzAGsAawAXAGuAAIBpgACBBU0ICAgIgB+AYQgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXQvoAawBrAGsAMQBrALMCdABrAGsAFwBrgACAAIAAgQVNCAgICIAfgGIICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAF0L6AGsAawBrADEAawCzAnUAawBrABcAa4AAgACAAIEFTQgICAiAH4BjCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABdC+gBrAGsAawAxAGsAswJ2AGsAawAXAGuAAIAAgACBBU0ICAgIgB+AZAgIgAAI3xASAKEAogCjRCAAIQClAKZEIQAjAKREIgCnAA4AJQCoAKkAKACqABcAFwAXACkASQBrAGtEKgAxAGsAXQBrAasBgABrAGtEMgBrXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBBPwICIEFWAiADgiAbYA/CAiBBVcIElw7yTbTADoAOwAORDZEOQBKogG0AbWARYBGokQ6RDuBBVmBBWSALtkAIQAlRD4ADgAoRD8AIwBcREBAWQG0AF0AfAAXACkAMQBrREhfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBVaARYAOgDWAAIAECIEFWtMAOgA7AA5ESkRTAEqoAcoBywHMAc0BzgHPAdAB0YBJgEqAS4BMgE2AToBPgFCoRFREVURWRFdEWERZRFpEW4EFW4EFXIEFXYEFX4EFYIEFYYEFYoEFY4Au3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXRDoAawBrAGsAMQBrALMBygBrAGsAFwBrgACAK4AAgQVZCAgICIAfgEkICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAF0Q6AGsAawBrADEAawCzAcsAawBrABcAa4AAgACAAIEFWQgICAiAH4BKCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAF0R9ABdEOgBrAGsAawAxAGsAswHMAGsAawAXAGuAAIEFXoAAgQVZCAgICIAfgEsICIAACNMAOgA7AA5Ei0SMAEqgoIAu3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcBGQAXRDoAawBrAGsAMQBrALMBzQBrAGsAFwBrgACAK4AAgQVZCAgICIAfgEwICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAF0Q6AGsAawBrADEAawCzAc4AawBrABcAa4AAgCuAAIEFWQgICAiAH4BNCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABdEOgBrAGsAawAxAGsAswHPAGsAawAXAGuAAIArgACBBVkICAgIgB+ATggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXRDoAawBrAGsAMQBrALMB0ABrAGsAFwBrgACAAIAAgQVZCAgICIAfgE8ICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXARkAF0Q6AGsAawBrADEAawCzAdEAawBrABcAa4AAgCuAAIEFWQgICAiAH4BQCAiAAAjZACEAJUTaAA4AKETbACMAXETcQFkBtQBdAHwAFwApADEAa0TkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQVWgEaADoA1gACABAiBBWXTADoAOwAOROZE7gBKpwJwAnECcgJzAnQCdQJ2gF6AX4BggGGAYoBjgGSnRO9E8ETxRPJE80T0RPWBBWaBBWeBBWiBBWmBBWqBBWuBBWyALt8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAF0Q7AGsAawBrADEAawCzAnAAawBrABcAa4AAgACAAIEFZAgICAiAH4BeCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwEZABdEOwBrAGsAawAxAGsAswJxAGsAawAXAGuAAIArgACBBWQICAgIgB+AXwgIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXRDsAawBrAGsAMQBrALMCcgBrAGsAFwBrgACAAIAAgQVkCAgICIAfgGAICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXBoMAF0Q7AGsAawBrADEAawCzAnMAawBrABcAa4AAgLGAAIEFZAgICAiAH4BhCAiAAAjfEA8AoQCiAKMAIQCkAKUApgAjAKcADgAlAKgAqQAoAKoAFwAXABdEOwBrAGsAawAxAGsAswJ0AGsAawAXAGuAAIAAgACBBWQICAgIgB+AYggIgAAI3xAPAKEAogCjACEApAClAKYAIwCnAA4AJQCoAKkAKACqABcAFwAXRDsAawBrAGsAMQBrALMCdQBrAGsAFwBrgACAAIAAgQVkCAgICIAfgGMICIAACN8QDwChAKIAowAhAKQApQCmACMApwAOACUAqACpACgAqgAXABcAF0Q7AGsAawBrADEAawCzAnYAawBrABcAa4AAgACAAIEFZAgICAiAH4BkCAiAAAjSADsADkVhALuggB7TADoAOwAORWRFZQBKoKCALtMAOgA7AA5FaEVpAEqgoIAu0wA6ADsADkVsRW0ASqCggC7SAL0AvkVwRXFeWERNb2RlbFBhY2thZ2WmRXJFc0V0RXVFdgDCXlhETW9kZWxQYWNrYWdlXxAPWERVTUxQYWNrYWdlSW1wXxARWERVTUxOYW1lc3BhY2VJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcNIAOwAORXgAu6CAHtMAOgA7AA5Fe0V8AEqgoIAuUNIAvQC+RYBFgVlYRFBNTW9kZWyjRYBFggDCV1hETW9kZWwAAAAIAAAAGQAAACIAAAAsAAAAMQAAADoAAAA/AAAAUQAAAFYAAABbAAAAXQAAC00AAAtTAAALcAAAC4IAAAuJAAALlgAAC6kAAAvBAAALzwAAC+kAAAvrAAAL7gAAC/EAAAvzAAAL9gAAC/gAAAv7AAAMNAAADFMAAAxwAAAMjwAADKEAAAzBAAAMyAAADOYAAAzyAAANDgAADRQAAA02AAANVwAADWoAAA1sAAANbwAADXIAAA10AAANdgAADXgAAA17AAANfgAADYAAAA2CAAANhAAADYYAAA2IAAANigAADYsAAA2PAAANnAAADaQAAA2vAAANvAAADb4AAA3AAAANwgAADcQAAA3GAAANyAAADdUAAA3XAAAN2gAADd0AAA3gAAAN4wAADeYAAA3oAAAOBgAADhkAAA4jAAAONwAADk0AAA5XAAAOmgAADr4AAA7iAAAPBQAADywAAA9MAAAPcwAAD5oAAA+6AAAP3gAAEAIAABAOAAAQEAAAEBIAABAUAAAQFgAAEBgAABAaAAAQHQAAEB8AABAhAAAQJAAAECYAABAoAAAQKwAAEC0AABAuAAAQNwAAED8AABBMAAAQTwAAEFEAABBUAAAQVgAAEFgAABBnAAAQjAAAELAAABDXAAAQ+wAAEP0AABD/AAARAQAAEQMAABEFAAARBwAAEQgAABEKAAARFwAAESoAABEsAAARLgAAETAAABEyAAARNAAAETYAABE4AAAROgAAETwAABFPAAARUQAAEVMAABFVAAARVwAAEVkAABFbAAARXQAAEV8AABFhAAARYwAAEXkAABGMAAARqAAAEcUAABHhAAAR9QAAEgcAABIdAAASNgAAEnUAABJ7AAAShAAAEpEAABKdAAASpwAAErEAABK8AAASxwAAEtQAABLcAAAS3gAAEuAAABLiAAAS5AAAEuUAABLmAAAS5wAAEugAABLqAAAS7AAAEu0AABLuAAAS8AAAEvEAABL6AAAS+wAAEv0AABMGAAATEQAAExoAABMpAAATMAAAEzgAABNBAAATSgAAE10AABNmAAATeQAAE5AAABOiAAAT4QAAE+MAABPlAAAT5wAAE+kAABPqAAAT6wAAE+wAABPtAAAT7wAAE/EAABPyAAAT8wAAE/UAABP2AAAUNQAAFDcAABQ5AAAUOwAAFD0AABQ+AAAUPwAAFEAAABRBAAAUQwAAFEUAABRGAAAURwAAFEkAABRKAAAUUwAAFFgAABRaAAAUXAAAFF4AABRnAAAUagAAFGwAABRuAAAUcwAAFHwAABR/AAAUgQAAFIMAABSSAAAU0QAAFNMAABTVAAAU1wAAFNkAABTaAAAU2wAAFNwAABTdAAAU3wAAFOEAABTiAAAU4wAAFOUAABTmAAAVJQAAFScAABUpAAAVKwAAFS0AABUuAAAVLwAAFTAAABUxAAAVMwAAFTUAABU2AAAVNwAAFTkAABU6AAAVQwAAFUQAABVGAAAVhQAAFYcAABWJAAAViwAAFY0AABWOAAAVjwAAFZAAABWRAAAVkwAAFZUAABWWAAAVlwAAFZkAABWaAAAVmwAAFdoAABXcAAAV3gAAFeAAABXiAAAV4wAAFeQAABXlAAAV5gAAFegAABXqAAAV6wAAFewAABXuAAAV7wAAFfwAABX9AAAV/gAAFgAAABYJAAAWHwAAFiYAABYzAAAWcgAAFnQAABZ2AAAWeAAAFnoAABZ7AAAWfAAAFn0AABZ+AAAWgAAAFoIAABaDAAAWhAAAFoYAABaHAAAWoAAAFqIAABakAAAWpgAAFqcAABapAAAWwAAAFskAABbXAAAW5AAAFvIAABcHAAAXGwAAFzIAABdEAAAXgwAAF4UAABeHAAAXiQAAF4sAABeMAAAXjQAAF44AABePAAAXkQAAF5MAABeUAAAXlQAAF5cAABeYAAAXtwAAF8AAABfVAAAX5AAAF/kAABgHAAAYHAAAGDAAABhHAAAYWQAAGGYAABh/AAAYgQAAGIMAABiFAAAYhwAAGIkAABiLAAAYjQAAGI8AABiRAAAYkwAAGJUAABiXAAAYsAAAGLIAABi0AAAYtgAAGLgAABi6AAAYvAAAGL4AABjAAAAYwwAAGMYAABjJAAAYzAAAGM4AABjoAAAZAQAAGQkAABkYAAAZHgAAGSUAABk4AAAZQgAAGUwAABlhAAAZeAAAGcMAABnmAAAaBgAAGiYAABooAAAaKgAAGiwAABouAAAaMAAAGjEAABoyAAAaNAAAGjUAABo3AAAaOAAAGjoAABo8AAAaPQAAGj4AABpAAAAaQQAAGkYAABpTAAAaWAAAGloAABpcAAAaYQAAGmMAABplAAAaZwAAGnwAABqRAAAatgAAGtoAABsBAAAbJQAAGycAABspAAAbKwAAGy0AABsvAAAbMQAAGzIAABs0AAAbQQAAG1IAABtUAAAbVgAAG1gAABtaAAAbXAAAG14AABtgAAAbYgAAG3MAABt1AAAbdwAAG3kAABt7AAAbfQAAG38AABuBAAAbgwAAG4UAABujAAAbwQAAG9QAABvoAAAb/QAAHBoAABwuAAAcRAAAHIMAAByFAAAchwAAHIkAAByLAAAcjAAAHI0AAByOAAAcjwAAHJEAAByTAAAclAAAHJUAAByXAAAcmAAAHNcAABzZAAAc2wAAHN0AABzfAAAc4AAAHOEAABziAAAc4wAAHOUAABznAAAc6AAAHOkAABzrAAAc7AAAHSsAAB0tAAAdLwAAHTEAAB0zAAAdNAAAHTUAAB02AAAdNwAAHTkAAB07AAAdPAAAHT0AAB0/AAAdQAAAHU0AAB1OAAAdTwAAHVEAAB2QAAAdkgAAHZQAAB2WAAAdmAAAHZkAAB2aAAAdmwAAHZwAAB2eAAAdoAAAHaEAAB2iAAAdpAAAHaUAAB3kAAAd5gAAHegAAB3qAAAd7AAAHe0AAB3uAAAd7wAAHfAAAB3yAAAd9AAAHfUAAB32AAAd+AAAHfkAAB36AAAeOQAAHjsAAB49AAAePwAAHkEAAB5CAAAeQwAAHkQAAB5FAAAeRwAAHkkAAB5KAAAeSwAAHk0AAB5OAAAejQAAHo8AAB6RAAAekwAAHpUAAB6WAAAelwAAHpgAAB6ZAAAemwAAHp0AAB6eAAAenwAAHqEAAB6iAAAeuwAAHvoAAB78AAAe/gAAHwAAAB8CAAAfAwAAHwQAAB8FAAAfBgAAHwgAAB8KAAAfCwAAHwwAAB8OAAAfDwAAHzQAAB9YAAAffwAAH6MAAB+lAAAfpwAAH6kAAB+rAAAfrQAAH68AAB+wAAAfsgAAH78AAB/OAAAf0AAAH9IAAB/UAAAf1gAAH9gAAB/aAAAf3AAAH+sAAB/tAAAf7wAAH/EAAB/zAAAf9QAAH/cAAB/5AAAf+wAAIBsAACBGAAAgYAAAIHkAACCTAAAgswAAINYAACEVAAAhFwAAIRkAACEbAAAhHQAAIR4AACEfAAAhIAAAISEAACEjAAAhJQAAISYAACEnAAAhKQAAISoAACFpAAAhawAAIW0AACFvAAAhcQAAIXIAACFzAAAhdAAAIXUAACF3AAAheQAAIXoAACF7AAAhfQAAIX4AACG9AAAhvwAAIcEAACHDAAAhxQAAIcYAACHHAAAhyAAAIckAACHLAAAhzQAAIc4AACHPAAAh0QAAIdIAACIRAAAiEwAAIhUAACIXAAAiGQAAIhoAACIbAAAiHAAAIh0AACIfAAAiIQAAIiIAACIjAAAiJQAAIiYAACIpAAAiaAAAImoAACJsAAAibgAAInAAACJxAAAicgAAInMAACJ0AAAidgAAIngAACJ5AAAiegAAInwAACJ9AAAivAAAIr4AACLAAAAiwgAAIsQAACLFAAAixgAAIscAACLIAAAiygAAIswAACLNAAAizgAAItAAACLRAAAjEAAAIxIAACMUAAAjFgAAIxgAACMZAAAjGgAAIxsAACMcAAAjHgAAIyAAACMhAAAjIgAAIyQAACMlAAAjLgAAIzwAACNJAAAjVwAAI2QAACN3AAAjjgAAI6AAACPrAAAkDgAAJC4AACROAAAkUAAAJFIAACRUAAAkVgAAJFgAACRZAAAkWgAAJFwAACRdAAAkXwAAJGAAACRiAAAkZAAAJGUAACRmAAAkaAAAJGkAACRuAAAkewAAJIAAACSCAAAkhAAAJIkAACSLAAAkjQAAJI8AACS0AAAk2AAAJP8AACUjAAAlJQAAJScAACUpAAAlKwAAJS0AACUvAAAlMAAAJTIAACU/AAAlUAAAJVIAACVUAAAlVgAAJVgAACVaAAAlXAAAJV4AACVgAAAlcQAAJXMAACV1AAAldwAAJXkAACV7AAAlfQAAJX8AACWBAAAlgwAAJcIAACXEAAAlxgAAJcgAACXKAAAlywAAJcwAACXNAAAlzgAAJdAAACXSAAAl0wAAJdQAACXWAAAl1wAAJhYAACYYAAAmGgAAJhwAACYeAAAmHwAAJiAAACYhAAAmIgAAJiQAACYmAAAmJwAAJigAACYqAAAmKwAAJmoAACZsAAAmbgAAJnAAACZyAAAmcwAAJnQAACZ1AAAmdgAAJngAACZ6AAAmewAAJnwAACZ+AAAmfwAAJowAACaNAAAmjgAAJpAAACbPAAAm0QAAJtMAACbVAAAm1wAAJtgAACbZAAAm2gAAJtsAACbdAAAm3wAAJuAAACbhAAAm4wAAJuQAACcjAAAnJQAAJycAACcpAAAnKwAAJywAACctAAAnLgAAJy8AACcxAAAnMwAAJzQAACc1AAAnNwAAJzgAACd3AAAneQAAJ3sAACd9AAAnfwAAJ4AAACeBAAAnggAAJ4MAACeFAAAnhwAAJ4gAACeJAAAniwAAJ4wAACfLAAAnzQAAJ88AACfRAAAn0wAAJ9QAACfVAAAn1gAAJ9cAACfZAAAn2wAAJ9wAACfdAAAn3wAAJ+AAACgfAAAoIQAAKCMAACglAAAoJwAAKCgAACgpAAAoKgAAKCsAACgtAAAoLwAAKDAAACgxAAAoMwAAKDQAAChZAAAofQAAKKQAACjIAAAoygAAKMwAACjOAAAo0AAAKNIAACjUAAAo1QAAKNcAACjkAAAo8wAAKPUAACj3AAAo+QAAKPsAACj9AAAo/wAAKQEAACkQAAApEgAAKRQAACkWAAApGAAAKRoAACkcAAApHgAAKSAAAClfAAApYQAAKWMAACllAAApZwAAKWgAAClpAAApagAAKWsAACltAAApbwAAKXAAAClxAAApcwAAKXQAACmzAAAptQAAKbcAACm5AAApuwAAKbwAACm9AAApvgAAKb8AACnBAAApwwAAKcQAACnFAAApxwAAKcgAACoHAAAqCQAAKgsAACoNAAAqDwAAKhAAACoRAAAqEgAAKhMAACoVAAAqFwAAKhgAACoZAAAqGwAAKhwAACpbAAAqXQAAKl8AACphAAAqYwAAKmQAACplAAAqZgAAKmcAACppAAAqawAAKmwAACptAAAqbwAAKnAAACpzAAAqsgAAKrQAACq2AAAquAAAKroAACq7AAAqvAAAKr0AACq+AAAqwAAAKsIAACrDAAAqxAAAKsYAACrHAAArBgAAKwgAACsKAAArDAAAKw4AACsPAAArEAAAKxEAACsSAAArFAAAKxYAACsXAAArGAAAKxoAACsbAAArWgAAK1wAACteAAArYAAAK2IAACtjAAArZAAAK2UAACtmAAAraAAAK2oAACtrAAArbAAAK24AACtvAAArugAAK90AACv9AAAsHQAALB8AACwhAAAsIwAALCUAACwnAAAsKAAALCkAACwrAAAsLAAALC4AACwvAAAsMQAALDMAACw0AAAsNQAALDcAACw4AAAsQQAALE4AACxTAAAsVQAALFcAACxcAAAsXgAALGAAACxiAAAshwAALKsAACzSAAAs9gAALPgAACz6AAAs/AAALP4AAC0AAAAtAgAALQMAAC0FAAAtEgAALSMAAC0lAAAtJwAALSkAAC0rAAAtLQAALS8AAC0xAAAtMwAALUQAAC1GAAAtSAAALUoAAC1MAAAtTgAALVAAAC1SAAAtVAAALVYAAC2VAAAtlwAALZkAAC2bAAAtnQAALZ4AAC2fAAAtoAAALaEAAC2jAAAtpQAALaYAAC2nAAAtqQAALaoAAC3pAAAt6wAALe0AAC3vAAAt8QAALfIAAC3zAAAt9AAALfUAAC33AAAt+QAALfoAAC37AAAt/QAALf4AAC49AAAuPwAALkEAAC5DAAAuRQAALkYAAC5HAAAuSAAALkkAAC5LAAAuTQAALk4AAC5PAAAuUQAALlIAAC5fAAAuYAAALmEAAC5jAAAuogAALqQAAC6mAAAuqAAALqoAAC6rAAAurAAALq0AAC6uAAAusAAALrIAAC6zAAAutAAALrYAAC63AAAu9gAALvgAAC76AAAu/AAALv4AAC7/AAAvAAAALwEAAC8CAAAvBAAALwYAAC8HAAAvCAAALwoAAC8LAAAvSgAAL0wAAC9OAAAvUAAAL1IAAC9TAAAvVAAAL1UAAC9WAAAvWAAAL1oAAC9bAAAvXAAAL14AAC9fAAAvngAAL6AAAC+iAAAvpAAAL6YAAC+nAAAvqAAAL6kAAC+qAAAvrAAAL64AAC+vAAAvsAAAL7IAAC+zAAAv8gAAL/QAAC/2AAAv+AAAL/oAAC/7AAAv/AAAL/0AAC/+AAAwAAAAMAIAADADAAAwBAAAMAYAADAHAAAwLAAAMFAAADB3AAAwmwAAMJ0AADCfAAAwoQAAMKMAADClAAAwpwAAMKgAADCqAAAwtwAAMMYAADDIAAAwygAAMMwAADDOAAAw0AAAMNIAADDUAAAw4wAAMOUAADDnAAAw6QAAMOsAADDtAAAw7wAAMPEAADDzAAAxMgAAMTQAADE2AAAxOAAAMToAADE7AAAxPAAAMT0AADE+AAAxQAAAMUIAADFDAAAxRAAAMUYAADFHAAAxhgAAMYgAADGKAAAxjAAAMY4AADGPAAAxkAAAMZEAADGSAAAxlAAAMZYAADGXAAAxmAAAMZoAADGbAAAx2gAAMdwAADHeAAAx4AAAMeIAADHjAAAx5AAAMeUAADHmAAAx6AAAMeoAADHrAAAx7AAAMe4AADHvAAAyLgAAMjAAADIyAAAyNAAAMjYAADI3AAAyOAAAMjkAADI6AAAyPAAAMj4AADI/AAAyQAAAMkIAADJDAAAyggAAMoQAADKGAAAyiAAAMooAADKLAAAyjAAAMo0AADKOAAAykAAAMpIAADKTAAAylAAAMpYAADKXAAAy1gAAMtgAADLaAAAy3AAAMt4AADLfAAAy4AAAMuEAADLiAAAy5AAAMuYAADLnAAAy6AAAMuoAADLrAAAzKgAAMywAADMuAAAzMAAAMzIAADMzAAAzNAAAMzUAADM2AAAzOAAAMzoAADM7AAAzPAAAMz4AADM/AAAzigAAM60AADPNAAAz7QAAM+8AADPxAAAz8wAAM/UAADP3AAAz+AAAM/kAADP7AAAz/AAAM/4AADP/AAA0AQAANAMAADQEAAA0BQAANAcAADQIAAA0DQAANBoAADQfAAA0IQAANCMAADQoAAA0KgAANCwAADQuAAA0UwAANHcAADSeAAA0wgAANMQAADTGAAA0yAAANMoAADTMAAA0zgAANM8AADTRAAA03gAANO8AADTxAAA08wAANPUAADT3AAA0+QAANPsAADT9AAA0/wAANRAAADUSAAA1FAAANRYAADUYAAA1GgAANRwAADUeAAA1IAAANSIAADVhAAA1YwAANWUAADVnAAA1aQAANWoAADVrAAA1bAAANW0AADVvAAA1cQAANXIAADVzAAA1dQAANXYAADW1AAA1twAANbkAADW7AAA1vQAANb4AADW/AAA1wAAANcEAADXDAAA1xQAANcYAADXHAAA1yQAANcoAADYJAAA2CwAANg0AADYPAAA2EQAANhIAADYTAAA2FAAANhUAADYXAAA2GQAANhoAADYbAAA2HQAANh4AADYrAAA2LAAANi0AADYvAAA2bgAANnAAADZyAAA2dAAANnYAADZ3AAA2eAAANnkAADZ6AAA2fAAANn4AADZ/AAA2gAAANoIAADaDAAA2wgAANsQAADbGAAA2yAAANsoAADbLAAA2zAAANs0AADbOAAA20AAANtIAADbTAAA21AAANtYAADbXAAA3FgAANxgAADcaAAA3HAAANx4AADcfAAA3IAAANyEAADciAAA3JAAANyYAADcnAAA3KAAANyoAADcrAAA3agAAN2wAADduAAA3cAAAN3IAADdzAAA3dAAAN3UAADd2AAA3eAAAN3oAADd7AAA3fAAAN34AADd/AAA3vgAAN8AAADfCAAA3xAAAN8YAADfHAAA3yAAAN8kAADfKAAA3zAAAN84AADfPAAA30AAAN9IAADfTAAA3+AAAOBwAADhDAAA4ZwAAOGkAADhrAAA4bQAAOG8AADhxAAA4cwAAOHQAADh2AAA4gwAAOJIAADiUAAA4lgAAOJgAADiaAAA4nAAAOJ4AADigAAA4rwAAOLEAADizAAA4tQAAOLcAADi5AAA4uwAAOL0AADi/AAA4/gAAOQAAADkCAAA5BAAAOQYAADkHAAA5CAAAOQkAADkKAAA5DAAAOQ4AADkPAAA5EAAAORIAADkTAAA5UgAAOVQAADlWAAA5WAAAOVoAADlbAAA5XAAAOV0AADleAAA5YAAAOWIAADljAAA5ZAAAOWYAADlnAAA5pgAAOagAADmqAAA5rAAAOa4AADmvAAA5sAAAObEAADmyAAA5tAAAObYAADm3AAA5uAAAOboAADm7AAA5+gAAOfwAADn+AAA6AAAAOgIAADoDAAA6BAAAOgUAADoGAAA6CAAAOgoAADoLAAA6DAAAOg4AADoPAAA6EgAAOlEAADpTAAA6VQAAOlcAADpZAAA6WgAAOlsAADpcAAA6XQAAOl8AADphAAA6YgAAOmMAADplAAA6ZgAAOqUAADqnAAA6qQAAOqsAADqtAAA6rgAAOq8AADqwAAA6sQAAOrMAADq1AAA6tgAAOrcAADq5AAA6ugAAOvkAADr7AAA6/QAAOv8AADsBAAA7AgAAOwMAADsEAAA7BQAAOwcAADsJAAA7CgAAOwsAADsNAAA7DgAAO1kAADt8AAA7nAAAO7wAADu+AAA7wAAAO8IAADvEAAA7xgAAO8cAADvIAAA7ygAAO8sAADvNAAA7zgAAO9AAADvSAAA70wAAO9QAADvWAAA71wAAO9wAADvpAAA77gAAO/AAADvyAAA79wAAO/kAADv7AAA7/QAAPCIAADxGAAA8bQAAPJEAADyTAAA8lQAAPJcAADyZAAA8mwAAPJ0AADyeAAA8oAAAPK0AADy+AAA8wAAAPMIAADzEAAA8xgAAPMgAADzKAAA8zAAAPM4AADzfAAA84QAAPOMAADzlAAA85wAAPOkAADzrAAA87QAAPO8AADzxAAA9MAAAPTIAAD00AAA9NgAAPTgAAD05AAA9OgAAPTsAAD08AAA9PgAAPUAAAD1BAAA9QgAAPUQAAD1FAAA9hAAAPYYAAD2IAAA9igAAPYwAAD2NAAA9jgAAPY8AAD2QAAA9kgAAPZQAAD2VAAA9lgAAPZgAAD2ZAAA92AAAPdoAAD3cAAA93gAAPeAAAD3hAAA94gAAPeMAAD3kAAA95gAAPegAAD3pAAA96gAAPewAAD3tAAA9+gAAPfsAAD38AAA9/gAAPj0AAD4/AAA+QQAAPkMAAD5FAAA+RgAAPkcAAD5IAAA+SQAAPksAAD5NAAA+TgAAPk8AAD5RAAA+UgAAPpEAAD6TAAA+lQAAPpcAAD6ZAAA+mgAAPpsAAD6cAAA+nQAAPp8AAD6hAAA+ogAAPqMAAD6lAAA+pgAAPuUAAD7nAAA+6QAAPusAAD7tAAA+7gAAPu8AAD7wAAA+8QAAPvMAAD71AAA+9gAAPvcAAD75AAA++gAAPzkAAD87AAA/PQAAPz8AAD9BAAA/QgAAP0MAAD9EAAA/RQAAP0cAAD9JAAA/SgAAP0sAAD9NAAA/TgAAP40AAD+PAAA/kQAAP5MAAD+VAAA/lgAAP5cAAD+YAAA/mQAAP5sAAD+dAAA/ngAAP58AAD+hAAA/ogAAP8cAAD/rAABAEgAAQDYAAEA4AABAOgAAQDwAAEA+AABAQAAAQEIAAEBDAABARQAAQFIAAEBhAABAYwAAQGUAAEBnAABAaQAAQGsAAEBtAABAbwAAQH4AAECAAABAggAAQIQAAECGAABAiAAAQIoAAECMAABAjgAAQM0AAEDPAABA0QAAQNMAAEDVAABA1gAAQNcAAEDYAABA2QAAQNsAAEDdAABA3gAAQN8AAEDhAABA4gAAQSEAAEEjAABBJQAAQScAAEEpAABBKgAAQSsAAEEsAABBLQAAQS8AAEExAABBMgAAQTMAAEE1AABBNgAAQXUAAEF3AABBeQAAQXsAAEF9AABBfgAAQX8AAEGAAABBgQAAQYMAAEGFAABBhgAAQYcAAEGJAABBigAAQckAAEHLAABBzQAAQc8AAEHRAABB0gAAQdMAAEHUAABB1QAAQdcAAEHZAABB2gAAQdsAAEHdAABB3gAAQeEAAEIgAABCIgAAQiQAAEImAABCKAAAQikAAEIqAABCKwAAQiwAAEIuAABCMAAAQjEAAEIyAABCNAAAQjUAAEJ0AABCdgAAQngAAEJ6AABCfAAAQn0AAEJ+AABCfwAAQoAAAEKCAABChAAAQoUAAEKGAABCiAAAQokAAELIAABCygAAQswAAELOAABC0AAAQtEAAELSAABC0wAAQtQAAELWAABC2AAAQtkAAELaAABC3AAAQt0AAEMoAABDSwAAQ2sAAEOLAABDjQAAQ48AAEORAABDkwAAQ5UAAEOWAABDlwAAQ5kAAEOaAABDnAAAQ50AAEOfAABDoQAAQ6IAAEOjAABDpQAAQ6YAAEOrAABDuAAAQ70AAEO/AABDwQAAQ8YAAEPIAABDygAAQ8wAAEPxAABEFQAARDwAAERgAABEYgAARGQAAERmAABEaAAARGoAAERsAABEbQAARG8AAER8AABEjQAARI8AAESRAABEkwAARJUAAESXAABEmQAARJsAAESdAABErgAARLAAAESyAABEtAAARLYAAES4AABEugAARLwAAES+AABEwAAARP8AAEUBAABFAwAARQUAAEUHAABFCAAARQkAAEUKAABFCwAARQ0AAEUPAABFEAAARREAAEUTAABFFAAARVMAAEVVAABFVwAARVkAAEVbAABFXAAARV0AAEVeAABFXwAARWEAAEVjAABFZAAARWUAAEVnAABFaAAARacAAEWpAABFqwAARa0AAEWvAABFsAAARbEAAEWyAABFswAARbUAAEW3AABFuAAARbkAAEW7AABFvAAARckAAEXKAABFywAARc0AAEYMAABGDgAARhAAAEYSAABGFAAARhUAAEYWAABGFwAARhgAAEYaAABGHAAARh0AAEYeAABGIAAARiEAAEZgAABGYgAARmQAAEZmAABGaAAARmkAAEZqAABGawAARmwAAEZuAABGcAAARnEAAEZyAABGdAAARnUAAEa0AABGtgAARrgAAEa6AABGvAAARr0AAEa+AABGvwAARsAAAEbCAABGxAAARsUAAEbGAABGyAAARskAAEcIAABHCgAARwwAAEcOAABHEAAARxEAAEcSAABHEwAARxQAAEcWAABHGAAARxkAAEcaAABHHAAARx0AAEdcAABHXgAAR2AAAEdiAABHZAAAR2UAAEdmAABHZwAAR2gAAEdqAABHbAAAR20AAEduAABHcAAAR3EAAEeWAABHugAAR+EAAEgFAABIBwAASAkAAEgLAABIDQAASA8AAEgRAABIEgAASBQAAEghAABIMAAASDIAAEg0AABINgAASDgAAEg6AABIPAAASD4AAEhNAABITwAASFEAAEhTAABIVQAASFcAAEhZAABIWwAASF0AAEicAABIngAASKAAAEiiAABIpAAASKUAAEimAABIpwAASKgAAEiqAABIrAAASK0AAEiuAABIsAAASLEAAEi1AABI9AAASPYAAEj4AABI+gAASPwAAEj9AABI/gAASP8AAEkAAABJAgAASQQAAEkFAABJBgAASQgAAEkJAABJSAAASUoAAElMAABJTgAASVAAAElRAABJUgAASVMAAElUAABJVgAASVgAAElZAABJWgAASVwAAEldAABJnAAASZ4AAEmgAABJogAASaQAAEmlAABJpgAASacAAEmoAABJqgAASawAAEmtAABJrgAASbAAAEmxAABJ8AAASfIAAEn0AABJ9gAASfgAAEn5AABJ+gAASfsAAEn8AABJ/gAASgAAAEoBAABKAgAASgQAAEoFAABKRAAASkYAAEpIAABKSgAASkwAAEpNAABKTgAASk8AAEpQAABKUgAASlQAAEpVAABKVgAASlgAAEpZAABKmAAASpoAAEqcAABKngAASqAAAEqhAABKogAASqMAAEqkAABKpgAASqgAAEqpAABKqgAASqwAAEqtAABK+AAASxsAAEs7AABLWwAAS10AAEtfAABLYQAAS2MAAEtlAABLZgAAS2cAAEtpAABLagAAS2wAAEttAABLbwAAS3EAAEtyAABLcwAAS3UAAEt2AABLfwAAS4wAAEuRAABLkwAAS5UAAEuaAABLnAAAS54AAEugAABLxQAAS+kAAEwQAABMNAAATDYAAEw4AABMOgAATDwAAEw+AABMQAAATEEAAExDAABMUAAATGEAAExjAABMZQAATGcAAExpAABMawAATG0AAExvAABMcQAATIIAAEyEAABMhgAATIgAAEyKAABMjAAATI4AAEyQAABMkgAATJQAAEzTAABM1QAATNcAAEzZAABM2wAATNwAAEzdAABM3gAATN8AAEzhAABM4wAATOQAAEzlAABM5wAATOgAAE0nAABNKQAATSsAAE0tAABNLwAATTAAAE0xAABNMgAATTMAAE01AABNNwAATTgAAE05AABNOwAATTwAAE17AABNfQAATX8AAE2BAABNgwAATYQAAE2FAABNhgAATYcAAE2JAABNiwAATYwAAE2NAABNjwAATZAAAE2dAABNngAATZ8AAE2hAABN4AAATeIAAE3kAABN5gAATegAAE3pAABN6gAATesAAE3sAABN7gAATfAAAE3xAABN8gAATfQAAE31AABONAAATjYAAE44AABOOgAATjwAAE49AABOPgAATj8AAE5AAABOQgAATkQAAE5FAABORgAATkgAAE5JAABOiAAATooAAE6MAABOjgAATpAAAE6RAABOkgAATpMAAE6UAABOlgAATpgAAE6ZAABOmgAATpwAAE6dAABO3AAATt4AAE7gAABO4gAATuQAAE7lAABO5gAATucAAE7oAABO6gAATuwAAE7tAABO7gAATvAAAE7xAABPMAAATzIAAE80AABPNgAATzgAAE85AABPOgAATzsAAE88AABPPgAAT0AAAE9BAABPQgAAT0QAAE9FAABPagAAT44AAE+1AABP2QAAT9sAAE/dAABP3wAAT+EAAE/jAABP5QAAT+YAAE/oAABP9QAAUAQAAFAGAABQCAAAUAoAAFAMAABQDgAAUBAAAFASAABQIQAAUCMAAFAlAABQJwAAUCkAAFArAABQLQAAUC8AAFAxAABQcAAAUHIAAFB0AABQdgAAUHgAAFB5AABQegAAUHsAAFB8AABQfgAAUIAAAFCBAABQggAAUIQAAFCFAABQhwAAUMYAAFDIAABQygAAUMwAAFDOAABQzwAAUNAAAFDRAABQ0gAAUNQAAFDWAABQ1wAAUNgAAFDaAABQ2wAAURoAAFEcAABRHgAAUSAAAFEiAABRIwAAUSQAAFElAABRJgAAUSgAAFEqAABRKwAAUSwAAFEuAABRLwAAUW4AAFFwAABRcgAAUXQAAFF2AABRdwAAUXgAAFF5AABRegAAUXwAAFF+AABRfwAAUYAAAFGCAABRgwAAUYUAAFHEAABRxgAAUcgAAFHKAABRzAAAUc0AAFHOAABRzwAAUdAAAFHSAABR1AAAUdUAAFHWAABR2AAAUdkAAFIYAABSGgAAUhwAAFIeAABSIAAAUiEAAFIiAABSIwAAUiQAAFImAABSKAAAUikAAFIqAABSLAAAUi0AAFJsAABSbgAAUnAAAFJyAABSdAAAUnUAAFJ2AABSdwAAUngAAFJ6AABSfAAAUn0AAFJ+AABSgAAAUoEAAFLMAABS7wAAUw8AAFMvAABTMQAAUzMAAFM1AABTNwAAUzkAAFM6AABTOwAAUz4AAFM/AABTQQAAU0IAAFNEAABTRgAAU0cAAFNIAABTSgAAU0sAAFNQAABTXQAAU2IAAFNkAABTZgAAU2sAAFNuAABTcQAAU3MAAFOYAABTvAAAU+MAAFQHAABUCQAAVAsAAFQNAABUDwAAVBEAAFQTAABUFAAAVBcAAFQkAABUNQAAVDcAAFQ5AABUOwAAVD0AAFQ/AABUQQAAVEMAAFRFAABUVgAAVFkAAFRcAABUXwAAVGIAAFRlAABUaAAAVGsAAFRuAABUcAAAVK8AAFSxAABUswAAVLUAAFS4AABUuQAAVLoAAFS7AABUvAAAVL4AAFTAAABUwQAAVMIAAFTEAABUxQAAVQQAAFUGAABVCAAAVQoAAFUNAABVDgAAVQ8AAFUQAABVEQAAVRMAAFUVAABVFgAAVRcAAFUZAABVGgAAVVkAAFVbAABVXgAAVWAAAFVjAABVZAAAVWUAAFVmAABVZwAAVWkAAFVrAABVbAAAVW0AAFVvAABVcAAAVX0AAFV+AABVfwAAVYEAAFXAAABVwgAAVcQAAFXGAABVyQAAVcoAAFXLAABVzAAAVc0AAFXPAABV0QAAVdIAAFXTAABV1QAAVdYAAFYVAABWFwAAVhkAAFYbAABWHgAAVh8AAFYgAABWIQAAViIAAFYkAABWJgAAVicAAFYoAABWKgAAVisAAFZqAABWbAAAVm4AAFZwAABWcwAAVnQAAFZ1AABWdgAAVncAAFZ5AABWewAAVnwAAFZ9AABWfwAAVoAAAFa/AABWwQAAVsMAAFbFAABWyAAAVskAAFbKAABWywAAVswAAFbOAABW0AAAVtEAAFbSAABW1AAAVtUAAFcUAABXFgAAVxgAAFcaAABXHQAAVx4AAFcfAABXIAAAVyEAAFcjAABXJQAAVyYAAFcnAABXKQAAVyoAAFdPAABXcwAAV5oAAFe+AABXwAAAV8IAAFfEAABXxgAAV8gAAFfKAABXywAAV84AAFfbAABX6gAAV+wAAFfuAABX8AAAV/IAAFf0AABX9gAAV/gAAFgHAABYCgAAWA0AAFgQAABYEwAAWBYAAFgZAABYHAAAWB4AAFhdAABYXwAAWGEAAFhjAABYZgAAWGcAAFhoAABYaQAAWGoAAFhsAABYbgAAWG8AAFhwAABYcgAAWHMAAFiyAABYtAAAWLYAAFi4AABYuwAAWLwAAFi9AABYvgAAWL8AAFjBAABYwwAAWMQAAFjFAABYxwAAWMgAAFkHAABZCQAAWQsAAFkNAABZEAAAWREAAFkSAABZEwAAWRQAAFkWAABZGAAAWRkAAFkaAABZHAAAWR0AAFlcAABZXgAAWWEAAFljAABZZgAAWWcAAFloAABZaQAAWWoAAFlsAABZbgAAWW8AAFlwAABZcgAAWXMAAFl2AABZtQAAWbcAAFm5AABZuwAAWb4AAFm/AABZwAAAWcEAAFnCAABZxAAAWcYAAFnHAABZyAAAWcoAAFnLAABaCgAAWgwAAFoOAABaEAAAWhMAAFoUAABaFQAAWhYAAFoXAABaGQAAWhsAAFocAABaHQAAWh8AAFogAABaXwAAWmEAAFpjAABaZQAAWmgAAFppAABaagAAWmsAAFpsAABabgAAWnAAAFpxAABacgAAWnQAAFp1AABawAAAWuMAAFsDAABbIwAAWyUAAFsnAABbKQAAWysAAFstAABbLgAAWy8AAFsyAABbMwAAWzUAAFs2AABbOAAAWzoAAFs7AABbPAAAWz8AAFtAAABbRQAAW1IAAFtXAABbWQAAW1sAAFtgAABbYwAAW2YAAFtoAABbjQAAW7EAAFvYAABb/AAAW/8AAFwBAABcAwAAXAUAAFwHAABcCQAAXAoAAFwNAABcGgAAXCsAAFwtAABcLwAAXDEAAFwzAABcNQAAXDcAAFw5AABcOwAAXEwAAFxPAABcUgAAXFUAAFxYAABcWwAAXF4AAFxhAABcZAAAXGYAAFylAABcpwAAXKkAAFyrAABcrgAAXK8AAFywAABcsQAAXLIAAFy0AABctgAAXLcAAFy4AABcugAAXLsAAFz6AABc/AAAXP4AAF0AAABdAwAAXQQAAF0FAABdBgAAXQcAAF0JAABdCwAAXQwAAF0NAABdDwAAXRAAAF1PAABdUQAAXVQAAF1WAABdWQAAXVoAAF1bAABdXAAAXV0AAF1fAABdYQAAXWIAAF1jAABdZQAAXWYAAF1zAABddAAAXXUAAF13AABdtgAAXbgAAF26AABdvAAAXb8AAF3AAABdwQAAXcIAAF3DAABdxQAAXccAAF3IAABdyQAAXcsAAF3MAABeCwAAXg0AAF4PAABeEQAAXhQAAF4VAABeFgAAXhcAAF4YAABeGgAAXhwAAF4dAABeHgAAXiAAAF4hAABeYAAAXmIAAF5kAABeZgAAXmkAAF5qAABeawAAXmwAAF5tAABebwAAXnEAAF5yAABecwAAXnUAAF52AABetQAAXrcAAF65AABeuwAAXr4AAF6/AABewAAAXsEAAF7CAABexAAAXsYAAF7HAABeyAAAXsoAAF7LAABfCgAAXwwAAF8OAABfEAAAXxMAAF8UAABfFQAAXxYAAF8XAABfGQAAXxsAAF8cAABfHQAAXx8AAF8gAABfRQAAX2kAAF+QAABftAAAX7cAAF+5AABfuwAAX70AAF+/AABfwQAAX8IAAF/FAABf0gAAX+EAAF/jAABf5QAAX+cAAF/pAABf6wAAX+0AAF/vAABf/gAAYAEAAGAEAABgBwAAYAoAAGANAABgEAAAYBMAAGAVAABgVAAAYFYAAGBYAABgWgAAYF0AAGBeAABgXwAAYGAAAGBhAABgYwAAYGUAAGBmAABgZwAAYGkAAGBqAABgqQAAYKsAAGCtAABgrwAAYLIAAGCzAABgtAAAYLUAAGC2AABguAAAYLoAAGC7AABgvAAAYL4AAGC/AABg/gAAYQAAAGECAABhBAAAYQcAAGEIAABhCQAAYQoAAGELAABhDQAAYQ8AAGEQAABhEQAAYRMAAGEUAABhUwAAYVUAAGFXAABhWQAAYVwAAGFdAABhXgAAYV8AAGFgAABhYgAAYWQAAGFlAABhZgAAYWgAAGFpAABhqAAAYaoAAGGsAABhrgAAYbEAAGGyAABhswAAYbQAAGG1AABhtwAAYbkAAGG6AABhuwAAYb0AAGG+AABh/QAAYf8AAGIBAABiAwAAYgYAAGIHAABiCAAAYgkAAGIKAABiDAAAYg4AAGIPAABiEAAAYhIAAGITAABiUgAAYlQAAGJWAABiWAAAYlsAAGJcAABiXQAAYl4AAGJfAABiYQAAYmMAAGJkAABiZQAAYmcAAGJoAABiswAAYtYAAGL2AABjFgAAYxgAAGMaAABjHAAAYx4AAGMgAABjIQAAYyIAAGMlAABjJgAAYygAAGMpAABjKwAAYy0AAGMuAABjLwAAYzIAAGMzAABjOAAAY0UAAGNKAABjTAAAY04AAGNTAABjVgAAY1kAAGNbAABjgAAAY6QAAGPLAABj7wAAY/IAAGP0AABj9gAAY/gAAGP6AABj/AAAY/0AAGQAAABkDQAAZB4AAGQgAABkIgAAZCQAAGQmAABkKAAAZCoAAGQsAABkLgAAZD8AAGRCAABkRQAAZEgAAGRLAABkTgAAZFEAAGRUAABkVwAAZFkAAGSYAABkmgAAZJwAAGSeAABkoQAAZKIAAGSjAABkpAAAZKUAAGSnAABkqQAAZKoAAGSrAABkrQAAZK4AAGTtAABk7wAAZPEAAGTzAABk9gAAZPcAAGT4AABk+QAAZPoAAGT8AABk/gAAZP8AAGUAAABlAgAAZQMAAGVCAABlRAAAZUcAAGVJAABlTAAAZU0AAGVOAABlTwAAZVAAAGVSAABlVAAAZVUAAGVWAABlWAAAZVkAAGVmAABlZwAAZWgAAGVqAABlqQAAZasAAGWtAABlrwAAZbIAAGWzAABltAAAZbUAAGW2AABluAAAZboAAGW7AABlvAAAZb4AAGW/AABl/gAAZgAAAGYCAABmBAAAZgcAAGYIAABmCQAAZgoAAGYLAABmDQAAZg8AAGYQAABmEQAAZhMAAGYUAABmUwAAZlUAAGZXAABmWQAAZlwAAGZdAABmXgAAZl8AAGZgAABmYgAAZmQAAGZlAABmZgAAZmgAAGZpAABmqAAAZqoAAGasAABmrgAAZrEAAGayAABmswAAZrQAAGa1AABmtwAAZrkAAGa6AABmuwAAZr0AAGa+AABm/QAAZv8AAGcBAABnAwAAZwYAAGcHAABnCAAAZwkAAGcKAABnDAAAZw4AAGcPAABnEAAAZxIAAGcTAABnOAAAZ1wAAGeDAABnpwAAZ6oAAGesAABnrgAAZ7AAAGeyAABntAAAZ7UAAGe4AABnxQAAZ9QAAGfWAABn2AAAZ9oAAGfcAABn3gAAZ+AAAGfiAABn8QAAZ/QAAGf3AABn+gAAZ/0AAGgAAABoAwAAaAYAAGgIAABoRwAAaEkAAGhLAABoTQAAaFAAAGhRAABoUgAAaFMAAGhUAABoVgAAaFgAAGhZAABoWgAAaFwAAGhdAABonAAAaJ4AAGigAABoogAAaKUAAGimAABopwAAaKgAAGipAABoqwAAaK0AAGiuAABorwAAaLEAAGiyAABo8QAAaPMAAGj1AABo9wAAaPoAAGj7AABo/AAAaP0AAGj+AABpAAAAaQIAAGkDAABpBAAAaQYAAGkHAABpRgAAaUgAAGlKAABpTAAAaU8AAGlQAABpUQAAaVIAAGlTAABpVQAAaVcAAGlYAABpWQAAaVsAAGlcAABpmwAAaZ0AAGmfAABpoQAAaaQAAGmlAABppgAAaacAAGmoAABpqgAAaawAAGmtAABprgAAabAAAGmxAABp8AAAafIAAGn0AABp9gAAafkAAGn6AABp+wAAafwAAGn9AABp/wAAagEAAGoCAABqAwAAagUAAGoGAABqRQAAakcAAGpJAABqSwAAak4AAGpPAABqUAAAalEAAGpSAABqVAAAalYAAGpXAABqWAAAaloAAGpbAABqpgAAaskAAGrpAABrCQAAawsAAGsNAABrDwAAaxEAAGsTAABrFAAAaxUAAGsYAABrGQAAaxsAAGscAABrHgAAayAAAGshAABrIgAAayUAAGsmAABrKwAAazgAAGs9AABrPwAAa0EAAGtGAABrSQAAa0wAAGtOAABrcwAAa5cAAGu+AABr4gAAa+UAAGvnAABr6QAAa+sAAGvtAABr7wAAa/AAAGvzAABsAAAAbBEAAGwTAABsFQAAbBcAAGwZAABsGwAAbB0AAGwfAABsIQAAbDIAAGw1AABsOAAAbDsAAGw+AABsQQAAbEQAAGxHAABsSgAAbEwAAGyLAABsjQAAbI8AAGyRAABslAAAbJUAAGyWAABslwAAbJgAAGyaAABsnAAAbJ0AAGyeAABsoAAAbKEAAGzgAABs4gAAbOQAAGzmAABs6QAAbOoAAGzrAABs7AAAbO0AAGzvAABs8QAAbPIAAGzzAABs9QAAbPYAAG01AABtNwAAbToAAG08AABtPwAAbUAAAG1BAABtQgAAbUMAAG1FAABtRwAAbUgAAG1JAABtSwAAbUwAAG1ZAABtWgAAbVsAAG1dAABtnAAAbZ4AAG2gAABtogAAbaUAAG2mAABtpwAAbagAAG2pAABtqwAAba0AAG2uAABtrwAAbbEAAG2yAABt8QAAbfMAAG31AABt9wAAbfoAAG37AABt/AAAbf0AAG3+AABuAAAAbgIAAG4DAABuBAAAbgYAAG4HAABuRgAAbkgAAG5KAABuTAAAbk8AAG5QAABuUQAAblIAAG5TAABuVQAAblcAAG5YAABuWQAAblsAAG5cAABumwAAbp0AAG6fAABuoQAAbqQAAG6lAABupgAAbqcAAG6oAABuqgAAbqwAAG6tAABurgAAbrAAAG6xAABu8AAAbvIAAG70AABu9gAAbvkAAG76AABu+wAAbvwAAG79AABu/wAAbwEAAG8CAABvAwAAbwUAAG8GAABvKwAAb08AAG92AABvmgAAb50AAG+fAABvoQAAb6MAAG+lAABvpwAAb6gAAG+rAABvuAAAb8cAAG/JAABvywAAb80AAG/PAABv0QAAb9MAAG/VAABv5AAAb+cAAG/qAABv7QAAb/AAAG/zAABv9gAAb/kAAG/7AABwOgAAcDwAAHA+AABwQAAAcEMAAHBEAABwRQAAcEYAAHBHAABwSQAAcEsAAHBMAABwTQAAcE8AAHBQAABwjwAAcJEAAHCTAABwlQAAcJgAAHCZAABwmgAAcJsAAHCcAABwngAAcKAAAHChAABwogAAcKQAAHClAABw5AAAcOYAAHDoAABw6gAAcO0AAHDuAABw7wAAcPAAAHDxAABw8wAAcPUAAHD2AABw9wAAcPkAAHD6AABxOQAAcTsAAHE9AABxPwAAcUIAAHFDAABxRAAAcUUAAHFGAABxSAAAcUoAAHFLAABxTAAAcU4AAHFPAABxjgAAcZAAAHGSAABxlAAAcZcAAHGYAABxmQAAcZoAAHGbAABxnQAAcZ8AAHGgAABxoQAAcaMAAHGkAABx4wAAceUAAHHnAABx6QAAcewAAHHtAABx7gAAce8AAHHwAABx8gAAcfQAAHH1AABx9gAAcfgAAHH5AAByOAAAcjoAAHI8AAByPgAAckEAAHJCAAByQwAAckQAAHJFAAByRwAAckkAAHJKAABySwAAck0AAHJOAABymQAAcrwAAHLcAABy/AAAcv4AAHMAAABzAgAAcwQAAHMGAABzBwAAcwgAAHMLAABzDAAAcw4AAHMPAABzEQAAcxMAAHMUAABzFQAAcxgAAHMZAABzHgAAcysAAHMwAABzMgAAczQAAHM5AABzPAAAcz8AAHNBAABzZgAAc4oAAHOxAABz1QAAc9gAAHPaAABz3AAAc94AAHPgAABz4gAAc+MAAHPmAABz8wAAdAQAAHQGAAB0CAAAdAoAAHQMAAB0DgAAdBAAAHQSAAB0FAAAdCUAAHQoAAB0KwAAdC4AAHQxAAB0NAAAdDcAAHQ6AAB0PQAAdD8AAHR+AAB0gAAAdIIAAHSEAAB0hwAAdIgAAHSJAAB0igAAdIsAAHSNAAB0jwAAdJAAAHSRAAB0kwAAdJQAAHTTAAB01QAAdNcAAHTZAAB03AAAdN0AAHTeAAB03wAAdOAAAHTiAAB05AAAdOUAAHTmAAB06AAAdOkAAHUoAAB1KgAAdS0AAHUvAAB1MgAAdTMAAHU0AAB1NQAAdTYAAHU4AAB1OgAAdTsAAHU8AAB1PgAAdT8AAHVMAAB1TQAAdU4AAHVQAAB1jwAAdZEAAHWTAAB1lQAAdZgAAHWZAAB1mgAAdZsAAHWcAAB1ngAAdaAAAHWhAAB1ogAAdaQAAHWlAAB15AAAdeYAAHXoAAB16gAAde0AAHXuAAB17wAAdfAAAHXxAAB18wAAdfUAAHX2AAB19wAAdfkAAHX6AAB2OQAAdjsAAHY9AAB2PwAAdkIAAHZDAAB2RAAAdkUAAHZGAAB2SAAAdkoAAHZLAAB2TAAAdk4AAHZPAAB2jgAAdpAAAHaSAAB2lAAAdpcAAHaYAAB2mQAAdpoAAHabAAB2nQAAdp8AAHagAAB2oQAAdqMAAHakAAB24wAAduUAAHbnAAB26QAAduwAAHbtAAB27gAAdu8AAHbwAAB28gAAdvQAAHb1AAB29gAAdvgAAHb5AAB3HgAAd0IAAHdpAAB3jQAAd5AAAHeSAAB3lAAAd5YAAHeYAAB3mgAAd5sAAHeeAAB3qwAAd7oAAHe8AAB3vgAAd8AAAHfCAAB3xAAAd8YAAHfIAAB31wAAd9oAAHfdAAB34AAAd+MAAHfmAAB36QAAd+wAAHfuAAB4LQAAeC8AAHgxAAB4MwAAeDYAAHg3AAB4OAAAeDkAAHg6AAB4PAAAeD4AAHg/AAB4QAAAeEIAAHhDAAB4ggAAeIQAAHiGAAB4iAAAeIsAAHiMAAB4jQAAeI4AAHiPAAB4kQAAeJMAAHiUAAB4lQAAeJcAAHiYAAB41wAAeNkAAHjbAAB43QAAeOAAAHjhAAB44gAAeOMAAHjkAAB45gAAeOgAAHjpAAB46gAAeOwAAHjtAAB5LAAAeS4AAHkwAAB5MgAAeTUAAHk2AAB5NwAAeTgAAHk5AAB5OwAAeT0AAHk+AAB5PwAAeUEAAHlCAAB5gQAAeYMAAHmFAAB5hwAAeYoAAHmLAAB5jAAAeY0AAHmOAAB5kAAAeZIAAHmTAAB5lAAAeZYAAHmXAAB51gAAedgAAHnaAAB53AAAed8AAHngAAB54QAAeeIAAHnjAAB55QAAeecAAHnoAAB56QAAeesAAHnsAAB6KwAAei0AAHovAAB6MQAAejQAAHo1AAB6NgAAejcAAHo4AAB6OgAAejwAAHo9AAB6PgAAekAAAHpBAAB6TAAAelUAAHpWAAB6WAAAemEAAHpsAAB6ewAAeoYAAHqUAAB6qQAAer0AAHrUAAB65gAAeykAAHtNAAB7cQAAe5QAAHu7AAB72wAAfAIAAHwpAAB8SQAAfG0AAHyRAAB8kwAAfJYAAHyYAAB8mgAAfJwAAHyfAAB8ogAAfKQAAHymAAB8qQAAfKsAAHytAAB8sAAAfLMAAHy0AAB8vQAAfMoAAHzNAAB8zwAAfNIAAHzVAAB81wAAfPwAAH0gAAB9RwAAfWsAAH1uAAB9cAAAfXIAAH10AAB9dgAAfXgAAH15AAB9fAAAfYkAAH2cAAB9ngAAfaAAAH2iAAB9pAAAfaYAAH2oAAB9qgAAfawAAH2uAAB9wQAAfcQAAH3HAAB9ygAAfc0AAH3QAAB90wAAfdYAAH3ZAAB93AAAfd4AAH4dAAB+HwAAfiIAAH4kAAB+JwAAfigAAH4pAAB+KgAAfisAAH4tAAB+LwAAfjAAAH4xAAB+MwAAfjQAAH49AAB+PgAAfkAAAH5/AAB+gQAAfoMAAH6FAAB+iAAAfokAAH6KAAB+iwAAfowAAH6OAAB+kAAAfpEAAH6SAAB+lAAAfpUAAH7UAAB+1gAAftkAAH7bAAB+3gAAft8AAH7gAAB+4QAAfuIAAH7kAAB+5gAAfucAAH7oAAB+6gAAfusAAH70AAB++QAAfvwAAH7/AAB/AQAAfwoAAH8NAAB/DwAAfxEAAH8aAAB/HQAAfyAAAH8iAAB/MQAAf3AAAH9yAAB/dAAAf3YAAH95AAB/egAAf3sAAH98AAB/fQAAf38AAH+BAAB/ggAAf4MAAH+FAAB/hgAAf8UAAH/HAAB/ygAAf8wAAH/PAAB/0AAAf9EAAH/SAAB/0wAAf9UAAH/XAAB/2AAAf9kAAH/bAAB/3AAAf+UAAH/mAAB/6AAAgCcAAIApAACAKwAAgC0AAIAwAACAMQAAgDIAAIAzAACANAAAgDYAAIA4AACAOQAAgDoAAIA8AACAPQAAgHwAAIB+AACAgQAAgIMAAICGAACAhwAAgIgAAICJAACAigAAgIwAAICOAACAjwAAgJAAAICSAACAkwAAgKAAAIChAACAogAAgKQAAIDjAACA5QAAgOcAAIDpAACA7AAAgO0AAIDuAACA7wAAgPAAAIDyAACA9AAAgPUAAID2AACA+AAAgPkAAIE4AACBOgAAgT0AAIE/AACBQgAAgUMAAIFEAACBRQAAgUYAAIFIAACBSgAAgUsAAIFMAACBTgAAgU8AAIFjAACBcAAAgYUAAIGIAACBiwAAgY0AAIGQAACBkwAAgZUAAIGYAACBmwAAgZ4AAIGhAACBtgAAgbkAAIG8AACBvwAAgcIAAIHFAACByAAAgcsAAIHOAACB0QAAgdQAAIHWAACB4gAAgfgAAIH+AACCDQAAghwAAIIlAACCMAAAgjwAAIKHAACCqgAAgsoAAILqAACC7AAAgu4AAILwAACC8gAAgvUAAIL2AACC9wAAgvoAAIL7AACC/QAAgv4AAIMAAACDAwAAgwQAAIMFAACDCAAAgwkAAIMOAACDGwAAgyAAAIMiAACDJAAAgykAAIMsAACDLwAAgzEAAINWAACDegAAg6EAAIPFAACDyAAAg8oAAIPMAACDzgAAg9AAAIPSAACD0wAAg9YAAIPjAACD9AAAg/YAAIP4AACD+gAAg/wAAIP+AACEAAAAhAIAAIQEAACEFQAAhBgAAIQbAACEHgAAhCEAAIQkAACEJwAAhCoAAIQtAACELwAAhG4AAIRwAACEcgAAhHQAAIR3AACEeAAAhHkAAIR6AACEewAAhH0AAIR/AACEgAAAhIEAAISDAACEhAAAhMMAAITFAACExwAAhMkAAITMAACEzQAAhM4AAITPAACE0AAAhNIAAITUAACE1QAAhNYAAITYAACE2QAAhRgAAIUaAACFHQAAhR8AAIUiAACFIwAAhSQAAIUlAACFJgAAhSgAAIUqAACFKwAAhSwAAIUuAACFLwAAhTwAAIU9AACFPgAAhUAAAIV/AACFgQAAhYMAAIWFAACFiAAAhYkAAIWKAACFiwAAhYwAAIWOAACFkAAAhZEAAIWSAACFlAAAhZUAAIXUAACF1gAAhdgAAIXaAACF3QAAhd4AAIXfAACF4AAAheEAAIXjAACF5QAAheYAAIXnAACF6QAAheoAAIYpAACGKwAAhi0AAIYvAACGMgAAhjMAAIY0AACGNQAAhjYAAIY4AACGOgAAhjsAAIY8AACGPgAAhj8AAIZ+AACGgAAAhoIAAIaEAACGhwAAhogAAIaJAACGigAAhosAAIaNAACGjwAAhpAAAIaRAACGkwAAhpQAAIbTAACG1QAAhtcAAIbZAACG3AAAht0AAIbeAACG3wAAhuAAAIbiAACG5AAAhuUAAIbmAACG6AAAhukAAIcOAACHMgAAh1kAAId9AACHgAAAh4IAAIeEAACHhgAAh4gAAIeKAACHiwAAh44AAIebAACHqgAAh6wAAIeuAACHsAAAh7IAAIe0AACHtgAAh7gAAIfHAACHygAAh80AAIfQAACH0wAAh9YAAIfZAACH3AAAh94AAIgdAACIHwAAiCIAAIgkAACIJwAAiCgAAIgpAACIKgAAiCsAAIgtAACILwAAiDAAAIgxAACIMwAAiDQAAIg2AACIdQAAiHcAAIh5AACIewAAiH4AAIh/AACIgAAAiIEAAIiCAACIhAAAiIYAAIiHAACIiAAAiIoAAIiLAACIygAAiMwAAIjOAACI0AAAiNMAAIjUAACI1QAAiNYAAIjXAACI2QAAiNsAAIjcAACI3QAAiN8AAIjgAACJHwAAiSEAAIkkAACJJgAAiSkAAIkqAACJKwAAiSwAAIktAACJLwAAiTEAAIkyAACJMwAAiTUAAIk2AACJOAAAiXcAAIl5AACJewAAiX0AAImAAACJgQAAiYIAAImDAACJhAAAiYYAAImIAACJiQAAiYoAAImMAACJjQAAicwAAInOAACJ0AAAidIAAInVAACJ1gAAidcAAInYAACJ2QAAidsAAIndAACJ3gAAid8AAInhAACJ4gAAiiEAAIojAACKJQAAiicAAIoqAACKKwAAiiwAAIotAACKLgAAijAAAIoyAACKMwAAijQAAIo2AACKNwAAioIAAIqlAACKxQAAiuUAAIrnAACK6QAAiusAAIrtAACK8AAAivEAAIryAACK9QAAivYAAIr4AACK+QAAivsAAIr+AACK/wAAiwAAAIsDAACLBAAAiwkAAIsWAACLGwAAix0AAIsfAACLJAAAiycAAIsqAACLLAAAi1EAAIt1AACLnAAAi8AAAIvDAACLxQAAi8cAAIvJAACLywAAi80AAIvOAACL0QAAi94AAIvvAACL8QAAi/MAAIv1AACL9wAAi/kAAIv7AACL/QAAi/8AAIwQAACMEwAAjBYAAIwZAACMHAAAjB8AAIwiAACMJQAAjCgAAIwqAACMaQAAjGsAAIxtAACMbwAAjHIAAIxzAACMdAAAjHUAAIx2AACMeAAAjHoAAIx7AACMfAAAjH4AAIx/AACMvgAAjMAAAIzCAACMxAAAjMcAAIzIAACMyQAAjMoAAIzLAACMzQAAjM8AAIzQAACM0QAAjNMAAIzUAACNEwAAjRUAAI0YAACNGgAAjR0AAI0eAACNHwAAjSAAAI0hAACNIwAAjSUAAI0mAACNJwAAjSkAAI0qAACNNwAAjTgAAI05AACNOwAAjXoAAI18AACNfgAAjYAAAI2DAACNhAAAjYUAAI2GAACNhwAAjYkAAI2LAACNjAAAjY0AAI2PAACNkAAAjc8AAI3RAACN0wAAjdUAAI3YAACN2QAAjdoAAI3bAACN3AAAjd4AAI3gAACN4QAAjeIAAI3kAACN5QAAjiQAAI4mAACOKAAAjioAAI4tAACOLgAAji8AAI4wAACOMQAAjjMAAI41AACONgAAjjcAAI45AACOOgAAjnkAAI57AACOfQAAjn8AAI6CAACOgwAAjoQAAI6FAACOhgAAjogAAI6KAACOiwAAjowAAI6OAACOjwAAjs4AAI7QAACO0gAAjtQAAI7XAACO2AAAjtkAAI7aAACO2wAAjt0AAI7fAACO4AAAjuEAAI7jAACO5AAAjwkAAI8tAACPVAAAj3gAAI97AACPfQAAj38AAI+BAACPgwAAj4UAAI+GAACPiQAAj5YAAI+lAACPpwAAj6kAAI+rAACPrQAAj68AAI+xAACPswAAj8IAAI/FAACPyAAAj8sAAI/OAACP0QAAj9QAAI/XAACP2QAAkBgAAJAaAACQHAAAkB4AAJAhAACQIgAAkCMAAJAkAACQJQAAkCcAAJApAACQKgAAkCsAAJAtAACQLgAAkG0AAJBvAACQcQAAkHMAAJB2AACQdwAAkHgAAJB5AACQegAAkHwAAJB+AACQfwAAkIAAAJCCAACQgwAAkMIAAJDEAACQxgAAkMgAAJDLAACQzAAAkM0AAJDOAACQzwAAkNEAAJDTAACQ1AAAkNUAAJDXAACQ2AAAkRcAAJEZAACRHAAAkR4AAJEhAACRIgAAkSMAAJEkAACRJQAAkScAAJEpAACRKgAAkSsAAJEtAACRLgAAkW0AAJFvAACRcQAAkXMAAJF2AACRdwAAkXgAAJF5AACRegAAkXwAAJF+AACRfwAAkYAAAJGCAACRgwAAkcIAAJHEAACRxgAAkcgAAJHLAACRzAAAkc0AAJHOAACRzwAAkdEAAJHTAACR1AAAkdUAAJHXAACR2AAAkhcAAJIZAACSGwAAkh0AAJIgAACSIQAAkiIAAJIjAACSJAAAkiYAAJIoAACSKQAAkioAAJIsAACSLQAAkngAAJKbAACSuwAAktsAAJLdAACS3wAAkuEAAJLjAACS5gAAkucAAJLoAACS6wAAkuwAAJLuAACS7wAAkvEAAJLzAACS9AAAkvUAAJL4AACS+QAAkv4AAJMLAACTEAAAkxIAAJMUAACTGQAAkxwAAJMfAACTIQAAk0YAAJNqAACTkQAAk7UAAJO4AACTugAAk7wAAJO+AACTwAAAk8IAAJPDAACTxgAAk9MAAJPkAACT5gAAk+gAAJPqAACT7AAAk+4AAJPwAACT8gAAk/QAAJQFAACUCAAAlAsAAJQOAACUEQAAlBQAAJQXAACUGgAAlB0AAJQfAACUXgAAlGAAAJRiAACUZAAAlGcAAJRoAACUaQAAlGoAAJRrAACUbQAAlG8AAJRwAACUcQAAlHMAAJR0AACUswAAlLUAAJS3AACUuQAAlLwAAJS9AACUvgAAlL8AAJTAAACUwgAAlMQAAJTFAACUxgAAlMgAAJTJAACVCAAAlQoAAJUNAACVDwAAlRIAAJUTAACVFAAAlRUAAJUWAACVGAAAlRoAAJUbAACVHAAAlR4AAJUfAACVLAAAlS0AAJUuAACVMAAAlW8AAJVxAACVcwAAlXUAAJV4AACVeQAAlXoAAJV7AACVfAAAlX4AAJWAAACVgQAAlYIAAJWEAACVhQAAlcQAAJXGAACVyAAAlcoAAJXNAACVzgAAlc8AAJXQAACV0QAAldMAAJXVAACV1gAAldcAAJXZAACV2gAAlhkAAJYbAACWHQAAlh8AAJYiAACWIwAAliQAAJYlAACWJgAAligAAJYqAACWKwAAliwAAJYuAACWLwAAlm4AAJZwAACWcgAAlnQAAJZ3AACWeAAAlnkAAJZ6AACWewAAln0AAJZ/AACWgAAAloEAAJaDAACWhAAAlsMAAJbFAACWxwAAlskAAJbMAACWzQAAls4AAJbPAACW0AAAltIAAJbUAACW1QAAltYAAJbYAACW2QAAlv4AAJciAACXSQAAl20AAJdwAACXcgAAl3QAAJd2AACXeAAAl3oAAJd7AACXfgAAl4sAAJeaAACXnAAAl54AAJegAACXogAAl6QAAJemAACXqAAAl7cAAJe6AACXvQAAl8AAAJfDAACXxgAAl8kAAJfMAACXzgAAmA0AAJgPAACYEQAAmBMAAJgWAACYFwAAmBgAAJgZAACYGgAAmBwAAJgeAACYHwAAmCAAAJgiAACYIwAAmGIAAJhkAACYZgAAmGgAAJhrAACYbAAAmG0AAJhuAACYbwAAmHEAAJhzAACYdAAAmHUAAJh3AACYeAAAmLcAAJi5AACYuwAAmL0AAJjAAACYwQAAmMIAAJjDAACYxAAAmMYAAJjIAACYyQAAmMoAAJjMAACYzQAAmQwAAJkOAACZEAAAmRIAAJkVAACZFgAAmRcAAJkYAACZGQAAmRsAAJkdAACZHgAAmR8AAJkhAACZIgAAmWEAAJljAACZZQAAmWcAAJlqAACZawAAmWwAAJltAACZbgAAmXAAAJlyAACZcwAAmXQAAJl2AACZdwAAmbYAAJm4AACZugAAmbwAAJm/AACZwAAAmcEAAJnCAACZwwAAmcUAAJnHAACZyAAAmckAAJnLAACZzAAAmgsAAJoNAACaDwAAmhEAAJoUAACaFQAAmhYAAJoXAACaGAAAmhoAAJocAACaHQAAmh4AAJogAACaIQAAmmwAAJqPAACarwAAms8AAJrRAACa0wAAmtUAAJrXAACa2gAAmtsAAJrcAACa3wAAmuAAAJriAACa4wAAmuUAAJroAACa6QAAmuoAAJrtAACa7gAAmvMAAJsAAACbBQAAmwcAAJsJAACbDgAAmxEAAJsUAACbFgAAmzsAAJtfAACbhgAAm6oAAJutAACbrwAAm7EAAJuzAACbtQAAm7cAAJu4AACbuwAAm8gAAJvZAACb2wAAm90AAJvfAACb4QAAm+MAAJvlAACb5wAAm+kAAJv6AACb/QAAnAAAAJwDAACcBgAAnAkAAJwMAACcDwAAnBIAAJwUAACcUwAAnFUAAJxXAACcWQAAnFwAAJxdAACcXgAAnF8AAJxgAACcYgAAnGQAAJxlAACcZgAAnGgAAJxpAACcqAAAnKoAAJysAACcrgAAnLEAAJyyAACcswAAnLQAAJy1AACctwAAnLkAAJy6AACcuwAAnL0AAJy+AACc/QAAnP8AAJ0CAACdBAAAnQcAAJ0IAACdCQAAnQoAAJ0LAACdDQAAnQ8AAJ0QAACdEQAAnRMAAJ0UAACdIQAAnSIAAJ0jAACdJQAAnWQAAJ1mAACdaAAAnWoAAJ1tAACdbgAAnW8AAJ1wAACdcQAAnXMAAJ11AACddgAAnXcAAJ15AACdegAAnbkAAJ27AACdvQAAnb8AAJ3CAACdwwAAncQAAJ3FAACdxgAAncgAAJ3KAACdywAAncwAAJ3OAACdzwAAng4AAJ4QAACeEgAAnhQAAJ4XAACeGAAAnhkAAJ4aAACeGwAAnh0AAJ4fAACeIAAAniEAAJ4jAACeJAAAnmMAAJ5lAACeZwAAnmkAAJ5sAACebQAAnm4AAJ5vAACecAAAnnIAAJ50AACedQAAnnYAAJ54AACeeQAAnrgAAJ66AACevAAAnr4AAJ7BAACewgAAnsMAAJ7EAACexQAAnscAAJ7JAACeygAAnssAAJ7NAACezgAAnvMAAJ8XAACfPgAAn2IAAJ9lAACfZwAAn2kAAJ9rAACfbQAAn28AAJ9wAACfcwAAn4AAAJ+PAACfkQAAn5MAAJ+VAACflwAAn5kAAJ+bAACfnQAAn6wAAJ+vAACfsgAAn7UAAJ+4AACfuwAAn74AAJ/BAACfwwAAoAIAAKAEAACgBgAAoAgAAKALAACgDAAAoA0AAKAOAACgDwAAoBEAAKATAACgFAAAoBUAAKAXAACgGAAAoFcAAKBZAACgWwAAoF0AAKBgAACgYQAAoGIAAKBjAACgZAAAoGYAAKBoAACgaQAAoGoAAKBsAACgbQAAoKwAAKCuAACgsAAAoLIAAKC1AACgtgAAoLcAAKC4AACguQAAoLsAAKC9AACgvgAAoL8AAKDBAACgwgAAoQEAAKEDAAChBQAAoQcAAKEKAAChCwAAoQwAAKENAAChDgAAoRAAAKESAAChEwAAoRQAAKEWAAChFwAAoVYAAKFYAAChWgAAoVwAAKFfAAChYAAAoWEAAKFiAAChYwAAoWUAAKFnAAChaAAAoWkAAKFrAAChbAAAoasAAKGtAAChrwAAobEAAKG0AAChtQAAobYAAKG3AAChuAAAoboAAKG8AAChvQAAob4AAKHAAAChwQAAogAAAKICAACiBAAAogYAAKIJAACiCgAAogsAAKIMAACiDQAAog8AAKIRAACiEgAAohMAAKIVAACiFgAAomEAAKKEAACipAAAosQAAKLGAACiyAAAosoAAKLMAACizwAAotAAAKLRAACi1AAAotUAAKLXAACi2AAAotoAAKLdAACi3gAAot8AAKLiAACi4wAAougAAKL1AACi+gAAovwAAKL+AACjAwAAowYAAKMJAACjCwAAozAAAKNUAACjewAAo58AAKOiAACjpAAAo6YAAKOoAACjqgAAo6wAAKOtAACjsAAAo70AAKPOAACj0AAAo9IAAKPUAACj1gAAo9gAAKPaAACj3AAAo94AAKPvAACj8gAAo/UAAKP4AACj+wAAo/4AAKQBAACkBAAApAcAAKQJAACkSAAApEoAAKRMAACkTgAApFEAAKRSAACkUwAApFQAAKRVAACkVwAApFkAAKRaAACkWwAApF0AAKReAACknQAApJ8AAKShAACkowAApKYAAKSnAACkqAAApKkAAKSqAACkrAAApK4AAKSvAACksAAApLIAAKSzAACk8gAApPQAAKT3AACk+QAApPwAAKT9AACk/gAApP8AAKUAAAClAgAApQQAAKUFAAClBgAApQgAAKUJAAClFgAApRcAAKUYAAClGgAApVkAAKVbAAClXQAApV8AAKViAAClYwAApWQAAKVlAAClZgAApWgAAKVqAAClawAApWwAAKVuAAClbwAApa4AAKWwAAClsgAApbQAAKW3AACluAAApbkAAKW6AACluwAApb0AAKW/AAClwAAApcEAAKXDAAClxAAApgMAAKYFAACmBwAApgkAAKYMAACmDQAApg4AAKYPAACmEAAAphIAAKYUAACmFQAAphYAAKYYAACmGQAAplgAAKZaAACmXAAApl4AAKZhAACmYgAApmMAAKZkAACmZQAApmcAAKZpAACmagAApmsAAKZtAACmbgAApq0AAKavAACmsQAAprMAAKa2AACmtwAAprgAAKa5AACmugAAprwAAKa+AACmvwAApsAAAKbCAACmwwAApugAAKcMAACnMwAAp1cAAKdaAACnXAAAp14AAKdgAACnYgAAp2QAAKdlAACnaAAAp3UAAKeEAACnhgAAp4gAAKeKAACnjAAAp44AAKeQAACnkgAAp6EAAKekAACnpwAAp6oAAKetAACnsAAAp7MAAKe2AACnuAAAp/cAAKf5AACn+wAAp/0AAKgAAACoAQAAqAIAAKgDAACoBAAAqAYAAKgIAACoCQAAqAoAAKgMAACoDQAAqEwAAKhOAACoUAAAqFIAAKhVAACoVgAAqFcAAKhYAACoWQAAqFsAAKhdAACoXgAAqF8AAKhhAACoYgAAqKEAAKijAACopQAAqKcAAKiqAACoqwAAqKwAAKitAACorgAAqLAAAKiyAACoswAAqLQAAKi2AACotwAAqPYAAKj4AACo+gAAqPwAAKj/AACpAAAAqQEAAKkCAACpAwAAqQUAAKkHAACpCAAAqQkAAKkLAACpDAAAqUsAAKlNAACpTwAAqVEAAKlUAACpVQAAqVYAAKlXAACpWAAAqVoAAKlcAACpXQAAqV4AAKlgAACpYQAAqaAAAKmiAACppAAAqaYAAKmpAACpqgAAqasAAKmsAACprQAAqa8AAKmxAACpsgAAqbMAAKm1AACptgAAqfUAAKn3AACp+QAAqfsAAKn+AACp/wAAqgAAAKoBAACqAgAAqgQAAKoGAACqBwAAqggAAKoKAACqCwAAqlYAAKp5AACqmQAAqrkAAKq7AACqvQAAqr8AAKrBAACqxAAAqsUAAKrGAACqyQAAqsoAAKrMAACqzQAAqs8AAKrRAACq0gAAqtMAAKrWAACq1wAAqtwAAKrpAACq7gAAqvAAAKryAACq9wAAqvoAAKr9AACq/wAAqyQAAKtIAACrbwAAq5MAAKuWAACrmAAAq5oAAKucAACrngAAq6AAAKuhAACrpAAAq7EAAKvCAACrxAAAq8YAAKvIAACrygAAq8wAAKvOAACr0AAAq9IAAKvjAACr5gAAq+kAAKvsAACr7wAAq/IAAKv1AACr+AAAq/sAAKv9AACsPAAArD4AAKxAAACsQgAArEUAAKxGAACsRwAArEgAAKxJAACsSwAArE0AAKxOAACsTwAArFEAAKxSAACskQAArJMAAKyVAACslwAArJoAAKybAACsnAAArJ0AAKyeAACsoAAArKIAAKyjAACspAAArKYAAKynAACs5gAArOgAAKzrAACs7QAArPAAAKzxAACs8gAArPMAAKz0AACs9gAArPgAAKz5AACs+gAArPwAAKz9AACtCgAArQsAAK0MAACtDgAArU0AAK1PAACtUQAArVMAAK1WAACtVwAArVgAAK1ZAACtWgAArVwAAK1eAACtXwAArWAAAK1iAACtYwAAraIAAK2kAACtpgAAragAAK2rAACtrAAAra0AAK2uAACtrwAArbEAAK2zAACttAAArbUAAK23AACtuAAArfcAAK35AACt+wAArf0AAK4AAACuAQAArgIAAK4DAACuBAAArgYAAK4IAACuCQAArgoAAK4MAACuDQAArkwAAK5OAACuUAAArlIAAK5VAACuVgAArlcAAK5YAACuWQAArlsAAK5dAACuXgAArl8AAK5hAACuYgAArqEAAK6jAACupQAArqcAAK6qAACuqwAArqwAAK6tAACurgAArrAAAK6yAACuswAArrQAAK62AACutwAArtwAAK8AAACvJwAAr0sAAK9OAACvUAAAr1IAAK9UAACvVgAAr1gAAK9ZAACvXAAAr2kAAK94AACvegAAr3wAAK9+AACvgAAAr4IAAK+EAACvhgAAr5UAAK+YAACvmwAAr54AAK+hAACvpAAAr6cAAK+qAACvrAAAr+sAAK/tAACv7wAAr/EAAK/0AACv9QAAr/YAAK/3AACv+AAAr/oAAK/8AACv/QAAr/4AALAAAACwAQAAsEAAALBCAACwRAAAsEYAALBJAACwSgAAsEsAALBMAACwTQAAsE8AALBRAACwUgAAsFMAALBVAACwVgAAsJUAALCXAACwmQAAsJsAALCeAACwnwAAsKAAALChAACwogAAsKQAALCmAACwpwAAsKgAALCqAACwqwAAsOoAALDsAACw7gAAsPAAALDzAACw9AAAsPUAALD2AACw9wAAsPkAALD7AACw/AAAsP0AALD/AACxAAAAsT8AALFBAACxQwAAsUUAALFIAACxSQAAsUoAALFLAACxTAAAsU4AALFQAACxUQAAsVIAALFUAACxVQAAsZQAALGWAACxmAAAsZoAALGdAACxngAAsZ8AALGgAACxoQAAsaMAALGlAACxpgAAsacAALGpAACxqgAAsekAALHrAACx7QAAse8AALHyAACx8wAAsfQAALH1AACx9gAAsfgAALH6AACx+wAAsfwAALH+AACx/wAAskoAALJtAACyjQAAsq0AALKvAACysQAAsrMAALK1AACyuAAAsrkAALK6AACyvQAAsr4AALLAAACywQAAssMAALLGAACyxwAAssgAALLLAACyzAAAstEAALLeAACy4wAAsuUAALLnAACy7AAAsu8AALLyAACy9AAAsxkAALM9AACzZAAAs4gAALOLAACzjQAAs48AALORAACzkwAAs5UAALOWAACzmQAAs6YAALO3AACzuQAAs7sAALO9AACzvwAAs8EAALPDAACzxQAAs8cAALPYAACz2wAAs94AALPhAACz5AAAs+cAALPqAACz7QAAs/AAALPyAAC0MQAAtDMAALQ1AAC0NwAAtDoAALQ7AAC0PAAAtD0AALQ+AAC0QAAAtEIAALRDAAC0RAAAtEYAALRHAAC0hgAAtIgAALSKAAC0jAAAtI8AALSQAAC0kQAAtJIAALSTAAC0lQAAtJcAALSYAAC0mQAAtJsAALScAAC02wAAtN0AALTgAAC04gAAtOUAALTmAAC05wAAtOgAALTpAAC06wAAtO0AALTuAAC07wAAtPEAALTyAAC0/wAAtQAAALUBAAC1AwAAtUIAALVEAAC1RgAAtUgAALVLAAC1TAAAtU0AALVOAAC1TwAAtVEAALVTAAC1VAAAtVUAALVXAAC1WAAAtZcAALWZAAC1mwAAtZ0AALWgAAC1oQAAtaIAALWjAAC1pAAAtaYAALWoAAC1qQAAtaoAALWsAAC1rQAAtewAALXuAAC18AAAtfIAALX1AAC19gAAtfcAALX4AAC1+QAAtfsAALX9AAC1/gAAtf8AALYBAAC2AgAAtkEAALZDAAC2RQAAtkcAALZKAAC2SwAAtkwAALZNAAC2TgAAtlAAALZSAAC2UwAAtlQAALZWAAC2VwAAtpYAALaYAAC2mgAAtpwAALafAAC2oAAAtqEAALaiAAC2owAAtqUAALanAAC2qAAAtqkAALarAAC2rAAAttEAALb1AAC3HAAAt0AAALdDAAC3RQAAt0cAALdJAAC3SwAAt00AALdOAAC3UQAAt14AALdtAAC3bwAAt3EAALdzAAC3dQAAt3cAALd5AAC3ewAAt4oAALeNAAC3kAAAt5MAALeWAAC3mQAAt5wAALefAAC3oQAAt+AAALfiAAC35AAAt+YAALfpAAC36gAAt+sAALfsAAC37QAAt+8AALfxAAC38gAAt/MAALf1AAC39gAAuDUAALg3AAC4OQAAuDsAALg+AAC4PwAAuEAAALhBAAC4QgAAuEQAALhGAAC4RwAAuEgAALhKAAC4SwAAuIoAALiMAAC4jgAAuJAAALiTAAC4lAAAuJUAALiWAAC4lwAAuJkAALibAAC4nAAAuJ0AALifAAC4oAAAuN8AALjhAAC44wAAuOUAALjoAAC46QAAuOoAALjrAAC47AAAuO4AALjwAAC48QAAuPIAALj0AAC49QAAuTQAALk2AAC5OAAAuToAALk9AAC5PgAAuT8AALlAAAC5QQAAuUMAALlFAAC5RgAAuUcAALlJAAC5SgAAuYkAALmLAAC5jQAAuY8AALmSAAC5kwAAuZQAALmVAAC5lgAAuZgAALmaAAC5mwAAuZwAALmeAAC5nwAAud4AALngAAC54gAAueQAALnnAAC56AAAuekAALnqAAC56wAAue0AALnvAAC58AAAufEAALnzAAC59AAAuj8AALpiAAC6ggAAuqIAALqkAAC6pgAAuqgAALqqAAC6rQAAuq4AALqvAAC6sgAAurMAALq1AAC6tgAAurgAALq7AAC6vAAAur0AALrAAAC6wQAAusYAALrTAAC62AAAutoAALrcAAC64QAAuuQAALrnAAC66QAAuw4AALsyAAC7WQAAu30AALuAAAC7ggAAu4QAALuGAAC7iAAAu4oAALuLAAC7jgAAu5sAALusAAC7rgAAu7AAALuyAAC7tAAAu7YAALu4AAC7ugAAu7wAALvNAAC70AAAu9MAALvWAAC72QAAu9wAALvfAAC74gAAu+UAALvnAAC8JgAAvCgAALwqAAC8LAAAvC8AALwwAAC8MQAAvDIAALwzAAC8NQAAvDcAALw4AAC8OQAAvDsAALw8AAC8ewAAvH0AALx/AAC8gQAAvIQAALyFAAC8hgAAvIcAALyIAAC8igAAvIwAALyNAAC8jgAAvJAAALyRAAC80AAAvNIAALzVAAC81wAAvNoAALzbAAC83AAAvN0AALzeAAC84AAAvOIAALzjAAC85AAAvOYAALznAAC89AAAvPUAALz2AAC8+AAAvTcAAL05AAC9OwAAvT0AAL1AAAC9QQAAvUIAAL1DAAC9RAAAvUYAAL1IAAC9SQAAvUoAAL1MAAC9TQAAvYwAAL2OAAC9kAAAvZIAAL2VAAC9lgAAvZcAAL2YAAC9mQAAvZsAAL2dAAC9ngAAvZ8AAL2hAAC9ogAAveEAAL3jAAC95QAAvecAAL3qAAC96wAAvewAAL3tAAC97gAAvfAAAL3yAAC98wAAvfQAAL32AAC99wAAvjYAAL44AAC+OgAAvjwAAL4/AAC+QAAAvkEAAL5CAAC+QwAAvkUAAL5HAAC+SAAAvkkAAL5LAAC+TAAAvosAAL6NAAC+jwAAvpEAAL6UAAC+lQAAvpYAAL6XAAC+mAAAvpoAAL6cAAC+nQAAvp4AAL6gAAC+oQAAvsYAAL7qAAC/EQAAvzUAAL84AAC/OgAAvzwAAL8+AAC/QAAAv0IAAL9DAAC/RgAAv1MAAL9iAAC/ZAAAv2YAAL9oAAC/agAAv2wAAL9uAAC/cAAAv38AAL+CAAC/hQAAv4gAAL+LAAC/jgAAv5EAAL+UAAC/lgAAv9UAAL/XAAC/2QAAv9sAAL/eAAC/3wAAv+AAAL/hAAC/4gAAv+QAAL/mAAC/5wAAv+gAAL/qAAC/6wAAwCoAAMAsAADALgAAwDAAAMAzAADANAAAwDUAAMA2AADANwAAwDkAAMA7AADAPAAAwD0AAMA/AADAQAAAwH8AAMCBAADAgwAAwIUAAMCIAADAiQAAwIoAAMCLAADAjAAAwI4AAMCQAADAkQAAwJIAAMCUAADAlQAAwNQAAMDWAADA2AAAwNoAAMDdAADA3gAAwN8AAMDgAADA4QAAwOMAAMDlAADA5gAAwOcAAMDpAADA6gAAwSkAAMErAADBLQAAwS8AAMEyAADBMwAAwTQAAME1AADBNgAAwTgAAME6AADBOwAAwTwAAME+AADBPwAAwX4AAMGAAADBggAAwYQAAMGHAADBiAAAwYkAAMGKAADBiwAAwY0AAMGPAADBkAAAwZEAAMGTAADBlAAAwdMAAMHVAADB1wAAwdkAAMHcAADB3QAAwd4AAMHfAADB4AAAweIAAMHkAADB5QAAweYAAMHoAADB6QAAwjQAAMJXAADCdwAAwpcAAMKZAADCmwAAwp0AAMKfAADCogAAwqMAAMKkAADCpwAAwqgAAMKqAADCqwAAwq0AAMKwAADCsQAAwrIAAMK1AADCtgAAwrsAAMLIAADCzQAAws8AAMLRAADC1gAAwtkAAMLcAADC3gAAwwMAAMMnAADDTgAAw3IAAMN1AADDdwAAw3kAAMN7AADDfQAAw38AAMOAAADDgwAAw5AAAMOhAADDowAAw6UAAMOnAADDqQAAw6sAAMOtAADDrwAAw7EAAMPCAADDxQAAw8gAAMPLAADDzgAAw9EAAMPUAADD1wAAw9oAAMPcAADEGwAAxB0AAMQfAADEIQAAxCQAAMQlAADEJgAAxCcAAMQoAADEKgAAxCwAAMQtAADELgAAxDAAAMQxAADEcAAAxHIAAMR0AADEdgAAxHkAAMR6AADEewAAxHwAAMR9AADEfwAAxIEAAMSCAADEgwAAxIUAAMSGAADExQAAxMcAAMTKAADEzAAAxM8AAMTQAADE0QAAxNIAAMTTAADE1QAAxNcAAMTYAADE2QAAxNsAAMTcAADE6QAAxOoAAMTrAADE7QAAxSwAAMUuAADFMAAAxTIAAMU1AADFNgAAxTcAAMU4AADFOQAAxTsAAMU9AADFPgAAxT8AAMVBAADFQgAAxYEAAMWDAADFhQAAxYcAAMWKAADFiwAAxYwAAMWNAADFjgAAxZAAAMWSAADFkwAAxZQAAMWWAADFlwAAxdYAAMXYAADF2gAAxdwAAMXfAADF4AAAxeEAAMXiAADF4wAAxeUAAMXnAADF6AAAxekAAMXrAADF7AAAxisAAMYtAADGLwAAxjEAAMY0AADGNQAAxjYAAMY3AADGOAAAxjoAAMY8AADGPQAAxj4AAMZAAADGQQAAxoAAAMaCAADGhAAAxoYAAMaJAADGigAAxosAAMaMAADGjQAAxo8AAMaRAADGkgAAxpMAAMaVAADGlgAAxrsAAMbfAADHBgAAxyoAAMctAADHLwAAxzEAAMczAADHNQAAxzcAAMc4AADHOwAAx0gAAMdXAADHWQAAx1sAAMddAADHXwAAx2EAAMdjAADHZQAAx3QAAMd3AADHegAAx30AAMeAAADHgwAAx4YAAMeJAADHiwAAx8oAAMfMAADHzgAAx9AAAMfTAADH1AAAx9UAAMfWAADH1wAAx9kAAMfbAADH3AAAx90AAMffAADH4AAAyB8AAMghAADIIwAAyCUAAMgoAADIKQAAyCoAAMgrAADILAAAyC4AAMgwAADIMQAAyDIAAMg0AADINQAAyHQAAMh2AADIeAAAyHoAAMh9AADIfgAAyH8AAMiAAADIgQAAyIMAAMiFAADIhgAAyIcAAMiJAADIigAAyMkAAMjLAADIzQAAyM8AAMjSAADI0wAAyNQAAMjVAADI1gAAyNgAAMjaAADI2wAAyNwAAMjeAADI3wAAyR4AAMkgAADJIgAAySQAAMknAADJKAAAySkAAMkqAADJKwAAyS0AAMkvAADJMAAAyTEAAMkzAADJNAAAyXMAAMl1AADJdwAAyXkAAMl8AADJfQAAyX4AAMl/AADJgAAAyYIAAMmEAADJhQAAyYYAAMmIAADJiQAAycgAAMnKAADJzAAAyc4AAMnRAADJ0gAAydMAAMnUAADJ1QAAydcAAMnZAADJ2gAAydsAAMndAADJ3gAAyikAAMpMAADKbAAAyowAAMqOAADKkAAAypIAAMqUAADKlwAAypgAAMqZAADKnAAAyp0AAMqfAADKoAAAyqIAAMqlAADKpgAAyqcAAMqqAADKqwAAyrAAAMq9AADKwgAAysQAAMrGAADKywAAys4AAMrRAADK0wAAyvgAAMscAADLQwAAy2cAAMtqAADLbAAAy24AAMtwAADLcgAAy3QAAMt1AADLeAAAy4UAAMuWAADLmAAAy5oAAMucAADLngAAy6AAAMuiAADLpAAAy6YAAMu3AADLugAAy70AAMvAAADLwwAAy8YAAMvJAADLzAAAy88AAMvRAADMEAAAzBIAAMwUAADMFgAAzBkAAMwaAADMGwAAzBwAAMwdAADMHwAAzCEAAMwiAADMIwAAzCUAAMwmAADMZQAAzGcAAMxpAADMawAAzG4AAMxvAADMcAAAzHEAAMxyAADMdAAAzHYAAMx3AADMeAAAzHoAAMx7AADMugAAzLwAAMy/AADMwQAAzMQAAMzFAADMxgAAzMcAAMzIAADMygAAzMwAAMzNAADMzgAAzNAAAMzRAADM3gAAzN8AAMzgAADM4gAAzSEAAM0jAADNJQAAzScAAM0qAADNKwAAzSwAAM0tAADNLgAAzTAAAM0yAADNMwAAzTQAAM02AADNNwAAzXYAAM14AADNegAAzXwAAM1/AADNgAAAzYEAAM2CAADNgwAAzYUAAM2HAADNiAAAzYkAAM2LAADNjAAAzcsAAM3NAADNzwAAzdEAAM3UAADN1QAAzdYAAM3XAADN2AAAzdoAAM3cAADN3QAAzd4AAM3gAADN4QAAziAAAM4iAADOJAAAziYAAM4pAADOKgAAzisAAM4sAADOLQAAzi8AAM4xAADOMgAAzjMAAM41AADONgAAznUAAM53AADOeQAAznsAAM5+AADOfwAAzoAAAM6BAADOggAAzoQAAM6GAADOhwAAzogAAM6KAADOiwAAzrAAAM7UAADO+wAAzx8AAM8iAADPJAAAzyYAAM8oAADPKgAAzywAAM8tAADPMAAAzz0AAM9MAADPTgAAz1AAAM9SAADPVAAAz1YAAM9YAADPWgAAz2kAAM9sAADPbwAAz3IAAM91AADPeAAAz3sAAM9+AADPgAAAz78AAM/BAADPwwAAz8UAAM/IAADPyQAAz8oAAM/LAADPzAAAz84AAM/QAADP0QAAz9IAAM/UAADP1QAA0BQAANAWAADQGAAA0BoAANAdAADQHgAA0B8AANAgAADQIQAA0CMAANAlAADQJgAA0CcAANApAADQKgAA0GkAANBrAADQbQAA0G8AANByAADQcwAA0HQAANB1AADQdgAA0HgAANB6AADQewAA0HwAANB+AADQfwAA0L4AANDAAADQwwAA0MUAANDIAADQyQAA0MoAANDLAADQzAAA0M4AANDQAADQ0QAA0NIAANDUAADQ1QAA0RQAANEWAADRGAAA0RoAANEdAADRHgAA0R8AANEgAADRIQAA0SMAANElAADRJgAA0ScAANEpAADRKgAA0WkAANFrAADRbQAA0W8AANFyAADRcwAA0XQAANF1AADRdgAA0XgAANF6AADRewAA0XwAANF+AADRfwAA0b4AANHAAADRwgAA0cQAANHHAADRyAAA0ckAANHKAADRywAA0c0AANHPAADR0AAA0dEAANHTAADR1AAA0d0AANHeAADR4AAA0iMAANJHAADSawAA0o4AANK1AADS1QAA0vwAANMjAADTQwAA02cAANOLAADTjQAA05AAANOSAADTlAAA05YAANOZAADTnAAA054AANOgAADTowAA06UAANOnAADTqgAA060AANOuAADTswAA08AAANPDAADTxQAA08gAANPLAADTzQAA0/IAANQWAADUPQAA1GEAANRkAADUZgAA1GgAANRqAADUbAAA1G4AANRvAADUcgAA1H8AANSSAADUlAAA1JYAANSYAADUmgAA1JwAANSeAADUoAAA1KIAANSkAADUtwAA1LoAANS9AADUwAAA1MMAANTGAADUyQAA1MwAANTPAADU0gAA1NQAANUTAADVFQAA1RgAANUaAADVHQAA1R4AANUfAADVIAAA1SEAANUjAADVJQAA1SYAANUnAADVKQAA1SoAANUzAADVNAAA1TYAANV1AADVdwAA1XkAANV7AADVfgAA1X8AANWAAADVgQAA1YIAANWEAADVhgAA1YcAANWIAADVigAA1YsAANXKAADVzAAA1c8AANXRAADV1AAA1dUAANXWAADV1wAA1dgAANXaAADV3AAA1d0AANXeAADV4AAA1eEAANXqAADV7QAA1fAAANXyAADV+wAA1f4AANYBAADWAwAA1gcAANZGAADWSAAA1koAANZMAADWTwAA1lAAANZRAADWUgAA1lMAANZVAADWVwAA1lgAANZZAADWWwAA1lwAANabAADWnQAA1qAAANaiAADWpQAA1qYAANanAADWqAAA1qkAANarAADWrQAA1q4AANavAADWsQAA1rIAANa7AADWvAAA1r4AANb9AADW/wAA1wEAANcDAADXBgAA1wcAANcIAADXCQAA1woAANcMAADXDgAA1w8AANcQAADXEgAA1xMAANdSAADXVAAA11cAANdZAADXXAAA110AANdeAADXXwAA12AAANdiAADXZAAA12UAANdmAADXaAAA12kAANd2AADXdwAA13gAANd6AADXuQAA17sAANe9AADXvwAA18IAANfDAADXxAAA18UAANfGAADXyAAA18oAANfLAADXzAAA184AANfPAADYDgAA2BAAANgTAADYFQAA2BgAANgZAADYGgAA2BsAANgcAADYHgAA2CAAANghAADYIgAA2CQAANglAADYMAAA2D0AANhWAADYWQAA2FwAANhfAADYYgAA2GQAANhnAADYagAA2G0AANhwAADYcwAA2HYAANh4AADYkQAA2JQAANiXAADYmgAA2J0AANigAADYowAA2KYAANipAADYrAAA2K8AANiyAADYtQAA2LcAANjAAADYxQAA2MoAANjSAADY1wAA2N0AANjmAADY7wAA2P4AANlJAADZbAAA2YwAANmsAADZrgAA2bAAANmyAADZtAAA2bcAANm4AADZuQAA2bwAANm9AADZvwAA2cAAANnCAADZxQAA2cYAANnHAADZygAA2csAANnQAADZ3QAA2eIAANnkAADZ5gAA2esAANnuAADZ8QAA2fMAANoYAADaPAAA2mMAANqHAADaigAA2owAANqOAADakAAA2pIAANqUAADalQAA2pgAANqlAADatgAA2rgAANq6AADavAAA2r4AANrAAADawgAA2sQAANrGAADa1wAA2toAANrdAADa4AAA2uMAANrmAADa6QAA2uwAANrvAADa8QAA2zAAANsyAADbNAAA2zYAANs5AADbOgAA2zsAANs8AADbPQAA2z8AANtBAADbQgAA20MAANtFAADbRgAA24UAANuHAADbiQAA24sAANuOAADbjwAA25AAANuRAADbkgAA25QAANuWAADblwAA25gAANuaAADbmwAA29oAANvcAADb3wAA2+EAANvkAADb5QAA2+YAANvnAADb6AAA2+oAANvsAADb7QAA2+4AANvwAADb8QAA2/4AANv/AADcAAAA3AIAANxBAADcQwAA3EUAANxHAADcSgAA3EsAANxMAADcTQAA3E4AANxQAADcUgAA3FMAANxUAADcVgAA3FcAANyWAADcmAAA3JoAANycAADcnwAA3KAAANyhAADcogAA3KMAANylAADcpwAA3KgAANypAADcqwAA3KwAANzrAADc7QAA3O8AANzxAADc9AAA3PUAANz2AADc9wAA3PgAANz6AADc/AAA3P0AANz+AADdAAAA3QEAAN1AAADdQgAA3UQAAN1GAADdSQAA3UoAAN1LAADdTAAA3U0AAN1PAADdUQAA3VIAAN1TAADdVQAA3VYAAN2VAADdlwAA3ZkAAN2bAADdngAA3Z8AAN2gAADdoQAA3aIAAN2kAADdpgAA3acAAN2oAADdqgAA3asAAN3QAADd9AAA3hsAAN4/AADeQgAA3kQAAN5GAADeSAAA3koAAN5MAADeTQAA3lAAAN5dAADebAAA3m4AAN5wAADecgAA3nQAAN52AADeeAAA3noAAN6JAADejAAA3o8AAN6SAADelQAA3pgAAN6bAADengAA3qAAAN7fAADe4QAA3uMAAN7lAADe6AAA3ukAAN7qAADe6wAA3uwAAN7uAADe8AAA3vEAAN7yAADe9AAA3vUAAN80AADfNgAA3zgAAN86AADfPQAA3z4AAN8/AADfQAAA30EAAN9DAADfRQAA30YAAN9HAADfSQAA30oAAN+JAADfiwAA340AAN+PAADfkgAA35MAAN+UAADflQAA35YAAN+YAADfmgAA35sAAN+cAADfngAA358AAN/eAADf4AAA3+IAAN/kAADf5wAA3+gAAN/pAADf6gAA3+sAAN/tAADf7wAA3/AAAN/xAADf8wAA3/QAAOAzAADgNQAA4DcAAOA5AADgPAAA4D0AAOA+AADgPwAA4EAAAOBCAADgRAAA4EUAAOBGAADgSAAA4EkAAOCIAADgigAA4IwAAOCOAADgkQAA4JIAAOCTAADglAAA4JUAAOCXAADgmQAA4JoAAOCbAADgnQAA4J4AAODdAADg3wAA4OEAAODjAADg5gAA4OcAAODoAADg6QAA4OoAAODsAADg7gAA4O8AAODwAADg8gAA4PMAAOE+AADhYQAA4YEAAOGhAADhowAA4aUAAOGnAADhqQAA4awAAOGtAADhrgAA4bEAAOGyAADhtAAA4bUAAOG3AADhugAA4bsAAOG8AADhvwAA4cAAAOHFAADh0gAA4dcAAOHZAADh2wAA4eAAAOHjAADh5gAA4egAAOINAADiMQAA4lgAAOJ8AADifwAA4oEAAOKDAADihQAA4ocAAOKJAADiigAA4o0AAOKaAADiqwAA4q0AAOKvAADisQAA4rMAAOK1AADitwAA4rkAAOK7AADizAAA4s8AAOLSAADi1QAA4tgAAOLbAADi3gAA4uEAAOLkAADi5gAA4yUAAOMnAADjKQAA4ysAAOMuAADjLwAA4zAAAOMxAADjMgAA4zQAAOM2AADjNwAA4zgAAOM6AADjOwAA43oAAON8AADjfgAA44AAAOODAADjhAAA44UAAOOGAADjhwAA44kAAOOLAADjjAAA440AAOOPAADjkAAA488AAOPRAADj1AAA49YAAOPZAADj2gAA49sAAOPcAADj3QAA498AAOPhAADj4gAA4+MAAOPlAADj5gAA4/MAAOP0AADj9QAA4/cAAOQ2AADkOAAA5DoAAOQ8AADkPwAA5EAAAORBAADkQgAA5EMAAORFAADkRwAA5EgAAORJAADkSwAA5EwAAOSLAADkjQAA5I8AAOSRAADklAAA5JUAAOSWAADklwAA5JgAAOSaAADknAAA5J0AAOSeAADkoAAA5KEAAOTgAADk4gAA5OQAAOTmAADk6QAA5OoAAOTrAADk7AAA5O0AAOTvAADk8QAA5PIAAOTzAADk9QAA5PYAAOU1AADlNwAA5TkAAOU7AADlPgAA5T8AAOVAAADlQQAA5UIAAOVEAADlRgAA5UcAAOVIAADlSgAA5UsAAOWKAADljAAA5Y4AAOWQAADlkwAA5ZQAAOWVAADllgAA5ZcAAOWZAADlmwAA5ZwAAOWdAADlnwAA5aAAAOXFAADl6QAA5hAAAOY0AADmNwAA5jkAAOY7AADmPQAA5j8AAOZBAADmQgAA5kUAAOZSAADmYQAA5mMAAOZlAADmZwAA5mkAAOZrAADmbQAA5m8AAOZ+AADmgQAA5oQAAOaHAADmigAA5o0AAOaQAADmkwAA5pUAAObUAADm1gAA5tgAAObaAADm3QAA5t4AAObfAADm4AAA5uEAAObjAADm5QAA5uYAAObnAADm6QAA5uoAAOcpAADnKwAA5y0AAOcvAADnMgAA5zMAAOc0AADnNQAA5zYAAOc4AADnOgAA5zsAAOc8AADnPgAA5z8AAOd+AADngAAA54IAAOeEAADnhwAA54gAAOeJAADnigAA54sAAOeNAADnjwAA55AAAOeRAADnkwAA55QAAOfTAADn1QAA59cAAOfZAADn3AAA590AAOfeAADn3wAA5+AAAOfiAADn5AAA5+UAAOfmAADn6AAA5+kAAOgoAADoKgAA6CwAAOguAADoMQAA6DIAAOgzAADoNAAA6DUAAOg3AADoOQAA6DoAAOg7AADoPQAA6D4AAOh9AADofwAA6IEAAOiDAADohgAA6IcAAOiIAADoiQAA6IoAAOiMAADojgAA6I8AAOiQAADokgAA6JMAAOjSAADo1AAA6NYAAOjYAADo2wAA6NwAAOjdAADo3gAA6N8AAOjhAADo4wAA6OQAAOjlAADo5wAA6OgAAOkzAADpVgAA6XYAAOmWAADpmAAA6ZoAAOmcAADpngAA6aEAAOmiAADpowAA6aYAAOmnAADpqQAA6aoAAOmsAADprwAA6bAAAOmxAADptAAA6bUAAOm+AADpywAA6dAAAOnSAADp1AAA6dkAAOncAADp3wAA6eEAAOoGAADqKgAA6lEAAOp1AADqeAAA6noAAOp8AADqfgAA6oAAAOqCAADqgwAA6oYAAOqTAADqpAAA6qYAAOqoAADqqgAA6qwAAOquAADqsAAA6rIAAOq0AADqxQAA6sgAAOrLAADqzgAA6tEAAOrUAADq1wAA6toAAOrdAADq3wAA6x4AAOsgAADrIgAA6yQAAOsnAADrKAAA6ykAAOsqAADrKwAA6y0AAOsvAADrMAAA6zEAAOszAADrNAAA63MAAOt1AADrdwAA63kAAOt8AADrfQAA634AAOt/AADrgAAA64IAAOuEAADrhQAA64YAAOuIAADriQAA68gAAOvKAADrzQAA688AAOvSAADr0wAA69QAAOvVAADr1gAA69gAAOvaAADr2wAA69wAAOveAADr3wAA6+wAAOvtAADr7gAA6/AAAOwvAADsMQAA7DMAAOw1AADsOAAA7DkAAOw6AADsOwAA7DwAAOw+AADsQAAA7EEAAOxCAADsRAAA7EUAAOyEAADshgAA7IgAAOyKAADsjQAA7I4AAOyPAADskAAA7JEAAOyTAADslQAA7JYAAOyXAADsmQAA7JoAAOzZAADs2wAA7N0AAOzfAADs4gAA7OMAAOzkAADs5QAA7OYAAOzoAADs6gAA7OsAAOzsAADs7gAA7O8AAO0uAADtMAAA7TIAAO00AADtNwAA7TgAAO05AADtOgAA7TsAAO09AADtPwAA7UAAAO1BAADtQwAA7UQAAO2DAADthQAA7YcAAO2JAADtjAAA7Y0AAO2OAADtjwAA7ZAAAO2SAADtlAAA7ZUAAO2WAADtmAAA7ZkAAO2+AADt4gAA7gkAAO4tAADuMAAA7jIAAO40AADuNgAA7jgAAO46AADuOwAA7j4AAO5LAADuWgAA7lwAAO5eAADuYAAA7mIAAO5kAADuZgAA7mgAAO53AADuegAA7n0AAO6AAADugwAA7oYAAO6JAADujAAA7o4AAO7NAADuzwAA7tEAAO7TAADu1gAA7tcAAO7YAADu2QAA7toAAO7cAADu3gAA7t8AAO7gAADu4gAA7uMAAO8iAADvJAAA7yYAAO8oAADvKwAA7ywAAO8tAADvLgAA7y8AAO8xAADvMwAA7zQAAO81AADvNwAA7zgAAO93AADveQAA73sAAO99AADvgAAA74EAAO+CAADvgwAA74QAAO+GAADviAAA74kAAO+KAADvjAAA740AAO/MAADvzgAA79EAAO/TAADv1gAA79cAAO/YAADv2QAA79oAAO/cAADv3gAA798AAO/gAADv4gAA7+MAAO/mAADwJQAA8CcAAPApAADwKwAA8C4AAPAvAADwMAAA8DEAAPAyAADwNAAA8DYAAPA3AADwOAAA8DoAAPA7AADwegAA8HwAAPB+AADwgAAA8IMAAPCEAADwhQAA8IYAAPCHAADwiQAA8IsAAPCMAADwjQAA8I8AAPCQAADwzwAA8NEAAPDTAADw1QAA8NgAAPDZAADw2gAA8NsAAPDcAADw3gAA8OAAAPDhAADw4gAA8OQAAPDlAADxMAAA8VMAAPFzAADxkwAA8ZUAAPGXAADxmQAA8ZsAAPGeAADxnwAA8aAAAPGjAADxpAAA8aYAAPGnAADxqQAA8awAAPGtAADxrgAA8bEAAPGyAADxtwAA8cQAAPHJAADxywAA8c0AAPHSAADx1QAA8dgAAPHaAADx/wAA8iMAAPJKAADybgAA8nEAAPJzAADydQAA8ncAAPJ5AADyewAA8nwAAPJ/AADyjAAA8p0AAPKfAADyoQAA8qMAAPKlAADypwAA8qkAAPKrAADyrQAA8r4AAPLBAADyxAAA8scAAPLKAADyzQAA8tAAAPLTAADy1gAA8tgAAPMXAADzGQAA8xsAAPMdAADzIAAA8yEAAPMiAADzIwAA8yQAAPMmAADzKAAA8ykAAPMqAADzLAAA8y0AAPNsAADzbgAA83AAAPNyAADzdQAA83YAAPN3AADzeAAA83kAAPN7AADzfQAA834AAPN/AADzgQAA84IAAPPBAADzwwAA88YAAPPIAADzywAA88wAAPPNAADzzgAA888AAPPRAADz0wAA89QAAPPVAADz1wAA89gAAPPlAADz5gAA8+cAAPPpAAD0KAAA9CoAAPQsAAD0LgAA9DEAAPQyAAD0MwAA9DQAAPQ1AAD0NwAA9DkAAPQ6AAD0OwAA9D0AAPQ+AAD0fQAA9H8AAPSBAAD0gwAA9IYAAPSHAAD0iAAA9IkAAPSKAAD0jAAA9I4AAPSPAAD0kAAA9JIAAPSTAAD00gAA9NQAAPTWAAD02AAA9NsAAPTcAAD03QAA9N4AAPTfAAD04QAA9OMAAPTkAAD05QAA9OcAAPToAAD1JwAA9SkAAPUrAAD1LQAA9TAAAPUxAAD1MgAA9TMAAPU0AAD1NgAA9TgAAPU5AAD1OgAA9TwAAPU9AAD1fAAA9X4AAPWAAAD1ggAA9YUAAPWGAAD1hwAA9YgAAPWJAAD1iwAA9Y0AAPWOAAD1jwAA9ZEAAPWSAAD1twAA9dsAAPYCAAD2JgAA9ikAAPYrAAD2LQAA9i8AAPYxAAD2MwAA9jQAAPY3AAD2RAAA9lMAAPZVAAD2VwAA9lkAAPZbAAD2XQAA9l8AAPZhAAD2cAAA9nMAAPZ2AAD2eQAA9nwAAPZ/AAD2ggAA9oUAAPaHAAD2xgAA9sgAAPbKAAD2zAAA9s8AAPbQAAD20QAA9tIAAPbTAAD21QAA9tcAAPbYAAD22QAA9tsAAPbcAAD3GwAA9x0AAPcfAAD3IQAA9yQAAPclAAD3JgAA9ycAAPcoAAD3KgAA9ywAAPctAAD3LgAA9zAAAPcxAAD3cAAA93IAAPd0AAD3dgAA93kAAPd6AAD3ewAA93wAAPd9AAD3fwAA94EAAPeCAAD3gwAA94UAAPeGAAD3xQAA98cAAPfJAAD3ywAA984AAPfPAAD30AAA99EAAPfSAAD31AAA99YAAPfXAAD32AAA99oAAPfbAAD4GgAA+BwAAPgeAAD4IAAA+CMAAPgkAAD4JQAA+CYAAPgnAAD4KQAA+CsAAPgsAAD4LQAA+C8AAPgwAAD4bwAA+HEAAPhzAAD4dQAA+HgAAPh5AAD4egAA+HsAAPh8AAD4fgAA+IAAAPiBAAD4ggAA+IQAAPiFAAD4xAAA+MYAAPjIAAD4ygAA+M0AAPjOAAD4zwAA+NAAAPjRAAD40wAA+NUAAPjWAAD41wAA+NkAAPjaAAD5JQAA+UgAAPloAAD5iAAA+YoAAPmMAAD5jgAA+ZAAAPmTAAD5lAAA+ZUAAPmYAAD5mQAA+ZsAAPmcAAD5ngAA+aAAAPmhAAD5ogAA+aUAAPmmAAD5rwAA+bwAAPnBAAD5wwAA+cUAAPnKAAD5zQAA+dAAAPnSAAD59wAA+hsAAPpCAAD6ZgAA+mkAAPprAAD6bQAA+m8AAPpxAAD6cwAA+nQAAPp3AAD6hAAA+pUAAPqXAAD6mQAA+psAAPqdAAD6nwAA+qEAAPqjAAD6pQAA+rYAAPq5AAD6vAAA+r8AAPrCAAD6xQAA+sgAAPrLAAD6zgAA+tAAAPsPAAD7EQAA+xMAAPsVAAD7GAAA+xkAAPsaAAD7GwAA+xwAAPseAAD7IAAA+yEAAPsiAAD7JAAA+yUAAPtkAAD7ZgAA+2gAAPtqAAD7bQAA+24AAPtvAAD7cAAA+3EAAPtzAAD7dQAA+3YAAPt3AAD7eQAA+3oAAPu5AAD7uwAA+74AAPvAAAD7wwAA+8QAAPvFAAD7xgAA+8cAAPvJAAD7ywAA+8wAAPvNAAD7zwAA+9AAAPvdAAD73gAA+98AAPvhAAD8IAAA/CIAAPwkAAD8JgAA/CkAAPwqAAD8KwAA/CwAAPwtAAD8LwAA/DEAAPwyAAD8MwAA/DUAAPw2AAD8dQAA/HcAAPx5AAD8ewAA/H4AAPx/AAD8gAAA/IEAAPyCAAD8hAAA/IYAAPyHAAD8iAAA/IoAAPyLAAD8ygAA/MwAAPzOAAD80AAA/NMAAPzUAAD81QAA/NYAAPzXAAD82QAA/NsAAPzcAAD83QAA/N8AAPzgAAD9HwAA/SEAAP0jAAD9JQAA/SgAAP0pAAD9KgAA/SsAAP0sAAD9LgAA/TAAAP0xAAD9MgAA/TQAAP01AAD9dAAA/XYAAP14AAD9egAA/X0AAP1+AAD9fwAA/YAAAP2BAAD9gwAA/YUAAP2GAAD9hwAA/YkAAP2KAAD9rwAA/dMAAP36AAD+HgAA/iEAAP4jAAD+JQAA/icAAP4pAAD+KwAA/iwAAP4vAAD+PAAA/ksAAP5NAAD+TwAA/lEAAP5TAAD+VQAA/lcAAP5ZAAD+aAAA/msAAP5uAAD+cQAA/nQAAP53AAD+egAA/n0AAP5/AAD+vgAA/sAAAP7CAAD+xAAA/scAAP7IAAD+yQAA/soAAP7LAAD+zQAA/s8AAP7QAAD+0QAA/tMAAP7UAAD/EwAA/xUAAP8XAAD/GQAA/xwAAP8dAAD/HgAA/x8AAP8gAAD/IgAA/yQAAP8lAAD/JgAA/ygAAP8pAAD/aAAA/2oAAP9sAAD/bgAA/3EAAP9yAAD/cwAA/3QAAP91AAD/dwAA/3kAAP96AAD/ewAA/30AAP9+AAD/vQAA/78AAP/BAAD/wwAA/8YAAP/HAAD/yAAA/8kAAP/KAAD/zAAA/84AAP/PAAD/0AAA/9IAAP/TAAEAEgABABQAAQAWAAEAGAABABsAAQAcAAEAHQABAB4AAQAfAAEAIQABACMAAQAkAAEAJQABACcAAQAoAAEAZwABAGkAAQBrAAEAbQABAHAAAQBxAAEAcgABAHMAAQB0AAEAdgABAHgAAQB5AAEAegABAHwAAQB9AAEAvAABAL4AAQDAAAEAwgABAMUAAQDGAAEAxwABAMgAAQDJAAEAywABAM0AAQDOAAEAzwABANEAAQDSAAEBHQABAUAAAQFgAAEBgAABAYIAAQGEAAEBhgABAYgAAQGLAAEBjAABAY0AAQGQAAEBkQABAZMAAQGUAAEBlgABAZkAAQGaAAEBmwABAZ4AAQGfAAEBpAABAbEAAQG2AAEBuAABAboAAQG/AAEBwgABAcUAAQHHAAEB7AABAhAAAQI3AAECWwABAl4AAQJgAAECYgABAmQAAQJmAAECaAABAmkAAQJsAAECeQABAooAAQKMAAECjgABApAAAQKSAAEClAABApYAAQKYAAECmgABAqsAAQKuAAECsQABArQAAQK3AAECugABAr0AAQLAAAECwwABAsUAAQMEAAEDBgABAwgAAQMKAAEDDQABAw4AAQMPAAEDEAABAxEAAQMTAAEDFQABAxYAAQMXAAEDGQABAxoAAQNZAAEDWwABA10AAQNfAAEDYgABA2MAAQNkAAEDZQABA2YAAQNoAAEDagABA2sAAQNsAAEDbgABA28AAQOuAAEDsAABA7MAAQO1AAEDuAABA7kAAQO6AAEDuwABA7wAAQO+AAEDwAABA8EAAQPCAAEDxAABA8UAAQPSAAED0wABA9QAAQPWAAEEFQABBBcAAQQZAAEEGwABBB4AAQQfAAEEIAABBCEAAQQiAAEEJAABBCYAAQQnAAEEKAABBCoAAQQrAAEEagABBGwAAQRuAAEEcAABBHMAAQR0AAEEdQABBHYAAQR3AAEEeQABBHsAAQR8AAEEfQABBH8AAQSAAAEEvwABBMEAAQTDAAEExQABBMgAAQTJAAEEygABBMsAAQTMAAEEzgABBNAAAQTRAAEE0gABBNQAAQTVAAEFFAABBRYAAQUYAAEFGgABBR0AAQUeAAEFHwABBSAAAQUhAAEFIwABBSUAAQUmAAEFJwABBSkAAQUqAAEFaQABBWsAAQVtAAEFbwABBXIAAQVzAAEFdAABBXUAAQV2AAEFeAABBXoAAQV7AAEFfAABBX4AAQV/AAEFpAABBcgAAQXvAAEGEwABBhYAAQYYAAEGGgABBhwAAQYeAAEGIAABBiEAAQYkAAEGMQABBkAAAQZCAAEGRAABBkYAAQZIAAEGSgABBkwAAQZOAAEGXQABBmAAAQZjAAEGZgABBmkAAQZsAAEGbwABBnIAAQZ0AAEGswABBrUAAQa4AAEGugABBr0AAQa+AAEGvwABBsAAAQbBAAEGwwABBsUAAQbGAAEGxwABBskAAQbKAAEGzQABBwwAAQcOAAEHEAABBxIAAQcVAAEHFgABBxcAAQcYAAEHGQABBxsAAQcdAAEHHgABBx8AAQchAAEHIgABB2EAAQdjAAEHZQABB2cAAQdqAAEHawABB2wAAQdtAAEHbgABB3AAAQdyAAEHcwABB3QAAQd2AAEHdwABB7YAAQe4AAEHuwABB70AAQfAAAEHwQABB8IAAQfDAAEHxAABB8YAAQfIAAEHyQABB8oAAQfMAAEHzQABCAwAAQgOAAEIEAABCBIAAQgVAAEIFgABCBcAAQgYAAEIGQABCBsAAQgdAAEIHgABCB8AAQghAAEIIgABCGEAAQhjAAEIZQABCGcAAQhqAAEIawABCGwAAQhtAAEIbgABCHAAAQhyAAEIcwABCHQAAQh2AAEIdwABCLYAAQi4AAEIugABCLwAAQi/AAEIwAABCMEAAQjCAAEIwwABCMUAAQjHAAEIyAABCMkAAQjLAAEIzAABCRcAAQk6AAEJWgABCXoAAQl8AAEJfgABCYAAAQmCAAEJhQABCYYAAQmHAAEJigABCYsAAQmNAAEJjgABCZAAAQmTAAEJlAABCZUAAQmYAAEJmQABCZ4AAQmrAAEJsAABCbIAAQm0AAEJuQABCbwAAQm/AAEJwQABCeYAAQoKAAEKMQABClUAAQpYAAEKWgABClwAAQpeAAEKYAABCmIAAQpjAAEKZgABCnMAAQqEAAEKhgABCogAAQqKAAEKjAABCo4AAQqQAAEKkgABCpQAAQqlAAEKqAABCqsAAQquAAEKsQABCrQAAQq3AAEKugABCr0AAQq/AAEK/gABCwAAAQsCAAELBAABCwcAAQsIAAELCQABCwoAAQsLAAELDQABCw8AAQsQAAELEQABCxMAAQsUAAELUwABC1UAAQtXAAELWQABC1wAAQtdAAELXgABC18AAQtgAAELYgABC2QAAQtlAAELZgABC2gAAQtpAAELqAABC6oAAQutAAELrwABC7IAAQuzAAELtAABC7UAAQu2AAELuAABC7oAAQu7AAELvAABC74AAQu/AAELzAABC80AAQvOAAEL0AABDA8AAQwRAAEMEwABDBUAAQwYAAEMGQABDBoAAQwbAAEMHAABDB4AAQwgAAEMIQABDCIAAQwkAAEMJQABDGQAAQxmAAEMaAABDGoAAQxtAAEMbgABDG8AAQxwAAEMcQABDHMAAQx1AAEMdgABDHcAAQx5AAEMegABDLkAAQy7AAEMvQABDL8AAQzCAAEMwwABDMQAAQzFAAEMxgABDMgAAQzKAAEMywABDMwAAQzOAAEMzwABDQ4AAQ0QAAENEgABDRQAAQ0XAAENGAABDRkAAQ0aAAENGwABDR0AAQ0fAAENIAABDSEAAQ0jAAENJAABDWMAAQ1lAAENZwABDWkAAQ1sAAENbQABDW4AAQ1vAAENcAABDXIAAQ10AAENdQABDXYAAQ14AAENeQABDZ4AAQ3CAAEN6QABDg0AAQ4QAAEOEgABDhQAAQ4WAAEOGAABDhoAAQ4bAAEOHgABDisAAQ46AAEOPAABDj4AAQ5AAAEOQgABDkQAAQ5GAAEOSAABDlcAAQ5aAAEOXQABDmAAAQ5jAAEOZgABDmkAAQ5sAAEObgABDq0AAQ6vAAEOsQABDrMAAQ62AAEOtwABDrgAAQ65AAEOugABDrwAAQ6+AAEOvwABDsAAAQ7CAAEOwwABDwIAAQ8EAAEPBgABDwgAAQ8LAAEPDAABDw0AAQ8OAAEPDwABDxEAAQ8TAAEPFAABDxUAAQ8XAAEPGAABD1cAAQ9ZAAEPWwABD10AAQ9gAAEPYQABD2IAAQ9jAAEPZAABD2YAAQ9oAAEPaQABD2oAAQ9sAAEPbQABD6wAAQ+uAAEPsAABD7IAAQ+1AAEPtgABD7cAAQ+4AAEPuQABD7sAAQ+9AAEPvgABD78AAQ/BAAEPwgABEAEAARADAAEQBQABEAcAARAKAAEQCwABEAwAARANAAEQDgABEBAAARASAAEQEwABEBQAARAWAAEQFwABEFYAARBYAAEQWgABEFwAARBfAAEQYAABEGEAARBiAAEQYwABEGUAARBnAAEQaAABEGkAARBrAAEQbAABEKsAARCtAAEQrwABELEAARC0AAEQtQABELYAARC3AAEQuAABELoAARC8AAEQvQABEL4AARDAAAEQwQABEQwAAREvAAERTwABEW8AARFxAAERcwABEXUAARF3AAERegABEXsAARF8AAERfwABEYAAARGCAAERgwABEYUAARGIAAERiQABEYoAARGNAAERjgABEZcAARGkAAERqQABEasAARGtAAERsgABEbUAARG4AAERugABEd8AARIDAAESKgABEk4AARJRAAESUwABElUAARJXAAESWQABElsAARJcAAESXwABEmwAARJ9AAESfwABEoEAARKDAAEShQABEocAARKJAAESiwABEo0AARKeAAESoQABEqQAARKnAAESqgABEq0AARKwAAESswABErYAARK4AAES9wABEvkAARL7AAES/QABEwAAARMBAAETAgABEwMAARMEAAETBgABEwgAARMJAAETCgABEwwAARMNAAETTAABE04AARNQAAETUgABE1UAARNWAAETVwABE1gAARNZAAETWwABE10AARNeAAETXwABE2EAARNiAAEToQABE6MAAROmAAETqAABE6sAAROsAAETrQABE64AAROvAAETsQABE7MAARO0AAETtQABE7cAARO4AAETxQABE8YAARPHAAETyQABFAgAARQKAAEUDAABFA4AARQRAAEUEgABFBMAARQUAAEUFQABFBcAARQZAAEUGgABFBsAARQdAAEUHgABFF0AARRfAAEUYQABFGMAARRmAAEUZwABFGgAARRpAAEUagABFGwAARRuAAEUbwABFHAAARRyAAEUcwABFLIAARS0AAEUtgABFLgAARS7AAEUvAABFL0AARS+AAEUvwABFMEAARTDAAEUxAABFMUAARTHAAEUyAABFQcAARUJAAEVCwABFQ0AARUQAAEVEQABFRIAARUTAAEVFAABFRYAARUYAAEVGQABFRoAARUcAAEVHQABFVwAARVeAAEVYAABFWIAARVlAAEVZgABFWcAARVoAAEVaQABFWsAARVtAAEVbgABFW8AARVxAAEVcgABFZcAARW7AAEV4gABFgYAARYJAAEWCwABFg0AARYPAAEWEQABFhMAARYUAAEWFwABFiQAARYzAAEWNQABFjcAARY5AAEWOwABFj0AARY/AAEWQQABFlAAARZTAAEWVgABFlkAARZcAAEWXwABFmIAARZlAAEWZwABFqYAARaoAAEWqgABFqwAARavAAEWsAABFrEAARayAAEWswABFrUAARa3AAEWuAABFrkAARa7AAEWvAABFvsAARb9AAEW/wABFwEAARcEAAEXBQABFwYAARcHAAEXCAABFwoAARcMAAEXDQABFw4AARcQAAEXEQABF1AAARdSAAEXVAABF1YAARdZAAEXWgABF1sAARdcAAEXXQABF18AARdhAAEXYgABF2MAARdlAAEXZgABF6UAARenAAEXqQABF6sAAReuAAEXrwABF7AAARexAAEXsgABF7QAARe2AAEXtwABF7gAARe6AAEXuwABF/oAARf8AAEX/gABGAAAARgDAAEYBAABGAUAARgGAAEYBwABGAkAARgLAAEYDAABGA0AARgPAAEYEAABGE8AARhRAAEYUwABGFUAARhYAAEYWQABGFoAARhbAAEYXAABGF4AARhgAAEYYQABGGIAARhkAAEYZQABGKQAARimAAEYqAABGKoAARitAAEYrgABGK8AARiwAAEYsQABGLMAARi1AAEYtgABGLcAARi5AAEYugABGQUAARkoAAEZSAABGWgAARlqAAEZbAABGW4AARlwAAEZcwABGXQAARl1AAEZeAABGXkAARl7AAEZfAABGX4AARmBAAEZggABGYMAARmGAAEZhwABGYwAARmZAAEZngABGaAAARmiAAEZpwABGaoAARmtAAEZrwABGdQAARn4AAEaHwABGkMAARpGAAEaSAABGkoAARpMAAEaTgABGlAAARpRAAEaVAABGmEAARpyAAEadAABGnYAARp4AAEaegABGnwAARp+AAEagAABGoIAARqTAAEalgABGpkAARqcAAEanwABGqIAARqlAAEaqAABGqsAARqtAAEa7AABGu4AARrwAAEa8gABGvUAARr2AAEa9wABGvgAARr5AAEa+wABGv0AARr+AAEa/wABGwEAARsCAAEbQQABG0MAARtFAAEbRwABG0oAARtLAAEbTAABG00AARtOAAEbUAABG1IAARtTAAEbVAABG1YAARtXAAEblgABG5gAARubAAEbnQABG6AAARuhAAEbogABG6MAARukAAEbpgABG6gAARupAAEbqgABG6wAARutAAEbugABG7sAARu8AAEbvgABG/0AARv/AAEcAQABHAMAARwGAAEcBwABHAgAARwJAAEcCgABHAwAARwOAAEcDwABHBAAARwSAAEcEwABHFIAARxUAAEcVgABHFgAARxbAAEcXAABHF0AARxeAAEcXwABHGEAARxjAAEcZAABHGUAARxnAAEcaAABHKcAARypAAEcqwABHK0AARywAAEcsQABHLIAARyzAAEctAABHLYAARy4AAEcuQABHLoAARy8AAEcvQABHPwAARz+AAEdAAABHQIAAR0FAAEdBgABHQcAAR0IAAEdCQABHQsAAR0NAAEdDgABHQ8AAR0RAAEdEgABHVEAAR1TAAEdVQABHVcAAR1aAAEdWwABHVwAAR1dAAEdXgABHWAAAR1iAAEdYwABHWQAAR1mAAEdZwABHYwAAR2wAAEd1wABHfsAAR3+AAEeAAABHgIAAR4EAAEeBgABHggAAR4JAAEeDAABHhkAAR4oAAEeKgABHiwAAR4uAAEeMAABHjIAAR40AAEeNgABHkUAAR5IAAEeSwABHk4AAR5RAAEeVAABHlcAAR5aAAEeXAABHpsAAR6dAAEeoAABHqIAAR6lAAEepgABHqcAAR6oAAEeqQABHqsAAR6tAAEergABHq8AAR6xAAEesgABHvEAAR7zAAEe9QABHvcAAR76AAEe+wABHvwAAR79AAEe/gABHwAAAR8CAAEfAwABHwQAAR8GAAEfBwABH0YAAR9IAAEfSgABH0wAAR9PAAEfUAABH1EAAR9SAAEfUwABH1UAAR9XAAEfWAABH1kAAR9bAAEfXAABH5sAAR+dAAEfoAABH6IAAR+lAAEfpgABH6cAAR+oAAEfqQABH6sAAR+tAAEfrgABH68AAR+xAAEfsgABH/EAAR/zAAEf9QABH/cAAR/6AAEf+wABH/wAAR/9AAEf/gABIAAAASACAAEgAwABIAQAASAGAAEgBwABIEYAASBIAAEgSgABIEwAASBPAAEgUAABIFEAASBSAAEgUwABIFUAASBXAAEgWAABIFkAASBbAAEgXAABIJsAASCdAAEgnwABIKEAASCkAAEgpQABIKYAASCnAAEgqAABIKoAASCsAAEgrQABIK4AASCwAAEgsQABIPwAASEfAAEhPwABIV8AASFhAAEhYwABIWUAASFnAAEhagABIWsAASFsAAEhbwABIXAAASFyAAEhcwABIXUAASF4AAEheQABIXoAASF9AAEhfgABIYMAASGQAAEhlQABIZcAASGZAAEhngABIaEAASGkAAEhpgABIcsAASHvAAEiFgABIjoAASI9AAEiPwABIkEAASJDAAEiRQABIkcAASJIAAEiSwABIlgAASJpAAEiawABIm0AASJvAAEicQABInMAASJ1AAEidwABInkAASKKAAEijQABIpAAASKTAAEilgABIpkAASKcAAEinwABIqIAASKkAAEi4wABIuUAASLnAAEi6QABIuwAASLtAAEi7gABIu8AASLwAAEi8gABIvQAASL1AAEi9gABIvgAASL5AAEjOAABIzoAASM8AAEjPgABI0EAASNCAAEjQwABI0QAASNFAAEjRwABI0kAASNKAAEjSwABI00AASNOAAEjjQABI48AASOSAAEjlAABI5cAASOYAAEjmQABI5oAASObAAEjnQABI58AASOgAAEjoQABI6MAASOkAAEjsQABI7IAASOzAAEjtQABI/QAASP2AAEj+AABI/oAASP9AAEj/gABI/8AASQAAAEkAQABJAMAASQFAAEkBgABJAcAASQJAAEkCgABJEkAASRLAAEkTQABJE8AASRSAAEkUwABJFQAASRVAAEkVgABJFgAASRaAAEkWwABJFwAASReAAEkXwABJJ4AASSgAAEkogABJKQAASSnAAEkqAABJKkAASSqAAEkqwABJK0AASSvAAEksAABJLEAASSzAAEktAABJPMAAST1AAEk9wABJPkAAST8AAEk/QABJP4AAST/AAElAAABJQIAASUEAAElBQABJQYAASUIAAElCQABJUgAASVKAAElTAABJU4AASVRAAElUgABJVMAASVUAAElVQABJVcAASVZAAElWgABJVsAASVdAAElXgABJYMAASWnAAElzgABJfIAASX1AAEl9wABJfkAASX7AAEl/QABJf8AASYAAAEmAwABJhAAASYfAAEmIQABJiMAASYlAAEmJwABJikAASYrAAEmLQABJjwAASY/AAEmQgABJkUAASZIAAEmSwABJk4AASZRAAEmUwABJpIAASaUAAEmlgABJpgAASabAAEmnAABJp0AASaeAAEmnwABJqEAASajAAEmpAABJqUAASanAAEmqAABJucAASbpAAEm6wABJu0AASbwAAEm8QABJvIAASbzAAEm9AABJvYAASb4AAEm+QABJvoAASb8AAEm/QABJzwAASc+AAEnQAABJ0IAASdFAAEnRgABJ0cAASdIAAEnSQABJ0sAASdNAAEnTgABJ08AASdRAAEnUgABJ5EAASeTAAEnlQABJ5cAASeaAAEnmwABJ5wAASedAAEnngABJ6AAASeiAAEnowABJ6QAASemAAEnpwABJ+YAASfoAAEn6gABJ+wAASfvAAEn8AABJ/EAASfyAAEn8wABJ/UAASf3AAEn+AABJ/kAASf7AAEn/AABKDsAASg9AAEoPwABKEEAAShEAAEoRQABKEYAAShHAAEoSAABKEoAAShMAAEoTQABKE4AAShQAAEoUQABKJAAASiSAAEolAABKJYAASiZAAEomgABKJsAASicAAEonQABKJ8AASihAAEoogABKKMAASilAAEopgABKPEAASkUAAEpNAABKVQAASlWAAEpWAABKVoAASlcAAEpXwABKWAAASlhAAEpZAABKWUAASlnAAEpaAABKWoAASltAAEpbgABKW8AASlyAAEpcwABKXgAASmFAAEpigABKYwAASmOAAEpkwABKZYAASmZAAEpmwABKcAAASnkAAEqCwABKi8AASoyAAEqNAABKjYAASo4AAEqOgABKjwAASo9AAEqQAABKk0AASpeAAEqYAABKmIAASpkAAEqZgABKmgAASpqAAEqbAABKm4AASp/AAEqggABKoUAASqIAAEqiwABKo4AASqRAAEqlAABKpcAASqZAAEq2AABKtoAASrcAAEq3gABKuEAASriAAEq4wABKuQAASrlAAEq5wABKukAASrqAAEq6wABKu0AASruAAErLQABKy8AASsxAAErMwABKzYAASs3AAErOAABKzkAASs6AAErPAABKz4AASs/AAErQAABK0IAAStDAAErggABK4QAASuHAAEriQABK4wAASuNAAErjgABK48AASuQAAErkgABK5QAASuVAAErlgABK5gAASuZAAErpgABK6cAASuoAAErqgABK+kAASvrAAEr7QABK+8AASvyAAEr8wABK/QAASv1AAEr9gABK/gAASv6AAEr+wABK/wAASv+AAEr/wABLD4AASxAAAEsQgABLEQAASxHAAEsSAABLEkAASxKAAEsSwABLE0AASxPAAEsUAABLFEAASxTAAEsVAABLJMAASyVAAEslwABLJkAASycAAEsnQABLJ4AASyfAAEsoAABLKIAASykAAEspQABLKYAASyoAAEsqQABLOgAASzqAAEs7AABLO4AASzxAAEs8gABLPMAASz0AAEs9QABLPcAASz5AAEs+gABLPsAASz9AAEs/gABLT0AAS0/AAEtQQABLUMAAS1GAAEtRwABLUgAAS1JAAEtSgABLUwAAS1OAAEtTwABLVAAAS1SAAEtUwABLXgAAS2cAAEtwwABLecAAS3qAAEt7AABLe4AAS3wAAEt8gABLfQAAS31AAEt+AABLgUAAS4UAAEuFgABLhgAAS4aAAEuHAABLh4AAS4gAAEuIgABLjEAAS40AAEuNwABLjoAAS49AAEuQAABLkMAAS5GAAEuSAABLocAAS6JAAEuiwABLo0AAS6QAAEukQABLpIAAS6TAAEulAABLpYAAS6YAAEumQABLpoAAS6cAAEunQABLtwAAS7eAAEu4AABLuIAAS7lAAEu5gABLucAAS7oAAEu6QABLusAAS7tAAEu7gABLu8AAS7xAAEu8gABLzEAAS8zAAEvNQABLzcAAS86AAEvOwABLzwAAS89AAEvPgABL0AAAS9CAAEvQwABL0QAAS9GAAEvRwABL4YAAS+IAAEvigABL4wAAS+PAAEvkAABL5EAAS+SAAEvkwABL5UAAS+XAAEvmAABL5kAAS+bAAEvnAABL9sAAS/dAAEv3wABL+EAAS/kAAEv5QABL+YAAS/nAAEv6AABL+oAAS/sAAEv7QABL+4AAS/wAAEv8QABMDAAATAyAAEwNAABMDYAATA5AAEwOgABMDsAATA8AAEwPQABMD8AATBBAAEwQgABMEMAATBFAAEwRgABMIUAATCHAAEwiQABMIsAATCOAAEwjwABMJAAATCRAAEwkgABMJQAATCWAAEwlwABMJgAATCaAAEwmwABMOYAATEJAAExKQABMUkAATFLAAExTQABMU8AATFRAAExVAABMVUAATFWAAExWQABMVoAATFcAAExXQABMV8AATFhAAExYgABMWMAATFmAAExZwABMWwAATF5AAExfgABMYAAATGCAAExhwABMYoAATGNAAExjwABMbQAATHYAAEx/wABMiMAATImAAEyKAABMioAATIsAAEyLgABMjAAATIxAAEyNAABMkEAATJSAAEyVAABMlYAATJYAAEyWgABMlwAATJeAAEyYAABMmIAATJzAAEydgABMnkAATJ8AAEyfwABMoIAATKFAAEyiAABMosAATKNAAEyzAABMs4AATLQAAEy0gABMtUAATLWAAEy1wABMtgAATLZAAEy2wABMt0AATLeAAEy3wABMuEAATLiAAEzIQABMyMAATMlAAEzJwABMyoAATMrAAEzLAABMy0AATMuAAEzMAABMzIAATMzAAEzNAABMzYAATM3AAEzdgABM3gAATN7AAEzfQABM4AAATOBAAEzggABM4MAATOEAAEzhgABM4gAATOJAAEzigABM4wAATONAAEzmgABM5sAATOcAAEzngABM90AATPfAAEz4QABM+MAATPmAAEz5wABM+gAATPpAAEz6gABM+wAATPuAAEz7wABM/AAATPyAAEz8wABNDIAATQ0AAE0NgABNDgAATQ7AAE0PAABND0AATQ+AAE0PwABNEEAATRDAAE0RAABNEUAATRHAAE0SAABNIcAATSJAAE0iwABNI0AATSQAAE0kQABNJIAATSTAAE0lAABNJYAATSYAAE0mQABNJoAATScAAE0nQABNNwAATTeAAE04AABNOIAATTlAAE05gABNOcAATToAAE06QABNOsAATTtAAE07gABNO8AATTxAAE08gABNTEAATUzAAE1NQABNTcAATU6AAE1OwABNTwAATU9AAE1PgABNUAAATVCAAE1QwABNUQAATVGAAE1RwABNWwAATWQAAE1twABNdsAATXeAAE14AABNeIAATXkAAE15gABNegAATXpAAE17AABNfkAATYIAAE2CgABNgwAATYOAAE2EAABNhIAATYUAAE2FgABNiUAATYoAAE2KwABNi4AATYxAAE2NAABNjcAATY6AAE2PAABNnsAATZ9AAE2fwABNoEAATaEAAE2hQABNoYAATaHAAE2iAABNooAATaMAAE2jQABNo4AATaQAAE2kQABNtAAATbSAAE21AABNtYAATbZAAE22gABNtsAATbcAAE23QABNt8AATbhAAE24gABNuMAATblAAE25gABNyUAATcnAAE3KQABNysAATcuAAE3LwABNzAAATcxAAE3MgABNzQAATc2AAE3NwABNzgAATc6AAE3OwABN3oAATd8AAE3fgABN4AAATeDAAE3hAABN4UAATeGAAE3hwABN4kAATeLAAE3jAABN40AATePAAE3kAABN88AATfRAAE30wABN9UAATfYAAE32QABN9oAATfbAAE33AABN94AATfgAAE34QABN+IAATfkAAE35QABOCQAATgmAAE4KAABOCoAATgtAAE4LgABOC8AATgwAAE4MQABODMAATg1AAE4NgABODcAATg5AAE4OgABOHkAATh7AAE4fQABOH8AATiCAAE4gwABOIQAATiFAAE4hgABOIgAATiKAAE4iwABOIwAATiOAAE4jwABOJgAATiZAAE4mwABON4AATkCAAE5JgABOUkAATlwAAE5kAABObcAATneAAE5/gABOiIAATpGAAE6SAABOksAATpNAAE6TwABOlEAATpUAAE6VwABOlkAATpbAAE6XgABOmAAATpiAAE6ZQABOmgAATppAAE6bgABOnsAATp+AAE6gAABOoMAATqGAAE6iAABOq0AATrRAAE6+AABOxwAATsfAAE7IQABOyMAATslAAE7JwABOykAATsqAAE7LQABOzoAATtNAAE7TwABO1EAATtTAAE7VQABO1cAATtZAAE7WwABO10AATtfAAE7cgABO3UAATt4AAE7ewABO34AATuBAAE7hAABO4cAATuKAAE7jQABO48AATvOAAE70AABO9MAATvVAAE72AABO9kAATvaAAE72wABO9wAATveAAE74AABO+EAATviAAE75AABO+UAATvuAAE77wABO/EAATwwAAE8MgABPDQAATw2AAE8OQABPDoAATw7AAE8PAABPD0AATw/AAE8QQABPEIAATxDAAE8RQABPEYAATyFAAE8hwABPIoAATyMAAE8jwABPJAAATyRAAE8kgABPJMAATyVAAE8lwABPJgAATyZAAE8mwABPJwAATylAAE8qAABPKsAATytAAE8tgABPLkAATy8AAE8vgABPMkAAT0IAAE9CgABPQwAAT0OAAE9EQABPRIAAT0TAAE9FAABPRUAAT0XAAE9GQABPRoAAT0bAAE9HQABPR4AAT1dAAE9XwABPWIAAT1kAAE9ZwABPWgAAT1pAAE9agABPWsAAT1tAAE9bwABPXAAAT1xAAE9cwABPXQAAT19AAE9fgABPYAAAT2/AAE9wQABPcMAAT3FAAE9yAABPckAAT3KAAE9ywABPcwAAT3OAAE90AABPdEAAT3SAAE91AABPdUAAT4UAAE+FgABPhkAAT4bAAE+HgABPh8AAT4gAAE+IQABPiIAAT4kAAE+JgABPicAAT4oAAE+KgABPisAAT44AAE+OQABPjoAAT48AAE+ewABPn0AAT5/AAE+gQABPoQAAT6FAAE+hgABPocAAT6IAAE+igABPowAAT6NAAE+jgABPpAAAT6RAAE+0AABPtIAAT7VAAE+1wABPtoAAT7bAAE+3AABPt0AAT7eAAE+4AABPuIAAT7jAAE+5AABPuYAAT7nAAE+/AABPwkAAT8QAAE/EwABPxYAAT8YAAE/HwABPyIAAT8lAAE/KAABPyoAAT81AAE/gAABP6MAAT/DAAE/4wABP+UAAT/nAAE/6QABP+sAAT/uAAE/7wABP/AAAT/zAAE/9AABP/YAAT/3AAE/+QABP/wAAT/9AAE//gABQAEAAUACAAFACwABQBgAAUAdAAFAHwABQCEAAUAmAAFAKQABQCwAAUAuAAFAUwABQHcAAUCeAAFAwgABQMUAAUDHAAFAyQABQMsAAUDNAAFAzwABQNAAAUDTAAFA4AABQPEAAUDzAAFA9QABQPcAAUD5AAFA+wABQP0AAUD/AAFBAQABQRIAAUEVAAFBGAABQRsAAUEeAAFBIQABQSQAAUEnAAFBKgABQSwAAUFrAAFBbQABQW8AAUFxAAFBdAABQXUAAUF2AAFBdwABQXgAAUF6AAFBfAABQX0AAUF+AAFBgAABQYEAAUHAAAFBwgABQcQAAUHGAAFByQABQcoAAUHLAAFBzAABQc0AAUHPAAFB0QABQdIAAUHTAAFB1QABQdYAAUIVAAFCFwABQhoAAUIcAAFCHwABQiAAAUIhAAFCIgABQiMAAUIlAAFCJwABQigAAUIpAAFCKwABQiwAAUI5AAFCOgABQjsAAUI9AAFCfAABQn4AAUKAAAFCggABQoUAAUKGAAFChwABQogAAUKJAAFCiwABQo0AAUKOAAFCjwABQpEAAUKSAAFC0QABQtMAAULVAAFC1wABQtoAAULbAAFC3AABQt0AAULeAAFC4AABQuIAAULjAAFC5AABQuYAAULnAAFDJgABQygAAUMqAAFDLAABQy8AAUMwAAFDMQABQzIAAUMzAAFDNQABQzcAAUM4AAFDOQABQzsAAUM8AAFDewABQ30AAUN/AAFDgQABQ4QAAUOFAAFDhgABQ4cAAUOIAAFDigABQ4wAAUONAAFDjgABQ5AAAUORAAFD0AABQ9IAAUPUAAFD1gABQ9kAAUPaAAFD2wABQ9wAAUPdAAFD3wABQ+EAAUPiAAFD4wABQ+UAAUPmAAFECwABRC8AAURWAAFEegABRH0AAUR/AAFEgQABRIMAAUSFAAFEhwABRIgAAUSLAAFEmAABRKcAAUSpAAFEqwABRK0AAUSvAAFEsQABRLMAAUS1AAFExAABRMcAAUTKAAFEzQABRNAAAUTTAAFE1gABRNkAAUTbAAFFGgABRRwAAUUeAAFFIAABRSMAAUUkAAFFJQABRSYAAUUnAAFFKQABRSsAAUUsAAFFLQABRS8AAUUwAAFFbwABRXEAAUVzAAFFdQABRXgAAUV5AAFFegABRXsAAUV8AAFFfgABRYAAAUWBAAFFggABRYQAAUWFAAFFxAABRcYAAUXIAAFFygABRc0AAUXOAAFFzwABRdAAAUXRAAFF0wABRdUAAUXWAAFF1wABRdkAAUXaAAFGGQABRhsAAUYeAAFGIAABRiMAAUYkAAFGJQABRiYAAUYnAAFGKQABRisAAUYsAAFGLQABRi8AAUYwAAFGbwABRnEAAUZzAAFGdQABRngAAUZ5AAFGegABRnsAAUZ8AAFGfgABRoAAAUaBAAFGggABRoQAAUaFAAFGxAABRsYAAUbIAAFGygABRs0AAUbOAAFGzwABRtAAAUbRAAFG0wABRtUAAUbWAAFG1wABRtkAAUbaAAFHGQABRxsAAUcdAAFHHwABRyIAAUcjAAFHJAABRyUAAUcmAAFHKAABRyoAAUcrAAFHLAABRy4AAUcvAAFHegABR50AAUe9AAFH3QABR98AAUfhAAFH4wABR+UAAUfoAAFH6QABR+oAAUftAAFH7gABR/AAAUfxAAFH8wABR/YAAUf3AAFH+AABR/sAAUf8AAFIAQABSA4AAUgTAAFIFQABSBcAAUgcAAFIHwABSCIAAUgkAAFISQABSG0AAUiUAAFIuAABSLsAAUi9AAFIvwABSMEAAUjDAAFIxQABSMYAAUjJAAFI1gABSOcAAUjpAAFI6wABSO0AAUjvAAFI8QABSPMAAUj1AAFI9wABSQgAAUkLAAFJDgABSREAAUkUAAFJFwABSRoAAUkdAAFJIAABSSIAAUlhAAFJYwABSWUAAUlnAAFJagABSWsAAUlsAAFJbQABSW4AAUlwAAFJcgABSXMAAUl0AAFJdgABSXcAAUm2AAFJuAABSboAAUm8AAFJvwABScAAAUnBAAFJwgABScMAAUnFAAFJxwABScgAAUnJAAFJywABScwAAUoLAAFKDQABShAAAUoSAAFKFQABShYAAUoXAAFKGAABShkAAUobAAFKHQABSh4AAUofAAFKIQABSiIAAUovAAFKMAABSjEAAUozAAFKcgABSnQAAUp2AAFKeAABSnsAAUp8AAFKfQABSn4AAUp/AAFKgQABSoMAAUqEAAFKhQABSocAAUqIAAFKxwABSskAAUrLAAFKzQABStAAAUrRAAFK0gABStMAAUrUAAFK1gABStgAAUrZAAFK2gABStwAAUrdAAFLHAABSx4AAUsgAAFLIgABSyUAAUsmAAFLJwABSygAAUspAAFLKwABSy0AAUsuAAFLLwABSzEAAUsyAAFLcQABS3MAAUt1AAFLdwABS3oAAUt7AAFLfAABS30AAUt+AAFLgAABS4IAAUuDAAFLhAABS4YAAUuHAAFLxgABS8gAAUvKAAFLzAABS88AAUvQAAFL0QABS9IAAUvTAAFL1QABS9cAAUvYAAFL2QABS9sAAUvcAAFMAQABTCUAAUxMAAFMcAABTHMAAUx1AAFMdwABTHkAAUx7AAFMfQABTH4AAUyBAAFMjgABTJ0AAUyfAAFMoQABTKMAAUylAAFMpwABTKkAAUyrAAFMugABTL0AAUzAAAFMwwABTMYAAUzJAAFMzAABTM8AAUzRAAFNEAABTRIAAU0UAAFNFgABTRkAAU0aAAFNGwABTRwAAU0dAAFNHwABTSEAAU0iAAFNIwABTSUAAU0mAAFNZQABTWcAAU1pAAFNawABTW4AAU1vAAFNcAABTXEAAU1yAAFNdAABTXYAAU13AAFNeAABTXoAAU17AAFNugABTbwAAU2+AAFNwAABTcMAAU3EAAFNxQABTcYAAU3HAAFNyQABTcsAAU3MAAFNzQABTc8AAU3QAAFODwABThEAAU4TAAFOFQABThgAAU4ZAAFOGgABThsAAU4cAAFOHgABTiAAAU4hAAFOIgABTiQAAU4lAAFOZAABTmYAAU5oAAFOagABTm0AAU5uAAFObwABTnAAAU5xAAFOcwABTnUAAU52AAFOdwABTnkAAU56AAFOuQABTrsAAU69AAFOvwABTsIAAU7DAAFOxAABTsUAAU7GAAFOyAABTsoAAU7LAAFOzAABTs4AAU7PAAFPDgABTxAAAU8SAAFPFAABTxcAAU8YAAFPGQABTxoAAU8bAAFPHQABTx8AAU8gAAFPIQABTyMAAU8kAAFPbwABT5IAAU+yAAFP0gABT9QAAU/WAAFP2AABT9oAAU/dAAFP3gABT98AAU/iAAFP4wABT+UAAU/mAAFP6AABT+oAAU/rAAFP7AABT+8AAU/wAAFP9QABUAIAAVAHAAFQCQABUAsAAVAQAAFQEwABUBYAAVAYAAFQPQABUGEAAVCIAAFQrAABUK8AAVCxAAFQswABULUAAVC3AAFQuQABULoAAVC9AAFQygABUNsAAVDdAAFQ3wABUOEAAVDjAAFQ5QABUOcAAVDpAAFQ6wABUPwAAVD/AAFRAgABUQUAAVEIAAFRCwABUQ4AAVERAAFRFAABURYAAVFVAAFRVwABUVkAAVFbAAFRXgABUV8AAVFgAAFRYQABUWIAAVFkAAFRZgABUWcAAVFoAAFRagABUWsAAVGqAAFRrAABUa4AAVGwAAFRswABUbQAAVG1AAFRtgABUbcAAVG5AAFRuwABUbwAAVG9AAFRvwABUcAAAVH/AAFSAQABUgQAAVIGAAFSCQABUgoAAVILAAFSDAABUg0AAVIPAAFSEQABUhIAAVITAAFSFQABUhYAAVIjAAFSJAABUiUAAVInAAFSZgABUmgAAVJqAAFSbAABUm8AAVJwAAFScQABUnIAAVJzAAFSdQABUncAAVJ4AAFSeQABUnsAAVJ8AAFSuwABUr0AAVK/AAFSwQABUsQAAVLFAAFSxgABUscAAVLIAAFSygABUswAAVLNAAFSzgABUtAAAVLRAAFTEAABUxIAAVMUAAFTFgABUxkAAVMaAAFTGwABUxwAAVMdAAFTHwABUyEAAVMiAAFTIwABUyUAAVMmAAFTZQABU2cAAVNpAAFTawABU24AAVNvAAFTcAABU3EAAVNyAAFTdAABU3YAAVN3AAFTeAABU3oAAVN7AAFTugABU7wAAVO+AAFTwAABU8MAAVPEAAFTxQABU8YAAVPHAAFTyQABU8sAAVPMAAFTzQABU88AAVPQAAFT9QABVBkAAVRAAAFUZAABVGcAAVRpAAFUawABVG0AAVRvAAFUcQABVHIAAVR1AAFUggABVJEAAVSTAAFUlQABVJcAAVSZAAFUmwABVJ0AAVSfAAFUrgABVLEAAVS0AAFUtwABVLoAAVS9AAFUwAABVMMAAVTFAAFVBAABVQYAAVUIAAFVCgABVQ0AAVUOAAFVDwABVRAAAVURAAFVEwABVRUAAVUWAAFVFwABVRkAAVUaAAFVWQABVVsAAVVdAAFVXwABVWIAAVVjAAFVZAABVWUAAVVmAAFVaAABVWoAAVVrAAFVbAABVW4AAVVvAAFVrgABVbAAAVWyAAFVtAABVbcAAVW4AAFVuQABVboAAVW7AAFVvQABVb8AAVXAAAFVwQABVcMAAVXEAAFWAwABVgUAAVYHAAFWCQABVgwAAVYNAAFWDgABVg8AAVYQAAFWEgABVhQAAVYVAAFWFgABVhgAAVYZAAFWWAABVloAAVZcAAFWXgABVmEAAVZiAAFWYwABVmQAAVZlAAFWZwABVmkAAVZqAAFWawABVm0AAVZuAAFWrQABVq8AAVaxAAFWswABVrYAAVa3AAFWuAABVrkAAVa6AAFWvAABVr4AAVa/AAFWwAABVsIAAVbDAAFXAgABVwQAAVcGAAFXCAABVwsAAVcMAAFXDQABVw4AAVcPAAFXEQABVxMAAVcUAAFXFQABVxcAAVcYAAFXIQABVyIAAVckAAFXZwABV4sAAVevAAFX0gABV/kAAVgZAAFYQAABWGcAAViHAAFYqwABWM8AAVjRAAFY1AABWNYAAVjYAAFY2gABWN0AAVjgAAFY4gABWOQAAVjnAAFY6QABWOsAAVjuAAFY8QABWPIAAVj3AAFZBAABWQcAAVkJAAFZDAABWQ8AAVkRAAFZNgABWVoAAVmBAAFZpQABWagAAVmqAAFZrAABWa4AAVmwAAFZsgABWbMAAVm2AAFZwwABWdYAAVnYAAFZ2gABWdwAAVneAAFZ4AABWeIAAVnkAAFZ5gABWegAAVn7AAFZ/gABWgEAAVoEAAFaBwABWgoAAVoNAAFaEAABWhMAAVoWAAFaGAABWlcAAVpZAAFaXAABWl4AAVphAAFaYgABWmMAAVpkAAFaZQABWmcAAVppAAFaagABWmsAAVptAAFabgABWncAAVp4AAFaegABWrkAAVq7AAFavQABWr8AAVrCAAFawwABWsQAAVrFAAFaxgABWsgAAVrKAAFaywABWswAAVrOAAFazwABWw4AAVsQAAFbEwABWxUAAVsYAAFbGQABWxoAAVsbAAFbHAABWx4AAVsgAAFbIQABWyIAAVskAAFbJQABWy4AAVszAAFbNgABWzkAAVs7AAFbRAABW0cAAVtJAAFbSwABW1QAAVtXAAFbWgABW1wAAVtrAAFbqgABW6wAAVuuAAFbsAABW7MAAVu0AAFbtQABW7YAAVu3AAFbuQABW7sAAVu8AAFbvQABW78AAVvAAAFb/wABXAEAAVwEAAFcBgABXAkAAVwKAAFcCwABXAwAAVwNAAFcDwABXBEAAVwSAAFcEwABXBUAAVwWAAFcHwABXCAAAVwiAAFcYQABXGMAAVxlAAFcZwABXGoAAVxrAAFcbAABXG0AAVxuAAFccAABXHIAAVxzAAFcdAABXHYAAVx3AAFctgABXLgAAVy7AAFcvQABXMAAAVzBAAFcwgABXMMAAVzEAAFcxgABXMgAAVzJAAFcygABXMwAAVzNAAFc2gABXNsAAVzcAAFc3gABXR0AAV0fAAFdIQABXSMAAV0mAAFdJwABXSgAAV0pAAFdKgABXSwAAV0uAAFdLwABXTAAAV0yAAFdMwABXXIAAV10AAFddwABXXkAAV18AAFdfQABXX4AAV1/AAFdgAABXYIAAV2EAAFdhQABXYYAAV2IAAFdiQABXaAAAV2tAAFdwAABXcMAAV3FAAFdyAABXcsAAV3NAAFd0AABXdIAAV3VAAFd2AABXesAAV3uAAFd8QABXfQAAV33AAFd+gABXf0AAV4AAAFeAwABXgYAAV4IAAFeFAABXiIAAV4tAAFePAABXlMAAV6eAAFewQABXuEAAV8BAAFfAwABXwUAAV8HAAFfCQABXwwAAV8NAAFfDgABXxEAAV8SAAFfFAABXxUAAV8XAAFfGgABXxsAAV8cAAFfHwABXyAAAV8pAAFfNgABXzsAAV89AAFfPwABX0QAAV9HAAFfSgABX0wAAV9xAAFflQABX7wAAV/gAAFf4wABX+UAAV/nAAFf6QABX+sAAV/tAAFf7gABX/EAAV/+AAFgDwABYBEAAWATAAFgFQABYBcAAWAZAAFgGwABYB0AAWAfAAFgMAABYDMAAWA2AAFgOQABYDwAAWA/AAFgQgABYEUAAWBIAAFgSgABYIkAAWCLAAFgjQABYI8AAWCSAAFgkwABYJQAAWCVAAFglgABYJgAAWCaAAFgmwABYJwAAWCeAAFgnwABYN4AAWDgAAFg4gABYOQAAWDnAAFg6AABYOkAAWDqAAFg6wABYO0AAWDvAAFg8AABYPEAAWDzAAFg9AABYTMAAWE1AAFhOAABYToAAWE9AAFhPgABYT8AAWFAAAFhQQABYUMAAWFFAAFhRgABYUcAAWFJAAFhSgABYVcAAWFYAAFhWQABYVsAAWGaAAFhnAABYZ4AAWGgAAFhowABYaQAAWGlAAFhpgABYacAAWGpAAFhqwABYawAAWGtAAFhrwABYbAAAWHvAAFh8QABYfMAAWH1AAFh+AABYfkAAWH6AAFh+wABYfwAAWH+AAFiAAABYgEAAWICAAFiBAABYgUAAWJEAAFiRgABYkgAAWJKAAFiTQABYk4AAWJPAAFiUAABYlEAAWJTAAFiVQABYlYAAWJXAAFiWQABYloAAWKZAAFimwABYp0AAWKfAAFiogABYqMAAWKkAAFipQABYqYAAWKoAAFiqgABYqsAAWKsAAFirgABYq8AAWLuAAFi8AABYvIAAWL0AAFi9wABYvgAAWL5AAFi+gABYvsAAWL9AAFi/wABYwAAAWMBAAFjAwABYwQAAWMpAAFjTQABY3QAAWOYAAFjmwABY50AAWOfAAFjoQABY6MAAWOlAAFjpgABY6kAAWO2AAFjxQABY8cAAWPJAAFjywABY80AAWPPAAFj0QABY9MAAWPiAAFj5QABY+gAAWPrAAFj7gABY/EAAWP0AAFj9wABY/kAAWQ4AAFkOgABZD0AAWQ/AAFkQgABZEMAAWREAAFkRQABZEYAAWRIAAFkSgABZEsAAWRMAAFkTgABZE8AAWSOAAFkkAABZJIAAWSUAAFklwABZJgAAWSZAAFkmgABZJsAAWSdAAFknwABZKAAAWShAAFkowABZKQAAWTjAAFk5QABZOcAAWTpAAFk7AABZO0AAWTuAAFk7wABZPAAAWTyAAFk9AABZPUAAWT2AAFk+AABZPkAAWU4AAFlOgABZT0AAWU/AAFlQgABZUMAAWVEAAFlRQABZUYAAWVIAAFlSgABZUsAAWVMAAFlTgABZU8AAWWOAAFlkAABZZIAAWWUAAFllwABZZgAAWWZAAFlmgABZZsAAWWdAAFlnwABZaAAAWWhAAFlowABZaQAAWXjAAFl5QABZecAAWXpAAFl7AABZe0AAWXuAAFl7wABZfAAAWXyAAFl9AABZfUAAWX2AAFl+AABZfkAAWY4AAFmOgABZjwAAWY+AAFmQQABZkIAAWZDAAFmRAABZkUAAWZHAAFmSQABZkoAAWZLAAFmTQABZk4AAWaZAAFmvAABZtwAAWb8AAFm/gABZwAAAWcCAAFnBAABZwcAAWcIAAFnCQABZwwAAWcNAAFnDwABZxAAAWcSAAFnFAABZxUAAWcWAAFnGQABZxoAAWcfAAFnLAABZzEAAWczAAFnNQABZzoAAWc9AAFnQAABZ0IAAWdnAAFniwABZ7IAAWfWAAFn2QABZ9sAAWfdAAFn3wABZ+EAAWfjAAFn5AABZ+cAAWf0AAFoBQABaAcAAWgJAAFoCwABaA0AAWgPAAFoEQABaBMAAWgVAAFoJgABaCkAAWgsAAFoLwABaDIAAWg1AAFoOAABaDsAAWg+AAFoQAABaH8AAWiBAAFogwABaIUAAWiIAAFoiQABaIoAAWiLAAFojAABaI4AAWiQAAFokQABaJIAAWiUAAFolQABaNQAAWjWAAFo2AABaNoAAWjdAAFo3gABaN8AAWjgAAFo4QABaOMAAWjlAAFo5gABaOcAAWjpAAFo6gABaSkAAWkrAAFpLgABaTAAAWkzAAFpNAABaTUAAWk2AAFpNwABaTkAAWk7AAFpPAABaT0AAWk/AAFpQAABaU0AAWlOAAFpTwABaVEAAWmQAAFpkgABaZQAAWmWAAFpmQABaZoAAWmbAAFpnAABaZ0AAWmfAAFpoQABaaIAAWmjAAFppQABaaYAAWnlAAFp5wABaekAAWnrAAFp7gABae8AAWnwAAFp8QABafIAAWn0AAFp9gABafcAAWn4AAFp+gABafsAAWo6AAFqPAABaj4AAWpAAAFqQwABakQAAWpFAAFqRgABakcAAWpJAAFqSwABakwAAWpNAAFqTwABalAAAWqPAAFqkQABapMAAWqVAAFqmAABapkAAWqaAAFqmwABapwAAWqeAAFqoAABaqEAAWqiAAFqpAABaqUAAWrkAAFq5gABaugAAWrqAAFq7QABau4AAWrvAAFq8AABavEAAWrzAAFq9QABavYAAWr3AAFq+QABavoAAWsfAAFrQwABa2oAAWuOAAFrkQABa5MAAWuVAAFrlwABa5kAAWubAAFrnAABa58AAWusAAFruwABa70AAWu/AAFrwQABa8MAAWvFAAFrxwABa8kAAWvYAAFr2wABa94AAWvhAAFr5AABa+cAAWvqAAFr7QABa+8AAWwuAAFsMAABbDIAAWw0AAFsNwABbDgAAWw5AAFsOgABbDsAAWw9AAFsPwABbEAAAWxBAAFsQwABbEQAAWyDAAFshQABbIcAAWyJAAFsjAABbI0AAWyOAAFsjwABbJAAAWySAAFslAABbJUAAWyWAAFsmAABbJkAAWzYAAFs2gABbNwAAWzeAAFs4QABbOIAAWzjAAFs5AABbOUAAWznAAFs6QABbOoAAWzrAAFs7QABbO4AAW0tAAFtLwABbTEAAW0zAAFtNgABbTcAAW04AAFtOQABbToAAW08AAFtPgABbT8AAW1AAAFtQgABbUMAAW2CAAFthAABbYYAAW2IAAFtiwABbYwAAW2NAAFtjgABbY8AAW2RAAFtkwABbZQAAW2VAAFtlwABbZgAAW3XAAFt2QABbdsAAW3dAAFt4AABbeEAAW3iAAFt4wABbeQAAW3mAAFt6AABbekAAW3qAAFt7AABbe0AAW4sAAFuLgABbjAAAW4yAAFuNQABbjYAAW43AAFuOAABbjkAAW47AAFuPQABbj4AAW4/AAFuQQABbkIAAW6NAAFusAABbtAAAW7wAAFu8gABbvQAAW72AAFu+AABbvsAAW78AAFu/QABbwAAAW8BAAFvAwABbwQAAW8GAAFvCQABbwoAAW8LAAFvDgABbw8AAW8UAAFvIQABbyYAAW8oAAFvKgABby8AAW8yAAFvNQABbzcAAW9cAAFvgAABb6cAAW/LAAFvzgABb9AAAW/SAAFv1AABb9YAAW/YAAFv2QABb9wAAW/pAAFv+gABb/wAAW/+AAFwAAABcAIAAXAEAAFwBgABcAgAAXAKAAFwGwABcB4AAXAhAAFwJAABcCcAAXAqAAFwLQABcDAAAXAzAAFwNQABcHQAAXB2AAFweAABcHoAAXB9AAFwfgABcH8AAXCAAAFwgQABcIMAAXCFAAFwhgABcIcAAXCJAAFwigABcMkAAXDLAAFwzQABcM8AAXDSAAFw0wABcNQAAXDVAAFw1gABcNgAAXDaAAFw2wABcNwAAXDeAAFw3wABcR4AAXEgAAFxIwABcSUAAXEoAAFxKQABcSoAAXErAAFxLAABcS4AAXEwAAFxMQABcTIAAXE0AAFxNQABcUIAAXFDAAFxRAABcUYAAXGFAAFxhwABcYkAAXGLAAFxjgABcY8AAXGQAAFxkQABcZIAAXGUAAFxlgABcZcAAXGYAAFxmgABcZsAAXHaAAFx3AABcd4AAXHgAAFx4wABceQAAXHlAAFx5gABcecAAXHpAAFx6wABcewAAXHtAAFx7wABcfAAAXIvAAFyMQABcjMAAXI1AAFyOAABcjkAAXI6AAFyOwABcjwAAXI+AAFyQAABckEAAXJCAAFyRAABckUAAXKEAAFyhgABcogAAXKKAAFyjQABco4AAXKPAAFykAABcpEAAXKTAAFylQABcpYAAXKXAAFymQABcpoAAXLZAAFy2wABct0AAXLfAAFy4gABcuMAAXLkAAFy5QABcuYAAXLoAAFy6gABcusAAXLsAAFy7gABcu8AAXMUAAFzOAABc18AAXODAAFzhgABc4gAAXOKAAFzjAABc44AAXOQAAFzkQABc5QAAXOhAAFzsAABc7IAAXO0AAFztgABc7gAAXO6AAFzvAABc74AAXPNAAFz0AABc9MAAXPWAAFz2QABc9wAAXPfAAFz4gABc+QAAXQjAAF0JQABdCgAAXQqAAF0LQABdC4AAXQvAAF0MAABdDEAAXQzAAF0NQABdDYAAXQ3AAF0OQABdDoAAXR5AAF0ewABdH0AAXR/AAF0ggABdIMAAXSEAAF0hQABdIYAAXSIAAF0igABdIsAAXSMAAF0jgABdI8AAXTOAAF00AABdNIAAXTUAAF01wABdNgAAXTZAAF02gABdNsAAXTdAAF03wABdOAAAXThAAF04wABdOQAAXUjAAF1JQABdSgAAXUqAAF1LQABdS4AAXUvAAF1MAABdTEAAXUzAAF1NQABdTYAAXU3AAF1OQABdToAAXV5AAF1ewABdX0AAXV/AAF1ggABdYMAAXWEAAF1hQABdYYAAXWIAAF1igABdYsAAXWMAAF1jgABdY8AAXXOAAF10AABddIAAXXUAAF11wABddgAAXXZAAF12gABddsAAXXdAAF13wABdeAAAXXhAAF14wABdeQAAXYjAAF2JQABdicAAXYpAAF2LAABdi0AAXYuAAF2LwABdjAAAXYyAAF2NAABdjUAAXY2AAF2OAABdjkAAXaEAAF2pwABdscAAXbnAAF26QABdusAAXbtAAF27wABdvIAAXbzAAF29AABdvcAAXb4AAF2+gABdvsAAXb9AAF3AAABdwEAAXcCAAF3BQABdwYAAXcLAAF3GAABdx0AAXcfAAF3IQABdyYAAXcpAAF3LAABdy4AAXdTAAF3dwABd54AAXfCAAF3xQABd8cAAXfJAAF3ywABd80AAXfPAAF30AABd9MAAXfgAAF38QABd/MAAXf1AAF39wABd/kAAXf7AAF3/QABd/8AAXgBAAF4EgABeBUAAXgYAAF4GwABeB4AAXghAAF4JAABeCcAAXgqAAF4LAABeGsAAXhtAAF4bwABeHEAAXh0AAF4dQABeHYAAXh3AAF4eAABeHoAAXh8AAF4fQABeH4AAXiAAAF4gQABeMAAAXjCAAF4xAABeMYAAXjJAAF4ygABeMsAAXjMAAF4zQABeM8AAXjRAAF40gABeNMAAXjVAAF41gABeRUAAXkXAAF5GgABeRwAAXkfAAF5IAABeSEAAXkiAAF5IwABeSUAAXknAAF5KAABeSkAAXkrAAF5LAABeTkAAXk6AAF5OwABeT0AAXl8AAF5fgABeYAAAXmCAAF5hQABeYYAAXmHAAF5iAABeYkAAXmLAAF5jQABeY4AAXmPAAF5kQABeZIAAXnRAAF50wABedUAAXnXAAF52gABedsAAXncAAF53QABed4AAXngAAF54gABeeMAAXnkAAF55gABeecAAXomAAF6KAABeioAAXosAAF6LwABejAAAXoxAAF6MgABejMAAXo1AAF6NwABejgAAXo5AAF6OwABejwAAXp7AAF6fQABen8AAXqBAAF6hAABeoUAAXqGAAF6hwABeogAAXqKAAF6jAABeo0AAXqOAAF6kAABepEAAXrQAAF60gABetQAAXrWAAF62QABetoAAXrbAAF63AABet0AAXrfAAF64QABeuIAAXrjAAF65QABeuYAAXsLAAF7LwABe1YAAXt6AAF7fQABe38AAXuBAAF7gwABe4UAAXuHAAF7iAABe4sAAXuYAAF7pwABe6kAAXurAAF7rQABe68AAXuxAAF7swABe7UAAXvEAAF7xwABe8oAAXvNAAF70AABe9MAAXvWAAF72QABe9sAAXwaAAF8HAABfB4AAXwgAAF8IwABfCQAAXwlAAF8JgABfCcAAXwpAAF8KwABfCwAAXwtAAF8LwABfDAAAXxvAAF8cQABfHMAAXx1AAF8eAABfHkAAXx6AAF8ewABfHwAAXx+AAF8gAABfIEAAXyCAAF8hAABfIUAAXzEAAF8xgABfMgAAXzKAAF8zQABfM4AAXzPAAF80AABfNEAAXzTAAF81QABfNYAAXzXAAF82QABfNoAAX0ZAAF9GwABfR0AAX0fAAF9IgABfSMAAX0kAAF9JQABfSYAAX0oAAF9KgABfSsAAX0sAAF9LgABfS8AAX1uAAF9cAABfXIAAX10AAF9dwABfXgAAX15AAF9egABfXsAAX19AAF9fwABfYAAAX2BAAF9gwABfYQAAX3DAAF9xQABfccAAX3JAAF9zAABfc0AAX3OAAF9zwABfdAAAX3SAAF91AABfdUAAX3WAAF92AABfdkAAX4YAAF+GgABfhwAAX4eAAF+IQABfiIAAX4jAAF+JAABfiUAAX4nAAF+KQABfioAAX4rAAF+LQABfi4AAX55AAF+nAABfrwAAX7cAAF+3gABfuAAAX7iAAF+5AABfucAAX7oAAF+6QABfuwAAX7tAAF+7wABfvAAAX7yAAF+9AABfvUAAX72AAF++QABfvoAAX7/AAF/DAABfxEAAX8TAAF/FQABfxoAAX8dAAF/IAABfyIAAX9HAAF/awABf5IAAX+2AAF/uQABf7sAAX+9AAF/vwABf8EAAX/DAAF/xAABf8cAAX/UAAF/5QABf+cAAX/pAAF/6wABf+0AAX/vAAF/8QABf/MAAX/1AAGABgABgAkAAYAMAAGADwABgBIAAYAVAAGAGAABgBsAAYAeAAGAIAABgF8AAYBhAAGAYwABgGUAAYBoAAGAaQABgGoAAYBrAAGAbAABgG4AAYBwAAGAcQABgHIAAYB0AAGAdQABgLQAAYC2AAGAuAABgLoAAYC9AAGAvgABgL8AAYDAAAGAwQABgMMAAYDFAAGAxgABgMcAAYDJAAGAygABgQkAAYELAAGBDgABgRAAAYETAAGBFAABgRUAAYEWAAGBFwABgRkAAYEbAAGBHAABgR0AAYEfAAGBIAABgS0AAYEuAAGBLwABgTEAAYFwAAGBcgABgXQAAYF2AAGBeQABgXoAAYF7AAGBfAABgX0AAYF/AAGBgQABgYIAAYGDAAGBhQABgYYAAYHFAAGBxwABgckAAYHLAAGBzgABgc8AAYHQAAGB0QABgdIAAYHUAAGB1gABgdcAAYHYAAGB2gABgdsAAYIaAAGCHAABgh4AAYIgAAGCIwABgiQAAYIlAAGCJgABgicAAYIpAAGCKwABgiwAAYItAAGCLwABgjAAAYJvAAGCcQABgnMAAYJ1AAGCeAABgnkAAYJ6AAGCewABgnwAAYJ+AAGCgAABgoEAAYKCAAGChAABgoUAAYLEAAGCxgABgsgAAYLKAAGCzQABgs4AAYLPAAGC0AABgtEAAYLTAAGC1QABgtYAAYLXAAGC2QABgtoAAYL/AAGDIwABg0oAAYNuAAGDcQABg3MAAYN1AAGDdwABg3kAAYN7AAGDfAABg38AAYOMAAGDmwABg50AAYOfAAGDoQABg6MAAYOlAAGDpwABg6kAAYO4AAGDuwABg74AAYPBAAGDxAABg8cAAYPKAAGDzQABg88AAYQOAAGEEAABhBIAAYQUAAGEFwABhBgAAYQZAAGEGgABhBsAAYQdAAGEHwABhCAAAYQhAAGEIwABhCQAAYRjAAGEZQABhGcAAYRpAAGEbAABhG0AAYRuAAGEbwABhHAAAYRyAAGEdAABhHUAAYR2AAGEeAABhHkAAYS4AAGEugABhLwAAYS+AAGEwQABhMIAAYTDAAGExAABhMUAAYTHAAGEyQABhMoAAYTLAAGEzQABhM4AAYUNAAGFDwABhREAAYUTAAGFFgABhRcAAYUYAAGFGQABhRoAAYUcAAGFHgABhR8AAYUgAAGFIgABhSMAAYViAAGFZAABhWYAAYVoAAGFawABhWwAAYVtAAGFbgABhW8AAYVxAAGFcwABhXQAAYV1AAGFdwABhXgAAYW3AAGFuQABhbsAAYW9AAGFwAABhcEAAYXCAAGFwwABhcQAAYXGAAGFyAABhckAAYXKAAGFzAABhc0AAYYMAAGGDgABhhAAAYYSAAGGFQABhhYAAYYXAAGGGAABhhkAAYYbAAGGHQABhh4AAYYfAAGGIQABhiIAAYZtAAGGkAABhrAAAYbQAAGG0gABhtQAAYbWAAGG2AABhtsAAYbcAAGG3QABhuAAAYbhAAGG4wABhuQAAYbmAAGG6QABhuoAAYbrAAGG7gABhu8AAYb0AAGHAQABhwYAAYcIAAGHCgABhw8AAYcSAAGHFQABhxcAAYc8AAGHYAABh4cAAYerAAGHrgABh7AAAYeyAAGHtAABh7YAAYe4AAGHuQABh7wAAYfJAAGH2gABh9wAAYfeAAGH4AABh+IAAYfkAAGH5gABh+gAAYfqAAGH+wABh/4AAYgBAAGIBAABiAcAAYgKAAGIDQABiBAAAYgTAAGIFQABiFQAAYhWAAGIWAABiFoAAYhdAAGIXgABiF8AAYhgAAGIYQABiGMAAYhlAAGIZgABiGcAAYhpAAGIagABiKkAAYirAAGIrQABiK8AAYiyAAGIswABiLQAAYi1AAGItgABiLgAAYi6AAGIuwABiLwAAYi+AAGIvwABiP4AAYkAAAGJAwABiQUAAYkIAAGJCQABiQoAAYkLAAGJDAABiQ4AAYkQAAGJEQABiRIAAYkUAAGJFQABiSIAAYkjAAGJJAABiSYAAYllAAGJZwABiWkAAYlrAAGJbgABiW8AAYlwAAGJcQABiXIAAYl0AAGJdgABiXcAAYl4AAGJegABiXsAAYm6AAGJvAABib4AAYnAAAGJwwABicQAAYnFAAGJxgABiccAAYnJAAGJywABicwAAYnNAAGJzwABidAAAYoPAAGKEQABihMAAYoVAAGKGAABihkAAYoaAAGKGwABihwAAYoeAAGKIAABiiEAAYoiAAGKJAABiiUAAYpkAAGKZgABimgAAYpqAAGKbQABim4AAYpvAAGKcAABinEAAYpzAAGKdQABinYAAYp3AAGKeQABinoAAYq5AAGKuwABir0AAYq/AAGKwgABisMAAYrEAAGKxQABisYAAYrIAAGKygABissAAYrMAAGKzgABis8AAYr0AAGLGAABiz8AAYtjAAGLZgABi2gAAYtqAAGLbAABi24AAYtwAAGLcQABi3QAAYuBAAGLkAABi5IAAYuUAAGLlgABi5gAAYuaAAGLnAABi54AAYutAAGLsAABi7MAAYu2AAGLuQABi7wAAYu/AAGLwgABi8QAAYwDAAGMBQABjAcAAYwJAAGMDAABjA0AAYwOAAGMDwABjBAAAYwSAAGMFAABjBUAAYwWAAGMGAABjBkAAYxYAAGMWgABjFwAAYxeAAGMYQABjGIAAYxjAAGMZAABjGUAAYxnAAGMaQABjGoAAYxrAAGMbQABjG4AAYytAAGMrwABjLEAAYyzAAGMtgABjLcAAYy4AAGMuQABjLoAAYy8AAGMvgABjL8AAYzAAAGMwgABjMMAAY0CAAGNBAABjQYAAY0IAAGNCwABjQwAAY0NAAGNDgABjQ8AAY0RAAGNEwABjRQAAY0VAAGNFwABjRgAAY1XAAGNWQABjVsAAY1dAAGNYAABjWEAAY1iAAGNYwABjWQAAY1mAAGNaAABjWkAAY1qAAGNbAABjW0AAY2sAAGNrgABjbAAAY2yAAGNtQABjbYAAY23AAGNuAABjbkAAY27AAGNvQABjb4AAY2/AAGNwQABjcIAAY4BAAGOAwABjgUAAY4HAAGOCgABjgsAAY4MAAGODQABjg4AAY4QAAGOEgABjhMAAY4UAAGOFgABjhcAAY5iAAGOhQABjqUAAY7FAAGOxwABjskAAY7LAAGOzQABjtAAAY7RAAGO0gABjtUAAY7WAAGO2AABjtkAAY7bAAGO3QABjt4AAY7fAAGO4gABjuMAAY7oAAGO9QABjvoAAY78AAGO/gABjwMAAY8GAAGPCQABjwsAAY8wAAGPVAABj3sAAY+fAAGPogABj6QAAY+mAAGPqAABj6oAAY+sAAGPrQABj7AAAY+9AAGPzgABj9AAAY/SAAGP1AABj9YAAY/YAAGP2gABj9wAAY/eAAGP7wABj/IAAY/1AAGP+AABj/sAAY/+AAGQAQABkAQAAZAHAAGQCQABkEgAAZBKAAGQTAABkE4AAZBRAAGQUgABkFMAAZBUAAGQVQABkFcAAZBZAAGQWgABkFsAAZBdAAGQXgABkJ0AAZCfAAGQoQABkKMAAZCmAAGQpwABkKgAAZCpAAGQqgABkKwAAZCuAAGQrwABkLAAAZCyAAGQswABkPIAAZD0AAGQ9wABkPkAAZD8AAGQ/QABkP4AAZD/AAGRAAABkQIAAZEEAAGRBQABkQYAAZEIAAGRCQABkRYAAZEXAAGRGAABkRoAAZFZAAGRWwABkV0AAZFfAAGRYgABkWMAAZFkAAGRZQABkWYAAZFoAAGRagABkWsAAZFsAAGRbgABkW8AAZGuAAGRsAABkbIAAZG0AAGRtwABkbgAAZG5AAGRugABkbsAAZG9AAGRvwABkcAAAZHBAAGRwwABkcQAAZIDAAGSBQABkgcAAZIJAAGSDAABkg0AAZIOAAGSDwABkhAAAZISAAGSFAABkhUAAZIWAAGSGAABkhkAAZJYAAGSWgABklwAAZJeAAGSYQABkmIAAZJjAAGSZAABkmUAAZJnAAGSaQABkmoAAZJrAAGSbQABkm4AAZKtAAGSrwABkrEAAZKzAAGStgABkrcAAZK4AAGSuQABkroAAZK8AAGSvgABkr8AAZLAAAGSwgABksMAAZLoAAGTDAABkzMAAZNXAAGTWgABk1wAAZNeAAGTYAABk2IAAZNkAAGTZQABk2gAAZN1AAGThAABk4YAAZOIAAGTigABk4wAAZOOAAGTkAABk5IAAZOhAAGTpAABk6cAAZOqAAGTrQABk7AAAZOzAAGTtgABk7gAAZP3AAGT+QABk/sAAZP9AAGUAAABlAEAAZQCAAGUAwABlAQAAZQGAAGUCAABlAkAAZQKAAGUDAABlA0AAZRMAAGUTgABlFAAAZRSAAGUVQABlFYAAZRXAAGUWAABlFkAAZRbAAGUXQABlF4AAZRfAAGUYQABlGIAAZShAAGUowABlKUAAZSnAAGUqgABlKsAAZSsAAGUrQABlK4AAZSwAAGUsgABlLMAAZS0AAGUtgABlLcAAZT2AAGU+AABlPoAAZT8AAGU/wABlQAAAZUBAAGVAgABlQMAAZUFAAGVBwABlQgAAZUJAAGVCwABlQwAAZVLAAGVTQABlU8AAZVRAAGVVAABlVUAAZVWAAGVVwABlVgAAZVaAAGVXAABlV0AAZVeAAGVYAABlWEAAZWgAAGVogABlaQAAZWmAAGVqQABlaoAAZWrAAGVrAABla0AAZWvAAGVsQABlbIAAZWzAAGVtQABlbYAAZX1AAGV9wABlfkAAZX7AAGV/gABlf8AAZYAAAGWAQABlgIAAZYEAAGWBgABlgcAAZYIAAGWCgABlgsAAZZWAAGWeQABlpkAAZa5AAGWuwABlr0AAZa/AAGWwQABlsQAAZbFAAGWxgABlskAAZbKAAGWzAABls0AAZbPAAGW0gABltMAAZbUAAGW1wABltgAAZbdAAGW6gABlu8AAZbxAAGW8wABlvgAAZb7AAGW/gABlwAAAZclAAGXSQABl3AAAZeUAAGXlwABl5kAAZebAAGXnQABl58AAZehAAGXogABl6UAAZeyAAGXwwABl8UAAZfHAAGXyQABl8sAAZfNAAGXzwABl9EAAZfTAAGX5AABl+cAAZfqAAGX7QABl/AAAZfzAAGX9gABl/kAAZf8AAGX/gABmD0AAZg/AAGYQQABmEMAAZhGAAGYRwABmEgAAZhJAAGYSgABmEwAAZhOAAGYTwABmFAAAZhSAAGYUwABmJIAAZiUAAGYlgABmJgAAZibAAGYnAABmJ0AAZieAAGYnwABmKEAAZijAAGYpAABmKUAAZinAAGYqAABmOcAAZjpAAGY7AABmO4AAZjxAAGY8gABmPMAAZj0AAGY9QABmPcAAZj5AAGY+gABmPsAAZj9AAGY/gABmQsAAZkMAAGZDQABmQ8AAZlOAAGZUAABmVIAAZlUAAGZVwABmVgAAZlZAAGZWgABmVsAAZldAAGZXwABmWAAAZlhAAGZYwABmWQAAZmjAAGZpQABmacAAZmpAAGZrAABma0AAZmuAAGZrwABmbAAAZmyAAGZtAABmbUAAZm2AAGZuAABmbkAAZn4AAGZ+gABmfwAAZn+AAGaAQABmgIAAZoDAAGaBAABmgUAAZoHAAGaCQABmgoAAZoLAAGaDQABmg4AAZpNAAGaTwABmlEAAZpTAAGaVgABmlcAAZpYAAGaWQABmloAAZpcAAGaXgABml8AAZpgAAGaYgABmmMAAZqiAAGapAABmqYAAZqoAAGaqwABmqwAAZqtAAGargABmq8AAZqxAAGaswABmrQAAZq1AAGatwABmrgAAZrdAAGbAQABmygAAZtMAAGbTwABm1EAAZtTAAGbVQABm1cAAZtZAAGbWgABm10AAZtqAAGbeQABm3sAAZt9AAGbfwABm4EAAZuDAAGbhQABm4cAAZuWAAGbmQABm5wAAZufAAGbogABm6UAAZuoAAGbqwABm60AAZvsAAGb7gABm/AAAZvyAAGb9QABm/YAAZv3AAGb+AABm/kAAZv7AAGb/QABm/4AAZv/AAGcAQABnAIAAZxBAAGcQwABnEUAAZxHAAGcSgABnEsAAZxMAAGcTQABnE4AAZxQAAGcUgABnFMAAZxUAAGcVgABnFcAAZyWAAGcmAABnJoAAZycAAGcnwABnKAAAZyhAAGcogABnKMAAZylAAGcpwABnKgAAZypAAGcqwABnKwAAZzrAAGc7QABnPAAAZzyAAGc9QABnPYAAZz3AAGc+AABnPkAAZz7AAGc/QABnP4AAZz/AAGdAQABnQIAAZ1BAAGdQwABnUUAAZ1HAAGdSgABnUsAAZ1MAAGdTQABnU4AAZ1QAAGdUgABnVMAAZ1UAAGdVgABnVcAAZ2WAAGdmAABnZoAAZ2cAAGdnwABnaAAAZ2hAAGdogABnaMAAZ2lAAGdpwABnagAAZ2pAAGdqwABnawAAZ3rAAGd7QABne8AAZ3xAAGd9AABnfUAAZ32AAGd9wABnfgAAZ36AAGd/AABnf0AAZ3+AAGeAAABngEAAZ5MAAGebwABno8AAZ6vAAGesQABnrMAAZ61AAGetwABnroAAZ67AAGevAABnr8AAZ7AAAGewgABnsMAAZ7FAAGeyAABnskAAZ7KAAGezQABns4AAZ7TAAGe4AABnuUAAZ7nAAGe6QABnu4AAZ7xAAGe9AABnvYAAZ8bAAGfPwABn2YAAZ+KAAGfjQABn48AAZ+RAAGfkwABn5UAAZ+XAAGfmAABn5sAAZ+oAAGfuQABn7sAAZ+9AAGfvwABn8EAAZ/DAAGfxQABn8cAAZ/JAAGf2gABn90AAZ/gAAGf4wABn+YAAZ/pAAGf7AABn+8AAZ/yAAGf9AABoDMAAaA1AAGgNwABoDkAAaA8AAGgPQABoD4AAaA/AAGgQAABoEIAAaBEAAGgRQABoEYAAaBIAAGgSQABoIgAAaCKAAGgjAABoI4AAaCRAAGgkgABoJMAAaCUAAGglQABoJcAAaCZAAGgmgABoJsAAaCdAAGgngABoN0AAaDfAAGg4gABoOQAAaDnAAGg6AABoOkAAaDqAAGg6wABoO0AAaDvAAGg8AABoPEAAaDzAAGg9AABoQEAAaECAAGhAwABoQUAAaFEAAGhRgABoUgAAaFKAAGhTQABoU4AAaFPAAGhUAABoVEAAaFTAAGhVQABoVYAAaFXAAGhWQABoVoAAaGZAAGhmwABoZ0AAaGfAAGhogABoaMAAaGkAAGhpQABoaYAAaGoAAGhqgABoasAAaGsAAGhrgABoa8AAaHuAAGh8AABofIAAaH0AAGh9wABofgAAaH5AAGh+gABofsAAaH9AAGh/wABogAAAaIBAAGiAwABogQAAaJDAAGiRQABokcAAaJJAAGiTAABok0AAaJOAAGiTwABolAAAaJSAAGiVAABolUAAaJWAAGiWAABolkAAaKYAAGimgABopwAAaKeAAGioQABoqIAAaKjAAGipAABoqUAAaKnAAGiqQABoqoAAaKrAAGirQABoq4AAaLTAAGi9wABox4AAaNCAAGjRQABo0cAAaNJAAGjSwABo00AAaNPAAGjUAABo1MAAaNgAAGjbwABo3EAAaNzAAGjdQABo3cAAaN5AAGjewABo30AAaOMAAGjjwABo5IAAaOVAAGjmAABo5sAAaOeAAGjoQABo6MAAaPiAAGj5AABo+YAAaPoAAGj6wABo+wAAaPtAAGj7gABo+8AAaPxAAGj8wABo/QAAaP1AAGj9wABo/gAAaQ3AAGkOQABpDsAAaQ9AAGkQAABpEEAAaRCAAGkQwABpEQAAaRGAAGkSAABpEkAAaRKAAGkTAABpE0AAaSMAAGkjgABpJAAAaSSAAGklQABpJYAAaSXAAGkmAABpJkAAaSbAAGknQABpJ4AAaSfAAGkoQABpKIAAaThAAGk4wABpOUAAaTnAAGk6gABpOsAAaTsAAGk7QABpO4AAaTwAAGk8gABpPMAAaT0AAGk9gABpPcAAaU2AAGlOAABpToAAaU8AAGlPwABpUAAAaVBAAGlQgABpUMAAaVFAAGlRwABpUgAAaVJAAGlSwABpUwAAaWLAAGljQABpY8AAaWRAAGllAABpZUAAaWWAAGllwABpZgAAaWaAAGlnAABpZ0AAaWeAAGloAABpaEAAaXgAAGl4gABpeQAAaXmAAGl6QABpeoAAaXrAAGl7AABpe0AAaXvAAGl8QABpfIAAaXzAAGl9QABpfYAAaX/AAGmAAABpgIAAaZFAAGmaQABpo0AAaawAAGm1wABpvcAAaceAAGnRQABp2UAAaeJAAGnrQABp68AAaeyAAGntAABp7YAAae4AAGnuwABp74AAafAAAGnwgABp8UAAafHAAGnyQABp8wAAafPAAGn0AABp9UAAafiAAGn5QABp+cAAafqAAGn7QABp+8AAagUAAGoOAABqF8AAaiDAAGohgABqIgAAaiKAAGojAABqI4AAaiQAAGokQABqJQAAaihAAGotAABqLYAAai4AAGougABqLwAAai+AAGowAABqMIAAajEAAGoxgABqNkAAajcAAGo3wABqOIAAajlAAGo6AABqOsAAajuAAGo8QABqPQAAaj2AAGpNQABqTcAAak6AAGpPAABqT8AAalAAAGpQQABqUIAAalDAAGpRQABqUcAAalIAAGpSQABqUsAAalMAAGpVQABqVYAAalYAAGplwABqZkAAambAAGpnQABqaAAAamhAAGpogABqaMAAamkAAGppgABqagAAampAAGpqgABqawAAamtAAGp7AABqe4AAanxAAGp8wABqfYAAan3AAGp+AABqfkAAan6AAGp/AABqf4AAan/AAGqAAABqgIAAaoDAAGqDAABqg0AAaoPAAGqTgABqlAAAapSAAGqVAABqlcAAapYAAGqWQABqloAAapbAAGqXQABql8AAapgAAGqYQABqmMAAapkAAGqowABqqUAAaqoAAGqqgABqq0AAaquAAGqrwABqrAAAaqxAAGqswABqrUAAaq2AAGqtwABqrkAAaq6AAGqwwABqsQAAarGAAGrBQABqwcAAasJAAGrCwABqw4AAasPAAGrEAABqxEAAasSAAGrFAABqxYAAasXAAGrGAABqxoAAasbAAGrWgABq1wAAatfAAGrYQABq2QAAatlAAGrZgABq2cAAatoAAGragABq2wAAattAAGrbgABq3AAAatxAAGrfgABq38AAauAAAGrggABq8EAAavDAAGrxQABq8cAAavKAAGrywABq8wAAavNAAGrzgABq9AAAavSAAGr0wABq9QAAavWAAGr1wABrBYAAawYAAGsGwABrB0AAawgAAGsIQABrCIAAawjAAGsJAABrCYAAawoAAGsKQABrCoAAawsAAGsLQABrDgAAaxFAAGsTgABrFEAAaxUAAGsVwABrFkAAaxiAAGsZQABrGgAAaxrAAGsbgABrHAAAax3AAGswgABrOUAAa0FAAGtJQABrScAAa0pAAGtKwABrS0AAa0wAAGtMQABrTIAAa01AAGtNgABrTgAAa05AAGtOwABrT4AAa0/AAGtQAABrUMAAa1EAAGtSQABrVYAAa1bAAGtXQABrV8AAa1kAAGtZwABrWoAAa1sAAGtkQABrbUAAa3cAAGuAAABrgMAAa4FAAGuBwABrgkAAa4LAAGuDQABrg4AAa4RAAGuHgABri8AAa4xAAGuMwABrjUAAa43AAGuOQABrjsAAa49AAGuPwABrlAAAa5TAAGuVgABrlkAAa5cAAGuXwABrmIAAa5lAAGuaAABrmoAAa6pAAGuqwABrq0AAa6vAAGusgABrrMAAa60AAGutQABrrYAAa64AAGuugABrrsAAa68AAGuvgABrr8AAa7+AAGvAAABrwIAAa8EAAGvBwABrwgAAa8JAAGvCgABrwsAAa8NAAGvDwABrxAAAa8RAAGvEwABrxQAAa9TAAGvVQABr1gAAa9aAAGvXQABr14AAa9fAAGvYAABr2EAAa9jAAGvZQABr2YAAa9nAAGvaQABr2oAAa93AAGveAABr3kAAa97AAGvugABr7wAAa++AAGvwAABr8MAAa/EAAGvxQABr8YAAa/HAAGvyQABr8sAAa/MAAGvzQABr88AAa/QAAGwDwABsBEAAbATAAGwFQABsBgAAbAZAAGwGgABsBsAAbAcAAGwHgABsCAAAbAhAAGwIgABsCQAAbAlAAGwZAABsGYAAbBoAAGwagABsG0AAbBuAAGwbwABsHAAAbBxAAGwcwABsHUAAbB2AAGwdwABsHkAAbB6AAGwuQABsLsAAbC9AAGwvwABsMIAAbDDAAGwxAABsMUAAbDGAAGwyAABsMoAAbDLAAGwzAABsM4AAbDPAAGxDgABsRAAAbESAAGxFAABsRcAAbEYAAGxGQABsRoAAbEbAAGxHQABsR8AAbEgAAGxIQABsSMAAbEkAAGxSQABsW0AAbGUAAGxuAABsbsAAbG9AAGxvwABscEAAbHDAAGxxQABscYAAbHJAAGx1gABseUAAbHnAAGx6QABsesAAbHtAAGx7wABsfEAAbHzAAGyAgABsgUAAbIIAAGyCwABsg4AAbIRAAGyFAABshcAAbIZAAGyWAABsloAAbJcAAGyXgABsmEAAbJiAAGyYwABsmQAAbJlAAGyZwABsmkAAbJqAAGyawABsm0AAbJuAAGyrQABsq8AAbKxAAGyswABsrYAAbK3AAGyuAABsrkAAbK6AAGyvAABsr4AAbK/AAGywAABssIAAbLDAAGzAgABswQAAbMGAAGzCAABswsAAbMMAAGzDQABsw4AAbMPAAGzEQABsxMAAbMUAAGzFQABsxcAAbMYAAGzVwABs1kAAbNbAAGzXQABs2AAAbNhAAGzYgABs2MAAbNkAAGzZgABs2gAAbNpAAGzagABs2wAAbNtAAGzrAABs64AAbOwAAGzsgABs7UAAbO2AAGztwABs7gAAbO5AAGzuwABs70AAbO+AAGzvwABs8EAAbPCAAG0AQABtAMAAbQFAAG0BwABtAoAAbQLAAG0DAABtA0AAbQOAAG0EAABtBIAAbQTAAG0FAABtBYAAbQXAAG0VgABtFgAAbRaAAG0XAABtF8AAbRgAAG0YQABtGIAAbRjAAG0ZQABtGcAAbRoAAG0aQABtGsAAbRsAAG0twABtNoAAbT6AAG1GgABtRwAAbUeAAG1IAABtSIAAbUlAAG1JgABtScAAbUqAAG1KwABtS0AAbUuAAG1MAABtTMAAbU0AAG1NQABtTgAAbU5AAG1PgABtUsAAbVQAAG1UgABtVQAAbVZAAG1XAABtV8AAbVhAAG1hgABtaoAAbXRAAG19QABtfgAAbX6AAG1/AABtf4AAbYAAAG2AgABtgMAAbYGAAG2EwABtiQAAbYmAAG2KAABtioAAbYsAAG2LgABtjAAAbYyAAG2NAABtkUAAbZIAAG2SwABtk4AAbZRAAG2VAABtlcAAbZaAAG2XQABtl8AAbaeAAG2oAABtqIAAbakAAG2pwABtqgAAbapAAG2qgABtqsAAbatAAG2rwABtrAAAbaxAAG2swABtrQAAbbzAAG29QABtvcAAbb5AAG2/AABtv0AAbb+AAG2/wABtwAAAbcCAAG3BAABtwUAAbcGAAG3CAABtwkAAbdIAAG3SgABt00AAbdPAAG3UgABt1MAAbdUAAG3VQABt1YAAbdYAAG3WgABt1sAAbdcAAG3XgABt18AAbdsAAG3bQABt24AAbdwAAG3rwABt7EAAbezAAG3tQABt7gAAbe5AAG3ugABt7sAAbe8AAG3vgABt8AAAbfBAAG3wgABt8QAAbfFAAG4BAABuAYAAbgIAAG4CgABuA0AAbgOAAG4DwABuBAAAbgRAAG4EwABuBUAAbgWAAG4FwABuBkAAbgaAAG4WQABuFsAAbhdAAG4XwABuGIAAbhjAAG4ZAABuGUAAbhmAAG4aAABuGoAAbhrAAG4bAABuG4AAbhvAAG4rgABuLAAAbiyAAG4tAABuLcAAbi4AAG4uQABuLoAAbi7AAG4vQABuL8AAbjAAAG4wQABuMMAAbjEAAG5AwABuQUAAbkHAAG5CQABuQwAAbkNAAG5DgABuQ8AAbkQAAG5EgABuRQAAbkVAAG5FgABuRgAAbkZAAG5PgABuWIAAbmJAAG5rQABubAAAbmyAAG5tAABubYAAbm4AAG5ugABubsAAbm+AAG5ywABudoAAbncAAG53gABueAAAbniAAG55AABueYAAbnoAAG59wABufoAAbn9AAG6AAABugMAAboGAAG6CQABugwAAboOAAG6TQABuk8AAbpRAAG6UwABulYAAbpXAAG6WAABulkAAbpaAAG6XAABul4AAbpfAAG6YAABumIAAbpjAAG6ogABuqQAAbqmAAG6qAABuqsAAbqsAAG6rQABuq4AAbqvAAG6sQABurMAAbq0AAG6tQABurcAAbq4AAG69wABuvkAAbr7AAG6/QABuwAAAbsBAAG7AgABuwMAAbsEAAG7BgABuwgAAbsJAAG7CgABuwwAAbsNAAG7TAABu04AAbtRAAG7UwABu1YAAbtXAAG7WAABu1kAAbtaAAG7XAABu14AAbtfAAG7YAABu2IAAbtjAAG7ogABu6QAAbumAAG7qAABu6sAAbusAAG7rQABu64AAbuvAAG7sQABu7MAAbu0AAG7tQABu7cAAbu4AAG79wABu/kAAbv7AAG7/QABvAAAAbwBAAG8AgABvAMAAbwEAAG8BgABvAgAAbwJAAG8CgABvAwAAbwNAAG8TAABvE4AAbxQAAG8UgABvFUAAbxWAAG8VwABvFgAAbxZAAG8WwABvF0AAbxeAAG8XwABvGEAAbxiAAG8rQABvNAAAbzwAAG9EAABvRIAAb0UAAG9FgABvRgAAb0bAAG9HAABvR0AAb0gAAG9IQABvSMAAb0kAAG9JgABvSkAAb0qAAG9KwABvS4AAb0vAAG9OAABvUUAAb1KAAG9TAABvU4AAb1TAAG9VgABvVkAAb1bAAG9gAABvaQAAb3LAAG97wABvfIAAb30AAG99gABvfgAAb36AAG9/AABvf0AAb4AAAG+DQABvh4AAb4gAAG+IgABviQAAb4mAAG+KAABvioAAb4sAAG+LgABvj8AAb5CAAG+RQABvkgAAb5LAAG+TgABvlEAAb5UAAG+VwABvlkAAb6YAAG+mgABvpwAAb6eAAG+oQABvqIAAb6jAAG+pAABvqUAAb6nAAG+qQABvqoAAb6rAAG+rQABvq4AAb7tAAG+7wABvvEAAb7zAAG+9gABvvcAAb74AAG++QABvvoAAb78AAG+/gABvv8AAb8AAAG/AgABvwMAAb9CAAG/RAABv0cAAb9JAAG/TAABv00AAb9OAAG/TwABv1AAAb9SAAG/VAABv1UAAb9WAAG/WAABv1kAAb9mAAG/ZwABv2gAAb9qAAG/qQABv6sAAb+tAAG/rwABv7IAAb+zAAG/tAABv7UAAb+2AAG/uAABv7oAAb+7AAG/vAABv74AAb+/AAG//gABwAAAAcACAAHABAABwAcAAcAIAAHACQABwAoAAcALAAHADQABwA8AAcAQAAHAEQABwBMAAcAUAAHAUwABwFUAAcBXAAHAWQABwFwAAcBdAAHAXgABwF8AAcBgAAHAYgABwGQAAcBlAAHAZgABwGgAAcBpAAHAqAABwKoAAcCsAAHArgABwLEAAcCyAAHAswABwLQAAcC1AAHAtwABwLkAAcC6AAHAuwABwL0AAcC+AAHA/QABwP8AAcEBAAHBAwABwQYAAcEHAAHBCAABwQkAAcEKAAHBDAABwQ4AAcEPAAHBEAABwRIAAcETAAHBOAABwVwAAcGDAAHBpwABwaoAAcGsAAHBrgABwbAAAcGyAAHBtAABwbUAAcG4AAHBxQABwdQAAcHWAAHB2AABwdoAAcHcAAHB3gABweAAAcHiAAHB8QABwfQAAcH3AAHB+gABwf0AAcIAAAHCAwABwgYAAcIIAAHCRwABwkkAAcJLAAHCTQABwlAAAcJRAAHCUgABwlMAAcJUAAHCVgABwlgAAcJZAAHCWgABwlwAAcJdAAHCnAABwp4AAcKgAAHCogABwqUAAcKmAAHCpwABwqgAAcKpAAHCqwABwq0AAcKuAAHCrwABwrEAAcKyAAHC8QABwvMAAcL1AAHC9wABwvoAAcL7AAHC/AABwv0AAcL+AAHDAAABwwIAAcMDAAHDBAABwwYAAcMHAAHDRgABw0gAAcNKAAHDTAABw08AAcNQAAHDUQABw1IAAcNTAAHDVQABw1cAAcNYAAHDWQABw1sAAcNcAAHDmwABw50AAcOfAAHDoQABw6QAAcOlAAHDpgABw6cAAcOoAAHDqgABw6wAAcOtAAHDrgABw7AAAcOxAAHD8AABw/IAAcP0AAHD9gABw/kAAcP6AAHD+wABw/wAAcP9AAHD/wABxAEAAcQCAAHEAwABxAUAAcQGAAHERQABxEcAAcRJAAHESwABxE4AAcRPAAHEUAABxFEAAcRSAAHEVAABxFYAAcRXAAHEWAABxFoAAcRbAAHEpgABxMkAAcTpAAHFCQABxQsAAcUNAAHFDwABxREAAcUUAAHFFQABxRYAAcUZAAHFGgABxRwAAcUdAAHFHwABxSEAAcUiAAHFIwABxSYAAcUnAAHFLAABxTkAAcU+AAHFQAABxUIAAcVHAAHFSgABxU0AAcVPAAHFdAABxZgAAcW/AAHF4wABxeYAAcXoAAHF6gABxewAAcXuAAHF8AABxfEAAcX0AAHGAQABxhIAAcYUAAHGFgABxhgAAcYaAAHGHAABxh4AAcYgAAHGIgABxjMAAcY2AAHGOQABxjwAAcY/AAHGQgABxkUAAcZIAAHGSwABxk0AAcaMAAHGjgABxpAAAcaSAAHGlQABxpYAAcaXAAHGmAABxpkAAcabAAHGnQABxp4AAcafAAHGoQABxqIAAcbhAAHG4wABxuUAAcbnAAHG6gABxusAAcbsAAHG7QABxu4AAcbwAAHG8gABxvMAAcb0AAHG9gABxvcAAcc2AAHHOAABxzsAAcc9AAHHQAABx0EAAcdCAAHHQwABx0QAAcdGAAHHSAABx0kAAcdKAAHHTAABx00AAcdaAAHHWwABx1wAAcdeAAHHnQABx58AAcehAAHHowABx6YAAcenAAHHqAABx6kAAceqAAHHrAABx64AAcevAAHHsAABx7IAAcezAAHH8gABx/QAAcf2AAHH+AABx/sAAcf8AAHH/QABx/4AAcf/AAHIAQAByAMAAcgEAAHIBQAByAcAAcgIAAHIRwAByEkAAchLAAHITQAByFAAAchRAAHIUgAByFMAAchUAAHIVgAByFgAAchZAAHIWgAByFwAAchdAAHInAAByJ4AAcigAAHIogAByKUAAcimAAHIpwAByKgAAcipAAHIqwAByK0AAciuAAHIrwAByLEAAciyAAHI8QAByPMAAcj1AAHI9wAByPoAAcj7AAHI/AAByP0AAcj+AAHJAAAByQIAAckDAAHJBAAByQYAAckHAAHJLAAByVAAAcl3AAHJmwAByZ4AAcmgAAHJogAByaQAAcmmAAHJqAAByakAAcmsAAHJuQABycgAAcnKAAHJzAAByc4AAcnQAAHJ0gABydQAAcnWAAHJ5QAByegAAcnrAAHJ7gAByfEAAcn0AAHJ9wAByfoAAcn8AAHKOwAByj0AAco/AAHKQQABykQAAcpFAAHKRgABykcAAcpIAAHKSgABykwAAcpNAAHKTgABylAAAcpRAAHKkAABypIAAcqUAAHKlgABypkAAcqaAAHKmwABypwAAcqdAAHKnwAByqEAAcqiAAHKowAByqUAAcqmAAHK5QAByucAAcrpAAHK6wAByu4AAcrvAAHK8AAByvEAAcryAAHK9AAByvYAAcr3AAHK+AAByvoAAcr7AAHLOgAByzwAAcs+AAHLQAABy0MAActEAAHLRQABy0YAActHAAHLSQABy0sAActMAAHLTQABy08AActQAAHLjwABy5EAAcuTAAHLlQABy5gAAcuZAAHLmgABy5sAAcucAAHLngABy6AAAcuhAAHLogABy6QAAculAAHL5AABy+YAAcvoAAHL6gABy+0AAcvuAAHL7wABy/AAAcvxAAHL8wABy/UAAcv2AAHL9wABy/kAAcv6AAHMOQABzDsAAcw9AAHMPwABzEIAAcxDAAHMRAABzEUAAcxGAAHMSAABzEoAAcxLAAHMTAABzE4AAcxPAAHMWAABzFkAAcxbAAHMaAABzGkAAcxqAAHMbAABzHkAAcx6AAHMewABzH0AAcyKAAHMiwABzIwAAcyOAAHMlwABzKYAAcyzAAHMwgABzNQAAczoAAHM/wABzREAAc0aAAHNGwABzR0AAc0qAAHNKwABzSwAAc0uAAHNLwABzTgAAc1CAAHNSQAAAAAAAAQCAAAAAAAARYMAAAAAAAAAAAAAAAAAAc1R - - LoopKit/Persistence/Model.xcdatamodeld/Modelv4.xcdatamodel - YnBsaXN0MDDUAAEAAgADAAQABQAGAAcAClgkdmVyc2lvblkkYXJjaGl2ZXJUJHRvcFgkb2JqZWN0 -cxIAAYagXxAPTlNLZXllZEFyY2hpdmVy0QAIAAlUcm9vdIABrxEIKgALAAwAGwA3ADgAOQBNAE4ATwBQAFEAUgBTAFQAbwBwAHEAdwB4AIQAmgCbAJwAnQCeAJ8AoAChAKIAowC8AL8AxgDMANsA6gDuAPIA8wECAREBFABuASQBMwE3ATsBSgFQAVEBWQFoAWkBcgGYAZkBmgGbAZwBnQGeAZ8BoAGhAaIBowGkAaUBpgGnAagBvQG+AcYBxwHIAdQB6AHpAeoB6wHsAe0B7gHvAfAB/wIOAh0CIQIwAj8CQAJPAl4CbQJ5AosCjAKNAo4CjwKQApECkgKhArACvwLOAs8C3gLtAvwDBAMZAxoDIgMuA0IDUQNgA28DcwOCA5EDoAOvA74DygPcA+sD+gQJBBgEJwQ2BEUEWgRbBGMEbwSDBJIEoQSwBLQEwwTSBOEE8AT/BQsFHQUsBTsFSgVZBWgFdwWGBZsFnAWkBbAFxAXTBeIF8QX1BgQGEwYiBjEGQAZMBl4GbQZ8BosGmgabBqoGuQbIBt0G3gbmBvIHBgcVByQHMwc3B0YHVQdkB3MHggeOB6AHrwe+B80H3AfrB/oICQgeCB8IJwgzCEcIVghlCHQIeAiHCJYIpQi0CMMIzwjhCPAI8QkACQ8JHgkfCS4JPQlMCWEJYglqCXYJigmZCagJtwm7CcoJ2QnoCfcKBgoSCiQKMwo0CkMKUgphCmIKcQqACo8KpAqlCq0KuQrNCtwK6wr6Cv4LDQscCysLOgtJC1ULZwt2C4ULlAujC6QLswvCC9EL5gvnC+8L+wwPDB4MLQw8DEAMTwxeDG0MfAyLDJcMqQy4DMcM1gzlDOYM9Q0EDRMNKA0pDTENPQ1RDWANbw1+DYINkQ2gDa8Nvg3NDdkN6w36DgkOGA4nDjYORQ5UDmkOag5yDn4Okg6hDrAOvw7DDtIO4Q7wDv8PDg8aDywPOw9KD1kPaA93D4YPlQ+qD6sPsw+/D9MP4g/xEAAQBBATECIQMRBAEE8QWxBtEHwQixCaEKkQqhC5EMgQ1xDsEO0Q9REBERURJBEzEUIRRhFVEWQRcxGCEZERnRGvEb4RvxHOEd0R7BH7EgoSGRIuEi8SNxJDElcSZhJ1EoQSiBKXEqYStRLEEtMS3xLxEwATDxMeEy0TPBNLE1oTbxNwE3gThBOYE6cTthPFE8kT2BPnE/YUBRQUFCAUMhRBFFAUXxRuFH0UjBSbFLAUsRS5FMUU2RToFPcVBhUKFRkVKBU3FUYVVRVhFXMVghWRFaAVrxW+Fc0V3BXxFfIV+hYGFhoWKRY4FkcWSxZaFmkWeBaHFpYWoha0FsMW0hbhFvAW/xcOFx0XHhchFyoXRBdFF0sXVxdtF3wXfxeOF50XohemF6cXqxesF7sXyhfNF9wX6xfvF/4YDRgOGDgYORg6GDsYPBg9GD4YPxhAGEEYQhhDGEQYRRhGGEcYSBhdGF4YZhhyGIYYlRikGLMYtxjGGNUY5BjzGPQZAxkPGSEZMBk/GU4ZXRlsGXsZihmfGaAZqBm0GcgZ1xnmGfUZ+RoIGhcaJho1GkQaUBpiGnEagBqPGp4arRq8Gssa4BrhGuka9RsJGxgbJxs2GzobSRtYG2cbdhuFG5EboxuyG8Eb0BvfG+4b/RwMHCEcIhwqHDYcShxZHGgcdxx7HIocmRyoHLccxhzSHOQc8x0CHREdIB0hHTAdPx1OHWMdZB1sHXgdjB2bHaoduR29Hcwd2x3qHfkeCB4UHiYeNR5EHlMeYh5xHoAejx6kHqUerR65Hs0e3B7rHvoe/h8NHxwfKx86H0kfVR9nH3YfhR+UH6Mfsh/BH9Af5R/mH+4f+iAOIB0gLCA7ID8gTiBdIGwgeyCKIJYgqCC3IMYg1SDkIPMhAiERISYhJyEvITshTyFeIW0hfCGAIY8hniGtIbwhyyHXIekh+CIHIhYiJSI0IkMiUiJnImgicCJ8IpAinyKuIr0iwSLQIt8i7iL9IwwjGCMqIzkjSCNXI2YjdSOEI5MjqCOpI7EjvSPRI+Aj7yP+JAIkESQgJC8kPiRNJFkkayR6JIkkmCSnJLYkxSTUJOkk6iTyJP4lEiUhJTAlPyVDJVIlYSVwJX8ljiWaJawluyXKJdkl6CX3JgYmFSYqJismMyY/JlMmYiZxJoAmhCaTJqImsSbAJs8m2ybtJvwnCycaJyknOCdHJ1YnaydsJ3QngCeUJ6MnsifBJ8Un1CfjJ/IoASgQKBwoLig9KEwoWyhqKHkoiCiXKKworSi1KMEo1SjkKPMpAikGKRUpJCkzKUIpUSldKW8pfimNKZwpqym6Kckp2CntKe4p9ioCKhYqJSo0KkMqRypWKmUqdCqDKpIqniqwKr8qzirdKuwq+ysKKxkrLisvKzcrQytXK2YrdSuEK4grlyumK7UrxCvTK98r8SwALA8sHiwtLDwsSyxaLG8scCx4LIQsmCynLLYsxSzJLNgs5yz2LQUtFC0gLTItQS1QLV8tbi19LYwtmy2wLbEtuS3FLdkt6C33LgYuCi4ZLiguNy5GLlUuYS5zLoIukS6gLq8uvi7NLtwu8S7yLvovBi8aLykvOC9HL0svWi9pL3gvhy+WL6IvtC/DL9Iv4S/wL/8wDjAdMCAwOjA7MEEwTTBjMHIwdTCEMJMwlzCbMJwwqzC6ML0wzDDbMN8w7jD9MP4xCDEJMQoxHzEgMSgxNDFIMVcxZjF1MXkxiDGXMaYxtTHEMdAx4jHxMgAyDzIeMi0yPDJLMmAyYTJpMnUyiTKYMqcytjK6Msky2DLnMvYzBTMRMyMzMjNBM1AzXzNuM30zjDOhM6IzqjO2M8oz2TPoM/cz+zQKNBk0KDQ3NEY0UjRkNHM0gjSRNKA0rzS+NM000DTqNOs08TT9NRM1IjUlNTQ1QzVGNVU1ZDVnNXY1hTWJNZg1pzWoNcw1zTXONc810DXRNdI10zXUNdU11jXXNdg12TXaNe818DX4NgQ2GDYnNjY2RTZJNlg2ZzZ2NoU2lDagNrI2wTbQNt827jb9Nww3GzcwNzE3OTdFN1k3aDd3N4Y3ijeZN6g3tzfGN8c31jfiN/Q4AzgSOCE4MDg/OE44XThyOHM4eziHOJs4qji5OMg4zDjbOOo4+TkIORc5Izk1OUQ5UzliOXE5gDmPOZ45szm0Obw5yDncOes5+joJOg06HDorOjo6STpYOmQ6djqFOpQ6ozqyOrM6wjrROuA69Tr2Ov47CjseOy07PDtLO087XjttO3w7izuaO6Y7uDvHO9Y75Tv0PAM8EjwhPDY8Nzw/PEs8XzxuPH08jDyQPJ88rjy9PMw82zznPPk9CD0XPSY9NT1EPVM9Yj13PXg9gD2MPaA9rz2+Pc090T3gPe89/j4NPhw+KD46Pkk+WD5nPnY+hT6UPqM+uD65PsE+zT7hPvA+/z8OPxI/IT8wPz8/Tj9dP2k/ez+KP5k/qD+3P8Y/1T/kP/k/+kACQA5AIkAxQEBAT0BTQGJAcUCAQI9AnkCqQLxAy0DaQOlA+EEHQRZBJUE6QTtBQ0FPQWNBckGBQZBBlEGjQbJBwUHQQd9B60H9QgxCG0IqQjlCSEJXQmZCe0J8QoRCkEKkQrNCwkLRQtVC5ELzQwJDEUMgQyxDPkNNQ1xDa0N6Q4lDmEOnQ7xDvUPFQ9FD5UP0RANEEkQWRCVENERDRFJEYURtRH9EjkSdRKxEu0TKRNlE6ET9RP5FBkUSRSZFNUVERVNFV0VmRXVFhEWTRaJFrkXARc9F3kXtRfxGC0YaRilGPkY/RkdGU0ZnRnZGhUaURphGp0a2RsVG1EbjRu9HAUcQRxFHIEcvRz5HTUdcR2tHgEeBR4lHlUepR7hHx0fWR9pH6Uf4SAdIFkglSDFIQ0hSSGFIcEh/SI5InUisSMFIwkjKSNZI6kj5SQhJF0kbSSpJOUlISVdJZklySYRJk0miSbFJwEnPSd5J7UnwSgpKC0oRSh1KM0pCSkVKVEpjSmhKbEpwSnFKgEqPSpJKoUqwSrRKw0rSStNK90r4SvlK+kr7SvxK/Ur+Sv9LAEsBSwJLA0sESxlLGksiSy5LQktRS2BLb0tzS4JLkUugS69LvkvKS9xL60v6TAlMGEwnTDZMRUxaTFtMY0xvTINMkkyhTLBMtEzDTNJM4UzwTP9NC00dTSxNO01KTVlNaE13TYZNm02cTaRNsE3ETdNN4k3xTfVOBE4TTiJOMU5ATkxOXk5tTnxOi06aTqlOuE7HTtxO3U7lTvFPBU8UTyNPMk82T0VPVE9jT3JPgU+NT59Prk+9T8xP20/qT/lQCFAdUB5QJlAyUEZQVVBkUHNQd1CGUJVQpFCzUMJQzlDgUO9Q/lENURxRK1E6UUlRXlFfUWdRc1GHUZZRpVG0UbhRx1HWUeVR9FIDUg9SIVIwUj9STlJdUmxSe1KKUp9SoFKoUrRSyFLXUuZS9VL5UwhTF1MmUzVTRFNQU2JTcVOAU49TnlOtU7xTy1PgU+FT6VP1VAlUGFQnVDZUOlRJVFhUZ1R2VIVUkVSjVLJUwVTQVN9U7lT9VQxVIVUiVSpVNlVKVVlVaFV3VXtVilWZVahVt1XGVdJV5FXzVgJWEVYgVi9WPlZNVmJWY1ZrVndWi1aaVqlWuFa8VstW2lbpVvhXB1cTVyVXNFdDV1JXYVdwV39XjlejV6RXrFe4V8xX21fqV/lX/VgMWBtYKlg5WEhYVFhmWHVYhFiTWKJYsVjAWM9Y5FjlWO1Y+VkNWRxZK1k6WT5ZTVlcWWtZelmJWZVZp1m2WcVZ1FnjWfJaAVoQWiVaJlouWjpaTlpdWmxae1p/Wo5anVqsWrtaylrWWuha91sGWxVbJFszW0JbUVtmW2dbb1t7W49bnlutW7xbwFvPW95b7Vv8XAtcF1wpXDhcR1xWXGVcdFyDXJJcp1yoXLBcvFzQXN9c7lz9XQFdEF0fXS5dPV1MXVhdal15XYhdl12mXbVdxF3TXehd6V3xXf1eEV4gXi9ePl5CXlFeYF5vXn5ejV6ZXqteul7JXthe5172XwVfFF8XXzFfMl84X0RfWl9pX2xfe1+KX41fnF+rX65fvV/MX9Bf31/uX+9f+1/8YBFgEmAaYCZgOmBJYFhgZ2BrYHpgiWCYYKdgtmDCYNRg42DyYQFhEGEfYS5hPWFSYVNhW2FnYXthimGZYahhrGG7Ycph2WHoYfdiA2IVYiRiM2JCYlFiYGJvYn5ik2KUYpxiqGK8Ysti2mLpYu1i/GMLYxpjKWM4Y0RjVmNlY3Rjg2OSY6FjsGO/Y9Rj1WPdY+lj/WQMZBtkKmQuZD1kTGRbZGpkeWSFZJdkpmS1ZMRk02TiZPFlAGUDZR1lHmUkZTBlRmVVZVhlZ2V2ZXlliGWXZZplqWW4Zbxly2XaZdtl5WXmZftl/GYEZhBmJGYzZkJmUWZVZmRmc2aCZpFmoGasZr5mzWbcZutm+mcJZxhnJ2c8Zz1nRWdRZ2VndGeDZ5JnlmelZ7Rnw2fSZ+Fn7Wf/aA5oHWgsaDtoSmhZaGhofWh+aIZokmimaLVoxGjTaNdo5mj1aQRpE2kiaS5pQGlPaV5pbWl8aYtpmmmpaaxpsGm0abhpwGnDacdVJG51bGzXAA0ADgAPABAAEQASABMAFAAVABYAFwAYABcAGl8QD194ZF9yb290UGFja2FnZVYkY2xhc3NcX3hkX2NvbW1lbnRzXxAQX3hkX21vZGVsTWFuYWdlcl8QFV9jb25maWd1cmF0aW9uc0J5TmFtZV1feGRfbW9kZWxOYW1lXxAXX21vZGVsVmVyc2lvbklkZW50aWZpZXKAAoEIKYEIJ4AAgQgogACBBYveABwAHQAeAB8AIAAhACIADgAjACQAJQAmACcAKAApACoAKwAJACkAFwAvADAAMQAyADMAKQApABdfEBxYREJ1Y2tldEZvckNsYXNzZXN3YXNFbmNvZGVkXxAaWERCdWNrZXRGb3JQYWNrYWdlc3N0b3JhZ2VfEBxYREJ1Y2tldEZvckludGVyZmFjZXNzdG9yYWdlXxAPX3hkX293bmluZ01vZGVsXxAdWERCdWNrZXRGb3JQYWNrYWdlc3dhc0VuY29kZWRWX293bmVyXxAbWERCdWNrZXRGb3JEYXRhVHlwZXNzdG9yYWdlW192aXNpYmlsaXR5XxAZWERCdWNrZXRGb3JDbGFzc2Vzc3RvcmFnZVVfbmFtZV8QH1hEQnVja2V0Rm9ySW50ZXJmYWNlc3dhc0VuY29kZWRfEB5YREJ1Y2tldEZvckRhdGFUeXBlc3dhc0VuY29kZWRfEBBfdW5pcXVlRWxlbWVudElEgASBCCWBCCOAAYAEgACBCCSBCCYQAIAFgAOABIAEgABQU1lFU9MAOgA7AA4APABEAExXTlMua2V5c1pOUy5vYmplY3RzpwA9AD4APwBAAEEAQgBDgAaAB4AIgAmACoALgAynAEUARgBHAEgASQBKAEuADYEB7YEDzYEEK4EFwYEHVoEHyIAtWVB1bXBFdmVudF8QG0NhY2hlZEluc3VsaW5EZWxpdmVyeU9iamVjdF8QFERvc2luZ0RlY2lzaW9uT2JqZWN0XxAQQ2FjaGVkQ2FyYk9iamVjdF8QE0NhY2hlZEdsdWNvc2VPYmplY3RZUmVzZXJ2b2lyXlNldHRpbmdzT2JqZWN03xAQAFUAVgBXAFgAIQBZAFoAIwBbAFwADgAlAF0AXgAoAF8AYABhACkAKQAUAGUAZgAxACkAYABpAD0AYABsAG0Abl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZV8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc2R1cGxpY2F0ZXNfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zc3RvcmFnZVtfaXNBYnN0cmFjdIAPgDWABIAEgAKAEIEB6oAEgA+BAeyABoAPgQHrgA4IEjwhLX5Xb3JkZXJlZNMAOgA7AA4AcgB0AEyhAHOAEaEAdYASgC1eWERfUFN0ZXJlb3R5cGXZACEAJQB5AA4AKAB6ACMAXwB7AEUAcwBgAH8AFwApADEAbgCDXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgA2AEYAPgDSAAIAECIAT0wA6ADsADgCFAI8ATKkAhgCHAIgAiQCKAIsAjACNAI6AFIAVgBaAF4AYgBmAGoAbgBypAJAAkQCSAJMAlACVAJYAlwCYgB2AIYAigCaAJ4ApgCuALoAygC1fEBNYRFBNQ29tcG91bmRJbmRleGVzXxAQWERfUFNLX2VsZW1lbnRJRF8QGVhEUE1VbmlxdWVuZXNzQ29uc3RyYWludHNfEBpYRF9QU0tfdmVyc2lvbkhhc2hNb2RpZmllcl8QGVhEX1BTS19mZXRjaFJlcXVlc3RzQXJyYXlfEBFYRF9QU0tfaXNBYnN0cmFjdF8QD1hEX1BTS191c2VySW5mb18QE1hEX1BTS19jbGFzc01hcHBpbmdfEBZYRF9QU0tfZW50aXR5Q2xhc3NOYW1l3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcArwAXAHUAbgBuAG4AMQBuALYAhgBuAG4AFwBuVV90eXBlWF9kZWZhdWx0XF9hc3NvY2lhdGlvbltfaXNSZWFkT25seVlfaXNTdGF0aWNZX2lzVW5pcXVlWl9pc0Rlcml2ZWRaX2lzT3JkZXJlZFxfaXNDb21wb3NpdGVXX2lzTGVhZoAAgB6AAIASCAgICIAggBQICIAACNIAOwAOAL0AvqCAH9IAwADBAMIAw1okY2xhc3NuYW1lWCRjbGFzc2VzXk5TTXV0YWJsZUFycmF5owDCAMQAxVdOU0FycmF5WE5TT2JqZWN00gDAAMEAxwDIXxAQWERVTUxQcm9wZXJ0eUltcKQAyQDKAMsAxV8QEFhEVU1MUHJvcGVydHlJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwB1AG4AbgBuADEAbgC2AIcAbgBuABcAboAAgACAAIASCAgICIAggBUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAN0AFwB1AG4AbgBuADEAbgC2AIgAbgBuABcAboAAgCOAAIASCAgICIAggBYICIAACNIAOwAOAOsAvqEA7IAkgB/SADsADgDvAL6hAPCAJYAfU3Jhd98QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwB1AG4AbgBuADEAbgC2AIkAbgBuABcAboAAgACAAIASCAgICIAggBcICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAQQAFwB1AG4AbgBuADEAbgC2AIoAbgBuABcAboAAgCiAAIASCAgICIAggBgICIAACNIAOwAOARIAvqCAH98QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwB1AG4AbgBuADEAbgC2AIsAbgBuABcAboAAgCqAAIASCAgICIAggBkICIAACAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEmABcAdQBuAG4AbgAxAG4AtgCMAG4AbgAXAG6AAIAsgACAEggICAiAIIAaCAiAAAjTADoAOwAOATQBNQBMoKCALdIAwADBATgBOV8QE05TTXV0YWJsZURpY3Rpb25hcnmjATgBOgDFXE5TRGljdGlvbmFyed8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAT0AFwB1AG4AbgBuADEAbgC2AI0AbgBuABcAboAAgC+AAIASCAgICIAggBsICIAACNYAJQAOACgAXwAhACMBSwFMABcAbgAXADGAMIAxgAAIgABfEBRYREdlbmVyaWNSZWNvcmRDbGFzc9IAwADBAVIBU11YRFVNTENsYXNzSW1wpgFUAVUBVgFXAVgAxV1YRFVNTENsYXNzSW1wXxASWERVTUxDbGFzc2lmaWVySW1wXxARWERVTUxOYW1lc3BhY2VJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAVsAFwB1AG4AbgBuADEAbgC2AI4AbgBuABcAboAAgDOAAIASCAgICIAggBwICIAACFouUHVtcEV2ZW500gDAAMEBagFrXxASWERVTUxTdGVyZW90eXBlSW1wpwFsAW0BbgFvAXABcQDFXxASWERVTUxTdGVyZW90eXBlSW1wXVhEVU1MQ2xhc3NJbXBfEBJYRFVNTENsYXNzaWZpZXJJbXBfEBFYRFVNTE5hbWVzcGFjZUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w0wA6ADsADgFzAYUATK8QEQF0AXUBdgDwAXgBeQF6AXsBfAF9AX4BfwGAAYEBggGDAYSANoA3gDiAJYA5gDqAO4A8gD2APoA/gECAQYBCgEOARIBFrxARAYYBhwGIAYkBigGLAYwBjQGOAY8BkAGRAZIBkwGUAZUBloBGgHGAiICfgLeAzoDngQEAgQEYgQEwgQFHgQFegQF2gQGOgQGlgQG8gQHTgC1YZG9zZVR5cGVZYWxhcm1UeXBlVHVuaXRUdHlwZV8QE21vZGlmaWNhdGlvbkNvdW50ZXJXbXV0YWJsZVRkYXRlW2luc3VsaW5UeXBlVXRpdGxlWHVwbG9hZGVkVXZhbHVlWGR1cmF0aW9uXmRlbGl2ZXJlZFVuaXRzWWNyZWF0ZWRBdFlhdXRvbWF0aWNfEBV3YXNQcm9ncmFtbWVkQnlQdW1wVUnfEBIApAClAKYBqQAhAKgAqQGqACMApwGrAKoADgAlAKsArAAoAK0AFwAXABcAKQBFAG4AbgGzADEAbgBgAG4BtwF0AG4AbgG7AG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIANCAiASAiADwiAcIA2CAiARwgSfmAtJtMAOgA7AA4BvwHCAEyiAcABwYBJgEqiAcMBxIBLgF+ALV8QElhEX1BQcm9wU3RlcmVvdHlwZV8QElhEX1BBdHRfU3RlcmVvdHlwZdkAIQAlAckADgAoAcoAIwBfAcsBhgHAAGAAfwAXACkAMQBuAdNfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WARoBJgA+ANIAAgAQIgEzTADoAOwAOAdUB3gBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqAHfAeAB4QHiAeMB5AHlAeaAVYBWgFeAWYBagFyAXYBegC1fEBtYRF9QUFNLX2lzU3RvcmVkSW5UcnV0aEZpbGVfEBtYRF9QUFNLX3ZlcnNpb25IYXNoTW9kaWZpZXJfEBBYRF9QUFNLX3VzZXJJbmZvXxARWERfUFBTS19pc0luZGV4ZWRfEBJYRF9QUFNLX2lzT3B0aW9uYWxfEBpYRF9QUFNLX2lzU3BvdGxpZ2h0SW5kZXhlZF8QEVhEX1BQU0tfZWxlbWVudElEXxATWERfUFBTS19pc1RyYW5zaWVudN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwHDAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIBLCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwHDAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIBLCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAhAAFwHDAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgFiAAIBLCAgICIAggE8ICIAACNMAOgA7AA4CHgIfAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXAcMAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgEsICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXAcMAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAW4AAgEsICAgIgCCAUQgIgAAICd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwHDAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIBLCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwHDAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIBLCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwHDAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIBLCAgICIAggFQICIAACNkAIQAlAm4ADgAoAm8AIwBfAnABhgHBAGAAfwAXACkAMQBuAnhfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WARoBKgA+ANIAAgAQIgGDTADoAOwAOAnoCggBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenAoMChAKFAoYChwKIAomAaIBpgGqAa4BtgG6Ab4AtXxAdWERfUEF0dEtfZGVmYXVsdFZhbHVlQXNTdHJpbmdfEChYRF9QQXR0S19hbGxvd3NFeHRlcm5hbEJpbmFyeURhdGFTdG9yYWdlXxAXWERfUEF0dEtfbWluVmFsdWVTdHJpbmdfEBZYRF9QQXR0S19hdHRyaWJ1dGVUeXBlXxAXWERfUEF0dEtfbWF4VmFsdWVTdHJpbmdfEB1YRF9QQXR0S192YWx1ZVRyYW5zZm9ybWVyTmFtZV8QIFhEX1BBdHRLX3JlZ3VsYXJFeHByZXNzaW9uU3RyaW5n3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXAcQAbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgF8ICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXAcQAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgF8ICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXAcQAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgF8ICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCwQAXAcQAbgBuAG4AMQBuALYCfgBuAG4AFwBugACAbIAAgF8ICAgIgCCAZAgIgAAIEQK83xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXAcQAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgF8ICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXAcQAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgF8ICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXAcQAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgF8ICAgIgCCAZwgIgAAI0gDAAMEC/QL+XVhEUE1BdHRyaWJ1dGWmAv8DAAMBAwIDAwDFXVhEUE1BdHRyaWJ1dGVcWERQTVByb3BlcnR5XxAQWERVTUxQcm9wZXJ0eUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xASAKQApQCmAwUAIQCoAKkDBgAjAKcDBwCqAA4AJQCrAKwAKACtABcAFwAXACkARQBuAG4DDwAxAG4AYABuAbcBdQBuAG4DFwBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASADQgIgHMIgA8IgHCANwgIgHIIEpgKpz7TADoAOwAOAxsDHgBMogHAAcGASYBKogMfAyCAdIB/gC3ZACEAJQMjAA4AKAMkACMAXwMlAYcBwABgAH8AFwApADEAbgMtXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgHGASYAPgDSAAIAECIB10wA6ADsADgMvAzgATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKgDOQM6AzsDPAM9Az4DPwNAgHaAd4B4gHqAe4B8gH2AfoAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXAx8AbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgHQICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXAx8AbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgHQICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcDYgAXAx8AbgBuAG4AMQBuALYB2ABuAG4AFwBugACAeYAAgHQICAgIgCCATwgIgAAI0wA6ADsADgNwA3EATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcDHwBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACAdAgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwIyABcDHwBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIBbgACAdAgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcDHwBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACAdAgICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcDHwBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACAdAgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcDHwBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACAdAgICAiAIIBUCAiAAAjZACEAJQO/AA4AKAPAACMAXwPBAYcBwQBgAH8AFwApADEAbgPJXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgHGASoAPgDSAAIAECICA0wA6ADsADgPLA9MATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpwPUA9UD1gPXA9gD2QPagIGAgoCDgISAhYCGgIeALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwMgAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIB/CAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwMgAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIB/CAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwMgAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIB/CAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAsEAFwMgAG4AbgBuADEAbgC2An4AbgBuABcAboAAgGyAAIB/CAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwMgAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIB/CAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwMgAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIB/CAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwMgAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIB/CAgICIAggGcICIAACN8QEgCkAKUApgRGACEAqACpBEcAIwCnBEgAqgAOACUAqwCsACgArQAXABcAFwApAEUAbgBuBFAAMQBuAGAAbgG3AXYAbgBuBFgAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgA0ICICKCIAPCIBwgDgICICJCBKcRBre0wA6ADsADgRcBF8ATKIBwAHBgEmASqIEYARhgIuAloAt2QAhACUEZAAOACgEZQAjAF8EZgGIAcAAYAB/ABcAKQAxAG4Ebl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYCIgEmAD4A0gACABAiAjNMAOgA7AA4EcAR5AEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoBHoEewR8BH0EfgR/BIAEgYCNgI6Aj4CRgJKAk4CUgJWALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwRgAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAICLCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwRgAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAICLCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXBKMAFwRgAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgJCAAICLCAgICIAggE8ICIAACNMAOgA7AA4EsQSyAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXBGAAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgIsICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXBGAAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAW4AAgIsICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXBGAAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgIsICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXBGAAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgIsICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXBGAAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgIsICAgIgCCAVAgIgAAI2QAhACUFAAAOACgFAQAjAF8FAgGIAcEAYAB/ABcAKQAxAG4FCl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYCIgEqAD4A0gACABAiAl9MAOgA7AA4FDAUUAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6cFFQUWBRcFGAUZBRoFG4CYgJmAmoCbgJyAnYCegC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcEYQBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACAlggICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcEYQBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACAlggICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcEYQBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACAlggICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwLBABcEYQBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIBsgACAlggICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcEYQBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACAlggICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcEYQBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACAlggICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcEYQBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACAlggICAiAIIBnCAiAAAjfEBIApAClAKYFhwAhAKgAqQWIACMApwWJAKoADgAlAKsArAAoAK0AFwAXABcAKQBFAG4AbgWRADEAbgBgAG4BtwDwAG4AbgWZAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIANCAiAoQiADwiAcIAlCAiAoAgSytSO99MAOgA7AA4FnQWgAEyiAcABwYBJgEqiBaEFooCigK2ALdkAIQAlBaUADgAoBaYAIwBfBacBiQHAAGAAfwAXACkAMQBuBa9fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAn4BJgA+ANIAAgAQIgKPTADoAOwAOBbEFugBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqAW7BbwFvQW+Bb8FwAXBBcKApIClgKaAqICpgKqAq4CsgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcFoQBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACAoggICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcFoQBuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACAoggICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwXkABcFoQBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAICngACAoggICAiAIIBPCAiAAAjTADoAOwAOBfIF8wBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwWhAG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAICiCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAFwWhAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAICiCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwWhAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAICiCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwWhAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAICiCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwWhAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAICiCAgICIAggFQICIAACNkAIQAlBkEADgAoBkIAIwBfBkMBiQHBAGAAfwAXACkAMQBuBktfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAn4BKgA+ANIAAgAQIgK7TADoAOwAOBk0GVQBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenBlYGVwZYBlkGWgZbBlyAr4CwgLGAsoC0gLWAtoAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXBaIAbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgK0ICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXBaIAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgK0ICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXBaIAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgK0ICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcGjQAXBaIAbgBuAG4AMQBuALYCfgBuAG4AFwBugACAs4AAgK0ICAgIgCCAZAgIgAAIEQPo3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXBaIAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgK0ICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXBaIAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgK0ICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXBaIAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgK0ICAgIgCCAZwgIgAAI3xASAKQApQCmBskAIQCoAKkGygAjAKcGywCqAA4AJQCrAKwAKACtABcAFwAXACkARQBuAG4G0wAxAG4AYABuAbcBeABuAG4G2wBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASADQgIgLkIgA8IgHCAOQgIgLgIEk3dkmnTADoAOwAOBt8G4gBMogHAAcGASYBKogbjBuSAuoDFgC3ZACEAJQbnAA4AKAboACMAXwbpAYoBwABgAH8AFwApADEAbgbxXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgLeASYAPgDSAAIAECIC70wA6ADsADgbzBvwATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKgG/Qb+Bv8HAAcBBwIHAwcEgLyAvYC+gMCAwYDCgMOAxIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXBuMAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgLoICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXBuMAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgLoICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcHJgAXBuMAbgBuAG4AMQBuALYB2ABuAG4AFwBugACAv4AAgLoICAgIgCCATwgIgAAI0wA6ADsADgc0BzUATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwIyABcG4wBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIBbgACAuggICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwIyABcG4wBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIBbgACAuggICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcG4wBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACAuggICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcG4wBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACAuggICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcG4wBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACAuggICAiAIIBUCAiAAAjZACEAJQeDAA4AKAeEACMAXweFAYoBwQBgAH8AFwApADEAbgeNXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgLeASoAPgDSAAIAECIDG0wA6ADsADgePB5cATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpweYB5kHmgebB5wHnQeegMeAyIDJgMqAy4DMgM2ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwbkAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIDFCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwbkAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIDFCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwbkAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIDFCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAsEAFwbkAG4AbgBuADEAbgC2An4AbgBuABcAboAAgGyAAIDFCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwbkAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIDFCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwbkAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIDFCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwbkAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIDFCAgICIAggGcICIAACN8QEgCkAKUApggKACEAqACpCAsAIwCnCAwAqgAOACUAqwCsACgArQAXABcAFwApAEUAbgBuCBQAMQBuAGAAbgG3AXkAbgBuCBwAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgA0ICIDQCIAPCIBwgDoICIDPCBJ2Axqc0wA6ADsADgggCCMATKIBwAHBgEmASqIIJAglgNGA3IAt2QAhACUIKAAOACgIKQAjAF8IKgGLAcAAYAB/ABcAKQAxAG4IMl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYDOgEmAD4A0gACABAiA0tMAOgA7AA4INAg9AEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoCD4IPwhACEEIQghDCEQIRYDTgNSA1YDXgNiA2YDagNuALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwgkAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIDRCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwgkAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIDRCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXCGcAFwgkAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgNaAAIDRCAgICIAggE8ICIAACNMAOgA7AA4IdQh2AEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXCCQAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgNEICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXCCQAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAKoAAgNEICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXCCQAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgNEICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXCCQAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgNEICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXCCQAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgNEICAgIgCCAVAgIgAAI2QAhACUIxAAOACgIxQAjAF8IxgGLAcEAYAB/ABcAKQAxAG4Izl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYDOgEqAD4A0gACABAiA3dMAOgA7AA4I0AjYAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6cI2QjaCNsI3AjdCN4I34DegOCA4YDigOSA5YDmgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwjjABcIJQBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIDfgACA3AgICAiAIIBhCAiAAAhRMN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwglAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIDcCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwglAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIDcCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXCREAFwglAG4AbgBuADEAbgC2An4AbgBuABcAboAAgOOAAIDcCAgICIAggGQICIAACBEBLN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwglAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIDcCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwglAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIDcCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwglAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIDcCAgICIAggGcICIAACN8QEgCkAKUApglNACEAqACpCU4AIwCnCU8AqgAOACUAqwCsACgArQAXABcAFwApAEUAbgBuCVcAMQBuAGAAbgG3AXoAbgBuCV8Abl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgA0ICIDpCIAPCIBwgDsICIDoCBJdT2Rp0wA6ADsADgljCWYATKIBwAHBgEmASqIJZwlogOqA9YAt2QAhACUJawAOACgJbAAjAF8JbQGMAcAAYAB/ABcAKQAxAG4JdV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYDngEmAD4A0gACABAiA69MAOgA7AA4JdwmAAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoCYEJggmDCYQJhQmGCYcJiIDsgO2A7oDwgPGA8oDzgPSALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwlnAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIDqCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwlnAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIDqCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXCaoAFwlnAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgO+AAIDqCAgICIAggE8ICIAACNMAOgA7AA4JuAm5AEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXCWcAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAW4AAgOoICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXCWcAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAKoAAgOoICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXCWcAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgOoICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXCWcAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgOoICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXCWcAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgOoICAgIgCCAVAgIgAAI2QAhACUKBwAOACgKCAAjAF8KCQGMAcEAYAB/ABcAKQAxAG4KEV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYDngEqAD4A0gACABAiA9tMAOgA7AA4KEwobAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6cKHAodCh4KHwogCiEKIoD3gPmA+oD7gP2A/oD/gC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwomABcJaABuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAID4gACA9QgICAiAIIBhCAiAAAhSTk/fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcJaABuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACA9QgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcJaABuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACA9QgICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwpUABcJaABuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAID8gACA9QgICAiAIIBkCAiAAAgRAyDfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcJaABuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACA9QgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcJaABuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACA9QgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcJaABuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACA9QgICAiAIIBnCAiAAAjfEBIApAClAKYKkAAhAKgAqQqRACMApwqSAKoADgAlAKsArAAoAK0AFwAXABcAKQBFAG4AbgqaADEAbgBgAG4BtwF7AG4AbgqiAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIANCAiBAQIIgA8IgHCAPAgIgQEBCBL3kzok0wA6ADsADgqmCqkATKIBwAHBgEmASqIKqgqrgQEDgQEOgC3ZACEAJQquAA4AKAqvACMAXwqwAY0BwABgAH8AFwApADEAbgq4XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQEAgEmAD4A0gACABAiBAQTTADoAOwAOCroKwwBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqArECsUKxgrHCsgKyQrKCsuBAQWBAQaBAQeBAQmBAQqBAQuBAQyBAQ2ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwqqAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIEBAwgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcKqgBuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBAQMICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcK7QAXCqoAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBAQiAAIEBAwgICAiAIIBPCAiAAAjTADoAOwAOCvsK/ABMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAFwqqAG4AbgBuADEAbgC2AdkAbgBuABcAboAAgFuAAIEBAwgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcKqgBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIAqgACBAQMICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXCqoAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQEDCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwqqAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIEBAwgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcKqgBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBAQMICAgIgCCAVAgIgAAI2QAhACULSgAOACgLSwAjAF8LTAGNAcEAYAB/ABcAKQAxAG4LVF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEBAIBKgA+ANIAAgAQIgQEP0wA6ADsADgtWC14ATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpwtfC2ALYQtiC2MLZAtlgQEQgQERgQESgQETgQEVgQEWgQEXgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcKqwBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACBAQ4ICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXCqsAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQEOCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwqrAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEBDggICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwuWABcKqwBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIEBFIAAgQEOCAgICIAggGQICIAACBEDhN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwqrAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEBDggICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcKqwBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBAQ4ICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXCqsAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQEOCAgICIAggGcICIAACN8QEgCkAKUApgvSACEAqACpC9MAIwCnC9QAqgAOACUAqwCsACgArQAXABcAFwApAEUAbgBuC9wAMQBuAGAAbgG3AXwAbgBuC+QAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgA0ICIEBGgiADwiAcIA9CAiBARkIEtSQ2QjTADoAOwAOC+gL6wBMogHAAcGASYBKogvsC+2BARuBASaALdkAIQAlC/AADgAoC/EAIwBfC/IBjgHAAGAAfwAXACkAMQBuC/pfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBARiASYAPgDSAAIAECIEBHNMAOgA7AA4L/AwFAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoDAYMBwwIDAkMCgwLDAwMDYEBHYEBHoEBH4EBIYEBIoEBI4EBJIEBJYAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXC+wAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQEbCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwvsAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEBGwgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwwvABcL7ABuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEBIIAAgQEbCAgICIAggE8ICIAACNMAOgA7AA4MPQw+AEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXC+wAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQEbCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAFwvsAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEBGwgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcL7ABuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBARsICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXC+wAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQEbCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFwvsAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEBGwgICAiAIIBUCAiAAAjZACEAJQyMAA4AKAyNACMAXwyOAY4BwQBgAH8AFwApADEAbgyWXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQEYgEqAD4A0gACABAiBASfTADoAOwAODJgMoABMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenDKEMogyjDKQMpQymDKeBASiBASmBASqBASuBAS2BAS6BAS+ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXCOMAFwvtAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgN+AAIEBJggICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcL7QBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBASYICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXC+0AbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQEmCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXDNgAFwvtAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQEsgACBASYICAgIgCCAZAgIgAAIEGTfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcL7QBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBASYICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXC+0AbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQEmCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFwvtAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEBJggICAiAIIBnCAiAAAjfEBIApAClAKYNFAAhAKgAqQ0VACMApw0WAKoADgAlAKsArAAoAK0AFwAXABcAKQBFAG4Abg0eADEAbgBgAG4BtwF9AG4Abg0mAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIANCAiBATIIgA8IgHCAPggIgQExCBLqSKrm0wA6ADsADg0qDS0ATKIBwAHBgEmASqINLg0vgQEzgQE+gC3ZACEAJQ0yAA4AKA0zACMAXw00AY8BwABgAH8AFwApADEAbg08XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQEwgEmAD4A0gACABAiBATTTADoAOwAODT4NRwBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqA1IDUkNSg1LDUwNTQ1ODU+BATWBATaBATeBATmBATqBATuBATyBAT2ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFw0uAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIEBMwgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcNLgBuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBATMICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcNcQAXDS4AbgBuAG4AMQBuALYB2ABuAG4AFwBugACBATiAAIEBMwgICAiAIIBPCAiAAAjTADoAOwAODX8NgABMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFw0uAG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIEBMwgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwIyABcNLgBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIBbgACBATMICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXDS4AbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQEzCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFw0uAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIEBMwgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcNLgBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBATMICAgIgCCAVAgIgAAI2QAhACUNzgAOACgNzwAjAF8N0AGPAcEAYAB/ABcAKQAxAG4N2F8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEBMIBKgA+ANIAAgAQIgQE/0wA6ADsADg3aDeIATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpw3jDeQN5Q3mDecN6A3pgQFAgQFBgQFCgQFDgQFEgQFFgQFGgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcNLwBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACBAT4ICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXDS8AbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQE+CAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFw0vAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEBPggICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwLBABcNLwBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIBsgACBAT4ICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXDS8AbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQE+CAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFw0vAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEBPggICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcNLwBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBAT4ICAgIgCCAZwgIgAAI3xASAKQApQCmDlUAIQCoAKkOVgAjAKcOVwCqAA4AJQCrAKwAKACtABcAFwAXACkARQBuAG4OXwAxAG4AYABuAbcBfgBuAG4OZwBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASADQgIgQFJCIAPCIBwgD8ICIEBSAgSNTbGg9MAOgA7AA4Oaw5uAEyiAcABwYBJgEqiDm8OcIEBSoEBVYAt2QAhACUOcwAOACgOdAAjAF8OdQGQAcAAYAB/ABcAKQAxAG4OfV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEBR4BJgA+ANIAAgAQIgQFL0wA6ADsADg5/DogATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKgOiQ6KDosOjA6NDo4Ojw6QgQFMgQFNgQFOgQFQgQFRgQFSgQFTgQFUgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcObwBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBAUoICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXDm8AbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQFKCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXDrIAFw5vAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQFPgACBAUoICAgIgCCATwgIgAAI0wA6ADsADg7ADsEATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwIyABcObwBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIBbgACBAUoICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXDm8AbgBuAG4AMQBuALYB2gBuAG4AFwBugACAKoAAgQFKCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFw5vAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEBSggICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcObwBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBAUoICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXDm8AbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQFKCAgICIAggFQICIAACNkAIQAlDw8ADgAoDxAAIwBfDxEBkAHBAGAAfwAXACkAMQBuDxlfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAUeASoAPgDSAAIAECIEBVtMAOgA7AA4PGw8jAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6cPJA8lDyYPJw8oDykPKoEBV4EBWIEBWYEBWoEBW4EBXIEBXYAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcKJgAXDnAAbgBuAG4AMQBuALYCewBuAG4AFwBugACA+IAAgQFVCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFw5wAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEBVQgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcOcABuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBAVUICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcKVAAXDnAAbgBuAG4AMQBuALYCfgBuAG4AFwBugACA/IAAgQFVCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFw5wAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEBVQgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcOcABuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBAVUICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXDnAAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQFVCAgICIAggGcICIAACN8QEgCkAKUApg+WACEAqACpD5cAIwCnD5gAqgAOACUAqwCsACgArQAXABcAFwApAEUAbgBuD6AAMQBuAGAAbgG3AX8AbgBuD6gAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgA0ICIEBYAiADwiAcIBACAiBAV8IEtr4Iu7TADoAOwAOD6wPrwBMogHAAcGASYBKog+wD7GBAWGBAWyALdkAIQAlD7QADgAoD7UAIwBfD7YBkQHAAGAAfwAXACkAMQBuD75fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAV6ASYAPgDSAAIAECIEBYtMAOgA7AA4PwA/JAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoD8oPyw/MD80Pzg/PD9AP0YEBY4EBZIEBZYEBZ4EBaIEBaYEBaoEBa4At3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXD7AAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQFhCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFw+wAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEBYQgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFw/zABcPsABuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEBZoAAgQFhCAgICIAggE8ICIAACNMAOgA7AA4QARACAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXD7AAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQFhCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAFw+wAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEBYQgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcPsABuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBAWEICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXD7AAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQFhCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFw+wAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEBYQgICAiAIIBUCAiAAAjZACEAJRBQAA4AKBBRACMAXxBSAZEBwQBgAH8AFwApADEAbhBaXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQFegEqAD4A0gACABAiBAW3TADoAOwAOEFwQZABMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenEGUQZhBnEGgQaRBqEGuBAW6BAW+BAXCBAXGBAXOBAXSBAXWALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFw+xAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEBbAgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcPsQBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBAWwICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXD7EAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQFsCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXEJwAFw+xAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQFygACBAWwICAgIgCCAZAgIgAAIEQH03xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXD7EAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQFsCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFw+xAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEBbAgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcPsQBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBAWwICAgIgCCAZwgIgAAI3xASAKQApQCmENgAIQCoAKkQ2QAjAKcQ2gCqAA4AJQCrAKwAKACtABcAFwAXACkARQBuAG4Q4gAxAG4AYABuAbcBgABuAG4Q6gBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASADQgIgQF4CIAPCIBwgEEICIEBdwgTAAAAAQGtVOnTADoAOwAOEO4Q8QBMogHAAcGASYBKohDyEPOBAXmBAYSALdkAIQAlEPYADgAoEPcAIwBfEPgBkgHAAGAAfwAXACkAMQBuEQBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAXaASYAPgDSAAIAECIEBetMAOgA7AA4RAhELAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoEQwRDREOEQ8REBERERIRE4EBe4EBfIEBfYEBf4EBgIEBgYEBgoEBg4At3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXEPIAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQF5CAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxDyAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEBeQgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFxE1ABcQ8gBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEBfoAAgQF5CAgICIAggE8ICIAACNMAOgA7AA4RQxFEAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXEPIAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQF5CAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxDyAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEBeQgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcQ8gBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBAXkICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXEPIAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQF5CAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxDyAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEBeQgICAiAIIBUCAiAAAjZACEAJRGSAA4AKBGTACMAXxGUAZIBwQBgAH8AFwApADEAbhGcXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQF2gEqAD4A0gACABAiBAYXTADoAOwAOEZ4RpgBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenEacRqBGpEaoRqxGsEa2BAYaBAYiBAYmBAYqBAYuBAYyBAY2ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXEbEAFxDzAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgQGHgACBAYQICAgIgCCAYQgIgAAIUzAuMN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxDzAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEBhAgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwjjABcQ8wBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIDfgACBAYQICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcQnAAXEPMAbgBuAG4AMQBuALYCfgBuAG4AFwBugACBAXKAAIEBhAgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcQ8wBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBAYQICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXEPMAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQGECAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxDzAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEBhAgICAiAIIBnCAiAAAjfEBIApAClAKYSGgAhAKgAqRIbACMApxIcAKoADgAlAKsArAAoAK0AFwAXABcAKQBFAG4AbhIkADEAbgBgAG4BtwGBAG4AbhIsAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIANCAiBAZAIgA8IgHCAQggIgQGPCBJbbEfo0wA6ADsADhIwEjMATKIBwAHBgEmASqISNBI1gQGRgQGcgC3ZACEAJRI4AA4AKBI5ACMAXxI6AZMBwABgAH8AFwApADEAbhJCXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQGOgEmAD4A0gACABAiBAZLTADoAOwAOEkQSTQBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqBJOEk8SUBJRElISUxJUElWBAZOBAZSBAZWBAZeBAZiBAZmBAZqBAZuALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxI0AG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIEBkQgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcSNABuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBAZEICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcSdwAXEjQAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBAZaAAIEBkQgICAiAIIBPCAiAAAjTADoAOwAOEoUShgBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxI0AG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIEBkQgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwIyABcSNABuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIBbgACBAZEICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXEjQAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQGRCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxI0AG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIEBkQgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcSNABuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBAZEICAgIgCCAVAgIgAAI2QAhACUS1AAOACgS1QAjAF8S1gGTAcEAYAB/ABcAKQAxAG4S3l8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEBjoBKgA+ANIAAgAQIgQGd0wA6ADsADhLgEugATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpxLpEuoS6xLsEu0S7hLvgQGegQGfgQGggQGhgQGigQGjgQGkgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcSNQBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACBAZwICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXEjUAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQGcCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxI1AG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEBnAgICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFxCcABcSNQBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIEBcoAAgQGcCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxI1AG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEBnAgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcSNQBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBAZwICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXEjUAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQGcCAgICIAggGcICIAACN8QEgCkAKUAphNbACEAqACpE1wAIwCnE10AqgAOACUAqwCsACgArQAXABcAFwApAEUAbgBuE2UAMQBuAGAAbgG3AYIAbgBuE20Abl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgA0ICIEBpwiADwiAcIBDCAiBAaYIEjYU5C/TADoAOwAOE3ETdABMogHAAcGASYBKohN1E3aBAaiBAbOALdkAIQAlE3kADgAoE3oAIwBfE3sBlAHAAGAAfwAXACkAMQBuE4NfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAaWASYAPgDSAAIAECIEBqdMAOgA7AA4ThROOAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoE48TkBORE5ITkxOUE5UTloEBqoEBq4EBrIEBroEBr4EBsIEBsYEBsoAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXE3UAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQGoCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxN1AG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEBqAgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFxO4ABcTdQBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEBrYAAgQGoCAgICIAggE8ICIAACNMAOgA7AA4TxhPHAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXE3UAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQGoCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxN1AG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEBqAgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcTdQBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBAagICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXE3UAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQGoCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxN1AG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEBqAgICAiAIIBUCAiAAAjZACEAJRQVAA4AKBQWACMAXxQXAZQBwQBgAH8AFwApADEAbhQfXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQGlgEqAD4A0gACABAiBAbTTADoAOwAOFCEUKQBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenFCoUKxQsFC0ULhQvFDCBAbWBAbaBAbeBAbiBAbmBAbqBAbuALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxN2AG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEBswgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcTdgBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBAbMICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXE3YAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQGzCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXC5YAFxN2AG4AbgBuADEAbgC2An4AbgBuABcAboAAgQEUgACBAbMICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXE3YAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQGzCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxN2AG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEBswgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcTdgBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBAbMICAgIgCCAZwgIgAAI3xASAKQApQCmFJwAIQCoAKkUnQAjAKcUngCqAA4AJQCrAKwAKACtABcAFwAXACkARQBuAG4UpgAxAG4AYABuAbcBgwBuAG4UrgBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASADQgIgQG+CIAPCIBwgEQICIEBvQgSVQksO9MAOgA7AA4UshS1AEyiAcABwYBJgEqiFLYUt4EBv4EByoAt2QAhACUUugAOACgUuwAjAF8UvAGVAcAAYAB/ABcAKQAxAG4UxF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEBvIBJgA+ANIAAgAQIgQHA0wA6ADsADhTGFM8ATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKgU0BTRFNIU0xTUFNUU1hTXgQHBgQHCgQHDgQHFgQHGgQHHgQHIgQHJgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcUtgBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBAb8ICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXFLYAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQG/CAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXFPkAFxS2AG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQHEgACBAb8ICAgIgCCATwgIgAAI0wA6ADsADhUHFQgATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcUtgBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBAb8ICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXFLYAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAW4AAgQG/CAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxS2AG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEBvwgICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcUtgBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBAb8ICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXFLYAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQG/CAgICIAggFQICIAACNkAIQAlFVYADgAoFVcAIwBfFVgBlQHBAGAAfwAXACkAMQBuFWBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAbyASoAPgDSAAIAECIEBy9MAOgA7AA4VYhVqAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6cVaxVsFW0VbhVvFXAVcYEBzIEBzYEBzoEBz4EB0IEB0YEB0oAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXFLcAbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgQHKCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxS3AG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEByggICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcUtwBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBAcoICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcKVAAXFLcAbgBuAG4AMQBuALYCfgBuAG4AFwBugACA/IAAgQHKCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxS3AG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEByggICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcUtwBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBAcoICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXFLcAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQHKCAgICIAggGcICIAACN8QEgCkAKUAphXdACEAqACpFd4AIwCnFd8AqgAOACUAqwCsACgArQAXABcAFwApAEUAbgBuFecAMQBuAGAAbgG3AYQAbgBuFe8Abl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgA0ICIEB1QiADwiAcIBFCAiBAdQIEu5MpoDTADoAOwAOFfMV9gBMogHAAcGASYBKohX3FfiBAdaBAeGALdkAIQAlFfsADgAoFfwAIwBfFf0BlgHAAGAAfwAXACkAMQBuFgVfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAdOASYAPgDSAAIAECIEB19MAOgA7AA4WBxYQAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoFhEWEhYTFhQWFRYWFhcWGIEB2IEB2YEB2oEB3IEB3YEB3oEB34EB4IAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXFfcAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQHWCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxX3AG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEB1ggICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFxY6ABcV9wBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEB24AAgQHWCAgICIAggE8ICIAACNMAOgA7AA4WSBZJAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXFfcAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQHWCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAFxX3AG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEB1ggICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcV9wBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBAdYICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXFfcAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQHWCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxX3AG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEB1ggICAiAIIBUCAiAAAjZACEAJRaXAA4AKBaYACMAXxaZAZYBwQBgAH8AFwApADEAbhahXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQHTgEqAD4A0gACABAiBAeLTADoAOwAOFqMWqwBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenFqwWrRauFq8WsBaxFrKBAeOBAeSBAeWBAeaBAeeBAeiBAemALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxX4AG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEB4QgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcV+ABuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBAeEICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXFfgAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQHhCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXClQAFxX4AG4AbgBuADEAbgC2An4AbgBuABcAboAAgPyAAIEB4QgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcV+ABuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBAeEICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXFfgAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQHhCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxX4AG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEB4QgICAiAIIBnCAiAAAhaZHVwbGljYXRlc9IAOwAOFx8AvqCAH9IAwADBFyIXI1pYRFBNRW50aXR5pxckFyUXJhcnFygXKQDFWlhEUE1FbnRpdHldWERVTUxDbGFzc0ltcF8QElhEVU1MQ2xhc3NpZmllckltcF8QEVhEVU1MTmFtZXNwYWNlSW1wXxAUWERVTUxOYW1lZEVsZW1lbnRJbXBfEA9YRFVNTEVsZW1lbnRJbXDfEBAXKxcsFy0XLgAhFy8XMAAjFzEXMgAOACUXMxc0ACgAXwBgFzYAKQApABQXOgBmADEAKQBgAGkAPgBgF0EXQgBuXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlgA+BAgSABIAEgAKBAe+BAeqABIAPgQHsgAeAD4EDzIEB7ggSY+Tmd9MAOgA7AA4XRhdIAEyhAHOAEaEXSYEB8IAt2QAhACUXTAAOACgXTQAjAF8XTgBGAHMAYAB/ABcAKQAxAG4XVl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEB7YARgA+ANIAAgAQIgQHx0wA6ADsADhdYF2IATKkAhgCHAIgAiQCKAIsAjACNAI6AFIAVgBaAF4AYgBmAGoAbgBypF2MXZBdlF2YXZxdoF2kXahdrgQHygQH0gQH1gQH7gQH8gQH+gQH/gQIBgQICgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFxdvABcXSQBuAG4AbgAxAG4AtgCGAG4AbgAXAG6AAIEB84AAgQHwCAgICIAggBQICIAACNIAOwAOF30AvqCAH98QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxdJAG4AbgBuADEAbgC2AIcAbgBuABcAboAAgACAAIEB8AgICAiAIIAVCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFxeQABcXSQBuAG4AbgAxAG4AtgCIAG4AbgAXAG6AAIEB9oAAgQHwCAgICIAggBYICIAACNIAOwAOF54AvqIXnxeggQH3gQH5gB/SADsADhejAL6hF6SBAfiAH1R1dWlk0gA7AA4XqAC+oRepgQH6gB9ec3luY0lkZW50aWZpZXLfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcXSQBuAG4AbgAxAG4AtgCJAG4AbgAXAG6AAIAAgACBAfAICAgIgCCAFwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcXvQAXF0kAbgBuAG4AMQBuALYAigBuAG4AFwBugACBAf2AAIEB8AgICAiAIIAYCAiAAAjSADsADhfLAL6ggB/fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcXSQBuAG4AbgAxAG4AtgCLAG4AbgAXAG6AAIAqgACBAfAICAgIgCCAGQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcX3gAXF0kAbgBuAG4AMQBuALYAjABuAG4AFwBugACBAgCAAIEB8AgICAiAIIAaCAiAAAjTADoAOwAOF+wX7QBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAT0AFxdJAG4AbgBuADEAbgC2AI0AbgBuABcAboAAgC+AAIEB8AgICAiAIIAbCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFxgAABcXSQBuAG4AbgAxAG4AtgCOAG4AbgAXAG6AAIECA4AAgQHwCAgICIAggBwICIAACF8QHC5DYWNoZWRJbnN1bGluRGVsaXZlcnlPYmplY3TTADoAOwAOGA8YIwBMrxATGBAYERgSF6QYFBgVGBYYFxgYGBkYGhgbGBwBfxgeGB8BghghGCKBAgWBAgaBAgeBAfiBAgiBAgmBAgqBAguBAgyBAg2BAg6BAg+BAhCAQIECEYECEoBDgQITgQIUrxATGCQYJRgmGCcYKBgpGCoYKxgsGC0YLhgvGDAYMRgyGDMYNBg1GDaBAhWBAi2BAkSBAluBAnOBAoqBAqGBAriBAs+BAuaBAv2BAxSBAyuBA0KBA1mBA3CBA4eBA56BA7WALV8QF3Byb2dyYW1tZWRUZW1wQmFzYWxSYXRlWXN0YXJ0RGF0ZV8QE2F1dG9tYXRpY2FsbHlJc3N1ZWRfEBV3YXNQcm9ncmFtbWVkQnlQdW1wVUlZaXNNdXRhYmxlWWlzU3VzcGVuZFdlbmREYXRlXxATbW9kaWZpY2F0aW9uQ291bnRlcltpbnN1bGluVHlwZV8QD21hbnVhbGx5RW50ZXJlZF5zeW5jSWRlbnRpZmllclZyZWFzb25fEBBoYXNMb29wS2l0T3JpZ2luXxAUcHJvdmVuYW5jZUlkZW50aWZpZXJZZGVsZXRlZEF0XxASc2NoZWR1bGVkQmFzYWxSYXRl3xASAKQApQCmGEkAIQCoAKkYSgAjAKcYSwCqAA4AJQCrAKwAKACtABcAFwAXACkARgBuAG4YUwAxAG4AYABuAbcYEABuAG4YWwBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAe0ICIECFwiADwiAcIECBQgIgQIWCBJhI8Gd0wA6ADsADhhfGGIATKIBwAHBgEmASqIYYxhkgQIYgQIkgC3ZACEAJRhnAA4AKBhoACMAXxhpGCQBwABgAH8AFwApADEAbhhxXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQIVgEmAD4A0gACABAiBAhnTADoAOwAOGHMYfABMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqBh9GH4YfxiAGIEYghiDGISBAhqBAhuBAhyBAh6BAh+BAiCBAiGBAiOALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxhjAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIECGAgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcYYwBuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBAhgICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcYpgAXGGMAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBAh2AAIECGAgICAiAIIBPCAiAAAjTADoAOwAOGLQYtQBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxhjAG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIECGAgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwIyABcYYwBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIBbgACBAhgICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXGGMAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQIYCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXGOYAFxhjAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgQIigACBAhgICAgIgCCAUwgIgAAIXxAWc2NoZWR1bGVkVGVtcEJhc2FsUmF0Zd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxhjAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIECGAgICAiAIIBUCAiAAAjZACEAJRkEAA4AKBkFACMAXxkGGCQBwQBgAH8AFwApADEAbhkOXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQIVgEqAD4A0gACABAiBAiXTADoAOwAOGRAZGABMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenGRkZGhkbGRwZHRkeGR+BAiaBAieBAiiBAimBAiqBAiuBAiyALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxhkAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIECJAgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcYZABuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBAiQICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXGGQAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQIkCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXEJwAFxhkAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQFygACBAiQICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXGGQAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQIkCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxhkAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIECJAgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcYZABuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBAiQICAgIgCCAZwgIgAAI3xASAKQApQCmGYsAIQCoAKkZjAAjAKcZjQCqAA4AJQCrAKwAKACtABcAFwAXACkARgBuAG4ZlQAxAG4AYABuAbcYEQBuAG4ZnQBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAe0ICIECLwiADwiAcIECBggIgQIuCBItOTlo0wA6ADsADhmhGaQATKIBwAHBgEmASqIZpRmmgQIwgQI7gC3ZACEAJRmpAA4AKBmqACMAXxmrGCUBwABgAH8AFwApADEAbhmzXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQItgEmAD4A0gACABAiBAjHTADoAOwAOGbUZvgBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqBm/GcAZwRnCGcMZxBnFGcaBAjKBAjOBAjSBAjaBAjeBAjiBAjmBAjqALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxmlAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIECMAgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcZpQBuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBAjAICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcZ6AAXGaUAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBAjWAAIECMAgICAiAIIBPCAiAAAjTADoAOwAOGfYZ9wBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxmlAG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIECMAgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcZpQBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIAqgACBAjAICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXGaUAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQIwCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxmlAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIECMAgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcZpQBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBAjAICAgIgCCAVAgIgAAI2QAhACUaRQAOACgaRgAjAF8aRxglAcEAYAB/ABcAKQAxAG4aT18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECLYBKgA+ANIAAgAQIgQI80wA6ADsADhpRGlkATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpxpaGlsaXBpdGl4aXxpggQI9gQI+gQI/gQJAgQJBgQJCgQJDgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcZpgBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACBAjsICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXGaYAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQI7CAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxmmAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIECOwgICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwuWABcZpgBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIEBFIAAgQI7CAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxmmAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIECOwgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcZpgBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBAjsICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXGaYAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQI7CAgICIAggGcICIAACN8QEgCkAKUAphrMACEAqACpGs0AIwCnGs4AqgAOACUAqwCsACgArQAXABcAFwApAEYAbgBuGtYAMQBuAGAAbgG3GBIAbgBuGt4Abl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQHtCAiBAkYIgA8IgHCBAgcICIECRQgS2Mf6ptMAOgA7AA4a4hrlAEyiAcABwYBJgEqiGuYa54ECR4ECUoAt2QAhACUa6gAOACga6wAjAF8a7BgmAcAAYAB/ABcAKQAxAG4a9F8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECRIBJgA+ANIAAgAQIgQJI0wA6ADsADhr2Gv8ATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKgbABsBGwIbAxsEGwUbBhsHgQJJgQJKgQJLgQJNgQJOgQJPgQJQgQJRgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABca5gBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBAkcICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXGuYAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQJHCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXGykAFxrmAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQJMgACBAkcICAgIgCCATwgIgAAI0wA6ADsADhs3GzgATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABca5gBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBAkcICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXGuYAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAW4AAgQJHCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxrmAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIECRwgICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABca5gBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBAkcICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXGuYAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQJHCAgICIAggFQICIAACNkAIQAlG4YADgAoG4cAIwBfG4gYJgHBAGAAfwAXACkAMQBuG5BfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAkSASoAPgDSAAIAECIECU9MAOgA7AA4bkhuaAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6cbmxucG50bnhufG6AboYECVIECVYECVoECV4ECWIECWYECWoAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXGucAbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgQJSCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxrnAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIECUggICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABca5wBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBAlIICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcKVAAXGucAbgBuAG4AMQBuALYCfgBuAG4AFwBugACA/IAAgQJSCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxrnAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIECUggICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABca5wBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBAlIICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXGucAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQJSCAgICIAggGcICIAACN8QEgCkAKUAphwNACEAqACpHA4AIwCnHA8AqgAOACUAqwCsACgArQAXABcAFwApAEYAbgBuHBcAMQBuAGAAbgG3F6QAbgBuHB8Abl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQHtCAiBAl0IgA8IgHCBAfgICIECXAgSiplCH9MAOgA7AA4cIxwmAEyiAcABwYBJgEqiHCccKIECXoECaYAt2QAhACUcKwAOACgcLAAjAF8cLRgnAcAAYAB/ABcAKQAxAG4cNV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECW4BJgA+ANIAAgAQIgQJf0wA6ADsADhw3HEAATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKgcQRxCHEMcRBxFHEYcRxxIgQJggQJhgQJigQJkgQJlgQJmgQJngQJogC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABccJwBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBAl4ICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXHCcAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQJeCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXHGoAFxwnAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQJjgACBAl4ICAgIgCCATwgIgAAI0wA6ADsADhx4HHkATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwIyABccJwBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIBbgACBAl4ICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXHCcAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAW4AAgQJeCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxwnAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIECXggICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABccJwBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBAl4ICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXHCcAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQJeCAgICIAggFQICIAACNkAIQAlHMcADgAoHMgAIwBfHMkYJwHBAGAAfwAXACkAMQBuHNFfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAluASoAPgDSAAIAECIECatMAOgA7AA4c0xzbAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6cc3BzdHN4c3xzgHOEc4oECa4ECbIECbYECboECcIECcYECcoAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXHCgAbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgQJpCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFxwoAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIECaQgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABccKABuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBAmkICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcdEwAXHCgAbgBuAG4AMQBuALYCfgBuAG4AFwBugACBAm+AAIECaQgICAiAIIBkCAiAAAgRBEzfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABccKABuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBAmkICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXHCgAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQJpCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFxwoAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIECaQgICAiAIIBnCAiAAAjfEBIApAClAKYdTwAhAKgAqR1QACMApx1RAKoADgAlAKsArAAoAK0AFwAXABcAKQBGAG4Abh1ZADEAbgBgAG4BtxgUAG4Abh1hAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEB7QgIgQJ1CIAPCIBwgQIICAiBAnQIEu9EdxfTADoAOwAOHWUdaABMogHAAcGASYBKoh1pHWqBAnaBAoGALdkAIQAlHW0ADgAoHW4AIwBfHW8YKAHAAGAAfwAXACkAMQBuHXdfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAnOASYAPgDSAAIAECIECd9MAOgA7AA4deR2CAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoHYMdhB2FHYYdhx2IHYkdioECeIECeYECeoECfIECfYECfoECf4ECgIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXHWkAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQJ2CAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFx1pAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIECdggICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFx2sABcdaQBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIECe4AAgQJ2CAgICIAggE8ICIAACNMAOgA7AA4duh27AEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXHWkAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQJ2CAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAFx1pAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIECdggICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcdaQBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBAnYICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXHWkAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQJ2CAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFx1pAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIECdggICAiAIIBUCAiAAAjZACEAJR4JAA4AKB4KACMAXx4LGCgBwQBgAH8AFwApADEAbh4TXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQJzgEqAD4A0gACABAiBAoLTADoAOwAOHhUeHQBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenHh4eHx4gHiEeIh4jHiSBAoOBAoSBAoWBAoaBAoeBAoiBAomALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFx1qAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIECgQgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcdagBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBAoEICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXHWoAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQKBCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXClQAFx1qAG4AbgBuADEAbgC2An4AbgBuABcAboAAgPyAAIECgQgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcdagBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBAoEICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXHWoAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQKBCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFx1qAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIECgQgICAiAIIBnCAiAAAjfEBIApAClAKYekAAhAKgAqR6RACMApx6SAKoADgAlAKsArAAoAK0AFwAXABcAKQBGAG4Abh6aADEAbgBgAG4BtxgVAG4Abh6iAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEB7QgIgQKMCIAPCIBwgQIJCAiBAosIElcOLmXTADoAOwAOHqYeqQBMogHAAcGASYBKoh6qHquBAo2BApiALdkAIQAlHq4ADgAoHq8AIwBfHrAYKQHAAGAAfwAXACkAMQBuHrhfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAoqASYAPgDSAAIAECIECjtMAOgA7AA4euh7DAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoHsQexR7GHsceyB7JHsoey4ECj4ECkIECkYECk4EClIEClYECloECl4At3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXHqoAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQKNCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFx6qAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIECjQgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFx7tABceqgBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIECkoAAgQKNCAgICIAggE8ICIAACNMAOgA7AA4e+x78AEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXHqoAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQKNCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFx6qAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIECjQgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABceqgBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBAo0ICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXHqoAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQKNCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFx6qAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIECjQgICAiAIIBUCAiAAAjZACEAJR9KAA4AKB9LACMAXx9MGCkBwQBgAH8AFwApADEAbh9UXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQKKgEqAD4A0gACABAiBApnTADoAOwAOH1YfXgBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenH18fYB9hH2IfYx9kH2WBApqBApuBApyBAp2BAp6BAp+BAqCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXCiYAFx6rAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgPiAAIECmAgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABceqwBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBApgICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXHqsAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQKYCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXClQAFx6rAG4AbgBuADEAbgC2An4AbgBuABcAboAAgPyAAIECmAgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABceqwBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBApgICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXHqsAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQKYCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFx6rAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIECmAgICAiAIIBnCAiAAAjfEBIApAClAKYf0QAhAKgAqR/SACMApx/TAKoADgAlAKsArAAoAK0AFwAXABcAKQBGAG4Abh/bADEAbgBgAG4BtxgWAG4Abh/jAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEB7QgIgQKjCIAPCIBwgQIKCAiBAqIIEwAAAAEexnJY0wA6ADsADh/nH+oATKIBwAHBgEmASqIf6x/sgQKkgQKvgC3ZACEAJR/vAA4AKB/wACMAXx/xGCoBwABgAH8AFwApADEAbh/5XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQKhgEmAD4A0gACABAiBAqXTADoAOwAOH/sgBABMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqCAFIAYgByAIIAkgCiALIAyBAqaBAqeBAqiBAqqBAquBAqyBAq2BAq6ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFx/rAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIECpAgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcf6wBuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBAqQICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcgLgAXH+sAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBAqmAAIECpAgICAiAIIBPCAiAAAjTADoAOwAOIDwgPQBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFx/rAG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIECpAgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcf6wBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIAqgACBAqQICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXH+sAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQKkCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFx/rAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIECpAgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcf6wBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBAqQICAgIgCCAVAgIgAAI2QAhACUgiwAOACggjAAjAF8gjRgqAcEAYAB/ABcAKQAxAG4glV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECoYBKgA+ANIAAgAQIgQKw0wA6ADsADiCXIJ8ATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpyCgIKEgoiCjIKQgpSCmgQKxgQKygQKzgQK0gQK1gQK2gQK3gC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwomABcf7ABuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAID4gACBAq8ICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXH+wAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQKvCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFx/sAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIECrwgICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwpUABcf7ABuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAID8gACBAq8ICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXH+wAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQKvCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFx/sAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIECrwgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcf7ABuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBAq8ICAgIgCCAZwgIgAAI3xASAKQApQCmIRIAIQCoAKkhEwAjAKchFACqAA4AJQCrAKwAKACtABcAFwAXACkARgBuAG4hHAAxAG4AYABuAbcYFwBuAG4hJABuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAe0ICIECugiADwiAcIECCwgIgQK5CBK/RitY0wA6ADsADiEoISsATKIBwAHBgEmASqIhLCEtgQK7gQLGgC3ZACEAJSEwAA4AKCExACMAXyEyGCsBwABgAH8AFwApADEAbiE6XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQK4gEmAD4A0gACABAiBArzTADoAOwAOITwhRQBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqCFGIUchSCFJIUohSyFMIU2BAr2BAr6BAr+BAsGBAsKBAsOBAsSBAsWALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFyEsAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIECuwgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABchLABuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBArsICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABchbwAXISwAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBAsCAAIECuwgICAiAIIBPCAiAAAjTADoAOwAOIX0hfgBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFyEsAG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIECuwgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABchLABuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIAqgACBArsICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXISwAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQK7CAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyEsAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIECuwgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABchLABuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBArsICAgIgCCAVAgIgAAI2QAhACUhzAAOACghzQAjAF8hzhgrAcEAYAB/ABcAKQAxAG4h1l8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECuIBKgA+ANIAAgAQIgQLH0wA6ADsADiHYIeAATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpyHhIeIh4yHkIeUh5iHngQLIgQLJgQLKgQLLgQLMgQLNgQLOgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABchLQBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACBAsYICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXIS0AbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQLGCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyEtAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIECxggICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwuWABchLQBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIEBFIAAgQLGCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyEtAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIECxggICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABchLQBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBAsYICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXIS0AbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQLGCAgICIAggGcICIAACN8QEgCkAKUApiJTACEAqACpIlQAIwCnIlUAqgAOACUAqwCsACgArQAXABcAFwApAEYAbgBuIl0AMQBuAGAAbgG3GBgAbgBuImUAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQHtCAiBAtEIgA8IgHCBAgwICIEC0AgS2bT0WdMAOgA7AA4iaSJsAEyiAcABwYBJgEqiIm0iboEC0oEC3YAt2QAhACUicQAOACgicgAjAF8icxgsAcAAYAB/ABcAKQAxAG4ie18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECz4BJgA+ANIAAgAQIgQLT0wA6ADsADiJ9IoYATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKgihyKIIokiiiKLIowijSKOgQLUgQLVgQLWgQLYgQLZgQLagQLbgQLcgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcibQBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBAtIICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXIm0AbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQLSCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXIrAAFyJtAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQLXgACBAtIICAgIgCCATwgIgAAI0wA6ADsADiK+Ir8ATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcibQBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBAtIICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXIm0AbgBuAG4AMQBuALYB2gBuAG4AFwBugACAKoAAgQLSCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFyJtAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEC0ggICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcibQBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBAtIICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXIm0AbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQLSCAgICIAggFQICIAACNkAIQAlIw0ADgAoIw4AIwBfIw8YLAHBAGAAfwAXACkAMQBuIxdfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAs+ASoAPgDSAAIAECIEC3tMAOgA7AA4jGSMhAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6cjIiMjIyQjJSMmIycjKIEC34EC4IEC4YEC4oEC44EC5IEC5YAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcI4wAXIm4AbgBuAG4AMQBuALYCewBuAG4AFwBugACA34AAgQLdCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFyJuAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEC3QgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcibgBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBAt0ICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcJEQAXIm4AbgBuAG4AMQBuALYCfgBuAG4AFwBugACA44AAgQLdCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyJuAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEC3QgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcibgBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBAt0ICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXIm4AbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQLdCAgICIAggGcICIAACN8QEgCkAKUApiOUACEAqACpI5UAIwCnI5YAqgAOACUAqwCsACgArQAXABcAFwApAEYAbgBuI54AMQBuAGAAbgG3GBkAbgBuI6YAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQHtCAiBAugIgA8IgHCBAg0ICIEC5wgTAAAAAQX2mYbTADoAOwAOI6ojrQBMogHAAcGASYBKoiOuI6+BAumBAvSALdkAIQAlI7IADgAoI7MAIwBfI7QYLQHAAGAAfwAXACkAMQBuI7xfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAuaASYAPgDSAAIAECIEC6tMAOgA7AA4jviPHAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoI8gjySPKI8sjzCPNI84jz4EC64EC7IEC7YEC74EC8IEC8YEC8oEC84At3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXI64AbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQLpCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyOuAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEC6QgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFyPxABcjrgBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEC7oAAgQLpCAgICIAggE8ICIAACNMAOgA7AA4j/yQAAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXI64AbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQLpCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAFyOuAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEC6QgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcjrgBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBAukICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXI64AbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQLpCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFyOuAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEC6QgICAiAIIBUCAiAAAjZACEAJSROAA4AKCRPACMAXyRQGC0BwQBgAH8AFwApADEAbiRYXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQLmgEqAD4A0gACABAiBAvXTADoAOwAOJFokYgBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenJGMkZCRlJGYkZyRoJGmBAvaBAveBAviBAvmBAvqBAvuBAvyALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXEbEAFyOvAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgQGHgACBAvQICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXI68AbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQL0CAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyOvAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEC9AgICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwzYABcjrwBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIEBLIAAgQL0CAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyOvAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEC9AgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcjrwBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBAvQICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXI68AbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQL0CAgICIAggGcICIAACN8QEgCkAKUApiTVACEAqACpJNYAIwCnJNcAqgAOACUAqwCsACgArQAXABcAFwApAEYAbgBuJN8AMQBuAGAAbgG3GBoAbgBuJOcAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQHtCAiBAv8IgA8IgHCBAg4ICIEC/ggTAAAAAR/4mKrTADoAOwAOJOsk7gBMogHAAcGASYBKoiTvJPCBAwCBAwuALdkAIQAlJPMADgAoJPQAIwBfJPUYLgHAAGAAfwAXACkAMQBuJP1fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAv2ASYAPgDSAAIAECIEDAdMAOgA7AA4k/yUIAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoJQklCiULJQwlDSUOJQ8lEIEDAoEDA4EDBIEDBoEDB4EDCIEDCYEDCoAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXJO8AbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQMACAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyTvAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEDAAgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFyUyABck7wBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEDBYAAgQMACAgICIAggE8ICIAACNMAOgA7AA4lQCVBAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXJO8AbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQMACAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFyTvAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEDAAgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABck7wBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBAwAICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXJO8AbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQMACAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFyTvAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEDAAgICAiAIIBUCAiAAAjZACEAJSWPAA4AKCWQACMAXyWRGC4BwQBgAH8AFwApADEAbiWZXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQL9gEqAD4A0gACABAiBAwzTADoAOwAOJZslowBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenJaQlpSWmJaclqCWpJaqBAw2BAw6BAw+BAxCBAxGBAxKBAxOALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXCiYAFyTwAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgPiAAIEDCwgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABck8ABuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBAwsICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXJPAAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQMLCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXClQAFyTwAG4AbgBuADEAbgC2An4AbgBuABcAboAAgPyAAIEDCwgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABck8ABuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBAwsICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXJPAAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQMLCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyTwAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEDCwgICAiAIIBnCAiAAAjfEBIApAClAKYmFgAhAKgAqSYXACMApyYYAKoADgAlAKsArAAoAK0AFwAXABcAKQBGAG4AbiYgADEAbgBgAG4BtxgbAG4AbiYoAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEB7QgIgQMWCIAPCIBwgQIPCAiBAxUIEpga2gTTADoAOwAOJiwmLwBMogHAAcGASYBKoiYwJjGBAxeBAyKALdkAIQAlJjQADgAoJjUAIwBfJjYYLwHAAGAAfwAXACkAMQBuJj5fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAxSASYAPgDSAAIAECIEDGNMAOgA7AA4mQCZJAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoJkomSyZMJk0mTiZPJlAmUYEDGYEDGoEDG4EDHYEDHoEDH4EDIIEDIYAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXJjAAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQMXCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyYwAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEDFwgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFyZzABcmMABuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEDHIAAgQMXCAgICIAggE8ICIAACNMAOgA7AA4mgSaCAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXJjAAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAW4AAgQMXCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFyYwAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEDFwgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcmMABuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBAxcICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXJjAAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQMXCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFyYwAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEDFwgICAiAIIBUCAiAAAjZACEAJSbQAA4AKCbRACMAXybSGC8BwQBgAH8AFwApADEAbibaXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQMUgEqAD4A0gACABAiBAyPTADoAOwAOJtwm5ABMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenJuUm5ibnJugm6SbqJuuBAySBAyWBAyaBAyeBAyiBAymBAyqALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyYxAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEDIggICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcmMQBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBAyIICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXJjEAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQMiCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAsEAFyYxAG4AbgBuADEAbgC2An4AbgBuABcAboAAgGyAAIEDIggICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcmMQBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBAyIICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXJjEAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQMiCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyYxAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEDIggICAiAIIBnCAiAAAjfEBIApAClAKYnVwAhAKgAqSdYACMApydZAKoADgAlAKsArAAoAK0AFwAXABcAKQBGAG4AbidhADEAbgBgAG4BtxgcAG4AbidpAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEB7QgIgQMtCIAPCIBwgQIQCAiBAywIEjvfTafTADoAOwAOJ20ncABMogHAAcGASYBKoidxJ3KBAy6BAzmALdkAIQAlJ3UADgAoJ3YAIwBfJ3cYMAHAAGAAfwAXACkAMQBuJ39fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAyuASYAPgDSAAIAECIEDL9MAOgA7AA4ngSeKAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoJ4snjCeNJ44njyeQJ5EnkoEDMIEDMYEDMoEDNIEDNYEDNoEDN4EDOIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXJ3EAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQMuCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFydxAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEDLggICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFye0ABcncQBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEDM4AAgQMuCAgICIAggE8ICIAACNMAOgA7AA4nwifDAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXJ3EAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQMuCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFydxAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEDLggICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcncQBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBAy4ICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXJ3EAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQMuCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFydxAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEDLggICAiAIIBUCAiAAAjZACEAJSgRAA4AKCgSACMAXygTGDABwQBgAH8AFwApADEAbigbXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQMrgEqAD4A0gACABAiBAzrTADoAOwAOKB0oJQBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenKCYoJygoKCkoKigrKCyBAzuBAzyBAz2BAz6BAz+BA0CBA0GALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFydyAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEDOQgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcncgBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBAzkICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXJ3IAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQM5CAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXDNgAFydyAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQEsgACBAzkICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXJ3IAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQM5CAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFydyAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEDOQgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcncgBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBAzkICAgIgCCAZwgIgAAI3xASAKQApQCmKJgAIQCoAKkomQAjAKcomgCqAA4AJQCrAKwAKACtABcAFwAXACkARgBuAG4oogAxAG4AYABuAbcBfwBuAG4oqgBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAe0ICIEDRAiADwiAcIBACAiBA0MIEpVRYOvTADoAOwAOKK4osQBMogHAAcGASYBKoiiyKLOBA0WBA1CALdkAIQAlKLYADgAoKLcAIwBfKLgYMQHAAGAAfwAXACkAMQBuKMBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBA0KASYAPgDSAAIAECIEDRtMAOgA7AA4owijLAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoKMwozSjOKM8o0CjRKNIo04EDR4EDSIEDSYEDS4EDTIEDTYEDToEDT4At3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXKLIAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQNFCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyiyAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEDRQgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFyj1ABcosgBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEDSoAAgQNFCAgICIAggE8ICIAACNMAOgA7AA4pAykEAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXKLIAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQNFCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFyiyAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEDRQgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcosgBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBA0UICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXKLIAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQNFCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFyiyAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEDRQgICAiAIIBUCAiAAAjZACEAJSlSAA4AKClTACMAXylUGDEBwQBgAH8AFwApADEAbilcXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQNCgEqAD4A0gACABAiBA1HTADoAOwAOKV4pZgBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenKWcpaClpKWopaylsKW2BA1KBA1OBA1SBA1WBA1aBA1eBA1iALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyizAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEDUAgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcoswBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBA1AICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXKLMAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQNQCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXEJwAFyizAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQFygACBA1AICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXKLMAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQNQCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyizAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEDUAgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcoswBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBA1AICAgIgCCAZwgIgAAI3xASAKQApQCmKdkAIQCoAKkp2gAjAKcp2wCqAA4AJQCrAKwAKACtABcAFwAXACkARgBuAG4p4wAxAG4AYABuAbcYHgBuAG4p6wBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAe0ICIEDWwiADwiAcIECEQgIgQNaCBKBPCNF0wA6ADsADinvKfIATKIBwAHBgEmASqIp8yn0gQNcgQNngC3ZACEAJSn3AA4AKCn4ACMAXyn5GDIBwABgAH8AFwApADEAbioBXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQNZgEmAD4A0gACABAiBA13TADoAOwAOKgMqDABMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqCoNKg4qDyoQKhEqEioTKhSBA16BA1+BA2CBA2KBA2OBA2SBA2WBA2aALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFynzAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIEDXAgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcp8wBuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBA1wICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcqNgAXKfMAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBA2GAAIEDXAgICAiAIIBPCAiAAAjTADoAOwAOKkQqRQBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFynzAG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIEDXAgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcp8wBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIAqgACBA1wICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXKfMAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQNcCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFynzAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIEDXAgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcp8wBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBA1wICAgIgCCAVAgIgAAI2QAhACUqkwAOACgqlAAjAF8qlRgyAcEAYAB/ABcAKQAxAG4qnV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDWYBKgA+ANIAAgAQIgQNo0wA6ADsADiqfKqcATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpyqoKqkqqiqrKqwqrSqugQNpgQNqgQNrgQNsgQNtgQNugQNvgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcp9ABuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACBA2cICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXKfQAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQNnCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyn0AG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEDZwgICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwpUABcp9ABuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAID8gACBA2cICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXKfQAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQNnCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyn0AG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEDZwgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcp9ABuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBA2cICAgIgCCAZwgIgAAI3xASAKQApQCmKxoAIQCoAKkrGwAjAKcrHACqAA4AJQCrAKwAKACtABcAFwAXACkARgBuAG4rJAAxAG4AYABuAbcYHwBuAG4rLABuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAe0ICIEDcgiADwiAcIECEggIgQNxCBJbf6bJ0wA6ADsADiswKzMATKIBwAHBgEmASqIrNCs1gQNzgQN+gC3ZACEAJSs4AA4AKCs5ACMAXys6GDMBwABgAH8AFwApADEAbitCXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQNwgEmAD4A0gACABAiBA3TTADoAOwAOK0QrTQBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqCtOK08rUCtRK1IrUytUK1WBA3WBA3aBA3eBA3mBA3qBA3uBA3yBA32ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFys0AG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIEDcwgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcrNABuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBA3MICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcrdwAXKzQAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBA3iAAIEDcwgICAiAIIBPCAiAAAjTADoAOwAOK4UrhgBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFys0AG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIEDcwgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcrNABuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIAqgACBA3MICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXKzQAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQNzCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFys0AG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIEDcwgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcrNABuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBA3MICAgIgCCAVAgIgAAI2QAhACUr1AAOACgr1QAjAF8r1hgzAcEAYAB/ABcAKQAxAG4r3l8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDcIBKgA+ANIAAgAQIgQN/0wA6ADsADivgK+gATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpyvpK+or6yvsK+0r7ivvgQOAgQOBgQOCgQODgQOEgQOFgQOGgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcrNQBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACBA34ICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXKzUAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQN+CAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFys1AG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEDfggICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwLBABcrNQBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIBsgACBA34ICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXKzUAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQN+CAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFys1AG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEDfggICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcrNQBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBA34ICAgIgCCAZwgIgAAI3xASAKQApQCmLFsAIQCoAKksXAAjAKcsXQCqAA4AJQCrAKwAKACtABcAFwAXACkARgBuAG4sZQAxAG4AYABuAbcBggBuAG4sbQBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAe0ICIEDiQiADwiAcIBDCAiBA4gIEnPReJHTADoAOwAOLHEsdABMogHAAcGASYBKoix1LHaBA4qBA5WALdkAIQAlLHkADgAoLHoAIwBfLHsYNAHAAGAAfwAXACkAMQBuLINfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBA4eASYAPgDSAAIAECIEDi9MAOgA7AA4shSyOAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoLI8skCyRLJIskyyULJUsloEDjIEDjYEDjoEDkIEDkYEDkoEDk4EDlIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXLHUAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQOKCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyx1AG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEDiggICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFyy4ABcsdQBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEDj4AAgQOKCAgICIAggE8ICIAACNMAOgA7AA4sxizHAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXLHUAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQOKCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFyx1AG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEDiggICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcsdQBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBA4oICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXLHUAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQOKCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFyx1AG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEDiggICAiAIIBUCAiAAAjZACEAJS0VAA4AKC0WACMAXy0XGDQBwQBgAH8AFwApADEAbi0fXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQOHgEqAD4A0gACABAiBA5bTADoAOwAOLSEtKQBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenLSotKy0sLS0tLi0vLTCBA5eBA5iBA5mBA5qBA5uBA5yBA52ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyx2AG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEDlQgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcsdgBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBA5UICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXLHYAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQOVCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXC5YAFyx2AG4AbgBuADEAbgC2An4AbgBuABcAboAAgQEUgACBA5UICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXLHYAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQOVCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFyx2AG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEDlQgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcsdgBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBA5UICAgIgCCAZwgIgAAI3xASAKQApQCmLZwAIQCoAKktnQAjAKctngCqAA4AJQCrAKwAKACtABcAFwAXACkARgBuAG4tpgAxAG4AYABuAbcYIQBuAG4trgBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAe0ICIEDoAiADwiAcIECEwgIgQOfCBMAAAABIopEXNMAOgA7AA4tsi21AEyiAcABwYBJgEqiLbYtt4EDoYEDrIAt2QAhACUtugAOACgtuwAjAF8tvBg1AcAAYAB/ABcAKQAxAG4txF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDnoBJgA+ANIAAgAQIgQOi0wA6ADsADi3GLc8ATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKgt0C3RLdIt0y3ULdUt1i3XgQOjgQOkgQOlgQOngQOogQOpgQOqgQOrgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcttgBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBA6EICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXLbYAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQOhCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXLfkAFy22AG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQOmgACBA6EICAgIgCCATwgIgAAI0wA6ADsADi4HLggATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcttgBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBA6EICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXLbYAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAW4AAgQOhCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFy22AG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEDoQgICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcttgBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBA6EICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXLbYAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQOhCAgICIAggFQICIAACNkAIQAlLlYADgAoLlcAIwBfLlgYNQHBAGAAfwAXACkAMQBuLmBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBA56ASoAPgDSAAIAECIEDrdMAOgA7AA4uYi5qAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6cuay5sLm0ubi5vLnAucYEDroEDr4EDsIEDsYEDsoEDs4EDtIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXLbcAbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgQOsCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFy23AG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEDrAgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcttwBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBA6wICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcLlgAXLbcAbgBuAG4AMQBuALYCfgBuAG4AFwBugACBARSAAIEDrAgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcttwBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBA6wICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXLbcAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQOsCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFy23AG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEDrAgICAiAIIBnCAiAAAjfEBIApAClAKYu3QAhAKgAqS7eACMApy7fAKoADgAlAKsArAAoAK0AFwAXABcAKQBGAG4Abi7nADEAbgBgAG4BtxgiAG4Abi7vAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEB7QgIgQO3CIAPCIBwgQIUCAiBA7YIEmp6QMrTADoAOwAOLvMu9gBMogHAAcGASYBKoi73LviBA7iBA8OALdkAIQAlLvsADgAoLvwAIwBfLv0YNgHAAGAAfwAXACkAMQBuLwVfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBA7WASYAPgDSAAIAECIEDudMAOgA7AA4vBy8QAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoLxEvEi8TLxQvFS8WLxcvGIEDuoEDu4EDvIEDvoEDv4EDwIEDwYEDwoAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXLvcAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQO4CAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFy73AG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEDuAgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFy86ABcu9wBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEDvYAAgQO4CAgICIAggE8ICIAACNMAOgA7AA4vSC9JAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXLvcAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQO4CAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAFy73AG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEDuAgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcu9wBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBA7gICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXLvcAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQO4CAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFy73AG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEDuAgICAiAIIBUCAiAAAjZACEAJS+XAA4AKC+YACMAXy+ZGDYBwQBgAH8AFwApADEAbi+hXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQO1gEqAD4A0gACABAiBA8TTADoAOwAOL6MvqwBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenL6wvrS+uL68vsC+xL7KBA8WBA8aBA8eBA8iBA8mBA8qBA8uALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFy74AG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEDwwgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcu+ABuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBA8MICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXLvgAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQPDCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXEJwAFy74AG4AbgBuADEAbgC2An4AbgBuABcAboAAgQFygACBA8MICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXLvgAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQPDCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFy74AG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEDwwgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcu+ABuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBA8MICAgIgCCAZwgIgAAI0gA7AA4wHgC+oIAf3xAQMCEwIjAjMCQAITAlMCYAIzAnMCgADgAlMCkwKgAoAF8AYDAsACkAKQAUMDAAZgAxACkAYABpAD8AYDA3MDgAbl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZV8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc2R1cGxpY2F0ZXNfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zc3RvcmFnZYAPgQPigASABIACgQPPgQHqgASAD4EB7IAIgA+BBCqBA84IEqPH5lXTADoAOwAOMDwwPgBMoQBzgBGhMD+BA9CALdkAIQAlMEIADgAoMEMAIwBfMEQARwBzAGAAfwAXACkAMQBuMExfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBA82AEYAPgDSAAIAECIED0dMAOgA7AA4wTjBYAEypAIYAhwCIAIkAigCLAIwAjQCOgBSAFYAWgBeAGIAZgBqAG4AcqTBZMFowWzBcMF0wXjBfMGAwYYED0oED1IED1YED2YED2oED3IED3YED34ED4IAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcwZQAXMD8AbgBuAG4AMQBuALYAhgBuAG4AFwBugACBA9OAAIED0AgICAiAIIAUCAiAAAjSADsADjBzAL6ggB/fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcwPwBuAG4AbgAxAG4AtgCHAG4AbgAXAG6AAIAAgACBA9AICAgIgCCAFQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcwhgAXMD8AbgBuAG4AMQBuALYAiABuAG4AFwBugACBA9aAAIED0AgICAiAIIAWCAiAAAjSADsADjCUAL6hMJWBA9eAH9IAOwAOMJgAvqEwmYED2IAfXxATbW9kaWZpY2F0aW9uQ291bnRlct8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzA/AG4AbgBuADEAbgC2AIkAbgBuABcAboAAgACAAIED0AgICAiAIIAXCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFzCtABcwPwBuAG4AbgAxAG4AtgCKAG4AbgAXAG6AAIED24AAgQPQCAgICIAggBgICIAACNIAOwAOMLsAvqCAH98QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzA/AG4AbgBuADEAbgC2AIsAbgBuABcAboAAgCqAAIED0AgICAiAIIAZCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFzDOABcwPwBuAG4AbgAxAG4AtgCMAG4AbgAXAG6AAIED3oAAgQPQCAgICIAggBoICIAACNMAOgA7AA4w3DDdAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBPQAXMD8AbgBuAG4AMQBuALYAjQBuAG4AFwBugACAL4AAgQPQCAgICIAggBsICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXMPAAFzA/AG4AbgBuADEAbgC2AI4AbgBuABcAboAAgQPhgACBA9AICAgIgCCAHAgIgAAIXxAVLkRvc2luZ0RlY2lzaW9uT2JqZWN00wA6ADsADjD/MQMATKMBezEBMQKAPIED44ED5KMxBDEFMQaBA+WBA/yBBBOALVRkYXRhXxATbW9kaWZpY2F0aW9uQ291bnRlct8QEgCkAKUApjELACEAqACpMQwAIwCnMQ0AqgAOACUAqwCsACgArQAXABcAFwApAEcAbgBuMRUAMQBuAGAAbgG3AXsAbgBuMR0Abl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQPNCAiBA+cIgA8IgHCAPAgIgQPmCBJ9d/g60wA6ADsADjEhMSQATKIBwAHBgEmASqIxJTEmgQPogQPzgC3ZACEAJTEpAA4AKDEqACMAXzErMQQBwABgAH8AFwApADEAbjEzXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQPlgEmAD4A0gACABAiBA+nTADoAOwAOMTUxPgBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqDE/MUAxQTFCMUMxRDFFMUaBA+qBA+uBA+yBA+6BA++BA/CBA/GBA/KALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzElAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIED6AgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcxJQBuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBA+gICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcxaAAXMSUAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBA+2AAIED6AgICAiAIIBPCAiAAAjTADoAOwAOMXYxdwBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAFzElAG4AbgBuADEAbgC2AdkAbgBuABcAboAAgFuAAIED6AgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcxJQBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIAqgACBA+gICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXMSUAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQPoCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzElAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIED6AgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcxJQBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBA+gICAgIgCCAVAgIgAAI2QAhACUxxQAOACgxxgAjAF8xxzEEAcEAYAB/ABcAKQAxAG4xz18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYED5YBKgA+ANIAAgAQIgQP00wA6ADsADjHRMdkATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpzHaMdsx3DHdMd4x3zHggQP1gQP2gQP3gQP4gQP5gQP6gQP7gC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcxJgBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACBA/MICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXMSYAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQPzCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzEmAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIED8wgICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwuWABcxJgBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIEBFIAAgQPzCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzEmAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIED8wgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcxJgBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBA/MICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXMSYAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQPzCAgICIAggGcICIAACN8QEgCkAKUApjJMACEAqACpMk0AIwCnMk4AqgAOACUAqwCsACgArQAXABcAFwApAEcAbgBuMlYAMQBuAGAAbgG3MQEAbgBuMl4Abl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQPNCAiBA/4IgA8IgHCBA+MICIED/QgS8xOgf9MAOgA7AA4yYjJlAEyiAcABwYBJgEqiMmYyZ4ED/4EECoAt2QAhACUyagAOACgyawAjAF8ybDEFAcAAYAB/ABcAKQAxAG4ydF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYED/IBJgA+ANIAAgAQIgQQA0wA6ADsADjJ2Mn8ATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKgygDKBMoIygzKEMoUyhjKHgQQBgQQCgQQDgQQFgQQGgQQHgQQIgQQJgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcyZgBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBA/8ICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXMmYAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQP/CAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXMqkAFzJmAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQQEgACBA/8ICAgIgCCATwgIgAAI0wA6ADsADjK3MrgATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABcyZgBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBA/8ICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXMmYAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAKoAAgQP/CAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzJmAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIED/wgICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcyZgBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBA/8ICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXMmYAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQP/CAgICIAggFQICIAACNkAIQAlMwYADgAoMwcAIwBfMwgxBQHBAGAAfwAXACkAMQBuMxBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBA/yASoAPgDSAAIAECIEEC9MAOgA7AA4zEjMaAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6czGzMcMx0zHjMfMyAzIYEEDIEEDYEEDoEED4EEEIEEEYEEEoAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXMmcAbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgQQKCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzJnAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEECggICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcyZwBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBBAoICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcGjQAXMmcAbgBuAG4AMQBuALYCfgBuAG4AFwBugACAs4AAgQQKCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzJnAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEECggICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABcyZwBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBBAoICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXMmcAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQQKCAgICIAggGcICIAACN8QEgCkAKUApjONACEAqACpM44AIwCnM48AqgAOACUAqwCsACgArQAXABcAFwApAEcAbgBuM5cAMQBuAGAAbgG3MQIAbgBuM58Abl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQPNCAiBBBUIgA8IgHCBA+QICIEEFAgSQY9Xl9MAOgA7AA4zozOmAEyiAcABwYBJgEqiM6czqIEEFoEEIYAt2QAhACUzqwAOACgzrAAjAF8zrTEGAcAAYAB/ABcAKQAxAG4ztV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEEE4BJgA+ANIAAgAQIgQQX0wA6ADsADjO3M8AATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKgzwTPCM8MzxDPFM8YzxzPIgQQYgQQZgQQagQQcgQQdgQQegQQfgQQggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABczpwBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBBBYICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXM6cAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQQWCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXM+oAFzOnAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQQbgACBBBYICAgIgCCATwgIgAAI0wA6ADsADjP4M/kATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABczpwBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBBBYICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXM6cAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAKoAAgQQWCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzOnAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEEFggICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABczpwBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBBBYICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXM6cAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQQWCAgICIAggFQICIAACNkAIQAlNEcADgAoNEgAIwBfNEkxBgHBAGAAfwAXACkAMQBuNFFfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBBOASoAPgDSAAIAECIEEItMAOgA7AA40UzRbAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6c0XDRdNF40XzRgNGE0YoEEI4EEJIEEJYEEJoEEJ4EEKIEEKYAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcI4wAXM6gAbgBuAG4AMQBuALYCewBuAG4AFwBugACA34AAgQQhCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzOoAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEEIQgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABczqABuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBBCEICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcJEQAXM6gAbgBuAG4AMQBuALYCfgBuAG4AFwBugACA44AAgQQhCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzOoAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEEIQgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABczqABuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBBCEICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXM6gAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQQhCAgICIAggGcICIAACNIAOwAONM4AvqCAH98QEDTRNNI00zTUACE01TTWACM01zTYAA4AJTTZNNoAKABfAGA03AApACkAFDTgAGYAMQApAGAAaQBAAGA05zToAG5fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2WAD4EEPoAEgASAAoEELYEB6oAEgA+BAeyACYAPgQXAgQQsCBLSIVnN0wA6ADsADjTsNO4ATKEAc4ARoTTvgQQugC3ZACEAJTTyAA4AKDTzACMAXzT0AEgAcwBgAH8AFwApADEAbjT8XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQQrgBGAD4A0gACABAiBBC/TADoAOwAONP41CABMqQCGAIcAiACJAIoAiwCMAI0AjoAUgBWAFoAXgBiAGYAagBuAHKk1CTUKNQs1DDUNNQ41DzUQNRGBBDCBBDKBBDOBBDWBBDaBBDiBBDmBBDuBBDyALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXNRUAFzTvAG4AbgBuADEAbgC2AIYAbgBuABcAboAAgQQxgACBBC4ICAgIgCCAFAgIgAAI0gA7AA41IwC+oIAf3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXNO8AbgBuAG4AMQBuALYAhwBuAG4AFwBugACAAIAAgQQuCAgICIAggBUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXNTYAFzTvAG4AbgBuADEAbgC2AIgAbgBuABcAboAAgQQ0gACBBC4ICAgIgCCAFggIgAAI0gA7AA41RAC+oIAf3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXNO8AbgBuAG4AMQBuALYAiQBuAG4AFwBugACAAIAAgQQuCAgICIAggBcICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXNVcAFzTvAG4AbgBuADEAbgC2AIoAbgBuABcAboAAgQQ3gACBBC4ICAgIgCCAGAgIgAAI0gA7AA41ZQC+oIAf3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXNO8AbgBuAG4AMQBuALYAiwBuAG4AFwBugACAKoAAgQQuCAgICIAggBkICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXNXgAFzTvAG4AbgBuADEAbgC2AIwAbgBuABcAboAAgQQ6gACBBC4ICAgIgCCAGggIgAAI0wA6ADsADjWGNYcATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwE9ABc07wBuAG4AbgAxAG4AtgCNAG4AbgAXAG6AAIAvgACBBC4ICAgIgCCAGwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABc1mgAXNO8AbgBuAG4AMQBuALYAjgBuAG4AFwBugACBBD2AAIEELggICAiAIIAcCAiAAAhfEBEuQ2FjaGVkQ2FyYk9iamVjdNMAOgA7AA41qTW6AEyvEBAXpDWrNaw1rTWuNa81sDWxNbI1szW0NbUYETW3Nbg1uYEB+IEEP4EEQIEEQYEEQoEEQ4EERIEERYEERoEER4EESIEESYECBoEESoEES4EETK8QEDW7Nbw1vTW+Nb81wDXBNcI1wzXENcU1xjXHNcg1yTXKgQRNgQRkgQR8gQSTgQSrgQTCgQTZgQTwgQUHgQUegQU1gQVMgQVjgQV6gQWSgQWpgC1ZYW5jaG9yS2V5WGZvb2RUeXBlWW9wZXJhdGlvbl5zdXBlcmNlZGVkRGF0ZV5zeW5jSWRlbnRpZmllcl5hYnNvcnB0aW9uVGltZVlhZGRlZERhdGVfEBNjcmVhdGVkQnlDdXJyZW50QXBwVWdyYW1zXxAPdXNlckNyZWF0ZWREYXRlXxAPdXNlckRlbGV0ZWREYXRlXxAUcHJvdmVuYW5jZUlkZW50aWZpZXJfEA91c2VyVXBkYXRlZERhdGVbc3luY1ZlcnNpb27fEBIApAClAKY12wAhAKgAqTXcACMApzXdAKoADgAlAKsArAAoAK0AFwAXABcAKQBIAG4AbjXlADEAbgBgAG4BtxekAG4AbjXtAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEEKwgIgQRPCIAPCIBwgQH4CAiBBE4IEumQd+bTADoAOwAONfE19ABMogHAAcGASYBKojX1NfaBBFCBBFuALdkAIQAlNfkADgAoNfoAIwBfNfs1uwHAAGAAfwAXACkAMQBuNgNfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBE2ASYAPgDSAAIAECIEEUdMAOgA7AA42BTYOAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoNg82EDYRNhI2EzYUNhU2FoEEUoEEU4EEVIEEVoEEV4EEWIEEWYEEWoAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXNfUAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQRQCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzX1AG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEEUAgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFzY4ABc19QBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEEVYAAgQRQCAgICIAggE8ICIAACNMAOgA7AA42RjZHAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXNfUAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQRQCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAFzX1AG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEEUAgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc19QBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBBFAICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXNfUAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQRQCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzX1AG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEEUAgICAiAIIBUCAiAAAjZACEAJTaVAA4AKDaWACMAXzaXNbsBwQBgAH8AFwApADEAbjafXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQRNgEqAD4A0gACABAiBBFzTADoAOwAONqE2qQBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenNqo2qzasNq02rjavNrCBBF2BBF6BBF+BBGCBBGGBBGKBBGOALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzX2AG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEEWwgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc19gBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBBFsICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXNfYAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQRbCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXHRMAFzX2AG4AbgBuADEAbgC2An4AbgBuABcAboAAgQJvgACBBFsICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXNfYAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQRbCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzX2AG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEEWwgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc19gBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBBFsICAgIgCCAZwgIgAAI3xASAKQApQCmNxwAIQCoAKk3HQAjAKc3HgCqAA4AJQCrAKwAKACtABcAFwAXACkASABuAG43JgAxAG4AYABuAbc1qwBuAG43LgBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBBCsICIEEZgiADwiAcIEEPwgIgQRlCBMAAAABCuPD59MAOgA7AA43Mjc1AEyiAcABwYBJgEqiNzY3N4EEZ4EEc4At2QAhACU3OgAOACg3OwAjAF83PDW8AcAAYAB/ABcAKQAxAG43RF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEEZIBJgA+ANIAAgAQIgQRo0wA6ADsADjdGN08ATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKg3UDdRN1I3UzdUN1U3VjdXgQRpgQRqgQRrgQRtgQRugQRvgQRwgQRygC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc3NgBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBBGcICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXNzYAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQRnCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXN3kAFzc2AG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQRsgACBBGcICAgIgCCATwgIgAAI0wA6ADsADjeHN4gATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc3NgBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBBGcICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXNzYAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAKoAAgQRnCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzc2AG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEEZwgICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFze5ABc3NgBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIEEcYAAgQRnCAgICIAggFMICIAACF8QE21vZGlmaWNhdGlvbkNvdW50ZXLfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc3NgBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBBGcICAgIgCCAVAgIgAAI2QAhACU31wAOACg32AAjAF832TW8AcEAYAB/ABcAKQAxAG434V8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEEZIBKgA+ANIAAgAQIgQR00wA6ADsADjfjN+sATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpzfsN+037jfvN/A38TfygQR1gQR2gQR3gQR4gQR5gQR6gQR7gC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwjjABc3NwBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIDfgACBBHMICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXNzcAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQRzCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzc3AG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEEcwgICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwkRABc3NwBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIDjgACBBHMICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXNzcAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQRzCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzc3AG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEEcwgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc3NwBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBBHMICAgIgCCAZwgIgAAI3xASAKQApQCmOF4AIQCoAKk4XwAjAKc4YACqAA4AJQCrAKwAKACtABcAFwAXACkASABuAG44aAAxAG4AYABuAbc1rABuAG44cABuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBBCsICIEEfgiADwiAcIEEQAgIgQR9CBK8/qgv0wA6ADsADjh0OHcATKIBwAHBgEmASqI4eDh5gQR/gQSKgC3ZACEAJTh8AA4AKDh9ACMAXzh+Nb0BwABgAH8AFwApADEAbjiGXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQR8gEmAD4A0gACABAiBBIDTADoAOwAOOIg4kQBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqDiSOJM4lDiVOJY4lziYOJmBBIGBBIKBBIOBBIWBBIaBBIeBBIiBBImALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzh4AG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIEEfwgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc4eABuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBBH8ICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABc4uwAXOHgAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBBISAAIEEfwgICAiAIIBPCAiAAAjTADoAOwAOOMk4ygBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzh4AG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIEEfwgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwIyABc4eABuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIBbgACBBH8ICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXOHgAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQR/CAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzh4AG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIEEfwgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc4eABuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBBH8ICAgIgCCAVAgIgAAI2QAhACU5GAAOACg5GQAjAF85GjW9AcEAYAB/ABcAKQAxAG45Il8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEEfIBKgA+ANIAAgAQIgQSL0wA6ADsADjkkOSwATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpzktOS45LzkwOTE5MjkzgQSMgQSNgQSOgQSPgQSQgQSRgQSSgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc4eQBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACBBIoICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXOHkAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQSKCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzh5AG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEEiggICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwLBABc4eQBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIBsgACBBIoICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXOHkAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQSKCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzh5AG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEEiggICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc4eQBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBBIoICAgIgCCAZwgIgAAI3xASAKQApQCmOZ8AIQCoAKk5oAAjAKc5oQCqAA4AJQCrAKwAKACtABcAFwAXACkASABuAG45qQAxAG4AYABuAbc1rQBuAG45sQBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBBCsICIEElQiADwiAcIEEQQgIgQSUCBI0Za9r0wA6ADsADjm1ObgATKIBwAHBgEmASqI5uTm6gQSWgQShgC3ZACEAJTm9AA4AKDm+ACMAXzm/Nb4BwABgAH8AFwApADEAbjnHXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQSTgEmAD4A0gACABAiBBJfTADoAOwAOOck50gBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqDnTOdQ51TnWOdc52DnZOdqBBJiBBJmBBJqBBJyBBJ2BBJ6BBJ+BBKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzm5AG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIEElggICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc5uQBuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBBJYICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABc5/AAXObkAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBBJuAAIEElggICAiAIIBPCAiAAAjTADoAOwAOOgo6CwBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzm5AG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIEElggICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc5uQBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIAqgACBBJYICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXObkAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQSWCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzm5AG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIEElggICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc5uQBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBBJYICAgIgCCAVAgIgAAI2QAhACU6WQAOACg6WgAjAF86WzW+AcEAYAB/ABcAKQAxAG46Y18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEEk4BKgA+ANIAAgAQIgQSi0wA6ADsADjplOm0ATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpzpuOm86cDpxOnI6czp0gQSjgQSkgQSlgQSmgQSogQSpgQSqgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwjjABc5ugBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIDfgACBBKEICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXOboAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQShCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzm6AG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEEoQgICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFzqlABc5ugBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIEEp4AAgQShCAgICIAggGQICIAACBDI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXOboAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQShCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzm6AG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEEoQgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc5ugBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBBKEICAgIgCCAZwgIgAAI3xASAKQApQCmOuEAIQCoAKk64gAjAKc64wCqAA4AJQCrAKwAKACtABcAFwAXACkASABuAG466wAxAG4AYABuAbc1rgBuAG468wBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBBCsICIEErQiADwiAcIEEQggIgQSsCBI2339B0wA6ADsADjr3OvoATKIBwAHBgEmASqI6+zr8gQSugQS5gC3ZACEAJTr/AA4AKDsAACMAXzsBNb8BwABgAH8AFwApADEAbjsJXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQSrgEmAD4A0gACABAiBBK/TADoAOwAOOws7FABMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqDsVOxY7FzsYOxk7GjsbOxyBBLCBBLGBBLKBBLSBBLWBBLaBBLeBBLiALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzr7AG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIEErggICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc6+wBuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBBK4ICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABc7PgAXOvsAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBBLOAAIEErggICAiAIIBPCAiAAAjTADoAOwAOO0w7TQBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzr7AG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIEErggICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwIyABc6+wBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIBbgACBBK4ICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXOvsAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQSuCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzr7AG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIEErggICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc6+wBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBBK4ICAgIgCCAVAgIgAAI2QAhACU7mwAOACg7nAAjAF87nTW/AcEAYAB/ABcAKQAxAG47pV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEEq4BKgA+ANIAAgAQIgQS60wA6ADsADjunO68ATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpzuwO7E7sjuzO7Q7tTu2gQS7gQS8gQS9gQS+gQS/gQTAgQTBgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc6/ABuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACBBLkICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXOvwAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQS5CAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzr8AG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEEuQgICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwuWABc6/ABuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIEBFIAAgQS5CAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzr8AG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEEuQgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc6/ABuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBBLkICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXOvwAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQS5CAgICIAggGcICIAACN8QEgCkAKUApjwiACEAqACpPCMAIwCnPCQAqgAOACUAqwCsACgArQAXABcAFwApAEgAbgBuPCwAMQBuAGAAbgG3Na8AbgBuPDQAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQQrCAiBBMQIgA8IgHCBBEMICIEEwwgSX63cgtMAOgA7AA48ODw7AEyiAcABwYBJgEqiPDw8PYEExYEE0IAt2QAhACU8QAAOACg8QQAjAF88QjXAAcAAYAB/ABcAKQAxAG48Sl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEEwoBJgA+ANIAAgAQIgQTG0wA6ADsADjxMPFUATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKg8VjxXPFg8WTxaPFs8XDxdgQTHgQTIgQTJgQTLgQTMgQTNgQTOgQTPgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc8PABuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBBMUICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXPDwAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQTFCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXPH8AFzw8AG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQTKgACBBMUICAgIgCCATwgIgAAI0wA6ADsADjyNPI4ATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc8PABuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBBMUICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXPDwAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAW4AAgQTFCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzw8AG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEExQgICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc8PABuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBBMUICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXPDwAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQTFCAgICIAggFQICIAACNkAIQAlPNwADgAoPN0AIwBfPN41wAHBAGAAfwAXACkAMQBuPOZfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBMKASoAPgDSAAIAECIEE0dMAOgA7AA486DzwAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6c88TzyPPM89Dz1PPY894EE0oEE04EE1IEE1YEE1oEE14EE2IAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXPD0AbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgQTQCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFzw9AG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEE0AgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc8PQBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBBNAICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCwQAXPD0AbgBuAG4AMQBuALYCfgBuAG4AFwBugACAbIAAgQTQCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFzw9AG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEE0AgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc8PQBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBBNAICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXPD0AbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQTQCAgICIAggGcICIAACN8QEgCkAKUApj1jACEAqACpPWQAIwCnPWUAqgAOACUAqwCsACgArQAXABcAFwApAEgAbgBuPW0AMQBuAGAAbgG3NbAAbgBuPXUAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQQrCAiBBNsIgA8IgHCBBEQICIEE2ggTAAAAAQNE5MLTADoAOwAOPXk9fABMogHAAcGASYBKoj19PX6BBNyBBOeALdkAIQAlPYEADgAoPYIAIwBfPYM1wQHAAGAAfwAXACkAMQBuPYtfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBNmASYAPgDSAAIAECIEE3dMAOgA7AA49jT2WAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoPZc9mD2ZPZo9mz2cPZ09noEE3oEE34EE4IEE4oEE44EE5IEE5YEE5oAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXPX0AbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQTcCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFz19AG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEE3AgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFz3AABc9fQBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEE4YAAgQTcCAgICIAggE8ICIAACNMAOgA7AA49zj3PAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXPX0AbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQTcCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAFz19AG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEE3AgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc9fQBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBBNwICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXPX0AbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQTcCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFz19AG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEE3AgICAiAIIBUCAiAAAjZACEAJT4dAA4AKD4eACMAXz4fNcEBwQBgAH8AFwApADEAbj4nXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQTZgEqAD4A0gACABAiBBOjTADoAOwAOPik+MQBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenPjI+Mz40PjU+Nj43PjiBBOmBBOqBBOuBBOyBBO2BBO6BBO+ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFz1+AG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEE5wgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc9fgBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBBOcICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXPX4AbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQTnCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXEJwAFz1+AG4AbgBuADEAbgC2An4AbgBuABcAboAAgQFygACBBOcICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXPX4AbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQTnCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFz1+AG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEE5wgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc9fgBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBBOcICAgIgCCAZwgIgAAI3xASAKQApQCmPqQAIQCoAKk+pQAjAKc+pgCqAA4AJQCrAKwAKACtABcAFwAXACkASABuAG4+rgAxAG4AYABuAbc1sQBuAG4+tgBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBBCsICIEE8giADwiAcIEERQgIgQTxCBJTtGVe0wA6ADsADj66Pr0ATKIBwAHBgEmASqI+vj6/gQTzgQT+gC3ZACEAJT7CAA4AKD7DACMAXz7ENcIBwABgAH8AFwApADEAbj7MXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQTwgEmAD4A0gACABAiBBPTTADoAOwAOPs4+1wBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqD7YPtk+2j7bPtw+3T7ePt+BBPWBBPaBBPeBBPmBBPqBBPuBBPyBBP2ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFz6+AG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIEE8wgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc+vgBuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBBPMICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABc/AQAXPr4AbgBuAG4AMQBuALYB2ABuAG4AFwBugACBBPiAAIEE8wgICAiAIIBPCAiAAAjTADoAOwAOPw8/EABMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFz6+AG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIEE8wgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwIyABc+vgBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIBbgACBBPMICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXPr4AbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQTzCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFz6+AG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIEE8wgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc+vgBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBBPMICAgIgCCAVAgIgAAI2QAhACU/XgAOACg/XwAjAF8/YDXCAcEAYAB/ABcAKQAxAG4/aF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEE8IBKgA+ANIAAgAQIgQT/0wA6ADsADj9qP3IATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnpz9zP3Q/dT92P3c/eD95gQUAgQUBgQUCgQUDgQUEgQUFgQUGgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc+vwBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACBBP4ICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXPr8AbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQT+CAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFz6/AG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEE/ggICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwuWABc+vwBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIEBFIAAgQT+CAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAFz6/AG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEE/ggICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc+vwBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBBP4ICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXPr8AbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQT+CAgICIAggGcICIAACN8QEgCkAKUApj/lACEAqACpP+YAIwCnP+cAqgAOACUAqwCsACgArQAXABcAFwApAEgAbgBuP+8AMQBuAGAAbgG3NbIAbgBuP/cAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQQrCAiBBQkIgA8IgHCBBEYICIEFCAgSteuAgtMAOgA7AA4/+z/+AEyiAcABwYBJgEqiP/9AAIEFCoEFFYAt2QAhACVAAwAOAChABAAjAF9ABTXDAcAAYAB/ABcAKQAxAG5ADV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEFB4BJgA+ANIAAgAQIgQUL0wA6ADsADkAPQBgATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKhAGUAaQBtAHEAdQB5AH0AggQUMgQUNgQUOgQUQgQURgQUSgQUTgQUUgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc//wBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBBQoICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXP/8AbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQUKCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXQEIAFz//AG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQUPgACBBQoICAgIgCCATwgIgAAI0wA6ADsADkBQQFEATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABc//wBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBBQoICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXP/8AbgBuAG4AMQBuALYB2gBuAG4AFwBugACAKoAAgQUKCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAFz//AG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEFCggICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABc//wBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBBQoICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXP/8AbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQUKCAgICIAggFQICIAACNkAIQAlQJ8ADgAoQKAAIwBfQKE1wwHBAGAAfwAXACkAMQBuQKlfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBQeASoAPgDSAAIAECIEFFtMAOgA7AA5Aq0CzAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6dAtEC1QLZAt0C4QLlAuoEFF4EFGIEFGYEFGoEFG4EFHIEFHYAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXQAAAbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgQUVCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0AAAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEFFQgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdAAABuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBBRUICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcKVAAXQAAAbgBuAG4AMQBuALYCfgBuAG4AFwBugACA/IAAgQUVCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0AAAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEFFQgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdAAABuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBBRUICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXQAAAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQUVCAgICIAggGcICIAACN8QEgCkAKUApkEmACEAqACpQScAIwCnQSgAqgAOACUAqwCsACgArQAXABcAFwApAEgAbgBuQTAAMQBuAGAAbgG3NbMAbgBuQTgAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQQrCAiBBSAIgA8IgHCBBEcICIEFHwgS3yFpXNMAOgA7AA5BPEE/AEyiAcABwYBJgEqiQUBBQYEFIYEFLIAt2QAhACVBRAAOAChBRQAjAF9BRjXEAcAAYAB/ABcAKQAxAG5BTl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEFHoBJgA+ANIAAgAQIgQUi0wA6ADsADkFQQVkATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKhBWkFbQVxBXUFeQV9BYEFhgQUjgQUkgQUlgQUngQUogQUpgQUqgQUrgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdBQABuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBBSEICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXQUAAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQUhCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXQYMAF0FAAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQUmgACBBSEICAgIgCCATwgIgAAI0wA6ADsADkGRQZIATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdBQABuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBBSEICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXQUAAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAKoAAgQUhCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0FAAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEFIQgICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdBQABuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBBSEICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXQUAAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQUhCAgICIAggFQICIAACNkAIQAlQeAADgAoQeEAIwBfQeI1xAHBAGAAfwAXACkAMQBuQepfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBR6ASoAPgDSAAIAECIEFLdMAOgA7AA5B7EH0AEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6dB9UH2QfdB+EH5QfpB+4EFLoEFL4EFMIEFMYEFMoEFM4EFNIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcRsQAXQUEAbgBuAG4AMQBuALYCewBuAG4AFwBugACBAYeAAIEFLAgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdBQQBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBBSwICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXQUEAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQUsCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXEJwAF0FBAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQFygACBBSwICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXQUEAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQUsCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0FBAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEFLAgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdBQQBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBBSwICAgIgCCAZwgIgAAI3xASAKQApQCmQmcAIQCoAKlCaAAjAKdCaQCqAA4AJQCrAKwAKACtABcAFwAXACkASABuAG5CcQAxAG4AYABuAbc1tABuAG5CeQBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBBCsICIEFNwiADwiAcIEESAgIgQU2CBMAAAABA7dF3NMAOgA7AA5CfUKAAEyiAcABwYBJgEqiQoFCgoEFOIEFQ4At2QAhACVChQAOAChChgAjAF9ChzXFAcAAYAB/ABcAKQAxAG5Cj18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEFNYBJgA+ANIAAgAQIgQU50wA6ADsADkKRQpoATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKhCm0KcQp1CnkKfQqBCoUKigQU6gQU7gQU8gQU+gQU/gQVAgQVBgQVCgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdCgQBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBBTgICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXQoEAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQU4CAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXQsQAF0KBAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQU9gACBBTgICAgIgCCATwgIgAAI0wA6ADsADkLSQtMATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdCgQBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBBTgICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXQoEAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAW4AAgQU4CAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0KBAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEFOAgICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdCgQBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBBTgICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXQoEAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQU4CAgICIAggFQICIAACNkAIQAlQyEADgAoQyIAIwBfQyM1xQHBAGAAfwAXACkAMQBuQytfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBTWASoAPgDSAAIAECIEFRNMAOgA7AA5DLUM1AEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6dDNkM3QzhDOUM6QztDPIEFRYEFRoEFR4EFSIEFSYEFSoEFS4At3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXQoIAbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgQVDCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0KCAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEFQwgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdCggBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBBUMICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcLlgAXQoIAbgBuAG4AMQBuALYCfgBuAG4AFwBugACBARSAAIEFQwgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdCggBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBBUMICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXQoIAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQVDCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0KCAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEFQwgICAiAIIBnCAiAAAjfEBIApAClAKZDqAAhAKgAqUOpACMAp0OqAKoADgAlAKsArAAoAK0AFwAXABcAKQBIAG4AbkOyADEAbgBgAG4BtzW1AG4AbkO6AG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEEKwgIgQVOCIAPCIBwgQRJCAiBBU0IEnCb7cHTADoAOwAOQ75DwQBMogHAAcGASYBKokPCQ8OBBU+BBVqALdkAIQAlQ8YADgAoQ8cAIwBfQ8g1xgHAAGAAfwAXACkAMQBuQ9BfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBUyASYAPgDSAAIAECIEFUNMAOgA7AA5D0kPbAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoQ9xD3UPeQ99D4EPhQ+JD44EFUYEFUoEFU4EFVYEFVoEFV4EFWIEFWYAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXQ8IAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQVPCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0PCAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEFTwgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF0QFABdDwgBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEFVIAAgQVPCAgICIAggE8ICIAACNMAOgA7AA5EE0QUAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXQ8IAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQVPCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAF0PCAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEFTwgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdDwgBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBBU8ICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXQ8IAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQVPCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0PCAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEFTwgICAiAIIBUCAiAAAjZACEAJURiAA4AKERjACMAX0RkNcYBwQBgAH8AFwApADEAbkRsXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQVMgEqAD4A0gACABAiBBVvTADoAOwAORG5EdgBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenRHdEeER5RHpEe0R8RH2BBVyBBV2BBV6BBV+BBWCBBWGBBWKALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0PDAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEFWggICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdDwwBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBBVoICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXQ8MAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQVaCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXC5YAF0PDAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQEUgACBBVoICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXQ8MAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQVaCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0PDAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEFWggICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdDwwBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBBVoICAgIgCCAZwgIgAAI3xASAKQApQCmROkAIQCoAKlE6gAjAKdE6wCqAA4AJQCrAKwAKACtABcAFwAXACkASABuAG5E8wAxAG4AYABuAbcYEQBuAG5E+wBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBBCsICIEFZQiADwiAcIECBggIgQVkCBJxgqMc0wA6ADsADkT/RQIATKIBwAHBgEmASqJFA0UEgQVmgQVxgC3ZACEAJUUHAA4AKEUIACMAX0UJNccBwABgAH8AFwApADEAbkURXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQVjgEmAD4A0gACABAiBBWfTADoAOwAORRNFHABMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqEUdRR5FH0UgRSFFIkUjRSSBBWiBBWmBBWqBBWyBBW2BBW6BBW+BBXCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0UDAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIEFZggICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdFAwBuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBBWYICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABdFRgAXRQMAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBBWuAAIEFZggICAiAIIBPCAiAAAjTADoAOwAORVRFVQBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0UDAG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIEFZggICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdFAwBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIAqgACBBWYICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXRQMAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQVmCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0UDAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIEFZggICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdFAwBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBBWYICAgIgCCAVAgIgAAI2QAhACVFowAOAChFpAAjAF9FpTXHAcEAYAB/ABcAKQAxAG5FrV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEFY4BKgA+ANIAAgAQIgQVy0wA6ADsADkWvRbcATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnp0W4RblFukW7RbxFvUW+gQVzgQV0gQV1gQV2gQV3gQV4gQV5gC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdFBABuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACBBXEICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXRQQAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQVxCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0UEAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEFcQgICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwuWABdFBABuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIEBFIAAgQVxCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0UEAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEFcQgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdFBABuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBBXEICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXRQQAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQVxCAgICIAggGcICIAACN8QEgCkAKUApkYqACEAqACpRisAIwCnRiwAqgAOACUAqwCsACgArQAXABcAFwApAEgAbgBuRjQAMQBuAGAAbgG3NbcAbgBuRjwAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQQrCAiBBXwIgA8IgHCBBEoICIEFewgSrAnwQ9MAOgA7AA5GQEZDAEyiAcABwYBJgEqiRkRGRYEFfYEFiIAt2QAhACVGSAAOAChGSQAjAF9GSjXIAcAAYAB/ABcAKQAxAG5GUl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEFeoBJgA+ANIAAgAQIgQV+0wA6ADsADkZURl0ATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKhGXkZfRmBGYUZiRmNGZEZlgQV/gQWAgQWBgQWDgQWEgQWFgQWGgQWHgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdGRABuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBBX0ICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXRkQAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQV9CAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXRocAF0ZEAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQWCgACBBX0ICAgIgCCATwgIgAAI0wA6ADsADkaVRpYATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdGRABuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBBX0ICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXRkQAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAKoAAgQV9CAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0ZEAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEFfQgICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdGRABuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBBX0ICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXRkQAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQV9CAgICIAggFQICIAACNkAIQAlRuQADgAoRuUAIwBfRuY1yAHBAGAAfwAXACkAMQBuRu5fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBXqASoAPgDSAAIAECIEFidMAOgA7AA5G8Eb4AEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6dG+Ub6RvtG/Eb9Rv5G/4EFioEFjIEFjYEFjoEFj4EFkIEFkYAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAGgAXRkUAbgBuAG4AMQBuALYCewBuAG4AFwBugACBBYuAAIEFiAgICAiAIIBhCAiAAAhQ3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXRkUAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQWICAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0ZFAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEFiAgICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwLBABdGRQBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIBsgACBBYgICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXRkUAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQWICAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0ZFAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEFiAgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdGRQBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBBYgICAgIgCCAZwgIgAAI3xASAKQApQCmR2wAIQCoAKlHbQAjAKdHbgCqAA4AJQCrAKwAKACtABcAFwAXACkASABuAG5HdgAxAG4AYABuAbc1uABuAG5HfgBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBBCsICIEFlAiADwiAcIEESwgIgQWTCBMAAAABJq3PpNMAOgA7AA5HgkeFAEyiAcABwYBJgEqiR4ZHh4EFlYEFoIAt2QAhACVHigAOAChHiwAjAF9HjDXJAcAAYAB/ABcAKQAxAG5HlF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEFkoBJgA+ANIAAgAQIgQWW0wA6ADsADkeWR58ATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKhHoEehR6JHo0ekR6VHpkengQWXgQWYgQWZgQWbgQWcgQWdgQWegQWfgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdHhgBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBBZUICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXR4YAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQWVCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXR8kAF0eGAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQWagACBBZUICAgIgCCATwgIgAAI0wA6ADsADkfXR9gATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdHhgBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBBZUICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXR4YAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAW4AAgQWVCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0eGAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEFlQgICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdHhgBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBBZUICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXR4YAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQWVCAgICIAggFQICIAACNkAIQAlSCYADgAoSCcAIwBfSCg1yQHBAGAAfwAXACkAMQBuSDBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBZKASoAPgDSAAIAECIEFodMAOgA7AA5IMkg6AEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6dIO0g8SD1IPkg/SEBIQYEFooEFo4EFpIEFpYEFpoEFp4EFqIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXR4cAbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgQWgCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0eHAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEFoAgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdHhwBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBBaAICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcLlgAXR4cAbgBuAG4AMQBuALYCfgBuAG4AFwBugACBARSAAIEFoAgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdHhwBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBBaAICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXR4cAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQWgCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0eHAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEFoAgICAiAIIBnCAiAAAjfEBIApAClAKZIrQAhAKgAqUiuACMAp0ivAKoADgAlAKsArAAoAK0AFwAXABcAKQBIAG4Abki3ADEAbgBgAG4BtzW5AG4Abki/AG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEEKwgIgQWrCIAPCIBwgQRMCAiBBaoIEjUmbDPTADoAOwAOSMNIxgBMogHAAcGASYBKokjHSMiBBayBBbeALdkAIQAlSMsADgAoSMwAIwBfSM01ygHAAGAAfwAXACkAMQBuSNVfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBamASYAPgDSAAIAECIEFrdMAOgA7AA5I10jgAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoSOFI4kjjSORI5UjmSOdI6IEFroEFr4EFsIEFsoEFs4EFtIEFtYEFtoAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXSMcAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQWsCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0jHAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEFrAgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF0kKABdIxwBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEFsYAAgQWsCAgICIAggE8ICIAACNMAOgA7AA5JGEkZAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXSMcAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQWsCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAF0jHAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEFrAgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdIxwBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBBawICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXSMcAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQWsCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0jHAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEFrAgICAiAIIBUCAiAAAjZACEAJUlnAA4AKEloACMAX0lpNcoBwQBgAH8AFwApADEAbklxXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQWpgEqAD4A0gACABAiBBbjTADoAOwAOSXNJewBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenSXxJfUl+SX9JgEmBSYKBBbmBBbqBBbuBBbyBBb2BBb6BBb+ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0jIAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEFtwgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdIyABuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBBbcICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXSMgAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQW3CAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXOqUAF0jIAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQSngACBBbcICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXSMgAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQW3CAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0jIAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEFtwgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdIyABuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBBbcICAgIgCCAZwgIgAAI0gA7AA5J7gC+oIAf3xAQSfFJ8knzSfQAIUn1SfYAI0n3SfgADgAlSflJ+gAoAF8AYEn8ACkAKQAUSgAAZgAxACkAYABpAEEAYEoHSggAbl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZV8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc2R1cGxpY2F0ZXNfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zc3RvcmFnZYAPgQXXgASABIACgQXDgQHqgASAD4EB7IAKgA+BB1WBBcIIEudmJ4HTADoAOwAOSgxKDgBMoQBzgBGhSg+BBcSALdkAIQAlShIADgAoShMAIwBfShQASQBzAGAAfwAXACkAMQBuShxfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBcGAEYAPgDSAAIAECIEFxdMAOgA7AA5KHkooAEypAIYAhwCIAIkAigCLAIwAjQCOgBSAFYAWgBeAGIAZgBqAG4AcqUopSipKK0osSi1KLkovSjBKMYEFxoEFyIEFyYEFzoEFz4EF0YEF0oEF1IEF1YAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABdKNQAXSg8AbgBuAG4AMQBuALYAhgBuAG4AFwBugACBBceAAIEFxAgICAiAIIAUCAiAAAjSADsADkpDAL6ggB/fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdKDwBuAG4AbgAxAG4AtgCHAG4AbgAXAG6AAIAAgACBBcQICAgIgCCAFQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABdKVgAXSg8AbgBuAG4AMQBuALYAiABuAG4AFwBugACBBcqAAIEFxAgICAiAIIAWCAiAAAjSADsADkpkAL6iSmVKZoEFy4EFzIAf0gA7AA5KaQC+oRekgQH4gB/SADsADkptAL6hSm6BBc2AH15zeW5jSWRlbnRpZmllct8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0oPAG4AbgBuADEAbgC2AIkAbgBuABcAboAAgACAAIEFxAgICAiAIIAXCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF0qCABdKDwBuAG4AbgAxAG4AtgCKAG4AbgAXAG6AAIEF0IAAgQXECAgICIAggBgICIAACNIAOwAOSpAAvqCAH98QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0oPAG4AbgBuADEAbgC2AIsAbgBuABcAboAAgCqAAIEFxAgICAiAIIAZCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF0qjABdKDwBuAG4AbgAxAG4AtgCMAG4AbgAXAG6AAIEF04AAgQXECAgICIAggBoICIAACNMAOgA7AA5KsUqyAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBPQAXSg8AbgBuAG4AMQBuALYAjQBuAG4AFwBugACAL4AAgQXECAgICIAggBsICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXSsUAF0oPAG4AbgBuADEAbgC2AI4AbgBuABcAboAAgQXWgACBBcQICAgIgCCAHAgIgAAIXxAULkNhY2hlZEdsdWNvc2VPYmplY3TTADoAOwAOStRK5QBMrxAQF6RK1krXSthK2UraStsBf0rdSt5K3xgRSuFK4krjSuSBAfiBBdiBBdmBBdqBBduBBdyBBd2AQIEF3oEF34EF4IECBoEF4YEF4oEF44EF5K8QEErmSudK6ErpSupK60rsSu1K7krvSvBK8UrySvNK9Er1gQXlgQX8gQYTgQYqgQZBgQZYgQZvgQaGgQadgQa0gQbLgQbigQb5gQcQgQcngQc+gC1edHJlbmRSYXRlVmFsdWVed2FzVXNlckVudGVyZWRZY29uZGl0aW9uXWlzRGlzcGxheU9ubHlec3luY0lkZW50aWZpZXJfEBNtb2RpZmljYXRpb25Db3VudGVyXxAVaGVhbHRoS2l0RWxpZ2libGVEYXRlVXRyZW5kXXRyZW5kUmF0ZVVuaXRfEBRwcm92ZW5hbmNlSWRlbnRpZmllclZkZXZpY2VadW5pdFN0cmluZ1tzeW5jVmVyc2lvbt8QEgCkAKUApksFACEAqACpSwYAIwCnSwcAqgAOACUAqwCsACgArQAXABcAFwApAEkAbgBuSw8AMQBuAGAAbgG3F6QAbgBuSxcAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQXBCAiBBecIgA8IgHCBAfgICIEF5ggTAAAAASNpYszTADoAOwAOSxtLHgBMogHAAcGASYBKoksfSyCBBeiBBfOALdkAIQAlSyMADgAoSyQAIwBfSyVK5gHAAGAAfwAXACkAMQBuSy1fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBeWASYAPgDSAAIAECIEF6dMAOgA7AA5LL0s4AEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoSzlLOks7SzxLPUs+Sz9LQIEF6oEF64EF7IEF7oEF74EF8IEF8YEF8oAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXSx8AbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQXoCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0sfAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEF6AgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF0tiABdLHwBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEF7YAAgQXoCAgICIAggE8ICIAACNMAOgA7AA5LcEtxAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXSx8AbgBuAG4AMQBuALYB2QBuAG4AFwBugACAW4AAgQXoCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAF0sfAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEF6AgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdLHwBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBBegICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXSx8AbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQXoCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0sfAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEF6AgICAiAIIBUCAiAAAjZACEAJUu/AA4AKEvAACMAX0vBSuYBwQBgAH8AFwApADEAbkvJXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQXlgEqAD4A0gACABAiBBfTTADoAOwAOS8tL0wBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenS9RL1UvWS9dL2EvZS9qBBfWBBfaBBfeBBfiBBfmBBfqBBfuALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0sgAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEF8wgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdLIABuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBBfMICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXSyAAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQXzCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXHRMAF0sgAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQJvgACBBfMICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXSyAAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQXzCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0sgAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEF8wgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdLIABuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBBfMICAgIgCCAZwgIgAAI3xASAKQApQCmTEYAIQCoAKlMRwAjAKdMSACqAA4AJQCrAKwAKACtABcAFwAXACkASQBuAG5MUAAxAG4AYABuAbdK1gBuAG5MWABuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBBcEICIEF/giADwiAcIEF2AgIgQX9CBL6vRfk0wA6ADsADkxcTF8ATKIBwAHBgEmASqJMYExhgQX/gQYKgC3ZACEAJUxkAA4AKExlACMAX0xmSucBwABgAH8AFwApADEAbkxuXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQX8gEmAD4A0gACABAiBBgDTADoAOwAOTHBMeQBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqEx6THtMfEx9TH5Mf0yATIGBBgGBBgKBBgOBBgWBBgaBBgeBBgiBBgmALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0xgAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIEF/wgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdMYABuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBBf8ICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABdMowAXTGAAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBBgSAAIEF/wgICAiAIIBPCAiAAAjTADoAOwAOTLFMsgBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF0xgAG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIEF/wgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwIyABdMYABuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIBbgACBBf8ICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXTGAAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQX/CAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0xgAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIEF/wgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdMYABuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBBf8ICAgIgCCAVAgIgAAI2QAhACVNAAAOAChNAQAjAF9NAkrnAcEAYAB/ABcAKQAxAG5NCl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEF/IBKgA+ANIAAgAQIgQYL0wA6ADsADk0MTRQATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnp00VTRZNF00YTRlNGk0bgQYMgQYNgQYOgQYPgQYQgQYRgQYSgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdMYQBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACBBgoICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXTGEAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQYKCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0xhAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEGCggICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFxCcABdMYQBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIEBcoAAgQYKCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF0xhAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEGCggICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdMYQBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBBgoICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXTGEAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQYKCAgICIAggGcICIAACN8QEgCkAKUApk2HACEAqACpTYgAIwCnTYkAqgAOACUAqwCsACgArQAXABcAFwApAEkAbgBuTZEAMQBuAGAAbgG3StcAbgBuTZkAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQXBCAiBBhUIgA8IgHCBBdkICIEGFAgSSla6HtMAOgA7AA5NnU2gAEyiAcABwYBJgEqiTaFNooEGFoEGIYAt2QAhACVNpQAOAChNpgAjAF9Np0roAcAAYAB/ABcAKQAxAG5Nr18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEGE4BJgA+ANIAAgAQIgQYX0wA6ADsADk2xTboATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKhNu028Tb1Nvk2/TcBNwU3CgQYYgQYZgQYagQYcgQYdgQYegQYfgQYggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdNoQBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBBhYICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXTaEAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQYWCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXTeQAF02hAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQYbgACBBhYICAgIgCCATwgIgAAI0wA6ADsADk3yTfMATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdNoQBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBBhYICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXTaEAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAKoAAgQYWCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF02hAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEGFggICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdNoQBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBBhYICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXTaEAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQYWCAgICIAggFQICIAACNkAIQAlTkEADgAoTkIAIwBfTkNK6AHBAGAAfwAXACkAMQBuTktfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBhOASoAPgDSAAIAECIEGItMAOgA7AA5OTU5VAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6dOVk5XTlhOWU5aTltOXIEGI4EGJIEGJYEGJoEGJ4EGKIEGKYAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcKJgAXTaIAbgBuAG4AMQBuALYCewBuAG4AFwBugACA+IAAgQYhCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF02iAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEGIQgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdNogBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBBiEICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcKVAAXTaIAbgBuAG4AMQBuALYCfgBuAG4AFwBugACA/IAAgQYhCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF02iAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEGIQgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdNogBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBBiEICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXTaIAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQYhCAgICIAggGcICIAACN8QEgCkAKUApk7IACEAqACpTskAIwCnTsoAqgAOACUAqwCsACgArQAXABcAFwApAEkAbgBuTtIAMQBuAGAAbgG3StgAbgBuTtoAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQXBCAiBBiwIgA8IgHCBBdoICIEGKwgSopKqFNMAOgA7AA5O3k7hAEyiAcABwYBJgEqiTuJO44EGLYEGOIAt2QAhACVO5gAOAChO5wAjAF9O6ErpAcAAYAB/ABcAKQAxAG5O8F8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEGKoBJgA+ANIAAgAQIgQYu0wA6ADsADk7yTvsATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKhO/E79Tv5O/08ATwFPAk8DgQYvgQYwgQYxgQYzgQY0gQY1gQY2gQY3gC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdO4gBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBBi0ICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXTuIAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQYtCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXTyUAF07iAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQYygACBBi0ICAgIgCCATwgIgAAI0wA6ADsADk8zTzQATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdO4gBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBBi0ICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXTuIAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAW4AAgQYtCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF07iAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEGLQgICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdO4gBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBBi0ICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXTuIAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQYtCAgICIAggFQICIAACNkAIQAlT4IADgAoT4MAIwBfT4RK6QHBAGAAfwAXACkAMQBuT4xfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBiqASoAPgDSAAIAECIEGOdMAOgA7AA5Pjk+WAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6dPl0+YT5lPmk+bT5xPnYEGOoEGO4EGPIEGPYEGPoEGP4EGQIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXTuMAbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgQY4CAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF07jAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEGOAgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdO4wBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBBjgICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCwQAXTuMAbgBuAG4AMQBuALYCfgBuAG4AFwBugACAbIAAgQY4CAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF07jAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEGOAgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdO4wBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBBjgICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXTuMAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQY4CAgICIAggGcICIAACN8QEgCkAKUAplAJACEAqACpUAoAIwCnUAsAqgAOACUAqwCsACgArQAXABcAFwApAEkAbgBuUBMAMQBuAGAAbgG3StkAbgBuUBsAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQXBCAiBBkMIgA8IgHCBBdsICIEGQggTAAAAAQI8wV7TADoAOwAOUB9QIgBMogHAAcGASYBKolAjUCSBBkSBBk+ALdkAIQAlUCcADgAoUCgAIwBfUClK6gHAAGAAfwAXACkAMQBuUDFfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBkGASYAPgDSAAIAECIEGRdMAOgA7AA5QM1A8AEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoUD1QPlA/UEBQQVBCUENQRIEGRoEGR4EGSIEGSoEGS4EGTIEGTYEGToAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXUCMAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQZECAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1AjAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEGRAgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF1BmABdQIwBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEGSYAAgQZECAgICIAggE8ICIAACNMAOgA7AA5QdFB1AEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXUCMAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQZECAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1AjAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEGRAgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdQIwBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBBkQICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXUCMAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQZECAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1AjAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEGRAgICAiAIIBUCAiAAAjZACEAJVDDAA4AKFDEACMAX1DFSuoBwQBgAH8AFwApADEAblDNXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQZBgEqAD4A0gACABAiBBlDTADoAOwAOUM9Q1wBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenUNhQ2VDaUNtQ3FDdUN6BBlGBBlKBBlOBBlSBBlWBBlaBBleALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXCiYAF1AkAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgPiAAIEGTwgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdQJABuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBBk8ICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXUCQAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQZPCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXClQAF1AkAG4AbgBuADEAbgC2An4AbgBuABcAboAAgPyAAIEGTwgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdQJABuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBBk8ICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXUCQAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQZPCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1AkAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEGTwgICAiAIIBnCAiAAAjfEBIApAClAKZRSgAhAKgAqVFLACMAp1FMAKoADgAlAKsArAAoAK0AFwAXABcAKQBJAG4AblFUADEAbgBgAG4Bt0raAG4AblFcAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEFwQgIgQZaCIAPCIBwgQXcCAiBBlkIEoxYNRvTADoAOwAOUWBRYwBMogHAAcGASYBKolFkUWWBBluBBmaALdkAIQAlUWgADgAoUWkAIwBfUWpK6wHAAGAAfwAXACkAMQBuUXJfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBliASYAPgDSAAIAECIEGXNMAOgA7AA5RdFF9AEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoUX5Rf1GAUYFRglGDUYRRhYEGXYEGXoEGX4EGYYEGYoEGY4EGZIEGZYAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXUWQAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQZbCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1FkAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEGWwgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF1GnABdRZABuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEGYIAAgQZbCAgICIAggE8ICIAACNMAOgA7AA5RtVG2AEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXUWQAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAW4AAgQZbCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAF1FkAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEGWwgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdRZABuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBBlsICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXUWQAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQZbCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1FkAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEGWwgICAiAIIBUCAiAAAjZACEAJVIEAA4AKFIFACMAX1IGSusBwQBgAH8AFwApADEAblIOXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQZYgEqAD4A0gACABAiBBmfTADoAOwAOUhBSGABMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenUhlSGlIbUhxSHVIeUh+BBmiBBmmBBmqBBmuBBmyBBm2BBm6ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1FlAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEGZggICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdRZQBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBBmYICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXUWUAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQZmCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAsEAF1FlAG4AbgBuADEAbgC2An4AbgBuABcAboAAgGyAAIEGZggICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdRZQBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBBmYICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXUWUAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQZmCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1FlAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEGZggICAiAIIBnCAiAAAjfEBIApAClAKZSiwAhAKgAqVKMACMAp1KNAKoADgAlAKsArAAoAK0AFwAXABcAKQBJAG4AblKVADEAbgBgAG4Bt0rbAG4AblKdAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEFwQgIgQZxCIAPCIBwgQXdCAiBBnAIEr0G1t/TADoAOwAOUqFSpABMogHAAcGASYBKolKlUqaBBnKBBn2ALdkAIQAlUqkADgAoUqoAIwBfUqtK7AHAAGAAfwAXACkAMQBuUrNfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBm+ASYAPgDSAAIAECIEGc9MAOgA7AA5StVK+AEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoUr9SwFLBUsJSw1LEUsVSxoEGdIEGdYEGdoEGeIEGeYEGeoEGe4EGfIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXUqUAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQZyCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1KlAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEGcggICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF1LoABdSpQBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEGd4AAgQZyCAgICIAggE8ICIAACNMAOgA7AA5S9lL3AEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXUqUAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQZyCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1KlAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEGcggICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdSpQBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBBnIICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXUqUAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQZyCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1KlAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEGcggICAiAIIBUCAiAAAjZACEAJVNFAA4AKFNGACMAX1NHSuwBwQBgAH8AFwApADEAblNPXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQZvgEqAD4A0gACABAiBBn7TADoAOwAOU1FTWQBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenU1pTW1NcU11TXlNfU2CBBn+BBoCBBoGBBoKBBoOBBoSBBoWALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXCOMAF1KmAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgN+AAIEGfQgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdSpgBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBBn0ICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXUqYAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQZ9CAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXCREAF1KmAG4AbgBuADEAbgC2An4AbgBuABcAboAAgOOAAIEGfQgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdSpgBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBBn0ICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXUqYAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQZ9CAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1KmAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEGfQgICAiAIIBnCAiAAAjfEBIApAClAKZTzAAhAKgAqVPNACMAp1POAKoADgAlAKsArAAoAK0AFwAXABcAKQBJAG4AblPWADEAbgBgAG4BtwF/AG4AblPeAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEFwQgIgQaICIAPCIBwgEAICIEGhwgSkD+ACtMAOgA7AA5T4lPlAEyiAcABwYBJgEqiU+ZT54EGiYEGlIAt2QAhACVT6gAOAChT6wAjAF9T7ErtAcAAYAB/ABcAKQAxAG5T9F8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEGhoBJgA+ANIAAgAQIgQaK0wA6ADsADlP2U/8ATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKhUAFQBVAJUA1QEVAVUBlQHgQaLgQaMgQaNgQaPgQaQgQaRgQaSgQaTgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdT5gBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBBokICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXU+YAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQaJCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXVCkAF1PmAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQaOgACBBokICAgIgCCATwgIgAAI0wA6ADsADlQ3VDgATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdT5gBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBBokICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXU+YAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAKoAAgQaJCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1PmAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEGiQgICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdT5gBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBBokICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXU+YAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQaJCAgICIAggFQICIAACNkAIQAlVIYADgAoVIcAIwBfVIhK7QHBAGAAfwAXACkAMQBuVJBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBoaASoAPgDSAAIAECIEGldMAOgA7AA5UklSaAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6dUm1ScVJ1UnlSfVKBUoYEGloEGl4EGmIEGmYEGmoEGm4EGnIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXU+cAbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgQaUCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1PnAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEGlAgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdT5wBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBBpQICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcQnAAXU+cAbgBuAG4AMQBuALYCfgBuAG4AFwBugACBAXKAAIEGlAgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdT5wBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBBpQICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXU+cAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQaUCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1PnAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEGlAgICAiAIIBnCAiAAAjfEBIApAClAKZVDQAhAKgAqVUOACMAp1UPAKoADgAlAKsArAAoAK0AFwAXABcAKQBJAG4AblUXADEAbgBgAG4Bt0rdAG4AblUfAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEFwQgIgQafCIAPCIBwgQXeCAiBBp4IEkvlVzPTADoAOwAOVSNVJgBMogHAAcGASYBKolUnVSiBBqCBBquALdkAIQAlVSsADgAoVSwAIwBfVS1K7gHAAGAAfwAXACkAMQBuVTVfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBp2ASYAPgDSAAIAECIEGodMAOgA7AA5VN1VAAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoVUFVQlVDVURVRVVGVUdVSIEGooEGo4EGpIEGpoEGp4EGqIEGqYEGqoAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXVScAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQagCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1UnAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEGoAgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF1VqABdVJwBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEGpYAAgQagCAgICIAggE8ICIAACNMAOgA7AA5VeFV5AEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXVScAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQagCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAF1UnAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEGoAgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdVJwBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBBqAICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXVScAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQagCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1UnAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEGoAgICAiAIIBUCAiAAAjZACEAJVXHAA4AKFXIACMAX1XJSu4BwQBgAH8AFwApADEAblXRXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQadgEqAD4A0gACABAiBBqzTADoAOwAOVdNV2wBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenVdxV3VXeVd9V4FXhVeKBBq2BBq6BBq+BBrCBBrGBBrKBBrOALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1UoAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEGqwgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdVKABuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBBqsICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXVSgAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQarCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXC5YAF1UoAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQEUgACBBqsICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXVSgAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQarCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1UoAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEGqwgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdVKABuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBBqsICAgIgCCAZwgIgAAI3xASAKQApQCmVk4AIQCoAKlWTwAjAKdWUACqAA4AJQCrAKwAKACtABcAFwAXACkASQBuAG5WWAAxAG4AYABuAbdK3gBuAG5WYABuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBBcEICIEGtgiADwiAcIEF3wgIgQa1CBItcoiP0wA6ADsADlZkVmcATKIBwAHBgEmASqJWaFZpgQa3gQbCgC3ZACEAJVZsAA4AKFZtACMAX1ZuSu8BwABgAH8AFwApADEAblZ2XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQa0gEmAD4A0gACABAiBBrjTADoAOwAOVnhWgQBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqFaCVoNWhFaFVoZWh1aIVomBBrmBBrqBBruBBr2BBr6BBr+BBsCBBsGALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1ZoAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIEGtwgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdWaABuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBBrcICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABdWqwAXVmgAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBBryAAIEGtwgICAiAIIBPCAiAAAjTADoAOwAOVrlWugBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1ZoAG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIEGtwgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwIyABdWaABuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIBbgACBBrcICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXVmgAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQa3CAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1ZoAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIEGtwgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdWaABuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBBrcICAgIgCCAVAgIgAAI2QAhACVXCAAOAChXCQAjAF9XCkrvAcEAYAB/ABcAKQAxAG5XEl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEGtIBKgA+ANIAAgAQIgQbD0wA6ADsADlcUVxwATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnp1cdVx5XH1cgVyFXIlcjgQbEgQbFgQbGgQbHgQbIgQbJgQbKgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwjjABdWaQBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIDfgACBBsIICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXVmkAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQbCCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1ZpAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEGwggICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwzYABdWaQBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIEBLIAAgQbCCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1ZpAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEGwggICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdWaQBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBBsIICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXVmkAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQbCCAgICIAggGcICIAACN8QEgCkAKUAplePACEAqACpV5AAIwCnV5EAqgAOACUAqwCsACgArQAXABcAFwApAEkAbgBuV5kAMQBuAGAAbgG3St8AbgBuV6EAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQXBCAiBBs0IgA8IgHCBBeAICIEGzAgSNlEQS9MAOgA7AA5XpVeoAEyiAcABwYBJgEqiV6lXqoEGzoEG2YAt2QAhACVXrQAOAChXrgAjAF9Xr0rwAcAAYAB/ABcAKQAxAG5Xt18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEGy4BJgA+ANIAAgAQIgQbP0wA6ADsADle5V8IATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKhXw1fEV8VXxlfHV8hXyVfKgQbQgQbRgQbSgQbUgQbVgQbWgQbXgQbYgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdXqQBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBBs4ICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXV6kAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQbOCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXV+wAF1epAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQbTgACBBs4ICAgIgCCATwgIgAAI0wA6ADsADlf6V/sATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdXqQBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIAqgACBBs4ICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCMgAXV6kAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAW4AAgQbOCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1epAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEGzggICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdXqQBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBBs4ICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXV6kAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQbOCAgICIAggFQICIAACNkAIQAlWEkADgAoWEoAIwBfWEtK8AHBAGAAfwAXACkAMQBuWFNfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBsuASoAPgDSAAIAECIEG2tMAOgA7AA5YVVhdAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6dYXlhfWGBYYVhiWGNYZIEG24EG3IEG3YEG3oEG34EG4IEG4YAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXV6oAbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgQbZCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1eqAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEG2QgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdXqgBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBBtkICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcCwQAXV6oAbgBuAG4AMQBuALYCfgBuAG4AFwBugACAbIAAgQbZCAgICIAggGQICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1eqAG4AbgBuADEAbgC2An8AbgBuABcAboAAgACAAIEG2QgICAiAIIBlCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdXqgBuAG4AbgAxAG4AtgKAAG4AbgAXAG6AAIAAgACBBtkICAgIgCCAZggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXV6oAbgBuAG4AMQBuALYCgQBuAG4AFwBugACAAIAAgQbZCAgICIAggGcICIAACN8QEgCkAKUApljQACEAqACpWNEAIwCnWNIAqgAOACUAqwCsACgArQAXABcAFwApAEkAbgBuWNoAMQBuAGAAbgG3GBEAbgBuWOIAbl8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQXBCAiBBuQIgA8IgHCBAgYICIEG4wgSX60lldMAOgA7AA5Y5ljpAEyiAcABwYBJgEqiWOpY64EG5YEG8IAt2QAhACVY7gAOAChY7wAjAF9Y8ErxAcAAYAB/ABcAKQAxAG5Y+F8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEG4oBJgA+ANIAAgAQIgQbm0wA6ADsADlj6WQMATKgB1gHXAdgB2QHaAdsB3AHdgE2AToBPgFCAUYBSgFOAVKhZBFkFWQZZB1kIWQlZClkLgQbngQbogQbpgQbrgQbsgQbtgQbugQbvgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdY6gBuAG4AbgAxAG4AtgHWAG4AbgAXAG6AAIAqgACBBuUICAgIgCCATQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXWOoAbgBuAG4AMQBuALYB1wBuAG4AFwBugACAAIAAgQblCAgICIAggE4ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXWS0AF1jqAG4AbgBuADEAbgC2AdgAbgBuABcAboAAgQbqgACBBuUICAgIgCCATwgIgAAI0wA6ADsADlk7WTwATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwIyABdY6gBuAG4AbgAxAG4AtgHZAG4AbgAXAG6AAIBbgACBBuUICAgIgCCAUAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXWOoAbgBuAG4AMQBuALYB2gBuAG4AFwBugACAKoAAgQblCAgICIAggFEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1jqAG4AbgBuADEAbgC2AdsAbgBuABcAboAAgCqAAIEG5QgICAiAIIBSCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdY6gBuAG4AbgAxAG4AtgHcAG4AbgAXAG6AAIAAgACBBuUICAgIgCCAUwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXWOoAbgBuAG4AMQBuALYB3QBuAG4AFwBugACAKoAAgQblCAgICIAggFQICIAACNkAIQAlWYoADgAoWYsAIwBfWYxK8QHBAGAAfwAXACkAMQBuWZRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBuKASoAPgDSAAIAECIEG8dMAOgA7AA5ZllmeAEynAnsCfAJ9An4CfwKAAoGAYYBigGOAZIBlgGaAZ6dZn1mgWaFZolmjWaRZpYEG8oEG84EG9IEG9YEG9oEG94EG+IAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXWOsAbgBuAG4AMQBuALYCewBuAG4AFwBugACAAIAAgQbwCAgICIAggGEICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1jrAG4AbgBuADEAbgC2AnwAbgBuABcAboAAgCqAAIEG8AgICAiAIIBiCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdY6wBuAG4AbgAxAG4AtgJ9AG4AbgAXAG6AAIAAgACBBvAICAgIgCCAYwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcLlgAXWOsAbgBuAG4AMQBuALYCfgBuAG4AFwBugACBARSAAIEG8AgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdY6wBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBBvAICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXWOsAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQbwCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1jrAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEG8AgICAiAIIBnCAiAAAjfEBIApAClAKZaEQAhAKgAqVoSACMAp1oTAKoADgAlAKsArAAoAK0AFwAXABcAKQBJAG4AblobADEAbgBgAG4Bt0rhAG4AblojAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEFwQgIgQb7CIAPCIBwgQXhCAiBBvoIEmz77vbTADoAOwAOWidaKgBMogHAAcGASYBKolorWiyBBvyBBweALdkAIQAlWi8ADgAoWjAAIwBfWjFK8gHAAGAAfwAXACkAMQBuWjlfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBvmASYAPgDSAAIAECIEG/dMAOgA7AA5aO1pEAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoWkVaRlpHWkhaSVpKWktaTIEG/oEG/4EHAIEHAoEHA4EHBIEHBYEHBoAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXWisAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQb8CAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1orAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEG/AgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF1puABdaKwBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEHAYAAgQb8CAgICIAggE8ICIAACNMAOgA7AA5afFp9AEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXWisAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQb8CAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1orAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEG/AgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdaKwBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBBvwICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXWisAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQb8CAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1orAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEG/AgICAiAIIBUCAiAAAjZACEAJVrLAA4AKFrMACMAX1rNSvIBwQBgAH8AFwApADEAblrVXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQb5gEqAD4A0gACABAiBBwjTADoAOwAOWtda3wBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenWuBa4VriWuNa5FrlWuaBBwmBBwqBBwuBBwyBBw2BBw6BBw+ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1osAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEHBwgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdaLABuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBBwcICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXWiwAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQcHCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAsEAF1osAG4AbgBuADEAbgC2An4AbgBuABcAboAAgGyAAIEHBwgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdaLABuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBBwcICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXWiwAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQcHCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1osAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEHBwgICAiAIIBnCAiAAAjfEBIApAClAKZbUgAhAKgAqVtTACMAp1tUAKoADgAlAKsArAAoAK0AFwAXABcAKQBJAG4AbltcADEAbgBgAG4Bt0riAG4AbltkAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEFwQgIgQcSCIAPCIBwgQXiCAiBBxEIEld+VyHTADoAOwAOW2hbawBMogHAAcGASYBKoltsW22BBxOBBx6ALdkAIQAlW3AADgAoW3EAIwBfW3JK8wHAAGAAfwAXACkAMQBuW3pfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBxCASYAPgDSAAIAECIEHFNMAOgA7AA5bfFuFAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoW4Zbh1uIW4lbiluLW4xbjYEHFYEHFoEHF4EHGYEHGoEHG4EHHIEHHYAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXW2wAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQcTCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1tsAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEHEwgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF1uvABdbbABuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEHGIAAgQcTCAgICIAggE8ICIAACNMAOgA7AA5bvVu+AEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXW2wAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQcTCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAF1tsAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEHEwgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdbbABuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBBxMICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXW2wAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQcTCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1tsAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEHEwgICAiAIIBUCAiAAAjZACEAJVwMAA4AKFwNACMAX1wOSvMBwQBgAH8AFwApADEAblwWXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQcQgEqAD4A0gACABAiBBx/TADoAOwAOXBhcIABMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenXCFcIlwjXCRcJVwmXCeBByCBByGBByKBByOBBySBByWBByaALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1ttAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEHHggICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdbbQBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBBx4ICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXW20AbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQceCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXBo0AF1ttAG4AbgBuADEAbgC2An4AbgBuABcAboAAgLOAAIEHHggICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdbbQBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBBx4ICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXW20AbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQceCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1ttAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEHHggICAiAIIBnCAiAAAjfEBIApAClAKZckwAhAKgAqVyUACMAp1yVAKoADgAlAKsArAAoAK0AFwAXABcAKQBJAG4AblydADEAbgBgAG4Bt0rjAG4AblylAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEFwQgIgQcpCIAPCIBwgQXjCAiBBygIEsJ+qizTADoAOwAOXKlcrABMogHAAcGASYBKolytXK6BByqBBzWALdkAIQAlXLEADgAoXLIAIwBfXLNK9AHAAGAAfwAXACkAMQBuXLtfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBByeASYAPgDSAAIAECIEHK9MAOgA7AA5cvVzGAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoXMdcyFzJXMpcy1zMXM1czoEHLIEHLYEHLoEHMIEHMYEHMoEHM4EHNIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXXK0AbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQcqCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1ytAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEHKggICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF1zwABdcrQBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEHL4AAgQcqCAgICIAggE8ICIAACNMAOgA7AA5c/lz/AEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXXK0AbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQcqCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1ytAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEHKggICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdcrQBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBByoICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXXK0AbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQcqCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF1ytAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEHKggICAiAIIBUCAiAAAjZACEAJV1NAA4AKF1OACMAX11PSvQBwQBgAH8AFwApADEAbl1XXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQcngEqAD4A0gACABAiBBzbTADoAOwAOXVldYQBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenXWJdY11kXWVdZl1nXWiBBzeBBziBBzmBBzqBBzuBBzyBBz2ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1yuAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEHNQgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdcrgBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBBzUICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXXK4AbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQc1CAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAsEAF1yuAG4AbgBuADEAbgC2An4AbgBuABcAboAAgGyAAIEHNQgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdcrgBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBBzUICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXXK4AbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQc1CAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF1yuAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEHNQgICAiAIIBnCAiAAAjfEBIApAClAKZd1AAhAKgAqV3VACMAp13WAKoADgAlAKsArAAoAK0AFwAXABcAKQBJAG4Abl3eADEAbgBgAG4Bt0rkAG4Abl3mAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEFwQgIgQdACIAPCIBwgQXkCAiBBz8IEu0fPGfTADoAOwAOXepd7QBMogHAAcGASYBKol3uXe+BB0GBB0yALdkAIQAlXfIADgAoXfMAIwBfXfRK9QHAAGAAfwAXACkAMQBuXfxfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBz6ASYAPgDSAAIAECIEHQtMAOgA7AA5d/l4HAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoXgheCV4KXgteDF4NXg5eD4EHQ4EHRIEHRYEHR4EHSIEHSYEHSoEHS4At3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXXe4AbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQdBCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF13uAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEHQQgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF14xABdd7gBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEHRoAAgQdBCAgICIAggE8ICIAACNMAOgA7AA5eP15AAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXXe4AbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQdBCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAF13uAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEHQQgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdd7gBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBB0EICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXXe4AbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQdBCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF13uAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEHQQgICAiAIIBUCAiAAAjZACEAJV6OAA4AKF6PACMAX16QSvUBwQBgAH8AFwApADEAbl6YXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQc+gEqAD4A0gACABAiBB03TADoAOwAOXppeogBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenXqNepF6lXqZep16oXqmBB06BB0+BB1CBB1GBB1KBB1OBB1SALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF13vAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEHTAgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdd7wBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBB0wICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXXe8AbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQdMCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXOqUAF13vAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQSngACBB0wICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXXe8AbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQdMCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF13vAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEHTAgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdd7wBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBB0wICAgIgCCAZwgIgAAI0gA7AA5fFQC+oIAf3xAQXxhfGV8aXxsAIV8cXx0AI18eXx8ADgAlXyBfIQAoAF8AYF8jACkAKQAUXycAZgAxACkAYABpAEIAYF8uXy8Abl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZV8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc2R1cGxpY2F0ZXNfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zc3RvcmFnZYAPgQdpgASABIACgQdYgQHqgASAD4EB7IALgA+BB8eBB1cIEwAAAAEPPNR/0wA6ADsADl8zXzUATKEAc4ARoV82gQdZgC3ZACEAJV85AA4AKF86ACMAX187AEoAcwBgAH8AFwApADEAbl9DXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQdWgBGAD4A0gACABAiBB1rTADoAOwAOX0VfTwBMqQCGAIcAiACJAIoAiwCMAI0AjoAUgBWAFoAXgBiAGYAagBuAHKlfUF9RX1JfU19UX1VfVl9XX1iBB1uBB12BB16BB2CBB2GBB2OBB2SBB2aBB2eALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXX1wAF182AG4AbgBuADEAbgC2AIYAbgBuABcAboAAgQdcgACBB1kICAgIgCCAFAgIgAAI0gA7AA5fagC+oIAf3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXXzYAbgBuAG4AMQBuALYAhwBuAG4AFwBugACAAIAAgQdZCAgICIAggBUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXX30AF182AG4AbgBuADEAbgC2AIgAbgBuABcAboAAgQdfgACBB1kICAgIgCCAFggIgAAI0gA7AA5fiwC+oIAf3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXXzYAbgBuAG4AMQBuALYAiQBuAG4AFwBugACAAIAAgQdZCAgICIAggBcICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXX54AF182AG4AbgBuADEAbgC2AIoAbgBuABcAboAAgQdigACBB1kICAgIgCCAGAgIgAAI0gA7AA5frAC+oIAf3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXXzYAbgBuAG4AMQBuALYAiwBuAG4AFwBugACAKoAAgQdZCAgICIAggBkICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXX78AF182AG4AbgBuADEAbgC2AIwAbgBuABcAboAAgQdlgACBB1kICAgIgCCAGggIgAAI0wA6ADsADl/NX84ATKCggC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwE9ABdfNgBuAG4AbgAxAG4AtgCNAG4AbgAXAG6AAIAvgACBB1kICAgIgCCAGwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABdf4QAXXzYAbgBuAG4AMQBuALYAjgBuAG4AFwBugACBB2iAAIEHWQgICAiAIIAcCAiAAAhaLlJlc2Vydm9pctMAOgA7AA5f8F/1AEykAXsA8F/zAYKAPIAlgQdqgEOkX/Zf91/4X/mBB2uBB4KBB5mBB7CALVZ2b2x1bWXfEBIApAClAKZf/QAhAKgAqV/+ACMAp1//AKoADgAlAKsArAAoAK0AFwAXABcAKQBKAG4AbmAHADEAbgBgAG4BtwF7AG4AbmAPAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEHVggIgQdtCIAPCIBwgDwICIEHbAgTAAAAARLSLTXTADoAOwAOYBNgFgBMogHAAcGASYBKomAXYBiBB26BB3mALdkAIQAlYBsADgAoYBwAIwBfYB1f9gHAAGAAfwAXACkAMQBuYCVfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBB2uASYAPgDSAAIAECIEHb9MAOgA7AA5gJ2AwAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoYDFgMmAzYDRgNWA2YDdgOIEHcIEHcYEHcoEHdIEHdYEHdoEHd4EHeIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXYBcAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQduCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2AXAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEHbggICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF2BaABdgFwBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEHc4AAgQduCAgICIAggE8ICIAACNMAOgA7AA5gaGBpAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXYBcAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQduCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF2AXAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEHbggICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdgFwBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBB24ICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXYBcAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQduCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF2AXAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEHbggICAiAIIBUCAiAAAjZACEAJWC3AA4AKGC4ACMAX2C5X/YBwQBgAH8AFwApADEAbmDBXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQdrgEqAD4A0gACABAiBB3rTADoAOwAOYMNgywBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenYMxgzWDOYM9g0GDRYNKBB3uBB3yBB32BB36BB3+BB4CBB4GALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2AYAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEHeQgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdgGABuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBB3kICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXYBgAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQd5CAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXC5YAF2AYAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQEUgACBB3kICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXYBgAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQd5CAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2AYAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEHeQgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdgGABuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBB3kICAgIgCCAZwgIgAAI3xASAKQApQCmYT4AIQCoAKlhPwAjAKdhQACqAA4AJQCrAKwAKACtABcAFwAXACkASgBuAG5hSAAxAG4AYABuAbcA8ABuAG5hUABuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBB1YICIEHhAiADwiAcIAlCAiBB4MIEvH6ZVzTADoAOwAOYVRhVwBMogHAAcGASYBKomFYYVmBB4WBB5CALdkAIQAlYVwADgAoYV0AIwBfYV5f9wHAAGAAfwAXACkAMQBuYWZfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBB4KASYAPgDSAAIAECIEHhtMAOgA7AA5haGFxAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoYXJhc2F0YXVhdmF3YXhheYEHh4EHiIEHiYEHi4EHjIEHjYEHjoEHj4At3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXYVgAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQeFCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2FYAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEHhQgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF2GbABdhWABuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEHioAAgQeFCAgICIAggE8ICIAACNMAOgA7AA5hqWGqAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXYVgAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQeFCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAjIAF2FYAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgFuAAIEHhQgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdhWABuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBB4UICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXYVgAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQeFCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF2FYAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEHhQgICAiAIIBUCAiAAAjZACEAJWH4AA4AKGH5ACMAX2H6X/cBwQBgAH8AFwApADEAbmICXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQeCgEqAD4A0gACABAiBB5HTADoAOwAOYgRiDABMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenYg1iDmIPYhBiEWISYhOBB5KBB5OBB5SBB5WBB5aBB5eBB5iALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2FZAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEHkAgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdhWQBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBB5AICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXYVkAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQeQCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXBo0AF2FZAG4AbgBuADEAbgC2An4AbgBuABcAboAAgLOAAIEHkAgICAiAIIBkCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdhWQBuAG4AbgAxAG4AtgJ/AG4AbgAXAG6AAIAAgACBB5AICAgIgCCAZQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXYVkAbgBuAG4AMQBuALYCgABuAG4AFwBugACAAIAAgQeQCAgICIAggGYICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2FZAG4AbgBuADEAbgC2AoEAbgBuABcAboAAgACAAIEHkAgICAiAIIBnCAiAAAjfEBIApAClAKZifwAhAKgAqWKAACMAp2KBAKoADgAlAKsArAAoAK0AFwAXABcAKQBKAG4AbmKJADEAbgBgAG4Bt1/zAG4AbmKRAG5fECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEHVggIgQebCIAPCIBwgQdqCAiBB5oIEo3C6rnTADoAOwAOYpVimABMogHAAcGASYBKomKZYpqBB5yBB6eALdkAIQAlYp0ADgAoYp4AIwBfYp9f+AHAAGAAfwAXACkAMQBuYqdfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBB5mASYAPgDSAAIAECIEHndMAOgA7AA5iqWKyAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoYrNitGK1YrZit2K4YrliuoEHnoEHn4EHoIEHooEHo4EHpIEHpYEHpoAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXYpkAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQecCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2KZAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEHnAgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF2LcABdimQBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEHoYAAgQecCAgICIAggE8ICIAACNMAOgA7AA5i6mLrAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXYpkAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQecCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF2KZAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEHnAgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdimQBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBB5wICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXYpkAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQecCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF2KZAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEHnAgICAiAIIBUCAiAAAjZACEAJWM5AA4AKGM6ACMAX2M7X/gBwQBgAH8AFwApADEAbmNDXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQeZgEqAD4A0gACABAiBB6jTADoAOwAOY0VjTQBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenY05jT2NQY1FjUmNTY1SBB6mBB6qBB6uBB6yBB62BB66BB6+ALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2KaAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEHpwgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdimgBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBB6cICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXYpoAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQenCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXEJwAF2KaAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQFygACBB6cICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXYpoAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQenCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2KaAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEHpwgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdimgBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBB6cICAgIgCCAZwgIgAAI3xASAKQApQCmY8AAIQCoAKljwQAjAKdjwgCqAA4AJQCrAKwAKACtABcAFwAXACkASgBuAG5jygAxAG4AYABuAbcBggBuAG5j0gBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBB1YICIEHsgiADwiAcIBDCAiBB7EIEu/n1QrTADoAOwAOY9Zj2QBMogHAAcGASYBKomPaY9uBB7OBB76ALdkAIQAlY94ADgAoY98AIwBfY+Bf+QHAAGAAfwAXACkAMQBuY+hfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBB7CASYAPgDSAAIAECIEHtNMAOgA7AA5j6mPzAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoY/Rj9WP2Y/dj+GP5Y/pj+4EHtYEHtoEHt4EHuYEHuoEHu4EHvIEHvYAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXY9oAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQezCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2PaAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEHswgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF2QdABdj2gBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEHuIAAgQezCAgICIAggE8ICIAACNMAOgA7AA5kK2QsAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXY9oAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQezCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF2PaAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEHswgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdj2gBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBB7MICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXY9oAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQezCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF2PaAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEHswgICAiAIIBUCAiAAAjZACEAJWR6AA4AKGR7ACMAX2R8X/kBwQBgAH8AFwApADEAbmSEXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQewgEqAD4A0gACABAiBB7/TADoAOwAOZIZkjgBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenZI9kkGSRZJJkk2SUZJWBB8CBB8GBB8KBB8OBB8SBB8WBB8aALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2PbAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEHvggICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdj2wBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBB74ICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXY9sAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQe+CAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXC5YAF2PbAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQEUgACBB74ICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXY9sAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQe+CAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2PbAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEHvggICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdj2wBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBB74ICAgIgCCAZwgIgAAI0gA7AA5lAQC+oIAf3xAQZQRlBWUGZQcAIWUIZQkAI2UKZQsADgAlZQxlDQAoAF8AYGUPACkAKQAUZRMAZgAxACkAYABpAEMAYGUaZRsAbl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZV8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc2R1cGxpY2F0ZXNfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zc3RvcmFnZYAPgQfbgASABIACgQfKgQHqgASAD4EB7IAMgA+BCCKBB8kIEkvrm/3TADoAOwAOZR9lIQBMoQBzgBGhZSKBB8uALdkAIQAlZSUADgAoZSYAIwBfZScASwBzAGAAfwAXACkAMQBuZS9fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBB8iAEYAPgDSAAIAECIEHzNMAOgA7AA5lMWU7AEypAIYAhwCIAIkAigCLAIwAjQCOgBSAFYAWgBeAGIAZgBqAG4AcqWU8ZT1lPmU/ZUBlQWVCZUNlRIEHzYEHz4EH0IEH0oEH04EH1YEH1oEH2IEH2YAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABdlSAAXZSIAbgBuAG4AMQBuALYAhgBuAG4AFwBugACBB86AAIEHywgICAiAIIAUCAiAAAjSADsADmVWAL6ggB/fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdlIgBuAG4AbgAxAG4AtgCHAG4AbgAXAG6AAIAAgACBB8sICAgIgCCAFQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABdlaQAXZSIAbgBuAG4AMQBuALYAiABuAG4AFwBugACBB9GAAIEHywgICAiAIIAWCAiAAAjSADsADmV3AL6ggB/fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdlIgBuAG4AbgAxAG4AtgCJAG4AbgAXAG6AAIAAgACBB8sICAgIgCCAFwgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABdligAXZSIAbgBuAG4AMQBuALYAigBuAG4AFwBugACBB9SAAIEHywgICAiAIIAYCAiAAAjSADsADmWYAL6ggB/fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdlIgBuAG4AbgAxAG4AtgCLAG4AbgAXAG6AAIAqgACBB8sICAgIgCCAGQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABdlqwAXZSIAbgBuAG4AMQBuALYAjABuAG4AFwBugACBB9eAAIEHywgICAiAIIAaCAiAAAjTADoAOwAOZbllugBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXAT0AF2UiAG4AbgBuADEAbgC2AI0AbgBuABcAboAAgC+AAIEHywgICAiAIIAbCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF2XNABdlIgBuAG4AbgAxAG4AtgCOAG4AbgAXAG6AAIEH2oAAgQfLCAgICIAggBwICIAACF8QDy5TZXR0aW5nc09iamVjdNMAOgA7AA5l3GXgAEyjAXsxAWXfgDyBA+OBB9yjZeFl4mXjgQfdgQf0gQgLgC1fEBNtb2RpZmljYXRpb25Db3VudGVy3xASAKQApQCmZecAIQCoAKll6AAjAKdl6QCqAA4AJQCrAKwAKACtABcAFwAXACkASwBuAG5l8QAxAG4AYABuAbcBewBuAG5l+QBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBB8gICIEH3wiADwiAcIA8CAiBB94IEuqJZDnTADoAOwAOZf1mAABMogHAAcGASYBKomYBZgKBB+CBB+uALdkAIQAlZgUADgAoZgYAIwBfZgdl4QHAAGAAfwAXACkAMQBuZg9fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBB92ASYAPgDSAAIAECIEH4dMAOgA7AA5mEWYaAEyoAdYB1wHYAdkB2gHbAdwB3YBNgE6AT4BQgFGAUoBTgFSoZhtmHGYdZh5mH2YgZiFmIoEH4oEH44EH5IEH5oEH54EH6IEH6YEH6oAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXZgEAbgBuAG4AMQBuALYB1gBuAG4AFwBugACAKoAAgQfgCAgICIAggE0ICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2YBAG4AbgBuADEAbgC2AdcAbgBuABcAboAAgACAAIEH4AgICAiAIIBOCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AF2ZEABdmAQBuAG4AbgAxAG4AtgHYAG4AbgAXAG6AAIEH5YAAgQfgCAgICIAggE8ICIAACNMAOgA7AA5mUmZTAEygoIAt3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXZgEAbgBuAG4AMQBuALYB2QBuAG4AFwBugACAKoAAgQfgCAgICIAggFAICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF2YBAG4AbgBuADEAbgC2AdoAbgBuABcAboAAgCqAAIEH4AgICAiAIIBRCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdmAQBuAG4AbgAxAG4AtgHbAG4AbgAXAG6AAIAqgACBB+AICAgIgCCAUggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXZgEAbgBuAG4AMQBuALYB3ABuAG4AFwBugACAAIAAgQfgCAgICIAggFMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF2YBAG4AbgBuADEAbgC2Ad0AbgBuABcAboAAgCqAAIEH4AgICAiAIIBUCAiAAAjZACEAJWahAA4AKGaiACMAX2ajZeEBwQBgAH8AFwApADEAbmarXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQfdgEqAD4A0gACABAiBB+zTADoAOwAOZq1mtQBMpwJ7AnwCfQJ+An8CgAKBgGGAYoBjgGSAZYBmgGenZrZmt2a4Zrlmuma7ZryBB+2BB+6BB++BB/CBB/GBB/KBB/OALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2YCAG4AbgBuADEAbgC2AnsAbgBuABcAboAAgACAAIEH6wgICAiAIIBhCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdmAgBuAG4AbgAxAG4AtgJ8AG4AbgAXAG6AAIAqgACBB+sICAgIgCCAYggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXZgIAbgBuAG4AMQBuALYCfQBuAG4AFwBugACAAIAAgQfrCAgICIAggGMICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXC5YAF2YCAG4AbgBuADEAbgC2An4AbgBuABcAboAAgQEUgACBB+sICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXZgIAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQfrCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2YCAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEH6wgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdmAgBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBB+sICAgIgCCAZwgIgAAI3xASAKQApQCmZygAIQCoAKlnKQAjAKdnKgCqAA4AJQCrAKwAKACtABcAFwAXACkASwBuAG5nMgAxAG4AYABuAbcxAQBuAG5nOgBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBB8gICIEH9giADwiAcIED4wgIgQf1CBJ6zEZ60wA6ADsADmc+Z0EATKIBwAHBgEmASqJnQmdDgQf3gQgCgC3ZACEAJWdGAA4AKGdHACMAX2dIZeIBwABgAH8AFwApADEAbmdQXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQf0gEmAD4A0gACABAiBB/jTADoAOwAOZ1JnWwBMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqGdcZ11nXmdfZ2BnYWdiZ2OBB/mBB/qBB/uBB/2BB/6BB/+BCACBCAGALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF2dCAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIEH9wgICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdnQgBuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBB/cICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABdnhQAXZ0IAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBB/yAAIEH9wgICAiAIIBPCAiAAAjTADoAOwAOZ5NnlABMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF2dCAG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIEH9wgICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdnQgBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIAqgACBB/cICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXZ0IAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQf3CAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2dCAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIEH9wgICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdnQgBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBB/cICAgIgCCAVAgIgAAI2QAhACVn4gAOAChn4wAjAF9n5GXiAcEAYAB/ABcAKQAxAG5n7F8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEH9IBKgA+ANIAAgAQIgQgD0wA6ADsADmfuZ/YATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnp2f3Z/hn+Wf6Z/tn/Gf9gQgEgQgFgQgGgQgHgQgIgQgJgQgKgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdnQwBuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIAAgACBCAIICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXZ0MAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQgCCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2dDAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEIAggICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwaNABdnQwBuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAICzgACBCAIICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXZ0MAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQgCCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2dDAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEIAggICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdnQwBuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBCAIICAgIgCCAZwgIgAAI3xASAKQApQCmaGkAIQCoAKloagAjAKdoawCqAA4AJQCrAKwAKACtABcAFwAXACkASwBuAG5ocwAxAG4AYABuAbdl3wBuAG5oewBuXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBB8gICIEIDQiADwiAcIEH3AgIgQgMCBIzjp5K0wA6ADsADmh/aIIATKIBwAHBgEmASqJog2iEgQgOgQgZgC3ZACEAJWiHAA4AKGiIACMAX2iJZeMBwABgAH8AFwApADEAbmiRXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQgLgEmAD4A0gACABAiBCA/TADoAOwAOaJNonABMqAHWAdcB2AHZAdoB2wHcAd2ATYBOgE+AUIBRgFKAU4BUqGidaJ5on2igaKFoomijaKSBCBCBCBGBCBKBCBSBCBWBCBaBCBeBCBiALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF2iDAG4AbgBuADEAbgC2AdYAbgBuABcAboAAgCqAAIEIDggICAiAIIBNCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdogwBuAG4AbgAxAG4AtgHXAG4AbgAXAG6AAIAAgACBCA4ICAgIgCCATggIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABdoxgAXaIMAbgBuAG4AMQBuALYB2ABuAG4AFwBugACBCBOAAIEIDggICAiAIIBPCAiAAAjTADoAOwAOaNRo1QBMoKCALd8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXARYAF2iDAG4AbgBuADEAbgC2AdkAbgBuABcAboAAgCqAAIEIDggICAiAIIBQCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdogwBuAG4AbgAxAG4AtgHaAG4AbgAXAG6AAIAqgACBCA4ICAgIgCCAUQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXaIMAbgBuAG4AMQBuALYB2wBuAG4AFwBugACAKoAAgQgOCAgICIAggFIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2iDAG4AbgBuADEAbgC2AdwAbgBuABcAboAAgACAAIEIDggICAiAIIBTCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwEWABdogwBuAG4AbgAxAG4AtgHdAG4AbgAXAG6AAIAqgACBCA4ICAgIgCCAVAgIgAAI2QAhACVpIwAOAChpJAAjAF9pJWXjAcEAYAB/ABcAKQAxAG5pLV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEIC4BKgA+ANIAAgAQIgQga0wA6ADsADmkvaTcATKcCewJ8An0CfgJ/AoACgYBhgGKAY4BkgGWAZoBnp2k4aTlpOmk7aTxpPWk+gQgbgQgcgQgdgQgegQgfgQgggQghgC3fEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwjjABdohABuAG4AbgAxAG4AtgJ7AG4AbgAXAG6AAIDfgACBCBkICAgIgCCAYQgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcBFgAXaIQAbgBuAG4AMQBuALYCfABuAG4AFwBugACAKoAAgQgZCAgICIAggGIICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2iEAG4AbgBuADEAbgC2An0AbgBuABcAboAAgACAAIEIGQgICAiAIIBjCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwkRABdohABuAG4AbgAxAG4AtgJ+AG4AbgAXAG6AAIDjgACBCBkICAgIgCCAZAgIgAAI3xAPAKQApQCmACEApwCoAKkAIwCqAA4AJQCrAKwAKACtABcAFwAXaIQAbgBuAG4AMQBuALYCfwBuAG4AFwBugACAAIAAgQgZCAgICIAggGUICIAACN8QDwCkAKUApgAhAKcAqACpACMAqgAOACUAqwCsACgArQAXABcAF2iEAG4AbgBuADEAbgC2AoAAbgBuABcAboAAgACAAIEIGQgICAiAIIBmCAiAAAjfEA8ApAClAKYAIQCnAKgAqQAjAKoADgAlAKsArAAoAK0AFwAXABdohABuAG4AbgAxAG4AtgKBAG4AbgAXAG6AAIAAgACBCBkICAgIgCCAZwgIgAAI0gA7AA5pqgC+oIAf0wA6ADsADmmtaa4ATKCggC3TADoAOwAOabFpsgBMoKCALdMAOgA7AA5ptWm2AEygoIAt0gDAAMFpuWm6XlhETW9kZWxQYWNrYWdlpmm7abxpvWm+ab8AxV5YRE1vZGVsUGFja2FnZV8QD1hEVU1MUGFja2FnZUltcF8QEVhEVU1MTmFtZXNwYWNlSW1wXxAUWERVTUxOYW1lZEVsZW1lbnRJbXBfEA9YRFVNTEVsZW1lbnRJbXDSADsADmnBAL6ggB/TADoAOwAOacRpxQBMoKCALdIAwADBachpyVlYRFBNTW9kZWyjachpygDFV1hETW9kZWwAAAAIAAAAGQAAACIAAAAsAAAAMQAAADoAAAA/AAAAUQAAAFYAAABbAAAAXQAAELUAABC7AAAQ2AAAEOoAABDxAAAQ/gAAEREAABEpAAARNwAAEVEAABFTAAARVgAAEVkAABFbAAARXgAAEWAAABFjAAARnAAAEbsAABHYAAAR9wAAEgkAABIpAAASMAAAEk4AABJaAAASdgAAEnwAABKeAAASvwAAEtIAABLUAAAS1wAAEtoAABLcAAAS3gAAEuAAABLjAAAS5gAAEugAABLqAAAS7AAAEu4AABLwAAAS8gAAEvMAABL3AAATBAAAEwwAABMXAAATJgAAEygAABMqAAATLAAAEy4AABMwAAATMgAAEzQAABNDAAATRQAAE0gAABNLAAATTgAAE1EAABNUAAATVwAAE1kAABNjAAATgQAAE5gAABOrAAATwQAAE8sAABPaAAAUHQAAFEEAABRlAAAUiAAAFK8AABTPAAAU9gAAFR0AABU9AAAVYQAAFYUAABWRAAAVkwAAFZUAABWXAAAVmQAAFZsAABWdAAAVoAAAFaIAABWkAAAVpwAAFakAABWrAAAVrgAAFbAAABWxAAAVtgAAFb4AABXLAAAVzgAAFdAAABXTAAAV1QAAFdcAABXmAAAWCwAAFi8AABZWAAAWegAAFnwAABZ+AAAWgAAAFoIAABaEAAAWhgAAFocAABaJAAAWlgAAFqkAABarAAAWrQAAFq8AABaxAAAWswAAFrUAABa3AAAWuQAAFrsAABbOAAAW0AAAFtIAABbUAAAW1gAAFtgAABbaAAAW3AAAFt4AABbgAAAW4gAAFvgAABcLAAAXJwAAF0QAABdgAAAXdAAAF4YAABecAAAXtQAAF/QAABf6AAAYAwAAGBAAABgcAAAYJgAAGDAAABg7AAAYRgAAGFMAABhbAAAYXQAAGF8AABhhAAAYYwAAGGQAABhlAAAYZgAAGGcAABhpAAAYawAAGGwAABhtAAAYbwAAGHAAABh5AAAYegAAGHwAABiFAAAYkAAAGJkAABioAAAYrwAAGLcAABjAAAAYyQAAGNwAABjlAAAY+AAAGQ8AABkhAAAZYAAAGWIAABlkAAAZZgAAGWgAABlpAAAZagAAGWsAABlsAAAZbgAAGXAAABlxAAAZcgAAGXQAABl1AAAZtAAAGbYAABm4AAAZugAAGbwAABm9AAAZvgAAGb8AABnAAAAZwgAAGcQAABnFAAAZxgAAGcgAABnJAAAZ0gAAGdUAABnXAAAZ2QAAGeIAABnlAAAZ5wAAGekAABntAAAaLAAAGi4AABowAAAaMgAAGjQAABo1AAAaNgAAGjcAABo4AAAaOgAAGjwAABo9AAAaPgAAGkAAABpBAAAagAAAGoIAABqEAAAahgAAGogAABqJAAAaigAAGosAABqMAAAajgAAGpAAABqRAAAakgAAGpQAABqVAAAangAAGp8AABqhAAAa4AAAGuIAABrkAAAa5gAAGugAABrpAAAa6gAAGusAABrsAAAa7gAAGvAAABrxAAAa8gAAGvQAABr1AAAa9gAAGzUAABs3AAAbOQAAGzsAABs9AAAbPgAAGz8AABtAAAAbQQAAG0MAABtFAAAbRgAAG0cAABtJAAAbSgAAG1cAABtYAAAbWQAAG1sAABtkAAAbegAAG4EAABuOAAAbzQAAG88AABvRAAAb0wAAG9UAABvWAAAb1wAAG9gAABvZAAAb2wAAG90AABveAAAb3wAAG+EAABviAAAb+wAAG/0AABv/AAAcAQAAHAIAABwEAAAcGwAAHCQAABwyAAAcPwAAHE0AABxiAAAcdgAAHI0AAByfAAAc3gAAHOAAABziAAAc5AAAHOYAABznAAAc6AAAHOkAABzqAAAc7AAAHO4AABzvAAAc8AAAHPIAABzzAAAc/gAAHQcAAB0cAAAdKwAAHUAAAB1OAAAdYwAAHXcAAB2OAAAdoAAAHa0AAB3SAAAd1AAAHdYAAB3YAAAd2gAAHdwAAB3eAAAd4AAAHeIAAB3kAAAd5gAAHegAAB3qAAAd7AAAHe4AAB3wAAAd8gAAHfQAAB4ZAAAeGwAAHh0AAB4fAAAeIQAAHiMAAB4lAAAeJwAAHioAAB4tAAAeMAAAHjMAAB42AAAeOQAAHjwAAB4/AAAeQgAAHkUAAB5HAAAeUAAAHloAAB5fAAAeZAAAHnoAAB6CAAAehwAAHpMAAB6ZAAAeogAAHqgAAB6xAAAewAAAHsoAAB7UAAAe7AAAHzcAAB9aAAAfegAAH5oAAB+cAAAfngAAH6AAAB+iAAAfpAAAH6UAAB+mAAAfqAAAH6kAAB+rAAAfrAAAH64AAB+wAAAfsQAAH7IAAB+0AAAftQAAH7oAAB/HAAAfzAAAH84AAB/QAAAf1QAAH9cAAB/ZAAAf2wAAH/AAACAFAAAgKgAAIE4AACB1AAAgmQAAIJsAACCdAAAgnwAAIKEAACCjAAAgpQAAIKYAACCoAAAgtQAAIMYAACDIAAAgygAAIMwAACDOAAAg0AAAINIAACDUAAAg1gAAIOcAACDpAAAg6wAAIO0AACDvAAAg8QAAIPMAACD1AAAg9wAAIPkAACEXAAAhNQAAIUgAACFcAAAhcQAAIY4AACGiAAAhuAAAIfcAACH5AAAh+wAAIf0AACH/AAAiAAAAIgEAACICAAAiAwAAIgUAACIHAAAiCAAAIgkAACILAAAiDAAAIksAACJNAAAiTwAAIlEAACJTAAAiVAAAIlUAACJWAAAiVwAAIlkAACJbAAAiXAAAIl0AACJfAAAiYAAAIp8AACKhAAAiowAAIqUAACKnAAAiqAAAIqkAACKqAAAiqwAAIq0AACKvAAAisAAAIrEAACKzAAAitAAAIsEAACLCAAAiwwAAIsUAACMEAAAjBgAAIwgAACMKAAAjDAAAIw0AACMOAAAjDwAAIxAAACMSAAAjFAAAIxUAACMWAAAjGAAAIxkAACNYAAAjWgAAI1wAACNeAAAjYAAAI2EAACNiAAAjYwAAI2QAACNmAAAjaAAAI2kAACNqAAAjbAAAI20AACNuAAAjrQAAI68AACOxAAAjswAAI7UAACO2AAAjtwAAI7gAACO5AAAjuwAAI70AACO+AAAjvwAAI8EAACPCAAAkAQAAJAMAACQFAAAkBwAAJAkAACQKAAAkCwAAJAwAACQNAAAkDwAAJBEAACQSAAAkEwAAJBUAACQWAAAkVQAAJFcAACRZAAAkWwAAJF0AACReAAAkXwAAJGAAACRhAAAkYwAAJGUAACRmAAAkZwAAJGkAACRqAAAkjwAAJLMAACTaAAAk/gAAJQAAACUCAAAlBAAAJQYAACUIAAAlCgAAJQsAACUNAAAlGgAAJSkAACUrAAAlLQAAJS8AACUxAAAlMwAAJTUAACU3AAAlRgAAJUgAACVKAAAlTAAAJU4AACVQAAAlUgAAJVQAACVWAAAldgAAJaEAACW7AAAl1AAAJe4AACYOAAAmMQAAJnAAACZyAAAmdAAAJnYAACZ4AAAmeQAAJnoAACZ7AAAmfAAAJn4AACaAAAAmgQAAJoIAACaEAAAmhQAAJsQAACbGAAAmyAAAJsoAACbMAAAmzQAAJs4AACbPAAAm0AAAJtIAACbUAAAm1QAAJtYAACbYAAAm2QAAJxgAACcaAAAnHAAAJx4AACcgAAAnIQAAJyIAACcjAAAnJAAAJyYAACcoAAAnKQAAJyoAACcsAAAnLQAAJ2wAACduAAAncAAAJ3IAACd0AAAndQAAJ3YAACd3AAAneAAAJ3oAACd8AAAnfQAAJ34AACeAAAAngQAAJ4QAACfDAAAnxQAAJ8cAACfJAAAnywAAJ8wAACfNAAAnzgAAJ88AACfRAAAn0wAAJ9QAACfVAAAn1wAAJ9gAACgXAAAoGQAAKBsAACgdAAAoHwAAKCAAACghAAAoIgAAKCMAACglAAAoJwAAKCgAACgpAAAoKwAAKCwAAChrAAAobQAAKG8AAChxAAAocwAAKHQAACh1AAAodgAAKHcAACh5AAAoewAAKHwAACh9AAAofwAAKIAAACiJAAAolwAAKKQAACiyAAAovwAAKNIAACjpAAAo+wAAKUYAAClpAAApiQAAKakAACmrAAAprQAAKa8AACmxAAApswAAKbQAACm1AAAptwAAKbgAACm6AAApuwAAKb0AACm/AAApwAAAKcEAACnDAAApxAAAKckAACnWAAAp2wAAKd0AACnfAAAp5AAAKeYAACnoAAAp6gAAKg8AACozAAAqWgAAKn4AACqAAAAqggAAKoQAACqGAAAqiAAAKooAACqLAAAqjQAAKpoAACqrAAAqrQAAKq8AACqxAAAqswAAKrUAACq3AAAquQAAKrsAACrMAAAqzgAAKtAAACrSAAAq1AAAKtYAACrYAAAq2gAAKtwAACreAAArHQAAKx8AACshAAArIwAAKyUAACsmAAArJwAAKygAACspAAArKwAAKy0AACsuAAArLwAAKzEAACsyAAArcQAAK3MAACt1AAArdwAAK3kAACt6AAArewAAK3wAACt9AAArfwAAK4EAACuCAAArgwAAK4UAACuGAAArxQAAK8cAACvJAAArywAAK80AACvOAAArzwAAK9AAACvRAAAr0wAAK9UAACvWAAAr1wAAK9kAACvaAAAr5wAAK+gAACvpAAAr6wAALCoAACwsAAAsLgAALDAAACwyAAAsMwAALDQAACw1AAAsNgAALDgAACw6AAAsOwAALDwAACw+AAAsPwAALH4AACyAAAAsggAALIQAACyGAAAshwAALIgAACyJAAAsigAALIwAACyOAAAsjwAALJAAACySAAAskwAALNIAACzUAAAs1gAALNgAACzaAAAs2wAALNwAACzdAAAs3gAALOAAACziAAAs4wAALOQAACzmAAAs5wAALSYAAC0oAAAtKgAALSwAAC0uAAAtLwAALTAAAC0xAAAtMgAALTQAAC02AAAtNwAALTgAAC06AAAtOwAALXoAAC18AAAtfgAALYAAAC2CAAAtgwAALYQAAC2FAAAthgAALYgAAC2KAAAtiwAALYwAAC2OAAAtjwAALbQAAC3YAAAt/wAALiMAAC4lAAAuJwAALikAAC4rAAAuLQAALi8AAC4wAAAuMgAALj8AAC5OAAAuUAAALlIAAC5UAAAuVgAALlgAAC5aAAAuXAAALmsAAC5tAAAubwAALnEAAC5zAAAudQAALncAAC55AAAuewAALroAAC68AAAuvgAALsAAAC7CAAAuwwAALsQAAC7FAAAuxgAALsgAAC7KAAAuywAALswAAC7OAAAuzwAALw4AAC8QAAAvEgAALxQAAC8WAAAvFwAALxgAAC8ZAAAvGgAALxwAAC8eAAAvHwAALyAAAC8iAAAvIwAAL2IAAC9kAAAvZgAAL2gAAC9qAAAvawAAL2wAAC9tAAAvbgAAL3AAAC9yAAAvcwAAL3QAAC92AAAvdwAAL7YAAC+4AAAvugAAL7wAAC++AAAvvwAAL8AAAC/BAAAvwgAAL8QAAC/GAAAvxwAAL8gAAC/KAAAvywAAMAoAADAMAAAwDgAAMBAAADASAAAwEwAAMBQAADAVAAAwFgAAMBgAADAaAAAwGwAAMBwAADAeAAAwHwAAMF4AADBgAAAwYgAAMGQAADBmAAAwZwAAMGgAADBpAAAwagAAMGwAADBuAAAwbwAAMHAAADByAAAwcwAAMLIAADC0AAAwtgAAMLgAADC6AAAwuwAAMLwAADC9AAAwvgAAMMAAADDCAAAwwwAAMMQAADDGAAAwxwAAMRIAADE1AAAxVQAAMXUAADF3AAAxeQAAMXsAADF9AAAxfwAAMYAAADGBAAAxgwAAMYQAADGGAAAxhwAAMYkAADGLAAAxjAAAMY0AADGPAAAxkAAAMZUAADGiAAAxpwAAMakAADGrAAAxsAAAMbIAADG0AAAxtgAAMdsAADH/AAAyJgAAMkoAADJMAAAyTgAAMlAAADJSAAAyVAAAMlYAADJXAAAyWQAAMmYAADJ3AAAyeQAAMnsAADJ9AAAyfwAAMoEAADKDAAAyhQAAMocAADKYAAAymgAAMpwAADKeAAAyoAAAMqIAADKkAAAypgAAMqgAADKqAAAy6QAAMusAADLtAAAy7wAAMvEAADLyAAAy8wAAMvQAADL1AAAy9wAAMvkAADL6AAAy+wAAMv0AADL+AAAzPQAAMz8AADNBAAAzQwAAM0UAADNGAAAzRwAAM0gAADNJAAAzSwAAM00AADNOAAAzTwAAM1EAADNSAAAzkQAAM5MAADOVAAAzlwAAM5kAADOaAAAzmwAAM5wAADOdAAAznwAAM6EAADOiAAAzowAAM6UAADOmAAAzswAAM7QAADO1AAAztwAAM/YAADP4AAAz+gAAM/wAADP+AAAz/wAANAAAADQBAAA0AgAANAQAADQGAAA0BwAANAgAADQKAAA0CwAANEoAADRMAAA0TgAANFAAADRSAAA0UwAANFQAADRVAAA0VgAANFgAADRaAAA0WwAANFwAADReAAA0XwAANJ4AADSgAAA0ogAANKQAADSmAAA0pwAANKgAADSpAAA0qgAANKwAADSuAAA0rwAANLAAADSyAAA0swAANPIAADT0AAA09gAANPgAADT6AAA0+wAANPwAADT9AAA0/gAANQAAADUCAAA1AwAANQQAADUGAAA1BwAANUYAADVIAAA1SgAANUwAADVOAAA1TwAANVAAADVRAAA1UgAANVQAADVWAAA1VwAANVgAADVaAAA1WwAANYAAADWkAAA1ywAANe8AADXxAAA18wAANfUAADX3AAA1+QAANfsAADX8AAA1/gAANgsAADYaAAA2HAAANh4AADYgAAA2IgAANiQAADYmAAA2KAAANjcAADY5AAA2OwAANj0AADY/AAA2QQAANkMAADZFAAA2RwAANoYAADaIAAA2igAANowAADaOAAA2jwAANpAAADaRAAA2kgAANpQAADaWAAA2lwAANpgAADaaAAA2mwAANtoAADbcAAA23gAANuAAADbiAAA24wAANuQAADblAAA25gAANugAADbqAAA26wAANuwAADbuAAA27wAANy4AADcwAAA3MgAANzQAADc2AAA3NwAANzgAADc5AAA3OgAANzwAADc+AAA3PwAAN0AAADdCAAA3QwAAN4IAADeEAAA3hgAAN4gAADeKAAA3iwAAN4wAADeNAAA3jgAAN5AAADeSAAA3kwAAN5QAADeWAAA3lwAAN9YAADfYAAA32gAAN9wAADfeAAA33wAAN+AAADfhAAA34gAAN+QAADfmAAA35wAAN+gAADfqAAA36wAAOCoAADgsAAA4LgAAODAAADgyAAA4MwAAODQAADg1AAA4NgAAODgAADg6AAA4OwAAODwAADg+AAA4PwAAOH4AADiAAAA4ggAAOIQAADiGAAA4hwAAOIgAADiJAAA4igAAOIwAADiOAAA4jwAAOJAAADiSAAA4kwAAON4AADkBAAA5IQAAOUEAADlDAAA5RQAAOUcAADlJAAA5SwAAOUwAADlNAAA5TwAAOVAAADlSAAA5UwAAOVUAADlXAAA5WAAAOVkAADlbAAA5XAAAOWEAADluAAA5cwAAOXUAADl3AAA5fAAAOX4AADmAAAA5ggAAOacAADnLAAA58gAAOhYAADoYAAA6GgAAOhwAADoeAAA6IAAAOiIAADojAAA6JQAAOjIAADpDAAA6RQAAOkcAADpJAAA6SwAAOk0AADpPAAA6UQAAOlMAADpkAAA6ZgAAOmgAADpqAAA6bAAAOm4AADpwAAA6cgAAOnQAADp2AAA6tQAAOrcAADq5AAA6uwAAOr0AADq+AAA6vwAAOsAAADrBAAA6wwAAOsUAADrGAAA6xwAAOskAADrKAAA7CQAAOwsAADsNAAA7DwAAOxEAADsSAAA7EwAAOxQAADsVAAA7FwAAOxkAADsaAAA7GwAAOx0AADseAAA7XQAAO18AADthAAA7YwAAO2UAADtmAAA7ZwAAO2gAADtpAAA7awAAO20AADtuAAA7bwAAO3EAADtyAAA7fwAAO4AAADuBAAA7gwAAO8IAADvEAAA7xgAAO8gAADvKAAA7ywAAO8wAADvNAAA7zgAAO9AAADvSAAA70wAAO9QAADvWAAA71wAAPBYAADwYAAA8GgAAPBwAADweAAA8HwAAPCAAADwhAAA8IgAAPCQAADwmAAA8JwAAPCgAADwqAAA8KwAAPGoAADxsAAA8bgAAPHAAADxyAAA8cwAAPHQAADx1AAA8dgAAPHgAADx6AAA8ewAAPHwAADx+AAA8fwAAPL4AADzAAAA8wgAAPMQAADzGAAA8xwAAPMgAADzJAAA8ygAAPMwAADzOAAA8zwAAPNAAADzSAAA80wAAPRIAAD0UAAA9FgAAPRgAAD0aAAA9GwAAPRwAAD0dAAA9HgAAPSAAAD0iAAA9IwAAPSQAAD0mAAA9JwAAPUwAAD1wAAA9lwAAPbsAAD29AAA9vwAAPcEAAD3DAAA9xQAAPccAAD3IAAA9ygAAPdcAAD3mAAA96AAAPeoAAD3sAAA97gAAPfAAAD3yAAA99AAAPgMAAD4FAAA+BwAAPgkAAD4LAAA+DQAAPg8AAD4RAAA+EwAAPlIAAD5UAAA+VgAAPlgAAD5aAAA+WwAAPlwAAD5dAAA+XgAAPmAAAD5iAAA+YwAAPmQAAD5mAAA+ZwAAPqYAAD6oAAA+qgAAPqwAAD6uAAA+rwAAPrAAAD6xAAA+sgAAPrQAAD62AAA+twAAPrgAAD66AAA+uwAAPvoAAD78AAA+/gAAPwAAAD8CAAA/AwAAPwQAAD8FAAA/BgAAPwgAAD8KAAA/CwAAPwwAAD8OAAA/DwAAP04AAD9QAAA/UgAAP1QAAD9WAAA/VwAAP1gAAD9ZAAA/WgAAP1wAAD9eAAA/XwAAP2AAAD9iAAA/YwAAP2YAAD+lAAA/pwAAP6kAAD+rAAA/rQAAP64AAD+vAAA/sAAAP7EAAD+zAAA/tQAAP7YAAD+3AAA/uQAAP7oAAD/5AAA/+wAAP/0AAD//AABAAQAAQAIAAEADAABABAAAQAUAAEAHAABACQAAQAoAAEALAABADQAAQA4AAEBNAABATwAAQFEAAEBTAABAVQAAQFYAAEBXAABAWAAAQFkAAEBbAABAXQAAQF4AAEBfAABAYQAAQGIAAECtAABA0AAAQPAAAEEQAABBEgAAQRQAAEEWAABBGAAAQRoAAEEbAABBHAAAQR4AAEEfAABBIQAAQSIAAEEkAABBJgAAQScAAEEoAABBKgAAQSsAAEEwAABBPQAAQUIAAEFEAABBRgAAQUsAAEFNAABBTwAAQVEAAEF2AABBmgAAQcEAAEHlAABB5wAAQekAAEHrAABB7QAAQe8AAEHxAABB8gAAQfQAAEIBAABCEgAAQhQAAEIWAABCGAAAQhoAAEIcAABCHgAAQiAAAEIiAABCMwAAQjUAAEI3AABCOQAAQjsAAEI9AABCPwAAQkEAAEJDAABCRQAAQoQAAEKGAABCiAAAQooAAEKMAABCjQAAQo4AAEKPAABCkAAAQpIAAEKUAABClQAAQpYAAEKYAABCmQAAQtgAAELaAABC3AAAQt4AAELgAABC4QAAQuIAAELjAABC5AAAQuYAAELoAABC6QAAQuoAAELsAABC7QAAQywAAEMuAABDMAAAQzIAAEM0AABDNQAAQzYAAEM3AABDOAAAQzoAAEM8AABDPQAAQz4AAENAAABDQQAAQ04AAENPAABDUAAAQ1IAAEORAABDkwAAQ5UAAEOXAABDmQAAQ5oAAEObAABDnAAAQ50AAEOfAABDoQAAQ6IAAEOjAABDpQAAQ6YAAEPlAABD5wAAQ+kAAEPrAABD7QAAQ+4AAEPvAABD8AAAQ/EAAEPzAABD9QAAQ/YAAEP3AABD+QAAQ/oAAEQ5AABEOwAARD0AAEQ/AABEQQAAREIAAERDAABERAAAREUAAERHAABESQAAREoAAERLAABETQAARE4AAESNAABEjwAARJEAAESTAABElQAARJYAAESXAABEmAAARJkAAESbAABEnQAARJ4AAESfAABEoQAARKIAAEThAABE4wAAROUAAETnAABE6QAAROoAAETrAABE7AAARO0AAETvAABE8QAARPIAAETzAABE9QAARPYAAEUbAABFPwAARWYAAEWKAABFjAAARY4AAEWQAABFkgAARZQAAEWWAABFlwAARZkAAEWmAABFtQAARbcAAEW5AABFuwAARb0AAEW/AABFwQAARcMAAEXSAABF1AAARdYAAEXYAABF2gAARdwAAEXeAABF4AAAReIAAEYhAABGIwAARiUAAEYnAABGKQAARioAAEYrAABGLAAARi0AAEYvAABGMQAARjIAAEYzAABGNQAARjYAAEZ1AABGdwAARnkAAEZ7AABGfQAARn4AAEZ/AABGgAAARoEAAEaDAABGhQAARoYAAEaHAABGiQAARooAAEbJAABGywAARs0AAEbPAABG0QAARtIAAEbTAABG1AAARtUAAEbXAABG2QAARtoAAEbbAABG3QAARt4AAEcdAABHHwAARyEAAEcjAABHJQAARyYAAEcnAABHKAAARykAAEcrAABHLQAARy4AAEcvAABHMQAARzIAAEdxAABHcwAAR3UAAEd3AABHeQAAR3oAAEd7AABHfAAAR30AAEd/AABHgQAAR4IAAEeDAABHhQAAR4YAAEfFAABHxwAAR8kAAEfLAABHzQAAR84AAEfPAABH0AAAR9EAAEfTAABH1QAAR9YAAEfXAABH2QAAR9oAAEgZAABIGwAASB0AAEgfAABIIQAASCIAAEgjAABIJAAASCUAAEgnAABIKQAASCoAAEgrAABILQAASC4AAEh5AABInAAASLwAAEjcAABI3gAASOAAAEjiAABI5AAASOYAAEjnAABI6AAASOoAAEjrAABI7QAASO4AAEjwAABI8gAASPMAAEj0AABI9gAASPcAAEj8AABJCQAASQ4AAEkQAABJEgAASRcAAEkZAABJGwAASR0AAElCAABJZgAASY0AAEmxAABJswAASbUAAEm3AABJuQAASbsAAEm9AABJvgAAScAAAEnNAABJ3gAASeAAAEniAABJ5AAASeYAAEnoAABJ6gAASewAAEnuAABJ/wAASgEAAEoDAABKBQAASgcAAEoJAABKCwAASg0AAEoPAABKEQAASlAAAEpSAABKVAAASlYAAEpYAABKWQAASloAAEpbAABKXAAASl4AAEpgAABKYQAASmIAAEpkAABKZQAASqQAAEqmAABKqAAASqoAAEqsAABKrQAASq4AAEqvAABKsAAASrIAAEq0AABKtQAASrYAAEq4AABKuQAASvgAAEr6AABK/AAASv4AAEsAAABLAQAASwIAAEsDAABLBAAASwYAAEsIAABLCQAASwoAAEsMAABLDQAASxoAAEsbAABLHAAASx4AAEtdAABLXwAAS2EAAEtjAABLZQAAS2YAAEtnAABLaAAAS2kAAEtrAABLbQAAS24AAEtvAABLcQAAS3IAAEuxAABLswAAS7UAAEu3AABLuQAAS7oAAEu7AABLvAAAS70AAEu/AABLwQAAS8IAAEvDAABLxQAAS8YAAEwFAABMBwAATAkAAEwLAABMDQAATA4AAEwPAABMEAAATBEAAEwTAABMFQAATBYAAEwXAABMGQAATBoAAExZAABMWwAATF0AAExfAABMYQAATGIAAExjAABMZAAATGUAAExnAABMaQAATGoAAExrAABMbQAATG4AAEytAABMrwAATLEAAEyzAABMtQAATLYAAEy3AABMuAAATLkAAEy7AABMvQAATL4AAEy/AABMwQAATMIAAEznAABNCwAATTIAAE1WAABNWAAATVoAAE1cAABNXgAATWAAAE1iAABNYwAATWUAAE1yAABNgQAATYMAAE2FAABNhwAATYkAAE2LAABNjQAATY8AAE2eAABNoAAATaIAAE2kAABNpgAATagAAE2qAABNrAAATa4AAE3tAABN7wAATfEAAE3zAABN9QAATfYAAE33AABN+AAATfkAAE37AABN/QAATf4AAE3/AABOAQAATgIAAE4EAABOQwAATkUAAE5HAABOSQAATksAAE5MAABOTQAATk4AAE5PAABOUQAATlMAAE5UAABOVQAATlcAAE5YAABOlwAATpkAAE6bAABOnQAATp8AAE6gAABOoQAATqIAAE6jAABOpQAATqcAAE6oAABOqQAATqsAAE6sAABO6wAATu0AAE7vAABO8QAATvMAAE70AABO9QAATvYAAE73AABO+QAATvsAAE78AABO/QAATv8AAE8AAABPAwAAT0IAAE9EAABPRgAAT0gAAE9KAABPSwAAT0wAAE9NAABPTgAAT1AAAE9SAABPUwAAT1QAAE9WAABPVwAAT5YAAE+YAABPmgAAT5wAAE+eAABPnwAAT6AAAE+hAABPogAAT6QAAE+mAABPpwAAT6gAAE+qAABPqwAAT+oAAE/sAABP7gAAT/AAAE/yAABP8wAAT/QAAE/1AABP9gAAT/gAAE/6AABP+wAAT/wAAE/+AABP/wAAUEoAAFBtAABQjQAAUK0AAFCvAABQsQAAULMAAFC1AABQtwAAULgAAFC5AABQuwAAULwAAFC+AABQvwAAUMEAAFDDAABQxAAAUMUAAFDHAABQyAAAUM0AAFDaAABQ3wAAUOEAAFDjAABQ6AAAUOoAAFDsAABQ7gAAURMAAFE3AABRXgAAUYIAAFGEAABRhgAAUYgAAFGKAABRjAAAUY4AAFGPAABRkQAAUZ4AAFGvAABRsQAAUbMAAFG1AABRtwAAUbkAAFG7AABRvQAAUb8AAFHQAABR0gAAUdQAAFHWAABR2AAAUdoAAFHcAABR3gAAUeAAAFHiAABSIQAAUiMAAFIlAABSJwAAUikAAFIqAABSKwAAUiwAAFItAABSLwAAUjEAAFIyAABSMwAAUjUAAFI2AABSdQAAUncAAFJ5AABSewAAUn0AAFJ+AABSfwAAUoAAAFKBAABSgwAAUoUAAFKGAABShwAAUokAAFKKAABSyQAAUssAAFLNAABSzwAAUtEAAFLSAABS0wAAUtQAAFLVAABS1wAAUtkAAFLaAABS2wAAUt0AAFLeAABS6wAAUuwAAFLtAABS7wAAUy4AAFMwAABTMgAAUzQAAFM2AABTNwAAUzgAAFM5AABTOgAAUzwAAFM+AABTPwAAU0AAAFNCAABTQwAAU4IAAFOEAABThgAAU4gAAFOKAABTiwAAU4wAAFONAABTjgAAU5AAAFOSAABTkwAAU5QAAFOWAABTlwAAU9YAAFPYAABT2gAAU9wAAFPeAABT3wAAU+AAAFPhAABT4gAAU+QAAFPmAABT5wAAU+gAAFPqAABT6wAAVCoAAFQsAABULgAAVDAAAFQyAABUMwAAVDQAAFQ1AABUNgAAVDgAAFQ6AABUOwAAVDwAAFQ+AABUPwAAVH4AAFSAAABUggAAVIQAAFSGAABUhwAAVIgAAFSJAABUigAAVIwAAFSOAABUjwAAVJAAAFSSAABUkwAAVLgAAFTcAABVAwAAVScAAFUpAABVKwAAVS0AAFUvAABVMQAAVTMAAFU0AABVNgAAVUMAAFVSAABVVAAAVVYAAFVYAABVWgAAVVwAAFVeAABVYAAAVW8AAFVxAABVcwAAVXUAAFV3AABVeQAAVXsAAFV9AABVfwAAVb4AAFXAAABVwgAAVcQAAFXGAABVxwAAVcgAAFXJAABVygAAVcwAAFXOAABVzwAAVdAAAFXSAABV0wAAVdYAAFYVAABWFwAAVhkAAFYbAABWHQAAVh4AAFYfAABWIAAAViEAAFYjAABWJQAAViYAAFYnAABWKQAAVioAAFZpAABWawAAVm0AAFZvAABWcQAAVnIAAFZzAABWdAAAVnUAAFZ3AABWeQAAVnoAAFZ7AABWfQAAVn4AAFa9AABWvwAAVsEAAFbDAABWxQAAVsYAAFbHAABWyAAAVskAAFbLAABWzQAAVs4AAFbPAABW0QAAVtIAAFbVAABXFAAAVxYAAFcYAABXGgAAVxwAAFcdAABXHgAAVx8AAFcgAABXIgAAVyQAAFclAABXJgAAVygAAFcpAABXaAAAV2oAAFdsAABXbgAAV3AAAFdxAABXcgAAV3MAAFd0AABXdgAAV3gAAFd5AABXegAAV3wAAFd9AABXvAAAV74AAFfAAABXwgAAV8QAAFfFAABXxgAAV8cAAFfIAABXygAAV8wAAFfNAABXzgAAV9AAAFfRAABYHAAAWD8AAFhfAABYfwAAWIEAAFiDAABYhQAAWIcAAFiJAABYigAAWIsAAFiOAABYjwAAWJEAAFiSAABYlAAAWJYAAFiXAABYmAAAWJsAAFicAABYoQAAWK4AAFizAABYtQAAWLcAAFi8AABYvwAAWMIAAFjEAABY6QAAWQ0AAFk0AABZWAAAWVsAAFldAABZXwAAWWEAAFljAABZZQAAWWYAAFlpAABZdgAAWYcAAFmJAABZiwAAWY0AAFmPAABZkQAAWZMAAFmVAABZlwAAWagAAFmrAABZrgAAWbEAAFm0AABZtwAAWboAAFm9AABZwAAAWcIAAFoBAABaAwAAWgUAAFoHAABaCgAAWgsAAFoMAABaDQAAWg4AAFoQAABaEgAAWhMAAFoUAABaFgAAWhcAAFpWAABaWAAAWloAAFpcAABaXwAAWmAAAFphAABaYgAAWmMAAFplAABaZwAAWmgAAFppAABaawAAWmwAAFqrAABarQAAWrAAAFqyAABatQAAWrYAAFq3AABauAAAWrkAAFq7AABavQAAWr4AAFq/AABawQAAWsIAAFrPAABa0AAAWtEAAFrTAABbEgAAWxQAAFsWAABbGAAAWxsAAFscAABbHQAAWx4AAFsfAABbIQAAWyMAAFskAABbJQAAWycAAFsoAABbZwAAW2kAAFtrAABbbQAAW3AAAFtxAABbcgAAW3MAAFt0AABbdgAAW3gAAFt5AABbegAAW3wAAFt9AABbvAAAW74AAFvAAABbwgAAW8UAAFvGAABbxwAAW8gAAFvJAABbywAAW80AAFvOAABbzwAAW9EAAFvSAABcEQAAXBMAAFwVAABcFwAAXBoAAFwbAABcHAAAXB0AAFweAABcIAAAXCIAAFwjAABcJAAAXCYAAFwnAABcZgAAXGgAAFxqAABcbAAAXG8AAFxwAABccQAAXHIAAFxzAABcdQAAXHcAAFx4AABceQAAXHsAAFx8AABcoQAAXMUAAFzsAABdEAAAXRMAAF0VAABdFwAAXRkAAF0bAABdHQAAXR4AAF0hAABdLgAAXT0AAF0/AABdQQAAXUMAAF1FAABdRwAAXUkAAF1LAABdWgAAXV0AAF1gAABdYwAAXWYAAF1pAABdbAAAXW8AAF1xAABdsAAAXbIAAF20AABdtgAAXbkAAF26AABduwAAXbwAAF29AABdvwAAXcEAAF3CAABdwwAAXcUAAF3GAABeBQAAXgcAAF4JAABeCwAAXg4AAF4PAABeEAAAXhEAAF4SAABeFAAAXhYAAF4XAABeGAAAXhoAAF4bAABeWgAAXlwAAF5eAABeYAAAXmMAAF5kAABeZQAAXmYAAF5nAABeaQAAXmsAAF5sAABebQAAXm8AAF5wAABerwAAXrEAAF60AABetgAAXrkAAF66AABeuwAAXrwAAF69AABevwAAXsEAAF7CAABewwAAXsUAAF7GAABeyQAAXwgAAF8KAABfDAAAXw4AAF8RAABfEgAAXxMAAF8UAABfFQAAXxcAAF8ZAABfGgAAXxsAAF8dAABfHgAAX10AAF9fAABfYQAAX2MAAF9mAABfZwAAX2gAAF9pAABfagAAX2wAAF9uAABfbwAAX3AAAF9yAABfcwAAX7IAAF+0AABftgAAX7gAAF+7AABfvAAAX70AAF++AABfvwAAX8EAAF/DAABfxAAAX8UAAF/HAABfyAAAYBMAAGA2AABgVgAAYHYAAGB4AABgegAAYHwAAGB+AABggAAAYIEAAGCCAABghQAAYIYAAGCIAABgiQAAYIsAAGCNAABgjgAAYI8AAGCSAABgkwAAYJgAAGClAABgqgAAYKwAAGCuAABgswAAYLYAAGC5AABguwAAYOAAAGEEAABhKwAAYU8AAGFSAABhVAAAYVYAAGFYAABhWgAAYVwAAGFdAABhYAAAYW0AAGF+AABhgAAAYYIAAGGEAABhhgAAYYgAAGGKAABhjAAAYY4AAGGfAABhogAAYaUAAGGoAABhqwAAYa4AAGGxAABhtAAAYbcAAGG5AABh+AAAYfoAAGH8AABh/gAAYgEAAGICAABiAwAAYgQAAGIFAABiBwAAYgkAAGIKAABiCwAAYg0AAGIOAABiTQAAYk8AAGJRAABiUwAAYlYAAGJXAABiWAAAYlkAAGJaAABiXAAAYl4AAGJfAABiYAAAYmIAAGJjAABiogAAYqQAAGKnAABiqQAAYqwAAGKtAABirgAAYq8AAGKwAABisgAAYrQAAGK1AABitgAAYrgAAGK5AABixgAAYscAAGLIAABiygAAYwkAAGMLAABjDQAAYw8AAGMSAABjEwAAYxQAAGMVAABjFgAAYxgAAGMaAABjGwAAYxwAAGMeAABjHwAAY14AAGNgAABjYgAAY2QAAGNnAABjaAAAY2kAAGNqAABjawAAY20AAGNvAABjcAAAY3EAAGNzAABjdAAAY7MAAGO1AABjtwAAY7kAAGO8AABjvQAAY74AAGO/AABjwAAAY8IAAGPEAABjxQAAY8YAAGPIAABjyQAAZAgAAGQKAABkDAAAZA4AAGQRAABkEgAAZBMAAGQUAABkFQAAZBcAAGQZAABkGgAAZBsAAGQdAABkHgAAZF0AAGRfAABkYQAAZGMAAGRmAABkZwAAZGgAAGRpAABkagAAZGwAAGRuAABkbwAAZHAAAGRyAABkcwAAZJgAAGS8AABk4wAAZQcAAGUKAABlDAAAZQ4AAGUQAABlEgAAZRQAAGUVAABlGAAAZSUAAGU0AABlNgAAZTgAAGU6AABlPAAAZT4AAGVAAABlQgAAZVEAAGVUAABlVwAAZVoAAGVdAABlYAAAZWMAAGVmAABlaAAAZacAAGWpAABlqwAAZa0AAGWwAABlsQAAZbIAAGWzAABltAAAZbYAAGW4AABluQAAZboAAGW8AABlvQAAZfwAAGX+AABmAAAAZgIAAGYFAABmBgAAZgcAAGYIAABmCQAAZgsAAGYNAABmDgAAZg8AAGYRAABmEgAAZlEAAGZTAABmVQAAZlcAAGZaAABmWwAAZlwAAGZdAABmXgAAZmAAAGZiAABmYwAAZmQAAGZmAABmZwAAZqYAAGaoAABmqwAAZq0AAGawAABmsQAAZrIAAGazAABmtAAAZrYAAGa4AABmuQAAZroAAGa8AABmvQAAZr8AAGb+AABnAAAAZwIAAGcEAABnBwAAZwgAAGcJAABnCgAAZwsAAGcNAABnDwAAZxAAAGcRAABnEwAAZxQAAGdTAABnVQAAZ1cAAGdZAABnXAAAZ10AAGdeAABnXwAAZ2AAAGdiAABnZAAAZ2UAAGdmAABnaAAAZ2kAAGeoAABnqgAAZ6wAAGeuAABnsQAAZ7IAAGezAABntAAAZ7UAAGe3AABnuQAAZ7oAAGe7AABnvQAAZ74AAGgJAABoLAAAaEwAAGhsAABobgAAaHAAAGhyAABodAAAaHYAAGh3AABoeAAAaHsAAGh8AABofgAAaH8AAGiBAABogwAAaIQAAGiFAABoiAAAaIkAAGiOAABomwAAaKAAAGiiAABopAAAaKkAAGisAABorwAAaLEAAGjWAABo+gAAaSEAAGlFAABpSAAAaUoAAGlMAABpTgAAaVAAAGlSAABpUwAAaVYAAGljAABpdAAAaXYAAGl4AABpegAAaXwAAGl+AABpgAAAaYIAAGmEAABplQAAaZgAAGmbAABpngAAaaEAAGmkAABppwAAaaoAAGmtAABprwAAae4AAGnwAABp8gAAafQAAGn3AABp+AAAafkAAGn6AABp+wAAaf0AAGn/AABqAAAAagEAAGoDAABqBAAAakMAAGpFAABqRwAAakkAAGpMAABqTQAAak4AAGpPAABqUAAAalIAAGpUAABqVQAAalYAAGpYAABqWQAAapgAAGqaAABqnQAAap8AAGqiAABqowAAaqQAAGqlAABqpgAAaqgAAGqqAABqqwAAaqwAAGquAABqrwAAarwAAGq9AABqvgAAasAAAGr/AABrAQAAawMAAGsFAABrCAAAawkAAGsKAABrCwAAawwAAGsOAABrEAAAaxEAAGsSAABrFAAAaxUAAGtUAABrVgAAa1gAAGtaAABrXQAAa14AAGtfAABrYAAAa2EAAGtjAABrZQAAa2YAAGtnAABraQAAa2oAAGupAABrqwAAa60AAGuvAABrsgAAa7MAAGu0AABrtQAAa7YAAGu4AABrugAAa7sAAGu8AABrvgAAa78AAGv+AABsAAAAbAIAAGwEAABsBwAAbAgAAGwJAABsCgAAbAsAAGwNAABsDwAAbBAAAGwRAABsEwAAbBQAAGxTAABsVQAAbFcAAGxZAABsXAAAbF0AAGxeAABsXwAAbGAAAGxiAABsZAAAbGUAAGxmAABsaAAAbGkAAGyOAABssgAAbNkAAGz9AABtAAAAbQIAAG0EAABtBgAAbQgAAG0KAABtCwAAbQ4AAG0bAABtKgAAbSwAAG0uAABtMAAAbTIAAG00AABtNgAAbTgAAG1HAABtSgAAbU0AAG1QAABtUwAAbVYAAG1ZAABtXAAAbV4AAG2dAABtnwAAbaEAAG2jAABtpgAAbacAAG2oAABtqQAAbaoAAG2sAABtrgAAba8AAG2wAABtsgAAbbMAAG3yAABt9AAAbfYAAG34AABt+wAAbfwAAG39AABt/gAAbf8AAG4BAABuAwAAbgQAAG4FAABuBwAAbggAAG5HAABuSQAAbksAAG5NAABuUAAAblEAAG5SAABuUwAAblQAAG5WAABuWAAAblkAAG5aAABuXAAAbl0AAG6cAABungAAbqAAAG6iAABupQAAbqYAAG6nAABuqAAAbqkAAG6rAABurQAAbq4AAG6vAABusQAAbrIAAG7xAABu8wAAbvUAAG73AABu+gAAbvsAAG78AABu/QAAbv4AAG8AAABvAgAAbwMAAG8EAABvBgAAbwcAAG9GAABvSAAAb0oAAG9MAABvTwAAb1AAAG9RAABvUgAAb1MAAG9VAABvVwAAb1gAAG9ZAABvWwAAb1wAAG+bAABvnQAAb58AAG+hAABvpAAAb6UAAG+mAABvpwAAb6gAAG+qAABvrAAAb60AAG+uAABvsAAAb7EAAG/8AABwHwAAcD8AAHBfAABwYQAAcGMAAHBlAABwZwAAcGkAAHBqAABwawAAcG4AAHBvAABwcQAAcHIAAHB0AABwdgAAcHcAAHB4AABwewAAcHwAAHCBAABwjgAAcJMAAHCVAABwlwAAcJwAAHCfAABwogAAcKQAAHDJAABw7QAAcRQAAHE4AABxOwAAcT0AAHE/AABxQQAAcUMAAHFFAABxRgAAcUkAAHFWAABxZwAAcWkAAHFrAABxbQAAcW8AAHFxAABxcwAAcXUAAHF3AABxiAAAcYsAAHGOAABxkQAAcZQAAHGXAABxmgAAcZ0AAHGgAABxogAAceEAAHHjAABx5QAAcecAAHHqAABx6wAAcewAAHHtAABx7gAAcfAAAHHyAABx8wAAcfQAAHH2AABx9wAAcjYAAHI4AAByOgAAcjwAAHI/AAByQAAAckEAAHJCAAByQwAAckUAAHJHAABySAAAckkAAHJLAAByTAAAcosAAHKNAABykAAAcpIAAHKVAABylgAAcpcAAHKYAABymQAAcpsAAHKdAAByngAAcp8AAHKhAAByogAAcq8AAHKwAABysQAAcrMAAHLyAABy9AAAcvYAAHL4AABy+wAAcvwAAHL9AABy/gAAcv8AAHMBAABzAwAAcwQAAHMFAABzBwAAcwgAAHNHAABzSQAAc0sAAHNNAABzUAAAc1EAAHNSAABzUwAAc1QAAHNWAABzWAAAc1kAAHNaAABzXAAAc10AAHOcAABzngAAc6AAAHOiAABzpQAAc6YAAHOnAABzqAAAc6kAAHOrAABzrQAAc64AAHOvAABzsQAAc7IAAHPxAABz8wAAc/UAAHP3AABz+gAAc/sAAHP8AABz/QAAc/4AAHQAAAB0AgAAdAMAAHQEAAB0BgAAdAcAAHRGAAB0SAAAdEoAAHRMAAB0TwAAdFAAAHRRAAB0UgAAdFMAAHRVAAB0VwAAdFgAAHRZAAB0WwAAdFwAAHSBAAB0pQAAdMwAAHTwAAB08wAAdPUAAHT3AAB0+QAAdPsAAHT9AAB0/gAAdQEAAHUOAAB1HQAAdR8AAHUhAAB1IwAAdSUAAHUnAAB1KQAAdSsAAHU6AAB1PQAAdUAAAHVDAAB1RgAAdUkAAHVMAAB1TwAAdVEAAHWQAAB1kgAAdZQAAHWWAAB1mQAAdZoAAHWbAAB1nAAAdZ0AAHWfAAB1oQAAdaIAAHWjAAB1pQAAdaYAAHXlAAB15wAAdekAAHXrAAB17gAAde8AAHXwAAB18QAAdfIAAHX0AAB19gAAdfcAAHX4AAB1+gAAdfsAAHY6AAB2PAAAdj4AAHZAAAB2QwAAdkQAAHZFAAB2RgAAdkcAAHZJAAB2SwAAdkwAAHZNAAB2TwAAdlAAAHaPAAB2kQAAdpMAAHaVAAB2mAAAdpkAAHaaAAB2mwAAdpwAAHaeAAB2oAAAdqEAAHaiAAB2pAAAdqUAAHbkAAB25gAAdugAAHbqAAB27QAAdu4AAHbvAAB28AAAdvEAAHbzAAB29QAAdvYAAHb3AAB2+QAAdvoAAHc5AAB3OwAAdz0AAHc/AAB3QgAAd0MAAHdEAAB3RQAAd0YAAHdIAAB3SgAAd0sAAHdMAAB3TgAAd08AAHeOAAB3kAAAd5IAAHeUAAB3lwAAd5gAAHeZAAB3mgAAd5sAAHedAAB3nwAAd6AAAHehAAB3owAAd6QAAHfvAAB4EgAAeDIAAHhSAAB4VAAAeFYAAHhYAAB4WgAAeFwAAHhdAAB4XgAAeGEAAHhiAAB4ZAAAeGUAAHhnAAB4aQAAeGoAAHhrAAB4bgAAeG8AAHh0AAB4gQAAeIYAAHiIAAB4igAAeI8AAHiSAAB4lQAAeJcAAHi8AAB44AAAeQcAAHkrAAB5LgAAeTAAAHkyAAB5NAAAeTYAAHk4AAB5OQAAeTwAAHlJAAB5WgAAeVwAAHleAAB5YAAAeWIAAHlkAAB5ZgAAeWgAAHlqAAB5ewAAeX4AAHmBAAB5hAAAeYcAAHmKAAB5jQAAeZAAAHmTAAB5lQAAedQAAHnWAAB52AAAedoAAHndAAB53gAAed8AAHngAAB54QAAeeMAAHnlAAB55gAAeecAAHnpAAB56gAAeikAAHorAAB6LQAAei8AAHoyAAB6MwAAejQAAHo1AAB6NgAAejgAAHo6AAB6OwAAejwAAHo+AAB6PwAAen4AAHqAAAB6gwAAeoUAAHqIAAB6iQAAeooAAHqLAAB6jAAAeo4AAHqQAAB6kQAAepIAAHqUAAB6lQAAeqIAAHqjAAB6pAAAeqYAAHrlAAB65wAAeukAAHrrAAB67gAAeu8AAHrwAAB68QAAevIAAHr0AAB69gAAevcAAHr4AAB6+gAAevsAAHs6AAB7PAAAez4AAHtAAAB7QwAAe0QAAHtFAAB7RgAAe0cAAHtJAAB7SwAAe0wAAHtNAAB7TwAAe1AAAHuPAAB7kQAAe5MAAHuVAAB7mAAAe5kAAHuaAAB7mwAAe5wAAHueAAB7oAAAe6EAAHuiAAB7pAAAe6UAAHvkAAB75gAAe+gAAHvqAAB77QAAe+4AAHvvAAB78AAAe/EAAHvzAAB79QAAe/YAAHv3AAB7+QAAe/oAAHw5AAB8OwAAfD0AAHw/AAB8QgAAfEMAAHxEAAB8RQAAfEYAAHxIAAB8SgAAfEsAAHxMAAB8TgAAfE8AAHx0AAB8mAAAfL8AAHzjAAB85gAAfOgAAHzqAAB87AAAfO4AAHzwAAB88QAAfPQAAH0BAAB9EAAAfRIAAH0UAAB9FgAAfRgAAH0aAAB9HAAAfR4AAH0tAAB9MAAAfTMAAH02AAB9OQAAfTwAAH0/AAB9QgAAfUQAAH2DAAB9hQAAfYcAAH2JAAB9jAAAfY0AAH2OAAB9jwAAfZAAAH2SAAB9lAAAfZUAAH2WAAB9mAAAfZkAAH3YAAB92gAAfdwAAH3eAAB94QAAfeIAAH3jAAB95AAAfeUAAH3nAAB96QAAfeoAAH3rAAB97QAAfe4AAH4tAAB+LwAAfjEAAH4zAAB+NgAAfjcAAH44AAB+OQAAfjoAAH48AAB+PgAAfj8AAH5AAAB+QgAAfkMAAH6CAAB+hAAAfocAAH6JAAB+jAAAfo0AAH6OAAB+jwAAfpAAAH6SAAB+lAAAfpUAAH6WAAB+mAAAfpkAAH6cAAB+2wAAft0AAH7fAAB+4QAAfuQAAH7lAAB+5gAAfucAAH7oAAB+6gAAfuwAAH7tAAB+7gAAfvAAAH7xAAB/MAAAfzIAAH80AAB/NgAAfzkAAH86AAB/OwAAfzwAAH89AAB/PwAAf0EAAH9CAAB/QwAAf0UAAH9GAAB/hQAAf4cAAH+JAAB/iwAAf44AAH+PAAB/kAAAf5EAAH+SAAB/lAAAf5YAAH+XAAB/mAAAf5oAAH+bAAB/5gAAgAkAAIApAACASQAAgEsAAIBNAACATwAAgFEAAIBTAACAVAAAgFUAAIBYAACAWQAAgFsAAIBcAACAXgAAgGAAAIBhAACAYgAAgGUAAIBmAACAbwAAgHwAAICBAACAgwAAgIUAAICKAACAjQAAgJAAAICSAACAtwAAgNsAAIECAACBJgAAgSkAAIErAACBLQAAgS8AAIExAACBMwAAgTQAAIE3AACBRAAAgVUAAIFXAACBWQAAgVsAAIFdAACBXwAAgWEAAIFjAACBZQAAgXYAAIF5AACBfAAAgX8AAIGCAACBhQAAgYgAAIGLAACBjgAAgZAAAIHPAACB0QAAgdMAAIHVAACB2AAAgdkAAIHaAACB2wAAgdwAAIHeAACB4AAAgeEAAIHiAACB5AAAgeUAAIIkAACCJgAAgigAAIIqAACCLQAAgi4AAIIvAACCMAAAgjEAAIIzAACCNQAAgjYAAII3AACCOQAAgjoAAIJ5AACCewAAgn4AAIKAAACCgwAAgoQAAIKFAACChgAAgocAAIKJAACCiwAAgowAAIKNAACCjwAAgpAAAIKdAACCngAAgp8AAIKhAACC4AAAguIAAILkAACC5gAAgukAAILqAACC6wAAguwAAILtAACC7wAAgvEAAILyAACC8wAAgvUAAIL2AACDNQAAgzcAAIM5AACDOwAAgz4AAIM/AACDQAAAg0EAAINCAACDRAAAg0YAAINHAACDSAAAg0oAAINLAACDigAAg4wAAIOOAACDkAAAg5MAAIOUAACDlQAAg5YAAIOXAACDmQAAg5sAAIOcAACDnQAAg58AAIOgAACD3wAAg+EAAIPjAACD5QAAg+gAAIPpAACD6gAAg+sAAIPsAACD7gAAg/AAAIPxAACD8gAAg/QAAIP1AACENAAAhDYAAIQ4AACEOgAAhD0AAIQ+AACEPwAAhEAAAIRBAACEQwAAhEUAAIRGAACERwAAhEkAAIRKAACEbwAAhJMAAIS6AACE3gAAhOEAAITjAACE5QAAhOcAAITpAACE6wAAhOwAAITvAACE/AAAhQsAAIUNAACFDwAAhREAAIUTAACFFQAAhRcAAIUZAACFKAAAhSsAAIUuAACFMQAAhTQAAIU3AACFOgAAhT0AAIU/AACFfgAAhYAAAIWDAACFhQAAhYgAAIWJAACFigAAhYsAAIWMAACFjgAAhZAAAIWRAACFkgAAhZQAAIWVAACFmQAAhdgAAIXaAACF3AAAhd4AAIXhAACF4gAAheMAAIXkAACF5QAAhecAAIXpAACF6gAAhesAAIXtAACF7gAAhi0AAIYvAACGMQAAhjMAAIY2AACGNwAAhjgAAIY5AACGOgAAhjwAAIY+AACGPwAAhkAAAIZCAACGQwAAhoIAAIaEAACGhwAAhokAAIaMAACGjQAAho4AAIaPAACGkAAAhpIAAIaUAACGlQAAhpYAAIaYAACGmQAAhtgAAIbaAACG3AAAht4AAIbhAACG4gAAhuMAAIbkAACG5QAAhucAAIbpAACG6gAAhusAAIbtAACG7gAAhy0AAIcvAACHMQAAhzMAAIc2AACHNwAAhzgAAIc5AACHOgAAhzwAAIc+AACHPwAAh0AAAIdCAACHQwAAh4IAAIeEAACHhgAAh4gAAIeLAACHjAAAh40AAIeOAACHjwAAh5EAAIeTAACHlAAAh5UAAIeXAACHmAAAh+MAAIgGAACIJgAAiEYAAIhIAACISgAAiEwAAIhOAACIUAAAiFEAAIhSAACIVQAAiFYAAIhYAACIWQAAiFsAAIhdAACIXgAAiF8AAIhiAACIYwAAiGgAAIh1AACIegAAiHwAAIh+AACIgwAAiIYAAIiJAACIiwAAiLAAAIjUAACI+wAAiR8AAIkiAACJJAAAiSYAAIkoAACJKgAAiSwAAIktAACJMAAAiT0AAIlOAACJUAAAiVIAAIlUAACJVgAAiVgAAIlaAACJXAAAiV4AAIlvAACJcgAAiXUAAIl4AACJewAAiX4AAImBAACJhAAAiYcAAImJAACJyAAAicoAAInMAACJzgAAidEAAInSAACJ0wAAidQAAInVAACJ1wAAidkAAInaAACJ2wAAid0AAIneAACKHQAAih8AAIohAACKIwAAiiYAAIonAACKKAAAiikAAIoqAACKLAAAii4AAIovAACKMAAAijIAAIozAACKcgAAinQAAIp3AACKeQAAinwAAIp9AACKfgAAin8AAIqAAACKggAAioQAAIqFAACKhgAAiogAAIqJAACKlgAAipcAAIqYAACKmgAAitkAAIrbAACK3QAAit8AAIriAACK4wAAiuQAAIrlAACK5gAAiugAAIrqAACK6wAAiuwAAIruAACK7wAAiy4AAIswAACLMgAAizQAAIs3AACLOAAAizkAAIs6AACLOwAAiz0AAIs/AACLQAAAi0EAAItDAACLRAAAi4MAAIuFAACLhwAAi4kAAIuMAACLjQAAi44AAIuPAACLkAAAi5IAAIuUAACLlQAAi5YAAIuYAACLmQAAi9gAAIvaAACL3AAAi94AAIvhAACL4gAAi+MAAIvkAACL5QAAi+cAAIvpAACL6gAAi+sAAIvtAACL7gAAjC0AAIwvAACMMQAAjDMAAIw2AACMNwAAjDgAAIw5AACMOgAAjDwAAIw+AACMPwAAjEAAAIxCAACMQwAAjGgAAIyMAACMswAAjNcAAIzaAACM3AAAjN4AAIzgAACM4gAAjOQAAIzlAACM6AAAjPUAAI0EAACNBgAAjQgAAI0KAACNDAAAjQ4AAI0QAACNEgAAjSEAAI0kAACNJwAAjSoAAI0tAACNMAAAjTMAAI02AACNOAAAjXcAAI15AACNewAAjX0AAI2AAACNgQAAjYIAAI2DAACNhAAAjYYAAI2IAACNiQAAjYoAAI2MAACNjQAAjcwAAI3OAACN0AAAjdIAAI3VAACN1gAAjdcAAI3YAACN2QAAjdsAAI3dAACN3gAAjd8AAI3hAACN4gAAjiEAAI4jAACOJQAAjicAAI4qAACOKwAAjiwAAI4tAACOLgAAjjAAAI4yAACOMwAAjjQAAI42AACONwAAjnYAAI54AACOewAAjn0AAI6AAACOgQAAjoIAAI6DAACOhAAAjoYAAI6IAACOiQAAjooAAI6MAACOjQAAjswAAI7OAACO0AAAjtIAAI7VAACO1gAAjtcAAI7YAACO2QAAjtsAAI7dAACO3gAAjt8AAI7hAACO4gAAjyEAAI8jAACPJQAAjycAAI8qAACPKwAAjywAAI8tAACPLgAAjzAAAI8yAACPMwAAjzQAAI82AACPNwAAj3YAAI94AACPegAAj3wAAI9/AACPgAAAj4EAAI+CAACPgwAAj4UAAI+HAACPiAAAj4kAAI+LAACPjAAAj9cAAI/6AACQGgAAkDoAAJA8AACQPgAAkEAAAJBCAACQRAAAkEUAAJBGAACQSQAAkEoAAJBMAACQTQAAkE8AAJBRAACQUgAAkFMAAJBWAACQVwAAkFwAAJBpAACQbgAAkHAAAJByAACQdwAAkHoAAJB9AACQfwAAkKQAAJDIAACQ7wAAkRMAAJEWAACRGAAAkRoAAJEcAACRHgAAkSAAAJEhAACRJAAAkTEAAJFCAACRRAAAkUYAAJFIAACRSgAAkUwAAJFOAACRUAAAkVIAAJFjAACRZgAAkWkAAJFsAACRbwAAkXIAAJF1AACReAAAkXsAAJF9AACRvAAAkb4AAJHAAACRwgAAkcUAAJHGAACRxwAAkcgAAJHJAACRywAAkc0AAJHOAACRzwAAkdEAAJHSAACSEQAAkhMAAJIVAACSFwAAkhoAAJIbAACSHAAAkh0AAJIeAACSIAAAkiIAAJIjAACSJAAAkiYAAJInAACSZgAAkmgAAJJrAACSbQAAknAAAJJxAACScgAAknMAAJJ0AACSdgAAkngAAJJ5AACSegAAknwAAJJ9AACSigAAkosAAJKMAACSjgAAks0AAJLPAACS0QAAktMAAJLWAACS1wAAktgAAJLZAACS2gAAktwAAJLeAACS3wAAkuAAAJLiAACS4wAAkyIAAJMkAACTJgAAkygAAJMrAACTLAAAky0AAJMuAACTLwAAkzEAAJMzAACTNAAAkzUAAJM3AACTOAAAk3cAAJN5AACTewAAk30AAJOAAACTgQAAk4IAAJODAACThAAAk4YAAJOIAACTiQAAk4oAAJOMAACTjQAAk8wAAJPOAACT0AAAk9IAAJPVAACT1gAAk9cAAJPYAACT2QAAk9sAAJPdAACT3gAAk98AAJPhAACT4gAAlCEAAJQjAACUJQAAlCcAAJQqAACUKwAAlCwAAJQtAACULgAAlDAAAJQyAACUMwAAlDQAAJQ2AACUNwAAlFwAAJSAAACUpwAAlMsAAJTOAACU0AAAlNIAAJTUAACU1gAAlNgAAJTZAACU3AAAlOkAAJT4AACU+gAAlPwAAJT+AACVAAAAlQIAAJUEAACVBgAAlRUAAJUYAACVGwAAlR4AAJUhAACVJAAAlScAAJUqAACVLAAAlWsAAJVtAACVbwAAlXEAAJV0AACVdQAAlXYAAJV3AACVeAAAlXoAAJV8AACVfQAAlX4AAJWAAACVgQAAlcAAAJXCAACVxAAAlcYAAJXJAACVygAAlcsAAJXMAACVzQAAlc8AAJXRAACV0gAAldMAAJXVAACV1gAAlhUAAJYXAACWGQAAlhsAAJYeAACWHwAAliAAAJYhAACWIgAAliQAAJYmAACWJwAAligAAJYqAACWKwAAlmoAAJZsAACWbwAAlnEAAJZ0AACWdQAAlnYAAJZ3AACWeAAAlnoAAJZ8AACWfQAAln4AAJaAAACWgQAAlsAAAJbCAACWxAAAlsYAAJbJAACWygAAlssAAJbMAACWzQAAls8AAJbRAACW0gAAltMAAJbVAACW1gAAlxUAAJcXAACXGQAAlxsAAJceAACXHwAAlyAAAJchAACXIgAAlyQAAJcmAACXJwAAlygAAJcqAACXKwAAl2oAAJdsAACXbgAAl3AAAJdzAACXdAAAl3UAAJd2AACXdwAAl3kAAJd7AACXfAAAl30AAJd/AACXgAAAl8sAAJfuAACYDgAAmC4AAJgwAACYMgAAmDQAAJg2AACYOAAAmDkAAJg6AACYPQAAmD4AAJhAAACYQQAAmEMAAJhFAACYRgAAmEcAAJhKAACYSwAAmFAAAJhdAACYYgAAmGQAAJhmAACYawAAmG4AAJhxAACYcwAAmJgAAJi8AACY4wAAmQcAAJkKAACZDAAAmQ4AAJkQAACZEgAAmRQAAJkVAACZGAAAmSUAAJk2AACZOAAAmToAAJk8AACZPgAAmUAAAJlCAACZRAAAmUYAAJlXAACZWgAAmV0AAJlgAACZYwAAmWYAAJlpAACZbAAAmW8AAJlxAACZsAAAmbIAAJm0AACZtgAAmbkAAJm6AACZuwAAmbwAAJm9AACZvwAAmcEAAJnCAACZwwAAmcUAAJnGAACaBQAAmgcAAJoJAACaCwAAmg4AAJoPAACaEAAAmhEAAJoSAACaFAAAmhYAAJoXAACaGAAAmhoAAJobAACaWgAAmlwAAJpfAACaYQAAmmQAAJplAACaZgAAmmcAAJpoAACaagAAmmwAAJptAACabgAAmnAAAJpxAACafgAAmn8AAJqAAACaggAAmsEAAJrDAACaxQAAmscAAJrKAACaywAAmswAAJrNAACazgAAmtAAAJrSAACa0wAAmtQAAJrWAACa1wAAmxYAAJsYAACbGgAAmxwAAJsfAACbIAAAmyEAAJsiAACbIwAAmyUAAJsnAACbKAAAmykAAJsrAACbLAAAm2sAAJttAACbbwAAm3EAAJt0AACbdQAAm3YAAJt3AACbeAAAm3oAAJt8AACbfQAAm34AAJuAAACbgQAAm8AAAJvCAACbxAAAm8YAAJvJAACbygAAm8sAAJvMAACbzQAAm88AAJvRAACb0gAAm9MAAJvVAACb1gAAnBUAAJwXAACcGQAAnBsAAJweAACcHwAAnCAAAJwhAACcIgAAnCQAAJwmAACcJwAAnCgAAJwqAACcKwAAnFAAAJx0AACcmwAAnL8AAJzCAACcxAAAnMYAAJzIAACcygAAnMwAAJzNAACc0AAAnN0AAJzsAACc7gAAnPAAAJzyAACc9AAAnPYAAJz4AACc+gAAnQkAAJ0MAACdDwAAnRIAAJ0VAACdGAAAnRsAAJ0eAACdIAAAnV8AAJ1hAACdYwAAnWUAAJ1oAACdaQAAnWoAAJ1rAACdbAAAnW4AAJ1wAACdcQAAnXIAAJ10AACddQAAnbQAAJ22AACduAAAnboAAJ29AACdvgAAnb8AAJ3AAACdwQAAncMAAJ3FAACdxgAAnccAAJ3JAACdygAAngkAAJ4LAACeDQAAng8AAJ4SAACeEwAAnhQAAJ4VAACeFgAAnhgAAJ4aAACeGwAAnhwAAJ4eAACeHwAAnl4AAJ5gAACeYgAAnmQAAJ5nAACeaAAAnmkAAJ5qAACeawAAnm0AAJ5vAACecAAAnnEAAJ5zAACedAAAnrMAAJ61AACetwAAnrkAAJ68AACevQAAnr4AAJ6/AACewAAAnsIAAJ7EAACexQAAnsYAAJ7IAACeyQAAnwgAAJ8KAACfDAAAnw4AAJ8RAACfEgAAnxMAAJ8UAACfFQAAnxcAAJ8ZAACfGgAAnxsAAJ8dAACfHgAAn10AAJ9fAACfYQAAn2MAAJ9mAACfZwAAn2gAAJ9pAACfagAAn2wAAJ9uAACfbwAAn3AAAJ9yAACfcwAAn74AAJ/hAACgAQAAoCEAAKAjAACgJQAAoCcAAKApAACgKwAAoCwAAKAtAACgMAAAoDEAAKAzAACgNAAAoDYAAKA4AACgOQAAoDoAAKA9AACgPgAAoEMAAKBQAACgVQAAoFcAAKBZAACgXgAAoGEAAKBkAACgZgAAoIsAAKCvAACg1gAAoPoAAKD9AACg/wAAoQEAAKEDAAChBQAAoQcAAKEIAAChCwAAoRgAAKEpAAChKwAAoS0AAKEvAAChMQAAoTMAAKE1AAChNwAAoTkAAKFKAAChTQAAoVAAAKFTAAChVgAAoVkAAKFcAAChXwAAoWIAAKFkAAChowAAoaUAAKGnAAChqQAAoawAAKGtAAChrgAAoa8AAKGwAAChsgAAobQAAKG1AAChtgAAobgAAKG5AACh+AAAofoAAKH8AACh/gAAogEAAKICAACiAwAAogQAAKIFAACiBwAAogkAAKIKAACiCwAAog0AAKIOAACiTQAAok8AAKJSAACiVAAAolcAAKJYAACiWQAAoloAAKJbAACiXQAAol8AAKJgAACiYQAAomMAAKJkAACicQAAonIAAKJzAACidQAAorQAAKK2AACiuAAAoroAAKK9AACivgAAor8AAKLAAACiwQAAosMAAKLFAACixgAAoscAAKLJAACiygAAowkAAKMLAACjDQAAow8AAKMSAACjEwAAoxQAAKMVAACjFgAAoxgAAKMaAACjGwAAoxwAAKMeAACjHwAAo14AAKNgAACjYgAAo2QAAKNnAACjaAAAo2kAAKNqAACjawAAo20AAKNvAACjcAAAo3EAAKNzAACjdAAAo7MAAKO1AACjtwAAo7kAAKO8AACjvQAAo74AAKO/AACjwAAAo8IAAKPEAACjxQAAo8YAAKPIAACjyQAApAgAAKQKAACkDAAApA4AAKQRAACkEgAApBMAAKQUAACkFQAApBcAAKQZAACkGgAApBsAAKQdAACkHgAApEMAAKRnAACkjgAApLIAAKS1AACktwAApLkAAKS7AACkvQAApL8AAKTAAACkwwAApNAAAKTfAACk4QAApOMAAKTlAACk5wAApOkAAKTrAACk7QAApPwAAKT/AAClAgAApQUAAKUIAAClCwAApQ4AAKURAAClEwAApVIAAKVUAAClVgAApVgAAKVbAAClXAAApV0AAKVeAAClXwAApWEAAKVjAAClZAAApWUAAKVnAAClaAAApacAAKWpAAClqwAApa0AAKWwAAClsQAApbIAAKWzAACltAAApbYAAKW4AACluQAApboAAKW8AAClvQAApfwAAKX+AACmAAAApgIAAKYFAACmBgAApgcAAKYIAACmCQAApgsAAKYNAACmDgAApg8AAKYRAACmEgAAplEAAKZTAACmVQAAplcAAKZaAACmWwAAplwAAKZdAACmXgAApmAAAKZiAACmYwAApmQAAKZmAACmZwAApqYAAKaoAACmqgAApqwAAKavAACmsAAAprEAAKayAACmswAAprUAAKa3AACmuAAAprkAAKa7AACmvAAApvsAAKb9AACm/wAApwEAAKcEAACnBQAApwYAAKcHAACnCAAApwoAAKcMAACnDQAApw4AAKcQAACnEQAAp1AAAKdSAACnVAAAp1YAAKdZAACnWgAAp1sAAKdcAACnXQAAp18AAKdhAACnYgAAp2MAAKdlAACnZgAAp3EAAKd6AACnewAAp30AAKeGAACnkQAAp6AAAKerAACnuQAAp84AAKfiAACn+QAAqAsAAKhOAACocgAAqJYAAKi5AACo4AAAqQAAAKknAACpTgAAqW4AAKmSAACptgAAqbgAAKm7AACpvQAAqb8AAKnBAACpxAAAqccAAKnJAACpywAAqc4AAKnQAACp0gAAqdUAAKnYAACp2QAAqd4AAKnrAACp7gAAqfAAAKnzAACp9gAAqfgAAKodAACqQQAAqmgAAKqMAACqjwAAqpEAAKqTAACqlQAAqpcAAKqZAACqmgAAqp0AAKqqAACqvQAAqr8AAKrBAACqwwAAqsUAAKrHAACqyQAAqssAAKrNAACqzwAAquIAAKrlAACq6AAAqusAAKruAACq8QAAqvQAAKr3AACq+gAAqv0AAKr/AACrPgAAq0AAAKtDAACrRQAAq0gAAKtJAACrSgAAq0sAAKtMAACrTgAAq1AAAKtRAACrUgAAq1QAAKtVAACrXgAAq18AAKthAACroAAAq6IAAKukAACrpgAAq6kAAKuqAACrqwAAq6wAAKutAACrrwAAq7EAAKuyAACrswAAq7UAAKu2AACr9QAAq/cAAKv6AACr/AAAq/8AAKwAAACsAQAArAIAAKwDAACsBQAArAcAAKwIAACsCQAArAsAAKwMAACsFQAArBoAAKwdAACsIAAArCIAAKwrAACsLgAArDEAAKwzAACsOAAArEEAAKxEAACsRwAArEkAAKxYAACslwAArJkAAKybAACsnQAArKAAAKyhAACsogAArKMAAKykAACspgAArKgAAKypAACsqgAArKwAAKytAACs7AAArO4AAKzxAACs8wAArPYAAKz3AACs+AAArPkAAKz6AACs/AAArP4AAKz/AACtAAAArQIAAK0DAACtDAAArQ0AAK0PAACtTgAArVAAAK1SAACtVAAArVcAAK1YAACtWQAArVoAAK1bAACtXQAArV8AAK1gAACtYQAArWMAAK1kAACtowAAraUAAK2oAACtqgAAra0AAK2uAACtrwAArbAAAK2xAACtswAArbUAAK22AACttwAArbkAAK26AACtxwAArcgAAK3JAACtywAArgoAAK4MAACuDgAArhAAAK4TAACuFAAArhUAAK4WAACuFwAArhkAAK4bAACuHAAArh0AAK4fAACuIAAArl8AAK5hAACuZAAArmYAAK5pAACuagAArmsAAK5sAACubQAArm8AAK5xAACucgAArnMAAK51AACudgAArpUAAK6iAACuywAArs4AAK7RAACu1AAArtcAAK7aAACu3QAAruAAAK7jAACu5gAArukAAK7sAACu7wAArvIAAK70AACu9wAArvoAAK78AACu/wAArwIAAK8rAACvLgAArzEAAK80AACvNwAArzoAAK89AACvQAAAr0MAAK9GAACvSQAAr0wAAK9PAACvUgAAr1UAAK9YAACvWwAAr14AAK9hAACvZAAAr2YAAK+AAACvigAAr6AAAK+4AACvwgAAr8wAAK/UAACv6gAAr/YAALAIAACwFwAAsB4AALAxAACwSAAAsFIAALBnAACwsgAAsNUAALD1AACxFQAAsRcAALEZAACxGwAAsR0AALEgAACxIQAAsSIAALElAACxJgAAsSgAALEpAACxKwAAsS4AALEvAACxMAAAsTMAALE0AACxOQAAsUYAALFLAACxTQAAsU8AALFUAACxVwAAsVoAALFcAACxgQAAsaUAALHMAACx8AAAsfMAALH1AACx9wAAsfkAALH7AACx/QAAsf4AALIBAACyDgAAsh8AALIhAACyIwAAsiUAALInAACyKQAAsisAALItAACyLwAAskAAALJDAACyRgAAskkAALJMAACyTwAAslIAALJVAACyWAAAsloAALKZAACymwAAsp0AALKfAACyogAAsqMAALKkAACypQAAsqYAALKoAACyqgAAsqsAALKsAACyrgAAsq8AALLuAACy8AAAsvIAALL0AACy9wAAsvgAALL5AACy+gAAsvsAALL9AACy/wAAswAAALMBAACzAwAAswQAALNDAACzRQAAs0gAALNKAACzTQAAs04AALNPAACzUAAAs1EAALNTAACzVQAAs1YAALNXAACzWQAAs1oAALNnAACzaAAAs2kAALNrAACzqgAAs6wAALOuAACzsAAAs7MAALO0AACztQAAs7YAALO3AACzuQAAs7sAALO8AACzvQAAs78AALPAAACz/wAAtAEAALQDAAC0BQAAtAgAALQJAAC0CgAAtAsAALQMAAC0DgAAtBAAALQRAAC0EgAAtBQAALQVAAC0VAAAtFYAALRYAAC0WgAAtF0AALReAAC0XwAAtGAAALRhAAC0YwAAtGUAALRmAAC0ZwAAtGkAALRqAAC0qQAAtKsAALSuAAC0sAAAtLMAALS0AAC0tQAAtLYAALS3AAC0uQAAtLsAALS8AAC0vQAAtL8AALTAAAC02QAAtRgAALUaAAC1HAAAtR4AALUhAAC1IgAAtSMAALUkAAC1JQAAtScAALUpAAC1KgAAtSsAALUtAAC1LgAAtVMAALV3AAC1ngAAtcIAALXFAAC1xwAAtckAALXLAAC1zQAAtc8AALXQAAC10wAAteAAALXvAAC18QAAtfMAALX1AAC19wAAtfkAALX7AAC1/QAAtgwAALYPAAC2EgAAthUAALYYAAC2GwAAth4AALYhAAC2IwAAtmIAALZkAAC2ZgAAtmgAALZrAAC2bAAAtm0AALZuAAC2bwAAtnEAALZzAAC2dAAAtnUAALZ3AAC2eAAAtrcAALa5AAC2uwAAtr0AALbAAAC2wQAAtsIAALbDAAC2xAAAtsYAALbIAAC2yQAAtsoAALbMAAC2zQAAtwwAALcOAAC3EAAAtxIAALcVAAC3FgAAtxcAALcYAAC3GQAAtxsAALcdAAC3HgAAtx8AALchAAC3IgAAt2EAALdjAAC3ZgAAt2gAALdrAAC3bAAAt20AALduAAC3bwAAt3EAALdzAAC3dAAAt3UAALd3AAC3eAAAt7cAALe5AAC3uwAAt70AALfAAAC3wQAAt8IAALfDAAC3xAAAt8YAALfIAAC3yQAAt8oAALfMAAC3zQAAuAwAALgOAAC4EAAAuBIAALgVAAC4FgAAuBcAALgYAAC4GQAAuBsAALgdAAC4HgAAuB8AALghAAC4IgAAuGEAALhjAAC4ZQAAuGcAALhqAAC4awAAuGwAALhtAAC4bgAAuHAAALhyAAC4cwAAuHQAALh2AAC4dwAAuMIAALjlAAC5BQAAuSUAALknAAC5KQAAuSsAALktAAC5MAAAuTEAALkyAAC5NQAAuTYAALk4AAC5OQAAuTsAALk+AAC5PwAAuUAAALlDAAC5RAAAuUkAALlWAAC5WwAAuV0AALlfAAC5ZAAAuWcAALlqAAC5bAAAuZEAALm1AAC53AAAugAAALoDAAC6BQAAugcAALoJAAC6CwAAug0AALoOAAC6EQAAuh4AALovAAC6MQAAujMAALo1AAC6NwAAujkAALo7AAC6PQAAuj8AALpQAAC6UwAAulYAALpZAAC6XAAAul8AALpiAAC6ZQAAumgAALpqAAC6qQAAuqsAALqtAAC6rwAAurIAALqzAAC6tAAAurUAALq2AAC6uAAAuroAALq7AAC6vAAAur4AALq/AAC6/gAAuwAAALsCAAC7BAAAuwcAALsIAAC7CQAAuwoAALsLAAC7DQAAuw8AALsQAAC7EQAAuxMAALsUAAC7UwAAu1UAALtYAAC7WgAAu10AALteAAC7XwAAu2AAALthAAC7YwAAu2UAALtmAAC7ZwAAu2kAALtqAAC7dwAAu3gAALt5AAC7ewAAu7oAALu8AAC7vgAAu8AAALvDAAC7xAAAu8UAALvGAAC7xwAAu8kAALvLAAC7zAAAu80AALvPAAC70AAAvA8AALwRAAC8EwAAvBUAALwYAAC8GQAAvBoAALwbAAC8HAAAvB4AALwgAAC8IQAAvCIAALwkAAC8JQAAvGQAALxmAAC8aAAAvGoAALxtAAC8bgAAvG8AALxwAAC8cQAAvHMAALx1AAC8dgAAvHcAALx5AAC8egAAvLkAALy7AAC8vQAAvL8AALzCAAC8wwAAvMQAALzFAAC8xgAAvMgAALzKAAC8ywAAvMwAALzOAAC8zwAAvQ4AAL0QAAC9EgAAvRQAAL0XAAC9GAAAvRkAAL0aAAC9GwAAvR0AAL0fAAC9IAAAvSEAAL0jAAC9JAAAvUkAAL1tAAC9lAAAvbgAAL27AAC9vQAAvb8AAL3BAAC9wwAAvcUAAL3GAAC9yQAAvdYAAL3lAAC95wAAvekAAL3rAAC97QAAve8AAL3xAAC98wAAvgIAAL4FAAC+CAAAvgsAAL4OAAC+EQAAvhQAAL4XAAC+GQAAvlgAAL5aAAC+XAAAvl4AAL5hAAC+YgAAvmMAAL5kAAC+ZQAAvmcAAL5pAAC+agAAvmsAAL5tAAC+bgAAvq0AAL6vAAC+sQAAvrMAAL62AAC+twAAvrgAAL65AAC+ugAAvrwAAL6+AAC+vwAAvsAAAL7CAAC+wwAAvwIAAL8EAAC/BgAAvwgAAL8LAAC/DAAAvw0AAL8OAAC/DwAAvxEAAL8TAAC/FAAAvxUAAL8XAAC/GAAAv1cAAL9ZAAC/XAAAv14AAL9hAAC/YgAAv2MAAL9kAAC/ZQAAv2cAAL9pAAC/agAAv2sAAL9tAAC/bgAAv60AAL+vAAC/sQAAv7MAAL+2AAC/twAAv7gAAL+5AAC/ugAAv7wAAL++AAC/vwAAv8AAAL/CAAC/wwAAwAIAAMAEAADABgAAwAgAAMALAADADAAAwA0AAMAOAADADwAAwBEAAMATAADAFAAAwBUAAMAXAADAGAAAwFcAAMBZAADAWwAAwF0AAMBgAADAYQAAwGIAAMBjAADAZAAAwGYAAMBoAADAaQAAwGoAAMBsAADAbQAAwLgAAMDbAADA+wAAwRsAAMEdAADBHwAAwSEAAMEjAADBJgAAwScAAMEoAADBKwAAwSwAAMEuAADBLwAAwTEAAME0AADBNQAAwTYAAME5AADBOgAAwT8AAMFMAADBUQAAwVMAAMFVAADBWgAAwV0AAMFgAADBYgAAwYcAAMGrAADB0gAAwfYAAMH5AADB+wAAwf0AAMH/AADCAQAAwgMAAMIEAADCBwAAwhQAAMIlAADCJwAAwikAAMIrAADCLQAAwi8AAMIxAADCMwAAwjUAAMJGAADCSQAAwkwAAMJPAADCUgAAwlUAAMJYAADCWwAAwl4AAMJgAADCnwAAwqEAAMKjAADCpQAAwqgAAMKpAADCqgAAwqsAAMKsAADCrgAAwrAAAMKxAADCsgAAwrQAAMK1AADC9AAAwvYAAML4AADC+gAAwv0AAML+AADC/wAAwwAAAMMBAADDAwAAwwUAAMMGAADDBwAAwwkAAMMKAADDSQAAw0sAAMNOAADDUAAAw1MAAMNUAADDVQAAw1YAAMNXAADDWQAAw1sAAMNcAADDXQAAw18AAMNgAADDbQAAw24AAMNvAADDcQAAw7AAAMOyAADDtAAAw7YAAMO5AADDugAAw7sAAMO8AADDvQAAw78AAMPBAADDwgAAw8MAAMPFAADDxgAAxAUAAMQHAADECQAAxAsAAMQOAADEDwAAxBAAAMQRAADEEgAAxBQAAMQWAADEFwAAxBgAAMQaAADEGwAAxFoAAMRcAADEXgAAxGAAAMRjAADEZAAAxGUAAMRmAADEZwAAxGkAAMRrAADEbAAAxG0AAMRvAADEcAAAxK8AAMSxAADEswAAxLUAAMS4AADEuQAAxLoAAMS7AADEvAAAxL4AAMTAAADEwQAAxMIAAMTEAADExQAAxQQAAMUGAADFCAAAxQoAAMUNAADFDgAAxQ8AAMUQAADFEQAAxRMAAMUVAADFFgAAxRcAAMUZAADFGgAAxT8AAMVjAADFigAAxa4AAMWxAADFswAAxbUAAMW3AADFuQAAxbsAAMW8AADFvwAAxcwAAMXbAADF3QAAxd8AAMXhAADF4wAAxeUAAMXnAADF6QAAxfgAAMX7AADF/gAAxgEAAMYEAADGBwAAxgoAAMYNAADGDwAAxk4AAMZQAADGUgAAxlQAAMZXAADGWAAAxlkAAMZaAADGWwAAxl0AAMZfAADGYAAAxmEAAMZjAADGZAAAxqMAAMalAADGpwAAxqkAAMasAADGrQAAxq4AAMavAADGsAAAxrIAAMa0AADGtQAAxrYAAMa4AADGuQAAxvgAAMb6AADG/AAAxv4AAMcBAADHAgAAxwMAAMcEAADHBQAAxwcAAMcJAADHCgAAxwsAAMcNAADHDgAAx00AAMdPAADHUQAAx1MAAMdWAADHVwAAx1gAAMdZAADHWgAAx1wAAMdeAADHXwAAx2AAAMdiAADHYwAAx6IAAMekAADHpgAAx6gAAMerAADHrAAAx60AAMeuAADHrwAAx7EAAMezAADHtAAAx7UAAMe3AADHuAAAx/cAAMf5AADH+wAAx/0AAMgAAADIAQAAyAIAAMgDAADIBAAAyAYAAMgIAADICQAAyAoAAMgMAADIDQAAyEwAAMhOAADIUAAAyFIAAMhVAADIVgAAyFcAAMhYAADIWQAAyFsAAMhdAADIXgAAyF8AAMhhAADIYgAAyK0AAMjQAADI8AAAyRAAAMkSAADJFAAAyRYAAMkYAADJGwAAyRwAAMkdAADJIAAAySEAAMkjAADJJAAAySYAAMkpAADJKgAAySsAAMkuAADJLwAAyTQAAMlBAADJRgAAyUgAAMlKAADJTwAAyVIAAMlVAADJVwAAyXwAAMmgAADJxwAAyesAAMnuAADJ8AAAyfIAAMn0AADJ9gAAyfgAAMn5AADJ/AAAygkAAMoaAADKHAAAyh4AAMogAADKIgAAyiQAAMomAADKKAAAyioAAMo7AADKPgAAykEAAMpEAADKRwAAykoAAMpNAADKUAAAylMAAMpVAADKlAAAypYAAMqYAADKmgAAyp0AAMqeAADKnwAAyqAAAMqhAADKowAAyqUAAMqmAADKpwAAyqkAAMqqAADK6QAAyusAAMrtAADK7wAAyvIAAMrzAADK9AAAyvUAAMr2AADK+AAAyvoAAMr7AADK/AAAyv4AAMr/AADLPgAAy0AAAMtDAADLRQAAy0gAAMtJAADLSgAAy0sAAMtMAADLTgAAy1AAAMtRAADLUgAAy1QAAMtVAADLYgAAy2MAAMtkAADLZgAAy6UAAMunAADLqQAAy6sAAMuuAADLrwAAy7AAAMuxAADLsgAAy7QAAMu2AADLtwAAy7gAAMu6AADLuwAAy/oAAMv8AADL/gAAzAAAAMwDAADMBAAAzAUAAMwGAADMBwAAzAkAAMwLAADMDAAAzA0AAMwPAADMEAAAzE8AAMxRAADMUwAAzFUAAMxYAADMWQAAzFoAAMxbAADMXAAAzF4AAMxgAADMYQAAzGIAAMxkAADMZQAAzKQAAMymAADMqAAAzKoAAMytAADMrgAAzK8AAMywAADMsQAAzLMAAMy1AADMtgAAzLcAAMy5AADMugAAzPkAAMz7AADM/QAAzP8AAM0CAADNAwAAzQQAAM0FAADNBgAAzQgAAM0KAADNCwAAzQwAAM0OAADNDwAAzTQAAM1YAADNfwAAzaMAAM2mAADNqAAAzaoAAM2sAADNrgAAzbAAAM2xAADNtAAAzcEAAM3QAADN0gAAzdQAAM3WAADN2AAAzdoAAM3cAADN3gAAze0AAM3wAADN8wAAzfYAAM35AADN/AAAzf8AAM4CAADOBAAAzkMAAM5FAADORwAAzkkAAM5MAADOTQAAzk4AAM5PAADOUAAAzlIAAM5UAADOVQAAzlYAAM5YAADOWQAAzpgAAM6aAADOnAAAzp4AAM6hAADOogAAzqMAAM6kAADOpQAAzqcAAM6pAADOqgAAzqsAAM6tAADOrgAAzu0AAM7vAADO8QAAzvMAAM72AADO9wAAzvgAAM75AADO+gAAzvwAAM7+AADO/wAAzwAAAM8CAADPAwAAz0IAAM9EAADPRwAAz0kAAM9MAADPTQAAz04AAM9PAADPUAAAz1IAAM9UAADPVQAAz1YAAM9YAADPWQAAz1wAAM+bAADPnQAAz58AAM+hAADPpAAAz6UAAM+mAADPpwAAz6gAAM+qAADPrAAAz60AAM+uAADPsAAAz7EAAM/wAADP8gAAz/QAAM/2AADP+QAAz/oAAM/7AADP/AAAz/0AAM//AADQAQAA0AIAANADAADQBQAA0AYAANBFAADQRwAA0EkAANBLAADQTgAA0E8AANBQAADQUQAA0FIAANBUAADQVgAA0FcAANBYAADQWgAA0FsAANCmAADQyQAA0OkAANEJAADRCwAA0Q0AANEPAADREQAA0RQAANEVAADRFgAA0RkAANEaAADRHAAA0R0AANEfAADRIgAA0SMAANEkAADRJwAA0SgAANEtAADROgAA0T8AANFBAADRQwAA0UgAANFLAADRTgAA0VAAANF1AADRmQAA0cAAANHkAADR5wAA0ekAANHrAADR7QAA0e8AANHxAADR8gAA0fUAANICAADSEwAA0hUAANIXAADSGQAA0hsAANIdAADSHwAA0iEAANIjAADSNAAA0jcAANI6AADSPQAA0kAAANJDAADSRgAA0kkAANJMAADSTgAA0o0AANKPAADSkQAA0pMAANKWAADSlwAA0pgAANKZAADSmgAA0pwAANKeAADSnwAA0qAAANKiAADSowAA0uIAANLkAADS5gAA0ugAANLrAADS7AAA0u0AANLuAADS7wAA0vEAANLzAADS9AAA0vUAANL3AADS+AAA0zcAANM5AADTPAAA0z4AANNBAADTQgAA00MAANNEAADTRQAA00cAANNJAADTSgAA00sAANNNAADTTgAA01sAANNcAADTXQAA018AANOeAADToAAA06IAANOkAADTpwAA06gAANOpAADTqgAA06sAANOtAADTrwAA07AAANOxAADTswAA07QAANPzAADT9QAA0/cAANP5AADT/AAA0/0AANP+AADT/wAA1AAAANQCAADUBAAA1AUAANQGAADUCAAA1AkAANRIAADUSgAA1EwAANROAADUUQAA1FIAANRTAADUVAAA1FUAANRXAADUWQAA1FoAANRbAADUXQAA1F4AANSdAADUnwAA1KEAANSjAADUpgAA1KcAANSoAADUqQAA1KoAANSsAADUrgAA1K8AANSwAADUsgAA1LMAANTyAADU9AAA1PYAANT4AADU+wAA1PwAANT9AADU/gAA1P8AANUBAADVAwAA1QQAANUFAADVBwAA1QgAANUtAADVUQAA1XgAANWcAADVnwAA1aEAANWjAADVpQAA1acAANWpAADVqgAA1a0AANW6AADVyQAA1csAANXNAADVzwAA1dEAANXTAADV1QAA1dcAANXmAADV6QAA1ewAANXvAADV8gAA1fUAANX4AADV+wAA1f0AANY8AADWPgAA1kAAANZCAADWRQAA1kYAANZHAADWSAAA1kkAANZLAADWTQAA1k4AANZPAADWUQAA1lIAANaRAADWkwAA1pUAANaXAADWmgAA1psAANacAADWnQAA1p4AANagAADWogAA1qMAANakAADWpgAA1qcAANbmAADW6AAA1uoAANbsAADW7wAA1vAAANbxAADW8gAA1vMAANb1AADW9wAA1vgAANb5AADW+wAA1vwAANc7AADXPQAA1z8AANdBAADXRAAA10UAANdGAADXRwAA10gAANdKAADXTAAA100AANdOAADXUAAA11EAANeQAADXkgAA15QAANeWAADXmQAA15oAANebAADXnAAA150AANefAADXoQAA16IAANejAADXpQAA16YAANflAADX5wAA1+kAANfrAADX7gAA1+8AANfwAADX8QAA1/IAANf0AADX9gAA1/cAANf4AADX+gAA1/sAANg6AADYPAAA2D4AANhAAADYQwAA2EQAANhFAADYRgAA2EcAANhJAADYSwAA2EwAANhNAADYTwAA2FAAANibAADYvgAA2N4AANj+AADZAAAA2QIAANkEAADZBgAA2QkAANkKAADZCwAA2Q4AANkPAADZEQAA2RIAANkUAADZFwAA2RgAANkZAADZHAAA2R0AANkiAADZLwAA2TQAANk2AADZOAAA2T0AANlAAADZQwAA2UUAANlqAADZjgAA2bUAANnZAADZ3AAA2d4AANngAADZ4gAA2eQAANnmAADZ5wAA2eoAANn3AADaCAAA2goAANoMAADaDgAA2hAAANoSAADaFAAA2hYAANoYAADaKQAA2iwAANovAADaMgAA2jUAANo4AADaOwAA2j4AANpBAADaQwAA2oIAANqEAADahgAA2ogAANqLAADajAAA2o0AANqOAADajwAA2pEAANqTAADalAAA2pUAANqXAADamAAA2tcAANrZAADa2wAA2t0AANrgAADa4QAA2uIAANrjAADa5AAA2uYAANroAADa6QAA2uoAANrsAADa7QAA2ywAANsuAADbMQAA2zMAANs2AADbNwAA2zgAANs5AADbOgAA2zwAANs+AADbPwAA20AAANtCAADbQwAA21AAANtRAADbUgAA21QAANuTAADblQAA25cAANuZAADbnAAA250AANueAADbnwAA26AAANuiAADbpAAA26UAANumAADbqAAA26kAANvoAADb6gAA2+wAANvuAADb8QAA2/IAANvzAADb9AAA2/UAANv3AADb+QAA2/oAANv7AADb/QAA2/4AANw9AADcPwAA3EEAANxDAADcRgAA3EcAANxIAADcSQAA3EoAANxMAADcTgAA3E8AANxQAADcUgAA3FMAANySAADclAAA3JYAANyYAADcmwAA3JwAANydAADcngAA3J8AANyhAADcowAA3KQAANylAADcpwAA3KgAANznAADc6QAA3OsAANztAADc8AAA3PEAANzyAADc8wAA3PQAANz2AADc+AAA3PkAANz6AADc/AAA3P0AAN0iAADdRgAA3W0AAN2RAADdlAAA3ZYAAN2YAADdmgAA3ZwAAN2eAADdnwAA3aIAAN2vAADdvgAA3cAAAN3CAADdxAAA3cYAAN3IAADdygAA3cwAAN3bAADd3gAA3eEAAN3kAADd5wAA3eoAAN3tAADd8AAA3fIAAN4xAADeMwAA3jUAAN43AADeOgAA3jsAAN48AADePQAA3j4AAN5AAADeQgAA3kMAAN5EAADeRgAA3kcAAN6GAADeiAAA3ooAAN6MAADejwAA3pAAAN6RAADekgAA3pMAAN6VAADelwAA3pgAAN6ZAADemwAA3pwAAN7bAADe3QAA3t8AAN7hAADe5AAA3uUAAN7mAADe5wAA3ugAAN7qAADe7AAA3u0AAN7uAADe8AAA3vEAAN8wAADfMgAA3zQAAN82AADfOQAA3zoAAN87AADfPAAA3z0AAN8/AADfQQAA30IAAN9DAADfRQAA30YAAN+FAADfhwAA34kAAN+LAADfjgAA348AAN+QAADfkQAA35IAAN+UAADflgAA35cAAN+YAADfmgAA35sAAN/aAADf3AAA394AAN/gAADf4wAA3+QAAN/lAADf5gAA3+cAAN/pAADf6wAA3+wAAN/tAADf7wAA3/AAAOAvAADgMQAA4DMAAOA1AADgOAAA4DkAAOA6AADgOwAA4DwAAOA+AADgQAAA4EEAAOBCAADgRAAA4EUAAOCQAADgswAA4NMAAODzAADg9QAA4PcAAOD5AADg+wAA4P4AAOD/AADhAAAA4QMAAOEEAADhBgAA4QcAAOEJAADhDAAA4Q0AAOEOAADhEQAA4RIAAOEbAADhKAAA4S0AAOEvAADhMQAA4TYAAOE5AADhPAAA4T4AAOFjAADhhwAA4a4AAOHSAADh1QAA4dcAAOHZAADh2wAA4d0AAOHfAADh4AAA4eMAAOHwAADiAQAA4gMAAOIFAADiBwAA4gkAAOILAADiDQAA4g8AAOIRAADiIgAA4iUAAOIoAADiKwAA4i4AAOIxAADiNAAA4jcAAOI6AADiPAAA4nsAAOJ9AADifwAA4oEAAOKEAADihQAA4oYAAOKHAADiiAAA4ooAAOKMAADijQAA4o4AAOKQAADikQAA4tAAAOLSAADi1AAA4tYAAOLZAADi2gAA4tsAAOLcAADi3QAA4t8AAOLhAADi4gAA4uMAAOLlAADi5gAA4yUAAOMnAADjKgAA4ywAAOMvAADjMAAA4zEAAOMyAADjMwAA4zUAAOM3AADjOAAA4zkAAOM7AADjPAAA40kAAONKAADjSwAA400AAOOMAADjjgAA45AAAOOSAADjlQAA45YAAOOXAADjmAAA45kAAOObAADjnQAA454AAOOfAADjoQAA46IAAOPhAADj4wAA4+UAAOPnAADj6gAA4+sAAOPsAADj7QAA4+4AAOPwAADj8gAA4/MAAOP0AADj9gAA4/cAAOQ2AADkOAAA5DoAAOQ8AADkPwAA5EAAAORBAADkQgAA5EMAAORFAADkRwAA5EgAAORJAADkSwAA5EwAAOSLAADkjQAA5I8AAOSRAADklAAA5JUAAOSWAADklwAA5JgAAOSaAADknAAA5J0AAOSeAADkoAAA5KEAAOTgAADk4gAA5OQAAOTmAADk6QAA5OoAAOTrAADk7AAA5O0AAOTvAADk8QAA5PIAAOTzAADk9QAA5PYAAOUbAADlPwAA5WYAAOWKAADljQAA5Y8AAOWRAADlkwAA5ZUAAOWXAADlmAAA5ZsAAOWoAADltwAA5bkAAOW7AADlvQAA5b8AAOXBAADlwwAA5cUAAOXUAADl1wAA5doAAOXdAADl4AAA5eMAAOXmAADl6QAA5esAAOYqAADmLAAA5i4AAOYwAADmMwAA5jQAAOY1AADmNgAA5jcAAOY5AADmOwAA5jwAAOY9AADmPwAA5kAAAOZ/AADmgQAA5oMAAOaFAADmiAAA5okAAOaKAADmiwAA5owAAOaOAADmkAAA5pEAAOaSAADmlAAA5pUAAObUAADm1gAA5tgAAObaAADm3QAA5t4AAObfAADm4AAA5uEAAObjAADm5QAA5uYAAObnAADm6QAA5uoAAOcpAADnKwAA5y0AAOcvAADnMgAA5zMAAOc0AADnNQAA5zYAAOc4AADnOgAA5zsAAOc8AADnPgAA5z8AAOd+AADngAAA54IAAOeEAADnhwAA54gAAOeJAADnigAA54sAAOeNAADnjwAA55AAAOeRAADnkwAA55QAAOfTAADn1QAA59cAAOfZAADn3AAA590AAOfeAADn3wAA5+AAAOfiAADn5AAA5+UAAOfmAADn6AAA5+kAAOgoAADoKgAA6CwAAOguAADoMQAA6DIAAOgzAADoNAAA6DUAAOg3AADoOQAA6DoAAOg7AADoPQAA6D4AAOiJAADorAAA6MwAAOjsAADo7gAA6PAAAOjyAADo9AAA6PcAAOj4AADo+QAA6PwAAOj9AADo/wAA6QAAAOkCAADpBQAA6QYAAOkHAADpCgAA6QsAAOkQAADpHQAA6SIAAOkkAADpJgAA6SsAAOkuAADpMQAA6TMAAOlYAADpfAAA6aMAAOnHAADpygAA6cwAAOnOAADp0AAA6dIAAOnUAADp1QAA6dgAAOnlAADp9gAA6fgAAOn6AADp/AAA6f4AAOoAAADqAgAA6gQAAOoGAADqFwAA6hoAAOodAADqIAAA6iMAAOomAADqKQAA6iwAAOovAADqMQAA6nAAAOpyAADqdAAA6nYAAOp5AADqegAA6nsAAOp8AADqfQAA6n8AAOqBAADqggAA6oMAAOqFAADqhgAA6sUAAOrHAADqyQAA6ssAAOrOAADqzwAA6tAAAOrRAADq0gAA6tQAAOrWAADq1wAA6tgAAOraAADq2wAA6xoAAOscAADrHwAA6yEAAOskAADrJQAA6yYAAOsnAADrKAAA6yoAAOssAADrLQAA6y4AAOswAADrMQAA6z4AAOs/AADrQAAA60IAAOuBAADrgwAA64UAAOuHAADrigAA64sAAOuMAADrjQAA644AAOuQAADrkgAA65MAAOuUAADrlgAA65cAAOvWAADr2AAA69oAAOvcAADr3wAA6+AAAOvhAADr4gAA6+MAAOvlAADr5wAA6+gAAOvpAADr6wAA6+wAAOwrAADsLQAA7C8AAOwxAADsNAAA7DUAAOw2AADsNwAA7DgAAOw6AADsPAAA7D0AAOw+AADsQAAA7EEAAOyAAADsggAA7IQAAOyGAADsiQAA7IoAAOyLAADsjAAA7I0AAOyPAADskQAA7JIAAOyTAADslQAA7JYAAOzVAADs1wAA7NkAAOzbAADs3gAA7N8AAOzgAADs4QAA7OIAAOzkAADs5gAA7OcAAOzoAADs6gAA7OsAAO0QAADtNAAA7VsAAO1/AADtggAA7YQAAO2GAADtiAAA7YoAAO2MAADtjQAA7ZAAAO2dAADtrAAA7a4AAO2wAADtsgAA7bQAAO22AADtuAAA7boAAO3JAADtzAAA7c8AAO3SAADt1QAA7dgAAO3bAADt3gAA7eAAAO4fAADuIQAA7iMAAO4lAADuKAAA7ikAAO4qAADuKwAA7iwAAO4uAADuMAAA7jEAAO4yAADuNAAA7jUAAO50AADudgAA7ngAAO56AADufQAA7n4AAO5/AADugAAA7oEAAO6DAADuhQAA7oYAAO6HAADuiQAA7ooAAO7JAADuywAA7s0AAO7PAADu0gAA7tMAAO7UAADu1QAA7tYAAO7YAADu2gAA7tsAAO7cAADu3gAA7t8AAO8eAADvIAAA7yMAAO8lAADvKAAA7ykAAO8qAADvKwAA7ywAAO8uAADvMAAA7zEAAO8yAADvNAAA7zUAAO90AADvdgAA73gAAO96AADvfQAA734AAO9/AADvgAAA74EAAO+DAADvhQAA74YAAO+HAADviQAA74oAAO/JAADvywAA780AAO/PAADv0gAA79MAAO/UAADv1QAA79YAAO/YAADv2gAA79sAAO/cAADv3gAA798AAPAeAADwIAAA8CIAAPAkAADwJwAA8CgAAPApAADwKgAA8CsAAPAtAADwLwAA8DAAAPAxAADwMwAA8DQAAPB/AADwogAA8MIAAPDiAADw5AAA8OYAAPDoAADw6gAA8O0AAPDuAADw7wAA8PIAAPDzAADw9QAA8PYAAPD4AADw+wAA8PwAAPD9AADxAAAA8QEAAPEGAADxEwAA8RgAAPEaAADxHAAA8SEAAPEkAADxJwAA8SkAAPFOAADxcgAA8ZkAAPG9AADxwAAA8cIAAPHEAADxxgAA8cgAAPHKAADxywAA8c4AAPHbAADx7AAA8e4AAPHwAADx8gAA8fQAAPH2AADx+AAA8foAAPH8AADyDQAA8hAAAPITAADyFgAA8hkAAPIcAADyHwAA8iIAAPIlAADyJwAA8mYAAPJoAADyagAA8mwAAPJvAADycAAA8nEAAPJyAADycwAA8nUAAPJ3AADyeAAA8nkAAPJ7AADyfAAA8rsAAPK9AADyvwAA8sEAAPLEAADyxQAA8sYAAPLHAADyyAAA8soAAPLMAADyzQAA8s4AAPLQAADy0QAA8xAAAPMSAADzFQAA8xcAAPMaAADzGwAA8xwAAPMdAADzHgAA8yAAAPMiAADzIwAA8yQAAPMmAADzJwAA8zQAAPM1AADzNgAA8zgAAPN3AADzeQAA83sAAPN9AADzgAAA84EAAPOCAADzgwAA84QAAPOGAADziAAA84kAAPOKAADzjAAA840AAPPMAADzzgAA89AAAPPSAADz1QAA89YAAPPXAADz2AAA89kAAPPbAADz3QAA894AAPPfAADz4QAA8+IAAPQhAAD0IwAA9CUAAPQnAAD0KgAA9CsAAPQsAAD0LQAA9C4AAPQwAAD0MgAA9DMAAPQ0AAD0NgAA9DcAAPR2AAD0eAAA9HoAAPR8AAD0fwAA9IAAAPSBAAD0ggAA9IMAAPSFAAD0hwAA9IgAAPSJAAD0iwAA9IwAAPTLAAD0zQAA9M8AAPTRAAD01AAA9NUAAPTWAAD01wAA9NgAAPTaAAD03AAA9N0AAPTeAAD04AAA9OEAAPUGAAD1KgAA9VEAAPV1AAD1eAAA9XoAAPV8AAD1fgAA9YAAAPWCAAD1gwAA9YYAAPWTAAD1ogAA9aQAAPWmAAD1qAAA9aoAAPWsAAD1rgAA9bAAAPW/AAD1wgAA9cUAAPXIAAD1ywAA9c4AAPXRAAD11AAA9dYAAPYVAAD2FwAA9hkAAPYbAAD2HgAA9h8AAPYgAAD2IQAA9iIAAPYkAAD2JgAA9icAAPYoAAD2KgAA9isAAPZqAAD2bAAA9m4AAPZwAAD2cwAA9nQAAPZ1AAD2dgAA9ncAAPZ5AAD2ewAA9nwAAPZ9AAD2fwAA9oAAAPa/AAD2wQAA9sMAAPbFAAD2yAAA9skAAPbKAAD2ywAA9swAAPbOAAD20AAA9tEAAPbSAAD21AAA9tUAAPcUAAD3FgAA9xgAAPcaAAD3HQAA9x4AAPcfAAD3IAAA9yEAAPcjAAD3JQAA9yYAAPcnAAD3KQAA9yoAAPdpAAD3awAA920AAPdvAAD3cgAA93MAAPd0AAD3dQAA93YAAPd4AAD3egAA93sAAPd8AAD3fgAA938AAPe+AAD3wAAA98IAAPfEAAD3xwAA98gAAPfJAAD3ygAA98sAAPfNAAD3zwAA99AAAPfRAAD30wAA99QAAPgTAAD4FQAA+BcAAPgZAAD4HAAA+B0AAPgeAAD4HwAA+CAAAPgiAAD4JAAA+CUAAPgmAAD4KAAA+CkAAPh0AAD4lwAA+LcAAPjXAAD42QAA+NsAAPjdAAD43wAA+OIAAPjjAAD45AAA+OcAAPjoAAD46gAA+OsAAPjtAAD48AAA+PEAAPjyAAD49QAA+PYAAPj/AAD5DAAA+REAAPkTAAD5FQAA+RoAAPkdAAD5IAAA+SIAAPlHAAD5awAA+ZIAAPm2AAD5uQAA+bsAAPm9AAD5vwAA+cEAAPnDAAD5xAAA+ccAAPnUAAD55QAA+ecAAPnpAAD56wAA+e0AAPnvAAD58QAA+fMAAPn1AAD6BgAA+gkAAPoMAAD6DwAA+hIAAPoVAAD6GAAA+hsAAPoeAAD6IAAA+l8AAPphAAD6YwAA+mUAAPpoAAD6aQAA+moAAPprAAD6bAAA+m4AAPpwAAD6cQAA+nIAAPp0AAD6dQAA+rQAAPq2AAD6uAAA+roAAPq9AAD6vgAA+r8AAPrAAAD6wQAA+sMAAPrFAAD6xgAA+scAAPrJAAD6ygAA+wkAAPsLAAD7DgAA+xAAAPsTAAD7FAAA+xUAAPsWAAD7FwAA+xkAAPsbAAD7HAAA+x0AAPsfAAD7IAAA+y0AAPsuAAD7LwAA+zEAAPtwAAD7cgAA+3QAAPt2AAD7eQAA+3oAAPt7AAD7fAAA+30AAPt/AAD7gQAA+4IAAPuDAAD7hQAA+4YAAPvFAAD7xwAA+8kAAPvLAAD7zgAA+88AAPvQAAD70QAA+9IAAPvUAAD71gAA+9cAAPvYAAD72gAA+9sAAPwaAAD8HAAA/B4AAPwgAAD8IwAA/CQAAPwlAAD8JgAA/CcAAPwpAAD8KwAA/CwAAPwtAAD8LwAA/DAAAPxvAAD8cQAA/HMAAPx1AAD8eAAA/HkAAPx6AAD8ewAA/HwAAPx+AAD8gAAA/IEAAPyCAAD8hAAA/IUAAPzEAAD8xgAA/MgAAPzKAAD8zQAA/M4AAPzPAAD80AAA/NEAAPzTAAD81QAA/NYAAPzXAAD82QAA/NoAAPz/AAD9IwAA/UoAAP1uAAD9cQAA/XMAAP11AAD9dwAA/XkAAP17AAD9fAAA/X8AAP2MAAD9mwAA/Z0AAP2fAAD9oQAA/aMAAP2lAAD9pwAA/akAAP24AAD9uwAA/b4AAP3BAAD9xAAA/ccAAP3KAAD9zQAA/c8AAP4OAAD+EAAA/hMAAP4VAAD+GAAA/hkAAP4aAAD+GwAA/hwAAP4eAAD+IAAA/iEAAP4iAAD+JAAA/iUAAP5kAAD+ZgAA/mgAAP5qAAD+bQAA/m4AAP5vAAD+cAAA/nEAAP5zAAD+dQAA/nYAAP53AAD+eQAA/noAAP65AAD+uwAA/r0AAP6/AAD+wgAA/sMAAP7EAAD+xQAA/sYAAP7IAAD+ygAA/ssAAP7MAAD+zgAA/s8AAP8OAAD/EAAA/xMAAP8VAAD/GAAA/xkAAP8aAAD/GwAA/xwAAP8eAAD/IAAA/yEAAP8iAAD/JAAA/yUAAP9kAAD/ZgAA/2gAAP9qAAD/bQAA/24AAP9vAAD/cAAA/3EAAP9zAAD/dQAA/3YAAP93AAD/eQAA/3oAAP+5AAD/uwAA/70AAP+/AAD/wgAA/8MAAP/EAAD/xQAA/8YAAP/IAAD/ygAA/8sAAP/MAAD/zgAA/88AAQAOAAEAEAABABIAAQAUAAEAFwABABgAAQAZAAEAGgABABsAAQAdAAEAHwABACAAAQAhAAEAIwABACQAAQBvAAEAkgABALIAAQDSAAEA1AABANYAAQDYAAEA2gABAN0AAQDeAAEA3wABAOIAAQDjAAEA5QABAOYAAQDoAAEA6wABAOwAAQDtAAEA8AABAPEAAQD6AAEBBwABAQwAAQEOAAEBEAABARUAAQEYAAEBGwABAR0AAQFCAAEBZgABAY0AAQGxAAEBtAABAbYAAQG4AAEBugABAbwAAQG+AAEBvwABAcIAAQHPAAEB4AABAeIAAQHkAAEB5gABAegAAQHqAAEB7AABAe4AAQHwAAECAQABAgQAAQIHAAECCgABAg0AAQIQAAECEwABAhYAAQIZAAECGwABAloAAQJcAAECXgABAmAAAQJjAAECZAABAmUAAQJmAAECZwABAmkAAQJrAAECbAABAm0AAQJvAAECcAABAq8AAQKxAAECswABArUAAQK4AAECuQABAroAAQK7AAECvAABAr4AAQLAAAECwQABAsIAAQLEAAECxQABAwQAAQMGAAEDCQABAwsAAQMOAAEDDwABAxAAAQMRAAEDEgABAxQAAQMWAAEDFwABAxgAAQMaAAEDGwABAygAAQMpAAEDKgABAywAAQNrAAEDbQABA28AAQNxAAEDdAABA3UAAQN2AAEDdwABA3gAAQN6AAEDfAABA30AAQN+AAEDgAABA4EAAQPAAAEDwgABA8QAAQPGAAEDyQABA8oAAQPLAAEDzAABA80AAQPPAAED0QABA9IAAQPTAAED1QABA9YAAQQVAAEEFwABBBkAAQQbAAEEHgABBB8AAQQgAAEEIQABBCIAAQQkAAEEJgABBCcAAQQoAAEEKgABBCsAAQRqAAEEbAABBG4AAQRwAAEEcwABBHQAAQR1AAEEdgABBHcAAQR5AAEEewABBHwAAQR9AAEEfwABBIAAAQS/AAEEwQABBMMAAQTFAAEEyAABBMkAAQTKAAEEywABBMwAAQTOAAEE0AABBNEAAQTSAAEE1AABBNUAAQT6AAEFHgABBUUAAQVpAAEFbAABBW4AAQVwAAEFcgABBXQAAQV2AAEFdwABBXoAAQWHAAEFlgABBZgAAQWaAAEFnAABBZ4AAQWgAAEFogABBaQAAQWzAAEFtgABBbkAAQW8AAEFvwABBcIAAQXFAAEFyAABBcoAAQYJAAEGCwABBg0AAQYPAAEGEgABBhMAAQYUAAEGFQABBhYAAQYYAAEGGgABBhsAAQYcAAEGHgABBh8AAQZeAAEGYAABBmIAAQZkAAEGZwABBmgAAQZpAAEGagABBmsAAQZtAAEGbwABBnAAAQZxAAEGcwABBnQAAQazAAEGtQABBrcAAQa5AAEGvAABBr0AAQa+AAEGvwABBsAAAQbCAAEGxAABBsUAAQbGAAEGyAABBskAAQcIAAEHCgABBwwAAQcOAAEHEQABBxIAAQcTAAEHFAABBxUAAQcXAAEHGQABBxoAAQcbAAEHHQABBx4AAQddAAEHXwABB2EAAQdjAAEHZgABB2cAAQdoAAEHaQABB2oAAQdsAAEHbgABB28AAQdwAAEHcgABB3MAAQeyAAEHtAABB7YAAQe4AAEHuwABB7wAAQe9AAEHvgABB78AAQfBAAEHwwABB8QAAQfFAAEHxwABB8gAAQgHAAEICQABCAsAAQgNAAEIEAABCBEAAQgSAAEIEwABCBQAAQgWAAEIGAABCBkAAQgaAAEIHAABCB0AAQhoAAEIiwABCKsAAQjLAAEIzQABCM8AAQjRAAEI0wABCNYAAQjXAAEI2AABCNsAAQjcAAEI3gABCN8AAQjhAAEI5AABCOUAAQjmAAEI6QABCOoAAQjvAAEI/AABCQEAAQkDAAEJBQABCQoAAQkNAAEJEAABCRIAAQk3AAEJWwABCYIAAQmmAAEJqQABCasAAQmtAAEJrwABCbEAAQmzAAEJtAABCbcAAQnEAAEJ1QABCdcAAQnZAAEJ2wABCd0AAQnfAAEJ4QABCeMAAQnlAAEJ9gABCfkAAQn8AAEJ/wABCgIAAQoFAAEKCAABCgsAAQoOAAEKEAABCk8AAQpRAAEKUwABClUAAQpYAAEKWQABCloAAQpbAAEKXAABCl4AAQpgAAEKYQABCmIAAQpkAAEKZQABCqQAAQqmAAEKqAABCqoAAQqtAAEKrgABCq8AAQqwAAEKsQABCrMAAQq1AAEKtgABCrcAAQq5AAEKugABCvkAAQr7AAEK/gABCwAAAQsDAAELBAABCwUAAQsGAAELBwABCwkAAQsLAAELDAABCw0AAQsPAAELEAABCx0AAQseAAELHwABCyEAAQtgAAELYgABC2QAAQtmAAELaQABC2oAAQtrAAELbAABC20AAQtvAAELcQABC3IAAQtzAAELdQABC3YAAQu1AAELtwABC7kAAQu7AAELvgABC78AAQvAAAELwQABC8IAAQvEAAELxgABC8cAAQvIAAELygABC8sAAQwKAAEMDAABDA4AAQwQAAEMEwABDBQAAQwVAAEMFgABDBcAAQwZAAEMGwABDBwAAQwdAAEMHwABDCAAAQxfAAEMYQABDGMAAQxlAAEMaAABDGkAAQxqAAEMawABDGwAAQxuAAEMcAABDHEAAQxyAAEMdAABDHUAAQy0AAEMtgABDLgAAQy6AAEMvQABDL4AAQy/AAEMwAABDMEAAQzDAAEMxQABDMYAAQzHAAEMyQABDMoAAQzvAAENEwABDToAAQ1eAAENYQABDWMAAQ1lAAENZwABDWkAAQ1rAAENbAABDW8AAQ18AAENiwABDY0AAQ2PAAENkQABDZMAAQ2VAAENlwABDZkAAQ2oAAENqwABDa4AAQ2xAAENtAABDbcAAQ26AAENvQABDb8AAQ3+AAEOAAABDgIAAQ4EAAEOBwABDggAAQ4JAAEOCgABDgsAAQ4NAAEODwABDhAAAQ4RAAEOEwABDhQAAQ5TAAEOVQABDlcAAQ5ZAAEOXAABDl0AAQ5eAAEOXwABDmAAAQ5iAAEOZAABDmUAAQ5mAAEOaAABDmkAAQ6oAAEOqgABDqwAAQ6uAAEOsQABDrIAAQ6zAAEOtAABDrUAAQ63AAEOuQABDroAAQ67AAEOvQABDr4AAQ79AAEO/wABDwEAAQ8DAAEPBgABDwcAAQ8IAAEPCQABDwoAAQ8MAAEPDgABDw8AAQ8QAAEPEgABDxMAAQ9SAAEPVAABD1YAAQ9YAAEPWwABD1wAAQ9dAAEPXgABD18AAQ9hAAEPYwABD2QAAQ9lAAEPZwABD2gAAQ+nAAEPqQABD6sAAQ+tAAEPsAABD7EAAQ+yAAEPswABD7QAAQ+2AAEPuAABD7kAAQ+6AAEPvAABD70AAQ/8AAEP/gABEAAAARACAAEQBQABEAYAARAHAAEQCAABEAkAARALAAEQDQABEA4AARAPAAEQEQABEBIAARBdAAEQgAABEKAAARDAAAEQwgABEMQAARDGAAEQyAABEMsAARDMAAEQzQABENAAARDRAAEQ0wABENQAARDWAAEQ2QABENoAARDbAAEQ3gABEN8AARDkAAEQ8QABEPYAARD4AAEQ+gABEP8AARECAAERBQABEQcAAREsAAERUAABEXcAARGbAAERngABEaAAARGiAAERpAABEaYAARGoAAERqQABEawAARG5AAERygABEcwAARHOAAER0AABEdIAARHUAAER1gABEdgAARHaAAER6wABEe4AARHxAAER9AABEfcAARH6AAER/QABEgAAARIDAAESBQABEkQAARJGAAESSAABEkoAARJNAAESTgABEk8AARJQAAESUQABElMAARJVAAESVgABElcAARJZAAESWgABEpkAARKbAAESnQABEp8AARKiAAESowABEqQAARKlAAESpgABEqgAARKqAAESqwABEqwAARKuAAESrwABEu4AARLwAAES8wABEvUAARL4AAES+QABEvoAARL7AAES/AABEv4AARMAAAETAQABEwIAARMEAAETBQABExIAARMTAAETFAABExYAARNVAAETVwABE1kAARNbAAETXgABE18AARNgAAETYQABE2IAARNkAAETZgABE2cAARNoAAETagABE2sAAROqAAETrAABE64AAROwAAETswABE7QAARO1AAETtgABE7cAARO5AAETuwABE7wAARO9AAETvwABE8AAARP/AAEUAQABFAMAARQFAAEUCAABFAkAARQKAAEUCwABFAwAARQOAAEUEAABFBEAARQSAAEUFAABFBUAARRUAAEUVgABFFgAARRaAAEUXQABFF4AARRfAAEUYAABFGEAARRjAAEUZQABFGYAARRnAAEUaQABFGoAARSpAAEUqwABFK0AARSvAAEUsgABFLMAARS0AAEUtQABFLYAARS4AAEUugABFLsAARS8AAEUvgABFL8AARTkAAEVCAABFS8AARVTAAEVVgABFVgAARVaAAEVXAABFV4AARVgAAEVYQABFWQAARVxAAEVgAABFYIAARWEAAEVhgABFYgAARWKAAEVjAABFY4AARWdAAEVoAABFaMAARWmAAEVqQABFawAARWvAAEVsgABFbQAARXzAAEV9QABFfcAARX5AAEV/AABFf0AARX+AAEV/wABFgAAARYCAAEWBAABFgUAARYGAAEWCAABFgkAARZIAAEWSgABFkwAARZOAAEWUQABFlIAARZTAAEWVAABFlUAARZXAAEWWQABFloAARZbAAEWXQABFl4AARadAAEWnwABFqEAARajAAEWpgABFqcAARaoAAEWqQABFqoAARasAAEWrgABFq8AARawAAEWsgABFrMAARbyAAEW9AABFvcAARb5AAEW/AABFv0AARb+AAEW/wABFwAAARcCAAEXBAABFwUAARcGAAEXCAABFwkAARdIAAEXSgABF0wAARdOAAEXUQABF1IAARdTAAEXVAABF1UAARdXAAEXWQABF1oAARdbAAEXXQABF14AARedAAEXnwABF6EAARejAAEXpgABF6cAAReoAAEXqQABF6oAAResAAEXrgABF68AARewAAEXsgABF7MAARfyAAEX9AABF/YAARf4AAEX+wABF/wAARf9AAEX/gABF/8AARgBAAEYAwABGAQAARgFAAEYBwABGAgAARhTAAEYdgABGJYAARi2AAEYuAABGLoAARi8AAEYvgABGMEAARjCAAEYwwABGMYAARjHAAEYyQABGMoAARjMAAEYzgABGM8AARjQAAEY0wABGNQAARjZAAEY5gABGOsAARjtAAEY7wABGPQAARj3AAEY+gABGPwAARkhAAEZRQABGWwAARmQAAEZkwABGZUAARmXAAEZmQABGZsAARmdAAEZngABGaEAARmuAAEZvwABGcEAARnDAAEZxQABGccAARnJAAEZywABGc0AARnPAAEZ4AABGeMAARnmAAEZ6QABGewAARnvAAEZ8gABGfUAARn4AAEZ+gABGjkAARo7AAEaPQABGj8AARpCAAEaQwABGkQAARpFAAEaRgABGkgAARpKAAEaSwABGkwAARpOAAEaTwABGo4AARqQAAEakgABGpQAARqXAAEamAABGpkAARqaAAEamwABGp0AARqfAAEaoAABGqEAARqjAAEapAABGuMAARrlAAEa6AABGuoAARrtAAEa7gABGu8AARrwAAEa8QABGvMAARr1AAEa9gABGvcAARr5AAEa+gABGwcAARsIAAEbCQABGwsAARtKAAEbTAABG04AARtQAAEbUwABG1QAARtVAAEbVgABG1cAARtZAAEbWwABG1wAARtdAAEbXwABG2AAARufAAEboQABG6MAARulAAEbqAABG6kAARuqAAEbqwABG6wAARuuAAEbsAABG7EAARuyAAEbtAABG7UAARv0AAEb9gABG/gAARv6AAEb/QABG/4AARv/AAEcAAABHAEAARwDAAEcBQABHAYAARwHAAEcCQABHAoAARxJAAEcSwABHE0AARxPAAEcUgABHFMAARxUAAEcVQABHFYAARxYAAEcWgABHFsAARxcAAEcXgABHF8AARyeAAEcoAABHKIAARykAAEcpwABHKgAARypAAEcqgABHKsAARytAAEcrwABHLAAARyxAAEcswABHLQAARzZAAEc/QABHSQAAR1IAAEdSwABHU0AAR1PAAEdUQABHVMAAR1VAAEdVgABHVkAAR1mAAEddQABHXcAAR15AAEdewABHX0AAR1/AAEdgQABHYMAAR2SAAEdlQABHZgAAR2bAAEdngABHaEAAR2kAAEdpwABHakAAR3oAAEd6gABHewAAR3uAAEd8QABHfIAAR3zAAEd9AABHfUAAR33AAEd+QABHfoAAR37AAEd/QABHf4AAR49AAEePwABHkEAAR5DAAEeRgABHkcAAR5IAAEeSQABHkoAAR5MAAEeTgABHk8AAR5QAAEeUgABHlMAAR6SAAEelAABHpYAAR6YAAEemwABHpwAAR6dAAEengABHp8AAR6hAAEeowABHqQAAR6lAAEepwABHqgAAR7nAAEe6QABHuwAAR7uAAEe8QABHvIAAR7zAAEe9AABHvUAAR73AAEe+QABHvoAAR77AAEe/QABHv4AAR89AAEfPwABH0EAAR9DAAEfRgABH0cAAR9IAAEfSQABH0oAAR9MAAEfTgABH08AAR9QAAEfUgABH1MAAR+SAAEflAABH5YAAR+YAAEfmwABH5wAAR+dAAEfngABH58AAR+hAAEfowABH6QAAR+lAAEfpwABH6gAAR/nAAEf6QABH+sAAR/tAAEf8AABH/EAAR/yAAEf8wABH/QAAR/2AAEf+AABH/kAAR/6AAEf/AABH/0AASBIAAEgawABIIsAASCrAAEgrQABIK8AASCxAAEgswABILYAASC3AAEguAABILsAASC8AAEgvgABIL8AASDBAAEgxAABIMUAASDGAAEgyQABIMoAASDPAAEg3AABIOEAASDjAAEg5QABIOoAASDtAAEg8AABIPIAASEXAAEhOwABIWIAASGGAAEhiQABIYsAASGNAAEhjwABIZEAASGTAAEhlAABIZcAASGkAAEhtQABIbcAASG5AAEhuwABIb0AASG/AAEhwQABIcMAASHFAAEh1gABIdkAASHcAAEh3wABIeIAASHlAAEh6AABIesAASHuAAEh8AABIi8AASIxAAEiMwABIjUAASI4AAEiOQABIjoAASI7AAEiPAABIj4AASJAAAEiQQABIkIAASJEAAEiRQABIoQAASKGAAEiiAABIooAASKNAAEijgABIo8AASKQAAEikQABIpMAASKVAAEilgABIpcAASKZAAEimgABItkAASLbAAEi3gABIuAAASLjAAEi5AABIuUAASLmAAEi5wABIukAASLrAAEi7AABIu0AASLvAAEi8AABIv0AASL+AAEi/wABIwEAASNAAAEjQgABI0QAASNGAAEjSQABI0oAASNLAAEjTAABI00AASNPAAEjUQABI1IAASNTAAEjVQABI1YAASOVAAEjlwABI5kAASObAAEjngABI58AASOgAAEjoQABI6IAASOkAAEjpgABI6cAASOoAAEjqgABI6sAASPqAAEj7AABI+4AASPwAAEj8wABI/QAASP1AAEj9gABI/cAASP5AAEj+wABI/wAASP9AAEj/wABJAAAASQ/AAEkQQABJEMAASRFAAEkSAABJEkAASRKAAEkSwABJEwAASROAAEkUAABJFEAASRSAAEkVAABJFUAASSUAAEklgABJJgAASSaAAEknQABJJ4AASSfAAEkoAABJKEAASSjAAEkpQABJKYAASSnAAEkqQABJKoAASTPAAEk8wABJRoAASU+AAElQQABJUMAASVFAAElRwABJUkAASVLAAElTAABJU8AASVcAAElawABJW0AASVvAAElcQABJXMAASV1AAEldwABJXkAASWIAAEliwABJY4AASWRAAEllAABJZcAASWaAAElnQABJZ8AASXeAAEl4AABJeIAASXkAAEl5wABJegAASXpAAEl6gABJesAASXtAAEl7wABJfAAASXxAAEl8wABJfQAASYzAAEmNQABJjcAASY5AAEmPAABJj0AASY+AAEmPwABJkAAASZCAAEmRAABJkUAASZGAAEmSAABJkkAASaIAAEmigABJowAASaOAAEmkQABJpIAASaTAAEmlAABJpUAASaXAAEmmQABJpoAASabAAEmnQABJp4AASbdAAEm3wABJuEAASbjAAEm5gABJucAASboAAEm6QABJuoAASbsAAEm7gABJu8AASbwAAEm8gABJvMAAScyAAEnNAABJzYAASc4AAEnOwABJzwAASc9AAEnPgABJz8AASdBAAEnQwABJ0QAASdFAAEnRwABJ0gAASeHAAEniQABJ4sAASeNAAEnkAABJ5EAASeSAAEnkwABJ5QAASeWAAEnmAABJ5kAASeaAAEnnAABJ50AASfcAAEn3gABJ+AAASfiAAEn5QABJ+YAASfnAAEn6AABJ+kAASfrAAEn7QABJ+4AASfvAAEn8QABJ/IAASg9AAEoYAABKIAAASigAAEoogABKKQAASimAAEoqAABKKsAASisAAEorQABKLAAASixAAEoswABKLQAASi2AAEouQABKLoAASi7AAEovgABKL8AASjEAAEo0QABKNYAASjYAAEo2gABKN8AASjiAAEo5QABKOcAASkMAAEpMAABKVcAASl7AAEpfgABKYAAASmCAAEphAABKYYAASmIAAEpiQABKYwAASmZAAEpqgABKawAASmuAAEpsAABKbIAASm0AAEptgABKbgAASm6AAEpywABKc4AASnRAAEp1AABKdcAASnaAAEp3QABKeAAASnjAAEp5QABKiQAASomAAEqKAABKioAASotAAEqLgABKi8AASowAAEqMQABKjMAASo1AAEqNgABKjcAASo5AAEqOgABKnkAASp7AAEqfQABKn8AASqCAAEqgwABKoQAASqFAAEqhgABKogAASqKAAEqiwABKowAASqOAAEqjwABKs4AASrQAAEq0wABKtUAASrYAAEq2QABKtoAASrbAAEq3AABKt4AASrgAAEq4QABKuIAASrkAAEq5QABKvIAASrzAAEq9AABKvYAASs1AAErNwABKzkAASs7AAErPgABKz8AAStAAAErQQABK0IAAStEAAErRgABK0cAAStIAAErSgABK0sAASuKAAErjAABK44AASuQAAErkwABK5QAASuVAAErlgABK5cAASuZAAErmwABK5wAASudAAErnwABK6AAASvfAAEr4QABK+MAASvlAAEr6AABK+kAASvqAAEr6wABK+wAASvuAAEr8AABK/EAASvyAAEr9AABK/UAASw0AAEsNgABLDgAASw6AAEsPQABLD4AASw/AAEsQAABLEEAASxDAAEsRQABLEYAASxHAAEsSQABLEoAASyJAAEsiwABLI0AASyPAAEskgABLJMAASyUAAEslQABLJYAASyYAAEsmgABLJsAASycAAEsngABLJ8AASzEAAEs6AABLQ8AAS0zAAEtNgABLTgAAS06AAEtPAABLT4AAS1AAAEtQQABLUQAAS1RAAEtYAABLWIAAS1kAAEtZgABLWgAAS1qAAEtbAABLW4AAS19AAEtgAABLYMAAS2GAAEtiQABLYwAAS2PAAEtkgABLZQAAS3TAAEt1QABLdcAAS3ZAAEt3AABLd0AAS3eAAEt3wABLeAAAS3iAAEt5AABLeUAAS3mAAEt6AABLekAAS4oAAEuKgABLiwAAS4uAAEuMQABLjIAAS4zAAEuNAABLjUAAS43AAEuOQABLjoAAS47AAEuPQABLj4AAS59AAEufwABLoEAAS6DAAEuhgABLocAAS6IAAEuiQABLooAAS6MAAEujgABLo8AAS6QAAEukgABLpMAAS7SAAEu1AABLtYAAS7YAAEu2wABLtwAAS7dAAEu3gABLt8AAS7hAAEu4wABLuQAAS7lAAEu5wABLugAAS8nAAEvKQABLysAAS8tAAEvMAABLzEAAS8yAAEvMwABLzQAAS82AAEvOAABLzkAAS86AAEvPAABLz0AAS98AAEvfgABL4AAAS+CAAEvhQABL4YAAS+HAAEviAABL4kAAS+LAAEvjQABL44AAS+PAAEvkQABL5IAAS/RAAEv0wABL9UAAS/XAAEv2gABL9sAAS/cAAEv3QABL94AAS/gAAEv4gABL+MAAS/kAAEv5gABL+cAATAyAAEwVQABMHUAATCVAAEwlwABMJkAATCbAAEwnQABMKAAATChAAEwogABMKUAATCmAAEwqAABMKkAATCrAAEwrQABMK4AATCvAAEwsgABMLMAATC4AAEwxQABMMoAATDMAAEwzgABMNMAATDWAAEw2QABMNsAATEAAAExJAABMUsAATFvAAExcgABMXQAATF2AAExeAABMXoAATF8AAExfQABMYAAATGNAAExngABMaAAATGiAAExpAABMaYAATGoAAExqgABMawAATGuAAExvwABMcIAATHFAAExyAABMcsAATHOAAEx0QABMdQAATHXAAEx2QABMhgAATIaAAEyHAABMh4AATIhAAEyIgABMiMAATIkAAEyJQABMicAATIpAAEyKgABMisAATItAAEyLgABMm0AATJvAAEycQABMnMAATJ2AAEydwABMngAATJ5AAEyegABMnwAATJ+AAEyfwABMoAAATKCAAEygwABMsIAATLEAAEyxwABMskAATLMAAEyzQABMs4AATLPAAEy0AABMtIAATLUAAEy1QABMtYAATLYAAEy2QABMuYAATLnAAEy6AABMuoAATMpAAEzKwABMy0AATMvAAEzMgABMzMAATM0AAEzNQABMzYAATM4AAEzOgABMzsAATM8AAEzPgABMz8AATN+AAEzgAABM4IAATOEAAEzhwABM4gAATOJAAEzigABM4sAATONAAEzjwABM5AAATORAAEzkwABM5QAATPTAAEz1QABM9cAATPZAAEz3AABM90AATPeAAEz3wABM+AAATPiAAEz5AABM+UAATPmAAEz6AABM+kAATQoAAE0KgABNCwAATQuAAE0MQABNDIAATQzAAE0NAABNDUAATQ3AAE0OQABNDoAATQ7AAE0PQABND4AATR9AAE0fwABNIEAATSDAAE0hgABNIcAATSIAAE0iQABNIoAATSMAAE0jgABNI8AATSQAAE0kgABNJMAATS4AAE03AABNQMAATUnAAE1KgABNSwAATUuAAE1MAABNTIAATU0AAE1NQABNTgAATVFAAE1VAABNVYAATVYAAE1WgABNVwAATVeAAE1YAABNWIAATVxAAE1dAABNXcAATV6AAE1fQABNYAAATWDAAE1hgABNYgAATXHAAE1yQABNcsAATXNAAE10AABNdEAATXSAAE10wABNdQAATXWAAE12AABNdkAATXaAAE13AABNd0AATYcAAE2HgABNiAAATYiAAE2JQABNiYAATYnAAE2KAABNikAATYrAAE2LQABNi4AATYvAAE2MQABNjIAATZxAAE2cwABNnUAATZ3AAE2egABNnsAATZ8AAE2fQABNn4AATaAAAE2ggABNoMAATaEAAE2hgABNocAATbGAAE2yAABNssAATbNAAE20AABNtEAATbSAAE20wABNtQAATbWAAE22AABNtkAATbaAAE23AABNt0AATccAAE3HgABNyAAATciAAE3JQABNyYAATcnAAE3KAABNykAATcrAAE3LQABNy4AATcvAAE3MQABNzIAATdxAAE3cwABN3UAATd3AAE3egABN3sAATd8AAE3fQABN34AATeAAAE3ggABN4MAATeEAAE3hgABN4cAATfGAAE3yAABN8oAATfMAAE3zwABN9AAATfRAAE30gABN9MAATfVAAE31wABN9gAATfZAAE32wABN9wAATgnAAE4SgABOGoAATiKAAE4jAABOI4AATiQAAE4kgABOJUAATiWAAE4lwABOJoAATibAAE4nQABOJ4AATigAAE4owABOKQAATilAAE4qAABOKkAATiyAAE4vwABOMQAATjGAAE4yAABOM0AATjQAAE40wABONUAATj6AAE5HgABOUUAATlpAAE5bAABOW4AATlwAAE5cgABOXQAATl2AAE5dwABOXoAATmHAAE5mAABOZoAATmcAAE5ngABOaAAATmiAAE5pAABOaYAATmoAAE5uQABObwAATm/AAE5wgABOcUAATnIAAE5ywABOc4AATnRAAE50wABOhIAAToUAAE6FgABOhgAATobAAE6HAABOh0AAToeAAE6HwABOiEAATojAAE6JAABOiUAATonAAE6KAABOmcAATppAAE6awABOm0AATpwAAE6cQABOnIAATpzAAE6dAABOnYAATp4AAE6eQABOnoAATp8AAE6fQABOrwAATq+AAE6wQABOsMAATrGAAE6xwABOsgAATrJAAE6ygABOswAATrOAAE6zwABOtAAATrSAAE60wABOuAAATrhAAE64gABOuQAATsjAAE7JQABOycAATspAAE7LAABOy0AATsuAAE7LwABOzAAATsyAAE7NAABOzUAATs2AAE7OAABOzkAATt4AAE7egABO3wAATt+AAE7gQABO4IAATuDAAE7hAABO4UAATuHAAE7iQABO4oAATuLAAE7jQABO44AATvNAAE7zwABO9EAATvTAAE71gABO9cAATvYAAE72QABO9oAATvcAAE73gABO98AATvgAAE74gABO+MAATwiAAE8JAABPCYAATwoAAE8KwABPCwAATwtAAE8LgABPC8AATwxAAE8MwABPDQAATw1AAE8NwABPDgAATx3AAE8eQABPHsAATx9AAE8gAABPIEAATyCAAE8gwABPIQAATyGAAE8iAABPIkAATyKAAE8jAABPI0AATyyAAE81gABPP0AAT0hAAE9JAABPSYAAT0oAAE9KgABPSwAAT0uAAE9LwABPTIAAT0/AAE9TgABPVAAAT1SAAE9VAABPVYAAT1YAAE9WgABPVwAAT1rAAE9bgABPXEAAT10AAE9dwABPXoAAT19AAE9gAABPYIAAT3BAAE9wwABPcUAAT3HAAE9ygABPcsAAT3MAAE9zQABPc4AAT3QAAE90gABPdMAAT3UAAE91gABPdcAAT4WAAE+GAABPhoAAT4cAAE+HwABPiAAAT4hAAE+IgABPiMAAT4lAAE+JwABPigAAT4pAAE+KwABPiwAAT5rAAE+bQABPm8AAT5xAAE+dAABPnUAAT52AAE+dwABPngAAT56AAE+fAABPn0AAT5+AAE+gAABPoEAAT7AAAE+wgABPsUAAT7HAAE+ygABPssAAT7MAAE+zQABPs4AAT7QAAE+0gABPtMAAT7UAAE+1gABPtcAAT8WAAE/GAABPxoAAT8cAAE/HwABPyAAAT8hAAE/IgABPyMAAT8lAAE/JwABPygAAT8pAAE/KwABPywAAT9rAAE/bQABP28AAT9xAAE/dAABP3UAAT92AAE/dwABP3gAAT96AAE/fAABP30AAT9+AAE/gAABP4EAAT/AAAE/wgABP8QAAT/GAAE/yQABP8oAAT/LAAE/zAABP80AAT/PAAE/0QABP9IAAT/TAAE/1QABP9YAAUAhAAFARAABQGQAAUCEAAFAhgABQIgAAUCKAAFAjAABQI8AAUCQAAFAkQABQJQAAUCVAAFAlwABQJgAAUCaAAFAnQABQJ4AAUCfAAFAogABQKMAAUCoAAFAtQABQLoAAUC8AAFAvgABQMMAAUDGAAFAyQABQMsAAUDwAAFBFAABQTsAAUFfAAFBYgABQWQAAUFmAAFBaAABQWoAAUFsAAFBbQABQXAAAUF9AAFBjgABQZAAAUGSAAFBlAABQZYAAUGYAAFBmgABQZwAAUGeAAFBrwABQbIAAUG1AAFBuAABQbsAAUG+AAFBwQABQcQAAUHHAAFByQABQggAAUIKAAFCDAABQg4AAUIRAAFCEgABQhMAAUIUAAFCFQABQhcAAUIZAAFCGgABQhsAAUIdAAFCHgABQl0AAUJfAAFCYQABQmMAAUJmAAFCZwABQmgAAUJpAAFCagABQmwAAUJuAAFCbwABQnAAAUJyAAFCcwABQrIAAUK0AAFCtwABQrkAAUK8AAFCvQABQr4AAUK/AAFCwAABQsIAAULEAAFCxQABQsYAAULIAAFCyQABQtYAAULXAAFC2AABQtoAAUMZAAFDGwABQx0AAUMfAAFDIgABQyMAAUMkAAFDJQABQyYAAUMoAAFDKgABQysAAUMsAAFDLgABQy8AAUNuAAFDcAABQ3IAAUN0AAFDdwABQ3gAAUN5AAFDegABQ3sAAUN9AAFDfwABQ4AAAUOBAAFDgwABQ4QAAUPDAAFDxQABQ8cAAUPJAAFDzAABQ80AAUPOAAFDzwABQ9AAAUPSAAFD1AABQ9UAAUPWAAFD2AABQ9kAAUQYAAFEGgABRBwAAUQeAAFEIQABRCIAAUQjAAFEJAABRCUAAUQnAAFEKQABRCoAAUQrAAFELQABRC4AAURtAAFEbwABRHEAAURzAAFEdgABRHcAAUR4AAFEeQABRHoAAUR8AAFEfgABRH8AAUSAAAFEggABRIMAAUSoAAFEzAABRPMAAUUXAAFFGgABRRwAAUUeAAFFIAABRSIAAUUkAAFFJQABRSgAAUU1AAFFRAABRUYAAUVIAAFFSgABRUwAAUVOAAFFUAABRVIAAUVhAAFFZAABRWcAAUVqAAFFbQABRXAAAUVzAAFFdgABRXgAAUW3AAFFuQABRbsAAUW9AAFFwAABRcEAAUXCAAFFwwABRcQAAUXGAAFFyAABRckAAUXKAAFFzAABRc0AAUYMAAFGDgABRhAAAUYSAAFGFQABRhYAAUYXAAFGGAABRhkAAUYbAAFGHQABRh4AAUYfAAFGIQABRiIAAUZhAAFGYwABRmUAAUZnAAFGagABRmsAAUZsAAFGbQABRm4AAUZwAAFGcgABRnMAAUZ0AAFGdgABRncAAUa2AAFGuAABRrsAAUa9AAFGwAABRsEAAUbCAAFGwwABRsQAAUbGAAFGyAABRskAAUbKAAFGzAABRs0AAUcMAAFHDgABRxAAAUcSAAFHFQABRxYAAUcXAAFHGAABRxkAAUcbAAFHHQABRx4AAUcfAAFHIQABRyIAAUdhAAFHYwABR2UAAUdnAAFHagABR2sAAUdsAAFHbQABR24AAUdwAAFHcgABR3MAAUd0AAFHdgABR3cAAUe2AAFHuAABR7oAAUe8AAFHvwABR8AAAUfBAAFHwgABR8MAAUfFAAFHxwABR8gAAUfJAAFHywABR8wAAUfVAAFH1gABR9gAAUgbAAFIPwABSGMAAUiGAAFIrQABSM0AAUj0AAFJGwABSTsAAUlfAAFJgwABSYUAAUmIAAFJigABSYwAAUmOAAFJkQABSZQAAUmWAAFJmAABSZsAAUmdAAFJnwABSaIAAUmlAAFJpgABSasAAUm4AAFJuwABSb0AAUnAAAFJwwABScUAAUnqAAFKDgABSjUAAUpZAAFKXAABSl4AAUpgAAFKYgABSmQAAUpmAAFKZwABSmoAAUp3AAFKigABSowAAUqOAAFKkAABSpIAAUqUAAFKlgABSpgAAUqaAAFKnAABSq8AAUqyAAFKtQABSrgAAUq7AAFKvgABSsEAAUrEAAFKxwABSsoAAUrMAAFLCwABSw0AAUsQAAFLEgABSxUAAUsWAAFLFwABSxgAAUsZAAFLGwABSx0AAUseAAFLHwABSyEAAUsiAAFLKwABSywAAUsuAAFLbQABS28AAUtxAAFLcwABS3YAAUt3AAFLeAABS3kAAUt6AAFLfAABS34AAUt/AAFLgAABS4IAAUuDAAFLwgABS8QAAUvHAAFLyQABS8wAAUvNAAFLzgABS88AAUvQAAFL0gABS9QAAUvVAAFL1gABS9gAAUvZAAFL4gABS+UAAUvoAAFL6gABS/MAAUv2AAFL+QABS/sAAUwRAAFMUAABTFIAAUxUAAFMVgABTFkAAUxaAAFMWwABTFwAAUxdAAFMXwABTGEAAUxiAAFMYwABTGUAAUxmAAFMpQABTKcAAUyqAAFMrAABTK8AAUywAAFMsQABTLIAAUyzAAFMtQABTLcAAUy4AAFMuQABTLsAAUy8AAFMxQABTMYAAUzIAAFNBwABTQkAAU0LAAFNDQABTRAAAU0RAAFNEgABTRMAAU0UAAFNFgABTRgAAU0ZAAFNGgABTRwAAU0dAAFNXAABTV4AAU1hAAFNYwABTWYAAU1nAAFNaAABTWkAAU1qAAFNbAABTW4AAU1vAAFNcAABTXIAAU1zAAFNgAABTYEAAU2CAAFNhAABTcMAAU3FAAFNxwABTckAAU3MAAFNzQABTc4AAU3PAAFN0AABTdIAAU3UAAFN1QABTdYAAU3YAAFN2QABThgAAU4aAAFOHQABTh8AAU4iAAFOIwABTiQAAU4lAAFOJgABTigAAU4qAAFOKwABTiwAAU4uAAFOLwABTkcAAU5UAAFOWwABTl0AAU5gAAFOYwABTmoAAU5tAAFOcAABTnMAAU51AAFOegABTpAAAU7bAAFO/gABTx4AAU8+AAFPQAABT0IAAU9EAAFPRgABT0kAAU9KAAFPSwABT04AAU9PAAFPUQABT1IAAU9UAAFPVgABT1cAAU9YAAFPWwABT1wAAU9hAAFPbgABT3MAAU91AAFPdwABT3wAAU9/AAFPggABT4QAAU+pAAFPzQABT/QAAVAYAAFQGwABUB0AAVAfAAFQIQABUCMAAVAlAAFQJgABUCkAAVA2AAFQRwABUEkAAVBLAAFQTQABUE8AAVBRAAFQUwABUFUAAVBXAAFQaAABUGsAAVBuAAFQcQABUHQAAVB3AAFQegABUH0AAVCAAAFQggABUMEAAVDDAAFQxQABUMcAAVDKAAFQywABUMwAAVDNAAFQzgABUNAAAVDSAAFQ0wABUNQAAVDWAAFQ1wABURYAAVEYAAFRGgABURwAAVEfAAFRIAABUSEAAVEiAAFRIwABUSUAAVEnAAFRKAABUSkAAVErAAFRLAABUWsAAVFtAAFRcAABUXIAAVF1AAFRdgABUXcAAVF4AAFReQABUXsAAVF9AAFRfgABUX8AAVGBAAFRggABUY8AAVGQAAFRkQABUZMAAVHSAAFR1AABUdYAAVHYAAFR2wABUdwAAVHdAAFR3gABUd8AAVHhAAFR4wABUeQAAVHlAAFR5wABUegAAVInAAFSKQABUisAAVItAAFSMAABUjEAAVIyAAFSMwABUjQAAVI2AAFSOAABUjkAAVI6AAFSPAABUj0AAVJ8AAFSfgABUoAAAVKCAAFShQABUoYAAVKHAAFSiAABUokAAVKLAAFSjQABUo4AAVKPAAFSkQABUpIAAVLRAAFS0wABUtUAAVLXAAFS2gABUtsAAVLcAAFS3QABUt4AAVLgAAFS4gABUuMAAVLkAAFS5gABUucAAVMmAAFTKAABUyoAAVMsAAFTLwABUzAAAVMxAAFTMgABUzMAAVM1AAFTNwABUzgAAVM5AAFTOwABUzwAAVNhAAFThQABU6wAAVPQAAFT0wABU9UAAVPXAAFT2QABU9sAAVPdAAFT3gABU+EAAVPuAAFT/QABU/8AAVQBAAFUAwABVAUAAVQHAAFUCQABVAsAAVQaAAFUHQABVCAAAVQjAAFUJgABVCkAAVQsAAFULwABVDEAAVRwAAFUcgABVHQAAVR2AAFUeQABVHoAAVR7AAFUfAABVH0AAVR/AAFUgQABVIIAAVSDAAFUhQABVIYAAVTFAAFUxwABVMkAAVTLAAFUzgABVM8AAVTQAAFU0QABVNIAAVTUAAFU1gABVNcAAVTYAAFU2gABVNsAAVUaAAFVHAABVR4AAVUgAAFVIwABVSQAAVUlAAFVJgABVScAAVUpAAFVKwABVSwAAVUtAAFVLwABVTAAAVVvAAFVcQABVXQAAVV2AAFVeQABVXoAAVV7AAFVfAABVX0AAVV/AAFVgQABVYIAAVWDAAFVhQABVYYAAVXFAAFVxwABVckAAVXLAAFVzgABVc8AAVXQAAFV0QABVdIAAVXUAAFV1gABVdcAAVXYAAFV2gABVdsAAVYaAAFWHAABVh4AAVYgAAFWIwABViQAAVYlAAFWJgABVicAAVYpAAFWKwABViwAAVYtAAFWLwABVjAAAVZvAAFWcQABVnMAAVZ1AAFWeAABVnkAAVZ6AAFWewABVnwAAVZ+AAFWgAABVoEAAVaCAAFWhAABVoUAAVbQAAFW8wABVxMAAVczAAFXNQABVzcAAVc5AAFXOwABVz4AAVc/AAFXQAABV0MAAVdEAAFXRgABV0cAAVdJAAFXTAABV00AAVdOAAFXUQABV1IAAVdXAAFXZAABV2kAAVdrAAFXbQABV3IAAVd1AAFXeAABV3oAAVefAAFXwwABV+oAAVgOAAFYEQABWBMAAVgVAAFYFwABWBkAAVgbAAFYHAABWB8AAVgsAAFYPQABWD8AAVhBAAFYQwABWEUAAVhHAAFYSQABWEsAAVhNAAFYXgABWGEAAVhkAAFYZwABWGoAAVhtAAFYcAABWHMAAVh2AAFYeAABWLcAAVi5AAFYuwABWL0AAVjAAAFYwQABWMIAAVjDAAFYxAABWMYAAVjIAAFYyQABWMoAAVjMAAFYzQABWQwAAVkOAAFZEAABWRIAAVkVAAFZFgABWRcAAVkYAAFZGQABWRsAAVkdAAFZHgABWR8AAVkhAAFZIgABWWEAAVljAAFZZgABWWgAAVlrAAFZbAABWW0AAVluAAFZbwABWXEAAVlzAAFZdAABWXUAAVl3AAFZeAABWYUAAVmGAAFZhwABWYkAAVnIAAFZygABWcwAAVnOAAFZ0QABWdIAAVnTAAFZ1AABWdUAAVnXAAFZ2QABWdoAAVnbAAFZ3QABWd4AAVodAAFaHwABWiEAAVojAAFaJgABWicAAVooAAFaKQABWioAAVosAAFaLgABWi8AAVowAAFaMgABWjMAAVpyAAFadAABWnYAAVp4AAFaewABWnwAAVp9AAFafgABWn8AAVqBAAFagwABWoQAAVqFAAFahwABWogAAVrHAAFayQABWssAAVrNAAFa0AABWtEAAVrSAAFa0wABWtQAAVrWAAFa2AABWtkAAVraAAFa3AABWt0AAVscAAFbHgABWyAAAVsiAAFbJQABWyYAAVsnAAFbKAABWykAAVsrAAFbLQABWy4AAVsvAAFbMQABWzIAAVtXAAFbewABW6IAAVvGAAFbyQABW8sAAVvNAAFbzwABW9EAAVvTAAFb1AABW9cAAVvkAAFb8wABW/UAAVv3AAFb+QABW/sAAVv9AAFb/wABXAEAAVwQAAFcEwABXBYAAVwZAAFcHAABXB8AAVwiAAFcJQABXCcAAVxmAAFcaAABXGoAAVxsAAFcbwABXHAAAVxxAAFccgABXHMAAVx1AAFcdwABXHgAAVx5AAFcewABXHwAAVy7AAFcvQABXL8AAVzBAAFcxAABXMUAAVzGAAFcxwABXMgAAVzKAAFczAABXM0AAVzOAAFc0AABXNEAAV0QAAFdEgABXRQAAV0WAAFdGQABXRoAAV0bAAFdHAABXR0AAV0fAAFdIQABXSIAAV0jAAFdJQABXSYAAV1lAAFdZwABXWkAAV1rAAFdbgABXW8AAV1wAAFdcQABXXIAAV10AAFddgABXXcAAV14AAFdegABXXsAAV26AAFdvAABXb4AAV3AAAFdwwABXcQAAV3FAAFdxgABXccAAV3JAAFdywABXcwAAV3NAAFdzwABXdAAAV4PAAFeEQABXhMAAV4VAAFeGAABXhkAAV4aAAFeGwABXhwAAV4eAAFeIAABXiEAAV4iAAFeJAABXiUAAV5kAAFeZgABXmgAAV5qAAFebQABXm4AAV5vAAFecAABXnEAAV5zAAFedQABXnYAAV53AAFeeQABXnoAAV7FAAFe6AABXwgAAV8oAAFfKgABXywAAV8uAAFfMAABXzMAAV80AAFfNQABXzgAAV85AAFfOwABXzwAAV8+AAFfQQABX0IAAV9DAAFfRgABX0cAAV9MAAFfWQABX14AAV9gAAFfYgABX2cAAV9qAAFfbQABX28AAV+UAAFfuAABX98AAWADAAFgBgABYAgAAWAKAAFgDAABYA4AAWAQAAFgEQABYBQAAWAhAAFgMgABYDQAAWA2AAFgOAABYDoAAWA8AAFgPgABYEAAAWBCAAFgUwABYFYAAWBZAAFgXAABYF8AAWBiAAFgZQABYGgAAWBrAAFgbQABYKwAAWCuAAFgsAABYLIAAWC1AAFgtgABYLcAAWC4AAFguQABYLsAAWC9AAFgvgABYL8AAWDBAAFgwgABYQEAAWEDAAFhBQABYQcAAWEKAAFhCwABYQwAAWENAAFhDgABYRAAAWESAAFhEwABYRQAAWEWAAFhFwABYVYAAWFYAAFhWwABYV0AAWFgAAFhYQABYWIAAWFjAAFhZAABYWYAAWFoAAFhaQABYWoAAWFsAAFhbQABYXoAAWF7AAFhfAABYX4AAWG9AAFhvwABYcEAAWHDAAFhxgABYccAAWHIAAFhyQABYcoAAWHMAAFhzgABYc8AAWHQAAFh0gABYdMAAWISAAFiFAABYhYAAWIYAAFiGwABYhwAAWIdAAFiHgABYh8AAWIhAAFiIwABYiQAAWIlAAFiJwABYigAAWJnAAFiaQABYmsAAWJtAAFicAABYnEAAWJyAAFicwABYnQAAWJ2AAFieAABYnkAAWJ6AAFifAABYn0AAWK8AAFivgABYsAAAWLCAAFixQABYsYAAWLHAAFiyAABYskAAWLLAAFizQABYs4AAWLPAAFi0QABYtIAAWMRAAFjEwABYxUAAWMXAAFjGgABYxsAAWMcAAFjHQABYx4AAWMgAAFjIgABYyMAAWMkAAFjJgABYycAAWNMAAFjcAABY5cAAWO7AAFjvgABY8AAAWPCAAFjxAABY8YAAWPIAAFjyQABY8wAAWPZAAFj6AABY+oAAWPsAAFj7gABY/AAAWPyAAFj9AABY/YAAWQFAAFkCAABZAsAAWQOAAFkEQABZBQAAWQXAAFkGgABZBwAAWRbAAFkXQABZF8AAWRhAAFkZAABZGUAAWRmAAFkZwABZGgAAWRqAAFkbAABZG0AAWRuAAFkcAABZHEAAWSwAAFksgABZLQAAWS2AAFkuQABZLoAAWS7AAFkvAABZL0AAWS/AAFkwQABZMIAAWTDAAFkxQABZMYAAWUFAAFlBwABZQkAAWULAAFlDgABZQ8AAWUQAAFlEQABZRIAAWUUAAFlFgABZRcAAWUYAAFlGgABZRsAAWVaAAFlXAABZV4AAWVgAAFlYwABZWQAAWVlAAFlZgABZWcAAWVpAAFlawABZWwAAWVtAAFlbwABZXAAAWWvAAFlsQABZbMAAWW1AAFluAABZbkAAWW6AAFluwABZbwAAWW+AAFlwAABZcEAAWXCAAFlxAABZcUAAWYEAAFmBgABZggAAWYKAAFmDQABZg4AAWYPAAFmEAABZhEAAWYTAAFmFQABZhYAAWYXAAFmGQABZhoAAWZZAAFmWwABZl0AAWZfAAFmYgABZmMAAWZkAAFmZQABZmYAAWZoAAFmagABZmsAAWZsAAFmbgABZm8AAWZ4AAFmeQABZnsAAWa+AAFm4gABZwYAAWcpAAFnUAABZ3AAAWeXAAFnvgABZ94AAWgCAAFoJgABaCgAAWgrAAFoLQABaC8AAWgxAAFoNAABaDcAAWg5AAFoOwABaD4AAWhAAAFoQgABaEUAAWhIAAFoSQABaE4AAWhbAAFoXgABaGAAAWhjAAFoZgABaGgAAWiNAAFosQABaNgAAWj8AAFo/wABaQEAAWkDAAFpBQABaQcAAWkJAAFpCgABaQ0AAWkaAAFpLQABaS8AAWkxAAFpMwABaTUAAWk3AAFpOQABaTsAAWk9AAFpPwABaVIAAWlVAAFpWAABaVsAAWleAAFpYQABaWQAAWlnAAFpagABaW0AAWlvAAFprgABabAAAWmzAAFptQABabgAAWm5AAFpugABabsAAWm8AAFpvgABacAAAWnBAAFpwgABacQAAWnFAAFpzgABac8AAWnRAAFqEAABahIAAWoUAAFqFgABahkAAWoaAAFqGwABahwAAWodAAFqHwABaiEAAWoiAAFqIwABaiUAAWomAAFqZQABamcAAWpqAAFqbAABam8AAWpwAAFqcQABanIAAWpzAAFqdQABancAAWp4AAFqeQABansAAWp8AAFqhQABaoYAAWqIAAFqxwABaskAAWrLAAFqzQABatAAAWrRAAFq0gABatMAAWrUAAFq1gABatgAAWrZAAFq2gABatwAAWrdAAFrHAABax4AAWshAAFrIwABayYAAWsnAAFrKAABaykAAWsqAAFrLAABay4AAWsvAAFrMAABazIAAWszAAFrPAABaz0AAWs/AAFrfgABa4AAAWuCAAFrhAABa4cAAWuIAAFriQABa4oAAWuLAAFrjQABa48AAWuQAAFrkQABa5MAAWuUAAFr0wABa9UAAWvYAAFr2gABa90AAWveAAFr3wABa+AAAWvhAAFr4wABa+UAAWvmAAFr5wABa+kAAWvqAAFr9wABa/gAAWv5AAFr+wABbDoAAWw8AAFsPgABbEAAAWxDAAFsRAABbEUAAWxGAAFsRwABbEkAAWxLAAFsTAABbE0AAWxPAAFsUAABbI8AAWyRAAFslAABbJYAAWyZAAFsmgABbJsAAWycAAFsnQABbJ8AAWyhAAFsogABbKMAAWylAAFspgABbLoAAWzHAAFs6gABbO0AAWzwAAFs8wABbPYAAWz5AAFs/AABbP8AAW0CAAFtBQABbQgAAW0LAAFtDgABbREAAW0UAAFtFwABbRoAAW09AAFtQAABbUMAAW1GAAFtSQABbUwAAW1PAAFtUgABbVUAAW1YAAFtWwABbV4AAW1hAAFtZAABbWcAAW1qAAFtbQABbW8AAW15AAFtggABbYwAAW2bAAFtqgABbbkAAW3DAAFt2QABbd8AAW3xAAFuAwABbhoAAW4sAAFuOAABboMAAW6mAAFuxgABbuYAAW7oAAFu6gABbuwAAW7uAAFu8QABbvIAAW7zAAFu9gABbvcAAW75AAFu+gABbvwAAW7/AAFvAAABbwEAAW8EAAFvBQABbwoAAW8XAAFvHAABbx4AAW8gAAFvJQABbygAAW8rAAFvLQABb1IAAW92AAFvnQABb8EAAW/EAAFvxgABb8gAAW/KAAFvzAABb84AAW/PAAFv0gABb98AAW/wAAFv8gABb/QAAW/2AAFv+AABb/oAAW/8AAFv/gABcAAAAXARAAFwFAABcBcAAXAaAAFwHQABcCAAAXAjAAFwJgABcCkAAXArAAFwagABcGwAAXBuAAFwcAABcHMAAXB0AAFwdQABcHYAAXB3AAFweQABcHsAAXB8AAFwfQABcH8AAXCAAAFwvwABcMEAAXDDAAFwxQABcMgAAXDJAAFwygABcMsAAXDMAAFwzgABcNAAAXDRAAFw0gABcNQAAXDVAAFxFAABcRYAAXEZAAFxGwABcR4AAXEfAAFxIAABcSEAAXEiAAFxJAABcSYAAXEnAAFxKAABcSoAAXErAAFxOAABcTkAAXE6AAFxPAABcXsAAXF9AAFxfwABcYEAAXGEAAFxhQABcYYAAXGHAAFxiAABcYoAAXGMAAFxjQABcY4AAXGQAAFxkQABcdAAAXHSAAFx1AABcdYAAXHZAAFx2gABcdsAAXHcAAFx3QABcd8AAXHhAAFx4gABceMAAXHlAAFx5gABciUAAXInAAFyKQABcisAAXIuAAFyLwABcjAAAXIxAAFyMgABcjQAAXI2AAFyNwABcjgAAXI6AAFyOwABcnoAAXJ8AAFyfgABcoAAAXKDAAFyhAABcoUAAXKGAAFyhwABcokAAXKLAAFyjAABco0AAXKPAAFykAABcs8AAXLRAAFy0wABctUAAXLYAAFy2QABctoAAXLbAAFy3AABct4AAXLgAAFy4QABcuIAAXLkAAFy5QABcwoAAXMuAAFzVQABc3kAAXN8AAFzfgABc4AAAXOCAAFzhAABc4YAAXOHAAFzigABc5cAAXOmAAFzqAABc6oAAXOsAAFzrgABc7AAAXOyAAFztAABc8MAAXPGAAFzyQABc8wAAXPPAAFz0gABc9UAAXPYAAFz2gABdBkAAXQbAAF0HQABdB8AAXQiAAF0IwABdCQAAXQlAAF0JgABdCgAAXQqAAF0KwABdCwAAXQuAAF0LwABdG4AAXRwAAF0cgABdHQAAXR3AAF0eAABdHkAAXR6AAF0ewABdH0AAXR/AAF0gAABdIEAAXSDAAF0hAABdMMAAXTFAAF0xwABdMkAAXTMAAF0zQABdM4AAXTPAAF00AABdNIAAXTUAAF01QABdNYAAXTYAAF02QABdRgAAXUaAAF1HQABdR8AAXUiAAF1IwABdSQAAXUlAAF1JgABdSgAAXUqAAF1KwABdSwAAXUuAAF1LwABdW4AAXVwAAF1cgABdXQAAXV3AAF1eAABdXkAAXV6AAF1ewABdX0AAXV/AAF1gAABdYEAAXWDAAF1hAABdcMAAXXFAAF1xwABdckAAXXMAAF1zQABdc4AAXXPAAF10AABddIAAXXUAAF11QABddYAAXXYAAF12QABdhgAAXYaAAF2HAABdh4AAXYhAAF2IgABdiMAAXYkAAF2JQABdicAAXYpAAF2KgABdisAAXYtAAF2LgABdnkAAXacAAF2vAABdtwAAXbeAAF24AABduIAAXbkAAF25wABdugAAXbpAAF27AABdu0AAXbvAAF28AABdvIAAXb1AAF29gABdvcAAXb6AAF2+wABdwQAAXcRAAF3FgABdxgAAXcaAAF3HwABdyIAAXclAAF3JwABd0wAAXdwAAF3lwABd7sAAXe+AAF3wAABd8IAAXfEAAF3xgABd8gAAXfJAAF3zAABd9kAAXfqAAF37AABd+4AAXfwAAF38gABd/QAAXf2AAF3+AABd/oAAXgLAAF4DgABeBEAAXgUAAF4FwABeBoAAXgdAAF4IAABeCMAAXglAAF4ZAABeGYAAXhoAAF4agABeG0AAXhuAAF4bwABeHAAAXhxAAF4cwABeHUAAXh2AAF4dwABeHkAAXh6AAF4uQABeLsAAXi9AAF4vwABeMIAAXjDAAF4xAABeMUAAXjGAAF4yAABeMoAAXjLAAF4zAABeM4AAXjPAAF5DgABeRAAAXkTAAF5FQABeRgAAXkZAAF5GgABeRsAAXkcAAF5HgABeSAAAXkhAAF5IgABeSQAAXklAAF5MgABeTMAAXk0AAF5NgABeXUAAXl3AAF5eQABeXsAAXl+AAF5fwABeYAAAXmBAAF5ggABeYQAAXmGAAF5hwABeYgAAXmKAAF5iwABecoAAXnMAAF5zgABedAAAXnTAAF51AABedUAAXnWAAF51wABedkAAXnbAAF53AABed0AAXnfAAF54AABeh8AAXohAAF6IwABeiUAAXooAAF6KQABeioAAXorAAF6LAABei4AAXowAAF6MQABejIAAXo0AAF6NQABenQAAXp2AAF6eQABensAAXp+AAF6fwABeoAAAXqBAAF6ggABeoQAAXqGAAF6hwABeogAAXqKAAF6iwABeqEAAXrgAAF64gABeuQAAXrmAAF66QABeuoAAXrrAAF67AABeu0AAXrvAAF68QABevIAAXrzAAF69QABevYAAXsbAAF7PwABe2YAAXuKAAF7jQABe48AAXuRAAF7kwABe5UAAXuXAAF7mAABe5sAAXuoAAF7twABe7kAAXu7AAF7vQABe78AAXvBAAF7wwABe8UAAXvUAAF71wABe9oAAXvdAAF74AABe+MAAXvmAAF76QABe+sAAXwqAAF8LAABfC4AAXwwAAF8MwABfDQAAXw1AAF8NgABfDcAAXw5AAF8OwABfDwAAXw9AAF8PwABfEAAAXx/AAF8gQABfIMAAXyFAAF8iAABfIkAAXyKAAF8iwABfIwAAXyOAAF8kAABfJEAAXySAAF8lAABfJUAAXzUAAF81gABfNgAAXzaAAF83QABfN4AAXzfAAF84AABfOEAAXzjAAF85QABfOYAAXznAAF86QABfOoAAX0pAAF9KwABfS0AAX0vAAF9MgABfTMAAX00AAF9NQABfTYAAX04AAF9OgABfTsAAX08AAF9PgABfT8AAX1+AAF9gAABfYIAAX2EAAF9hwABfYgAAX2JAAF9igABfYsAAX2NAAF9jwABfZAAAX2RAAF9kwABfZQAAX3TAAF91QABfdcAAX3ZAAF93AABfd0AAX3eAAF93wABfeAAAX3iAAF95AABfeUAAX3mAAF96AABfekAAX4oAAF+KgABfiwAAX4uAAF+MQABfjIAAX4zAAF+NAABfjUAAX43AAF+OQABfjoAAX47AAF+PQABfj4AAX6JAAF+rAABfswAAX7sAAF+7gABfvAAAX7yAAF+9AABfvcAAX74AAF++QABfvwAAX79AAF+/wABfwAAAX8CAAF/BQABfwYAAX8HAAF/CgABfwsAAX8QAAF/HQABfyIAAX8kAAF/JgABfysAAX8uAAF/MQABfzMAAX9YAAF/fAABf6MAAX/HAAF/ygABf8wAAX/OAAF/0AABf9IAAX/UAAF/1QABf9gAAX/lAAF/9gABf/gAAX/6AAF//AABf/4AAYAAAAGAAgABgAQAAYAGAAGAFwABgBoAAYAdAAGAIAABgCMAAYAmAAGAKQABgCwAAYAvAAGAMQABgHAAAYByAAGAdAABgHYAAYB5AAGAegABgHsAAYB8AAGAfQABgH8AAYCBAAGAggABgIMAAYCFAAGAhgABgMUAAYDHAAGAyQABgMsAAYDOAAGAzwABgNAAAYDRAAGA0gABgNQAAYDWAAGA1wABgNgAAYDaAAGA2wABgRoAAYEcAAGBHwABgSEAAYEkAAGBJQABgSYAAYEnAAGBKAABgSoAAYEsAAGBLQABgS4AAYEwAAGBMQABgT4AAYE/AAGBQAABgUIAAYGBAAGBgwABgYUAAYGHAAGBigABgYsAAYGMAAGBjQABgY4AAYGQAAGBkgABgZMAAYGUAAGBlgABgZcAAYHWAAGB2AABgdoAAYHcAAGB3wABgeAAAYHhAAGB4gABgeMAAYHlAAGB5wABgegAAYHpAAGB6wABgewAAYIrAAGCLQABgi8AAYIxAAGCNAABgjUAAYI2AAGCNwABgjgAAYI6AAGCPAABgj0AAYI+AAGCQAABgkEAAYKAAAGCggABgoQAAYKGAAGCiQABgooAAYKLAAGCjAABgo0AAYKPAAGCkQABgpIAAYKTAAGClQABgpYAAYLVAAGC1wABgtkAAYLbAAGC3gABgt8AAYLgAAGC4QABguIAAYLkAAGC5gABgucAAYLoAAGC6gABgusAAYMQAAGDNAABg1sAAYN/AAGDggABg4QAAYOGAAGDiAABg4oAAYOMAAGDjQABg5AAAYOdAAGDrAABg64AAYOwAAGDsgABg7QAAYO2AAGDuAABg7oAAYPJAAGDzAABg88AAYPSAAGD1QABg9gAAYPbAAGD3gABg+AAAYQfAAGEIQABhCMAAYQlAAGEKAABhCkAAYQqAAGEKwABhCwAAYQuAAGEMAABhDEAAYQyAAGENAABhDUAAYR0AAGEdgABhHgAAYR6AAGEfQABhH4AAYR/AAGEgAABhIEAAYSDAAGEhQABhIYAAYSHAAGEiQABhIoAAYTJAAGEywABhM0AAYTPAAGE0gABhNMAAYTUAAGE1QABhNYAAYTYAAGE2gABhNsAAYTcAAGE3gABhN8AAYUeAAGFIAABhSIAAYUkAAGFJwABhSgAAYUpAAGFKgABhSsAAYUtAAGFLwABhTAAAYUxAAGFMwABhTQAAYVzAAGFdQABhXcAAYV5AAGFfAABhX0AAYV+AAGFfwABhYAAAYWCAAGFhAABhYUAAYWGAAGFiAABhYkAAYXIAAGFygABhcwAAYXOAAGF0QABhdIAAYXTAAGF1AABhdUAAYXXAAGF2QABhdoAAYXbAAGF3QABhd4AAYYdAAGGHwABhiEAAYYjAAGGJgABhicAAYYoAAGGKQABhioAAYYsAAGGLgABhi8AAYYwAAGGMgABhjMAAYZ+AAGGoQABhsEAAYbhAAGG4wABhuUAAYbnAAGG6QABhuwAAYbtAAGG7gABhvEAAYbyAAGG9AABhvUAAYb3AAGG+gABhvsAAYb8AAGG/wABhwAAAYcFAAGHEgABhxcAAYcZAAGHGwABhyAAAYcjAAGHJgABhygAAYdNAAGHcQABh5gAAYe8AAGHvwABh8EAAYfDAAGHxQABh8cAAYfJAAGHygABh80AAYfaAAGH6wABh+0AAYfvAAGH8QABh/MAAYf1AAGH9wABh/kAAYf7AAGIDAABiA8AAYgSAAGIFQABiBgAAYgbAAGIHgABiCEAAYgkAAGIJgABiGUAAYhnAAGIaQABiGsAAYhuAAGIbwABiHAAAYhxAAGIcgABiHQAAYh2AAGIdwABiHgAAYh6AAGIewABiLoAAYi8AAGIvgABiMAAAYjDAAGIxAABiMUAAYjGAAGIxwABiMkAAYjLAAGIzAABiM0AAYjPAAGI0AABiQ8AAYkRAAGJFAABiRYAAYkZAAGJGgABiRsAAYkcAAGJHQABiR8AAYkhAAGJIgABiSMAAYklAAGJJgABiTMAAYk0AAGJNQABiTcAAYl2AAGJeAABiXoAAYl8AAGJfwABiYAAAYmBAAGJggABiYMAAYmFAAGJhwABiYgAAYmJAAGJiwABiYwAAYnLAAGJzQABic8AAYnRAAGJ1AABidUAAYnWAAGJ1wABidgAAYnaAAGJ3AABid0AAYneAAGJ4AABieEAAYogAAGKIgABiiQAAYomAAGKKQABiioAAYorAAGKLAABii0AAYovAAGKMQABijIAAYozAAGKNQABijYAAYp1AAGKdwABinkAAYp7AAGKfgABin8AAYqAAAGKgQABioIAAYqEAAGKhgABiocAAYqIAAGKigABiosAAYrKAAGKzAABis4AAYrQAAGK0wABitQAAYrVAAGK1gABitcAAYrZAAGK2wABitwAAYrdAAGK3wABiuAAAYsFAAGLKQABi1AAAYt0AAGLdwABi3kAAYt7AAGLfQABi38AAYuBAAGLggABi4UAAYuSAAGLoQABi6MAAYulAAGLpwABi6kAAYurAAGLrQABi68AAYu+AAGLwQABi8QAAYvHAAGLygABi80AAYvQAAGL0wABi9UAAYwUAAGMFgABjBgAAYwaAAGMHQABjB4AAYwfAAGMIAABjCEAAYwjAAGMJQABjCYAAYwnAAGMKQABjCoAAYxpAAGMawABjG0AAYxvAAGMcgABjHMAAYx0AAGMdQABjHYAAYx4AAGMegABjHsAAYx8AAGMfgABjH8AAYy+AAGMwAABjMIAAYzEAAGMxwABjMgAAYzJAAGMygABjMsAAYzNAAGMzwABjNAAAYzRAAGM0wABjNQAAY0TAAGNFQABjRgAAY0aAAGNHQABjR4AAY0fAAGNIAABjSEAAY0jAAGNJQABjSYAAY0nAAGNKQABjSoAAY0sAAGNawABjW0AAY1vAAGNcQABjXQAAY11AAGNdgABjXcAAY14AAGNegABjXwAAY19AAGNfgABjYAAAY2BAAGNwAABjcIAAY3EAAGNxgABjckAAY3KAAGNywABjcwAAY3NAAGNzwABjdEAAY3SAAGN0wABjdUAAY3WAAGOFQABjhcAAY4ZAAGOGwABjh4AAY4fAAGOIAABjiEAAY4iAAGOJAABjiYAAY4nAAGOKAABjioAAY4rAAGOdgABjpkAAY65AAGO2QABjtsAAY7dAAGO3wABjuEAAY7kAAGO5QABjuYAAY7pAAGO6gABjuwAAY7tAAGO7wABjvIAAY7zAAGO9AABjvcAAY74AAGO/QABjwoAAY8PAAGPEQABjxMAAY8YAAGPGwABjx4AAY8gAAGPRQABj2kAAY+QAAGPtAABj7cAAY+5AAGPuwABj70AAY+/AAGPwQABj8IAAY/FAAGP0gABj+MAAY/lAAGP5wABj+kAAY/rAAGP7QABj+8AAY/xAAGP8wABkAQAAZAHAAGQCgABkA0AAZAQAAGQEwABkBYAAZAZAAGQHAABkB4AAZBdAAGQXwABkGEAAZBjAAGQZgABkGcAAZBoAAGQaQABkGoAAZBsAAGQbgABkG8AAZBwAAGQcgABkHMAAZCyAAGQtAABkLYAAZC4AAGQuwABkLwAAZC9AAGQvgABkL8AAZDBAAGQwwABkMQAAZDFAAGQxwABkMgAAZEHAAGRCQABkQwAAZEOAAGREQABkRIAAZETAAGRFAABkRUAAZEXAAGRGQABkRoAAZEbAAGRHQABkR4AAZErAAGRLAABkS0AAZEvAAGRbgABkXAAAZFyAAGRdAABkXcAAZF4AAGReQABkXoAAZF7AAGRfQABkX8AAZGAAAGRgQABkYMAAZGEAAGRwwABkcUAAZHHAAGRyQABkcwAAZHNAAGRzgABkc8AAZHQAAGR0gABkdQAAZHVAAGR1gABkdgAAZHZAAGSGAABkhoAAZIcAAGSHgABkiEAAZIiAAGSIwABkiQAAZIlAAGSJwABkikAAZIqAAGSKwABki0AAZIuAAGSbQABkm8AAZJxAAGScwABknYAAZJ3AAGSeAABknkAAZJ6AAGSfAABkn4AAZJ/AAGSgAABkoIAAZKDAAGSwgABksQAAZLGAAGSyAABkssAAZLMAAGSzQABks4AAZLPAAGS0QABktMAAZLUAAGS1QABktcAAZLYAAGS/QABkyEAAZNIAAGTbAABk28AAZNxAAGTcwABk3UAAZN3AAGTeQABk3oAAZN9AAGTigABk5kAAZObAAGTnQABk58AAZOhAAGTowABk6UAAZOnAAGTtgABk7kAAZO8AAGTvwABk8IAAZPFAAGTyAABk8sAAZPNAAGUDAABlA4AAZQQAAGUEgABlBUAAZQWAAGUFwABlBgAAZQZAAGUGwABlB0AAZQeAAGUHwABlCEAAZQiAAGUYQABlGMAAZRlAAGUZwABlGoAAZRrAAGUbAABlG0AAZRuAAGUcAABlHIAAZRzAAGUdAABlHYAAZR3AAGUtgABlLgAAZS6AAGUvAABlL8AAZTAAAGUwQABlMIAAZTDAAGUxQABlMcAAZTIAAGUyQABlMsAAZTMAAGVCwABlQ0AAZUQAAGVEgABlRUAAZUWAAGVFwABlRgAAZUZAAGVGwABlR0AAZUeAAGVHwABlSEAAZUiAAGVYQABlWMAAZVlAAGVZwABlWoAAZVrAAGVbAABlW0AAZVuAAGVcAABlXIAAZVzAAGVdAABlXYAAZV3AAGVtgABlbgAAZW6AAGVvAABlb8AAZXAAAGVwQABlcIAAZXDAAGVxQABlccAAZXIAAGVyQABlcsAAZXMAAGWCwABlg0AAZYPAAGWEQABlhQAAZYVAAGWFgABlhcAAZYYAAGWGgABlhwAAZYdAAGWHgABliAAAZYhAAGWbAABlo8AAZavAAGWzwABltEAAZbTAAGW1QABltcAAZbaAAGW2wABltwAAZbfAAGW4AABluIAAZbjAAGW5QABlugAAZbpAAGW6gABlu0AAZbuAAGW8wABlwAAAZcFAAGXBwABlwkAAZcOAAGXEQABlxQAAZcWAAGXOwABl18AAZeGAAGXqgABl60AAZevAAGXsQABl7MAAZe1AAGXtwABl7gAAZe7AAGXyAABl9kAAZfbAAGX3QABl98AAZfhAAGX4wABl+UAAZfnAAGX6QABl/oAAZf9AAGYAAABmAMAAZgGAAGYCQABmAwAAZgPAAGYEgABmBQAAZhTAAGYVQABmFcAAZhZAAGYXAABmF0AAZheAAGYXwABmGAAAZhiAAGYZAABmGUAAZhmAAGYaAABmGkAAZioAAGYqgABmKwAAZiuAAGYsQABmLIAAZizAAGYtAABmLUAAZi3AAGYuQABmLoAAZi7AAGYvQABmL4AAZj9AAGY/wABmQIAAZkEAAGZBwABmQgAAZkJAAGZCgABmQsAAZkNAAGZDwABmRAAAZkRAAGZEwABmRQAAZkhAAGZIgABmSMAAZklAAGZZAABmWYAAZloAAGZagABmW0AAZluAAGZbwABmXAAAZlxAAGZcwABmXUAAZl2AAGZdwABmXkAAZl6AAGZuQABmbsAAZm9AAGZvwABmcIAAZnDAAGZxAABmcUAAZnGAAGZyAABmcoAAZnLAAGZzAABmc4AAZnPAAGaDgABmhAAAZoSAAGaFAABmhcAAZoYAAGaGQABmhoAAZobAAGaHQABmh8AAZogAAGaIQABmiMAAZokAAGaYwABmmUAAZpnAAGaaQABmmwAAZptAAGabgABmm8AAZpwAAGacgABmnQAAZp1AAGadgABmngAAZp5AAGauAABmroAAZq8AAGavgABmsEAAZrCAAGawwABmsQAAZrFAAGaxwABmskAAZrKAAGaywABms0AAZrOAAGa8wABmxcAAZs+AAGbYgABm2UAAZtnAAGbaQABm2sAAZttAAGbbwABm3AAAZtzAAGbgAABm48AAZuRAAGbkwABm5UAAZuXAAGbmQABm5sAAZudAAGbrAABm68AAZuyAAGbtQABm7gAAZu7AAGbvgABm8EAAZvDAAGcAgABnAQAAZwGAAGcCAABnAsAAZwMAAGcDQABnA4AAZwPAAGcEQABnBMAAZwUAAGcFQABnBcAAZwYAAGcVwABnFkAAZxbAAGcXQABnGAAAZxhAAGcYgABnGMAAZxkAAGcZgABnGgAAZxpAAGcagABnGwAAZxtAAGcrAABnK4AAZywAAGcsgABnLUAAZy2AAGctwABnLgAAZy5AAGcuwABnL0AAZy+AAGcvwABnMEAAZzCAAGdAQABnQMAAZ0FAAGdBwABnQoAAZ0LAAGdDAABnQ0AAZ0OAAGdEAABnRIAAZ0TAAGdFAABnRYAAZ0XAAGdVgABnVgAAZ1aAAGdXAABnV8AAZ1gAAGdYQABnWIAAZ1jAAGdZQABnWcAAZ1oAAGdaQABnWsAAZ1sAAGdqwABna0AAZ2vAAGdsQABnbQAAZ21AAGdtgABnbcAAZ24AAGdugABnbwAAZ29AAGdvgABncAAAZ3BAAGeAAABngIAAZ4EAAGeBgABngkAAZ4KAAGeCwABngwAAZ4NAAGeDwABnhEAAZ4SAAGeEwABnhUAAZ4WAAGeYQABnoQAAZ6kAAGexAABnsYAAZ7IAAGeygABnswAAZ7PAAGe0AABntEAAZ7UAAGe1QABntcAAZ7YAAGe2gABnt0AAZ7eAAGe3wABnuIAAZ7jAAGe7AABnvkAAZ7+AAGfAAABnwIAAZ8HAAGfCgABnw0AAZ8PAAGfNAABn1gAAZ9/AAGfowABn6YAAZ+oAAGfqgABn6wAAZ+uAAGfsAABn7EAAZ+0AAGfwQABn9IAAZ/UAAGf1gABn9gAAZ/aAAGf3AABn94AAZ/gAAGf4gABn/MAAZ/2AAGf+QABn/wAAZ//AAGgAgABoAUAAaAIAAGgCwABoA0AAaBMAAGgTgABoFAAAaBSAAGgVQABoFYAAaBXAAGgWAABoFkAAaBbAAGgXQABoF4AAaBfAAGgYQABoGIAAaChAAGgowABoKUAAaCnAAGgqgABoKsAAaCsAAGgrQABoK4AAaCwAAGgsgABoLMAAaC0AAGgtgABoLcAAaD2AAGg+AABoPsAAaD9AAGhAAABoQEAAaECAAGhAwABoQQAAaEGAAGhCAABoQkAAaEKAAGhDAABoQ0AAaEaAAGhGwABoRwAAaEeAAGhXQABoV8AAaFhAAGhYwABoWYAAaFnAAGhaAABoWkAAaFqAAGhbAABoW4AAaFvAAGhcAABoXIAAaFzAAGhsgABobQAAaG2AAGhuAABobsAAaG8AAGhvQABob4AAaG/AAGhwQABocMAAaHEAAGhxQABoccAAaHIAAGiBwABogkAAaILAAGiDQABohAAAaIRAAGiEgABohMAAaIUAAGiFgABohgAAaIZAAGiGgABohwAAaIdAAGiXAABol4AAaJgAAGiYgABomUAAaJmAAGiZwABomgAAaJpAAGiawABom0AAaJuAAGibwABonEAAaJyAAGisQABorMAAaK1AAGitwABoroAAaK7AAGivAABor0AAaK+AAGiwAABosIAAaLDAAGixAABosYAAaLHAAGi7AABoxAAAaM3AAGjWwABo14AAaNgAAGjYgABo2QAAaNmAAGjaAABo2kAAaNsAAGjeQABo4gAAaOKAAGjjAABo44AAaOQAAGjkgABo5QAAaOWAAGjpQABo6gAAaOrAAGjrgABo7EAAaO0AAGjtwABo7oAAaO8AAGj+wABo/0AAaP/AAGkAQABpAQAAaQFAAGkBgABpAcAAaQIAAGkCgABpAwAAaQNAAGkDgABpBAAAaQRAAGkUAABpFIAAaRUAAGkVgABpFkAAaRaAAGkWwABpFwAAaRdAAGkXwABpGEAAaRiAAGkYwABpGUAAaRmAAGkpQABpKcAAaSpAAGkqwABpK4AAaSvAAGksAABpLEAAaSyAAGktAABpLYAAaS3AAGkuAABpLoAAaS7AAGk+gABpPwAAaT/AAGlAQABpQQAAaUFAAGlBgABpQcAAaUIAAGlCgABpQwAAaUNAAGlDgABpRAAAaURAAGlUAABpVIAAaVUAAGlVgABpVkAAaVaAAGlWwABpVwAAaVdAAGlXwABpWEAAaViAAGlYwABpWUAAaVmAAGlpQABpacAAaWpAAGlqwABpa4AAaWvAAGlsAABpbEAAaWyAAGltAABpbYAAaW3AAGluAABpboAAaW7AAGl+gABpfwAAaX+AAGmAAABpgMAAaYEAAGmBQABpgYAAaYHAAGmCQABpgsAAaYMAAGmDQABpg8AAaYQAAGmWwABpn4AAaaeAAGmvgABpsAAAabCAAGmxAABpsYAAabJAAGmygABpssAAabOAAGmzwABptEAAabSAAGm1AABptcAAabYAAGm2QABptwAAabdAAGm4gABpu8AAab0AAGm9gABpvgAAab9AAGnAAABpwMAAacFAAGnKgABp04AAad1AAGnmQABp5wAAaeeAAGnoAABp6IAAaekAAGnpgABp6cAAaeqAAGntwABp8gAAafKAAGnzAABp84AAafQAAGn0gABp9QAAafWAAGn2AABp+kAAafsAAGn7wABp/IAAaf1AAGn+AABp/sAAaf+AAGoAQABqAMAAahCAAGoRAABqEYAAahIAAGoSwABqEwAAahNAAGoTgABqE8AAahRAAGoUwABqFQAAahVAAGoVwABqFgAAaiXAAGomQABqJsAAaidAAGooAABqKEAAaiiAAGoowABqKQAAaimAAGoqAABqKkAAaiqAAGorAABqK0AAajsAAGo7gABqPEAAajzAAGo9gABqPcAAaj4AAGo+QABqPoAAaj8AAGo/gABqP8AAakAAAGpAgABqQMAAakQAAGpEQABqRIAAakUAAGpUwABqVUAAalXAAGpWQABqVwAAaldAAGpXgABqV8AAalgAAGpYgABqWQAAallAAGpZgABqWgAAalpAAGpqAABqaoAAamsAAGprgABqbEAAamyAAGpswABqbQAAam1AAGptwABqbkAAam6AAGpuwABqb0AAam+AAGp/QABqf8AAaoBAAGqAwABqgYAAaoHAAGqCAABqgkAAaoKAAGqDAABqg4AAaoPAAGqEAABqhIAAaoTAAGqUgABqlQAAapWAAGqWAABqlsAAapcAAGqXQABql4AAapfAAGqYQABqmMAAapkAAGqZQABqmcAAapoAAGqpwABqqkAAaqrAAGqrQABqrAAAaqxAAGqsgABqrMAAaq0AAGqtgABqrgAAaq5AAGqugABqrwAAaq9AAGq4gABqwYAAastAAGrUQABq1QAAatWAAGrWAABq1oAAatcAAGrXgABq18AAatiAAGrbwABq34AAauAAAGrggABq4QAAauGAAGriAABq4oAAauMAAGrmwABq54AAauhAAGrpAABq6cAAauqAAGrrQABq7AAAauyAAGr8QABq/MAAav1AAGr9wABq/oAAav7AAGr/AABq/0AAav+AAGsAAABrAIAAawDAAGsBAABrAYAAawHAAGsRgABrEgAAaxKAAGsTAABrE8AAaxQAAGsUQABrFIAAaxTAAGsVQABrFcAAaxYAAGsWQABrFsAAaxcAAGsmwABrJ0AAayfAAGsoQABrKQAAaylAAGspgABrKcAAayoAAGsqgABrKwAAaytAAGsrgABrLAAAayxAAGs8AABrPIAAaz1AAGs9wABrPoAAaz7AAGs/AABrP0AAaz+AAGtAAABrQIAAa0DAAGtBAABrQYAAa0HAAGtRgABrUgAAa1KAAGtTAABrU8AAa1QAAGtUQABrVIAAa1TAAGtVQABrVcAAa1YAAGtWQABrVsAAa1cAAGtmwABrZ0AAa2fAAGtoQABraQAAa2lAAGtpgABracAAa2oAAGtqgABrawAAa2tAAGtrgABrbAAAa2xAAGt8AABrfIAAa30AAGt9gABrfkAAa36AAGt+wABrfwAAa39AAGt/wABrgEAAa4CAAGuAwABrgUAAa4GAAGuUQABrnQAAa6UAAGutAABrrYAAa64AAGuugABrrwAAa6/AAGuwAABrsEAAa7EAAGuxQABrscAAa7IAAGuygABrs0AAa7OAAGuzwABrtIAAa7TAAGu2AABruUAAa7qAAGu7AABru4AAa7zAAGu9gABrvkAAa77AAGvIAABr0QAAa9rAAGvjwABr5IAAa+UAAGvlgABr5gAAa+aAAGvnAABr50AAa+gAAGvrQABr74AAa/AAAGvwgABr8QAAa/GAAGvyAABr8oAAa/MAAGvzgABr98AAa/iAAGv5QABr+gAAa/rAAGv7gABr/EAAa/0AAGv9wABr/kAAbA4AAGwOgABsDwAAbA+AAGwQQABsEIAAbBDAAGwRAABsEUAAbBHAAGwSQABsEoAAbBLAAGwTQABsE4AAbCNAAGwjwABsJEAAbCTAAGwlgABsJcAAbCYAAGwmQABsJoAAbCcAAGwngABsJ8AAbCgAAGwogABsKMAAbDiAAGw5AABsOcAAbDpAAGw7AABsO0AAbDuAAGw7wABsPAAAbDyAAGw9AABsPUAAbD2AAGw+AABsPkAAbEGAAGxBwABsQgAAbEKAAGxSQABsUsAAbFNAAGxTwABsVIAAbFTAAGxVAABsVUAAbFWAAGxWAABsVoAAbFbAAGxXAABsV4AAbFfAAGxngABsaAAAbGiAAGxpAABsacAAbGoAAGxqQABsaoAAbGrAAGxrQABsa8AAbGwAAGxsQABsbMAAbG0AAGx8wABsfUAAbH3AAGx+QABsfwAAbH9AAGx/gABsf8AAbIAAAGyAgABsgQAAbIFAAGyBgABsggAAbIJAAGySAABskoAAbJMAAGyTgABslEAAbJSAAGyUwABslQAAbJVAAGyVwABslkAAbJaAAGyWwABsl0AAbJeAAGynQABsp8AAbKhAAGyowABsqYAAbKnAAGyqAABsqkAAbKqAAGyrAABsq4AAbKvAAGysAABsrIAAbKzAAGy2AABsvwAAbMjAAGzRwABs0oAAbNMAAGzTgABs1AAAbNSAAGzVAABs1UAAbNYAAGzZQABs3QAAbN2AAGzeAABs3oAAbN8AAGzfgABs4AAAbOCAAGzkQABs5QAAbOXAAGzmgABs50AAbOgAAGzowABs6YAAbOoAAGz5wABs+kAAbPrAAGz7QABs/AAAbPxAAGz8gABs/MAAbP0AAGz9gABs/gAAbP5AAGz+gABs/wAAbP9AAG0PAABtD4AAbRAAAG0QgABtEUAAbRGAAG0RwABtEgAAbRJAAG0SwABtE0AAbROAAG0TwABtFEAAbRSAAG0kQABtJMAAbSVAAG0lwABtJoAAbSbAAG0nAABtJ0AAbSeAAG0oAABtKIAAbSjAAG0pAABtKYAAbSnAAG05gABtOgAAbTqAAG07AABtO8AAbTwAAG08QABtPIAAbTzAAG09QABtPcAAbT4AAG0+QABtPsAAbT8AAG1OwABtT0AAbU/AAG1QQABtUQAAbVFAAG1RgABtUcAAbVIAAG1SgABtUwAAbVNAAG1TgABtVAAAbVRAAG1kAABtZIAAbWUAAG1lgABtZkAAbWaAAG1mwABtZwAAbWdAAG1nwABtaEAAbWiAAG1owABtaUAAbWmAAG15QABtecAAbXpAAG16wABte4AAbXvAAG18AABtfEAAbXyAAG19AABtfYAAbX3AAG1+AABtfoAAbX7AAG2RgABtmkAAbaJAAG2qQABtqsAAbatAAG2rwABtrEAAba0AAG2tQABtrYAAba5AAG2ugABtrwAAba9AAG2vwABtsIAAbbDAAG2xAABtscAAbbIAAG2zQABttoAAbbfAAG24QABtuMAAbboAAG26wABtu4AAbbwAAG3FQABtzkAAbdgAAG3hAABt4cAAbeJAAG3iwABt40AAbePAAG3kQABt5IAAbeVAAG3ogABt7MAAbe1AAG3twABt7kAAbe7AAG3vQABt78AAbfBAAG3wwABt9QAAbfXAAG32gABt90AAbfgAAG34wABt+YAAbfpAAG37AABt+4AAbgtAAG4LwABuDEAAbgzAAG4NgABuDcAAbg4AAG4OQABuDoAAbg8AAG4PgABuD8AAbhAAAG4QgABuEMAAbiCAAG4hAABuIYAAbiIAAG4iwABuIwAAbiNAAG4jgABuI8AAbiRAAG4kwABuJQAAbiVAAG4lwABuJgAAbjXAAG42QABuNwAAbjeAAG44QABuOIAAbjjAAG45AABuOUAAbjnAAG46QABuOoAAbjrAAG47QABuO4AAbj7AAG4/AABuP0AAbj/AAG5PgABuUAAAblCAAG5RAABuUcAAblIAAG5SQABuUoAAblLAAG5TQABuU8AAblQAAG5UQABuVMAAblUAAG5kwABuZUAAbmXAAG5mQABuZwAAbmdAAG5ngABuZ8AAbmgAAG5ogABuaQAAbmlAAG5pgABuagAAbmpAAG56AABueoAAbnsAAG57gABufEAAbnyAAG58wABufQAAbn1AAG59wABufkAAbn6AAG5+wABuf0AAbn+AAG6PQABuj8AAbpBAAG6QwABukYAAbpHAAG6SAABukkAAbpKAAG6TAABuk4AAbpPAAG6UAABulIAAbpTAAG6kgABupQAAbqWAAG6mAABupsAAbqcAAG6nQABup4AAbqfAAG6oQABuqMAAbqkAAG6pQABuqcAAbqoAAG6zQABuvEAAbsYAAG7PAABuz8AAbtBAAG7QwABu0UAAbtHAAG7SQABu0oAAbtNAAG7WgABu2kAAbtrAAG7bQABu28AAbtxAAG7cwABu3UAAbt3AAG7hgABu4kAAbuMAAG7jwABu5IAAbuVAAG7mAABu5sAAbudAAG73AABu94AAbvhAAG74wABu+YAAbvnAAG76AABu+kAAbvqAAG77AABu+4AAbvvAAG78AABu/IAAbvzAAG8MgABvDQAAbw2AAG8OAABvDsAAbw8AAG8PQABvD4AAbw/AAG8QQABvEMAAbxEAAG8RQABvEcAAbxIAAG8hwABvIkAAbyLAAG8jQABvJAAAbyRAAG8kgABvJMAAbyUAAG8lgABvJgAAbyZAAG8mgABvJwAAbydAAG83AABvN4AAbzhAAG84wABvOYAAbznAAG86AABvOkAAbzqAAG87AABvO4AAbzvAAG88AABvPIAAbzzAAG9MgABvTQAAb02AAG9OAABvTsAAb08AAG9PQABvT4AAb0/AAG9QQABvUMAAb1EAAG9RQABvUcAAb1IAAG9hwABvYkAAb2LAAG9jQABvZAAAb2RAAG9kgABvZMAAb2UAAG9lgABvZgAAb2ZAAG9mgABvZwAAb2dAAG93AABvd4AAb3gAAG94gABveUAAb3mAAG95wABvegAAb3pAAG96wABve0AAb3uAAG97wABvfEAAb3yAAG+PQABvmAAAb6AAAG+oAABvqIAAb6kAAG+pgABvqgAAb6rAAG+rAABvq0AAb6wAAG+sQABvrMAAb60AAG+tgABvrkAAb66AAG+uwABvr4AAb6/AAG+yAABvtUAAb7aAAG+3AABvt4AAb7jAAG+5gABvukAAb7rAAG/EAABvzQAAb9bAAG/fwABv4IAAb+EAAG/hgABv4gAAb+KAAG/jAABv40AAb+QAAG/nQABv64AAb+wAAG/sgABv7QAAb+2AAG/uAABv7oAAb+8AAG/vgABv88AAb/SAAG/1QABv9gAAb/bAAG/3gABv+EAAb/kAAG/5wABv+kAAcAoAAHAKgABwCwAAcAuAAHAMQABwDIAAcAzAAHANAABwDUAAcA3AAHAOQABwDoAAcA7AAHAPQABwD4AAcB9AAHAfwABwIEAAcCDAAHAhgABwIcAAcCIAAHAiQABwIoAAcCMAAHAjgABwI8AAcCQAAHAkgABwJMAAcDSAAHA1AABwNcAAcDZAAHA3AABwN0AAcDeAAHA3wABwOAAAcDiAAHA5AABwOUAAcDmAAHA6AABwOkAAcD2AAHA9wABwPgAAcD6AAHBOQABwTsAAcE9AAHBPwABwUIAAcFDAAHBRAABwUUAAcFGAAHBSAABwUoAAcFLAAHBTAABwU4AAcFPAAHBjgABwZAAAcGSAAHBlAABwZcAAcGYAAHBmQABwZoAAcGbAAHBnQABwZ8AAcGgAAHBoQABwaMAAcGkAAHB4wABweUAAcHnAAHB6QABwewAAcHtAAHB7gABwe8AAcHwAAHB8gABwfQAAcH1AAHB9gABwfgAAcH5AAHCOAABwjoAAcI8AAHCPgABwkEAAcJCAAHCQwABwkQAAcJFAAHCRwABwkkAAcJKAAHCSwABwk0AAcJOAAHCjQABwo8AAcKRAAHCkwABwpYAAcKXAAHCmAABwpkAAcKaAAHCnAABwp4AAcKfAAHCoAABwqIAAcKjAAHCyAABwuwAAcMTAAHDNwABwzoAAcM8AAHDPgABw0AAAcNCAAHDRAABw0UAAcNIAAHDVQABw2QAAcNmAAHDaAABw2oAAcNsAAHDbgABw3AAAcNyAAHDgQABw4QAAcOHAAHDigABw40AAcOQAAHDkwABw5YAAcOYAAHD1wABw9kAAcPbAAHD3QABw+AAAcPhAAHD4gABw+MAAcPkAAHD5gABw+gAAcPpAAHD6gABw+wAAcPtAAHELAABxC4AAcQwAAHEMgABxDUAAcQ2AAHENwABxDgAAcQ5AAHEOwABxD0AAcQ+AAHEPwABxEEAAcRCAAHEgQABxIMAAcSFAAHEhwABxIoAAcSLAAHEjAABxI0AAcSOAAHEkAABxJIAAcSTAAHElAABxJYAAcSXAAHE1gABxNgAAcTbAAHE3QABxOAAAcThAAHE4gABxOMAAcTkAAHE5gABxOgAAcTpAAHE6gABxOwAAcTtAAHFLAABxS4AAcUwAAHFMgABxTUAAcU2AAHFNwABxTgAAcU5AAHFOwABxT0AAcU+AAHFPwABxUEAAcVCAAHFgQABxYMAAcWFAAHFhwABxYoAAcWLAAHFjAABxY0AAcWOAAHFkAABxZIAAcWTAAHFlAABxZYAAcWXAAHF1gABxdgAAcXaAAHF3AABxd8AAcXgAAHF4QABxeIAAcXjAAHF5QABxecAAcXoAAHF6QABxesAAcXsAAHGNwABxloAAcZ6AAHGmgABxpwAAcaeAAHGoAABxqIAAcalAAHGpgABxqcAAcaqAAHGqwABxq0AAcauAAHGsAABxrMAAca0AAHGtQABxrgAAca5AAHGvgABxssAAcbQAAHG0gABxtQAAcbZAAHG3AABxt8AAcbhAAHHBgABxyoAAcdRAAHHdQABx3gAAcd6AAHHfAABx34AAceAAAHHggABx4MAAceGAAHHkwABx6QAAcemAAHHqAABx6oAAcesAAHHrgABx7AAAceyAAHHtAABx8UAAcfIAAHHywABx84AAcfRAAHH1AABx9cAAcfaAAHH3QABx98AAcgeAAHIIAAByCIAAcgkAAHIJwAByCgAAcgpAAHIKgAByCsAAcgtAAHILwAByDAAAcgxAAHIMwAByDQAAchzAAHIdQAByHcAAch5AAHIfAAByH0AAch+AAHIfwAByIAAAciCAAHIhAAByIUAAciGAAHIiAAByIkAAcjIAAHIygAByM0AAcjPAAHI0gAByNMAAcjUAAHI1QAByNYAAcjYAAHI2gAByNsAAcjcAAHI3gAByN8AAcjsAAHI7QAByO4AAcjwAAHJLwAByTEAAckzAAHJNQAByTgAAck5AAHJOgAByTsAAck8AAHJPgAByUAAAclBAAHJQgAByUQAAclFAAHJhAAByYYAAcmIAAHJigAByY0AAcmOAAHJjwAByZAAAcmRAAHJkwAByZUAAcmWAAHJlwAByZkAAcmaAAHJ2QABydsAAcndAAHJ3wAByeIAAcnjAAHJ5AAByeUAAcnmAAHJ6AAByeoAAcnrAAHJ7AABye4AAcnvAAHKLgAByjAAAcoyAAHKNAAByjcAAco4AAHKOQAByjoAAco7AAHKPQAByj8AAcpAAAHKQQABykMAAcpEAAHKgwAByoUAAcqHAAHKiQAByowAAcqNAAHKjgAByo8AAcqQAAHKkgABypQAAcqVAAHKlgABypgAAcqZAAHKvgAByuIAAcsJAAHLLQAByzAAAcsyAAHLNAAByzYAAcs4AAHLOgAByzsAAcs+AAHLSwABy1oAActcAAHLXgABy2AAActiAAHLZAABy2YAActoAAHLdwABy3oAAct9AAHLgAABy4MAAcuGAAHLiQABy4wAAcuOAAHLzQABy88AAcvRAAHL0wABy9YAAcvXAAHL2AABy9kAAcvaAAHL3AABy94AAcvfAAHL4AABy+IAAcvjAAHMIgABzCQAAcwmAAHMKAABzCsAAcwsAAHMLQABzC4AAcwvAAHMMQABzDMAAcw0AAHMNQABzDcAAcw4AAHMdwABzHkAAcx7AAHMfQABzIAAAcyBAAHMggABzIMAAcyEAAHMhgABzIgAAcyJAAHMigABzIwAAcyNAAHMzAABzM4AAczRAAHM0wABzNYAAczXAAHM2AABzNkAAczaAAHM3AABzN4AAczfAAHM4AABzOIAAczjAAHNIgABzSQAAc0mAAHNKAABzSsAAc0sAAHNLQABzS4AAc0vAAHNMQABzTMAAc00AAHNNQABzTcAAc04AAHNdwABzXkAAc17AAHNfQABzYAAAc2BAAHNggABzYMAAc2EAAHNhgABzYgAAc2JAAHNigABzYwAAc2NAAHNzAABzc4AAc3QAAHN0gABzdUAAc3WAAHN1wABzdgAAc3ZAAHN2wABzd0AAc3eAAHN3wABzeEAAc3iAAHOLQABzlAAAc5wAAHOkAABzpIAAc6UAAHOlgABzpgAAc6bAAHOnAABzp0AAc6gAAHOoQABzqMAAc6kAAHOpgABzqkAAc6qAAHOqwABzq4AAc6vAAHOtAABzsEAAc7GAAHOyAABzsoAAc7PAAHO0gABztUAAc7XAAHO/AABzyAAAc9HAAHPawABz24AAc9wAAHPcgABz3QAAc92AAHPeAABz3kAAc98AAHPiQABz5oAAc+cAAHPngABz6AAAc+iAAHPpAABz6YAAc+oAAHPqgABz7sAAc++AAHPwQABz8QAAc/HAAHPygABz80AAc/QAAHP0wABz9UAAdAUAAHQFgAB0BgAAdAaAAHQHQAB0B4AAdAfAAHQIAAB0CEAAdAjAAHQJQAB0CYAAdAnAAHQKQAB0CoAAdBpAAHQawAB0G0AAdBvAAHQcgAB0HMAAdB0AAHQdQAB0HYAAdB4AAHQegAB0HsAAdB8AAHQfgAB0H8AAdC+AAHQwAAB0MMAAdDFAAHQyAAB0MkAAdDKAAHQywAB0MwAAdDOAAHQ0AAB0NEAAdDSAAHQ1AAB0NUAAdDiAAHQ4wAB0OQAAdDmAAHRJQAB0ScAAdEpAAHRKwAB0S4AAdEvAAHRMAAB0TEAAdEyAAHRNAAB0TYAAdE3AAHROAAB0ToAAdE7AAHRegAB0XwAAdF+AAHRgAAB0YMAAdGEAAHRhQAB0YYAAdGHAAHRiQAB0YsAAdGMAAHRjQAB0Y8AAdGQAAHRzwAB0dEAAdHTAAHR1QAB0dgAAdHZAAHR2gAB0dsAAdHcAAHR3gAB0eAAAdHhAAHR4gAB0eQAAdHlAAHSJAAB0iYAAdIoAAHSKgAB0i0AAdIuAAHSLwAB0jAAAdIxAAHSMwAB0jUAAdI2AAHSNwAB0jkAAdI6AAHSeQAB0nsAAdJ9AAHSfwAB0oIAAdKDAAHShAAB0oUAAdKGAAHSiAAB0ooAAdKLAAHSjAAB0o4AAdKPAAHStAAB0tgAAdL/AAHTIwAB0yYAAdMoAAHTKgAB0ywAAdMuAAHTMAAB0zEAAdM0AAHTQQAB01AAAdNSAAHTVAAB01YAAdNYAAHTWgAB01wAAdNeAAHTbQAB03AAAdNzAAHTdgAB03kAAdN8AAHTfwAB04IAAdOEAAHTwwAB08UAAdPHAAHTyQAB08wAAdPNAAHTzgAB088AAdPQAAHT0gAB09QAAdPVAAHT1gAB09gAAdPZAAHUGAAB1BoAAdQcAAHUHgAB1CEAAdQiAAHUIwAB1CQAAdQlAAHUJwAB1CkAAdQqAAHUKwAB1C0AAdQuAAHUbQAB1G8AAdRxAAHUcwAB1HYAAdR3AAHUeAAB1HkAAdR6AAHUfAAB1H4AAdR/AAHUgAAB1IIAAdSDAAHUwgAB1MQAAdTHAAHUyQAB1MwAAdTNAAHUzgAB1M8AAdTQAAHU0gAB1NQAAdTVAAHU1gAB1NgAAdTZAAHVGAAB1RoAAdUcAAHVHgAB1SEAAdUiAAHVIwAB1SQAAdUlAAHVJwAB1SkAAdUqAAHVKwAB1S0AAdUuAAHVbQAB1W8AAdVxAAHVcwAB1XYAAdV3AAHVeAAB1XkAAdV6AAHVfAAB1X4AAdV/AAHVgAAB1YIAAdWDAAHVwgAB1cQAAdXGAAHVyAAB1csAAdXMAAHVzQAB1c4AAdXPAAHV0QAB1dMAAdXUAAHV1QAB1dcAAdXYAAHWIwAB1kYAAdZmAAHWhgAB1ogAAdaKAAHWjAAB1o4AAdaRAAHWkgAB1pMAAdaWAAHWlwAB1pkAAdaaAAHWnAAB1p8AAdagAAHWoQAB1qQAAdalAAHWqgAB1rcAAda8AAHWvgAB1sAAAdbFAAHWyAAB1ssAAdbNAAHW8gAB1xYAAdc9AAHXYQAB12QAAddmAAHXaAAB12oAAddsAAHXbgAB128AAddyAAHXfwAB15AAAdeSAAHXlAAB15YAAdeYAAHXmgAB15wAAdeeAAHXoAAB17EAAde0AAHXtwAB17oAAde9AAHXwAAB18MAAdfGAAHXyQAB18sAAdgKAAHYDAAB2A4AAdgQAAHYEwAB2BQAAdgVAAHYFgAB2BcAAdgZAAHYGwAB2BwAAdgdAAHYHwAB2CAAAdhfAAHYYQAB2GMAAdhlAAHYaAAB2GkAAdhqAAHYawAB2GwAAdhuAAHYcAAB2HEAAdhyAAHYdAAB2HUAAdi0AAHYtgAB2LkAAdi7AAHYvgAB2L8AAdjAAAHYwQAB2MIAAdjEAAHYxgAB2McAAdjIAAHYygAB2MsAAdjYAAHY2QAB2NoAAdjcAAHZGwAB2R0AAdkfAAHZIQAB2SQAAdklAAHZJgAB2ScAAdkoAAHZKgAB2SwAAdktAAHZLgAB2TAAAdkxAAHZcAAB2XIAAdl0AAHZdgAB2XkAAdl6AAHZewAB2XwAAdl9AAHZfwAB2YEAAdmCAAHZgwAB2YUAAdmGAAHZxQAB2ccAAdnJAAHZywAB2c4AAdnPAAHZ0AAB2dEAAdnSAAHZ1AAB2dYAAdnXAAHZ2AAB2doAAdnbAAHaGgAB2hwAAdoeAAHaIAAB2iMAAdokAAHaJQAB2iYAAdonAAHaKQAB2isAAdosAAHaLQAB2i8AAdowAAHabwAB2nEAAdpzAAHadQAB2ngAAdp5AAHaegAB2nsAAdp8AAHafgAB2oAAAdqBAAHaggAB2oQAAdqFAAHaqgAB2s4AAdr1AAHbGQAB2xwAAdseAAHbIAAB2yIAAdskAAHbJgAB2ycAAdsqAAHbNwAB20YAAdtIAAHbSgAB20wAAdtOAAHbUAAB21IAAdtUAAHbYwAB22YAAdtpAAHbbAAB228AAdtyAAHbdQAB23gAAdt6AAHbuQAB27sAAdu+AAHbwAAB28MAAdvEAAHbxQAB28YAAdvHAAHbyQAB28sAAdvMAAHbzQAB288AAdvQAAHb0QAB3BAAAdwSAAHcFAAB3BYAAdwZAAHcGgAB3BsAAdwcAAHcHQAB3B8AAdwhAAHcIgAB3CMAAdwlAAHcJgAB3GUAAdxnAAHcaQAB3GsAAdxuAAHcbwAB3HAAAdxxAAHccgAB3HQAAdx2AAHcdwAB3HgAAdx6AAHcewAB3LoAAdy8AAHcvgAB3MAAAdzDAAHcxAAB3MUAAdzGAAHcxwAB3MkAAdzLAAHczAAB3M0AAdzPAAHc0AAB3Q8AAd0RAAHdEwAB3RUAAd0YAAHdGQAB3RoAAd0bAAHdHAAB3R4AAd0gAAHdIQAB3SIAAd0kAAHdJQAB3WQAAd1mAAHdaAAB3WoAAd1tAAHdbgAB3W8AAd1wAAHdcQAB3XMAAd11AAHddgAB3XcAAd15AAHdegAB3bkAAd27AAHdvQAB3b8AAd3CAAHdwwAB3cQAAd3FAAHdxgAB3cgAAd3KAAHdywAB3cwAAd3OAAHdzwAB3hoAAd49AAHeXQAB3n0AAd5/AAHegQAB3oMAAd6FAAHeiAAB3okAAd6KAAHejQAB3o4AAd6QAAHekQAB3pMAAd6WAAHelwAB3pgAAd6bAAHenAAB3qUAAd6yAAHetwAB3rkAAd67AAHewAAB3sMAAd7GAAHeyAAB3u0AAd8RAAHfOAAB31wAAd9fAAHfYQAB32MAAd9lAAHfZwAB32kAAd9qAAHfbQAB33oAAd+LAAHfjQAB348AAd+RAAHfkwAB35UAAd+XAAHfmQAB35sAAd+sAAHfrwAB37IAAd+1AAHfuAAB37sAAd++AAHfwQAB38QAAd/GAAHgBQAB4AcAAeAJAAHgCwAB4A4AAeAPAAHgEAAB4BEAAeASAAHgFAAB4BYAAeAXAAHgGAAB4BoAAeAbAAHgWgAB4FwAAeBeAAHgYAAB4GMAAeBkAAHgZQAB4GYAAeBnAAHgaQAB4GsAAeBsAAHgbQAB4G8AAeBwAAHgrwAB4LEAAeC0AAHgtgAB4LkAAeC6AAHguwAB4LwAAeC9AAHgvwAB4MEAAeDCAAHgwwAB4MUAAeDGAAHg0wAB4NQAAeDVAAHg1wAB4RYAAeEYAAHhGgAB4RwAAeEfAAHhIAAB4SEAAeEiAAHhIwAB4SUAAeEnAAHhKAAB4SkAAeErAAHhLAAB4WsAAeFtAAHhbwAB4XEAAeF0AAHhdQAB4XYAAeF3AAHheAAB4XoAAeF8AAHhfQAB4X4AAeGAAAHhgQAB4cAAAeHCAAHhxAAB4cYAAeHJAAHhygAB4csAAeHMAAHhzQAB4c8AAeHRAAHh0gAB4dMAAeHVAAHh1gAB4hUAAeIXAAHiGQAB4hsAAeIeAAHiHwAB4iAAAeIhAAHiIgAB4iQAAeImAAHiJwAB4igAAeIqAAHiKwAB4moAAeJsAAHibgAB4nAAAeJzAAHidAAB4nUAAeJ2AAHidwAB4nkAAeJ7AAHifAAB4n0AAeJ/AAHigAAB4qUAAeLJAAHi8AAB4xQAAeMXAAHjGQAB4xsAAeMdAAHjHwAB4yEAAeMiAAHjJQAB4zIAAeNBAAHjQwAB40UAAeNHAAHjSQAB40sAAeNNAAHjTwAB414AAeNhAAHjZAAB42cAAeNqAAHjbQAB43AAAeNzAAHjdQAB47QAAeO2AAHjuAAB47oAAeO9AAHjvgAB478AAePAAAHjwQAB48MAAePFAAHjxgAB48cAAePJAAHjygAB5AkAAeQLAAHkDQAB5A8AAeQSAAHkEwAB5BQAAeQVAAHkFgAB5BgAAeQaAAHkGwAB5BwAAeQeAAHkHwAB5F4AAeRgAAHkYgAB5GQAAeRnAAHkaAAB5GkAAeRqAAHkawAB5G0AAeRvAAHkcAAB5HEAAeRzAAHkdAAB5LMAAeS1AAHkuAAB5LoAAeS9AAHkvgAB5L8AAeTAAAHkwQAB5MMAAeTFAAHkxgAB5McAAeTJAAHkygAB5QkAAeULAAHlDQAB5Q8AAeUSAAHlEwAB5RQAAeUVAAHlFgAB5RgAAeUaAAHlGwAB5RwAAeUeAAHlHwAB5V4AAeVgAAHlYgAB5WQAAeVnAAHlaAAB5WkAAeVqAAHlawAB5W0AAeVvAAHlcAAB5XEAAeVzAAHldAAB5bMAAeW1AAHltwAB5bkAAeW8AAHlvQAB5b4AAeW/AAHlwAAB5cIAAeXEAAHlxQAB5cYAAeXIAAHlyQAB5hQAAeY3AAHmVwAB5ncAAeZ5AAHmewAB5n0AAeZ/AAHmggAB5oMAAeaEAAHmhwAB5ogAAeaKAAHmiwAB5o0AAeaQAAHmkQAB5pIAAeaVAAHmlgAB5psAAeaoAAHmrQAB5q8AAeaxAAHmtgAB5rkAAea8AAHmvgAB5uMAAecHAAHnLgAB51IAAedVAAHnVwAB51kAAedbAAHnXQAB518AAedgAAHnYwAB53AAAeeBAAHngwAB54UAAeeHAAHniQAB54sAAeeNAAHnjwAB55EAAeeiAAHnpQAB56gAAeerAAHnrgAB57EAAee0AAHntwAB57oAAee8AAHn+wAB5/0AAef/AAHoAQAB6AQAAegFAAHoBgAB6AcAAegIAAHoCgAB6AwAAegNAAHoDgAB6BAAAegRAAHoUAAB6FIAAehUAAHoVgAB6FkAAehaAAHoWwAB6FwAAehdAAHoXwAB6GEAAehiAAHoYwAB6GUAAehmAAHopQAB6KcAAeiqAAHorAAB6K8AAeiwAAHosQAB6LIAAeizAAHotQAB6LcAAei4AAHouQAB6LsAAei8AAHoyQAB6MoAAejLAAHozQAB6QwAAekOAAHpEAAB6RIAAekVAAHpFgAB6RcAAekYAAHpGQAB6RsAAekdAAHpHgAB6R8AAekhAAHpIgAB6WEAAeljAAHpZQAB6WcAAelqAAHpawAB6WwAAeltAAHpbgAB6XAAAelyAAHpcwAB6XQAAel2AAHpdwAB6bYAAem4AAHpugAB6bwAAem/AAHpwAAB6cEAAenCAAHpwwAB6cUAAenHAAHpyAAB6ckAAenLAAHpzAAB6gsAAeoNAAHqDwAB6hEAAeoUAAHqFQAB6hYAAeoXAAHqGAAB6hoAAeocAAHqHQAB6h4AAeogAAHqIQAB6mAAAepiAAHqZAAB6mYAAeppAAHqagAB6msAAepsAAHqbQAB6m8AAepxAAHqcgAB6nMAAep1AAHqdgAB6psAAeq/AAHq5gAB6woAAesNAAHrDwAB6xEAAesTAAHrFQAB6xcAAesYAAHrGwAB6ygAAes3AAHrOQAB6zsAAes9AAHrPwAB60EAAetDAAHrRQAB61QAAetXAAHrWgAB610AAetgAAHrYwAB62YAAetpAAHrawAB66oAAeusAAHrrgAB67AAAeuzAAHrtAAB67UAAeu2AAHrtwAB67kAAeu7AAHrvAAB670AAeu/AAHrwAAB6/8AAewBAAHsAwAB7AUAAewIAAHsCQAB7AoAAewLAAHsDAAB7A4AAewQAAHsEQAB7BIAAewUAAHsFQAB7FQAAexWAAHsWAAB7FoAAexdAAHsXgAB7F8AAexgAAHsYQAB7GMAAexlAAHsZgAB7GcAAexpAAHsagAB7KkAAeyrAAHsrgAB7LAAAeyzAAHstAAB7LUAAey2AAHstwAB7LkAAey7AAHsvAAB7L0AAey/AAHswAAB7P8AAe0BAAHtAwAB7QUAAe0IAAHtCQAB7QoAAe0LAAHtDAAB7Q4AAe0QAAHtEQAB7RIAAe0UAAHtFQAB7VQAAe1WAAHtWAAB7VoAAe1dAAHtXgAB7V8AAe1gAAHtYQAB7WMAAe1lAAHtZgAB7WcAAe1pAAHtagAB7akAAe2rAAHtrQAB7a8AAe2yAAHtswAB7bQAAe21AAHttgAB7bgAAe26AAHtuwAB7bwAAe2+AAHtvwAB7cgAAe3JAAHtywAB7g4AAe4yAAHuVgAB7nkAAe6gAAHuwAAB7ucAAe8OAAHvLgAB71IAAe92AAHveAAB73sAAe99AAHvfwAB74EAAe+EAAHvhwAB74kAAe+LAAHvjgAB75AAAe+SAAHvlQAB75gAAe+ZAAHvngAB76sAAe+uAAHvsAAB77MAAe+2AAHvuAAB790AAfABAAHwKAAB8EwAAfBPAAHwUQAB8FMAAfBVAAHwVwAB8FkAAfBaAAHwXQAB8GoAAfB9AAHwfwAB8IEAAfCDAAHwhQAB8IcAAfCJAAHwiwAB8I0AAfCPAAHwogAB8KUAAfCoAAHwqwAB8K4AAfCxAAHwtAAB8LcAAfC6AAHwvQAB8L8AAfD+AAHxAAAB8QMAAfEFAAHxCAAB8QkAAfEKAAHxCwAB8QwAAfEOAAHxEAAB8REAAfESAAHxFAAB8RUAAfEeAAHxHwAB8SEAAfFgAAHxYgAB8WQAAfFmAAHxaQAB8WoAAfFrAAHxbAAB8W0AAfFvAAHxcQAB8XIAAfFzAAHxdQAB8XYAAfG1AAHxtwAB8boAAfG8AAHxvwAB8cAAAfHBAAHxwgAB8cMAAfHFAAHxxwAB8cgAAfHJAAHxywAB8cwAAfHVAAHx2gAB8d0AAfHgAAHx4gAB8esAAfHuAAHx8QAB8fMAAfH8AAHx/wAB8gIAAfIEAAHyEwAB8lIAAfJUAAHyVgAB8lgAAfJbAAHyXAAB8l0AAfJeAAHyXwAB8mEAAfJjAAHyZAAB8mUAAfJnAAHyaAAB8qcAAfKpAAHyrAAB8q4AAfKxAAHysgAB8rMAAfK0AAHytQAB8rcAAfK5AAHyugAB8rsAAfK9AAHyvgAB8scAAfLIAAHyygAB8wkAAfMLAAHzDQAB8w8AAfMSAAHzEwAB8xQAAfMVAAHzFgAB8xgAAfMaAAHzGwAB8xwAAfMeAAHzHwAB814AAfNgAAHzYwAB82UAAfNoAAHzaQAB82oAAfNrAAHzbAAB824AAfNwAAHzcQAB83IAAfN0AAHzdQAB84IAAfODAAHzhAAB84YAAfPFAAHzxwAB88kAAfPLAAHzzgAB888AAfPQAAHz0QAB89IAAfPUAAHz1gAB89cAAfPYAAHz2gAB89sAAfQaAAH0HAAB9B8AAfQhAAH0JAAB9CUAAfQmAAH0JwAB9CgAAfQqAAH0LAAB9C0AAfQuAAH0MAAB9DEAAfRIAAH0VQAB9HgAAfR7AAH0fgAB9IEAAfSEAAH0hwAB9IoAAfSNAAH0jwAB9JIAAfSVAAH0mAAB9JsAAfSeAAH0oQAB9KQAAfSnAAH0ygAB9M0AAfTQAAH00wAB9NYAAfTZAAH03AAB9N8AAfTiAAH05QAB9OgAAfTrAAH07gAB9PEAAfT0AAH09wAB9PoAAfT8AAH1CwAB9RoAAfUkAAH1MgAB9UEAAfVXAAH1bwAB9XUAAfWDAAH1mgAB9aEAAfWsAAH1uAAB9gMAAfYmAAH2RgAB9mYAAfZoAAH2agAB9mwAAfZuAAH2cQAB9nIAAfZzAAH2dgAB9ncAAfZ5AAH2egAB9nwAAfZ/AAH2gAAB9oEAAfaEAAH2hQAB9o4AAfabAAH2oAAB9qIAAfakAAH2qQAB9qwAAfavAAH2sQAB9tYAAfb6AAH3IQAB90UAAfdIAAH3SgAB90wAAfdOAAH3UAAB91IAAfdTAAH3VgAB92MAAfd0AAH3dgAB93gAAfd6AAH3fAAB934AAfeAAAH3ggAB94QAAfeVAAH3mAAB95sAAfeeAAH3oQAB96QAAfenAAH3qgAB960AAfevAAH37gAB9/AAAffyAAH39AAB9/cAAff4AAH3+QAB9/oAAff7AAH3/QAB9/8AAfgAAAH4AQAB+AMAAfgEAAH4QwAB+EUAAfhHAAH4SQAB+EwAAfhNAAH4TgAB+E8AAfhQAAH4UgAB+FQAAfhVAAH4VgAB+FgAAfhZAAH4mAAB+JoAAfidAAH4nwAB+KIAAfijAAH4pAAB+KUAAfimAAH4qAAB+KoAAfirAAH4rAAB+K4AAfivAAH4vAAB+L0AAfi+AAH4wAAB+P8AAfkBAAH5AwAB+QUAAfkIAAH5CQAB+QoAAfkLAAH5DAAB+Q4AAfkQAAH5EQAB+RIAAfkUAAH5FQAB+VQAAflWAAH5WAAB+VoAAfldAAH5XgAB+V8AAflgAAH5YQAB+WMAAfllAAH5ZgAB+WcAAflpAAH5agAB+akAAfmrAAH5rQAB+a8AAfmyAAH5swAB+bQAAfm1AAH5tgAB+bgAAfm6AAH5uwAB+bwAAfm+AAH5vwAB+f4AAfoAAAH6AgAB+gQAAfoHAAH6CAAB+gkAAfoKAAH6CwAB+g0AAfoPAAH6EAAB+hEAAfoTAAH6FAAB+lMAAfpVAAH6VwAB+lkAAfpcAAH6XQAB+l4AAfpfAAH6YAAB+mIAAfpkAAH6ZQAB+mYAAfpoAAH6aQAB+o4AAfqyAAH62QAB+v0AAfsAAAH7AgAB+wQAAfsGAAH7CAAB+woAAfsLAAH7DgAB+xsAAfsqAAH7LAAB+y4AAfswAAH7MgAB+zQAAfs2AAH7OAAB+0cAAftKAAH7TQAB+1AAAftTAAH7VgAB+1kAAftcAAH7XgAB+50AAfufAAH7oQAB+6MAAfumAAH7pwAB+6gAAfupAAH7qgAB+6wAAfuuAAH7rwAB+7AAAfuyAAH7swAB+/IAAfv0AAH79gAB+/gAAfv7AAH7/AAB+/0AAfv+AAH7/wAB/AEAAfwDAAH8BAAB/AUAAfwHAAH8CAAB/EcAAfxJAAH8SwAB/E0AAfxQAAH8UQAB/FIAAfxTAAH8VAAB/FYAAfxYAAH8WQAB/FoAAfxcAAH8XQAB/JwAAfyeAAH8oQAB/KMAAfymAAH8pwAB/KgAAfypAAH8qgAB/KwAAfyuAAH8rwAB/LAAAfyyAAH8swAB/PIAAfz0AAH89gAB/PgAAfz7AAH8/AAB/P0AAfz+AAH8/wAB/QEAAf0DAAH9BAAB/QUAAf0HAAH9CAAB/UcAAf1JAAH9SwAB/U0AAf1QAAH9UQAB/VIAAf1TAAH9VAAB/VYAAf1YAAH9WQAB/VoAAf1cAAH9XQAB/ZwAAf2eAAH9oAAB/aIAAf2lAAH9pgAB/acAAf2oAAH9qQAB/asAAf2tAAH9rgAB/a8AAf2xAAH9sgAB/f0AAf4gAAH+QAAB/mAAAf5iAAH+ZAAB/mYAAf5oAAH+awAB/mwAAf5tAAH+cAAB/nEAAf5zAAH+dAAB/nYAAf55AAH+egAB/nsAAf5+AAH+fwAB/oQAAf6RAAH+lgAB/pgAAf6aAAH+nwAB/qIAAf6lAAH+pwAB/swAAf7wAAH/FwAB/zsAAf8+AAH/QAAB/0IAAf9EAAH/RgAB/0gAAf9JAAH/TAAB/1kAAf9qAAH/bAAB/24AAf9wAAH/cgAB/3QAAf92AAH/eAAB/3oAAf+LAAH/jgAB/5EAAf+UAAH/lwAB/5oAAf+dAAH/oAAB/6MAAf+lAAH/5AAB/+YAAf/oAAH/6gAB/+0AAf/uAAH/7wAB//AAAf/xAAH/8wAB//UAAf/2AAH/9wAB//kAAf/6AAIAOQACADsAAgA9AAIAPwACAEIAAgBDAAIARAACAEUAAgBGAAIASAACAEoAAgBLAAIATAACAE4AAgBPAAIAjgACAJAAAgCTAAIAlQACAJgAAgCZAAIAmgACAJsAAgCcAAIAngACAKAAAgChAAIAogACAKQAAgClAAIAsgACALMAAgC0AAIAtgACAPUAAgD3AAIA+QACAPsAAgD+AAIA/wACAQAAAgEBAAIBAgACAQQAAgEGAAIBBwACAQgAAgEKAAIBCwACAUoAAgFMAAIBTgACAVAAAgFTAAIBVAACAVUAAgFWAAIBVwACAVkAAgFbAAIBXAACAV0AAgFfAAIBYAACAZ8AAgGhAAIBowACAaUAAgGoAAIBqQACAaoAAgGrAAIBrAACAa4AAgGwAAIBsQACAbIAAgG0AAIBtQACAfQAAgH2AAIB+AACAfoAAgH9AAIB/gACAf8AAgIAAAICAQACAgMAAgIFAAICBgACAgcAAgIJAAICCgACAkkAAgJLAAICTQACAk8AAgJSAAICUwACAlQAAgJVAAICVgACAlgAAgJaAAICWwACAlwAAgJeAAICXwACAoQAAgKoAAICzwACAvMAAgL2AAIC+AACAvoAAgL8AAIC/gACAwAAAgMBAAIDBAACAxEAAgMgAAIDIgACAyQAAgMmAAIDKAACAyoAAgMsAAIDLgACAz0AAgNAAAIDQwACA0YAAgNJAAIDTAACA08AAgNSAAIDVAACA5MAAgOVAAIDlwACA5kAAgOcAAIDnQACA54AAgOfAAIDoAACA6IAAgOkAAIDpQACA6YAAgOoAAIDqQACA+gAAgPqAAID7AACA+4AAgPxAAID8gACA/MAAgP0AAID9QACA/cAAgP5AAID+gACA/sAAgP9AAID/gACBD0AAgQ/AAIEQQACBEMAAgRGAAIERwACBEgAAgRJAAIESgACBEwAAgROAAIETwACBFAAAgRSAAIEUwACBJIAAgSUAAIElwACBJkAAgScAAIEnQACBJ4AAgSfAAIEoAACBKIAAgSkAAIEpQACBKYAAgSoAAIEqQACBOgAAgTqAAIE7AACBO4AAgTxAAIE8gACBPMAAgT0AAIE9QACBPcAAgT5AAIE+gACBPsAAgT9AAIE/gACBT0AAgU/AAIFQQACBUMAAgVGAAIFRwACBUgAAgVJAAIFSgACBUwAAgVOAAIFTwACBVAAAgVSAAIFUwACBZIAAgWUAAIFlgACBZgAAgWbAAIFnAACBZ0AAgWeAAIFnwACBaEAAgWjAAIFpAACBaUAAgWnAAIFqAACBfMAAgYWAAIGNgACBlYAAgZYAAIGWgACBlwAAgZeAAIGYQACBmIAAgZjAAIGZgACBmcAAgZpAAIGagACBmwAAgZvAAIGcAACBnEAAgZ0AAIGdQACBnoAAgaHAAIGjAACBo4AAgaQAAIGlQACBpgAAgabAAIGnQACBsIAAgbmAAIHDQACBzEAAgc0AAIHNgACBzgAAgc6AAIHPAACBz4AAgc/AAIHQgACB08AAgdgAAIHYgACB2QAAgdmAAIHaAACB2oAAgdsAAIHbgACB3AAAgeBAAIHhAACB4cAAgeKAAIHjQACB5AAAgeTAAIHlgACB5kAAgebAAIH2gACB9wAAgfeAAIH4AACB+MAAgfkAAIH5QACB+YAAgfnAAIH6QACB+sAAgfsAAIH7QACB+8AAgfwAAIILwACCDEAAggzAAIINQACCDgAAgg5AAIIOgACCDsAAgg8AAIIPgACCEAAAghBAAIIQgACCEQAAghFAAIIhAACCIYAAgiJAAIIiwACCI4AAgiPAAIIkAACCJEAAgiSAAIIlAACCJYAAgiXAAIImAACCJoAAgibAAIIqAACCKkAAgiqAAIIrAACCOsAAgjtAAII7wACCPEAAgj0AAII9QACCPYAAgj3AAII+AACCPoAAgj8AAII/QACCP4AAgkAAAIJAQACCUAAAglCAAIJRAACCUYAAglJAAIJSgACCUsAAglMAAIJTQACCU8AAglRAAIJUgACCVMAAglVAAIJVgACCZUAAgmXAAIJmQACCZsAAgmeAAIJnwACCaAAAgmhAAIJogACCaQAAgmmAAIJpwACCagAAgmqAAIJqwACCeoAAgnsAAIJ7gACCfAAAgnzAAIJ9AACCfUAAgn2AAIJ9wACCfkAAgn7AAIJ/AACCf0AAgn/AAIKAAACCj8AAgpBAAIKQwACCkUAAgpIAAIKSQACCkoAAgpLAAIKTAACCk4AAgpQAAIKUQACClIAAgpUAAIKVQACCnoAAgqeAAIKxQACCukAAgrsAAIK7gACCvAAAgryAAIK9AACCvYAAgr3AAIK+gACCwcAAgsWAAILGAACCxoAAgscAAILHgACCyAAAgsiAAILJAACCzMAAgs2AAILOQACCzwAAgs/AAILQgACC0UAAgtIAAILSgACC4kAAguLAAILjQACC48AAguSAAILkwACC5QAAguVAAILlgACC5gAAguaAAILmwACC5wAAgueAAILnwACC94AAgvgAAIL4gACC+QAAgvnAAIL6AACC+kAAgvqAAIL6wACC+0AAgvvAAIL8AACC/EAAgvzAAIL9AACDDMAAgw1AAIMNwACDDkAAgw8AAIMPQACDD4AAgw/AAIMQAACDEIAAgxEAAIMRQACDEYAAgxIAAIMSQACDIgAAgyKAAIMjAACDI4AAgyRAAIMkgACDJMAAgyUAAIMlQACDJcAAgyZAAIMmgACDJsAAgydAAIMngACDN0AAgzfAAIM4QACDOMAAgzmAAIM5wACDOgAAgzpAAIM6gACDOwAAgzuAAIM7wACDPAAAgzyAAIM8wACDTIAAg00AAINNgACDTgAAg07AAINPAACDT0AAg0+AAINPwACDUEAAg1DAAINRAACDUUAAg1HAAINSAACDYcAAg2JAAINiwACDY0AAg2QAAINkQACDZIAAg2TAAINlAACDZYAAg2YAAINmQACDZoAAg2cAAINnQACDegAAg4LAAIOKwACDksAAg5NAAIOTwACDlEAAg5TAAIOVgACDlcAAg5YAAIOWwACDlwAAg5eAAIOXwACDmEAAg5kAAIOZQACDmYAAg5pAAIOagACDm8AAg58AAIOgQACDoMAAg6FAAIOigACDo0AAg6QAAIOkgACDrcAAg7bAAIPAgACDyYAAg8pAAIPKwACDy0AAg8vAAIPMQACDzMAAg80AAIPNwACD0QAAg9VAAIPVwACD1kAAg9bAAIPXQACD18AAg9hAAIPYwACD2UAAg92AAIPeQACD3wAAg9/AAIPggACD4UAAg+IAAIPiwACD44AAg+QAAIPzwACD9EAAg/TAAIP1QACD9gAAg/ZAAIP2gACD9sAAg/cAAIP3gACD+AAAg/hAAIP4gACD+QAAg/lAAIQJAACECYAAhAoAAIQKgACEC0AAhAuAAIQLwACEDAAAhAxAAIQMwACEDUAAhA2AAIQNwACEDkAAhA6AAIQeQACEHsAAhB+AAIQgAACEIMAAhCEAAIQhQACEIYAAhCHAAIQiQACEIsAAhCMAAIQjQACEI8AAhCQAAIQnQACEJ4AAhCfAAIQoQACEOAAAhDiAAIQ5AACEOYAAhDpAAIQ6gACEOsAAhDsAAIQ7QACEO8AAhDxAAIQ8gACEPMAAhD1AAIQ9gACETUAAhE3AAIROQACETsAAhE+AAIRPwACEUAAAhFBAAIRQgACEUQAAhFGAAIRRwACEUgAAhFKAAIRSwACEYoAAhGMAAIRjgACEZAAAhGTAAIRlAACEZUAAhGWAAIRlwACEZkAAhGbAAIRnAACEZ0AAhGfAAIRoAACEd8AAhHhAAIR4wACEeUAAhHoAAIR6QACEeoAAhHrAAIR7AACEe4AAhHwAAIR8QACEfIAAhH0AAIR9QACEjQAAhI2AAISOAACEjoAAhI9AAISPgACEj8AAhJAAAISQQACEkMAAhJFAAISRgACEkcAAhJJAAISSgACEm8AAhKTAAISugACEt4AAhLhAAIS4wACEuUAAhLnAAIS6QACEusAAhLsAAIS7wACEvwAAhMLAAITDQACEw8AAhMRAAITEwACExUAAhMXAAITGQACEygAAhMrAAITLgACEzEAAhM0AAITNwACEzoAAhM9AAITPwACE34AAhOAAAITggACE4QAAhOHAAITiAACE4kAAhOKAAITiwACE40AAhOPAAITkAACE5EAAhOTAAITlAACE9MAAhPVAAIT1wACE9kAAhPcAAIT3QACE94AAhPfAAIT4AACE+IAAhPkAAIT5QACE+YAAhPoAAIT6QACFCgAAhQqAAIULAACFC4AAhQxAAIUMgACFDMAAhQ0AAIUNQACFDcAAhQ5AAIUOgACFDsAAhQ9AAIUPgACFH0AAhR/AAIUgQACFIMAAhSGAAIUhwACFIgAAhSJAAIUigACFIwAAhSOAAIUjwACFJAAAhSSAAIUkwACFNIAAhTUAAIU1gACFNgAAhTbAAIU3AACFN0AAhTeAAIU3wACFOEAAhTjAAIU5AACFOUAAhTnAAIU6AACFScAAhUpAAIVKwACFS0AAhUwAAIVMQACFTIAAhUzAAIVNAACFTYAAhU4AAIVOQACFToAAhU8AAIVPQACFXwAAhV+AAIVgAACFYIAAhWFAAIVhgACFYcAAhWIAAIViQACFYsAAhWNAAIVjgACFY8AAhWRAAIVkgACFd0AAhYAAAIWIAACFkAAAhZCAAIWRAACFkYAAhZIAAIWSwACFkwAAhZNAAIWUAACFlEAAhZTAAIWVAACFlYAAhZZAAIWWgACFlsAAhZeAAIWXwACFmgAAhZ1AAIWegACFnwAAhZ+AAIWgwACFoYAAhaJAAIWiwACFrAAAhbUAAIW+wACFx8AAhciAAIXJAACFyYAAhcoAAIXKgACFywAAhctAAIXMAACFz0AAhdOAAIXUAACF1IAAhdUAAIXVgACF1gAAhdaAAIXXAACF14AAhdvAAIXcgACF3UAAhd4AAIXewACF34AAheBAAIXhAACF4cAAheJAAIXyAACF8oAAhfMAAIXzgACF9EAAhfSAAIX0wACF9QAAhfVAAIX1wACF9kAAhfaAAIX2wACF90AAhfeAAIYHQACGB8AAhghAAIYIwACGCYAAhgnAAIYKAACGCkAAhgqAAIYLAACGC4AAhgvAAIYMAACGDIAAhgzAAIYcgACGHQAAhh3AAIYeQACGHwAAhh9AAIYfgACGH8AAhiAAAIYggACGIQAAhiFAAIYhgACGIgAAhiJAAIYlgACGJcAAhiYAAIYmgACGNkAAhjbAAIY3QACGN8AAhjiAAIY4wACGOQAAhjlAAIY5gACGOgAAhjqAAIY6wACGOwAAhjuAAIY7wACGS4AAhkwAAIZMgACGTQAAhk3AAIZOAACGTkAAhk6AAIZOwACGT0AAhk/AAIZQAACGUEAAhlDAAIZRAACGYMAAhmFAAIZhwACGYkAAhmMAAIZjQACGY4AAhmPAAIZkAACGZIAAhmUAAIZlQACGZYAAhmYAAIZmQACGdgAAhnaAAIZ3AACGd4AAhnhAAIZ4gACGeMAAhnkAAIZ5QACGecAAhnpAAIZ6gACGesAAhntAAIZ7gACGi0AAhovAAIaMQACGjMAAho2AAIaNwACGjgAAho5AAIaOgACGjwAAho+AAIaPwACGkAAAhpCAAIaQwACGmgAAhqMAAIaswACGtcAAhraAAIa3AACGt4AAhrgAAIa4gACGuQAAhrlAAIa6AACGvUAAhsEAAIbBgACGwgAAhsKAAIbDAACGw4AAhsQAAIbEgACGyEAAhskAAIbJwACGyoAAhstAAIbMAACGzMAAhs2AAIbOAACG3cAAht5AAIbewACG30AAhuAAAIbgQACG4IAAhuDAAIbhAACG4YAAhuIAAIbiQACG4oAAhuMAAIbjQACG8wAAhvOAAIb0AACG9IAAhvVAAIb1gACG9cAAhvYAAIb2QACG9sAAhvdAAIb3gACG98AAhvhAAIb4gACHCEAAhwjAAIcJQACHCcAAhwqAAIcKwACHCwAAhwtAAIcLgACHDAAAhwyAAIcMwACHDQAAhw2AAIcNwACHHYAAhx4AAIcegACHHwAAhx/AAIcgAACHIEAAhyCAAIcgwACHIUAAhyHAAIciAACHIkAAhyLAAIcjAACHMsAAhzNAAIczwACHNEAAhzUAAIc1QACHNYAAhzXAAIc2AACHNoAAhzcAAIc3QACHN4AAhzgAAIc4QACHSAAAh0iAAIdJAACHSYAAh0pAAIdKgACHSsAAh0sAAIdLQACHS8AAh0xAAIdMgACHTMAAh01AAIdNgACHXUAAh13AAIdeQACHXsAAh1+AAIdfwACHYAAAh2BAAIdggACHYQAAh2GAAIdhwACHYgAAh2KAAIdiwACHdYAAh35AAIeGQACHjkAAh47AAIePQACHj8AAh5BAAIeRAACHkUAAh5GAAIeSQACHkoAAh5MAAIeTQACHk8AAh5SAAIeUwACHlQAAh5XAAIeWAACHl0AAh5qAAIebwACHnEAAh5zAAIeeAACHnsAAh5+AAIegAACHqUAAh7JAAIe8AACHxQAAh8XAAIfGQACHxsAAh8dAAIfHwACHyEAAh8iAAIfJQACHzIAAh9DAAIfRQACH0cAAh9JAAIfSwACH00AAh9PAAIfUQACH1MAAh9kAAIfZwACH2oAAh9tAAIfcAACH3MAAh92AAIfeQACH3wAAh9+AAIfvQACH78AAh/BAAIfwwACH8YAAh/HAAIfyAACH8kAAh/KAAIfzAACH84AAh/PAAIf0AACH9IAAh/TAAIgEgACIBQAAiAWAAIgGAACIBsAAiAcAAIgHQACIB4AAiAfAAIgIQACICMAAiAkAAIgJQACICcAAiAoAAIgZwACIGkAAiBsAAIgbgACIHEAAiByAAIgcwACIHQAAiB1AAIgdwACIHkAAiB6AAIgewACIH0AAiB+AAIgiwACIIwAAiCNAAIgjwACIM4AAiDQAAIg0gACINQAAiDXAAIg2AACINkAAiDaAAIg2wACIN0AAiDfAAIg4AACIOEAAiDjAAIg5AACISMAAiElAAIhJwACISkAAiEsAAIhLQACIS4AAiEvAAIhMAACITIAAiE0AAIhNQACITYAAiE4AAIhOQACIXgAAiF6AAIhfAACIX4AAiGBAAIhggACIYMAAiGEAAIhhQACIYcAAiGJAAIhigACIYsAAiGNAAIhjgACIc0AAiHPAAIh0QACIdMAAiHWAAIh1wACIdgAAiHZAAIh2gACIdwAAiHeAAIh3wACIeAAAiHiAAIh4wACIiIAAiIkAAIiJgACIigAAiIrAAIiLAACIi0AAiIuAAIiLwACIjEAAiIzAAIiNAACIjUAAiI3AAIiOAACIl0AAiKBAAIiqAACIswAAiLPAAIi0QACItMAAiLVAAIi1wACItkAAiLaAAIi3QACIuoAAiL5AAIi+wACIv0AAiL/AAIjAQACIwMAAiMFAAIjBwACIxYAAiMZAAIjHAACIx8AAiMiAAIjJQACIygAAiMrAAIjLQACI2wAAiNuAAIjcAACI3IAAiN1AAIjdgACI3cAAiN4AAIjeQACI3sAAiN9AAIjfgACI38AAiOBAAIjggACI8EAAiPDAAIjxQACI8cAAiPKAAIjywACI8wAAiPNAAIjzgACI9AAAiPSAAIj0wACI9QAAiPWAAIj1wACJBYAAiQYAAIkGgACJBwAAiQfAAIkIAACJCEAAiQiAAIkIwACJCUAAiQnAAIkKAACJCkAAiQrAAIkLAACJGsAAiRtAAIkbwACJHEAAiR0AAIkdQACJHYAAiR3AAIkeAACJHoAAiR8AAIkfQACJH4AAiSAAAIkgQACJMAAAiTCAAIkxAACJMYAAiTJAAIkygACJMsAAiTMAAIkzQACJM8AAiTRAAIk0gACJNMAAiTVAAIk1gACJRUAAiUXAAIlGQACJRsAAiUeAAIlHwACJSAAAiUhAAIlIgACJSQAAiUmAAIlJwACJSgAAiUqAAIlKwACJWoAAiVsAAIlbgACJXAAAiVzAAIldAACJXUAAiV2AAIldwACJXkAAiV7AAIlfAACJX0AAiV/AAIlgAACJcsAAiXuAAImDgACJi4AAiYwAAImMgACJjQAAiY2AAImOQACJjoAAiY7AAImPgACJj8AAiZBAAImQgACJkQAAiZHAAImSAACJkkAAiZMAAImTQACJlIAAiZfAAImZAACJmYAAiZoAAImbQACJnAAAiZzAAImdQACJpoAAia+AAIm5QACJwkAAicMAAInDgACJxAAAicSAAInFAACJxYAAicXAAInGgACJycAAic4AAInOgACJzwAAic+AAInQAACJ0IAAidEAAInRgACJ0gAAidZAAInXAACJ18AAidiAAInZQACJ2gAAidrAAInbgACJ3EAAidzAAInsgACJ7QAAie2AAInuAACJ7sAAie8AAInvQACJ74AAie/AAInwQACJ8MAAifEAAInxQACJ8cAAifIAAIoBwACKAkAAigLAAIoDQACKBAAAigRAAIoEgACKBMAAigUAAIoFgACKBgAAigZAAIoGgACKBwAAigdAAIoXAACKF4AAihhAAIoYwACKGYAAihnAAIoaAACKGkAAihqAAIobAACKG4AAihvAAIocAACKHIAAihzAAIogAACKIEAAiiCAAIohAACKMMAAijFAAIoxwACKMkAAijMAAIozQACKM4AAijPAAIo0AACKNIAAijUAAIo1QACKNYAAijYAAIo2QACKRgAAikaAAIpHAACKR4AAikhAAIpIgACKSMAAikkAAIpJQACKScAAikpAAIpKgACKSsAAiktAAIpLgACKW0AAilvAAIpcQACKXMAAil2AAIpdwACKXgAAil5AAIpegACKXwAAil+AAIpfwACKYAAAimCAAIpgwACKcIAAinEAAIpxgACKcgAAinLAAIpzAACKc0AAinOAAIpzwACKdEAAinTAAIp1AACKdUAAinXAAIp2AACKhcAAioZAAIqGwACKh0AAiogAAIqIQACKiIAAiojAAIqJAACKiYAAiooAAIqKQACKioAAiosAAIqLQACKlIAAip2AAIqnQACKsEAAirEAAIqxgACKsgAAirKAAIqzAACKs4AAirPAAIq0gACKt8AAiruAAIq8AACKvIAAir0AAIq9gACKvgAAir6AAIq/AACKwsAAisOAAIrEQACKxQAAisXAAIrGgACKx0AAisgAAIrIgACK2EAAitjAAIrZQACK2cAAitqAAIrawACK2wAAittAAIrbgACK3AAAityAAIrcwACK3QAAit2AAIrdwACK7YAAiu4AAIrugACK7wAAiu/AAIrwAACK8EAAivCAAIrwwACK8UAAivHAAIryAACK8kAAivLAAIrzAACLAsAAiwNAAIsDwACLBEAAiwUAAIsFQACLBYAAiwXAAIsGAACLBoAAiwcAAIsHQACLB4AAiwgAAIsIQACLGAAAixiAAIsZAACLGYAAixpAAIsagACLGsAAixsAAIsbQACLG8AAixxAAIscgACLHMAAix1AAIsdgACLLUAAiy3AAIsuQACLLsAAiy+AAIsvwACLMAAAizBAAIswgACLMQAAizGAAIsxwACLMgAAizKAAIsywACLQoAAi0MAAItDgACLRAAAi0TAAItFAACLRUAAi0WAAItFwACLRkAAi0bAAItHAACLR0AAi0fAAItIAACLV8AAi1hAAItYwACLWUAAi1oAAItaQACLWoAAi1rAAItbAACLW4AAi1wAAItcQACLXIAAi10AAItdQACLcAAAi3jAAIuAwACLiMAAi4lAAIuJwACLikAAi4rAAIuLgACLi8AAi4wAAIuMwACLjQAAi42AAIuNwACLjkAAi47AAIuPAACLj0AAi5AAAIuQQACLkYAAi5TAAIuWAACLloAAi5cAAIuYQACLmQAAi5nAAIuaQACLo4AAi6yAAIu2QACLv0AAi8AAAIvAgACLwQAAi8GAAIvCAACLwoAAi8LAAIvDgACLxsAAi8sAAIvLgACLzAAAi8yAAIvNAACLzYAAi84AAIvOgACLzwAAi9NAAIvUAACL1MAAi9WAAIvWQACL1wAAi9fAAIvYgACL2UAAi9nAAIvpgACL6gAAi+qAAIvrAACL68AAi+wAAIvsQACL7IAAi+zAAIvtQACL7cAAi+4AAIvuQACL7sAAi+8AAIv+wACL/0AAi//AAIwAQACMAQAAjAFAAIwBgACMAcAAjAIAAIwCgACMAwAAjANAAIwDgACMBAAAjARAAIwUAACMFIAAjBVAAIwVwACMFoAAjBbAAIwXAACMF0AAjBeAAIwYAACMGIAAjBjAAIwZAACMGYAAjBnAAIwdAACMHUAAjB2AAIweAACMLcAAjC5AAIwuwACML0AAjDAAAIwwQACMMIAAjDDAAIwxAACMMYAAjDIAAIwyQACMMoAAjDMAAIwzQACMQwAAjEOAAIxEAACMRIAAjEVAAIxFgACMRcAAjEYAAIxGQACMRsAAjEdAAIxHgACMR8AAjEhAAIxIgACMWEAAjFjAAIxZQACMWcAAjFqAAIxawACMWwAAjFtAAIxbgACMXAAAjFyAAIxcwACMXQAAjF2AAIxdwACMbYAAjG4AAIxugACMbwAAjG/AAIxwAACMcEAAjHCAAIxwwACMcUAAjHHAAIxyAACMckAAjHLAAIxzAACMgsAAjINAAIyDwACMhEAAjIUAAIyFQACMhYAAjIXAAIyGAACMhoAAjIcAAIyHQACMh4AAjIgAAIyIQACMkYAAjJqAAIykQACMrUAAjK4AAIyugACMrwAAjK+AAIywAACMsIAAjLDAAIyxgACMtMAAjLiAAIy5AACMuYAAjLoAAIy6gACMuwAAjLuAAIy8AACMv8AAjMCAAIzBQACMwgAAjMLAAIzDgACMxEAAjMUAAIzFgACM1UAAjNXAAIzWQACM1sAAjNeAAIzXwACM2AAAjNhAAIzYgACM2QAAjNmAAIzZwACM2gAAjNqAAIzawACM6oAAjOsAAIzrgACM7AAAjOzAAIztAACM7UAAjO2AAIztwACM7kAAjO7AAIzvAACM70AAjO/AAIzwAACM/8AAjQBAAI0AwACNAUAAjQIAAI0CQACNAoAAjQLAAI0DAACNA4AAjQQAAI0EQACNBIAAjQUAAI0FQACNFQAAjRWAAI0WQACNFsAAjReAAI0XwACNGAAAjRhAAI0YgACNGQAAjRmAAI0ZwACNGgAAjRqAAI0awACNKoAAjSsAAI0rgACNLAAAjSzAAI0tAACNLUAAjS2AAI0twACNLkAAjS7AAI0vAACNL0AAjS/AAI0wAACNP8AAjUBAAI1AwACNQUAAjUIAAI1CQACNQoAAjULAAI1DAACNQ4AAjUQAAI1EQACNRIAAjUUAAI1FQACNVQAAjVWAAI1WAACNVoAAjVdAAI1XgACNV8AAjVgAAI1YQACNWMAAjVlAAI1ZgACNWcAAjVpAAI1agACNbUAAjXYAAI1+AACNhgAAjYaAAI2HAACNh4AAjYgAAI2IwACNiQAAjYlAAI2KAACNikAAjYrAAI2LAACNi4AAjYxAAI2MgACNjMAAjY2AAI2NwACNjwAAjZJAAI2TgACNlAAAjZSAAI2VwACNloAAjZdAAI2XwACNoQAAjaoAAI2zwACNvMAAjb2AAI2+AACNvoAAjb8AAI2/gACNwAAAjcBAAI3BAACNxEAAjciAAI3JAACNyYAAjcoAAI3KgACNywAAjcuAAI3MAACNzIAAjdDAAI3RgACN0kAAjdMAAI3TwACN1IAAjdVAAI3WAACN1sAAjddAAI3nAACN54AAjegAAI3ogACN6UAAjemAAI3pwACN6gAAjepAAI3qwACN60AAjeuAAI3rwACN7EAAjeyAAI38QACN/MAAjf1AAI39wACN/oAAjf7AAI3/AACN/0AAjf+AAI4AAACOAIAAjgDAAI4BAACOAYAAjgHAAI4RgACOEgAAjhLAAI4TQACOFAAAjhRAAI4UgACOFMAAjhUAAI4VgACOFgAAjhZAAI4WgACOFwAAjhdAAI4agACOGsAAjhsAAI4bgACOK0AAjivAAI4sQACOLMAAji2AAI4twACOLgAAji5AAI4ugACOLwAAji+AAI4vwACOMAAAjjCAAI4wwACOQIAAjkEAAI5BgACOQgAAjkLAAI5DAACOQ0AAjkOAAI5DwACOREAAjkTAAI5FAACORUAAjkXAAI5GAACOVcAAjlZAAI5WwACOV0AAjlgAAI5YQACOWIAAjljAAI5ZAACOWYAAjloAAI5aQACOWoAAjlsAAI5bQACOawAAjmuAAI5sAACObIAAjm1AAI5tgACObcAAjm4AAI5uQACObsAAjm9AAI5vgACOb8AAjnBAAI5wgACOgEAAjoDAAI6BQACOgcAAjoKAAI6CwACOgwAAjoNAAI6DgACOhAAAjoSAAI6EwACOhQAAjoWAAI6FwACOjwAAjpgAAI6hwACOqsAAjquAAI6sAACOrIAAjq0AAI6tgACOrgAAjq5AAI6vAACOskAAjrYAAI62gACOtwAAjreAAI64AACOuIAAjrkAAI65gACOvUAAjr4AAI6+wACOv4AAjsBAAI7BAACOwcAAjsKAAI7DAACO0sAAjtNAAI7TwACO1EAAjtUAAI7VQACO1YAAjtXAAI7WAACO1oAAjtcAAI7XQACO14AAjtgAAI7YQACO6AAAjuiAAI7pAACO6YAAjupAAI7qgACO6sAAjusAAI7rQACO68AAjuxAAI7sgACO7MAAju1AAI7tgACO/UAAjv3AAI7+QACO/sAAjv+AAI7/wACPAAAAjwBAAI8AgACPAQAAjwGAAI8BwACPAgAAjwKAAI8CwACPEoAAjxMAAI8TwACPFEAAjxUAAI8VQACPFYAAjxXAAI8WAACPFoAAjxcAAI8XQACPF4AAjxgAAI8YQACPKAAAjyiAAI8pAACPKYAAjypAAI8qgACPKsAAjysAAI8rQACPK8AAjyxAAI8sgACPLMAAjy1AAI8tgACPPUAAjz3AAI8+QACPPsAAjz+AAI8/wACPQAAAj0BAAI9AgACPQQAAj0GAAI9BwACPQgAAj0KAAI9CwACPUoAAj1MAAI9TgACPVAAAj1TAAI9VAACPVUAAj1WAAI9VwACPVkAAj1bAAI9XAACPV0AAj1fAAI9YAACPasAAj3OAAI97gACPg4AAj4QAAI+EgACPhQAAj4WAAI+GQACPhoAAj4bAAI+HgACPh8AAj4hAAI+IgACPiQAAj4nAAI+KAACPikAAj4sAAI+LQACPjIAAj4/AAI+RAACPkYAAj5IAAI+TQACPlAAAj5TAAI+VQACPnoAAj6eAAI+xQACPukAAj7sAAI+7gACPvAAAj7yAAI+9AACPvYAAj73AAI++gACPwcAAj8YAAI/GgACPxwAAj8eAAI/IAACPyIAAj8kAAI/JgACPygAAj85AAI/PAACPz8AAj9CAAI/RQACP0gAAj9LAAI/TgACP1EAAj9TAAI/kgACP5QAAj+WAAI/mAACP5sAAj+cAAI/nQACP54AAj+fAAI/oQACP6MAAj+kAAI/pQACP6cAAj+oAAI/5wACP+kAAj/rAAI/7QACP/AAAj/xAAI/8gACP/MAAj/0AAI/9gACP/gAAj/5AAI/+gACP/wAAj/9AAJAPAACQD4AAkBBAAJAQwACQEYAAkBHAAJASAACQEkAAkBKAAJATAACQE4AAkBPAAJAUAACQFIAAkBTAAJAYAACQGEAAkBiAAJAZAACQKMAAkClAAJApwACQKkAAkCsAAJArQACQK4AAkCvAAJAsAACQLIAAkC0AAJAtQACQLYAAkC4AAJAuQACQPgAAkD6AAJA/AACQP4AAkEBAAJBAgACQQMAAkEEAAJBBQACQQcAAkEJAAJBCgACQQsAAkENAAJBDgACQU0AAkFPAAJBUQACQVMAAkFWAAJBVwACQVgAAkFZAAJBWgACQVwAAkFeAAJBXwACQWAAAkFiAAJBYwACQaIAAkGkAAJBpgACQagAAkGrAAJBrAACQa0AAkGuAAJBrwACQbEAAkGzAAJBtAACQbUAAkG3AAJBuAACQfcAAkH5AAJB+wACQf0AAkIAAAJCAQACQgIAAkIDAAJCBAACQgYAAkIIAAJCCQACQgoAAkIMAAJCDQACQjIAAkJWAAJCfQACQqEAAkKkAAJCpgACQqgAAkKqAAJCrAACQq4AAkKvAAJCsgACQr8AAkLOAAJC0AACQtIAAkLUAAJC1gACQtgAAkLaAAJC3AACQusAAkLuAAJC8QACQvQAAkL3AAJC+gACQv0AAkMAAAJDAgACQ0EAAkNDAAJDRQACQ0cAAkNKAAJDSwACQ0wAAkNNAAJDTgACQ1AAAkNSAAJDUwACQ1QAAkNWAAJDVwACQ5YAAkOYAAJDmgACQ5wAAkOfAAJDoAACQ6EAAkOiAAJDowACQ6UAAkOnAAJDqAACQ6kAAkOrAAJDrAACQ+sAAkPtAAJD7wACQ/EAAkP0AAJD9QACQ/YAAkP3AAJD+AACQ/oAAkP8AAJD/QACQ/4AAkQAAAJEAQACREAAAkRCAAJERQACREcAAkRKAAJESwACREwAAkRNAAJETgACRFAAAkRSAAJEUwACRFQAAkRWAAJEVwACRJYAAkSYAAJEmgACRJwAAkSfAAJEoAACRKEAAkSiAAJEowACRKUAAkSnAAJEqAACRKkAAkSrAAJErAACROsAAkTtAAJE7wACRPEAAkT0AAJE9QACRPYAAkT3AAJE+AACRPoAAkT8AAJE/QACRP4AAkUAAAJFAQACRUAAAkVCAAJFRAACRUYAAkVJAAJFSgACRUsAAkVMAAJFTQACRU8AAkVRAAJFUgACRVMAAkVVAAJFVgACRaEAAkXEAAJF5AACRgQAAkYGAAJGCAACRgoAAkYMAAJGDwACRhAAAkYRAAJGFAACRhUAAkYXAAJGGAACRhoAAkYdAAJGHgACRh8AAkYiAAJGIwACRigAAkY1AAJGOgACRjwAAkY+AAJGQwACRkYAAkZJAAJGSwACRnAAAkaUAAJGuwACRt8AAkbiAAJG5AACRuYAAkboAAJG6gACRuwAAkbtAAJG8AACRv0AAkcOAAJHEAACRxIAAkcUAAJHFgACRxgAAkcaAAJHHAACRx4AAkcvAAJHMgACRzUAAkc4AAJHOwACRz4AAkdBAAJHRAACR0cAAkdJAAJHiAACR4oAAkeMAAJHjgACR5EAAkeSAAJHkwACR5QAAkeVAAJHlwACR5kAAkeaAAJHmwACR50AAkeeAAJH3QACR98AAkfhAAJH4wACR+YAAkfnAAJH6AACR+kAAkfqAAJH7AACR+4AAkfvAAJH8AACR/IAAkfzAAJIMgACSDQAAkg3AAJIOQACSDwAAkg9AAJIPgACSD8AAkhAAAJIQgACSEQAAkhFAAJIRgACSEgAAkhJAAJIVgACSFcAAkhYAAJIWgACSJkAAkibAAJInQACSJ8AAkiiAAJIowACSKQAAkilAAJIpgACSKgAAkiqAAJIqwACSKwAAkiuAAJIrwACSO4AAkjwAAJI8gACSPQAAkj3AAJI+AACSPkAAkj6AAJI+wACSP0AAkj/AAJJAAACSQEAAkkDAAJJBAACSUMAAklFAAJJRwACSUkAAklMAAJJTQACSU4AAklPAAJJUAACSVIAAklUAAJJVQACSVYAAklYAAJJWQACSZgAAkmaAAJJnAACSZ4AAkmhAAJJogACSaMAAkmkAAJJpQACSacAAkmpAAJJqgACSasAAkmtAAJJrgACSe0AAknvAAJJ8QACSfMAAkn2AAJJ9wACSfgAAkn5AAJJ+gACSfwAAkn+AAJJ/wACSgAAAkoCAAJKAwACSigAAkpMAAJKcwACSpcAAkqaAAJKnAACSp4AAkqgAAJKogACSqQAAkqlAAJKqAACSrUAAkrEAAJKxgACSsgAAkrKAAJKzAACSs4AAkrQAAJK0gACSuEAAkrkAAJK5wACSuoAAkrtAAJK8AACSvMAAkr2AAJK+AACSzcAAks5AAJLOwACSz0AAktAAAJLQQACS0IAAktDAAJLRAACS0YAAktIAAJLSQACS0oAAktMAAJLTQACS4wAAkuOAAJLkAACS5IAAkuVAAJLlgACS5cAAkuYAAJLmQACS5sAAkudAAJLngACS58AAkuhAAJLogACS+EAAkvjAAJL5QACS+cAAkvqAAJL6wACS+wAAkvtAAJL7gACS/AAAkvyAAJL8wACS/QAAkv2AAJL9wACTDYAAkw4AAJMOgACTDwAAkw/AAJMQAACTEEAAkxCAAJMQwACTEUAAkxHAAJMSAACTEkAAkxLAAJMTAACTIsAAkyNAAJMjwACTJEAAkyUAAJMlQACTJYAAkyXAAJMmAACTJoAAkycAAJMnQACTJ4AAkygAAJMoQACTOAAAkziAAJM5AACTOYAAkzpAAJM6gACTOsAAkzsAAJM7QACTO8AAkzxAAJM8gACTPMAAkz1AAJM9gACTTUAAk03AAJNOQACTTsAAk0+AAJNPwACTUAAAk1BAAJNQgACTUQAAk1GAAJNRwACTUgAAk1KAAJNSwACTZYAAk25AAJN2QACTfkAAk37AAJN/QACTf8AAk4BAAJOBAACTgUAAk4GAAJOCQACTgoAAk4MAAJODQACTg8AAk4SAAJOEwACThQAAk4XAAJOGAACTh0AAk4qAAJOLwACTjEAAk4zAAJOOAACTjsAAk4+AAJOQAACTmUAAk6JAAJOsAACTtQAAk7XAAJO2QACTtsAAk7dAAJO3wACTuEAAk7iAAJO5QACTvIAAk8DAAJPBQACTwcAAk8JAAJPCwACTw0AAk8PAAJPEQACTxMAAk8kAAJPJwACTyoAAk8tAAJPMAACTzMAAk82AAJPOQACTzwAAk8+AAJPfQACT38AAk+BAAJPgwACT4YAAk+HAAJPiAACT4kAAk+KAAJPjAACT44AAk+PAAJPkAACT5IAAk+TAAJP0gACT9QAAk/WAAJP2AACT9sAAk/cAAJP3QACT94AAk/fAAJP4QACT+MAAk/kAAJP5QACT+cAAk/oAAJQJwACUCkAAlAsAAJQLgACUDEAAlAyAAJQMwACUDQAAlA1AAJQNwACUDkAAlA6AAJQOwACUD0AAlA+AAJQSwACUEwAAlBNAAJQTwACUI4AAlCQAAJQkgACUJQAAlCXAAJQmAACUJkAAlCaAAJQmwACUJ0AAlCfAAJQoAACUKEAAlCjAAJQpAACUOMAAlDlAAJQ5wACUOkAAlDsAAJQ7QACUO4AAlDvAAJQ8AACUPIAAlD0AAJQ9QACUPYAAlD4AAJQ+QACUTgAAlE6AAJRPAACUT4AAlFBAAJRQgACUUMAAlFEAAJRRQACUUcAAlFJAAJRSgACUUsAAlFNAAJRTgACUY0AAlGPAAJRkQACUZMAAlGWAAJRlwACUZgAAlGZAAJRmgACUZwAAlGeAAJRnwACUaAAAlGiAAJRowACUeIAAlHkAAJR5gACUegAAlHrAAJR7AACUe0AAlHuAAJR7wACUfEAAlHzAAJR9AACUfUAAlH3AAJR+AACUh0AAlJBAAJSaAACUowAAlKPAAJSkQACUpMAAlKVAAJSlwACUpkAAlKaAAJSnQACUqoAAlK5AAJSuwACUr0AAlK/AAJSwQACUsMAAlLFAAJSxwACUtYAAlLZAAJS3AACUt8AAlLiAAJS5QACUugAAlLrAAJS7QACUywAAlMuAAJTMAACUzIAAlM1AAJTNgACUzcAAlM4AAJTOQACUzsAAlM9AAJTPgACUz8AAlNBAAJTQgACU4EAAlODAAJThQACU4cAAlOKAAJTiwACU4wAAlONAAJTjgACU5AAAlOSAAJTkwACU5QAAlOWAAJTlwACU9YAAlPYAAJT2gACU9wAAlPfAAJT4AACU+EAAlPiAAJT4wACU+UAAlPnAAJT6AACU+kAAlPrAAJT7AACVCsAAlQtAAJUMAACVDIAAlQ1AAJUNgACVDcAAlQ4AAJUOQACVDsAAlQ9AAJUPgACVD8AAlRBAAJUQgACVIEAAlSDAAJUhQACVIcAAlSKAAJUiwACVIwAAlSNAAJUjgACVJAAAlSSAAJUkwACVJQAAlSWAAJUlwACVNYAAlTYAAJU2gACVNwAAlTfAAJU4AACVOEAAlTiAAJU4wACVOUAAlTnAAJU6AACVOkAAlTrAAJU7AACVSsAAlUtAAJVLwACVTEAAlU0AAJVNQACVTYAAlU3AAJVOAACVToAAlU8AAJVPQACVT4AAlVAAAJVQQACVYwAAlWvAAJVzwACVe8AAlXxAAJV8wACVfUAAlX3AAJV+gACVfsAAlX8AAJV/wACVgAAAlYCAAJWAwACVgUAAlYIAAJWCQACVgoAAlYNAAJWDgACVhMAAlYgAAJWJQACVicAAlYpAAJWLgACVjEAAlY0AAJWNgACVlsAAlZ/AAJWpgACVsoAAlbNAAJWzwACVtEAAlbTAAJW1QACVtcAAlbYAAJW2wACVugAAlb5AAJW+wACVv0AAlb/AAJXAQACVwMAAlcFAAJXBwACVwkAAlcaAAJXHQACVyAAAlcjAAJXJgACVykAAlcsAAJXLwACVzIAAlc0AAJXcwACV3UAAld3AAJXeQACV3wAAld9AAJXfgACV38AAleAAAJXggACV4QAAleFAAJXhgACV4gAAleJAAJXyAACV8oAAlfMAAJXzgACV9EAAlfSAAJX0wACV9QAAlfVAAJX1wACV9kAAlfaAAJX2wACV90AAlfeAAJYHQACWB8AAlgiAAJYJAACWCcAAlgoAAJYKQACWCoAAlgrAAJYLQACWC8AAlgwAAJYMQACWDMAAlg0AAJYQQACWEIAAlhDAAJYRQACWIQAAliGAAJYiAACWIoAAliNAAJYjgACWI8AAliQAAJYkQACWJMAAliVAAJYlgACWJcAAliZAAJYmgACWNkAAljbAAJY3QACWN8AAljiAAJY4wACWOQAAljlAAJY5gACWOgAAljqAAJY6wACWOwAAljuAAJY7wACWS4AAlkwAAJZMgACWTQAAlk3AAJZOAACWTkAAlk6AAJZOwACWT0AAlk/AAJZQAACWUEAAllDAAJZRAACWYMAAlmFAAJZhwACWYkAAlmMAAJZjQACWY4AAlmPAAJZkAACWZIAAlmUAAJZlQACWZYAAlmYAAJZmQACWdgAAlnaAAJZ3AACWd4AAlnhAAJZ4gACWeMAAlnkAAJZ5QACWecAAlnpAAJZ6gACWesAAlntAAJZ7gACWhMAAlo3AAJaXgACWoIAAlqFAAJahwACWokAAlqLAAJajQACWo8AAlqQAAJakwACWqAAAlqvAAJasQACWrMAAlq1AAJatwACWrkAAlq7AAJavQACWswAAlrPAAJa0gACWtUAAlrYAAJa2wACWt4AAlrhAAJa4wACWyIAAlskAAJbJgACWygAAlsrAAJbLAACWy0AAlsuAAJbLwACWzEAAlszAAJbNAACWzUAAls3AAJbOAACW3cAAlt5AAJbewACW30AAluAAAJbgQACW4IAAluDAAJbhAACW4YAAluIAAJbiQACW4oAAluMAAJbjQACW8wAAlvOAAJb0AACW9IAAlvVAAJb1gACW9cAAlvYAAJb2QACW9sAAlvdAAJb3gACW98AAlvhAAJb4gACXCEAAlwjAAJcJQACXCcAAlwqAAJcKwACXCwAAlwtAAJcLgACXDAAAlwyAAJcMwACXDQAAlw2AAJcNwACXHYAAlx4AAJcegACXHwAAlx/AAJcgAACXIEAAlyCAAJcgwACXIUAAlyHAAJciAACXIkAAlyLAAJcjAACXMsAAlzNAAJczwACXNEAAlzUAAJc1QACXNYAAlzXAAJc2AACXNoAAlzcAAJc3QACXN4AAlzgAAJc4QACXSAAAl0iAAJdJAACXSYAAl0pAAJdKgACXSsAAl0sAAJdLQACXS8AAl0xAAJdMgACXTMAAl01AAJdNgACXYEAAl2kAAJdxAACXeQAAl3mAAJd6AACXeoAAl3sAAJd7wACXfAAAl3xAAJd9AACXfUAAl33AAJd+AACXfoAAl39AAJd/gACXf8AAl4CAAJeAwACXggAAl4VAAJeGgACXhwAAl4eAAJeIwACXiYAAl4pAAJeKwACXlAAAl50AAJemwACXr8AAl7CAAJexAACXsYAAl7IAAJeygACXswAAl7NAAJe0AACXt0AAl7uAAJe8AACXvIAAl70AAJe9gACXvgAAl76AAJe/AACXv4AAl8PAAJfEgACXxUAAl8YAAJfGwACXx4AAl8hAAJfJAACXycAAl8pAAJfaAACX2oAAl9sAAJfbgACX3EAAl9yAAJfcwACX3QAAl91AAJfdwACX3kAAl96AAJfewACX30AAl9+AAJfvQACX78AAl/BAAJfwwACX8YAAl/HAAJfyAACX8kAAl/KAAJfzAACX84AAl/PAAJf0AACX9IAAl/TAAJgEgACYBQAAmAXAAJgGQACYBwAAmAdAAJgHgACYB8AAmAgAAJgIgACYCQAAmAlAAJgJgACYCgAAmApAAJgNgACYDcAAmA4AAJgOgACYHkAAmB7AAJgfQACYH8AAmCCAAJggwACYIQAAmCFAAJghgACYIgAAmCKAAJgiwACYIwAAmCOAAJgjwACYM4AAmDQAAJg0gACYNQAAmDXAAJg2AACYNkAAmDaAAJg2wACYN0AAmDfAAJg4AACYOEAAmDjAAJg5AACYSMAAmElAAJhJwACYSkAAmEsAAJhLQACYS4AAmEvAAJhMAACYTIAAmE0AAJhNQACYTYAAmE4AAJhOQACYXgAAmF6AAJhfAACYX4AAmGBAAJhggACYYMAAmGEAAJhhQACYYcAAmGJAAJhigACYYsAAmGNAAJhjgACYc0AAmHPAAJh0QACYdMAAmHWAAJh1wACYdgAAmHZAAJh2gACYdwAAmHeAAJh3wACYeAAAmHiAAJh4wACYggAAmIsAAJiUwACYncAAmJ6AAJifAACYn4AAmKAAAJiggACYoQAAmKFAAJiiAACYpUAAmKkAAJipgACYqgAAmKqAAJirAACYq4AAmKwAAJisgACYsEAAmLEAAJixwACYsoAAmLNAAJi0AACYtMAAmLWAAJi2AACYxcAAmMZAAJjGwACYx0AAmMgAAJjIQACYyIAAmMjAAJjJAACYyYAAmMoAAJjKQACYyoAAmMsAAJjLQACY2wAAmNuAAJjcAACY3IAAmN1AAJjdgACY3cAAmN4AAJjeQACY3sAAmN9AAJjfgACY38AAmOBAAJjggACY8EAAmPDAAJjxQACY8cAAmPKAAJjywACY8wAAmPNAAJjzgACY9AAAmPSAAJj0wACY9QAAmPWAAJj1wACZBYAAmQYAAJkGgACZBwAAmQfAAJkIAACZCEAAmQiAAJkIwACZCUAAmQnAAJkKAACZCkAAmQrAAJkLAACZGsAAmRtAAJkbwACZHEAAmR0AAJkdQACZHYAAmR3AAJkeAACZHoAAmR8AAJkfQACZH4AAmSAAAJkgQACZMAAAmTCAAJkxAACZMYAAmTJAAJkygACZMsAAmTMAAJkzQACZM8AAmTRAAJk0gACZNMAAmTVAAJk1gACZRUAAmUXAAJlGQACZRsAAmUeAAJlHwACZSAAAmUhAAJlIgACZSQAAmUmAAJlJwACZSgAAmUqAAJlKwACZXYAAmWZAAJluQACZdkAAmXbAAJl3QACZd8AAmXhAAJl5AACZeUAAmXmAAJl6QACZeoAAmXsAAJl7QACZe8AAmXyAAJl8wACZfQAAmX3AAJl+AACZf0AAmYKAAJmDwACZhEAAmYTAAJmGAACZhsAAmYeAAJmIAACZkUAAmZpAAJmkAACZrQAAma3AAJmuQACZrsAAma9AAJmvwACZsEAAmbCAAJmxQACZtIAAmbjAAJm5QACZucAAmbpAAJm6wACZu0AAmbvAAJm8QACZvMAAmcEAAJnBwACZwoAAmcNAAJnEAACZxMAAmcWAAJnGQACZxwAAmceAAJnXQACZ18AAmdhAAJnYwACZ2YAAmdnAAJnaAACZ2kAAmdqAAJnbAACZ24AAmdvAAJncAACZ3IAAmdzAAJnsgACZ7QAAme2AAJnuAACZ7sAAme8AAJnvQACZ74AAme/AAJnwQACZ8MAAmfEAAJnxQACZ8cAAmfIAAJoBwACaAkAAmgMAAJoDgACaBEAAmgSAAJoEwACaBQAAmgVAAJoFwACaBkAAmgaAAJoGwACaB0AAmgeAAJoKwACaCwAAmgtAAJoLwACaG4AAmhwAAJocgACaHQAAmh3AAJoeAACaHkAAmh6AAJoewACaH0AAmh/AAJogAACaIEAAmiDAAJohAACaMMAAmjFAAJoxwACaMkAAmjMAAJozQACaM4AAmjPAAJo0AACaNIAAmjUAAJo1QACaNYAAmjYAAJo2QACaRgAAmkaAAJpHAACaR4AAmkhAAJpIgACaSMAAmkkAAJpJQACaScAAmkpAAJpKgACaSsAAmktAAJpLgACaW0AAmlvAAJpcQACaXMAAml2AAJpdwACaXgAAml5AAJpegACaXwAAml+AAJpfwACaYAAAmmCAAJpgwACacIAAmnEAAJpxgACacgAAmnLAAJpzAACac0AAmnOAAJpzwACadEAAmnTAAJp1AACadUAAmnXAAJp2AACaf0AAmohAAJqSAACamwAAmpvAAJqcQACanMAAmp1AAJqdwACankAAmp6AAJqfQACaooAAmqZAAJqmwACap0AAmqfAAJqoQACaqMAAmqlAAJqpwACarYAAmq5AAJqvAACar8AAmrCAAJqxQACasgAAmrLAAJqzQACawwAAmsOAAJrEAACaxIAAmsVAAJrFgACaxcAAmsYAAJrGQACaxsAAmsdAAJrHgACax8AAmshAAJrIgACa2EAAmtjAAJrZQACa2cAAmtqAAJrawACa2wAAmttAAJrbgACa3AAAmtyAAJrcwACa3QAAmt2AAJrdwACa7YAAmu4AAJrugACa7wAAmu/AAJrwAACa8EAAmvCAAJrwwACa8UAAmvHAAJryAACa8kAAmvLAAJrzAACbAsAAmwNAAJsDwACbBEAAmwUAAJsFQACbBYAAmwXAAJsGAACbBoAAmwcAAJsHQACbB4AAmwgAAJsIQACbGAAAmxiAAJsZAACbGYAAmxpAAJsagACbGsAAmxsAAJsbQACbG8AAmxxAAJscgACbHMAAmx1AAJsdgACbLUAAmy3AAJsuQACbLsAAmy+AAJsvwACbMAAAmzBAAJswgACbMQAAmzGAAJsxwACbMgAAmzKAAJsywACbQoAAm0MAAJtDgACbRAAAm0TAAJtFAACbRUAAm0WAAJtFwACbRkAAm0bAAJtHAACbR0AAm0fAAJtIAACbWsAAm2OAAJtrgACbc4AAm3QAAJt0gACbdQAAm3WAAJt2QACbdoAAm3bAAJt3gACbd8AAm3hAAJt4gACbeQAAm3nAAJt6AACbekAAm3sAAJt7QACbfIAAm3/AAJuBAACbgYAAm4IAAJuDQACbhAAAm4TAAJuFQACbjoAAm5eAAJuhQACbqkAAm6sAAJurgACbrAAAm6yAAJutAACbrYAAm63AAJuugACbscAAm7YAAJu2gACbtwAAm7eAAJu4AACbuIAAm7kAAJu5gACbugAAm75AAJu/AACbv8AAm8CAAJvBQACbwgAAm8LAAJvDgACbxEAAm8TAAJvUgACb1QAAm9WAAJvWAACb1sAAm9cAAJvXQACb14AAm9fAAJvYQACb2MAAm9kAAJvZQACb2cAAm9oAAJvpwACb6kAAm+rAAJvrQACb7AAAm+xAAJvsgACb7MAAm+0AAJvtgACb7gAAm+5AAJvugACb7wAAm+9AAJv/AACb/4AAnABAAJwAwACcAYAAnAHAAJwCAACcAkAAnAKAAJwDAACcA4AAnAPAAJwEAACcBIAAnATAAJwIAACcCEAAnAiAAJwJAACcGMAAnBlAAJwZwACcGkAAnBsAAJwbQACcG4AAnBvAAJwcAACcHIAAnB0AAJwdQACcHYAAnB4AAJweQACcLgAAnC6AAJwvAACcL4AAnDBAAJwwgACcMMAAnDEAAJwxQACcMcAAnDJAAJwygACcMsAAnDNAAJwzgACcQ0AAnEPAAJxEQACcRMAAnEWAAJxFwACcRgAAnEZAAJxGgACcRwAAnEeAAJxHwACcSAAAnEiAAJxIwACcWIAAnFkAAJxZgACcWgAAnFrAAJxbAACcW0AAnFuAAJxbwACcXEAAnFzAAJxdAACcXUAAnF3AAJxeAACcbcAAnG5AAJxuwACcb0AAnHAAAJxwQACccIAAnHDAAJxxAACccYAAnHIAAJxyQACccoAAnHMAAJxzQACcfIAAnIWAAJyPQACcmEAAnJkAAJyZgACcmgAAnJqAAJybAACcm4AAnJvAAJycgACcn8AAnKOAAJykAACcpIAAnKUAAJylgACcpgAAnKaAAJynAACcqsAAnKuAAJysQACcrQAAnK3AAJyugACcr0AAnLAAAJywgACcwEAAnMDAAJzBQACcwcAAnMKAAJzCwACcwwAAnMNAAJzDgACcxAAAnMSAAJzEwACcxQAAnMWAAJzFwACc1YAAnNYAAJzWgACc1wAAnNfAAJzYAACc2EAAnNiAAJzYwACc2UAAnNnAAJzaAACc2kAAnNrAAJzbAACc6sAAnOtAAJzrwACc7EAAnO0AAJztQACc7YAAnO3AAJzuAACc7oAAnO8AAJzvQACc74AAnPAAAJzwQACdAAAAnQCAAJ0BQACdAcAAnQKAAJ0CwACdAwAAnQNAAJ0DgACdBAAAnQSAAJ0EwACdBQAAnQWAAJ0FwACdFYAAnRYAAJ0WgACdFwAAnRfAAJ0YAACdGEAAnRiAAJ0YwACdGUAAnRnAAJ0aAACdGkAAnRrAAJ0bAACdKsAAnStAAJ0rwACdLEAAnS0AAJ0tQACdLYAAnS3AAJ0uAACdLoAAnS8AAJ0vQACdL4AAnTAAAJ0wQACdQAAAnUCAAJ1BAACdQYAAnUJAAJ1CgACdQsAAnUMAAJ1DQACdQ8AAnURAAJ1EgACdRMAAnUVAAJ1FgACdR8AAnUgAAJ1IgACdWUAAnWJAAJ1rQACddAAAnX3AAJ2FwACdj4AAnZlAAJ2hQACdqkAAnbNAAJ2zwACdtIAAnbUAAJ21gACdtgAAnbbAAJ23gACduAAAnbiAAJ25QACducAAnbpAAJ27AACdu8AAnbwAAJ2+QACdwYAAncJAAJ3CwACdw4AAncRAAJ3EwACdzgAAndcAAJ3gwACd6cAAneqAAJ3rAACd64AAnewAAJ3sgACd7QAAne1AAJ3uAACd8UAAnfYAAJ32gACd9wAAnfeAAJ34AACd+IAAnfkAAJ35gACd+gAAnfqAAJ3/QACeAAAAngDAAJ4BgACeAkAAngMAAJ4DwACeBIAAngVAAJ4GAACeBoAAnhZAAJ4WwACeF4AAnhgAAJ4YwACeGQAAnhlAAJ4ZgACeGcAAnhpAAJ4awACeGwAAnhtAAJ4bwACeHAAAnh5AAJ4egACeHwAAni7AAJ4vQACeL8AAnjBAAJ4xAACeMUAAnjGAAJ4xwACeMgAAnjKAAJ4zAACeM0AAnjOAAJ40AACeNEAAnkQAAJ5EgACeRUAAnkXAAJ5GgACeRsAAnkcAAJ5HQACeR4AAnkgAAJ5IgACeSMAAnkkAAJ5JgACeScAAnkwAAJ5MQACeTMAAnlyAAJ5dAACeXYAAnl4AAJ5ewACeXwAAnl9AAJ5fgACeX8AAnmBAAJ5gwACeYQAAnmFAAJ5hwACeYgAAnnHAAJ5yQACecwAAnnOAAJ50QACedIAAnnTAAJ51AACedUAAnnXAAJ52QACedoAAnnbAAJ53QACed4AAnnnAAJ56AACeeoAAnopAAJ6KwACei0AAnovAAJ6MgACejMAAno0AAJ6NQACejYAAno4AAJ6OgACejsAAno8AAJ6PgACej8AAnp+AAJ6gAACeoMAAnqFAAJ6iAACeokAAnqKAAJ6iwACeowAAnqOAAJ6kAACepEAAnqSAAJ6lAACepUAAnqiAAJ6owACeqQAAnqmAAJ65QACeucAAnrpAAJ66wACeu4AAnrvAAJ68AACevEAAnryAAJ69AACevYAAnr3AAJ6+AACevoAAnr7AAJ7OgACezwAAns/AAJ7QQACe0QAAntFAAJ7RgACe0cAAntIAAJ7SgACe0wAAntNAAJ7TgACe1AAAntRAAJ7XAACe2kAAntyAAJ7dAACe3YAAnt5AAJ7ewACe4QAAnuHAAJ7igACe40AAnuQAAJ7kgACe5kAAnvkAAJ8BwACfCcAAnxHAAJ8SQACfEsAAnxNAAJ8TwACfFIAAnxTAAJ8VAACfFcAAnxYAAJ8WgACfFsAAnxdAAJ8XwACfGAAAnxhAAJ8ZAACfGUAAnxuAAJ8ewACfIAAAnyCAAJ8hAACfIkAAnyMAAJ8jwACfJEAAny2AAJ82gACfQEAAn0lAAJ9KAACfSoAAn0sAAJ9LgACfTAAAn0yAAJ9MwACfTYAAn1DAAJ9VAACfVYAAn1YAAJ9WgACfVwAAn1eAAJ9YAACfWIAAn1kAAJ9dQACfXgAAn17AAJ9fgACfYEAAn2EAAJ9hwACfYoAAn2NAAJ9jwACfc4AAn3QAAJ90gACfdQAAn3XAAJ92AACfdkAAn3aAAJ92wACfd0AAn3fAAJ94AACfeEAAn3jAAJ95AACfiMAAn4lAAJ+JwACfikAAn4sAAJ+LQACfi4AAn4vAAJ+MAACfjIAAn40AAJ+NQACfjYAAn44AAJ+OQACfngAAn56AAJ+fQACfn8AAn6CAAJ+gwACfoQAAn6FAAJ+hgACfogAAn6KAAJ+iwACfowAAn6OAAJ+jwACfpwAAn6dAAJ+ngACfqAAAn7fAAJ+4QACfuMAAn7lAAJ+6AACfukAAn7qAAJ+6wACfuwAAn7uAAJ+8AACfvEAAn7yAAJ+9AACfvUAAn80AAJ/NgACfzgAAn86AAJ/PQACfz4AAn8/AAJ/QAACf0EAAn9DAAJ/RQACf0YAAn9HAAJ/SQACf0oAAn+JAAJ/iwACf40AAn+PAAJ/kgACf5MAAn+UAAJ/lQACf5YAAn+YAAJ/mgACf5sAAn+cAAJ/ngACf58AAn/eAAJ/4AACf+IAAn/kAAJ/5wACf+gAAn/pAAJ/6gACf+sAAn/tAAJ/7wACf/AAAn/xAAJ/8wACf/QAAoAzAAKANQACgDcAAoA5AAKAPAACgD0AAoA+AAKAPwACgEAAAoBCAAKARAACgEUAAoBGAAKASAACgEkAAoBuAAKAkgACgLkAAoDdAAKA4AACgOIAAoDkAAKA5gACgOgAAoDqAAKA6wACgO4AAoD7AAKBCgACgQwAAoEOAAKBEAACgRIAAoEUAAKBFgACgRgAAoEnAAKBKgACgS0AAoEwAAKBMwACgTYAAoE5AAKBPAACgT4AAoF9AAKBfwACgYEAAoGDAAKBhgACgYcAAoGIAAKBiQACgYoAAoGMAAKBjgACgY8AAoGQAAKBkgACgZMAAoHSAAKB1AACgdYAAoHYAAKB2wACgdwAAoHdAAKB3gACgd8AAoHhAAKB4wACgeQAAoHlAAKB5wACgegAAoInAAKCKQACgisAAoItAAKCMAACgjEAAoIyAAKCMwACgjQAAoI2AAKCOAACgjkAAoI6AAKCPAACgj0AAoJ8AAKCfgACgoEAAoKDAAKChgACgocAAoKIAAKCiQACgooAAoKMAAKCjgACgo8AAoKQAAKCkgACgpMAAoLSAAKC1AACgtYAAoLYAAKC2wACgtwAAoLdAAKC3gACgt8AAoLhAAKC4wACguQAAoLlAAKC5wACgugAAoMnAAKDKQACgysAAoMtAAKDMAACgzEAAoMyAAKDMwACgzQAAoM2AAKDOAACgzkAAoM6AAKDPAACgz0AAoN8AAKDfgACg4AAAoOCAAKDhQACg4YAAoOHAAKDiAACg4kAAoOLAAKDjQACg44AAoOPAAKDkQACg5IAAoPdAAKEAAAChCAAAoRAAAKEQgAChEQAAoRGAAKESAAChEsAAoRMAAKETQAChFAAAoRRAAKEUwAChFQAAoRWAAKEWAAChFkAAoRaAAKEXQAChF4AAoRjAAKEcAAChHUAAoR3AAKEeQAChH4AAoSBAAKEhAAChIYAAoSrAAKEzwAChPYAAoUaAAKFHQAChR8AAoUhAAKFIwAChSUAAoUnAAKFKAAChSsAAoU4AAKFSQAChUsAAoVNAAKFTwAChVEAAoVTAAKFVQAChVcAAoVZAAKFagAChW0AAoVwAAKFcwAChXYAAoV5AAKFfAAChX8AAoWCAAKFhAAChcMAAoXFAAKFxwAChckAAoXMAAKFzQAChc4AAoXPAAKF0AAChdIAAoXUAAKF1QAChdYAAoXYAAKF2QAChhgAAoYaAAKGHAAChh4AAoYhAAKGIgAChiMAAoYkAAKGJQAChicAAoYpAAKGKgAChisAAoYtAAKGLgAChm0AAoZvAAKGcgAChnQAAoZ3AAKGeAAChnkAAoZ6AAKGewAChn0AAoZ/AAKGgAAChoEAAoaDAAKGhAAChpEAAoaSAAKGkwAChpUAAobUAAKG1gAChtgAAobaAAKG3QACht4AAobfAAKG4AAChuEAAobjAAKG5QAChuYAAobnAAKG6QAChuoAAocpAAKHKwAChy0AAocvAAKHMgAChzMAAoc0AAKHNQAChzYAAoc4AAKHOgAChzsAAoc8AAKHPgAChz8AAod+AAKHgAACh4IAAoeEAAKHhwACh4gAAoeJAAKHigACh4sAAoeNAAKHjwACh5AAAoeRAAKHkwACh5QAAofTAAKH1QACh9cAAofZAAKH3AACh90AAofeAAKH3wACh+AAAofiAAKH5AACh+UAAofmAAKH6AACh+kAAogoAAKIKgACiCwAAoguAAKIMQACiDIAAogzAAKINAACiDUAAog3AAKIOQACiDoAAog7AAKIPQACiD4AAohjAAKIhwACiK4AAojSAAKI1QACiNcAAojZAAKI2wACiN0AAojfAAKI4AACiOMAAojwAAKI/wACiQEAAokDAAKJBQACiQcAAokJAAKJCwACiQ0AAokcAAKJHwACiSIAAoklAAKJKAACiSsAAokuAAKJMQACiTMAAolyAAKJdAACiXYAAol4AAKJewACiXwAAol9AAKJfgACiX8AAomBAAKJgwACiYQAAomFAAKJhwACiYgAAonHAAKJyQACicsAAonNAAKJ0AACidEAAonSAAKJ0wACidQAAonWAAKJ2AACidkAAonaAAKJ3AACid0AAoocAAKKHgACiiAAAooiAAKKJQACiiYAAoonAAKKKAACiikAAoorAAKKLQACii4AAoovAAKKMQACijIAAopxAAKKcwACinUAAop3AAKKegACinsAAop8AAKKfQACin4AAoqAAAKKggACioMAAoqEAAKKhgACiocAAorGAAKKyAACisoAAorMAAKKzwACitAAAorRAAKK0gACitMAAorVAAKK1wACitgAAorZAAKK2wACitwAAosbAAKLHQACix8AAoshAAKLJAACiyUAAosmAAKLJwACiygAAosqAAKLLAACiy0AAosuAAKLMAACizEAAotwAAKLcgACi3QAAot2AAKLeQACi3oAAot7AAKLfAACi30AAot/AAKLgQACi4IAAouDAAKLhQACi4YAAovRAAKL9AACjBQAAow0AAKMNgACjDgAAow6AAKMPAACjD8AAoxAAAKMQQACjEQAAoxFAAKMRwACjEgAAoxKAAKMTQACjE4AAoxPAAKMUgACjFMAAoxYAAKMZQACjGoAAoxsAAKMbgACjHMAAox2AAKMeQACjHsAAoygAAKMxAACjOsAAo0PAAKNEgACjRQAAo0WAAKNGAACjRoAAo0cAAKNHQACjSAAAo0tAAKNPgACjUAAAo1CAAKNRAACjUYAAo1IAAKNSgACjUwAAo1OAAKNXwACjWIAAo1lAAKNaAACjWsAAo1uAAKNcQACjXQAAo13AAKNeQACjbgAAo26AAKNvAACjb4AAo3BAAKNwgACjcMAAo3EAAKNxQACjccAAo3JAAKNygACjcsAAo3NAAKNzgACjg0AAo4PAAKOEQACjhMAAo4WAAKOFwACjhgAAo4ZAAKOGgACjhwAAo4eAAKOHwACjiAAAo4iAAKOIwACjmIAAo5kAAKOZwACjmkAAo5sAAKObQACjm4AAo5vAAKOcAACjnIAAo50AAKOdQACjnYAAo54AAKOeQACjoYAAo6HAAKOiAACjooAAo7JAAKOywACjs0AAo7PAAKO0gACjtMAAo7UAAKO1QACjtYAAo7YAAKO2gACjtsAAo7cAAKO3gACjt8AAo8eAAKPIAACjyIAAo8kAAKPJwACjygAAo8pAAKPKgACjysAAo8tAAKPLwACjzAAAo8xAAKPMwACjzQAAo9zAAKPdQACj3cAAo95AAKPfAACj30AAo9+AAKPfwACj4AAAo+CAAKPhAACj4UAAo+GAAKPiAACj4kAAo/IAAKPygACj8wAAo/OAAKP0QACj9IAAo/TAAKP1AACj9UAAo/XAAKP2QACj9oAAo/bAAKP3QACj94AApAdAAKQHwACkCEAApAjAAKQJgACkCcAApAoAAKQKQACkCoAApAsAAKQLgACkC8AApAwAAKQMgACkDMAApBYAAKQfAACkKMAApDHAAKQygACkMwAApDOAAKQ0AACkNIAApDUAAKQ1QACkNgAApDlAAKQ9AACkPYAApD4AAKQ+gACkPwAApD+AAKRAAACkQIAApERAAKRFAACkRcAApEaAAKRHQACkSAAApEjAAKRJgACkSgAApFnAAKRaQACkWsAApFtAAKRcAACkXEAApFyAAKRcwACkXQAApF2AAKReAACkXkAApF6AAKRfAACkX0AApG8AAKRvgACkcAAApHCAAKRxQACkcYAApHHAAKRyAACkckAApHLAAKRzQACkc4AApHPAAKR0QACkdIAApIRAAKSEwACkhUAApIXAAKSGgACkhsAApIcAAKSHQACkh4AApIgAAKSIgACkiMAApIkAAKSJgACkicAApJmAAKSaAACkmsAApJtAAKScAACknEAApJyAAKScwACknQAApJ2AAKSeAACknkAApJ6AAKSfAACkn0AApK8AAKSvgACksAAApLCAAKSxQACksYAApLHAAKSyAACkskAApLLAAKSzQACks4AApLPAAKS0QACktIAApMRAAKTEwACkxUAApMXAAKTGgACkxsAApMcAAKTHQACkx4AApMgAAKTIgACkyMAApMkAAKTJgACkycAApNmAAKTaAACk2oAApNsAAKTbwACk3AAApNxAAKTcgACk3MAApN1AAKTdwACk3gAApN5AAKTewACk3wAApPHAAKT6gAClAoAApQqAAKULAAClC4AApQwAAKUMgAClDUAApQ2AAKUNwAClDoAApQ7AAKUPQAClD4AApRAAAKUQgAClEMAApREAAKURwAClEgAApRNAAKUWgAClF8AApRhAAKUYwAClGgAApRrAAKUbgAClHAAApSVAAKUuQAClOAAApUEAAKVBwAClQkAApULAAKVDQAClQ8AApURAAKVEgAClRUAApUiAAKVMwAClTUAApU3AAKVOQAClTsAApU9AAKVPwAClUEAApVDAAKVVAAClVcAApVaAAKVXQAClWAAApVjAAKVZgAClWkAApVsAAKVbgACla0AApWvAAKVsQAClbMAApW2AAKVtwAClbgAApW5AAKVugAClbwAApW+AAKVvwAClcAAApXCAAKVwwAClgIAApYEAAKWBgAClggAApYLAAKWDAAClg0AApYOAAKWDwAClhEAApYTAAKWFAAClhUAApYXAAKWGAACllcAApZZAAKWXAACll4AApZhAAKWYgAClmMAApZkAAKWZQAClmcAApZpAAKWagAClmsAApZtAAKWbgAClnsAApZ8AAKWfQACln8AApa+AAKWwAAClsIAApbEAAKWxwAClsgAApbJAAKWygAClssAApbNAAKWzwACltAAApbRAAKW0wACltQAApcTAAKXFQAClxcAApcZAAKXHAAClx0AApceAAKXHwAClyAAApciAAKXJAAClyUAApcmAAKXKAAClykAApdoAAKXagACl2wAApduAAKXcQACl3IAApdzAAKXdAACl3UAApd3AAKXeQACl3oAApd7AAKXfQACl34AApe9AAKXvwACl8EAApfDAAKXxgACl8cAApfIAAKXyQACl8oAApfMAAKXzgACl88AApfQAAKX0gACl9MAApgSAAKYFAACmBYAApgYAAKYGwACmBwAApgdAAKYHgACmB8AApghAAKYIwACmCQAApglAAKYJwACmCgAAphNAAKYcQACmJgAApi8AAKYvwACmMEAApjDAAKYxQACmMcAApjJAAKYygACmM0AApjaAAKY6QACmOsAApjtAAKY7wACmPEAApjzAAKY9QACmPcAApkGAAKZCQACmQwAApkPAAKZEgACmRUAApkYAAKZGwACmR0AAplcAAKZXgACmWAAApliAAKZZQACmWYAAplnAAKZaAACmWkAAplrAAKZbQACmW4AAplvAAKZcQACmXIAApmxAAKZswACmbUAApm3AAKZugACmbsAApm8AAKZvQACmb4AApnAAAKZwgACmcMAApnEAAKZxgACmccAApoGAAKaCAACmgoAApoMAAKaDwACmhAAApoRAAKaEgACmhMAApoVAAKaFwACmhgAApoZAAKaGwACmhwAAppbAAKaXQACmmAAAppiAAKaZQACmmYAAppnAAKaaAACmmkAApprAAKabQACmm4AAppvAAKacQACmnIAApqxAAKaswACmrUAApq3AAKaugACmrsAApq8AAKavQACmr4AAprAAAKawgACmsMAAprEAAKaxgACmscAApsGAAKbCAACmwoAApsMAAKbDwACmxAAApsRAAKbEgACmxMAApsVAAKbFwACmxgAApsZAAKbGwACmxwAAptbAAKbXQACm18AApthAAKbZAACm2UAAptmAAKbZwACm2gAAptqAAKbbAACm20AAptuAAKbcAACm3EAApt6AAKbewACm30AApvAAAKb5AACnAgAApwrAAKcUgACnHIAApyZAAKcwAACnOAAAp0EAAKdKAACnSoAAp0tAAKdLwACnTEAAp0zAAKdNgACnTkAAp07AAKdPQACnUAAAp1CAAKdRAACnUcAAp1KAAKdSwACnVAAAp1dAAKdYAACnWIAAp1lAAKdaAACnWoAAp2PAAKdswACndoAAp3+AAKeAQACngMAAp4FAAKeBwACngkAAp4LAAKeDAACng8AAp4cAAKeLwACnjEAAp4zAAKeNQACnjcAAp45AAKeOwACnj0AAp4/AAKeQQACnlQAAp5XAAKeWgACnl0AAp5gAAKeYwACnmYAAp5pAAKebAACnm8AAp5xAAKesAACnrIAAp61AAKetwACnroAAp67AAKevAACnr0AAp6+AAKewAACnsIAAp7DAAKexAACnsYAAp7HAAKe0AACntEAAp7TAAKfEgACnxQAAp8WAAKfGAACnxsAAp8cAAKfHQACnx4AAp8fAAKfIQACnyMAAp8kAAKfJQACnycAAp8oAAKfZwACn2kAAp9sAAKfbgACn3EAAp9yAAKfcwACn3QAAp91AAKfdwACn3kAAp96AAKfewACn30AAp9+AAKfhwACn4gAAp+KAAKfyQACn8sAAp/NAAKfzwACn9IAAp/TAAKf1AACn9UAAp/WAAKf2AACn9oAAp/bAAKf3AACn94AAp/fAAKgHgACoCAAAqAjAAKgJQACoCgAAqApAAKgKgACoCsAAqAsAAKgLgACoDAAAqAxAAKgMgACoDQAAqA1AAKgPgACoD8AAqBBAAKggAACoIIAAqCEAAKghgACoIkAAqCKAAKgiwACoIwAAqCNAAKgjwACoJEAAqCSAAKgkwACoJUAAqCWAAKg1QACoNcAAqDaAAKg3AACoN8AAqDgAAKg4QACoOIAAqDjAAKg5QACoOcAAqDoAAKg6QACoOsAAqDsAAKg+QACoPoAAqD7AAKg/QACoTwAAqE+AAKhQAACoUIAAqFFAAKhRgACoUcAAqFIAAKhSQACoUsAAqFNAAKhTgACoU8AAqFRAAKhUgACoZEAAqGTAAKhlgACoZgAAqGbAAKhnAACoZ0AAqGeAAKhnwACoaEAAqGjAAKhpAACoaUAAqGnAAKhqAACoboAAqHHAAKhzgACodAAAqHTAAKh1gACod0AAqHgAAKh4wACoeYAAqHoAAKh/gACokkAAqJsAAKijAACoqwAAqKuAAKisAACorIAAqK0AAKitwACorgAAqK5AAKivAACor0AAqK/AAKiwAACosIAAqLEAAKixQACosYAAqLJAAKiygACos8AAqLcAAKi4QACouMAAqLlAAKi6gACou0AAqLwAAKi8gACoxcAAqM7AAKjYgACo4YAAqOJAAKjiwACo40AAqOPAAKjkQACo5MAAqOUAAKjlwACo6QAAqO1AAKjtwACo7kAAqO7AAKjvQACo78AAqPBAAKjwwACo8UAAqPWAAKj2QACo9wAAqPfAAKj4gACo+UAAqPoAAKj6wACo+4AAqPwAAKkLwACpDEAAqQzAAKkNQACpDgAAqQ5AAKkOgACpDsAAqQ8AAKkPgACpEAAAqRBAAKkQgACpEQAAqRFAAKkhAACpIYAAqSIAAKkigACpI0AAqSOAAKkjwACpJAAAqSRAAKkkwACpJUAAqSWAAKklwACpJkAAqSaAAKk2QACpNsAAqTeAAKk4AACpOMAAqTkAAKk5QACpOYAAqTnAAKk6QACpOsAAqTsAAKk7QACpO8AAqTwAAKk/QACpP4AAqT/AAKlAQACpUAAAqVCAAKlRAACpUYAAqVJAAKlSgACpUsAAqVMAAKlTQACpU8AAqVRAAKlUgACpVMAAqVVAAKlVgACpZUAAqWXAAKlmQACpZsAAqWeAAKlnwACpaAAAqWhAAKlogACpaQAAqWmAAKlpwACpagAAqWqAAKlqwACpeoAAqXsAAKl7gACpfAAAqXzAAKl9AACpfUAAqX2AAKl9wACpfkAAqX7AAKl/AACpf0AAqX/AAKmAAACpj8AAqZBAAKmQwACpkUAAqZIAAKmSQACpkoAAqZLAAKmTAACpk4AAqZQAAKmUQACplIAAqZUAAKmVQACppQAAqaWAAKmmAACppoAAqadAAKmngACpp8AAqagAAKmoQACpqMAAqalAAKmpgACpqcAAqapAAKmqgACps8AAqbzAAKnGgACpz4AAqdBAAKnQwACp0UAAqdHAAKnSQACp0sAAqdMAAKnTwACp1wAAqdrAAKnbQACp28AAqdxAAKncwACp3UAAqd3AAKneQACp4gAAqeLAAKnjgACp5EAAqeUAAKnlwACp5oAAqedAAKnnwACp94AAqfgAAKn4gACp+QAAqfnAAKn6AACp+kAAqfqAAKn6wACp+0AAqfvAAKn8AACp/EAAqfzAAKn9AACqDMAAqg1AAKoNwACqDkAAqg8AAKoPQACqD4AAqg/AAKoQAACqEIAAqhEAAKoRQACqEYAAqhIAAKoSQACqIgAAqiKAAKojAACqI4AAqiRAAKokgACqJMAAqiUAAKolQACqJcAAqiZAAKomgACqJsAAqidAAKongACqN0AAqjfAAKo4gACqOQAAqjnAAKo6AACqOkAAqjqAAKo6wACqO0AAqjvAAKo8AACqPEAAqjzAAKo9AACqTMAAqk1AAKpNwACqTkAAqk8AAKpPQACqT4AAqk/AAKpQAACqUIAAqlEAAKpRQACqUYAAqlIAAKpSQACqYgAAqmKAAKpjAACqY4AAqmRAAKpkgACqZMAAqmUAAKplQACqZcAAqmZAAKpmgACqZsAAqmdAAKpngACqd0AAqnfAAKp4QACqeMAAqnmAAKp5wACqegAAqnpAAKp6gACqewAAqnuAAKp7wACqfAAAqnyAAKp8wACqj4AAqphAAKqgQACqqEAAqqjAAKqpQACqqcAAqqpAAKqrAACqq0AAqquAAKqsQACqrIAAqq0AAKqtQACqrcAAqq6AAKquwACqrwAAqq/AAKqwAACqsUAAqrSAAKq1wACqtkAAqrbAAKq4AACquMAAqrmAAKq6AACqw0AAqsxAAKrWAACq3wAAqt/AAKrgQACq4MAAquFAAKrhwACq4kAAquKAAKrjQACq5oAAqurAAKrrQACq68AAquxAAKrswACq7UAAqu3AAKruQACq7sAAqvMAAKrzwACq9IAAqvVAAKr2AACq9sAAqveAAKr4QACq+QAAqvmAAKsJQACrCcAAqwpAAKsKwACrC4AAqwvAAKsMAACrDEAAqwyAAKsNAACrDYAAqw3AAKsOAACrDoAAqw7AAKsegACrHwAAqx+AAKsgAACrIMAAqyEAAKshQACrIYAAqyHAAKsiQACrIsAAqyMAAKsjQACrI8AAqyQAAKszwACrNEAAqzUAAKs1gACrNkAAqzaAAKs2wACrNwAAqzdAAKs3wACrOEAAqziAAKs4wACrOUAAqzmAAKs8wACrPQAAqz1AAKs9wACrTYAAq04AAKtOgACrTwAAq0/AAKtQAACrUEAAq1CAAKtQwACrUUAAq1HAAKtSAACrUkAAq1LAAKtTAACrYsAAq2NAAKtjwACrZEAAq2UAAKtlQACrZYAAq2XAAKtmAACrZoAAq2cAAKtnQACrZ4AAq2gAAKtoQACreAAAq3iAAKt5AACreYAAq3pAAKt6gACresAAq3sAAKt7QACre8AAq3xAAKt8gACrfMAAq31AAKt9gACrjUAAq43AAKuOQACrjsAAq4+AAKuPwACrkAAAq5BAAKuQgACrkQAAq5GAAKuRwACrkgAAq5KAAKuSwACrooAAq6MAAKujgACrpAAAq6TAAKulAACrpUAAq6WAAKulwACrpkAAq6bAAKunAACrp0AAq6fAAKuoAACrsUAAq7pAAKvEAACrzQAAq83AAKvOQACrzsAAq89AAKvPwACr0EAAq9CAAKvRQACr1IAAq9hAAKvYwACr2UAAq9nAAKvaQACr2sAAq9tAAKvbwACr34AAq+BAAKvhAACr4cAAq+KAAKvjQACr5AAAq+TAAKvlQACr9QAAq/WAAKv2AACr9oAAq/dAAKv3gACr98AAq/gAAKv4QACr+MAAq/lAAKv5gACr+cAAq/pAAKv6gACsCkAArArAAKwLQACsC8AArAyAAKwMwACsDQAArA1AAKwNgACsDgAArA6AAKwOwACsDwAArA+AAKwPwACsH4AArCAAAKwggACsIQAArCHAAKwiAACsIkAArCKAAKwiwACsI0AArCPAAKwkAACsJEAArCTAAKwlAACsNMAArDVAAKw1wACsNkAArDcAAKw3QACsN4AArDfAAKw4AACsOIAArDkAAKw5QACsOYAArDoAAKw6QACsSgAArEqAAKxLAACsS4AArExAAKxMgACsTMAArE0AAKxNQACsTcAArE5AAKxOgACsTsAArE9AAKxPgACsX0AArF/AAKxgQACsYMAArGGAAKxhwACsYgAArGJAAKxigACsYwAArGOAAKxjwACsZAAArGSAAKxkwACsdIAArHUAAKx1gACsdgAArHbAAKx3AACsd0AArHeAAKx3wACseEAArHjAAKx5AACseUAArHnAAKx6AACsjMAArJWAAKydgACspYAArKYAAKymgACspwAArKeAAKyoQACsqIAArKjAAKypgACsqcAArKpAAKyqgACsqwAArKvAAKysAACsrEAArK0AAKytQACsroAArLHAAKyzAACss4AArLQAAKy1QACstgAArLbAAKy3QACswIAArMmAAKzTQACs3EAArN0AAKzdgACs3gAArN6AAKzfAACs34AArN/AAKzggACs48AArOgAAKzogACs6QAArOmAAKzqAACs6oAArOsAAKzrgACs7AAArPBAAKzxAACs8cAArPKAAKzzQACs9AAArPTAAKz1gACs9kAArPbAAK0GgACtBwAArQeAAK0IAACtCMAArQkAAK0JQACtCYAArQnAAK0KQACtCsAArQsAAK0LQACtC8AArQwAAK0bwACtHEAArRzAAK0dQACtHgAArR5AAK0egACtHsAArR8AAK0fgACtIAAArSBAAK0ggACtIQAArSFAAK0xAACtMYAArTJAAK0ywACtM4AArTPAAK00AACtNEAArTSAAK01AACtNYAArTXAAK02AACtNoAArTbAAK06AACtOkAArTqAAK07AACtSsAArUtAAK1LwACtTEAArU0AAK1NQACtTYAArU3AAK1OAACtToAArU8AAK1PQACtT4AArVAAAK1QQACtYAAArWCAAK1hAACtYYAArWJAAK1igACtYsAArWMAAK1jQACtY8AArWRAAK1kgACtZMAArWVAAK1lgACtdUAArXXAAK12QACtdsAArXeAAK13wACteAAArXhAAK14gACteQAArXmAAK15wACtegAArXqAAK16wACtioAArYsAAK2LgACtjAAArYzAAK2NAACtjUAArY2AAK2NwACtjkAArY7AAK2PAACtj0AArY/AAK2QAACtn8AAraBAAK2gwACtoUAAraIAAK2iQACtooAAraLAAK2jAACto4AAraQAAK2kQACtpIAAraUAAK2lQACtroAArbeAAK3BQACtykAArcsAAK3LgACtzAAArcyAAK3NAACtzYAArc3AAK3OgACt0cAArdWAAK3WAACt1oAArdcAAK3XgACt2AAArdiAAK3ZAACt3MAArd2AAK3eQACt3wAArd/AAK3ggACt4UAAreIAAK3igACt8kAArfLAAK3zQACt88AArfSAAK30wACt9QAArfVAAK31gACt9gAArfaAAK32wACt9wAArfeAAK33wACuB4AArggAAK4IgACuCQAArgnAAK4KAACuCkAArgqAAK4KwACuC0AArgvAAK4MAACuDEAArgzAAK4NAACuHMAArh1AAK4dwACuHkAArh8AAK4fQACuH4AArh/AAK4gAACuIIAAriEAAK4hQACuIYAAriIAAK4iQACuMgAArjKAAK4zAACuM4AArjRAAK40gACuNMAArjUAAK41QACuNcAArjZAAK42gACuNsAArjdAAK43gACuR0AArkfAAK5IQACuSMAArkmAAK5JwACuSgAArkpAAK5KgACuSwAArkuAAK5LwACuTAAArkyAAK5MwACuXIAArl0AAK5dgACuXgAArl7AAK5fAACuX0AArl+AAK5fwACuYEAArmDAAK5hAACuYUAArmHAAK5iAACuccAArnJAAK5ywACuc0AArnQAAK50QACudIAArnTAAK51AACudYAArnYAAK52QACudoAArncAAK53QACueYAArnnAAK56QACufYAArn3AAK5+AACufoAAroHAAK6CAACugkAAroLAAK6GAACuhkAAroaAAK6HAACuiUAAro0AAK6QQACulAAArpiAAK6dgACuo0AArqfAAK6qAACuqkAArqrAAK6uAACurkAArq6AAK6vAACusUAArrPAAK61gAAAAAAAAQCAAAAAAAAacsAAAAAAAAAAAAAAAAAArre - - - - - data - - - - PumpEvent - Undefined - 2 - PumpEvent - 1 - - - - - - userUpdatedDate - - - - Undefined - 3 - DosingDecisionObject - 1 - - - - - - programmedTempBasalRate - - - - date - - - - syncIdentifier - - - - date - - - - CachedInsulinDeliveryObject - Undefined - 4 - CachedInsulinDeliveryObject - 1 - - - - - - alarmType - - - - automaticallyIssued - - - - healthKitEligibleDate - - - - device - - - - unitString - - - - hasLoopKitOrigin - - - - trendRateValue - - - - addedDate - - - - deliveredUnits - - - - uuid - - - - foodType - - - - type - - - - provenanceIdentifier - - - - doseType - - - - title - - - - syncIdentifier - - - - raw - - - - uuid - - - - uuid - - - - absorptionTime - - - - grams - - - - startDate - - - - raw - - - - value - - - - isSuspend - - - - createdByCurrentApp - - - - userCreatedDate - - - - isDisplayOnly - - - - CachedGlucoseObject - Undefined - 3 - CachedGlucoseObject - 1 - - - - - - date - - - - endDate - - - - startDate - - - - LoopKit.CachedCarbObjectv3EntityMigrationPolicy - CachedCarbObject - Undefined - 5 - CachedCarbObject - 1 - - - - - - modificationCounter - - - - syncVersion - - - - duration - - - - provenanceIdentifier - - - - insulinType - - - - volume - - - - wasUserEntered - - - - operation - - - - userDeletedDate - - - - modificationCounter - - - - DeletedCarbObject - LoopKit.DeletedCarbObjectv3EntityMigrationPolicy - CachedCarbObject - DeletedCarbObjectToCachedCarbObject - Undefined - 6 - 1 - - - - - - absorptionTime - - - - addedDate - - - - anchorKey - - - - createdByCurrentApp - - - - foodType - - - - grams - - - - operation - - - - provenanceIdentifier - - - - startDate - - - - supercededDate - - - - syncIdentifier - - - - syncVersion - - - - userCreatedDate - - - - userDeletedDate - - - - userUpdatedDate - - - - uuid - - - - - - - - - - CachedInsulinDeliveryObject - Undefined - 0 - CachedInsulinDeliveryObject - 1 - - - - - - CachedCarbObject - Undefined - 0 - CachedCarbObject - 1 - - - - - - Undefined - 1 - SettingsObject - 1 - - - - - - date - - - - modificationCounter - - - - data - - - - Reservoir - Undefined - 0 - Reservoir - 1 - - - - - - CachedGlucoseObject - Undefined - 0 - CachedGlucoseObject - 1 - - - - - - date - - - - data - - - - modificationCounter - - - - Undefined - 2 - DosingDecisionObject - 1 - - - - - - PumpEvent - Undefined - 0 - PumpEvent - 1 - - - - - - date - - - - CachedInsulinDeliveryObject - Undefined - 0 - CachedInsulinDeliveryObject - 1 - - - - - - modificationCounter - - - - date - - - - wasProgrammedByPumpUI - - - - modificationCounter - - - - wasProgrammedByPumpUI - - - - data - - - - Undefined - 2 - DosingDecisionObject - 1 - - - - - - PumpEvent - Undefined - 0 - PumpEvent - 1 - - - - - - Undefined - 1 - SettingsObject - 1 - - - - - - CachedCarbObject - Undefined - 0 - CachedCarbObject - 1 - - - - - - Reservoir - Undefined - 0 - Reservoir - 1 - - - - - - CachedGlucoseObject - Undefined - 0 - CachedGlucoseObject - 1 - - - - - - data - - - \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKit/Persistence/Modelv3EntityMigrationPolicy.swift b/Dependencies/LoopKit/LoopKit/Persistence/Modelv3EntityMigrationPolicy.swift deleted file mode 100644 index de9b9f7ce..000000000 --- a/Dependencies/LoopKit/LoopKit/Persistence/Modelv3EntityMigrationPolicy.swift +++ /dev/null @@ -1,113 +0,0 @@ -// -// Modelv3EntityMigrationPolicy.swift -// LoopKit -// -// Created by Darin Krauss on 8/24/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation -import CoreData -import HealthKit - -class CachedCarbObjectv3EntityMigrationPolicy: NSEntityMigrationPolicy { - override func createDestinationInstances(forSource sourceInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws { - - // Perform lightweight migration - try super.createDestinationInstances(forSource: sourceInstance, in: mapping, manager: manager) - - // Find assigned destination instance based upon previous lightweight migration - let destinationInstance = manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sourceInstance]).first! - - // Only for Loop-specific data - if destinationInstance.createdByCurrentApp { - - // Since this is known Loop data, migrate to use correct provenance identifier - destinationInstance.provenanceIdentifier = HKSource.default().bundleIdentifier - - // Since this is known Loop data, migrate any known update operations when sync version > 1 - // Note: Default operation upon migration (according to data model) is create - if destinationInstance.syncIdentifier != nil, let syncVersion = destinationInstance.syncVersion, syncVersion > 1 { - destinationInstance.operation = .update - } - } - - // If any external ID and no sync identifier, then use that with initial version - if let externalID = sourceInstance.externalID, destinationInstance.syncIdentifier == nil { - destinationInstance.syncIdentifier = externalID - destinationInstance.syncVersion = 1 - } - } -} - -class DeletedCarbObjectv3EntityMigrationPolicy: NSEntityMigrationPolicy { - override func createDestinationInstances(forSource sourceInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws { - - // Create new destination instance from scratch since the source entity is being deleted - let destinationInstance = NSEntityDescription.insertNewObject(forEntityName: mapping.destinationEntityName!, into: manager.destinationContext) - - // Migrate from DeletedCarbObject to CachedCarbObject - destinationInstance.createdByCurrentApp = false // Since we don't know from DeletedCarbObject, it is safest to assume not - destinationInstance.startDate = sourceInstance.startDate - destinationInstance.uuid = sourceInstance.uuid - destinationInstance.syncIdentifier = sourceInstance.syncIdentifier - destinationInstance.syncVersion = sourceInstance.syncVersion - destinationInstance.operation = .delete - destinationInstance.anchorKey = sourceInstance.modificationCounter // Manually retain modification counter in anchor key - - // If any external ID and no sync identifier, then use that with initial version - if let externalID = sourceInstance.externalID, sourceInstance.syncIdentifier == nil { - destinationInstance.syncIdentifier = externalID - destinationInstance.syncVersion = 1 - } - - // Associate new destination instance with the previous source instance - manager.associate(sourceInstance: sourceInstance, withDestinationInstance: destinationInstance, for: mapping) - } -} - -fileprivate extension NSManagedObject { - var createdByCurrentApp: Bool { - get { value(forKey: "createdByCurrentApp") as! Bool == true } - set { setValue(newValue, forKey: "createdByCurrentApp") } - } - - var startDate: Date { - get { value(forKey: "startDate") as! Date } - set { setValue(newValue, forKey: "startDate") } - } - - var uuid: UUID? { - get { value(forKey: "uuid") as? UUID } - set { setValue(newValue, forKey: "uuid") } - } - - var provenanceIdentifier: String? { - get { value(forKey: "provenanceIdentifier") as? String } - set { setValue(newValue, forKey: "provenanceIdentifier") } - } - - var syncIdentifier: String? { - get { value(forKey: "syncIdentifier") as? String } - set { setValue(newValue, forKey: "syncIdentifier") } - } - - var syncVersion: Int? { - get { (value(forKey: "syncVersion") as? Int32).map { Int($0) } } - set { setValue(newValue.map { Int32($0) }, forKey: "syncVersion") } - } - - var operation: Operation { - get { Operation(rawValue: Int(value(forKey: "operation") as! Int32))! } - set { setValue(Int32(newValue.rawValue), forKey: "operation") } - } - - var anchorKey: Int64 { - get { value(forKey: "anchorKey") as! Int64 } - set { setValue(newValue, forKey: "anchorKey") } - } - - var externalID: String? { value(forKey: "externalID") as? String } - - var modificationCounter: Int64 { value(forKey: "modificationCounter") as! Int64 } -} diff --git a/Dependencies/LoopKit/LoopKit/Persistence/NSManagedObjectContext.swift b/Dependencies/LoopKit/LoopKit/Persistence/NSManagedObjectContext.swift deleted file mode 100644 index d465e9c81..000000000 --- a/Dependencies/LoopKit/LoopKit/Persistence/NSManagedObjectContext.swift +++ /dev/null @@ -1,105 +0,0 @@ -// -// NSManagedObjectContext.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import CoreData - - -extension NSManagedObjectContext { - - /// Deletes all saved objects matching the specified type and predicate from the context's persistent store - /// - /// - Parameters: - /// - type: The object type to delete - /// - predicate: The predicate to match - /// - Returns: The number of deleted objects - /// - Throws: NSBatchDeleteRequest execution errors - public func purgeObjects(of type: T.Type, matching predicate: NSPredicate? = nil) throws -> Int { - let fetchRequest: NSFetchRequest = T.fetchRequest() - fetchRequest.predicate = predicate - - let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) - deleteRequest.resultType = .resultTypeObjectIDs - - let result = try execute(deleteRequest) - guard let deleteResult = result as? NSBatchDeleteResult, - let objectIDs = deleteResult.result as? [NSManagedObjectID] - else { - return 0 - } - - if objectIDs.count > 0 { - let changes = [NSDeletedObjectsKey: objectIDs] - NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [self]) - self.refreshAllObjects() - } - - return objectIDs.count - } - - /// Deletes all saved objects returned from the specified fetch request - /// - /// - Parameters: - /// - fetchRequest: The fetch request performed to determine objects to subsequently delete - /// - Returns: The number of deleted objects - /// - Throws: Any core data error during fetch or delete - public func deleteObjects(matching fetchRequest: NSFetchRequest) throws -> Int where T: NSManagedObject { - let objects = try fetch(fetchRequest) - objects.forEach { delete($0) } - if hasChanges { - try save() - } - return objects.count - } -} - -extension NSManagedObjectContext { - - /// Returns the anchor key. The anchor key is a monotonically increasing integer - /// that auto-increments on every call to this property. The global value is stored in the first - /// peristent store associated with this context. - /// - /// - Return: The next anchor key for the persistent store associated with this context. - public var anchorKey: Int64? { modificationCounter } - - /// Returns the modification counter. The modification counter is a monotonically increasing integer - /// that auto-increments on every call to this property. The global value is stored in the first - /// peristent store associated with this context. - /// - /// - Return: The next modification counter for the persistent store associated with this context. - public var modificationCounter: Int64? { - get { - guard let persistentStoreCoordinator = persistentStoreCoordinator, - let persistentStore = persistentStoreCoordinator.persistentStores.first - else { - return nil - } - - return NSManagedObjectContext.modificationCounterLock.withLock { - var metadata = persistentStoreCoordinator.metadata(for: persistentStore) - - var modificationCounter: Int64 - if let previousModificationCounter = metadata[NSManagedObjectContext.modificationCounterMetadataKey] as? Int64 { - modificationCounter = previousModificationCounter + 1 - } else { - modificationCounter = 1 - } - - metadata[NSManagedObjectContext.modificationCounterMetadataKey] = modificationCounter - - persistentStoreCoordinator.setMetadata(metadata, for: persistentStore) - - return modificationCounter - } - } - } - - private static let modificationCounterMetadataKey = "modificationCounter" - - private static let modificationCounterLock = UnfairLock() - -} diff --git a/Dependencies/LoopKit/LoopKit/Persistence/PersistenceController.swift b/Dependencies/LoopKit/LoopKit/Persistence/PersistenceController.swift deleted file mode 100644 index e9187b3bd..000000000 --- a/Dependencies/LoopKit/LoopKit/Persistence/PersistenceController.swift +++ /dev/null @@ -1,298 +0,0 @@ -// -// PersistenceController.swift -// Naterade -// -// Inspired by http://martiancraft.com/blog/2015/03/core-data-stack/ -// - -import CoreData -import os.log -import HealthKit - - - -public protocol PersistenceControllerDelegate: AnyObject { - /// Informs the delegate that a save operation will start, so it can start a background task on its behalf - /// - /// - Parameter controller: The persistence controller - func persistenceControllerWillSave(_ controller: PersistenceController) - - /// Informs the delegate that a save operation did end - /// - /// - Parameters: - /// - controller: The persistence controller - /// - error: An error describing why the save failed - func persistenceControllerDidSave(_ controller: PersistenceController, error: PersistenceController.PersistenceControllerError?) -} - - -/// Provides a Core Data persistence stack for the LoopKit data model -public final class PersistenceController { - - public enum PersistenceControllerError: Error, LocalizedError { - case configurationError(String) - case coreDataError(NSError) - - public var errorDescription: String? { - switch self { - case .configurationError(let description): - return description - case .coreDataError(let error): - return error.localizedDescription - } - } - - public var recoverySuggestion: String? { - switch self { - case .configurationError: - return "Unrecoverable Error" - case .coreDataError(let error): - return error.localizedRecoverySuggestion - } - } - } - - internal let managedObjectContext: NSManagedObjectContext - - public let isReadOnly: Bool - - public let directoryURL: URL - - public weak var delegate: PersistenceControllerDelegate? - - private let log = OSLog(category: "PersistenceController") - - private var queue = DispatchQueue(label: "com.loopkit.PersistenceController", qos: .utility) - - // MARK: - ReadyState - private enum ReadyState { - case waiting - case ready - case error(PersistenceControllerError) - } - - public typealias ReadyCallback = (_ error: PersistenceControllerError?) -> Void - - private var readyCallbacks: [ReadyCallback] = [] - - private var readyState: ReadyState = .waiting - - func onReady(_ callback: @escaping ReadyCallback) { - queue.async { - switch self.readyState { - case .waiting: - self.readyCallbacks.append(callback) - case .ready: - callback(nil) - case .error(let error): - callback(error) - } - } - } - - /// Initializes a new persistence controller in the specified directory - /// - /// - Parameters: - /// - directoryURL: The directory where the SQLlite database is stored. Will be created with no file protection if it doesn't exist. - /// - model: The managed object model definition - /// - isReadOnly: Whether the persistent store is intended to be read-only. Read-only stores will observe cross-process notifications and reload all contexts when data changes. Writable stores will post these notifications. - public init( - directoryURL: URL, - isReadOnly: Bool = false - ) { - - guard let url = LocalBundle.main.url(forResource: "Model", withExtension: "momd") else { - log.error("Could not find Model url") - fatalError("Unable to find Model url") - } - - guard let model = NSManagedObjectModel(contentsOf: url) else { - log.error("Could not open Model url at %@", String(describing: url)) - fatalError("Unable to find Model url") - } - - managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) - managedObjectContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy - managedObjectContext.automaticallyMergesChangesFromParent = true - - self.directoryURL = directoryURL - self.isReadOnly = isReadOnly - - initializeStack(inDirectory: directoryURL, model: model) - } - - @discardableResult - func save(_ completion: ((_ error: PersistenceControllerError?) -> Void)? = nil) -> PersistenceControllerError? { - var error: PersistenceControllerError? - - self.managedObjectContext.performAndWait { - guard self.managedObjectContext.hasChanges else { - completion?(nil) - return - } - - error = self.saveInternal() - completion?(error) - } - - return error - } - - // Should only be called from managedObjectContext thread - internal func saveInternal() -> PersistenceControllerError? { - guard !self.isReadOnly else { - return nil - } - - do { - delegate?.persistenceControllerWillSave(self) - try self.managedObjectContext.save() - delegate?.persistenceControllerDidSave(self, error: nil) - return nil - } catch let saveError as NSError { - self.log.error("Error while saving context: %{public}@", saveError) - delegate?.persistenceControllerDidSave(self, error: .coreDataError(saveError)) - return .coreDataError(saveError) - } - } - - - // Should only be called on managedObjectContext thread - func updateMetadata(key: String, value: Any?) { - if let coordinator = self.managedObjectContext.persistentStoreCoordinator, let store = coordinator.persistentStores.first { - var metadata = coordinator.metadata(for: store) - metadata[key] = value - coordinator.setMetadata(metadata, for: store) - } - } - - // Should only be called on managedObjectContext thread - func fetchMetadata(key: String) -> Any? { - if let coordinator = self.managedObjectContext.persistentStoreCoordinator, let store = coordinator.persistentStores.first { - let metadata = coordinator.metadata(for: store) - return metadata[key] - } else { - return nil - } - } - - // MARK: - - - private func initializeStack(inDirectory directoryURL: URL, model: NSManagedObjectModel) { - managedObjectContext.perform { - var error: PersistenceControllerError? - - let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) - - self.managedObjectContext.persistentStoreCoordinator = coordinator - - do { - try FileManager.default.ensureDirectoryExists(at: directoryURL, with: FileProtectionType.completeUntilFirstUserAuthentication) - } catch { - // Ignore errors here, let Core Data explain the problem - } - - let storeURL = directoryURL.appendingPathComponent("Model.sqlite") - - var options: [AnyHashable : Any] = [ - NSMigratePersistentStoresAutomaticallyOption: true, - NSInferMappingModelAutomaticallyOption: true - ] - -#if os(iOS) - options[NSPersistentStoreFileProtectionKey] = FileProtectionType.completeUntilFirstUserAuthentication -#endif - - do { - try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, - configurationName: nil, - at: storeURL, - options: options - ) - } catch let storeError as NSError { - self.log.error("Failed to initialize persistenceController: %{public}@", storeError) - error = .coreDataError(storeError) - } - - self.queue.async { - if let error = error { - self.readyState = .error(error) - } else { - self.readyState = .ready - } - - for callback in self.readyCallbacks { - callback(error) - } - - self.readyCallbacks = [] - } - } - } -} - - -extension PersistenceController: CustomDebugStringConvertible { - public var debugDescription: String { - return [ - "## PersistenceController", - "* isReadOnly: \(isReadOnly)", - "* directoryURL: \(directoryURL)", - "* persistenceStoreCoordinator: \(String(describing: managedObjectContext.persistentStoreCoordinator))", - ].joined(separator: "\n") - } -} - - -// MARK: - Anchor store/fetch helpers - -extension PersistenceController { - func storeAnchor(_ anchor: HKQueryAnchor?, key: String) { - managedObjectContext.perform { - let encoded: Data? - if let anchor = anchor { - encoded = try? NSKeyedArchiver.archivedData(withRootObject: anchor, requiringSecureCoding: true) - if encoded == nil { - self.log.error("Encoding anchor %{public} failed.", String(describing: anchor)) - } - } else { - encoded = nil - } - self.updateMetadata(key: key, value: encoded) - let _ = self.saveInternal() - } - } - - func fetchAnchor(key: String, completion: @escaping (HKQueryAnchor?) -> Void) { - managedObjectContext.perform { - let value = self.fetchMetadata(key: key) - if let encoded = value as? Data { - let anchor = try? NSKeyedUnarchiver.unarchivedObject(ofClass: HKQueryAnchor.self, from: encoded) - if anchor == nil { - self.log.error("Decoding anchor from %{public}@ failed.", String(describing: encoded)) - } - completion(anchor) - } else { - self.log.error("Anchor metadata invalid %{public}@.", String(describing: value)) - completion(nil) - } - } - } -} - -fileprivate extension FileManager { - - func ensureDirectoryExists(at url: URL, with protectionType: FileProtectionType? = nil) throws { - try createDirectory(at: url, withIntermediateDirectories: true, attributes: protectionType.map { [FileAttributeKey.protectionKey: $0 ] }) - guard let protectionType = protectionType else { - return - } - // double check protection type - var attrs = try attributesOfItem(atPath: url.path) - if attrs[FileAttributeKey.protectionKey] as? FileProtectionType != protectionType { - attrs[FileAttributeKey.protectionKey] = protectionType - try setAttributes(attrs, ofItemAtPath: url.path) - } - } - -} diff --git a/Dependencies/LoopKit/LoopKit/Prescription.swift b/Dependencies/LoopKit/LoopKit/Prescription.swift deleted file mode 100644 index 2e300eb85..000000000 --- a/Dependencies/LoopKit/LoopKit/Prescription.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// Prescription.swift -// LoopKit -// -// Created by Rick Pasetto on 7/22/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - -public protocol Prescription { - /// Date prescription was prescribed - var datePrescribed: Date { get } - /// Name of clinician prescribing - var providerName: String { get } -} diff --git a/Dependencies/LoopKit/LoopKit/QuantityFormatter.swift b/Dependencies/LoopKit/LoopKit/QuantityFormatter.swift deleted file mode 100644 index b374f8281..000000000 --- a/Dependencies/LoopKit/LoopKit/QuantityFormatter.swift +++ /dev/null @@ -1,342 +0,0 @@ -// -// QuantityFormatter.swift -// LoopKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - - -/// Formats unit quantities as localized strings -open class QuantityFormatter { - - public init() { - } - - public convenience init(for unit: HKUnit) { - self.init() - setPreferredNumberFormatter(for: unit) - } - - /// The unit style determines how the unit strings are abbreviated, and spacing between the value and unit - open var unitStyle: Formatter.UnitStyle = .medium { - didSet { - if hasMeasurementFormatter { - measurementFormatter.unitStyle = unitStyle - } - - if hasMassFormatter { - massFormatter.unitStyle = unitStyle - } - } - } - - open var locale: Locale = Locale.current { - didSet { - if hasNumberFormatter { - numberFormatter.locale = locale - } - - if hasMeasurementFormatter { - measurementFormatter.locale = locale - } - } - } - - /// Updates `numberFormatter` configuration for the specified unit - /// - /// - Parameter unit: The unit - open func setPreferredNumberFormatter(for unit: HKUnit) { - numberFormatter.numberStyle = .decimal - numberFormatter.minimumFractionDigits = unit.preferredFractionDigits - numberFormatter.maximumFractionDigits = unit.maxFractionDigits - } - - private var hasNumberFormatter = false - - /// The formatter used for the quantity values - open private(set) lazy var numberFormatter: NumberFormatter = { - hasNumberFormatter = true - - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.locale = self.locale - return formatter - }() - - private var hasMeasurementFormatter = false - - /// MeasurementFormatter is used for gram measurements, mg/dL units, and mmol/L units. - /// It does not properly handle glucose measurements, as it changes unit scales: 100 mg/dL -> 1 g/L - private lazy var measurementFormatter: MeasurementFormatter = { - hasMeasurementFormatter = true - - let formatter = MeasurementFormatter() - formatter.unitOptions = [.providedUnit] - formatter.numberFormatter = self.numberFormatter - formatter.locale = self.locale - formatter.unitStyle = self.unitStyle - return formatter - }() - - private var hasMassFormatter = false - - /// MassFormatter properly creates unit strings for grams in .short/.medium style as "g", where MeasurementFormatter uses "gram"/"grams" - private lazy var massFormatter: MassFormatter = { - hasMassFormatter = true - - let formatter = MassFormatter() - formatter.numberFormatter = self.numberFormatter - formatter.unitStyle = self.unitStyle - return formatter - }() - - /// When `avoidLineBreaking` is true, the formatter avoids unit strings or values and their unit strings being split by a line break. - open var avoidLineBreaking: Bool = true - - /// Formats a quantity and unit as a localized string - /// - /// - Parameters: - /// - quantity: The quantity - /// - unit: The unit. An exception is thrown if `quantity` is not compatible with the unit. - /// - includeUnit: Whether or not to include the unit in the returned string - /// - Returns: A localized string, or nil if `numberFormatter` is unable to format the quantity value - open func string(from quantity: HKQuantity, for unit: HKUnit, includeUnit: Bool = true) -> String? { - let value = quantity.doubleValue(for: unit) - - if !includeUnit { - return numberFormatter.string(from: value) - } - - if let foundationUnit = unit.foundationUnit, unit.usesMeasurementFormatterForMeasurement { - return measurementFormatter.string(from: Measurement(value: value, unit: foundationUnit)).avoidLineBreaking(enabled: avoidLineBreaking) - } - - // Pass 'false' for `avoidLineBreaking` because we don't want to do it twice. - return numberFormatter.string(from: value, unit: string(from: unit, forValue: value, avoidLineBreaking: false), - style: unitStyle, avoidLineBreaking: avoidLineBreaking) - } - - /// Formats a unit as a localized string - /// - /// - Parameters: - /// - unit: The unit - /// - value: An optional value for determining the plurality of the unit string - /// - Returns: A string for the unit. If no localization entry is available, the unlocalized `unitString` is returned. - open func string(from unit: HKUnit, forValue value: Double = 10, avoidLineBreaking: Bool? = nil) -> String { - let avoidLineBreaking = avoidLineBreaking ?? self.avoidLineBreaking - if let string = unit.localizedUnitString(in: unitStyle, singular: abs(1.0 - value) < .ulpOfOne, avoidLineBreaking: avoidLineBreaking) { - return string - } - - let string: String - if unit.usesMassFormatterForUnitString { - string = massFormatter.unitString(fromValue: value, unit: HKUnit.massFormatterUnit(from: unit)) - } else if let foundationUnit = unit.foundationUnit { - string = measurementFormatter.string(from: foundationUnit) - } else { - // Fallback, unlocalized - string = unit.unitString - } - - return string.avoidLineBreaking(enabled: avoidLineBreaking) - } -} - -public extension HKQuantity { - func doubleValue(for unit: HKUnit, withRounding: Bool) -> Double { - var value = self.doubleValue(for: unit) - if withRounding { - value = unit.round(value: value, fractionalDigits: unit.maxFractionDigits) - } - - return value - } -} - -public extension HKUnit { - var usesMassFormatterForUnitString: Bool { - return self == .gram() - } - - var usesMeasurementFormatterForMeasurement: Bool { - return self == .gram() - } - - var preferredFractionDigits: Int { - switch self { - case .millimolesPerLiter, - HKUnit.millimolesPerLiter.unitDivided(by: .internationalUnit()), - HKUnit.millimolesPerLiter.unitDivided(by: .minute()): - return 1 - default: - return 0 - } - } - - var pickerFractionDigits: Int { - switch self { - case .internationalUnit(), .internationalUnitsPerHour: - return 3 - case HKUnit.gram().unitDivided(by: .internationalUnit()): - return 1 - case .millimolesPerLiter, - HKUnit.millimolesPerLiter.unitDivided(by: .internationalUnit()), - HKUnit.millimolesPerLiter.unitDivided(by: .minute()): - return 1 - default: - return 0 - } - } - - func round(value: Double, fractionalDigits: Int) -> Double { - if fractionalDigits == 0 { - return value.rounded() - } else { - let scaleFactor = pow(10.0, Double(fractionalDigits)) - return (value * scaleFactor).rounded() / scaleFactor - } - } - - func round(value: Double) -> Double { - return roundForPreferredDigits(value: value) - } - - func roundForPreferredDigits(value: Double) -> Double { - return round(value: value, fractionalDigits: preferredFractionDigits) - } - - func roundForPicker(value: Double) -> Double { - return round(value: value, fractionalDigits: pickerFractionDigits) - } - - var maxFractionDigits: Int { - switch self { - case .internationalUnit(), .internationalUnitsPerHour: - return 3 - case HKUnit.gram().unitDivided(by: .internationalUnit()): - return 1 - default: - return preferredFractionDigits - } - } - - // Short localized unit string with unlocalized fallback - func shortLocalizedUnitString(avoidLineBreaking: Bool = true) -> String { - return localizedUnitString(in: .short, avoidLineBreaking: avoidLineBreaking) ?? - unitString.avoidLineBreaking(enabled: avoidLineBreaking) - } - - func localizedUnitString(in style: Formatter.UnitStyle, singular: Bool = false, avoidLineBreaking: Bool = true) -> String? { - - func localizedUnitStringInternal(in style: Formatter.UnitStyle, singular: Bool = false) -> String? { - if self == .internationalUnit() { - switch style { - case .short, .medium: - return LocalizedString("U", comment: "The short unit display string for international units of insulin") - case .long: - fallthrough - @unknown default: - if singular { - return LocalizedString("Unit", comment: "The long unit display string for a singular international unit of insulin") - } else { - return LocalizedString("Units", comment: "The long unit display string for international units of insulin") - } - } - } - - if self == .hour() { - switch style { - case .short, .medium: - return unitString - case .long: - fallthrough - @unknown default: - if singular { - return LocalizedString("Hour", comment: "The long unit display string for a singular hour") - } else { - return LocalizedString("Hours", comment: "The long unit display string for hours") - } - } - } - - if self == .internationalUnitsPerHour { - switch style { - case .short, .medium: - return LocalizedString("U/hr", comment: "The short unit display string for international units of insulin per hour") - case .long: - fallthrough - @unknown default: - if singular { - return LocalizedString("Unit/hour", comment: "The long unit display string for a singular international unit of insulin per hour") - } else { - return LocalizedString("Units/hour", comment: "The long unit display string for international units of insulin per hour") - } - } - } - - if self == HKUnit.millimolesPerLiter { - switch style { - case .short, .medium: - return LocalizedString("mmol/L", comment: "The short unit display string for millimoles per liter") - case .long: - break // Fallback to the MeasurementFormatter localization - @unknown default: - break - } - } - - if self == HKUnit.milligramsPerDeciliter.unitDivided(by: HKUnit.internationalUnit()) { - switch style { - case .short, .medium: - return LocalizedString("mg/dL/U", comment: "The short unit display string for milligrams per deciliter per U") - case .long: - break // Fallback to the MeasurementFormatter localization - @unknown default: - break - } - } - - if self == HKUnit.millimolesPerLiter.unitDivided(by: HKUnit.internationalUnit()) { - switch style { - case .short, .medium: - return LocalizedString("mmol/L/U", comment: "The short unit display string for millimoles per liter per U") - case .long: - break // Fallback to the MeasurementFormatter localization - @unknown default: - break - } - } - - if self == HKUnit.gram().unitDivided(by: HKUnit.internationalUnit()) { - switch style { - case .short, .medium: - return LocalizedString("g/U", comment: "The short unit display string for grams per U") - case .long: - fallthrough - @unknown default: - break // Fallback to the MeasurementFormatter localization - } - } - - return nil - } - - if style != .long { - return localizedUnitStringInternal(in: style, singular: singular)?.avoidLineBreaking(enabled: avoidLineBreaking) - } else { - return localizedUnitStringInternal(in: style, singular: singular) - } - } -} - -fileprivate extension String { - func avoidLineBreaking(around string: String = "/", enabled: Bool) -> String { - guard enabled else { - return self - } - return self.replacingOccurrences(of: string, with: "\(String.wordJoiner)\(string)\(String.wordJoiner)") - } -} diff --git a/Dependencies/LoopKit/LoopKit/Resources/Base.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/Base.lproj/Localizable.strings deleted file mode 100644 index 39dc4ee39..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/Base.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Describes a certain bolus failure (1: size of the bolus in units) */ -"%1$@ U bolus failed" = "%1$@ U bolus failed"; - -/* Describes an uncertain bolus failure (1: size of the bolus in units) */ -"%1$@ U bolus may not have succeeded" = "%1$@ U bolus may not have succeeded"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Authorization Denied"; - -/* Recovery instruction for an uncertain bolus failure */ -"Check your pump before retrying" = "Check your pump before retrying"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Authorization Denied"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "This sample can be deleted from the Health app"; - -/* Generic pump error description */ -"Communication Failure" = "Communication Failure"; - -/* Generic pump error description */ -"Connection Failure" = "Connection Failure"; - -/* Generic pump error description */ -"Device Refused" = "Device Refused"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Ensure carb data exists for the specified date"; - -/* Glucose trend down */ -"Falling" = "Falling"; - -/* Glucose trend down-down */ -"Falling fast" = "Falling fast"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Falling very fast"; - -/* Glucose trend flat */ -"Flat" = "Flat"; - -/* The short unit display string for grams per U */ -"g/U" = "g/U"; - -/* Generic pump error description */ -"Invalid Configuration" = "Invalid Configuration"; - -/* Recovery instruction for a certain bolus failure */ -"It is safe to retry" = "It is safe to retry"; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/U"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/U"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Needs Attention"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "No values found"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Please re-enable sharing in Health"; - -/* Glucose trend up */ -"Rising" = "Rising"; - -/* Glucose trend up-up */ -"Rising fast" = "Rising fast"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Rising very fast"; - -/* The short unit display string for international units of insulin */ -"U" = "U"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "U/hr"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Unit"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Unit/hour"; - -/* The long unit display string for international units of insulin */ -"Units" = "Units"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Units/hour"; diff --git a/Dependencies/LoopKit/LoopKit/Resources/ar.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/ar.lproj/Localizable.strings deleted file mode 100644 index 71b003f50..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/ar.lproj/Localizable.strings +++ /dev/null @@ -1,43 +0,0 @@ -/* Title text for basal rates */ -"Basal Rates" = "الضخ المستمر"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "معاملات الكارب"; - -/* Title text for glucose target range */ -"Correction Range" = "نطاق التصحيح"; - -/* Title text for delivery limits */ -"Delivery Limits" = "حدود الضخ"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "نوع الأنسولين"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "حساسية الأنسولين"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* Sensor state description for the valid state */ -"OK" = "موافق"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Pre-Meal"; - -/* The short unit display string for international units of insulin */ -"U" = "وحدة"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "وحدة لكل ساعة"; - -/* Title for workout mode */ -"Workout" = "التمارين"; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/cs.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/cs.lproj/Localizable.strings deleted file mode 100644 index 2c2c9053b..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/cs.lproj/Localizable.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Title text for basal rates */ -"Basal Rates" = "Úrovně bazálu"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Limity podávání"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* Title for suspend dose type */ -"Suspended" = "Pozastaveno"; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/da.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/da.lproj/Localizable.strings deleted file mode 100644 index 12418864b..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/da.lproj/Localizable.strings +++ /dev/null @@ -1,267 +0,0 @@ -/* Format for correction range override therapy setting card */ -"%@ Range" = "%@ område"; - -/* Descriptive format string for glucose safety limit (1: app name) */ -"%1$@ will deliver basal and recommend bolus insulin only if your glucose is predicted to be above this limit for the next three hours." = "%1$@ vil kun afgive basal og anbefale bolus, hvis blodsukkeret forventes at være over denne grænse i de næste tre timer."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"A value you have entered is higher than what is typically recommended for most people." = "En værdi, du har angivet, er højere end den, der typisk anbefales til de fleste."; - -/* Descriptive text for guardrail low value warning for schedule interface */ -"A value you have entered is lower than what is typically recommended for most people." = "En værdi, du har angivet, er lavere end den, der typisk anbefales til de fleste."; - -/* Brand name for afrezza insulin type - Title for Afrezza insulin type */ -"Afrezza" = "Afrezza"; - -/* Description for afrezza insulin type */ -"Afrezza is an ultra rapid-acting mealtime insulin that is breathed in through your lungs using an oral inhaler and made by MannKind" = "Afrezza er en ultrahurtigt virkende måltidsinsulin, som indåndes gennem lungerne ved hjælp af en oral inhalator og fremstilles af MannKind."; - -/* Brand name for apidra insulin type */ -"Apidra" = "Apidra"; - -/* Title for Apidra insulin type */ -"Apidra (insulin glulisine)" = "Apidra (insulin glulisin)"; - -/* Description for apidra insulin type */ -"Apidra (insulin glulisine) is a rapid-acting insulin made by Sanofi-aventis " = "Apidra (insulin glulisine) er en hurtigtvirkende insulin fremstillet af Sanofi-aventis "; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Tilladelse nægtet"; - -/* Title for basal dose type */ -"Basal" = "Basal"; - -/* Title text for basal rates */ -"Basal Rates" = "Basalrater"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Kulhydratforhold"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Tilladelse nægtet"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Dette eksempel kan slettes fra appen Sundhed"; - -/* Generic pump error description */ -"Communication Failure" = "Kommunikationsfejl"; - -/* Failure reason for uncertain delivery */ -"Communications interrupted during insulin delivery command." = "Kommunikation afbrudt under insulinafgivelse (kommando)."; - -/* Generic pump error description */ -"Connection Failure" = "Forbindelsesfejl"; - -/* Title text for glucose target range */ -"Correction Range" = "Korrektionsområde"; - -/* Descriptive text for glucose target range (1: app name) */ -"Correction Range is the glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin and helping you calculate your boluses." = "Korrektionsområdet er det blodsukkerinterval som du vil have %1$@ til at sigte efter, når din basal justeres og hjælper dig med at beregne bolus."; - -/* Description of critical software update needed */ -"Critical Update" = "Kritisk opdatering"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Insulingrænser"; - -/* Generic pump error description */ -"Device Refused" = "Enhed nægtet"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Sørg for, at kulhydratdata findes for den angivne dato"; - -/* Glucose trend down */ -"Falling" = "Falder"; - -/* Glucose trend down-down */ -"Falling fast" = "Falder hurtigt"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Falder meget hurtigt"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Description for fiasp insulin type */ -"Fiasp is a mealtime insulin aspart formulation with the addition of nicotinamide (vitamin B3) made by Novo Nordisk" = "Fiasp er et måltidsinsulin aspart med tilsætning af nicotinamid (vitamin B3) fremstillet af Novo Nordisk"; - -/* Glucose trend flat */ -"Flat" = "Flad"; - -/* Descriptive text for fast acting insulin model (1: app name) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from different models for the peak activity." = "For hurtigt virkende insulin, %1$@ antager det arbejder aktivt i 6 timer. Du kan vælge mellem forskellige modeller til spidsbelastningsaktiviteten."; - -/* The short unit display string for grams per U */ -"g/U" = "g/E"; - -/* Title text for glucose safety limit */ -"Glucose Safety Limit" = "Sikkerhedsgrænse for blodsukker"; - -/* The long unit display string for a singular hour */ -"Hour" = "Time"; - -/* The long unit display string for hours */ -"Hours" = "Timer"; - -/* Brand name for humalog insulin type */ -"Humalog" = "Humalog"; - -/* Title for Humalog insulin type */ -"Humalog (insulin lispro)" = "Humalog (insulin lispro)"; - -/* Description for humalog insulin type */ -"Humalog (insulin lispro) is a rapid-acting insulin made by Eli Lilly" = "Humalog (insulin lispro) er et hurtigtvirkende insulin fremstillet af Eli Lilly"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Insulinmodel"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Insulinfølsomheder"; - -/* Generic pump error description */ -"Invalid Configuration" = "Forkert indstilling"; - -/* Brand name for lyumjev insulin type - Title for Lyumjev insulin type */ -"Lyumjev" = "Lyumjev"; - -/* Description for lyumjev insulin type */ -"Lyumjev is a mealtime insulin lispro formulation with the addition of citrate and treprostinil made by Eli Lilly" = "Lyumjev er en måltidsinsulin lispro med tilsætning af citrat og treprostinil fremstillet af Eli Lilly"; - -/* Recovery suggestion for uncertain delivery */ -"Make sure your pump is within communication range of your phone." = "Sørg for, at din pumpe er tæt på din telefon."; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Maksimal basalrate"; - -/* Descriptive text for maximum basal rate (1: app name) */ -"Maximum Basal Rate is the highest temporary basal rate %1$@ is allowed to set." = "Maksimal basalrate er den højeste midlertidige basalhastighed, som %1$@ har lov til at indstille."; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Maksimal bolus"; - -/* Descriptive text for maximum bolus */ -"Maximum Bolus is the highest bolus amount you can deliver at one time to cover carbs or bring down high glucose." = "Maksimal bolus er den højeste bolus mængde, du kan afgive på én gang, i forbindelse med indtastning af kulhydrater eller en korrektionsbolus."; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/E"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/E"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Handling påkrævet"; - -/* Description of no software update needed */ -"No Update" = "Ingen opdatering"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "Ingen værdier fundet"; - -/* Brand name for novolog insulin type */ -"Novolog" = "Novolog"; - -/* Title for Novolog insulin type */ -"Novolog (insulin aspart)" = "Novolog (insulin aspart)"; - -/* Description for novolog insulin type */ -"NovoLog (insulin aspart) is a rapid-acting insulin made by Novo Nordisk" = "NovoLog (insulin aspart) er et hurtigtvirkende insulin fremstillet af Novo Nordisk"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* Descriptive text for saving settings outside the recommended range */ -"One or more of the values you have entered is outside of what is typically recommended for most people." = "En eller flere af de værdier, du har indtastet, er udenfor hvad der generelt anbefales."; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Venligst gen-aktiver deling i Sundhed"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Før-måltid"; - -/* Description of supported software update needed */ -"Recommended Update" = "Anbefalet opdatering"; - -/* Title for resume dose type */ -"Resumed" = "Genoptaget"; - -/* Glucose trend up */ -"Rising" = "Stiger"; - -/* Glucose trend up-up */ -"Rising fast" = "Stiger hurtigt"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Stiger meget hurtigt"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"Some of the values you have entered are outside of what is typically recommended for most people." = "Nogle af de værdier, du har angivet, ligger uden for det, der typisk anbefales til de fleste."; - -/* Title for suspend dose type */ -"Suspended" = "Suspenderet"; - -/* Title for temp basal dose type */ -"Temp Basal" = "Midlertidig basal"; - -/* Descriptive text for pre-meal correction range override */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Sænker midlertidigt dit blodsukker mål før et måltid for at modvirke stigning i blodsukker efter måltidet."; - -/* Descriptive text for workout correction range override */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Hæver midlertidigt dit blodsukkermål før, under eller efter fysisk aktivitet for at reducere risikoen for lavt blodsukker."; - -/* Descriptive text for guardrail high value warning */ -"The value you have entered is higher than what is typically recommended for most people." = "En værdi, du har angivet, er højere end den, der typisk anbefales til de fleste."; - -/* Descriptive text for guardrail low value warning */ -"The value you have entered is lower than what is typically recommended for most people." = "En værdi, du har angivet, er lavere end den, der typisk anbefales til de fleste."; - -/* Descriptive text for guardrail high value warning */ -"The values you have entered are outside of what is typically recommended for most people." = "Nogle af de værdier, du har angivet, ligger uden for det, der typisk anbefales til de fleste."; - -/* The short unit display string for international units of insulin */ -"U" = "E"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "E/t"; - -/* Error description for uncertain delivery */ -"Uncertain Delivery" = "Usikker indgivelse"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Enhed"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Enhed/time"; - -/* The long unit display string for international units of insulin */ -"Units" = "Enheder"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Enheder/time"; - -/* Description of informational software update needed */ -"Update Available" = "Opdatering tilgængelig"; - -/* Title for workout mode */ -"Workout" = "Motion"; - -/* Descriptive text for basal rate */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "En basalrate, er det antal af enheder i timen, som du skal bruge for at dække dit basale insulinbehov."; - -/* Descriptive text for carb ratio */ -"Your Carb Ratio is the number of grams of carbohydrates covered by one unit of insulin." = "Kulhydratforhold er antallet af kulhydrater i gram, der dækkes af én enhed insulin."; - -/* Descriptive text for insulin sensitivity */ -"Your Insulin Sensitivities refer to the drop in glucose expected from one unit of insulin." = "Insulinfølsomhed henviser til det fald i blodsukker, der forventes fra én insulinenhed."; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/de.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/de.lproj/Localizable.strings deleted file mode 100644 index 837fad9c2..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/de.lproj/Localizable.strings +++ /dev/null @@ -1,267 +0,0 @@ -/* Format for correction range override therapy setting card */ -"%@ Range" = "%@ Bereich"; - -/* Descriptive format string for glucose safety limit (1: app name) */ -"%1$@ will deliver basal and recommend bolus insulin only if your glucose is predicted to be above this limit for the next three hours." = "%1$@ gibt nur dann Basalinsulin ab und empfiehlt Bolusinsulin, wenn Dein Blutzucker voraussichtlich in den nächsten drei Stunden über diesem Grenzwert liegen wird."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"A value you have entered is higher than what is typically recommended for most people." = "Ein eingegebener Wert liegt über dem, was normalerweise für die meisten Menschen empfohlen wird."; - -/* Descriptive text for guardrail low value warning for schedule interface */ -"A value you have entered is lower than what is typically recommended for most people." = "Ein eingegebener Wert liegt unter dem, was normalerweise für die meisten Menschen empfohlen wird."; - -/* Brand name for afrezza insulin type - Title for Afrezza insulin type */ -"Afrezza" = "Afrezza"; - -/* Description for afrezza insulin type */ -"Afrezza is an ultra rapid-acting mealtime insulin that is breathed in through your lungs using an oral inhaler and made by MannKind" = "Afrezza ist ein ultraschnell wirkendes Mahlzeiteninsulin, das mit einem oralen Inhalator durch Ihre Lungen eingeatmet wird und von MannKind hergestellt wird."; - -/* Brand name for apidra insulin type */ -"Apidra" = "Apidra"; - -/* Title for Apidra insulin type */ -"Apidra (insulin glulisine)" = "Apidra (Insulinglulisin)"; - -/* Description for apidra insulin type */ -"Apidra (insulin glulisine) is a rapid-acting insulin made by Sanofi-aventis " = "Apidra (Insulinglulisin) ist ein schnell wirkendes Insulin, das von Sanofi-aventis hergestellt wird"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Autorisierung verweigert"; - -/* Title for basal dose type */ -"Basal" = "Basal"; - -/* Title text for basal rates */ -"Basal Rates" = "Basalrate"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "KH-Verhältnis"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Autorisierung verweigert"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Dieses Beispiel kann in der Health-App gelöscht werden."; - -/* Generic pump error description */ -"Communication Failure" = "Kommunikationsfehler"; - -/* Failure reason for uncertain delivery */ -"Communications interrupted during insulin delivery command." = "Die Kommunikation wurde während der Insulinabgabe unterbrochen."; - -/* Generic pump error description */ -"Connection Failure" = "Verbindungsfehler"; - -/* Title text for glucose target range */ -"Correction Range" = "Korrekturbereich"; - -/* Descriptive text for glucose target range (1: app name) */ -"Correction Range is the glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin and helping you calculate your boluses." = "Der Korrekturbereich ist der Blutzuckerbereich, den %1$@ bei der Anpassung Deines Basalinsulins anstreben und Dir bei der Berechnung der Boli helfen soll."; - -/* Description of critical software update needed */ -"Critical Update" = "Kritisches Update"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Abgabelimits"; - -/* Generic pump error description */ -"Device Refused" = "Gerät verweigert"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Stelle sicher, das die Kohlenhydrate für den ausgewählten Zeitraum eingegeben wurden"; - -/* Glucose trend down */ -"Falling" = "Fällt"; - -/* Glucose trend down-down */ -"Falling fast" = "Fällt schnell"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Fällt sehr schnell"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Description for fiasp insulin type */ -"Fiasp is a mealtime insulin aspart formulation with the addition of nicotinamide (vitamin B3) made by Novo Nordisk" = "Fiasp ist eine von Novo Nordisk hergestellte Insulin aspart-Variante zur Mahlzeit mit dem Zusatz von Nicotinamid (Vitamin B3)."; - -/* Glucose trend flat */ -"Flat" = "Gleichbleibend"; - -/* Descriptive text for fast acting insulin model (1: app name) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from different models for the peak activity." = "Bei schnell wirkendem Insulin geht %1$@ davon aus, dass es 6 Stunden lang wirkt. Du kannst aus verschiedenen Modellen für die Spitzenaktivität wählen."; - -/* The short unit display string for grams per U */ -"g/U" = "g/IE"; - -/* Title text for glucose safety limit */ -"Glucose Safety Limit" = "Blutzuckersicherheitsgrenze"; - -/* The long unit display string for a singular hour */ -"Hour" = "Stunde"; - -/* The long unit display string for hours */ -"Hours" = "Stunden"; - -/* Brand name for humalog insulin type */ -"Humalog" = "Humalog"; - -/* Title for Humalog insulin type */ -"Humalog (insulin lispro)" = "Humalog (Insulin Lispro)"; - -/* Description for humalog insulin type */ -"Humalog (insulin lispro) is a rapid-acting insulin made by Eli Lilly" = "Humalog (Insulin Lispro) ist ein schnell wirkendes Insulin, das von Eli Lilly hergestellt wird"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Insulin-Modell"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Insulinempfindlichkeit"; - -/* Generic pump error description */ -"Invalid Configuration" = "Fehlerhafte Konfiguration"; - -/* Brand name for lyumjev insulin type - Title for Lyumjev insulin type */ -"Lyumjev" = "Lyumjev"; - -/* Description for lyumjev insulin type */ -"Lyumjev is a mealtime insulin lispro formulation with the addition of citrate and treprostinil made by Eli Lilly" = "Lyumjev ist eine Insulin-Lispro-Variante zur Mahlzeit mit dem Zusatz von Citrat und Treprostinil, hergestellt von Eli Lilly"; - -/* Recovery suggestion for uncertain delivery */ -"Make sure your pump is within communication range of your phone." = "Stelle sicher, dass sich Deine Pumpe in Kommunikationsreichweite Deines Telefons befindet."; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Maximale Basalrate"; - -/* Descriptive text for maximum basal rate (1: app name) */ -"Maximum Basal Rate is the highest temporary basal rate %1$@ is allowed to set." = "Die maximale Basalrate ist die höchste temporäre Basalrate, die %1$@ einstellen darf."; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Maximaler Bolus"; - -/* Descriptive text for maximum bolus */ -"Maximum Bolus is the highest bolus amount you can deliver at one time to cover carbs or bring down high glucose." = "Maximaler Bolus ist die höchste Bolusmenge, die Du auf einmal abgeben kannst, um Kohlenhydrate abzudecken oder hohe Blutzuckerwerte zu senken."; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/IE"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/IE"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Erfordert Aufmerksamkeit"; - -/* Description of no software update needed */ -"No Update" = "Kein Update"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "Keine Werte gefunden"; - -/* Brand name for novolog insulin type */ -"Novolog" = "Novolog"; - -/* Title for Novolog insulin type */ -"Novolog (insulin aspart)" = "Novolog (Insulin Aspart)"; - -/* Description for novolog insulin type */ -"NovoLog (insulin aspart) is a rapid-acting insulin made by Novo Nordisk" = "NovoLog (Insulin Aspart) ist ein schnell wirkendes Insulin von Novo Nordisk"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* Descriptive text for saving settings outside the recommended range */ -"One or more of the values you have entered is outside of what is typically recommended for most people." = "Mindestens einer der eingegebenen Werte liegt außerhalb dessen, was normalerweise für die meisten Menschen empfohlen wird."; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Bitte aktiviere das Teilen in HealthKit erneut"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Vor dem Essen"; - -/* Description of supported software update needed */ -"Recommended Update" = "Empfohlenes Update"; - -/* Title for resume dose type */ -"Resumed" = "Wiederaufgenommen"; - -/* Glucose trend up */ -"Rising" = "Steigt"; - -/* Glucose trend up-up */ -"Rising fast" = "Steigt schnell"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Steigt sehr schnell"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"Some of the values you have entered are outside of what is typically recommended for most people." = "Einige der eingegebenen Werte liegen außerhalb dessen, was normalerweise für die meisten Menschen empfohlen wird."; - -/* Title for suspend dose type */ -"Suspended" = "Unterbrochen"; - -/* Title for temp basal dose type */ -"Temp Basal" = "Temporäre Basalrate"; - -/* Descriptive text for pre-meal correction range override */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Senke Deinen Blutzuckerziel vor einer Mahlzeit vorübergehend ab, um Blutzuckerspitzen nach der Mahlzeit auszugleichen."; - -/* Descriptive text for workout correction range override */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Erhöhe Dein Blutzuckerziel vorübergehend vor, während oder nach körperlicher Aktivität, um das Risiko von Ereignissen mit niedrigem Blutzucker zu verringern."; - -/* Descriptive text for guardrail high value warning */ -"The value you have entered is higher than what is typically recommended for most people." = "Der eingegebene Wert liegt über dem, was normalerweise für die meisten Menschen empfohlen wird."; - -/* Descriptive text for guardrail low value warning */ -"The value you have entered is lower than what is typically recommended for most people." = "Der eingegebene Wert liegt unter dem, was normalerweise für die meisten Menschen empfohlen wird."; - -/* Descriptive text for guardrail high value warning */ -"The values you have entered are outside of what is typically recommended for most people." = "Die eingegebenen Werte liegen außerhalb der für die meisten Menschen empfohlenen Werte."; - -/* The short unit display string for international units of insulin */ -"U" = "IE"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "IE/h"; - -/* Error description for uncertain delivery */ -"Uncertain Delivery" = "Unsichere Abgabe"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Einheit"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Einheit/Std."; - -/* The long unit display string for international units of insulin */ -"Units" = "Einheiten"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Einheiten/Stunde"; - -/* Description of informational software update needed */ -"Update Available" = "Update verfügbar"; - -/* Title for workout mode */ -"Workout" = "Training"; - -/* Descriptive text for basal rate */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Deine Basalrate ist die Anzahl der Einheiten pro Stunde, die Du verwenden möchtest, um Deinen Hintergrund-Insulinbedarf zu decken."; - -/* Descriptive text for carb ratio */ -"Your Carb Ratio is the number of grams of carbohydrates covered by one unit of insulin." = "Dein Kohlenhydratverhältnis ist die Anzahl an Kohlenhydraten in Gramm, die von einer Insulineinheit abgedeckt wird."; - -/* Descriptive text for insulin sensitivity */ -"Your Insulin Sensitivities refer to the drop in glucose expected from one unit of insulin." = "Deine Insulinempfindlichkeit bezieht sich auf den Abfall des Blutzuckers, der von einer Einheit Insulin erwartet wird."; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/en.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/en.lproj/Localizable.strings deleted file mode 100644 index 2b8af5a79..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/en.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - LoopKit - - Created by Pete Schwamb on 3/19/23. - Copyright © 2023 LoopKit Authors. All rights reserved. -*/ diff --git a/Dependencies/LoopKit/LoopKit/Resources/es.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/es.lproj/Localizable.strings deleted file mode 100644 index 63956522f..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/es.lproj/Localizable.strings +++ /dev/null @@ -1,267 +0,0 @@ -/* Format for correction range override therapy setting card */ -"%@ Range" = "%@ Rango"; - -/* Descriptive format string for glucose safety limit (1: app name) */ -"%1$@ will deliver basal and recommend bolus insulin only if your glucose is predicted to be above this limit for the next three hours." = "%1$@ administrará insulina basal y bolo recomendado solo si se prevé que tu nivel de glucosa estará por encima de este límite durante las próximas tres horas."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"A value you have entered is higher than what is typically recommended for most people." = "El valor introducido es superior al recomendado para la mayoría de las personas."; - -/* Descriptive text for guardrail low value warning for schedule interface */ -"A value you have entered is lower than what is typically recommended for most people." = "El valor introducido es inferior al recomendado para la mayoría de las personas."; - -/* Brand name for afrezza insulin type - Title for Afrezza insulin type */ -"Afrezza" = "Afrezza"; - -/* Description for afrezza insulin type */ -"Afrezza is an ultra rapid-acting mealtime insulin that is breathed in through your lungs using an oral inhaler and made by MannKind" = "Afrezza es una insulina de acción ultrarrápida que se inhala a través de los pulmones mediante un inhalador oral, fabricado por MannKind."; - -/* Brand name for apidra insulin type */ -"Apidra" = "Apidra"; - -/* Title for Apidra insulin type */ -"Apidra (insulin glulisine)" = "Apidra (insulina glulisina)"; - -/* Description for apidra insulin type */ -"Apidra (insulin glulisine) is a rapid-acting insulin made by Sanofi-aventis " = "Apidra (insulina glulisina) es una insulina de acción rápida fabricada por Sanofi-aventis"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Autorización Denegada"; - -/* Title for basal dose type */ -"Basal" = "Basal"; - -/* Title text for basal rates */ -"Basal Rates" = "Tasas basales"; - -/* Title for bolus dose type */ -"Bolus" = "Bolo"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Ratios de carbohidratos"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Autorización Denegada"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Esta muestra se puede eliminar de la aplicación Salud"; - -/* Generic pump error description */ -"Communication Failure" = "Falla de Comunicación"; - -/* Failure reason for uncertain delivery */ -"Communications interrupted during insulin delivery command." = "Comunicaciones interrumpidas durante el comando de administración de insulina."; - -/* Generic pump error description */ -"Connection Failure" = "Falla de Conexión"; - -/* Title text for glucose target range */ -"Correction Range" = "Rango de Corrección"; - -/* Descriptive text for glucose target range (1: app name) */ -"Correction Range is the glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin and helping you calculate your boluses." = "El Rango de Corrección es el valor de glucosa (o rango de valores) al que %1$@ debe apuntar para ajustar su insulina basal y ayudarle a calcular sus bolos."; - -/* Description of critical software update needed */ -"Critical Update" = "Actualización crítica"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Límites de Administración de Insulina"; - -/* Generic pump error description */ -"Device Refused" = "Dispositivo Rechazado"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Asegurar que los datos de carbohidratos existen para la fecha especificada"; - -/* Glucose trend down */ -"Falling" = "Descendiendo"; - -/* Glucose trend down-down */ -"Falling fast" = "Descendiendo rápido"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Descendiendo muy rápido"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Description for fiasp insulin type */ -"Fiasp is a mealtime insulin aspart formulation with the addition of nicotinamide (vitamin B3) made by Novo Nordisk" = "Fiasp es una formulación de insulina Aspart con nicotinamida (vitamina B3) fabricada por Novo Nordisk."; - -/* Glucose trend flat */ -"Flat" = "Estable"; - -/* Descriptive text for fast acting insulin model (1: app name) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from different models for the peak activity." = "En el caso de la insulina de acción rápida, %1$@ asume que actúa activamente durante 6 horas. Puedes elegir entre modelos diferentes para que la aplicación mida el pico de actividad de la insulina."; - -/* The short unit display string for grams per U */ -"g/U" = "g/U"; - -/* Title text for glucose safety limit */ -"Glucose Safety Limit" = "Límite de seguridad de glucosa"; - -/* The long unit display string for a singular hour */ -"Hour" = "Hora"; - -/* The long unit display string for hours */ -"Hours" = "Horas"; - -/* Brand name for humalog insulin type */ -"Humalog" = "Humalog"; - -/* Title for Humalog insulin type */ -"Humalog (insulin lispro)" = "Humalog (insulina lispro)"; - -/* Description for humalog insulin type */ -"Humalog (insulin lispro) is a rapid-acting insulin made by Eli Lilly" = "Humalog (insulina lispro) es una insulina de acción rápida fabricada por Eli Lilly"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Modelo de Insulina"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Sensibilidad a la insulina"; - -/* Generic pump error description */ -"Invalid Configuration" = "Configuración no Válida"; - -/* Brand name for lyumjev insulin type - Title for Lyumjev insulin type */ -"Lyumjev" = "Lyumjev"; - -/* Description for lyumjev insulin type */ -"Lyumjev is a mealtime insulin lispro formulation with the addition of citrate and treprostinil made by Eli Lilly" = "Lyumjev es una formulación de insulina Lispro que incluye la adición de citrato y treprostinil fabricada por Eli Lilly"; - -/* Recovery suggestion for uncertain delivery */ -"Make sure your pump is within communication range of your phone." = "Asegúrate de que tu bomba esté dentro del rango de comunicación de tu teléfono."; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Perfil Basal Máximo"; - -/* Descriptive text for maximum basal rate (1: app name) */ -"Maximum Basal Rate is the highest temporary basal rate %1$@ is allowed to set." = "Tasa Basal Máxima es la tasa basal temporal más alta que %1$@ puede establecer."; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Bolo Máximo"; - -/* Descriptive text for maximum bolus */ -"Maximum Bolus is the highest bolus amount you can deliver at one time to cover carbs or bring down high glucose." = "El bolo máximo es la maxima cantidad de insulina bolo que se puede administrar en una sola toma para cubrir los carbohidratos o bajar un nivel de glucosa alta."; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/U"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/U"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Necesita Atención"; - -/* Description of no software update needed */ -"No Update" = "Sin actualización"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "No hay datos"; - -/* Brand name for novolog insulin type */ -"Novolog" = "Novolog"; - -/* Title for Novolog insulin type */ -"Novolog (insulin aspart)" = "Novolog (insulina aspart)"; - -/* Description for novolog insulin type */ -"NovoLog (insulin aspart) is a rapid-acting insulin made by Novo Nordisk" = "NovoLog (insulina Aspart) es una insulina de acción rápida fabricada por Novo Nordisk"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* Descriptive text for saving settings outside the recommended range */ -"One or more of the values you have entered is outside of what is typically recommended for most people." = "Uno o más de los valores que ha introducido están fuera de lo que se suele recomendar para la mayoría de las personas."; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Por favor, vuelva a habilitar compartir en Salud"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Pre-Comida"; - -/* Description of supported software update needed */ -"Recommended Update" = "Actualización recomendada"; - -/* Title for resume dose type */ -"Resumed" = "Reanudado"; - -/* Glucose trend up */ -"Rising" = "Ascendiendo"; - -/* Glucose trend up-up */ -"Rising fast" = "Ascendiendo rápido"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Ascendiendo muy rápido"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"Some of the values you have entered are outside of what is typically recommended for most people." = "Algunos de los valores que ingresó están fuera de lo que normalmente se recomienda para la mayoría de las personas."; - -/* Title for suspend dose type */ -"Suspended" = "Suspendido"; - -/* Title for temp basal dose type */ -"Temp Basal" = "Insulina basal temporal"; - -/* Descriptive text for pre-meal correction range override */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Reduzca temporalmente su objetivo de glucosa antes de una comida para reducir los picos de glucosa después de las comidas."; - -/* Descriptive text for workout correction range override */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Aumente temporalmente su objetivo de glucosa antes, durante o después de la actividad física para reducir el riesgo de tener eventos de glucosa baja."; - -/* Descriptive text for guardrail high value warning */ -"The value you have entered is higher than what is typically recommended for most people." = "El valor que ha introducido es superior al que se suele recomendar para la mayoría de las personas."; - -/* Descriptive text for guardrail low value warning */ -"The value you have entered is lower than what is typically recommended for most people." = "El valor que ha introducido es inferior al que se suele recomendar para la mayoría de las personas."; - -/* Descriptive text for guardrail high value warning */ -"The values you have entered are outside of what is typically recommended for most people." = "Los valores que ha introducido están fuera de lo que normalmente se recomienda para la mayoría de las personas."; - -/* The short unit display string for international units of insulin */ -"U" = "U"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "U/hra"; - -/* Error description for uncertain delivery */ -"Uncertain Delivery" = "Entrega incierta"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Unidad"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Unidad/hora"; - -/* The long unit display string for international units of insulin */ -"Units" = "Unidades"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Unidades/hora"; - -/* Description of informational software update needed */ -"Update Available" = "Actualización disponible"; - -/* Title for workout mode */ -"Workout" = "Ejercicio"; - -/* Descriptive text for basal rate */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Su tasa basal de insulina es la cantidad de unidades por hora que desea usar para cubrir sus necesidades de insulina de fondo, no relacionadas con las comidas."; - -/* Descriptive text for carb ratio */ -"Your Carb Ratio is the number of grams of carbohydrates covered by one unit of insulin." = "El ratio de carbohidratos es el número de gramos de carbohidratos que cubre una unidad de insulina."; - -/* Descriptive text for insulin sensitivity */ -"Your Insulin Sensitivities refer to the drop in glucose expected from one unit of insulin." = "Su sensibilidad a la insulina se refiere a la disminución en los niveles de glucosa esperados por una unidad de insulina."; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/fi.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/fi.lproj/Localizable.strings deleted file mode 100644 index b69161655..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/fi.lproj/Localizable.strings +++ /dev/null @@ -1,223 +0,0 @@ -/* Format for correction range override therapy setting card */ -"%@ Range" = "%@ -tavoite"; - -/* Descriptive format string for glucose safety limit (1: app name) */ -"%1$@ will deliver basal and recommend bolus insulin only if your glucose is predicted to be above this limit for the next three hours." = "%1$@ annostelee basaalia ja suosittelee bolusinsuliinia vain, jos glukoosin ennustetaan ylittävän tämän rajan seuraavien kolmen tunnin aikana."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"A value you have entered is higher than what is typically recommended for most people." = "Antamasi arvo on suurempi kuin useimmille ihmisille yleensä suositeltava arvo."; - -/* Descriptive text for guardrail low value warning for schedule interface */ -"A value you have entered is lower than what is typically recommended for most people." = "Antamasi arvo on pienempi kuin useimmille ihmisille yleensä suositeltava arvo."; - -/* Brand name for apidra insulin type */ -"Apidra" = "Apidra"; - -/* Title for Apidra insulin type */ -"Apidra (insulin glulisine)" = "Apidra (glulisinsuliini)"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Valtuutus hylättiin"; - -/* Title for basal dose type */ -"Basal" = "Basaali"; - -/* Title text for basal rates */ -"Basal Rates" = "Basaalitasot"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Hiilihydraattisuhteet"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Valtuutus hylättiin"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Tämä näyte voidaan poistaa Terveys-sovelluksesta"; - -/* Generic pump error description */ -"Communication Failure" = "Kommunikaatiovirhe"; - -/* Failure reason for uncertain delivery */ -"Communications interrupted during insulin delivery command." = "Yhteys katkesi insuliinin annostelu -toiminnon aikana."; - -/* Generic pump error description */ -"Connection Failure" = "Yhteysvirhe"; - -/* Title text for glucose target range */ -"Correction Range" = "Korjausalue"; - -/* Descriptive text for glucose target range (1: app name) */ -"Correction Range is the glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin and helping you calculate your boluses." = "Korjausalue tarkoittaa glukoosiarvoa (tai arvoaluetta), johon %1$@ tähtää säätäessään basaalia ja auttaessaan boluslaskelmissa."; - -/* Title text for delivery limits */ -"Delivery Limits" = "Annostelurajat"; - -/* Generic pump error description */ -"Device Refused" = "Laite hylättiin"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Varmista, että hiilihydraattitiedot ovat olemassa määritettynä ajankohtana"; - -/* Glucose trend down */ -"Falling" = "Laskeva"; - -/* Glucose trend down-down */ -"Falling fast" = "Nopeasti laskeva"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Erittäin nopeasti laskeva"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Description for fiasp insulin type */ -"Fiasp is a mealtime insulin aspart formulation with the addition of nicotinamide (vitamin B3) made by Novo Nordisk" = "Fiasp on Novo Nordiskin valmistama aterianaikainen aspartinsuliinivalmiste, johon on lisätty nikotiiniamidia (B3-vitamiini)"; - -/* Glucose trend flat */ -"Flat" = "Tasainen"; - -/* Descriptive text for fast acting insulin model (1: app name) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from different models for the peak activity." = "%1$@ olettaa, että nopeavaikutteinen insuliini vaikuttaa aktiivisesti 6 tuntia. Vaikutushuipulle on valittavissa erilaisia malleja."; - -/* The short unit display string for grams per U */ -"g/U" = "g/U"; - -/* Title text for glucose safety limit */ -"Glucose Safety Limit" = "Glukoosin turvaraja"; - -/* Brand name for humalog insulin type */ -"Humalog" = "Humalog"; - -/* Title for Humalog insulin type */ -"Humalog (insulin lispro)" = "Humalog (lisproinsuliini)"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Insuliinimalli"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Insuliiniherkkyydet"; - -/* Generic pump error description */ -"Invalid Configuration" = "Virheellinen määritys"; - -/* Recovery suggestion for uncertain delivery */ -"Make sure your pump is within communication range of your phone." = "Varmista, että pumppu on puhelimen yhteysalueen sisällä."; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Suurin sallittu basaalitaso"; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Suurin sallittu bolus"; - -/* Descriptive text for maximum bolus */ -"Maximum Bolus is the highest bolus amount you can deliver at one time to cover carbs or bring down high glucose." = "Suurin sallittu bolus tarkoittaa suurinta insuliiniannosta, jonka voi annostella yhdellä kertaa kattamaan hiilihydraatteja tai alentamaan korkeaa glukoosia."; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/U"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/U"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Tarvitsee huomiota"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "Arvoja ei löydy"; - -/* Brand name for novolog insulin type */ -"Novolog" = "Novorapid"; - -/* Title for Novolog insulin type */ -"Novolog (insulin aspart)" = "Novorapid (aspartinsuliini)"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* Descriptive text for saving settings outside the recommended range */ -"One or more of the values you have entered is outside of what is typically recommended for most people." = "Yksi tai useampi antamistasi arvoista on sen ulkopuolella, mitä useimmille ihmisille yleensä suositellaan."; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Ota jakaminen uudelleen käyttöön Terveys-sovelluksessa"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Ennen ateriaa"; - -/* Title for resume dose type */ -"Resumed" = "Jatkettu"; - -/* Glucose trend up */ -"Rising" = "Nouseva"; - -/* Glucose trend up-up */ -"Rising fast" = "Nopeasti nouseva"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Erittäin nopeasti nouseva"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"Some of the values you have entered are outside of what is typically recommended for most people." = "Jotkut antamistasi arvoista on sen ulkopuolella, mitä useimmille ihmisille yleensä suositellaan."; - -/* Title for suspend dose type */ -"Suspended" = "Pysäytetty"; - -/* Title for temp basal dose type */ -"Temp Basal" = "Tilapäinen basaali"; - -/* Descriptive text for pre-meal correction range override */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Laske glukoositavoitetta väliaikaisesti ennen ateriaa vaikuttaaksesi aterian jälkeiseen glukoosin nousuun."; - -/* Descriptive text for workout correction range override */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Nosta glukoositavoitetta väliaikaisesti ennen liikuntaa, sen aikana tai sen jälkeen, jotta matalan glukoosin riski pienenee."; - -/* Descriptive text for guardrail high value warning */ -"The value you have entered is higher than what is typically recommended for most people." = "Antamasi arvo on suurempi kuin useimmille ihmisille yleensä suositellaan."; - -/* Descriptive text for guardrail low value warning */ -"The value you have entered is lower than what is typically recommended for most people." = "Antamasi arvo on pienempi kuin useimmille ihmisille yleensä suositellaan."; - -/* Descriptive text for guardrail high value warning */ -"The values you have entered are outside of what is typically recommended for most people." = "Antamasi arvot ovat useimmille ihmisille yleensä suositeltujen arvojen ulkopuolella."; - -/* The short unit display string for international units of insulin */ -"U" = "U"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "U/h"; - -/* Error description for uncertain delivery */ -"Uncertain Delivery" = "Epävarma annostelu"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Yksikkö"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Yksikkö/tunti"; - -/* The long unit display string for international units of insulin */ -"Units" = "Yksikköä"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Yksikköä/tunnissa"; - -/* Title for workout mode */ -"Workout" = "Liikunta"; - -/* Descriptive text for basal rate */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Basaalitaso tarkoittaa sitä yksikkömäärää insuliinia tunnissa, jonka tarvitset insuliinin perustarpeen kattamiseen."; - -/* Descriptive text for carb ratio */ -"Your Carb Ratio is the number of grams of carbohydrates covered by one unit of insulin." = "Hiilihydraattisuhde tarkoittaa sitä, kuinka monta grammaa hiilihydraatteja yksi insuliiniyksikkö kattaa."; - -/* Descriptive text for insulin sensitivity */ -"Your Insulin Sensitivities refer to the drop in glucose expected from one unit of insulin." = "Insuliiniherkkyys tarkoittaa sitä, kuinka paljon glukoosi laskee yhdellä insuliiniyksiköllä."; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/fr.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/fr.lproj/Localizable.strings deleted file mode 100644 index 7dc149159..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/fr.lproj/Localizable.strings +++ /dev/null @@ -1,267 +0,0 @@ -/* Format for correction range override therapy setting card */ -"%@ Range" = "%@ Plage"; - -/* Descriptive format string for glucose safety limit (1: app name) */ -"%1$@ will deliver basal and recommend bolus insulin only if your glucose is predicted to be above this limit for the next three hours." = "%1$@ ne délivrera de l'insuline basale et ne recommandera un bolus que si la projection de glycémie est supérieure à cette limite au cours des trois prochaines heures."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"A value you have entered is higher than what is typically recommended for most people." = "Une valeur a été entrée qui est supérieure ce qui est typiquement recommandé pour la majorité des personnes."; - -/* Descriptive text for guardrail low value warning for schedule interface */ -"A value you have entered is lower than what is typically recommended for most people." = "Une valeur a été entrée qui est inférieure à ce qui est typiquement recommandé pour la majorité des personnes."; - -/* Brand name for afrezza insulin type - Title for Afrezza insulin type */ -"Afrezza" = "Afrezza"; - -/* Description for afrezza insulin type */ -"Afrezza is an ultra rapid-acting mealtime insulin that is breathed in through your lungs using an oral inhaler and made by MannKind" = "Afrezza est une insuline prandiale à action ultra rapide qui est inhalée par vos poumons à l'aide d'un inhalateur oral et fabriquée par MannKind."; - -/* Brand name for apidra insulin type */ -"Apidra" = "Apidra"; - -/* Title for Apidra insulin type */ -"Apidra (insulin glulisine)" = "Apidra (insuline glulisine)"; - -/* Description for apidra insulin type */ -"Apidra (insulin glulisine) is a rapid-acting insulin made by Sanofi-aventis " = "Apidra (insuline glulisine) est une insuline à action rapide fabriquée par Sanofi-Aventis "; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Autorisation refusée"; - -/* Title for basal dose type */ -"Basal" = "Basal"; - -/* Title text for basal rates */ -"Basal Rates" = "Débits basaux"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Ratios Insuline-Glucides"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Autorisation refusée"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Cette entrée peut être supprimée de l'application Health"; - -/* Generic pump error description */ -"Communication Failure" = "Échec de la communication"; - -/* Failure reason for uncertain delivery */ -"Communications interrupted during insulin delivery command." = "Communications interrompues pendant la commande d’administration d’insuline."; - -/* Generic pump error description */ -"Connection Failure" = "Échec de connexion"; - -/* Title text for glucose target range */ -"Correction Range" = "Plage de correction"; - -/* Descriptive text for glucose target range (1: app name) */ -"Correction Range is the glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin and helping you calculate your boluses." = "La plage de correction est la valeur de glucose (ou la plage de valeurs) que vous voulez que %1$@ vise en ajustant votre insuline basale et en vous aidant à calculer vos bolus."; - -/* Description of critical software update needed */ -"Critical Update" = "Mise à jour critique"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Limites d'Administration"; - -/* Generic pump error description */ -"Device Refused" = "Dispositif refusé"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "S'assurer que les données sur les glucides existent pour la date spécifiée"; - -/* Glucose trend down */ -"Falling" = "Diminue"; - -/* Glucose trend down-down */ -"Falling fast" = "Diminue rapidement"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Diminue très rapidement"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Description for fiasp insulin type */ -"Fiasp is a mealtime insulin aspart formulation with the addition of nicotinamide (vitamin B3) made by Novo Nordisk" = "Fiasp est une formulation d'insuline asparte prandiale avec ajout de nicotinamide (vitamine B3) qui est produite par Novo Nordisk"; - -/* Glucose trend flat */ -"Flat" = "Stable"; - -/* Descriptive text for fast acting insulin model (1: app name) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from different models for the peak activity." = "Pour l'insuline à action rapide, %1$@ suppose qu'elle agit activement pendant 6 heures. Vous pouvez choisir parmi différents modèles pour le pic d'activité."; - -/* The short unit display string for grams per U */ -"g/U" = "g/U"; - -/* Title text for glucose safety limit */ -"Glucose Safety Limit" = "Limite de sécurité pour la glycémie"; - -/* The long unit display string for a singular hour */ -"Hour" = "Heure"; - -/* The long unit display string for hours */ -"Hours" = "Heures"; - -/* Brand name for humalog insulin type */ -"Humalog" = "Humalog"; - -/* Title for Humalog insulin type */ -"Humalog (insulin lispro)" = "Humalog (insulin lispro)"; - -/* Description for humalog insulin type */ -"Humalog (insulin lispro) is a rapid-acting insulin made by Eli Lilly" = "Humalog (insuline lispro) est une insuline à action rapide fabriquée par Eli Lilly"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Modèle d'insuline"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Facteurs de sensibilité à l'insuline"; - -/* Generic pump error description */ -"Invalid Configuration" = "Configuration invalide"; - -/* Brand name for lyumjev insulin type - Title for Lyumjev insulin type */ -"Lyumjev" = "Lyumjev"; - -/* Description for lyumjev insulin type */ -"Lyumjev is a mealtime insulin lispro formulation with the addition of citrate and treprostinil made by Eli Lilly" = "Lyumjev est une formulation d'insuline lispro prandiale avec ajout de citrate et de tréprostinil fabriqué par Eli Lilly"; - -/* Recovery suggestion for uncertain delivery */ -"Make sure your pump is within communication range of your phone." = "Assurez-vous que votre pompe soit à portée de communication de votre téléphone."; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Débit Basal Maximum"; - -/* Descriptive text for maximum basal rate (1: app name) */ -"Maximum Basal Rate is the highest temporary basal rate %1$@ is allowed to set." = "Le débit basal maximum est le débit de base temporaire le plus élevé que %1$@ est autorisé à définir."; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Bolus Maximum"; - -/* Descriptive text for maximum bolus */ -"Maximum Bolus is the highest bolus amount you can deliver at one time to cover carbs or bring down high glucose." = "Le bolus maximum est la quantité de bolus la plus élevée que vous pouvez délivrer en une fois pour couvrir les glucides ou abaisser le taux de glucose élevé."; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/U"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/U"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Demande votre attention"; - -/* Description of no software update needed */ -"No Update" = "Pas de mise à jour"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "Aucune entrée trouvée"; - -/* Brand name for novolog insulin type */ -"Novolog" = "Novolog"; - -/* Title for Novolog insulin type */ -"Novolog (insulin aspart)" = "Novolog (insuline asparte)"; - -/* Description for novolog insulin type */ -"NovoLog (insulin aspart) is a rapid-acting insulin made by Novo Nordisk" = "NovoLog (insuline asparte) est une insuline à action rapide fabriquée par Novo Nordisk"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* Descriptive text for saving settings outside the recommended range */ -"One or more of the values you have entered is outside of what is typically recommended for most people." = "Une ou plusieurs des valeurs que vous avez entrées sont en dehors de ce qui est généralement recommandé pour la plupart des personnes."; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Veuillez réactiver le partage dans l'application Santé"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Pré-Repas"; - -/* Description of supported software update needed */ -"Recommended Update" = "Mise à jour recommandée"; - -/* Title for resume dose type */ -"Resumed" = "Reprendre"; - -/* Glucose trend up */ -"Rising" = "Augmente"; - -/* Glucose trend up-up */ -"Rising fast" = "Augmente rapidement"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Augmente très rapidement"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"Some of the values you have entered are outside of what is typically recommended for most people." = "Des valeurs que vous avez entrées sont en dehors de ce qui est généralement recommandé pour la plupart des personnes."; - -/* Title for suspend dose type */ -"Suspended" = "Suspendu"; - -/* Title for temp basal dose type */ -"Temp Basal" = "Débit basal temporaire"; - -/* Descriptive text for pre-meal correction range override */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Diminue temporairement votre cible de glycémie avant un repas pour influer sur les pics d'hyperglycémie post-repas."; - -/* Descriptive text for workout correction range override */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Augmente temporairement votre cible de glycémie avant, pendant ou après l'activité physique pour réduire le risque d'hypoglycémie."; - -/* Descriptive text for guardrail high value warning */ -"The value you have entered is higher than what is typically recommended for most people." = "La valeur que vous avez saisie est supérieure à ce qui est généralement recommandé pour la plupart des personnes."; - -/* Descriptive text for guardrail low value warning */ -"The value you have entered is lower than what is typically recommended for most people." = "La valeur que vous avez saisie est inférieure à ce qui est généralement recommandé pour la plupart des personnes."; - -/* Descriptive text for guardrail high value warning */ -"The values you have entered are outside of what is typically recommended for most people." = "Les valeurs que vous avez saisies sont en dehors de ce qui est généralement recommandé pour la plupart des personnes."; - -/* The short unit display string for international units of insulin */ -"U" = "U"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "U/h"; - -/* Error description for uncertain delivery */ -"Uncertain Delivery" = "Administration incertaine"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Unité"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "unité / heure"; - -/* The long unit display string for international units of insulin */ -"Units" = "Unités"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "unités / heure"; - -/* Description of informational software update needed */ -"Update Available" = "Mise à jour disponible"; - -/* Title for workout mode */ -"Workout" = "Exercice"; - -/* Descriptive text for basal rate */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Votre débit basal d'insuline est le nombre d'unités par heure que vous souhaitez utiliser pour couvrir vos besoins vitaux d'insuline."; - -/* Descriptive text for carb ratio */ -"Your Carb Ratio is the number of grams of carbohydrates covered by one unit of insulin." = "Votre ratio insuline-glucides est le nombre de grammes de glucides couverts par une unité d'insuline."; - -/* Descriptive text for insulin sensitivity */ -"Your Insulin Sensitivities refer to the drop in glucose expected from one unit of insulin." = "Vos sensibilités à l'insuline se réfèrent à la baisse de glycémie prévue entrainée par une unité d'insuline."; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/he.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/he.lproj/Localizable.strings deleted file mode 100644 index e1ace64f0..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/he.lproj/Localizable.strings +++ /dev/null @@ -1,130 +0,0 @@ -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Authorization Denied"; - -/* Title text for basal rates */ -"Basal Rates" = "Basal Rates"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Carb Ratios"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Authorization Denied"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "This sample can be deleted from the Health app"; - -/* Generic pump error description */ -"Communication Failure" = "Communication Failure"; - -/* Generic pump error description */ -"Connection Failure" = "Connection Failure"; - -/* Title text for glucose target range */ -"Correction Range" = "Correction Range"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Delivery Limits"; - -/* Generic pump error description */ -"Device Refused" = "Device Refused"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Ensure carb data exists for the specified date"; - -/* Glucose trend down */ -"Falling" = "Falling"; - -/* Glucose trend down-down */ -"Falling fast" = "Falling fast"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Falling very fast"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Glucose trend flat */ -"Flat" = "Flat"; - -/* The short unit display string for grams per U */ -"g/U" = "g/U"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Insulin Model"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Insulin Sensitivities"; - -/* Generic pump error description */ -"Invalid Configuration" = "Invalid Configuration"; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Maximum Basal Rate"; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Maximum Bolus"; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/U"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/U"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Needs Attention"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "No values found"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Please re-enable sharing in Health"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Pre-Meal"; - -/* Glucose trend up */ -"Rising" = "Rising"; - -/* Glucose trend up-up */ -"Rising fast" = "Rising fast"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Rising very fast"; - -/* Title for suspend dose type */ -"Suspended" = "Suspended"; - -/* The short unit display string for international units of insulin */ -"U" = "U"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "U/hr"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Unit"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Unit/hour"; - -/* The long unit display string for international units of insulin */ -"Units" = "Units"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Units/hour"; - -/* Title for workout mode */ -"Workout" = "Workout"; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/hu.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/hu.lproj/Localizable.strings deleted file mode 100644 index 39dc4ee39..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/hu.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Describes a certain bolus failure (1: size of the bolus in units) */ -"%1$@ U bolus failed" = "%1$@ U bolus failed"; - -/* Describes an uncertain bolus failure (1: size of the bolus in units) */ -"%1$@ U bolus may not have succeeded" = "%1$@ U bolus may not have succeeded"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Authorization Denied"; - -/* Recovery instruction for an uncertain bolus failure */ -"Check your pump before retrying" = "Check your pump before retrying"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Authorization Denied"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "This sample can be deleted from the Health app"; - -/* Generic pump error description */ -"Communication Failure" = "Communication Failure"; - -/* Generic pump error description */ -"Connection Failure" = "Connection Failure"; - -/* Generic pump error description */ -"Device Refused" = "Device Refused"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Ensure carb data exists for the specified date"; - -/* Glucose trend down */ -"Falling" = "Falling"; - -/* Glucose trend down-down */ -"Falling fast" = "Falling fast"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Falling very fast"; - -/* Glucose trend flat */ -"Flat" = "Flat"; - -/* The short unit display string for grams per U */ -"g/U" = "g/U"; - -/* Generic pump error description */ -"Invalid Configuration" = "Invalid Configuration"; - -/* Recovery instruction for a certain bolus failure */ -"It is safe to retry" = "It is safe to retry"; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/U"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/U"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Needs Attention"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "No values found"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Please re-enable sharing in Health"; - -/* Glucose trend up */ -"Rising" = "Rising"; - -/* Glucose trend up-up */ -"Rising fast" = "Rising fast"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Rising very fast"; - -/* The short unit display string for international units of insulin */ -"U" = "U"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "U/hr"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Unit"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Unit/hour"; - -/* The long unit display string for international units of insulin */ -"Units" = "Units"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Units/hour"; diff --git a/Dependencies/LoopKit/LoopKit/Resources/it.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/it.lproj/Localizable.strings deleted file mode 100644 index 3cb4481f5..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/it.lproj/Localizable.strings +++ /dev/null @@ -1,267 +0,0 @@ -/* Format for correction range override therapy setting card */ -"%@ Range" = "%@ Intervallo"; - -/* Descriptive format string for glucose safety limit (1: app name) */ -"%1$@ will deliver basal and recommend bolus insulin only if your glucose is predicted to be above this limit for the next three hours." = "%1$@ erogherà l'insulina basale e consiglierà il bolo solo se si prevede che il tuo glucosio sarà superiore a questo limite per le prossime tre ore."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"A value you have entered is higher than what is typically recommended for most people." = "Il valore inserito è superiore a quello tipicamente consigliato per la maggior parte delle persone."; - -/* Descriptive text for guardrail low value warning for schedule interface */ -"A value you have entered is lower than what is typically recommended for most people." = "Il valore inserito è inferiore a quello tipicamente consigliato per la maggior parte delle persone."; - -/* Brand name for afrezza insulin type - Title for Afrezza insulin type */ -"Afrezza" = "Afrezza"; - -/* Description for afrezza insulin type */ -"Afrezza is an ultra rapid-acting mealtime insulin that is breathed in through your lungs using an oral inhaler and made by MannKind" = "Afrezza è un'insulina prandiale ad azione ultra rapida che viene inalata attraverso i polmoni utilizzando un inalatore orale e prodotta da MannKind"; - -/* Brand name for apidra insulin type */ -"Apidra" = "Apidra"; - -/* Title for Apidra insulin type */ -"Apidra (insulin glulisine)" = "Apidra (insulina glulisina)"; - -/* Description for apidra insulin type */ -"Apidra (insulin glulisine) is a rapid-acting insulin made by Sanofi-aventis " = "Apidra (insulina glulisina) è un'insulina ad azione rapida prodotta da Sanofi-aventis"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Autorizzazione negata"; - -/* Title for basal dose type */ -"Basal" = "Basale"; - -/* Title text for basal rates */ -"Basal Rates" = "Velocità basali"; - -/* Title for bolus dose type */ -"Bolus" = "Bolo"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Rapporti carboidrati"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Autorizzazione negata"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Questo campione puo essere cancellato dall’ app Salute"; - -/* Generic pump error description */ -"Communication Failure" = "Errore di comunicazione"; - -/* Failure reason for uncertain delivery */ -"Communications interrupted during insulin delivery command." = "Comunicazioni interrotte durante il comando di erogazione dell'insulina."; - -/* Generic pump error description */ -"Connection Failure" = "Errore di connessione"; - -/* Title text for glucose target range */ -"Correction Range" = "Intervallo Glicemico"; - -/* Descriptive text for glucose target range (1: app name) */ -"Correction Range is the glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin and helping you calculate your boluses." = "Intervallo di correzione è il valore glicemico (o l'intervallo di valori) a cui vuoi che %1$@ miri per regolare l'insulina basale e aiutarti a calcolare i boli."; - -/* Description of critical software update needed */ -"Critical Update" = "Aggiornamento critico"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Limiti Erogazione"; - -/* Generic pump error description */ -"Device Refused" = "Il dispositivo è stato rifiutato"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Assicurati che i dati sui carboidrati esistano per la data specificata"; - -/* Glucose trend down */ -"Falling" = "Abbassamento"; - -/* Glucose trend down-down */ -"Falling fast" = "Abbassamento veloce"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Abbassamento molto veloce"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Description for fiasp insulin type */ -"Fiasp is a mealtime insulin aspart formulation with the addition of nicotinamide (vitamin B3) made by Novo Nordisk" = "Fiasp è una formulazione di insulina ad azione rapida con un l'aggiunta di Nicotinamide (vitamina B3) prodotta da Novo Nordisk. "; - -/* Glucose trend flat */ -"Flat" = "Piatto"; - -/* Descriptive text for fast acting insulin model (1: app name) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from different models for the peak activity." = "Per l'insulina ad azione veloce,%1$@ si presume che sarà attiva per 6 ore. Si può scegliere fra modelli diversi a seconda dei rispettivi picchi d'azione."; - -/* The short unit display string for grams per U */ -"g/U" = "g/U"; - -/* Title text for glucose safety limit */ -"Glucose Safety Limit" = "Limite Glicemico di Sicurezza"; - -/* The long unit display string for a singular hour */ -"Hour" = "Ora"; - -/* The long unit display string for hours */ -"Hours" = "Ore"; - -/* Brand name for humalog insulin type */ -"Humalog" = "Humalog"; - -/* Title for Humalog insulin type */ -"Humalog (insulin lispro)" = "Humalog (insulina lispro)"; - -/* Description for humalog insulin type */ -"Humalog (insulin lispro) is a rapid-acting insulin made by Eli Lilly" = "Humalog (insulin Lispro) è una insulina ad azione rapida prodotta dalla Ely Lilly"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Modello di azione dell'Insulina"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Sensibilità Insulinica"; - -/* Generic pump error description */ -"Invalid Configuration" = "Configurazione non valida"; - -/* Brand name for lyumjev insulin type - Title for Lyumjev insulin type */ -"Lyumjev" = "Lyumjev"; - -/* Description for lyumjev insulin type */ -"Lyumjev is a mealtime insulin lispro formulation with the addition of citrate and treprostinil made by Eli Lilly" = "Lyumjev e' una formulazione veloce di insulina lispro (humalog) con due additivi: un citrato e Treprostinil, prodotta dalla compagnia Eli Lilly "; - -/* Recovery suggestion for uncertain delivery */ -"Make sure your pump is within communication range of your phone." = "Fare sicuro che il microinfusore e' nel cerchio di comunicazione del cellulare"; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Profilo Basale Massimo"; - -/* Descriptive text for maximum basal rate (1: app name) */ -"Maximum Basal Rate is the highest temporary basal rate %1$@ is allowed to set." = "Velocità Basale Massima è la velocità basale temporanea più alta che %1$@ può impostare."; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Bolo Massimo"; - -/* Descriptive text for maximum bolus */ -"Maximum Bolus is the highest bolus amount you can deliver at one time to cover carbs or bring down high glucose." = "Il bolo massimo e' il valore piu' alto di bolo che puo'essere erogato tutto in una volta per coprire i carboidrati inseriti o per abbassare una iperglicemia"; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/U"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/U"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Esige Attenzione"; - -/* Description of no software update needed */ -"No Update" = "Nessun aggiornamento"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "Nessun valore trovato"; - -/* Brand name for novolog insulin type */ -"Novolog" = "Novolog"; - -/* Title for Novolog insulin type */ -"Novolog (insulin aspart)" = "Novolog (insulina aspart)"; - -/* Description for novolog insulin type */ -"NovoLog (insulin aspart) is a rapid-acting insulin made by Novo Nordisk" = "NovoLog (insulina aspart) è un'insulina ad azione rapida prodotta da Novo Nordisk"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* Descriptive text for saving settings outside the recommended range */ -"One or more of the values you have entered is outside of what is typically recommended for most people." = "Uno o più dei valori inseriti non rientrano in quelli generalmente consigliati per la maggior parte delle persone."; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Per favore, riattiva la condivisione in Salute"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Pre-Pasto"; - -/* Description of supported software update needed */ -"Recommended Update" = "Aggiornamento consigliato"; - -/* Title for resume dose type */ -"Resumed" = "Ripresa"; - -/* Glucose trend up */ -"Rising" = "Crescente"; - -/* Glucose trend up-up */ -"Rising fast" = "Crescente veloce"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Crescente molto veloce"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"Some of the values you have entered are outside of what is typically recommended for most people." = "Alcuni dei Valori Inseriti sono al di fuori dei parametri che generalmente sono raccomandati per la maggior parte degli Utenti."; - -/* Title for suspend dose type */ -"Suspended" = "Sospeso"; - -/* Title for temp basal dose type */ -"Temp Basal" = "Basale Temporanea"; - -/* Descriptive text for pre-meal correction range override */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Abbassa temporaneamente il tuo target glicemico prima di un pasto per influenzare i picchi glicemici postprandiali."; - -/* Descriptive text for workout correction range override */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Aumentare temporaneamente il target glicemico prima, durante o dopo l'attività fisica per ridurre il rischio di eventi ipoglicemici."; - -/* Descriptive text for guardrail high value warning */ -"The value you have entered is higher than what is typically recommended for most people." = "Il valore inserito è superiore a quello generalmente consigliato per la maggior parte delle persone."; - -/* Descriptive text for guardrail low value warning */ -"The value you have entered is lower than what is typically recommended for most people." = "Il valore inserito è inferiore a quello generalmente consigliato per la maggior parte delle persone."; - -/* Descriptive text for guardrail high value warning */ -"The values you have entered are outside of what is typically recommended for most people." = "I valori che hai inserito non rientrano in quelli generalmente consigliati per la maggior parte delle persone."; - -/* The short unit display string for international units of insulin */ -"U" = "U"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "U/ora"; - -/* Error description for uncertain delivery */ -"Uncertain Delivery" = "Consegna incerta"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Unità"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Unità/ora"; - -/* The long unit display string for international units of insulin */ -"Units" = "Unità"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Unità/ora"; - -/* Description of informational software update needed */ -"Update Available" = "Aggiornamento disponibile"; - -/* Title for workout mode */ -"Workout" = "Allenarsi"; - -/* Descriptive text for basal rate */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "La velocità basale d'insulina è il numero di unità all'ora che si desidera utilizzare per coprire il tuo fabbisogno d'insulina basale."; - -/* Descriptive text for carb ratio */ -"Your Carb Ratio is the number of grams of carbohydrates covered by one unit of insulin." = "Il tuo rapporto carboidrati è il numero di grammi di carboidrati coperti da un'unità di insulina."; - -/* Descriptive text for insulin sensitivity */ -"Your Insulin Sensitivities refer to the drop in glucose expected from one unit of insulin." = "La tua sensibilità all'insulina si riferisce al calo di glucosio previsto da un'unità d'insulina."; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/ja.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/ja.lproj/Localizable.strings deleted file mode 100644 index 2612cea56..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/ja.lproj/Localizable.strings +++ /dev/null @@ -1,130 +0,0 @@ -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "認証が拒否されました"; - -/* Title text for basal rates */ -"Basal Rates" = "基礎レート"; - -/* Title for bolus dose type */ -"Bolus" = "ボーラス"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Carb Ratios"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "認証が拒否されました"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "This sample can be deleted from the Health app"; - -/* Generic pump error description */ -"Communication Failure" = "通信エラー"; - -/* Generic pump error description */ -"Connection Failure" = "接続エラー"; - -/* Title text for glucose target range */ -"Correction Range" = "ターゲット範囲"; - -/* Title text for delivery limits */ -"Delivery Limits" = "注入限度"; - -/* Generic pump error description */ -"Device Refused" = "機器拒否"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "指定した日に糖質のデータがあるか確認してください"; - -/* Glucose trend down */ -"Falling" = "降下"; - -/* Glucose trend down-down */ -"Falling fast" = "急降下"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "超急降下"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Glucose trend flat */ -"Flat" = "平坦"; - -/* The short unit display string for grams per U */ -"g/U" = "g/U"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "インスリンモデル"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "インスリン効果値"; - -/* Generic pump error description */ -"Invalid Configuration" = "コンフィグレーションが無効"; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "最大基礎レート"; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "最大ボーラス"; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/U"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/U"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "注意してください"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "値が見つかりません"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "ヘルスケアの共有を有効にしてください"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "食前"; - -/* Glucose trend up */ -"Rising" = "上昇"; - -/* Glucose trend up-up */ -"Rising fast" = "急上昇"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "超急上昇"; - -/* Title for suspend dose type */ -"Suspended" = "一時停止"; - -/* The short unit display string for international units of insulin */ -"U" = "U"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "U/時"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Unit"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Unit/hour"; - -/* The long unit display string for international units of insulin */ -"Units" = "単位"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "U/時"; - -/* Title for workout mode */ -"Workout" = "運動"; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/nb.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/nb.lproj/Localizable.strings deleted file mode 100644 index 8adc92853..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/nb.lproj/Localizable.strings +++ /dev/null @@ -1,267 +0,0 @@ -/* Format for correction range override therapy setting card */ -"%@ Range" = "%@ Målområde"; - -/* Descriptive format string for glucose safety limit (1: app name) */ -"%1$@ will deliver basal and recommend bolus insulin only if your glucose is predicted to be above this limit for the next three hours." = "%1$@ vil levere basal og anbefale bolusinsulin bare hvis blodsukkeret ditt forventes å være over denne grensen de neste tre timene."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"A value you have entered is higher than what is typically recommended for most people." = "En verdi du har lagt inn er høyere enn det som vanligvis anbefales for de fleste."; - -/* Descriptive text for guardrail low value warning for schedule interface */ -"A value you have entered is lower than what is typically recommended for most people." = "En verdi du har lagt inn er lavere enn det som vanligvis anbefales for de fleste."; - -/* Brand name for afrezza insulin type - Title for Afrezza insulin type */ -"Afrezza" = "Afrezza"; - -/* Description for afrezza insulin type */ -"Afrezza is an ultra rapid-acting mealtime insulin that is breathed in through your lungs using an oral inhaler and made by MannKind" = "Afrezza er et ultrahurtigvirkende måltidsinsulin som pustes inn gjennom lungene ved hjelp av en oral inhalator og laget av MannKind"; - -/* Brand name for apidra insulin type */ -"Apidra" = "Apidra"; - -/* Title for Apidra insulin type */ -"Apidra (insulin glulisine)" = "Apidra (insulin glulisin)"; - -/* Description for apidra insulin type */ -"Apidra (insulin glulisine) is a rapid-acting insulin made by Sanofi-aventis " = "Apidra (insulin glulisin) er et hurtigvirkende insulin laget av Sanofi-aventis"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Autorisasjon avslått"; - -/* Title for basal dose type */ -"Basal" = "Basal"; - -/* Title text for basal rates */ -"Basal Rates" = "Basal-satser"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Karb forhold"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Autorisasjon avslått"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Denne testen kan slettes fra Helse-appen"; - -/* Generic pump error description */ -"Communication Failure" = "Kommunikasjonsfeil"; - -/* Failure reason for uncertain delivery */ -"Communications interrupted during insulin delivery command." = "Kommunikasjonen ble avbrutt ved administrasjon av insulin."; - -/* Generic pump error description */ -"Connection Failure" = "Tilkoblingsfeil"; - -/* Title text for glucose target range */ -"Correction Range" = "Korreksjonsområde"; - -/* Descriptive text for glucose target range (1: app name) */ -"Correction Range is the glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin and helping you calculate your boluses." = "Korreksjonsområde er blodsukkerverdien (eller verdiområdet) som du vil at %1$@ skal sikte på for å justere basalinsulinet og hjelpe deg med å beregne bolusene dine."; - -/* Description of critical software update needed */ -"Critical Update" = "Kritisk oppdatering"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Leveringsgrenser"; - -/* Generic pump error description */ -"Device Refused" = "Enheten nektet"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Verifiser at karbohydratoppføring eksisterer for den valgte datoen"; - -/* Glucose trend down */ -"Falling" = "Synker"; - -/* Glucose trend down-down */ -"Falling fast" = "Synker raskt"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Synker veldig raskt"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Description for fiasp insulin type */ -"Fiasp is a mealtime insulin aspart formulation with the addition of nicotinamide (vitamin B3) made by Novo Nordisk" = "Fiasp er en måltidsformulering av insulin aspart i tillegg til nikotinamid (vitamin B3) laget av Novo Nordisk"; - -/* Glucose trend flat */ -"Flat" = "Flatt"; - -/* Descriptive text for fast acting insulin model (1: app name) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from different models for the peak activity." = "For hurtigvirkende insulin antar %1$@ at det virker aktivt i 6 timer. Du kan velge mellom ulike modeller for toppaktiviteten."; - -/* The short unit display string for grams per U */ -"g/U" = "g/E"; - -/* Title text for glucose safety limit */ -"Glucose Safety Limit" = "Sikkerhetsgrense for blodsukker"; - -/* The long unit display string for a singular hour */ -"Hour" = "Time"; - -/* The long unit display string for hours */ -"Hours" = "Timer"; - -/* Brand name for humalog insulin type */ -"Humalog" = "Humalog"; - -/* Title for Humalog insulin type */ -"Humalog (insulin lispro)" = "Humalog (insulin lispro)"; - -/* Description for humalog insulin type */ -"Humalog (insulin lispro) is a rapid-acting insulin made by Eli Lilly" = "Humalog (insulin lispro) er et hurtigvirkende insulin laget av Eli Lilly"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Insulin modell"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Insulinsensitivitet"; - -/* Generic pump error description */ -"Invalid Configuration" = "Ugyldig konfigurasjon"; - -/* Brand name for lyumjev insulin type - Title for Lyumjev insulin type */ -"Lyumjev" = "Lyumjev"; - -/* Description for lyumjev insulin type */ -"Lyumjev is a mealtime insulin lispro formulation with the addition of citrate and treprostinil made by Eli Lilly" = "Lyumjev er en insulin lispro-formulering for måltider med tillegg av citrat og treprostinil laget av Eli Lilly"; - -/* Recovery suggestion for uncertain delivery */ -"Make sure your pump is within communication range of your phone." = "Kontroller at pumpen er innenfor kommunikasjonsområdet til telefonen."; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Maks basalgrense"; - -/* Descriptive text for maximum basal rate (1: app name) */ -"Maximum Basal Rate is the highest temporary basal rate %1$@ is allowed to set." = "Maksimal basaldose er den høyeste midlertidige basaldosen %1$@ er tillatt å angi."; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Maks bolus"; - -/* Descriptive text for maximum bolus */ -"Maximum Bolus is the highest bolus amount you can deliver at one time to cover carbs or bring down high glucose." = "Maksimal bolus er den høyeste bolusmengden du kan gi på en gang for å dekke karbohydrater eller redusere høyt blodsukker."; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/E"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/E"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Trenger tilsyn"; - -/* Description of no software update needed */ -"No Update" = "Ingen oppdatering"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "Ingen verdier funnet"; - -/* Brand name for novolog insulin type */ -"Novolog" = "Novolog"; - -/* Title for Novolog insulin type */ -"Novolog (insulin aspart)" = "Novolog (insulin aspart)"; - -/* Description for novolog insulin type */ -"NovoLog (insulin aspart) is a rapid-acting insulin made by Novo Nordisk" = "NovoLog (insulin aspart) er et hurtigvirkende insulin laget av Novo Nordisk"; - -/* Sensor state description for the valid state */ -"OK" = "Ok"; - -/* Descriptive text for saving settings outside the recommended range */ -"One or more of the values you have entered is outside of what is typically recommended for most people." = "En verdi du har lagt inn er lavere enn det som vanligvis anbefales for de fleste."; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Vennligst aktiver deling i Helse-appen på nytt"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Pre-måltid"; - -/* Description of supported software update needed */ -"Recommended Update" = "Anbefalt oppdatering"; - -/* Title for resume dose type */ -"Resumed" = "Gjenopptatt"; - -/* Glucose trend up */ -"Rising" = "Stiger"; - -/* Glucose trend up-up */ -"Rising fast" = "Stiger fort"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Stiger veldig fort"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"Some of the values you have entered are outside of what is typically recommended for most people." = "Noen av verdiene du har lagt inn er utenfor det som vanligvis anbefales for de fleste."; - -/* Title for suspend dose type */ -"Suspended" = "Suspendert"; - -/* Title for temp basal dose type */ -"Temp Basal" = "Midlertidig basal"; - -/* Descriptive text for pre-meal correction range override */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Reduser blodsukkermålet ditt midlertidig før et måltid for å påvirke blodsukkertoppene etter måltidet."; - -/* Descriptive text for workout correction range override */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Øk blodsukkermålet ditt midlertidig før, under eller etter fysisk aktivitet for å redusere risikoen for hendelser med lavt blodsukker."; - -/* Descriptive text for guardrail high value warning */ -"The value you have entered is higher than what is typically recommended for most people." = "Verdien du har lagt inn er høyere enn det som vanligvis anbefales for de fleste."; - -/* Descriptive text for guardrail low value warning */ -"The value you have entered is lower than what is typically recommended for most people." = "Verdien du har lagt inn er lavere enn det som vanligvis anbefales for de fleste."; - -/* Descriptive text for guardrail high value warning */ -"The values you have entered are outside of what is typically recommended for most people." = "Verdiene du har lagt inn er utenfor det som vanligvis anbefales for de fleste."; - -/* The short unit display string for international units of insulin */ -"U" = "E"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "E/t"; - -/* Error description for uncertain delivery */ -"Uncertain Delivery" = "Usikker levering"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Enhet"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Enhet/time"; - -/* The long unit display string for international units of insulin */ -"Units" = "Enheter"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Enheter/time"; - -/* Description of informational software update needed */ -"Update Available" = "Oppdatering tilgjengelig"; - -/* Title for workout mode */ -"Workout" = "Trening"; - -/* Descriptive text for basal rate */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Din basaldose av insulin er antall enheter per time du vil bruke for å dekke ditt bakgrunnsinsulinbehov."; - -/* Descriptive text for carb ratio */ -"Your Carb Ratio is the number of grams of carbohydrates covered by one unit of insulin." = "Karbforholdet ditt er antall gram karbohydrater som dekkes av én enhet insulin."; - -/* Descriptive text for insulin sensitivity */ -"Your Insulin Sensitivities refer to the drop in glucose expected from one unit of insulin." = "Din insulinfølsomhet refererer til fallet i blodsukker som forventes fra én enhet insulin."; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/nl.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/nl.lproj/Localizable.strings deleted file mode 100644 index 90214f217..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/nl.lproj/Localizable.strings +++ /dev/null @@ -1,267 +0,0 @@ -/* Format for correction range override therapy setting card */ -"%@ Range" = "%@ bereik"; - -/* Descriptive format string for glucose safety limit (1: app name) */ -"%1$@ will deliver basal and recommend bolus insulin only if your glucose is predicted to be above this limit for the next three hours." = "%1$@ zal alleen een basaal geven en een bolusinsuline aanbevelen als je glucose de komende drie uur hoger zal zijn dan deze limiet."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"A value you have entered is higher than what is typically recommended for most people." = "Een waarde die je hebt ingevoerd is hoger dan wat gebruikelijk voor de meeste mensen wordt aanbevolen."; - -/* Descriptive text for guardrail low value warning for schedule interface */ -"A value you have entered is lower than what is typically recommended for most people." = "Een waarde die je hebt ingevoerd is lager dan wat gebruikelijk voor de meeste mensen wordt aanbevolen."; - -/* Brand name for afrezza insulin type - Title for Afrezza insulin type */ -"Afrezza" = "Afrezza"; - -/* Description for afrezza insulin type */ -"Afrezza is an ultra rapid-acting mealtime insulin that is breathed in through your lungs using an oral inhaler and made by MannKind" = "Afrezza is een ultrasnelwerkende maaltijdinsuline die via je longen wordt ingeademd met een orale inhalator en wordt gemaakt door MannKind"; - -/* Brand name for apidra insulin type */ -"Apidra" = "Apidra"; - -/* Title for Apidra insulin type */ -"Apidra (insulin glulisine)" = "Apidra (insuline glulisine)"; - -/* Description for apidra insulin type */ -"Apidra (insulin glulisine) is a rapid-acting insulin made by Sanofi-aventis " = "Apidra (insuline glulisine) is een snelwerkende insuline gemaakt door Sanofi-aventis"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Autorisatie Geweigerd"; - -/* Title for basal dose type */ -"Basal" = "Basaal"; - -/* Title text for basal rates */ -"Basal Rates" = "Basaalsnelheden"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Koolhydraatratio's"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Autorisatie Geweigerd"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Dit voorbeeld kan verwijderd worden uit de app Gezondheid"; - -/* Generic pump error description */ -"Communication Failure" = "Communicatiefout"; - -/* Failure reason for uncertain delivery */ -"Communications interrupted during insulin delivery command." = "Communicatie onderbroken tijdens het commando voor insulinetoediening."; - -/* Generic pump error description */ -"Connection Failure" = "Verbindingsfout"; - -/* Title text for glucose target range */ -"Correction Range" = "Correctiebereik"; - -/* Descriptive text for glucose target range (1: app name) */ -"Correction Range is the glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin and helping you calculate your boluses." = "Correctiebereik is de glucosewaarde (of een bereik van waarden) waar je wilt dat %1$@ naar streeft bij het aanpassen van je basale insuline en het berekenen van je bolussen."; - -/* Description of critical software update needed */ -"Critical Update" = "Kritieke Update"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Toedieningslimieten"; - -/* Generic pump error description */ -"Device Refused" = "Apparaat Geweigerd"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Zorg ervoor dat er koolhydraten gegevens bestaan voor de opgegeven datum"; - -/* Glucose trend down */ -"Falling" = "Dalend"; - -/* Glucose trend down-down */ -"Falling fast" = "Snel dalend"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Zeer snel dalend"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Description for fiasp insulin type */ -"Fiasp is a mealtime insulin aspart formulation with the addition of nicotinamide (vitamin B3) made by Novo Nordisk" = "Fiasp is een maaltijdinsuline aspart formule met de toevoeging van nicotinamide (vitamine B3) gemaakt door Novo Nordisk"; - -/* Glucose trend flat */ -"Flat" = "Gelijk"; - -/* Descriptive text for fast acting insulin model (1: app name) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from different models for the peak activity." = "Voor snelwerkende insuline gaat %1$@ ervan uit dat het 6 uur lang actief is. Je kunt kiezen uit verschillende modellen voor de piekactiviteit."; - -/* The short unit display string for grams per U */ -"g/U" = "g/E"; - -/* Title text for glucose safety limit */ -"Glucose Safety Limit" = "Glucoseveiligheidslimiet"; - -/* The long unit display string for a singular hour */ -"Hour" = "Uur"; - -/* The long unit display string for hours */ -"Hours" = "Uur"; - -/* Brand name for humalog insulin type */ -"Humalog" = "Humalog"; - -/* Title for Humalog insulin type */ -"Humalog (insulin lispro)" = "Humalog (insulin lispro)"; - -/* Description for humalog insulin type */ -"Humalog (insulin lispro) is a rapid-acting insulin made by Eli Lilly" = "Humalog (insuline lispro) is een snelwerkende insuline gemaakt door Eli Lilly"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Insulinemodel"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Insulinegevoeligheden"; - -/* Generic pump error description */ -"Invalid Configuration" = "Ongeldige Configuratie"; - -/* Brand name for lyumjev insulin type - Title for Lyumjev insulin type */ -"Lyumjev" = "Lyumjev"; - -/* Description for lyumjev insulin type */ -"Lyumjev is a mealtime insulin lispro formulation with the addition of citrate and treprostinil made by Eli Lilly" = "Lyumjev is een maaltijdinsuline lispro formule met de toevoeging van citraat en treprostinil gemaakt door Eli Lilly"; - -/* Recovery suggestion for uncertain delivery */ -"Make sure your pump is within communication range of your phone." = "Zorg ervoor dat je pomp binnen het communicatiebereik van je telefoon ligt."; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Maximale Basaalsnelheid"; - -/* Descriptive text for maximum basal rate (1: app name) */ -"Maximum Basal Rate is the highest temporary basal rate %1$@ is allowed to set." = "Maximale Basaalsnelheid is de maximale tijdelijke basaalsnelheid die %1$@ mag instellen."; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Maximale Bolus"; - -/* Descriptive text for maximum bolus */ -"Maximum Bolus is the highest bolus amount you can deliver at one time to cover carbs or bring down high glucose." = "Maximale Bolus is de hoogste bolushoeveelheid die je in één keer kunt toedienen om koolhydraten te dekken of om een hoge glucose te verlagen."; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/E"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/E"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Aandacht Nodig"; - -/* Description of no software update needed */ -"No Update" = "Geen Update"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "Geen waarden gevonden"; - -/* Brand name for novolog insulin type */ -"Novolog" = "Novolog"; - -/* Title for Novolog insulin type */ -"Novolog (insulin aspart)" = "Novolog (insulin aspart)"; - -/* Description for novolog insulin type */ -"NovoLog (insulin aspart) is a rapid-acting insulin made by Novo Nordisk" = "NovoLog (insuline aspart) is een snelwerkende insuline gemaakt door Novo Nordisk"; - -/* Sensor state description for the valid state */ -"OK" = "Ok"; - -/* Descriptive text for saving settings outside the recommended range */ -"One or more of the values you have entered is outside of what is typically recommended for most people." = "Een of meer van de waarden die je hebt ingevoerd valt buiten wat algemeen wordt aanbevolen."; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Stel delen opnieuw in in Gezondheid, alsjeblieft"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Pre-Meal"; - -/* Description of supported software update needed */ -"Recommended Update" = "Aanbevolen Update"; - -/* Title for resume dose type */ -"Resumed" = "Hervatten"; - -/* Glucose trend up */ -"Rising" = "Stijgend"; - -/* Glucose trend up-up */ -"Rising fast" = "Snel stijgend"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Zeer snel stijgend"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"Some of the values you have entered are outside of what is typically recommended for most people." = "Sommige van de waarden die u hebt ingevoerd vallen buiten wat algemeen wordt aanbevolen."; - -/* Title for suspend dose type */ -"Suspended" = "Onderbroken"; - -/* Title for temp basal dose type */ -"Temp Basal" = "Tijdelijk Basaal"; - -/* Descriptive text for pre-meal correction range override */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Tijdelijk verlagen van je glucosedoel vóór de maaltijd om de kans op post-maaltijd glucosepieken te verkleinen."; - -/* Descriptive text for workout correction range override */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Verhoog tijdelijk je glucosedoel voor, gedurende of na fysieke activiteit om het risico van lage glucosewaarden te verminderen."; - -/* Descriptive text for guardrail high value warning */ -"The value you have entered is higher than what is typically recommended for most people." = "Een waarde die je hebt ingevoerd is hoger dan wat algemeen voor de meeste mensen wordt aanbevolen."; - -/* Descriptive text for guardrail low value warning */ -"The value you have entered is lower than what is typically recommended for most people." = "Een waarde die je hebt ingevoerd is lager dan wat algemeen voor de meeste mensen wordt aanbevolen."; - -/* Descriptive text for guardrail high value warning */ -"The values you have entered are outside of what is typically recommended for most people." = "Sommige van de waarden die u hebt ingevoerd vallen buiten wat algemeen wordt aanbevolen."; - -/* The short unit display string for international units of insulin */ -"U" = "E"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "E/uur"; - -/* Error description for uncertain delivery */ -"Uncertain Delivery" = "Toediening Onzeker"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Eenheid"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Eenheid/uur"; - -/* The long unit display string for international units of insulin */ -"Units" = "Eenheden"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Eenheden/uur"; - -/* Description of informational software update needed */ -"Update Available" = "Update Beschikbaar"; - -/* Title for workout mode */ -"Workout" = "Training"; - -/* Descriptive text for basal rate */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Je basale insulinesnelheid is het aantal eenheden per uur dat je wilt toedienen om in je basale insulinebehoefte te voorzien."; - -/* Descriptive text for carb ratio */ -"Your Carb Ratio is the number of grams of carbohydrates covered by one unit of insulin." = "Je koolhydraatratio is het aantal gram koolhydraten dat wordt verwerkt door één eenheid insuline."; - -/* Descriptive text for insulin sensitivity */ -"Your Insulin Sensitivities refer to the drop in glucose expected from one unit of insulin." = "Je Insulinegevoeligheid is de daling van de glucose verwacht van één eenheid insuline."; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/pl.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/pl.lproj/Localizable.strings deleted file mode 100644 index fd86aaad0..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/pl.lproj/Localizable.strings +++ /dev/null @@ -1,267 +0,0 @@ -/* Format for correction range override therapy setting card */ -"%@ Range" = "%@ Zakres"; - -/* Descriptive format string for glucose safety limit (1: app name) */ -"%1$@ will deliver basal and recommend bolus insulin only if your glucose is predicted to be above this limit for the next three hours." = "%1$@ będzie dostarczać insulinę podstawową i zalecaną w bolusie tylko wtedy, gdy przewiduje się, że poziom glukozy przekroczy ten limit przez następne trzy godziny."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"A value you have entered is higher than what is typically recommended for most people." = "Wprowadzona wartość jest wyższa niż zwykle zalecana dla większości osób."; - -/* Descriptive text for guardrail low value warning for schedule interface */ -"A value you have entered is lower than what is typically recommended for most people." = "Wprowadzona wartość jest niższa niż zwykle zalecana dla większości osób."; - -/* Brand name for afrezza insulin type - Title for Afrezza insulin type */ -"Afrezza" = "Afrezza"; - -/* Description for afrezza insulin type */ -"Afrezza is an ultra rapid-acting mealtime insulin that is breathed in through your lungs using an oral inhaler and made by MannKind" = "Afrezza to ultraszybko działająca doposiłkowa insulina wziewna, którą wdycha się przy użyciu doustnego inhalatora, wytwarzana przez firmę MannKind."; - -/* Brand name for apidra insulin type */ -"Apidra" = "Apidra"; - -/* Title for Apidra insulin type */ -"Apidra (insulin glulisine)" = "Apidra (insulina glulizynowa)"; - -/* Description for apidra insulin type */ -"Apidra (insulin glulisine) is a rapid-acting insulin made by Sanofi-aventis " = "Apidra (insulina glulizynowa) to szybko działająca insulina firmy Sanofi-Aventis."; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Odmowa autoryzacji"; - -/* Title for basal dose type */ -"Basal" = "Dawka podstawowa"; - -/* Title text for basal rates */ -"Basal Rates" = "Dawka Podstawowa (Baza)"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Współczynniki węglowodanowe"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Odmowa autoryzacji"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Ten wynik może być usunięty z aplikacji Zdrowie"; - -/* Generic pump error description */ -"Communication Failure" = "Błąd komunikacji"; - -/* Failure reason for uncertain delivery */ -"Communications interrupted during insulin delivery command." = "Komunikacja przerwana podczas polecenia podania insuliny."; - -/* Generic pump error description */ -"Connection Failure" = "Błąd połączenia"; - -/* Title text for glucose target range */ -"Correction Range" = "Zakres docelowy"; - -/* Descriptive text for glucose target range (1: app name) */ -"Correction Range is the glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin and helping you calculate your boluses." = "Zakres docelowy (zakres korekty) to wartość glukozy (lub zakres wartości), do której chcesz dążyć %1$@ podczas dostosowywania insuliny bazowej i pomagania w obliczaniu bolusów."; - -/* Description of critical software update needed */ -"Critical Update" = "Krytyczna aktualizacja"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Limity podawania"; - -/* Generic pump error description */ -"Device Refused" = "Urządzenie odmówiło"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Upewnij się, że wartość istnieje w tej dacie"; - -/* Glucose trend down */ -"Falling" = "Spadek"; - -/* Glucose trend down-down */ -"Falling fast" = "Szybki spadek"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Bardzo szybki spadek"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Description for fiasp insulin type */ -"Fiasp is a mealtime insulin aspart formulation with the addition of nicotinamide (vitamin B3) made by Novo Nordisk" = "Fiasp to insulina aspart do posiłków z dodatkiem nikotynamidu (witaminy B3) firmy Novo Nordisk."; - -/* Glucose trend flat */ -"Flat" = "Powolna zmiana"; - -/* Descriptive text for fast acting insulin model (1: app name) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from different models for the peak activity." = "W przypadku szybko działającej insuliny %1$@ zakłada jej działanie przez 6 godzin. Możesz wybrać spośród różnych modeli szczytowej aktywności."; - -/* The short unit display string for grams per U */ -"g/U" = "g/J"; - -/* Title text for glucose safety limit */ -"Glucose Safety Limit" = "Granica bezpiecznego poziomu glukozy"; - -/* The long unit display string for a singular hour */ -"Hour" = "Godzina"; - -/* The long unit display string for hours */ -"Hours" = "Godziny"; - -/* Brand name for humalog insulin type */ -"Humalog" = "Humalog"; - -/* Title for Humalog insulin type */ -"Humalog (insulin lispro)" = "Humalog (insulina lispro)"; - -/* Description for humalog insulin type */ -"Humalog (insulin lispro) is a rapid-acting insulin made by Eli Lilly" = "Humalog (insulina lispro) to szybko działająca insulina firmy Eli Lilly"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Model insuliny"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Wrażliwość na insulinę (ISF)"; - -/* Generic pump error description */ -"Invalid Configuration" = "Nieprawidłowa konfiguracja"; - -/* Brand name for lyumjev insulin type - Title for Lyumjev insulin type */ -"Lyumjev" = "Lyumjev"; - -/* Description for lyumjev insulin type */ -"Lyumjev is a mealtime insulin lispro formulation with the addition of citrate and treprostinil made by Eli Lilly" = "Lyumjev to preparat insuliny lispro do posiłków z dodatkiem cytrynianu i treprostinilu wyprodukowany przez firmę Eli Lilly."; - -/* Recovery suggestion for uncertain delivery */ -"Make sure your pump is within communication range of your phone." = "Upewnij się, że pompa jest połączona z Twoim telefonem."; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Maksymalna dawka podstawowa"; - -/* Descriptive text for maximum basal rate (1: app name) */ -"Maximum Basal Rate is the highest temporary basal rate %1$@ is allowed to set." = "Maksymalna dawka podstawowa to najwyższa tymczasowa dawka podstawowa, jaką %1$@ może ustawić."; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Maksymalny bolus"; - -/* Descriptive text for maximum bolus */ -"Maximum Bolus is the highest bolus amount you can deliver at one time to cover carbs or bring down high glucose." = "Maksymalny bolus to największa wielkość bolusa, jaką można podać w jednym czasie, aby pokryć węglowodany lub obniżyć wysoki poziom glukozy."; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/J"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/J"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Potrzebuje uwagi"; - -/* Description of no software update needed */ -"No Update" = "Brak aktualizacji"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "Nie znaleziono wartości"; - -/* Brand name for novolog insulin type */ -"Novolog" = "Novolog"; - -/* Title for Novolog insulin type */ -"Novolog (insulin aspart)" = "Novolog (insulina aspart)"; - -/* Description for novolog insulin type */ -"NovoLog (insulin aspart) is a rapid-acting insulin made by Novo Nordisk" = "NovoLog (insulina aspart) to szybko działająca insulina firmy Novo Nordisk."; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* Descriptive text for saving settings outside the recommended range */ -"One or more of the values you have entered is outside of what is typically recommended for most people." = "Co najmniej jedna z wprowadzonych wartości wykracza poza to, co jest zwykle zalecane dla większości osób."; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Włącz ponownie udostępnianie w aplikacji Zdrowie"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Przed posiłkiem"; - -/* Description of supported software update needed */ -"Recommended Update" = "Zalecana aktualizacja"; - -/* Title for resume dose type */ -"Resumed" = "Wznowione"; - -/* Glucose trend up */ -"Rising" = "Wzrost"; - -/* Glucose trend up-up */ -"Rising fast" = "Szybki wzrost"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Bardzo szybki wzrost"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"Some of the values you have entered are outside of what is typically recommended for most people." = "Niektóre z wprowadzonych wartości wykraczają poza to, co jest zwykle zalecane dla większości osób."; - -/* Title for suspend dose type */ -"Suspended" = "Wstrzymane"; - -/* Title for temp basal dose type */ -"Temp Basal" = "Tymczasowa dawka podstawowa"; - -/* Descriptive text for pre-meal correction range override */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Tymczasowo obniż docelowy poziom glukozy przed posiłkiem, aby ograniczyć gwałtowny wzrost glukozy po posiłku."; - -/* Descriptive text for workout correction range override */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Tymczasowo zwiększ docelowy poziom glukozy przed, w trakcie lub po aktywności fizycznej, aby zmniejszyć ryzyko wystąpienia niskiego poziomu glukozy (Hipoglikemia)."; - -/* Descriptive text for guardrail high value warning */ -"The value you have entered is higher than what is typically recommended for most people." = "Wprowadzona wartość jest wyższa niż zwykle zalecana dla większości osób."; - -/* Descriptive text for guardrail low value warning */ -"The value you have entered is lower than what is typically recommended for most people." = "Wprowadzona wartość jest niższa niż zwykle zalecana dla większości osób."; - -/* Descriptive text for guardrail high value warning */ -"The values you have entered are outside of what is typically recommended for most people." = "Wprowadzone wartości wykraczają poza to, co jest zwykle zalecane dla większości osób."; - -/* The short unit display string for international units of insulin */ -"U" = "J"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "J/godz"; - -/* Error description for uncertain delivery */ -"Uncertain Delivery" = "Niepewne podanie"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Jednostka"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Jednostka/godzinę"; - -/* The long unit display string for international units of insulin */ -"Units" = "Jednostki"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Jednostki/godzinę"; - -/* Description of informational software update needed */ -"Update Available" = "Dostępna aktualizacja"; - -/* Title for workout mode */ -"Workout" = "Wysiłek fizyczny"; - -/* Descriptive text for basal rate */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Dawka podstawowa insuliny to liczba jednostek na godzinę, którą chcesz wykorzystać do pokrycia podstawowego zapotrzebowania na insulinę."; - -/* Descriptive text for carb ratio */ -"Your Carb Ratio is the number of grams of carbohydrates covered by one unit of insulin." = "Twój Współczynnik Węglowodanowy to liczba gramów węglowodanów rekompensowanych przez jedną jednostkę insuliny."; - -/* Descriptive text for insulin sensitivity */ -"Your Insulin Sensitivities refer to the drop in glucose expected from one unit of insulin." = "Wrażliwość na insulinę odnosi się do oczekiwanego spadku glukozy po jednej jednostce insuliny."; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/pt-BR.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/pt-BR.lproj/Localizable.strings deleted file mode 100644 index c3a402cf9..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,130 +0,0 @@ -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Autorização negada"; - -/* Title text for basal rates */ -"Basal Rates" = "Taxas Basais"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Taxas de Carbs"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Autorização negada"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Este exemplo pode ser excluído do app Saúde"; - -/* Generic pump error description */ -"Communication Failure" = "Falha de Comunicação"; - -/* Generic pump error description */ -"Connection Failure" = "Falha na Conexão"; - -/* Title text for glucose target range */ -"Correction Range" = "Faixa de Correção"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Limites de Entrega"; - -/* Generic pump error description */ -"Device Refused" = "Dispositivo Recusado"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Verifique se os dados de carboidratos existem na data especificada"; - -/* Glucose trend down */ -"Falling" = "Caindo"; - -/* Glucose trend down-down */ -"Falling fast" = "Caindo rápido"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Caindo muito rápido"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Glucose trend flat */ -"Flat" = "Estável"; - -/* The short unit display string for grams per U */ -"g/U" = "g/U"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Modelo de Insulina"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Sensibilidades a Insulina"; - -/* Generic pump error description */ -"Invalid Configuration" = "Configuração Inválida"; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Taxa Basal Máxima"; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Bolus Máximo"; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/U"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/U"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Precisa de Atenção"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "Nenhum valor encontrado"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Reative o compartilhamento no app Saúde"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Pré-Refeição"; - -/* Glucose trend up */ -"Rising" = "Subindo"; - -/* Glucose trend up-up */ -"Rising fast" = "Subindo rápido"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Subindo muito rápido"; - -/* Title for suspend dose type */ -"Suspended" = "Suspenso"; - -/* The short unit display string for international units of insulin */ -"U" = "U"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "U/hr"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Unidade"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Unidade/hora"; - -/* The long unit display string for international units of insulin */ -"Units" = "Unidades"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Unidades/hora"; - -/* Title for workout mode */ -"Workout" = "Exercício"; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/ro.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/ro.lproj/Localizable.strings deleted file mode 100644 index 038e0eea3..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/ro.lproj/Localizable.strings +++ /dev/null @@ -1,267 +0,0 @@ -/* Format for correction range override therapy setting card */ -"%@ Range" = "%@ Interval"; - -/* Descriptive format string for glucose safety limit (1: app name) */ -"%1$@ will deliver basal and recommend bolus insulin only if your glucose is predicted to be above this limit for the next three hours." = "%1$@ va livra bazala şi bolusul recomandat numai dacă glucoza este estimată a fi peste această limită pentru următoarele trei ore."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"A value you have entered is higher than what is typically recommended for most people." = "Valoarea pe care ați introdus-o este mai mare decât cea recomandată de obicei pentru majoritatea oamenilor."; - -/* Descriptive text for guardrail low value warning for schedule interface */ -"A value you have entered is lower than what is typically recommended for most people." = "Valoarea pe care ați introdus-o este mai mica decât cea recomandată de obicei pentru majoritatea oamenilor."; - -/* Brand name for afrezza insulin type - Title for Afrezza insulin type */ -"Afrezza" = "Afrezza"; - -/* Description for afrezza insulin type */ -"Afrezza is an ultra rapid-acting mealtime insulin that is breathed in through your lungs using an oral inhaler and made by MannKind" = "Afrezza este o insulină cu acțiune ultra rapidă în timpul mesei, care este inspirată prin plămâni folosind un inhalator oral și produsă de MannKind."; - -/* Brand name for apidra insulin type */ -"Apidra" = "Apidra"; - -/* Title for Apidra insulin type */ -"Apidra (insulin glulisine)" = "Apidra (insulină glulisine)"; - -/* Description for apidra insulin type */ -"Apidra (insulin glulisine) is a rapid-acting insulin made by Sanofi-aventis " = "Apidra (insulina glulizină) este o insulină cu acțiune rapidă produsă de Sanofi-aventis"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Autorizare refuzată"; - -/* Title for basal dose type */ -"Basal" = "Bazală"; - -/* Title text for basal rates */ -"Basal Rates" = "Rate bazale"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Raport carbohidrați/insulină"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Autorizare refuzată"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Acest exemplu poate fi șters din aplicația Sănătate"; - -/* Generic pump error description */ -"Communication Failure" = "Eroare de comunicare"; - -/* Failure reason for uncertain delivery */ -"Communications interrupted during insulin delivery command." = "Comunicații întrerupte în timpul comenzii de livrare a insulinei."; - -/* Generic pump error description */ -"Connection Failure" = "Eroare de conectare"; - -/* Title text for glucose target range */ -"Correction Range" = "Interval țintă pentru corecție"; - -/* Descriptive text for glucose target range (1: app name) */ -"Correction Range is the glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin and helping you calculate your boluses." = "Intervalul de corecție este valoarea glicemiei (sau intervalul de valori) spre care doriți ca %1$@ să țintească în ajustarea insulinei bazale și în calculul bolusurilor."; - -/* Description of critical software update needed */ -"Critical Update" = "Actualizare critică"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Limite de livrare"; - -/* Generic pump error description */ -"Device Refused" = "Dispozitiv refuzat"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Asigurați-vă că există date despre carbohidrați pentru data specificată"; - -/* Glucose trend down */ -"Falling" = "În scădere"; - -/* Glucose trend down-down */ -"Falling fast" = "În scădere rapidă"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "În scădere foarte rapidă"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Description for fiasp insulin type */ -"Fiasp is a mealtime insulin aspart formulation with the addition of nicotinamide (vitamin B3) made by Novo Nordisk" = "Fiasp este o formă de insulină aspart administrată în timpul mesei, cu adaos de nicotinamidă (vitamina B3) produsă de Novo Nordisk"; - -/* Glucose trend flat */ -"Flat" = "Constantă"; - -/* Descriptive text for fast acting insulin model (1: app name) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from different models for the peak activity." = "Pentru insulina cu acțiune rapida, %1$@ presupune ca funcționează activ timp de 6 ore. Poți alege dintre modele diferite pentru vârful acțiunii."; - -/* The short unit display string for grams per U */ -"g/U" = "g/U"; - -/* Title text for glucose safety limit */ -"Glucose Safety Limit" = "Limita de siguranță a glicemiei"; - -/* The long unit display string for a singular hour */ -"Hour" = "Oră"; - -/* The long unit display string for hours */ -"Hours" = "Ore"; - -/* Brand name for humalog insulin type */ -"Humalog" = "Humalog"; - -/* Title for Humalog insulin type */ -"Humalog (insulin lispro)" = "Humalog (insulină lispro)"; - -/* Description for humalog insulin type */ -"Humalog (insulin lispro) is a rapid-acting insulin made by Eli Lilly" = "Humalog (insulina lispro) este o insulină cu acțiune rapidă produsă de Eli Lilly"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Modelul de insulină"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Factor de sensibilitate la insulină"; - -/* Generic pump error description */ -"Invalid Configuration" = "Configurație invalidă"; - -/* Brand name for lyumjev insulin type - Title for Lyumjev insulin type */ -"Lyumjev" = "Lyumjev"; - -/* Description for lyumjev insulin type */ -"Lyumjev is a mealtime insulin lispro formulation with the addition of citrate and treprostinil made by Eli Lilly" = "Lyumjev este o formulă de insulină lispro la masă, cu adaos de citrat și treprostinil, produse de Eli Lilly"; - -/* Recovery suggestion for uncertain delivery */ -"Make sure your pump is within communication range of your phone." = "Asigură-te că pompa ta se află în raza de comunicare a telefonului."; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Rată bazală maximă"; - -/* Descriptive text for maximum basal rate (1: app name) */ -"Maximum Basal Rate is the highest temporary basal rate %1$@ is allowed to set." = "Rata bazală maximă este cea mai mare rată bazală temporară pe care %1$@ are voie să o seteze."; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Bolus maxim"; - -/* Descriptive text for maximum bolus */ -"Maximum Bolus is the highest bolus amount you can deliver at one time to cover carbs or bring down high glucose." = "Bolusul maxim este cea mai mare cantitate de insulina pe care o poți livra instantaneu pentru a acoperi carbohidrați sau pentru a corecta o glicemie mare."; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/U"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/U"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Necesită atenție"; - -/* Description of no software update needed */ -"No Update" = "Nicio actualizare"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "Nu s-au găsit valori"; - -/* Brand name for novolog insulin type */ -"Novolog" = "Novolog"; - -/* Title for Novolog insulin type */ -"Novolog (insulin aspart)" = "Novolog (insulină aspart)"; - -/* Description for novolog insulin type */ -"NovoLog (insulin aspart) is a rapid-acting insulin made by Novo Nordisk" = "NovoLog (insulină aspart) este o insulină cu acțiune rapidă produsă de Novo Nordisk"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* Descriptive text for saving settings outside the recommended range */ -"One or more of the values you have entered is outside of what is typically recommended for most people." = "Unele dintre valorile introduse sunt în afara a ceea ce este recomandat de obicei pentru majoritatea oamenilor."; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Vă rugăm să re-activați partajarea datelor în Sănătate"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Preprandial"; - -/* Description of supported software update needed */ -"Recommended Update" = "Actualizare recomandată"; - -/* Title for resume dose type */ -"Resumed" = "Reluat"; - -/* Glucose trend up */ -"Rising" = "În creștere"; - -/* Glucose trend up-up */ -"Rising fast" = "În creștere rapidă"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "În creștere foarte rapidă"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"Some of the values you have entered are outside of what is typically recommended for most people." = "Câteva dintre valorile introduse sunt în afara a ceea ce este recomandat de obicei pentru majoritatea oamenilor."; - -/* Title for suspend dose type */ -"Suspended" = "Suspendat"; - -/* Title for temp basal dose type */ -"Temp Basal" = "Bazală temporară"; - -/* Descriptive text for pre-meal correction range override */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Reduceți temporar glicemia țintă înainte de masă pentru a avea un impact asupra vârfurilor postprandiale."; - -/* Descriptive text for workout correction range override */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Creșteți temporar valoarea ținta a glicemiei înainte, în timpul sau după activitatea fizică pentru a reduce riscul de apariție a hipoglicemiei."; - -/* Descriptive text for guardrail high value warning */ -"The value you have entered is higher than what is typically recommended for most people." = "Valoarea pe care ați introdus-o este mai mare decât cea recomandată de obicei pentru majoritatea oamenilor."; - -/* Descriptive text for guardrail low value warning */ -"The value you have entered is lower than what is typically recommended for most people." = "Valoarea pe care ați introdus-o este mai mica decât cea recomandată de obicei pentru majoritatea oamenilor."; - -/* Descriptive text for guardrail high value warning */ -"The values you have entered are outside of what is typically recommended for most people." = "Valorile introduse sunt în afara a ceea ce este recomandat de obicei pentru majoritatea oamenilor."; - -/* The short unit display string for international units of insulin */ -"U" = "U"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "U/oră"; - -/* Error description for uncertain delivery */ -"Uncertain Delivery" = "Livrare incertă"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Unități"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Unități/oră"; - -/* The long unit display string for international units of insulin */ -"Units" = "Unități"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Unități/oră"; - -/* Description of informational software update needed */ -"Update Available" = "Actualizare disponibilă"; - -/* Title for workout mode */ -"Workout" = "Activitate sportivă"; - -/* Descriptive text for basal rate */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Rata bazală de insulină este numărul de unități pe oră pe care doriți să le utilizați pentru a acoperi necesarul bazal de insulina al organismului."; - -/* Descriptive text for carb ratio */ -"Your Carb Ratio is the number of grams of carbohydrates covered by one unit of insulin." = "Raportul carbohidrați/insulina este numărul de grame de carbohidrați acoperiți de o unitate de insulină."; - -/* Descriptive text for insulin sensitivity */ -"Your Insulin Sensitivities refer to the drop in glucose expected from one unit of insulin." = "Factorul de sensibilitate la insulină se referă la scăderea glicemiei determinata de o unitate de insulină."; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/ru.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/ru.lproj/Localizable.strings deleted file mode 100644 index 140025266..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/ru.lproj/Localizable.strings +++ /dev/null @@ -1,267 +0,0 @@ -/* Format for correction range override therapy setting card */ -"%@ Range" = "%@ Диапазон"; - -/* Descriptive format string for glucose safety limit (1: app name) */ -"%1$@ will deliver basal and recommend bolus insulin only if your glucose is predicted to be above this limit for the next three hours." = "%1$@ будет вводить базу и рекомендовать болюсы, только если прогнозируется, что уровень глюкозы будет выше этого предела в течение следующих трех часов."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"A value you have entered is higher than what is typically recommended for most people." = "Введенное вами значение выше, чем обычно рекомендуется для большинства людей."; - -/* Descriptive text for guardrail low value warning for schedule interface */ -"A value you have entered is lower than what is typically recommended for most people." = "Введенное вами значение ниже того, которое обычно рекомендуется для большинства людей."; - -/* Brand name for afrezza insulin type - Title for Afrezza insulin type */ -"Afrezza" = "Afrezza"; - -/* Description for afrezza insulin type */ -"Afrezza is an ultra rapid-acting mealtime insulin that is breathed in through your lungs using an oral inhaler and made by MannKind" = "Afrezza - это инсулин сверхбыстрого действия во время еды, который вдыхается через легкие с помощью перорального ингалятора и производится MannKind"; - -/* Brand name for apidra insulin type */ -"Apidra" = "Апидра"; - -/* Title for Apidra insulin type */ -"Apidra (insulin glulisine)" = "Апидра (инсулин глюлизин)"; - -/* Description for apidra insulin type */ -"Apidra (insulin glulisine) is a rapid-acting insulin made by Sanofi-aventis " = "Апидра (инсулин глюлизин) - это инсулин быстрого действия, производимый Sanofi-aventis "; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Авторизация не состоялась"; - -/* Title for basal dose type */ -"Basal" = "Базал"; - -/* Title text for basal rates */ -"Basal Rates" = "Скорости базала"; - -/* Title for bolus dose type */ -"Bolus" = "Болюс"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Соотношения углеводов"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Авторизация не состоялась"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Этот экземпляр может быть удален из приложения Здоровье"; - -/* Generic pump error description */ -"Communication Failure" = "Ошибка связи"; - -/* Failure reason for uncertain delivery */ -"Communications interrupted during insulin delivery command." = "Связь прервана во время подачи команды на введение инсулина."; - -/* Generic pump error description */ -"Connection Failure" = "Ошибка соединения"; - -/* Title text for glucose target range */ -"Correction Range" = "Диапазон коррекции"; - -/* Descriptive text for glucose target range (1: app name) */ -"Correction Range is the glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin and helping you calculate your boluses." = "Диапазон коррекции - это значение глюкозы (или диапазон значений), к которому вы хотите, чтобы %1$@ стремился при корректировке ВБС и расчете болюсов."; - -/* Description of critical software update needed */ -"Critical Update" = "Критическое обновление"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Пределы подачи"; - -/* Generic pump error description */ -"Device Refused" = "Устройство отклонено"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Убедитесь, что данные об углеводах имеются на указанную дату"; - -/* Glucose trend down */ -"Falling" = "Падение"; - -/* Glucose trend down-down */ -"Falling fast" = "Быстрое падение"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Очень быстрое падение"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Description for fiasp insulin type */ -"Fiasp is a mealtime insulin aspart formulation with the addition of nicotinamide (vitamin B3) made by Novo Nordisk" = "Fiasp - это препарат инсулин аспарт с добавлением никотинамида (витамина B3) производства Novo Nordisk"; - -/* Glucose trend flat */ -"Flat" = "Стабильно"; - -/* Descriptive text for fast acting insulin model (1: app name) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from different models for the peak activity." = "Для быстродействующего инсулина %1$@ предполагается, что он активно работает в течение 6 часов. Вы можете выбрать различные модели для пика активности."; - -/* The short unit display string for grams per U */ -"g/U" = "g/U"; - -/* Title text for glucose safety limit */ -"Glucose Safety Limit" = "Безопасный предел глюкозы"; - -/* The long unit display string for a singular hour */ -"Hour" = "Час"; - -/* The long unit display string for hours */ -"Hours" = "Часы"; - -/* Brand name for humalog insulin type */ -"Humalog" = "Хумалог"; - -/* Title for Humalog insulin type */ -"Humalog (insulin lispro)" = "Хумалог (инсулин лизпро)"; - -/* Description for humalog insulin type */ -"Humalog (insulin lispro) is a rapid-acting insulin made by Eli Lilly" = "Хумалог (инсулин лизпро) - это инсулин быстрого действия, производимый компанией Eli Lilly."; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Модель инсулина"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Факторы чувствительности инсулина"; - -/* Generic pump error description */ -"Invalid Configuration" = "Неверная конфигурация"; - -/* Brand name for lyumjev insulin type - Title for Lyumjev insulin type */ -"Lyumjev" = "Lyumjev"; - -/* Description for lyumjev insulin type */ -"Lyumjev is a mealtime insulin lispro formulation with the addition of citrate and treprostinil made by Eli Lilly" = "Lyumjev представляет собой лекарственную форму инсулина лизпро для приема пищи с добавлением цитрата и трепростинила производства Eli Lilly."; - -/* Recovery suggestion for uncertain delivery */ -"Make sure your pump is within communication range of your phone." = "Убедитесь, что помпа находится в пределах досягаемости вашего телефона."; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Максимальная скорость базала"; - -/* Descriptive text for maximum basal rate (1: app name) */ -"Maximum Basal Rate is the highest temporary basal rate %1$@ is allowed to set." = "Максимальная базальная скорость — это самая высокая ВБС, которую может установить %1$@."; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Максимальный Болюс"; - -/* Descriptive text for maximum bolus */ -"Maximum Bolus is the highest bolus amount you can deliver at one time to cover carbs or bring down high glucose." = "Максимальный болюс - это наибольший болюс, который вы можете ввести за один раз, чтобы покрыть углеводы или снизить высокий уровень глюкозы."; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/U"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/U"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Требует внимания"; - -/* Description of no software update needed */ -"No Update" = "Нет обновлений"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "Данные не найдены"; - -/* Brand name for novolog insulin type */ -"Novolog" = "Новолог"; - -/* Title for Novolog insulin type */ -"Novolog (insulin aspart)" = "Новолог (инсулин аспарт)"; - -/* Description for novolog insulin type */ -"NovoLog (insulin aspart) is a rapid-acting insulin made by Novo Nordisk" = "NovoLog (инсулин аспарт) - инсулин быстрого действия производства Novo Nordisk"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* Descriptive text for saving settings outside the recommended range */ -"One or more of the values you have entered is outside of what is typically recommended for most people." = "Одно или несколько введенных вами значений выходят за рамки того, что обычно рекомендуется для большинства людей."; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Пожалуйста повторно разрешите совместное использование в разделе Здоровье"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "До еды"; - -/* Description of supported software update needed */ -"Recommended Update" = "Рекомендуемое обновление"; - -/* Title for resume dose type */ -"Resumed" = "Возобновлено"; - -/* Glucose trend up */ -"Rising" = "Повышение"; - -/* Glucose trend up-up */ -"Rising fast" = "Быстрое повышение"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Очень быстрое повышение"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"Some of the values you have entered are outside of what is typically recommended for most people." = "Некоторые из введенных вами значений выходят за рамки того, что обычно рекомендуется для большинства людей."; - -/* Title for suspend dose type */ -"Suspended" = "Остановлено"; - -/* Title for temp basal dose type */ -"Temp Basal" = "ВБС"; - -/* Descriptive text for pre-meal correction range override */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Временно понизьте целевое значение уровня глюкозы перед едой, чтобы уменьшить пики глюкозы после еды."; - -/* Descriptive text for workout correction range override */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Временно повышайте целевой уровень глюкозы до, во время или после физической активности, чтобы снизить риск развития событий, связанных с низким уровнем глюкозы."; - -/* Descriptive text for guardrail high value warning */ -"The value you have entered is higher than what is typically recommended for most people." = "Введенное вами значение выше, чем то, которое обычно рекомендуется для большинства людей."; - -/* Descriptive text for guardrail low value warning */ -"The value you have entered is lower than what is typically recommended for most people." = "Введенное вами значение ниже того, которое обычно рекомендуется для большинства людей."; - -/* Descriptive text for guardrail high value warning */ -"The values you have entered are outside of what is typically recommended for most people." = "Введенные вами значения выходят за рамки того, что обычно рекомендуется для большинства людей."; - -/* The short unit display string for international units of insulin */ -"U" = "ед"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "U/hr"; - -/* Error description for uncertain delivery */ -"Uncertain Delivery" = "Неопределенная подача"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Unit"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Unit/hour"; - -/* The long unit display string for international units of insulin */ -"Units" = "Единицы"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Units/hour"; - -/* Description of informational software update needed */ -"Update Available" = "Доступно обновление"; - -/* Title for workout mode */ -"Workout" = "Физическая нагрузка"; - -/* Descriptive text for basal rate */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Ваша базальная норма инсулина - это количество единиц в час, которое вы хотите использовать для покрытия своих фоновых потребностей в инсулине."; - -/* Descriptive text for carb ratio */ -"Your Carb Ratio is the number of grams of carbohydrates covered by one unit of insulin." = "Ваш углеводный коэффициент - это количество граммов углеводов, покрываемых одной единицей инсулина."; - -/* Descriptive text for insulin sensitivity */ -"Your Insulin Sensitivities refer to the drop in glucose expected from one unit of insulin." = "Ваша чувствительность к инсулину означает снижение уровня глюкозы, ожидаемое от одной единицы инсулина."; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/sk.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/sk.lproj/Localizable.strings deleted file mode 100644 index ab2d9b4a2..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/sk.lproj/Localizable.strings +++ /dev/null @@ -1,36 +0,0 @@ -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* Title text for basal rates */ -"Basal Rates" = "Bazálne dávky"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Inzulínovo sacharidový pomer"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Limity podávania"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Inzulínový model"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* Title for suspend dose type */ -"Suspended" = "Pozastavené"; - -/* Title for temp basal dose type */ -"Temp Basal" = "Dočasný bazál"; - -/* The short unit display string for international units of insulin */ -"U" = "j"; - -/* The long unit display string for international units of insulin */ -"Units" = "jednotky"; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/sv.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/sv.lproj/Localizable.strings deleted file mode 100644 index bf276ff8d..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/sv.lproj/Localizable.strings +++ /dev/null @@ -1,223 +0,0 @@ -/* Format for correction range override therapy setting card */ -"%@ Range" = "%@sintervall"; - -/* Descriptive format string for glucose safety limit (1: app name) */ -"%1$@ will deliver basal and recommend bolus insulin only if your glucose is predicted to be above this limit for the next three hours." = "%1$@ kommer att tillföra basal och rekommendera insulin endast om ditt blodsocker förväntas ligga över denna gräns under de kommande tre timmarna."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"A value you have entered is higher than what is typically recommended for most people." = "Det värde du har angett är högre än vad som normalt rekommenderas för de flesta."; - -/* Descriptive text for guardrail low value warning for schedule interface */ -"A value you have entered is lower than what is typically recommended for most people." = "Det värde du har angett är lägre än vad som normalt rekommenderas för de flesta."; - -/* Brand name for apidra insulin type */ -"Apidra" = "Apidra"; - -/* Title for Apidra insulin type */ -"Apidra (insulin glulisine)" = "Apidra (insulinglulisin)"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Auktorisation nekad"; - -/* Title for basal dose type */ -"Basal" = "Basal"; - -/* Title text for basal rates */ -"Basal Rates" = "Basaldoser"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Insulinkvoter"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Auktorisation nekad"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Detta värde kan raderas från Hälsa-appen"; - -/* Generic pump error description */ -"Communication Failure" = "Kommunikationsfel"; - -/* Failure reason for uncertain delivery */ -"Communications interrupted during insulin delivery command." = "Kommunikation avbruten under insulintillförselkommando."; - -/* Generic pump error description */ -"Connection Failure" = "Anslutningsfel"; - -/* Title text for glucose target range */ -"Correction Range" = "Målvärde"; - -/* Descriptive text for glucose target range (1: app name) */ -"Correction Range is the glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin and helping you calculate your boluses." = "Målvärde är det ideala blodsockerintervall som du vill att %1$@ ska hålla dig inom."; - -/* Title text for delivery limits */ -"Delivery Limits" = "Maxdoser"; - -/* Generic pump error description */ -"Device Refused" = "Enhet vägrade"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Kontrollera att kolhydratvärde finns"; - -/* Glucose trend down */ -"Falling" = "Sjunker"; - -/* Glucose trend down-down */ -"Falling fast" = "Sjunker snabbt"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Sjunker väldigt snabbt"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Description for fiasp insulin type */ -"Fiasp is a mealtime insulin aspart formulation with the addition of nicotinamide (vitamin B3) made by Novo Nordisk" = "Fiasp är ett snabbverkande insulin-aspart med tillägg av nikotinamid (vitamin B3) från Novo Nordisk"; - -/* Glucose trend flat */ -"Flat" = "Jämnt"; - -/* Descriptive text for fast acting insulin model (1: app name) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from different models for the peak activity." = "Får snabbverkande insulin, antar %1$@ ett insulin med 6 timmars verkan. Du kan välja mellan olika modeller med olika tid för insulinets maximala blodsockersänkande effekt i minuter."; - -/* The short unit display string for grams per U */ -"g/U" = "g/E"; - -/* Title text for glucose safety limit */ -"Glucose Safety Limit" = "Tröskelvärde för blodsocker"; - -/* Brand name for humalog insulin type */ -"Humalog" = "Humalog"; - -/* Title for Humalog insulin type */ -"Humalog (insulin lispro)" = "Humalog (insulin lispro)"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Insulinmodell"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Insulinkänslighet"; - -/* Generic pump error description */ -"Invalid Configuration" = "Ogiltig konfiguration"; - -/* Recovery suggestion for uncertain delivery */ -"Make sure your pump is within communication range of your phone." = "Säkerställ att din pump är inom räckvidd för kommunikation med telefon."; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Maximal basaldos"; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Maximal bolus"; - -/* Descriptive text for maximum bolus */ -"Maximum Bolus is the highest bolus amount you can deliver at one time to cover carbs or bring down high glucose." = "Maximal bolus är den högsta bolusmängd som kan ges vid ett tillfälle för att täcka kolhydrater eller ett högt blodsocker."; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dl/E"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/E"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Kräver uppmärksamhet"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "Inga värden funna"; - -/* Brand name for novolog insulin type */ -"Novolog" = "Novolog"; - -/* Title for Novolog insulin type */ -"Novolog (insulin aspart)" = "Novolog (insulin aspart)"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* Descriptive text for saving settings outside the recommended range */ -"One or more of the values you have entered is outside of what is typically recommended for most people." = "Ett eller flera av de värden du har angett är utanför vad som generellt rekommenderas."; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Tillåt delning i Hälsa igen"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Före måltid"; - -/* Title for resume dose type */ -"Resumed" = "Återupptagen"; - -/* Glucose trend up */ -"Rising" = "Stiger"; - -/* Glucose trend up-up */ -"Rising fast" = "Stiger snabbt"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Stiger väldigt snabbt"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"Some of the values you have entered are outside of what is typically recommended for most people." = "Ett eller flera av de värden du har angett är utanför vad som generellt rekommenderas."; - -/* Title for suspend dose type */ -"Suspended" = "Pausad"; - -/* Title for temp basal dose type */ -"Temp Basal" = "Temporär basal"; - -/* Descriptive text for pre-meal correction range override */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Sänker tillfälligt ditt målvärde före en måltid för att motverka postprandiella hyperglykemier (stegrade blodsocker efter en måltid)."; - -/* Descriptive text for workout correction range override */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Höj tillfälligt ditt målvärde före, under eller efter fysisk aktivitet för att minska risken för låga blodsockervärden."; - -/* Descriptive text for guardrail high value warning */ -"The value you have entered is higher than what is typically recommended for most people." = "Det värde du har angett är högre än vad som normalt rekommenderas för de flesta."; - -/* Descriptive text for guardrail low value warning */ -"The value you have entered is lower than what is typically recommended for most people." = "Det värde du har angett är lägre än vad som normalt rekommenderas för de flesta."; - -/* Descriptive text for guardrail high value warning */ -"The values you have entered are outside of what is typically recommended for most people." = "Ett eller flera av de värden du har angett är utanför vad som generellt rekommenderas."; - -/* The short unit display string for international units of insulin */ -"U" = "E"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "E/timme"; - -/* Error description for uncertain delivery */ -"Uncertain Delivery" = "Oklart ifall bolus administrerats"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Enhet"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Enhet/timme"; - -/* The long unit display string for international units of insulin */ -"Units" = "Eheter"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Enhet/timme"; - -/* Title for workout mode */ -"Workout" = "Träning"; - -/* Descriptive text for basal rate */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Din bassaldos är det antal enheter insulin per timme som krävs för din basala ämnesomsättning."; - -/* Descriptive text for carb ratio */ -"Your Carb Ratio is the number of grams of carbohydrates covered by one unit of insulin." = "Din insulinkvot är det antal gram kolhydrater som svarar mot en enhet insulin."; - -/* Descriptive text for insulin sensitivity */ -"Your Insulin Sensitivities refer to the drop in glucose expected from one unit of insulin." = "Insulinkänslighet är ett mått på hur mycket ditt blodsocker sänks av en enhet insulin."; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/tr.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/tr.lproj/Localizable.strings deleted file mode 100644 index 0d0003d73..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/tr.lproj/Localizable.strings +++ /dev/null @@ -1,267 +0,0 @@ -/* Format for correction range override therapy setting card */ -"%@ Range" = "%@ Aralık"; - -/* Descriptive format string for glucose safety limit (1: app name) */ -"%1$@ will deliver basal and recommend bolus insulin only if your glucose is predicted to be above this limit for the next three hours." = "%1$@ bazal insülin verecek ve yalnızca KŞ'nizin önümüzdeki üç saat boyunca bu sınırın üzerinde olacağı tahmin ediliyorsa bolus insülin önerecektir."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"A value you have entered is higher than what is typically recommended for most people." = "Girdiğiniz bir değer, çoğu insan için tipik olarak önerilenden daha yüksektir."; - -/* Descriptive text for guardrail low value warning for schedule interface */ -"A value you have entered is lower than what is typically recommended for most people." = "Girdiğiniz bir değer, çoğu insan için tipik olarak önerilenden daha düşüktür."; - -/* Brand name for afrezza insulin type - Title for Afrezza insulin type */ -"Afrezza" = "Afrezza"; - -/* Description for afrezza insulin type */ -"Afrezza is an ultra rapid-acting mealtime insulin that is breathed in through your lungs using an oral inhaler and made by MannKind" = "Afrezza, oral bir inhaler kullanılarak akciğerlerinizden solunan ve MannKind tarafından üretilen ultra hızlı etkili bir öğün insülinidir."; - -/* Brand name for apidra insulin type */ -"Apidra" = "Apidra"; - -/* Title for Apidra insulin type */ -"Apidra (insulin glulisine)" = "Apidra (insülin glulisin)"; - -/* Description for apidra insulin type */ -"Apidra (insulin glulisine) is a rapid-acting insulin made by Sanofi-aventis " = "Apidra (insülin glulisine) Sanofi-aventis tarafından üretilen hızlı etkili bir insülindir"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Yetkilendirme Reddedildi"; - -/* Title for basal dose type */ -"Basal" = "Bazal"; - -/* Title text for basal rates */ -"Basal Rates" = "Bazal Oranlar"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Karbonhidrat Oranları"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Yetkilendirme Reddedildi"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Bu örnek Health uygulamasından silinebilir"; - -/* Generic pump error description */ -"Communication Failure" = "İletişim Hatası"; - -/* Failure reason for uncertain delivery */ -"Communications interrupted during insulin delivery command." = "İnsülin iletim komutu sırasında iletişim kesildi."; - -/* Generic pump error description */ -"Connection Failure" = "Bağlantı hatası"; - -/* Title text for glucose target range */ -"Correction Range" = "Düzeltme Aralığı"; - -/* Descriptive text for glucose target range (1: app name) */ -"Correction Range is the glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin and helping you calculate your boluses." = "Düzeltme Aralığı, bazal insülininizi ayarlamak ve boluslarınızı hesaplamanıza yardımcı olmak için %1$@ 'ın hedeflemesini istediğiniz KŞ değeridir (veya değer aralığıdır)."; - -/* Description of critical software update needed */ -"Critical Update" = "Kritik Güncelleme"; - -/* Title text for delivery limits */ -"Delivery Limits" = "İletim Limitleri"; - -/* Generic pump error description */ -"Device Refused" = "Cihaz Reddedildi"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Belirtilen tarih için karbonhidrat verilerinin var olduğundan emin olun"; - -/* Glucose trend down */ -"Falling" = "Düşüyor"; - -/* Glucose trend down-down */ -"Falling fast" = "Hızlı Düşüyor"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Çok Hızlı Düşüyor"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Description for fiasp insulin type */ -"Fiasp is a mealtime insulin aspart formulation with the addition of nicotinamide (vitamin B3) made by Novo Nordisk" = "Fiasp, Novo Nordisk tarafından üretilen nikotinamid (B3 vitamini) ilaveli bir öğün insülin aspart formülasyonudur"; - -/* Glucose trend flat */ -"Flat" = "Sabit"; - -/* Descriptive text for fast acting insulin model (1: app name) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from different models for the peak activity." = "Hızlı etkili insülin için, %1$@ 6 saat boyunca aktif olarak çalıştığını varsayar. En yüksek etki için farklı modeller arasından seçim yapabilirsiniz."; - -/* The short unit display string for grams per U */ -"g/U" = "gr/Ü"; - -/* Title text for glucose safety limit */ -"Glucose Safety Limit" = "KŞ Güvenlik Limiti"; - -/* The long unit display string for a singular hour */ -"Hour" = "Saat"; - -/* The long unit display string for hours */ -"Hours" = "Saat"; - -/* Brand name for humalog insulin type */ -"Humalog" = "Humalog"; - -/* Title for Humalog insulin type */ -"Humalog (insulin lispro)" = "Hümalog (insülin lispro)"; - -/* Description for humalog insulin type */ -"Humalog (insulin lispro) is a rapid-acting insulin made by Eli Lilly" = "Humalog (insülin lispro), Eli Lilly tarafından üretilen hızlı etkili bir insülindir"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "İnsülin Modeli"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "İnsülin Duyarlılığı"; - -/* Generic pump error description */ -"Invalid Configuration" = "Geçersiz Konfigürasyon"; - -/* Brand name for lyumjev insulin type - Title for Lyumjev insulin type */ -"Lyumjev" = "Lyumjev"; - -/* Description for lyumjev insulin type */ -"Lyumjev is a mealtime insulin lispro formulation with the addition of citrate and treprostinil made by Eli Lilly" = "Lyumjev, Eli Lilly tarafından üretilen sitrat ve treprostinil ilaveli bir öğün insülin lispro formülasyonudur"; - -/* Recovery suggestion for uncertain delivery */ -"Make sure your pump is within communication range of your phone." = "Pompanızın telefonunuzun iletişim menzilinde olduğundan emin olun."; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Maksimum Bazal Oranı"; - -/* Descriptive text for maximum basal rate (1: app name) */ -"Maximum Basal Rate is the highest temporary basal rate %1$@ is allowed to set." = "Maksimum Bazal Oranı, %1$@ 'ın ayarlamasına izin verilen en yüksek geçici bazal orandır."; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Maksimum Bolus"; - -/* Descriptive text for maximum bolus */ -"Maximum Bolus is the highest bolus amount you can deliver at one time to cover carbs or bring down high glucose." = "Maksimum Bolus, karbonhidratları karşılamak veya yüksek KŞ'ni düşürmek için tek seferde verebileceğiniz en yüksek bolus miktarıdır."; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/Ü"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/Ü"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "İlgilenmeniz gerekiyor"; - -/* Description of no software update needed */ -"No Update" = "Güncelleme yok"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "Değer bulunamadı"; - -/* Brand name for novolog insulin type */ -"Novolog" = "Novolog"; - -/* Title for Novolog insulin type */ -"Novolog (insulin aspart)" = "Novolog (insülin aspart)"; - -/* Description for novolog insulin type */ -"NovoLog (insulin aspart) is a rapid-acting insulin made by Novo Nordisk" = "NovoLog (insülin aspart), Novo Nordisk tarafından üretilen hızlı etkili bir insülindir."; - -/* Sensor state description for the valid state */ -"OK" = "Tamam"; - -/* Descriptive text for saving settings outside the recommended range */ -"One or more of the values you have entered is outside of what is typically recommended for most people." = "Girdiğiniz değerlerden biri veya daha fazlası, çoğu insan için tipik olarak önerilen değerlerin dışındadır."; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Lütfen Health paylaşımı yeniden etkinleştirin"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Yemek öncesi"; - -/* Description of supported software update needed */ -"Recommended Update" = "Önerilen Güncelleme"; - -/* Title for resume dose type */ -"Resumed" = "Devam ettirildi"; - -/* Glucose trend up */ -"Rising" = "Yükseliyor"; - -/* Glucose trend up-up */ -"Rising fast" = "Hızlı yükseliyor"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Çok hızlı yükseliyor"; - -/* Descriptive text for guardrail high value warning for schedule interface */ -"Some of the values you have entered are outside of what is typically recommended for most people." = "Girdiğiniz değerlerden bazıları, çoğu insan için tipik olarak önerilen değerlerin dışındadır."; - -/* Title for suspend dose type */ -"Suspended" = "Askıya alındı"; - -/* Title for temp basal dose type */ -"Temp Basal" = "Geçici Bazal"; - -/* Descriptive text for pre-meal correction range override */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Yemek sonrası KŞ artışlarını engellemek için yemekten önce KŞ hedefinizi geçici olarak düşürün."; - -/* Descriptive text for workout correction range override */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Düşük KŞ riskini azaltmak için fiziksel aktivite öncesinde, sırasında veya sonrasında KŞ hedefinizi geçici olarak yükseltin."; - -/* Descriptive text for guardrail high value warning */ -"The value you have entered is higher than what is typically recommended for most people." = "Girdiğiniz değer, çoğu insan için tipik olarak önerilenden daha yüksektir."; - -/* Descriptive text for guardrail low value warning */ -"The value you have entered is lower than what is typically recommended for most people." = "Girdiğiniz değer, çoğu insan için tipik olarak önerilenden daha düşüktür."; - -/* Descriptive text for guardrail high value warning */ -"The values you have entered are outside of what is typically recommended for most people." = "Girdiğiniz değerler, çoğu insan için tipik olarak önerilen değerlerin dışındadır."; - -/* The short unit display string for international units of insulin */ -"U" = "Ü"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "Ü/sa"; - -/* Error description for uncertain delivery */ -"Uncertain Delivery" = "Belirsiz İletim"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Ünite"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Ünite/saat"; - -/* The long unit display string for international units of insulin */ -"Units" = "Ünite"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Ünite/saat"; - -/* Description of informational software update needed */ -"Update Available" = "Güncelleme Mevcut"; - -/* Title for workout mode */ -"Workout" = "Egzersiz"; - -/* Descriptive text for basal rate */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Bazal İnsülin Oranınız, arka plan insülin ihtiyaçlarınızı karşılamak için kullanmak istediğiniz saat başına ünite miktarıdır."; - -/* Descriptive text for carb ratio */ -"Your Carb Ratio is the number of grams of carbohydrates covered by one unit of insulin." = "Karbonhidrat İnsülin Oranınız, bir ünite insülinin kaç gram karbonhidrat karşılayacağını ifade eder."; - -/* Descriptive text for insulin sensitivity */ -"Your Insulin Sensitivities refer to the drop in glucose expected from one unit of insulin." = "İnsülin Duyarlılık faktörünüz, bir ünite insülinden beklenen KŞ düşüşünü ifade eder."; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/vi.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/vi.lproj/Localizable.strings deleted file mode 100644 index 0b3a07e70..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/vi.lproj/Localizable.strings +++ /dev/null @@ -1,130 +0,0 @@ -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "Cấp quyền bị từ chối"; - -/* Title text for basal rates */ -"Basal Rates" = "Lịch biểu tiêm liều nền"; - -/* Title for bolus dose type */ -"Bolus" = "Bolus"; - -/* Title text for carb ratios */ -"Carb Ratios" = "Carb Ratios"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Cấp quyền bị từ chối"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Mẫu này có thể bị xóa khỏi ứng dụng Health"; - -/* Generic pump error description */ -"Communication Failure" = "Liên lạc thất bại"; - -/* Generic pump error description */ -"Connection Failure" = "Kết nối thất bại"; - -/* Title text for glucose target range */ -"Correction Range" = "Phạm vi liều Bổ sung"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Giới hạn liều tiêm"; - -/* Generic pump error description */ -"Device Refused" = "Thiết bị bị từ chối"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "Đảm bảo dữ liệu carb tồn tại cho ngày cụ thể"; - -/* Glucose trend down */ -"Falling" = "Đang hạ"; - -/* Glucose trend down-down */ -"Falling fast" = "Đang hạ nhanh"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "Đang hạ rất nhanh"; - -/* Brand name for fiasp insulin type - Title for Fiasp insulin type */ -"Fiasp" = "Fiasp"; - -/* Glucose trend flat */ -"Flat" = "Flat"; - -/* The short unit display string for grams per U */ -"g/U" = "g/U"; - -/* Title text for fast acting insulin model */ -"Insulin Model" = "Chủng loại Insulin"; - -/* Title text for insulin sensitivity */ -"Insulin Sensitivities" = "Độ nhạy của Insulin"; - -/* Generic pump error description */ -"Invalid Configuration" = "Cấu hình không hiệu lực"; - -/* Title text for maximum basal rate configuration */ -"Maximum Basal Rate" = "Lượng Basal tối đa"; - -/* Title text for maximum bolus configuration */ -"Maximum Bolus" = "Liều Bolus tối đa"; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "mg/dL/U"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "mmol/L"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "mmol/L/U"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Cần chú ý"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "Không tìm thấy giá trị nào"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Xin hãy cấp quyền chia sẻ lại trong ứng dụng Health"; - -/* Title for pre-meal mode */ -"Pre-Meal" = "Trước bữa ăn"; - -/* Glucose trend up */ -"Rising" = "Đang tăng"; - -/* Glucose trend up-up */ -"Rising fast" = "Đang tăng nhanh"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "Đang tăng rất nhanh"; - -/* Title for suspend dose type */ -"Suspended" = "Đã tạm ngưng"; - -/* The short unit display string for international units of insulin */ -"U" = "U"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "U/giờ"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "Unit"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "Unit/giờ"; - -/* The long unit display string for international units of insulin */ -"Units" = "Units"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "Units/giờ"; - -/* Title for workout mode */ -"Workout" = "Workout"; - diff --git a/Dependencies/LoopKit/LoopKit/Resources/zh-Hans.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/Resources/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index df749fdc0..000000000 --- a/Dependencies/LoopKit/LoopKit/Resources/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,93 +0,0 @@ -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* The error description describing when Health sharing was denied */ -"Authorization Denied" = "没有权限"; - -/* Title text for basal rates */ -"Basal Rates" = "基础率"; - -/* The description of an error returned when attempting to delete a sample not shared by the current app */ -"com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "没有权限"; - -/* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "该样本可以从HealthKit中删除"; - -/* Generic pump error description */ -"Communication Failure" = "通信失败"; - -/* Generic pump error description */ -"Connection Failure" = "连接失败"; - -/* Title text for delivery limits */ -"Delivery Limits" = "输注限制"; - -/* Generic pump error description */ -"Device Refused" = "设备拒绝连接"; - -/* Recovery suggestion for a no data error */ -"Ensure carb data exists for the specified date" = "确认当天存在碳水化合物记录"; - -/* Glucose trend down */ -"Falling" = "下降"; - -/* Glucose trend down-down */ -"Falling fast" = "快速下降"; - -/* Glucose trend down-down-down */ -"Falling very fast" = "非常快速下降"; - -/* Glucose trend flat */ -"Flat" = "平稳"; - -/* The short unit display string for grams per U */ -"g/U" = "克/U"; - -/* Generic pump error description */ -"Invalid Configuration" = "无效配置"; - -/* The short unit display string for milligrams per deciliter per U */ -"mg/dL/U" = "毫克/分升/U"; - -/* The short unit display string for millimoles per liter */ -"mmol/L" = "毫摩尔/升"; - -/* The short unit display string for millimoles per liter per U */ -"mmol/L/U" = "毫摩尔/升/U"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "请注意"; - -/* Describes an error for no data found in a CarbStore request */ -"No values found" = "未发现数据"; - -/* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "请先在Health Kit中允许Loop读写数据"; - -/* Glucose trend up */ -"Rising" = "上升"; - -/* Glucose trend up-up */ -"Rising fast" = "快速上升"; - -/* Glucose trend up-up-up */ -"Rising very fast" = "非常快速上升"; - -/* Title for suspend dose type */ -"Suspended" = "暂停"; - -/* The short unit display string for international units of insulin per hour */ -"U/hr" = "U/小时"; - -/* The long unit display string for a singular international unit of insulin */ -"Unit" = "单位"; - -/* The long unit display string for a singular international unit of insulin per hour */ -"Unit/hour" = "单位/小时"; - -/* The long unit display string for international units of insulin */ -"Units" = "单位"; - -/* The long unit display string for international units of insulin per hour */ -"Units/hour" = "单位/小时"; - diff --git a/Dependencies/LoopKit/LoopKit/SampleValue.swift b/Dependencies/LoopKit/LoopKit/SampleValue.swift deleted file mode 100644 index 267e915cc..000000000 --- a/Dependencies/LoopKit/LoopKit/SampleValue.swift +++ /dev/null @@ -1,115 +0,0 @@ -// -// SampleValue.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/24/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -public protocol TimelineValue { - var startDate: Date { get } - var endDate: Date { get } -} - - -public extension TimelineValue { - var endDate: Date { - return startDate - } -} - - -public protocol SampleValue: TimelineValue { - var quantity: HKQuantity { get } -} - - -public extension Sequence where Element: TimelineValue { - /** - Returns the closest element in the sorted sequence prior to the specified date - - - parameter date: The date to use in the search - - - returns: The closest element, if any exist before the specified date - */ - func closestPrior(to date: Date) -> Iterator.Element? { - return elementsAdjacent(to: date).before - } - - /// Returns the elements immediately before and after the specified date - /// - /// - Parameter date: The date to use in the search - /// - Returns: The closest elements, if found - func elementsAdjacent(to date: Date) -> (before: Iterator.Element?, after: Iterator.Element?) { - var before: Iterator.Element? - var after: Iterator.Element? - - for value in self { - if value.startDate <= date { - before = value - } else { - after = value - break - } - } - - return (before, after) - } - - /// Returns all elements inmmediately adjacent to the specified date - /// - /// Use Sequence.elementsAdjacent(to:) if specific before/after references are necessary - /// - /// - Parameter date: The date to use in the search - /// - Returns: The closest elements, if found - func allElementsAdjacent(to date: Date) -> [Iterator.Element] { - let (before, after) = elementsAdjacent(to: date) - return [before, after].compactMap({ $0 }) - } - - /** - Returns an array of elements filtered by the specified date range. - - This behavior mimics HKQueryOptionNone, where the value must merely overlap the specified range, - not strictly exist inside of it. - - - parameter startDate: The earliest date of elements to return - - parameter endDate: The latest date of elements to return - - - returns: A new array of elements - */ - func filterDateRange(_ startDate: Date?, _ endDate: Date?) -> [Iterator.Element] { - return filter { (value) -> Bool in - if let startDate = startDate, value.endDate < startDate { - return false - } - - if let endDate = endDate, value.startDate > endDate { - return false - } - - return true - } - } -} - -public extension Sequence where Element: SampleValue { - func average(unit: HKUnit) -> HKQuantity? { - let (sum, count) = reduce(into: (sum: 0.0, count: 0)) { result, element in - result.0 += element.quantity.doubleValue(for: unit) - result.1 += 1 - } - - guard count > 0 else { - return nil - } - - let average = sum / Double(count) - - return HKQuantity(unit: unit, doubleValue: average) - } -} diff --git a/Dependencies/LoopKit/LoopKit/Service/AnalyticsService.swift b/Dependencies/LoopKit/LoopKit/Service/AnalyticsService.swift deleted file mode 100644 index 10f680c94..000000000 --- a/Dependencies/LoopKit/LoopKit/Service/AnalyticsService.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// AnalyticsService.swift -// LoopKit -// -// Created by Darin Krauss on 5/11/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - -public protocol AnalyticsService: Service { - - func recordAnalyticsEvent(_ name: String, withProperties properties: [AnyHashable: Any]?, outOfSession: Bool) - - func recordIdentify(_ property: String, value: String) -} diff --git a/Dependencies/LoopKit/LoopKit/Service/LoggingService.swift b/Dependencies/LoopKit/LoopKit/Service/LoggingService.swift deleted file mode 100644 index 4256dbb8f..000000000 --- a/Dependencies/LoopKit/LoopKit/Service/LoggingService.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// LoggingService.swift -// LoopKit -// -// Created by Darin Krauss on 6/17/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import os.log - -public protocol Logging { - - /// Log a message for the specific subsystem, category, type, and optional arguments. Modeled after OSLog, but - /// captures all of the necessary data in one function call per message. Note that like OSLog, the message may - /// contain "%{public}" and "%{private}" string substitution qualifiers that should be observed based upon the - /// OSLog rules. That is, scalar values are considered public by default, while strings and objects are considered - /// private by default. The explicitly specified qualifiers override these defaults. - /// - /// - Parameters: - /// - message: The message to log with optional string substitution. Note that like OSLog, it make contain "%{public}" - /// and "%{private}" string substitution qualifiers that should be observed based upon the OSLog rules. - /// - subsystem: The subsystem logging the message. Typical the reverse dot notation identifier of the framework. - /// - category: The category for the message. Typically the class or extension name. - /// - type: The type of the message. One of OSLogType. - /// - args: Optional arguments to be substituted into the string. - func log(_ message: StaticString, subsystem: String, category: String, type: OSLogType, _ args: [CVarArg]) - -} - -public protocol LoggingService: Logging, Service {} - diff --git a/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/Action.swift b/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/Action.swift deleted file mode 100644 index 433b3de77..000000000 --- a/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/Action.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// Action.swift -// LoopKit -// -// Created by Bill Gestrich on 12/25/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum Action: Codable { - case temporaryScheduleOverride(OverrideAction) - case cancelTemporaryOverride(OverrideCancelAction) - case bolusEntry(BolusAction) - case carbsEntry(CarbAction) -} diff --git a/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/BolusAction.swift b/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/BolusAction.swift deleted file mode 100644 index 3a56d81eb..000000000 --- a/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/BolusAction.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// BolusAction.swift -// LoopKit -// -// Created by Bill Gestrich on 12/25/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct BolusAction: Codable { - - public let amountInUnits: Double - - public init(amountInUnits: Double) { - self.amountInUnits = amountInUnits - } -} diff --git a/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/CarbAction.swift b/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/CarbAction.swift deleted file mode 100644 index 38659897a..000000000 --- a/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/CarbAction.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// CarbAction.swift -// LoopKit -// -// Created by Bill Gestrich on 12/25/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct CarbAction: Codable{ - - public let amountInGrams: Double - public let absorptionTime: TimeInterval? - public let foodType: String? - public let startDate: Date? - - public init(amountInGrams: Double, absorptionTime: TimeInterval? = nil, foodType: String? = nil, startDate: Date? = nil) { - self.amountInGrams = amountInGrams - self.absorptionTime = absorptionTime - self.foodType = foodType - self.startDate = startDate - } -} diff --git a/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/OverrideAction.swift b/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/OverrideAction.swift deleted file mode 100644 index bc4f7589a..000000000 --- a/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/OverrideAction.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// OverrideAction.swift -// LoopKit -// -// Created by Bill Gestrich on 12/25/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct OverrideAction: Codable { - - public let name: String - public let durationTime: TimeInterval? - public let remoteAddress: String - - public init(name: String, durationTime: TimeInterval? = nil, remoteAddress: String) { - self.name = name - self.durationTime = durationTime - self.remoteAddress = remoteAddress - } - -} diff --git a/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/OverrideCancelAction.swift b/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/OverrideCancelAction.swift deleted file mode 100644 index a0cf02e81..000000000 --- a/Dependencies/LoopKit/LoopKit/Service/Remote/Actions/OverrideCancelAction.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// OverrideCancelAction.swift -// LoopKit -// -// Created by Bill Gestrich on 12/25/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct OverrideCancelAction: Codable { - - let remoteAddress: String - - public init(remoteAddress: String) { - self.remoteAddress = remoteAddress - } - -} diff --git a/Dependencies/LoopKit/LoopKit/Service/RemoteDataService.swift b/Dependencies/LoopKit/LoopKit/Service/RemoteDataService.swift deleted file mode 100644 index 4e49d8440..000000000 --- a/Dependencies/LoopKit/LoopKit/Service/RemoteDataService.swift +++ /dev/null @@ -1,136 +0,0 @@ -// -// RemoteDataService.swift -// LoopKit -// -// Created by Darin Krauss on 5/21/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -/** - Protocol for a remote data service. -*/ - -import Foundation - -public protocol RemoteDataService: Service { - - /// The maximum number of alert data to upload to the remote data service at one time. - var alertDataLimit: Int? { get } - - /** - Upload alert data to the remote data service. - - - Parameter stored: The stored alert data to upload. - - Parameter completion: The completion function to call with any success or failure. - */ - func uploadAlertData(_ stored: [SyncAlertObject], completion: @escaping (_ result: Result) -> Void) - - /// The maximum number of carb data to upload to the remote data service at one time. - var carbDataLimit: Int? { get } - - /** - Upload carb data to the remote data service. - - - Parameter created: The created carb data to upload. - - Parameter updated: The updated carb data to upload. - - Parameter deleted: The deleted carb data to upload. - - Parameter completion: The completion function to call with any success or failure. - */ - func uploadCarbData(created: [SyncCarbObject], updated: [SyncCarbObject], deleted: [SyncCarbObject], completion: @escaping (_ result: Result) -> Void) - - /** - Upload overrides to the remote data service. - - - Parameter updated: The updated or new overrides to upload. - - Parameter deleted: The deleted overrides to upload. - - Parameter completion: The completion function to call with any success or failure. - */ - func uploadTemporaryOverrideData(updated: [TemporaryScheduleOverride], deleted: [TemporaryScheduleOverride], completion: @escaping (_ result: Result) -> Void) - - /// The maximum number of dose data to upload to the remote data service at one time. - var doseDataLimit: Int? { get } - - /** - Upload dose data to the remote data service. - - - Parameter created: The created dose data to upload. - - Parameter deleted: The deleted dose data to upload. - - Parameter completion: The completion function to call with any success or failure. - */ - func uploadDoseData(created: [DoseEntry], deleted: [DoseEntry], completion: @escaping (_ result: Result) -> Void) - - /// The maximum number of dosing decision data to upload to the remote data service at one time. - var dosingDecisionDataLimit: Int? { get } - - /** - Upload dosing decision data to the remote data service. - - - Parameter stored: The stored dosing decision data to upload. - - Parameter completion: The completion function to call with any success or failure. - */ - func uploadDosingDecisionData(_ stored: [StoredDosingDecision], completion: @escaping (_ result: Result) -> Void) - - /// The maximum number of glucose data to upload to the remote data service at one time. - var glucoseDataLimit: Int? { get } - - /** - Upload glucose data to the remote data service. - - - Parameter stored: The stored glucose data to upload. - - Parameter completion: The completion function to call with any success or failure. - */ - func uploadGlucoseData(_ stored: [StoredGlucoseSample], completion: @escaping (_ result: Result) -> Void) - - /// The maximum number of pump event data to upload to the remote data service at one time. - var pumpEventDataLimit: Int? { get } - - /** - Upload pump event data to the remote data service. - - - Parameter stored: The stored pump event data to upload. - - Parameter completion: The completion function to call with any success or failure. - */ - func uploadPumpEventData(_ stored: [PersistedPumpEvent], completion: @escaping (_ result: Result) -> Void) - - /// The maximum number of settings data to upload to the remote data service at one time. - var settingsDataLimit: Int? { get } - - /** - Upload settings data to the remote data service. - - - Parameter stored: The stored settings data to upload. - - Parameter completion: The completion function to call with any success or failure. - */ - func uploadSettingsData(_ stored: [StoredSettings], completion: @escaping (_ result: Result) -> Void) - - /** - Validates a push notification originated from this data service. - - Parameter notification: The push notification dictionary - - Returns: Success - */ - func validatePushNotificationSource(_ notification: [String: AnyObject]) -> Result - -} - -public extension RemoteDataService { - var alertDataLimit: Int? { return nil } - var carbDataLimit: Int? { return nil } - var doseDataLimit: Int? { return nil } - var dosingDecisionDataLimit: Int? { return nil } - var glucoseDataLimit: Int? { return nil } - var pumpEventDataLimit: Int? { return nil } - var settingsDataLimit: Int? { return nil } - - func validatePushNotificationSource(_ notification: [String: AnyObject]) -> Result { return .failure(PushNotificationValidationError.notificationsNotSupported) } -} - -enum PushNotificationValidationError: LocalizedError { - case notificationsNotSupported - - var errorDescription: String? { - switch self { - case .notificationsNotSupported: - return "Service does not handle push notifications" - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/Service/Service.swift b/Dependencies/LoopKit/LoopKit/Service/Service.swift deleted file mode 100644 index f9f9865cf..000000000 --- a/Dependencies/LoopKit/LoopKit/Service/Service.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// Service.swift -// LoopKit -// -// Created by Darin Krauss on 5/17/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -public protocol PluginHost { - /// An identifier for the host of this service. Usually something that identifies the app. Example: "com.loopkit.Loop", or "org.tidepool.Loop" - var hostIdentifier: String { get } - - /// The version of the host of this service. - var hostVersion: String { get } -} - -public protocol ServiceDelegate: AnyObject, PluginHost { - /// Informs the delegate that the state of the specified service was updated and the delegate should persist the service. May - /// be invoked prior to the service completing setup. - /// - /// - Parameters: - /// - service: The service that updated state. - func serviceDidUpdateState(_ service: Service) - - /// Informs the delegate that the service wants deletion. - /// - /// - Parameters: - /// - service: The service that wants deletion. - func serviceWantsDeletion(_ service: Service) - -} - -public protocol Service: AnyObject { - typealias RawStateValue = [String: Any] - - /// The unique identifier of this type of service. - static var serviceIdentifier: String { get } - - /// The localized title of this type of service. - static var localizedTitle: String { get } - - /// The delegate to notify of service updates. - var serviceDelegate: ServiceDelegate? { get set } - - /// Initializes the service with the previously-serialized state. - /// - /// - Parameters: - /// - rawState: The previously-serialized state of the service. - init?(rawState: RawStateValue) - - /// The current, serializable state of the service. - var rawState: RawStateValue { get } - - /// Is the service onboarded and ready for use? - var isOnboarded: Bool { get } -} - -public extension Service { - var serviceIdentifier: String { return type(of: self).serviceIdentifier } - var localizedTitle: String { return type(of: self).localizedTitle } -} diff --git a/Dependencies/LoopKit/LoopKit/ServiceAuthentication.swift b/Dependencies/LoopKit/LoopKit/ServiceAuthentication.swift deleted file mode 100644 index 5c2e5202b..000000000 --- a/Dependencies/LoopKit/LoopKit/ServiceAuthentication.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// ServiceAuthentication.swift -// Loop -// -// Created by Nate Racklyeft on 7/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - - -// Defines the authentication for a service -public protocol ServiceAuthentication: AnyObject { - // The title of the service - var title: String { get } - - // The indexed credentials (e.g. username, password) used to authenticate - var credentialValues: [String?] { get set } - - // Whether the current credential values are valid authorization - var isAuthorized: Bool { get set } - - // Tests the credentials for valid authorization - func verify(_ completion: @escaping (_ success: Bool, _ error: Error?) -> Void) - - // Clears the credential values and authorization status - func reset() -} diff --git a/Dependencies/LoopKit/LoopKit/SettingsObject+CoreDataClass.swift b/Dependencies/LoopKit/LoopKit/SettingsObject+CoreDataClass.swift deleted file mode 100644 index a138c7a9d..000000000 --- a/Dependencies/LoopKit/LoopKit/SettingsObject+CoreDataClass.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// SettingsObject+CoreDataClass.swift -// LoopKit -// -// Created by Darin Krauss on 4/30/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import CoreData - -class SettingsObject: NSManagedObject { - var hasUpdatedModificationCounter: Bool { changedValues().keys.contains("modificationCounter") } - - func updateModificationCounter() { setPrimitiveValue(managedObjectContext!.modificationCounter!, forKey: "modificationCounter") } - - override func awakeFromInsert() { - super.awakeFromInsert() - updateModificationCounter() - } - - override func willSave() { - if isUpdated && !hasUpdatedModificationCounter { - updateModificationCounter() - } - super.willSave() - } -} diff --git a/Dependencies/LoopKit/LoopKit/SettingsObject+CoreDataProperties.swift b/Dependencies/LoopKit/LoopKit/SettingsObject+CoreDataProperties.swift deleted file mode 100644 index 5d78831fb..000000000 --- a/Dependencies/LoopKit/LoopKit/SettingsObject+CoreDataProperties.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// SettingsObject+CoreDataProperties.swift -// LoopKit -// -// Created by Darin Krauss on 4/30/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation -import CoreData - -extension SettingsObject { - @nonobjc public class func fetchRequest() -> NSFetchRequest { - return NSFetchRequest(entityName: "SettingsObject") - } - - @NSManaged public var data: Data - @NSManaged public var date: Date - @NSManaged public var modificationCounter: Int64 -} - -extension SettingsObject: Encodable { - func encode(to encoder: Encoder) throws { - try EncodableSettingsObject(self).encode(to: encoder) - } -} - -fileprivate struct EncodableSettingsObject: Encodable { - var data: StoredSettings - var date: Date - var modificationCounter: Int64 - - init(_ object: SettingsObject) throws { - self.data = try PropertyListDecoder().decode(StoredSettings.self, from: object.data) - self.date = object.date - self.modificationCounter = object.modificationCounter - } -} diff --git a/Dependencies/LoopKit/LoopKit/SettingsStore.swift b/Dependencies/LoopKit/LoopKit/SettingsStore.swift deleted file mode 100644 index afcb9d874..000000000 --- a/Dependencies/LoopKit/LoopKit/SettingsStore.swift +++ /dev/null @@ -1,551 +0,0 @@ -// -// SettingsStore.swift -// LoopKit -// -// Created by Darin Krauss on 10/14/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import os.log -import Foundation -import CoreData -import HealthKit - -public protocol SettingsStoreDelegate: AnyObject { - /** - Informs the delegate that the settings store has updated settings data. - - - Parameter settingsStore: The settings store that has updated settings data. - */ - func settingsStoreHasUpdatedSettingsData(_ settingsStore: SettingsStore) - -} - -public class SettingsStore { - public weak var delegate: SettingsStoreDelegate? - - public private(set) var latestSettings: StoredSettings? { - get { - return lockedLatestSettings.value - } - set { - lockedLatestSettings.value = newValue - } - } - private let lockedLatestSettings: Locked - - private let store: PersistenceController - private let expireAfter: TimeInterval - private let dataAccessQueue = DispatchQueue(label: "com.loopkit.SettingsStore.dataAccessQueue", qos: .utility) - private let log = OSLog(category: "SettingsStore") - - public init(store: PersistenceController, expireAfter: TimeInterval) { - self.store = store - self.expireAfter = expireAfter - self.lockedLatestSettings = Locked(nil) - - dataAccessQueue.sync { - self.store.managedObjectContext.performAndWait { - let storedRequest: NSFetchRequest = SettingsObject.fetchRequest() - - storedRequest.sortDescriptors = [NSSortDescriptor(key: "modificationCounter", ascending: false)] - storedRequest.fetchLimit = 1 - - do { - let stored = try self.store.managedObjectContext.fetch(storedRequest) - self.latestSettings = stored.first.flatMap { self.decodeSettings(fromData: $0.data) } - } catch let error { - self.log.error("Error fetching latest settings: %@", String(describing: error)) - return - } - } - } - } - - func storeSettings(_ settings: StoredSettings) async { - await withCheckedContinuation { continuation in - storeSettings(settings) { (_) in - continuation.resume() - } - } - } - - public func storeSettings(_ settings: StoredSettings, completion: @escaping (Error?) -> Void) { - dataAccessQueue.async { - var error: Error? - - if let data = self.encodeSettings(settings) { - self.store.managedObjectContext.performAndWait { - let object = SettingsObject(context: self.store.managedObjectContext) - object.data = data - object.date = settings.date - error = self.store.save() - } - } - - self.latestSettings = settings - self.purgeExpiredSettings() - completion(error) - } - } - - public var expireDate: Date { - return Date(timeIntervalSinceNow: -expireAfter) - } - - private func purgeExpiredSettings() { - guard let latestSettings = latestSettings else { - return - } - - guard expireDate < latestSettings.date else { - return - } - - purgeSettingsObjects(before: expireDate) - } - - public func purgeSettings(before date: Date, completion: @escaping (Error?) -> Void) { - dataAccessQueue.async { - self.purgeSettingsObjects(before: date, completion: completion) - } - } - - private func purgeSettingsObjects(before date: Date, completion: ((Error?) -> Void)? = nil) { - dispatchPrecondition(condition: .onQueue(dataAccessQueue)) - - var purgeError: Error? - - store.managedObjectContext.performAndWait { - do { - let count = try self.store.managedObjectContext.purgeObjects(of: SettingsObject.self, matching: NSPredicate(format: "date < %@", date as NSDate)) - if count > 0 { - self.log.default("Purged %d SettingsObjects", count) - } - } catch let error { - self.log.error("Unable to purge SettingsObjects: %{public}@", String(describing: error)) - purgeError = error - } - } - - if let purgeError = purgeError { - completion?(purgeError) - return - } - - delegate?.settingsStoreHasUpdatedSettingsData(self) - completion?(nil) - } - - private static var encoder: PropertyListEncoder = { - let encoder = PropertyListEncoder() - encoder.outputFormat = .binary - return encoder - }() - - private func encodeSettings(_ settings: StoredSettings) -> Data? { - do { - return try Self.encoder.encode(settings) - } catch let error { - self.log.error("Error encoding StoredSettings: %@", String(describing: error)) - return nil - } - } - - private static var decoder = PropertyListDecoder() - - private func decodeSettings(fromData data: Data) -> StoredSettings? { - do { - return try Self.decoder.decode(StoredSettings.self, from: data) - } catch let error { - self.log.error("Error decoding StoredSettings: %@", String(describing: error)) - return nil - } - } -} - -extension SettingsStore { - public struct QueryAnchor: Equatable, RawRepresentable { - public typealias RawValue = [String: Any] - - internal var modificationCounter: Int64 - - public init() { - self.modificationCounter = 0 - } - - public init?(rawValue: RawValue) { - guard let modificationCounter = rawValue["modificationCounter"] as? Int64 else { - return nil - } - self.modificationCounter = modificationCounter - } - - public var rawValue: RawValue { - var rawValue: RawValue = [:] - rawValue["modificationCounter"] = modificationCounter - return rawValue - } - } - - public enum SettingsQueryResult { - case success(QueryAnchor, [StoredSettings]) - case failure(Error) - } - - public func executeSettingsQuery(fromQueryAnchor queryAnchor: QueryAnchor?, limit: Int, completion: @escaping (SettingsQueryResult) -> Void) { - dataAccessQueue.async { - var queryAnchor = queryAnchor ?? QueryAnchor() - var queryResult = [StoredSettingsData]() - var queryError: Error? - - guard limit > 0 else { - completion(.success(queryAnchor, [])) - return - } - - self.store.managedObjectContext.performAndWait { - let storedRequest: NSFetchRequest = SettingsObject.fetchRequest() - - storedRequest.predicate = NSPredicate(format: "modificationCounter > %d", queryAnchor.modificationCounter) - storedRequest.sortDescriptors = [NSSortDescriptor(key: "modificationCounter", ascending: true)] - storedRequest.fetchLimit = limit - - do { - let stored = try self.store.managedObjectContext.fetch(storedRequest) - if let modificationCounter = stored.max(by: { $0.modificationCounter < $1.modificationCounter })?.modificationCounter { - queryAnchor.modificationCounter = modificationCounter - } - queryResult.append(contentsOf: stored.compactMap { StoredSettingsData(date: $0.date, data: $0.data) }) - } catch let error { - queryError = error - return - } - } - - if let queryError = queryError { - completion(.failure(queryError)) - return - } - - // Decoding a large number of settings can be very CPU intensive and may take considerable wall clock time. - // Do not block SettingsStore dataAccessQueue. Perform work and callback in global utility queue. - DispatchQueue.global(qos: .utility).async { - completion(.success(queryAnchor, queryResult.compactMap { self.decodeSettings(fromData: $0.data) })) - } - } - } -} - -public struct StoredSettingsData { - public let date: Date - public let data: Data - - public init(date: Date, data: Data) { - self.date = date - self.data = data - } -} - -public struct StoredSettings: Equatable { - public let date: Date - public var controllerTimeZone: TimeZone - public let dosingEnabled: Bool - public let glucoseTargetRangeSchedule: GlucoseRangeSchedule? - public let preMealTargetRange: ClosedRange? - public let workoutTargetRange: ClosedRange? - public let overridePresets: [TemporaryScheduleOverridePreset]? - public let scheduleOverride: TemporaryScheduleOverride? - public let preMealOverride: TemporaryScheduleOverride? - public let maximumBasalRatePerHour: Double? - public let maximumBolus: Double? - public let suspendThreshold: GlucoseThreshold? - public let deviceToken: String? - public let insulinType: InsulinType? - public let defaultRapidActingModel: StoredInsulinModel? - public let basalRateSchedule: BasalRateSchedule? - public let insulinSensitivitySchedule: InsulinSensitivitySchedule? - public let carbRatioSchedule: CarbRatioSchedule? - public var notificationSettings: NotificationSettings? - public let controllerDevice: ControllerDevice? - public let cgmDevice: HKDevice? - public let pumpDevice: HKDevice? - // This is the user's display preference glucose unit. TODO: Rename? - public let bloodGlucoseUnit: HKUnit? - public let automaticDosingStrategy: AutomaticDosingStrategy - public let syncIdentifier: UUID - - public init(date: Date = Date(), - controllerTimeZone: TimeZone = TimeZone.current, - dosingEnabled: Bool = false, - glucoseTargetRangeSchedule: GlucoseRangeSchedule? = nil, - preMealTargetRange: ClosedRange? = nil, - workoutTargetRange: ClosedRange? = nil, - overridePresets: [TemporaryScheduleOverridePreset]? = nil, - scheduleOverride: TemporaryScheduleOverride? = nil, - preMealOverride: TemporaryScheduleOverride? = nil, - maximumBasalRatePerHour: Double? = nil, - maximumBolus: Double? = nil, - suspendThreshold: GlucoseThreshold? = nil, - deviceToken: String? = nil, - insulinType: InsulinType? = nil, - defaultRapidActingModel: StoredInsulinModel? = nil, - basalRateSchedule: BasalRateSchedule? = nil, - insulinSensitivitySchedule: InsulinSensitivitySchedule? = nil, - carbRatioSchedule: CarbRatioSchedule? = nil, - notificationSettings: NotificationSettings? = nil, - controllerDevice: ControllerDevice? = nil, - cgmDevice: HKDevice? = nil, - pumpDevice: HKDevice? = nil, - bloodGlucoseUnit: HKUnit? = nil, - automaticDosingStrategy: AutomaticDosingStrategy = .tempBasalOnly, - syncIdentifier: UUID = UUID()) { - self.date = date - self.controllerTimeZone = controllerTimeZone - self.dosingEnabled = dosingEnabled - self.glucoseTargetRangeSchedule = glucoseTargetRangeSchedule - self.preMealTargetRange = preMealTargetRange - self.workoutTargetRange = workoutTargetRange - self.overridePresets = overridePresets - self.scheduleOverride = scheduleOverride - self.preMealOverride = preMealOverride - self.maximumBasalRatePerHour = maximumBasalRatePerHour - self.maximumBolus = maximumBolus - self.suspendThreshold = suspendThreshold - self.deviceToken = deviceToken - self.insulinType = insulinType - self.defaultRapidActingModel = defaultRapidActingModel - self.basalRateSchedule = basalRateSchedule - self.insulinSensitivitySchedule = insulinSensitivitySchedule - self.carbRatioSchedule = carbRatioSchedule - self.notificationSettings = notificationSettings - self.controllerDevice = controllerDevice - self.cgmDevice = cgmDevice - self.pumpDevice = pumpDevice - self.bloodGlucoseUnit = bloodGlucoseUnit - self.automaticDosingStrategy = automaticDosingStrategy - self.syncIdentifier = syncIdentifier - } -} - -extension StoredSettings: Codable { - fileprivate static let codingGlucoseUnit = HKUnit.milligramsPerDeciliter - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let bloodGlucoseUnit = HKUnit(from: try container.decode(String.self, forKey: .bloodGlucoseUnit)) - self.init(date: try container.decode(Date.self, forKey: .date), - controllerTimeZone: try container.decode(TimeZone.self, forKey: .controllerTimeZone), - dosingEnabled: try container.decode(Bool.self, forKey: .dosingEnabled), - glucoseTargetRangeSchedule: try container.decodeIfPresent(GlucoseRangeSchedule.self, forKey: .glucoseTargetRangeSchedule), - preMealTargetRange: try container.decodeIfPresent(DoubleRange.self, forKey: .preMealTargetRange)?.quantityRange(for: bloodGlucoseUnit), - workoutTargetRange: try container.decodeIfPresent(DoubleRange.self, forKey: .workoutTargetRange)?.quantityRange(for: bloodGlucoseUnit), - overridePresets: try container.decodeIfPresent([TemporaryScheduleOverridePreset].self, forKey: .overridePresets), - scheduleOverride: try container.decodeIfPresent(TemporaryScheduleOverride.self, forKey: .scheduleOverride), - preMealOverride: try container.decodeIfPresent(TemporaryScheduleOverride.self, forKey: .preMealOverride), - maximumBasalRatePerHour: try container.decodeIfPresent(Double.self, forKey: .maximumBasalRatePerHour), - maximumBolus: try container.decodeIfPresent(Double.self, forKey: .maximumBolus), - suspendThreshold: try container.decodeIfPresent(GlucoseThreshold.self, forKey: .suspendThreshold), - deviceToken: try container.decodeIfPresent(String.self, forKey: .deviceToken), - insulinType: try container.decodeIfPresent(InsulinType.self, forKey: .insulinType), - defaultRapidActingModel: try container.decodeIfPresent(StoredInsulinModel.self, forKey: .defaultRapidActingModel), - basalRateSchedule: try container.decodeIfPresent(BasalRateSchedule.self, forKey: .basalRateSchedule), - insulinSensitivitySchedule: try container.decodeIfPresent(InsulinSensitivitySchedule.self, forKey: .insulinSensitivitySchedule), - carbRatioSchedule: try container.decodeIfPresent(CarbRatioSchedule.self, forKey: .carbRatioSchedule), - notificationSettings: try container.decodeIfPresent(NotificationSettings.self, forKey: .notificationSettings), - controllerDevice: try container.decodeIfPresent(ControllerDevice.self, forKey: .controllerDevice), - cgmDevice: try container.decodeIfPresent(CodableDevice.self, forKey: .cgmDevice)?.device, - pumpDevice: try container.decodeIfPresent(CodableDevice.self, forKey: .pumpDevice)?.device, - bloodGlucoseUnit: bloodGlucoseUnit, - automaticDosingStrategy: try container.decodeIfPresent(AutomaticDosingStrategy.self, forKey: .automaticDosingStrategy) ?? .tempBasalOnly, - syncIdentifier: try container.decode(UUID.self, forKey: .syncIdentifier)) - } - - public func encode(to encoder: Encoder) throws { - let bloodGlucoseUnit = self.bloodGlucoseUnit ?? StoredSettings.codingGlucoseUnit - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(date, forKey: .date) - try container.encode(controllerTimeZone, forKey: .controllerTimeZone) - try container.encode(dosingEnabled, forKey: .dosingEnabled) - try container.encodeIfPresent(glucoseTargetRangeSchedule, forKey: .glucoseTargetRangeSchedule) - try container.encodeIfPresent(preMealTargetRange?.doubleRange(for: bloodGlucoseUnit), forKey: .preMealTargetRange) - try container.encodeIfPresent(workoutTargetRange?.doubleRange(for: bloodGlucoseUnit), forKey: .workoutTargetRange) - try container.encodeIfPresent(overridePresets, forKey: .overridePresets) - try container.encodeIfPresent(scheduleOverride, forKey: .scheduleOverride) - try container.encodeIfPresent(preMealOverride, forKey: .preMealOverride) - try container.encodeIfPresent(maximumBasalRatePerHour, forKey: .maximumBasalRatePerHour) - try container.encodeIfPresent(maximumBolus, forKey: .maximumBolus) - try container.encodeIfPresent(suspendThreshold, forKey: .suspendThreshold) - try container.encodeIfPresent(insulinType, forKey: .insulinType) - try container.encodeIfPresent(deviceToken, forKey: .deviceToken) - try container.encodeIfPresent(defaultRapidActingModel, forKey: .defaultRapidActingModel) - try container.encodeIfPresent(basalRateSchedule, forKey: .basalRateSchedule) - try container.encodeIfPresent(insulinSensitivitySchedule, forKey: .insulinSensitivitySchedule) - try container.encodeIfPresent(carbRatioSchedule, forKey: .carbRatioSchedule) - try container.encodeIfPresent(notificationSettings, forKey: .notificationSettings) - try container.encodeIfPresent(controllerDevice, forKey: .controllerDevice) - try container.encodeIfPresent(cgmDevice.map { CodableDevice($0) }, forKey: .cgmDevice) - try container.encodeIfPresent(pumpDevice.map { CodableDevice($0) }, forKey: .pumpDevice) - try container.encode(bloodGlucoseUnit.unitString, forKey: .bloodGlucoseUnit) - try container.encode(automaticDosingStrategy, forKey: .automaticDosingStrategy) - try container.encode(syncIdentifier, forKey: .syncIdentifier) - } - - public struct ControllerDevice: Codable, Equatable { - public let name: String - public let systemName: String - public let systemVersion: String - public let model: String - public let modelIdentifier: String - - public init(name: String, systemName: String, systemVersion: String, model: String, modelIdentifier: String) { - self.name = name - self.systemName = systemName - self.systemVersion = systemVersion - self.model = model - self.modelIdentifier = modelIdentifier - } - } - - private enum CodingKeys: String, CodingKey { - case date - case controllerTimeZone - case dosingEnabled - case glucoseTargetRangeSchedule - case preMealTargetRange - case workoutTargetRange - case overridePresets - case scheduleOverride - case preMealOverride - case maximumBasalRatePerHour - case maximumBolus - case suspendThreshold - case deviceToken - case insulinType - case defaultRapidActingModel - case basalRateSchedule - case insulinSensitivitySchedule - case carbRatioSchedule - case notificationSettings - case controllerDevice - case cgmDevice - case pumpDevice - case bloodGlucoseUnit - case automaticDosingStrategy - case syncIdentifier - } -} - -// MARK: - Critical Event Log Export - -extension SettingsStore: CriticalEventLog { - private var exportProgressUnitCountPerObject: Int64 { 11 } - private var exportFetchLimit: Int { Int(criticalEventLogExportProgressUnitCountPerFetch / exportProgressUnitCountPerObject) } - - public var exportName: String { "Settings.json" } - - public func exportProgressTotalUnitCount(startDate: Date, endDate: Date? = nil) -> Result { - var result: Result? - - self.store.managedObjectContext.performAndWait { - do { - let request: NSFetchRequest = SettingsObject.fetchRequest() - request.predicate = self.exportDatePredicate(startDate: startDate, endDate: endDate) - - let objectCount = try self.store.managedObjectContext.count(for: request) - result = .success(Int64(objectCount) * exportProgressUnitCountPerObject) - } catch let error { - result = .failure(error) - } - } - - return result! - } - - public func export(startDate: Date, endDate: Date, to stream: OutputStream, progress: Progress) -> Error? { - let encoder = JSONStreamEncoder(stream: stream) - var modificationCounter: Int64 = 0 - var fetching = true - var error: Error? - - while fetching && error == nil { - self.store.managedObjectContext.performAndWait { - do { - guard !progress.isCancelled else { - throw CriticalEventLogError.cancelled - } - - let request: NSFetchRequest = SettingsObject.fetchRequest() - request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format: "modificationCounter > %d", modificationCounter), - self.exportDatePredicate(startDate: startDate, endDate: endDate)]) - request.sortDescriptors = [NSSortDescriptor(key: "modificationCounter", ascending: true)] - request.fetchLimit = self.exportFetchLimit - - let objects = try self.store.managedObjectContext.fetch(request) - if objects.isEmpty { - fetching = false - return - } - - try encoder.encode(objects) - - modificationCounter = objects.last!.modificationCounter - - progress.completedUnitCount += Int64(objects.count) * exportProgressUnitCountPerObject - } catch let fetchError { - error = fetchError - } - } - } - - if let closeError = encoder.close(), error == nil { - error = closeError - } - - return error - } - - private func exportDatePredicate(startDate: Date, endDate: Date? = nil) -> NSPredicate { - var predicate = NSPredicate(format: "date >= %@", startDate as NSDate) - if let endDate = endDate { - predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSPredicate(format: "date < %@", endDate as NSDate)]) - } - return predicate - } -} - -// MARK: - Core Data (Bulk) - TEST ONLY - -extension SettingsStore { - public func addStoredSettings(settings: [StoredSettings], completion: @escaping (Error?) -> Void) { - guard !settings.isEmpty else { - completion(nil) - return - } - - dataAccessQueue.async { - var error: Error? - - self.store.managedObjectContext.performAndWait { - for setting in settings { - guard let data = self.encodeSettings(setting) else { - continue - } - let object = SettingsObject(context: self.store.managedObjectContext) - object.data = data - object.date = setting.date - } - error = self.store.save() - } - - guard error == nil else { - completion(error) - return - } - - self.log.info("Added %d SettingsObjects", settings.count) - self.delegate?.settingsStoreHasUpdatedSettingsData(self) - completion(nil) - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/StoredInsulinModel.swift b/Dependencies/LoopKit/LoopKit/StoredInsulinModel.swift deleted file mode 100644 index e4bac2f63..000000000 --- a/Dependencies/LoopKit/LoopKit/StoredInsulinModel.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// StoredInsulinModel.swift -// LoopKit -// -// Created by Darin Krauss on 7/23/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct StoredInsulinModel: Codable, Equatable { - public enum ModelType: String, Codable { - case afrezza - case fiasp - case lyumjev - case rapidAdult - case rapidChild - } - - public let modelType: ModelType - public let delay: TimeInterval - public let actionDuration: TimeInterval - public let peakActivity: TimeInterval - - public init(modelType: ModelType, delay: TimeInterval, actionDuration: TimeInterval, peakActivity: TimeInterval) { - self.modelType = modelType - self.delay = delay - self.actionDuration = actionDuration - self.peakActivity = peakActivity - } -} - -public extension StoredInsulinModel { - init(_ preset: ExponentialInsulinModelPreset) { - var modelType: StoredInsulinModel.ModelType - - switch preset { - case .afrezza: - modelType = .afrezza - case .fiasp: - modelType = .fiasp - case .lyumjev: - modelType = .lyumjev - case .rapidActingAdult: - modelType = .rapidAdult - case .rapidActingChild: - modelType = .rapidChild - } - - self.init(modelType: modelType, delay: preset.delay, actionDuration: preset.actionDuration, peakActivity: preset.peakActivity) - } - - var presetForRapidActingInsulin: ExponentialInsulinModelPreset? { - switch modelType { - case .rapidAdult: - return .rapidActingAdult - case .rapidChild: - return .rapidActingChild - default: - return nil - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/SyncAlertObject.swift b/Dependencies/LoopKit/LoopKit/SyncAlertObject.swift deleted file mode 100644 index ef5c2e214..000000000 --- a/Dependencies/LoopKit/LoopKit/SyncAlertObject.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// SyncAlertObject.swift -// LoopKit -// -// Created by Darin Krauss on 1/19/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct SyncAlertObject: Codable { - public let identifier: Alert.Identifier - public let trigger: Alert.Trigger - public let interruptionLevel: Alert.InterruptionLevel - public let foregroundContent: Alert.Content? - public let backgroundContent: Alert.Content? - public let sound: Alert.Sound? - public let metadata: Alert.Metadata? - public let issuedDate: Date - public let acknowledgedDate: Date? - public let retractedDate: Date? - public let syncIdentifier: UUID - - public init(identifier: Alert.Identifier, - trigger: Alert.Trigger, - interruptionLevel: Alert.InterruptionLevel, - foregroundContent: Alert.Content?, - backgroundContent: Alert.Content?, - sound: Alert.Sound?, - metadata: Alert.Metadata?, - issuedDate: Date, - acknowledgedDate: Date?, - retractedDate: Date?, - syncIdentifier: UUID) { - self.identifier = identifier - self.trigger = trigger - self.interruptionLevel = interruptionLevel - self.foregroundContent = foregroundContent - self.backgroundContent = backgroundContent - self.sound = sound - self.metadata = metadata - self.issuedDate = issuedDate - self.acknowledgedDate = acknowledgedDate - self.retractedDate = retractedDate - self.syncIdentifier = syncIdentifier - } -} diff --git a/Dependencies/LoopKit/LoopKit/TemporaryScheduleOverride.swift b/Dependencies/LoopKit/LoopKit/TemporaryScheduleOverride.swift deleted file mode 100644 index 156412ded..000000000 --- a/Dependencies/LoopKit/LoopKit/TemporaryScheduleOverride.swift +++ /dev/null @@ -1,419 +0,0 @@ -// -// TemporaryScheduleOverride.swift -// LoopKit -// -// Created by Michael Pangburn on 1/1/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - - -public struct TemporaryScheduleOverride: Hashable { - public enum Context: Hashable { - case preMeal - case legacyWorkout - case preset(TemporaryScheduleOverridePreset) - case custom - } - - public enum EnactTrigger: Hashable { - case local - case remote(String) - } - - public enum Duration: Hashable, Comparable { - case finite(TimeInterval) - case indefinite - - public var timeInterval: TimeInterval { - switch self { - case .finite(let interval): - return interval - case .indefinite: - return .infinity - } - } - - public var isFinite: Bool { - return timeInterval.isFinite - } - - public var isInfinite: Bool { - return timeInterval.isInfinite - } - - public static func < (lhs: Duration, rhs: Duration) -> Bool { - return lhs.timeInterval < rhs.timeInterval - } - } - - public var context: Context - public var settings: TemporaryScheduleOverrideSettings - public var startDate: Date - public let enactTrigger: EnactTrigger - public let syncIdentifier: UUID - - public var actualEnd: End = .natural - - public var actualEndDate: Date { - switch actualEnd { - case .natural: - return scheduledEndDate - case .early(let endDate): - return endDate - case .deleted: - return scheduledEndDate - } - } - - public var duration: Duration { - didSet { - precondition(duration.timeInterval > 0) - } - } - - public var scheduledEndDate: Date { - get { - return startDate + duration.timeInterval - } - set { - precondition(newValue > startDate) - if newValue == .distantFuture { - duration = .indefinite - } else { - duration = .finite(newValue.timeIntervalSince(startDate)) - } - } - } - - public var activeInterval: DateInterval { - return DateInterval(start: startDate, end: actualEndDate) - } - - public var scheduledInterval: DateInterval { - get { - return DateInterval(start: startDate, end: scheduledEndDate) - } - set { - startDate = newValue.start - scheduledEndDate = newValue.end - } - } - - public func hasFinished(relativeTo date: Date = Date()) -> Bool { - return date > actualEndDate - } - - public init(context: Context, settings: TemporaryScheduleOverrideSettings, startDate: Date, duration: Duration, enactTrigger: EnactTrigger, syncIdentifier: UUID) { - precondition(duration.timeInterval > 0) - self.context = context - self.settings = settings - self.startDate = startDate - self.duration = duration - self.enactTrigger = enactTrigger - self.syncIdentifier = syncIdentifier - } - - public func isActive(at date: Date = Date()) -> Bool { - return activeInterval.contains(date) - } -} - -extension TemporaryScheduleOverride: RawRepresentable { - public typealias RawValue = [String: Any] - - public init?(rawValue: RawValue) { - guard - let contextRawValue = rawValue["context"] as? Context.RawValue, - let context = Context(rawValue: contextRawValue), - let settingsRawValue = rawValue["settings"] as? TemporaryScheduleOverrideSettings.RawValue, - let settings = TemporaryScheduleOverrideSettings(rawValue: settingsRawValue), - let startDateSeconds = rawValue["startDate"] as? TimeInterval, - let durationRawValue = rawValue["duration"] as? Duration.RawValue, - let duration = Duration(rawValue: durationRawValue) - else { - return nil - } - - let startDate = Date(timeIntervalSince1970: startDateSeconds) - - let enactTrigger: EnactTrigger - if let enactTriggerRaw = rawValue["enactTrigger"] as? EnactTrigger.RawValue, - let storedEnactTrigger = EnactTrigger(rawValue: enactTriggerRaw) - { - enactTrigger = storedEnactTrigger - } else { - enactTrigger = .local - } - - let syncIdentifier: UUID - if let syncIdentifierRaw = rawValue["syncIdentifier"] as? String, - let storedSyncIdentifier = UUID(uuidString: syncIdentifierRaw) { - syncIdentifier = storedSyncIdentifier - } else { - syncIdentifier = UUID() - } - - self.init(context: context, settings: settings, startDate: startDate, duration: duration, enactTrigger: enactTrigger, syncIdentifier: syncIdentifier) - } - - public var rawValue: RawValue { - return [ - "context": context.rawValue, - "settings": settings.rawValue, - "startDate": startDate.timeIntervalSince1970, - "duration": duration.rawValue, - "syncIdentifier": syncIdentifier.uuidString, - "enactTrigger": enactTrigger.rawValue, - ] - } -} - -extension TemporaryScheduleOverride: Codable {} - -extension TemporaryScheduleOverride.Context: RawRepresentable { - public typealias RawValue = [String: Any] - - public init?(rawValue: RawValue) { - guard let context = rawValue["context"] as? String else { - return nil - } - - switch context { - case "premeal": - self = .preMeal - case "legacyWorkout": - self = .legacyWorkout - case "preset": - guard - let presetRawValue = rawValue["preset"] as? TemporaryScheduleOverridePreset.RawValue, - let preset = TemporaryScheduleOverridePreset(rawValue: presetRawValue) - else { - return nil - } - self = .preset(preset) - case "custom": - self = .custom - default: - return nil - } - } - - public var rawValue: RawValue { - switch self { - case .preMeal: - return ["context": "premeal"] - case .legacyWorkout: - return ["context": "legacyWorkout"] - case .preset(let preset): - return [ - "context": "preset", - "preset": preset.rawValue - ] - case .custom: - return ["context": "custom"] - } - } -} - -extension TemporaryScheduleOverride.Context: Codable { - public init(from decoder: Decoder) throws { - if let string = try? decoder.singleValueContainer().decode(String.self) { - switch string { - case CodableKeys.preMeal.rawValue: - self = .preMeal - case CodableKeys.legacyWorkout.rawValue: - self = .legacyWorkout - case CodableKeys.custom.rawValue: - self = .custom - default: - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "invalid enumeration")) - } - } else { - let container = try decoder.container(keyedBy: CodableKeys.self) - if let preset = try container.decodeIfPresent(Preset.self, forKey: .preset) { - self = .preset(preset.preset) - } else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "invalid enumeration")) - } - } - } - - public func encode(to encoder: Encoder) throws { - switch self { - case .preMeal: - var container = encoder.singleValueContainer() - try container.encode(CodableKeys.preMeal.rawValue) - case .legacyWorkout: - var container = encoder.singleValueContainer() - try container.encode(CodableKeys.legacyWorkout.rawValue) - case .preset(let preset): - var container = encoder.container(keyedBy: CodableKeys.self) - try container.encode(Preset(preset: preset), forKey: .preset) - case .custom: - var container = encoder.singleValueContainer() - try container.encode(CodableKeys.custom.rawValue) - } - } - - private struct Preset: Codable { - let preset: TemporaryScheduleOverridePreset - } - - private enum CodableKeys: String, CodingKey { - case preMeal - case legacyWorkout - case preset - case custom - } -} - -extension TemporaryScheduleOverride.Duration: RawRepresentable { - public typealias RawValue = [String: Any] - - public init?(rawValue: RawValue) { - guard let duration = rawValue["duration"] as? String else { - return nil - } - - switch duration { - case "finite": - guard let interval = rawValue["interval"] as? TimeInterval else { - return nil - } - self = .finite(interval) - case "indefinite": - self = .indefinite - default: - return nil - } - } - - public var rawValue: RawValue { - switch self { - case .finite(let interval): - return [ - "duration": "finite", - "interval": interval - ] - case .indefinite: - return ["duration": "indefinite"] - } - } -} - -extension TemporaryScheduleOverride.Duration: Codable { - public init(from decoder: Decoder) throws { - if let string = try? decoder.singleValueContainer().decode(String.self) { - switch string { - case CodableKeys.indefinite.rawValue: - self = .indefinite - default: - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "invalid enumeration")) - } - } else { - let container = try decoder.container(keyedBy: CodableKeys.self) - if let finite = try container.decodeIfPresent(Finite.self, forKey: .finite) { - self = .finite(finite.duration) - } else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "invalid enumeration")) - } - } - } - - public func encode(to encoder: Encoder) throws { - switch self { - case .finite(let duration): - var container = encoder.container(keyedBy: CodableKeys.self) - try container.encode(Finite(duration: duration), forKey: .finite) - case .indefinite: - var container = encoder.singleValueContainer() - try container.encode(CodableKeys.indefinite.rawValue) - } - } - - private struct Finite: Codable { - let duration: TimeInterval - } - - private enum CodableKeys: String, CodingKey { - case finite - case indefinite - } -} - -extension TemporaryScheduleOverride.EnactTrigger: RawRepresentable { - public typealias RawValue = [String: Any] - - public init?(rawValue: RawValue) { - guard let trigger = rawValue["trigger"] as? String else { - return nil - } - - switch trigger { - case "local": - self = .local - case "remote": - guard let remoteAddress = rawValue["remoteAddress"] as? String else { - return nil - } - self = .remote(remoteAddress) - default: - return nil - } - } - - public var rawValue: RawValue { - switch self { - case .local: - return ["trigger": "local"] - case .remote(let remoteAddress): - return [ - "trigger": "remote", - "remoteAddress": remoteAddress - ] - } - } -} - -extension TemporaryScheduleOverride.EnactTrigger: Codable { - public init(from decoder: Decoder) throws { - if let string = try? decoder.singleValueContainer().decode(String.self) { - switch string { - case CodableKeys.local.rawValue: - self = .local - default: - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "invalid enumeration")) - } - } else { - let container = try decoder.container(keyedBy: CodableKeys.self) - if let remote = try container.decodeIfPresent(Remote.self, forKey: .remote) { - self = .remote(remote.address) - } else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "invalid enumeration")) - } - } - } - - public func encode(to encoder: Encoder) throws { - switch self { - case .local: - var container = encoder.singleValueContainer() - try container.encode(CodableKeys.local.rawValue) - case .remote(let address): - var container = encoder.container(keyedBy: CodableKeys.self) - try container.encode(Remote(address: address), forKey: .remote) - } - } - - private struct Remote: Codable { - let address: String - } - - private enum CodableKeys: String, CodingKey { - case local - case remote - } -} diff --git a/Dependencies/LoopKit/LoopKit/TemporaryScheduleOverrideHistory.swift b/Dependencies/LoopKit/LoopKit/TemporaryScheduleOverrideHistory.swift deleted file mode 100644 index 5720d9ee1..000000000 --- a/Dependencies/LoopKit/LoopKit/TemporaryScheduleOverrideHistory.swift +++ /dev/null @@ -1,392 +0,0 @@ -// -// TemporaryScheduleOverrideHistory.swift -// LoopKit -// -// Created by Michael Pangburn on 3/25/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum End: Equatable, Hashable, Codable { - case natural - case early(Date) - case deleted // Ended before started - - private enum EndType: String, Decodable { - case natural, early, deleted - } - - private enum CodingKeys: String, CodingKey { - case type - case date - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let endType = try container.decode(EndType.self, forKey: .type) - - switch endType { - case .natural: - self = .natural - case .early: - let date = try container.decode(Date.self, forKey: .date) - self = .early(date) - case .deleted: - self = .deleted - } - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - switch self { - case .natural: - try container.encode(EndType.natural.rawValue, forKey: .type) - case .early(let date): - try container.encode(EndType.early.rawValue, forKey: .type) - try container.encode(date, forKey: .date) - case .deleted: - try container.encode(EndType.deleted.rawValue, forKey: .type) - } - } -} - -private struct OverrideEvent: Equatable { - - var override: TemporaryScheduleOverride - var modificationCounter: Int64 - - init(override: TemporaryScheduleOverride, modificationCounter: Int64) { - self.override = override - self.modificationCounter = modificationCounter - } -} - - -public protocol TemporaryScheduleOverrideHistoryDelegate: AnyObject { - func temporaryScheduleOverrideHistoryDidUpdate(_ history: TemporaryScheduleOverrideHistory) -} - -public final class TemporaryScheduleOverrideHistory { - public struct QueryAnchor: RawRepresentable { - public typealias RawValue = [String: Any] - - internal var modificationCounter: Int64 - - public init() { - self.modificationCounter = 0 - } - - public init?(rawValue: RawValue) { - guard let modificationCounter = rawValue["modificationCounter"] as? Int64 else { - return nil - } - self.modificationCounter = modificationCounter - } - - public var rawValue: RawValue { - var rawValue: RawValue = [:] - rawValue["modificationCounter"] = modificationCounter - return rawValue - } - } - - private var recentEvents: [OverrideEvent] = [] { - didSet { - modificationCounter += 1 - - if let lastTaintedEvent = taintedEventLog.last, - Date().timeIntervalSince(lastTaintedEvent.override.startDate) > .hours(48) - { - taintedEventLog.removeAll() - } - } - } - - /// Tracks a sequence of override events that failed validation checks. - /// Stored to enable retrieval via issue report after a deliberate crash. - private var taintedEventLog: [OverrideEvent] = [] - - private var modificationCounter: Int64 - - public var relevantTimeWindow: TimeInterval = TimeInterval.hours(10) - - public weak var delegate: TemporaryScheduleOverrideHistoryDelegate? - - public init() { - modificationCounter = 0 - } - - public func recordOverride(_ override: TemporaryScheduleOverride?, at enableDate: Date = Date()) { - guard override != lastUndeletedEvent?.override else { - return - } - - if let override = override { - record(override, at: enableDate) - } else { - cancelActiveOverride(at: enableDate) - } - delegate?.temporaryScheduleOverrideHistoryDidUpdate(self) - } - - private var lastUndeletedEvent: OverrideEvent? { - return recentEvents.reversed().first { $0.override.actualEnd != .deleted } - } - - private func deleteEventsStartingOnOrAfter(_ date: Date) { - recentEvents.mutateEach { (event) in - if event.override.startDate >= date { - event.override.actualEnd = .deleted - event.modificationCounter = modificationCounter - } - } - } - - // Deletes overrides that start after the passed in override. - private func record(_ override: TemporaryScheduleOverride, at enableDate: Date) { - - // Check for modification of existing entry - var index = recentEvents.endIndex - while index != recentEvents.startIndex { - recentEvents.formIndex(before: &index) - if recentEvents[index].override.syncIdentifier == override.syncIdentifier { - recentEvents[index].override = override - recentEvents[index].modificationCounter = modificationCounter - return - } - } - - deleteEventsStartingOnOrAfter(override.startDate) - - let overrideEnd = min(override.startDate.nearestPrevious, enableDate) - - cancelActiveOverride(at: overrideEnd) - - let enabledEvent = OverrideEvent(override: override, modificationCounter: modificationCounter) - recentEvents.append(enabledEvent) - } - - private func cancelActiveOverride(at date: Date) { - var index = recentEvents.endIndex - while index != recentEvents.startIndex { - recentEvents.formIndex(before: &index) - - if recentEvents[index].override.actualEnd != .deleted { - if recentEvents[index].override.actualEndDate > date { - if recentEvents[index].override.startDate > date { - recentEvents[index].override.actualEnd = .deleted - } else { - recentEvents[index].override.actualEnd = .early(date) - } - recentEvents[index].modificationCounter = modificationCounter - } - break - } - } - } - - public func resolvingRecentBasalSchedule(_ base: BasalRateSchedule, relativeTo referenceDate: Date = Date()) -> BasalRateSchedule { - filterRecentEvents(relativeTo: referenceDate) - return overridesReflectingEnabledDuration(relativeTo: referenceDate).reduce(base) { base, override in - base.applyingBasalRateMultiplier(from: override, relativeTo: referenceDate) - } - } - - public func resolvingRecentInsulinSensitivitySchedule(_ base: InsulinSensitivitySchedule, relativeTo referenceDate: Date = Date()) -> InsulinSensitivitySchedule { - filterRecentEvents(relativeTo: referenceDate) - return overridesReflectingEnabledDuration(relativeTo: referenceDate).reduce(base) { base, override in - base.applyingSensitivityMultiplier(from: override, relativeTo: referenceDate) - } - } - - public func resolvingRecentCarbRatioSchedule(_ base: CarbRatioSchedule, relativeTo referenceDate: Date = Date()) -> CarbRatioSchedule { - filterRecentEvents(relativeTo: referenceDate) - return overridesReflectingEnabledDuration(relativeTo: referenceDate).reduce(base) { base, override in - base.applyingCarbRatioMultiplier(from: override, relativeTo: referenceDate) - } - } - - public func getEvents(relativeTo referenceDate: Date = Date()) -> [TemporaryScheduleOverride] { - filterRecentEvents(relativeTo: referenceDate) - return recentEvents.map { $0.override } - } - - private func relevantPeriod(relativeTo referenceDate: Date) -> DateInterval { - return DateInterval( - start: referenceDate.addingTimeInterval(-relevantTimeWindow), - end: referenceDate.addingTimeInterval(relevantTimeWindow) - ) - } - - private func filterRecentEvents(relativeTo referenceDate: Date) { - let period = relevantPeriod(relativeTo: referenceDate) - var recentEvents = self.recentEvents - recentEvents.removeAll(where: { event in - event.override.actualEndDate < period.start || event.override.startDate > period.end - }) - - if recentEvents != self.recentEvents { - self.recentEvents = recentEvents - } - } - - private func overridesReflectingEnabledDuration(relativeTo referenceDate: Date) -> [TemporaryScheduleOverride] { - var overrides = recentEvents.filter({$0.override.actualEnd != .deleted}).map { event -> TemporaryScheduleOverride in - var override = event.override - if case .early(let endDate) = event.override.actualEnd { - override.scheduledEndDate = endDate - } - return override - } - let period = relevantPeriod(relativeTo: referenceDate) - overrides.mutateEach { override in - // Save the actual (computed) end date prior to modifying the start date, which shifts the whole interval - let end = override.scheduledEndDate - override.startDate = max(override.startDate, period.start) - override.scheduledEndDate = min(end, period.end) - } - validateOverridesReflectingEnabledDuration(overrides) - return overrides - } - - private func validateOverridesReflectingEnabledDuration(_ overrides: [TemporaryScheduleOverride]) { - let overlappingOverridePairIndices: [(Int, Int)] = - Array(overrides.enumerated()) - .allPairs() - .compactMap { - let ((index1, override1), (index2, override2)) = ($0, $1) - if override1.activeInterval.intersects(override2.activeInterval) { - return (index1, index2) - } else { - return nil - } - } - - let invalidOverrideIndices = overlappingOverridePairIndices.flatMap { [$0, $1] } - guard invalidOverrideIndices.isEmpty else { - // Save the invalid event history for debugging. - taintedEventLog = recentEvents - - // Wipe only conflicting overrides to retain as much history as possible. - recentEvents.removeAll(at: invalidOverrideIndices) - - // Store the history without the conflicting overrides - delegate?.temporaryScheduleOverrideHistoryDidUpdate(self) - - // Crash deliberately to notify something has gone wrong. - preconditionFailure("No overrides should overlap.") - } - } - - func wipeHistory() { - recentEvents.removeAll() - modificationCounter = 0 - } - - public func queryByAnchor(_ anchor: QueryAnchor?) -> (resultOverrides: [TemporaryScheduleOverride], deletedOverrides: [TemporaryScheduleOverride], newAnchor: QueryAnchor) { - var resultOverrides = [TemporaryScheduleOverride]() - var deletedOverrides = [TemporaryScheduleOverride]() - for event in recentEvents { - if anchor == nil || event.modificationCounter >= anchor!.modificationCounter { - var override = event.override - if case .early(let endDate) = event.override.actualEnd { - override.scheduledEndDate = endDate - } - if event.override.actualEnd == .deleted { - deletedOverrides.append(override) - } else { - resultOverrides.append(override) - } - } - } - var newAnchor = QueryAnchor() - newAnchor.modificationCounter = modificationCounter - return (resultOverrides: resultOverrides, deletedOverrides: deletedOverrides, newAnchor: newAnchor) - } -} - - -extension OverrideEvent: RawRepresentable { - typealias RawValue = [String: Any] - - init?(rawValue: RawValue) { - guard - let overrideRawValue = rawValue["override"] as? TemporaryScheduleOverride.RawValue, - let override = TemporaryScheduleOverride(rawValue: overrideRawValue) - else { - return nil - } - - self.override = override - - self.modificationCounter = rawValue["modificationCounter"] as? Int64 ?? 0 - - if let isDeleted = rawValue["isDeleted"] as? Bool, isDeleted { - self.override.actualEnd = .deleted - } else if let endDate = rawValue["endDate"] as? Date { - self.override.actualEnd = .early(endDate) - } - } - - var rawValue: RawValue { - var raw: RawValue = [ - "override": override.rawValue, - "modificationCounter": modificationCounter, - "isDeleted": override.actualEnd == .deleted, - ] - - if case .early(let endDate) = override.actualEnd { - raw["endDate"] = endDate - } - - return raw - } -} - - -extension TemporaryScheduleOverrideHistory: RawRepresentable { - public typealias RawValue = [String: Any] - - public convenience init?(rawValue: RawValue) { - self.init() - if let recentEventsRawValue = rawValue["recentEvents"] as? [[String: Any]] { - let recentEvents = recentEventsRawValue.compactMap(OverrideEvent.init(rawValue:)) - guard recentEvents.count == recentEventsRawValue.count else { - return nil - } - self.recentEvents = recentEvents - } - if let taintedEventsRawValue = rawValue["taintedEventLog"] as? [[String: Any]] { - let taintedEventLog = taintedEventsRawValue.compactMap(OverrideEvent.init(rawValue:)) - guard taintedEventLog.count == taintedEventsRawValue.count else { - return nil - } - self.taintedEventLog = taintedEventLog - } - - self.modificationCounter = rawValue["modificationCounter"] as? Int64 ?? 0 - } - - public var rawValue: RawValue { - return [ - "recentEvents": recentEvents.map { $0.rawValue }, - "taintedEventLog": taintedEventLog.map { $0.rawValue }, - "modificationCounter": modificationCounter - ] - } -} - - -extension TemporaryScheduleOverrideHistory: CustomDebugStringConvertible { - public var debugDescription: String { - return "TemporaryScheduleOverrideHistory(recentEvents: \(recentEvents), taintedEventLog: \(taintedEventLog))" - } -} - - -private extension Date { - var nearestPrevious: Date { - return Date(timeIntervalSince1970: timeIntervalSince1970.nextDown) - } -} diff --git a/Dependencies/LoopKit/LoopKit/TemporaryScheduleOverridePreset.swift b/Dependencies/LoopKit/LoopKit/TemporaryScheduleOverridePreset.swift deleted file mode 100644 index db3f3ce6b..000000000 --- a/Dependencies/LoopKit/LoopKit/TemporaryScheduleOverridePreset.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// TemporaryScheduleOverridePreset.swift -// Loop -// -// Created by Michael Pangburn on 1/2/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - - -public struct TemporaryScheduleOverridePreset: Hashable { - public let id: UUID - public var symbol: String - public var name: String - public var settings: TemporaryScheduleOverrideSettings - public var duration: TemporaryScheduleOverride.Duration - - public init(id: UUID = UUID(), symbol: String, name: String, settings: TemporaryScheduleOverrideSettings, duration: TemporaryScheduleOverride.Duration) { - self.id = id - self.symbol = symbol - self.name = name - self.settings = settings - self.duration = duration - } - - public func createOverride(enactTrigger: TemporaryScheduleOverride.EnactTrigger, beginningAt date: Date = Date()) -> TemporaryScheduleOverride { - return TemporaryScheduleOverride( - context: .preset(self), - settings: settings, - startDate: date, - duration: duration, - enactTrigger: enactTrigger, - syncIdentifier: UUID() - ) - } -} - -extension TemporaryScheduleOverridePreset: RawRepresentable { - public typealias RawValue = [String: Any] - - public init?(rawValue: RawValue) { - guard - let idString = rawValue["id"] as? String, - let id = UUID(uuidString: idString), - let symbol = rawValue["symbol"] as? String, - let name = rawValue["name"] as? String, - let settingsRawValue = rawValue["settings"] as? TemporaryScheduleOverrideSettings.RawValue, - let settings = TemporaryScheduleOverrideSettings(rawValue: settingsRawValue), - let durationRawValue = rawValue["duration"] as? TemporaryScheduleOverride.Duration.RawValue, - let duration = TemporaryScheduleOverride.Duration(rawValue: durationRawValue) - else { - return nil - } - - self.init(id: id, symbol: symbol, name: name, settings: settings, duration: duration) - } - - public var rawValue: RawValue { - return [ - "id": id.uuidString, - "symbol": symbol, - "name": name, - "settings": settings.rawValue, - "duration": duration.rawValue - ] - } -} - -extension TemporaryScheduleOverridePreset: Codable {} diff --git a/Dependencies/LoopKit/LoopKit/TemporaryScheduleOverrideSettings.swift b/Dependencies/LoopKit/LoopKit/TemporaryScheduleOverrideSettings.swift deleted file mode 100644 index 4b729c71d..000000000 --- a/Dependencies/LoopKit/LoopKit/TemporaryScheduleOverrideSettings.swift +++ /dev/null @@ -1,87 +0,0 @@ -// -// TemporaryScheduleOverrideSettings.swift -// LoopKit -// -// Created by Michael Pangburn on 1/2/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import HealthKit - - -public struct TemporaryScheduleOverrideSettings: Hashable { - private var targetRangeInMgdl: DoubleRange? - public var insulinNeedsScaleFactor: Double? - - public var targetRange: ClosedRange? { - return targetRangeInMgdl.map { $0.quantityRange(for: .milligramsPerDeciliter) } - } - - public var basalRateMultiplier: Double? { - return insulinNeedsScaleFactor - } - - public var insulinSensitivityMultiplier: Double? { - return insulinNeedsScaleFactor.map { 1.0 / $0 } - } - - public var carbRatioMultiplier: Double? { - return insulinNeedsScaleFactor.map { 1.0 / $0 } - } - - public var effectiveInsulinNeedsScaleFactor: Double { - return insulinNeedsScaleFactor ?? 1.0 - } - - public init(unit: HKUnit, targetRange: DoubleRange?, insulinNeedsScaleFactor: Double? = nil) { - self.init(targetRange: targetRange?.quantityRange(for: unit), insulinNeedsScaleFactor: insulinNeedsScaleFactor) - } - - public init(targetRange: ClosedRange?, insulinNeedsScaleFactor: Double? = nil) { - self.targetRangeInMgdl = targetRange?.doubleRange(for: .milligramsPerDeciliter) - self.insulinNeedsScaleFactor = insulinNeedsScaleFactor - } -} - -extension TemporaryScheduleOverrideSettings: RawRepresentable { - public typealias RawValue = [String: Any] - - private enum Key { - static let targetRange = "targetRange" - static let insulinNeedsScaleFactor = "insulinNeedsScaleFactor" - static let version = "version" - } - - public init?(rawValue: RawValue) { - if let targetRangeRawValue = rawValue[Key.targetRange] as? DoubleRange.RawValue, - let targetRange = DoubleRange(rawValue: targetRangeRawValue) { - self.targetRangeInMgdl = targetRange - } - let version = rawValue[Key.version] as? Int ?? 0 - - // Do not allow target ranges from versions < 1, as there was no unit convention at that point. - if version < 1 && targetRange != nil { - return nil - } - - self.insulinNeedsScaleFactor = rawValue[Key.insulinNeedsScaleFactor] as? Double - } - - public var rawValue: RawValue { - var raw: RawValue = [:] - - if let targetRangeInMgdl = targetRangeInMgdl { - raw[Key.targetRange] = targetRangeInMgdl.rawValue - } - - if let insulinNeedsScaleFactor = insulinNeedsScaleFactor { - raw[Key.insulinNeedsScaleFactor] = insulinNeedsScaleFactor - } - - raw[Key.version] = 1 - - return raw - } -} - -extension TemporaryScheduleOverrideSettings: Codable {} diff --git a/Dependencies/LoopKit/LoopKit/TherapySetting.swift b/Dependencies/LoopKit/LoopKit/TherapySetting.swift deleted file mode 100644 index 045b27634..000000000 --- a/Dependencies/LoopKit/LoopKit/TherapySetting.swift +++ /dev/null @@ -1,127 +0,0 @@ -// -// TherapySetting.swift -// LoopKit -// -// Created by Rick Pasetto on 7/14/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - - -public enum TherapySetting { - case glucoseTargetRange - case preMealCorrectionRangeOverride - case workoutCorrectionRangeOverride - case suspendThreshold - case basalRate(Int?) - case deliveryLimits - case insulinModel - case carbRatio - case insulinSensitivity - case none -} - -public extension TherapySetting { - static var basalRate: TherapySetting { - .basalRate(nil) - } -} - -extension TherapySetting: Equatable { } - -public extension TherapySetting { - - // The following comes from https://tidepool.atlassian.net/browse/IFU-24 - var title: String { - switch self { - case .glucoseTargetRange: - return LocalizedString("Correction Range", comment: "Title text for glucose target range") - case .preMealCorrectionRangeOverride: - return String(format: LocalizedString("%@ Range", comment: "Format for correction range override therapy setting card"), CorrectionRangeOverrides.Preset.preMeal.title) - case .workoutCorrectionRangeOverride: - return String(format: LocalizedString("%@ Range", comment: "Format for correction range override therapy setting card"), CorrectionRangeOverrides.Preset.workout.title) - case .suspendThreshold: - return LocalizedString("Glucose Safety Limit", comment: "Title text for glucose safety limit") - case .basalRate: - return LocalizedString("Basal Rates", comment: "Title text for basal rates") - case .deliveryLimits: - return LocalizedString("Delivery Limits", comment: "Title text for delivery limits") - case .insulinModel: - return LocalizedString("Insulin Model", comment: "Title text for fast acting insulin model") - case .carbRatio: - return LocalizedString("Carb Ratios", comment: "Title text for carb ratios") - case .insulinSensitivity: - return LocalizedString("Insulin Sensitivities", comment: "Title text for insulin sensitivity") - case .none: - return "" - } - } - - var smallTitle: String { - switch self { - default: - return title - } - } - - func descriptiveText(appName: String) -> String { - switch self { - case .glucoseTargetRange: - return String(format: LocalizedString("Correction Range is the glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin and helping you calculate your boluses.", comment: "Descriptive text for glucose target range (1: app name)"), appName) - case .preMealCorrectionRangeOverride: - return LocalizedString("Temporarily lower your glucose target before a meal to impact post-meal glucose spikes.", comment: "Descriptive text for pre-meal correction range override") - case .workoutCorrectionRangeOverride: - return LocalizedString("Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events.", comment: "Descriptive text for workout correction range override") - case .suspendThreshold: - return String(format: LocalizedString("%1$@ will deliver basal and recommend bolus insulin only if your glucose is predicted to be above this limit for the next three hours.", comment: "Descriptive format string for glucose safety limit (1: app name)"), appName) - case .basalRate: - return LocalizedString("Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs.", comment: "Descriptive text for basal rate") - case .deliveryLimits: - return "\(DeliveryLimits.Setting.maximumBasalRate.localizedDescriptiveText(appName: appName))\n\n\(DeliveryLimits.Setting.maximumBolus.localizedDescriptiveText(appName: appName))" - case .insulinModel: - return String(format: LocalizedString("For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from different models for the peak activity.", comment: "Descriptive text for fast acting insulin model (1: app name)"), appName) - case .carbRatio: - return LocalizedString("Your Carb Ratio is the number of grams of carbohydrates covered by one unit of insulin.", comment: "Descriptive text for carb ratio") - case .insulinSensitivity: - return LocalizedString("Your Insulin Sensitivities refer to the drop in glucose expected from one unit of insulin.", comment: "Descriptive text for insulin sensitivity") - case .none: - return "" - } - } -} - -// MARK: Guardrails -public extension TherapySetting { - var guardrailCaptionForLowValue: String { - switch self { - case .glucoseTargetRange, .preMealCorrectionRangeOverride, .workoutCorrectionRangeOverride: - return LocalizedString("A value you have entered is lower than what is typically recommended for most people.", comment: "Descriptive text for guardrail low value warning for schedule interface") - default: - return LocalizedString("The value you have entered is lower than what is typically recommended for most people.", comment: "Descriptive text for guardrail low value warning") - } - } - - var guardrailCaptionForHighValue: String { - switch self { - case .glucoseTargetRange, .preMealCorrectionRangeOverride, .workoutCorrectionRangeOverride: - return LocalizedString("A value you have entered is higher than what is typically recommended for most people.", comment: "Descriptive text for guardrail high value warning for schedule interface") - default: - return LocalizedString("The value you have entered is higher than what is typically recommended for most people.", comment: "Descriptive text for guardrail high value warning") - } - } - - var guardrailCaptionForOutsideValues: String { - switch self { - case .deliveryLimits: - return LocalizedString("The values you have entered are outside of what is typically recommended for most people.", comment: "Descriptive text for guardrail high value warning") - default: - return LocalizedString("Some of the values you have entered are outside of what is typically recommended for most people.", comment: "Descriptive text for guardrail high value warning for schedule interface") - } - } - - var guardrailSaveWarningCaption: String { - switch self { - default: - return LocalizedString("One or more of the values you have entered is outside of what is typically recommended for most people.", comment: "Descriptive text for saving settings outside the recommended range") - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/TherapySettings.swift b/Dependencies/LoopKit/LoopKit/TherapySettings.swift deleted file mode 100644 index dd4de7bb7..000000000 --- a/Dependencies/LoopKit/LoopKit/TherapySettings.swift +++ /dev/null @@ -1,164 +0,0 @@ -// -// TherapySettings.swift -// LoopKit -// -// Created by Anna Quinlan on 7/6/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import HealthKit - -public struct TherapySettings: Equatable { - - public var glucoseTargetRangeSchedule: GlucoseRangeSchedule? - - public var correctionRangeOverrides: CorrectionRangeOverrides? - - public var overridePresets: [TemporaryScheduleOverridePreset]? - - public var maximumBasalRatePerHour: Double? - - public var maximumBolus: Double? - - public var suspendThreshold: GlucoseThreshold? - - public var insulinSensitivitySchedule: InsulinSensitivitySchedule? - - public var carbRatioSchedule: CarbRatioSchedule? - - public var basalRateSchedule: BasalRateSchedule? - - public var defaultRapidActingModel: ExponentialInsulinModelPreset? - - public var isComplete: Bool { - return - glucoseTargetRangeSchedule != nil && - /* Correction Range (Premeal and workout) targets are optional */ - // correctionRangeOverrides != nil && - maximumBasalRatePerHour != nil && - maximumBolus != nil && - suspendThreshold != nil && - insulinSensitivitySchedule != nil && - carbRatioSchedule != nil && - basalRateSchedule != nil - } - - public init( - glucoseTargetRangeSchedule: GlucoseRangeSchedule? = nil, - correctionRangeOverrides: CorrectionRangeOverrides? = nil, - overridePresets: [TemporaryScheduleOverridePreset]? = nil, - maximumBasalRatePerHour: Double? = nil, - maximumBolus: Double? = nil, - suspendThreshold: GlucoseThreshold? = nil, - insulinSensitivitySchedule: InsulinSensitivitySchedule? = nil, - carbRatioSchedule: CarbRatioSchedule? = nil, - basalRateSchedule: BasalRateSchedule? = nil, - defaultRapidActingModel: ExponentialInsulinModelPreset? = nil - ){ - self.glucoseTargetRangeSchedule = glucoseTargetRangeSchedule - self.correctionRangeOverrides = correctionRangeOverrides - self.overridePresets = overridePresets - self.maximumBasalRatePerHour = maximumBasalRatePerHour - self.maximumBolus = maximumBolus - self.suspendThreshold = suspendThreshold - self.insulinSensitivitySchedule = insulinSensitivitySchedule - self.carbRatioSchedule = carbRatioSchedule - self.basalRateSchedule = basalRateSchedule - self.defaultRapidActingModel = defaultRapidActingModel - } -} - -extension TherapySettings: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - let glucoseTargetRangeSchedule = try container.decodeIfPresent(GlucoseRangeSchedule.self, forKey: .glucoseTargetRangeSchedule) - let correctionRangeOverrides = try container.decodeIfPresent(CorrectionRangeOverrides.self, forKey: .correctionRangeOverrides) - let maximumBasalRatePerHour = try container.decodeIfPresent(Double.self, forKey: .maximumBasalRatePerHour) - let maximumBolus = try container.decodeIfPresent(Double.self, forKey: .maximumBolus) - let suspendThreshold = try container.decodeIfPresent(GlucoseThreshold.self, forKey: .suspendThreshold) - let insulinSensitivitySchedule = try container.decodeIfPresent(InsulinSensitivitySchedule.self, forKey: .insulinSensitivitySchedule) - let carbRatioSchedule = try container.decodeIfPresent(CarbRatioSchedule.self, forKey: .carbRatioSchedule) - let basalRateSchedule = try container.decodeIfPresent(BasalRateSchedule.self, forKey: .basalRateSchedule) - let defaultRapidActingModel = try container.decodeIfPresent(ExponentialInsulinModelPreset.self, forKey: .defaultRapidActingModel) - - self.init(glucoseTargetRangeSchedule: glucoseTargetRangeSchedule, - correctionRangeOverrides: correctionRangeOverrides, - maximumBasalRatePerHour: maximumBasalRatePerHour, - maximumBolus: maximumBolus, - suspendThreshold: suspendThreshold, - insulinSensitivitySchedule: insulinSensitivitySchedule, - carbRatioSchedule: carbRatioSchedule, - basalRateSchedule: basalRateSchedule, - defaultRapidActingModel: defaultRapidActingModel) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encodeIfPresent(glucoseTargetRangeSchedule, forKey: .glucoseTargetRangeSchedule) - try container.encodeIfPresent(correctionRangeOverrides, forKey: .correctionRangeOverrides) - try container.encodeIfPresent(maximumBasalRatePerHour, forKey: .maximumBasalRatePerHour) - try container.encodeIfPresent(maximumBolus, forKey: .maximumBolus) - try container.encodeIfPresent(suspendThreshold, forKey: .suspendThreshold) - try container.encodeIfPresent(insulinSensitivitySchedule, forKey: .insulinSensitivitySchedule) - try container.encodeIfPresent(carbRatioSchedule, forKey: .carbRatioSchedule) - try container.encodeIfPresent(basalRateSchedule, forKey: .basalRateSchedule) - try container.encodeIfPresent(defaultRapidActingModel, forKey: .defaultRapidActingModel) - } - - private enum CodingKeys: String, CodingKey { - case glucoseTargetRangeSchedule - case correctionRangeOverrides - case maximumBasalRatePerHour - case maximumBolus - case suspendThreshold - case insulinSensitivitySchedule - case carbRatioSchedule - case basalRateSchedule - case defaultRapidActingModel - } -} - -extension TherapySettings { - // Mock therapy settings for QA and mock prescriptions - public static var mockTherapySettings: TherapySettings { - let timeZone = TimeZone(identifier: "America/Los_Angeles")! - let glucoseTargetRangeSchedule = GlucoseRangeSchedule( - rangeSchedule: DailyQuantitySchedule(unit: .milligramsPerDeciliter, - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: DoubleRange(minValue: 100.0, maxValue: 110.0)), - RepeatingScheduleValue(startTime: .hours(8), value: DoubleRange(minValue: 105.0, maxValue: 115.0)), - RepeatingScheduleValue(startTime: .hours(21), value: DoubleRange(minValue: 100.0, maxValue: 110.0))], - timeZone: timeZone)!, - override: GlucoseRangeSchedule.Override(value: DoubleRange(minValue: 80.0, maxValue: 90.0), - start: Date().addingTimeInterval(.minutes(-30)), - end: Date().addingTimeInterval(.minutes(30))) - ) - let correctionRangeOverrides = CorrectionRangeOverrides(preMeal: DoubleRange(minValue: 80.0, maxValue: 90.0), - workout: DoubleRange(minValue: 140.0, maxValue: 160.0), - unit: .milligramsPerDeciliter) - let basalRateSchedule = BasalRateSchedule( - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 1), - RepeatingScheduleValue(startTime: .hours(15), value: 0.85)], - timeZone: timeZone)! - let insulinSensitivitySchedule = InsulinSensitivitySchedule( - unit: .milligramsPerDeciliter, - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 45.0), - RepeatingScheduleValue(startTime: .hours(9), value: 55.0)], - timeZone: timeZone)! - let carbRatioSchedule = CarbRatioSchedule( - unit: .gram(), - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 10.0)], - timeZone: timeZone)! - return TherapySettings( - glucoseTargetRangeSchedule: glucoseTargetRangeSchedule, - correctionRangeOverrides: correctionRangeOverrides, - maximumBasalRatePerHour: 5, - maximumBolus: 10, - suspendThreshold: GlucoseThreshold(unit: .milligramsPerDeciliter, value: 75), - insulinSensitivitySchedule: insulinSensitivitySchedule, - carbRatioSchedule: carbRatioSchedule, - basalRateSchedule: basalRateSchedule, - defaultRapidActingModel: .rapidActingAdult - ) - } -} diff --git a/Dependencies/LoopKit/LoopKit/UnfairLock.swift b/Dependencies/LoopKit/LoopKit/UnfairLock.swift deleted file mode 100644 index 974192055..000000000 --- a/Dependencies/LoopKit/LoopKit/UnfairLock.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// UnfairLock.swift -// LoopKit Example -// -// Created by Pete Schwamb on 3/22/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -// Source: http://www.russbishop.net/the-law - -import Foundation - -public class UnfairLock { - private var _lock: UnsafeMutablePointer - - public init() { - _lock = UnsafeMutablePointer.allocate(capacity: 1) - _lock.initialize(to: os_unfair_lock()) - } - - deinit { - _lock.deallocate() - } - - public func withLock(_ f: () throws -> ReturnValue) rethrows -> ReturnValue { - os_unfair_lock_lock(_lock) - defer { os_unfair_lock_unlock(_lock) } - return try f() - } - - public func assertOwned() { - os_unfair_lock_assert_owner(_lock) - } - - public func assertNotOwned() { - os_unfair_lock_assert_not_owner(_lock) - } -} diff --git a/Dependencies/LoopKit/LoopKit/VersionUpdate.swift b/Dependencies/LoopKit/LoopKit/VersionUpdate.swift deleted file mode 100644 index 0f43a39b3..000000000 --- a/Dependencies/LoopKit/LoopKit/VersionUpdate.swift +++ /dev/null @@ -1,67 +0,0 @@ -// -// VersionUpdate.swift -// LoopKit -// -// Created by Rick Pasetto on 9/8/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -// Note: order is important for VersionUpdate. Later version updates are more critical than earlier ones. Do not reorder! -public enum VersionUpdate: Comparable, CaseIterable { - /// No version update needed. - case none - /// A update is available, but it is just informational (supported update). - case available - /// The version is unsupported; the app needs to be updated to the latest "supported" version. Not a critical update. - case recommended - /// The app must be updated immediately. - case required -} - -extension VersionUpdate: RawRepresentable { - public typealias RawValue = String - public init?(rawValue: RawValue) { - switch rawValue { - case "none": self = .none - case "available": self = .available - case "recommended": self = .recommended - case "required": self = .required - default: return nil - } - } - public var rawValue: RawValue { - switch self { - case .none: return "none" - case .available: return "available" - case .recommended: return "recommended" - case .required: return "required" - } - } -} - -extension VersionUpdate { - public static let `default` = VersionUpdate.none - - public var softwareUpdateAvailable: Bool { self > .none } -} - -extension VersionUpdate { - public var localizedDescription: String { - switch self { - case .none: - return LocalizedString("No Update", comment: "Description of no software update needed") - case .available: - return LocalizedString("Update Available", comment: "Description of informational software update needed") - case .recommended: - return LocalizedString("Recommended Update", comment: "Description of supported software update needed") - case .required: - return LocalizedString("Critical Update", comment: "Description of critical software update needed") - } - } -} - -public extension Notification.Name { - static let SoftwareUpdateAvailable = Notification.Name(rawValue: "com.loopkit.Loop.SoftwareUpdateAvailable") -} diff --git a/Dependencies/LoopKit/LoopKit/WeakSet.swift b/Dependencies/LoopKit/LoopKit/WeakSet.swift deleted file mode 100644 index e63a81a00..000000000 --- a/Dependencies/LoopKit/LoopKit/WeakSet.swift +++ /dev/null @@ -1,179 +0,0 @@ -// -// WeakSet.swift -// LoopKit -// -// Created by Michael Pangburn -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct Weak { - // Rather than constrain `Value` to `AnyObject`, we store the value privately as `AnyObject`. - // This allows us to hold weak references to class-constrained protocol types, - // which as types do not themselves conform to `AnyObject`. - private weak var _value: AnyObject? - - public var value: Value? { - return _value as? Value - } - - public init(_ value: Value) { - // All Swift values are implicitly convertible to `AnyObject`, - // so this runtime check is the tradeoff for supporting class-constrained protocol types. - precondition(Mirror(reflecting: value).displayStyle == .class, "Weak references can only be held of class types.") - _value = value as AnyObject - } -} - -/// A set that holds weak references to its members. -/// -/// `Element` must be a class or class-constrained protocol type. -public struct WeakSet { - private var storage: [ObjectIdentifier: Weak] - - public init(_ sequence: S) where S.Element == Element { - let keysAndValues = sequence.map { (key: ObjectIdentifier($0 as AnyObject), value: Weak($0)) } - storage = Dictionary(keysAndValues, uniquingKeysWith: { $1 }) - } - - public mutating func cleanupDeallocatedElements() { - for (id, element) in storage where element.value == nil { - storage.removeValue(forKey: id) - } - } -} - -extension WeakSet: SetAlgebra { - public init() { - storage = [:] - } - - public var isEmpty: Bool { - return storage.values.allSatisfy { $0.value == nil } - } - - public func contains(_ member: Element) -> Bool { - let id = ObjectIdentifier(member as AnyObject) - return storage[id] != nil - } - - @discardableResult - public mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element) { - let id = ObjectIdentifier(newMember as AnyObject) - if let existingMember = storage[id]?.value { - return (inserted: false, memberAfterInsert: existingMember) - } else { - storage[id] = Weak(newMember) - return (inserted: true, memberAfterInsert: newMember) - } - } - - @discardableResult - public mutating func update(with newMember: Element) -> Element? { - let id = ObjectIdentifier(newMember as AnyObject) - let previousMember = storage.removeValue(forKey: id) - storage[id] = Weak(newMember) - return previousMember?.value - } - - @discardableResult - public mutating func remove(_ member: Element) -> Element? { - let id = ObjectIdentifier(member as AnyObject) - return storage.removeValue(forKey: id)?.value - } - - public mutating func formUnion(_ other: WeakSet) { - for (id, element) in other.storage where storage[id] == nil { - // Ignore deallocated elements - if element.value != nil { - storage[id] = element - } - } - } - - public func union(_ other: WeakSet) -> WeakSet { - var result = self - result.formUnion(other) - return result - } - - public mutating func formIntersection(_ other: WeakSet) { - for id in storage.keys where other.storage[id] == nil { - storage.removeValue(forKey: id) - } - } - - public func intersection(_ other: WeakSet) -> WeakSet { - var result = self - result.formIntersection(other) - return result - } - - public mutating func formSymmetricDifference(_ other: WeakSet) { - for (id, element) in other.storage { - if storage[id] == nil { - // Ignore deallocated elements - if element.value != nil { - storage[id] = element - } - } else { - storage.removeValue(forKey: id) - } - } - } - - public func symmetricDifference(_ other: WeakSet) -> WeakSet { - var result = self - result.formSymmetricDifference(other) - return result - } -} - -extension WeakSet: Sequence { - public struct Iterator: IteratorProtocol { - private var base: Dictionary>.Iterator - - fileprivate init(_ base: Dictionary>.Iterator) { - self.base = base - } - - public mutating func next() -> Element? { - while let element = base.next()?.value { - if let value = element.value { - return value - } - } - - return nil - } - } - - public func makeIterator() -> Iterator { - return Iterator(storage.makeIterator()) - } -} - -extension WeakSet: Equatable { - public static func == (lhs: WeakSet, rhs: WeakSet) -> Bool { - return lhs.identifiers() == rhs.identifiers() - } - - private func identifiers() -> Set { - let ids = storage.compactMap { (id, element) -> ObjectIdentifier? in - // Ignore deallocated elements - guard element.value != nil else { - return nil - } - return id - } - - return Set(ids) - } -} - -extension WeakSet: ExpressibleByArrayLiteral { - public init(arrayLiteral elements: Element...) { - self.init(elements) - } -} diff --git a/Dependencies/LoopKit/LoopKit/WeakSynchronizedDelegate.swift b/Dependencies/LoopKit/LoopKit/WeakSynchronizedDelegate.swift deleted file mode 100644 index a67264995..000000000 --- a/Dependencies/LoopKit/LoopKit/WeakSynchronizedDelegate.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// WeakSynchronizedDelegate.swift -// LoopKit -// -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - -public class WeakSynchronizedDelegate { - - private let lock = UnfairLock() - private weak var _delegate: AnyObject? - private var _queue: DispatchQueue - - public init(queue: DispatchQueue = .main) { - _queue = queue - } - - public var delegate: Delegate? { - get { - return lock.withLock { - return _delegate as? Delegate - } - } - set { - lock.withLock { - _delegate = newValue as AnyObject - } - } - } - - public var queue: DispatchQueue! { - get { - return lock.withLock { - return _queue - } - } - set { - lock.withLock { - _queue = newValue ?? .main - } - } - } - - public func notify(_ block: @escaping (_ delegate: Delegate?) -> Void) { - var delegate: Delegate? - var queue: DispatchQueue! - - lock.withLock { - delegate = _delegate as? Delegate - queue = _queue - } - - queue.async { - block(delegate) - } - } - - public func notifyDelayed(by interval: TimeInterval, _ block: @escaping (_ delegate: Delegate?) -> Void) { - var delegate: Delegate? - var queue: DispatchQueue! - - lock.withLock { - delegate = _delegate as? Delegate - queue = _queue - } - - queue.asyncAfter(deadline: .now() + interval) { - block(delegate) - } - } - - public func call(_ block: (_ delegate: Delegate?) -> ReturnType) -> ReturnType { - return lock.withLock { () -> ReturnType in - var result: ReturnType! - _queue.sync { - result = block(_delegate as? Delegate) - } - return result - } - } -} diff --git a/Dependencies/LoopKit/LoopKit/WeakSynchronizedSet.swift b/Dependencies/LoopKit/LoopKit/WeakSynchronizedSet.swift deleted file mode 100644 index 54e87b1b2..000000000 --- a/Dependencies/LoopKit/LoopKit/WeakSynchronizedSet.swift +++ /dev/null @@ -1,145 +0,0 @@ -// -// WeakSynchronizedSet.swift -// LoopKit -// -// Created by Michael Pangburn -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - - -/// A set-like collection of weak types, providing closure-based iteration on a client-specified queue -/// Mutations and iterations are thread-safe -public class WeakSynchronizedSet { - private typealias Identifier = ObjectIdentifier - private typealias ElementContainer = ElementDispatchContainer - - private class ElementDispatchContainer { - private weak var _element: AnyObject? - weak var queue: DispatchQueue? - - var element: Element? { - return _element as? Element - } - - init(element: Element, queue: DispatchQueue) { - // All Swift values are implicitly convertible to `AnyObject`, - // so this runtime check is the tradeoff for supporting class-constrained protocol types. - precondition(Mirror(reflecting: element).displayStyle == .class, "Weak references can only be held of class types.") - - self._element = element as AnyObject - self.queue = queue - } - - func call(_ body: @escaping (_ element: Element) -> Void) { - guard let queue = self.queue, let element = self.element else { - return - } - - queue.async { - body(element) - } - } - } - - private let elements: Locked<[Identifier: ElementContainer]> - - public init() { - elements = Locked([:]) - } - - /// Adds an element and its calling queue - /// - /// - Parameters: - /// - element: The element - /// - queue: The queue to use when performing calls with the element - public func insert(_ element: Element, queue: DispatchQueue) { - insert(ElementDispatchContainer(element: element, queue: queue)) - } - - /// Prunes any element references that have been deallocated - /// - Returns: A reference to the instance for easy chaining - @discardableResult public func cleanupDeallocatedElements() -> Self { - elements.mutate { (storage) in - storage = storage.compactMapValues { $0.element == nil ? nil : $0 } - } - return self - } - - /// Whether the element is in the set - /// - /// - Parameter element: The element - /// - Returns: True if the element is in the set - public func contains(_ element: Element) -> Bool { - let id = identifier(for: element) - return elements.value[id] != nil - } - - /// The total number of element in the set - /// - /// Deallocated references are counted, so calling `cleanupDeallocatedElements` is advised to maintain accuracy of this value - public var count: Int { - return elements.value.count - } - - /// Calls the given closure on each element in the set, on the queue specified when the element was added - /// - /// The order of calls is not defined - /// - /// - Parameter body: The closure to execute - public func forEach(_ body: @escaping (Element) -> Void) { - // Hold the lock while we iterate, since each call is dispatched out - elements.mutate { (elements) in - elements.forEach { (pair) in - pair.value.call(body) - } - } - } - - /// Removes the specified element from the set - /// - /// - Parameter element: The element - public func removeElement(_ element: Element) { - removeValue(forKey: identifier(for: element)) - } -} - -extension WeakSynchronizedSet { - private func identifier(for element: Element) -> ObjectIdentifier { - return ObjectIdentifier(element as AnyObject) - } - - private func identifier(for elementContainer: ElementContainer) -> ObjectIdentifier? { - guard let element = elementContainer.element else { - return nil - } - return identifier(for: element) - } - - @discardableResult - private func insert(_ newMember: ElementContainer) -> (inserted: Bool, memberAfterInsert: ElementContainer?) { - guard let id = identifier(for: newMember) else { - return (inserted: false, memberAfterInsert: nil) - } - var result: (inserted: Bool, memberAfterInsert: ElementContainer?)! - elements.mutate { (storage) in - if let existingMember = storage[id] { - result = (inserted: false, memberAfterInsert: existingMember) - } else { - storage[id] = newMember - result = (inserted: true, memberAfterInsert: newMember) - } - } - return result - } - - @discardableResult - private func removeValue(forKey key: Identifier) -> ElementContainer? { - var previousMember: ElementContainer? - elements.mutate { (storage) in - previousMember = storage.removeValue(forKey: key) - } - return previousMember - } -} diff --git a/Dependencies/LoopKit/LoopKitHostedTests/CarbStoreHKQueryTests.swift b/Dependencies/LoopKit/LoopKitHostedTests/CarbStoreHKQueryTests.swift deleted file mode 100644 index 29846eeb4..000000000 --- a/Dependencies/LoopKit/LoopKitHostedTests/CarbStoreHKQueryTests.swift +++ /dev/null @@ -1,164 +0,0 @@ -// -// CarbStoreHKQueryTests.swift -// LoopKitHostedTests -// -// Created by Darin Krauss on 10/9/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class CarbStoreHKQueryTestsBase: PersistenceControllerTestCase { - var healthStore: HKHealthStoreMock! - var carbStore: CarbStore! - var authorizationStatus: HKAuthorizationStatus = .notDetermined - - override func setUp() { - super.setUp() - - healthStore = HKHealthStoreMock() - healthStore.authorizationStatus = authorizationStatus - carbStore = CarbStore(healthStore: healthStore, - cacheStore: cacheStore, - cacheLength: .hours(24), - defaultAbsorptionTimes: (fast: .minutes(30), medium: .hours(3), slow: .hours(5)), - observationInterval: .hours(1), - provenanceIdentifier: Bundle.main.bundleIdentifier!) - - let semaphore = DispatchSemaphore(value: 0) - cacheStore.onReady { (error) in - semaphore.signal() - } - semaphore.wait() - } - - override func tearDown() { - carbStore = nil - healthStore = nil - - super.tearDown() - } - -} - -class CarbStoreHKQueryTestsAuthorized: CarbStoreHKQueryTestsBase { - override func setUp() { - authorizationStatus = .sharingAuthorized - super.setUp() - } - - func testObserverQueryStartup() { - // Check that an observer query is registered when authorization is already determined. - XCTAssertFalse(carbStore.authorizationRequired); - - let observerQueryCreated = expectation(description: "observer query created") - - carbStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in - let observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler) - observerQueryCreated.fulfill() - return observerQuery - } - - waitForExpectations(timeout: 2) - } -} - -class CarbStoreHKQueryTests: CarbStoreHKQueryTestsBase { - func testHKQueryAnchorPersistence() { - var observerQuery: HKObserverQueryMock? = nil - var anchoredObjectQuery: HKAnchoredObjectQueryMock? = nil - - XCTAssert(carbStore.authorizationRequired); - XCTAssertNil(carbStore.observerQuery); - - let observerQueryCreated = expectation(description: "observer query created") - - carbStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in - observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler) - observerQueryCreated.fulfill() - return observerQuery! - } - - let authorizationCompletion = expectation(description: "authorization completion") - carbStore.authorize { (result) in - print(result) - authorizationCompletion.fulfill() - } - - waitForExpectations(timeout: 3) - - XCTAssertNotNil(observerQuery) - - let anchoredObjectQueryCreationExpectation = expectation(description: "anchored object query creation") - carbStore.createAnchoredObjectQuery = { (sampleType, predicate, anchor, limit, resultsHandler) -> HKAnchoredObjectQuery in - anchoredObjectQuery = HKAnchoredObjectQueryMock(type: sampleType, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: resultsHandler) - anchoredObjectQueryCreationExpectation.fulfill() - return anchoredObjectQuery! - } - - let observerQueryCompletionExpectation = expectation(description: "observer query completion") - - let observerQueryCompletionHandler = { - observerQueryCompletionExpectation.fulfill() - } - // This simulates a signal marking the arrival of new HK Data. - observerQuery!.updateHandler(observerQuery!, observerQueryCompletionHandler, nil) - - wait(for: [anchoredObjectQueryCreationExpectation], timeout: 3) - - // Trigger results handler for anchored object query - let returnedAnchor = HKQueryAnchor(fromValue: 5) - anchoredObjectQuery!.resultsHandler(anchoredObjectQuery!, [], [], returnedAnchor, nil) - - // Wait for observerQueryCompletionExpectation - waitForExpectations(timeout: 3) - - XCTAssertNotNil(carbStore.queryAnchor) - - cacheStore.managedObjectContext.performAndWait {} - - // Create a new carb store, and ensure it uses the last query anchor - let newCarbStore = CarbStore(healthStore: healthStore, - cacheStore: cacheStore, - cacheLength: .hours(24), - defaultAbsorptionTimes: (fast: .minutes(30), medium: .hours(3), slow: .hours(5)), - observationInterval: .hours(1), - provenanceIdentifier: Bundle.main.bundleIdentifier!) - - observerQuery = nil - - let newObserverQueryCreated = expectation(description: "new observer query created") - newCarbStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in - observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler) - newObserverQueryCreated.fulfill() - return observerQuery! - } - - let newAuthorizationCompletion = expectation(description: "authorization completion") - newCarbStore.authorize { (result) in - newAuthorizationCompletion.fulfill() - } - waitForExpectations(timeout: 3) - - anchoredObjectQuery = nil - - let newAnchoredObjectQueryCreationExpectation = expectation(description: "new anchored object query creation") - newCarbStore.createAnchoredObjectQuery = { (sampleType, predicate, anchor, limit, resultsHandler) -> HKAnchoredObjectQuery in - anchoredObjectQuery = HKAnchoredObjectQueryMock(type: sampleType, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: resultsHandler) - newAnchoredObjectQueryCreationExpectation.fulfill() - return anchoredObjectQuery! - } - - // This simulates a signal marking the arrival of new HK Data. - observerQuery!.updateHandler(observerQuery!, {}, nil) - - wait(for: [newAnchoredObjectQueryCreationExpectation], timeout: 3) - - // Assert new carb store is querying with the last anchor that our HealthKit mock returned - XCTAssertEqual(returnedAnchor, anchoredObjectQuery?.anchor) - - anchoredObjectQuery!.resultsHandler(anchoredObjectQuery!, [], [], returnedAnchor, nil) - } -} diff --git a/Dependencies/LoopKit/LoopKitHostedTests/CoreDataMigrationTests.swift b/Dependencies/LoopKit/LoopKitHostedTests/CoreDataMigrationTests.swift deleted file mode 100644 index e343a2e3e..000000000 --- a/Dependencies/LoopKit/LoopKitHostedTests/CoreDataMigrationTests.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// CoreDataMigrationTests.swift -// LoopKitHostedTests -// -// Created by Rick Pasetto on 8/9/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import CoreData -import HealthKit -import XCTest -@testable import LoopKit - -class CoreDataV1MigrationTests: XCTestCase { - - var cacheStore: PersistenceController! - let fileManager = FileManager() - static let bundleURL = Bundle(for: CoreDataV1MigrationTests.self).bundleURL - - override func setUpWithError() throws { - try? fileManager.removeItem(at: Self.bundleURL.appendingPathComponent("Model.sqlite")) - try fileManager.copyItem(at: Self.bundleURL.appendingPathComponent("Model.sqlite.v1.original"), - to: Self.bundleURL.appendingPathComponent("Model.sqlite")) - } - - override func tearDownWithError() throws { - - // remove all stores - try cacheStore.managedObjectContext.persistentStoreCoordinator?.persistentStores.forEach { store in - try cacheStore.managedObjectContext.persistentStoreCoordinator?.remove(store) - } - - try fileManager.removeItem(at: Self.bundleURL.appendingPathComponent("Model.sqlite")) - cacheStore = nil - } - - func testV1Migration() throws { - let e = expectation(description: "\(#function): init") - cacheStore = PersistenceController.init(directoryURL: Self.bundleURL) - var error: Error? - cacheStore.onReady { - if let err = $0 { - error = err - XCTFail("Error opening \(Self.bundleURL): \(err)") - } - e.fulfill() - } - wait(for: [e], timeout: 10.0) - if let error = error { throw error } - var entries: [CachedCarbObject]! - let e0 = expectation(description: "\(#function): fetch") - cacheStore.managedObjectContext.performAndWait { - do { - entries = try cacheStore.managedObjectContext.fetch(CachedCarbObject.fetchRequest()) - } catch let err { - error = err - } - e0.fulfill() - } - wait(for: [e0], timeout: 1.0) - if let error = error { throw error } - XCTAssertEqual(1, entries.count) - - // Do some spot checks. - XCTAssertTrue(entityHasAttribute(entityName: "CachedGlucoseObject", attributeName: "device")) - XCTAssertTrue(entityHasAttribute(entityName: "CachedGlucoseObject", attributeName: "trend")) - } - - func entityHasAttribute(entityName: String, attributeName: String) -> Bool { - XCTAssertNotNil(cacheStore.managedObjectContext.persistentStoreCoordinator?.managedObjectModel.entities) - if let entities = cacheStore.managedObjectContext.persistentStoreCoordinator?.managedObjectModel.entities { - for entity in entities { - if entity.name == entityName, entity.attributesByName.contains(where: { (key: String, value: NSAttributeDescription) in - key == attributeName - }) { - return true - } - } - } - return false - } -} diff --git a/Dependencies/LoopKit/LoopKitHostedTests/GlucoseStoreTests.swift b/Dependencies/LoopKit/LoopKitHostedTests/GlucoseStoreTests.swift deleted file mode 100644 index 9e5a0191f..000000000 --- a/Dependencies/LoopKit/LoopKitHostedTests/GlucoseStoreTests.swift +++ /dev/null @@ -1,963 +0,0 @@ -// -// GlucoseStoreTests.swift -// LoopKitHostedTests -// -// Created by Darin Krauss on 10/12/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class GlucoseStoreTestsBase: PersistenceControllerTestCase, GlucoseStoreDelegate { - private static let device = HKDevice(name: "NAME", manufacturer: "MANUFACTURER", model: "MODEL", hardwareVersion: "HARDWAREVERSION", firmwareVersion: "FIRMWAREVERSION", softwareVersion: "SOFTWAREVERSION", localIdentifier: "LOCALIDENTIFIER", udiDeviceIdentifier: "UDIDEVICEIDENTIFIER") - internal let sample1 = NewGlucoseSample(date: Date(timeIntervalSinceNow: -.minutes(6)), - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 123.4), - condition: nil, - trend: nil, - trendRate: nil, - isDisplayOnly: true, - wasUserEntered: false, - syncIdentifier: "1925558F-E98F-442F-BBA6-F6F75FB4FD91", - syncVersion: 2, - device: device) - internal let sample2 = NewGlucoseSample(date: Date(timeIntervalSinceNow: -.minutes(2)), - quantity: HKQuantity(unit: .millimolesPerLiter, doubleValue: 7.4), - condition: nil, - trend: .flat, - trendRate: HKQuantity(unit: .millimolesPerLiterPerMinute, doubleValue: 0.0), - isDisplayOnly: false, - wasUserEntered: true, - syncIdentifier: "535F103C-3DFE-48F2-B15A-47313191E7B7", - syncVersion: 3, - device: device) - internal let sample3 = NewGlucoseSample(date: Date(timeIntervalSinceNow: -.minutes(4)), - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 400.0), - condition: .aboveRange, - trend: .upUpUp, - trendRate: HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: 4.2), - isDisplayOnly: false, - wasUserEntered: false, - syncIdentifier: "E1624D2B-A971-41B8-B8A0-3A8212AC3D71", - syncVersion: 4, - device: device) - - var healthStore: HKHealthStoreMock! - var glucoseStore: GlucoseStore! - var delegateCompletion: XCTestExpectation? - var authorizationStatus: HKAuthorizationStatus = .notDetermined - - override func setUp() { - super.setUp() - - let semaphore = DispatchSemaphore(value: 0) - cacheStore.onReady { error in - XCTAssertNil(error) - semaphore.signal() - } - semaphore.wait() - - healthStore = HKHealthStoreMock() - healthStore.authorizationStatus = authorizationStatus - glucoseStore = GlucoseStore(healthStore: healthStore, - cacheStore: cacheStore, - cacheLength: .hours(1), - observationInterval: .minutes(30), - provenanceIdentifier: HKSource.default().bundleIdentifier) - glucoseStore.delegate = self - } - - override func tearDown() { - let semaphore = DispatchSemaphore(value: 0) - glucoseStore.purgeAllGlucoseSamples(healthKitPredicate: HKQuery.predicateForObjects(from: HKSource.default())) { error in - XCTAssertNil(error) - semaphore.signal() - } - semaphore.wait() - - delegateCompletion = nil - glucoseStore = nil - healthStore = nil - - super.tearDown() - } - - // MARK: - GlucoseStoreDelegate - - func glucoseStoreHasUpdatedGlucoseData(_ glucoseStore: GlucoseStore) { - delegateCompletion?.fulfill() - } -} - -class GlucoseStoreTestsAuthorizationRequired: GlucoseStoreTestsBase { - func testObserverQueryStartup() { - XCTAssert(glucoseStore.authorizationRequired); - XCTAssertNil(glucoseStore.observerQuery); - - let observerQueryCreated = expectation(description: "observer query created") - - glucoseStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in - let observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler) - observerQueryCreated.fulfill() - return observerQuery - } - - - let authorizationCompletion = expectation(description: "authorization completion") - glucoseStore.authorize { (result) in - authorizationCompletion.fulfill() - } - - waitForExpectations(timeout: 10) - XCTAssertNotNil(glucoseStore.observerQuery); - } -} - -class GlucoseStoreStoreTestsAuthorized: GlucoseStoreTestsBase { - override func setUp() { - authorizationStatus = .sharingAuthorized - super.setUp() - } - - func testObserverQueryStartup() { - // Check that an observer query is registered when authorization is already determined. - XCTAssertFalse(glucoseStore.authorizationRequired); - - let observerQueryCreated = expectation(description: "observer query created") - - glucoseStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in - let observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler) - observerQueryCreated.fulfill() - return observerQuery - } - - waitForExpectations(timeout: 2) - } -} - - -class GlucoseStoreTests: GlucoseStoreTestsBase { - override func setUp() { - authorizationStatus = .sharingAuthorized - super.setUp() - } - - // MARK: - HealthKitSampleStore - - func testHealthKitQueryAnchorPersistence() { - var observerQuery: HKObserverQueryMock? = nil - var anchoredObjectQuery: HKAnchoredObjectQueryMock? = nil - - // Check that an observer query was registered even without authorize() being called. - XCTAssertFalse(glucoseStore.authorizationRequired); - - let observerQueryCreated = expectation(description: "observer query created") - - glucoseStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in - observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler) - observerQueryCreated.fulfill() - return observerQuery! - } - - let authorizationCompletion = expectation(description: "authorization completion") - glucoseStore.authorize { (result) in - authorizationCompletion.fulfill() - } - - waitForExpectations(timeout: 10) - - XCTAssertNotNil(observerQuery) - - let anchoredObjectQueryCreationExpectation = expectation(description: "anchored object query creation") - glucoseStore.createAnchoredObjectQuery = { (sampleType, predicate, anchor, limit, resultsHandler) -> HKAnchoredObjectQuery in - anchoredObjectQuery = HKAnchoredObjectQueryMock(type: sampleType, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: resultsHandler) - anchoredObjectQueryCreationExpectation.fulfill() - return anchoredObjectQuery! - } - - let observerQueryCompletionExpectation = expectation(description: "observer query completion") - - let observerQueryCompletionHandler = { - observerQueryCompletionExpectation.fulfill() - } - // This simulates a signal marking the arrival of new HK Data. - observerQuery!.updateHandler(observerQuery!, observerQueryCompletionHandler, nil) - - wait(for: [anchoredObjectQueryCreationExpectation], timeout: 10) - - // Trigger results handler for anchored object query - let returnedAnchor = HKQueryAnchor(fromValue: 5) - anchoredObjectQuery!.resultsHandler(anchoredObjectQuery!, [], [], returnedAnchor, nil) - - // Wait for observerQueryCompletionExpectation - waitForExpectations(timeout: 10) - - XCTAssertNotNil(glucoseStore.queryAnchor) - - cacheStore.managedObjectContext.performAndWait {} - - // Create a new glucose store, and ensure it uses the last query anchor - let newGlucoseStore = GlucoseStore(healthStore: healthStore, - cacheStore: cacheStore, - provenanceIdentifier: HKSource.default().bundleIdentifier) - - let newAuthorizationCompletion = expectation(description: "authorization completion") - - observerQuery = nil - - let newObserverQueryCreated = expectation(description: "new observer query created") - - newGlucoseStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in - observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler) - newObserverQueryCreated.fulfill() - return observerQuery! - } - - newGlucoseStore.authorize { (result) in - newAuthorizationCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - anchoredObjectQuery = nil - - let newAnchoredObjectQueryCreationExpectation = expectation(description: "new anchored object query creation") - newGlucoseStore.createAnchoredObjectQuery = { (sampleType, predicate, anchor, limit, resultsHandler) -> HKAnchoredObjectQuery in - anchoredObjectQuery = HKAnchoredObjectQueryMock(type: sampleType, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: resultsHandler) - newAnchoredObjectQueryCreationExpectation.fulfill() - return anchoredObjectQuery! - } - - // This simulates a signal marking the arrival of new HK Data. - observerQuery!.updateHandler(observerQuery!, {}, nil) - - waitForExpectations(timeout: 10) - - // Assert new glucose store is querying with the last anchor that our HealthKit mock returned - XCTAssertEqual(returnedAnchor, anchoredObjectQuery?.anchor) - - anchoredObjectQuery!.resultsHandler(anchoredObjectQuery!, [], [], returnedAnchor, nil) - } - - // MARK: - Fetching - - func testGetGlucoseSamples() { - let addGlucoseSamplesCompletion = expectation(description: "addGlucoseSamples") - glucoseStore.addGlucoseSamples([sample1, sample2, sample3]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - } - addGlucoseSamplesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getGlucoseSamples1Completion = expectation(description: "getGlucoseSamples1") - glucoseStore.getGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - XCTAssertNotNil(samples[0].uuid) - XCTAssertNil(samples[0].healthKitEligibleDate) - assertEqualSamples(samples[0], self.sample1) - XCTAssertNotNil(samples[1].uuid) - XCTAssertNil(samples[1].healthKitEligibleDate) - assertEqualSamples(samples[1], self.sample3) - XCTAssertNotNil(samples[2].uuid) - XCTAssertNil(samples[2].healthKitEligibleDate) - assertEqualSamples(samples[2], self.sample2) - } - getGlucoseSamples1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let getGlucoseSamples2Completion = expectation(description: "getGlucoseSamples2") - glucoseStore.getGlucoseSamples(start: Date(timeIntervalSinceNow: -.minutes(5)), end: Date(timeIntervalSinceNow: -.minutes(3))) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 1) - XCTAssertNotNil(samples[0].uuid) - XCTAssertNil(samples[0].healthKitEligibleDate) - assertEqualSamples(samples[0], self.sample3) - } - getGlucoseSamples2Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let purgeCachedGlucoseObjectsCompletion = expectation(description: "purgeCachedGlucoseObjects") - glucoseStore.purgeCachedGlucoseObjects() { error in - XCTAssertNil(error) - purgeCachedGlucoseObjectsCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getGlucoseSamples3Completion = expectation(description: "getGlucoseSamples3") - glucoseStore.getGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 0) - } - getGlucoseSamples3Completion.fulfill() - } - waitForExpectations(timeout: 10) - } - - enum Error: Swift.Error { case arbitrary } - - func testGetGlucoseSamplesDelayedHealthKitStorage() { - glucoseStore.healthKitStorageDelay = .minutes(5) - var hkobjects = [HKObject]() - healthStore.setSaveHandler { o, _, _ in hkobjects = o } - let addGlucoseSamplesCompletion = expectation(description: "addGlucoseSamples") - glucoseStore.addGlucoseSamples([sample1, sample2, sample3]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - } - addGlucoseSamplesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getGlucoseSamples1Completion = expectation(description: "getGlucoseSamples1") - glucoseStore.getGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - // HealthKit storage is deferred, so the second 2 UUIDs are nil - XCTAssertNotNil(samples[0].uuid) - XCTAssertNil(samples[0].healthKitEligibleDate) - assertEqualSamples(samples[0], self.sample1) - XCTAssertNil(samples[1].uuid) - XCTAssertNotNil(samples[1].healthKitEligibleDate) - assertEqualSamples(samples[1], self.sample3) - XCTAssertNil(samples[2].uuid) - XCTAssertNotNil(samples[2].healthKitEligibleDate) - assertEqualSamples(samples[2], self.sample2) - } - getGlucoseSamples1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let stored = hkobjects[0] as! HKQuantitySample - XCTAssertEqual(sample1.quantitySample.quantity, stored.quantity) - } - - func testGetGlucoseSamplesErrorHealthKitStorage() { - healthStore.saveError = Error.arbitrary - var hkobjects = [HKObject]() - healthStore.setSaveHandler { o, _, _ in hkobjects = o } - let addGlucoseSamplesCompletion = expectation(description: "addGlucoseSamples") - glucoseStore.addGlucoseSamples([sample1, sample2, sample3]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - } - addGlucoseSamplesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getGlucoseSamples1Completion = expectation(description: "getGlucoseSamples1") - glucoseStore.getGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - // HealthKit storage is deferred, so the second 2 UUIDs are nil - XCTAssertNil(samples[0].uuid) - XCTAssertNotNil(samples[0].healthKitEligibleDate) - assertEqualSamples(samples[0], self.sample1) - XCTAssertNil(samples[1].uuid) - XCTAssertNotNil(samples[1].healthKitEligibleDate) - assertEqualSamples(samples[1], self.sample3) - XCTAssertNil(samples[2].uuid) - XCTAssertNotNil(samples[2].healthKitEligibleDate) - assertEqualSamples(samples[2], self.sample2) - } - getGlucoseSamples1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - XCTAssertEqual(3, hkobjects.count) - } - - func testGetGlucoseSamplesDeniedHealthKitStorage() { - healthStore.authorizationStatus = .sharingDenied - var hkobjects = [HKObject]() - healthStore.setSaveHandler { o, _, _ in hkobjects = o } - let addGlucoseSamplesCompletion = expectation(description: "addGlucoseSamples") - glucoseStore.addGlucoseSamples([sample1, sample2, sample3]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - } - addGlucoseSamplesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getGlucoseSamples1Completion = expectation(description: "getGlucoseSamples1") - glucoseStore.getGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - // HealthKit storage is denied, so all UUIDs are nil - XCTAssertNil(samples[0].uuid) - XCTAssertNil(samples[0].healthKitEligibleDate) - assertEqualSamples(samples[0], self.sample1) - XCTAssertNil(samples[1].uuid) - XCTAssertNil(samples[1].healthKitEligibleDate) - assertEqualSamples(samples[1], self.sample3) - XCTAssertNil(samples[2].uuid) - XCTAssertNil(samples[2].healthKitEligibleDate) - assertEqualSamples(samples[2], self.sample2) - } - getGlucoseSamples1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - XCTAssertTrue(hkobjects.isEmpty) - } - - func testGetGlucoseSamplesSomeDeniedHealthKitStorage() { - glucoseStore.healthKitStorageDelay = 0 - var hkobjects = [HKObject]() - healthStore.setSaveHandler { o, _, _ in hkobjects = o } - let addGlucoseSamples1Completion = expectation(description: "addGlucoseSamples1") - // Authorized - glucoseStore.addGlucoseSamples([sample1]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 1) - } - addGlucoseSamples1Completion.fulfill() - } - waitForExpectations(timeout: 10) - XCTAssertEqual(1, hkobjects.count) - hkobjects = [] - - healthStore.authorizationStatus = .sharingDenied - let addGlucoseSamples2Completion = expectation(description: "addGlucoseSamples2") - // Denied - glucoseStore.addGlucoseSamples([sample2]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 1) - } - addGlucoseSamples2Completion.fulfill() - } - waitForExpectations(timeout: 10) - XCTAssertEqual(0, hkobjects.count) - hkobjects = [] - - healthStore.authorizationStatus = .sharingAuthorized - let addGlucoseSamples3Completion = expectation(description: "addGlucoseSamples3") - // Authorized - glucoseStore.addGlucoseSamples([sample3]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 1) - } - addGlucoseSamples3Completion.fulfill() - } - waitForExpectations(timeout: 10) - XCTAssertEqual(1, hkobjects.count) - hkobjects = [] - - let getGlucoseSamples1Completion = expectation(description: "getGlucoseSamples1") - glucoseStore.getGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - XCTAssertNotNil(samples[0].uuid) - XCTAssertNil(samples[0].healthKitEligibleDate) - assertEqualSamples(samples[0], self.sample1) - XCTAssertNotNil(samples[1].uuid) - XCTAssertNil(samples[1].healthKitEligibleDate) - assertEqualSamples(samples[1], self.sample3) - XCTAssertNil(samples[2].uuid) - XCTAssertNil(samples[2].healthKitEligibleDate) - assertEqualSamples(samples[2], self.sample2) - } - getGlucoseSamples1Completion.fulfill() - } - waitForExpectations(timeout: 10) - } - - func testLatestGlucose() { - XCTAssertNil(glucoseStore.latestGlucose) - - let addGlucoseSamplesCompletion = expectation(description: "addGlucoseSamples") - glucoseStore.addGlucoseSamples([sample1, sample2, sample3]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - assertEqualSamples(samples[0], self.sample1) - assertEqualSamples(samples[1], self.sample2) - assertEqualSamples(samples[2], self.sample3) - } - addGlucoseSamplesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - XCTAssertNotNil(glucoseStore.latestGlucose) - XCTAssertEqual(glucoseStore.latestGlucose?.startDate, sample2.date) - XCTAssertEqual(glucoseStore.latestGlucose?.endDate, sample2.date) - XCTAssertEqual(glucoseStore.latestGlucose?.quantity, sample2.quantity) - XCTAssertEqual(glucoseStore.latestGlucose?.provenanceIdentifier, HKSource.default().bundleIdentifier) - XCTAssertEqual(glucoseStore.latestGlucose?.isDisplayOnly, sample2.isDisplayOnly) - XCTAssertEqual(glucoseStore.latestGlucose?.wasUserEntered, sample2.wasUserEntered) - - let purgeCachedGlucoseObjectsCompletion = expectation(description: "purgeCachedGlucoseObjects") - glucoseStore.purgeCachedGlucoseObjects() { error in - XCTAssertNil(error) - purgeCachedGlucoseObjectsCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - XCTAssertNil(glucoseStore.latestGlucose) - } - - // MARK: - Modification - - func testAddGlucoseSamples() { - let addGlucoseSamples1Completion = expectation(description: "addGlucoseSamples1") - glucoseStore.addGlucoseSamples([sample1, sample2, sample3, sample1, sample2, sample3]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - // Note: the HealthKit UUID is no longer updated before being returned as a result of addGlucoseSamples. - XCTAssertNil(samples[0].uuid) - XCTAssertNotNil(samples[0].healthKitEligibleDate) - assertEqualSamples(samples[0], self.sample1) - XCTAssertNil(samples[1].uuid) - XCTAssertNotNil(samples[1].healthKitEligibleDate) - assertEqualSamples(samples[1], self.sample2) - XCTAssertNil(samples[2].uuid) - XCTAssertNotNil(samples[2].healthKitEligibleDate) - assertEqualSamples(samples[2], self.sample3) - } - addGlucoseSamples1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let getGlucoseSamples1Completion = expectation(description: "getGlucoseSamples1") - glucoseStore.getGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - XCTAssertNotNil(samples[0].uuid) - XCTAssertNil(samples[0].healthKitEligibleDate) - assertEqualSamples(samples[0], self.sample1) - XCTAssertNotNil(samples[1].uuid) - XCTAssertNil(samples[1].healthKitEligibleDate) - assertEqualSamples(samples[1], self.sample3) - XCTAssertNotNil(samples[2].uuid) - XCTAssertNil(samples[2].healthKitEligibleDate) - assertEqualSamples(samples[2], self.sample2) - } - getGlucoseSamples1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let addGlucoseSamples2Completion = expectation(description: "addGlucoseSamples2") - glucoseStore.addGlucoseSamples([sample3, sample1, sample2]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 0) - } - addGlucoseSamples2Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let getGlucoseSamples2Completion = expectation(description: "getGlucoseSamples2Completion") - glucoseStore.getGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - XCTAssertNotNil(samples[0].uuid) - XCTAssertNil(samples[0].healthKitEligibleDate) - assertEqualSamples(samples[0], self.sample1) - XCTAssertNotNil(samples[1].uuid) - XCTAssertNil(samples[1].healthKitEligibleDate) - assertEqualSamples(samples[1], self.sample3) - XCTAssertNotNil(samples[2].uuid) - XCTAssertNil(samples[2].healthKitEligibleDate) - assertEqualSamples(samples[2], self.sample2) - } - getGlucoseSamples2Completion.fulfill() - } - waitForExpectations(timeout: 10) - } - - func testAddGlucoseSamplesEmpty() { - let addGlucoseSamplesCompletion = expectation(description: "addGlucoseSamples") - glucoseStore.addGlucoseSamples([]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 0) - } - addGlucoseSamplesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - } - - func testAddGlucoseSamplesNotification() { - delegateCompletion = expectation(description: "delegate") - let glucoseSamplesDidChangeCompletion = expectation(description: "glucoseSamplesDidChange") - let observer = NotificationCenter.default.addObserver(forName: GlucoseStore.glucoseSamplesDidChange, object: glucoseStore, queue: nil) { notification in - glucoseSamplesDidChangeCompletion.fulfill() - } - - let addGlucoseSamplesCompletion = expectation(description: "addGlucoseSamples") - glucoseStore.addGlucoseSamples([sample1, sample2, sample3]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - } - addGlucoseSamplesCompletion.fulfill() - } - wait(for: [glucoseSamplesDidChangeCompletion, delegateCompletion!, addGlucoseSamplesCompletion], timeout: 10, enforceOrder: true) - - NotificationCenter.default.removeObserver(observer) - delegateCompletion = nil - } - - // MARK: - Watch Synchronization - - func testSyncGlucoseSamples() { - var syncGlucoseSamples: [StoredGlucoseSample] = [] - - let addGlucoseSamplesCompletion = expectation(description: "addGlucoseSamples") - glucoseStore.addGlucoseSamples([sample1, sample2, sample3]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - } - addGlucoseSamplesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getSyncGlucoseSamples1Completion = expectation(description: "getSyncGlucoseSamples1") - glucoseStore.getSyncGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let objects): - XCTAssertEqual(objects.count, 3) - XCTAssertNotNil(objects[0].uuid) - assertEqualSamples(objects[0], self.sample1) - XCTAssertNotNil(objects[1].uuid) - assertEqualSamples(objects[1], self.sample3) - XCTAssertNotNil(objects[2].uuid) - assertEqualSamples(objects[2], self.sample2) - syncGlucoseSamples = objects - } - getSyncGlucoseSamples1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let getSyncGlucoseSamples2Completion = expectation(description: "getSyncGlucoseSamples2") - glucoseStore.getSyncGlucoseSamples(start: Date(timeIntervalSinceNow: -.minutes(5)), end: Date(timeIntervalSinceNow: -.minutes(3))) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let objects): - XCTAssertEqual(objects.count, 1) - XCTAssertNotNil(objects[0].uuid) - assertEqualSamples(objects[0], self.sample3) - } - getSyncGlucoseSamples2Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let purgeCachedGlucoseObjectsCompletion = expectation(description: "purgeCachedGlucoseObjects") - glucoseStore.purgeCachedGlucoseObjects() { error in - XCTAssertNil(error) - purgeCachedGlucoseObjectsCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getSyncGlucoseSamples3Completion = expectation(description: "getSyncGlucoseSamples3") - glucoseStore.getSyncGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 0) - } - getSyncGlucoseSamples3Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let setSyncGlucoseSamplesCompletion = expectation(description: "setSyncGlucoseSamples") - glucoseStore.setSyncGlucoseSamples(syncGlucoseSamples) { error in - XCTAssertNil(error) - setSyncGlucoseSamplesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getSyncGlucoseSamples4Completion = expectation(description: "getSyncGlucoseSamples4") - glucoseStore.getSyncGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let objects): - XCTAssertEqual(objects.count, 3) - XCTAssertNotNil(objects[0].uuid) - assertEqualSamples(objects[0], self.sample1) - XCTAssertNotNil(objects[1].uuid) - assertEqualSamples(objects[1], self.sample3) - XCTAssertNotNil(objects[2].uuid) - assertEqualSamples(objects[2], self.sample2) - syncGlucoseSamples = objects - } - getSyncGlucoseSamples4Completion.fulfill() - } - waitForExpectations(timeout: 10) - } - - // MARK: - Cache Management - - func testEarliestCacheDate() { - XCTAssertEqual(glucoseStore.earliestCacheDate.timeIntervalSinceNow, -.hours(1), accuracy: 1) - } - - func testPurgeAllGlucoseSamples() { - let addGlucoseSamplesCompletion = expectation(description: "addGlucoseSamples") - glucoseStore.addGlucoseSamples([sample1, sample2, sample3]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - } - addGlucoseSamplesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getGlucoseSamples1Completion = expectation(description: "getGlucoseSamples1") - glucoseStore.getGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - } - getGlucoseSamples1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let purgeAllGlucoseSamplesCompletion = expectation(description: "purgeAllGlucoseSamples") - glucoseStore.purgeAllGlucoseSamples(healthKitPredicate: HKQuery.predicateForObjects(from: HKSource.default())) { error in - XCTAssertNil(error) - purgeAllGlucoseSamplesCompletion.fulfill() - - } - waitForExpectations(timeout: 10) - - let getGlucoseSamples2Completion = expectation(description: "getGlucoseSamples2") - glucoseStore.getGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 0) - } - getGlucoseSamples2Completion.fulfill() - } - waitForExpectations(timeout: 10) - } - - func testPurgeExpiredGlucoseObjects() { - let expiredSample = NewGlucoseSample(date: Date(timeIntervalSinceNow: -.hours(2)), - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 198.7), - condition: nil, - trend: nil, - trendRate: nil, - isDisplayOnly: false, - wasUserEntered: false, - syncIdentifier: "6AB8C7F3-A2CE-442F-98C4-3D0514626B5F", - syncVersion: 3) - - let addGlucoseSamplesCompletion = expectation(description: "addGlucoseSamples") - glucoseStore.addGlucoseSamples([sample1, sample2, sample3, expiredSample]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 4) - } - addGlucoseSamplesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getGlucoseSamplesCompletion = expectation(description: "getGlucoseSamples") - glucoseStore.getGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - } - getGlucoseSamplesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - } - - func testPurgeCachedGlucoseObjects() { - let addGlucoseSamplesCompletion = expectation(description: "addGlucoseSamples") - glucoseStore.addGlucoseSamples([sample1, sample2, sample3]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - } - addGlucoseSamplesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getGlucoseSamples1Completion = expectation(description: "getGlucoseSamples1") - glucoseStore.getGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - } - getGlucoseSamples1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let purgeCachedGlucoseObjects1Completion = expectation(description: "purgeCachedGlucoseObjects1") - glucoseStore.purgeCachedGlucoseObjects(before: Date(timeIntervalSinceNow: -.minutes(5))) { error in - XCTAssertNil(error) - purgeCachedGlucoseObjects1Completion.fulfill() - - } - waitForExpectations(timeout: 10) - - let getGlucoseSamples2Completion = expectation(description: "getGlucoseSamples2") - glucoseStore.getGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 2) - } - getGlucoseSamples2Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let purgeCachedGlucoseObjects2Completion = expectation(description: "purgeCachedGlucoseObjects2") - glucoseStore.purgeCachedGlucoseObjects() { error in - XCTAssertNil(error) - purgeCachedGlucoseObjects2Completion.fulfill() - - } - waitForExpectations(timeout: 10) - - let getGlucoseSamples3Completion = expectation(description: "getGlucoseSamples3") - glucoseStore.getGlucoseSamples() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 0) - } - getGlucoseSamples3Completion.fulfill() - } - waitForExpectations(timeout: 10) - } - - func testPurgeCachedGlucoseObjectsNotification() { - let addGlucoseSamplesCompletion = expectation(description: "addGlucoseSamples") - glucoseStore.addGlucoseSamples([sample1, sample2, sample3]) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(samples.count, 3) - } - addGlucoseSamplesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - delegateCompletion = expectation(description: "delegate") - let glucoseSamplesDidChangeCompletion = expectation(description: "glucoseSamplesDidChange") - let observer = NotificationCenter.default.addObserver(forName: GlucoseStore.glucoseSamplesDidChange, object: glucoseStore, queue: nil) { notification in - glucoseSamplesDidChangeCompletion.fulfill() - } - - let purgeCachedGlucoseObjectsCompletion = expectation(description: "purgeCachedGlucoseObjects") - glucoseStore.purgeCachedGlucoseObjects() { error in - XCTAssertNil(error) - purgeCachedGlucoseObjectsCompletion.fulfill() - - } - wait(for: [glucoseSamplesDidChangeCompletion, delegateCompletion!, purgeCachedGlucoseObjectsCompletion], timeout: 10, enforceOrder: true) - - NotificationCenter.default.removeObserver(observer) - delegateCompletion = nil - } -} - -fileprivate func assertEqualSamples(_ storedGlucoseSample: StoredGlucoseSample, - _ newGlucoseSample: NewGlucoseSample, - provenanceIdentifier: String = HKSource.default().bundleIdentifier, - file: StaticString = #file, - line: UInt = #line) { - XCTAssertEqual(storedGlucoseSample.provenanceIdentifier, provenanceIdentifier, file: file, line: line) - XCTAssertEqual(storedGlucoseSample.syncIdentifier, newGlucoseSample.syncIdentifier, file: file, line: line) - XCTAssertEqual(storedGlucoseSample.syncVersion, newGlucoseSample.syncVersion, file: file, line: line) - XCTAssertEqual(storedGlucoseSample.startDate, newGlucoseSample.date, file: file, line: line) - XCTAssertEqual(storedGlucoseSample.quantity, newGlucoseSample.quantity, file: file, line: line) - XCTAssertEqual(storedGlucoseSample.isDisplayOnly, newGlucoseSample.isDisplayOnly, file: file, line: line) - XCTAssertEqual(storedGlucoseSample.wasUserEntered, newGlucoseSample.wasUserEntered, file: file, line: line) - XCTAssertEqual(storedGlucoseSample.device, newGlucoseSample.device, file: file, line: line) - XCTAssertEqual(storedGlucoseSample.condition, newGlucoseSample.condition, file: file, line: line) - XCTAssertEqual(storedGlucoseSample.trend, newGlucoseSample.trend, file: file, line: line) - XCTAssertEqual(storedGlucoseSample.trendRate, newGlucoseSample.trendRate, file: file, line: line) -} diff --git a/Dependencies/LoopKit/LoopKitHostedTests/HKAnchoredObjectQueryMock.swift b/Dependencies/LoopKit/LoopKitHostedTests/HKAnchoredObjectQueryMock.swift deleted file mode 100644 index a4af933eb..000000000 --- a/Dependencies/LoopKit/LoopKitHostedTests/HKAnchoredObjectQueryMock.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// HKAnchoredObjectQueryMock.swift -// LoopKitTests -// -// Created by Pete Schwamb on 9/2/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - -class HKAnchoredObjectQueryMock: HKAnchoredObjectQuery { - let anchor: HKQueryAnchor? - let resultsHandler: (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, Error?) -> Void - - @available(iOS 15.0, *) - override init(queryDescriptors: [HKQueryDescriptor], - anchor: HKQueryAnchor?, - limit: Int, - resultsHandler handler: @escaping (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, Error?) -> Void) { - self.resultsHandler = handler - self.anchor = anchor - super.init(queryDescriptors: queryDescriptors, anchor: anchor, limit: limit, resultsHandler: handler) - } - - override init(type: HKSampleType, - predicate: NSPredicate?, - anchor: HKQueryAnchor?, - limit: Int, - resultsHandler handler: @escaping (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, Error?) -> Void) { - self.resultsHandler = handler - self.anchor = anchor - super.init(type: type, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: handler) - } -} diff --git a/Dependencies/LoopKit/LoopKitHostedTests/HKObserverQueryMock.swift b/Dependencies/LoopKit/LoopKitHostedTests/HKObserverQueryMock.swift deleted file mode 100644 index 29d554e52..000000000 --- a/Dependencies/LoopKit/LoopKitHostedTests/HKObserverQueryMock.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// HKObserverQueryMock.swift -// LoopKitHostedTests -// -// Created by Pete Schwamb on 9/2/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - -class HKObserverQueryMock: HKObserverQuery { - let updateHandler: (HKObserverQuery, @escaping HKObserverQueryCompletionHandler, Error?) -> Void - - @available(iOS 15.0, *) - override init(queryDescriptors: [HKQueryDescriptor], updateHandler: @escaping (HKObserverQuery, Set?, @escaping HKObserverQueryCompletionHandler, Error?) -> Void) { - self.updateHandler = { - updateHandler($0, nil, $1, $2) - } - super.init(queryDescriptors: queryDescriptors, updateHandler: updateHandler) - } - - override init(sampleType: HKSampleType, predicate: NSPredicate?, updateHandler: @escaping (HKObserverQuery, @escaping HKObserverQueryCompletionHandler, Error?) -> Void) { - self.updateHandler = updateHandler - super.init(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler) - } -} diff --git a/Dependencies/LoopKit/LoopKitHostedTests/InsulinDeliveryStoreTests.swift b/Dependencies/LoopKit/LoopKitHostedTests/InsulinDeliveryStoreTests.swift deleted file mode 100644 index fea1619c2..000000000 --- a/Dependencies/LoopKit/LoopKitHostedTests/InsulinDeliveryStoreTests.swift +++ /dev/null @@ -1,1037 +0,0 @@ -// -// InsulinDeliveryStoreTests.swift -// LoopKitHostedTests -// -// Created by Darin Krauss on 10/22/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class InsulinDeliveryStoreTestsBase: PersistenceControllerTestCase { - internal let entry1 = DoseEntry(type: .basal, - startDate: Date(timeIntervalSinceNow: -.minutes(6)), - endDate: Date(timeIntervalSinceNow: -.minutes(5.5)), - value: 1.8, - unit: .unitsPerHour, - deliveredUnits: 0.015, - syncIdentifier: "4B14522E-A7B5-4E73-B76B-5043CD7176B0", - scheduledBasalRate: nil) - internal let entry2 = DoseEntry(type: .tempBasal, - startDate: Date(timeIntervalSinceNow: -.minutes(2)), - endDate: Date(timeIntervalSinceNow: -.minutes(1.5)), - value: 2.4, - unit: .unitsPerHour, - deliveredUnits: 0.02, - syncIdentifier: "A1F8E29B-33D6-4B38-B4CD-D84F14744871", - scheduledBasalRate: HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.8)) - internal let entry3 = DoseEntry(type: .bolus, - startDate: Date(timeIntervalSinceNow: -.minutes(4)), - endDate: Date(timeIntervalSinceNow: -.minutes(3.5)), - value: 1.0, - unit: .units, - deliveredUnits: nil, - syncIdentifier: "1A1D6192-1521-4469-B962-1B82C4534BB1", - scheduledBasalRate: nil) - internal let device = HKDevice(name: UUID().uuidString, - manufacturer: UUID().uuidString, - model: UUID().uuidString, - hardwareVersion: UUID().uuidString, - firmwareVersion: UUID().uuidString, - softwareVersion: UUID().uuidString, - localIdentifier: UUID().uuidString, - udiDeviceIdentifier: UUID().uuidString) - - var healthStore: HKHealthStoreMock! - var insulinDeliveryStore: InsulinDeliveryStore! - var authorizationStatus: HKAuthorizationStatus = .notDetermined - - override func setUp() { - super.setUp() - - healthStore = HKHealthStoreMock() - healthStore.authorizationStatus = authorizationStatus - insulinDeliveryStore = InsulinDeliveryStore(healthStore: healthStore, - cacheStore: cacheStore, - cacheLength: .hours(1), - provenanceIdentifier: HKSource.default().bundleIdentifier) - - let semaphore = DispatchSemaphore(value: 0) - cacheStore.onReady { error in - XCTAssertNil(error) - semaphore.signal() - } - semaphore.wait() - } - - override func tearDown() { - let semaphore = DispatchSemaphore(value: 0) - insulinDeliveryStore.purgeAllDoseEntries(healthKitPredicate: HKQuery.predicateForObjects(from: HKSource.default())) { error in - XCTAssertNil(error) - semaphore.signal() - } - semaphore.wait() - - insulinDeliveryStore = nil - healthStore = nil - - super.tearDown() - } -} - -class InsulinDeliveryStoreTestsAuthorized: InsulinDeliveryStoreTestsBase { - override func setUp() { - authorizationStatus = .sharingAuthorized - super.setUp() - } - - func testObserverQueryStartup() { - // Check that an observer query is registered when authorization is already determined. - XCTAssertFalse(insulinDeliveryStore.authorizationRequired); - - let observerQueryCreated = expectation(description: "observer query created") - - insulinDeliveryStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in - let observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler) - observerQueryCreated.fulfill() - return observerQuery - } - - waitForExpectations(timeout: 2) - } -} - -class InsulinDeliveryStoreTests: InsulinDeliveryStoreTestsBase { - // MARK: - HealthKitSampleStore - - func testHealthKitQueryAnchorPersistence() { - var observerQuery: HKObserverQueryMock? = nil - var anchoredObjectQuery: HKAnchoredObjectQueryMock? = nil - - XCTAssert(insulinDeliveryStore.authorizationRequired); - XCTAssertNil(insulinDeliveryStore.observerQuery); - - let observerQueryCreated = expectation(description: "observer query created") - - insulinDeliveryStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in - observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler) - observerQueryCreated.fulfill() - return observerQuery! - } - - let authorizationCompletion = expectation(description: "authorization completion") - insulinDeliveryStore.authorize { (result) in - authorizationCompletion.fulfill() - } - - waitForExpectations(timeout: 2) - - XCTAssertNotNil(observerQuery) - - let anchoredObjectQueryCreationExpectation = expectation(description: "anchored object query creation") - insulinDeliveryStore.createAnchoredObjectQuery = { (sampleType, predicate, anchor, limit, resultsHandler) -> HKAnchoredObjectQuery in - anchoredObjectQuery = HKAnchoredObjectQueryMock(type: sampleType, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: resultsHandler) - anchoredObjectQueryCreationExpectation.fulfill() - return anchoredObjectQuery! - } - - let observerQueryCompletionExpectation = expectation(description: "observer query completion") - - let observerQueryCompletionHandler = { - observerQueryCompletionExpectation.fulfill() - } - // This simulates a signal marking the arrival of new HK Data. - observerQuery!.updateHandler(observerQuery!, observerQueryCompletionHandler, nil) - - wait(for: [anchoredObjectQueryCreationExpectation], timeout: 10) - - // Trigger results handler for anchored object query - let returnedAnchor = HKQueryAnchor(fromValue: 5) - anchoredObjectQuery!.resultsHandler(anchoredObjectQuery!, [], [], returnedAnchor, nil) - - // Wait for observerQueryCompletionExpectation - waitForExpectations(timeout: 10) - - XCTAssertNotNil(insulinDeliveryStore.queryAnchor) - - // Allow any managedObjectContext tasks to complete, like storing the anchor - cacheStore.managedObjectContext.performAndWait {} - - // Create a new glucose store, and ensure it uses the last query anchor - let newInsulinDeliveryStore = InsulinDeliveryStore(healthStore: healthStore, - cacheStore: cacheStore, - provenanceIdentifier: HKSource.default().bundleIdentifier) - - let newAuthorizationCompletion = expectation(description: "authorization completion") - - observerQuery = nil - - let newObserverQueryCreationExpectation = expectation(description: "new observer query created") - - newInsulinDeliveryStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in - observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler) - newObserverQueryCreationExpectation.fulfill() - return observerQuery! - } - - newInsulinDeliveryStore.authorize { (result) in - newAuthorizationCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - anchoredObjectQuery = nil - - let newAnchoredObjectQueryCreationExpectation = expectation(description: "new anchored object query creation") - newInsulinDeliveryStore.createAnchoredObjectQuery = { (sampleType, predicate, anchor, limit, resultsHandler) -> HKAnchoredObjectQuery in - anchoredObjectQuery = HKAnchoredObjectQueryMock(type: sampleType, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: resultsHandler) - newAnchoredObjectQueryCreationExpectation.fulfill() - return anchoredObjectQuery! - } - - // This simulates a signal marking the arrival of new HK Data. - observerQuery!.updateHandler(observerQuery!, {}, nil) - - waitForExpectations(timeout: 10) - - // Assert new glucose store is querying with the last anchor that our HealthKit mock returned - XCTAssertEqual(returnedAnchor, anchoredObjectQuery?.anchor) - - anchoredObjectQuery!.resultsHandler(anchoredObjectQuery!, [], [], returnedAnchor, nil) - } - - // MARK: - Fetching - - func testGetDoseEntries() { - let addDoseEntriesCompletion = expectation(description: "addDoseEntries") - insulinDeliveryStore.addDoseEntries([entry1, entry2, entry3], from: device, syncVersion: 2) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success: - break - } - addDoseEntriesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getDoseEntries1Completion = expectation(description: "getDoseEntries1") - insulinDeliveryStore.getDoseEntries() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 3) - XCTAssertEqual(entries[0].type, self.entry1.type) - XCTAssertEqual(entries[0].startDate, self.entry1.startDate) - XCTAssertEqual(entries[0].endDate, self.entry1.endDate) - XCTAssertEqual(entries[0].value, 0.015) - XCTAssertEqual(entries[0].unit, .units) - XCTAssertNil(entries[0].deliveredUnits) - XCTAssertEqual(entries[0].description, self.entry1.description) - XCTAssertEqual(entries[0].syncIdentifier, self.entry1.syncIdentifier) - XCTAssertEqual(entries[0].scheduledBasalRate, self.entry1.scheduledBasalRate) - XCTAssertEqual(entries[1].type, self.entry3.type) - XCTAssertEqual(entries[1].startDate, self.entry3.startDate) - XCTAssertEqual(entries[1].endDate, self.entry3.endDate) - XCTAssertEqual(entries[1].value, self.entry3.value) - XCTAssertEqual(entries[1].unit, self.entry3.unit) - XCTAssertEqual(entries[1].deliveredUnits, self.entry3.deliveredUnits) - XCTAssertEqual(entries[1].description, self.entry3.description) - XCTAssertEqual(entries[1].syncIdentifier, self.entry3.syncIdentifier) - XCTAssertEqual(entries[1].scheduledBasalRate, self.entry3.scheduledBasalRate) - XCTAssertEqual(entries[2].type, self.entry2.type) - XCTAssertEqual(entries[2].startDate, self.entry2.startDate) - XCTAssertEqual(entries[2].endDate, self.entry2.endDate) - XCTAssertEqual(entries[2].value, self.entry2.value) - XCTAssertEqual(entries[2].unit, self.entry2.unit) - XCTAssertEqual(entries[2].deliveredUnits, self.entry2.deliveredUnits) - XCTAssertEqual(entries[2].description, self.entry2.description) - XCTAssertEqual(entries[2].syncIdentifier, self.entry2.syncIdentifier) - XCTAssertEqual(entries[2].scheduledBasalRate, self.entry2.scheduledBasalRate) - } - getDoseEntries1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - - let getDoseEntries2Completion = expectation(description: "getDoseEntries2") - insulinDeliveryStore.getDoseEntries(start: Date(timeIntervalSinceNow: -.minutes(3.75)), end: Date(timeIntervalSinceNow: -.minutes(1.75))) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 2) - XCTAssertEqual(entries[0].type, self.entry3.type) - XCTAssertEqual(entries[0].startDate, self.entry3.startDate) - XCTAssertEqual(entries[0].endDate, self.entry3.endDate) - XCTAssertEqual(entries[0].value, self.entry3.value) - XCTAssertEqual(entries[0].unit, self.entry3.unit) - XCTAssertEqual(entries[0].deliveredUnits, self.entry3.deliveredUnits) - XCTAssertEqual(entries[0].description, self.entry3.description) - XCTAssertEqual(entries[0].syncIdentifier, self.entry3.syncIdentifier) - XCTAssertEqual(entries[0].scheduledBasalRate, self.entry3.scheduledBasalRate) - XCTAssertEqual(entries[1].type, self.entry2.type) - XCTAssertEqual(entries[1].startDate, self.entry2.startDate) - XCTAssertEqual(entries[1].endDate, self.entry2.endDate) - XCTAssertEqual(entries[1].value, self.entry2.value) - XCTAssertEqual(entries[1].unit, self.entry2.unit) - XCTAssertEqual(entries[1].deliveredUnits, self.entry2.deliveredUnits) - XCTAssertEqual(entries[1].description, self.entry2.description) - XCTAssertEqual(entries[1].syncIdentifier, self.entry2.syncIdentifier) - XCTAssertEqual(entries[1].scheduledBasalRate, self.entry2.scheduledBasalRate) - } - getDoseEntries2Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let purgeCachedInsulinDeliveryObjectsCompletion = expectation(description: "purgeCachedInsulinDeliveryObjects") - insulinDeliveryStore.purgeCachedInsulinDeliveryObjects() { error in - XCTAssertNil(error) - purgeCachedInsulinDeliveryObjectsCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getDoseEntries3Completion = expectation(description: "getDoseEntries3") - insulinDeliveryStore.getDoseEntries() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 0) - } - getDoseEntries3Completion.fulfill() - } - waitForExpectations(timeout: 10) - } - - func testLastBasalEndDate() { - let getLastImmutableBasalEndDate1Completion = expectation(description: "getLastImmutableBasalEndDate1") - insulinDeliveryStore.getLastImmutableBasalEndDate() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let lastBasalEndDate): - XCTAssertEqual(lastBasalEndDate, .distantPast) - } - getLastImmutableBasalEndDate1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let addDoseEntriesCompletion = expectation(description: "addDoseEntries") - insulinDeliveryStore.addDoseEntries([entry1, entry2, entry3], from: device, syncVersion: 2) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success: - break - } - addDoseEntriesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getLastImmutableBasalEndDate2Completion = expectation(description: "getLastImmutableBasalEndDate2") - insulinDeliveryStore.getLastImmutableBasalEndDate() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let lastBasalEndDate): - XCTAssertEqual(lastBasalEndDate, self.entry2.endDate) - } - getLastImmutableBasalEndDate2Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let purgeCachedInsulinDeliveryObjectsCompletion = expectation(description: "purgeCachedInsulinDeliveryObjects") - insulinDeliveryStore.purgeCachedInsulinDeliveryObjects() { error in - XCTAssertNil(error) - purgeCachedInsulinDeliveryObjectsCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getLastImmutableBasalEndDate3Completion = expectation(description: "getLastImmutableBasalEndDate3") - insulinDeliveryStore.getLastImmutableBasalEndDate() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let lastBasalEndDate): - XCTAssertEqual(lastBasalEndDate, .distantPast) - } - getLastImmutableBasalEndDate3Completion.fulfill() - } - waitForExpectations(timeout: 10) - } - - // MARK: - Modification - - func testAddDoseEntries() { - let addDoseEntries1Completion = expectation(description: "addDoseEntries1") - insulinDeliveryStore.addDoseEntries([entry1, entry2, entry3], from: device, syncVersion: 2) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success: - break - } - addDoseEntries1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let getDoseEntries1Completion = expectation(description: "getDoseEntries1") - insulinDeliveryStore.getDoseEntries() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 3) - XCTAssertEqual(entries[0].type, self.entry1.type) - XCTAssertEqual(entries[0].startDate, self.entry1.startDate) - XCTAssertEqual(entries[0].endDate, self.entry1.endDate) - XCTAssertEqual(entries[0].value, 0.015) - XCTAssertEqual(entries[0].unit, .units) - XCTAssertNil(entries[0].deliveredUnits) - XCTAssertEqual(entries[0].description, self.entry1.description) - XCTAssertEqual(entries[0].syncIdentifier, self.entry1.syncIdentifier) - XCTAssertEqual(entries[0].scheduledBasalRate, self.entry1.scheduledBasalRate) - XCTAssertEqual(entries[1].type, self.entry3.type) - XCTAssertEqual(entries[1].startDate, self.entry3.startDate) - XCTAssertEqual(entries[1].endDate, self.entry3.endDate) - XCTAssertEqual(entries[1].value, self.entry3.value) - XCTAssertEqual(entries[1].unit, self.entry3.unit) - XCTAssertEqual(entries[1].deliveredUnits, self.entry3.deliveredUnits) - XCTAssertEqual(entries[1].description, self.entry3.description) - XCTAssertEqual(entries[1].syncIdentifier, self.entry3.syncIdentifier) - XCTAssertEqual(entries[1].scheduledBasalRate, self.entry3.scheduledBasalRate) - XCTAssertEqual(entries[2].type, self.entry2.type) - XCTAssertEqual(entries[2].startDate, self.entry2.startDate) - XCTAssertEqual(entries[2].endDate, self.entry2.endDate) - XCTAssertEqual(entries[2].value, self.entry2.value) - XCTAssertEqual(entries[2].unit, self.entry2.unit) - XCTAssertEqual(entries[2].deliveredUnits, self.entry2.deliveredUnits) - XCTAssertEqual(entries[2].description, self.entry2.description) - XCTAssertEqual(entries[2].syncIdentifier, self.entry2.syncIdentifier) - XCTAssertEqual(entries[2].scheduledBasalRate, self.entry2.scheduledBasalRate) - } - getDoseEntries1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let addDoseEntries2Completion = expectation(description: "addDoseEntries2") - insulinDeliveryStore.addDoseEntries([entry3, entry1, entry2], from: device, syncVersion: 2) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success: - break - } - addDoseEntries2Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let getDoseEntries2Completion = expectation(description: "getDoseEntries2Completion") - insulinDeliveryStore.getDoseEntries() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 3) - XCTAssertEqual(entries[0].type, self.entry1.type) - XCTAssertEqual(entries[0].startDate, self.entry1.startDate) - XCTAssertEqual(entries[0].endDate, self.entry1.endDate) - XCTAssertEqual(entries[0].value, 0.015) - XCTAssertEqual(entries[0].unit, .units) - XCTAssertNil(entries[0].deliveredUnits) - XCTAssertEqual(entries[0].description, self.entry1.description) - XCTAssertEqual(entries[0].syncIdentifier, self.entry1.syncIdentifier) - XCTAssertEqual(entries[0].scheduledBasalRate, self.entry1.scheduledBasalRate) - XCTAssertEqual(entries[1].type, self.entry3.type) - XCTAssertEqual(entries[1].startDate, self.entry3.startDate) - XCTAssertEqual(entries[1].endDate, self.entry3.endDate) - XCTAssertEqual(entries[1].value, self.entry3.value) - XCTAssertEqual(entries[1].unit, self.entry3.unit) - XCTAssertEqual(entries[1].deliveredUnits, self.entry3.deliveredUnits) - XCTAssertEqual(entries[1].description, self.entry3.description) - XCTAssertEqual(entries[1].syncIdentifier, self.entry3.syncIdentifier) - XCTAssertEqual(entries[1].scheduledBasalRate, self.entry3.scheduledBasalRate) - XCTAssertEqual(entries[2].type, self.entry2.type) - XCTAssertEqual(entries[2].startDate, self.entry2.startDate) - XCTAssertEqual(entries[2].endDate, self.entry2.endDate) - XCTAssertEqual(entries[2].value, self.entry2.value) - XCTAssertEqual(entries[2].unit, self.entry2.unit) - XCTAssertEqual(entries[2].deliveredUnits, self.entry2.deliveredUnits) - XCTAssertEqual(entries[2].description, self.entry2.description) - XCTAssertEqual(entries[2].syncIdentifier, self.entry2.syncIdentifier) - XCTAssertEqual(entries[2].scheduledBasalRate, self.entry2.scheduledBasalRate) - } - getDoseEntries2Completion.fulfill() - } - waitForExpectations(timeout: 10) - } - - func testAddDoseEntriesEmpty() { - let addDoseEntriesCompletion = expectation(description: "addDoseEntries") - insulinDeliveryStore.addDoseEntries([], from: device, syncVersion: 2) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success: - break - } - addDoseEntriesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - } - - func testAddDoseEntriesNotification() { - let doseEntriesDidChangeCompletion = expectation(description: "doseEntriesDidChange") - let observer = NotificationCenter.default.addObserver(forName: InsulinDeliveryStore.doseEntriesDidChange, object: insulinDeliveryStore, queue: nil) { notification in - doseEntriesDidChangeCompletion.fulfill() - } - - let addDoseEntriesCompletion = expectation(description: "addDoseEntries") - insulinDeliveryStore.addDoseEntries([entry1, entry2, entry3], from: device, syncVersion: 2) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success: - break - } - addDoseEntriesCompletion.fulfill() - } - wait(for: [doseEntriesDidChangeCompletion, addDoseEntriesCompletion], timeout: 10, enforceOrder: true) - - NotificationCenter.default.removeObserver(observer) - } - - func testManuallyEnteredDoses() { - let manualEntry = DoseEntry(type: .bolus, - startDate: Date(timeIntervalSinceNow: -.minutes(15)), - endDate: Date(timeIntervalSinceNow: -.minutes(10)), - value: 3.0, - unit: .units, - syncIdentifier: "C0AB1CBD-6B36-4113-9D49-709A022B2451", - manuallyEntered: true) - - let addDoseEntriesCompletion = expectation(description: "addDoseEntries") - insulinDeliveryStore.addDoseEntries([entry1, manualEntry, entry2, entry3], from: device, syncVersion: 2) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success: - break - } - addDoseEntriesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getManuallyEnteredDoses1Completion = expectation(description: "getManuallyEnteredDoses1") - insulinDeliveryStore.getManuallyEnteredDoses(since: .distantPast) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 1) - XCTAssertEqual(entries[0], manualEntry) - } - getManuallyEnteredDoses1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let getManuallyEnteredDoses2Completion = expectation(description: "getManuallyEnteredDoses2") - insulinDeliveryStore.getManuallyEnteredDoses(since: Date(timeIntervalSinceNow: -.minutes(12))) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 0) - } - getManuallyEnteredDoses2Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let deleteAllManuallyEnteredDoses1Completion = expectation(description: "deleteAllManuallyEnteredDoses1") - insulinDeliveryStore.deleteAllManuallyEnteredDoses(since: Date(timeIntervalSinceNow: -.minutes(12))) { error in - XCTAssertNil(error) - deleteAllManuallyEnteredDoses1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let getManuallyEnteredDoses3Completion = expectation(description: "getManuallyEnteredDoses3") - insulinDeliveryStore.getManuallyEnteredDoses(since: .distantPast) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 1) - XCTAssertEqual(entries[0], manualEntry) - } - getManuallyEnteredDoses3Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let deleteAllManuallyEnteredDose2Completion = expectation(description: "deleteAllManuallyEnteredDose2") - insulinDeliveryStore.deleteAllManuallyEnteredDoses(since: Date(timeIntervalSinceNow: -.minutes(20))) { error in - XCTAssertNil(error) - deleteAllManuallyEnteredDose2Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let getManuallyEnteredDoses4Completion = expectation(description: "getManuallyEnteredDoses4") - insulinDeliveryStore.getManuallyEnteredDoses(since: .distantPast) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 0) - } - getManuallyEnteredDoses4Completion.fulfill() - } - waitForExpectations(timeout: 10) - } - - // MARK: - Cache Management - - func testEarliestCacheDate() { - XCTAssertEqual(insulinDeliveryStore.earliestCacheDate.timeIntervalSinceNow, -.hours(1), accuracy: 1) - } - - func testPurgeAllDoseEntries() { - let addDoseEntriesCompletion = expectation(description: "addDoseEntries") - insulinDeliveryStore.addDoseEntries([entry1, entry2, entry3], from: device, syncVersion: 2) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success: - break - } - addDoseEntriesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getDoseEntries1Completion = expectation(description: "getDoseEntries1") - insulinDeliveryStore.getDoseEntries() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 3) - } - getDoseEntries1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let purgeAllDoseEntriesCompletion = expectation(description: "purgeAllDoseEntries") - insulinDeliveryStore.purgeAllDoseEntries(healthKitPredicate: HKQuery.predicateForObjects(from: HKSource.default())) { error in - XCTAssertNil(error) - purgeAllDoseEntriesCompletion.fulfill() - - } - waitForExpectations(timeout: 10) - - let getDoseEntries2Completion = expectation(description: "getDoseEntries2") - insulinDeliveryStore.getDoseEntries() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 0) - } - getDoseEntries2Completion.fulfill() - } - waitForExpectations(timeout: 10) - } - - func testPurgeExpiredGlucoseObjects() { - let expiredEntry = DoseEntry(type: .bolus, - startDate: Date(timeIntervalSinceNow: -.hours(3)), - endDate: Date(timeIntervalSinceNow: -.hours(2)), - value: 3.0, - unit: .units, - deliveredUnits: nil, - syncIdentifier: "7530B8CA-827A-4DE8-ADE3-9E10FF80A4A9", - scheduledBasalRate: nil) - - let addDoseEntriesCompletion = expectation(description: "addDoseEntries") - insulinDeliveryStore.addDoseEntries([entry1, entry2, entry3, expiredEntry], from: device, syncVersion: 2) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success: - break - } - addDoseEntriesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getDoseEntriesCompletion = expectation(description: "getDoseEntries") - insulinDeliveryStore.getDoseEntries() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 3) - } - getDoseEntriesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - } - - func testPurgeCachedInsulinDeliveryObjects() { - let addDoseEntriesCompletion = expectation(description: "addDoseEntries") - insulinDeliveryStore.addDoseEntries([entry1, entry2, entry3], from: device, syncVersion: 2) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success: - break - } - addDoseEntriesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let getDoseEntries1Completion = expectation(description: "getDoseEntries1") - insulinDeliveryStore.getDoseEntries() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 3) - } - getDoseEntries1Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let purgeCachedInsulinDeliveryObjects1Completion = expectation(description: "purgeCachedInsulinDeliveryObjects1") - insulinDeliveryStore.purgeCachedInsulinDeliveryObjects(before: Date(timeIntervalSinceNow: -.minutes(5))) { error in - XCTAssertNil(error) - purgeCachedInsulinDeliveryObjects1Completion.fulfill() - - } - waitForExpectations(timeout: 10) - - let getDoseEntries2Completion = expectation(description: "getDoseEntries2") - insulinDeliveryStore.getDoseEntries() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 2) - } - getDoseEntries2Completion.fulfill() - } - waitForExpectations(timeout: 10) - - let purgeCachedInsulinDeliveryObjects2Completion = expectation(description: "purgeCachedInsulinDeliveryObjects2") - insulinDeliveryStore.purgeCachedInsulinDeliveryObjects() { error in - XCTAssertNil(error) - purgeCachedInsulinDeliveryObjects2Completion.fulfill() - - } - waitForExpectations(timeout: 10) - - let getDoseEntries3Completion = expectation(description: "getDoseEntries3") - insulinDeliveryStore.getDoseEntries() { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 0) - } - getDoseEntries3Completion.fulfill() - } - waitForExpectations(timeout: 10) - } - - func testPurgeCachedInsulinDeliveryObjectsNotification() { - let addDoseEntriesCompletion = expectation(description: "addDoseEntries") - insulinDeliveryStore.addDoseEntries([entry1, entry2, entry3], from: device, syncVersion: 2) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success: - break - } - addDoseEntriesCompletion.fulfill() - } - waitForExpectations(timeout: 10) - - let doseEntriesDidChangeCompletion = expectation(description: "doseEntriesDidChange") - let observer = NotificationCenter.default.addObserver(forName: InsulinDeliveryStore.doseEntriesDidChange, object: insulinDeliveryStore, queue: nil) { notification in - doseEntriesDidChangeCompletion.fulfill() - } - - let purgeCachedInsulinDeliveryObjectsCompletion = expectation(description: "purgeCachedInsulinDeliveryObjects") - insulinDeliveryStore.purgeCachedInsulinDeliveryObjects() { error in - XCTAssertNil(error) - purgeCachedInsulinDeliveryObjectsCompletion.fulfill() - - } - wait(for: [doseEntriesDidChangeCompletion, purgeCachedInsulinDeliveryObjectsCompletion], timeout: 10, enforceOrder: true) - - NotificationCenter.default.removeObserver(observer) - } -} - -class InsulinDeliveryStoreQueryAnchorTests: XCTestCase { - - var rawValue: InsulinDeliveryStore.QueryAnchor.RawValue = [ - "modificationCounter": Int64(123) - ] - - func testInitializerDefault() { - let queryAnchor = InsulinDeliveryStore.QueryAnchor() - XCTAssertEqual(queryAnchor.modificationCounter, 0) - } - - func testInitializerRawValue() { - let queryAnchor = InsulinDeliveryStore.QueryAnchor(rawValue: rawValue) - XCTAssertNotNil(queryAnchor) - XCTAssertEqual(queryAnchor?.modificationCounter, 123) - } - - func testInitializerRawValueMissingModificationCounter() { - rawValue["modificationCounter"] = nil - XCTAssertNil(InsulinDeliveryStore.QueryAnchor(rawValue: rawValue)) - } - - func testInitializerRawValueInvalidModificationCounter() { - rawValue["modificationCounter"] = "123" - XCTAssertNil(InsulinDeliveryStore.QueryAnchor(rawValue: rawValue)) - } - - func testRawValueWithDefault() { - let rawValue = InsulinDeliveryStore.QueryAnchor().rawValue - XCTAssertEqual(rawValue.count, 1) - XCTAssertEqual(rawValue["modificationCounter"] as? Int64, Int64(0)) - } - - func testRawValueWithNonDefault() { - var queryAnchor = InsulinDeliveryStore.QueryAnchor() - queryAnchor.modificationCounter = 123 - let rawValue = queryAnchor.rawValue - XCTAssertEqual(rawValue.count, 1) - XCTAssertEqual(rawValue["modificationCounter"] as? Int64, Int64(123)) - } - -} - -class InsulinDeliveryStoreQueryTests: PersistenceControllerTestCase { - - let insulinModel = WalshInsulinModel(actionDuration: .hours(4)) - let basalProfile = BasalRateSchedule(rawValue: ["timeZone": -28800, "items": [["value": 0.75, "startTime": 0.0], ["value": 0.8, "startTime": 10800.0], ["value": 0.85, "startTime": 32400.0], ["value": 1.0, "startTime": 68400.0]]]) - let insulinSensitivitySchedule = InsulinSensitivitySchedule(rawValue: ["unit": "mg/dL", "timeZone": -28800, "items": [["value": 40.0, "startTime": 0.0], ["value": 35.0, "startTime": 21600.0], ["value": 40.0, "startTime": 57600.0]]]) - - var insulinDeliveryStore: InsulinDeliveryStore! - var completion: XCTestExpectation! - var queryAnchor: InsulinDeliveryStore.QueryAnchor! - var limit: Int! - - override func setUp() { - super.setUp() - - insulinDeliveryStore = InsulinDeliveryStore(healthStore: HKHealthStoreMock(), - storeSamplesToHealthKit: false, - cacheStore: cacheStore, - observationEnabled: false, - provenanceIdentifier: HKSource.default().bundleIdentifier) - completion = expectation(description: "Completion") - queryAnchor = InsulinDeliveryStore.QueryAnchor() - limit = Int.max - } - - override func tearDown() { - limit = nil - queryAnchor = nil - completion = nil - insulinDeliveryStore = nil - - super.tearDown() - } - - func testDoseEmptyWithDefaultQueryAnchor() { - insulinDeliveryStore.executeDoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let deleted): - XCTAssertEqual(anchor.modificationCounter, 0) - XCTAssertEqual(created.count, 0) - XCTAssertEqual(deleted.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDoseEmptyWithMissingQueryAnchor() { - queryAnchor = nil - - insulinDeliveryStore.executeDoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let deleted): - XCTAssertEqual(anchor.modificationCounter, 0) - XCTAssertEqual(created.count, 0) - XCTAssertEqual(deleted.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDoseEmptyWithNonDefaultQueryAnchor() { - queryAnchor.modificationCounter = 1 - - insulinDeliveryStore.executeDoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let deleted): - XCTAssertEqual(anchor.modificationCounter, 1) - XCTAssertEqual(created.count, 0) - XCTAssertEqual(deleted.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDoseDataWithUnusedQueryAnchor() { - let doseData = [DoseDatum(), DoseDatum(deleted: true), DoseDatum()] - - addDoseData(doseData) - - insulinDeliveryStore.executeDoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let deleted): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(created.count, 2) - XCTAssertEqual(deleted.count, 1) - if created.count >= 2 { - XCTAssertEqual(created[0].syncIdentifier, doseData[0].syncIdentifier) - XCTAssertEqual(created[1].syncIdentifier, doseData[2].syncIdentifier) - } - if deleted.count >= 1 { - XCTAssertEqual(deleted[0].syncIdentifier, doseData[1].syncIdentifier) - } - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDoseDataWithStaleQueryAnchor() { - let doseData = [DoseDatum(), DoseDatum(deleted: true), DoseDatum()] - - addDoseData(doseData) - - queryAnchor.modificationCounter = 2 - - insulinDeliveryStore.executeDoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let deleted): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(created.count, 1) - XCTAssertEqual(deleted.count, 0) - if created.count >= 1 { - XCTAssertEqual(created[0].syncIdentifier, doseData[2].syncIdentifier) - } - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDoseDataWithCurrentQueryAnchor() { - let doseData = [DoseDatum(), DoseDatum(deleted: true), DoseDatum()] - - addDoseData(doseData) - - queryAnchor.modificationCounter = 3 - - insulinDeliveryStore.executeDoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let deleted): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(created.count, 0) - XCTAssertEqual(deleted.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDoseDataWithLimitCoveredByData() { - let doseData = [DoseDatum(), DoseDatum(deleted: true), DoseDatum()] - - addDoseData(doseData) - - limit = 2 - - insulinDeliveryStore.executeDoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let deleted): - XCTAssertEqual(anchor.modificationCounter, 2) - XCTAssertEqual(created.count, 1) - XCTAssertEqual(deleted.count, 1) - if created.count >= 1 { - XCTAssertEqual(created[0].syncIdentifier, doseData[0].syncIdentifier) - } - if deleted.count >= 1 { - XCTAssertEqual(deleted[0].syncIdentifier, doseData[1].syncIdentifier) - } - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - private func addDoseData(_ doseData: [DoseDatum]) { - cacheStore.managedObjectContext.performAndWait { - for doseDatum in doseData { - let object = CachedInsulinDeliveryObject(context: self.cacheStore.managedObjectContext) - object.provenanceIdentifier = HKSource.default().bundleIdentifier - object.hasLoopKitOrigin = true - object.startDate = Date().addingTimeInterval(-.minutes(15)) - object.endDate = Date().addingTimeInterval(-.minutes(5)) - object.syncIdentifier = doseDatum.syncIdentifier - object.value = 1.0 - object.reason = .bolus - object.createdAt = Date() - object.deletedAt = doseDatum.deleted ? Date() : nil - object.manuallyEntered = false - object.isSuspend = false - - self.cacheStore.save() - } - } - } - - private struct DoseDatum { - let syncIdentifier: String - let deleted: Bool - - init(deleted: Bool = false) { - self.syncIdentifier = UUID().uuidString - self.deleted = deleted - } - } - -} diff --git a/Dependencies/LoopKit/LoopKitHostedTests/LoopKitHostedTests.plist b/Dependencies/LoopKit/LoopKitHostedTests/LoopKitHostedTests.plist deleted file mode 100644 index 9f26c7a5b..000000000 --- a/Dependencies/LoopKit/LoopKitHostedTests/LoopKitHostedTests.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 2.2.1 - CFBundleSignature - ???? - CFBundleVersion - 1 - - diff --git a/Dependencies/LoopKit/LoopKitHostedTests/Persistence/CachedGlucoseObjectTests.swift b/Dependencies/LoopKit/LoopKitHostedTests/Persistence/CachedGlucoseObjectTests.swift deleted file mode 100644 index 4155c3673..000000000 --- a/Dependencies/LoopKit/LoopKitHostedTests/Persistence/CachedGlucoseObjectTests.swift +++ /dev/null @@ -1,135 +0,0 @@ -// -// CachedGlucoseObjectTests.swift -// LoopKitHostedTests -// -// Created by Darin Krauss on 10/12/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class CachedGlucoseObjectOperationsTests: PersistenceControllerTestCase { - func testCreateFromNewGlucoseSample() { - cacheStore.managedObjectContext.performAndWait { - let startDate = dateFormatter.date(from: "2020-01-02T03:04:05Z")! - let quantity = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 123.4) - let device = HKDevice(name: "NAME", manufacturer: "MANUFACTURER", model: "MODEL", hardwareVersion: "HARDWAREVERSION", firmwareVersion: "FIRMWAREVERSION", softwareVersion: "SOFTWAREVERSION", localIdentifier: "LOCALIDENTIFIER", udiDeviceIdentifier: "UDIDEVICEIDENTIFIER") - let newGlucoseSample = NewGlucoseSample(date: startDate, - quantity: quantity, - condition: .belowRange, - trend: .flat, - trendRate: HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: 0.1), - isDisplayOnly: true, - wasUserEntered: false, - syncIdentifier: "F4C094AA-9EBE-4804-8F02-90C7B613BDEC", - syncVersion: 2, - device: device) - let object = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object.create(from: newGlucoseSample, provenanceIdentifier: "06173C6A-4945-4139-A77D-E3ABC3221EA9", healthKitStorageDelay: .minutes(1)) - XCTAssertNil(object.uuid) - XCTAssertEqual(object.provenanceIdentifier, "06173C6A-4945-4139-A77D-E3ABC3221EA9") - XCTAssertEqual(object.syncIdentifier, "F4C094AA-9EBE-4804-8F02-90C7B613BDEC") - XCTAssertEqual(object.primitiveSyncVersion, 2) - XCTAssertEqual(object.value, quantity.doubleValue(for: .milligramsPerDeciliter)) - XCTAssertEqual(object.unitString, HKUnit.milligramsPerDeciliter.unitString) - XCTAssertEqual(object.startDate, startDate) - XCTAssertEqual(object.isDisplayOnly, true) - XCTAssertEqual(object.wasUserEntered, false) - XCTAssertEqual(object.condition, .belowRange) - XCTAssertEqual(object.trend, .flat) - XCTAssertEqual(object.trendRateUnit, HKUnit.milligramsPerDeciliterPerMinute.unitString) - XCTAssertEqual(object.trendRateValue, 0.1) - XCTAssertEqual(object.modificationCounter, 1) - XCTAssertEqual(object.device, device) - XCTAssertEqual(object.healthKitEligibleDate, startDate.addingTimeInterval(.minutes(1))) - } - } - - func testCreateFromQuantitySample() { - cacheStore.managedObjectContext.performAndWait { - let type = HKQuantityType.quantityType(forIdentifier: .bloodGlucose)! - let startDate = dateFormatter.date(from: "2020-02-03T04:05:06Z")! - let quantity = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 123.4) - let device = HKDevice(name: "NAME", manufacturer: "MANUFACTURER", model: "MODEL", hardwareVersion: "HARDWAREVERSION", firmwareVersion: "FIRMWAREVERSION", softwareVersion: "SOFTWAREVERSION", localIdentifier: "LOCALIDENTIFIER", udiDeviceIdentifier: "UDIDEVICEIDENTIFIER") - let metadata: [String: Any] = [ - HKMetadataKeySyncIdentifier: "0B2353CD-7F98-4297-81E2-8D6FCDD02655", - HKMetadataKeySyncVersion: 2, - MetadataKeyGlucoseIsDisplayOnly: false, - HKMetadataKeyWasUserEntered: true, - MetadataKeyGlucoseCondition: "belowRange", - MetadataKeyGlucoseTrend: "→", - MetadataKeyGlucoseTrendRateUnit: HKUnit.milligramsPerDeciliterPerMinute.unitString, - MetadataKeyGlucoseTrendRateValue: 0.1 - ] - let quantitySample = HKQuantitySample(type: type, quantity: quantity, start: startDate, end: startDate, device: device, metadata: metadata) - let object = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object.create(from: quantitySample) - XCTAssertNotNil(object.uuid) - XCTAssertEqual(object.provenanceIdentifier, "") - XCTAssertEqual(object.syncIdentifier, "0B2353CD-7F98-4297-81E2-8D6FCDD02655") - XCTAssertEqual(object.primitiveSyncVersion, 2) - XCTAssertEqual(object.value, quantity.doubleValue(for: .milligramsPerDeciliter)) - XCTAssertEqual(object.unitString, HKUnit.milligramsPerDeciliter.unitString) - XCTAssertEqual(object.startDate, startDate) - XCTAssertEqual(object.isDisplayOnly, false) - XCTAssertEqual(object.wasUserEntered, true) - XCTAssertEqual(object.condition, .belowRange) - XCTAssertEqual(object.trend, .flat) - XCTAssertEqual(object.trendRateUnit, HKUnit.milligramsPerDeciliterPerMinute.unitString) - XCTAssertEqual(object.trendRateValue, 0.1) - XCTAssertEqual(object.modificationCounter, 1) - XCTAssertEqual(object.device, device) - XCTAssertEqual(object.healthKitEligibleDate, nil) - } - } - - func testToHKQuantitySample() { - cacheStore.managedObjectContext.performAndWait { - let type = HKQuantityType.quantityType(forIdentifier: .bloodGlucose)! - let startDate = dateFormatter.date(from: "2020-02-03T04:05:06Z")! - let quantity = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 123.4) - let device = HKDevice(name: "NAME", manufacturer: "MANUFACTURER", model: "MODEL", hardwareVersion: "HARDWAREVERSION", firmwareVersion: "FIRMWAREVERSION", softwareVersion: "SOFTWAREVERSION", localIdentifier: "LOCALIDENTIFIER", udiDeviceIdentifier: "UDIDEVICEIDENTIFIER") - let metadata: [String: Any] = [ - HKMetadataKeySyncIdentifier: "0B2353CD-7F98-4297-81E2-8D6FCDD02655", - HKMetadataKeySyncVersion: 2, - MetadataKeyGlucoseIsDisplayOnly: true, - HKMetadataKeyWasUserEntered: true, - MetadataKeyGlucoseCondition: "belowRange", - MetadataKeyGlucoseTrend: "→", - MetadataKeyGlucoseTrendRateUnit: HKUnit.milligramsPerDeciliterPerMinute.unitString, - MetadataKeyGlucoseTrendRateValue: 0.1 - ] - let quantitySample = HKQuantitySample(type: type, quantity: quantity, start: startDate, end: startDate, device: device, metadata: metadata) - let object = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object.create(from: quantitySample) - XCTAssertEqual(quantitySample.quantity, object.quantitySample.quantity) - XCTAssertEqual(quantitySample.quantityType, object.quantitySample.quantityType) - XCTAssertEqual(quantitySample.condition, object.quantitySample.condition) - XCTAssertEqual(quantitySample.trend, object.quantitySample.trend) - XCTAssertEqual(quantitySample.trendRate, object.quantitySample.trendRate) - XCTAssertEqual(quantitySample.provenanceIdentifier, object.quantitySample.provenanceIdentifier) - XCTAssertEqual(quantitySample.absorptionTime, object.quantitySample.absorptionTime) - XCTAssertEqual(quantitySample.automaticallyIssued, object.quantitySample.automaticallyIssued) - XCTAssertEqual(quantitySample.count, object.quantitySample.count) - XCTAssertEqual(quantitySample.createdByCurrentApp, object.quantitySample.createdByCurrentApp) - XCTAssertEqual(quantitySample.hasLoopKitOrigin, object.quantitySample.hasLoopKitOrigin) - XCTAssertEqual(quantitySample.isDisplayOnly, object.quantitySample.isDisplayOnly) - XCTAssertEqual(quantitySample.manuallyEntered, object.quantitySample.manuallyEntered) - XCTAssertEqual(quantitySample.wasUserEntered, object.quantitySample.wasUserEntered) - XCTAssertEqual(quantitySample.syncVersion, object.quantitySample.syncVersion) - XCTAssertEqual(quantitySample.syncIdentifier, object.quantitySample.syncIdentifier) - XCTAssertEqual(quantitySample.startDate, object.quantitySample.startDate) - XCTAssertEqual(quantitySample.endDate, object.quantitySample.endDate) - XCTAssertNotEqual(quantitySample.uuid, object.quantitySample.uuid) // the UUIDs won't be the same... - XCTAssertEqual(quantitySample.dose, object.quantitySample.dose) - XCTAssertEqual(quantitySample.foodType, object.quantitySample.foodType) - XCTAssertEqual(quantitySample.insulinType, object.quantitySample.insulinType) - XCTAssertEqual(quantitySample.insulinDeliveryReason, object.quantitySample.insulinDeliveryReason) - XCTAssertEqual(quantitySample.device, object.quantitySample.device) - } - } - - private let dateFormatter = ISO8601DateFormatter() -} diff --git a/Dependencies/LoopKit/LoopKitHostedTests/TestCoreData/Model.sqlite.v1.original b/Dependencies/LoopKit/LoopKitHostedTests/TestCoreData/Model.sqlite.v1.original deleted file mode 100644 index f5cef1dca..000000000 Binary files a/Dependencies/LoopKit/LoopKitHostedTests/TestCoreData/Model.sqlite.v1.original and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitTests/AlertTests.swift b/Dependencies/LoopKit/LoopKitTests/AlertTests.swift deleted file mode 100644 index f0d03acd7..000000000 --- a/Dependencies/LoopKit/LoopKitTests/AlertTests.swift +++ /dev/null @@ -1,116 +0,0 @@ -// -// AlertTests.swift -// LoopKitTests -// -// Created by Rick Pasetto on 5/1/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import LoopKit - -class AlertTests: XCTestCase { - let identifier = Alert.Identifier(managerIdentifier: "managerIdentifier1", alertIdentifier: "alertIdentifier1") - let foregroundContent = Alert.Content(title: "title1", body: "body1", acknowledgeActionButtonLabel: "acknowledgeActionButtonLabel1") - let backgroundContent = Alert.Content(title: "title2", body: "body2", acknowledgeActionButtonLabel: "acknowledgeActionButtonLabel2") - - func testIdentifierValue() { - XCTAssertEqual("managerIdentifier1.alertIdentifier1", identifier.value) - } - - func testAlertImmediateEncodable() { - let alert = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .immediate) - let str = try? alert.encodeToString() - XCTAssertEqual("{\"trigger\":\"immediate\",\"interruptionLevel\":\"timeSensitive\",\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\",\"body\":\"body1\"},\"backgroundContent\":{\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\",\"body\":\"body2\"}}", str) - } - - func testAlertDelayedEncodable() { - let alert = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .delayed(interval: 1.0)) - let str = try? alert.encodeToString() - XCTAssertEqual("{\"trigger\":{\"delayed\":{\"delayInterval\":1}},\"interruptionLevel\":\"timeSensitive\",\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\",\"body\":\"body1\"},\"backgroundContent\":{\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\",\"body\":\"body2\"}}", str) - } - - func testAlertRepeatingEncodable() { - let alert = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .repeating(repeatInterval: 2.0)) - let str = try? alert.encodeToString() - XCTAssertEqual("{\"trigger\":{\"repeating\":{\"repeatInterval\":2}},\"interruptionLevel\":\"timeSensitive\",\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\",\"body\":\"body1\"},\"backgroundContent\":{\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\",\"body\":\"body2\"}}", str) - } - - func testAlertVibrateSoundEncodable() { - let alert = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .immediate, sound: .vibrate) - let str = try? alert.encodeToString() - XCTAssertEqual("{\"trigger\":\"immediate\",\"interruptionLevel\":\"timeSensitive\",\"sound\":\"vibrate\",\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\",\"body\":\"body1\"},\"backgroundContent\":{\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\",\"body\":\"body2\"}}", str) - } - - func testAlertSoundEncodable() { - let alert = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .immediate, sound: .sound(name: "soundName")) - let str = try? alert.encodeToString() - XCTAssertEqual("{\"trigger\":\"immediate\",\"interruptionLevel\":\"timeSensitive\",\"sound\":{\"sound\":{\"name\":\"soundName\"}},\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\",\"body\":\"body1\"},\"backgroundContent\":{\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\",\"body\":\"body2\"}}", str) - } - - func testAlertImmediateDecodable() { - let str = "{\"trigger\":\"immediate\",\"interruptionLevel\":\"timeSensitive\",\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"body\":\"body1\",\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\"},\"backgroundContent\":{\"body\":\"body2\",\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\"}}" - let expected = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .immediate) - let alert = try? Alert.decode(from: str) - XCTAssertEqual(expected, alert) - } - - func testAlertDelayedDecodable() { - let str = "{\"trigger\":{\"delayed\":{\"delayInterval\":1}},\"interruptionLevel\":\"timeSensitive\",\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"body\":\"body1\",\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\"},\"backgroundContent\":{\"body\":\"body2\",\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\"}}" - let expected = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .delayed(interval: 1.0)) - let alert = try? Alert.decode(from: str) - XCTAssertEqual(expected, alert) - } - - func testAlertRepeatingDecodable() { - let str = "{\"trigger\":{\"repeating\":{\"repeatInterval\":2}},\"interruptionLevel\":\"timeSensitive\",\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"body\":\"body1\",\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\"},\"backgroundContent\":{\"body\":\"body2\",\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\"}}" - let expected = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .repeating(repeatInterval: 2.0)) - let alert = try? Alert.decode(from: str) - XCTAssertEqual(expected, alert) - } - - func testAlertVibrateSoundDecodable() { - let str = "{\"trigger\":\"immediate\",\"sound\":\"vibrate\",\"interruptionLevel\":\"timeSensitive\",\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"body\":\"body1\",\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\"},\"backgroundContent\":{\"body\":\"body2\",\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\"}}" - let expected = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .immediate, sound: .vibrate) - let alert = try? Alert.decode(from: str) - XCTAssertEqual(expected, alert) - } - - func testAlertSoundDecodable() { - let str = "{\"trigger\":\"immediate\",\"sound\":{\"sound\":{\"name\":\"soundName\"}},\"interruptionLevel\":\"timeSensitive\",\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"body\":\"body1\",\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\"},\"backgroundContent\":{\"body\":\"body2\",\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\"}}" - let expected = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .immediate, sound: .sound(name: "soundName")) - let alert = try? Alert.decode(from: str) - XCTAssertEqual(expected, alert) - } - - func testAlertSoundFilename() { - XCTAssertNil(Alert.Sound.vibrate.filename) - XCTAssertEqual("foo", Alert.Sound.sound(name: "foo").filename) - } -} - -extension Alert { - enum CodableError: Swift.Error { case encodeFailed, decodeFailed } - func encode() throws -> Data { - let encoder = JSONEncoder() - return try encoder.encode(self) - } - static func decode(from data: Data) throws -> Alert { - let decoder = JSONDecoder() - return try decoder.decode(Alert.self, from: data) - } - func encodeToString() throws -> String { - let data = try encode() - guard let result = String(data: data, encoding: .utf8) else { - throw CodableError.encodeFailed - } - return result - } - static func decode(from string: String) throws -> Alert { - guard let data = string.data(using: .utf8) else { - throw CodableError.decodeFailed - } - return try decode(from: data) - } -} - diff --git a/Dependencies/LoopKit/LoopKitTests/BasalRateScheduleTests.swift b/Dependencies/LoopKit/LoopKitTests/BasalRateScheduleTests.swift deleted file mode 100644 index e526c057b..000000000 --- a/Dependencies/LoopKit/LoopKitTests/BasalRateScheduleTests.swift +++ /dev/null @@ -1,181 +0,0 @@ -// -// BasalRateScheduleTests.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/5/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import LoopKit - -private class TestingBundle { - /// Returns the resource bundle associated with the current Swift module. - static var main: Bundle = { - if let mainResourceURL = Bundle(for: TestingBundle.self).resourceURL, - let bundle = Bundle(url: mainResourceURL.appendingPathComponent("LoopKit_LoopKitTests.bundle")) - { - return bundle - } - return Bundle(for: TestingBundle.self) - }() -} - - -func ==(lhs: RepeatingScheduleValue, rhs: RepeatingScheduleValue) -> Bool { - return lhs.startTime == rhs.startTime && lhs.value == rhs.value -} - -func ==(lhs: AbsoluteScheduleValue, rhs: AbsoluteScheduleValue) -> Bool { - return lhs.startDate == rhs.startDate && lhs.endDate == rhs.endDate && lhs.value == rhs.value -} - - -func ==(lhs: ArraySlice>, rhs: ArraySlice>) -> Bool { - guard lhs.count == rhs.count else { - return false - } - - for (l, r) in zip(lhs, rhs) { - if !(l == r) { - return false - } - } - - return true -} - - -class BasalRateScheduleTests: XCTestCase { - - var items: [RepeatingScheduleValue]! - - override func setUp() { - super.setUp() - - let path = TestingBundle.main.path(forResource: "basal", ofType: "json")! - let fixture = try! JSONSerialization.jsonObject(with: Data(contentsOf: URL(fileURLWithPath: path)), options: []) as! [JSONDictionary] - - items = fixture.map { - return RepeatingScheduleValue(startTime: TimeInterval(minutes: $0["minutes"] as! Double), value: $0["rate"] as! Double) - } - } - - func testBasalScheduleRanges() { - let therapyTimeZone = TimeZone(secondsFromGMT: -6*60*60)! - let schedule = BasalRateSchedule(dailyItems: items, timeZone: therapyTimeZone)! - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = therapyTimeZone - - let midnight = calendar.startOfDay(for: Date()) - - var absoluteItems: [AbsoluteScheduleValue] = (0.. Bool { - switch (lhs, rhs) { - case (.glucoseBelowSuspendThreshold(let lhsGlucoseValue), .glucoseBelowSuspendThreshold(let rhsGlucoseValue)), - (.currentGlucoseBelowTarget(let lhsGlucoseValue), .currentGlucoseBelowTarget(let rhsGlucoseValue)), - (.predictedGlucoseBelowTarget(let lhsGlucoseValue), .predictedGlucoseBelowTarget(let rhsGlucoseValue)), - (.allGlucoseBelowTarget(let lhsGlucoseValue), .allGlucoseBelowTarget(let rhsGlucoseValue)): - return lhsGlucoseValue.startDate == rhsGlucoseValue.startDate && - lhsGlucoseValue.endDate == rhsGlucoseValue.endDate && - lhsGlucoseValue.quantity == rhsGlucoseValue.quantity - case (.predictedGlucoseInRange, .predictedGlucoseInRange): - return true - default: - return false - } - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/CGMManagerStatusTests.swift b/Dependencies/LoopKit/LoopKitTests/CGMManagerStatusTests.swift deleted file mode 100644 index 9df343bb3..000000000 --- a/Dependencies/LoopKit/LoopKitTests/CGMManagerStatusTests.swift +++ /dev/null @@ -1,67 +0,0 @@ -// -// CGMManagerStatusTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 11/3/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit - -@testable import LoopKit - -class CGMManagerStatusCodableTests: XCTestCase { - func testCodable() throws { - let device = HKDevice(name: "Acme Best Device", - manufacturer: "Acme", - model: "Best", - hardwareVersion: "0.1.2", - firmwareVersion: "1.2.3", - softwareVersion: "2.3.4", - localIdentifier: "Locally Identified", - udiDeviceIdentifier: "U0D1I2") - try assertCGMManagerStatusCodable(CGMManagerStatus(hasValidSensorSession: true, - lastCommunicationDate: dateFormatter.date(from: "2020-05-14T15:56:09Z")!, - device: device), - encodesJSON: """ -{ - "device" : { - "firmwareVersion" : "1.2.3", - "hardwareVersion" : "0.1.2", - "localIdentifier" : "Locally Identified", - "manufacturer" : "Acme", - "model" : "Best", - "name" : "Acme Best Device", - "softwareVersion" : "2.3.4", - "udiDeviceIdentifier" : "U0D1I2" - }, - "hasValidSensorSession" : true, - "lastCommunicationDate" : "2020-05-14T15:56:09Z" -} -""" - ) - } - - private func assertCGMManagerStatusCodable(_ original: CGMManagerStatus, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(CGMManagerStatus.self, from: data) - XCTAssertEqual(decoded, original) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() -} diff --git a/Dependencies/LoopKit/LoopKitTests/CarbMathTests.swift b/Dependencies/LoopKit/LoopKitTests/CarbMathTests.swift deleted file mode 100644 index c862cd753..000000000 --- a/Dependencies/LoopKit/LoopKitTests/CarbMathTests.swift +++ /dev/null @@ -1,940 +0,0 @@ -// -// CarbMathTests.swift -// CarbKitTests -// -// Created by Nathan Racklyeft on 1/18/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import LoopKit -import HealthKit - - -class CarbMathTests: XCTestCase { - - private func printCarbValues(_ carbValues: [CarbValue]) { - let unit = HKUnit.gram() - - print("\n\n") - print(String(data: try! JSONSerialization.data( - withJSONObject: carbValues.map({ (value) -> [String: Any] in - return [ - "date": ISO8601DateFormatter.localTimeDate().string(from: value.startDate), - "amount": value.quantity.doubleValue(for: unit), - "unit": "g" - ] - }), - options: .prettyPrinted), encoding: .utf8)!) - print("\n\n") - } - - private func loadSchedules() -> (CarbRatioSchedule, InsulinSensitivitySchedule) { - let fixture: JSONDictionary = loadFixture("read_carb_ratios") - let schedule = fixture["schedule"] as! [JSONDictionary] - - let items = schedule.map { - return RepeatingScheduleValue(startTime: TimeInterval(minutes: $0["offset"] as! Double), value: $0["ratio"] as! Double) - } - - return ( - CarbRatioSchedule(unit: HKUnit.gram(), dailyItems: items)!, - InsulinSensitivitySchedule(unit: HKUnit.milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: 0.0, value: 40.0)])! - ) - } - - private func loadHistoryFixture(_ name: String) -> [NewCarbEntry] { - let fixture: [JSONDictionary] = loadFixture(name) - return carbEntriesFromFixture(fixture) - } - - private func loadCarbEntryFixture() -> [NewCarbEntry] { - let fixture: [JSONDictionary] = loadFixture("carb_entry_input") - return carbEntriesFromFixture(fixture) - } - - private func carbEntriesFromFixture(_ fixture: [JSONDictionary]) -> [NewCarbEntry] { - let dateFormatter = ISO8601DateFormatter.localTimeDate() - - return fixture.map { - let absorptionTime: TimeInterval? - if let absorptionTimeMinutes = $0["absorption_time"] as? Double { - absorptionTime = TimeInterval(minutes: absorptionTimeMinutes) - } else { - absorptionTime = nil - } - let startAt = dateFormatter.date(from: $0["start_at"] as! String)! - return NewCarbEntry( - date: startAt, - quantity: HKQuantity(unit: HKUnit(from: $0["unit"] as! String), doubleValue: $0["amount"] as! Double), - startDate: startAt, - foodType: nil, - absorptionTime: absorptionTime - ) - } - } - - private func loadEffectOutputFixture(_ name: String) -> [GlucoseEffect] { - let fixture: [JSONDictionary] = loadFixture(name) - let dateFormatter = ISO8601DateFormatter.localTimeDate() - - return fixture.map { - return GlucoseEffect(startDate: dateFormatter.date(from: $0["date"] as! String)!, quantity: HKQuantity(unit: HKUnit(from: $0["unit"] as! String), doubleValue:$0["amount"] as! Double)) - } - } - - private func loadCOBOutputFixture(_ name: String) -> [CarbValue] { - let fixture: [JSONDictionary] = loadFixture(name) - let dateFormatter = ISO8601DateFormatter.localTimeDate() - - return fixture.map { - return CarbValue(startDate: dateFormatter.date(from: $0["date"] as! String)!, quantity: HKQuantity(unit: HKUnit(from: $0["unit"] as! String), doubleValue:$0["amount"] as! Double)) - } - } - - private func loadICEInputFixture(_ name: String) -> [GlucoseEffectVelocity] { - let fixture: [JSONDictionary] = loadFixture(name) - let dateFormatter = ISO8601DateFormatter.localTimeDate() - - let unit = HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) - - return fixture.map { - let quantity = HKQuantity(unit: unit, doubleValue: $0["velocity"] as! Double) - return GlucoseEffectVelocity( - startDate: dateFormatter.date(from: $0["start_at"] as! String)!, - endDate: dateFormatter.date(from: $0["end_at"] as! String)!, - quantity: quantity) - } - } - - func testCarbEffectWithZeroEntry() { - let inputICE = loadICEInputFixture("ice_35_min_input") - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let startDate = inputICE[0].startDate - let carbEntry = NewCarbEntry( - date: startDate, - quantity: HKQuantity(unit: HKUnit.gram(), doubleValue: 0), - startDate: startDate, - foodType: nil, - absorptionTime: TimeInterval(minutes: 120) - ) - - let statuses = [carbEntry].map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: 1.5, - absorptionModel: LinearAbsorption(), - adaptiveAbsorptionRateEnabled: false, - adaptiveRateStandbyIntervalFraction: 0.2 - ) - - XCTAssertEqual(statuses.count, 1) - XCTAssertEqual(statuses[0].absorption?.estimatedTimeRemaining, 0) - } - - func testCarbEffectFromHistory() { - let input = loadHistoryFixture("carb_effect_from_history_input") - let output = loadEffectOutputFixture("carb_effect_from_history_output") - let (carbRatios, insulinSensitivities) = loadSchedules() - - let effects = input.glucoseEffects(carbRatios: carbRatios, insulinSensitivities: insulinSensitivities, defaultAbsorptionTime: TimeInterval(minutes: 180), absorptionModel: ParabolicAbsorption()) - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), calculated.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), accuracy: Double(Float.ulpOfOne)) - } - } - - func testCarbsOnBoardFromHistory() { - let input = loadHistoryFixture("carb_effect_from_history_input") - let output = loadCOBOutputFixture("carbs_on_board_output") - - let cob = input.carbsOnBoard(defaultAbsorptionTime: TimeInterval(minutes: 180), absorptionModel: ParabolicAbsorption(), delay: TimeInterval(minutes: 10), delta: TimeInterval(minutes: 5)) - - XCTAssertEqual(output.count, cob.count) - - for (expected, calculated) in zip(output, cob) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.gram()), calculated.quantity.doubleValue(for: HKUnit.gram()), accuracy: Double(Float.ulpOfOne)) - } - } - - func testDynamicGlucoseEffectAbsorptionNoneObserved() { - let inputICE = loadICEInputFixture("ice_35_min_input") - let carbEntries = loadCarbEntryFixture() - let output = loadEffectOutputFixture("dynamic_glucose_effect_none_observed_output") - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let futureCarbEntry = carbEntries[2] - - let statuses = [futureCarbEntry].map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption(), - adaptiveAbsorptionRateEnabled: false, - adaptiveRateStandbyIntervalFraction: 0.2 - ) - - XCTAssertEqual(statuses.count, 1) - - // Full absorption remains - XCTAssertEqual(statuses[0].absorption!.estimatedTimeRemaining, TimeInterval(hours: 4), accuracy: 1) - - let effects = statuses.dynamicGlucoseEffects( - from: inputICE[0].startDate, - to: inputICE[0].startDate.addingTimeInterval(TimeInterval(hours: 6)), - carbRatios: carbRatios, - insulinSensitivities: insulinSensitivities, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption(), - delay: 0 - ) - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: .milligramsPerDeciliter), calculated.quantity.doubleValue(for: .milligramsPerDeciliter), accuracy: Double(Float.ulpOfOne)) - } - } - - func testDynamicAbsorptionNoneObserved() { - let inputICE = loadICEInputFixture("ice_35_min_input") - let carbEntries = loadCarbEntryFixture() - let output = loadCOBOutputFixture("ice_35_min_none_output") - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let futureCarbEntry = carbEntries[2] - - let statuses = [futureCarbEntry].map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption(), - adaptiveAbsorptionRateEnabled: false, - adaptiveRateStandbyIntervalFraction: 0.2 - ) - - XCTAssertEqual(statuses.count, 1) - - // Full absorption remains - XCTAssertEqual(statuses[0].absorption!.estimatedTimeRemaining, TimeInterval(hours: 4), accuracy: 1) - - let carbsOnBoard = statuses.dynamicCarbsOnBoard( - from: inputICE[0].startDate, - to: inputICE[0].startDate.addingTimeInterval(TimeInterval(hours: 6)), - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption(), - delay: TimeInterval(minutes: 10), - delta: TimeInterval(minutes: 5)) - - let unit = HKUnit.gram() - - XCTAssertEqual(output.count, carbsOnBoard.count) - - for (expected, calculated) in zip(output, carbsOnBoard) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.gram()), calculated.quantity.doubleValue(for: HKUnit.gram()), accuracy: Double(Float.ulpOfOne)) - } - - XCTAssertEqual(carbsOnBoard.first!.quantity.doubleValue(for: unit), 0, accuracy: 1) - XCTAssertEqual(carbsOnBoard.last!.quantity.doubleValue(for: unit), 0, accuracy: 1) - } - - func testDynamicAbsorptionPartiallyObserved() { - let inputICE = loadICEInputFixture("ice_35_min_input") - let carbEntries = loadCarbEntryFixture() - let output = loadCOBOutputFixture("ice_35_min_partial_output") - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let statuses = [carbEntries[0]].map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption(), - adaptiveAbsorptionRateEnabled: false, - adaptiveRateStandbyIntervalFraction: 0.2) - - XCTAssertEqual(statuses.count, 1) - - XCTAssertEqual(statuses[0].absorption!.estimatedTimeRemaining, 8509, accuracy: 1) - - let absorption = statuses[0].absorption! - let unit = HKUnit.gram() - - XCTAssertEqual(absorption.observed.doubleValue(for: unit), 18, accuracy: Double(Float.ulpOfOne)) - - let carbsOnBoard = statuses.dynamicCarbsOnBoard( - from: inputICE[0].startDate, - to: inputICE[0].startDate.addingTimeInterval(TimeInterval(hours: 6)), - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption(), - delay: TimeInterval(minutes: 10), - delta: TimeInterval(minutes: 5) - ) - - XCTAssertEqual(output.count, carbsOnBoard.count) - - for (expected, calculated) in zip(output, carbsOnBoard) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.gram()), calculated.quantity.doubleValue(for: HKUnit.gram()), accuracy: Double(Float.ulpOfOne)) - } - - XCTAssertEqual(carbsOnBoard.first!.quantity.doubleValue(for: unit), 0, accuracy: 1) - XCTAssertEqual(carbsOnBoard[2].quantity.doubleValue(for: unit), 44, accuracy: 1) - XCTAssertEqual(carbsOnBoard[25].quantity.doubleValue(for: unit), 9, accuracy: 1) - XCTAssertEqual(carbsOnBoard.last!.quantity.doubleValue(for: unit), 0, accuracy: 1) - } - - func testDynamicGlucoseEffectAbsorptionPartiallyObserved() { - let inputICE = loadICEInputFixture("ice_35_min_input") - let carbEntries = loadCarbEntryFixture() - let output = loadEffectOutputFixture("dynamic_glucose_effect_partially_observed_output") - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let statuses = [carbEntries[0]].map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption(), - adaptiveAbsorptionRateEnabled: false, - adaptiveRateStandbyIntervalFraction: 0.2) - - XCTAssertEqual(statuses.count, 1) - - XCTAssertEqual(statuses[0].absorption!.estimatedTimeRemaining, 8509, accuracy: 1) - - let absorption = statuses[0].absorption! - let unit = HKUnit.gram() - - XCTAssertEqual(absorption.observed.doubleValue(for: unit), 18, accuracy: Double(Float.ulpOfOne)) - - let effects = statuses.dynamicGlucoseEffects( - from: inputICE[0].startDate, - to: inputICE[0].startDate.addingTimeInterval(TimeInterval(hours: 6)), - carbRatios: carbRatios, - insulinSensitivities: insulinSensitivities, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption() - ) - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: .milligramsPerDeciliter), calculated.quantity.doubleValue(for: .milligramsPerDeciliter), accuracy: Double(Float.ulpOfOne)) - } - } - - - func testDynamicAbsorptionFullyObserved() { - let inputICE = loadICEInputFixture("ice_1_hour_input") - let carbEntries = loadCarbEntryFixture() - let output = loadCOBOutputFixture("ice_1_hour_output") - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let statuses = [carbEntries[0]].map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption(), - adaptiveAbsorptionRateEnabled: false, - adaptiveRateStandbyIntervalFraction: 0.2 - ) - - XCTAssertEqual(statuses.count, 1) - XCTAssertNotNil(statuses[0].absorption) - - // No remaining absorption - XCTAssertEqual(statuses[0].absorption!.estimatedTimeRemaining, 0, accuracy: 1) - - let absorption = statuses[0].absorption! - let unit = HKUnit.gram() - - // All should be absorbed - XCTAssertEqual(absorption.observed.doubleValue(for: unit), 44, accuracy: 1) - - let carbsOnBoard = statuses.dynamicCarbsOnBoard( - from: inputICE[0].startDate, - to: inputICE[0].startDate.addingTimeInterval(TimeInterval(hours: 6)), - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption(), - delay: TimeInterval(minutes: 10), - delta: TimeInterval(minutes: 5) - ) - - XCTAssertEqual(output.count, carbsOnBoard.count) - - for (expected, calculated) in zip(output, carbsOnBoard) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.gram()), calculated.quantity.doubleValue(for: HKUnit.gram()), accuracy: Double(Float.ulpOfOne)) - } - - XCTAssertEqual(carbsOnBoard[0].quantity.doubleValue(for: unit), 0, accuracy: 1) - XCTAssertEqual(carbsOnBoard[1].quantity.doubleValue(for: unit), 44, accuracy: 1) - XCTAssertEqual(carbsOnBoard[2].quantity.doubleValue(for: unit), 44, accuracy: 1) - XCTAssertEqual(carbsOnBoard[10].quantity.doubleValue(for: unit), 21, accuracy: 1) - XCTAssertEqual(carbsOnBoard[17].quantity.doubleValue(for: unit), 7, accuracy: 1) - XCTAssertEqual(carbsOnBoard[18].quantity.doubleValue(for: unit), 4, accuracy: 1) - XCTAssertEqual(carbsOnBoard[30].quantity.doubleValue(for: unit), 0, accuracy: 1) - } - - func testDynamicGlucoseEffectsAbsorptionFullyObserved() { - let inputICE = loadICEInputFixture("ice_1_hour_input") - let carbEntries = loadCarbEntryFixture() - let output = loadEffectOutputFixture("dynamic_glucose_effect_fully_observed_output") - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let statuses = [carbEntries[0]].map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption(), - adaptiveAbsorptionRateEnabled: false, - adaptiveRateStandbyIntervalFraction: 0.2 - ) - - XCTAssertEqual(statuses.count, 1) - XCTAssertNotNil(statuses[0].absorption) - - // No remaining absorption - XCTAssertEqual(statuses[0].absorption!.estimatedTimeRemaining, 0, accuracy: 1) - - let absorption = statuses[0].absorption! - let unit = HKUnit.gram() - - // All should be absorbed - XCTAssertEqual(absorption.observed.doubleValue(for: unit), 44, accuracy: 1) - - let effects = statuses.dynamicGlucoseEffects( - from: inputICE[0].startDate, - to: inputICE[0].startDate.addingTimeInterval(TimeInterval(hours: 6)), - carbRatios: carbRatios, - insulinSensitivities: insulinSensitivities, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption() - ) - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: .milligramsPerDeciliter), calculated.quantity.doubleValue(for: .milligramsPerDeciliter), accuracy: Double(Float.ulpOfOne)) - } - } - - func testDynamicAbsorptionNeverFullyObserved() { - let inputICE = loadICEInputFixture("ice_slow_absorption") - let carbEntries = loadCarbEntryFixture() - let output = loadCOBOutputFixture("ice_slow_absorption_output") - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let statuses = [carbEntries[1]].map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption(), - adaptiveAbsorptionRateEnabled: false, - adaptiveRateStandbyIntervalFraction: 0.2) - - XCTAssertEqual(statuses.count, 1) - XCTAssertNotNil(statuses[0].absorption) - - XCTAssertEqual(statuses[0].absorption!.estimatedTimeRemaining, 10488, accuracy: 1) - - // Check 12 hours later - let carbsOnBoard = statuses.dynamicCarbsOnBoard( - from: inputICE[0].startDate, - to: inputICE[0].startDate.addingTimeInterval(TimeInterval(hours: 18)), - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption(), - delay: TimeInterval(minutes: 10), - delta: TimeInterval(minutes: 5) - ) - - let unit = HKUnit.gram() - - XCTAssertEqual(output.count, carbsOnBoard.count) - - for (expected, calculated) in zip(output, carbsOnBoard) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.gram()), calculated.quantity.doubleValue(for: HKUnit.gram()), accuracy: Double(Float.ulpOfOne)) - } - - XCTAssertEqual(carbsOnBoard.first!.quantity.doubleValue(for: unit), 0, accuracy: 1) - XCTAssertEqual(carbsOnBoard[5].quantity.doubleValue(for: unit), 30, accuracy: 1) - XCTAssertEqual(carbsOnBoard.last!.quantity.doubleValue(for: unit), 0, accuracy: 1) - } - - func testDynamicGlucoseEffectsAbsorptionNeverFullyObserved() { - let inputICE = loadICEInputFixture("ice_slow_absorption") - let carbEntries = loadCarbEntryFixture() - let output = loadEffectOutputFixture("dynamic_glucose_effect_never_fully_observed_output") - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let statuses = [carbEntries[1]].map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption(), - adaptiveAbsorptionRateEnabled: false, - adaptiveRateStandbyIntervalFraction: 0.2) - - XCTAssertEqual(statuses.count, 1) - XCTAssertNotNil(statuses[0].absorption) - - XCTAssertEqual(statuses[0].absorption!.estimatedTimeRemaining, 10488, accuracy: 1) - - // Check 12 hours later - let effects = statuses.dynamicGlucoseEffects( - from: inputICE[0].startDate, - to: inputICE[0].startDate.addingTimeInterval(TimeInterval(hours: 18)), - carbRatios: carbRatios, - insulinSensitivities: insulinSensitivities, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption() - ) - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: .milligramsPerDeciliter), calculated.quantity.doubleValue(for: .milligramsPerDeciliter), accuracy: Double(Float.ulpOfOne)) - } - } - - func testGroupedByOverlappingAbsorptionTimeFromHistory() { - let input = loadHistoryFixture("grouped_by_overlapping_absorption_times_input") - let outputFixture: [[JSONDictionary]] = loadFixture("grouped_by_overlapping_absorption_times_output") - let output = outputFixture.map { self.carbEntriesFromFixture($0) } - let grouped = input.groupedByOverlappingAbsorptionTimes(defaultAbsorptionTime: TimeInterval(minutes: 180)) - - XCTAssertEqual(output.count, grouped.count) - - for (expected, calculated) in zip(output, grouped) { - XCTAssertEqual(expected, calculated) - } - } - - func testGroupedByOverlappingAbsorptionTimeEdgeCases() { - let input = loadHistoryFixture("grouped_by_overlapping_absorption_times_border_case_input") - let outputFixture: [[JSONDictionary]] = loadFixture("grouped_by_overlapping_absorption_times_border_case_output") - let output = outputFixture.map { self.carbEntriesFromFixture($0) } - let grouped = input.groupedByOverlappingAbsorptionTimes(defaultAbsorptionTime: TimeInterval(minutes: 180)) - - XCTAssertEqual(output.count, grouped.count) - - for (expected, calculated) in zip(output, grouped) { - XCTAssertEqual(expected, calculated) - } - } - - // Aditional tests for nonlinear and adaptive-rate carb absorption models - - func testDynamicAbsorptionPiecewiseLinearNoneObserved() { - let inputICE = loadICEInputFixture("ice_35_min_input") - let carbEntries = loadCarbEntryFixture() - let output = loadCOBOutputFixture("ice_35_min_none_piecewiselinear_output") - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let futureCarbEntry = carbEntries[2] - - let statuses = [futureCarbEntry].map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: 1.5, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: 1.5, - absorptionModel: PiecewiseLinearAbsorption(), - adaptiveAbsorptionRateEnabled: false, - adaptiveRateStandbyIntervalFraction: 0.2 - ) - - XCTAssertEqual(statuses.count, 1) - - // Full absorption remains - XCTAssertEqual(statuses[0].absorption!.estimatedTimeRemaining, TimeInterval(hours: 3), accuracy: 1) - - let carbsOnBoard = statuses.dynamicCarbsOnBoard( - from: inputICE[0].startDate, - to: inputICE[0].startDate.addingTimeInterval(TimeInterval(hours: 6)), - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: PiecewiseLinearAbsorption(), - delay: TimeInterval(minutes: 10), - delta: TimeInterval(minutes: 5)) - - let unit = HKUnit.gram() - - XCTAssertEqual(output.count, carbsOnBoard.count) - - for (expected, calculated) in zip(output, carbsOnBoard) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.gram()), calculated.quantity.doubleValue(for: HKUnit.gram()), accuracy: Double(Float.ulpOfOne)) - } - - XCTAssertEqual(carbsOnBoard.first!.quantity.doubleValue(for: unit), 0, accuracy: 1) - XCTAssertEqual(carbsOnBoard.last!.quantity.doubleValue(for: unit), 0, accuracy: 1) - } - - func testDynamicAbsorptionPiecewiseLinearPartiallyObserved() { - let inputICE = loadICEInputFixture("ice_35_min_input") - let carbEntries = loadCarbEntryFixture() - let output = loadCOBOutputFixture("ice_35_min_partial_piecewiselinear_output") - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let statuses = [carbEntries[0]].map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: 1.5, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: 1.5, - absorptionModel: PiecewiseLinearAbsorption(), - adaptiveAbsorptionRateEnabled: false, - adaptiveRateStandbyIntervalFraction: 0.2) - - XCTAssertEqual(statuses.count, 1) - - XCTAssertEqual(statuses[0].absorption!.estimatedTimeRemaining, 7008, accuracy: 1) - - let absorption = statuses[0].absorption! - let unit = HKUnit.gram() - - XCTAssertEqual(absorption.observed.doubleValue(for: unit), 18, accuracy: Double(Float.ulpOfOne)) - - let carbsOnBoard = statuses.dynamicCarbsOnBoard( - from: inputICE[0].startDate, - to: inputICE[0].startDate.addingTimeInterval(TimeInterval(hours: 6)), - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: PiecewiseLinearAbsorption(), - delay: TimeInterval(minutes: 10), - delta: TimeInterval(minutes: 5) - ) - - XCTAssertEqual(output.count, carbsOnBoard.count) - - for (expected, calculated) in zip(output, carbsOnBoard) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.gram()), calculated.quantity.doubleValue(for: HKUnit.gram()), accuracy: Double(Float.ulpOfOne)) - } - - XCTAssertEqual(carbsOnBoard.first!.quantity.doubleValue(for: unit), 0, accuracy: 1) - XCTAssertEqual(carbsOnBoard[2].quantity.doubleValue(for: unit), 44, accuracy: 1) - XCTAssertEqual(carbsOnBoard[20].quantity.doubleValue(for: unit), 5, accuracy: 1) - XCTAssertEqual(carbsOnBoard.last!.quantity.doubleValue(for: unit), 0, accuracy: 1) - } - - func testDynamicAbsorptionPiecewiseLinearFullyObserved() { - let inputICE = loadICEInputFixture("ice_1_hour_input") - let carbEntries = loadCarbEntryFixture() - let output = loadCOBOutputFixture("ice_1_hour_output") - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let statuses = [carbEntries[0]].map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: 1.5, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: 1.5, - absorptionModel: PiecewiseLinearAbsorption(), - adaptiveAbsorptionRateEnabled: false, - adaptiveRateStandbyIntervalFraction: 0.2 - ) - - XCTAssertEqual(statuses.count, 1) - XCTAssertNotNil(statuses[0].absorption) - - // No remaining absorption - XCTAssertEqual(statuses[0].absorption!.estimatedTimeRemaining, 0, accuracy: 1) - - let absorption = statuses[0].absorption! - let unit = HKUnit.gram() - - // All should be absorbed - XCTAssertEqual(absorption.observed.doubleValue(for: unit), 44, accuracy: 1) - - let carbsOnBoard = statuses.dynamicCarbsOnBoard( - from: inputICE[0].startDate, - to: inputICE[0].startDate.addingTimeInterval(TimeInterval(hours: 6)), - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: PiecewiseLinearAbsorption(), - delay: TimeInterval(minutes: 10), - delta: TimeInterval(minutes: 5) - ) - - XCTAssertEqual(output.count, carbsOnBoard.count) - - for (expected, calculated) in zip(output, carbsOnBoard) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.gram()), calculated.quantity.doubleValue(for: HKUnit.gram()), accuracy: Double(Float.ulpOfOne)) - } - - XCTAssertEqual(carbsOnBoard[0].quantity.doubleValue(for: unit), 0, accuracy: 1) - XCTAssertEqual(carbsOnBoard[1].quantity.doubleValue(for: unit), 44, accuracy: 1) - XCTAssertEqual(carbsOnBoard[2].quantity.doubleValue(for: unit), 44, accuracy: 1) - XCTAssertEqual(carbsOnBoard[10].quantity.doubleValue(for: unit), 21, accuracy: 1) - XCTAssertEqual(carbsOnBoard[17].quantity.doubleValue(for: unit), 7, accuracy: 1) - XCTAssertEqual(carbsOnBoard[18].quantity.doubleValue(for: unit), 4, accuracy: 1) - XCTAssertEqual(carbsOnBoard[30].quantity.doubleValue(for: unit), 0, accuracy: 1) - } - - func testDynamicAbsorptionPiecewiseLinearNeverFullyObserved() { - let inputICE = loadICEInputFixture("ice_slow_absorption") - let carbEntries = loadCarbEntryFixture() - let output = loadCOBOutputFixture("ice_slow_absorption_piecewiselinear_output") - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let statuses = [carbEntries[1]].map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: 1.5, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: 1.5, - absorptionModel: PiecewiseLinearAbsorption(), - adaptiveAbsorptionRateEnabled: false, - adaptiveRateStandbyIntervalFraction: 0.2) - - XCTAssertEqual(statuses.count, 1) - XCTAssertNotNil(statuses[0].absorption) - - XCTAssertEqual(statuses[0].absorption!.estimatedTimeRemaining, 6888, accuracy: 1) - - // Check 12 hours later - let carbsOnBoard = statuses.dynamicCarbsOnBoard( - from: inputICE[0].startDate, - to: inputICE[0].startDate.addingTimeInterval(TimeInterval(hours: 18)), - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: PiecewiseLinearAbsorption(), - delay: TimeInterval(minutes: 10), - delta: TimeInterval(minutes: 5) - ) - - let unit = HKUnit.gram() - - XCTAssertEqual(output.count, carbsOnBoard.count) - - for (expected, calculated) in zip(output, carbsOnBoard) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.gram()), calculated.quantity.doubleValue(for: HKUnit.gram()), accuracy: Double(Float.ulpOfOne)) - } - - XCTAssertEqual(carbsOnBoard.first!.quantity.doubleValue(for: unit), 0, accuracy: 1) - XCTAssertEqual(carbsOnBoard[5].quantity.doubleValue(for: unit), 30, accuracy: 1) - XCTAssertEqual(carbsOnBoard.last!.quantity.doubleValue(for: unit), 0, accuracy: 1) - } - - func testDynamicAbsorptionPiecewiseLinearAdaptiveRatePartiallyObserved() { - let inputICE = loadICEInputFixture("ice_35_min_input") - let carbEntries = loadCarbEntryFixture() - let output = loadCOBOutputFixture("ice_35_min_partial_piecewiselinear_adaptiverate_output") - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let statuses = [carbEntries[0]].map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: 1.5, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: 1.0, - absorptionModel: PiecewiseLinearAbsorption(), - adaptiveAbsorptionRateEnabled: true, - adaptiveRateStandbyIntervalFraction: 0.2) - - XCTAssertEqual(statuses.count, 1) - - XCTAssertEqual(statuses[0].absorption!.estimatedTimeRemaining, 3326, accuracy: 1) - - let absorption = statuses[0].absorption! - let unit = HKUnit.gram() - - XCTAssertEqual(absorption.observed.doubleValue(for: unit), 18, accuracy: Double(Float.ulpOfOne)) - - let carbsOnBoard = statuses.dynamicCarbsOnBoard( - from: inputICE[0].startDate, - to: inputICE[0].startDate.addingTimeInterval(TimeInterval(hours: 6)), - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - absorptionModel: PiecewiseLinearAbsorption(), - delay: TimeInterval(minutes: 10), - delta: TimeInterval(minutes: 5) - ) - - XCTAssertEqual(output.count, carbsOnBoard.count) - - for (expected, calculated) in zip(output, carbsOnBoard) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.gram()), calculated.quantity.doubleValue(for: HKUnit.gram()), accuracy: Double(Float.ulpOfOne)) - } - - XCTAssertEqual(carbsOnBoard.first!.quantity.doubleValue(for: unit), 0, accuracy: 1) - XCTAssertEqual(carbsOnBoard[2].quantity.doubleValue(for: unit), 44, accuracy: 1) - XCTAssertEqual(carbsOnBoard[10].quantity.doubleValue(for: unit), 15, accuracy: 1) - XCTAssertEqual(carbsOnBoard.last!.quantity.doubleValue(for: unit), 0, accuracy: 1) - } - - func testDynamicAbsorptionMultipleEntries() { - let inputICE = loadICEInputFixture("ice_35_min_input") - let carbEntries = loadCarbEntryFixture() - - let (carbRatios, insulinSensitivities) = loadSchedules() - let defaultAbsorptionTimes = CarbStore.DefaultAbsorptionTimes( - fast: TimeInterval(hours: 1), - medium: TimeInterval(hours: 2), - slow: TimeInterval(hours: 4) - ) - - let statuses = carbEntries.map( - to: inputICE, - carbRatio: carbRatios, - insulinSensitivity: insulinSensitivities, - absorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - defaultAbsorptionTime: defaultAbsorptionTimes.medium, - delay: TimeInterval(minutes: 0), - initialAbsorptionTimeOverrun: defaultAbsorptionTimes.slow / defaultAbsorptionTimes.medium, - absorptionModel: LinearAbsorption(), - adaptiveAbsorptionRateEnabled: false, - adaptiveRateStandbyIntervalFraction: 0.2 - ) - - - // Tuple structure: (observed absorption, estimated time remaining) - let expected = [(16.193665456944906, 9100.254941363484), (1.806334543055097, 13532.959419333554) , (0, 14400)] - XCTAssertEqual(expected.count, statuses.count) - - for (expected, calculated) in zip(expected, statuses) { - XCTAssertEqual(expected.0, calculated.absorption?.observed.doubleValue(for: HKUnit.gram())) - XCTAssertEqual(expected.1, calculated.absorption?.estimatedTimeRemaining) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/CarbStoreTests.swift b/Dependencies/LoopKit/LoopKitTests/CarbStoreTests.swift deleted file mode 100644 index c0e449a77..000000000 --- a/Dependencies/LoopKit/LoopKitTests/CarbStoreTests.swift +++ /dev/null @@ -1,1346 +0,0 @@ -// -// CarbStoreTests.swift -// LoopKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -import CoreData -@testable import LoopKit - -class CarbStorePersistenceTests: PersistenceControllerTestCase, CarbStoreDelegate { - - var healthStore: HKHealthStoreMock! - var carbStore: CarbStore! - - override func setUp() { - super.setUp() - - healthStore = HKHealthStoreMock() - carbStore = CarbStore( - healthStore: healthStore, - cacheStore: cacheStore, - cacheLength: .hours(24), - defaultAbsorptionTimes: (fast: .minutes(30), medium: .hours(3), slow: .hours(5)), - observationInterval: 0, - provenanceIdentifier: Bundle.main.bundleIdentifier!) - carbStore.testQueryStore = healthStore - carbStore.delegate = self - - let semaphore = DispatchSemaphore(value: 0) - cacheStore.onReady { (error) in - semaphore.signal() - } - semaphore.wait() - - } - - override func tearDown() { - carbStore.delegate = nil - carbStore = nil - healthStore = nil - - carbStoreHasUpdatedCarbDataHandler = nil - - super.tearDown() - } - - // MARK: - CarbStoreDelegate - - var carbStoreHasUpdatedCarbDataHandler: ((_ : CarbStore) -> Void)? - - func carbStoreHasUpdatedCarbData(_ carbStore: CarbStore) { - carbStoreHasUpdatedCarbDataHandler?(carbStore) - } - - func carbStore(_ carbStore: CarbStore, didError error: CarbStore.CarbStoreError) {} - - // MARK: - - - func testGetCarbEntriesAfterAdd() { - let firstCarbEntry = NewCarbEntry(quantity: HKQuantity(unit: .gram(), doubleValue: 10), startDate: Date(timeIntervalSinceNow: -1), foodType: "First", absorptionTime: .hours(5)) - let secondCarbEntry = NewCarbEntry(quantity: HKQuantity(unit: .gram(), doubleValue: 20), startDate: Date(), foodType: "Second", absorptionTime: .hours(3)) - let thirdCarbEntry = NewCarbEntry(quantity: HKQuantity(unit: .gram(), doubleValue: 30), startDate: Date(timeIntervalSinceNow: 1), foodType: "Third", absorptionTime: .minutes(30)) - let getCarbEntriesCompletion = expectation(description: "Get carb entries completion") - - carbStore.addCarbEntry(firstCarbEntry) { (_) in - DispatchQueue.main.async { - self.carbStore.addCarbEntry(secondCarbEntry) { (_) in - DispatchQueue.main.async { - self.carbStore.addCarbEntry(thirdCarbEntry) { (_) in - DispatchQueue.main.async { - self.carbStore.getCarbEntries(start: Date().addingTimeInterval(-.minutes(1))) { result in - getCarbEntriesCompletion.fulfill() - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 3) - - // First - XCTAssertNotNil(entries[0].uuid) - XCTAssertEqual(entries[0].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertNotNil(entries[0].syncIdentifier) - XCTAssertEqual(entries[0].syncVersion, 1) - XCTAssertEqual(entries[0].startDate, firstCarbEntry.startDate) - XCTAssertEqual(entries[0].quantity, firstCarbEntry.quantity) - XCTAssertEqual(entries[0].foodType, firstCarbEntry.foodType) - XCTAssertEqual(entries[0].absorptionTime, firstCarbEntry.absorptionTime) - XCTAssertEqual(entries[0].createdByCurrentApp, true) - XCTAssertEqual(entries[0].userCreatedDate, firstCarbEntry.date) - XCTAssertNil(entries[0].userUpdatedDate) - - // Second - XCTAssertNotNil(entries[1].uuid) - XCTAssertEqual(entries[1].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertNotNil(entries[1].syncIdentifier) - XCTAssertEqual(entries[1].syncVersion, 1) - XCTAssertEqual(entries[1].startDate, secondCarbEntry.startDate) - XCTAssertEqual(entries[1].quantity, secondCarbEntry.quantity) - XCTAssertEqual(entries[1].foodType, secondCarbEntry.foodType) - XCTAssertEqual(entries[1].absorptionTime, secondCarbEntry.absorptionTime) - XCTAssertEqual(entries[1].createdByCurrentApp, true) - XCTAssertEqual(entries[1].userCreatedDate, secondCarbEntry.date) - XCTAssertNil(entries[1].userUpdatedDate) - - // Third - XCTAssertNotNil(entries[2].uuid) - XCTAssertEqual(entries[2].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertNotNil(entries[2].syncIdentifier) - XCTAssertEqual(entries[2].syncVersion, 1) - XCTAssertEqual(entries[2].startDate, thirdCarbEntry.startDate) - XCTAssertEqual(entries[2].quantity, thirdCarbEntry.quantity) - XCTAssertEqual(entries[2].foodType, thirdCarbEntry.foodType) - XCTAssertEqual(entries[2].absorptionTime, thirdCarbEntry.absorptionTime) - XCTAssertEqual(entries[2].createdByCurrentApp, true) - XCTAssertEqual(entries[2].userCreatedDate, thirdCarbEntry.date) - XCTAssertNil(entries[2].userUpdatedDate) - } - } - } - } - } - } - } - } - - wait(for: [getCarbEntriesCompletion], timeout: 2, enforceOrder: true) - } - - // MARK: - - - func testAddCarbEntry() { - let addCarbEntry = NewCarbEntry(quantity: HKQuantity(unit: .gram(), doubleValue: 10), startDate: Date(), foodType: "Add", absorptionTime: .hours(3)) - let addHealthStoreHandler = expectation(description: "Add health store handler") - let addCarbEntryCompletion = expectation(description: "Add carb entry completion") - let addCarbEntryHandler = expectation(description: "Add carb entry handler") - let getCarbEntriesCompletion = expectation(description: "Get carb entries completion") - - var handlerInvocation = 0 - - var addUUID: UUID? - var addSyncIdentifier: String? - - healthStore.setSaveHandler({ (objects, success, error) in - XCTAssertEqual(1, objects.count) - - let sample = objects.first as! HKQuantitySample - - XCTAssertEqual(sample.absorptionTime, addCarbEntry.absorptionTime) - XCTAssertEqual(sample.foodType, addCarbEntry.foodType) - XCTAssertEqual(sample.quantity, addCarbEntry.quantity) - XCTAssertEqual(sample.startDate, addCarbEntry.startDate) - XCTAssertNotNil(sample.syncIdentifier) - XCTAssertEqual(sample.syncVersion, 1) - XCTAssertEqual(sample.userCreatedDate, addCarbEntry.date) - XCTAssertNil(sample.userUpdatedDate) - - addUUID = sample.uuid - addSyncIdentifier = sample.syncIdentifier - - addHealthStoreHandler.fulfill() - }) - - carbStoreHasUpdatedCarbDataHandler = { (carbStore) in - handlerInvocation += 1 - - self.cacheStore.managedObjectContext.performAndWait { - switch handlerInvocation { - case 1: - addCarbEntryHandler.fulfill() - let objects: [CachedCarbObject] = self.cacheStore.managedObjectContext.all() - XCTAssertEqual(objects.count, 1) - - // Added object - XCTAssertEqual(objects[0].absorptionTime, addCarbEntry.absorptionTime) - XCTAssertEqual(objects[0].createdByCurrentApp, true) - XCTAssertEqual(objects[0].foodType, addCarbEntry.foodType) - XCTAssertEqual(objects[0].grams, addCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[0].startDate, addCarbEntry.startDate) - XCTAssertEqual(objects[0].uuid, addUUID) - XCTAssertEqual(objects[0].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(objects[0].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(objects[0].syncVersion, 1) - XCTAssertEqual(objects[0].userCreatedDate, addCarbEntry.date) - XCTAssertNil(objects[0].userUpdatedDate) - XCTAssertNil(objects[0].userDeletedDate) - XCTAssertEqual(objects[0].operation, .create) - XCTAssertNotNil(objects[0].addedDate) - XCTAssertNil(objects[0].supercededDate) - XCTAssertGreaterThan(objects[0].anchorKey, 0) - - DispatchQueue.main.async { - carbStore.getCarbEntries(start: Date().addingTimeInterval(-.minutes(1))) { result in - getCarbEntriesCompletion.fulfill() - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 1) - - // Added sample - XCTAssertEqual(entries[0].uuid, addUUID) - XCTAssertEqual(entries[0].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(entries[0].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(entries[0].syncVersion, 1) - XCTAssertEqual(entries[0].startDate, addCarbEntry.startDate) - XCTAssertEqual(entries[0].quantity, addCarbEntry.quantity) - XCTAssertEqual(entries[0].foodType, addCarbEntry.foodType) - XCTAssertEqual(entries[0].absorptionTime, addCarbEntry.absorptionTime) - XCTAssertEqual(entries[0].createdByCurrentApp, true) - XCTAssertEqual(entries[0].userCreatedDate, addCarbEntry.date) - XCTAssertNil(entries[0].userUpdatedDate) - } - } - } - default: - XCTFail("Unexpected handler invocation") - } - } - } - - carbStore.addCarbEntry(addCarbEntry) { (result) in - addCarbEntryCompletion.fulfill() - } - - wait(for: [addHealthStoreHandler, addCarbEntryCompletion, addCarbEntryHandler, getCarbEntriesCompletion], timeout: 10, enforceOrder: true) - } - - func testAddAndReplaceCarbEntry() { - let addCarbEntry = NewCarbEntry(quantity: HKQuantity(unit: .gram(), doubleValue: 10), startDate: Date(), foodType: "Add", absorptionTime: .hours(3)) - let replaceCarbEntry = NewCarbEntry(quantity: HKQuantity(unit: .gram(), doubleValue: 15), startDate: Date(), foodType: "Replace", absorptionTime: .hours(4)) - let addHealthStoreHandler = expectation(description: "Add health store handler") - let addCarbEntryCompletion = expectation(description: "Add carb entry completion") - let addCarbEntryHandler = expectation(description: "Add carb entry handler") - let updateHealthStoreHandler = expectation(description: "Update health store handler") - let updateCarbEntryCompletion = expectation(description: "Update carb entry completion") - let updateCarbEntryHandler = expectation(description: "Update carb entry handler") - let getCarbEntriesCompletion = expectation(description: "Get carb entries completion") - - var handlerInvocation = 0 - - var addUUID: UUID? - var addSyncIdentifier: String? - var addAnchorKey: Int64? - var updateUUID: UUID? - - healthStore.setSaveHandler({ (objects, success, error) in - XCTAssertEqual(1, objects.count) - - let sample = objects.first as! HKQuantitySample - - XCTAssertEqual(sample.absorptionTime, addCarbEntry.absorptionTime) - XCTAssertEqual(sample.foodType, addCarbEntry.foodType) - XCTAssertEqual(sample.quantity, addCarbEntry.quantity) - XCTAssertEqual(sample.startDate, addCarbEntry.startDate) - XCTAssertNotNil(sample.syncIdentifier) - XCTAssertEqual(sample.syncVersion, 1) - XCTAssertEqual(sample.userCreatedDate, addCarbEntry.date) - XCTAssertNil(sample.userUpdatedDate) - - addUUID = sample.uuid - addSyncIdentifier = sample.syncIdentifier - - addHealthStoreHandler.fulfill() - }) - - carbStoreHasUpdatedCarbDataHandler = { (carbStore) in - handlerInvocation += 1 - - self.cacheStore.managedObjectContext.performAndWait { - switch handlerInvocation { - case 1: - addCarbEntryHandler.fulfill() - let objects: [CachedCarbObject] = self.cacheStore.managedObjectContext.all() - XCTAssertEqual(objects.count, 1) - - // Added object - XCTAssertEqual(objects[0].absorptionTime, addCarbEntry.absorptionTime) - XCTAssertEqual(objects[0].createdByCurrentApp, true) - XCTAssertEqual(objects[0].foodType, addCarbEntry.foodType) - XCTAssertEqual(objects[0].grams, addCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[0].startDate, addCarbEntry.startDate) - XCTAssertEqual(objects[0].uuid, addUUID) - XCTAssertEqual(objects[0].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(objects[0].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(objects[0].syncVersion, 1) - XCTAssertEqual(objects[0].userCreatedDate, addCarbEntry.date) - XCTAssertNil(objects[0].userUpdatedDate) - XCTAssertNil(objects[0].userDeletedDate) - XCTAssertEqual(objects[0].operation, .create) - XCTAssertNotNil(objects[0].addedDate) - XCTAssertNil(objects[0].supercededDate) - XCTAssertGreaterThan(objects[0].anchorKey, 0) - - addAnchorKey = objects[0].anchorKey - - self.healthStore.setSaveHandler({ (objects, success, error) in - XCTAssertEqual(1, objects.count) - - let sample = objects.first as! HKQuantitySample - - XCTAssertNotEqual(sample.uuid, addUUID) - XCTAssertEqual(sample.absorptionTime, replaceCarbEntry.absorptionTime) - XCTAssertEqual(sample.foodType, replaceCarbEntry.foodType) - XCTAssertEqual(sample.quantity, replaceCarbEntry.quantity) - XCTAssertEqual(sample.startDate, replaceCarbEntry.startDate) - XCTAssertEqual(sample.syncIdentifier, addSyncIdentifier) - XCTAssertEqual(sample.syncVersion, 2) - XCTAssertEqual(sample.userCreatedDate, addCarbEntry.date) - XCTAssertEqual(sample.userUpdatedDate, replaceCarbEntry.date) - - updateUUID = sample.uuid - - updateHealthStoreHandler.fulfill() - }) - - self.carbStore.replaceCarbEntry(StoredCarbEntry(managedObject: objects[0]), withEntry: replaceCarbEntry) { (result) in - updateCarbEntryCompletion.fulfill() - } - case 2: - updateCarbEntryHandler.fulfill() - let objects: [CachedCarbObject] = self.cacheStore.managedObjectContext.all().sorted { $0.syncVersion! < $1.syncVersion! } - XCTAssertEqual(objects.count, 2) - - // Added object, superceded - XCTAssertEqual(objects[0].absorptionTime, addCarbEntry.absorptionTime) - XCTAssertEqual(objects[0].createdByCurrentApp, true) - XCTAssertEqual(objects[0].foodType, addCarbEntry.foodType) - XCTAssertEqual(objects[0].grams, addCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[0].startDate, addCarbEntry.startDate) - XCTAssertEqual(objects[0].uuid, addUUID) - XCTAssertEqual(objects[0].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(objects[0].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(objects[0].syncVersion, 1) - XCTAssertEqual(objects[0].userCreatedDate, addCarbEntry.date) - XCTAssertNil(objects[0].userUpdatedDate) - XCTAssertNil(objects[0].userDeletedDate) - XCTAssertEqual(objects[0].operation, .create) - XCTAssertNotNil(objects[0].addedDate) - XCTAssertNotNil(objects[0].supercededDate) - XCTAssertEqual(objects[0].anchorKey, addAnchorKey) - - // Updated object - XCTAssertEqual(objects[1].absorptionTime, replaceCarbEntry.absorptionTime) - XCTAssertEqual(objects[1].createdByCurrentApp, true) - XCTAssertEqual(objects[1].foodType, replaceCarbEntry.foodType) - XCTAssertEqual(objects[1].grams, replaceCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[1].startDate, replaceCarbEntry.startDate) - XCTAssertEqual(objects[1].uuid, updateUUID) - XCTAssertEqual(objects[1].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(objects[1].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(objects[1].syncVersion, 2) - XCTAssertEqual(objects[1].userCreatedDate, addCarbEntry.date) - XCTAssertEqual(objects[1].userUpdatedDate, replaceCarbEntry.date) - XCTAssertNil(objects[1].userDeletedDate) - XCTAssertEqual(objects[1].operation, .update) - XCTAssertNotNil(objects[1].addedDate) - XCTAssertNil(objects[1].supercededDate) - XCTAssertGreaterThan(objects[1].anchorKey, addAnchorKey!) - - DispatchQueue.main.async { - carbStore.getCarbEntries(start: Date().addingTimeInterval(-.minutes(1))) { result in - getCarbEntriesCompletion.fulfill() - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 1) - - // Updated sample - XCTAssertEqual(entries[0].uuid, updateUUID) - XCTAssertEqual(entries[0].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(entries[0].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(entries[0].syncVersion, 2) - XCTAssertEqual(entries[0].startDate, replaceCarbEntry.startDate) - XCTAssertEqual(entries[0].quantity, replaceCarbEntry.quantity) - XCTAssertEqual(entries[0].foodType, replaceCarbEntry.foodType) - XCTAssertEqual(entries[0].absorptionTime, replaceCarbEntry.absorptionTime) - XCTAssertEqual(entries[0].createdByCurrentApp, true) - XCTAssertEqual(entries[0].userCreatedDate, addCarbEntry.date) - XCTAssertEqual(entries[0].userUpdatedDate, replaceCarbEntry.date) - } - } - } - default: - XCTFail("Unexpected handler invocation") - } - } - } - - carbStore.addCarbEntry(addCarbEntry) { (result) in - addCarbEntryCompletion.fulfill() - } - - wait(for: [addHealthStoreHandler, addCarbEntryCompletion, addCarbEntryHandler, updateHealthStoreHandler, updateCarbEntryCompletion, updateCarbEntryHandler, getCarbEntriesCompletion], timeout: 10, enforceOrder: true) - } - - func testAddAndDeleteCarbEntry() { - let addCarbEntry = NewCarbEntry(quantity: HKQuantity(unit: .gram(), doubleValue: 10), startDate: Date(), foodType: "Add", absorptionTime: .hours(3)) - let addHealthStoreHandler = expectation(description: "Add health store handler") - let addCarbEntryCompletion = expectation(description: "Add carb entry completion") - let addCarbEntryHandler = expectation(description: "Add carb entry handler") - let deleteHealthStoreHandler = expectation(description: "Delete health store handler") - let deleteCarbEntryCompletion = expectation(description: "Delete carb entry completion") - let deleteCarbEntryHandler = expectation(description: "Delete carb entry handler") - let getCarbEntriesCompletion = expectation(description: "Get carb entries completion") - - var handlerInvocation = 0 - - var addUUID: UUID? - var addSyncIdentifier: String? - var addAnchorKey: Int64? - - healthStore.setSaveHandler({ (objects, success, error) in - XCTAssertEqual(1, objects.count) - - let sample = objects.first as! HKQuantitySample - - XCTAssertEqual(sample.absorptionTime, addCarbEntry.absorptionTime) - XCTAssertEqual(sample.foodType, addCarbEntry.foodType) - XCTAssertEqual(sample.quantity, addCarbEntry.quantity) - XCTAssertEqual(sample.startDate, addCarbEntry.startDate) - XCTAssertNotNil(sample.syncIdentifier) - XCTAssertEqual(sample.syncVersion, 1) - XCTAssertEqual(sample.userCreatedDate, addCarbEntry.date) - XCTAssertNil(sample.userUpdatedDate) - - addUUID = sample.uuid - addSyncIdentifier = sample.syncIdentifier - - addHealthStoreHandler.fulfill() - }) - - carbStoreHasUpdatedCarbDataHandler = { (carbStore) in - handlerInvocation += 1 - - self.cacheStore.managedObjectContext.performAndWait { - switch handlerInvocation { - case 1: - addCarbEntryHandler.fulfill() - let objects: [CachedCarbObject] = self.cacheStore.managedObjectContext.all() - XCTAssertEqual(objects.count, 1) - - // Added object - XCTAssertEqual(objects[0].absorptionTime, addCarbEntry.absorptionTime) - XCTAssertEqual(objects[0].createdByCurrentApp, true) - XCTAssertEqual(objects[0].foodType, addCarbEntry.foodType) - XCTAssertEqual(objects[0].grams, addCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[0].startDate, addCarbEntry.startDate) - XCTAssertEqual(objects[0].uuid, addUUID) - XCTAssertEqual(objects[0].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(objects[0].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(objects[0].syncVersion, 1) - XCTAssertEqual(objects[0].userCreatedDate, addCarbEntry.date) - XCTAssertNil(objects[0].userUpdatedDate) - XCTAssertNil(objects[0].userDeletedDate) - XCTAssertEqual(objects[0].operation, .create) - XCTAssertNotNil(objects[0].addedDate) - XCTAssertNil(objects[0].supercededDate) - XCTAssertGreaterThan(objects[0].anchorKey, 0) - - addUUID = objects[0].uuid - addSyncIdentifier = objects[0].syncIdentifier - addAnchorKey = objects[0].anchorKey - - self.healthStore.setDeletedObjectsHandler({ (objectType, predicate, success, count, error) in - XCTAssertEqual(objectType, HKObjectType.quantityType(forIdentifier: .dietaryCarbohydrates)) - XCTAssertEqual(predicate.predicateFormat, "UUID == \(addUUID!)") - - deleteHealthStoreHandler.fulfill() - }) - - self.carbStore.deleteCarbEntry(StoredCarbEntry(managedObject: objects[0])) { (result) in - deleteCarbEntryCompletion.fulfill() - } - case 2: - deleteCarbEntryHandler.fulfill() - let objects: [CachedCarbObject] = self.cacheStore.managedObjectContext.all() - XCTAssertEqual(objects.count, 2) - - // Added object, superceded - XCTAssertEqual(objects[0].absorptionTime, addCarbEntry.absorptionTime) - XCTAssertEqual(objects[0].createdByCurrentApp, true) - XCTAssertEqual(objects[0].foodType, addCarbEntry.foodType) - XCTAssertEqual(objects[0].grams, addCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[0].startDate, addCarbEntry.startDate) - XCTAssertEqual(objects[0].uuid, addUUID) - XCTAssertEqual(objects[0].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(objects[0].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(objects[0].syncVersion, 1) - XCTAssertEqual(objects[0].userCreatedDate, addCarbEntry.date) - XCTAssertNil(objects[0].userUpdatedDate) - XCTAssertNil(objects[0].userDeletedDate) - XCTAssertEqual(objects[0].operation, .create) - XCTAssertNotNil(objects[0].addedDate) - XCTAssertNotNil(objects[0].supercededDate) - XCTAssertEqual(objects[0].anchorKey, addAnchorKey) - - // Deleted object - XCTAssertEqual(objects[1].absorptionTime, addCarbEntry.absorptionTime) - XCTAssertEqual(objects[1].createdByCurrentApp, true) - XCTAssertEqual(objects[1].foodType, addCarbEntry.foodType) - XCTAssertEqual(objects[1].grams, addCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[1].startDate, addCarbEntry.startDate) - XCTAssertNil(objects[1].uuid) - XCTAssertEqual(objects[1].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(objects[1].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(objects[1].syncVersion, 1) - XCTAssertEqual(objects[1].userCreatedDate, addCarbEntry.date) - XCTAssertNil(objects[1].userUpdatedDate) - XCTAssertNotNil(objects[1].userDeletedDate) - XCTAssertEqual(objects[1].operation, .delete) - XCTAssertNotNil(objects[1].addedDate) - XCTAssertNil(objects[1].supercededDate) - XCTAssertGreaterThan(objects[1].anchorKey, addAnchorKey!) - - DispatchQueue.main.async { - carbStore.getCarbEntries(start: Date().addingTimeInterval(-.minutes(1))) { result in - getCarbEntriesCompletion.fulfill() - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 0) - } - } - } - default: - XCTFail("Unexpected handler invocation") - } - } - - } - - carbStore.addCarbEntry(addCarbEntry) { (result) in - addCarbEntryCompletion.fulfill() - } - - wait(for: [addHealthStoreHandler, addCarbEntryCompletion, addCarbEntryHandler, deleteHealthStoreHandler, deleteCarbEntryCompletion, deleteCarbEntryHandler, getCarbEntriesCompletion], timeout: 10, enforceOrder: true) - } - - func testAddAndReplaceAndDeleteCarbEntry() { - let addCarbEntry = NewCarbEntry(quantity: HKQuantity(unit: .gram(), doubleValue: 10), startDate: Date(), foodType: "Add", absorptionTime: .hours(3)) - let replaceCarbEntry = NewCarbEntry(quantity: HKQuantity(unit: .gram(), doubleValue: 15), startDate: Date(), foodType: "Replace", absorptionTime: .hours(4)) - let addHealthStoreHandler = expectation(description: "Add health store handler") - let addCarbEntryCompletion = expectation(description: "Add carb entry completion") - let addCarbEntryHandler = expectation(description: "Add carb entry handler") - let updateHealthStoreHandler = expectation(description: "Update health store handler") - let updateCarbEntryCompletion = expectation(description: "Update carb entry completion") - let updateCarbEntryHandler = expectation(description: "Update carb entry handler") - let deleteHealthStoreHandler = expectation(description: "Delete health store handler") - let deleteCarbEntryCompletion = expectation(description: "Delete carb entry completion") - let deleteCarbEntryHandler = expectation(description: "Delete carb entry handler") - let getCarbEntriesCompletion = expectation(description: "Get carb entries completion") - - var handlerInvocation = 0 - - var addUUID: UUID? - var addSyncIdentifier: String? - var addAnchorKey: Int64? - var updateUUID: UUID? - var updateAnchorKey: Int64? - - healthStore.setSaveHandler({ (objects, success, error) in - XCTAssertEqual(1, objects.count) - - let sample = objects.first as! HKQuantitySample - - XCTAssertEqual(sample.absorptionTime, addCarbEntry.absorptionTime) - XCTAssertEqual(sample.foodType, addCarbEntry.foodType) - XCTAssertEqual(sample.quantity, addCarbEntry.quantity) - XCTAssertEqual(sample.startDate, addCarbEntry.startDate) - XCTAssertNotNil(sample.syncIdentifier) - XCTAssertEqual(sample.syncVersion, 1) - XCTAssertEqual(sample.userCreatedDate, addCarbEntry.date) - XCTAssertNil(sample.userUpdatedDate) - - addUUID = sample.uuid - addSyncIdentifier = sample.syncIdentifier - - addHealthStoreHandler.fulfill() - }) - - carbStoreHasUpdatedCarbDataHandler = { (carbStore) in - handlerInvocation += 1 - - self.cacheStore.managedObjectContext.performAndWait { - switch handlerInvocation { - case 1: - addCarbEntryHandler.fulfill() - let objects: [CachedCarbObject] = self.cacheStore.managedObjectContext.all() - XCTAssertEqual(objects.count, 1) - - // Added object - XCTAssertEqual(objects[0].absorptionTime, addCarbEntry.absorptionTime) - XCTAssertEqual(objects[0].createdByCurrentApp, true) - XCTAssertEqual(objects[0].foodType, addCarbEntry.foodType) - XCTAssertEqual(objects[0].grams, addCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[0].startDate, addCarbEntry.startDate) - XCTAssertEqual(objects[0].uuid, addUUID) - XCTAssertEqual(objects[0].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(objects[0].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(objects[0].syncVersion, 1) - XCTAssertEqual(objects[0].userCreatedDate, addCarbEntry.date) - XCTAssertNil(objects[0].userUpdatedDate) - XCTAssertNil(objects[0].userDeletedDate) - XCTAssertEqual(objects[0].operation, .create) - XCTAssertNotNil(objects[0].addedDate) - XCTAssertNil(objects[0].supercededDate) - XCTAssertGreaterThan(objects[0].anchorKey, 0) - - addAnchorKey = objects[0].anchorKey - - self.healthStore.setSaveHandler({ (objects, success, error) in - XCTAssertEqual(1, objects.count) - - let sample = objects.first as! HKQuantitySample - - XCTAssertNotEqual(sample.uuid, addUUID) - XCTAssertEqual(sample.absorptionTime, replaceCarbEntry.absorptionTime) - XCTAssertEqual(sample.foodType, replaceCarbEntry.foodType) - XCTAssertEqual(sample.quantity, replaceCarbEntry.quantity) - XCTAssertEqual(sample.startDate, replaceCarbEntry.startDate) - XCTAssertEqual(sample.syncIdentifier, addSyncIdentifier) - XCTAssertEqual(sample.syncVersion, 2) - XCTAssertEqual(sample.userCreatedDate, addCarbEntry.date) - XCTAssertEqual(sample.userUpdatedDate, replaceCarbEntry.date) - - updateUUID = sample.uuid - - updateHealthStoreHandler.fulfill() - }) - - self.carbStore.replaceCarbEntry(StoredCarbEntry(managedObject: objects[0]), withEntry: replaceCarbEntry) { (result) in - updateCarbEntryCompletion.fulfill() - } - case 2: - updateCarbEntryHandler.fulfill() - let objects: [CachedCarbObject] = self.cacheStore.managedObjectContext.all().sorted { $0.syncVersion! < $1.syncVersion! } - XCTAssertEqual(objects.count, 2) - - // Added object, superceded - XCTAssertEqual(objects[0].absorptionTime, addCarbEntry.absorptionTime) - XCTAssertEqual(objects[0].createdByCurrentApp, true) - XCTAssertEqual(objects[0].foodType, addCarbEntry.foodType) - XCTAssertEqual(objects[0].grams, addCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[0].startDate, addCarbEntry.startDate) - XCTAssertEqual(objects[0].uuid, addUUID) - XCTAssertEqual(objects[0].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(objects[0].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(objects[0].syncVersion, 1) - XCTAssertEqual(objects[0].userCreatedDate, addCarbEntry.date) - XCTAssertNil(objects[0].userUpdatedDate) - XCTAssertNil(objects[0].userDeletedDate) - XCTAssertEqual(objects[0].operation, .create) - XCTAssertNotNil(objects[0].addedDate) - XCTAssertNotNil(objects[0].supercededDate) - XCTAssertEqual(objects[0].anchorKey, addAnchorKey) - - // Updated object - XCTAssertEqual(objects[1].absorptionTime, replaceCarbEntry.absorptionTime) - XCTAssertEqual(objects[1].createdByCurrentApp, true) - XCTAssertEqual(objects[1].foodType, replaceCarbEntry.foodType) - XCTAssertEqual(objects[1].grams, replaceCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[1].startDate, replaceCarbEntry.startDate) - XCTAssertEqual(objects[1].uuid, updateUUID) - XCTAssertEqual(objects[1].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(objects[1].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(objects[1].syncVersion, 2) - XCTAssertEqual(objects[1].userCreatedDate, addCarbEntry.date) - XCTAssertEqual(objects[1].userUpdatedDate, replaceCarbEntry.date) - XCTAssertNil(objects[1].userDeletedDate) - XCTAssertEqual(objects[1].operation, .update) - XCTAssertNotNil(objects[1].addedDate) - XCTAssertNil(objects[1].supercededDate) - XCTAssertGreaterThan(objects[1].anchorKey, addAnchorKey!) - - updateAnchorKey = objects[1].anchorKey - - self.healthStore.setDeletedObjectsHandler({ (objectType, predicate, success, count, error) in - XCTAssertEqual(objectType, HKObjectType.quantityType(forIdentifier: .dietaryCarbohydrates)) - XCTAssertEqual(predicate.predicateFormat, "UUID == \(updateUUID!)") - - deleteHealthStoreHandler.fulfill() - }) - - self.carbStore.deleteCarbEntry(StoredCarbEntry(managedObject: objects[1])) { (result) in - deleteCarbEntryCompletion.fulfill() - } - case 3: - deleteCarbEntryHandler.fulfill() - let objects: [CachedCarbObject] = self.cacheStore.managedObjectContext.all().sorted { $0.syncVersion! < $1.syncVersion! } - XCTAssertEqual(objects.count, 3) - - // Added object, superceded - XCTAssertEqual(objects[0].absorptionTime, addCarbEntry.absorptionTime) - XCTAssertEqual(objects[0].createdByCurrentApp, true) - XCTAssertEqual(objects[0].foodType, addCarbEntry.foodType) - XCTAssertEqual(objects[0].grams, addCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[0].startDate, addCarbEntry.startDate) - XCTAssertEqual(objects[0].uuid, addUUID) - XCTAssertEqual(objects[0].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(objects[0].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(objects[0].syncVersion, 1) - XCTAssertEqual(objects[0].userCreatedDate, addCarbEntry.date) - XCTAssertNil(objects[0].userUpdatedDate) - XCTAssertNil(objects[0].userDeletedDate) - XCTAssertEqual(objects[0].operation, .create) - XCTAssertNotNil(objects[0].addedDate) - XCTAssertNotNil(objects[0].supercededDate) - XCTAssertEqual(objects[0].anchorKey, addAnchorKey) - - // Updated object, superceded - XCTAssertEqual(objects[1].absorptionTime, replaceCarbEntry.absorptionTime) - XCTAssertEqual(objects[1].createdByCurrentApp, true) - XCTAssertEqual(objects[1].foodType, replaceCarbEntry.foodType) - XCTAssertEqual(objects[1].grams, replaceCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[1].startDate, replaceCarbEntry.startDate) - XCTAssertEqual(objects[1].uuid, updateUUID) - XCTAssertEqual(objects[1].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(objects[1].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(objects[1].syncVersion, 2) - XCTAssertEqual(objects[1].userCreatedDate, addCarbEntry.date) - XCTAssertEqual(objects[1].userUpdatedDate, replaceCarbEntry.date) - XCTAssertNil(objects[1].userDeletedDate) - XCTAssertEqual(objects[1].operation, .update) - XCTAssertNotNil(objects[1].addedDate) - XCTAssertNotNil(objects[1].supercededDate) - XCTAssertEqual(objects[1].anchorKey, updateAnchorKey) - - // Deleted object - XCTAssertEqual(objects[2].absorptionTime, replaceCarbEntry.absorptionTime) - XCTAssertEqual(objects[2].createdByCurrentApp, true) - XCTAssertEqual(objects[2].foodType, replaceCarbEntry.foodType) - XCTAssertEqual(objects[2].grams, replaceCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[2].startDate, replaceCarbEntry.startDate) - XCTAssertNil(objects[2].uuid) - XCTAssertEqual(objects[2].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertEqual(objects[2].syncIdentifier, addSyncIdentifier) - XCTAssertEqual(objects[2].syncVersion, 2) - XCTAssertEqual(objects[2].userCreatedDate, addCarbEntry.date) - XCTAssertEqual(objects[2].userUpdatedDate, replaceCarbEntry.date) - XCTAssertNotNil(objects[2].userDeletedDate) - XCTAssertEqual(objects[2].operation, .delete) - XCTAssertNotNil(objects[2].addedDate) - XCTAssertNil(objects[2].supercededDate) - XCTAssertGreaterThan(objects[2].anchorKey, updateAnchorKey!) - - DispatchQueue.main.async { - carbStore.getCarbEntries(start: Date().addingTimeInterval(-.minutes(1))) { result in - getCarbEntriesCompletion.fulfill() - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 0) - } - } - } - default: - XCTFail("Unexpected handler invocation") - } - } - - } - - carbStore.addCarbEntry(addCarbEntry) { (result) in - addCarbEntryCompletion.fulfill() - } - - wait(for: [addHealthStoreHandler, addCarbEntryCompletion, addCarbEntryHandler, updateHealthStoreHandler, updateCarbEntryCompletion, updateCarbEntryHandler, deleteHealthStoreHandler, deleteCarbEntryCompletion, deleteCarbEntryHandler, getCarbEntriesCompletion], timeout: 10, enforceOrder: true) - } - - // MARK: - - - func testGetSyncCarbObjects() { - let firstCarbEntry = NewCarbEntry(quantity: HKQuantity(unit: .gram(), doubleValue: 10), startDate: Date(timeIntervalSinceNow: -1), foodType: "First", absorptionTime: .hours(5)) - let secondCarbEntry = NewCarbEntry(quantity: HKQuantity(unit: .gram(), doubleValue: 20), startDate: Date(), foodType: "Second", absorptionTime: .hours(3)) - let thirdCarbEntry = NewCarbEntry(quantity: HKQuantity(unit: .gram(), doubleValue: 30), startDate: Date(timeIntervalSinceNow: 1), foodType: "Third", absorptionTime: .minutes(30)) - let getSyncCarbObjectsCompletion = expectation(description: "Get sync carb objects completion") - - carbStore.addCarbEntry(firstCarbEntry) { (_) in - DispatchQueue.main.async { - self.carbStore.addCarbEntry(secondCarbEntry) { (_) in - DispatchQueue.main.async { - self.carbStore.addCarbEntry(thirdCarbEntry) { (_) in - DispatchQueue.main.async { - self.carbStore.getSyncCarbObjects(start: Date().addingTimeInterval(-.minutes(1))) { result in - getSyncCarbObjectsCompletion.fulfill() - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let objects): - XCTAssertEqual(objects.count, 3) - - // First - XCTAssertEqual(objects[0].absorptionTime, firstCarbEntry.absorptionTime) - XCTAssertEqual(objects[0].createdByCurrentApp, true) - XCTAssertEqual(objects[0].foodType, firstCarbEntry.foodType) - XCTAssertEqual(objects[0].grams, firstCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[0].startDate, firstCarbEntry.startDate) - XCTAssertNotNil(objects[0].uuid) - XCTAssertEqual(objects[0].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertNotNil(objects[0].syncIdentifier) - XCTAssertEqual(objects[0].syncVersion, 1) - XCTAssertEqual(objects[0].userCreatedDate, firstCarbEntry.date) - XCTAssertNil(objects[0].userUpdatedDate) - XCTAssertNil(objects[0].userDeletedDate) - XCTAssertEqual(objects[0].operation, .create) - XCTAssertNotNil(objects[0].addedDate) - XCTAssertNil(objects[0].supercededDate) - - // Second - XCTAssertEqual(objects[1].absorptionTime, secondCarbEntry.absorptionTime) - XCTAssertEqual(objects[1].createdByCurrentApp, true) - XCTAssertEqual(objects[1].foodType, secondCarbEntry.foodType) - XCTAssertEqual(objects[1].grams, secondCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[1].startDate, secondCarbEntry.startDate) - XCTAssertNotNil(objects[1].uuid) - XCTAssertEqual(objects[1].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertNotNil(objects[1].syncIdentifier) - XCTAssertEqual(objects[1].syncVersion, 1) - XCTAssertEqual(objects[1].userCreatedDate, secondCarbEntry.date) - XCTAssertNil(objects[1].userUpdatedDate) - XCTAssertNil(objects[1].userDeletedDate) - XCTAssertEqual(objects[1].operation, .create) - XCTAssertNotNil(objects[1].addedDate) - XCTAssertNil(objects[1].supercededDate) - - // Third - XCTAssertEqual(objects[2].absorptionTime, thirdCarbEntry.absorptionTime) - XCTAssertEqual(objects[2].createdByCurrentApp, true) - XCTAssertEqual(objects[2].foodType, thirdCarbEntry.foodType) - XCTAssertEqual(objects[2].grams, thirdCarbEntry.quantity.doubleValue(for: .gram())) - XCTAssertEqual(objects[2].startDate, thirdCarbEntry.startDate) - XCTAssertNotNil(objects[2].uuid) - XCTAssertEqual(objects[2].provenanceIdentifier, Bundle.main.bundleIdentifier!) - XCTAssertNotNil(objects[2].syncIdentifier) - XCTAssertEqual(objects[2].syncVersion, 1) - XCTAssertEqual(objects[2].userCreatedDate, thirdCarbEntry.date) - XCTAssertNil(objects[2].userUpdatedDate) - XCTAssertNil(objects[2].userDeletedDate) - XCTAssertEqual(objects[2].operation, .create) - XCTAssertNotNil(objects[2].addedDate) - XCTAssertNil(objects[2].supercededDate) - } - } - } - } - } - } - } - } - - wait(for: [getSyncCarbObjectsCompletion], timeout: 2, enforceOrder: true) - } - - func testSetSyncCarbObjects() { - let carbEntry = NewCarbEntry(quantity: HKQuantity(unit: .gram(), doubleValue: 10), startDate: Date(timeIntervalSinceNow: -1), foodType: "First", absorptionTime: .hours(5)) - let syncCarbObjects = [SyncCarbObject(absorptionTime: .hours(5), - createdByCurrentApp: true, - foodType: "Pizza", - grams: 45, - startDate: Date(timeIntervalSinceNow: -30), - uuid: UUID(), - provenanceIdentifier: "com.loopkit.Loop", - syncIdentifier: UUID().uuidString, - syncVersion: 4, - userCreatedDate: Date(timeIntervalSinceNow: -35), - userUpdatedDate: Date(timeIntervalSinceNow: -34), - userDeletedDate: nil, - operation: .update, - addedDate: Date(timeIntervalSinceNow: -34), - supercededDate: nil), - SyncCarbObject(absorptionTime: .hours(3), - createdByCurrentApp: false, - foodType: "Pasta", - grams: 25, - startDate: Date(timeIntervalSinceNow: -15), - uuid: UUID(), - provenanceIdentifier: "com.abc.Example", - syncIdentifier: UUID().uuidString, - syncVersion: 1, - userCreatedDate: Date(timeIntervalSinceNow: -16), - userUpdatedDate: nil, - userDeletedDate: nil, - operation: .create, - addedDate: Date(timeIntervalSinceNow: -16), - supercededDate: nil), - SyncCarbObject(absorptionTime: .minutes(30), - createdByCurrentApp: true, - foodType: "Sugar", - grams: 15, - startDate: Date(timeIntervalSinceNow: 0), - uuid: UUID(), - provenanceIdentifier: "com.loopkit.Loop", - syncIdentifier: UUID().uuidString, - syncVersion: 1, - userCreatedDate: Date(timeIntervalSinceNow: -1), - userUpdatedDate: nil, - userDeletedDate: nil, - operation: .create, - addedDate: Date(timeIntervalSinceNow: -1), - supercededDate: nil) - ] - let getCarbEntriesCompletion = expectation(description: "Get carb entries completion") - - // Add a carb entry first, that will be purged when setSyncCarbObjects is invoked - carbStore.addCarbEntry(carbEntry) { (_) in - DispatchQueue.main.async { - self.carbStore.setSyncCarbObjects(syncCarbObjects) { (error) in - XCTAssertNil(error) - DispatchQueue.main.async { - self.carbStore.getCarbEntries(start: Date().addingTimeInterval(-.minutes(1))) { result in - getCarbEntriesCompletion.fulfill() - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let entries): - XCTAssertEqual(entries.count, 3) - for index in 0..<3 { - XCTAssertEqual(entries[index].uuid, syncCarbObjects[index].uuid) - XCTAssertEqual(entries[index].provenanceIdentifier, syncCarbObjects[index].provenanceIdentifier) - XCTAssertEqual(entries[index].syncIdentifier, syncCarbObjects[index].syncIdentifier) - XCTAssertEqual(entries[index].syncVersion, syncCarbObjects[index].syncVersion) - XCTAssertEqual(entries[index].startDate, syncCarbObjects[index].startDate) - XCTAssertEqual(entries[index].quantity, syncCarbObjects[index].quantity) - XCTAssertEqual(entries[index].foodType, syncCarbObjects[index].foodType) - XCTAssertEqual(entries[index].absorptionTime, syncCarbObjects[index].absorptionTime) - XCTAssertEqual(entries[index].createdByCurrentApp, syncCarbObjects[index].createdByCurrentApp) - XCTAssertEqual(entries[index].userCreatedDate, syncCarbObjects[index].userCreatedDate) - XCTAssertEqual(entries[index].userCreatedDate, syncCarbObjects[index].userCreatedDate) - } - } - } - } - } - } - } - - wait(for: [getCarbEntriesCompletion], timeout: 2, enforceOrder: true) - } - - // MARK: - - - private func generateSyncIdentifier() -> String { - return UUID().uuidString - } - -} - -class CarbStoreQueryAnchorTests: XCTestCase { - - var rawValue: CarbStore.QueryAnchor.RawValue = [ - "anchorKey": Int64(123) - ] - - func testInitializerDefault() { - let queryAnchor = CarbStore.QueryAnchor() - XCTAssertEqual(queryAnchor.anchorKey, 0) - } - - func testInitializerRawValue() { - let queryAnchor = CarbStore.QueryAnchor(rawValue: rawValue) - XCTAssertNotNil(queryAnchor) - XCTAssertEqual(queryAnchor?.anchorKey, 123) - } - - func testInitializerRawValueMissingAnchorKey() { - rawValue["anchorKey"] = nil - XCTAssertNil(CarbStore.QueryAnchor(rawValue: rawValue)) - } - - func testInitializerRawValueInvalidAnchorKey() { - rawValue["anchorKey"] = "123" - XCTAssertNil(CarbStore.QueryAnchor(rawValue: rawValue)) - } - - func testInitializerRawValueIgnoresDeprecatedStoredModificationCounter() { - rawValue["storedModificationCounter"] = Int64(456) - let queryAnchor = CarbStore.QueryAnchor(rawValue: rawValue) - XCTAssertNotNil(queryAnchor) - XCTAssertEqual(queryAnchor?.anchorKey, 123) - } - - func testInitializerRawValueUsesDeprecatedStoredModificationCounter() { - rawValue["anchorKey"] = nil - rawValue["storedModificationCounter"] = Int64(456) - let queryAnchor = CarbStore.QueryAnchor(rawValue: rawValue) - XCTAssertNotNil(queryAnchor) - XCTAssertEqual(queryAnchor?.anchorKey, 456) - } - - func testRawValueWithDefault() { - let rawValue = CarbStore.QueryAnchor().rawValue - XCTAssertEqual(rawValue.count, 1) - XCTAssertEqual(rawValue["anchorKey"] as? Int64, Int64(0)) - } - - func testRawValueWithNonDefault() { - var queryAnchor = CarbStore.QueryAnchor() - queryAnchor.anchorKey = 123 - let rawValue = queryAnchor.rawValue - XCTAssertEqual(rawValue.count, 1) - XCTAssertEqual(rawValue["anchorKey"] as? Int64, Int64(123)) - } - -} - -class CarbStoreQueryTests: PersistenceControllerTestCase { - - var carbStore: CarbStore! - var completion: XCTestExpectation! - var queryAnchor: CarbStore.QueryAnchor! - var limit: Int! - - override func setUp() { - super.setUp() - - carbStore = CarbStore( - healthStore: HKHealthStoreMock(), - cacheStore: cacheStore, - cacheLength: .hours(24), - defaultAbsorptionTimes: (fast: .minutes(30), medium: .hours(3), slow: .hours(5)), - observationInterval: 0, - provenanceIdentifier: Bundle.main.bundleIdentifier!) - - let semaphore = DispatchSemaphore(value: 0) - cacheStore.onReady { (error) in - semaphore.signal() - } - semaphore.wait() - - completion = expectation(description: "Completion") - queryAnchor = CarbStore.QueryAnchor() - limit = Int.max - } - - override func tearDown() { - limit = nil - queryAnchor = nil - completion = nil - carbStore = nil - - super.tearDown() - } - - func testEmptyWithDefaultQueryAnchor() { - carbStore.executeCarbQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let updated, let deleted): - XCTAssertEqual(anchor.anchorKey, 0) - XCTAssertEqual(created.count, 0) - XCTAssertEqual(updated.count, 0) - XCTAssertEqual(deleted.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testEmptyWithMissingQueryAnchor() { - queryAnchor = nil - - carbStore.executeCarbQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let updated, let deleted): - XCTAssertEqual(anchor.anchorKey, 0) - XCTAssertEqual(created.count, 0) - XCTAssertEqual(updated.count, 0) - XCTAssertEqual(deleted.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testEmptyWithNonDefaultQueryAnchor() { - queryAnchor.anchorKey = 1 - - carbStore.executeCarbQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let updated, let deleted): - XCTAssertEqual(anchor.anchorKey, 1) - XCTAssertEqual(created.count, 0) - XCTAssertEqual(updated.count, 0) - XCTAssertEqual(deleted.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithUnusedQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - carbStore.executeCarbQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let updated, let deleted): - XCTAssertEqual(anchor.anchorKey, 3) - XCTAssertEqual(created.count, 1) - XCTAssertEqual(created[0].syncIdentifier, syncIdentifiers[0]) - XCTAssertEqual(created[0].syncVersion, 0) - XCTAssertEqual(updated.count, 1) - XCTAssertEqual(updated[0].syncIdentifier, syncIdentifiers[1]) - XCTAssertEqual(updated[0].syncVersion, 1) - XCTAssertEqual(deleted.count, 1) - XCTAssertEqual(deleted[0].syncIdentifier, syncIdentifiers[2]) - XCTAssertEqual(deleted[0].syncVersion, 2) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithStaleQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - queryAnchor.anchorKey = 2 - - carbStore.executeCarbQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let updated, let deleted): - XCTAssertEqual(anchor.anchorKey, 3) - XCTAssertEqual(created.count, 0) - XCTAssertEqual(updated.count, 0) - XCTAssertEqual(deleted.count, 1) - XCTAssertEqual(deleted[0].syncIdentifier, syncIdentifiers[2]) - XCTAssertEqual(deleted[0].syncVersion, 2) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithCurrentQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - queryAnchor.anchorKey = 3 - - carbStore.executeCarbQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let updated, let deleted): - XCTAssertEqual(anchor.anchorKey, 3) - XCTAssertEqual(created.count, 0) - XCTAssertEqual(updated.count, 0) - XCTAssertEqual(deleted.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithLimitZero() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - limit = 0 - - carbStore.executeCarbQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let updated, let deleted): - XCTAssertEqual(anchor.anchorKey, 0) - XCTAssertEqual(created.count, 0) - XCTAssertEqual(updated.count, 0) - XCTAssertEqual(deleted.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithLimitCoveredByData() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - limit = 2 - - carbStore.executeCarbQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let created, let updated, let deleted): - XCTAssertEqual(anchor.anchorKey, 2) - XCTAssertEqual(created.count, 1) - XCTAssertEqual(created[0].syncIdentifier, syncIdentifiers[0]) - XCTAssertEqual(created[0].syncVersion, 0) - XCTAssertEqual(updated.count, 1) - XCTAssertEqual(updated[0].syncIdentifier, syncIdentifiers[1]) - XCTAssertEqual(updated[0].syncVersion, 1) - XCTAssertEqual(deleted.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - private func addData(withSyncIdentifiers syncIdentifiers: [String]) { - cacheStore.managedObjectContext.performAndWait { - for (index, syncIdentifier) in syncIdentifiers.enumerated() { - let cachedCarbObject = CachedCarbObject(context: self.cacheStore.managedObjectContext) - cachedCarbObject.createdByCurrentApp = true - cachedCarbObject.startDate = Date() - cachedCarbObject.uuid = UUID() - cachedCarbObject.syncIdentifier = syncIdentifier - cachedCarbObject.syncVersion = index - cachedCarbObject.operation = Operation(rawValue: index % Operation.allCases.count)! - cachedCarbObject.addedDate = Date() - self.cacheStore.save() - } - } - } - - private func generateSyncIdentifier() -> String { - return UUID().uuidString - } - -} - -class CarbStoreCriticalEventLogTests: PersistenceControllerTestCase { - var carbStore: CarbStore! - var outputStream: MockOutputStream! - var progress: Progress! - - override func setUp() { - super.setUp() - - let objects = [SyncCarbObject(absorptionTime: nil, createdByCurrentApp: true, foodType: nil, grams: 11, startDate: dateFormatter.date(from: "2100-01-02T03:08:00Z")!, uuid: nil, provenanceIdentifier: Bundle.main.bundleIdentifier!, syncIdentifier: nil, syncVersion: nil, userCreatedDate: nil, userUpdatedDate: nil, userDeletedDate: nil, operation: .create, addedDate: dateFormatter.date(from: "2100-01-02T03:08:00Z")!, supercededDate: nil), - SyncCarbObject(absorptionTime: nil, createdByCurrentApp: true, foodType: nil, grams: 12, startDate: dateFormatter.date(from: "2100-01-02T03:10:00Z")!, uuid: nil, provenanceIdentifier: Bundle.main.bundleIdentifier!, syncIdentifier: nil, syncVersion: nil, userCreatedDate: nil, userUpdatedDate: nil, userDeletedDate: nil, operation: .create, addedDate: dateFormatter.date(from: "2100-01-02T03:10:00Z")!, supercededDate: nil), - SyncCarbObject(absorptionTime: nil, createdByCurrentApp: true, foodType: nil, grams: 13, startDate: dateFormatter.date(from: "2100-01-02T03:04:00Z")!, uuid: nil, provenanceIdentifier: Bundle.main.bundleIdentifier!, syncIdentifier: nil, syncVersion: nil, userCreatedDate: nil, userUpdatedDate: nil, userDeletedDate: nil, operation: .create, addedDate: dateFormatter.date(from: "2100-01-02T02:04:00Z")!, supercededDate: dateFormatter.date(from: "2100-01-02T03:04:00Z")!), - SyncCarbObject(absorptionTime: nil, createdByCurrentApp: true, foodType: nil, grams: 14, startDate: dateFormatter.date(from: "2100-01-02T03:06:00Z")!, uuid: nil, provenanceIdentifier: Bundle.main.bundleIdentifier!, syncIdentifier: nil, syncVersion: nil, userCreatedDate: nil, userUpdatedDate: nil, userDeletedDate: nil, operation: .create, addedDate: dateFormatter.date(from: "2100-01-02T03:06:00Z")!, supercededDate: nil), - SyncCarbObject(absorptionTime: nil, createdByCurrentApp: true, foodType: nil, grams: 15, startDate: dateFormatter.date(from: "2100-01-02T03:02:00Z")!, uuid: nil, provenanceIdentifier: Bundle.main.bundleIdentifier!, syncIdentifier: nil, syncVersion: nil, userCreatedDate: nil, userUpdatedDate: nil, userDeletedDate: nil, operation: .create, addedDate: dateFormatter.date(from: "2100-01-02T03:02:00Z")!, supercededDate: nil)] - - carbStore = CarbStore( - healthStore: HKHealthStoreMock(), - cacheStore: cacheStore, - cacheLength: .hours(24), - defaultAbsorptionTimes: (fast: .minutes(30), medium: .hours(3), slow: .hours(5)), - observationInterval: 0, - provenanceIdentifier: Bundle.main.bundleIdentifier!) - - let dispatchGroup = DispatchGroup() - dispatchGroup.enter() - carbStore.setSyncCarbObjects(objects) { error in - XCTAssertNil(error) - dispatchGroup.leave() - } - dispatchGroup.wait() - - outputStream = MockOutputStream() - progress = Progress() - } - - override func tearDown() { - carbStore = nil - - super.tearDown() - } - - func testExportProgressTotalUnitCount() { - switch carbStore.exportProgressTotalUnitCount(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!) { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let progressTotalUnitCount): - XCTAssertEqual(progressTotalUnitCount, 3 * 1) - } - } - - func testExportProgressTotalUnitCountEmpty() { - switch carbStore.exportProgressTotalUnitCount(startDate: dateFormatter.date(from: "2100-01-02T03:00:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:01:00Z")!) { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let progressTotalUnitCount): - XCTAssertEqual(progressTotalUnitCount, 0) - } - } - - func testExport() { - XCTAssertNil(carbStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!, - to: outputStream, - progress: progress)) - XCTAssertEqual(outputStream.string, """ -[ -{"addedDate":"2100-01-02T03:08:00.000Z","anchorKey":1,"createdByCurrentApp":true,"grams":11,"operation":0,"provenanceIdentifier":"com.apple.dt.xctest.tool","startDate":"2100-01-02T03:08:00.000Z"}, -{"addedDate":"2100-01-02T02:04:00.000Z","anchorKey":3,"createdByCurrentApp":true,"grams":13,"operation":0,"provenanceIdentifier":"com.apple.dt.xctest.tool","startDate":"2100-01-02T03:04:00.000Z","supercededDate":"2100-01-02T03:04:00.000Z"}, -{"addedDate":"2100-01-02T03:06:00.000Z","anchorKey":4,"createdByCurrentApp":true,"grams":14,"operation":0,"provenanceIdentifier":"com.apple.dt.xctest.tool","startDate":"2100-01-02T03:06:00.000Z"} -] -""" - ) - XCTAssertEqual(progress.completedUnitCount, 3 * 1) - } - - func testExportEmpty() { - XCTAssertNil(carbStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:00:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:01:00Z")!, - to: outputStream, - progress: progress)) - XCTAssertEqual(outputStream.string, "[]") - XCTAssertEqual(progress.completedUnitCount, 0) - } - - func testExportCancelled() { - progress.cancel() - XCTAssertEqual(carbStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!, - to: outputStream, - progress: progress) as? CriticalEventLogError, CriticalEventLogError.cancelled) - } - - private let dateFormatter = ISO8601DateFormatter() -} diff --git a/Dependencies/LoopKit/LoopKitTests/CarbValueTests.swift b/Dependencies/LoopKit/LoopKitTests/CarbValueTests.swift deleted file mode 100644 index 60dd59fb4..000000000 --- a/Dependencies/LoopKit/LoopKitTests/CarbValueTests.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// CarbValueTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 5/4/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit - -@testable import LoopKit - -class CarbValueCodableTests: XCTestCase { - func testCodable() throws { - try assertCarbValueCodable(CarbValue(startDate: dateFormatter.date(from: "2020-05-14T12:18:14Z")!, - endDate: dateFormatter.date(from: "2020-05-14T13:18:14Z")!, - quantity: HKQuantity(unit: .gram(), doubleValue: 34.5)), - encodesJSON: """ -{ - "endDate" : "2020-05-14T13:18:14Z", - "quantity" : 34.5, - "quantityUnit" : "g", - "startDate" : "2020-05-14T12:18:14Z" -} -""" - ) - } - - private func assertCarbValueCodable(_ original: CarbValue, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(CarbValue.self, from: data) - XCTAssertEqual(decoded, original) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() -} diff --git a/Dependencies/LoopKit/LoopKitTests/CollectionTests.swift b/Dependencies/LoopKit/LoopKitTests/CollectionTests.swift deleted file mode 100644 index 50becc4f8..000000000 --- a/Dependencies/LoopKit/LoopKitTests/CollectionTests.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// CollectionTests.swift -// LoopKitTests -// -// Created by Pete Schwamb on 9/2/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import LoopKit - - -class CollectionTests: XCTestCase { - - func testChunkedWithEmptyArray() { - let result = [].chunked(into: 5) - XCTAssertTrue(result.isEmpty) - } - - func testChunkedWithArrayEvenMultipleOfChunkSize() { - let result = [1,2,3,4].chunked(into: 2) - XCTAssertEqual([[1,2], [3,4]], result) - } - - func testArrayChunkedWithModuloRemainder() { - let result = [1,2,3].chunked(into: 2) - XCTAssertEqual([[1,2], [3]], result) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/CorrectionRangeOverridesTests.swift b/Dependencies/LoopKit/LoopKitTests/CorrectionRangeOverridesTests.swift deleted file mode 100644 index 66f819758..000000000 --- a/Dependencies/LoopKit/LoopKitTests/CorrectionRangeOverridesTests.swift +++ /dev/null @@ -1,158 +0,0 @@ -// -// CorrectionRangeOverridesTests.swift -// LoopKitTests -// -// Created by Nathaniel Hamming on 2021-03-12. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit - -@testable import LoopKit - -class CorrectionRangeOverridesTests: XCTestCase { - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() - - func testInitializerDouble() throws { - let unit = HKUnit.milligramsPerDeciliter - let correctionRangeOverrides = CorrectionRangeOverrides( - preMeal: DoubleRange(minValue: 75, maxValue: 90), - workout: DoubleRange(minValue: 80, maxValue: 100), - unit: unit) - - var expectedRanges: [CorrectionRangeOverrides.Preset: ClosedRange] = [:] - expectedRanges[.preMeal] = DoubleRange(minValue: 75, maxValue: 90).quantityRange(for: unit) - expectedRanges[.workout] = DoubleRange(minValue: 80, maxValue: 100).quantityRange(for: unit) - - XCTAssertEqual(correctionRangeOverrides.ranges, expectedRanges) - XCTAssertEqual(correctionRangeOverrides.preMeal, expectedRanges[.preMeal]) - XCTAssertEqual(correctionRangeOverrides.workout, expectedRanges[.workout]) - } - - func testInitializerGlucoseRange() throws { - let unit = HKUnit.milligramsPerDeciliter - let correctionRangeOverrides = CorrectionRangeOverrides( - preMeal: GlucoseRange(minValue: 75, maxValue: 90, unit: unit), - workout: GlucoseRange(minValue: 80, maxValue: 100, unit: unit)) - - var expectedRanges: [CorrectionRangeOverrides.Preset: ClosedRange] = [:] - expectedRanges[.preMeal] = DoubleRange(minValue: 75, maxValue: 90).quantityRange(for: unit) - expectedRanges[.workout] = DoubleRange(minValue: 80, maxValue: 100).quantityRange(for: unit) - - XCTAssertEqual(correctionRangeOverrides.ranges, expectedRanges) - XCTAssertEqual(correctionRangeOverrides.preMeal, expectedRanges[.preMeal]) - XCTAssertEqual(correctionRangeOverrides.workout, expectedRanges[.workout]) - } - - func testInitializerQuantity() throws { - let unit = HKUnit.millimolesPerLiter - let correctionRangeOverrides = CorrectionRangeOverrides( - preMeal: DoubleRange(minValue: 4.0, maxValue: 5.0).quantityRange(for: unit), - workout: DoubleRange(minValue: 4.5, maxValue: 6.0).quantityRange(for: unit)) - - var expectedRanges: [CorrectionRangeOverrides.Preset: ClosedRange] = [:] - expectedRanges[.preMeal] = DoubleRange(minValue: 4.0, maxValue: 5.0).quantityRange(for: unit) - expectedRanges[.workout] = DoubleRange(minValue: 4.5, maxValue: 6.0).quantityRange(for: unit) - - XCTAssertEqual(correctionRangeOverrides.ranges, expectedRanges) - XCTAssertEqual(correctionRangeOverrides.preMeal, expectedRanges[.preMeal]) - XCTAssertEqual(correctionRangeOverrides.workout, expectedRanges[.workout]) - } - - func testPresetTitle() throws { - XCTAssertEqual(CorrectionRangeOverrides.Preset.preMeal.title, "Pre-Meal") - XCTAssertEqual(CorrectionRangeOverrides.Preset.workout.title, "Workout") - } - - func testPresetTherapySettings() throws { - XCTAssertEqual(CorrectionRangeOverrides.Preset.preMeal.therapySetting, .preMealCorrectionRangeOverride) - XCTAssertEqual(CorrectionRangeOverrides.Preset.workout.therapySetting, .workoutCorrectionRangeOverride) - } - - let encodedString = """ - { - "preMealRange" : { - "bloodGlucoseUnit" : "mg/dL", - "range" : { - "maxValue" : 90, - "minValue" : 75 - } - }, - "workoutRange" : { - "bloodGlucoseUnit" : "mg/dL", - "range" : { - "maxValue" : 100, - "minValue" : 80 - } - } - } - """ - - func testEncoding() throws { - let correctionRangeOverrides = CorrectionRangeOverrides( - preMeal: DoubleRange(minValue: 75, maxValue: 90), - workout: DoubleRange(minValue: 80, maxValue: 100), - unit: .milligramsPerDeciliter) - let data = try encoder.encode(correctionRangeOverrides) - XCTAssertEqual(encodedString, String(data: data, encoding: .utf8)!) - } - - func testDecoding() throws { - let data = encodedString.data(using: .utf8)! - let decoded = try decoder.decode(CorrectionRangeOverrides.self, from: data) - let expected = CorrectionRangeOverrides( - preMeal: DoubleRange(minValue: 75, maxValue: 90), - workout: DoubleRange(minValue: 80, maxValue: 100), - unit: .milligramsPerDeciliter) - - XCTAssertEqual(expected, decoded) - XCTAssertEqual(decoded.ranges, expected.ranges) - } - - func testRawValue() throws { - let unit = HKUnit.milligramsPerDeciliter - let preMealDoubleRange = DoubleRange(minValue: 75, maxValue: 90) - let workoutDoubleRange = DoubleRange(minValue: 80, maxValue: 100) - let correctionRangeOverrides = CorrectionRangeOverrides( - preMeal: preMealDoubleRange, - workout: workoutDoubleRange, - unit: unit) - var expectedRawValue: [String:Any] = [:] - expectedRawValue["preMealTargetRange"] = GlucoseRange(range: preMealDoubleRange, unit: unit).rawValue - expectedRawValue["workoutTargetRange"] = GlucoseRange(range: workoutDoubleRange, unit: unit).rawValue - - let preMealTargetRange = GlucoseRange(rawValue: correctionRangeOverrides.rawValue["preMealTargetRange"] as! GlucoseRange.RawValue) - let expectedPreMealTargetRange = GlucoseRange(rawValue: expectedRawValue["preMealTargetRange"] as! GlucoseRange.RawValue) - XCTAssertEqual(preMealTargetRange, expectedPreMealTargetRange) - - let workoutTargetRange = GlucoseRange(rawValue: correctionRangeOverrides.rawValue["workoutTargetRange"] as! GlucoseRange.RawValue) - let expectedWorkoutTargetRange = GlucoseRange(rawValue: expectedRawValue["workoutTargetRange"] as! GlucoseRange.RawValue) - XCTAssertEqual(workoutTargetRange, expectedWorkoutTargetRange) - } - - func testInitializeFromRawValue() throws { - let unit = HKUnit.milligramsPerDeciliter - var rawValue: [String:Any] = [:] - rawValue["preMealTargetRange"] = GlucoseRange(minValue: 80, maxValue: 100, unit: unit).rawValue - rawValue["workoutTargetRange"] = GlucoseRange(minValue: 110, maxValue: 130, unit: unit).rawValue - - let correctionRangeOverrides = CorrectionRangeOverrides(rawValue: rawValue) - var expectedRanges: [CorrectionRangeOverrides.Preset: ClosedRange] = [:] - expectedRanges[.preMeal] = DoubleRange(minValue: 80, maxValue: 100).quantityRange(for: unit) - expectedRanges[.workout] = DoubleRange(minValue: 110, maxValue: 130).quantityRange(for: unit) - XCTAssertEqual(correctionRangeOverrides?.ranges, expectedRanges) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/CriticalEventLogTests.swift b/Dependencies/LoopKit/LoopKitTests/CriticalEventLogTests.swift deleted file mode 100644 index f63419736..000000000 --- a/Dependencies/LoopKit/LoopKitTests/CriticalEventLogTests.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// CriticalEventLogTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 8/26/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -class MockOutputStream: OutputStream { - var status: Status = .open - var error: Error? = nil - var data: Data = Data() - - override var streamStatus: Status { status } - override var streamError: Error? { error } - - override func write(_ buffer: UnsafePointer, maxLength len: Int) -> Int { - data.append(UnsafeBufferPointer(start: buffer, count: len)) - return len - } - - var string: String { String(data: data, encoding: .utf8)! } -} diff --git a/Dependencies/LoopKit/LoopKitTests/DailyQuantityScheduleTests.swift b/Dependencies/LoopKit/LoopKitTests/DailyQuantityScheduleTests.swift deleted file mode 100644 index 4adcfde62..000000000 --- a/Dependencies/LoopKit/LoopKitTests/DailyQuantityScheduleTests.swift +++ /dev/null @@ -1,153 +0,0 @@ -// -// DailyQuantityScheduleTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 5/1/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import LoopKit - -class DailyQuantityScheduleCodableTests: XCTestCase { - func testCodableDouble() throws { - try assertCodable(DailyQuantitySchedule(unit: .milligramsPerDeciliter, - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 110.3), - RepeatingScheduleValue(startTime: .hours(5), value: 100.5), - RepeatingScheduleValue(startTime: .hours(18), value: 120.5)], - timeZone: TimeZone(identifier: "America/New_York")!)!, - encodesJSON: """ -{ - "unit" : "mg/dL", - "valueSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : 110.3 - }, - { - "startTime" : 18000, - "value" : 100.5 - }, - { - "startTime" : 64800, - "value" : 120.5 - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "America/New_York" - } - } -} -""" - ) - } - - func testCodableDoubleRange() throws { - try assertCodable(DailyQuantitySchedule(unit: .milligramsPerDeciliter, - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: DoubleRange(minValue: 100.2, maxValue: 111.2)), - RepeatingScheduleValue(startTime: .hours(6), value: DoubleRange(minValue: 90.5, maxValue: 101.2)), - RepeatingScheduleValue(startTime: .hours(19), value: DoubleRange(minValue: 110.2, maxValue: 121.2))], - timeZone: TimeZone(identifier: "America/Chicago")!)!, - encodesJSON: """ -{ - "unit" : "mg/dL", - "valueSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : { - "maxValue" : 111.2, - "minValue" : 100.2 - } - }, - { - "startTime" : 21600, - "value" : { - "maxValue" : 101.2, - "minValue" : 90.5 - } - }, - { - "startTime" : 68400, - "value" : { - "maxValue" : 121.2, - "minValue" : 110.2 - } - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "America/Chicago" - } - } -} -""" - ) - } - - func testCodableInt() throws { - try assertCodable(DailyQuantitySchedule(unit: .milligramsPerDeciliter, - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 112), - RepeatingScheduleValue(startTime: .hours(7), value: 102), - RepeatingScheduleValue(startTime: .hours(20), value: 122)], - timeZone: TimeZone(identifier: "America/Los_Angeles")!)!, - encodesJSON: """ -{ - "unit" : "mg/dL", - "valueSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : 112 - }, - { - "startTime" : 25200, - "value" : 102 - }, - { - "startTime" : 72000, - "value" : 122 - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "America/Los_Angeles" - } - } -} -""" - ) - } - - func assertCodable(_ original: DailyQuantitySchedule, encodesJSON string: String) throws where T: RawRepresentable & Codable & Equatable { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(DailyQuantitySchedule.self, from: data) - XCTAssertEqual(decoded, original) - } - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - return encoder - }() - - private let decoder = JSONDecoder() -} - -extension Int: RawRepresentable { - public typealias RawValue = Int - - public init?(rawValue: RawValue) { - self = rawValue - } - - public var rawValue: RawValue { - return self - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/DailyValueScheduleTests.swift b/Dependencies/LoopKit/LoopKitTests/DailyValueScheduleTests.swift deleted file mode 100644 index 9cc8ac62b..000000000 --- a/Dependencies/LoopKit/LoopKitTests/DailyValueScheduleTests.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// DailyValueScheduleTests.swift -// LoopKitTests -// -// Created by Michael Pangburn on 3/27/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import LoopKit - - -final class DailyValueScheduleTests: XCTestCase { - func testZipSingleAlignedValue() { - let lhs = DailyValueSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: 1.0) - ])! - let rhs = DailyValueSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: 1.5) - ])! - let expected = DailyValueSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: (1.0, 1.5)) - ])! - XCTAssert(.zip(lhs, rhs) == expected) - } - - func testZipMultipleAlignedValues() { - let lhs = DailyValueSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: 1.0), - RepeatingScheduleValue(startTime: 3600, value: 2.0), - ])! - let rhs = DailyValueSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: 1.5), - RepeatingScheduleValue(startTime: 3600, value: 3.0) - ])! - let expected = DailyValueSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: (1.0, 1.5)), - RepeatingScheduleValue(startTime: 3600, value: (2.0, 3.0)) - ])! - XCTAssert(.zip(lhs, rhs) == expected) - } - - func testZipStaggeredValues() { - let lhs = DailyValueSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: 1.0), - RepeatingScheduleValue(startTime: 3600, value: 2.0), - ])! - let rhs = DailyValueSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: 1.5), - RepeatingScheduleValue(startTime: 7200, value: 3.0) - ])! - let expected = DailyValueSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: (1.0, 1.5)), - RepeatingScheduleValue(startTime: 3600, value: (2.0, 1.5)), - RepeatingScheduleValue(startTime: 7200, value: (2.0, 3.0)) - ])! - XCTAssert(.zip(lhs, rhs) == expected) - } - - func testZipDifferentCounts() { - let lhs = DailyValueSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: 1.0), - RepeatingScheduleValue(startTime: 3600, value: 2.0), - RepeatingScheduleValue(startTime: 10800, value: 4.0), - ])! - let rhs = DailyValueSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: 1.5), - RepeatingScheduleValue(startTime: 7200, value: 3.0) - ])! - let expected = DailyValueSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: (1.0, 1.5)), - RepeatingScheduleValue(startTime: 3600, value: (2.0, 1.5)), - RepeatingScheduleValue(startTime: 7200, value: (2.0, 3.0)), - RepeatingScheduleValue(startTime: 10800, value: (4.0, 3.0)), - ])! - XCTAssert(.zip(lhs, rhs) == expected) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/DoseEntryTests.swift b/Dependencies/LoopKit/LoopKitTests/DoseEntryTests.swift deleted file mode 100644 index 062869bc5..000000000 --- a/Dependencies/LoopKit/LoopKitTests/DoseEntryTests.swift +++ /dev/null @@ -1,123 +0,0 @@ -// -// DoseEntryTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 5/4/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit - -@testable import LoopKit - -class DoseEntryCodableTests: XCTestCase { - func testCodable() throws { - try assertDoseEntryCodable(DoseEntry(type: .bolus, - startDate: dateFormatter.date(from: "2020-05-14T22:07:19Z")!, - value: 2.5, - unit: .units), - encodesJSON: """ -{ - "endDate" : "2020-05-14T22:07:19Z", - "isMutable" : false, - "manuallyEntered" : false, - "startDate" : "2020-05-14T22:07:19Z", - "type" : "bolus", - "unit" : "U", - "value" : 2.5, - "wasProgrammedByPumpUI" : false -} -""" - ) - } - - func testCodableOptional() throws { - try assertDoseEntryCodable(DoseEntry(type: .tempBasal, - startDate: dateFormatter.date(from: "2020-05-14T22:07:19Z")!, - endDate: dateFormatter.date(from: "2020-05-14T22:37:19Z")!, - value: 1.25, - unit: .unitsPerHour, - deliveredUnits: 0.5, - description: "Temporary Basal", - syncIdentifier: "238E41EA-9576-4981-A1A4-51E10228584F", - scheduledBasalRate: HKQuantity(unit: DoseEntry.unitsPerHour, doubleValue: 1.5), - insulinType: .fiasp, - automatic: true, - manuallyEntered: true, - isMutable: true, - wasProgrammedByPumpUI: true), - encodesJSON: """ -{ - "automatic" : true, - "deliveredUnits" : 0.5, - "description" : "Temporary Basal", - "endDate" : "2020-05-14T22:37:19Z", - "insulinType" : 3, - "isMutable" : true, - "manuallyEntered" : true, - "scheduledBasalRate" : 1.5, - "scheduledBasalRateUnit" : "IU/hr", - "startDate" : "2020-05-14T22:07:19Z", - "syncIdentifier" : "238E41EA-9576-4981-A1A4-51E10228584F", - "type" : "tempBasal", - "unit" : "U/hour", - "value" : 1.25, - "wasProgrammedByPumpUI" : true -} -""" - ) - } - - private func assertDoseEntryCodable(_ original: DoseEntry, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(DoseEntry.self, from: data) - XCTAssertEqual(decoded, original) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() -} - -class DoseEntryRawRepresentableTests: XCTestCase { - func testDoseEntryRawRepresentable() { - let original = DoseEntry(type: .bolus, - startDate: Date(), - value: 2.5, - unit: .units) - let actual = DoseEntry(rawValue: original.rawValue) - XCTAssertEqual(actual, original) - } - - func testDoseEntryRawRepresentableOptional() { - let original = DoseEntry(type: .tempBasal, - startDate: Date(), - endDate: Date().addingTimeInterval(.minutes(30)), - value: 1.25, - unit: .unitsPerHour, - deliveredUnits: 0.5, - description: "Temporary Basal", - syncIdentifier: UUID().uuidString, - scheduledBasalRate: HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.5), - insulinType: .fiasp, - automatic: true, - manuallyEntered: true, - isMutable: true, - wasProgrammedByPumpUI: true) - let actual = DoseEntry(rawValue: original.rawValue) - XCTAssertEqual(actual, original) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/DoseProgressTests.swift b/Dependencies/LoopKit/LoopKitTests/DoseProgressTests.swift deleted file mode 100644 index 9bf4e9d57..000000000 --- a/Dependencies/LoopKit/LoopKitTests/DoseProgressTests.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// DoseProgressTests.swift -// LoopKitTests -// -// Created by Nathaniel Hamming on 2020-11-25. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import LoopKit - -class DoseProgressTests: XCTestCase { - - func testIsCompleted() { - var doseProgress = DoseProgress(deliveredUnits: 0, percentComplete: 0) - XCTAssertFalse(doseProgress.isComplete) - - doseProgress = DoseProgress(deliveredUnits: 0, percentComplete: 0.5) - XCTAssertFalse(doseProgress.isComplete) - - doseProgress = DoseProgress(deliveredUnits: 0, percentComplete: 0.9999999999999999) // less than ulpOfOne from 1 - XCTAssertTrue(doseProgress.isComplete) - - doseProgress = DoseProgress(deliveredUnits: 0, percentComplete: 1) - XCTAssertTrue(doseProgress.isComplete) - - doseProgress = DoseProgress(deliveredUnits: 0, percentComplete: 2) - XCTAssertTrue(doseProgress.isComplete) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/DoseStoreTests.swift b/Dependencies/LoopKit/LoopKitTests/DoseStoreTests.swift deleted file mode 100644 index 09247a82c..000000000 --- a/Dependencies/LoopKit/LoopKitTests/DoseStoreTests.swift +++ /dev/null @@ -1,1576 +0,0 @@ -// -// DoseStoreTests.swift -// LoopKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import XCTest -import CoreData -import HealthKit -@testable import LoopKit - -class DoseStoreTests: PersistenceControllerTestCase { - - func loadReservoirFixture(_ resourceName: String) -> [NewReservoirValue] { - - let fixture: [JSONDictionary] = loadFixture(resourceName) - let dateFormatter = ISO8601DateFormatter.localTimeDate(timeZone: .utcTimeZone) - - return fixture.map { - return NewReservoirValue(startDate: dateFormatter.date(from: $0["date"] as! String)!, unitVolume: $0["amount"] as! Double) - } - } - - func defaultStore(testingDate: Date? = nil) -> DoseStore { - let healthStore = HKHealthStoreMock() - let doseStore = DoseStore( - healthStore: healthStore, - cacheStore: cacheStore, - observationEnabled: false, - insulinModelProvider: StaticInsulinModelProvider(WalshInsulinModel(actionDuration: .hours(4))), - longestEffectDuration: .hours(4), - basalProfile: BasalRateSchedule(rawValue: ["timeZone": -28800, "items": [["value": 0.75, "startTime": 0.0], ["value": 0.8, "startTime": 10800.0], ["value": 0.85, "startTime": 32400.0], ["value": 1.0, "startTime": 68400.0]]]), - insulinSensitivitySchedule: InsulinSensitivitySchedule(rawValue: ["unit": "mg/dL", "timeZone": -28800, "items": [["value": 40.0, "startTime": 0.0], ["value": 35.0, "startTime": 21600.0], ["value": 40.0, "startTime": 57600.0]]]), - syncVersion: 1, - provenanceIdentifier: Bundle.main.bundleIdentifier!, - test_currentDate: testingDate - ) - - let semaphore = DispatchSemaphore(value: 0) - cacheStore.onReady { (error) in - semaphore.signal() - } - semaphore.wait() - - return doseStore - } - - let testingDateFormatter = DateFormatter.descriptionFormatter - - func testingDate(_ input: String) -> Date { - return testingDateFormatter.date(from: input)! - } - - func testEmptyDoseStoreReturnsZeroInsulinOnBoard() { - let doseStore = defaultStore() - - let queryFinishedExpectation = expectation(description: "query finished") - - doseStore.insulinOnBoard(at: Date()) { (result) in - switch result { - case .failure(let error): - XCTFail("Unexpected error: \(error)") - case .success(let value): - XCTAssertEqual(0, value.value) - } - queryFinishedExpectation.fulfill() - } - waitForExpectations(timeout: 3) - } - - func testGetNormalizedDoseEntriesUsingReservoir() { - let now = testingDate("2022-09-05 02:04:00 +0000") - let doseStore = defaultStore(testingDate: now) - - let reservoirReadings = loadReservoirFixture("reservoir_iob_test") - - let storageExpectations = expectation(description: "reservoir store finished") - storageExpectations.expectedFulfillmentCount = reservoirReadings.count + 1 - for reading in reservoirReadings.reversed() { - doseStore.addReservoirValue(reading.unitVolume, at: reading.startDate) { _, _, _, _ in storageExpectations.fulfill() } - } - - let bolusStart = testingDate("2022-09-05 01:49:47 +0000") - let bolusEnd = testingDate("2022-09-05 01:51:19 +0000") - let bolus = DoseEntry(type: .bolus, startDate: bolusStart, endDate: bolusEnd, value: 2.3, unit: .units, isMutable: true) - let pumpEvent = NewPumpEvent(date: bolus.startDate, dose: bolus, raw: Data(hexadecimalString: "0000")!, title: "Bolus 2.3U") - - doseStore.addPumpEvents([pumpEvent], lastReconciliation: testingDate("2022-09-05 01:50:18 +0000")) { error in - storageExpectations.fulfill() - } - - waitForExpectations(timeout: 2) - - let queryFinishedExpectation = expectation(description: "query finished") - - doseStore.insulinOnBoard(at: now) { (result) in - switch result { - case .failure(let error): - XCTFail("Unexpected error: \(error)") - case .success(let value): - XCTAssertEqual(2.25, value.value, accuracy: 0.01) - } - queryFinishedExpectation.fulfill() - } - waitForExpectations(timeout: 3) - } - - func testMutableDosesIncludedInIOB() { - let now = testingDate("2023-01-08 17:11:14 +0000") - let doseStore = defaultStore(testingDate: now) - - let reservoirReadings = loadReservoirFixture("reservoir_for_iob_missing") - - let storageExpectations = expectation(description: "reservoir store finished") - storageExpectations.expectedFulfillmentCount = reservoirReadings.count + 1 - for reading in reservoirReadings.reversed() { - doseStore.addReservoirValue(reading.unitVolume, at: reading.startDate) { _, _, _, _ in storageExpectations.fulfill() } - } - - let lastReconciliation = testingDate("2023-01-08 17:08:27 +0000") - - // NewPumpEvent(date: 2023-01-08 17:04:58 +0000, dose: Optional(LoopKit.DoseEntry(type: LoopKit.DoseType.bolus, startDate: 2023-01-08 17:04:58 +0000, endDate: 2023-01-08 17:08:24 +0000, value: 5.15, unit: LoopKit.DoseUnit.units, deliveredUnits: Optional(5.15), description: nil, insulinType: Optional(LoopKit.InsulinType.novolog), automatic: Optional(false), manuallyEntered: false, syncIdentifier: Optional("464327afd390446786cced682f22448f"), isMutable: true, wasProgrammedByPumpUI: false, scheduledBasalRate: nil)), raw: 16 bytes, type: Optional(LoopKit.PumpEventType.bolus), title: "Bolus", alarmType: nil), - - // NewPumpEvent(date: 2023-01-08 17:02:35 +0000, dose: Optional(LoopKit.DoseEntry(type: LoopKit.DoseType.tempBasal, startDate: 2023-01-08 17:02:35 +0000, endDate: 2023-01-08 17:32:35 +0000, value: 0.575, unit: LoopKit.DoseUnit.unitsPerHour, deliveredUnits: nil, description: nil, insulinType: Optional(LoopKit.InsulinType.novolog), automatic: Optional(true), manuallyEntered: false, syncIdentifier: Optional("61487bd5d34f4ff49a7f0766066e7773"), isMutable: false, wasProgrammedByPumpUI: false, scheduledBasalRate: nil)), raw: 16 bytes, type: Optional(LoopKit.PumpEventType.tempBasal), title: "Temp Basal", alarmType: nil)] - - let bolusStart = testingDate("2023-01-08 17:04:58 +0000") - let bolusEnd = testingDate("2023-01-08 17:08:24 +0000") - let bolus = DoseEntry(type: .bolus, startDate: bolusStart, endDate: bolusEnd, value: 5.15, unit: .units, isMutable: true) - - let tempBasalStart = testingDate("2023-01-08 17:02:35 +0000") - let tempBasalEnd = testingDate("2023-01-08 17:32:35 +0000") - let tempBasal = DoseEntry(type: .tempBasal, startDate: tempBasalStart, endDate: tempBasalEnd, value:0.575, unit: .unitsPerHour, isMutable: false) - - let pumpEvents: [NewPumpEvent] = [ - NewPumpEvent(date: bolus.startDate, dose: bolus, raw: Data(hexadecimalString: "0000")!, title: "Bolus 5.15U"), - NewPumpEvent(date: tempBasal.startDate, dose: tempBasal, raw: Data(hexadecimalString: "0001")!, title: "TempBasal 0.575 U/hr") - ] - - doseStore.addPumpEvents(pumpEvents, lastReconciliation: lastReconciliation) { error in - storageExpectations.fulfill() - } - - waitForExpectations(timeout: 2) - - let queryFinishedExpectation = expectation(description: "query finished") - - doseStore.insulinOnBoard(at: now) { (result) in - switch result { - case .failure(let error): - XCTFail("Unexpected error: \(error)") - case .success(let value): - XCTAssertEqual(5.07, value.value, accuracy: 0.01) - } - queryFinishedExpectation.fulfill() - } - waitForExpectations(timeout: 3) - } - - - func testPumpEventTypeDoseMigration() { - cacheStore.managedObjectContext.performAndWait { - let event = PumpEvent(entity: PumpEvent.entity(), insertInto: cacheStore.managedObjectContext) - - event.date = Date() - event.duration = .minutes(30) - event.unit = .unitsPerHour - event.type = .tempBasal - event.value = 0.5 - event.doseType = nil - - XCTAssertNotNil(event.dose) - XCTAssertEqual(.tempBasal, event.dose!.type) - } - } - - func testDeduplication() { - cacheStore.managedObjectContext.performAndWait { - let bolus1 = PumpEvent(context: cacheStore.managedObjectContext) - - bolus1.date = DateFormatter.descriptionFormatter.date(from: "2018-04-30 02:12:42 +0000") - bolus1.raw = Data(hexadecimalString: "0100a600a6001b006a0c335d12")! - bolus1.type = PumpEventType.bolus - bolus1.dose = DoseEntry(type: .bolus, startDate: bolus1.date!, value: 4.15, unit: .units, syncIdentifier: bolus1.raw?.hexadecimalString) - - let bolus2 = PumpEvent(context: cacheStore.managedObjectContext) - - bolus2.date = DateFormatter.descriptionFormatter.date(from: "2018-04-30 00:00:00 +0000") - bolus2.raw = Data(hexadecimalString: "0100a600a6001b006a0c335d12")! - bolus2.type = PumpEventType.bolus - bolus2.dose = DoseEntry(type: .bolus, startDate: bolus2.date!, value: 0.15, unit: .units, syncIdentifier: bolus1.raw?.hexadecimalString) - - let request: NSFetchRequest = PumpEvent.fetchRequest() - let eventsBeforeSave = try! cacheStore.managedObjectContext.fetch(request) - XCTAssertEqual(2, eventsBeforeSave.count) - - try! cacheStore.managedObjectContext.save() - - let eventsAfterSave = try! cacheStore.managedObjectContext.fetch(request) - XCTAssertEqual(1, eventsAfterSave.count) - } - } - - /// See https://github.com/LoopKit/Loop/issues/853 - func testOutOfOrderDosesSyncedToHealth() { - let formatter = DateFormatter.descriptionFormatter - let f = { (input) in - return formatter.date(from: input)! - } - - // 1. Create a DoseStore - let healthStore = HKHealthStoreMock() - - let doseStoreInitialization = expectation(description: "Expect DoseStore to finish initialization") - - let doseStore = DoseStore( - healthStore: healthStore, - cacheStore: cacheStore, - observationEnabled: false, - insulinModelProvider: StaticInsulinModelProvider(WalshInsulinModel(actionDuration: .hours(4))), - longestEffectDuration: .hours(4), - basalProfile: BasalRateSchedule(rawValue: ["timeZone": -28800, "items": [ // Timezone = -0800 - ["value": 0.75, "startTime": 0.0], // 0000 - Midnight - ["value": 0.8, "startTime": 10800.0], // 0300 - 3am - ["value": 0.85, "startTime": 32400.0], // 0900 - 9am - ["value": 1.0, "startTime": 68400.0]]]), // 1900 - 7pm - insulinSensitivitySchedule: InsulinSensitivitySchedule(rawValue: ["unit": "mg/dL", "timeZone": -28800, "items": [["value": 40.0, "startTime": 0.0], ["value": 35.0, "startTime": 21600.0], ["value": 40.0, "startTime": 57600.0]]]), - syncVersion: 1, - provenanceIdentifier: Bundle.main.bundleIdentifier!, - onReady: { _ in doseStoreInitialization.fulfill() }, - - // Set the current date - test_currentDate: f("2018-12-12 18:07:14 +0000") - ) - - waitForExpectations(timeout: 3) - - // 2. Add a temp basal which has already ended. It should be saved to Health - let pumpEvents1 = [ - NewPumpEvent(date: f("2018-12-12 17:35:58 +0000"), dose: nil, raw: UUID().data, title: "TempBasalPumpEvent(length: 8, rawData: 8 bytes, rateType: MinimedKit.TempBasalPumpEvent.RateType.Absolute, rate: 2.125, timestamp: calendar: gregorian (fixed) year: 2018 month: 12 day: 12 hour: 9 minute: 35 second: 58 isLeapMonth: false )", type: nil), - NewPumpEvent(date: f("2018-12-12 17:35:58 +0000"), dose: DoseEntry(type: .tempBasal, startDate: f("2018-12-12 17:35:58 +0000"), endDate: f("2018-12-12 18:05:58 +0000"), value: 2.125, unit: .unitsPerHour), raw: Data(hexadecimalString: "1601fa23094c12")!, title: "TempBasalDurationPumpEvent(length: 7, rawData: 7 bytes, duration: 30, timestamp: calendar: gregorian (fixed) year: 2018 month: 12 day: 12 hour: 9 minute: 35 second: 58 isLeapMonth: false )", type: .tempBasal) - ] - - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate = f("2018-12-12 17:35:58 +0000") - - let addPumpEvents1 = expectation(description: "add pumpEvents1") - addPumpEvents1.expectedFulfillmentCount = 2 - healthStore.setSaveHandler({ (objects, success, error) in - XCTAssertEqual(1, objects.count) - let sample = objects.first as! HKQuantitySample - XCTAssertEqual(HKInsulinDeliveryReason.basal, sample.insulinDeliveryReason) - XCTAssertNil(error) - addPumpEvents1.fulfill() - }) - let lastBasalEndDateSetExpectation = expectation(description: "last basal end date set") - lastBasalEndDateSetExpectation.assertForOverFulfill = false - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDateDidSet = { - lastBasalEndDateSetExpectation.fulfill() - } - doseStore.addPumpEvents(pumpEvents1, lastReconciliation: Date()) { (error) in - XCTAssertNil(error) - addPumpEvents1.fulfill() - } - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-12-12 18:05:58 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - - - // 3. Add a bolus a little later, which started before the last temp basal ends, but wasn't written to pump history until it completed (x22 pump behavior) - // Even though it is before lastBasalEndDate, it should be saved to HealthKit. - doseStore.insulinDeliveryStore.test_currentDate = f("2018-12-12 18:16:23 +0000") - - let pumpEvents2 = [ - NewPumpEvent(date: f("2018-12-12 18:05:14 +0000"), dose: DoseEntry(type: .bolus, startDate: f("2018-12-12 18:05:14 +0000"), endDate: f("2018-12-12 18:05:14 +0000"), value: 5.0, unit: .units), raw: Data(hexadecimalString: "01323200ce052a0c12")!, title: "BolusNormalPumpEvent(length: 9, rawData: 9 bytes, timestamp: calendar: gregorian (fixed) year: 2018 month: 12 day: 12 hour: 10 minute: 5 second: 14 isLeapMonth: false , unabsorbedInsulinRecord: nil, amount: 5.0, programmed: 5.0, unabsorbedInsulinTotal: 0.0, type: MinimedKit.BolusNormalPumpEvent.BolusType.normal, duration: 0.0, deliveryUnitsPerMinute: 1.5)", type: .bolus) - ] - - let addPumpEvents2 = expectation(description: "add pumpEvents2") - addPumpEvents2.expectedFulfillmentCount = 3 - healthStore.setSaveHandler({ (objects, success, error) in - XCTAssertEqual(1, objects.count) - let sample = objects.first as! HKQuantitySample - XCTAssertEqual(HKInsulinDeliveryReason.bolus, sample.insulinDeliveryReason) - XCTAssertEqual(5.0, sample.quantity.doubleValue(for: .internationalUnit())) - XCTAssertEqual(f("2018-12-12 18:05:14 +0000"), sample.startDate) - XCTAssertNil(error) - addPumpEvents2.fulfill() - }) - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDateDidSet = { - addPumpEvents2.fulfill() - } - doseStore.addPumpEvents(pumpEvents2, lastReconciliation: Date()) { (error) in - XCTAssertNil(error) - addPumpEvents2.fulfill() - } - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-12-12 18:05:58 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - - - // Add the next set of pump events, which haven't completed and shouldn't be saved to HealthKit - doseStore.insulinDeliveryStore.test_currentDate = f("2018-12-12 18:21:22 +0000") - - let pumpEvents3 = [ - NewPumpEvent(date: f("2018-12-12 18:16:31 +0000"), dose: nil, raw: UUID().data, title: "TempBasalPumpEvent(length: 8, rawData: 8 bytes, rateType: MinimedKit.TempBasalPumpEvent.RateType.Absolute, rate: 0.0, timestamp: calendar: gregorian (fixed) year: 2018 month: 12 day: 12 hour: 10 minute: 16 second: 31 isLeapMonth: false )", type: nil), - NewPumpEvent(date: f("2018-12-12 18:16:31 +0000"), dose: DoseEntry(type: .tempBasal, startDate: f("2018-12-12 18:16:31 +0000"), endDate: f("2018-12-12 18:46:31 +0000"), value: 0.0, unit: .unitsPerHour), raw: Data(hexadecimalString: "1601df100a4c12")!, title: "TempBasalDurationPumpEvent(length: 7, rawData: 7 bytes, duration: 30, timestamp: calendar: gregorian (fixed) year: 2018 month: 12 day: 12 hour: 10 minute: 16 second: 31 isLeapMonth: false )", type: .tempBasal), - ] - - let addPumpEvents3 = expectation(description: "add pumpEvents3") - addPumpEvents3.expectedFulfillmentCount = 1 - healthStore.setSaveHandler({ (objects, success, error) in - XCTFail() - }) - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDateDidSet = nil - doseStore.addPumpEvents(pumpEvents3, lastReconciliation: Date()) { (error) in - XCTAssertNil(error) - addPumpEvents3.fulfill() - } - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-12-12 18:05:58 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - } - - /// https://github.com/LoopKit/Loop/issues/852 - func testSplitBasalsSyncedToHealth() { - let formatter = DateFormatter.descriptionFormatter - let f = { (input) in - return formatter.date(from: input)! - } - - // Create a DoseStore - let healthStore = HKHealthStoreMock() - - let doseStoreInitialization = expectation(description: "Expect DoseStore to finish initialization") - - let doseStore = DoseStore( - healthStore: healthStore, - cacheStore: cacheStore, - observationEnabled: false, - insulinModelProvider: StaticInsulinModelProvider(WalshInsulinModel(actionDuration: .hours(4))), - longestEffectDuration: .hours(4), - basalProfile: BasalRateSchedule(rawValue: ["timeZone": -28800, "items": [["value": 0.75, "startTime": 0.0], ["value": 0.8, "startTime": 10800.0], ["value": 0.85, "startTime": 32400.0], ["value": 1.0, "startTime": 68400.0]]]), - insulinSensitivitySchedule: InsulinSensitivitySchedule(rawValue: ["unit": "mg/dL", "timeZone": -28800, "items": [["value": 40.0, "startTime": 0.0], ["value": 35.0, "startTime": 21600.0], ["value": 40.0, "startTime": 57600.0]]]), - syncVersion: 1, - provenanceIdentifier: Bundle.main.bundleIdentifier!, - - onReady: { _ in doseStoreInitialization.fulfill() }, - - // Set the current date (5 minutes later) - test_currentDate: f("2018-11-29 11:04:27 +0000") - ) - - waitForExpectations(timeout: 3) - - doseStore.pumpRecordsBasalProfileStartEvents = false - - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate = f("2018-11-29 10:54:28 +0000") - - // Add a temp basal. It hasn't finished yet, and should not be saved to Health - let pumpEvents1 = [ - NewPumpEvent(date: f("2018-11-29 10:59:28 +0000"), dose: nil, raw: UUID().data, title: "TempBasalPumpEvent(length: 8, rawData: 8 bytes, rateType: MinimedKit.TempBasalPumpEvent.RateType.Absolute, rate: 0.3, timestamp: calendar: gregorian (fixed) year: 2018 month: 11 day: 29 hour: 2 minute: 59 second: 28 isLeapMonth: false )", type: nil), - NewPumpEvent(date: f("2018-11-29 10:59:28 +0000"), dose: DoseEntry(type: .tempBasal, startDate: f("2018-11-29 10:59:28 +0000"), endDate: f("2018-11-29 11:29:28 +0000"), value: 0.3, unit: .unitsPerHour), raw: Data(hexadecimalString: "5bffc7cace53e48e87f7cfcb")!, title: "TempBasalDurationPumpEvent(length: 7, rawData: 7 bytes, duration: 30, timestamp: calendar: gregorian (fixed) year: 2018 month: 11 day: 29 hour: 2 minute: 59 second: 28 isLeapMonth: false )", type: .tempBasal) - ] - - let addPumpEvents1 = expectation(description: "add pumpEvents1") - addPumpEvents1.expectedFulfillmentCount = 1 - healthStore.setSaveHandler({ (objects, success, error) in - XCTFail() - }) - doseStore.addPumpEvents(pumpEvents1, lastReconciliation: Date()) { (error) in - XCTAssertNil(error) - addPumpEvents1.fulfill() - } - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-11-29 10:54:28 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - XCTAssertEqual(f("2018-11-29 10:59:28 +0000"), doseStore.pumpEventQueryAfterDate) - - // Add the next query of the same pump events (no new data) 5 minutes later. Expect the same result - doseStore.insulinDeliveryStore.test_currentDate = f("2018-11-29 11:09:27 +0000") - - let addPumpEvents2 = expectation(description: "add pumpEvents2") - addPumpEvents2.expectedFulfillmentCount = 1 - healthStore.setSaveHandler({ (objects, success, error) in - XCTFail() - }) - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDateDidSet = { - XCTFail() - } - doseStore.addPumpEvents(pumpEvents1, lastReconciliation: Date()) { (error) in - XCTAssertNil(error) - addPumpEvents2.fulfill() - } - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-11-29 10:54:28 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - XCTAssertEqual(f("2018-11-29 10:59:28 +0000"), doseStore.pumpEventQueryAfterDate) - - // Add the next set of pump events, including the last temp basal change. - // The previous, completed basal entries should be saved to Health - doseStore.insulinDeliveryStore.test_currentDate = f("2018-11-29 11:14:28 +0000") - - let pumpEvents3 = [ - NewPumpEvent(date: f("2018-11-29 11:09:27 +0000"), dose: nil, raw: UUID().data, title: "TempBasalPumpEvent(length: 8, rawData: 8 bytes, rateType: MinimedKit.TempBasalPumpEvent.RateType.Absolute, rate: 0.325, timestamp: calendar: gregorian (fixed) year: 2018 month: 11 day: 29 hour: 3 minute: 9 second: 27 isLeapMonth: false )", type: nil), - NewPumpEvent(date: f("2018-11-29 11:09:27 +0000"), dose: DoseEntry(type: .tempBasal, startDate: f("2018-11-29 11:09:27 +0000"), endDate: f("2018-11-29 11:39:27 +0000"), value: 0.325, unit: .unitsPerHour), raw: Data(hexadecimalString: "5bffca22ce53e48e87f7d624")!, title: "TempBasalDurationPumpEvent(length: 7, rawData: 7 bytes, duration: 30, timestamp: calendar: gregorian (fixed) year: 2018 month: 11 day: 29 hour: 3 minute: 9 second: 27 isLeapMonth: false )", type: .tempBasal) - ] - - let addPumpEvents3 = expectation(description: "add pumpEvents3") - addPumpEvents3.expectedFulfillmentCount = 3 - healthStore.setSaveHandler({ (objects, success, error) in - XCTAssertEqual(3, objects.count) - let basal = objects[0] as! HKQuantitySample - XCTAssertEqual(HKInsulinDeliveryReason.basal, basal.insulinDeliveryReason) - XCTAssertEqual(f("2018-11-29 10:54:28 +0000"), basal.startDate) - XCTAssertEqual(f("2018-11-29 10:59:28 +0000"), basal.endDate) - XCTAssertEqual("BasalRateSchedule 2018-11-29T10:54:28Z 2018-11-29T10:59:28Z", basal.metadata![HKMetadataKeySyncIdentifier] as! String) - let temp1 = objects[1] as! HKQuantitySample - XCTAssertEqual(HKInsulinDeliveryReason.basal, temp1.insulinDeliveryReason) - XCTAssertEqual(f("2018-11-29 10:59:28 +0000"), temp1.startDate) - XCTAssertEqual(f("2018-11-29 11:00:00 +0000"), temp1.endDate) - XCTAssertEqual("5bffc7cace53e48e87f7cfcb 1/2", temp1.metadata![HKMetadataKeySyncIdentifier] as! String) - XCTAssertEqual(0.003, temp1.quantity.doubleValue(for: .internationalUnit()), accuracy: 0.01) - let temp2 = objects[2] as! HKQuantitySample - XCTAssertEqual(HKInsulinDeliveryReason.basal, temp2.insulinDeliveryReason) - XCTAssertEqual(f("2018-11-29 11:00:00 +0000"), temp2.startDate) - XCTAssertEqual(f("2018-11-29 11:09:27 +0000"), temp2.endDate) - XCTAssertEqual("5bffc7cace53e48e87f7cfcb 2/2", temp2.metadata![HKMetadataKeySyncIdentifier] as! String) - XCTAssertEqual(0.047, temp2.quantity.doubleValue(for: .internationalUnit()), accuracy: 0.01) - XCTAssertNil(error) - addPumpEvents3.fulfill() - }) - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDateDidSet = { - addPumpEvents3.fulfill() - } - doseStore.addPumpEvents(pumpEvents3, lastReconciliation: Date()) { (error) in - XCTAssertNil(error) - addPumpEvents3.fulfill() - } - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-11-29 11:09:27 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - XCTAssertEqual(f("2018-11-29 11:09:27 +0000"), doseStore.pumpEventQueryAfterDate) - - // Add the next set of pump events, including the last immutable temp basal cancel - doseStore.insulinDeliveryStore.test_currentDate = f("2018-11-29 11:19:28 +0000") - - let pumpEvents4 = [ - NewPumpEvent(date: f("2018-11-29 11:14:28 +0000"), dose: nil, raw: UUID().data, title: "TempBasalPumpEvent(length: 8, rawData: 8 bytes, rateType: MinimedKit.TempBasalPumpEvent.RateType.Absolute, rate: 0, timestamp: calendar: gregorian (fixed) year: 2018 month: 11 day: 29 hour: 3 minute: 14 second: 28 isLeapMonth: false )", type: nil), - NewPumpEvent(date: f("2018-11-29 11:14:28 +0000"), dose: DoseEntry(type: .tempBasal, startDate: f("2018-11-29 11:14:28 +0000"), endDate: f("2018-11-29 11:14:28 +0000"), value: 0.0, unit: .unitsPerHour), raw: Data(hexadecimalString: "5bffced1ce53e48e87f7e33b")!, title: "TempBasalDurationPumpEvent(length: 7, rawData: 7 bytes, duration: 30, timestamp: calendar: gregorian (fixed) year: 2018 month: 11 day: 29 hour: 3 minute: 14 second: 28 isLeapMonth: false )", type: .tempBasal) - ] - - let addPumpEvents4 = expectation(description: "add pumpEvents4") - addPumpEvents4.expectedFulfillmentCount = 3 - healthStore.setSaveHandler({ (objects, success, error) in - XCTAssertEqual(1, objects.count) - let temp = objects[0] as! HKQuantitySample - XCTAssertEqual(HKInsulinDeliveryReason.basal, temp.insulinDeliveryReason) - XCTAssertEqual(f("2018-11-29 11:09:27 +0000"), temp.startDate) - XCTAssertEqual(f("2018-11-29 11:14:28 +0000"), temp.endDate) - XCTAssertEqual("5bffca22ce53e48e87f7d624", temp.metadata![HKMetadataKeySyncIdentifier] as! String) - XCTAssertEqual(0.05, temp.quantity.doubleValue(for: .internationalUnit()), accuracy: 0.01) - XCTAssertNil(error) - addPumpEvents4.fulfill() - }) - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDateDidSet = { - addPumpEvents4.fulfill() - } - doseStore.addPumpEvents(pumpEvents4, lastReconciliation: Date()) { (error) in - XCTAssertNil(error) - addPumpEvents4.fulfill() - } - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-11-29 11:14:28 +0000"), doseStore.pumpEventQueryAfterDate) - XCTAssertEqual(f("2018-11-29 11:14:28 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - - // Add the final mutable pump event, it should NOT be synced to HealthKit - doseStore.insulinDeliveryStore.test_currentDate = f("2018-11-29 11:24:28 +0000") - - let pumpEvents5 = [ - NewPumpEvent(date: f("2018-11-29 11:14:28 +0000"), dose: DoseEntry(type: .tempBasal, startDate: f("2018-11-29 11:14:28 +0000"), endDate: f("2018-11-29 11:44:28 +0000"), value: 1.0, unit: .unitsPerHour, isMutable: true), raw: Data(hexadecimalString: "e48e87f7e33b5bffced1ce53")!, title: "TempBasalDurationPumpEvent(length: 7, rawData: 7 bytes, duration: 30, timestamp: calendar: gregorian (fixed) year: 2018 month: 11 day: 29 hour: 3 minute: 14 second: 28 isLeapMonth: false )", type: .tempBasal) - ] - - let addPumpEvents5 = expectation(description: "add pumpEvents5") - addPumpEvents5.expectedFulfillmentCount = 2 - healthStore.setSaveHandler({ (objects, success, error) in - XCTFail() - }) - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDateDidSet = { - addPumpEvents5.fulfill() - } - doseStore.addPumpEvents(pumpEvents5, lastReconciliation: Date()) { (error) in - XCTAssertNil(error) - addPumpEvents5.fulfill() - } - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-11-29 11:14:28 +0000"), doseStore.pumpEventQueryAfterDate) - XCTAssertEqual(f("2018-11-29 11:14:28 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - } - - func testAddPumpEventsProgrammedByPumpUI() { - let formatter = DateFormatter.descriptionFormatter - let f = { (input) in - return formatter.date(from: input)! - } - - let doseStoreInitialization = expectation(description: "Expect DoseStore to finish initialization") - - - // 1. Create a DoseStore - let doseStore = DoseStore( - healthStore: HKHealthStoreMock(), - cacheStore: cacheStore, - observationEnabled: false, - insulinModelProvider: StaticInsulinModelProvider(WalshInsulinModel(actionDuration: .hours(4))), - longestEffectDuration: .hours(4), - basalProfile: BasalRateSchedule(rawValue: ["timeZone": -28800, "items": [["value": 0.75, "startTime": 0.0], ["value": 0.8, "startTime": 10800.0], ["value": 0.85, "startTime": 32400.0], ["value": 1.0, "startTime": 37800.0]]]), - insulinSensitivitySchedule: InsulinSensitivitySchedule(rawValue: ["unit": "mg/dL", "timeZone": -28800, "items": [["value": 40.0, "startTime": 0.0], ["value": 35.0, "startTime": 21600.0], ["value": 40.0, "startTime": 57600.0]]]), - syncVersion: 1, - provenanceIdentifier: Bundle.main.bundleIdentifier!, - - onReady: { _ in doseStoreInitialization.fulfill() }, - - // Set the current date - test_currentDate: f("2018-12-12 18:07:14 +0000") - ) - waitForExpectations(timeout: 3) - - - // 2. Add a temp basal which has already ended. It should persist in InsulinDeliveryStore. - let pumpEvents1 = [ - NewPumpEvent(date: f("2018-12-12 17:35:00 +0000"), dose: nil, raw: UUID().data, title: "TempBasalPumpEvent(length: 8, rawData: 8 bytes, rateType: MinimedKit.TempBasalPumpEvent.RateType.Absolute, rate: 2.125, timestamp: calendar: gregorian (fixed) year: 2018 month: 12 day: 12 hour: 9 minute: 35 second: 0 isLeapMonth: false )", type: nil), - NewPumpEvent(date: f("2018-12-12 17:35:00 +0000"), dose: DoseEntry(type: .tempBasal, startDate: f("2018-12-12 17:35:00 +0000"), endDate: f("2018-12-12 18:05:00 +0000"), value: 2.125, unit: .unitsPerHour, wasProgrammedByPumpUI: true), raw: Data(hexadecimalString: "1601fa23094c12")!, title: "TempBasalDurationPumpEvent(length: 7, rawData: 7 bytes, duration: 30, timestamp: calendar: gregorian (fixed) year: 2018 month: 12 day: 12 hour: 9 minute: 35 second: 0 isLeapMonth: false )", type: .tempBasal) - ] - - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate = f("2018-12-12 17:35:00 +0000") - doseStore.insulinDeliveryStore.test_currentDate = f("2018-12-12 18:07:14 +0000") - - let addPumpEvents1 = expectation(description: "addPumpEvents1") - addPumpEvents1.expectedFulfillmentCount = 2 - doseStore.addPumpEvents(pumpEvents1, lastReconciliation: Date()) { (error) in - XCTAssertNil(error) - doseStore.insulinDeliveryStore.getDoseEntries { result in - switch result { - case .failure: - XCTFail() - case .success(let doseEntries): - XCTAssertEqual(doseEntries.count, 1) - XCTAssertEqual(doseEntries[0].type, .tempBasal) - XCTAssertEqual(doseEntries[0].startDate, f("2018-12-12 17:35:00 +0000")) - XCTAssertEqual(doseEntries[0].endDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[0].value, 2.125) - XCTAssertEqual(doseEntries[0].deliveredUnits, 1.05) - XCTAssertEqual(doseEntries[0].syncIdentifier, "1601fa23094c12") - XCTAssertEqual(doseEntries[0].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[0].isMutable) - } - addPumpEvents1.fulfill(); - } - doseStore.insulinDeliveryStore.getDoseEntries(includeMutable: true) { result in - switch result { - case .failure: - XCTFail() - case .success(let doseEntries): - XCTAssertEqual(doseEntries.count, 1) - XCTAssertEqual(doseEntries[0].type, .tempBasal) - XCTAssertEqual(doseEntries[0].startDate, f("2018-12-12 17:35:00 +0000")) - XCTAssertEqual(doseEntries[0].endDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[0].value, 2.125) - XCTAssertEqual(doseEntries[0].deliveredUnits, 1.05) - XCTAssertEqual(doseEntries[0].syncIdentifier, "1601fa23094c12") - XCTAssertEqual(doseEntries[0].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[0].isMutable) - XCTAssertTrue(doseEntries[0].wasProgrammedByPumpUI) - } - addPumpEvents1.fulfill(); - } - } - - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-12-12 18:05:00 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - - } - - func testBasalInsertionBetweenTempBasals() { - - - let start = testingDate("2018-12-12 17:00:00 +0000") - let now = start.addingTimeInterval(.minutes(20)) - - let doseStore = defaultStore(testingDate: now) - - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate = start - - - // 2. Add a temp basal which has already ended. It should persist in InsulinDeliveryStore. - let pumpEvents1 = [ - NewPumpEvent( - date: start, - dose: DoseEntry( - type: .tempBasal, - startDate: start, - endDate: start.addingTimeInterval(.minutes(5)), - value: 1.5, - unit: .unitsPerHour, - automatic: true), - raw: Data(hexadecimalString: "01")!, - title: "First Temp", - type: .tempBasal), - NewPumpEvent( - date: start.addingTimeInterval(.minutes(10)), - dose: DoseEntry( - type: .tempBasal, - startDate: start.addingTimeInterval(.minutes(10)), - endDate: start.addingTimeInterval(.minutes(15)), - value: 1.5, - unit: .unitsPerHour, - automatic: true), - raw: Data(hexadecimalString: "02")!, - title: "Second Temp", - type: .tempBasal) - ] - - let addPumpEvents = expectation(description: "addPumpEvents") - doseStore.addPumpEvents(pumpEvents1, lastReconciliation: now) { (error) in - XCTAssertNil(error) - doseStore.insulinDeliveryStore.getDoseEntries(start: start, end: start.addingTimeInterval(.minutes(20))) { result in - switch result { - case .failure: - XCTFail() - case .success(let doseEntries): - XCTAssertEqual(doseEntries.count, 3) - XCTAssertTrue(doseEntries[0].automatic!) - XCTAssertTrue(doseEntries[1].automatic!) - XCTAssertTrue(doseEntries[2].automatic!) - } - addPumpEvents.fulfill(); - } - } - - waitForExpectations(timeout: 3) - - } - - func testAddPumpEventsPurgesMutableDosesFromInsulinDeliveryStore() { - let formatter = DateFormatter.descriptionFormatter - let f = { (input) in - return formatter.date(from: input)! - } - - let doseStoreInitialization = expectation(description: "Expect DoseStore to finish initialization") - - - // 1. Create a DoseStore - let doseStore = DoseStore( - healthStore: HKHealthStoreMock(), - cacheStore: cacheStore, - observationEnabled: false, - insulinModelProvider: StaticInsulinModelProvider(WalshInsulinModel(actionDuration: .hours(4))), - longestEffectDuration: .hours(4), - basalProfile: BasalRateSchedule(rawValue: ["timeZone": -28800, "items": [["value": 0.75, "startTime": 0.0], ["value": 0.8, "startTime": 10800.0], ["value": 0.85, "startTime": 32400.0], ["value": 1.0, "startTime": 37800.0]]]), - insulinSensitivitySchedule: InsulinSensitivitySchedule(rawValue: ["unit": "mg/dL", "timeZone": -28800, "items": [["value": 40.0, "startTime": 0.0], ["value": 35.0, "startTime": 21600.0], ["value": 40.0, "startTime": 57600.0]]]), - syncVersion: 1, - provenanceIdentifier: Bundle.main.bundleIdentifier!, - - onReady: { _ in doseStoreInitialization.fulfill() }, - // Set the current date - test_currentDate: f("2018-12-12 18:07:14 +0000") - ) - - waitForExpectations(timeout: 3) - - // 2. Add a temp basal which has already ended. It should persist in InsulinDeliveryStore. - let pumpEvents1 = [ - NewPumpEvent(date: f("2018-12-12 17:35:00 +0000"), dose: nil, raw: UUID().data, title: "TempBasalPumpEvent(length: 8, rawData: 8 bytes, rateType: MinimedKit.TempBasalPumpEvent.RateType.Absolute, rate: 2.125, timestamp: calendar: gregorian (fixed) year: 2018 month: 12 day: 12 hour: 9 minute: 35 second: 0 isLeapMonth: false )", type: nil), - NewPumpEvent(date: f("2018-12-12 17:35:00 +0000"), dose: DoseEntry(type: .tempBasal, startDate: f("2018-12-12 17:35:00 +0000"), endDate: f("2018-12-12 18:05:00 +0000"), value: 2.125, unit: .unitsPerHour), raw: Data(hexadecimalString: "1601fa23094c12")!, title: "TempBasalDurationPumpEvent(length: 7, rawData: 7 bytes, duration: 30, timestamp: calendar: gregorian (fixed) year: 2018 month: 12 day: 12 hour: 9 minute: 35 second: 0 isLeapMonth: false )", type: .tempBasal) - ] - - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate = f("2018-12-12 17:35:00 +0000") - doseStore.insulinDeliveryStore.test_currentDate = f("2018-12-12 18:07:14 +0000") - - let addPumpEvents1 = expectation(description: "addPumpEvents1") - addPumpEvents1.expectedFulfillmentCount = 2 - doseStore.addPumpEvents(pumpEvents1, lastReconciliation: Date()) { (error) in - XCTAssertNil(error) - doseStore.insulinDeliveryStore.getDoseEntries { result in - switch result { - case .failure: - XCTFail() - case .success(let doseEntries): - XCTAssertEqual(doseEntries.count, 1) - XCTAssertEqual(doseEntries[0].type, .tempBasal) - XCTAssertEqual(doseEntries[0].startDate, f("2018-12-12 17:35:00 +0000")) - XCTAssertEqual(doseEntries[0].endDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[0].value, 2.125) - XCTAssertEqual(doseEntries[0].deliveredUnits, 1.05) - XCTAssertEqual(doseEntries[0].syncIdentifier, "1601fa23094c12") - XCTAssertEqual(doseEntries[0].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[0].isMutable) - } - addPumpEvents1.fulfill(); - } - doseStore.insulinDeliveryStore.getDoseEntries(includeMutable: true) { result in - switch result { - case .failure: - XCTFail() - case .success(let doseEntries): - XCTAssertEqual(doseEntries.count, 1) - XCTAssertEqual(doseEntries[0].type, .tempBasal) - XCTAssertEqual(doseEntries[0].startDate, f("2018-12-12 17:35:00 +0000")) - XCTAssertEqual(doseEntries[0].endDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[0].value, 2.125) - XCTAssertEqual(doseEntries[0].deliveredUnits, 1.05) - XCTAssertEqual(doseEntries[0].syncIdentifier, "1601fa23094c12") - XCTAssertEqual(doseEntries[0].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[0].isMutable) - } - addPumpEvents1.fulfill(); - } - } - - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-12-12 18:05:00 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - - // 3. Add a mutable temp basal. It should persist in InsulinDeliveryStore. - let pumpEvents2 = [ - NewPumpEvent(date: f("2018-12-12 18:05:00 +0000"), dose: DoseEntry(type: .tempBasal, startDate: f("2018-12-12 18:05:00 +0000"), endDate: f("2018-12-12 18:25:00 +0000"), value: 1.375, unit: .unitsPerHour, isMutable: true, wasProgrammedByPumpUI: true), raw: Data(hexadecimalString: "3094c121601fa2")!, title: "TempBasalDurationPumpEvent(length: 7, rawData: 7 bytes, duration: 30, timestamp: calendar: gregorian (fixed) year: 2018 month: 12 day: 12 hour: 10 minute: 05 second: 0 isLeapMonth: false )", type: .tempBasal) - ] - - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate = f("2018-12-12 18:05:00 +0000") - doseStore.insulinDeliveryStore.test_currentDate = f("2018-12-12 18:07:14 +0000") - - let addPumpEvents2 = expectation(description: "addPumpEvents2") - addPumpEvents2.expectedFulfillmentCount = 2 - doseStore.addPumpEvents(pumpEvents2, lastReconciliation: Date()) { (error) in - XCTAssertNil(error) - doseStore.insulinDeliveryStore.getDoseEntries { result in - switch result { - case .failure: - XCTFail() - case .success(let doseEntries): - XCTAssertEqual(doseEntries.count, 1) - XCTAssertEqual(doseEntries[0].type, .tempBasal) - XCTAssertEqual(doseEntries[0].startDate, f("2018-12-12 17:35:00 +0000")) - XCTAssertEqual(doseEntries[0].endDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[0].value, 2.125) - XCTAssertEqual(doseEntries[0].deliveredUnits, 1.05) - XCTAssertEqual(doseEntries[0].syncIdentifier, "1601fa23094c12") - XCTAssertEqual(doseEntries[0].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[0].isMutable) - XCTAssertFalse(doseEntries[0].wasProgrammedByPumpUI) - } - addPumpEvents2.fulfill(); - } - doseStore.insulinDeliveryStore.getDoseEntries(includeMutable: true) { result in - switch result { - case .failure: - XCTFail() - case .success(let doseEntries): - XCTAssertEqual(doseEntries.count, 2) - XCTAssertEqual(doseEntries[0].type, .tempBasal) - XCTAssertEqual(doseEntries[0].startDate, f("2018-12-12 17:35:00 +0000")) - XCTAssertEqual(doseEntries[0].endDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[0].value, 2.125) - XCTAssertEqual(doseEntries[0].deliveredUnits, 1.05) - XCTAssertEqual(doseEntries[0].syncIdentifier, "1601fa23094c12") - XCTAssertEqual(doseEntries[0].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[0].isMutable) - XCTAssertEqual(doseEntries[1].type, .tempBasal) - XCTAssertEqual(doseEntries[1].startDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[1].endDate, f("2018-12-12 18:25:00 +0000")) - XCTAssertEqual(doseEntries[1].value, 1.375) - XCTAssertNil(doseEntries[1].deliveredUnits) - XCTAssertEqual(doseEntries[1].syncIdentifier, "3094c121601fa2") - XCTAssertEqual(doseEntries[1].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertTrue(doseEntries[1].isMutable) - XCTAssertTrue(doseEntries[1].wasProgrammedByPumpUI) - } - addPumpEvents2.fulfill(); - } - } - - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-12-12 18:05:00 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - - // 4. Update the mutable temp basal that crossing scheduled basal boundary. It should persist in InsulinDeliveryStore. - let pumpEvents3 = [ - NewPumpEvent(date: f("2018-12-12 18:05:00 +0000"), dose: DoseEntry(type: .tempBasal, startDate: f("2018-12-12 18:05:00 +0000"), endDate: f("2018-12-12 18:35:00 +0000"), value: 0.875, unit: .unitsPerHour, isMutable: true), raw: Data(hexadecimalString: "3094c121601fa2")!, title: "TempBasalDurationPumpEvent(length: 7, rawData: 7 bytes, duration: 30, timestamp: calendar: gregorian (fixed) year: 2018 month: 12 day: 12 hour: 10 minute: 05 second: 0 isLeapMonth: false )", type: .tempBasal) - ] - - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate = f("2018-12-12 18:05:00 +0000") - doseStore.insulinDeliveryStore.test_currentDate = f("2018-12-12 18:07:14 +0000") - - let addPumpEvents3 = expectation(description: "addPumpEvents3") - addPumpEvents3.expectedFulfillmentCount = 2 - doseStore.addPumpEvents(pumpEvents3, lastReconciliation: Date()) { (error) in - XCTAssertNil(error) - doseStore.insulinDeliveryStore.getDoseEntries { result in - switch result { - case .failure: - XCTFail() - case .success(let doseEntries): - XCTAssertEqual(doseEntries.count, 1) - XCTAssertEqual(doseEntries[0].type, .tempBasal) - XCTAssertEqual(doseEntries[0].startDate, f("2018-12-12 17:35:00 +0000")) - XCTAssertEqual(doseEntries[0].endDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[0].value, 2.125) - XCTAssertEqual(doseEntries[0].deliveredUnits, 1.05) - XCTAssertEqual(doseEntries[0].syncIdentifier, "1601fa23094c12") - XCTAssertEqual(doseEntries[0].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[0].isMutable) - } - addPumpEvents3.fulfill(); - } - doseStore.insulinDeliveryStore.getDoseEntries(includeMutable: true) { result in - switch result { - case .failure: - XCTFail() - case .success(let doseEntries): - XCTAssertEqual(doseEntries.count, 3) - XCTAssertEqual(doseEntries[0].type, .tempBasal) - XCTAssertEqual(doseEntries[0].startDate, f("2018-12-12 17:35:00 +0000")) - XCTAssertEqual(doseEntries[0].endDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[0].value, 2.125) - XCTAssertEqual(doseEntries[0].deliveredUnits, 1.05) - XCTAssertEqual(doseEntries[0].syncIdentifier, "1601fa23094c12") - XCTAssertEqual(doseEntries[0].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[0].isMutable) - XCTAssertEqual(doseEntries[1].type, .tempBasal) - XCTAssertEqual(doseEntries[1].startDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[1].endDate, f("2018-12-12 18:30:00 +0000")) - XCTAssertEqual(doseEntries[1].value, 0.875) - XCTAssertNil(doseEntries[1].deliveredUnits) - XCTAssertEqual(doseEntries[1].syncIdentifier, "3094c121601fa2 1/2") - XCTAssertEqual(doseEntries[1].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertTrue(doseEntries[1].isMutable) - XCTAssertEqual(doseEntries[2].type, .tempBasal) - XCTAssertEqual(doseEntries[2].startDate, f("2018-12-12 18:30:00 +0000")) - XCTAssertEqual(doseEntries[2].endDate, f("2018-12-12 18:35:00 +0000")) - XCTAssertEqual(doseEntries[2].value, 0.875) - XCTAssertNil(doseEntries[2].deliveredUnits) - XCTAssertEqual(doseEntries[2].syncIdentifier, "3094c121601fa2 2/2") - XCTAssertEqual(doseEntries[2].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0)) - XCTAssertTrue(doseEntries[2].isMutable) - } - addPumpEvents3.fulfill(); - } - } - - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-12-12 18:05:00 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - - // 5. Add a different mutable temp basal that crossing scheduled basal boundary. It should persist in InsulinDeliveryStore. A scheduled basal should be added. - let pumpEvents4 = [ - NewPumpEvent(date: f("2018-12-12 18:15:00 +0000"), dose: DoseEntry(type: .tempBasal, startDate: f("2018-12-12 18:15:00 +0000"), endDate: f("2018-12-12 18:45:00 +0000"), value: 0.5, unit: .unitsPerHour, isMutable: true), raw: Data(hexadecimalString: "121601f3094ca2")!, title: "TempBasalDurationPumpEvent(length: 7, rawData: 7 bytes, duration: 30, timestamp: calendar: gregorian (fixed) year: 2018 month: 12 day: 12 hour: 10 minute: 15 second: 0 isLeapMonth: false )", type: .tempBasal) - ] - - var basalDoseEntry: DoseEntry? = nil - - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate = f("2018-12-12 18:05:00 +0000") - doseStore.insulinDeliveryStore.test_currentDate = f("2018-12-12 18:17:14 +0000") - - let addPumpEvents4 = expectation(description: "addPumpEvents4") - addPumpEvents4.expectedFulfillmentCount = 2 - doseStore.addPumpEvents(pumpEvents4, lastReconciliation: Date()) { (error) in - XCTAssertNil(error) - doseStore.insulinDeliveryStore.getDoseEntries { result in - switch result { - case .failure: - XCTFail() - case .success(let doseEntries): - XCTAssertEqual(doseEntries.count, 2) - XCTAssertEqual(doseEntries[0].type, .tempBasal) - XCTAssertEqual(doseEntries[0].startDate, f("2018-12-12 17:35:00 +0000")) - XCTAssertEqual(doseEntries[0].endDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[0].value, 2.125) - XCTAssertEqual(doseEntries[0].deliveredUnits, 1.05) - XCTAssertEqual(doseEntries[0].syncIdentifier, "1601fa23094c12") - XCTAssertEqual(doseEntries[0].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[0].isMutable) - XCTAssertEqual(doseEntries[1].type, .basal) - XCTAssertEqual(doseEntries[1].startDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[1].endDate, f("2018-12-12 18:15:00 +0000")) - XCTAssertEqual(doseEntries[1].value, 0.15) - XCTAssertNil(doseEntries[1].deliveredUnits) - XCTAssertEqual(doseEntries[1].syncIdentifier, "BasalRateSchedule 2018-12-12T18:05:00Z 2018-12-12T18:15:00Z") - XCTAssertEqual(doseEntries[1].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[1].isMutable) - - basalDoseEntry = doseEntries[1] - } - addPumpEvents4.fulfill(); - } - doseStore.insulinDeliveryStore.getDoseEntries(includeMutable: true) { result in - switch result { - case .failure: - XCTFail() - case .success(let doseEntries): - XCTAssertEqual(doseEntries.count, 4) - XCTAssertEqual(doseEntries[0].type, .tempBasal) - XCTAssertEqual(doseEntries[0].startDate, f("2018-12-12 17:35:00 +0000")) - XCTAssertEqual(doseEntries[0].endDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[0].value, 2.125) - XCTAssertEqual(doseEntries[0].deliveredUnits, 1.05) - XCTAssertEqual(doseEntries[0].syncIdentifier, "1601fa23094c12") - XCTAssertEqual(doseEntries[0].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[0].isMutable) - XCTAssertEqual(doseEntries[1].type, .basal) - XCTAssertEqual(doseEntries[1].startDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[1].endDate, f("2018-12-12 18:15:00 +0000")) - XCTAssertEqual(doseEntries[1].value, 0.15) - XCTAssertNil(doseEntries[1].deliveredUnits) - XCTAssertEqual(doseEntries[1].syncIdentifier, "BasalRateSchedule 2018-12-12T18:05:00Z 2018-12-12T18:15:00Z") - XCTAssertEqual(doseEntries[1].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[1].isMutable) - XCTAssertEqual(doseEntries[2].type, .tempBasal) - XCTAssertEqual(doseEntries[2].startDate, f("2018-12-12 18:15:00 +0000")) - XCTAssertEqual(doseEntries[2].endDate, f("2018-12-12 18:30:00 +0000")) - XCTAssertEqual(doseEntries[2].value, 0.5) - XCTAssertNil(doseEntries[2].deliveredUnits) - XCTAssertEqual(doseEntries[2].syncIdentifier, "121601f3094ca2 1/2") - XCTAssertEqual(doseEntries[2].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertTrue(doseEntries[2].isMutable) - XCTAssertEqual(doseEntries[3].type, .tempBasal) - XCTAssertEqual(doseEntries[3].startDate, f("2018-12-12 18:30:00 +0000")) - XCTAssertEqual(doseEntries[3].endDate, f("2018-12-12 18:45:00 +0000")) - XCTAssertEqual(doseEntries[3].value, 0.5) - XCTAssertNil(doseEntries[3].deliveredUnits) - XCTAssertEqual(doseEntries[3].syncIdentifier, "121601f3094ca2 2/2") - XCTAssertEqual(doseEntries[3].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0)) - XCTAssertTrue(doseEntries[3].isMutable) - } - addPumpEvents4.fulfill(); - } - } - - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-12-12 18:15:00 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - - // 6. Deleted scheduled basal dose entry. Tombstones entry so should not be returned again. - let addPumpEvents5 = expectation(description: "addPumpEvents5") - doseStore.deleteDose(basalDoseEntry!) { result in - XCTAssertNil(result) - addPumpEvents5.fulfill(); - } - - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-12-12 18:05:00 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - - // 7. Add an immutable temp basal that crossing scheduled basal boundary. It should persist in InsulinDeliveryStore. - let pumpEvents6 = [ - NewPumpEvent(date: f("2018-12-12 18:25:00 +0000"), dose: DoseEntry(type: .tempBasal, startDate: f("2018-12-12 18:25:00 +0000"), endDate: f("2018-12-12 18:40:00 +0000"), value: 0.75, unit: .unitsPerHour), raw: Data(hexadecimalString: "1201f3094c16a2")!, title: "TempBasalDurationPumpEvent(length: 7, rawData: 7 bytes, duration: 30, timestamp: calendar: gregorian (fixed) year: 2018 month: 12 day: 12 hour: 10 minute: 25 second: 0 isLeapMonth: false )", type: .tempBasal) - ] - - doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate = f("2018-12-12 18:05:00 +0000") - doseStore.insulinDeliveryStore.test_currentDate = f("2018-12-12 18:41:14 +0000") - - let addPumpEvents6 = expectation(description: "addPumpEvents6") - addPumpEvents6.expectedFulfillmentCount = 2 - doseStore.addPumpEvents(pumpEvents6, lastReconciliation: Date()) { (error) in - XCTAssertNil(error) - doseStore.insulinDeliveryStore.getDoseEntries { result in - switch result { - case .failure: - XCTFail() - case .success(let doseEntries): - XCTAssertEqual(doseEntries.count, 4) - XCTAssertEqual(doseEntries[0].type, .tempBasal) - XCTAssertEqual(doseEntries[0].startDate, f("2018-12-12 17:35:00 +0000")) - XCTAssertEqual(doseEntries[0].endDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[0].value, 2.125) - XCTAssertEqual(doseEntries[0].deliveredUnits, 1.05) - XCTAssertEqual(doseEntries[0].syncIdentifier, "1601fa23094c12") - XCTAssertEqual(doseEntries[0].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[0].isMutable) - XCTAssertEqual(doseEntries[1].type, .basal) - XCTAssertEqual(doseEntries[1].startDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[1].endDate, f("2018-12-12 18:25:00 +0000")) - XCTAssertEqual(doseEntries[1].value, 0.3) - XCTAssertNil(doseEntries[1].deliveredUnits) - XCTAssertEqual(doseEntries[1].syncIdentifier, "BasalRateSchedule 2018-12-12T18:05:00Z 2018-12-12T18:25:00Z") - XCTAssertEqual(doseEntries[1].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[1].isMutable) - XCTAssertEqual(doseEntries[2].type, .tempBasal) - XCTAssertEqual(doseEntries[2].startDate, f("2018-12-12 18:25:00 +0000")) - XCTAssertEqual(doseEntries[2].endDate, f("2018-12-12 18:30:00 +0000")) - XCTAssertEqual(doseEntries[2].value, 0.75) - XCTAssertEqual(doseEntries[2].deliveredUnits, 0.06666666666666667) - XCTAssertEqual(doseEntries[2].syncIdentifier, "1201f3094c16a2 1/2") - XCTAssertEqual(doseEntries[2].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[2].isMutable) - XCTAssertEqual(doseEntries[3].type, .tempBasal) - XCTAssertEqual(doseEntries[3].startDate, f("2018-12-12 18:30:00 +0000")) - XCTAssertEqual(doseEntries[3].endDate, f("2018-12-12 18:40:00 +0000")) - XCTAssertEqual(doseEntries[3].value, 0.75) - XCTAssertEqual(doseEntries[3].deliveredUnits, 0.13333333333333333) - XCTAssertEqual(doseEntries[3].syncIdentifier, "1201f3094c16a2 2/2") - XCTAssertEqual(doseEntries[3].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0)) - XCTAssertFalse(doseEntries[3].isMutable) - } - addPumpEvents6.fulfill(); - } - doseStore.insulinDeliveryStore.getDoseEntries(includeMutable: true) { result in - switch result { - case .failure: - XCTFail() - case .success(let doseEntries): - XCTAssertEqual(doseEntries.count, 4) - XCTAssertEqual(doseEntries[0].type, .tempBasal) - XCTAssertEqual(doseEntries[0].startDate, f("2018-12-12 17:35:00 +0000")) - XCTAssertEqual(doseEntries[0].endDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[0].value, 2.125) - XCTAssertEqual(doseEntries[0].deliveredUnits, 1.05) - XCTAssertEqual(doseEntries[0].syncIdentifier, "1601fa23094c12") - XCTAssertEqual(doseEntries[0].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[0].isMutable) - XCTAssertEqual(doseEntries[1].type, .basal) - XCTAssertEqual(doseEntries[1].startDate, f("2018-12-12 18:05:00 +0000")) - XCTAssertEqual(doseEntries[1].endDate, f("2018-12-12 18:25:00 +0000")) - XCTAssertEqual(doseEntries[1].value, 0.3) - XCTAssertNil(doseEntries[1].deliveredUnits) - XCTAssertEqual(doseEntries[1].syncIdentifier, "BasalRateSchedule 2018-12-12T18:05:00Z 2018-12-12T18:25:00Z") - XCTAssertEqual(doseEntries[1].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[1].isMutable) - XCTAssertEqual(doseEntries[2].type, .tempBasal) - XCTAssertEqual(doseEntries[2].startDate, f("2018-12-12 18:25:00 +0000")) - XCTAssertEqual(doseEntries[2].endDate, f("2018-12-12 18:30:00 +0000")) - XCTAssertEqual(doseEntries[2].value, 0.75) - XCTAssertEqual(doseEntries[2].deliveredUnits, 0.06666666666666667) - XCTAssertEqual(doseEntries[2].syncIdentifier, "1201f3094c16a2 1/2") - XCTAssertEqual(doseEntries[2].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.85)) - XCTAssertFalse(doseEntries[2].isMutable) - XCTAssertEqual(doseEntries[3].type, .tempBasal) - XCTAssertEqual(doseEntries[3].startDate, f("2018-12-12 18:30:00 +0000")) - XCTAssertEqual(doseEntries[3].endDate, f("2018-12-12 18:40:00 +0000")) - XCTAssertEqual(doseEntries[3].value, 0.75) - XCTAssertEqual(doseEntries[3].deliveredUnits, 0.13333333333333333) - XCTAssertEqual(doseEntries[3].syncIdentifier, "1201f3094c16a2 2/2") - XCTAssertEqual(doseEntries[3].scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0)) - XCTAssertFalse(doseEntries[3].isMutable) - } - addPumpEvents6.fulfill(); - } - } - - waitForExpectations(timeout: 3) - - XCTAssertEqual(f("2018-12-12 18:40:00 +0000"), doseStore.insulinDeliveryStore.test_lastImmutableBasalEndDate) - } -} - -class DoseStoreQueryAnchorTests: XCTestCase { - - var rawValue: DoseStore.QueryAnchor.RawValue = [ - "modificationCounter": Int64(123) - ] - - func testInitializerDefault() { - let queryAnchor = DoseStore.QueryAnchor() - XCTAssertEqual(queryAnchor.modificationCounter, 0) - } - - func testInitializerRawValue() { - let queryAnchor = DoseStore.QueryAnchor(rawValue: rawValue) - XCTAssertNotNil(queryAnchor) - XCTAssertEqual(queryAnchor?.modificationCounter, 123) - } - - func testInitializerRawValueMissingModificationCounter() { - rawValue["modificationCounter"] = nil - XCTAssertNil(DoseStore.QueryAnchor(rawValue: rawValue)) - } - - func testInitializerRawValueInvalidModificationCounter() { - rawValue["modificationCounter"] = "123" - XCTAssertNil(DoseStore.QueryAnchor(rawValue: rawValue)) - } - - func testRawValueWithDefault() { - let rawValue = DoseStore.QueryAnchor().rawValue - XCTAssertEqual(rawValue.count, 1) - XCTAssertEqual(rawValue["modificationCounter"] as? Int64, Int64(0)) - } - - func testRawValueWithNonDefault() { - var queryAnchor = DoseStore.QueryAnchor() - queryAnchor.modificationCounter = 123 - let rawValue = queryAnchor.rawValue - XCTAssertEqual(rawValue.count, 1) - XCTAssertEqual(rawValue["modificationCounter"] as? Int64, Int64(123)) - } - -} - -class DoseStoreQueryTests: PersistenceControllerTestCase { - - let insulinModel = WalshInsulinModel(actionDuration: .hours(4)) - let basalProfile = BasalRateSchedule(rawValue: ["timeZone": -28800, "items": [["value": 0.75, "startTime": 0.0], ["value": 0.8, "startTime": 10800.0], ["value": 0.85, "startTime": 32400.0], ["value": 1.0, "startTime": 68400.0]]]) - let insulinSensitivitySchedule = InsulinSensitivitySchedule(rawValue: ["unit": "mg/dL", "timeZone": -28800, "items": [["value": 40.0, "startTime": 0.0], ["value": 35.0, "startTime": 21600.0], ["value": 40.0, "startTime": 57600.0]]]) - - var doseStore: DoseStore! - var completion: XCTestExpectation! - var queryAnchor: DoseStore.QueryAnchor! - var limit: Int! - - override func setUp() { - super.setUp() - - doseStore = DoseStore(healthStore: HKHealthStoreMock(), - cacheStore: cacheStore, - observationEnabled: false, - insulinModelProvider: StaticInsulinModelProvider(insulinModel), - longestEffectDuration: insulinModel.effectDuration, - basalProfile: basalProfile, - insulinSensitivitySchedule: insulinSensitivitySchedule, - provenanceIdentifier: Bundle.main.bundleIdentifier!) - - let semaphore = DispatchSemaphore(value: 0) - cacheStore.onReady { (error) in - semaphore.signal() - } - semaphore.wait() - - completion = expectation(description: "Completion") - queryAnchor = DoseStore.QueryAnchor() - limit = Int.max - } - - override func tearDown() { - limit = nil - queryAnchor = nil - completion = nil - doseStore = nil - - super.tearDown() - } - - func testPumpEventEmptyWithDefaultQueryAnchor() { - doseStore.executePumpEventQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 0) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testPumpEventEmptyWithMissingQueryAnchor() { - queryAnchor = nil - - doseStore.executePumpEventQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 0) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testPumpEventEmptyWithNonDefaultQueryAnchor() { - queryAnchor.modificationCounter = 1 - - doseStore.executePumpEventQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 1) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testPumpEventDataWithUnusedQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addPumpEventData(withSyncIdentifiers: syncIdentifiers) - - doseStore.executePumpEventQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(data.count, 3) - for (index, syncIdentifier) in syncIdentifiers.enumerated() { - XCTAssertEqual(data[index].raw?.hexadecimalString, syncIdentifier) - } - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testPumpEventDataWithStaleQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addPumpEventData(withSyncIdentifiers: syncIdentifiers) - - queryAnchor.modificationCounter = 2 - - doseStore.executePumpEventQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(data.count, 1) - XCTAssertEqual(data[0].raw?.hexadecimalString, syncIdentifiers[2]) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testPumpEventDataWithCurrentQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addPumpEventData(withSyncIdentifiers: syncIdentifiers) - - queryAnchor.modificationCounter = 3 - - doseStore.executePumpEventQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testPumpEventDataWithLimitCoveredByData() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addPumpEventData(withSyncIdentifiers: syncIdentifiers) - - limit = 2 - - doseStore.executePumpEventQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 2) - XCTAssertEqual(data.count, 2) - XCTAssertEqual(data[0].raw?.hexadecimalString, syncIdentifiers[0]) - XCTAssertEqual(data[1].raw?.hexadecimalString, syncIdentifiers[1]) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - private func addPumpEventData(withSyncIdentifiers syncIdentifiers: [String]) { - cacheStore.managedObjectContext.performAndWait { - for syncIdentifier in syncIdentifiers { - let pumpEvent = PumpEvent(context: self.cacheStore.managedObjectContext) - pumpEvent.date = Date() - pumpEvent.type = PumpEventType.allCases.randomElement()! - pumpEvent.raw = Data(hexadecimalString: syncIdentifier) - - self.cacheStore.save() - } - } - } - - private func generateSyncIdentifier() -> String { - return UUID().data.hexadecimalString - } - -} - -class DoseStoreCriticalEventLogTests: PersistenceControllerTestCase { - let insulinModel = WalshInsulinModel(actionDuration: .hours(4)) - let basalProfile = BasalRateSchedule(rawValue: ["timeZone": -28800, "items": [["value": 0.75, "startTime": 0.0], ["value": 0.8, "startTime": 10800.0], ["value": 0.85, "startTime": 32400.0], ["value": 1.0, "startTime": 68400.0]]]) - let insulinSensitivitySchedule = InsulinSensitivitySchedule(rawValue: ["unit": "mg/dL", "timeZone": -28800, "items": [["value": 40.0, "startTime": 0.0], ["value": 35.0, "startTime": 21600.0], ["value": 40.0, "startTime": 57600.0]]]) - - var doseStore: DoseStore! - var outputStream: MockOutputStream! - var progress: Progress! - - override func setUp() { - super.setUp() - - let persistedDate = dateFormatter.date(from: "2100-01-02T03:00:00Z")! - let url = URL(string: "http://a.b.com")! - let events = [PersistedPumpEvent(date: dateFormatter.date(from: "2100-01-02T03:08:00Z")!, persistedDate: persistedDate, dose: nil, isUploaded: false, objectIDURL: url, raw: nil, title: nil, type: nil), - PersistedPumpEvent(date: dateFormatter.date(from: "2100-01-02T03:10:00Z")!, persistedDate: persistedDate, dose: nil, isUploaded: false, objectIDURL: url, raw: nil, title: nil, type: nil), - PersistedPumpEvent(date: dateFormatter.date(from: "2100-01-02T03:04:00Z")!, persistedDate: persistedDate, dose: nil, isUploaded: false, objectIDURL: url, raw: nil, title: nil, type: nil), - PersistedPumpEvent(date: dateFormatter.date(from: "2100-01-02T03:06:00Z")!, persistedDate: persistedDate, dose: nil, isUploaded: false, objectIDURL: url, raw: nil, title: nil, type: nil), - PersistedPumpEvent(date: dateFormatter.date(from: "2100-01-02T03:02:00Z")!, persistedDate: persistedDate, dose: nil, isUploaded: false, objectIDURL: url, raw: nil, title: nil, type: nil)] - - doseStore = DoseStore(healthStore: HKHealthStoreMock(), - cacheStore: cacheStore, - observationEnabled: false, - insulinModelProvider: StaticInsulinModelProvider(insulinModel), - longestEffectDuration: insulinModel.effectDuration, - basalProfile: basalProfile, - insulinSensitivitySchedule: insulinSensitivitySchedule, - provenanceIdentifier: Bundle.main.bundleIdentifier!) - XCTAssertNil(doseStore.addPumpEvents(events: events)) - - outputStream = MockOutputStream() - progress = Progress() - } - - override func tearDown() { - doseStore = nil - - super.tearDown() - } - - func testExportProgressTotalUnitCount() { - switch doseStore.exportProgressTotalUnitCount(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!) { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let progressTotalUnitCount): - XCTAssertEqual(progressTotalUnitCount, 3 * 1) - } - } - - func testExportProgressTotalUnitCountEmpty() { - switch doseStore.exportProgressTotalUnitCount(startDate: dateFormatter.date(from: "2100-01-02T03:00:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:01:00Z")!) { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let progressTotalUnitCount): - XCTAssertEqual(progressTotalUnitCount, 0) - } - } - - func testExport() { - XCTAssertNil(doseStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!, - to: outputStream, - progress: progress)) - XCTAssertEqual(outputStream.string, """ -[ -{"createdAt":"2100-01-02T03:00:00.000Z","date":"2100-01-02T03:08:00.000Z","duration":0,"insulinType":0,"modificationCounter":1,"mutable":false,"uploaded":false,"wasProgrammedByPumpUI":false}, -{"createdAt":"2100-01-02T03:00:00.000Z","date":"2100-01-02T03:04:00.000Z","duration":0,"insulinType":0,"modificationCounter":3,"mutable":false,"uploaded":false,"wasProgrammedByPumpUI":false}, -{"createdAt":"2100-01-02T03:00:00.000Z","date":"2100-01-02T03:06:00.000Z","duration":0,"insulinType":0,"modificationCounter":4,"mutable":false,"uploaded":false,"wasProgrammedByPumpUI":false} -] -""" - ) - XCTAssertEqual(progress.completedUnitCount, 3 * 1) - } - - func testExportEmpty() { - XCTAssertNil(doseStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:00:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:01:00Z")!, - to: outputStream, - progress: progress)) - XCTAssertEqual(outputStream.string, "[]") - XCTAssertEqual(progress.completedUnitCount, 0) - } - - func testExportCancelled() { - progress.cancel() - XCTAssertEqual(doseStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!, - to: outputStream, - progress: progress) as? CriticalEventLogError, CriticalEventLogError.cancelled) - } - - private let dateFormatter = ISO8601DateFormatter() -} - -class DoseStoreEffectTests: PersistenceControllerTestCase { - var doseStore: DoseStore! - - var insulinSensitivitySchedule: InsulinSensitivitySchedule { - return InsulinSensitivitySchedule(unit: HKUnit.milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: 0.0, value: 40.0)], timeZone: .currentFixed)! - } - - let dateFormatter = ISO8601DateFormatter.localTimeDate() - - override func setUp() { - super.setUp() - let healthStore = HKHealthStoreMock() - let exponentialInsulinModel: InsulinModel = ExponentialInsulinModelPreset.rapidActingAdult - let startDate = dateFormatter.date(from: "2015-07-13T12:00:00")! - - doseStore = DoseStore( - healthStore: healthStore, - observeHealthKitSamplesFromOtherApps: false, - cacheStore: cacheStore, - observationEnabled: false, - insulinModelProvider: StaticInsulinModelProvider(exponentialInsulinModel), - longestEffectDuration: exponentialInsulinModel.effectDuration, - basalProfile: BasalRateSchedule(dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 1.0)]), - insulinSensitivitySchedule: insulinSensitivitySchedule, - overrideHistory: TemporaryScheduleOverrideHistory(), - provenanceIdentifier: Bundle.main.bundleIdentifier!, - test_currentDate: startDate - ) - } - - override func tearDown() { - doseStore = nil - - super.tearDown() - } - - func loadGlucoseEffectFixture(_ resourceName: String) -> [GlucoseEffect] { - let fixture: [JSONDictionary] = loadFixture(resourceName) - let dateFormatter = ISO8601DateFormatter.localTimeDate() - - return fixture.map { - return GlucoseEffect(startDate: dateFormatter.date(from: $0["date"] as! String)!, quantity: HKQuantity(unit: HKUnit(from: $0["unit"] as! String), doubleValue:$0["amount"] as! Double)) - } - } - - func loadDoseFixture(_ resourceName: String) -> [DoseEntry] { - let fixture: [JSONDictionary] = loadFixture(resourceName) - let dateFormatter = ISO8601DateFormatter.localTimeDate() - - return fixture.compactMap { - guard let unit = DoseUnit(rawValue: $0["unit"] as! String), - let pumpType = PumpEventType(rawValue: $0["type"] as! String), - let type = DoseType(pumpEventType: pumpType) - else { - return nil - } - - var scheduledBasalRate: HKQuantity? = nil - if let scheduled = $0["scheduled"] as? Double { - scheduledBasalRate = HKQuantity(unit: unit.unit, doubleValue: scheduled) - } - - return DoseEntry( - type: type, - startDate: dateFormatter.date(from: $0["start_at"] as! String)!, - endDate: dateFormatter.date(from: $0["end_at"] as! String)!, - value: $0["amount"] as! Double, - unit: unit, - description: $0["description"] as? String, - syncIdentifier: $0["raw"] as? String, - scheduledBasalRate: scheduledBasalRate - ) - } - } - - func injectDoseEvents(from fixture: String) { - let events = loadDoseFixture(fixture).map { - NewPumpEvent( - date: $0.startDate, - dose: $0, - raw: Data(UUID().uuidString.utf8), - title: "", - type: $0.type.pumpEventType - ) - } - - let updateGroup = DispatchGroup() - updateGroup.enter() - doseStore.addPumpEvents(events, lastReconciliation: nil) { error in - if error != nil { - XCTFail("Doses should be added successfully to dose store") - } - updateGroup.leave() - } - updateGroup.wait() - } - - func testGlucoseEffectFromTempBasal() { - injectDoseEvents(from: "basal_dose") - let output = loadGlucoseEffectFixture("effect_from_basal_output_exponential") - - var insulinEffects: [GlucoseEffect]! - let startDate = dateFormatter.date(from: "2015-07-13T12:00:00")! - let updateGroup = DispatchGroup() - updateGroup.enter() - doseStore.getGlucoseEffects(start: startDate) { (result) -> Void in - switch result { - case .failure(let error): - print(error) - XCTFail("Mock should always return success") - case .success(let effects): - insulinEffects = effects - } - updateGroup.leave() - } - updateGroup.wait() - - XCTAssertEqual(output.count, insulinEffects.count) - - for (expected, calculated) in zip(output, insulinEffects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), calculated.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), accuracy: 1.0, String(describing: expected.startDate)) - } - } - - func testGlucoseEffectFromTempBasalWithOldDoses() { - injectDoseEvents(from: "basal_dose_with_expired") - let output = loadGlucoseEffectFixture("effect_from_basal_output_exponential") - - var insulinEffects: [GlucoseEffect]! - let startDate = dateFormatter.date(from: "2015-07-13T12:00:00")! - let updateGroup = DispatchGroup() - updateGroup.enter() - doseStore.getGlucoseEffects(start: startDate) { (result) -> Void in - switch result { - case .failure(let error): - print(error) - XCTFail("Mock should always return success") - case .success(let effects): - insulinEffects = effects - } - updateGroup.leave() - } - updateGroup.wait() - - XCTAssertEqual(output.count, insulinEffects.count) - - for (expected, calculated) in zip(output, insulinEffects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), calculated.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), accuracy: 1.0, String(describing: expected.startDate)) - } - } - - func testGlucoseEffectFromHistory() { - injectDoseEvents(from: "dose_history_with_delivered_units") - let output = loadGlucoseEffectFixture("effect_from_history_exponential_delivered_units_output") - - var insulinEffects: [GlucoseEffect]! - let startDate = dateFormatter.date(from: "2016-01-30T15:40:49")! - let updateGroup = DispatchGroup() - updateGroup.enter() - doseStore.getGlucoseEffects(start: startDate) { (result) -> Void in - switch result { - case .failure(let error): - print(error) - XCTFail("Mock should always return success") - case .success(let effects): - insulinEffects = effects - } - updateGroup.leave() - } - updateGroup.wait() - - XCTAssertEqual(output.count, insulinEffects.count) - - for (expected, calculated) in zip(output, insulinEffects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), calculated.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), accuracy: 1.0, String(describing: expected.startDate)) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/DosingDecisionStoreTests.swift b/Dependencies/LoopKit/LoopKitTests/DosingDecisionStoreTests.swift deleted file mode 100644 index 583d0e54c..000000000 --- a/Dependencies/LoopKit/LoopKitTests/DosingDecisionStoreTests.swift +++ /dev/null @@ -1,1198 +0,0 @@ -// -// DosingDecisionStoreTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 1/6/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class DosingDecisionStorePersistenceTests: PersistenceControllerTestCase, DosingDecisionStoreDelegate { - - var dosingDecisionStore: DosingDecisionStore! - - override func setUp() { - super.setUp() - - dosingDecisionStoreHasUpdatedDosingDecisionDataHandler = nil - dosingDecisionStore = DosingDecisionStore(store: cacheStore, expireAfter: .hours(1)) - dosingDecisionStore.delegate = self - } - - override func tearDown() { - dosingDecisionStore.delegate = nil - dosingDecisionStore = nil - dosingDecisionStoreHasUpdatedDosingDecisionDataHandler = nil - - super.tearDown() - } - - // MARK: - DosingDecisionStoreDelegate - - var dosingDecisionStoreHasUpdatedDosingDecisionDataHandler: ((_ : DosingDecisionStore) -> Void)? - - func dosingDecisionStoreHasUpdatedDosingDecisionData(_ dosingDecisionStore: DosingDecisionStore) { - dosingDecisionStoreHasUpdatedDosingDecisionDataHandler?(dosingDecisionStore) - } - - // MARK: - - - func testStoreDosingDecision() { - let storeDosingDecisionHandler = expectation(description: "Store dosing decision handler") - let storeDosingDecisionCompletion = expectation(description: "Store dosing decision completion") - - var handlerInvocation = 0 - - dosingDecisionStoreHasUpdatedDosingDecisionDataHandler = { dosingDecisionStore in - handlerInvocation += 1 - - switch handlerInvocation { - case 1: - storeDosingDecisionHandler.fulfill() - default: - XCTFail("Unexpected handler invocation") - } - } - - dosingDecisionStore.storeDosingDecision(StoredDosingDecision(reason: "test")) { - storeDosingDecisionCompletion.fulfill() - } - - wait(for: [storeDosingDecisionHandler, storeDosingDecisionCompletion], timeout: 2, enforceOrder: true) - } - - func testStoreDosingDecisionMultiple() { - let storeDosingDecisionHandler1 = expectation(description: "Store dosing decision handler 1") - let storeDosingDecisionHandler2 = expectation(description: "Store dosing decision handler 2") - let storeDosingDecisionCompletion1 = expectation(description: "Store dosing decision completion 1") - let storeDosingDecisionCompletion2 = expectation(description: "Store dosing decision completion 2") - - var handlerInvocation = 0 - - dosingDecisionStoreHasUpdatedDosingDecisionDataHandler = { dosingDecisionStore in - handlerInvocation += 1 - - switch handlerInvocation { - case 1: - storeDosingDecisionHandler1.fulfill() - case 2: - storeDosingDecisionHandler2.fulfill() - default: - XCTFail("Unexpected handler invocation") - } - } - - dosingDecisionStore.storeDosingDecision(StoredDosingDecision(reason: "test")) { - storeDosingDecisionCompletion1.fulfill() - } - - dosingDecisionStore.storeDosingDecision(StoredDosingDecision(reason: "test")) { - storeDosingDecisionCompletion2.fulfill() - } - - wait(for: [storeDosingDecisionHandler1, storeDosingDecisionCompletion1, storeDosingDecisionHandler2, storeDosingDecisionCompletion2], timeout: 2, enforceOrder: true) - } - - func testDosingDecisionObjectEncodable() throws { - cacheStore.managedObjectContext.performAndWait { - do { - let object = DosingDecisionObject(context: cacheStore.managedObjectContext) - object.data = try PropertyListEncoder().encode(StoredDosingDecision.test) - object.date = dateFormatter.date(from: "2100-01-02T03:03:00Z")! - object.modificationCounter = 123 - try assertDosingDecisionObjectEncodable(object, encodesJSON: """ -{ - "data" : { - "automaticDoseRecommendation" : { - "basalAdjustment" : { - "duration" : 1800, - "unitsPerHour" : 0.75 - }, - "bolusUnits" : 1.25 - }, - "carbEntry" : { - "absorptionTime" : 18000, - "createdByCurrentApp" : true, - "foodType" : "Pizza", - "provenanceIdentifier" : "com.loopkit.loop", - "quantity" : 29, - "startDate" : "2020-01-02T03:00:23Z", - "syncIdentifier" : "2B03D96C-6F5D-4140-99CD-80C3E64D6010", - "syncVersion" : 2, - "userCreatedDate" : "2020-05-14T22:06:12Z", - "userUpdatedDate" : "2020-05-14T22:07:32Z", - "uuid" : "135CDABE-9343-7242-4233-1020384789AE" - }, - "carbsOnBoard" : { - "endDate" : "2020-05-14T23:18:41Z", - "quantity" : 45.5, - "quantityUnit" : "g", - "startDate" : "2020-05-14T22:48:41Z" - }, - "cgmManagerStatus" : { - "device" : { - "firmwareVersion" : "CGM Firmware Version", - "hardwareVersion" : "CGM Hardware Version", - "localIdentifier" : "CGM Local Identifier", - "manufacturer" : "CGM Manufacturer", - "model" : "CGM Model", - "name" : "CGM Name", - "softwareVersion" : "CGM Software Version", - "udiDeviceIdentifier" : "CGM UDI Device Identifier" - }, - "hasValidSensorSession" : true, - "lastCommunicationDate" : "2020-05-14T22:07:01Z" - }, - "controllerStatus" : { - "batteryLevel" : 0.5, - "batteryState" : "charging" - }, - "controllerTimeZone" : { - "identifier" : "America/Los_Angeles" - }, - "date" : "2020-05-14T22:38:14Z", - "errors" : [ - { - "id" : "alpha" - }, - { - "details" : { - "size" : "tiny" - }, - "id" : "bravo" - } - ], - "glucoseTargetRangeSchedule" : { - "override" : { - "end" : "2020-05-14T23:12:17Z", - "start" : "2020-05-14T21:12:17Z", - "value" : { - "maxValue" : 115, - "minValue" : 105 - } - }, - "rangeSchedule" : { - "unit" : "mg/dL", - "valueSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : { - "maxValue" : 110, - "minValue" : 100 - } - }, - { - "startTime" : 25200, - "value" : { - "maxValue" : 100, - "minValue" : 90 - } - }, - { - "startTime" : 75600, - "value" : { - "maxValue" : 120, - "minValue" : 110 - } - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "GMT-0700" - } - } - } - }, - "historicalGlucose" : [ - { - "quantity" : 117.3, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T22:29:15Z" - }, - { - "quantity" : 119.5, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T22:33:15Z" - }, - { - "quantity" : 121.8, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T22:38:15Z" - } - ], - "insulinOnBoard" : { - "startDate" : "2020-05-14T22:38:26Z", - "value" : 1.5 - }, - "lastReservoirValue" : { - "startDate" : "2020-05-14T22:07:19Z", - "unitVolume" : 113.3 - }, - "manualBolusRecommendation" : { - "date" : "2020-05-14T22:38:16Z", - "recommendation" : { - "amount" : 1.2, - "notice" : { - "predictedGlucoseBelowTarget" : { - "minGlucose" : { - "endDate" : "2020-05-14T23:03:15Z", - "quantity" : 75.5, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T23:03:15Z" - } - } - }, - "pendingInsulin" : 0.75 - } - }, - "manualBolusRequested" : 0.80000000000000004, - "manualGlucoseSample" : { - "condition" : "aboveRange", - "device" : { - "firmwareVersion" : "Device Firmware Version", - "hardwareVersion" : "Device Hardware Version", - "localIdentifier" : "Device Local Identifier", - "manufacturer" : "Device Manufacturer", - "model" : "Device Model", - "name" : "Device Name", - "softwareVersion" : "Device Software Version", - "udiDeviceIdentifier" : "Device UDI Device Identifier" - }, - "isDisplayOnly" : false, - "provenanceIdentifier" : "com.loopkit.loop", - "quantity" : 400, - "startDate" : "2020-05-14T22:09:00Z", - "syncIdentifier" : "d3876f59-adb3-4a4f-8b29-315cda22062e", - "syncVersion" : 1, - "trend" : 7, - "trendRate" : -10.199999999999999, - "uuid" : "DA0CED44-E4F1-49C4-BAF8-6EFA6D75525F", - "wasUserEntered" : true - }, - "originalCarbEntry" : { - "absorptionTime" : 18000, - "createdByCurrentApp" : true, - "foodType" : "Pizza", - "provenanceIdentifier" : "com.loopkit.loop", - "quantity" : 19, - "startDate" : "2020-01-02T03:00:23Z", - "syncIdentifier" : "2B03D96C-6F5D-4140-99CD-80C3E64D6010", - "syncVersion" : 1, - "userCreatedDate" : "2020-05-14T22:06:12Z", - "uuid" : "18CF3948-0B3D-4B12-8BFE-14986B0E6784" - }, - "predictedGlucose" : [ - { - "quantity" : 123.3, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T22:43:15Z" - }, - { - "quantity" : 125.5, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T22:48:15Z" - }, - { - "quantity" : 127.8, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T22:53:15Z" - } - ], - "pumpManagerStatus" : { - "basalDeliveryState" : "initiatingTempBasal", - "bolusState" : "noBolus", - "deliveryIsUncertain" : false, - "device" : { - "firmwareVersion" : "Pump Firmware Version", - "hardwareVersion" : "Pump Hardware Version", - "localIdentifier" : "Pump Local Identifier", - "manufacturer" : "Pump Manufacturer", - "model" : "Pump Model", - "name" : "Pump Name", - "softwareVersion" : "Pump Software Version", - "udiDeviceIdentifier" : "Pump UDI Device Identifier" - }, - "insulinType" : 0, - "pumpBatteryChargeRemaining" : 0.75, - "timeZone" : { - "identifier" : "GMT-0700" - } - }, - "reason" : "test", - "scheduleOverride" : { - "actualEnd" : { - "type" : "natural" - }, - "context" : "preMeal", - "duration" : { - "finite" : { - "duration" : 3600 - } - }, - "enactTrigger" : "local", - "settings" : { - "insulinNeedsScaleFactor" : 1.5, - "targetRangeInMgdl" : { - "maxValue" : 90, - "minValue" : 80 - } - }, - "startDate" : "2020-05-14T22:22:01Z", - "syncIdentifier" : "394818CF-99CD-4B12-99CD-0E678414986B" - }, - "settings" : { - "syncIdentifier" : "2B03D96C-99CD-4140-99CD-80C3E64D6011" - }, - "syncIdentifier" : "2A67A303-5203-4CB8-8263-79498265368E", - "warnings" : [ - { - "id" : "one" - }, - { - "details" : { - "size" : "small" - }, - "id" : "two" - } - ] - }, - "date" : "2100-01-02T03:03:00Z", - "modificationCounter" : 123 -} -""" - ) - } catch let error { - XCTFail("Unexpected failure: \(error)") - } - } - } - - private func assertDosingDecisionObjectEncodable(_ original: DosingDecisionObject, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() -} - -class DosingDecisionStoreQueryAnchorTests: XCTestCase { - - var rawValue: DosingDecisionStore.QueryAnchor.RawValue = [ - "modificationCounter": Int64(123) - ] - - func testInitializerDefault() { - let queryAnchor = DosingDecisionStore.QueryAnchor() - XCTAssertEqual(queryAnchor.modificationCounter, 0) - } - - func testInitializerRawValue() { - let queryAnchor = DosingDecisionStore.QueryAnchor(rawValue: rawValue) - XCTAssertNotNil(queryAnchor) - XCTAssertEqual(queryAnchor?.modificationCounter, 123) - } - - func testInitializerRawValueMissingModificationCounter() { - rawValue["modificationCounter"] = nil - XCTAssertNil(DosingDecisionStore.QueryAnchor(rawValue: rawValue)) - } - - func testInitializerRawValueInvalidModificationCounter() { - rawValue["modificationCounter"] = "123" - XCTAssertNil(DosingDecisionStore.QueryAnchor(rawValue: rawValue)) - } - - func testRawValueWithDefault() { - let rawValue = DosingDecisionStore.QueryAnchor().rawValue - XCTAssertEqual(rawValue.count, 1) - XCTAssertEqual(rawValue["modificationCounter"] as? Int64, Int64(0)) - } - - func testRawValueWithNonDefault() { - var queryAnchor = DosingDecisionStore.QueryAnchor() - queryAnchor.modificationCounter = 123 - let rawValue = queryAnchor.rawValue - XCTAssertEqual(rawValue.count, 1) - XCTAssertEqual(rawValue["modificationCounter"] as? Int64, Int64(123)) - } - -} - -class DosingDecisionStoreQueryTests: PersistenceControllerTestCase { - - var dosingDecisionStore: DosingDecisionStore! - var completion: XCTestExpectation! - var queryAnchor: DosingDecisionStore.QueryAnchor! - var limit: Int! - - override func setUp() { - super.setUp() - - dosingDecisionStore = DosingDecisionStore(store: cacheStore, expireAfter: .hours(1)) - completion = expectation(description: "Completion") - queryAnchor = DosingDecisionStore.QueryAnchor() - limit = Int.max - } - - override func tearDown() { - limit = nil - queryAnchor = nil - completion = nil - dosingDecisionStore = nil - - super.tearDown() - } - - // MARK: - - - func testEmptyWithDefaultQueryAnchor() { - dosingDecisionStore.executeDosingDecisionQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 0) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testEmptyWithMissingQueryAnchor() { - queryAnchor = nil - - dosingDecisionStore.executeDosingDecisionQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 0) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testEmptyWithNonDefaultQueryAnchor() { - queryAnchor.modificationCounter = 1 - - dosingDecisionStore.executeDosingDecisionQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 1) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithUnusedQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - dosingDecisionStore.executeDosingDecisionQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(data.count, 3) - for (index, syncIdentifier) in syncIdentifiers.enumerated() { - XCTAssertEqual(data[index].syncIdentifier, syncIdentifier) - } - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithStaleQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - queryAnchor.modificationCounter = 2 - - dosingDecisionStore.executeDosingDecisionQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(data.count, 1) - XCTAssertEqual(data[0].syncIdentifier, syncIdentifiers[2]) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithCurrentQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - queryAnchor.modificationCounter = 3 - - dosingDecisionStore.executeDosingDecisionQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithLimitZero() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - limit = 0 - - dosingDecisionStore.executeDosingDecisionQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 0) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithLimitCoveredByData() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - limit = 2 - - dosingDecisionStore.executeDosingDecisionQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 2) - XCTAssertEqual(data.count, 2) - XCTAssertEqual(data[0].syncIdentifier, syncIdentifiers[0]) - XCTAssertEqual(data[1].syncIdentifier, syncIdentifiers[1]) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - private func addData(withSyncIdentifiers syncIdentifiers: [UUID]) { - let semaphore = DispatchSemaphore(value: 0) - for syncIdentifier in syncIdentifiers { - self.dosingDecisionStore.storeDosingDecision(StoredDosingDecision(reason: "test", syncIdentifier: syncIdentifier)) { semaphore.signal() } - } - for _ in syncIdentifiers { semaphore.wait() } - } - - private func generateSyncIdentifier() -> UUID { UUID() } -} - -class DosingDecisionStoreCriticalEventLogTests: PersistenceControllerTestCase { - var dosingDecisionStore: DosingDecisionStore! - var outputStream: MockOutputStream! - var progress: Progress! - - override func setUp() { - super.setUp() - - let dosingDecisions = [StoredDosingDecision(date: dateFormatter.date(from: "2100-01-02T03:08:00Z")!, controllerTimeZone: TimeZone(identifier: "America/Los_Angeles")!, reason: "test", syncIdentifier: UUID(uuidString: "18CF3948-0B3D-4B12-8BFE-14986B0E6784")!), - StoredDosingDecision(date: dateFormatter.date(from: "2100-01-02T03:10:00Z")!, controllerTimeZone: TimeZone(identifier: "America/Los_Angeles")!, reason: "test", syncIdentifier: UUID(uuidString: "C86DEB61-68E9-464E-9DD5-96A9CB445FD3")!), - StoredDosingDecision(date: dateFormatter.date(from: "2100-01-02T03:04:00Z")!, controllerTimeZone: TimeZone(identifier: "America/Los_Angeles")!, reason: "test", syncIdentifier: UUID(uuidString: "2B03D96C-6F5D-4140-99CD-80C3E64D6010")!), - StoredDosingDecision(date: dateFormatter.date(from: "2100-01-02T03:06:00Z")!, controllerTimeZone: TimeZone(identifier: "America/Los_Angeles")!, reason: "test", syncIdentifier: UUID(uuidString: "FF1C4F01-3558-4FB2-957E-FA1522C4735E")!), - StoredDosingDecision(date: dateFormatter.date(from: "2100-01-02T03:02:00Z")!, controllerTimeZone: TimeZone(identifier: "America/Los_Angeles")!, reason: "test", syncIdentifier: UUID(uuidString: "71B699D7-0E8F-4B13-B7A1-E7751EB78E74")!)] - - dosingDecisionStore = DosingDecisionStore(store: cacheStore, expireAfter: .hours(1)) - - let dispatchGroup = DispatchGroup() - dispatchGroup.enter() - dosingDecisionStore.addStoredDosingDecisions(dosingDecisions: dosingDecisions) { error in - XCTAssertNil(error) - dispatchGroup.leave() - } - dispatchGroup.wait() - - outputStream = MockOutputStream() - progress = Progress() - } - - override func tearDown() { - dosingDecisionStore = nil - - super.tearDown() - } - - func testExportProgressTotalUnitCount() { - switch dosingDecisionStore.exportProgressTotalUnitCount(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!) { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let progressTotalUnitCount): - XCTAssertEqual(progressTotalUnitCount, 3 * 33) - } - } - - func testExportProgressTotalUnitCountEmpty() { - switch dosingDecisionStore.exportProgressTotalUnitCount(startDate: dateFormatter.date(from: "2100-01-02T03:00:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:01:00Z")!) { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let progressTotalUnitCount): - XCTAssertEqual(progressTotalUnitCount, 0) - } - } - - func testExport() { - XCTAssertNil(dosingDecisionStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!, - to: outputStream, - progress: progress)) - XCTAssertEqual(outputStream.string, """ -[ -{"data":{"controllerTimeZone":{"identifier":"America/Los_Angeles"},"date":"2100-01-02T03:08:00.000Z","reason":"test","syncIdentifier":"18CF3948-0B3D-4B12-8BFE-14986B0E6784"},"date":"2100-01-02T03:08:00.000Z","modificationCounter":1}, -{"data":{"controllerTimeZone":{"identifier":"America/Los_Angeles"},"date":"2100-01-02T03:04:00.000Z","reason":"test","syncIdentifier":"2B03D96C-6F5D-4140-99CD-80C3E64D6010"},"date":"2100-01-02T03:04:00.000Z","modificationCounter":3}, -{"data":{"controllerTimeZone":{"identifier":"America/Los_Angeles"},"date":"2100-01-02T03:06:00.000Z","reason":"test","syncIdentifier":"FF1C4F01-3558-4FB2-957E-FA1522C4735E"},"date":"2100-01-02T03:06:00.000Z","modificationCounter":4} -] -""" - ) - XCTAssertEqual(progress.completedUnitCount, 3 * 33) - } - - func testExportEmpty() { - XCTAssertNil(dosingDecisionStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:00:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:01:00Z")!, - to: outputStream, - progress: progress)) - XCTAssertEqual(outputStream.string, "[]") - XCTAssertEqual(progress.completedUnitCount, 0) - } - - func testExportCancelled() { - progress.cancel() - XCTAssertEqual(dosingDecisionStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!, - to: outputStream, - progress: progress) as? CriticalEventLogError, CriticalEventLogError.cancelled) - } - - private let dateFormatter = ISO8601DateFormatter() -} - -class StoredDosingDecisionCodableTests: XCTestCase { - func testCodable() throws { - try assertStoredDosingDecisionCodable(StoredDosingDecision.test, encodesJSON: """ -{ - "automaticDoseRecommendation" : { - "basalAdjustment" : { - "duration" : 1800, - "unitsPerHour" : 0.75 - }, - "bolusUnits" : 1.25 - }, - "carbEntry" : { - "absorptionTime" : 18000, - "createdByCurrentApp" : true, - "foodType" : "Pizza", - "provenanceIdentifier" : "com.loopkit.loop", - "quantity" : 29, - "startDate" : "2020-01-02T03:00:23Z", - "syncIdentifier" : "2B03D96C-6F5D-4140-99CD-80C3E64D6010", - "syncVersion" : 2, - "userCreatedDate" : "2020-05-14T22:06:12Z", - "userUpdatedDate" : "2020-05-14T22:07:32Z", - "uuid" : "135CDABE-9343-7242-4233-1020384789AE" - }, - "carbsOnBoard" : { - "endDate" : "2020-05-14T23:18:41Z", - "quantity" : 45.5, - "quantityUnit" : "g", - "startDate" : "2020-05-14T22:48:41Z" - }, - "cgmManagerStatus" : { - "device" : { - "firmwareVersion" : "CGM Firmware Version", - "hardwareVersion" : "CGM Hardware Version", - "localIdentifier" : "CGM Local Identifier", - "manufacturer" : "CGM Manufacturer", - "model" : "CGM Model", - "name" : "CGM Name", - "softwareVersion" : "CGM Software Version", - "udiDeviceIdentifier" : "CGM UDI Device Identifier" - }, - "hasValidSensorSession" : true, - "lastCommunicationDate" : "2020-05-14T22:07:01Z" - }, - "controllerStatus" : { - "batteryLevel" : 0.5, - "batteryState" : "charging" - }, - "controllerTimeZone" : { - "identifier" : "America/Los_Angeles" - }, - "date" : "2020-05-14T22:38:14Z", - "errors" : [ - { - "id" : "alpha" - }, - { - "details" : { - "size" : "tiny" - }, - "id" : "bravo" - } - ], - "glucoseTargetRangeSchedule" : { - "override" : { - "end" : "2020-05-14T23:12:17Z", - "start" : "2020-05-14T21:12:17Z", - "value" : { - "maxValue" : 115, - "minValue" : 105 - } - }, - "rangeSchedule" : { - "unit" : "mg/dL", - "valueSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : { - "maxValue" : 110, - "minValue" : 100 - } - }, - { - "startTime" : 25200, - "value" : { - "maxValue" : 100, - "minValue" : 90 - } - }, - { - "startTime" : 75600, - "value" : { - "maxValue" : 120, - "minValue" : 110 - } - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "GMT-0700" - } - } - } - }, - "historicalGlucose" : [ - { - "quantity" : 117.3, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T22:29:15Z" - }, - { - "quantity" : 119.5, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T22:33:15Z" - }, - { - "quantity" : 121.8, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T22:38:15Z" - } - ], - "insulinOnBoard" : { - "startDate" : "2020-05-14T22:38:26Z", - "value" : 1.5 - }, - "lastReservoirValue" : { - "startDate" : "2020-05-14T22:07:19Z", - "unitVolume" : 113.3 - }, - "manualBolusRecommendation" : { - "date" : "2020-05-14T22:38:16Z", - "recommendation" : { - "amount" : 1.2, - "notice" : { - "predictedGlucoseBelowTarget" : { - "minGlucose" : { - "endDate" : "2020-05-14T23:03:15Z", - "quantity" : 75.5, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T23:03:15Z" - } - } - }, - "pendingInsulin" : 0.75 - } - }, - "manualBolusRequested" : 0.80000000000000004, - "manualGlucoseSample" : { - "condition" : "aboveRange", - "device" : { - "firmwareVersion" : "Device Firmware Version", - "hardwareVersion" : "Device Hardware Version", - "localIdentifier" : "Device Local Identifier", - "manufacturer" : "Device Manufacturer", - "model" : "Device Model", - "name" : "Device Name", - "softwareVersion" : "Device Software Version", - "udiDeviceIdentifier" : "Device UDI Device Identifier" - }, - "isDisplayOnly" : false, - "provenanceIdentifier" : "com.loopkit.loop", - "quantity" : 400, - "startDate" : "2020-05-14T22:09:00Z", - "syncIdentifier" : "d3876f59-adb3-4a4f-8b29-315cda22062e", - "syncVersion" : 1, - "trend" : 7, - "trendRate" : -10.199999999999999, - "uuid" : "DA0CED44-E4F1-49C4-BAF8-6EFA6D75525F", - "wasUserEntered" : true - }, - "originalCarbEntry" : { - "absorptionTime" : 18000, - "createdByCurrentApp" : true, - "foodType" : "Pizza", - "provenanceIdentifier" : "com.loopkit.loop", - "quantity" : 19, - "startDate" : "2020-01-02T03:00:23Z", - "syncIdentifier" : "2B03D96C-6F5D-4140-99CD-80C3E64D6010", - "syncVersion" : 1, - "userCreatedDate" : "2020-05-14T22:06:12Z", - "uuid" : "18CF3948-0B3D-4B12-8BFE-14986B0E6784" - }, - "predictedGlucose" : [ - { - "quantity" : 123.3, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T22:43:15Z" - }, - { - "quantity" : 125.5, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T22:48:15Z" - }, - { - "quantity" : 127.8, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T22:53:15Z" - } - ], - "pumpManagerStatus" : { - "basalDeliveryState" : "initiatingTempBasal", - "bolusState" : "noBolus", - "deliveryIsUncertain" : false, - "device" : { - "firmwareVersion" : "Pump Firmware Version", - "hardwareVersion" : "Pump Hardware Version", - "localIdentifier" : "Pump Local Identifier", - "manufacturer" : "Pump Manufacturer", - "model" : "Pump Model", - "name" : "Pump Name", - "softwareVersion" : "Pump Software Version", - "udiDeviceIdentifier" : "Pump UDI Device Identifier" - }, - "insulinType" : 0, - "pumpBatteryChargeRemaining" : 0.75, - "timeZone" : { - "identifier" : "GMT-0700" - } - }, - "reason" : "test", - "scheduleOverride" : { - "actualEnd" : { - "type" : "natural" - }, - "context" : "preMeal", - "duration" : { - "finite" : { - "duration" : 3600 - } - }, - "enactTrigger" : "local", - "settings" : { - "insulinNeedsScaleFactor" : 1.5, - "targetRangeInMgdl" : { - "maxValue" : 90, - "minValue" : 80 - } - }, - "startDate" : "2020-05-14T22:22:01Z", - "syncIdentifier" : "394818CF-99CD-4B12-99CD-0E678414986B" - }, - "settings" : { - "syncIdentifier" : "2B03D96C-99CD-4140-99CD-80C3E64D6011" - }, - "syncIdentifier" : "2A67A303-5203-4CB8-8263-79498265368E", - "warnings" : [ - { - "id" : "one" - }, - { - "details" : { - "size" : "small" - }, - "id" : "two" - } - ] -} -""" - ) - } - - private func assertStoredDosingDecisionCodable(_ original: StoredDosingDecision, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(StoredDosingDecision.self, from: data) - XCTAssertEqual(decoded, original) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() -} - -extension StoredDosingDecision: Equatable { - public static func == (lhs: StoredDosingDecision, rhs: StoredDosingDecision) -> Bool { - return lhs.date == rhs.date && - lhs.controllerTimeZone == rhs.controllerTimeZone && - lhs.reason == rhs.reason && - lhs.settings == rhs.settings && - lhs.controllerStatus == rhs.controllerStatus && - lhs.pumpManagerStatus == rhs.pumpManagerStatus && - lhs.cgmManagerStatus == rhs.cgmManagerStatus && - lhs.lastReservoirValue == rhs.lastReservoirValue && - lhs.historicalGlucose == rhs.historicalGlucose && - lhs.originalCarbEntry == rhs.originalCarbEntry && - lhs.carbEntry == rhs.carbEntry && - lhs.manualGlucoseSample == rhs.manualGlucoseSample && - lhs.carbsOnBoard == rhs.carbsOnBoard && - lhs.insulinOnBoard == rhs.insulinOnBoard && - lhs.glucoseTargetRangeSchedule == rhs.glucoseTargetRangeSchedule && - lhs.predictedGlucose == rhs.predictedGlucose && - lhs.automaticDoseRecommendation == rhs.automaticDoseRecommendation && - lhs.manualBolusRecommendation == rhs.manualBolusRecommendation && - lhs.manualBolusRequested == rhs.manualBolusRequested && - lhs.warnings == rhs.warnings && - lhs.errors == rhs.errors && - lhs.syncIdentifier == rhs.syncIdentifier - } -} - -extension StoredDosingDecision.LastReservoirValue: Equatable { - public static func == (lhs: StoredDosingDecision.LastReservoirValue, rhs: StoredDosingDecision.LastReservoirValue) -> Bool { - return lhs.startDate == rhs.startDate && lhs.unitVolume == rhs.unitVolume - } -} - -extension ManualBolusRecommendationWithDate: Equatable { - public static func == (lhs: ManualBolusRecommendationWithDate, rhs: ManualBolusRecommendationWithDate) -> Bool { - return lhs.recommendation == rhs.recommendation && lhs.date == rhs.date - } -} - -extension ManualBolusRecommendation: Equatable { - public static func == (lhs: ManualBolusRecommendation, rhs: ManualBolusRecommendation) -> Bool { - return lhs.amount == rhs.amount && lhs.pendingInsulin == rhs.pendingInsulin && lhs.notice == rhs.notice - } -} - -fileprivate extension StoredDosingDecision { - static var test: StoredDosingDecision { - let controllerTimeZone = TimeZone(identifier: "America/Los_Angeles")! - let scheduleTimeZone = TimeZone(secondsFromGMT: TimeZone(identifier: "America/Phoenix")!.secondsFromGMT())! - let reason = "test" - let settings = StoredDosingDecision.Settings(syncIdentifier: UUID(uuidString: "2B03D96C-99CD-4140-99CD-80C3E64D6011")!) - let scheduleOverride = TemporaryScheduleOverride(context: .preMeal, - settings: TemporaryScheduleOverrideSettings(unit: .milligramsPerDeciliter, - targetRange: DoubleRange(minValue: 80.0, - maxValue: 90.0), - insulinNeedsScaleFactor: 1.5), - startDate: dateFormatter.date(from: "2020-05-14T22:22:01Z")!, - duration: .finite(.hours(1)), - enactTrigger: .local, - syncIdentifier: UUID(uuidString: "394818CF-99CD-4B12-99CD-0E678414986B")!) - let controllerStatus = StoredDosingDecision.ControllerStatus(batteryState: .charging, - batteryLevel: 0.5) - let pumpManagerStatus = PumpManagerStatus(timeZone: scheduleTimeZone, - device: HKDevice(name: "Pump Name", - manufacturer: "Pump Manufacturer", - model: "Pump Model", - hardwareVersion: "Pump Hardware Version", - firmwareVersion: "Pump Firmware Version", - softwareVersion: "Pump Software Version", - localIdentifier: "Pump Local Identifier", - udiDeviceIdentifier: "Pump UDI Device Identifier"), - pumpBatteryChargeRemaining: 0.75, - basalDeliveryState: .initiatingTempBasal, - bolusState: .noBolus, - insulinType: .novolog) - let cgmManagerStatus = CGMManagerStatus(hasValidSensorSession: true, - lastCommunicationDate: dateFormatter.date(from: "2020-05-14T22:07:01Z")!, - device: HKDevice(name: "CGM Name", - manufacturer: "CGM Manufacturer", - model: "CGM Model", - hardwareVersion: "CGM Hardware Version", - firmwareVersion: "CGM Firmware Version", - softwareVersion: "CGM Software Version", - localIdentifier: "CGM Local Identifier", - udiDeviceIdentifier: "CGM UDI Device Identifier")) - let lastReservoirValue = StoredDosingDecision.LastReservoirValue(startDate: dateFormatter.date(from: "2020-05-14T22:07:19Z")!, - unitVolume: 113.3) - let historicalGlucose = [HistoricalGlucoseValue(startDate: dateFormatter.date(from: "2020-05-14T22:29:15Z")!, - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 117.3)), - HistoricalGlucoseValue(startDate: dateFormatter.date(from: "2020-05-14T22:33:15Z")!, - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 119.5)), - HistoricalGlucoseValue(startDate: dateFormatter.date(from: "2020-05-14T22:38:15Z")!, - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 121.8))] - let originalCarbEntry = StoredCarbEntry(uuid: UUID(uuidString: "18CF3948-0B3D-4B12-8BFE-14986B0E6784")!, - provenanceIdentifier: "com.loopkit.loop", - syncIdentifier: "2B03D96C-6F5D-4140-99CD-80C3E64D6010", - syncVersion: 1, - startDate: dateFormatter.date(from: "2020-01-02T03:00:23Z")!, - quantity: HKQuantity(unit: .gram(), doubleValue: 19), - foodType: "Pizza", - absorptionTime: .hours(5), - createdByCurrentApp: true, - userCreatedDate: dateFormatter.date(from: "2020-05-14T22:06:12Z")!, - userUpdatedDate: nil) - let carbEntry = StoredCarbEntry(uuid: UUID(uuidString: "135CDABE-9343-7242-4233-1020384789AE")!, - provenanceIdentifier: "com.loopkit.loop", - syncIdentifier: "2B03D96C-6F5D-4140-99CD-80C3E64D6010", - syncVersion: 2, - startDate: dateFormatter.date(from: "2020-01-02T03:00:23Z")!, - quantity: HKQuantity(unit: .gram(), doubleValue: 29), - foodType: "Pizza", - absorptionTime: .hours(5), - createdByCurrentApp: true, - userCreatedDate: dateFormatter.date(from: "2020-05-14T22:06:12Z")!, - userUpdatedDate: dateFormatter.date(from: "2020-05-14T22:07:32Z")!) - let manualGlucoseSample = StoredGlucoseSample(uuid: UUID(uuidString: "da0ced44-e4f1-49c4-baf8-6efa6d75525f")!, - provenanceIdentifier: "com.loopkit.loop", - syncIdentifier: "d3876f59-adb3-4a4f-8b29-315cda22062e", - syncVersion: 1, - startDate: dateFormatter.date(from: "2020-05-14T22:09:00Z")!, - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 400), - condition: .aboveRange, - trend: .downDownDown, - trendRate: HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: -10.2), - isDisplayOnly: false, - wasUserEntered: true, - device: HKDevice(name: "Device Name", - manufacturer: "Device Manufacturer", - model: "Device Model", - hardwareVersion: "Device Hardware Version", - firmwareVersion: "Device Firmware Version", - softwareVersion: "Device Software Version", - localIdentifier: "Device Local Identifier", - udiDeviceIdentifier: "Device UDI Device Identifier"), - healthKitEligibleDate: nil) - let carbsOnBoard = CarbValue(startDate: dateFormatter.date(from: "2020-05-14T22:48:41Z")!, - endDate: dateFormatter.date(from: "2020-05-14T23:18:41Z")!, - quantity: HKQuantity(unit: .gram(), doubleValue: 45.5)) - let insulinOnBoard = InsulinValue(startDate: dateFormatter.date(from: "2020-05-14T22:38:26Z")!, value: 1.5) - let glucoseTargetRangeSchedule = GlucoseRangeSchedule(rangeSchedule: DailyQuantitySchedule(unit: .milligramsPerDeciliter, - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: DoubleRange(minValue: 100.0, maxValue: 110.0)), - RepeatingScheduleValue(startTime: .hours(7), value: DoubleRange(minValue: 90.0, maxValue: 100.0)), - RepeatingScheduleValue(startTime: .hours(21), value: DoubleRange(minValue: 110.0, maxValue: 120.0))], - timeZone: scheduleTimeZone)!, - override: GlucoseRangeSchedule.Override(value: DoubleRange(minValue: 105.0, maxValue: 115.0), - start: dateFormatter.date(from: "2020-05-14T21:12:17Z")!, - end: dateFormatter.date(from: "2020-05-14T23:12:17Z")!)) - let predictedGlucose = [PredictedGlucoseValue(startDate: dateFormatter.date(from: "2020-05-14T22:43:15Z")!, - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 123.3)), - PredictedGlucoseValue(startDate: dateFormatter.date(from: "2020-05-14T22:48:15Z")!, - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 125.5)), - PredictedGlucoseValue(startDate: dateFormatter.date(from: "2020-05-14T22:53:15Z")!, - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 127.8))] - let tempBasalRecommendation = TempBasalRecommendation(unitsPerHour: 0.75, - duration: .minutes(30)) - let automaticDoseRecommendation = AutomaticDoseRecommendation(basalAdjustment: tempBasalRecommendation, bolusUnits: 1.25) - let manualBolusRecommendation = ManualBolusRecommendationWithDate(recommendation: ManualBolusRecommendation(amount: 1.2, - pendingInsulin: 0.75, - notice: .predictedGlucoseBelowTarget(minGlucose: PredictedGlucoseValue(startDate: dateFormatter.date(from: "2020-05-14T23:03:15Z")!, - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 75.5)))), - date: dateFormatter.date(from: "2020-05-14T22:38:16Z")!) - let manualBolusRequested = 0.8 - let warnings: [Issue] = [Issue(id: "one"), - Issue(id: "two", details: ["size": "small"])] - let errors: [Issue] = [Issue(id: "alpha"), - Issue(id: "bravo", details: ["size": "tiny"])] - - return StoredDosingDecision(date: dateFormatter.date(from: "2020-05-14T22:38:14Z")!, - controllerTimeZone: controllerTimeZone, - reason: reason, - settings: settings, - scheduleOverride: scheduleOverride, - controllerStatus: controllerStatus, - pumpManagerStatus: pumpManagerStatus, - cgmManagerStatus: cgmManagerStatus, - lastReservoirValue: lastReservoirValue, - historicalGlucose: historicalGlucose, - originalCarbEntry: originalCarbEntry, - carbEntry: carbEntry, - manualGlucoseSample: manualGlucoseSample, - carbsOnBoard: carbsOnBoard, - insulinOnBoard: insulinOnBoard, - glucoseTargetRangeSchedule: glucoseTargetRangeSchedule, - predictedGlucose: predictedGlucose, - automaticDoseRecommendation: automaticDoseRecommendation, - manualBolusRecommendation: manualBolusRecommendation, - manualBolusRequested: manualBolusRequested, - warnings: warnings, - errors: errors, - syncIdentifier: UUID(uuidString: "2A67A303-5203-4CB8-8263-79498265368E")!) - } - - private static let dateFormatter = ISO8601DateFormatter() -} diff --git a/Dependencies/LoopKit/LoopKitTests/Extensions/CacheStore.swift b/Dependencies/LoopKit/LoopKitTests/Extensions/CacheStore.swift deleted file mode 100644 index 45015cecf..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Extensions/CacheStore.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// CacheStore.swift -// LoopKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import CoreData -@testable import LoopKit - - -extension PersistenceController { - func tearDown() { - managedObjectContext.performAndWait { - let coordinator = self.managedObjectContext.persistentStoreCoordinator! - let store = coordinator.persistentStores.first! - let url = coordinator.url(for: store) - try! self.managedObjectContext.persistentStoreCoordinator!.destroyPersistentStore(at: url, ofType: NSSQLiteStoreType, options: nil) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/Extensions/DailyValueSchedule.swift b/Dependencies/LoopKit/LoopKitTests/Extensions/DailyValueSchedule.swift deleted file mode 100644 index db0e162f1..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Extensions/DailyValueSchedule.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// DailyValueSchedule.swift -// LoopKitTests -// -// Created by Michael Pangburn on 3/25/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import LoopKit - - -extension DailyValueSchedule where T: FloatingPoint { - func equals(_ other: DailyValueSchedule, accuracy epsilon: T) -> Bool { - guard items.count == other.items.count else { return false } - return Swift.zip(items, other.items).allSatisfy { thisItem, otherItem in - thisItem.startTime == otherItem.startTime - && abs(thisItem.value - otherItem.value) <= epsilon - } - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/Extensions/HKHealthStoreMock.swift b/Dependencies/LoopKit/LoopKitTests/Extensions/HKHealthStoreMock.swift deleted file mode 100644 index cb5c953b0..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Extensions/HKHealthStoreMock.swift +++ /dev/null @@ -1,112 +0,0 @@ -// -// HKHealthStoreMock.swift -// LoopKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import HealthKit -import Foundation -@testable import LoopKit - - -class HKHealthStoreMock: HKHealthStore { - - var saveError: Error? - var deleteError: Error? - var queryResults: (samples: [HKSample]?, error: Error?)? - var lastQuery: HKQuery? - var authorizationStatus: HKAuthorizationStatus? - let authorizationRequestUserResponse: Result = .success(true) - - private var saveHandler: ((_ objects: [HKObject], _ success: Bool, _ error: Error?) -> Void)? - private var deleteObjectsHandler: ((_ objectType: HKObjectType, _ predicate: NSPredicate, _ success: Bool, _ count: Int, _ error: Error?) -> Void)? - - let queue = DispatchQueue(label: "HKHealthStoreMock") - - override func save(_ object: HKObject, withCompletion completion: @escaping (Bool, Error?) -> Void) { - queue.async { - self.saveHandler?([object], self.saveError == nil, self.saveError) - completion(self.saveError == nil, self.saveError) - } - } - - override func save(_ objects: [HKObject], withCompletion completion: @escaping (Bool, Error?) -> Void) { - queue.async { - self.saveHandler?(objects, self.saveError == nil, self.saveError) - completion(self.saveError == nil, self.saveError) - } - } - - override func delete(_ objects: [HKObject], withCompletion completion: @escaping (Bool, Error?) -> Void) { - queue.async { - completion(self.deleteError == nil, self.deleteError) - } - } - - override func deleteObjects(of objectType: HKObjectType, predicate: NSPredicate, withCompletion completion: @escaping (Bool, Int, Error?) -> Void) { - queue.async { - self.deleteObjectsHandler?(objectType, predicate, self.deleteError == nil, 0, self.deleteError) - completion(self.deleteError == nil, 0, self.deleteError) - } - } - - func setSaveHandler(_ saveHandler: ((_ objects: [HKObject], _ success: Bool, _ error: Error?) -> Void)?) { - queue.sync { - self.saveHandler = saveHandler - } - } - - override func requestAuthorization(toShare typesToShare: Set?, read typesToRead: Set?, completion: @escaping (Bool, Error?) -> Void) { - switch authorizationRequestUserResponse { - - case .success(let authorized): - authorizationStatus = authorized ? .sharingAuthorized : .sharingDenied - DispatchQueue.main.async { - completion(true, nil) - } - case .failure(let error): - DispatchQueue.main.async { - completion(false, error) - } - } - } - - override func authorizationStatus(for type: HKObjectType) -> HKAuthorizationStatus { - return authorizationStatus ?? .notDetermined - } - - func setDeletedObjectsHandler(_ deleteObjectsHandler: ((_ objectType: HKObjectType, _ predicate: NSPredicate, _ success: Bool, _ count: Int, _ error: Error?) -> Void)?) { - queue.sync { - self.deleteObjectsHandler = deleteObjectsHandler - } - } -} - -extension HKHealthStoreMock { - - override func execute(_ query: HKQuery) { - self.lastQuery = query - } -} - -extension HKHealthStoreMock: HKSampleQueryTestable { - func executeSampleQuery( - for type: HKSampleType, - matching predicate: NSPredicate, - limit: Int, - sortDescriptors: [NSSortDescriptor]?, - resultsHandler: @escaping (_ query: HKSampleQuery, _ results: [HKSample]?, _ error: Error?) -> Void - ) { - let query = HKSampleQuery(sampleType: type, predicate: predicate, limit: limit, sortDescriptors: sortDescriptors, resultsHandler: resultsHandler) - - guard let results = queryResults else { - execute(query) - return - } - - queue.async { - resultsHandler(query, results.samples, results.error) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/Extensions/NSManagedObjectContext.swift b/Dependencies/LoopKit/LoopKitTests/Extensions/NSManagedObjectContext.swift deleted file mode 100644 index 1a343e79b..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Extensions/NSManagedObjectContext.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// NSManagedObjectContext.swift -// LoopKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import CoreData - - -extension NSManagedObjectContext { - func all() -> [T] { - let request = NSFetchRequest(entityName: T.entity().name!) - return (try? fetch(request)) ?? [] - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/carb_effect_from_history_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/carb_effect_from_history_input.json deleted file mode 100644 index 08a608e66..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/carb_effect_from_history_input.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "amount": 44, - "description": "BolusWizard: 44g", - "end_at": "2015-10-15T21:35:12", - "start_at": "2015-10-15T21:35:12", - "type": "Meal", - "unit": "g" - }, - { - "amount": 35, - "description": "JournalEntryMealMarker: 35g", - "end_at": "2015-10-15T20:55:28", - "start_at": "2015-10-15T20:55:28", - "type": "Meal", - "unit": "g" - }, - { - "amount": 30, - "description": "BolusWizard: 30g", - "end_at": "2015-10-15T20:05:10", - "start_at": "2015-10-15T20:05:10", - "type": "Meal", - "unit": "g" - }, - { - "amount": 20, - "description": "JournalEntryMealMarker: 20g", - "end_at": "2015-10-15T18:58:10", - "start_at": "2015-10-15T18:58:10", - "type": "Meal", - "unit": "g" - }, - { - "amount": 30, - "description": "JournalEntryMealMarker: 30g", - "end_at": "2015-10-15T18:52:32", - "start_at": "2015-10-15T18:52:32", - "type": "Meal", - "unit": "g" - }, - { - "amount": 30, - "description": "JournalEntryMealMarker: 30g", - "end_at": "2015-10-15T18:43:56", - "start_at": "2015-10-15T18:43:56", - "type": "Meal", - "unit": "g" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/carb_effect_from_history_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/carb_effect_from_history_output.json deleted file mode 100644 index f32d03b09..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/carb_effect_from_history_output.json +++ /dev/null @@ -1,377 +0,0 @@ -[ - { - "amount": 0.0, - "date": "2015-10-15T18:40:00", - "unit": "mg/dL" - }, - { - "amount": 0.0, - "date": "2015-10-15T18:45:00", - "unit": "mg/dL" - }, - { - "amount": 0.0, - "date": "2015-10-15T18:50:00", - "unit": "mg/dL" - }, - { - "amount": 0.010534979423868308, - "date": "2015-10-15T18:55:00", - "unit": "mg/dL" - }, - { - "amount": 0.3407818930041152, - "date": "2015-10-15T19:00:00", - "unit": "mg/dL" - }, - { - "amount": 1.1903292181069958, - "date": "2015-10-15T19:05:00", - "unit": "mg/dL" - }, - { - "amount": 2.927126200274348, - "date": "2015-10-15T19:10:00", - "unit": "mg/dL" - }, - { - "amount": 5.8365912208504795, - "date": "2015-10-15T19:15:00", - "unit": "mg/dL" - }, - { - "amount": 9.980624142661181, - "date": "2015-10-15T19:20:00", - "unit": "mg/dL" - }, - { - "amount": 15.359224965706453, - "date": "2015-10-15T19:25:00", - "unit": "mg/dL" - }, - { - "amount": 21.972393689986284, - "date": "2015-10-15T19:30:00", - "unit": "mg/dL" - }, - { - "amount": 29.820130315500695, - "date": "2015-10-15T19:35:00", - "unit": "mg/dL" - }, - { - "amount": 38.90243484224966, - "date": "2015-10-15T19:40:00", - "unit": "mg/dL" - }, - { - "amount": 49.2193072702332, - "date": "2015-10-15T19:45:00", - "unit": "mg/dL" - }, - { - "amount": 60.7707475994513, - "date": "2015-10-15T19:50:00", - "unit": "mg/dL" - }, - { - "amount": 73.55675582990398, - "date": "2015-10-15T19:55:00", - "unit": "mg/dL" - }, - { - "amount": 87.57733196159123, - "date": "2015-10-15T20:00:00", - "unit": "mg/dL" - }, - { - "amount": 102.83247599451303, - "date": "2015-10-15T20:05:00", - "unit": "mg/dL" - }, - { - "amount": 119.32218792866941, - "date": "2015-10-15T20:10:00", - "unit": "mg/dL" - }, - { - "amount": 137.04646776406037, - "date": "2015-10-15T20:15:00", - "unit": "mg/dL" - }, - { - "amount": 156.221622085048, - "date": "2015-10-15T20:20:00", - "unit": "mg/dL" - }, - { - "amount": 177.07298010973932, - "date": "2015-10-15T20:25:00", - "unit": "mg/dL" - }, - { - "amount": 198.9824451303155, - "date": "2015-10-15T20:30:00", - "unit": "mg/dL" - }, - { - "amount": 221.5508401920439, - "date": "2015-10-15T20:35:00", - "unit": "mg/dL" - }, - { - "amount": 244.04226680384085, - "date": "2015-10-15T20:40:00", - "unit": "mg/dL" - }, - { - "amount": 265.88588820301777, - "date": "2015-10-15T20:45:00", - "unit": "mg/dL" - }, - { - "amount": 286.95790466392316, - "date": "2015-10-15T20:50:00", - "unit": "mg/dL" - }, - { - "amount": 307.258316186557, - "date": "2015-10-15T20:55:00", - "unit": "mg/dL" - }, - { - "amount": 326.7871227709191, - "date": "2015-10-15T21:00:00", - "unit": "mg/dL" - }, - { - "amount": 345.54432441700965, - "date": "2015-10-15T21:05:00", - "unit": "mg/dL" - }, - { - "amount": 363.7519238683127, - "date": "2015-10-15T21:10:00", - "unit": "mg/dL" - }, - { - "amount": 381.7256893004116, - "date": "2015-10-15T21:15:00", - "unit": "mg/dL" - }, - { - "amount": 399.46797325102887, - "date": "2015-10-15T21:20:00", - "unit": "mg/dL" - }, - { - "amount": 416.97877572016455, - "date": "2015-10-15T21:25:00", - "unit": "mg/dL" - }, - { - "amount": 434.25809670781905, - "date": "2015-10-15T21:30:00", - "unit": "mg/dL" - }, - { - "amount": 451.3059362139918, - "date": "2015-10-15T21:35:00", - "unit": "mg/dL" - }, - { - "amount": 468.12229423868314, - "date": "2015-10-15T21:40:00", - "unit": "mg/dL" - }, - { - "amount": 484.70717078189307, - "date": "2015-10-15T21:45:00", - "unit": "mg/dL" - }, - { - "amount": 500.94084156378614, - "date": "2015-10-15T21:50:00", - "unit": "mg/dL" - }, - { - "amount": 516.7066234567901, - "date": "2015-10-15T21:55:00", - "unit": "mg/dL" - }, - { - "amount": 532.3137222222223, - "date": "2015-10-15T22:00:00", - "unit": "mg/dL" - }, - { - "amount": 547.9617263374486, - "date": "2015-10-15T22:05:00", - "unit": "mg/dL" - }, - { - "amount": 564.018585048011, - "date": "2015-10-15T22:10:00", - "unit": "mg/dL" - }, - { - "amount": 580.7697167352538, - "date": "2015-10-15T22:15:00", - "unit": "mg/dL" - }, - { - "amount": 598.2770212620028, - "date": "2015-10-15T22:20:00", - "unit": "mg/dL" - }, - { - "amount": 616.5404986282579, - "date": "2015-10-15T22:25:00", - "unit": "mg/dL" - }, - { - "amount": 635.5601488340192, - "date": "2015-10-15T22:30:00", - "unit": "mg/dL" - }, - { - "amount": 655.3359718792867, - "date": "2015-10-15T22:35:00", - "unit": "mg/dL" - }, - { - "amount": 675.423962277092, - "date": "2015-10-15T22:40:00", - "unit": "mg/dL" - }, - { - "amount": 695.1925836762689, - "date": "2015-10-15T22:45:00", - "unit": "mg/dL" - }, - { - "amount": 714.6371310013717, - "date": "2015-10-15T22:50:00", - "unit": "mg/dL" - }, - { - "amount": 733.7576042524006, - "date": "2015-10-15T22:55:00", - "unit": "mg/dL" - }, - { - "amount": 752.5540034293554, - "date": "2015-10-15T23:00:00", - "unit": "mg/dL" - }, - { - "amount": 771.026328532236, - "date": "2015-10-15T23:05:00", - "unit": "mg/dL" - }, - { - "amount": 789.1745795610426, - "date": "2015-10-15T23:10:00", - "unit": "mg/dL" - }, - { - "amount": 806.9987565157751, - "date": "2015-10-15T23:15:00", - "unit": "mg/dL" - }, - { - "amount": 824.0893882030178, - "date": "2015-10-15T23:20:00", - "unit": "mg/dL" - }, - { - "amount": 839.9617133058985, - "date": "2015-10-15T23:25:00", - "unit": "mg/dL" - }, - { - "amount": 854.6149026063101, - "date": "2015-10-15T23:30:00", - "unit": "mg/dL" - }, - { - "amount": 868.0489561042525, - "date": "2015-10-15T23:35:00", - "unit": "mg/dL" - }, - { - "amount": 880.2638737997256, - "date": "2015-10-15T23:40:00", - "unit": "mg/dL" - }, - { - "amount": 891.2596556927298, - "date": "2015-10-15T23:45:00", - "unit": "mg/dL" - }, - { - "amount": 901.0363017832649, - "date": "2015-10-15T23:50:00", - "unit": "mg/dL" - }, - { - "amount": 909.5938120713306, - "date": "2015-10-15T23:55:00", - "unit": "mg/dL" - }, - { - "amount": 916.9321865569274, - "date": "2015-10-16T00:00:00", - "unit": "mg/dL" - }, - { - "amount": 923.0514252400549, - "date": "2015-10-16T00:05:00", - "unit": "mg/dL" - }, - { - "amount": 928.1735308641976, - "date": "2015-10-16T00:10:00", - "unit": "mg/dL" - }, - { - "amount": 932.6142716049383, - "date": "2015-10-16T00:15:00", - "unit": "mg/dL" - }, - { - "amount": 936.376, - "date": "2015-10-16T00:20:00", - "unit": "mg/dL" - }, - { - "amount": 939.4587160493827, - "date": "2015-10-16T00:25:00", - "unit": "mg/dL" - }, - { - "amount": 941.8624197530864, - "date": "2015-10-16T00:30:00", - "unit": "mg/dL" - }, - { - "amount": 943.5871111111112, - "date": "2015-10-16T00:35:00", - "unit": "mg/dL" - }, - { - "amount": 944.6327901234567, - "date": "2015-10-16T00:40:00", - "unit": "mg/dL" - }, - { - "amount": 944.9994567901235, - "date": "2015-10-16T00:45:00", - "unit": "mg/dL" - }, - { - "amount": 945.0, - "date": "2015-10-16T00:50:00", - "unit": "mg/dL" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/carb_entry_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/carb_entry_input.json deleted file mode 100644 index d6b3d75e7..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/carb_entry_input.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "amount": 44, - "start_at": "2015-10-15T21:35:12", - "absorption_time": 120, - "unit": "g" - }, - { - "amount": 30, - "start_at": "2015-10-15T21:55:00", - "absorption_time": 120, - "unit": "g" - }, - { - "amount": 30, - "start_at": "2015-10-15T23:00:00", - "absorption_time": 120, - "unit": "g" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/carbs_on_board_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/carbs_on_board_output.json deleted file mode 100644 index 5589d008f..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/carbs_on_board_output.json +++ /dev/null @@ -1,377 +0,0 @@ -[ - { - "amount": 0.0, - "date": "2015-10-15T18:40:00", - "unit": "g" - }, - { - "amount": 30.0, - "date": "2015-10-15T18:45:00", - "unit": "g" - }, - { - "amount": 30.0, - "date": "2015-10-15T18:50:00", - "unit": "g" - }, - { - "amount": 59.99789300411523, - "date": "2015-10-15T18:55:00", - "unit": "g" - }, - { - "amount": 79.93184362139917, - "date": "2015-10-15T19:00:00", - "unit": "g" - }, - { - "amount": 79.7619341563786, - "date": "2015-10-15T19:05:00", - "unit": "g" - }, - { - "amount": 79.41457475994514, - "date": "2015-10-15T19:10:00", - "unit": "g" - }, - { - "amount": 78.8326817558299, - "date": "2015-10-15T19:15:00", - "unit": "g" - }, - { - "amount": 78.00387517146775, - "date": "2015-10-15T19:20:00", - "unit": "g" - }, - { - "amount": 76.92815500685872, - "date": "2015-10-15T19:25:00", - "unit": "g" - }, - { - "amount": 75.60552126200274, - "date": "2015-10-15T19:30:00", - "unit": "g" - }, - { - "amount": 74.03597393689986, - "date": "2015-10-15T19:35:00", - "unit": "g" - }, - { - "amount": 72.21951303155006, - "date": "2015-10-15T19:40:00", - "unit": "g" - }, - { - "amount": 70.15613854595335, - "date": "2015-10-15T19:45:00", - "unit": "g" - }, - { - "amount": 67.84585048010975, - "date": "2015-10-15T19:50:00", - "unit": "g" - }, - { - "amount": 65.28864883401921, - "date": "2015-10-15T19:55:00", - "unit": "g" - }, - { - "amount": 62.484533607681755, - "date": "2015-10-15T20:00:00", - "unit": "g" - }, - { - "amount": 59.4335048010974, - "date": "2015-10-15T20:05:00", - "unit": "g" - }, - { - "amount": 86.13556241426612, - "date": "2015-10-15T20:10:00", - "unit": "g" - }, - { - "amount": 82.59070644718793, - "date": "2015-10-15T20:15:00", - "unit": "g" - }, - { - "amount": 78.75567558299039, - "date": "2015-10-15T20:20:00", - "unit": "g" - }, - { - "amount": 74.58540397805214, - "date": "2015-10-15T20:25:00", - "unit": "g" - }, - { - "amount": 70.20351097393689, - "date": "2015-10-15T20:30:00", - "unit": "g" - }, - { - "amount": 65.68983196159121, - "date": "2015-10-15T20:35:00", - "unit": "g" - }, - { - "amount": 61.19154663923184, - "date": "2015-10-15T20:40:00", - "unit": "g" - }, - { - "amount": 56.82282235939644, - "date": "2015-10-15T20:45:00", - "unit": "g" - }, - { - "amount": 52.608419067215365, - "date": "2015-10-15T20:50:00", - "unit": "g" - }, - { - "amount": 48.5483367626886, - "date": "2015-10-15T20:55:00", - "unit": "g" - }, - { - "amount": 79.64257544581618, - "date": "2015-10-15T21:00:00", - "unit": "g" - }, - { - "amount": 75.89113511659808, - "date": "2015-10-15T21:05:00", - "unit": "g" - }, - { - "amount": 72.24961522633745, - "date": "2015-10-15T21:10:00", - "unit": "g" - }, - { - "amount": 68.65486213991768, - "date": "2015-10-15T21:15:00", - "unit": "g" - }, - { - "amount": 65.10640534979423, - "date": "2015-10-15T21:20:00", - "unit": "g" - }, - { - "amount": 61.60424485596708, - "date": "2015-10-15T21:25:00", - "unit": "g" - }, - { - "amount": 58.148380658436196, - "date": "2015-10-15T21:30:00", - "unit": "g" - }, - { - "amount": 54.73881275720164, - "date": "2015-10-15T21:35:00", - "unit": "g" - }, - { - "amount": 95.37554115226338, - "date": "2015-10-15T21:40:00", - "unit": "g" - }, - { - "amount": 92.05856584362138, - "date": "2015-10-15T21:45:00", - "unit": "g" - }, - { - "amount": 88.81183168724279, - "date": "2015-10-15T21:50:00", - "unit": "g" - }, - { - "amount": 85.65867530864196, - "date": "2015-10-15T21:55:00", - "unit": "g" - }, - { - "amount": 82.53725555555555, - "date": "2015-10-15T22:00:00", - "unit": "g" - }, - { - "amount": 79.4076547325103, - "date": "2015-10-15T22:05:00", - "unit": "g" - }, - { - "amount": 76.1962829903978, - "date": "2015-10-15T22:10:00", - "unit": "g" - }, - { - "amount": 72.84605665294923, - "date": "2015-10-15T22:15:00", - "unit": "g" - }, - { - "amount": 69.34459574759944, - "date": "2015-10-15T22:20:00", - "unit": "g" - }, - { - "amount": 65.69190027434843, - "date": "2015-10-15T22:25:00", - "unit": "g" - }, - { - "amount": 61.88797023319616, - "date": "2015-10-15T22:30:00", - "unit": "g" - }, - { - "amount": 57.93280562414267, - "date": "2015-10-15T22:35:00", - "unit": "g" - }, - { - "amount": 53.91520754458161, - "date": "2015-10-15T22:40:00", - "unit": "g" - }, - { - "amount": 49.96148326474622, - "date": "2015-10-15T22:45:00", - "unit": "g" - }, - { - "amount": 46.072573799725646, - "date": "2015-10-15T22:50:00", - "unit": "g" - }, - { - "amount": 42.248479149519895, - "date": "2015-10-15T22:55:00", - "unit": "g" - }, - { - "amount": 38.48919931412893, - "date": "2015-10-15T23:00:00", - "unit": "g" - }, - { - "amount": 34.79473429355281, - "date": "2015-10-15T23:05:00", - "unit": "g" - }, - { - "amount": 31.165084087791485, - "date": "2015-10-15T23:10:00", - "unit": "g" - }, - { - "amount": 27.600248696844996, - "date": "2015-10-15T23:15:00", - "unit": "g" - }, - { - "amount": 24.182122359396423, - "date": "2015-10-15T23:20:00", - "unit": "g" - }, - { - "amount": 21.0076573388203, - "date": "2015-10-15T23:25:00", - "unit": "g" - }, - { - "amount": 18.077019478737984, - "date": "2015-10-15T23:30:00", - "unit": "g" - }, - { - "amount": 15.390208779149512, - "date": "2015-10-15T23:35:00", - "unit": "g" - }, - { - "amount": 12.94722524005487, - "date": "2015-10-15T23:40:00", - "unit": "g" - }, - { - "amount": 10.748068861454042, - "date": "2015-10-15T23:45:00", - "unit": "g" - }, - { - "amount": 8.792739643347032, - "date": "2015-10-15T23:50:00", - "unit": "g" - }, - { - "amount": 7.081237585733879, - "date": "2015-10-15T23:55:00", - "unit": "g" - }, - { - "amount": 5.613562688614522, - "date": "2015-10-16T00:00:00", - "unit": "g" - }, - { - "amount": 4.389714951989029, - "date": "2015-10-16T00:05:00", - "unit": "g" - }, - { - "amount": 3.3652938271604995, - "date": "2015-10-16T00:10:00", - "unit": "g" - }, - { - "amount": 2.477145679012356, - "date": "2015-10-16T00:15:00", - "unit": "g" - }, - { - "amount": 1.7247999999999957, - "date": "2015-10-16T00:20:00", - "unit": "g" - }, - { - "amount": 1.1082567901234581, - "date": "2015-10-16T00:25:00", - "unit": "g" - }, - { - "amount": 0.6275160493827139, - "date": "2015-10-16T00:30:00", - "unit": "g" - }, - { - "amount": 0.2825777777777727, - "date": "2015-10-16T00:35:00", - "unit": "g" - }, - { - "amount": 0.07344197530864438, - "date": "2015-10-16T00:40:00", - "unit": "g" - }, - { - "amount": 0.00010864197529958375, - "date": "2015-10-16T00:45:00", - "unit": "g" - }, - { - "amount": 0.0, - "date": "2015-10-16T00:50:00", - "unit": "g" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/dynamic_glucose_effect_fully_observed_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/dynamic_glucose_effect_fully_observed_output.json deleted file mode 100644 index ee49919ec..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/dynamic_glucose_effect_fully_observed_output.json +++ /dev/null @@ -1,373 +0,0 @@ -[ - { - "date" : "2015-10-15T21:30:00", - "amount" : 0, - "unit": "mg/dL" - - }, - { - "date" : "2015-10-15T21:35:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "amount" : 0, - "date" : "2015-10-15T21:40:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T21:45:00", - "amount" : 25.000000000000004, - "unit": "mg/dL" - }, - { - "amount" : 40, - "date" : "2015-10-15T21:50:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T21:55:00", - "amount" : 50.000000000000007, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:00:00", - "amount" : 65, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:05:00", - "amount" : 90, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:10:00", - "amount" : 90, - "unit": "mg/dL" - }, - { - "amount" : 90, - "date" : "2015-10-15T22:15:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:20:00", - "amount" : 115, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:25:00", - "amount" : 135, - "unit": "mg/dL" - }, - { - "amount" : 150, - "date" : "2015-10-15T22:30:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:35:00", - "amount" : 160, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:40:00", - "amount" : 165, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:45:00", - "amount" : 170, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:50:00", - "amount" : 175, - "unit": "mg/dL" - }, - { - "amount" : 185, - "date" : "2015-10-15T22:55:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T23:00:00", - "amount" : 200, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-15T23:05:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-15T23:10:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-15T23:15:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T23:20:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T23:25:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T23:30:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T23:35:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T23:40:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-15T23:45:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-15T23:50:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T23:55:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:00:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:05:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T00:10:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T00:15:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:20:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:25:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T00:30:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:35:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:40:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T00:45:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:50:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T00:55:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T01:00:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T01:05:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T01:10:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T01:15:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T01:20:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T01:25:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T01:30:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T01:35:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T01:40:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T01:45:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T01:50:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T01:55:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T02:00:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T02:05:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T02:10:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T02:15:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T02:20:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T02:25:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T02:30:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T02:35:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T02:40:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T02:45:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T02:50:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T02:55:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T03:00:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T03:05:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T03:10:00", - "amount" : 220, - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T03:15:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T03:20:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T03:25:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T03:30:00", - "unit": "mg/dL" - }, - { - "amount" : 220, - "date" : "2015-10-16T03:35:00", - "unit": "mg/dL" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/dynamic_glucose_effect_never_fully_observed_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/dynamic_glucose_effect_never_fully_observed_output.json deleted file mode 100644 index 279f6047d..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/dynamic_glucose_effect_never_fully_observed_output.json +++ /dev/null @@ -1,1092 +0,0 @@ -[ - { - "unit" : "mg\/dL", - "date" : "2015-10-15T21:30:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "mg\/dL", - "date" : "2015-10-15T21:35:00" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-15T21:40:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "mg\/dL", - "date" : "2015-10-15T21:45:00" - }, - { - "date" : "2015-10-15T21:50:00", - "unit" : "mg\/dL", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "mg\/dL", - "date" : "2015-10-15T21:55:00" - }, - { - "amount" : 0, - "unit" : "mg\/dL", - "date" : "2015-10-15T22:00:00" - }, - { - "date" : "2015-10-15T22:05:00", - "amount" : 0, - "unit" : "mg\/dL" - }, - { - "amount" : 3.125, - "unit" : "mg\/dL", - "date" : "2015-10-15T22:10:00" - }, - { - "date" : "2015-10-15T22:15:00", - "amount" : 6.25, - "unit" : "mg\/dL" - }, - { - "amount" : 9.375, - "date" : "2015-10-15T22:20:00", - "unit" : "mg\/dL" - }, - { - "amount" : 12.5, - "date" : "2015-10-15T22:25:00", - "unit" : "mg\/dL" - }, - { - "amount" : 15.625, - "date" : "2015-10-15T22:30:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "amount" : 18.75, - "date" : "2015-10-15T22:35:00" - }, - { - "unit" : "mg\/dL", - "amount" : 21.875, - "date" : "2015-10-15T22:40:00" - }, - { - "date" : "2015-10-15T22:45:00", - "amount" : 25, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-15T22:50:00", - "amount" : 28.125 - }, - { - "amount" : 31.25, - "unit" : "mg\/dL", - "date" : "2015-10-15T22:55:00" - }, - { - "date" : "2015-10-15T23:00:00", - "amount" : 34.375, - "unit" : "mg\/dL" - }, - { - "amount" : 37.5, - "unit" : "mg\/dL", - "date" : "2015-10-15T23:05:00" - }, - { - "amount" : 40.625, - "date" : "2015-10-15T23:10:00", - "unit" : "mg\/dL" - }, - { - "amount" : 43.75, - "unit" : "mg\/dL", - "date" : "2015-10-15T23:15:00" - }, - { - "date" : "2015-10-15T23:20:00", - "amount" : 46.875, - "unit" : "mg\/dL" - }, - { - "amount" : 50, - "date" : "2015-10-15T23:25:00", - "unit" : "mg\/dL" - }, - { - "amount" : 53.125, - "unit" : "mg\/dL", - "date" : "2015-10-15T23:30:00" - }, - { - "unit" : "mg\/dL", - "amount" : 56.25, - "date" : "2015-10-15T23:35:00" - }, - { - "date" : "2015-10-15T23:40:00", - "unit" : "mg\/dL", - "amount" : 59.375 - }, - { - "date" : "2015-10-15T23:45:00", - "amount" : 62.5, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-15T23:50:00", - "amount" : 65.625 - }, - { - "date" : "2015-10-15T23:55:00", - "amount" : 68.75, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T00:00:00", - "amount" : 71.875, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T00:05:00", - "amount" : 75 - }, - { - "amount" : 78.125000000000014, - "unit" : "mg\/dL", - "date" : "2015-10-16T00:10:00" - }, - { - "date" : "2015-10-16T00:15:00", - "unit" : "mg\/dL", - "amount" : 81.25 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T00:20:00", - "amount" : 84.375 - }, - { - "date" : "2015-10-16T00:25:00", - "unit" : "mg\/dL", - "amount" : 87.5 - }, - { - "date" : "2015-10-16T00:30:00", - "amount" : 90.625, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T00:35:00", - "amount" : 93.75, - "unit" : "mg\/dL" - }, - { - "amount" : 96.875, - "unit" : "mg\/dL", - "date" : "2015-10-16T00:40:00" - }, - { - "unit" : "mg\/dL", - "amount" : 100, - "date" : "2015-10-16T00:45:00" - }, - { - "amount" : 103.125, - "unit" : "mg\/dL", - "date" : "2015-10-16T00:50:00" - }, - { - "date" : "2015-10-16T00:55:00", - "unit" : "mg\/dL", - "amount" : 106.25 - }, - { - "amount" : 109.375, - "unit" : "mg\/dL", - "date" : "2015-10-16T01:00:00" - }, - { - "date" : "2015-10-16T01:05:00", - "amount" : 112.5, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T01:10:00", - "amount" : 115.625 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T01:15:00", - "amount" : 118.75 - }, - { - "amount" : 121.875, - "unit" : "mg\/dL", - "date" : "2015-10-16T01:20:00" - }, - { - "amount" : 125, - "date" : "2015-10-16T01:25:00", - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T01:30:00", - "unit" : "mg\/dL", - "amount" : 128.125 - }, - { - "date" : "2015-10-16T01:35:00", - "unit" : "mg\/dL", - "amount" : 131.25 - }, - { - "amount" : 134.375, - "date" : "2015-10-16T01:40:00", - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T01:45:00", - "unit" : "mg\/dL", - "amount" : 137.5 - }, - { - "date" : "2015-10-16T01:50:00", - "amount" : 140.625, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "amount" : 143.75, - "date" : "2015-10-16T01:55:00" - }, - { - "amount" : 146.875, - "date" : "2015-10-16T02:00:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T02:05:00" - }, - { - "date" : "2015-10-16T02:10:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "amount" : 150, - "date" : "2015-10-16T02:15:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T02:20:00" - }, - { - "date" : "2015-10-16T02:25:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T02:30:00", - "amount" : 150 - }, - { - "amount" : 150, - "date" : "2015-10-16T02:35:00", - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T02:40:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T02:45:00" - }, - { - "date" : "2015-10-16T02:50:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T02:55:00", - "amount" : 150 - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T03:00:00" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T03:05:00", - "amount" : 150 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T03:10:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T03:15:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T03:20:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T03:25:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "amount" : 150, - "date" : "2015-10-16T03:30:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T03:35:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T03:40:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T03:45:00" - }, - { - "amount" : 150, - "date" : "2015-10-16T03:50:00", - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T03:55:00" - }, - { - "date" : "2015-10-16T04:00:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T04:05:00" - }, - { - "date" : "2015-10-16T04:10:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T04:15:00" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T04:20:00" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T04:25:00" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T04:30:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T04:35:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "date" : "2015-10-16T04:40:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T04:45:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T04:50:00", - "amount" : 150 - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T04:55:00" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T05:00:00" - }, - { - "date" : "2015-10-16T05:05:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T05:10:00" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T05:15:00" - }, - { - "date" : "2015-10-16T05:20:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T05:25:00" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T05:30:00" - }, - { - "date" : "2015-10-16T05:35:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T05:40:00" - }, - { - "date" : "2015-10-16T05:45:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "date" : "2015-10-16T05:50:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "date" : "2015-10-16T05:55:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "amount" : 150, - "date" : "2015-10-16T06:00:00", - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "date" : "2015-10-16T06:05:00", - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T06:10:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T06:15:00" - }, - { - "date" : "2015-10-16T06:20:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "date" : "2015-10-16T06:25:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "date" : "2015-10-16T06:30:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "amount" : 150, - "date" : "2015-10-16T06:35:00", - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T06:40:00" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T06:45:00" - }, - { - "date" : "2015-10-16T06:50:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "date" : "2015-10-16T06:55:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T07:00:00", - "amount" : 150 - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T07:05:00" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T07:10:00" - }, - { - "amount" : 150, - "date" : "2015-10-16T07:15:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T07:20:00", - "amount" : 150 - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T07:25:00" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T07:30:00" - }, - { - "amount" : 150, - "date" : "2015-10-16T07:35:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T07:40:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T07:45:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "date" : "2015-10-16T07:50:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "date" : "2015-10-16T07:55:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T08:00:00", - "amount" : 150 - }, - { - "amount" : 150, - "date" : "2015-10-16T08:05:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T08:10:00", - "amount" : 150 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T08:15:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T08:20:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T08:25:00", - "amount" : 150 - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T08:30:00" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T08:35:00" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T08:40:00" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T08:45:00" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T08:50:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T08:55:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "date" : "2015-10-16T09:00:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "date" : "2015-10-16T09:05:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T09:10:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T09:15:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T09:20:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T09:25:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T09:30:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T09:35:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T09:40:00" - }, - { - "date" : "2015-10-16T09:45:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T09:50:00" - }, - { - "date" : "2015-10-16T09:55:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T10:00:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T10:05:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T10:10:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T10:15:00" - }, - { - "amount" : 150, - "date" : "2015-10-16T10:20:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T10:25:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T10:30:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T10:35:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T10:40:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T10:45:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "date" : "2015-10-16T10:50:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T10:55:00" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T11:00:00" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T11:05:00" - }, - { - "date" : "2015-10-16T11:10:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T11:15:00" - }, - { - "date" : "2015-10-16T11:20:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T11:25:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T11:30:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T11:35:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T11:40:00" - }, - { - "date" : "2015-10-16T11:45:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T11:50:00" - }, - { - "date" : "2015-10-16T11:55:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T12:00:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T12:05:00" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T12:10:00", - "amount" : 150 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T12:15:00", - "amount" : 150 - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T12:20:00" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T12:25:00" - }, - { - "date" : "2015-10-16T12:30:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T12:35:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T12:40:00" - }, - { - "amount" : 150, - "date" : "2015-10-16T12:45:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T12:50:00" - }, - { - "date" : "2015-10-16T12:55:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T13:00:00", - "amount" : 150 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T13:05:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T13:10:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T13:15:00" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T13:20:00", - "amount" : 150 - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T13:25:00" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T13:30:00" - }, - { - "amount" : 150, - "date" : "2015-10-16T13:35:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T13:40:00", - "amount" : 150 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T13:45:00", - "amount" : 150 - }, - { - "amount" : 150, - "date" : "2015-10-16T13:50:00", - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T13:55:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T14:00:00", - "amount" : 150 - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T14:05:00" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T14:10:00", - "amount" : 150 - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T14:15:00" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T14:20:00" - }, - { - "unit" : "mg\/dL", - "amount" : 150, - "date" : "2015-10-16T14:25:00" - }, - { - "date" : "2015-10-16T14:30:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T14:35:00", - "unit" : "mg\/dL", - "amount" : 150 - }, - { - "amount" : 150, - "date" : "2015-10-16T14:40:00", - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "date" : "2015-10-16T14:45:00", - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T14:50:00" - }, - { - "amount" : 150, - "unit" : "mg\/dL", - "date" : "2015-10-16T14:55:00" - }, - { - "date" : "2015-10-16T15:00:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T15:05:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T15:10:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "date" : "2015-10-16T15:15:00", - "unit" : "mg\/dL" - }, - { - "amount" : 150, - "date" : "2015-10-16T15:20:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T15:25:00", - "amount" : 150 - }, - { - "date" : "2015-10-16T15:30:00", - "amount" : 150, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T15:35:00", - "amount" : 150 - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/dynamic_glucose_effect_none_observed_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/dynamic_glucose_effect_none_observed_output.json deleted file mode 100644 index 0dd97823a..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/dynamic_glucose_effect_none_observed_output.json +++ /dev/null @@ -1,372 +0,0 @@ -[ - { - "date" : "2015-10-15T21:30:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T21:35:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T21:40:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "amount" : 0, - "date" : "2015-10-15T21:45:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T21:50:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T21:55:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:00:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:05:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "amount" : 0, - "date" : "2015-10-15T22:10:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:15:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:20:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:25:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:30:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "amount" : 0, - "date" : "2015-10-15T22:35:00", - "unit": "mg/dL" - }, - { - "amount" : 0, - "date" : "2015-10-15T22:40:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:45:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "amount" : 0, - "date" : "2015-10-15T22:50:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T22:55:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T23:00:00", - "amount" : 0, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T23:05:00", - "amount" : 2.7777777777777777, - "unit": "mg/dL" - }, - { - "amount" : 5.5555555555555554, - "date" : "2015-10-15T23:10:00", - "unit": "mg/dL" - }, - { - "amount" : 8.3333333333333339, - "date" : "2015-10-15T23:15:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T23:20:00", - "amount" : 11.111111111111111, - "unit": "mg/dL" - }, - { - "amount" : 13.888888888888889, - "date" : "2015-10-15T23:25:00", - "unit": "mg/dL" - }, - { - "amount" : 16.666666666666668, - "date" : "2015-10-15T23:30:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T23:35:00", - "amount" : 19.444444444444446, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T23:40:00", - "amount" : 22.222222222222221, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T23:45:00", - "amount" : 25, - "unit": "mg/dL" - }, - { - "date" : "2015-10-15T23:50:00", - "amount" : 27.777777777777779, - "unit": "mg/dL" - }, - { - "amount" : 30.555555555555557, - "date" : "2015-10-15T23:55:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:00:00", - "amount" : 33.333333333333336, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:05:00", - "amount" : 36.111111111111114, - "unit": "mg/dL" - }, - { - "amount" : 38.888888888888893, - "date" : "2015-10-16T00:10:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:15:00", - "amount" : 41.666666666666671, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:20:00", - "amount" : 44.444444444444443, - "unit": "mg/dL" - }, - { - "amount" : 47.222222222222221, - "date" : "2015-10-16T00:25:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:30:00", - "amount" : 50, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:35:00", - "amount" : 52.777777777777779, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:40:00", - "amount" : 55.555555555555557, - "unit": "mg/dL" - }, - { - "amount" : 58.333333333333336, - "date" : "2015-10-16T00:45:00", - "unit": "mg/dL" - }, - { - "amount" : 61.111111111111114, - "date" : "2015-10-16T00:50:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T00:55:00", - "amount" : 63.888888888888893, - "unit": "mg/dL" - }, - { - "amount" : 66.666666666666671, - "date" : "2015-10-16T01:00:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T01:05:00", - "amount" : 69.444444444444457, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T01:10:00", - "amount" : 72.222222222222229, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T01:15:00", - "amount" : 75, - "unit": "mg/dL" - }, - { - "amount" : 77.777777777777786, - "date" : "2015-10-16T01:20:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T01:25:00", - "amount" : 80.555555555555557, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T01:30:00", - "amount" : 83.333333333333343, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T01:35:00", - "amount" : 86.111111111111114, - "unit": "mg/dL" - }, - { - "amount" : 88.888888888888886, - "date" : "2015-10-16T01:40:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T01:45:00", - "amount" : 91.666666666666671, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T01:50:00", - "amount" : 94.444444444444443, - "unit": "mg/dL" - }, - { - "amount" : 97.222222222222229, - "date" : "2015-10-16T01:55:00", - "unit": "mg/dL" - }, - { - "amount" : 100, - "date" : "2015-10-16T02:00:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T02:05:00", - "amount" : 102.77777777777779, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T02:10:00", - "amount" : 105.55555555555556, - "unit": "mg/dL" - }, - { - "amount" : 108.33333333333334, - "date" : "2015-10-16T02:15:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T02:20:00", - "amount" : 111.11111111111111, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T02:25:00", - "amount" : 113.8888888888889, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T02:30:00", - "amount" : 116.66666666666667, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T02:35:00", - "amount" : 119.44444444444444, - "unit": "mg/dL" - }, - { - "amount" : 122.22222222222223, - "date" : "2015-10-16T02:40:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T02:45:00", - "amount" : 125, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T02:50:00", - "amount" : 127.77777777777779, - "unit": "mg/dL" - }, - { - "amount" : 130.55555555555557, - "date" : "2015-10-16T02:55:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T03:00:00", - "amount" : 133.33333333333334, - "unit": "mg/dL" - }, - { - "amount" : 133.33333333333334, - "date" : "2015-10-16T03:05:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T03:10:00", - "amount" : 133.33333333333334, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T03:15:00", - "amount" : 133.33333333333334, - "unit": "mg/dL" - }, - { - "amount" : 133.33333333333334, - "date" : "2015-10-16T03:20:00", - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T03:25:00", - "amount" : 133.33333333333334, - "unit": "mg/dL" - }, - { - "date" : "2015-10-16T03:30:00", - "amount" : 133.33333333333334, - "unit": "mg/dL" - }, - { - "amount" : 133.33333333333334, - "date" : "2015-10-16T03:35:00", - "unit": "mg/dL" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/dynamic_glucose_effect_partially_observed_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/dynamic_glucose_effect_partially_observed_output.json deleted file mode 100644 index e3e1fb459..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/dynamic_glucose_effect_partially_observed_output.json +++ /dev/null @@ -1,372 +0,0 @@ -[ - { - "amount" : 0, - "unit" : "mg\/dL", - "date" : "2015-10-15T21:30:00" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-15T21:35:00", - "amount" : 0 - }, - { - "unit" : "mg\/dL", - "amount" : 0, - "date" : "2015-10-15T21:40:00" - }, - { - "amount" : 25.000000000000004, - "date" : "2015-10-15T21:45:00", - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-15T21:50:00", - "amount" : 40, - "unit" : "mg\/dL" - }, - { - "amount" : 50.000000000000007, - "unit" : "mg\/dL", - "date" : "2015-10-15T21:55:00" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-15T22:00:00", - "amount" : 65 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-15T22:05:00", - "amount" : 90 - }, - { - "date" : "2015-10-15T22:10:00", - "amount" : 94.399999999999991, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "amount" : 98.983333333333334, - "date" : "2015-10-15T22:15:00" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-15T22:20:00", - "amount" : 103.56666666666668 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-15T22:25:00", - "amount" : 108.15000000000001 - }, - { - "date" : "2015-10-15T22:30:00", - "unit" : "mg\/dL", - "amount" : 112.73333333333333 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-15T22:35:00", - "amount" : 117.31666666666668 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-15T22:40:00", - "amount" : 121.90000000000001 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-15T22:45:00", - "amount" : 126.48333333333333 - }, - { - "date" : "2015-10-15T22:50:00", - "amount" : 131.06666666666666, - "unit" : "mg\/dL" - }, - { - "amount" : 135.65000000000001, - "unit" : "mg\/dL", - "date" : "2015-10-15T22:55:00" - }, - { - "date" : "2015-10-15T23:00:00", - "unit" : "mg\/dL", - "amount" : 140.23333333333335 - }, - { - "amount" : 144.81666666666666, - "unit" : "mg\/dL", - "date" : "2015-10-15T23:05:00" - }, - { - "amount" : 149.40000000000001, - "date" : "2015-10-15T23:10:00", - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-15T23:15:00", - "amount" : 153.98333333333335, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-15T23:20:00", - "amount" : 158.56666666666666, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-15T23:25:00", - "unit" : "mg\/dL", - "amount" : 163.15000000000001 - }, - { - "unit" : "mg\/dL", - "amount" : 167.73333333333335, - "date" : "2015-10-15T23:30:00" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-15T23:35:00", - "amount" : 172.31666666666669 - }, - { - "date" : "2015-10-15T23:40:00", - "unit" : "mg\/dL", - "amount" : 176.90000000000001 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-15T23:45:00", - "amount" : 181.48333333333335 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-15T23:50:00", - "amount" : 186.06666666666669 - }, - { - "amount" : 190.65000000000001, - "date" : "2015-10-15T23:55:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T00:00:00", - "amount" : 195.23333333333335 - }, - { - "date" : "2015-10-16T00:05:00", - "amount" : 199.81666666666669, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T00:10:00", - "amount" : 204.40000000000001, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T00:15:00", - "amount" : 208.98333333333335, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "amount" : 213.56666666666669, - "date" : "2015-10-16T00:20:00" - }, - { - "amount" : 218.15000000000001, - "date" : "2015-10-16T00:25:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T00:30:00", - "amount" : 220 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T00:35:00", - "amount" : 220 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T00:40:00", - "amount" : 220 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T00:45:00", - "amount" : 220 - }, - { - "date" : "2015-10-16T00:50:00", - "amount" : 220, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T00:55:00", - "amount" : 220 - }, - { - "amount" : 220, - "unit" : "mg\/dL", - "date" : "2015-10-16T01:00:00" - }, - { - "amount" : 220, - "date" : "2015-10-16T01:05:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T01:10:00", - "amount" : 220 - }, - { - "unit" : "mg\/dL", - "amount" : 220, - "date" : "2015-10-16T01:15:00" - }, - { - "date" : "2015-10-16T01:20:00", - "amount" : 220, - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T01:25:00", - "amount" : 220 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T01:30:00", - "amount" : 220 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T01:35:00", - "amount" : 220 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T01:40:00", - "amount" : 220 - }, - { - "date" : "2015-10-16T01:45:00", - "amount" : 220, - "unit" : "mg\/dL" - }, - { - "amount" : 220, - "unit" : "mg\/dL", - "date" : "2015-10-16T01:50:00" - }, - { - "amount" : 220, - "date" : "2015-10-16T01:55:00", - "unit" : "mg\/dL" - }, - { - "amount" : 220, - "unit" : "mg\/dL", - "date" : "2015-10-16T02:00:00" - }, - { - "amount" : 220, - "date" : "2015-10-16T02:05:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T02:10:00", - "amount" : 220 - }, - { - "unit" : "mg\/dL", - "amount" : 220, - "date" : "2015-10-16T02:15:00" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T02:20:00", - "amount" : 220 - }, - { - "amount" : 220, - "date" : "2015-10-16T02:25:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T02:30:00", - "amount" : 220 - }, - { - "amount" : 220, - "date" : "2015-10-16T02:35:00", - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T02:40:00", - "unit" : "mg\/dL", - "amount" : 220 - }, - { - "date" : "2015-10-16T02:45:00", - "amount" : 220, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T02:50:00", - "amount" : 220, - "unit" : "mg\/dL" - }, - { - "date" : "2015-10-16T02:55:00", - "unit" : "mg\/dL", - "amount" : 220 - }, - { - "date" : "2015-10-16T03:00:00", - "unit" : "mg\/dL", - "amount" : 220 - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T03:05:00", - "amount" : 220 - }, - { - "unit" : "mg\/dL", - "amount" : 220, - "date" : "2015-10-16T03:10:00" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T03:15:00", - "amount" : 220 - }, - { - "amount" : 220, - "unit" : "mg\/dL", - "date" : "2015-10-16T03:20:00" - }, - { - "unit" : "mg\/dL", - "amount" : 220, - "date" : "2015-10-16T03:25:00" - }, - { - "amount" : 220, - "date" : "2015-10-16T03:30:00", - "unit" : "mg\/dL" - }, - { - "unit" : "mg\/dL", - "date" : "2015-10-16T03:35:00", - "amount" : 220 - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/grouped_by_overlapping_absorption_times_border_case_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/grouped_by_overlapping_absorption_times_border_case_input.json deleted file mode 100644 index dc6ab9eeb..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/grouped_by_overlapping_absorption_times_border_case_input.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "amount": 44, - "description": "BolusWizard: 44g", - "end_at": "2015-10-15T15:55:28", - "start_at": "2015-10-15T15:55:28", - "type": "Meal", - "unit": "g" - }, - { - "amount": 35, - "description": "JournalEntryMealMarker: 35g", - "end_at": "2015-10-15T12:55:28", - "start_at": "2015-10-15T12:55:28", - "type": "Meal", - "unit": "g" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/grouped_by_overlapping_absorption_times_border_case_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/grouped_by_overlapping_absorption_times_border_case_output.json deleted file mode 100644 index d9550c14f..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/grouped_by_overlapping_absorption_times_border_case_output.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - [ - { - "amount": 35, - "description": "JournalEntryMealMarker: 35g", - "end_at": "2015-10-15T12:55:28", - "start_at": "2015-10-15T12:55:28", - "type": "Meal", - "unit": "g" - } - ], - [ - { - "amount": 44, - "description": "BolusWizard: 44g", - "end_at": "2015-10-15T15:55:28", - "start_at": "2015-10-15T15:55:28", - "type": "Meal", - "unit": "g" - } - ] -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/grouped_by_overlapping_absorption_times_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/grouped_by_overlapping_absorption_times_input.json deleted file mode 100644 index 318012718..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/grouped_by_overlapping_absorption_times_input.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "amount": 44, - "description": "BolusWizard: 44g", - "end_at": "2015-10-15T21:35:12", - "start_at": "2015-10-15T21:35:12", - "type": "Meal", - "unit": "g" - }, - { - "amount": 35, - "description": "JournalEntryMealMarker: 35g", - "end_at": "2015-10-15T12:55:28", - "start_at": "2015-10-15T12:55:28", - "type": "Meal", - "unit": "g" - }, - { - "amount": 30, - "description": "BolusWizard: 30g", - "end_at": "2015-10-15T15:05:10", - "start_at": "2015-10-15T15:05:10", - "type": "Meal", - "unit": "g" - }, - { - "amount": 20, - "description": "JournalEntryMealMarker: 20g", - "end_at": "2015-10-15T18:58:10", - "start_at": "2015-10-15T18:58:10", - "type": "Meal", - "unit": "g" - }, - { - "amount": 30, - "description": "JournalEntryMealMarker: 30g", - "end_at": "2015-10-15T18:52:32", - "start_at": "2015-10-15T18:52:32", - "type": "Meal", - "unit": "g" - }, - { - "amount": 30, - "description": "JournalEntryMealMarker: 30g", - "end_at": "2015-10-15T18:43:56", - "start_at": "2015-10-15T18:43:56", - "type": "Meal", - "unit": "g" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/grouped_by_overlapping_absorption_times_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/grouped_by_overlapping_absorption_times_output.json deleted file mode 100644 index d8562f0ce..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/grouped_by_overlapping_absorption_times_output.json +++ /dev/null @@ -1,54 +0,0 @@ -[ - [ - { - "amount": 35, - "description": "JournalEntryMealMarker: 35g", - "end_at": "2015-10-15T12:55:28", - "start_at": "2015-10-15T12:55:28", - "type": "Meal", - "unit": "g" - }, - { - "amount": 30, - "description": "BolusWizard: 30g", - "end_at": "2015-10-15T15:05:10", - "start_at": "2015-10-15T15:05:10", - "type": "Meal", - "unit": "g" - } - ], - [ - { - "amount": 30, - "description": "JournalEntryMealMarker: 30g", - "end_at": "2015-10-15T18:43:56", - "start_at": "2015-10-15T18:43:56", - "type": "Meal", - "unit": "g" - }, - { - "amount": 30, - "description": "JournalEntryMealMarker: 30g", - "end_at": "2015-10-15T18:52:32", - "start_at": "2015-10-15T18:52:32", - "type": "Meal", - "unit": "g" - }, - { - "amount": 20, - "description": "JournalEntryMealMarker: 20g", - "end_at": "2015-10-15T18:58:10", - "start_at": "2015-10-15T18:58:10", - "type": "Meal", - "unit": "g" - }, - { - "amount": 44, - "description": "BolusWizard: 44g", - "end_at": "2015-10-15T21:35:12", - "start_at": "2015-10-15T21:35:12", - "type": "Meal", - "unit": "g" - } - ] -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_1_hour_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_1_hour_input.json deleted file mode 100644 index 861aec5b8..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_1_hour_input.json +++ /dev/null @@ -1,92 +0,0 @@ -[ - { - "velocity": 0.0, - "start_at": "2015-10-15T21:30:12", - "end_at": "2015-10-15T21:35:12" - }, - { - "velocity": 5.0, - "start_at": "2015-10-15T21:35:12", - "end_at": "2015-10-15T21:40:12" - }, - { - "velocity": 3.0, - "start_at": "2015-10-15T21:40:12", - "end_at": "2015-10-15T21:45:12" - }, - { - "velocity": 2.0, - "start_at": "2015-10-15T21:45:12", - "end_at": "2015-10-15T21:50:12" - }, - { - "velocity": 3.0, - "start_at": "2015-10-15T21:50:12", - "end_at": "2015-10-15T21:55:12" - }, - { - "velocity": 5.0, - "start_at": "2015-10-15T21:55:12", - "end_at": "2015-10-15T22:00:12" - }, - { - "velocity": -2.0, - "start_at": "2015-10-15T22:00:12", - "end_at": "2015-10-15T22:05:12" - }, - { - "velocity": -1.0, - "start_at": "2015-10-15T22:05:12", - "end_at": "2015-10-15T22:10:12" - }, - { - "velocity": 5.0, - "start_at": "2015-10-15T22:10:12", - "end_at": "2015-10-15T22:15:12" - }, - { - "velocity": 4.0, - "start_at": "2015-10-15T22:15:12", - "end_at": "2015-10-15T22:20:12" - }, - { - "velocity": 3.0, - "start_at": "2015-10-15T22:20:12", - "end_at": "2015-10-15T22:25:12" - }, - { - "velocity": 2.0, - "start_at": "2015-10-15T22:25:12", - "end_at": "2015-10-15T22:30:12" - }, - { - "velocity": 1.0, - "start_at": "2015-10-15T22:30:12", - "end_at": "2015-10-15T22:35:12" - }, - { - "velocity": 1.0, - "start_at": "2015-10-15T22:35:12", - "end_at": "2015-10-15T22:40:12" - }, - { - "velocity": 1.0, - "start_at": "2015-10-15T22:40:12", - "end_at": "2015-10-15T22:45:12" - }, - { - "velocity": 2.0, - "start_at": "2015-10-15T22:45:12", - "end_at": "2015-10-15T22:50:12" - }, - { - "velocity": 3.0, - "start_at": "2015-10-15T22:50:12", - "end_at": "2015-10-15T22:55:12" - }, - { - "velocity": 4.0, - "start_at": "2015-10-15T22:55:12", - "end_at": "2015-10-15T23:00:12" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_1_hour_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_1_hour_output.json deleted file mode 100644 index f30ca9009..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_1_hour_output.json +++ /dev/null @@ -1,372 +0,0 @@ -[ - { - "unit" : "g", - "date" : "2015-10-15T21:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:35:00", - "amount" : 44 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:40:00", - "amount" : 44 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:45:00", - "amount" : 39 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:50:00", - "amount" : 36 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:55:00", - "amount" : 34 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:00:00", - "amount" : 31 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:05:00", - "amount" : 26 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:10:00", - "amount" : 26 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:15:00", - "amount" : 26 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:20:00", - "amount" : 21 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:25:00", - "amount" : 17 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:30:00", - "amount" : 14 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:35:00", - "amount" : 12 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:40:00", - "amount" : 11 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:45:00", - "amount" : 10 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:50:00", - "amount" : 9 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:55:00", - "amount" : 7 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:00:00", - "amount" : 4 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:35:00", - "amount" : 0 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_input.json deleted file mode 100644 index 78f7cddb5..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_input.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "velocity": 0.0, - "start_at": "2015-10-15T21:30:12", - "end_at": "2015-10-15T21:35:12" - }, - { - "velocity": 5.0, - "start_at": "2015-10-15T21:35:12", - "end_at": "2015-10-15T21:40:12" - }, - { - "velocity": 3.0, - "start_at": "2015-10-15T21:40:12", - "end_at": "2015-10-15T21:45:12" - }, - { - "velocity": 2.0, - "start_at": "2015-10-15T21:45:12", - "end_at": "2015-10-15T21:50:12" - }, - { - "velocity": 3.0, - "start_at": "2015-10-15T21:50:12", - "end_at": "2015-10-15T21:55:12" - }, - { - "velocity": 5.0, - "start_at": "2015-10-15T21:55:12", - "end_at": "2015-10-15T22:00:12" - }, - { - "velocity": -2.0, - "start_at": "2015-10-15T22:00:12", - "end_at": "2015-10-15T22:05:12" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_none_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_none_output.json deleted file mode 100644 index 3efc5c621..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_none_output.json +++ /dev/null @@ -1,372 +0,0 @@ -[ - { - "unit" : "g", - "date" : "2015-10-15T21:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:55:00", - "amount" : 30 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:00:00", - "amount" : 30 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:05:00", - "amount" : 30 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:10:00", - "amount" : 30 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:15:00", - "amount" : 29.375 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:20:00", - "amount" : 28.75 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:25:00", - "amount" : 28.125 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:30:00", - "amount" : 27.5 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:35:00", - "amount" : 26.875 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:40:00", - "amount" : 26.25 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:45:00", - "amount" : 25.625 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:50:00", - "amount" : 25 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:55:00", - "amount" : 24.375 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:00:00", - "amount" : 23.75 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:05:00", - "amount" : 23.125 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:10:00", - "amount" : 22.5 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:15:00", - "amount" : 21.875 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:20:00", - "amount" : 21.25 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:25:00", - "amount" : 20.625 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:30:00", - "amount" : 20 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:35:00", - "amount" : 19.375 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:40:00", - "amount" : 18.75 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:45:00", - "amount" : 18.125 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:50:00", - "amount" : 17.5 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:55:00", - "amount" : 16.875 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:00:00", - "amount" : 16.25 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:05:00", - "amount" : 15.625 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:10:00", - "amount" : 15 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:15:00", - "amount" : 14.375 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:20:00", - "amount" : 13.75 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:25:00", - "amount" : 13.125 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:30:00", - "amount" : 12.5 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:35:00", - "amount" : 11.875 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:40:00", - "amount" : 11.25 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:45:00", - "amount" : 10.625 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:50:00", - "amount" : 10 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:55:00", - "amount" : 9.375 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:00:00", - "amount" : 8.75 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:05:00", - "amount" : 8.125 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:10:00", - "amount" : 7.5 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:15:00", - "amount" : 6.875 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:20:00", - "amount" : 6.25 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:25:00", - "amount" : 5.625 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:30:00", - "amount" : 5 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:35:00", - "amount" : 4.375 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:40:00", - "amount" : 3.75 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:45:00", - "amount" : 3.125 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:50:00", - "amount" : 2.5 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:55:00", - "amount" : 1.875 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:00:00", - "amount" : 1.25 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:05:00", - "amount" : 0.625 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:35:00", - "amount" : 0 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_none_piecewiselinear_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_none_piecewiselinear_output.json deleted file mode 100644 index f5b909ec6..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_none_piecewiselinear_output.json +++ /dev/null @@ -1,372 +0,0 @@ -[ - { - "amount" : 0, - "date" : "2015-10-15T21:30:00", - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-15T21:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:40:00", - "amount" : 0 - }, - { - "amount" : 0, - "date" : "2015-10-15T21:45:00", - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-15T21:50:00", - "unit" : "g" - }, - { - "date" : "2015-10-15T21:55:00", - "unit" : "g", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-15T22:05:00" - }, - { - "unit" : "g", - "date" : "2015-10-15T22:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:25:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-15T22:30:00" - }, - { - "date" : "2015-10-15T22:35:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-15T22:40:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-15T22:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-15T22:50:00" - }, - { - "date" : "2015-10-15T22:55:00", - "amount" : 30, - "unit" : "g" - }, - { - "amount" : 30, - "unit" : "g", - "date" : "2015-10-15T23:00:00" - }, - { - "unit" : "g", - "date" : "2015-10-15T23:05:00", - "amount" : 30 - }, - { - "date" : "2015-10-15T23:10:00", - "amount" : 30, - "unit" : "g" - }, - { - "amount" : 29.885688157293096, - "unit" : "g", - "date" : "2015-10-15T23:15:00" - }, - { - "date" : "2015-10-15T23:20:00", - "amount" : 29.542752629172384, - "unit" : "g" - }, - { - "date" : "2015-10-15T23:25:00", - "amount" : 28.97119341563786, - "unit" : "g" - }, - { - "date" : "2015-10-15T23:30:00", - "amount" : 28.171010516689527, - "unit" : "g" - }, - { - "amount" : 27.142203932327391, - "unit" : "g", - "date" : "2015-10-15T23:35:00" - }, - { - "date" : "2015-10-15T23:40:00", - "amount" : 25.925925925925927, - "unit" : "g" - }, - { - "amount" : 24.691358024691358, - "date" : "2015-10-15T23:45:00", - "unit" : "g" - }, - { - "date" : "2015-10-15T23:50:00", - "amount" : 23.456790123456791, - "unit" : "g" - }, - { - "date" : "2015-10-15T23:55:00", - "unit" : "g", - "amount" : 22.222222222222221 - }, - { - "amount" : 20.987654320987655, - "date" : "2015-10-16T00:00:00", - "unit" : "g" - }, - { - "amount" : 19.753086419753085, - "date" : "2015-10-16T00:05:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T00:10:00", - "amount" : 18.518518518518519, - "unit" : "g" - }, - { - "date" : "2015-10-16T00:15:00", - "unit" : "g", - "amount" : 17.283950617283953 - }, - { - "unit" : "g", - "amount" : 16.049382716049383, - "date" : "2015-10-16T00:20:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T00:25:00", - "amount" : 14.814814814814813 - }, - { - "date" : "2015-10-16T00:30:00", - "amount" : 13.580246913580249, - "unit" : "g" - }, - { - "amount" : 12.345679012345679, - "unit" : "g", - "date" : "2015-10-16T00:35:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T00:40:00", - "amount" : 11.111111111111114 - }, - { - "date" : "2015-10-16T00:45:00", - "unit" : "g", - "amount" : 9.910836762688616 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:50:00", - "amount" : 8.7791495198902609 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:55:00", - "amount" : 7.716049382716049 - }, - { - "amount" : 6.7215363511659802, - "date" : "2015-10-16T01:00:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T01:05:00", - "unit" : "g", - "amount" : 5.7956104252400564 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:10:00", - "amount" : 4.9382716049382722 - }, - { - "amount" : 4.1495198902606383, - "unit" : "g", - "date" : "2015-10-16T01:15:00" - }, - { - "amount" : 3.4293552812071395, - "date" : "2015-10-16T01:20:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T01:25:00", - "unit" : "g", - "amount" : 2.7777777777777768 - }, - { - "amount" : 2.1947873799725635, - "date" : "2015-10-16T01:30:00", - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T01:35:00", - "amount" : 1.6803840877914999 - }, - { - "unit" : "g", - "amount" : 1.2345679012345689, - "date" : "2015-10-16T01:40:00" - }, - { - "unit" : "g", - "amount" : 0.85733882030178399, - "date" : "2015-10-16T01:45:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T01:50:00", - "amount" : 0.54869684499314175 - }, - { - "unit" : "g", - "amount" : 0.30864197530864557, - "date" : "2015-10-16T01:55:00" - }, - { - "date" : "2015-10-16T02:00:00", - "unit" : "g", - "amount" : 0.13717421124828544 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:05:00", - "amount" : 0.03429355281207469 - }, - { - "date" : "2015-10-16T02:10:00", - "unit" : "g", - "amount" : 0 - }, - { - "date" : "2015-10-16T02:15:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T02:20:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T02:25:00" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T02:30:00" - }, - { - "date" : "2015-10-16T02:35:00", - "unit" : "g", - "amount" : 0 - }, - { - "amount" : 0, - "date" : "2015-10-16T02:40:00", - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T02:45:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T02:50:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T02:55:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T03:00:00" - }, - { - "date" : "2015-10-16T03:05:00", - "unit" : "g", - "amount" : 0 - }, - { - "date" : "2015-10-16T03:10:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T03:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:20:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T03:25:00", - "unit" : "g", - "amount" : 0 - }, - { - "date" : "2015-10-16T03:30:00", - "unit" : "g", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:35:00", - "amount" : 0 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_partial_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_partial_output.json deleted file mode 100644 index 794e58f08..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_partial_output.json +++ /dev/null @@ -1,372 +0,0 @@ -[ - { - "unit" : "g", - "date" : "2015-10-15T21:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:35:00", - "amount" : 44 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:40:00", - "amount" : 44 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:45:00", - "amount" : 39 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:50:00", - "amount" : 36 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:55:00", - "amount" : 34 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:00:00", - "amount" : 31 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:05:00", - "amount" : 26 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:10:00", - "amount" : 25.12 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:15:00", - "amount" : 24.20333333333333 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:20:00", - "amount" : 23.28666666666667 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:25:00", - "amount" : 22.37 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:30:00", - "amount" : 21.45333333333333 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:35:00", - "amount" : 20.53666666666667 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:40:00", - "amount" : 19.62 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:45:00", - "amount" : 18.70333333333333 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:50:00", - "amount" : 17.78666666666667 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:55:00", - "amount" : 16.87 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:00:00", - "amount" : 15.95333333333333 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:05:00", - "amount" : 15.03666666666667 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:10:00", - "amount" : 14.12 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:15:00", - "amount" : 13.20333333333333 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:20:00", - "amount" : 12.28666666666667 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:25:00", - "amount" : 11.37 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:30:00", - "amount" : 10.45333333333333 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:35:00", - "amount" : 9.536666666666664 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:40:00", - "amount" : 8.619999999999997 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:45:00", - "amount" : 7.703333333333331 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:50:00", - "amount" : 6.786666666666665 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:55:00", - "amount" : 5.869999999999999 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:00:00", - "amount" : 4.95333333333333 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:05:00", - "amount" : 4.036666666666664 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:10:00", - "amount" : 3.119999999999997 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:15:00", - "amount" : 2.20333333333333 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:20:00", - "amount" : 1.286666666666664 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:25:00", - "amount" : 0.3699999999999981 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:35:00", - "amount" : 0 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_partial_piecewiselinear_adaptiverate_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_partial_piecewiselinear_adaptiverate_output.json deleted file mode 100644 index b70ec14f7..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_partial_piecewiselinear_adaptiverate_output.json +++ /dev/null @@ -1,372 +0,0 @@ -[ - { - "unit" : "g", - "date" : "2015-10-15T21:30:00", - "amount" : 0 - }, - { - "date" : "2015-10-15T21:35:00", - "amount" : 44, - "unit" : "g" - }, - { - "amount" : 44, - "date" : "2015-10-15T21:40:00", - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-15T21:45:00", - "amount" : 39 - }, - { - "date" : "2015-10-15T21:50:00", - "amount" : 36, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-15T21:55:00", - "amount" : 34 - }, - { - "date" : "2015-10-15T22:00:00", - "amount" : 31, - "unit" : "g" - }, - { - "date" : "2015-10-15T22:05:00", - "amount" : 26, - "unit" : "g" - }, - { - "amount" : 22.337777777777781, - "unit" : "g", - "date" : "2015-10-15T22:10:00" - }, - { - "date" : "2015-10-15T22:15:00", - "amount" : 18.522962962962964, - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 14.746841212121204, - "date" : "2015-10-15T22:20:00" - }, - { - "amount" : 11.341165286195286, - "date" : "2015-10-15T22:25:00", - "unit" : "g" - }, - { - "amount" : 8.38199609427609, - "unit" : "g", - "date" : "2015-10-15T22:30:00" - }, - { - "amount" : 5.869333636363633, - "unit" : "g", - "date" : "2015-10-15T22:35:00" - }, - { - "date" : "2015-10-15T22:40:00", - "amount" : 3.803177912457913, - "unit" : "g" - }, - { - "amount" : 2.1835289225589243, - "date" : "2015-10-15T22:45:00", - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-15T22:50:00", - "amount" : 1.0103866666666668 - }, - { - "amount" : 0.28375114478115027, - "date" : "2015-10-15T22:55:00", - "unit" : "g" - }, - { - "date" : "2015-10-15T23:00:00", - "amount" : 0.0036223569023552393, - "unit" : "g" - }, - { - "date" : "2015-10-15T23:05:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-15T23:10:00", - "amount" : 0 - }, - { - "date" : "2015-10-15T23:15:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-15T23:20:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-15T23:25:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-15T23:30:00" - }, - { - "date" : "2015-10-15T23:35:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-15T23:40:00", - "unit" : "g", - "amount" : 0 - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-15T23:45:00" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-15T23:50:00" - }, - { - "amount" : 0, - "date" : "2015-10-15T23:55:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T00:00:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T00:05:00" - }, - { - "date" : "2015-10-16T00:10:00", - "unit" : "g", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T00:15:00" - }, - { - "amount" : 0, - "date" : "2015-10-16T00:20:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T00:25:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T00:30:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T00:35:00" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T00:40:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T00:45:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T00:50:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T00:55:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T01:00:00", - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T01:05:00", - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T01:10:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T01:15:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T01:20:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T01:25:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T01:30:00", - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T01:35:00", - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T01:40:00" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T01:45:00" - }, - { - "amount" : 0, - "date" : "2015-10-16T01:50:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T01:55:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T02:00:00", - "unit" : "g", - "amount" : 0 - }, - { - "date" : "2015-10-16T02:05:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T02:10:00" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T02:15:00" - }, - { - "date" : "2015-10-16T02:20:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T02:25:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T02:30:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T02:35:00", - "unit" : "g", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T02:40:00" - }, - { - "date" : "2015-10-16T02:45:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T02:50:00" - }, - { - "date" : "2015-10-16T02:55:00", - "unit" : "g", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T03:00:00" - }, - { - "date" : "2015-10-16T03:05:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T03:10:00" - }, - { - "date" : "2015-10-16T03:15:00", - "unit" : "g", - "amount" : 0 - }, - { - "amount" : 0, - "date" : "2015-10-16T03:20:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T03:25:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T03:30:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T03:35:00", - "amount" : 0 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_partial_piecewiselinear_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_partial_piecewiselinear_output.json deleted file mode 100644 index fb3ed22a6..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_35_min_partial_piecewiselinear_output.json +++ /dev/null @@ -1,372 +0,0 @@ -[ - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-15T21:30:00" - }, - { - "unit" : "g", - "amount" : 44, - "date" : "2015-10-15T21:35:00" - }, - { - "date" : "2015-10-15T21:40:00", - "amount" : 44, - "unit" : "g" - }, - { - "amount" : 39, - "date" : "2015-10-15T21:45:00", - "unit" : "g" - }, - { - "amount" : 36, - "date" : "2015-10-15T21:50:00", - "unit" : "g" - }, - { - "date" : "2015-10-15T21:55:00", - "unit" : "g", - "amount" : 34 - }, - { - "date" : "2015-10-15T22:00:00", - "unit" : "g", - "amount" : 31 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:05:00", - "amount" : 26 - }, - { - "amount" : 24.261728395061731, - "unit" : "g", - "date" : "2015-10-15T22:10:00" - }, - { - "unit" : "g", - "amount" : 22.451028806584361, - "date" : "2015-10-15T22:15:00" - }, - { - "unit" : "g", - "amount" : 20.640329218106992, - "date" : "2015-10-15T22:20:00" - }, - { - "unit" : "g", - "date" : "2015-10-15T22:25:00", - "amount" : 18.829629629629629 - }, - { - "unit" : "g", - "amount" : 17.018930041152263, - "date" : "2015-10-15T22:30:00" - }, - { - "date" : "2015-10-15T22:35:00", - "unit" : "g", - "amount" : 15.226392359812111 - }, - { - "amount" : 13.526438084549193, - "unit" : "g", - "date" : "2015-10-15T22:40:00" - }, - { - "unit" : "g", - "amount" : 11.92707823086835, - "date" : "2015-10-15T22:45:00" - }, - { - "date" : "2015-10-15T22:50:00", - "amount" : 10.428312798769589, - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 9.0301417882528927, - "date" : "2015-10-15T22:55:00" - }, - { - "amount" : 7.7325651993182838, - "unit" : "g", - "date" : "2015-10-15T23:00:00" - }, - { - "date" : "2015-10-15T23:05:00", - "amount" : 6.53558303196575, - "unit" : "g" - }, - { - "date" : "2015-10-15T23:10:00", - "amount" : 5.4391952861952868, - "unit" : "g" - }, - { - "date" : "2015-10-15T23:15:00", - "amount" : 4.4434019620068952, - "unit" : "g" - }, - { - "amount" : 3.5482030594005942, - "date" : "2015-10-15T23:20:00", - "unit" : "g" - }, - { - "amount" : 2.7535985783763595, - "unit" : "g", - "date" : "2015-10-15T23:25:00" - }, - { - "date" : "2015-10-15T23:30:00", - "amount" : 2.0595885189341958, - "unit" : "g" - }, - { - "amount" : 1.466172881074113, - "date" : "2015-10-15T23:35:00", - "unit" : "g" - }, - { - "date" : "2015-10-15T23:40:00", - "amount" : 0.97335166479610624, - "unit" : "g" - }, - { - "date" : "2015-10-15T23:45:00", - "amount" : 0.58112487010018032, - "unit" : "g" - }, - { - "amount" : 0.28949249698633039, - "date" : "2015-10-15T23:50:00", - "unit" : "g" - }, - { - "amount" : 0.098454545454546682, - "date" : "2015-10-15T23:55:00", - "unit" : "g" - }, - { - "amount" : 0.0080110155048438436, - "unit" : "g", - "date" : "2015-10-16T00:00:00" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T00:05:00" - }, - { - "date" : "2015-10-16T00:10:00", - "unit" : "g", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T00:15:00" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T00:20:00" - }, - { - "amount" : 0, - "date" : "2015-10-16T00:25:00", - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T00:30:00" - }, - { - "date" : "2015-10-16T00:35:00", - "unit" : "g", - "amount" : 0 - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T00:40:00" - }, - { - "date" : "2015-10-16T00:45:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T00:50:00", - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T00:55:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T01:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T01:05:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T01:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:15:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T01:20:00" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T01:25:00" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T01:30:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T01:35:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T01:40:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T01:45:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T01:50:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T01:55:00" - }, - { - "amount" : 0, - "date" : "2015-10-16T02:00:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T02:05:00", - "unit" : "g", - "amount" : 0 - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T02:10:00" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T02:15:00" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T02:20:00" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T02:25:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T02:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T02:35:00" - }, - { - "date" : "2015-10-16T02:40:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T02:45:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T02:50:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T02:55:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T03:00:00" - }, - { - "date" : "2015-10-16T03:05:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T03:10:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T03:15:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T03:20:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T03:25:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T03:30:00", - "amount" : 0 - }, - { - "amount" : 0, - "date" : "2015-10-16T03:35:00", - "unit" : "g" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_slow_absorption.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_slow_absorption.json deleted file mode 100644 index 62f97168f..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_slow_absorption.json +++ /dev/null @@ -1,92 +0,0 @@ -[ - { - "velocity": 0.0, - "start_at": "2015-10-15T21:30:12", - "end_at": "2015-10-15T21:35:12" - }, - { - "velocity": 2.0, - "start_at": "2015-10-15T21:35:12", - "end_at": "2015-10-15T21:40:12" - }, - { - "velocity": 3.0, - "start_at": "2015-10-15T21:40:12", - "end_at": "2015-10-15T21:45:12" - }, - { - "velocity": 2.0, - "start_at": "2015-10-15T21:45:12", - "end_at": "2015-10-15T21:50:12" - }, - { - "velocity": 1.0, - "start_at": "2015-10-15T21:50:12", - "end_at": "2015-10-15T21:55:12" - }, - { - "velocity": 0.0, - "start_at": "2015-10-15T21:55:12", - "end_at": "2015-10-15T22:00:12" - }, - { - "velocity": -2.0, - "start_at": "2015-10-15T22:00:12", - "end_at": "2015-10-15T22:05:12" - }, - { - "velocity": -1.0, - "start_at": "2015-10-15T22:05:12", - "end_at": "2015-10-15T22:10:12" - }, - { - "velocity": 0.0, - "start_at": "2015-10-15T22:10:12", - "end_at": "2015-10-15T22:15:12" - }, - { - "velocity": 1.0, - "start_at": "2015-10-15T22:15:12", - "end_at": "2015-10-15T22:20:12" - }, - { - "velocity": 0.0, - "start_at": "2015-10-15T22:20:12", - "end_at": "2015-10-15T22:25:12" - }, - { - "velocity": 0.0, - "start_at": "2015-10-15T22:25:12", - "end_at": "2015-10-15T22:30:12" - }, - { - "velocity": -1.0, - "start_at": "2015-10-15T22:30:12", - "end_at": "2015-10-15T22:35:12" - }, - { - "velocity": -2.0, - "start_at": "2015-10-15T22:35:12", - "end_at": "2015-10-15T22:40:12" - }, - { - "velocity": -2.0, - "start_at": "2015-10-15T22:40:12", - "end_at": "2015-10-15T22:45:12" - }, - { - "velocity": -3.0, - "start_at": "2015-10-15T22:45:12", - "end_at": "2015-10-15T22:50:12" - }, - { - "velocity": -3.0, - "start_at": "2015-10-15T22:50:12", - "end_at": "2015-10-15T22:55:12" - }, - { - "velocity": -2.0, - "start_at": "2015-10-15T22:55:12", - "end_at": "2015-10-15T23:00:12" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_slow_absorption_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_slow_absorption_output.json deleted file mode 100644 index f23dc4dc3..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_slow_absorption_output.json +++ /dev/null @@ -1,1092 +0,0 @@ -[ - { - "unit" : "g", - "date" : "2015-10-15T21:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:50:00", - "amount" : 30 - }, - { - "unit" : "g", - "date" : "2015-10-15T21:55:00", - "amount" : 30 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:00:00", - "amount" : 30 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:05:00", - "amount" : 30 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:10:00", - "amount" : 29.375 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:15:00", - "amount" : 28.75 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:20:00", - "amount" : 28.125 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:25:00", - "amount" : 27.5 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:30:00", - "amount" : 26.875 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:35:00", - "amount" : 26.25 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:40:00", - "amount" : 25.625 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:45:00", - "amount" : 25 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:50:00", - "amount" : 24.375 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:55:00", - "amount" : 23.75 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:00:00", - "amount" : 23.125 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:05:00", - "amount" : 22.5 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:10:00", - "amount" : 21.875 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:15:00", - "amount" : 21.25 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:20:00", - "amount" : 20.625 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:25:00", - "amount" : 20 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:30:00", - "amount" : 19.375 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:35:00", - "amount" : 18.75 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:40:00", - "amount" : 18.125 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:45:00", - "amount" : 17.5 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:50:00", - "amount" : 16.875 - }, - { - "unit" : "g", - "date" : "2015-10-15T23:55:00", - "amount" : 16.25 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:00:00", - "amount" : 15.625 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:05:00", - "amount" : 15 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:10:00", - "amount" : 14.375 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:15:00", - "amount" : 13.75 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:20:00", - "amount" : 13.125 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:25:00", - "amount" : 12.5 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:30:00", - "amount" : 11.875 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:35:00", - "amount" : 11.25 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:40:00", - "amount" : 10.625 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:45:00", - "amount" : 10 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:50:00", - "amount" : 9.375 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:55:00", - "amount" : 8.75 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:00:00", - "amount" : 8.125 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:05:00", - "amount" : 7.5 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:10:00", - "amount" : 6.875 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:15:00", - "amount" : 6.25 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:20:00", - "amount" : 5.625 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:25:00", - "amount" : 5 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:30:00", - "amount" : 4.375 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:35:00", - "amount" : 3.75 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:40:00", - "amount" : 3.125 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:45:00", - "amount" : 2.5 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:50:00", - "amount" : 1.875 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:55:00", - "amount" : 1.25 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:00:00", - "amount" : 0.625 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T03:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T04:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T04:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T04:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T04:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T04:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T04:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T04:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T04:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T04:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T04:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T04:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T04:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T05:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T05:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T05:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T05:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T05:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T05:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T05:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T05:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T05:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T05:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T05:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T05:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T06:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T06:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T06:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T06:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T06:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T06:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T06:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T06:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T06:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T06:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T06:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T06:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T07:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T07:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T07:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T07:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T07:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T07:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T07:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T07:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T07:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T07:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T07:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T07:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T09:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T09:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T09:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T09:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T09:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T09:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T09:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T09:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T09:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T09:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T09:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T09:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T10:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T10:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T10:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T10:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T10:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T10:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T10:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T10:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T10:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T10:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T10:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T10:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T11:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T11:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T11:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T11:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T11:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T11:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T11:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T11:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T11:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T11:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T11:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T11:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T12:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T12:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T12:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T12:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T12:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T12:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T12:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T12:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T12:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T12:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T12:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T12:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T13:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T13:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T13:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T13:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T13:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T13:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T13:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T13:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T13:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T13:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T13:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T13:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T14:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T14:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T14:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T14:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T14:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T14:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T14:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T14:35:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T14:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T14:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T14:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T14:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T15:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T15:05:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T15:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T15:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T15:20:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T15:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T15:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T15:35:00", - "amount" : 0 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_slow_absorption_piecewiselinear_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_slow_absorption_piecewiselinear_output.json deleted file mode 100644 index 09bb9b4eb..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/ice_slow_absorption_piecewiselinear_output.json +++ /dev/null @@ -1,1092 +0,0 @@ -[ - { - "unit" : "g", - "date" : "2015-10-15T21:30:00", - "amount" : 0 - }, - { - "amount" : 0, - "date" : "2015-10-15T21:35:00", - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-15T21:40:00" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-15T21:45:00" - }, - { - "amount" : 30, - "unit" : "g", - "date" : "2015-10-15T21:50:00" - }, - { - "date" : "2015-10-15T21:55:00", - "unit" : "g", - "amount" : 30 - }, - { - "date" : "2015-10-15T22:00:00", - "amount" : 30, - "unit" : "g" - }, - { - "amount" : 30, - "date" : "2015-10-15T22:05:00", - "unit" : "g" - }, - { - "amount" : 29.885688157293096, - "date" : "2015-10-15T22:10:00", - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-15T22:15:00", - "amount" : 29.542752629172384 - }, - { - "date" : "2015-10-15T22:20:00", - "amount" : 28.97119341563786, - "unit" : "g" - }, - { - "amount" : 28.171010516689527, - "unit" : "g", - "date" : "2015-10-15T22:25:00" - }, - { - "date" : "2015-10-15T22:30:00", - "unit" : "g", - "amount" : 27.142203932327391 - }, - { - "unit" : "g", - "date" : "2015-10-15T22:35:00", - "amount" : 25.925925925925927 - }, - { - "amount" : 24.691358024691358, - "unit" : "g", - "date" : "2015-10-15T22:40:00" - }, - { - "date" : "2015-10-15T22:45:00", - "amount" : 23.456790123456791, - "unit" : "g" - }, - { - "amount" : 22.222222222222221, - "unit" : "g", - "date" : "2015-10-15T22:50:00" - }, - { - "amount" : 20.987654320987655, - "date" : "2015-10-15T22:55:00", - "unit" : "g" - }, - { - "date" : "2015-10-15T23:00:00", - "amount" : 19.753086419753085, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-15T23:05:00", - "amount" : 18.518518518518519 - }, - { - "date" : "2015-10-15T23:10:00", - "unit" : "g", - "amount" : 17.283950617283953 - }, - { - "amount" : 16.049382716049383, - "unit" : "g", - "date" : "2015-10-15T23:15:00" - }, - { - "unit" : "g", - "date" : "2015-10-15T23:20:00", - "amount" : 14.814814814814813 - }, - { - "unit" : "g", - "amount" : 13.580246913580249, - "date" : "2015-10-15T23:25:00" - }, - { - "date" : "2015-10-15T23:30:00", - "unit" : "g", - "amount" : 12.345679012345679 - }, - { - "date" : "2015-10-15T23:35:00", - "amount" : 11.111111111111114, - "unit" : "g" - }, - { - "date" : "2015-10-15T23:40:00", - "unit" : "g", - "amount" : 9.910836762688616 - }, - { - "date" : "2015-10-15T23:45:00", - "unit" : "g", - "amount" : 8.7791495198902609 - }, - { - "amount" : 7.716049382716049, - "date" : "2015-10-15T23:50:00", - "unit" : "g" - }, - { - "date" : "2015-10-15T23:55:00", - "unit" : "g", - "amount" : 6.7215363511659802 - }, - { - "date" : "2015-10-16T00:00:00", - "amount" : 5.7956104252400564, - "unit" : "g" - }, - { - "date" : "2015-10-16T00:05:00", - "amount" : 4.9382716049382722, - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 4.1495198902606383, - "date" : "2015-10-16T00:10:00" - }, - { - "amount" : 3.4293552812071395, - "date" : "2015-10-16T00:15:00", - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 2.7777777777777768, - "date" : "2015-10-16T00:20:00" - }, - { - "date" : "2015-10-16T00:25:00", - "unit" : "g", - "amount" : 2.1947873799725635 - }, - { - "unit" : "g", - "date" : "2015-10-16T00:30:00", - "amount" : 1.6803840877914999 - }, - { - "amount" : 1.2345679012345689, - "date" : "2015-10-16T00:35:00", - "unit" : "g" - }, - { - "amount" : 0.85733882030178399, - "date" : "2015-10-16T00:40:00", - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T00:45:00", - "amount" : 0.54869684499314175 - }, - { - "unit" : "g", - "amount" : 0.30864197530864557, - "date" : "2015-10-16T00:50:00" - }, - { - "amount" : 0.13717421124828544, - "unit" : "g", - "date" : "2015-10-16T00:55:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T01:00:00", - "amount" : 0.03429355281207469 - }, - { - "date" : "2015-10-16T01:05:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T01:10:00", - "unit" : "g", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T01:15:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T01:20:00" - }, - { - "date" : "2015-10-16T01:25:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T01:30:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T01:35:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T01:40:00" - }, - { - "date" : "2015-10-16T01:45:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T01:50:00", - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T01:55:00", - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T02:00:00" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T02:05:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T02:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:15:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T02:20:00", - "amount" : 0 - }, - { - "amount" : 0, - "date" : "2015-10-16T02:25:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T02:30:00", - "unit" : "g", - "amount" : 0 - }, - { - "date" : "2015-10-16T02:35:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T02:40:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T02:45:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T02:50:00" - }, - { - "date" : "2015-10-16T02:55:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T03:00:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T03:05:00" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T03:10:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T03:15:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T03:20:00", - "unit" : "g", - "amount" : 0 - }, - { - "amount" : 0, - "date" : "2015-10-16T03:25:00", - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T03:30:00", - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T03:35:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T03:40:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T03:45:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T03:50:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T03:55:00", - "unit" : "g", - "amount" : 0 - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T04:00:00" - }, - { - "amount" : 0, - "date" : "2015-10-16T04:05:00", - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T04:10:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T04:15:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T04:20:00" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T04:25:00" - }, - { - "date" : "2015-10-16T04:30:00", - "unit" : "g", - "amount" : 0 - }, - { - "date" : "2015-10-16T04:35:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T04:40:00" - }, - { - "date" : "2015-10-16T04:45:00", - "unit" : "g", - "amount" : 0 - }, - { - "amount" : 0, - "date" : "2015-10-16T04:50:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T04:55:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T05:00:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T05:05:00" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T05:10:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T05:15:00", - "amount" : 0 - }, - { - "amount" : 0, - "date" : "2015-10-16T05:20:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T05:25:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T05:30:00" - }, - { - "amount" : 0, - "date" : "2015-10-16T05:35:00", - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T05:40:00" - }, - { - "amount" : 0, - "date" : "2015-10-16T05:45:00", - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T05:50:00" - }, - { - "amount" : 0, - "date" : "2015-10-16T05:55:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T06:00:00", - "unit" : "g", - "amount" : 0 - }, - { - "amount" : 0, - "date" : "2015-10-16T06:05:00", - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T06:10:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T06:15:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T06:20:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T06:25:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T06:30:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T06:35:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T06:40:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T06:45:00", - "unit" : "g", - "amount" : 0 - }, - { - "date" : "2015-10-16T06:50:00", - "unit" : "g", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T06:55:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T07:00:00" - }, - { - "date" : "2015-10-16T07:05:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T07:10:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T07:15:00" - }, - { - "amount" : 0, - "date" : "2015-10-16T07:20:00", - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T07:25:00" - }, - { - "date" : "2015-10-16T07:30:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T07:35:00", - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T07:40:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T07:45:00", - "unit" : "g", - "amount" : 0 - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T07:50:00" - }, - { - "amount" : 0, - "date" : "2015-10-16T07:55:00", - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T08:00:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:05:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T08:10:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T08:15:00" - }, - { - "date" : "2015-10-16T08:20:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T08:25:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T08:30:00", - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T08:35:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T08:40:00", - "unit" : "g", - "amount" : 0 - }, - { - "date" : "2015-10-16T08:45:00", - "unit" : "g", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T08:55:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T09:00:00" - }, - { - "amount" : 0, - "date" : "2015-10-16T09:05:00", - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T09:10:00", - "amount" : 0 - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T09:15:00" - }, - { - "date" : "2015-10-16T09:20:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T09:25:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T09:30:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T09:35:00", - "unit" : "g", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T09:40:00" - }, - { - "date" : "2015-10-16T09:45:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T09:50:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T09:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T10:00:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T10:05:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T10:10:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T10:15:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T10:20:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T10:25:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T10:30:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T10:35:00" - }, - { - "date" : "2015-10-16T10:40:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T10:45:00", - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T10:50:00" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T10:55:00" - }, - { - "date" : "2015-10-16T11:00:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T11:05:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T11:10:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T11:15:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T11:20:00", - "amount" : 0 - }, - { - "amount" : 0, - "date" : "2015-10-16T11:25:00", - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T11:30:00", - "amount" : 0 - }, - { - "amount" : 0, - "date" : "2015-10-16T11:35:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T11:40:00", - "unit" : "g", - "amount" : 0 - }, - { - "amount" : 0, - "date" : "2015-10-16T11:45:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T11:50:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T11:55:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T12:00:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T12:05:00" - }, - { - "date" : "2015-10-16T12:10:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T12:15:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T12:20:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T12:25:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T12:30:00", - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T12:35:00" - }, - { - "date" : "2015-10-16T12:40:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T12:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T12:50:00", - "amount" : 0 - }, - { - "amount" : 0, - "date" : "2015-10-16T12:55:00", - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T13:00:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T13:05:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T13:10:00" - }, - { - "date" : "2015-10-16T13:15:00", - "amount" : 0, - "unit" : "g" - }, - { - "date" : "2015-10-16T13:20:00", - "amount" : 0, - "unit" : "g" - }, - { - "unit" : "g", - "date" : "2015-10-16T13:25:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T13:30:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T13:35:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T13:40:00", - "amount" : 0 - }, - { - "date" : "2015-10-16T13:45:00", - "unit" : "g", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T13:50:00" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T13:55:00" - }, - { - "date" : "2015-10-16T14:00:00", - "unit" : "g", - "amount" : 0 - }, - { - "date" : "2015-10-16T14:05:00", - "amount" : 0, - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T14:10:00", - "unit" : "g" - }, - { - "date" : "2015-10-16T14:15:00", - "unit" : "g", - "amount" : 0 - }, - { - "date" : "2015-10-16T14:20:00", - "unit" : "g", - "amount" : 0 - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T14:25:00" - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T14:30:00" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T14:35:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T14:40:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T14:45:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T14:50:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T14:55:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T15:00:00", - "amount" : 0 - }, - { - "amount" : 0, - "unit" : "g", - "date" : "2015-10-16T15:05:00" - }, - { - "amount" : 0, - "date" : "2015-10-16T15:10:00", - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T15:15:00", - "unit" : "g" - }, - { - "amount" : 0, - "date" : "2015-10-16T15:20:00", - "unit" : "g" - }, - { - "unit" : "g", - "amount" : 0, - "date" : "2015-10-16T15:25:00" - }, - { - "unit" : "g", - "date" : "2015-10-16T15:30:00", - "amount" : 0 - }, - { - "unit" : "g", - "date" : "2015-10-16T15:35:00", - "amount" : 0 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/reconcile_bolus_wizard_duplicates_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/reconcile_bolus_wizard_duplicates_input.json deleted file mode 100644 index 5b7282d74..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/reconcile_bolus_wizard_duplicates_input.json +++ /dev/null @@ -1,58 +0,0 @@ -[ - { - "amount": 2.0, - "description": "Normal bolus: 2.0U", - "end_at": "2015-06-05T16:21:01", - "start_at": "2015-06-05T16:21:01", - "type": "Bolus", - "unit": "U" - }, - { - "amount": 65, - "description": "BolusWizard: 65g", - "end_at": "2015-06-05T18:44:47", - "start_at": "2015-06-05T18:44:47", - "type": "Meal", - "unit": "g" - }, - { - "amount": 65, - "description": "BolusWizard: 65g", - "end_at": "2015-06-05T18:44:54", - "start_at": "2015-06-05T18:44:54", - "type": "Meal", - "unit": "g" - }, - { - "amount": 0.6, - "description": "Normal bolus: 0.6U", - "end_at": "2015-06-05T18:44:54", - "start_at": "2015-06-05T18:44:54", - "type": "Bolus", - "unit": "U" - }, - { - "amount": 30, - "description": "BolusWizard: 30g", - "end_at": "2015-06-05T18:54:43", - "start_at": "2015-06-05T18:54:43", - "type": "Meal", - "unit": "g" - }, - { - "amount": 2.0, - "description": "Normal bolus: 2.0U", - "end_at": "2015-06-05T18:54:43", - "start_at": "2015-06-05T18:54:43", - "type": "Bolus", - "unit": "U" - }, - { - "amount": 10, - "description": "BolusWizard: 10g", - "end_at": "2015-06-05T18:57:22", - "start_at": "2015-06-05T18:57:22", - "type": "Meal", - "unit": "g" - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/reconcile_bolus_wizard_duplicates_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/reconcile_bolus_wizard_duplicates_output.json deleted file mode 100644 index a44aecbe5..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/CarbKit/reconcile_bolus_wizard_duplicates_output.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "amount": 2.0, - "description": "Normal bolus: 2.0U", - "end_at": "2015-06-05T16:21:01", - "start_at": "2015-06-05T16:21:01", - "type": "Bolus", - "unit": "U" - }, - { - "amount": 65, - "description": "BolusWizard: 65g", - "end_at": "2015-06-05T18:44:54", - "start_at": "2015-06-05T18:44:54", - "type": "Meal", - "unit": "g" - }, - { - "amount": 0.6, - "description": "Normal bolus: 0.6U", - "end_at": "2015-06-05T18:44:54", - "start_at": "2015-06-05T18:44:54", - "type": "Bolus", - "unit": "U" - }, - { - "amount": 30, - "description": "BolusWizard: 30g", - "end_at": "2015-06-05T18:54:43", - "start_at": "2015-06-05T18:54:43", - "type": "Meal", - "unit": "g" - }, - { - "amount": 2.0, - "description": "Normal bolus: 2.0U", - "end_at": "2015-06-05T18:54:43", - "start_at": "2015-06-05T18:54:43", - "type": "Bolus", - "unit": "U" - }, - { - "amount": 10, - "description": "BolusWizard: 10g", - "end_at": "2015-06-05T18:57:22", - "start_at": "2015-06-05T18:57:22", - "type": "Meal", - "unit": "g" - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_almost_duplicates_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_almost_duplicates_input.json deleted file mode 100644 index 49392a0c5..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_almost_duplicates_input.json +++ /dev/null @@ -1,34 +0,0 @@ -[ - { - "date": "2015-10-25T19:15:00", - "amount": 159 - }, - { - "date": "2015-10-25T19:15:01", - "amount": 159 - }, - { - "date": "2015-10-25T19:19:59", - "amount": 136 - }, - { - "date": "2015-10-25T19:20:00", - "amount": 136 - }, - { - "date": "2015-10-25T19:25:00", - "amount": 123 - }, - { - "date": "2015-10-25T19:25:01", - "amount": 123 - }, - { - "date": "2015-10-25T19:30:00", - "amount": 120 - }, - { - "date": "2015-10-25T19:30:01", - "amount": 120 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_almost_duplicates_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_almost_duplicates_output.json deleted file mode 100644 index adfbec4a9..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_almost_duplicates_output.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "value" : -4.61538461538461, - "startDate" : "2015-10-25T19:15:00", - "unit" : "mg\/min·dL", - "endDate" : "2015-10-25T19:19:59" - }, - { - "value" : -2.59136212624585, - "startDate" : "2015-10-25T19:19:59", - "unit" : "mg\/min·dL", - "endDate" : "2015-10-25T19:25:00" - }, - { - "value" : -0.59999999999999998, - "startDate" : "2015-10-25T19:25:00", - "unit" : "mg\/min·dL", - "endDate" : "2015-10-25T19:30:00" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_double_entries._input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_double_entries._input.json deleted file mode 100644 index 7efafb817..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_double_entries._input.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "date": "2015-10-25T19:15:00", - "amount": 159 - }, - { - "date": "2015-10-25T19:20:00", - "amount": 136 - }, - { - "date": "2015-10-25T19:25:00", - "amount": 123 - }, - { - "date": "2015-10-25T19:30:00", - "amount": 120 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_input.json deleted file mode 100644 index 7efafb817..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_input.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "date": "2015-10-25T19:15:00", - "amount": 159 - }, - { - "date": "2015-10-25T19:20:00", - "amount": 136 - }, - { - "date": "2015-10-25T19:25:00", - "amount": 123 - }, - { - "date": "2015-10-25T19:30:00", - "amount": 120 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_insulin.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_insulin.json deleted file mode 100644 index 088b682a5..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_insulin.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - { - "date": "2015-10-25T19:15:00", - "amount": 100, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:20:00", - "amount": 100, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:25:00", - "amount": 100, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:30:00", - "amount": 100, - "unit": "mg/dL" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_output.json deleted file mode 100644 index a8ce5191b..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/counteraction_effect_falling_glucose_output.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "value" : -4.5999999999999988, - "startDate" : "2015-10-25T19:15:00", - "unit" : "mg\/min·dL", - "endDate" : "2015-10-25T19:20:00" - }, - { - "value" : -2.5999999999999996, - "startDate" : "2015-10-25T19:20:00", - "unit" : "mg\/min·dL", - "endDate" : "2015-10-25T19:25:00" - }, - { - "value" : -0.59999999999999998, - "startDate" : "2015-10-25T19:25:00", - "unit" : "mg\/min·dL", - "endDate" : "2015-10-25T19:30:00" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_bouncing_glucose_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_bouncing_glucose_input.json deleted file mode 100644 index f95ecf1e5..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_bouncing_glucose_input.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "date": "2015-10-25T19:19:37", - "amount": 123 - }, - { - "date": "2015-10-25T19:24:36", - "amount": 120 - }, - { - "date": "2015-10-25T19:29:37", - "amount": 129 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_bouncing_glucose_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_bouncing_glucose_output.json deleted file mode 100644 index 8214796b0..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_bouncing_glucose_output.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { - "date": "2015-10-25T19:25:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:30:00", - "amount": 0.23051025736941719, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:35:00", - "amount": 3.2371657882748588, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:40:00", - "amount": 6.2438213191803005, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:45:00", - "amount": 9.2504768500857413, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:50:00", - "amount": 12.257132380991184, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:55:00", - "amount": 15.263787911896625, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T20:00:00", - "amount": 18.270443442802062, - "unit": "mg/dL" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_display_only_glucose_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_display_only_glucose_input.json deleted file mode 100644 index 6e6d97655..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_display_only_glucose_input.json +++ /dev/null @@ -1,17 +0,0 @@ -[ - { - "date": "2015-10-25T19:19:37", - "amount": 123, - "display_only": false, - }, - { - "date": "2015-10-25T19:24:36", - "amount": 120, - "display_only": true, - }, - { - "date": "2015-10-25T19:29:37", - "amount": 129, - "display_only": false, - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_duplicate_glucose_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_duplicate_glucose_input.json deleted file mode 100644 index 2cd6db672..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_duplicate_glucose_input.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "date": "2015-10-25T19:25:00", - "amount": 125 - }, - { - "date": "2015-10-25T19:25:00", - "amount": 125 - }, - { - "date": "2015-10-25T19:25:00", - "amount": 125 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_falling_glucose_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_falling_glucose_input.json deleted file mode 100644 index dad3a6b68..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_falling_glucose_input.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "date": "2015-10-25T19:15:00", - "amount": 129 - }, - { - "date": "2015-10-25T19:20:00", - "amount": 126 - }, - { - "date": "2015-10-25T19:25:00", - "amount": 123 - }, - { - "date": "2015-10-25T19:30:00", - "amount": 120 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_falling_glucose_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_falling_glucose_output.json deleted file mode 100644 index ad766c66d..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_falling_glucose_output.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "date": "2015-10-25T19:30:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:35:00", - "amount": -3, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:40:00", - "amount": -6, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:45:00", - "amount": -9, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:50:00", - "amount": -12, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:55:00", - "amount": -15, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T20:00:00", - "amount": -18, - "unit": "mg/dL" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_impossible_rising_glucose_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_impossible_rising_glucose_input.json deleted file mode 100644 index 44d8dd6ff..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_impossible_rising_glucose_input.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "date": "2015-10-25T19:15:00", - "amount": 120 - }, - { - "date": "2015-10-25T19:20:00", - "amount": 180 - }, - { - "date": "2015-10-25T19:25:00", - "amount": 240 - }, - { - "date": "2015-10-25T19:30:00", - "amount": 300 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_impossible_rising_glucose_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_impossible_rising_glucose_output.json deleted file mode 100644 index 8baa0fcde..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_impossible_rising_glucose_output.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "date": "2015-10-25T19:30:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:35:00", - "amount": 20, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:40:00", - "amount": 40, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:45:00", - "amount": 60, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:50:00", - "amount": 80, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:55:00", - "amount": 100, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T20:00:00", - "amount": 120, - "unit": "mg/dL" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_incomplete_glucose_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_incomplete_glucose_input.json deleted file mode 100644 index 6e8c0e3f5..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_incomplete_glucose_input.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "date": "2015-10-25T19:14:37", - "amount": 123 - }, - { - "date": "2015-10-25T19:24:36", - "amount": 120 - }, - { - "date": "2015-10-25T19:29:37", - "amount": 129 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_mixed_provenance_glucose_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_mixed_provenance_glucose_input.json deleted file mode 100644 index 9446f1f9c..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_mixed_provenance_glucose_input.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "date": "2015-10-25T19:19:37", - "amount": 123, - "display_only": false, - }, - { - "date": "2015-10-25T19:24:36", - "amount": 120, - "display_only": false, - "provenance_identifier": "com.developer.BLEGlucoseMeter" - }, - { - "date": "2015-10-25T19:29:37", - "amount": 129, - "display_only": false, - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_rising_glucose_double_entries_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_rising_glucose_double_entries_input.json deleted file mode 100644 index 63bbc3d2e..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_rising_glucose_double_entries_input.json +++ /dev/null @@ -1,30 +0,0 @@ -[ - { - "date": "2015-10-25T19:15:00", - "amount": 120 - }, - { - "date": "2015-10-25T19:17:30", - "amount": 121.5 - }, - { - "date": "2015-10-25T19:20:00", - "amount": 123 - }, - { - "date": "2015-10-25T19:22:30", - "amount": 124.5 - }, - { - "date": "2015-10-25T19:25:00", - "amount": 126 - }, - { - "date": "2015-10-25T19:27:30", - "amount": 127.5 - }, - { - "date": "2015-10-25T19:30:00", - "amount": 129 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_rising_glucose_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_rising_glucose_input.json deleted file mode 100644 index 20a6fb796..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_rising_glucose_input.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "date": "2015-10-25T19:15:00", - "amount": 120 - }, - { - "date": "2015-10-25T19:20:00", - "amount": 123 - }, - { - "date": "2015-10-25T19:25:00", - "amount": 126 - }, - { - "date": "2015-10-25T19:30:00", - "amount": 129 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_rising_glucose_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_rising_glucose_output.json deleted file mode 100644 index 304c657e3..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_rising_glucose_output.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "date": "2015-10-25T19:30:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:35:00", - "amount": 3, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:40:00", - "amount": 6, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:45:00", - "amount": 9, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:50:00", - "amount": 12, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:55:00", - "amount": 15, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T20:00:00", - "amount": 18, - "unit": "mg/dL" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_stable_glucose_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_stable_glucose_input.json deleted file mode 100644 index dc6441ea7..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_stable_glucose_input.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "date": "2015-10-25T19:20:00", - "amount": 120 - }, - { - "date": "2015-10-25T19:25:00", - "amount": 120 - }, - { - "date": "2015-10-25T19:30:00", - "amount": 120 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_stable_glucose_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_stable_glucose_output.json deleted file mode 100644 index f7dd49fd2..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/GlucoseKit/momentum_effect_stable_glucose_output.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "date": "2015-10-25T19:30:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:35:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:40:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:45:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:50:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T19:55:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-25T20:00:00", - "amount": 0.0, - "unit": "mg/dL" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/basal_dose.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/basal_dose.json deleted file mode 100644 index 786060037..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/basal_dose.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "type": "TempBasal", - "start_at": "2015-07-13T12:00:00", - "end_at": "2015-07-13T13:00:00", - "amount": 2.0, - "unit": "U/hour", - "scheduled": 1.0 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/basal_dose_with_delivered.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/basal_dose_with_delivered.json deleted file mode 100644 index 346c5c33d..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/basal_dose_with_delivered.json +++ /dev/null @@ -1,11 +0,0 @@ -[ - { - "type": "TempBasal", - "start_at": "2015-07-13T12:00:00", - "end_at": "2015-07-13T13:00:00", - "amount": 2.0, - "unit": "U/hour", - "scheduled": 1.0, - "delivered": 2.0 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/basal_dose_with_expired.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/basal_dose_with_expired.json deleted file mode 100644 index 09d5a49a3..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/basal_dose_with_expired.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "type": "TempBasal", - "start_at": "2015-07-12T12:00:00", - "end_at": "2015-07-12T13:00:00", - "amount": 2.0, - "unit": "U/hour", - "scheduled": 1.0 - }, - { - "type": "TempBasal", - "start_at": "2015-07-13T12:00:00", - "end_at": "2015-07-13T13:00:00", - "amount": 2.0, - "unit": "U/hour", - "scheduled": 1.0 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/bolus_dose.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/bolus_dose.json deleted file mode 100644 index dc2a8134a..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/bolus_dose.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "type": "Bolus", - "start_at": "2015-07-13T12:02:37", - "end_at": "2015-07-13T12:02:37", - "amount": 1.5, - "unit": "U" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/dose_history_with_delivered_units.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/dose_history_with_delivered_units.json deleted file mode 100644 index a0f8c3d50..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/dose_history_with_delivered_units.json +++ /dev/null @@ -1,488 +0,0 @@ -[ - { - "start_at" : "2016-01-30T20:30:43", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:35:41", - "type" : "TempBasal", - "amount" : 0.90604026845637575, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T20:25:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:30:43", - "type" : "TempBasal", - "amount" : 0.89700996677740863, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T20:20:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:25:42", - "type" : "TempBasal", - "amount" : 0.60000000000000009, - "unit" : "U/hour", - "delivered": 0.05 - }, - { - "start_at" : "2016-01-30T20:15:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:20:42", - "type" : "TempBasal", - "amount" : 14.352159468438538, - "unit" : "U/hour", - "delivered": 1.2 - }, - { - "start_at" : "2016-01-30T20:10:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:15:41", - "type" : "TempBasal", - "amount" : 3.0100334448160533, - "unit" : "U/hour", - "delivered": 0.25 - }, - { - "start_at" : "2016-01-30T20:05:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:10:42", - "type" : "TempBasal", - "amount" : 2.4000000000000004, - "unit" : "U/hour", - "delivered": 0.2 - }, - { - "start_at" : "2016-01-30T20:00:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:05:42", - "type" : "TempBasal", - "amount" : 2.9900332225913622, - "unit" : "U/hour", - "delivered": 0.25 - }, - { - "start_at" : "2016-01-30T19:55:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:00:41", - "type" : "TempBasal", - "amount" : 1.8, - "unit" : "U/hour", - "delivered": 0.15 - }, - { - "start_at" : "2016-01-30T19:50:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:55:41", - "type" : "TempBasal", - "amount" : 2.4000000000000004, - "unit" : "U/hour", - "delivered": 0.2 - }, - { - "start_at" : "2016-01-30T19:45:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:50:41", - "type" : "TempBasal", - "amount" : 1.2000000000000002, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T19:40:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:45:41", - "type" : "TempBasal", - "amount" : 0.90000000000000002, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T19:35:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:40:41", - "type" : "TempBasal", - "amount" : 9.6321070234113702, - "unit" : "U/hour", - "delivered": 0.8 - }, - { - "start_at" : "2016-01-30T19:25:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:35:42", - "type" : "TempBasal", - "amount" : 4.2000000000000002, - "unit" : "U/hour", - "delivered": 0.7 - }, - { - "start_at" : "2016-01-30T19:20:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:25:42", - "type" : "TempBasal", - "amount" : 0.60000000000000009, - "unit" : "U/hour", - "delivered": 0.05 - }, - { - "start_at" : "2016-01-30T19:15:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:20:42", - "type" : "TempBasal", - "amount" : 0.90000000000000002, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T19:10:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:15:42", - "type" : "TempBasal", - "amount" : 0.89700996677740863, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T19:05:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:10:41", - "type" : "TempBasal", - "amount" : 0.60200668896321063, - "unit" : "U/hour", - "delivered": 0.05 - }, - { - "start_at" : "2016-01-30T19:00:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:05:42", - "type" : "TempBasal", - "amount" : 0.90000000000000002, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T18:55:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:00:42", - "type" : "TempBasal", - "amount" : 0.89700996677740863, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T18:50:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:55:41", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U/hour", - "delivered": 0 - }, - { - "start_at" : "2016-01-30T18:45:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:50:41", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U/hour", - "delivered": 0 - }, - { - "start_at" : "2016-01-30T18:40:43", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:45:41", - "type" : "TempBasal", - "amount" : 0.30201342281879195, - "unit" : "U/hour", - "delivered": 0.05 - }, - { - "start_at" : "2016-01-30T18:35:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:40:43", - "type" : "TempBasal", - "amount" : 0.59602649006622521, - "unit" : "U/hour", - "delivered": 0.05 - }, - { - "start_at" : "2016-01-30T18:30:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:35:41", - "type" : "TempBasal", - "amount" : 0.9030100334448159, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T18:25:43", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:30:42", - "type" : "TempBasal", - "amount" : 0.9030100334448159, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T18:20:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:25:43", - "type" : "TempBasal", - "amount" : 0.89700996677740863, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T18:10:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:15:44", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U/hour", - "delivered": 0 - }, - { - "start_at" : "2016-01-30T18:05:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:10:42", - "type" : "TempBasal", - "amount" : 0.30000000000000004, - "unit" : "U/hour", - "delivered": 0.05 - }, - { - "start_at" : "2016-01-30T18:00:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:05:42", - "type" : "TempBasal", - "amount" : 16.5, - "unit" : "U/hour", - "delivered": 1.4 - }, - { - "start_at" : "2016-01-30T17:55:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:00:42", - "type" : "TempBasal", - "amount" : 0.90000000000000002, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T17:50:44", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:55:42", - "type" : "TempBasal", - "amount" : 0.60402684563758391, - "unit" : "U/hour", - "delivered": 0.05 - }, - { - "start_at" : "2016-01-30T17:45:44", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:50:44", - "type" : "TempBasal", - "amount" : 0.90000000000000002, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T17:40:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:45:44", - "type" : "TempBasal", - "amount" : 1.7880794701986755, - "unit" : "U/hour", - "delivered": 0.15 - }, - { - "start_at" : "2016-01-30T17:35:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:40:42", - "type" : "TempBasal", - "amount" : 1.2000000000000002, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T17:30:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:35:42", - "type" : "TempBasal", - "amount" : 1.7940199335548173, - "unit" : "U/hour", - "delivered": 0.15 - }, - { - "start_at" : "2016-01-30T17:25:43", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:30:41", - "type" : "TempBasal", - "amount" : 1.8120805369127515, - "unit" : "U/hour", - "delivered": 0.15 - }, - { - "start_at" : "2016-01-30T17:20:44", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:25:43", - "type" : "TempBasal", - "amount" : 0.60200668896321063, - "unit" : "U/hour", - "delivered": 0.05 - }, - { - "start_at" : "2016-01-30T17:15:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:20:44", - "type" : "TempBasal", - "amount" : 0.89403973509933776, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T17:10:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:15:42", - "type" : "TempBasal", - "amount" : 0.89700996677740863, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T17:05:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:10:41", - "type" : "TempBasal", - "amount" : 0.60200668896321063, - "unit" : "U/hour", - "delivered": 0.05 - }, - { - "start_at" : "2016-01-30T17:00:45", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:05:42", - "type" : "TempBasal", - "amount" : 46.969696969696969, - "unit" : "U/hour", - "delivered": 3.9 - }, - { - "start_at" : "2016-01-30T16:50:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:00:45", - "type" : "TempBasal", - "amount" : 2.9850746268656714, - "unit" : "U/hour", - "delivered": 0.5 - }, - { - "start_at" : "2016-01-30T16:45:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:50:42", - "type" : "TempBasal", - "amount" : 2.4000000000000004, - "unit" : "U/hour", - "delivered": 0.2 - }, - { - "start_at" : "2016-01-30T16:40:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:45:42", - "type" : "TempBasal", - "amount" : 2.4000000000000004, - "unit" : "U/hour", - "delivered": 0.2 - }, - { - "start_at" : "2016-01-30T16:35:43", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:40:42", - "type" : "TempBasal", - "amount" : 3.0100334448160533, - "unit" : "U/hour", - "delivered": 0.25 - }, - { - "start_at" : "2016-01-30T16:30:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:35:43", - "type" : "TempBasal", - "amount" : 1.7940199335548173, - "unit" : "U/hour", - "delivered": 0.15 - }, - { - "start_at" : "2016-01-30T16:25:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:30:42", - "type" : "TempBasal", - "amount" : 1.8, - "unit" : "U/hour", - "delivered": 0.15 - }, - { - "start_at" : "2016-01-30T16:20:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:25:42", - "type" : "TempBasal", - "amount" : 0.59800664451827246, - "unit" : "U/hour", - "delivered": 0.05 - }, - { - "start_at" : "2016-01-30T16:15:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:20:41", - "type" : "TempBasal", - "amount" : 0.9030100334448159, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T16:10:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:15:42", - "type" : "TempBasal", - "amount" : 0.90000000000000002, - "unit" : "U/hour", - "delivered": 0.1 - }, - { - "start_at" : "2016-01-30T16:05:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:10:42", - "type" : "TempBasal", - "amount" : 0.60000000000000009, - "unit" : "U/hour", - "delivered": 0.05 - }, - { - "start_at" : "2016-01-30T16:00:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:05:42", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U/hour", - "delivered": 0 - }, - { - "start_at" : "2016-01-30T15:45:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T15:50:42", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U/hour", - "delivered": 0 - }, - { - "start_at" : "2016-01-30T15:40:49", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T15:45:42", - "type" : "TempBasal", - "amount" : 2.4573378839590441, - "unit" : "U/hour", - "delivered": 0.2 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/doses_overlay_basal_profile_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/doses_overlay_basal_profile_output.json deleted file mode 100644 index f36ff55a6..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/doses_overlay_basal_profile_output.json +++ /dev/null @@ -1,306 +0,0 @@ -[ - { - "start_at" : "2016-02-15T14:01:04", - "end_at" : "2016-02-15T14:58:02", - "type" : "BasalProfileStart", - "amount" : 0.75, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T14:58:02", - "end_at" : "2016-02-15T15:00:00", - "type" : "TempBasal", - "amount" : 3.5, - "unit" : "U\/hour", - "raw" : "TB0 1/2" - }, - { - "start_at" : "2016-02-15T15:00:00", - "end_at" : "2016-02-15T15:06:05", - "type" : "TempBasal", - "amount" : 3.5, - "unit" : "U\/hour", - "raw" : "TB0 2/2" - }, - { - "start_at" : "2016-02-15T15:06:05", - "end_at" : "2016-02-15T15:21:06", - "type" : "TempBasal", - "amount" : 3.5, - "unit" : "U\/hour", - "raw" : "TB1" - }, - { - "start_at" : "2016-02-15T15:18:56", - "end_at" : "2016-02-15T15:18:56", - "type" : "Bolus", - "amount" : 2.1499999999999999, - "unit" : "U" - }, - { - "start_at" : "2016-02-15T15:21:06", - "end_at" : "2016-02-15T15:26:05", - "type" : "TempBasal", - "amount" : 2.25, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T15:26:05", - "end_at" : "2016-02-15T15:31:06", - "type" : "TempBasal", - "amount" : 2.6000000000000001, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T15:31:06", - "end_at" : "2016-02-15T15:36:05", - "type" : "TempBasal", - "amount" : 2.8250000000000002, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T15:36:05", - "end_at" : "2016-02-15T15:41:05", - "type" : "TempBasal", - "amount" : 2.4750000000000001, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T15:41:05", - "end_at" : "2016-02-15T15:46:05", - "type" : "TempBasal", - "amount" : 1.95, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T15:50:08", - "end_at" : "2016-02-15T15:50:08", - "type" : "Bolus", - "amount" : 2.3999999999999999, - "unit" : "U" - }, - { - "start_at" : "2016-02-15T15:46:05", - "end_at" : "2016-02-15T16:01:07", - "type" : "BasalProfileStart", - "amount" : 0.80000000000000004, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T16:01:07", - "end_at" : "2016-02-15T16:21:11", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T16:21:11", - "end_at" : "2016-02-15T16:41:09", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T16:41:09", - "end_at" : "2016-02-15T17:01:08", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T17:01:08", - "end_at" : "2016-02-15T17:11:08", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T17:05:39", - "end_at" : "2016-02-15T17:05:39", - "type" : "Bolus", - "amount" : 1.1000000000000001, - "unit" : "U" - }, - { - "start_at" : "2016-02-15T17:11:08", - "end_at" : "2016-02-15T17:41:08", - "type" : "TempBasal", - "amount" : 3.4750000000000001, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T17:36:40", - "end_at" : "2016-02-15T17:36:40", - "type" : "Bolus", - "amount" : 2.5, - "unit" : "U" - }, - { - "start_at" : "2016-02-15T17:41:08", - "end_at" : "2016-02-15T17:56:17", - "type" : "BasalProfileStart", - "amount" : 0.80000000000000004, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T17:56:17", - "end_at" : "2016-02-15T18:01:09", - "type" : "TempBasal", - "amount" : 3.5, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T18:01:09", - "end_at" : "2016-02-15T18:21:11", - "type" : "TempBasal", - "amount" : 3.3250000000000002, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T18:21:11", - "end_at" : "2016-02-15T18:51:07", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T18:41:27", - "end_at" : "2016-02-15T18:41:27", - "type" : "Bolus", - "amount" : 2.2000000000000002, - "unit" : "U" - }, - { - "start_at" : "2016-02-15T18:45:17", - "end_at" : "2016-02-15T18:45:17", - "type" : "Bolus", - "amount" : 1.1499999999999999, - "unit" : "U" - }, - { - "start_at" : "2016-02-15T18:51:07", - "end_at" : "2016-02-15T18:56:08", - "type" : "TempBasal", - "amount" : 0.050000000000000003, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T18:56:08", - "end_at" : "2016-02-15T19:01:09", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T19:01:09", - "end_at" : "2016-02-15T19:31:08", - "type" : "BasalProfileStart", - "amount" : 0.80000000000000004, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T19:31:08", - "end_at" : "2016-02-15T19:36:11", - "type" : "TempBasal", - "amount" : 0.050000000000000003, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T19:36:11", - "end_at" : "2016-02-15T19:41:07", - "type" : "BasalProfileStart", - "amount" : 0.80000000000000004, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T19:41:07", - "end_at" : "2016-02-15T19:46:07", - "type" : "TempBasal", - "amount" : 1.425, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T19:46:07", - "end_at" : "2016-02-15T19:51:07", - "type" : "TempBasal", - "amount" : 1.675, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T19:51:07", - "end_at" : "2016-02-15T19:56:09", - "type" : "TempBasal", - "amount" : 1.75, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T19:56:09", - "end_at" : "2016-02-15T20:06:08", - "type" : "TempBasal", - "amount" : 1.95, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T20:06:08", - "end_at" : "2016-02-15T20:11:15", - "type" : "TempBasal", - "amount" : 2, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T20:11:15", - "end_at" : "2016-02-15T20:16:08", - "type" : "TempBasal", - "amount" : 2, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T20:16:08", - "end_at" : "2016-02-15T20:19:21", - "type" : "TempBasal", - "amount" : 2.5, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T20:18:54", - "end_at" : "2016-02-15T20:18:54", - "type" : "Bolus", - "amount" : 0.65000000000000002, - "unit" : "U" - }, - { - "start_at" : "2016-02-15T20:19:21", - "end_at" : "2016-02-15T20:25:01", - "type" : "PumpSuspend", - "amount" : 0, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T20:25:01", - "end_at" : "2016-02-15T20:36:08", - "type" : "TempBasal", - "amount" : 2.5, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T20:36:08", - "end_at" : "2016-02-15T20:41:10", - "type" : "TempBasal", - "amount" : 2.875, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T20:41:10", - "end_at" : "2016-02-15T20:46:09", - "type" : "TempBasal", - "amount" : 2.9750000000000001, - "unit" : "U\/hour" - }, - { - "start_at" : "2016-02-15T20:46:09", - "end_at" : "2016-02-15T21:16:09", - "type" : "TempBasal", - "amount" : 2.125, - "unit" : "U\/hour" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_basal_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_basal_output.json deleted file mode 100644 index 8ee8503ea..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_basal_output.json +++ /dev/null @@ -1 +0,0 @@ -[{"date": "2015-07-13T12:00:00", "amount": 0.0, "unit": "mg/dL"}, {"date": "2015-07-13T12:05:00", "amount": 0.0, "unit": "mg/dL"}, {"date": "2015-07-13T12:10:00", "amount": 0.0, "unit": "mg/dL"}, {"date": "2015-07-13T12:15:00", "amount": -0.0212969395833333, "unit": "mg/dL"}, {"date": "2015-07-13T12:20:00", "amount": -0.070784639583333, "unit": "mg/dL"}, {"date": "2015-07-13T12:25:00", "amount": -0.156415912499999, "unit": "mg/dL"}, {"date": "2015-07-13T12:30:00", "amount": -0.285552445833332, "unit": "mg/dL"}, {"date": "2015-07-13T12:35:00", "amount": -1.439312598291702, "unit": "mg/dL"}, {"date": "2015-07-13T12:40:00", "amount": -1.646352036684694, "unit": "mg/dL"}, {"date": "2015-07-13T12:45:00", "amount": -1.9135041214355557, "unit": "mg/dL"}, {"date": "2015-07-13T12:50:00", "amount": -2.244933881729385, "unit": "mg/dL"}, {"date": "2015-07-13T12:55:00", "amount": -2.6460811799493813, "unit": "mg/dL"}, {"date": "2015-07-13T13:00:00", "amount": -3.121352446768033, "unit": "mg/dL"}, {"date": "2015-07-13T13:05:00", "amount": -3.674670564478693, "unit": "mg/dL"}, {"date": "2015-07-13T13:10:00", "amount": -4.307710907658077, "unit": "mg/dL"}, {"date": "2015-07-13T13:15:00", "amount": -5.009601365473694, "unit": "mg/dL"}, {"date": "2015-07-13T13:20:00", "amount": -5.771810136391176, "unit": "mg/dL"}, {"date": "2015-07-13T13:25:00", "amount": -6.58856323870386, "unit": "mg/dL"}, {"date": "2015-07-13T13:30:00", "amount": -7.454146661371742, "unit": "mg/dL"}, {"date": "2015-07-13T13:35:00", "amount": -8.363039697354816, "unit": "mg/dL"}, {"date": "2015-07-13T13:40:00", "amount": -9.309914943613103, "unit": "mg/dL"}, {"date": "2015-07-13T13:45:00", "amount": -10.289638301106587, "unit": "mg/dL"}, {"date": "2015-07-13T13:50:00", "amount": -11.297268974795276, "unit": "mg/dL"}, {"date": "2015-07-13T13:55:00", "amount": -12.328059473639158, "unit": "mg/dL"}, {"date": "2015-07-13T14:00:00", "amount": -13.377455610598233, "unit": "mg/dL"}, {"date": "2015-07-13T14:05:00", "amount": -14.441096502632519, "unit": "mg/dL"}, {"date": "2015-07-13T14:10:00", "amount": -15.514814570702004, "unit": "mg/dL"}, {"date": "2015-07-13T14:15:00", "amount": -16.594635539766685, "unit": "mg/dL"}, {"date": "2015-07-13T14:20:00", "amount": -17.676778438786563, "unit": "mg/dL"}, {"date": "2015-07-13T14:25:00", "amount": -18.757655600721648, "unit": "mg/dL"}, {"date": "2015-07-13T14:30:00", "amount": -19.833872662531927, "unit": "mg/dL"}, {"date": "2015-07-13T14:35:00", "amount": -20.90222856517741, "unit": "mg/dL"}, {"date": "2015-07-13T14:40:00", "amount": -21.95971555361809, "unit": "mg/dL"}, {"date": "2015-07-13T14:45:00", "amount": -23.003519176813974, "unit": "mg/dL"}, {"date": "2015-07-13T14:50:00", "amount": -24.03101828772506, "unit": "mg/dL"}, {"date": "2015-07-13T14:55:00", "amount": -25.039785043311344, "unit": "mg/dL"}, {"date": "2015-07-13T15:00:00", "amount": -26.027584904532823, "unit": "mg/dL"}, {"date": "2015-07-13T15:05:00", "amount": -26.99237663634951, "unit": "mg/dL"}, {"date": "2015-07-13T15:10:00", "amount": -27.93231230772139, "unit": "mg/dL"}, {"date": "2015-07-13T15:15:00", "amount": -28.845737291608465, "unit": "mg/dL"}, {"date": "2015-07-13T15:20:00", "amount": -29.731190264970753, "unit": "mg/dL"}, {"date": "2015-07-13T15:25:00", "amount": -30.587403208768237, "unit": "mg/dL"}, {"date": "2015-07-13T15:30:00", "amount": -31.41330140796092, "unit": "mg/dL"}, {"date": "2015-07-13T15:35:00", "amount": -32.2080034515088, "unit": "mg/dL"}, {"date": "2015-07-13T15:40:00", "amount": -32.97082123237188, "unit": "mg/dL"}, {"date": "2015-07-13T15:45:00", "amount": -33.70125994751017, "unit": "mg/dL"}, {"date": "2015-07-13T15:50:00", "amount": -34.39901809788364, "unit": "mg/dL"}, {"date": "2015-07-13T15:55:00", "amount": -35.06398748845233, "unit": "mg/dL"}, {"date": "2015-07-13T16:00:00", "amount": -35.69625322817621, "unit": "mg/dL"}, {"date": "2015-07-13T16:05:00", "amount": -36.29609373001529, "unit": "mg/dL"}, {"date": "2015-07-13T16:10:00", "amount": -36.86583922826291, "unit": "mg/dL"}, {"date": "2015-07-13T16:15:00", "amount": -37.408830876376534, "unit": "mg/dL"}, {"date": "2015-07-13T16:20:00", "amount": -37.89110380286491, "unit": "mg/dL"}, {"date": "2015-07-13T16:25:00", "amount": -38.31555703053625, "unit": "mg/dL"}, {"date": "2015-07-13T16:30:00", "amount": -38.68508788661321, "unit": "mg/dL"}, {"date": "2015-07-13T16:35:00", "amount": -39.00257545273462, "unit": "mg/dL"}, {"date": "2015-07-13T16:40:00", "amount": -39.27829808429049, "unit": "mg/dL"}, {"date": "2015-07-13T16:45:00", "amount": -39.49976700542361, "unit": "mg/dL"}, {"date": "2015-07-13T16:50:00", "amount": -39.677555985574045, "unit": "mg/dL"}, {"date": "2015-07-13T16:55:00", "amount": -39.81430562072619, "unit": "mg/dL"}, {"date": "2015-07-13T17:00:00", "amount": -39.91255551127546, "unit": "mg/dL"}, {"date": "2015-07-13T17:05:00", "amount": -39.97472771203005, "unit": "mg/dL"}, {"date": "2015-07-13T17:10:00", "amount": -40.0, "unit": "mg/dL"}] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_basal_output_exponential.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_basal_output_exponential.json deleted file mode 100644 index f1dfa9b1b..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_basal_output_exponential.json +++ /dev/null @@ -1,89 +0,0 @@ -[ - {"date": "2015-07-13T12:00:00", "unit": "mg/dL", "amount": 0.0}, - {"date": "2015-07-13T12:05:00", "unit": "mg/dL", "amount": 0.0}, - {"date": "2015-07-13T12:10:00", "unit": "mg/dL", "amount": 0.0}, - {"date": "2015-07-13T12:15:00", "unit": "mg/dL", "amount": -0.008033011416282616}, - {"date": "2015-07-13T12:20:00", "unit": "mg/dL", "amount": -0.038849033428092566}, - {"date": "2015-07-13T12:25:00", "unit": "mg/dL", "amount": -0.10535384721456284}, - {"date": "2015-07-13T12:30:00", "unit": "mg/dL", "amount": -0.2187716638654017}, - {"date": "2015-07-13T12:35:00", "unit": "mg/dL", "amount": -0.3887954707819904}, - {"date": "2015-07-13T12:40:00", "unit": "mg/dL", "amount": -0.6237259275384043}, - {"date": "2015-07-13T12:45:00", "unit": "mg/dL", "amount": -0.9305996066814043}, - {"date": "2015-07-13T12:50:00", "unit": "mg/dL", "amount": -1.3153073229267587}, - {"date": "2015-07-13T12:55:00", "unit": "mg/dL", "amount": -1.7827032454462588}, - {"date": "2015-07-13T13:00:00", "unit": "mg/dL", "amount": -2.3367054422379145}, - {"date": "2015-07-13T13:05:00", "unit": "mg/dL", "amount": -2.9803884627450197}, - {"date": "2015-07-13T13:10:00", "unit": "mg/dL", "amount": -3.716068524763217}, - {"date": "2015-07-13T13:15:00", "unit": "mg/dL", "amount": -4.537348822667461}, - {"date": "2015-07-13T13:20:00", "unit": "mg/dL", "amount": -5.430507496682818}, - {"date": "2015-07-13T13:25:00", "unit": "mg/dL", "amount": -6.383124870502446}, - {"date": "2015-07-13T13:30:00", "unit": "mg/dL", "amount": -7.383981350855815}, - {"date": "2015-07-13T13:35:00", "unit": "mg/dL", "amount": -8.422962544690117}, - {"date": "2015-07-13T13:40:00", "unit": "mg/dL", "amount": -9.490971116416274}, - {"date": "2015-07-13T13:45:00", "unit": "mg/dL", "amount": -10.579844937837562}, - {"date": "2015-07-13T13:50:00", "unit": "mg/dL", "amount": -11.682281111704016}, - {"date": "2015-07-13T13:55:00", "unit": "mg/dL", "amount": -12.791765476429436}, - {"date": "2015-07-13T14:00:00", "unit": "mg/dL", "amount": -13.902507224472615}, - {"date": "2015-07-13T14:05:00", "unit": "mg/dL", "amount": -15.009378290317489}, - {"date": "2015-07-13T14:10:00", "unit": "mg/dL", "amount": -16.107857185980087}, - {"date": "2015-07-13T14:15:00", "unit": "mg/dL", "amount": -17.193976982608607}, - {"date": "2015-07-13T14:20:00", "unit": "mg/dL", "amount": -18.264277156108786}, - {"date": "2015-07-13T14:25:00", "unit": "mg/dL", "amount": -19.315759032895308}, - {"date": "2015-07-13T14:30:00", "unit": "mg/dL", "amount": -20.34584458891372}, - {"date": "2015-07-13T14:35:00", "unit": "mg/dL", "amount": -21.352338371063585}, - {"date": "2015-07-13T14:40:00", "unit": "mg/dL", "amount": -22.333392325146022}, - {"date": "2015-07-13T14:45:00", "unit": "mg/dL", "amount": -23.28747332851744}, - {"date": "2015-07-13T14:50:00", "unit": "mg/dL", "amount": -24.21333323881225}, - {"date": "2015-07-13T14:55:00", "unit": "mg/dL", "amount": -25.10998128245411}, - {"date": "2015-07-13T15:00:00", "unit": "mg/dL", "amount": -25.976658618257098}, - {"date": "2015-07-13T15:05:00", "unit": "mg/dL", "amount": -26.812814922273176}, - {"date": "2015-07-13T15:10:00", "unit": "mg/dL", "amount": -27.618086850213118}, - {"date": "2015-07-13T15:15:00", "unit": "mg/dL", "amount": -28.392278243297827}, - {"date": "2015-07-13T15:20:00", "unit": "mg/dL", "amount": -29.135341952323728}, - {"date": "2015-07-13T15:25:00", "unit": "mg/dL", "amount": -29.847363163086847}, - {"date": "2015-07-13T15:30:00", "unit": "mg/dL", "amount": -30.528544114140047}, - {"date": "2015-07-13T15:35:00", "unit": "mg/dL", "amount": -31.179190105188912}, - {"date": "2015-07-13T15:40:00", "unit": "mg/dL", "amount": -31.79969670129493}, - {"date": "2015-07-13T15:45:00", "unit": "mg/dL", "amount": -32.39053804447812}, - {"date": "2015-07-13T15:50:00", "unit": "mg/dL", "amount": -32.952256190323006}, - {"date": "2015-07-13T15:55:00", "unit": "mg/dL", "amount": -33.485451392816486}, - {"date": "2015-07-13T16:00:00", "unit": "mg/dL", "amount": -33.990773265907926}, - {"date": "2015-07-13T16:05:00", "unit": "mg/dL", "amount": -34.46891275520359}, - {"date": "2015-07-13T16:10:00", "unit": "mg/dL", "amount": -34.920594857809405}, - {"date": "2015-07-13T16:15:00", "unit": "mg/dL", "amount": -35.34657203263932}, - {"date": "2015-07-13T16:20:00", "unit": "mg/dL", "amount": -35.7476182475284}, - {"date": "2015-07-13T16:25:00", "unit": "mg/dL", "amount": -36.124523613248925}, - {"date": "2015-07-13T16:30:00", "unit": "mg/dL", "amount": -36.4780895580399}, - {"date": "2015-07-13T16:35:00", "unit": "mg/dL", "amount": -36.80912449954168}, - {"date": "2015-07-13T16:40:00", "unit": "mg/dL", "amount": -37.118439974091196}, - {"date": "2015-07-13T16:45:00", "unit": "mg/dL", "amount": -37.406847186195435}, - {"date": "2015-07-13T16:50:00", "unit": "mg/dL", "amount": -37.675153943670864}, - {"date": "2015-07-13T16:55:00", "unit": "mg/dL", "amount": -37.92416194643027}, - {"date": "2015-07-13T17:00:00", "unit": "mg/dL", "amount": -38.15466439922404}, - {"date": "2015-07-13T17:05:00", "unit": "mg/dL", "amount": -38.367443920812725}, - {"date": "2015-07-13T17:10:00", "unit": "mg/dL", "amount": -38.56327072407135}, - {"date": "2015-07-13T17:15:00", "unit": "mg/dL", "amount": -38.74290104341243}, - {"date": "2015-07-13T17:20:00", "unit": "mg/dL", "amount": -38.907075787672774}, - {"date": "2015-07-13T17:25:00", "unit": "mg/dL", "amount": -39.05651939824797}, - {"date": "2015-07-13T17:30:00", "unit": "mg/dL", "amount": -39.19193889378452}, - {"date": "2015-07-13T17:35:00", "unit": "mg/dL", "amount": -39.31402308416055}, - {"date": "2015-07-13T17:40:00", "unit": "mg/dL", "amount": -39.423441937809876}, - {"date": "2015-07-13T17:45:00", "unit": "mg/dL", "amount": -39.520846087674585}, - {"date": "2015-07-13T17:50:00", "unit": "mg/dL", "amount": -39.606866462217795}, - {"date": "2015-07-13T17:55:00", "unit": "mg/dL", "amount": -39.682114028992764}, - {"date": "2015-07-13T18:00:00", "unit": "mg/dL", "amount": -39.747179639255556}, - {"date": "2015-07-13T18:05:00", "unit": "mg/dL", "amount": -39.802633963028484}, - {"date": "2015-07-13T18:10:00", "unit": "mg/dL", "amount": -39.84902750487664}, - {"date": "2015-07-13T18:15:00", "unit": "mg/dL", "amount": -39.88712884500522}, - {"date": "2015-07-13T18:20:00", "unit": "mg/dL", "amount": -39.91790264063589}, - {"date": "2015-07-13T18:25:00", "unit": "mg/dL", "amount": -39.94226172251777}, - {"date": "2015-07-13T18:30:00", "unit": "mg/dL", "amount": -39.96106881144775}, - {"date": "2015-07-13T18:35:00", "unit": "mg/dL", "amount": -39.97513823895366}, - {"date": "2015-07-13T18:40:00", "unit": "mg/dL", "amount": -39.985237665417124}, - {"date": "2015-07-13T18:45:00", "unit": "mg/dL", "amount": -39.99208978966262}, - {"date": "2015-07-13T18:50:00", "unit": "mg/dL", "amount": -39.996374044725805}, - {"date": "2015-07-13T18:55:00", "unit": "mg/dL", "amount": -39.99872827514451}, - {"date": "2015-07-13T19:00:00", "unit": "mg/dL", "amount": -39.999750391692004}, - {"date": "2015-07-13T19:05:00", "unit": "mg/dL", "amount": -40.0}, - {"date": "2015-07-13T19:10:00", "unit": "mg/dL", "amount": -40.0} -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_bolus_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_bolus_output.json deleted file mode 100644 index 4234b6b48..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_bolus_output.json +++ /dev/null @@ -1 +0,0 @@ -[{"date": "2015-07-13T12:00:00", "amount": 0.0, "unit": "mg/dL"}, {"date": "2015-07-13T12:05:00", "amount": 0.0, "unit": "mg/dL"}, {"date": "2015-07-13T12:10:00", "amount": 0.0, "unit": "mg/dL"}, {"date": "2015-07-13T12:15:00", "amount": -0.25809001811542664, "unit": "mg/dL"}, {"date": "2015-07-13T12:20:00", "amount": -0.7194464555747171, "unit": "mg/dL"}, {"date": "2015-07-13T12:25:00", "amount": -1.3272762139540095, "unit": "mg/dL"}, {"date": "2015-07-13T12:30:00", "amount": -2.0708476872532966, "unit": "mg/dL"}, {"date": "2015-07-13T12:35:00", "amount": -2.9397271694725857, "unit": "mg/dL"}, {"date": "2015-07-13T12:40:00", "amount": -3.9237788546118724, "unit": "mg/dL"}, {"date": "2015-07-13T12:45:00", "amount": -5.0131648366711605, "unit": "mg/dL"}, {"date": "2015-07-13T12:50:00", "amount": -6.198345109650454, "unit": "mg/dL"}, {"date": "2015-07-13T12:55:00", "amount": -7.47007756754974, "unit": "mg/dL"}, {"date": "2015-07-13T13:00:00", "amount": -8.819418004369034, "unit": "mg/dL"}, {"date": "2015-07-13T13:05:00", "amount": -10.237720114108315, "unit": "mg/dL"}, {"date": "2015-07-13T13:10:00", "amount": -11.716635490767612, "unit": "mg/dL"}, {"date": "2015-07-13T13:15:00", "amount": -13.248113628346898, "unit": "mg/dL"}, {"date": "2015-07-13T13:20:00", "amount": -14.824401920846185, "unit": "mg/dL"}, {"date": "2015-07-13T13:25:00", "amount": -16.43804566226547, "unit": "mg/dL"}, {"date": "2015-07-13T13:30:00", "amount": -18.08188804660476, "unit": "mg/dL"}, {"date": "2015-07-13T13:35:00", "amount": -19.749070167864055, "unit": "mg/dL"}, {"date": "2015-07-13T13:40:00", "amount": -21.433031020043337, "unit": "mg/dL"}, {"date": "2015-07-13T13:45:00", "amount": -23.127507497142634, "unit": "mg/dL"}, {"date": "2015-07-13T13:50:00", "amount": -24.826534393161918, "unit": "mg/dL"}, {"date": "2015-07-13T13:55:00", "amount": -26.52444440210121, "unit": "mg/dL"}, {"date": "2015-07-13T14:00:00", "amount": -28.215868117960493, "unit": "mg/dL"}, {"date": "2015-07-13T14:05:00", "amount": -29.89573403473978, "unit": "mg/dL"}, {"date": "2015-07-13T14:10:00", "amount": -31.559268546439075, "unit": "mg/dL"}, {"date": "2015-07-13T14:15:00", "amount": -33.201995947058364, "unit": "mg/dL"}, {"date": "2015-07-13T14:20:00", "amount": -34.819738430597646, "unit": "mg/dL"}, {"date": "2015-07-13T14:25:00", "amount": -36.408616091056935, "unit": "mg/dL"}, {"date": "2015-07-13T14:30:00", "amount": -37.96504692243623, "unit": "mg/dL"}, {"date": "2015-07-13T14:35:00", "amount": -39.48574681873551, "unit": "mg/dL"}, {"date": "2015-07-13T14:40:00", "amount": -40.967729573954806, "unit": "mg/dL"}, {"date": "2015-07-13T14:45:00", "amount": -42.408306882094095, "unit": "mg/dL"}, {"date": "2015-07-13T14:50:00", "amount": -43.805088337153364, "unit": "mg/dL"}, {"date": "2015-07-13T14:55:00", "amount": -45.15598143313266, "unit": "mg/dL"}, {"date": "2015-07-13T15:00:00", "amount": -46.459191564031954, "unit": "mg/dL"}, {"date": "2015-07-13T15:05:00", "amount": -47.71322202385125, "unit": "mg/dL"}, {"date": "2015-07-13T15:10:00", "amount": -48.91687400659053, "unit": "mg/dL"}, {"date": "2015-07-13T15:15:00", "amount": -50.06924660624982, "unit": "mg/dL"}, {"date": "2015-07-13T15:20:00", "amount": -51.16973681682911, "unit": "mg/dL"}, {"date": "2015-07-13T15:25:00", "amount": -52.218039532328405, "unit": "mg/dL"}, {"date": "2015-07-13T15:30:00", "amount": -53.21414754674769, "unit": "mg/dL"}, {"date": "2015-07-13T15:35:00", "amount": -54.15835155408698, "unit": "mg/dL"}, {"date": "2015-07-13T15:40:00", "amount": -55.05124014834625, "unit": "mg/dL"}, {"date": "2015-07-13T15:45:00", "amount": -55.893699823525544, "unit": "mg/dL"}, {"date": "2015-07-13T15:50:00", "amount": -56.68691497362482, "unit": "mg/dL"}, {"date": "2015-07-13T15:55:00", "amount": -57.43236789264414, "unit": "mg/dL"}, {"date": "2015-07-13T16:00:00", "amount": -58.131838774583414, "unit": "mg/dL"}, {"date": "2015-07-13T16:05:00", "amount": -58.787405713442716, "unit": "mg/dL"}, {"date": "2015-07-13T16:10:00", "amount": -59.40144470322201, "unit": "mg/dL"}, {"date": "2015-07-13T16:15:00", "amount": -60.0, "unit": "mg/dL"}, {"date": "2015-07-13T16:20:00", "amount": -60.0, "unit": "mg/dL"}] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_history_exponential_delivered_units_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_history_exponential_delivered_units_output.json deleted file mode 100644 index 0b40c6cfe..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_history_exponential_delivered_units_output.json +++ /dev/null @@ -1,136 +0,0 @@ -[ - {"date": "2016-01-30T15:45:00", "unit": "mg/dL", "amount": 0.0}, - {"date": "2016-01-30T15:50:00", "unit": "mg/dL", "amount": 0.0}, - {"date": "2016-01-30T15:55:00", "unit": "mg/dL", "amount": -0.008058637134079156}, - {"date": "2016-01-30T16:00:00", "unit": "mg/dL", "amount": -0.03126699925677042}, - {"date": "2016-01-30T16:05:00", "unit": "mg/dL", "amount": -0.05840028045463749}, - {"date": "2016-01-30T16:10:00", "unit": "mg/dL", "amount": -0.08873132466351286}, - {"date": "2016-01-30T16:15:00", "unit": "mg/dL", "amount": -0.1157743010921895}, - {"date": "2016-01-30T16:20:00", "unit": "mg/dL", "amount": -0.1277967501255132}, - {"date": "2016-01-30T16:25:00", "unit": "mg/dL", "amount": -0.12372760515161077}, - {"date": "2016-01-30T16:30:00", "unit": "mg/dL", "amount": -0.10856690616443714}, - {"date": "2016-01-30T16:35:00", "unit": "mg/dL", "amount": -0.08324578139790119}, - {"date": "2016-01-30T16:40:00", "unit": "mg/dL", "amount": -0.05002239413559397}, - {"date": "2016-01-30T16:45:00", "unit": "mg/dL", "amount": -0.02236941617729054}, - {"date": "2016-01-30T16:50:00", "unit": "mg/dL", "amount": -0.019401763665137448}, - {"date": "2016-01-30T16:55:00", "unit": "mg/dL", "amount": -0.06602825535036101}, - {"date": "2016-01-30T17:00:00", "unit": "mg/dL", "amount": -0.17830862368857017}, - {"date": "2016-01-30T17:05:00", "unit": "mg/dL", "amount": -0.37351349193495204}, - {"date": "2016-01-30T17:10:00", "unit": "mg/dL", "amount": -0.6721359900968964}, - {"date": "2016-01-30T17:15:00", "unit": "mg/dL", "amount": -1.3476871100362766}, - {"date": "2016-01-30T17:20:00", "unit": "mg/dL", "amount": -2.796375106779187}, - {"date": "2016-01-30T17:25:00", "unit": "mg/dL", "amount": -4.925459912085938}, - {"date": "2016-01-30T17:30:00", "unit": "mg/dL", "amount": -7.648187207088725}, - {"date": "2016-01-30T17:35:00", "unit": "mg/dL", "amount": -10.882062262817067}, - {"date": "2016-01-30T17:40:00", "unit": "mg/dL", "amount": -14.55353456891312}, - {"date": "2016-01-30T17:45:00", "unit": "mg/dL", "amount": -18.60737914367776}, - {"date": "2016-01-30T17:50:00", "unit": "mg/dL", "amount": -22.989630905827887}, - {"date": "2016-01-30T17:55:00", "unit": "mg/dL", "amount": -27.64906184580903}, - {"date": "2016-01-30T18:00:00", "unit": "mg/dL", "amount": -32.54130237357997}, - {"date": "2016-01-30T18:05:00", "unit": "mg/dL", "amount": -37.617062099023165}, - {"date": "2016-01-30T18:10:00", "unit": "mg/dL", "amount": -42.82969246092595}, - {"date": "2016-01-30T18:15:00", "unit": "mg/dL", "amount": -48.236262279156044}, - {"date": "2016-01-30T18:20:00", "unit": "mg/dL", "amount": -53.93941759865179}, - {"date": "2016-01-30T18:25:00", "unit": "mg/dL", "amount": -59.87119257744761}, - {"date": "2016-01-30T18:30:00", "unit": "mg/dL", "amount": -65.96842048228727}, - {"date": "2016-01-30T18:35:00", "unit": "mg/dL", "amount": -72.18537348149229}, - {"date": "2016-01-30T18:40:00", "unit": "mg/dL", "amount": -78.48319543380462}, - {"date": "2016-01-30T18:45:00", "unit": "mg/dL", "amount": -84.82729622830595}, - {"date": "2016-01-30T18:50:00", "unit": "mg/dL", "amount": -91.18321612790837}, - {"date": "2016-01-30T18:55:00", "unit": "mg/dL", "amount": -97.51469443227829}, - {"date": "2016-01-30T19:00:00", "unit": "mg/dL", "amount": -103.78609620542139}, - {"date": "2016-01-30T19:05:00", "unit": "mg/dL", "amount": -109.96038873729371}, - {"date": "2016-01-30T19:10:00", "unit": "mg/dL", "amount": -116.01237829192482}, - {"date": "2016-01-30T19:15:00", "unit": "mg/dL", "amount": -121.93176182909212}, - {"date": "2016-01-30T19:20:00", "unit": "mg/dL", "amount": -127.70658294986585}, - {"date": "2016-01-30T19:25:00", "unit": "mg/dL", "amount": -133.3246637214885}, - {"date": "2016-01-30T19:30:00", "unit": "mg/dL", "amount": -138.781487761029}, - {"date": "2016-01-30T19:35:00", "unit": "mg/dL", "amount": -144.07023537090407}, - {"date": "2016-01-30T19:40:00", "unit": "mg/dL", "amount": -149.20129881913283}, - {"date": "2016-01-30T19:45:00", "unit": "mg/dL", "amount": -154.21897903353934}, - {"date": "2016-01-30T19:50:00", "unit": "mg/dL", "amount": -159.19557830358974}, - {"date": "2016-01-30T19:55:00", "unit": "mg/dL", "amount": -164.196699080784}, - {"date": "2016-01-30T20:00:00", "unit": "mg/dL", "amount": -169.20001331869452}, - {"date": "2016-01-30T20:05:00", "unit": "mg/dL", "amount": -174.1917801837248}, - {"date": "2016-01-30T20:10:00", "unit": "mg/dL", "amount": -179.16776502180073}, - {"date": "2016-01-30T20:15:00", "unit": "mg/dL", "amount": -184.12588351000534}, - {"date": "2016-01-30T20:20:00", "unit": "mg/dL", "amount": -189.07204799070053}, - {"date": "2016-01-30T20:25:00", "unit": "mg/dL", "amount": -194.0095911101109}, - {"date": "2016-01-30T20:30:00", "unit": "mg/dL", "amount": -199.01587158937315}, - {"date": "2016-01-30T20:35:00", "unit": "mg/dL", "amount": -204.1847935578997}, - {"date": "2016-01-30T20:40:00", "unit": "mg/dL", "amount": -209.47141687087347}, - {"date": "2016-01-30T20:45:00", "unit": "mg/dL", "amount": -214.83944415242763}, - {"date": "2016-01-30T20:50:00", "unit": "mg/dL", "amount": -220.25544697132966}, - {"date": "2016-01-30T20:55:00", "unit": "mg/dL", "amount": -225.68771153826862}, - {"date": "2016-01-30T21:00:00", "unit": "mg/dL", "amount": -231.10813185919068}, - {"date": "2016-01-30T21:05:00", "unit": "mg/dL", "amount": -236.4919351226982}, - {"date": "2016-01-30T21:10:00", "unit": "mg/dL", "amount": -241.8173943218202}, - {"date": "2016-01-30T21:15:00", "unit": "mg/dL", "amount": -247.0655623213702}, - {"date": "2016-01-30T21:20:00", "unit": "mg/dL", "amount": -252.22002590076102}, - {"date": "2016-01-30T21:25:00", "unit": "mg/dL", "amount": -257.26667839737706}, - {"date": "2016-01-30T21:30:00", "unit": "mg/dL", "amount": -262.19350966491965}, - {"date": "2016-01-30T21:35:00", "unit": "mg/dL", "amount": -266.99041214488375}, - {"date": "2016-01-30T21:40:00", "unit": "mg/dL", "amount": -271.6490019278395}, - {"date": "2016-01-30T21:45:00", "unit": "mg/dL", "amount": -276.16245375479957}, - {"date": "2016-01-30T21:50:00", "unit": "mg/dL", "amount": -280.52534897792924}, - {"date": "2016-01-30T21:55:00", "unit": "mg/dL", "amount": -284.7337737616358}, - {"date": "2016-01-30T22:00:00", "unit": "mg/dL", "amount": -288.78494375273607}, - {"date": "2016-01-30T22:05:00", "unit": "mg/dL", "amount": -292.67655010600373}, - {"date": "2016-01-30T22:10:00", "unit": "mg/dL", "amount": -296.40749215851605}, - {"date": "2016-01-30T22:15:00", "unit": "mg/dL", "amount": -299.9773086730975}, - {"date": "2016-01-30T22:20:00", "unit": "mg/dL", "amount": -303.3860869895834}, - {"date": "2016-01-30T22:25:00", "unit": "mg/dL", "amount": -306.6348503015701}, - {"date": "2016-01-30T22:30:00", "unit": "mg/dL", "amount": -309.7253623047983}, - {"date": "2016-01-30T22:35:00", "unit": "mg/dL", "amount": -312.6597633596425}, - {"date": "2016-01-30T22:40:00", "unit": "mg/dL", "amount": -315.44065618961065}, - {"date": "2016-01-30T22:45:00", "unit": "mg/dL", "amount": -318.07135168159755}, - {"date": "2016-01-30T22:50:00", "unit": "mg/dL", "amount": -320.5556618817559}, - {"date": "2016-01-30T22:55:00", "unit": "mg/dL", "amount": -322.897870851888}, - {"date": "2016-01-30T23:00:00", "unit": "mg/dL", "amount": -325.1022564271946}, - {"date": "2016-01-30T23:05:00", "unit": "mg/dL", "amount": -327.1733364746358}, - {"date": "2016-01-30T23:10:00", "unit": "mg/dL", "amount": -329.1158971250881}, - {"date": "2016-01-30T23:15:00", "unit": "mg/dL", "amount": -330.9423468532821}, - {"date": "2016-01-30T23:20:00", "unit": "mg/dL", "amount": -332.6694646924529}, - {"date": "2016-01-30T23:25:00", "unit": "mg/dL", "amount": -334.2999821145705}, - {"date": "2016-01-30T23:30:00", "unit": "mg/dL", "amount": -335.8366666893559}, - {"date": "2016-01-30T23:35:00", "unit": "mg/dL", "amount": -337.2822689409061}, - {"date": "2016-01-30T23:40:00", "unit": "mg/dL", "amount": -338.63964894164116}, - {"date": "2016-01-30T23:45:00", "unit": "mg/dL", "amount": -339.9120639319112}, - {"date": "2016-01-30T23:50:00", "unit": "mg/dL", "amount": -341.10267385392797}, - {"date": "2016-01-30T23:55:00", "unit": "mg/dL", "amount": -342.2145729183633}, - {"date": "2016-01-31T00:00:00", "unit": "mg/dL", "amount": -343.25091298228944}, - {"date": "2016-01-31T00:05:00", "unit": "mg/dL", "amount": -344.2145517709102}, - {"date": "2016-01-31T00:10:00", "unit": "mg/dL", "amount": -345.1082620161427}, - {"date": "2016-01-31T00:15:00", "unit": "mg/dL", "amount": -345.9377255416103}, - {"date": "2016-01-31T00:20:00", "unit": "mg/dL", "amount": -346.71005139085037}, - {"date": "2016-01-31T00:25:00", "unit": "mg/dL", "amount": -347.4272753569584}, - {"date": "2016-01-31T00:30:00", "unit": "mg/dL", "amount": -348.0913562960017}, - {"date": "2016-01-31T00:35:00", "unit": "mg/dL", "amount": -348.7045679961915}, - {"date": "2016-01-31T00:40:00", "unit": "mg/dL", "amount": -349.2692091927786}, - {"date": "2016-01-31T00:45:00", "unit": "mg/dL", "amount": -349.78753573717546}, - {"date": "2016-01-31T00:50:00", "unit": "mg/dL", "amount": -350.2616449413677}, - {"date": "2016-01-31T00:55:00", "unit": "mg/dL", "amount": -350.69341586755917}, - {"date": "2016-01-31T01:00:00", "unit": "mg/dL", "amount": -351.084582560579}, - {"date": "2016-01-31T01:05:00", "unit": "mg/dL", "amount": -351.43667336058223}, - {"date": "2016-01-31T01:10:00", "unit": "mg/dL", "amount": -351.75140518526655}, - {"date": "2016-01-31T01:15:00", "unit": "mg/dL", "amount": -352.0308007492433}, - {"date": "2016-01-31T01:20:00", "unit": "mg/dL", "amount": -352.2767179818597}, - {"date": "2016-01-31T01:25:00", "unit": "mg/dL", "amount": -352.49088810075807}, - {"date": "2016-01-31T01:30:00", "unit": "mg/dL", "amount": -352.67515677972347}, - {"date": "2016-01-31T01:35:00", "unit": "mg/dL", "amount": -352.83120048604326}, - {"date": "2016-01-31T01:40:00", "unit": "mg/dL", "amount": -352.96109874204103}, - {"date": "2016-01-31T01:45:00", "unit": "mg/dL", "amount": -353.0678794858281}, - {"date": "2016-01-31T01:50:00", "unit": "mg/dL", "amount": -353.1553795370504}, - {"date": "2016-01-31T01:55:00", "unit": "mg/dL", "amount": -353.2272911859489}, - {"date": "2016-01-31T02:00:00", "unit": "mg/dL", "amount": -353.28467539016685}, - {"date": "2016-01-31T02:05:00", "unit": "mg/dL", "amount": -353.32872420878937}, - {"date": "2016-01-31T02:10:00", "unit": "mg/dL", "amount": -353.3608125688518}, - {"date": "2016-01-31T02:15:00", "unit": "mg/dL", "amount": -353.3822889210281}, - {"date": "2016-01-31T02:20:00", "unit": "mg/dL", "amount": -353.39466369537524}, - {"date": "2016-01-31T02:25:00", "unit": "mg/dL", "amount": -353.3993021429604}, - {"date": "2016-01-31T02:30:00", "unit": "mg/dL", "amount": -353.3996944954715}, - {"date": "2016-01-31T02:35:00", "unit": "mg/dL", "amount": -353.3999313965389}, - {"date": "2016-01-31T02:40:00", "unit": "mg/dL", "amount": -353.3999989612983}, - {"date": "2016-01-31T02:45:00", "unit": "mg/dL", "amount": -353.40000000000015}, - {"date": "2016-01-31T02:50:00", "unit": "mg/dL", "amount": -353.40000000000015} -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_history_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_history_output.json deleted file mode 100644 index b60dd2577..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/effect_from_history_output.json +++ /dev/null @@ -1,104 +0,0 @@ -[{"date": "2015-10-15T18:05:00", "amount": 0.0, "unit": "mg/dL"}, -{"date": "2015-10-15T18:10:00", "amount": 0.0, "unit": "mg/dL"}, -{"date": "2015-10-15T18:15:00", "amount": 0.0, "unit": "mg/dL"}, -{"date": "2015-10-15T18:20:00", "amount": 0.0006660982605206369, "unit": "mg/dL"}, -{"date": "2015-10-15T18:25:00", "amount": 0.4319784823610822, "unit": "mg/dL"}, -{"date": "2015-10-15T18:30:00", "amount": 0.44733221227527764, "unit": "mg/dL"}, -{"date": "2015-10-15T18:35:00", "amount": 0.48375082617688026, "unit": "mg/dL"}, -{"date": "2015-10-15T18:40:00", "amount": 0.5479479941286376, "unit": "mg/dL"}, -{"date": "2015-10-15T18:45:00", "amount": 0.6454842620882801, "unit": "mg/dL"}, -{"date": "2015-10-15T18:50:00", "amount": 0.7820579409770838, "unit": "mg/dL"}, -{"date": "2015-10-15T18:55:00", "amount": 0.9623103893258668, "unit": "mg/dL"}, -{"date": "2015-10-15T19:00:00", "amount": 1.1802588001439995, "unit": "mg/dL"}, -{"date": "2015-10-15T19:05:00", "amount": 1.4308032930809993, "unit": "mg/dL"}, -{"date": "2015-10-15T19:10:00", "amount": 1.7112340724483681, "unit": "mg/dL"}, -{"date": "2015-10-15T19:15:00", "amount": 2.2972885498746414, "unit": "mg/dL"}, -{"date": "2015-10-15T19:20:00", "amount": 2.657016843602961, "unit": "mg/dL"}, -{"date": "2015-10-15T19:25:00", "amount": 3.064535111779773, "unit": "mg/dL"}, -{"date": "2015-10-15T19:30:00", "amount": 3.524362622697622, "unit": "mg/dL"}, -{"date": "2015-10-15T19:35:00", "amount": 2.645152642588718, "unit": "mg/dL"}, -{"date": "2015-10-15T19:40:00", "amount": 2.1433293952834864, "unit": "mg/dL"}, -{"date": "2015-10-15T19:45:00", "amount": 1.0383154699059773, "unit": "mg/dL"}, -{"date": "2015-10-15T19:50:00", "amount": -0.6037289472355739, "unit": "mg/dL"}, -{"date": "2015-10-15T19:55:00", "amount": -2.7717544797822367, "unit": "mg/dL"}, -{"date": "2015-10-15T20:00:00", "amount": -5.455035986284498, "unit": "mg/dL"}, -{"date": "2015-10-15T20:05:00", "amount": -7.79751242933939, "unit": "mg/dL"}, -{"date": "2015-10-15T20:10:00", "amount": -11.517522500886, "unit": "mg/dL"}, -{"date": "2015-10-15T20:15:00", "amount": -15.716273635751, "unit": "mg/dL"}, -{"date": "2015-10-15T20:20:00", "amount": -21.1870685982325, "unit": "mg/dL"}, -{"date": "2015-10-15T20:25:00", "amount": -27.3631817597881, "unit": "mg/dL"}, -{"date": "2015-10-15T20:30:00", "amount": -34.2256777352351, "unit": "mg/dL"}, -{"date": "2015-10-15T20:35:00", "amount": -41.7099106346659, "unit": "mg/dL"}, -{"date": "2015-10-15T20:40:00", "amount": -49.7561873037511, "unit": "mg/dL"}, -{"date": "2015-10-15T20:45:00", "amount": -59.27102637839595, "unit": "mg/dL"}, -{"date": "2015-10-15T20:50:00", "amount": -67.90057488365268, "unit": "mg/dL"}, -{"date": "2015-10-15T20:55:00", "amount": -77.19519450218243, "unit": "mg/dL"}, -{"date": "2015-10-15T21:00:00", "amount": -86.8085049447589, "unit": "mg/dL"}, -{"date": "2015-10-15T21:05:00", "amount": -96.68477972174647, "unit": "mg/dL"}, -{"date": "2015-10-15T21:10:00", "amount": -106.77048448794005, "unit": "mg/dL"}, -{"date": "2015-10-15T21:15:00", "amount": -117.24440610028151, "unit": "mg/dL"}, -{"date": "2015-10-15T21:20:00", "amount": -127.67910744385503, "unit": "mg/dL"}, -{"date": "2015-10-15T21:25:00", "amount": -138.2396776587623, "unit": "mg/dL"}, -{"date": "2015-10-15T21:30:00", "amount": -148.88226145443326, "unit": "mg/dL"}, -{"date": "2015-10-15T21:35:00", "amount": -159.56499033505642, "unit": "mg/dL"}, -{"date": "2015-10-15T21:40:00", "amount": -170.2513561674504, "unit": "mg/dL"}, -{"date": "2015-10-15T21:45:00", "amount": -180.90675495330677, "unit": "mg/dL"}, -{"date": "2015-10-15T21:50:00", "amount": -192.4751418656235, "unit": "mg/dL"}, -{"date": "2015-10-15T21:55:00", "amount": -204.31129319425713, "unit": "mg/dL"}, -{"date": "2015-10-15T22:00:00", "amount": -216.40765980729208, "unit": "mg/dL"}, -{"date": "2015-10-15T22:05:00", "amount": -228.70879990446016, "unit": "mg/dL"}, -{"date": "2015-10-15T22:10:00", "amount": -241.112574438284, "unit": "mg/dL"}, -{"date": "2015-10-15T22:15:00", "amount": -253.7479400469, "unit": "mg/dL"}, -{"date": "2015-10-15T22:20:00", "amount": -266.494351926145, "unit": "mg/dL"}, -{"date": "2015-10-15T22:25:00", "amount": -279.323001345175, "unit": "mg/dL"}, -{"date": "2015-10-15T22:30:00", "amount": -293.2161250905183, "unit": "mg/dL"}, -{"date": "2015-10-15T22:35:00", "amount": -306.10434323611, "unit": "mg/dL"}, -{"date": "2015-10-15T22:40:00", "amount": -319.0224174958953, "unit": "mg/dL"}, -{"date": "2015-10-15T22:45:00", "amount": -331.92442295925844, "unit": "mg/dL"}, -{"date": "2015-10-15T22:50:00", "amount": -344.7614413986003, "unit": "mg/dL"}, -{"date": "2015-10-15T22:55:00", "amount": -357.4985644921268, "unit": "mg/dL"}, -{"date": "2015-10-15T23:00:00", "amount": -370.0997621103307, "unit": "mg/dL"}, -{"date": "2015-10-15T23:05:00", "amount": -382.5116285629616, "unit": "mg/dL"}, -{"date": "2015-10-15T23:10:00", "amount": -394.7084163066953, "unit": "mg/dL"}, -{"date": "2015-10-15T23:15:00", "amount": -406.66202868680824, "unit": "mg/dL"}, -{"date": "2015-10-15T23:20:00", "amount": -418.380026718382, "unit": "mg/dL"}, -{"date": "2015-10-15T23:25:00", "amount": -429.8474254518422, "unit": "mg/dL"}, -{"date": "2015-10-15T23:30:00", "amount": -441.04071612573085, "unit": "mg/dL"}, -{"date": "2015-10-15T23:35:00", "amount": -451.9832999579977, "unit": "mg/dL"}, -{"date": "2015-10-15T23:40:00", "amount": -462.46842592415237, "unit": "mg/dL"}, -{"date": "2015-10-15T23:45:00", "amount": -470.9378219290769, "unit": "mg/dL"}, -{"date": "2015-10-15T23:50:00", "amount": -479.11572935989676, "unit": "mg/dL"}, -{"date": "2015-10-15T23:55:00", "amount": -486.99657300588615, "unit": "mg/dL"}, -{"date": "2015-10-16T00:00:00", "amount": -494.5908193412654, "unit": "mg/dL"}, -{"date": "2015-10-16T00:05:00", "amount": -501.8628086209436, "unit": "mg/dL"}, -{"date": "2015-10-16T00:10:00", "amount": -508.88507182844774, "unit": "mg/dL"}, -{"date": "2015-10-16T00:15:00", "amount": -515.6007765994074, "unit": "mg/dL"}, -{"date": "2015-10-16T00:20:00", "amount": -521.7524801441155, "unit": "mg/dL"}, -{"date": "2015-10-16T00:25:00", "amount": -526.678274488565, "unit": "mg/dL"}, -{"date": "2015-10-16T00:30:00", "amount": -531.4447495748509, "unit": "mg/dL"}, -{"date": "2015-10-16T00:35:00", "amount": -536.0644055267877, "unit": "mg/dL"}, -{"date": "2015-10-16T00:40:00", "amount": -540.5295961381503, "unit": "mg/dL"}, -{"date": "2015-10-16T00:45:00", "amount": -544.8222739849136, "unit": "mg/dL"}, -{"date": "2015-10-16T00:50:00", "amount": -548.9890101619071, "unit": "mg/dL"}, -{"date": "2015-10-16T00:55:00", "amount": -552.9823593323354, "unit": "mg/dL"}, -{"date": "2015-10-16T01:00:00", "amount": -556.8260617933233, "unit": "mg/dL"}, -{"date": "2015-10-16T01:05:00", "amount": -560.5209949579603, "unit": "mg/dL"}, -{"date": "2015-10-16T01:10:00", "amount": -564.0644737271039, "unit": "mg/dL"}, -{"date": "2015-10-16T01:15:00", "amount": -567.4470540344793, "unit": "mg/dL"}, -{"date": "2015-10-16T01:20:00", "amount": -570.6264032893645, "unit": "mg/dL"}, -{"date": "2015-10-16T01:25:00", "amount": -573.5980315609713, "unit": "mg/dL"}, -{"date": "2015-10-16T01:30:00", "amount": -576.3722239003739, "unit": "mg/dL"}, -{"date": "2015-10-16T01:35:00", "amount": -578.9877073683267, "unit": "mg/dL"}, -{"date": "2015-10-16T01:40:00", "amount": -581.4501136238224, "unit": "mg/dL"}, -{"date": "2015-10-16T01:45:00", "amount": -583.7660851884525, "unit": "mg/dL"}, -{"date": "2015-10-16T01:50:00", "amount": -585.6148458007469, "unit": "mg/dL"}, -{"date": "2015-10-16T01:55:00", "amount": -586.2453549649722, "unit": "mg/dL"}, -{"date": "2015-10-16T02:00:00", "amount": -586.8400843798366, "unit": "mg/dL"}, -{"date": "2015-10-16T02:05:00", "amount": -587.3999796067811, "unit": "mg/dL"}, -{"date": "2015-10-16T02:10:00", "amount": -587.9299744107797, "unit": "mg/dL"}, -{"date": "2015-10-16T02:15:00", "amount": -588.4355419490084, "unit": "mg/dL"}, -{"date": "2015-10-16T02:20:00", "amount": -588.8431930574274, "unit": "mg/dL"}, -{"date": "2015-10-16T02:25:00", "amount": -589.1668633185876, "unit": "mg/dL"}, -{"date": "2015-10-16T02:30:00", "amount": -589.395649400709, "unit": "mg/dL"}, -{"date": "2015-10-16T02:35:00", "amount": -589.5435294582638, "unit": "mg/dL"}, -{"date": "2015-10-16T02:40:00", "amount": -589.6111111111112, "unit": "mg/dL"}] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_120min_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_120min_output.json deleted file mode 100644 index e926180bf..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_120min_output.json +++ /dev/null @@ -1,114 +0,0 @@ -[ - { - "date" : "2015-07-13T12:00:00", - "value" : 0 - }, - { - "date" : "2015-07-13T12:05:00", - "value" : 1.5 - }, - { - "date" : "2015-07-13T12:10:00", - "value" : 1.5 - }, - { - "date" : "2015-07-13T12:15:00", - "value" : 1.500947838937214 - }, - { - "date" : "2015-07-13T12:20:00", - "value" : 1.484963834098891 - }, - { - "date" : "2015-07-13T12:25:00", - "value" : 1.446460021180044 - }, - { - "date" : "2015-07-13T12:30:00", - "value" : 1.389856198466611 - }, - { - "date" : "2015-07-13T12:35:00", - "value" : 1.31920732252578 - }, - { - "date" : "2015-07-13T12:40:00", - "value" : 1.238203508205988 - }, - { - "date" : "2015-07-13T12:45:00", - "value" : 1.150170028636922 - }, - { - "date" : "2015-07-13T12:50:00", - "value" : 1.058067315229521 - }, - { - "date" : "2015-07-13T12:55:00", - "value" : 0.964490957675971 - }, - { - "date" : "2015-07-13T13:00:00", - "value" : 0.8716717039497102 - }, - { - "date" : "2015-07-13T13:05:00", - "value" : 0.7814754603054258 - }, - { - "date" : "2015-07-13T13:10:00", - "value" : 0.6954032912790558 - }, - { - "date" : "2015-07-13T13:15:00", - "value" : 0.6145914196877871 - }, - { - "date" : "2015-07-13T13:20:00", - "value" : 0.5398112266300577 - }, - { - "date" : "2015-07-13T13:25:00", - "value" : 0.4714692514855546 - }, - { - "date" : "2015-07-13T13:30:00", - "value" : 0.4096071919152159 - }, - { - "date" : "2015-07-13T13:35:00", - "value" : 0.3539019038612285 - }, - { - "date" : "2015-07-13T13:40:00", - "value" : 0.3036654015470306 - }, - { - "date" : "2015-07-13T13:45:00", - "value" : 0.2578448574773081 - }, - { - "date" : "2015-07-13T13:50:00", - "value" : 0.2150226024380012 - }, - { - "date" : "2015-07-13T13:55:00", - "value" : 0.1734161254962953 - }, - { - "date" : "2015-07-13T14:00:00", - "value" : 0.130878074000628 - }, - { - "date" : "2015-07-13T14:05:00", - "value" : 0.08489625358068836 - }, - { - "date" : "2015-07-13T14:10:00", - "value" : 0.03259362814740968 - }, - { - "date" : "2015-07-13T14:15:00", - "value" : 0 - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_180min_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_180min_output.json deleted file mode 100644 index d272dbf2c..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_180min_output.json +++ /dev/null @@ -1,162 +0,0 @@ -[ - { - "date" : "2015-07-13T12:00:00", - "value" : 0 - }, - { - "date" : "2015-07-13T12:05:00", - "value" : 1.5 - }, - { - "date" : "2015-07-13T12:10:00", - "value" : 1.5 - }, - { - "date" : "2015-07-13T12:15:00", - "value" : 1.501102261857068 - }, - { - "date" : "2015-07-13T12:20:00", - "value" : 1.495934680094406 - }, - { - "date" : "2015-07-13T12:25:00", - "value" : 1.479739352013368 - }, - { - "date" : "2015-07-13T12:30:00", - "value" : 1.453897074188956 - }, - { - "date" : "2015-07-13T12:35:00", - "value" : 1.419716575696168 - }, - { - "date" : "2015-07-13T12:40:00", - "value" : 1.378434518110006 - }, - { - "date" : "2015-07-13T12:45:00", - "value" : 1.331215495505468 - }, - { - "date" : "2015-07-13T12:50:00", - "value" : 1.279152034457555 - }, - { - "date" : "2015-07-13T12:55:00", - "value" : 1.223264594041267 - }, - { - "date" : "2015-07-13T13:00:00", - "value" : 1.164501565831605 - }, - { - "date" : "2015-07-13T13:05:00", - "value" : 1.103739273903567 - }, - { - "date" : "2015-07-13T13:10:00", - "value" : 1.041781974832154 - }, - { - "date" : "2015-07-13T13:15:00", - "value" : 0.9793618576923671 - }, - { - "date" : "2015-07-13T13:20:00", - "value" : 0.917139044059204 - }, - { - "date" : "2015-07-13T13:25:00", - "value" : 0.8557015880076666 - }, - { - "date" : "2015-07-13T13:30:00", - "value" : 0.795565476112754 - }, - { - "date" : "2015-07-13T13:35:00", - "value" : 0.7371746274494664 - }, - { - "date" : "2015-07-13T13:40:00", - "value" : 0.680900893592804 - }, - { - "date" : "2015-07-13T13:45:00", - "value" : 0.627044058617766 - }, - { - "date" : "2015-07-13T13:50:00", - "value" : 0.5758318390993532 - }, - { - "date" : "2015-07-13T13:55:00", - "value" : 0.5274198841125657 - }, - { - "date" : "2015-07-13T14:00:00", - "value" : 0.4818917752324039 - }, - { - "date" : "2015-07-13T14:05:00", - "value" : 0.4392590265338656 - }, - { - "date" : "2015-07-13T14:10:00", - "value" : 0.3994610845919526 - }, - { - "date" : "2015-07-13T14:15:00", - "value" : 0.362365328481666 - }, - { - "date" : "2015-07-13T14:20:00", - "value" : 0.327767069778003 - }, - { - "date" : "2015-07-13T14:25:00", - "value" : 0.2953895525559652 - }, - { - "date" : "2015-07-13T14:30:00", - "value" : 0.2648839533905529 - }, - { - "date" : "2015-07-13T14:35:00", - "value" : 0.2358293813567644 - }, - { - "date" : "2015-07-13T14:40:00", - "value" : 0.2077328780296031 - }, - { - "date" : "2015-07-13T14:45:00", - "value" : 0.180029417484065 - }, - { - "date" : "2015-07-13T14:50:00", - "value" : 0.1520819062951513 - }, - { - "date" : "2015-07-13T14:55:00", - "value" : 0.1231811835378662 - }, - { - "date" : "2015-07-13T15:00:00", - "value" : 0.0925460207872027 - }, - { - "date" : "2015-07-13T15:05:00", - "value" : 0.05932312211816376 - }, - { - "date" : "2015-07-13T15:10:00", - "value" : 0.02258712410575253 - }, - { - "date" : "2015-07-13T15:15:00", - "value" : 0 - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_240min_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_240min_output.json deleted file mode 100644 index d48c66baa..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_240min_output.json +++ /dev/null @@ -1,210 +0,0 @@ -[ - { - "date" : "2015-07-13T12:00:00", - "value" : 0 - }, - { - "date" : "2015-07-13T12:05:00", - "value" : 1.5 - }, - { - "date" : "2015-07-13T12:10:00", - "value" : 1.5 - }, - { - "date" : "2015-07-13T12:15:00", - "value" : 1.495537401691061 - }, - { - "date" : "2015-07-13T12:20:00", - "value" : 1.48483297535133 - }, - { - "date" : "2015-07-13T12:25:00", - "value" : 1.470407604834223 - }, - { - "date" : "2015-07-13T12:30:00", - "value" : 1.452531193914742 - }, - { - "date" : "2015-07-13T12:35:00", - "value" : 1.431466198867885 - }, - { - "date" : "2015-07-13T12:40:00", - "value" : 1.407467628468654 - }, - { - "date" : "2015-07-13T12:45:00", - "value" : 1.380783043992047 - }, - { - "date" : "2015-07-13T12:50:00", - "value" : 1.351652559213066 - }, - { - "date" : "2015-07-13T12:55:00", - "value" : 1.320308840406709 - }, - { - "date" : "2015-07-13T13:00:00", - "value" : 1.286977106347978 - }, - { - "date" : "2015-07-13T13:05:00", - "value" : 1.251875128311871 - }, - { - "date" : "2015-07-13T13:10:00", - "value" : 1.21521323007339 - }, - { - "date" : "2015-07-13T13:15:00", - "value" : 1.177194287907533 - }, - { - "date" : "2015-07-13T13:20:00", - "value" : 1.138013730589301 - }, - { - "date" : "2015-07-13T13:25:00", - "value" : 1.097859539393695 - }, - { - "date" : "2015-07-13T13:30:00", - "value" : 1.056912248095713 - }, - { - "date" : "2015-07-13T13:35:00", - "value" : 1.015344942970357 - }, - { - "date" : "2015-07-13T13:40:00", - "value" : 0.9733232627926256 - }, - { - "date" : "2015-07-13T13:45:00", - "value" : 0.9310053988375189 - }, - { - "date" : "2015-07-13T13:50:00", - "value" : 0.8885420948800374 - }, - { - "date" : "2015-07-13T13:55:00", - "value" : 0.8460766471951808 - }, - { - "date" : "2015-07-13T14:00:00", - "value" : 0.8037449045579494 - }, - { - "date" : "2015-07-13T14:05:00", - "value" : 0.7616752682433428 - }, - { - "date" : "2015-07-13T14:10:00", - "value" : 0.7199886920263612 - }, - { - "date" : "2015-07-13T14:15:00", - "value" : 0.6787986821820048 - }, - { - "date" : "2015-07-13T14:20:00", - "value" : 0.6382112974852733 - }, - { - "date" : "2015-07-13T14:25:00", - "value" : 0.5983251492111668 - }, - { - "date" : "2015-07-13T14:30:00", - "value" : 0.5592314011346853 - }, - { - "date" : "2015-07-13T14:35:00", - "value" : 0.5210137695308286 - }, - { - "date" : "2015-07-13T14:40:00", - "value" : 0.483748523174597 - }, - { - "date" : "2015-07-13T14:45:00", - "value" : 0.4475044833409908 - }, - { - "date" : "2015-07-13T14:50:00", - "value" : 0.412343023805009 - }, - { - "date" : "2015-07-13T14:55:00", - "value" : 0.378318070841653 - }, - { - "date" : "2015-07-13T15:00:00", - "value" : 0.3454761032259215 - }, - { - "date" : "2015-07-13T15:05:00", - "value" : 0.3138561522328148 - }, - { - "date" : "2015-07-13T15:10:00", - "value" : 0.2834898016373331 - }, - { - "date" : "2015-07-13T15:15:00", - "value" : 0.2544011877144767 - }, - { - "date" : "2015-07-13T15:20:00", - "value" : 0.2266069992392455 - }, - { - "date" : "2015-07-13T15:25:00", - "value" : 0.2001164774866391 - }, - { - "date" : "2015-07-13T15:30:00", - "value" : 0.174931416231657 - }, - { - "date" : "2015-07-13T15:35:00", - "value" : 0.1510461617493006 - }, - { - "date" : "2015-07-13T15:40:00", - "value" : 0.128447612814569 - }, - { - "date" : "2015-07-13T15:45:00", - "value" : 0.1071152207024623 - }, - { - "date" : "2015-07-13T15:50:00", - "value" : 0.08702098918798074 - }, - { - "date" : "2015-07-13T15:55:00", - "value" : 0.06812947454612395 - }, - { - "date" : "2015-07-13T16:00:00", - "value" : 0.05039778555189273 - }, - { - "date" : "2015-07-13T16:05:00", - "value" : 0.0337755834802867 - }, - { - "date" : "2015-07-13T16:10:00", - "value" : 0.01820508210630561 - }, - { - "date" : "2015-07-13T16:15:00", - "value" : 0 - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_300min_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_300min_output.json deleted file mode 100644 index d199f357c..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_300min_output.json +++ /dev/null @@ -1,258 +0,0 @@ -[ - { - "date" : "2015-07-13T12:00:00", - "value" : 0 - }, - { - "date" : "2015-07-13T12:05:00", - "value" : 1.5 - }, - { - "date" : "2015-07-13T12:10:00", - "value" : 1.5 - }, - { - "date" : "2015-07-13T12:15:00", - "value" : 1.49063698881988 - }, - { - "date" : "2015-07-13T12:20:00", - "value" : 1.490073169155184 - }, - { - "date" : "2015-07-13T12:25:00", - "value" : 1.485724469683612 - }, - { - "date" : "2015-07-13T12:30:00", - "value" : 1.477838770280166 - }, - { - "date" : "2015-07-13T12:35:00", - "value" : 1.466657313319844 - }, - { - "date" : "2015-07-13T12:40:00", - "value" : 1.452414703677648 - }, - { - "date" : "2015-07-13T12:45:00", - "value" : 1.435338908728576 - }, - { - "date" : "2015-07-13T12:50:00", - "value" : 1.41565125834763 - }, - { - "date" : "2015-07-13T12:55:00", - "value" : 1.393566444909808 - }, - { - "date" : "2015-07-13T13:00:00", - "value" : 1.369292523290112 - }, - { - "date" : "2015-07-13T13:05:00", - "value" : 1.34303091086354 - }, - { - "date" : "2015-07-13T13:10:00", - "value" : 1.314976387505094 - }, - { - "date" : "2015-07-13T13:15:00", - "value" : 1.285317095589772 - }, - { - "date" : "2015-07-13T13:20:00", - "value" : 1.254234539992575 - }, - { - "date" : "2015-07-13T13:25:00", - "value" : 1.221903588088504 - }, - { - "date" : "2015-07-13T13:30:00", - "value" : 1.188492469752558 - }, - { - "date" : "2015-07-13T13:35:00", - "value" : 1.154162777359736 - }, - { - "date" : "2015-07-13T13:40:00", - "value" : 1.11906946578504 - }, - { - "date" : "2015-07-13T13:45:00", - "value" : 1.083360852403468 - }, - { - "date" : "2015-07-13T13:50:00", - "value" : 1.047178617090021 - }, - { - "date" : "2015-07-13T13:55:00", - "value" : 1.0106578022197 - }, - { - "date" : "2015-07-13T14:00:00", - "value" : 0.9739268126675034 - }, - { - "date" : "2015-07-13T14:05:00", - "value" : 0.9371074158084317 - }, - { - "date" : "2015-07-13T14:10:00", - "value" : 0.9003147415174855 - }, - { - "date" : "2015-07-13T14:15:00", - "value" : 0.8636572821696638 - }, - { - "date" : "2015-07-13T14:20:00", - "value" : 0.8272368926399674 - }, - { - "date" : "2015-07-13T14:25:00", - "value" : 0.7911487903033959 - }, - { - "date" : "2015-07-13T14:30:00", - "value" : 0.7554815550349494 - }, - { - "date" : "2015-07-13T14:35:00", - "value" : 0.7203171292096276 - }, - { - "date" : "2015-07-13T14:40:00", - "value" : 0.6857308177024313 - }, - { - "date" : "2015-07-13T14:45:00", - "value" : 0.6517912878883598 - }, - { - "date" : "2015-07-13T14:50:00", - "value" : 0.6185605696424131 - }, - { - "date" : "2015-07-13T14:55:00", - "value" : 0.5860940553395918 - }, - { - "date" : "2015-07-13T15:00:00", - "value" : 0.5544404998548951 - }, - { - "date" : "2015-07-13T15:05:00", - "value" : 0.5236420205633237 - }, - { - "date" : "2015-07-13T15:10:00", - "value" : 0.4937340973398772 - }, - { - "date" : "2015-07-13T15:15:00", - "value" : 0.4647455725595555 - }, - { - "date" : "2015-07-13T15:20:00", - "value" : 0.4366986510973594 - }, - { - "date" : "2015-07-13T15:25:00", - "value" : 0.4096089003282874 - }, - { - "date" : "2015-07-13T15:30:00", - "value" : 0.3834852501273406 - }, - { - "date" : "2015-07-13T15:35:00", - "value" : 0.3583299928695195 - }, - { - "date" : "2015-07-13T15:40:00", - "value" : 0.3341387834298227 - }, - { - "date" : "2015-07-13T15:45:00", - "value" : 0.3109006391832512 - }, - { - "date" : "2015-07-13T15:50:00", - "value" : 0.2885979400048053 - }, - { - "date" : "2015-07-13T15:55:00", - "value" : 0.2672064282694833 - }, - { - "date" : "2015-07-13T16:00:00", - "value" : 0.2466952088522872 - }, - { - "date" : "2015-07-13T16:05:00", - "value" : 0.2270267491282156 - }, - { - "date" : "2015-07-13T16:10:00", - "value" : 0.208156878972269 - }, - { - "date" : "2015-07-13T16:15:00", - "value" : 0.1900347907594464 - }, - { - "date" : "2015-07-13T16:20:00", - "value" : 0.1726030393647512 - }, - { - "date" : "2015-07-13T16:25:00", - "value" : 0.1557975421631793 - }, - { - "date" : "2015-07-13T16:30:00", - "value" : 0.1395475790297329 - }, - { - "date" : "2015-07-13T16:35:00", - "value" : 0.1237757923394113 - }, - { - "date" : "2015-07-13T16:40:00", - "value" : 0.1083981869672155 - }, - { - "date" : "2015-07-13T16:45:00", - "value" : 0.09332413028814285 - }, - { - "date" : "2015-07-13T16:50:00", - "value" : 0.07845635217719643 - }, - { - "date" : "2015-07-13T16:55:00", - "value" : 0.0636909450093765 - }, - { - "date" : "2015-07-13T17:00:00", - "value" : 0.04891736365967769 - }, - { - "date" : "2015-07-13T17:05:00", - "value" : 0.03401842550310802 - }, - { - "date" : "2015-07-13T17:10:00", - "value" : 0.01887031041466186 - }, - { - "date" : "2015-07-13T17:15:00", - "value" : 0 - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_312min_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_312min_output.json deleted file mode 100644 index 58ecf10b2..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_312min_output.json +++ /dev/null @@ -1,266 +0,0 @@ -[ - { - "date" : "2015-07-13T12:00:00", - "value" : 0 - }, - { - "date" : "2015-07-13T12:05:00", - "value" : 1.5 - }, - { - "date" : "2015-07-13T12:10:00", - "value" : 1.5 - }, - { - "date" : "2015-07-13T12:15:00", - "value" : 1.490610406523825 - }, - { - "date" : "2015-07-13T12:20:00", - "value" : 1.490208938757759 - }, - { - "date" : "2015-07-13T12:25:00", - "value" : 1.486294975082037 - }, - { - "date" : "2015-07-13T12:30:00", - "value" : 1.479089328408437 - }, - { - "date" : "2015-07-13T12:35:00", - "value" : 1.468807137885917 - }, - { - "date" : "2015-07-13T12:40:00", - "value" : 1.455657868900616 - }, - { - "date" : "2015-07-13T12:45:00", - "value" : 1.439845313075858 - }, - { - "date" : "2015-07-13T12:50:00", - "value" : 1.421567588272146 - }, - { - "date" : "2015-07-13T12:55:00", - "value" : 1.401017138587167 - }, - { - "date" : "2015-07-13T13:00:00", - "value" : 1.37838073435579 - }, - { - "date" : "2015-07-13T13:05:00", - "value" : 1.353839472150066 - }, - { - "date" : "2015-07-13T13:10:00", - "value" : 1.327568774779226 - }, - { - "date" : "2015-07-13T13:15:00", - "value" : 1.299738391289685 - }, - { - "date" : "2015-07-13T13:20:00", - "value" : 1.270512396965041 - }, - { - "date" : "2015-07-13T13:25:00", - "value" : 1.240049193326071 - }, - { - "date" : "2015-07-13T13:30:00", - "value" : 1.208501508130738 - }, - { - "date" : "2015-07-13T13:35:00", - "value" : 1.176016395374182 - }, - { - "date" : "2015-07-13T13:40:00", - "value" : 1.14273523528873 - }, - { - "date" : "2015-07-13T13:45:00", - "value" : 1.108793734343888 - }, - { - "date" : "2015-07-13T13:50:00", - "value" : 1.074321925246345 - }, - { - "date" : "2015-07-13T13:55:00", - "value" : 1.039444166939972 - }, - { - "date" : "2015-07-13T14:00:00", - "value" : 1.004279144605822 - }, - { - "date" : "2015-07-13T14:05:00", - "value" : 0.9689398696621303 - }, - { - "date" : "2015-07-13T14:10:00", - "value" : 0.9335336797643136 - }, - { - "date" : "2015-07-13T14:15:00", - "value" : 0.8981622388049708 - }, - { - "date" : "2015-07-13T14:20:00", - "value" : 0.8629215369138838 - }, - { - "date" : "2015-07-13T14:25:00", - "value" : 0.8279018904580151 - }, - { - "date" : "2015-07-13T14:30:00", - "value" : 0.7931879420415106 - }, - { - "date" : "2015-07-13T14:35:00", - "value" : 0.7588586605056968 - }, - { - "date" : "2015-07-13T14:40:00", - "value" : 0.7249873409290836 - }, - { - "date" : "2015-07-13T14:45:00", - "value" : 0.6916416046273619 - }, - { - "date" : "2015-07-13T14:50:00", - "value" : 0.658883399153406 - }, - { - "date" : "2015-07-13T14:55:00", - "value" : 0.6267689982972702 - }, - { - "date" : "2015-07-13T15:00:00", - "value" : 0.5953490020861928 - }, - { - "date" : "2015-07-13T15:05:00", - "value" : 0.5646683367845928 - }, - { - "date" : "2015-07-13T15:10:00", - "value" : 0.534766254894073 - }, - { - "date" : "2015-07-13T15:15:00", - "value" : 0.5056763351534146 - }, - { - "date" : "2015-07-13T15:20:00", - "value" : 0.4774264825385851 - }, - { - "date" : "2015-07-13T15:25:00", - "value" : 0.4500389282627319 - }, - { - "date" : "2015-07-13T15:30:00", - "value" : 0.4235302297761846 - }, - { - "date" : "2015-07-13T15:35:00", - "value" : 0.3979112707664551 - }, - { - "date" : "2015-07-13T15:40:00", - "value" : 0.3731872611582366 - }, - { - "date" : "2015-07-13T15:45:00", - "value" : 0.3493577371134051 - }, - { - "date" : "2015-07-13T15:50:00", - "value" : 0.3264165610310197 - }, - { - "date" : "2015-07-13T15:55:00", - "value" : 0.3043519215473182 - }, - { - "date" : "2015-07-13T16:00:00", - "value" : 0.2831463335357246 - }, - { - "date" : "2015-07-13T16:05:00", - "value" : 0.2627766381068415 - }, - { - "date" : "2015-07-13T16:10:00", - "value" : 0.2432140026084561 - }, - { - "date" : "2015-07-13T16:15:00", - "value" : 0.2244239206255346 - }, - { - "date" : "2015-07-13T16:20:00", - "value" : 0.2063662119802297 - }, - { - "date" : "2015-07-13T16:25:00", - "value" : 0.188995022731872 - }, - { - "date" : "2015-07-13T16:30:00", - "value" : 0.1722588251769752 - }, - { - "date" : "2015-07-13T16:35:00", - "value" : 0.1561004178492368 - }, - { - "date" : "2015-07-13T16:40:00", - "value" : 0.1404569255195355 - }, - { - "date" : "2015-07-13T16:45:00", - "value" : 0.1252597991959289 - }, - { - "date" : "2015-07-13T16:50:00", - "value" : 0.1104348161236617 - }, - { - "date" : "2015-07-13T16:55:00", - "value" : 0.09590207978515752 - }, - { - "date" : "2015-07-13T17:00:00", - "value" : 0.08157601990002478 - }, - { - "date" : "2015-07-13T17:05:00", - "value" : 0.0673653924250483 - }, - { - "date" : "2015-07-13T17:10:00", - "value" : 0.05317327955420448 - }, - { - "date" : "2015-07-13T17:15:00", - "value" : 0.03889708971863698 - }, - { - "date" : "2015-07-13T17:20:00", - "value" : 0.02442855758668588 - }, - { - "date" : "2015-07-13T17:25:00", - "value" : 0 - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_360min_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_360min_output.json deleted file mode 100644 index 6a48e549f..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_360min_output.json +++ /dev/null @@ -1,306 +0,0 @@ -[ - { - "date" : "2015-07-13T12:00:00", - "value" : 0 - }, - { - "date" : "2015-07-13T12:05:00", - "value" : 1.5 - }, - { - "date" : "2015-07-13T12:10:00", - "value" : 1.5 - }, - { - "date" : "2015-07-13T12:15:00", - "value" : 1.497429438589748 - }, - { - "date" : "2015-07-13T12:20:00", - "value" : 1.49928538163146 - }, - { - "date" : "2015-07-13T12:25:00", - "value" : 1.49830086686371 - }, - { - "date" : "2015-07-13T12:30:00", - "value" : 1.494628216668997 - }, - { - "date" : "2015-07-13T12:35:00", - "value" : 1.488416394179823 - }, - { - "date" : "2015-07-13T12:40:00", - "value" : 1.479811003278685 - }, - { - "date" : "2015-07-13T12:45:00", - "value" : 1.468954288598085 - }, - { - "date" : "2015-07-13T12:50:00", - "value" : 1.455985135520522 - }, - { - "date" : "2015-07-13T12:55:00", - "value" : 1.441039070178497 - }, - { - "date" : "2015-07-13T13:00:00", - "value" : 1.42424825945451 - }, - { - "date" : "2015-07-13T13:05:00", - "value" : 1.40574151098106 - }, - { - "date" : "2015-07-13T13:10:00", - "value" : 1.385644273140647 - }, - { - "date" : "2015-07-13T13:15:00", - "value" : 1.364078635065772 - }, - { - "date" : "2015-07-13T13:20:00", - "value" : 1.341163326638935 - }, - { - "date" : "2015-07-13T13:25:00", - "value" : 1.317013718492635 - }, - { - "date" : "2015-07-13T13:30:00", - "value" : 1.291741822009372 - }, - { - "date" : "2015-07-13T13:35:00", - "value" : 1.265456289321647 - }, - { - "date" : "2015-07-13T13:40:00", - "value" : 1.23826241331196 - }, - { - "date" : "2015-07-13T13:45:00", - "value" : 1.21026212761281 - }, - { - "date" : "2015-07-13T13:50:00", - "value" : 1.181554006606697 - }, - { - "date" : "2015-07-13T13:55:00", - "value" : 1.152233265426122 - }, - { - "date" : "2015-07-13T14:00:00", - "value" : 1.122391759953585 - }, - { - "date" : "2015-07-13T14:05:00", - "value" : 1.092117986821585 - }, - { - "date" : "2015-07-13T14:10:00", - "value" : 1.061497083412622 - }, - { - "date" : "2015-07-13T14:15:00", - "value" : 1.030610827859197 - }, - { - "date" : "2015-07-13T14:20:00", - "value" : 0.9995376390438095 - }, - { - "date" : "2015-07-13T14:25:00", - "value" : 0.9683525765989598 - }, - { - "date" : "2015-07-13T14:30:00", - "value" : 0.9371273409071474 - }, - { - "date" : "2015-07-13T14:35:00", - "value" : 0.9059302731008723 - }, - { - "date" : "2015-07-13T14:40:00", - "value" : 0.8748263550626347 - }, - { - "date" : "2015-07-13T14:45:00", - "value" : 0.8438772094249348 - }, - { - "date" : "2015-07-13T14:50:00", - "value" : 0.8131410995702719 - }, - { - "date" : "2015-07-13T14:55:00", - "value" : 0.7826729296311472 - }, - { - "date" : "2015-07-13T15:00:00", - "value" : 0.7525242444900597 - }, - { - "date" : "2015-07-13T15:05:00", - "value" : 0.7227432297795096 - }, - { - "date" : "2015-07-13T15:10:00", - "value" : 0.6933747118819975 - }, - { - "date" : "2015-07-13T15:15:00", - "value" : 0.6644601579300222 - }, - { - "date" : "2015-07-13T15:20:00", - "value" : 0.6360376758060848 - }, - { - "date" : "2015-07-13T15:25:00", - "value" : 0.6081420141426849 - }, - { - "date" : "2015-07-13T15:30:00", - "value" : 0.5808045623223219 - }, - { - "date" : "2015-07-13T15:35:00", - "value" : 0.5540533504774969 - }, - { - "date" : "2015-07-13T15:40:00", - "value" : 0.5279130494907096 - }, - { - "date" : "2015-07-13T15:45:00", - "value" : 0.5024049709944594 - }, - { - "date" : "2015-07-13T15:50:00", - "value" : 0.477547067371247 - }, - { - "date" : "2015-07-13T15:55:00", - "value" : 0.4533539317535719 - }, - { - "date" : "2015-07-13T16:00:00", - "value" : 0.4298367980239348 - }, - { - "date" : "2015-07-13T16:05:00", - "value" : 0.407003540814835 - }, - { - "date" : "2015-07-13T16:10:00", - "value" : 0.3848586755087723 - }, - { - "date" : "2015-07-13T16:15:00", - "value" : 0.3634033582382466 - }, - { - "date" : "2015-07-13T16:20:00", - "value" : 0.3426353858857603 - }, - { - "date" : "2015-07-13T16:25:00", - "value" : 0.3225491960838095 - }, - { - "date" : "2015-07-13T16:30:00", - "value" : 0.3031358672148975 - }, - { - "date" : "2015-07-13T16:35:00", - "value" : 0.2843831184115222 - }, - { - "date" : "2015-07-13T16:40:00", - "value" : 0.2662753095561847 - }, - { - "date" : "2015-07-13T16:45:00", - "value" : 0.2487934412813842 - }, - { - "date" : "2015-07-13T16:50:00", - "value" : 0.231915154969623 - }, - { - "date" : "2015-07-13T16:55:00", - "value" : 0.2156147327533977 - }, - { - "date" : "2015-07-13T17:00:00", - "value" : 0.1998630975152084 - }, - { - "date" : "2015-07-13T17:05:00", - "value" : 0.1846278128875592 - }, - { - "date" : "2015-07-13T17:10:00", - "value" : 0.1698730832529469 - }, - { - "date" : "2015-07-13T17:15:00", - "value" : 0.1555597537438714 - }, - { - "date" : "2015-07-13T17:20:00", - "value" : 0.1416453102428346 - }, - { - "date" : "2015-07-13T17:25:00", - "value" : 0.1280838793823358 - }, - { - "date" : "2015-07-13T17:30:00", - "value" : 0.1148262285448728 - }, - { - "date" : "2015-07-13T17:35:00", - "value" : 0.1018197658629483 - }, - { - "date" : "2015-07-13T17:40:00", - "value" : 0.08900854021906146 - }, - { - "date" : "2015-07-13T17:45:00", - "value" : 0.07633324124570978 - }, - { - "date" : "2015-07-13T17:50:00", - "value" : 0.06373119932539717 - }, - { - "date" : "2015-07-13T17:55:00", - "value" : 0.051136385590622 - }, - { - "date" : "2015-07-13T18:00:00", - "value" : 0.03847941192388332 - }, - { - "date" : "2015-07-13T18:05:00", - "value" : 0.02568753095768483 - }, - { - "date" : "2015-07-13T18:10:00", - "value" : 0.01268463607452125 - }, - { - "date" : "2015-07-13T18:15:00", - "value" : 0 - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_420min_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_420min_output.json deleted file mode 100644 index c56c5de92..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_420min_output.json +++ /dev/null @@ -1,354 +0,0 @@ -[ - { - "date" : "2015-07-13T12:00:00", - "value" : 0 - }, - { - "date" : "2015-07-13T12:05:00", - "value" : 1.5 - }, - { - "date" : "2015-07-13T12:10:00", - "value" : 1.5 - }, - { - "date" : "2015-07-13T12:15:00", - "value" : 1.497195878090686 - }, - { - "date" : "2015-07-13T12:20:00", - "value" : 1.499135444738147 - }, - { - "date" : "2015-07-13T12:25:00", - "value" : 1.498964276007823 - }, - { - "date" : "2015-07-13T12:30:00", - "value" : 1.49677889239439 - }, - { - "date" : "2015-07-13T12:35:00", - "value" : 1.492674001153042 - }, - { - "date" : "2015-07-13T12:40:00", - "value" : 1.48674249629949 - }, - { - "date" : "2015-07-13T12:45:00", - "value" : 1.479075458609959 - }, - { - "date" : "2015-07-13T12:50:00", - "value" : 1.469762155621194 - }, - { - "date" : "2015-07-13T12:55:00", - "value" : 1.458890041630452 - }, - { - "date" : "2015-07-13T13:00:00", - "value" : 1.446544757695512 - }, - { - "date" : "2015-07-13T13:05:00", - "value" : 1.432810131634664 - }, - { - "date" : "2015-07-13T13:10:00", - "value" : 1.417768178026717 - }, - { - "date" : "2015-07-13T13:15:00", - "value" : 1.401499098210997 - }, - { - "date" : "2015-07-13T13:20:00", - "value" : 1.384081280287346 - }, - { - "date" : "2015-07-13T13:25:00", - "value" : 1.365591299116122 - }, - { - "date" : "2015-07-13T13:30:00", - "value" : 1.346103916318199 - }, - { - "date" : "2015-07-13T13:35:00", - "value" : 1.325692080274968 - }, - { - "date" : "2015-07-13T13:40:00", - "value" : 1.304426926128337 - }, - { - "date" : "2015-07-13T13:45:00", - "value" : 1.282377775780731 - }, - { - "date" : "2015-07-13T13:50:00", - "value" : 1.259612137895089 - }, - { - "date" : "2015-07-13T13:55:00", - "value" : 1.236195707894868 - }, - { - "date" : "2015-07-13T14:00:00", - "value" : 1.212192367964042 - }, - { - "date" : "2015-07-13T14:05:00", - "value" : 1.1876641870471 - }, - { - "date" : "2015-07-13T14:10:00", - "value" : 1.162671420849049 - }, - { - "date" : "2015-07-13T14:15:00", - "value" : 1.137272511835411 - }, - { - "date" : "2015-07-13T14:20:00", - "value" : 1.111524089232227 - }, - { - "date" : "2015-07-13T14:25:00", - "value" : 1.08548096902605 - }, - { - "date" : "2015-07-13T14:30:00", - "value" : 1.059196153963953 - }, - { - "date" : "2015-07-13T14:35:00", - "value" : 1.032720833553525 - }, - { - "date" : "2015-07-13T14:40:00", - "value" : 1.006104384062871 - }, - { - "date" : "2015-07-13T14:45:00", - "value" : 0.9793943685206116 - }, - { - "date" : "2015-07-13T14:50:00", - "value" : 0.9526365367158854 - }, - { - "date" : "2015-07-13T14:55:00", - "value" : 0.9258748251983466 - }, - { - "date" : "2015-07-13T15:00:00", - "value" : 0.899151357278166 - }, - { - "date" : "2015-07-13T15:05:00", - "value" : 0.8725064430260299 - }, - { - "date" : "2015-07-13T15:10:00", - "value" : 0.8459785792731431 - }, - { - "date" : "2015-07-13T15:15:00", - "value" : 0.8196044496112256 - }, - { - "date" : "2015-07-13T15:20:00", - "value" : 0.7934189243925133 - }, - { - "date" : "2015-07-13T15:25:00", - "value" : 0.7674550607297597 - }, - { - "date" : "2015-07-13T15:30:00", - "value" : 0.7417441024962342 - }, - { - "date" : "2015-07-13T15:35:00", - "value" : 0.7163154803257227 - }, - { - "date" : "2015-07-13T15:40:00", - "value" : 0.6911968116125273 - }, - { - "date" : "2015-07-13T15:45:00", - "value" : 0.6664139005114675 - }, - { - "date" : "2015-07-13T15:50:00", - "value" : 0.641990737937878 - }, - { - "date" : "2015-07-13T15:55:00", - "value" : 0.6179495015676104 - }, - { - "date" : "2015-07-13T16:00:00", - "value" : 0.5943105558370336 - }, - { - "date" : "2015-07-13T16:05:00", - "value" : 0.5710924519430318 - }, - { - "date" : "2015-07-13T16:10:00", - "value" : 0.5483119278430064 - }, - { - "date" : "2015-07-13T16:15:00", - "value" : 0.5259839082548736 - }, - { - "date" : "2015-07-13T16:20:00", - "value" : 0.5041215046570691 - }, - { - "date" : "2015-07-13T16:25:00", - "value" : 0.4827360152885428 - }, - { - "date" : "2015-07-13T16:30:00", - "value" : 0.4618369251487609 - }, - { - "date" : "2015-07-13T16:35:00", - "value" : 0.4414319059977084 - }, - { - "date" : "2015-07-13T16:40:00", - "value" : 0.4215268163558824 - }, - { - "date" : "2015-07-13T16:45:00", - "value" : 0.4021257015043017 - }, - { - "date" : "2015-07-13T16:50:00", - "value" : 0.3832307934844976 - }, - { - "date" : "2015-07-13T16:55:00", - "value" : 0.3648425110985195 - }, - { - "date" : "2015-07-13T17:00:00", - "value" : 0.3469594599089338 - }, - { - "date" : "2015-07-13T17:05:00", - "value" : 0.3295784322388223 - }, - { - "date" : "2015-07-13T17:10:00", - "value" : 0.3126944071717815 - }, - { - "date" : "2015-07-13T17:15:00", - "value" : 0.2963005505519296 - }, - { - "date" : "2015-07-13T17:20:00", - "value" : 0.2803882149838948 - }, - { - "date" : "2015-07-13T17:25:00", - "value" : 0.264946939832828 - }, - { - "date" : "2015-07-13T17:30:00", - "value" : 0.2499644512243914 - }, - { - "date" : "2015-07-13T17:35:00", - "value" : 0.2354266620447654 - }, - { - "date" : "2015-07-13T17:40:00", - "value" : 0.2213176719406496 - }, - { - "date" : "2015-07-13T17:45:00", - "value" : 0.2076197673192561 - }, - { - "date" : "2015-07-13T17:50:00", - "value" : 0.1943134213483148 - }, - { - "date" : "2015-07-13T17:55:00", - "value" : 0.1813772939560714 - }, - { - "date" : "2015-07-13T18:00:00", - "value" : 0.1687882318312915 - }, - { - "date" : "2015-07-13T18:05:00", - "value" : 0.1565212684232548 - }, - { - "date" : "2015-07-13T18:10:00", - "value" : 0.1445496239417524 - }, - { - "date" : "2015-07-13T18:15:00", - "value" : 0.1328447053571012 - }, - { - "date" : "2015-07-13T18:20:00", - "value" : 0.1213761064001301 - }, - { - "date" : "2015-07-13T18:25:00", - "value" : 0.1101116075621806 - }, - { - "date" : "2015-07-13T18:30:00", - "value" : 0.09901717609512045 - }, - { - "date" : "2015-07-13T18:35:00", - "value" : 0.08805696601132124 - }, - { - "date" : "2015-07-13T18:40:00", - "value" : 0.07719331808368057 - }, - { - "date" : "2015-07-13T18:45:00", - "value" : 0.06638675984561032 - }, - { - "date" : "2015-07-13T18:50:00", - "value" : 0.05559600559103445 - }, - { - "date" : "2015-07-13T18:55:00", - "value" : 0.04477795637440352 - }, - { - "date" : "2015-07-13T19:00:00", - "value" : 0.03388770001067304 - }, - { - "date" : "2015-07-13T19:05:00", - "value" : 0.0228785110753208 - }, - { - "date" : "2015-07-13T19:10:00", - "value" : 0.01170185090434001 - }, - { - "date" : "2015-07-13T19:15:00", - "value" : 0 - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_exponential_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_exponential_output.json deleted file mode 100644 index 3bdb76ad3..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_bolus_exponential_output.json +++ /dev/null @@ -1,382 +0,0 @@ -[ - { - "unit" : "U", - "date" : "2015-07-13T12:00:00", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2015-07-13T12:05:00", - "value" : 1.5 - }, - { - "unit" : "U", - "date" : "2015-07-13T12:10:00", - "value" : 1.5 - }, - { - "unit" : "U", - "date" : "2015-07-13T12:15:00", - "value" : 1.499160449046046 - }, - { - "unit" : "U", - "date" : "2015-07-13T12:20:00", - "value" : 1.492273339718537 - }, - { - "unit" : "U", - "date" : "2015-07-13T12:25:00", - "value" : 1.479153811176018 - }, - { - "unit" : "U", - "date" : "2015-07-13T12:30:00", - "value" : 1.460596157792121 - }, - { - "unit" : "U", - "date" : "2015-07-13T12:35:00", - "value" : 1.437324170463916 - }, - { - "unit" : "U", - "date" : "2015-07-13T12:40:00", - "value" : 1.409996486540917 - }, - { - "unit" : "U", - "date" : "2015-07-13T12:45:00", - "value" : 1.37921156892143 - }, - { - "unit" : "U", - "date" : "2015-07-13T12:50:00", - "value" : 1.345512338530745 - }, - { - "unit" : "U", - "date" : "2015-07-13T12:55:00", - "value" : 1.309390482880479 - }, - { - "unit" : "U", - "date" : "2015-07-13T13:00:00", - "value" : 1.271290461985078 - }, - { - "unit" : "U", - "date" : "2015-07-13T13:05:00", - "value" : 1.231613231574466 - }, - { - "unit" : "U", - "date" : "2015-07-13T13:10:00", - "value" : 1.190719702286193 - }, - { - "unit" : "U", - "date" : "2015-07-13T13:15:00", - "value" : 1.148933952341161 - }, - { - "unit" : "U", - "date" : "2015-07-13T13:20:00", - "value" : 1.106546210099772 - }, - { - "unit" : "U", - "date" : "2015-07-13T13:25:00", - "value" : 1.063815621855631 - }, - { - "unit" : "U", - "date" : "2015-07-13T13:30:00", - "value" : 1.02097281924799 - }, - { - "unit" : "U", - "date" : "2015-07-13T13:35:00", - "value" : 0.9782222997578941 - }, - { - "unit" : "U", - "date" : "2015-07-13T13:40:00", - "value" : 0.9357446328931253 - }, - { - "unit" : "U", - "date" : "2015-07-13T13:45:00", - "value" : 0.8936985038600359 - }, - { - "unit" : "U", - "date" : "2015-07-13T13:50:00", - "value" : 0.8522226057631148 - }, - { - "unit" : "U", - "date" : "2015-07-13T13:55:00", - "value" : 0.8114373906626636 - }, - { - "unit" : "U", - "date" : "2015-07-13T14:00:00", - "value" : 0.7714466891544411 - }, - { - "unit" : "U", - "date" : "2015-07-13T14:05:00", - "value" : 0.7323392075099404 - }, - { - "unit" : "U", - "date" : "2015-07-13T14:10:00", - "value" : 0.6941899108296028 - }, - { - "unit" : "U", - "date" : "2015-07-13T14:15:00", - "value" : 0.6570613001114222 - }, - { - "unit" : "U", - "date" : "2015-07-13T14:20:00", - "value" : 0.6210045906218151 - }, - { - "unit" : "U", - "date" : "2015-07-13T14:25:00", - "value" : 0.5860607984722972 - }, - { - "unit" : "U", - "date" : "2015-07-13T14:30:00", - "value" : 0.5522617418524287 - }, - { - "unit" : "U", - "date" : "2015-07-13T14:35:00", - "value" : 0.5196309629448566 - }, - { - "unit" : "U", - "date" : "2015-07-13T14:40:00", - "value" : 0.4881845761503622 - }, - { - "unit" : "U", - "date" : "2015-07-13T14:45:00", - "value" : 0.4579320478779753 - }, - { - "unit" : "U", - "date" : "2015-07-13T14:50:00", - "value" : 0.4288769128059384 - }, - { - "unit" : "U", - "date" : "2015-07-13T14:55:00", - "value" : 0.4010174311921458 - }, - { - "unit" : "U", - "date" : "2015-07-13T15:00:00", - "value" : 0.3743471915062866 - }, - { - "unit" : "U", - "date" : "2015-07-13T15:05:00", - "value" : 0.3488556623690194 - }, - { - "unit" : "U", - "date" : "2015-07-13T15:10:00", - "value" : 0.324528697514922 - }, - { - "unit" : "U", - "date" : "2015-07-13T15:15:00", - "value" : 0.3013489972445283 - }, - { - "unit" : "U", - "date" : "2015-07-13T15:20:00", - "value" : 0.2792965295954646 - }, - { - "unit" : "U", - "date" : "2015-07-13T15:25:00", - "value" : 0.2583489142425283 - }, - { - "unit" : "U", - "date" : "2015-07-13T15:30:00", - "value" : 0.2384817719305489 - }, - { - "unit" : "U", - "date" : "2015-07-13T15:35:00", - "value" : 0.2196690420512133 - }, - { - "unit" : "U", - "date" : "2015-07-13T15:40:00", - "value" : 0.2018832707948264 - }, - { - "unit" : "U", - "date" : "2015-07-13T15:45:00", - "value" : 0.1850958721395112 - }, - { - "unit" : "U", - "date" : "2015-07-13T15:50:00", - "value" : 0.169277363782843 - }, - { - "unit" : "U", - "date" : "2015-07-13T15:55:00", - "value" : 0.1543975799737031 - }, - { - "unit" : "U", - "date" : "2015-07-13T16:00:00", - "value" : 0.1404258630645872 - }, - { - "unit" : "U", - "date" : "2015-07-13T16:05:00", - "value" : 0.1273312354760828 - }, - { - "unit" : "U", - "date" : "2015-07-13T16:10:00", - "value" : 0.1150825536452085 - }, - { - "unit" : "U", - "date" : "2015-07-13T16:15:00", - "value" : 0.1036486454171986 - }, - { - "unit" : "U", - "date" : "2015-07-13T16:20:00", - "value" : 0.0929984322356967 - }, - { - "unit" : "U", - "date" : "2015-07-13T16:25:00", - "value" : 0.08310103738861502 - }, - { - "unit" : "U", - "date" : "2015-07-13T16:30:00", - "value" : 0.07392588147579587 - }, - { - "unit" : "U", - "date" : "2015-07-13T16:35:00", - "value" : 0.06544276617956363 - }, - { - "unit" : "U", - "date" : "2015-07-13T16:40:00", - "value" : 0.05762194733996256 - }, - { - "unit" : "U", - "date" : "2015-07-13T16:45:00", - "value" : 0.05043419826251677 - }, - { - "unit" : "U", - "date" : "2015-07-13T16:50:00", - "value" : 0.04385086411743044 - }, - { - "unit" : "U", - "date" : "2015-07-13T16:55:00", - "value" : 0.03784390822490596 - }, - { - "unit" : "U", - "date" : "2015-07-13T17:00:00", - "value" : 0.03238595096141428 - }, - { - "unit" : "U", - "date" : "2015-07-13T17:05:00", - "value" : 0.02745030196602199 - }, - { - "unit" : "U", - "date" : "2015-07-13T17:10:00", - "value" : 0.02301098627398618 - }, - { - "unit" : "U", - "date" : "2015-07-13T17:15:00", - "value" : 0.01904276495652973 - }, - { - "unit" : "U", - "date" : "2015-07-13T17:20:00", - "value" : 0.01552115080078043 - }, - { - "unit" : "U", - "date" : "2015-07-13T17:25:00", - "value" : 0.01242241952204715 - }, - { - "unit" : "U", - "date" : "2015-07-13T17:30:00", - "value" : 0.009723616961757331 - }, - { - "unit" : "U", - "date" : "2015-07-13T17:35:00", - "value" : 0.007402562688253456 - }, - { - "unit" : "U", - "date" : "2015-07-13T17:40:00", - "value" : 0.005437850384089726 - }, - { - "unit" : "U", - "date" : "2015-07-13T17:45:00", - "value" : 0.003808845372300529 - }, - { - "unit" : "U", - "date" : "2015-07-13T17:50:00", - "value" : 0.002495679605187984 - }, - { - "unit" : "U", - "date" : "2015-07-13T17:55:00", - "value" : 0.001479244412315284 - }, - { - "unit" : "U", - "date" : "2015-07-13T18:00:00", - "value" : 0.0007411812795057315 - }, - { - "unit" : "U", - "date" : "2015-07-13T18:05:00", - "value" : 0.0002638709075447054 - }, - { - "unit" : "U", - "date" : "2015-07-13T18:10:00", - "value" : 3.042077790255115e-05 - }, - { - "unit" : "U", - "date" : "2015-07-13T18:15:00", - "value" : 0 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_doses_exponential_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_doses_exponential_output.json deleted file mode 100644 index a4dcf8cfe..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_doses_exponential_output.json +++ /dev/null @@ -1,643 +0,0 @@ - [ - { - "unit" : "U", - "date" : "2015-10-15T18:05:00", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2015-10-15T18:10:00", - "value" : -0.0185623382045902 - }, - { - "unit" : "U", - "date" : "2015-10-15T18:15:00", - "value" : -0.21316778246801987 - }, - { - "unit" : "U", - "date" : "2015-10-15T18:20:00", - "value" : -0.27970759441100979 - }, - { - "unit" : "U", - "date" : "2015-10-15T18:25:00", - "value" : -0.34632167451995299 - }, - { - "unit" : "U", - "date" : "2015-10-15T18:30:00", - "value" : -0.41268674309345654 - }, - { - "unit" : "U", - "date" : "2015-10-15T18:35:00", - "value" : -0.41499211967545518 - }, - { - "unit" : "U", - "date" : "2015-10-15T18:40:00", - "value" : -0.41506377582462262 - }, - { - "unit" : "U", - "date" : "2015-10-15T18:45:00", - "value" : -0.4131659654676178 - }, - { - "unit" : "U", - "date" : "2015-10-15T18:50:00", - "value" : -0.40954008512944956 - }, - { - "unit" : "U", - "date" : "2015-10-15T18:55:00", - "value" : -0.40440638539822188 - }, - { - "unit" : "U", - "date" : "2015-10-15T19:00:00", - "value" : -0.39796556472933875 - }, - { - "unit" : "U", - "date" : "2015-10-15T19:05:00", - "value" : -0.58773036095248288 - }, - { - "unit" : "U", - "date" : "2015-10-15T19:10:00", - "value" : -0.63288770080511247 - }, - { - "unit" : "U", - "date" : "2015-10-15T19:15:00", - "value" : -0.62494364966705629 - }, - { - "unit" : "U", - "date" : "2015-10-15T19:20:00", - "value" : -0.66446397306998384 - }, - { - "unit" : "U", - "date" : "2015-10-15T19:25:00", - "value" : 0.0032388152635020127 - }, - { - "unit" : "U", - "date" : "2015-10-15T19:30:00", - "value" : 5.2223837786879708 - }, - { - "unit" : "U", - "date" : "2015-10-15T19:35:00", - "value" : 5.4799525552297652 - }, - { - "unit" : "U", - "date" : "2015-10-15T19:40:00", - "value" : 5.6695925614864793 - }, - { - "unit" : "U", - "date" : "2015-10-15T19:45:00", - "value" : 5.6635295378079631 - }, - { - "unit" : "U", - "date" : "2015-10-15T19:50:00", - "value" : 5.6314732820551523 - }, - { - "unit" : "U", - "date" : "2015-10-15T19:55:00", - "value" : 6.2330598731481377 - }, - { - "unit" : "U", - "date" : "2015-10-15T20:00:00", - "value" : 6.1683612604082079 - }, - { - "unit" : "U", - "date" : "2015-10-15T20:05:00", - "value" : 6.0821526408986202 - }, - { - "unit" : "U", - "date" : "2015-10-15T20:10:00", - "value" : 9.339007755648586 - }, - { - "unit" : "U", - "date" : "2015-10-15T20:15:00", - "value" : 9.2590283914153222 - }, - { - "unit" : "U", - "date" : "2015-10-15T20:20:00", - "value" : 9.1177525184481762 - }, - { - "unit" : "U", - "date" : "2015-10-15T20:25:00", - "value" : 8.9499314682966453 - }, - { - "unit" : "U", - "date" : "2015-10-15T20:30:00", - "value" : 8.7561396343602915 - }, - { - "unit" : "U", - "date" : "2015-10-15T20:35:00", - "value" : 8.4845832726234924 - }, - { - "unit" : "U", - "date" : "2015-10-15T20:40:00", - "value" : 8.0639768823272657 - }, - { - "unit" : "U", - "date" : "2015-10-15T20:45:00", - "value" : 7.7586249263232387 - }, - { - "unit" : "U", - "date" : "2015-10-15T20:50:00", - "value" : 7.506473113392933 - }, - { - "unit" : "U", - "date" : "2015-10-15T20:55:00", - "value" : 7.2480670287672622 - }, - { - "unit" : "U", - "date" : "2015-10-15T21:00:00", - "value" : 6.9852872103854624 - }, - { - "unit" : "U", - "date" : "2015-10-15T21:05:00", - "value" : 7.0089553560527715 - }, - { - "unit" : "U", - "date" : "2015-10-15T21:10:00", - "value" : 6.7445586368252401 - }, - { - "unit" : "U", - "date" : "2015-10-15T21:15:00", - "value" : 6.4786519837698089 - }, - { - "unit" : "U", - "date" : "2015-10-15T21:20:00", - "value" : 6.2126037074653739 - }, - { - "unit" : "U", - "date" : "2015-10-15T21:25:00", - "value" : 5.9476248770643201 - }, - { - "unit" : "U", - "date" : "2015-10-15T21:30:00", - "value" : 5.6847826666103902 - }, - { - "unit" : "U", - "date" : "2015-10-15T21:35:00", - "value" : 5.425012715286786 - }, - { - "unit" : "U", - "date" : "2015-10-15T21:40:00", - "value" : 9.1643679446550816 - }, - { - "unit" : "U", - "date" : "2015-10-15T21:45:00", - "value" : 8.9244766284811767 - }, - { - "unit" : "U", - "date" : "2015-10-15T21:50:00", - "value" : 8.6695219976170197 - }, - { - "unit" : "U", - "date" : "2015-10-15T21:55:00", - "value" : 8.4024569792995507 - }, - { - "unit" : "U", - "date" : "2015-10-15T22:00:00", - "value" : 8.6729644081724775 - }, - { - "unit" : "U", - "date" : "2015-10-15T22:05:00", - "value" : 8.5743665469999559 - }, - { - "unit" : "U", - "date" : "2015-10-15T22:10:00", - "value" : 8.4712929747642391 - }, - { - "unit" : "U", - "date" : "2015-10-15T22:15:00", - "value" : 8.3588393812508137 - }, - { - "unit" : "U", - "date" : "2015-10-15T22:20:00", - "value" : 8.0729388216902063 - }, - { - "unit" : "U", - "date" : "2015-10-15T22:25:00", - "value" : 7.781199361715804 - }, - { - "unit" : "U", - "date" : "2015-10-15T22:30:00", - "value" : 7.4856649161427367 - }, - { - "unit" : "U", - "date" : "2015-10-15T22:35:00", - "value" : 7.1881572119253176 - }, - { - "unit" : "U", - "date" : "2015-10-15T22:40:00", - "value" : 6.890294293790161 - }, - { - "unit" : "U", - "date" : "2015-10-15T22:45:00", - "value" : 6.5935076751445409 - }, - { - "unit" : "U", - "date" : "2015-10-15T22:50:00", - "value" : 6.2990582259842016 - }, - { - "unit" : "U", - "date" : "2015-10-15T22:55:00", - "value" : 6.0080508836345787 - }, - { - "unit" : "U", - "date" : "2015-10-15T23:00:00", - "value" : 5.7214482666333124 - }, - { - "unit" : "U", - "date" : "2015-10-15T23:05:00", - "value" : 5.4400832668777497 - }, - { - "unit" : "U", - "date" : "2015-10-15T23:10:00", - "value" : 5.1646706902986974 - }, - { - "unit" : "U", - "date" : "2015-10-15T23:15:00", - "value" : 4.8958180117613948 - }, - { - "unit" : "U", - "date" : "2015-10-15T23:20:00", - "value" : 4.6340353056183625 - }, - { - "unit" : "U", - "date" : "2015-10-15T23:25:00", - "value" : 4.3797444093293967 - }, - { - "unit" : "U", - "date" : "2015-10-15T23:30:00", - "value" : 4.1332873738051532 - }, - { - "unit" : "U", - "date" : "2015-10-15T23:35:00", - "value" : 3.8949342506077977 - }, - { - "unit" : "U", - "date" : "2015-10-15T23:40:00", - "value" : 3.6648902628399975 - }, - { - "unit" : "U", - "date" : "2015-10-15T23:45:00", - "value" : 3.4433024034597164 - }, - { - "unit" : "U", - "date" : "2015-10-15T23:50:00", - "value" : 3.2302655018590798 - }, - { - "unit" : "U", - "date" : "2015-10-15T23:55:00", - "value" : 3.0258277968300611 - }, - { - "unit" : "U", - "date" : "2015-10-16T00:00:00", - "value" : 2.8299960514961033 - }, - { - "unit" : "U", - "date" : "2015-10-16T00:05:00", - "value" : 2.6427402434067315 - }, - { - "unit" : "U", - "date" : "2015-10-16T00:10:00", - "value" : 2.4639978607618818 - }, - { - "unit" : "U", - "date" : "2015-10-16T00:15:00", - "value" : 2.2936778336446353 - }, - { - "unit" : "U", - "date" : "2015-10-16T00:20:00", - "value" : 2.1316641271865899 - }, - { - "unit" : "U", - "date" : "2015-10-16T00:25:00", - "value" : 1.9778190217611142 - }, - { - "unit" : "U", - "date" : "2015-10-16T00:30:00", - "value" : 1.8319861035882414 - }, - { - "unit" : "U", - "date" : "2015-10-16T00:35:00", - "value" : 1.6939929875339457 - }, - { - "unit" : "U", - "date" : "2015-10-16T00:40:00", - "value" : 1.563653792388946 - }, - { - "unit" : "U", - "date" : "2015-10-16T00:45:00", - "value" : 1.4407713875118167 - }, - { - "unit" : "U", - "date" : "2015-10-16T00:50:00", - "value" : 1.3251394284117142 - }, - { - "unit" : "U", - "date" : "2015-10-16T00:55:00", - "value" : 1.2165441976220599 - }, - { - "unit" : "U", - "date" : "2015-10-16T01:00:00", - "value" : 1.1147662660725697 - }, - { - "unit" : "U", - "date" : "2015-10-16T01:05:00", - "value" : 1.0195819890980728 - }, - { - "unit" : "U", - "date" : "2015-10-16T01:10:00", - "value" : 0.93076485022399513 - }, - { - "unit" : "U", - "date" : "2015-10-16T01:15:00", - "value" : 0.84808666493571383 - }, - { - "unit" : "U", - "date" : "2015-10-16T01:20:00", - "value" : 0.77131865576805436 - }, - { - "unit" : "U", - "date" : "2015-10-16T01:25:00", - "value" : 0.70023240923815977 - }, - { - "unit" : "U", - "date" : "2015-10-16T01:30:00", - "value" : 0.63460072438612125 - }, - { - "unit" : "U", - "date" : "2015-10-16T01:35:00", - "value" : 0.57419836197964125 - }, - { - "unit" : "U", - "date" : "2015-10-16T01:40:00", - "value" : 0.51880270277843998 - }, - { - "unit" : "U", - "date" : "2015-10-16T01:45:00", - "value" : 0.46819432263809552 - }, - { - "unit" : "U", - "date" : "2015-10-16T01:50:00", - "value" : 0.42215749165855393 - }, - { - "unit" : "U", - "date" : "2015-10-16T01:55:00", - "value" : 0.38048060404717887 - }, - { - "unit" : "U", - "date" : "2015-10-16T02:00:00", - "value" : 0.34295654486728216 - }, - { - "unit" : "U", - "date" : "2015-10-16T02:05:00", - "value" : 0.30938299937825653 - }, - { - "unit" : "U", - "date" : "2015-10-16T02:10:00", - "value" : 0.27956271024064777 - }, - { - "unit" : "U", - "date" : "2015-10-16T02:15:00", - "value" : 0.2533036874564259 - }, - { - "unit" : "U", - "date" : "2015-10-16T02:20:00", - "value" : 0.23041937553972908 - }, - { - "unit" : "U", - "date" : "2015-10-16T02:25:00", - "value" : 0.2107287820643487 - }, - { - "unit" : "U", - "date" : "2015-10-16T02:30:00", - "value" : 0.19405657140966867 - }, - { - "unit" : "U", - "date" : "2015-10-16T02:35:00", - "value" : 0.18023312722505264 - }, - { - "unit" : "U", - "date" : "2015-10-16T02:40:00", - "value" : 0.16909458685217435 - }, - { - "unit" : "U", - "date" : "2015-10-16T02:45:00", - "value" : 0.16048285068425361 - }, - { - "unit" : "U", - "date" : "2015-10-16T02:50:00", - "value" : 0.15424556919921259 - }, - { - "unit" : "U", - "date" : "2015-10-16T02:55:00", - "value" : 0.15023611017911773 - }, - { - "unit" : "U", - "date" : "2015-10-16T03:00:00", - "value" : 0.14831350841984142 - }, - { - "unit" : "U", - "date" : "2015-10-16T03:05:00", - "value" : 0.14834240004162749 - }, - { - "unit" : "U", - "date" : "2015-10-16T03:10:00", - "value" : 0.1501929433319496 - }, - { - "unit" : "U", - "date" : "2015-10-16T03:15:00", - "value" : 0.1537407278860535 - }, - { - "unit" : "U", - "date" : "2015-10-16T03:20:00", - "value" : 0.1588666736567606 - }, - { - "unit" : "U", - "date" : "2015-10-16T03:25:00", - "value" : 0.1654569213827066 - }, - { - "unit" : "U", - "date" : "2015-10-16T03:30:00", - "value" : 0.17340271573256466 - }, - { - "unit" : "U", - "date" : "2015-10-16T03:35:00", - "value" : 0.18260028238088521 - }, - { - "unit" : "U", - "date" : "2015-10-16T03:40:00", - "value" : 0.19295070011876822 - }, - { - "unit" : "U", - "date" : "2015-10-16T03:45:00", - "value" : 0.2043597689985599 - }, - { - "unit" : "U", - "date" : "2015-10-16T03:50:00", - "value" : 0.21673787541587172 - }, - { - "unit" : "U", - "date" : "2015-10-16T03:55:00", - "value" : 0.22999985494373165 - }, - { - "unit" : "U", - "date" : "2015-10-16T04:00:00", - "value" : 0.24406485365216241 - }, - { - "unit" : "U", - "date" : "2015-10-16T04:05:00", - "value" : 0.25885618857136167 - }, - { - "unit" : "U", - "date" : "2015-10-16T04:10:00", - "value" : 0.2743012078875498 - }, - { - "unit" : "U", - "date" : "2015-10-16T04:15:00", - "value" : 0.29033115139706561 - }, - { - "unit" : "U", - "date" : "2015-10-16T04:20:00", - "value" : 0.30688101168585979 - }, - { - "unit" : "U", - "date" : "2015-10-16T04:25:00", - "value" : 0.3238893964480174 - }, - { - "unit" : "U", - "date" : "2015-10-16T04:30:00", - "value" : 0.34129839230781273 - }, - { - "unit" : "U", - "date" : "2015-10-16T04:35:00", - "value" : 0.35905343046482319 - }, - { - "unit" : "U", - "date" : "2015-10-16T04:40:00", - "value" : 0.37710315444047537 - } - ] - diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_doses_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_doses_output.json deleted file mode 100644 index b6570231a..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_doses_output.json +++ /dev/null @@ -1 +0,0 @@ -[{"date": "2015-10-15T18:05:00", "value": 0.0, "unit": "U"}, {"date": "2015-10-15T18:10:00", "value": -0.018750000000000006, "unit": "U"}, {"date": "2015-10-15T18:15:00", "value": -0.085416666666666669, "unit": "U"}, {"date": "2015-10-15T18:20:00", "value": -0.15206668087682032, "unit": "U"}, {"date": "2015-10-15T18:25:00", "value": -0.21857935431982956, "unit": "U"}, {"date": "2015-10-15T18:30:00", "value": -0.28464801252543015, "unit": "U"}, {"date": "2015-10-15T18:35:00", "value": -0.35010510247148485, "unit": "U"}, {"date": "2015-10-15T18:40:00", "value": -0.41479512492210602, "unit": "U"}, {"date": "2015-10-15T18:45:00", "value": -0.41190763676098952, "unit": "U"}, {"date": "2015-10-15T18:50:00", "value": -0.40797691999141444, "unit": "U"}, {"date": "2015-10-15T18:55:00", "value": -0.40292107811937894, "unit": "U"}, {"date": "2015-10-15T19:00:00", "value": -0.39698624056940118, "unit": "U"}, {"date": "2015-10-15T19:05:00", "value": -0.45690984213971042, "unit": "U"}, {"date": "2015-10-15T19:10:00", "value": -0.5160939052014526, "unit": "U"}, {"date": "2015-10-15T19:15:00", "value": -0.5741902604296798, "unit": "U"}, {"date": "2015-10-15T19:20:00", "value": -0.66778492452731286, "unit": "U"}, {"date": "2015-10-15T19:25:00", "value": -0.43178101319080897, "unit": "U"}, {"date": "2015-10-15T19:30:00", "value": 4.8055335550120359, "unit": "U"}, {"date": "2015-10-15T19:35:00", "value": 5.0439569248931519, "unit": "U"}, {"date": "2015-10-15T19:40:00", "value": 5.2564032091288739, "unit": "U"}, {"date": "2015-10-15T19:45:00", "value": 5.4534881571023126, "unit": "U"}, {"date": "2015-10-15T19:50:00", "value": 5.5918540183876919, "unit": "U"}, {"date": "2015-10-15T19:55:00", "value": 5.7617970521213326, "unit": "U"}, {"date": "2015-10-15T20:00:00", "value": 5.9186590272588271, "unit": "U"}, {"date": "2015-10-15T20:05:00", "value": 6.0629788559331814, "unit": "U"}, {"date": "2015-10-15T20:10:00", "value": 9.3416452708111812, "unit": "U"}, {"date": "2015-10-15T20:15:00", "value": 9.2679264924395568, "unit": "U"}, {"date": "2015-10-15T20:20:00", "value": 9.1311566183775188, "unit": "U"}, {"date": "2015-10-15T20:25:00", "value": 8.9767537893386322, "unit": "U"}, {"date": "2015-10-15T20:30:00", "value": 8.8018580566191247, "unit": "U"}, {"date": "2015-10-15T20:35:00", "value": 8.552252234133352, "unit": "U"}, {"date": "2015-10-15T20:40:00", "value": 8.2844286507395548, "unit": "U"}, {"date": "2015-10-15T20:45:00", "value": 8.0040683600139655, "unit": "U"}, {"date": "2015-10-15T20:50:00", "value": 7.712867310317252, "unit": "U"}, {"date": "2015-10-15T20:55:00", "value": 7.4123606321714997, "unit": "U"}, {"date": "2015-10-15T21:00:00", "value": 7.1706722555753073, "unit": "U"}, {"date": "2015-10-15T21:05:00", "value": 7.1254496600122827, "unit": "U"}, {"date": "2015-10-15T21:10:00", "value": 6.9617393970761903, "unit": "U"}, {"date": "2015-10-15T21:15:00", "value": 6.7034202910941953, "unit": "U"}, {"date": "2015-10-15T21:20:00", "value": 6.4411294655025397, "unit": "U"}, {"date": "2015-10-15T21:25:00", "value": 6.1756930346329053, "unit": "U"}, {"date": "2015-10-15T21:30:00", "value": 5.9083425409811152, "unit": "U"}, {"date": "2015-10-15T21:35:00", "value": 5.6400399553070137, "unit": "U"}, {"date": "2015-10-15T21:40:00", "value": 9.3783661475995945, "unit": "U"}, {"date": "2015-10-15T21:45:00", "value": 9.1108542204103582, "unit": "U"}, {"date": "2015-10-15T21:50:00", "value": 8.8205731329424886, "unit": "U"}, {"date": "2015-10-15T21:55:00", "value": 8.5236544857453715, "unit": "U"}, {"date": "2015-10-15T22:00:00", "value": 8.4121628508470163, "unit": "U"}, {"date": "2015-10-15T22:05:00", "value": 8.2891516195852599, "unit": "U"}, {"date": "2015-10-15T22:10:00", "value": 8.1623939723762202, "unit": "U"}, {"date": "2015-10-15T22:15:00", "value": 8.031926498827497, "unit": "U"}, {"date": "2015-10-15T22:20:00", "value": 7.898682868513041, "unit": "U"}, {"date": "2015-10-15T22:25:00", "value": 7.7572027441484082, "unit": "U"}, {"date": "2015-10-15T22:30:00", "value": 7.4342948897702952, "unit": "U"}, {"date": "2015-10-15T22:35:00", "value": 7.1098374176912387, "unit": "U"}, {"date": "2015-10-15T22:40:00", "value": 6.7844713305118889, "unit": "U"}, {"date": "2015-10-15T22:45:00", "value": 6.4599143409690667, "unit": "U"}, {"date": "2015-10-15T22:50:00", "value": 6.1370686677850914, "unit": "U"}, {"date": "2015-10-15T22:55:00", "value": 5.8163964384449898, "unit": "U"}, {"date": "2015-10-15T23:00:00", "value": 5.4998105211368991, "unit": "U"}, {"date": "2015-10-15T23:05:00", "value": 5.1880290027561484, "unit": "U"}, {"date": "2015-10-15T23:10:00", "value": 4.8816947056251614, "unit": "U"}, {"date": "2015-10-15T23:15:00", "value": 4.5812274778780608, "unit": "U"}, {"date": "2015-10-15T23:20:00", "value": 4.2866787472586676, "unit": "U"}, {"date": "2015-10-15T23:25:00", "value": 3.9985006890305459, "unit": "U"}, {"date": "2015-10-15T23:30:00", "value": 3.7174102768933639, "unit": "U"}, {"date": "2015-10-15T23:35:00", "value": 3.4413002004784681, "unit": "U"}, {"date": "2015-10-15T23:40:00", "value": 3.1790663931988168, "unit": "U"}, {"date": "2015-10-15T23:45:00", "value": 2.9674459025121354, "unit": "U"}, {"date": "2015-10-15T23:50:00", "value": 2.7629813356602755, "unit": "U"}, {"date": "2015-10-15T23:55:00", "value": 2.5658111309990193, "unit": "U"}, {"date": "2015-10-16T00:00:00", "value": 2.3763386371089359, "unit": "U"}, {"date": "2015-10-16T00:05:00", "value": 2.1936103849532484, "unit": "U"}, {"date": "2015-10-16T00:10:00", "value": 2.0183994767110565, "unit": "U"}, {"date": "2015-10-16T00:15:00", "value": 1.8507002564177386, "unit": "U"}, {"date": "2015-10-16T00:20:00", "value": 1.6985068266336847, "unit": "U"}, {"date": "2015-10-16T00:25:00", "value": 1.5747066972951482, "unit": "U"}, {"date": "2015-10-16T00:30:00", "value": 1.4549325333370042, "unit": "U"}, {"date": "2015-10-16T00:35:00", "value": 1.3388718304255545, "unit": "U"}, {"date": "2015-10-16T00:40:00", "value": 1.2267156075864047, "unit": "U"}, {"date": "2015-10-16T00:45:00", "value": 1.1189147793984533, "unit": "U"}, {"date": "2015-10-16T00:50:00", "value": 1.0147401216299032, "unit": "U"}, {"date": "2015-10-16T00:55:00", "value": 0.9142150372798441, "unit": "U"}, {"date": "2015-10-16T01:00:00", "value": 0.81744236897927469, "unit": "U"}, {"date": "2015-10-16T01:05:00", "value": 0.72449566972835622, "unit": "U"}, {"date": "2015-10-16T01:10:00", "value": 0.63497148245908197, "unit": "U"}, {"date": "2015-10-16T01:15:00", "value": 0.54966882501852599, "unit": "U"}, {"date": "2015-10-16T01:20:00", "value": 0.47039614943892216, "unit": "U"}, {"date": "2015-10-16T01:25:00", "value": 0.3967708826026185, "unit": "U"}, {"date": "2015-10-16T01:30:00", "value": 0.32725818119704375, "unit": "U"}, {"date": "2015-10-16T01:35:00", "value": 0.26174046235113074, "unit": "U"}, {"date": "2015-10-16T01:40:00", "value": 0.20007472515215177, "unit": "U"}, {"date": "2015-10-16T01:45:00", "value": 0.14209255064571641, "unit": "U"}, {"date": "2015-10-16T01:50:00", "value": 0.095810842977274838, "unit": "U"}, {"date": "2015-10-16T01:55:00", "value": 0.080002965672173271, "unit": "U"}, {"date": "2015-10-16T02:00:00", "value": 0.065104330918007297, "unit": "U"}, {"date": "2015-10-16T02:05:00", "value": 0.051088357857381354, "unit": "U"}, {"date": "2015-10-16T02:10:00", "value": 0.036587766581119896, "unit": "U"}, {"date": "2015-10-16T02:15:00", "value": 0.024746042994965325, "unit": "U"}, {"date": "2015-10-16T02:20:00", "value": 0.015304914415581596, "unit": "U"}, {"date": "2015-10-16T02:25:00", "value": 0.0081185642627603517, "unit": "U"}, {"date": "2015-10-16T02:30:00", "value": 0.0030469902521267325, "unit": "U"}, {"date": "2015-10-16T02:35:00", "value": 0.0, "unit": "U"}, {"date": "2015-10-16T02:40:00", "value": 0.0, "unit": "U"}] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_multiple_curves_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_multiple_curves_output.json deleted file mode 100644 index 84ea03dac..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_multiple_curves_output.json +++ /dev/null @@ -1,1832 +0,0 @@ -[ - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-15T14:30:00" - }, - { - "date" : "2018-05-15T14:35:00", - "unit" : "U", - "value" : 0.47499999999999998 - }, - { - "unit" : "U", - "date" : "2018-05-15T14:40:00", - "value" : 0.6333333333333333 - }, - { - "date" : "2018-05-15T14:45:00", - "value" : 1.6915740087465312, - "unit" : "U" - }, - { - "value" : 1.8489316417304882, - "unit" : "U", - "date" : "2018-05-15T14:50:00" - }, - { - "date" : "2018-05-15T14:55:00", - "unit" : "U", - "value" : 2.0712399104673604 - }, - { - "value" : 2.1370939589095088, - "date" : "2018-05-15T15:00:00", - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-15T15:05:00", - "value" : 2.19336788771338 - }, - { - "unit" : "U", - "value" : 2.2403345921609774, - "date" : "2018-05-15T15:10:00" - }, - { - "value" : 2.2782879035205195, - "unit" : "U", - "date" : "2018-05-15T15:15:00" - }, - { - "unit" : "U", - "value" : 2.3082278942435908, - "date" : "2018-05-15T15:20:00" - }, - { - "date" : "2018-05-15T15:25:00", - "value" : 2.3311963398163353, - "unit" : "U" - }, - { - "date" : "2018-05-15T15:30:00", - "value" : 2.3481189511825669, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-15T15:35:00", - "value" : 2.3598173463208263 - }, - { - "value" : 2.3670198473624873, - "unit" : "U", - "date" : "2018-05-15T15:40:00" - }, - { - "value" : 2.2953712142565323, - "unit" : "U", - "date" : "2018-05-15T15:45:00" - }, - { - "unit" : "U", - "value" : 2.2204414158007308, - "date" : "2018-05-15T15:50:00" - }, - { - "unit" : "U", - "value" : 2.1427335295852732, - "date" : "2018-05-15T15:55:00" - }, - { - "date" : "2018-05-15T16:00:00", - "value" : 2.0626908539533693, - "unit" : "U" - }, - { - "date" : "2018-05-15T16:05:00", - "value" : 1.980747197994547, - "unit" : "U" - }, - { - "date" : "2018-05-15T16:10:00", - "value" : 1.8976192482894976, - "unit" : "U" - }, - { - "date" : "2018-05-15T16:15:00", - "value" : 1.8139973641998268, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-15T16:20:00", - "value" : 1.7304759186052754 - }, - { - "date" : "2018-05-15T16:25:00", - "value" : 1.6475635788732115, - "unit" : "U" - }, - { - "unit" : "U", - "value" : 1.5656926070620716, - "date" : "2018-05-15T16:30:00" - }, - { - "date" : "2018-05-15T16:35:00", - "value" : 1.4852272670887603, - "unit" : "U" - }, - { - "date" : "2018-05-15T16:40:00", - "value" : 1.4064714190471779, - "unit" : "U" - }, - { - "date" : "2018-05-15T16:45:00", - "value" : 1.3296753739542622, - "unit" : "U" - }, - { - "date" : "2018-05-15T16:50:00", - "unit" : "U", - "value" : 1.255042075869125 - }, - { - "unit" : "U", - "date" : "2018-05-15T16:55:00", - "value" : 1.182732672532232 - }, - { - "date" : "2018-05-15T17:00:00", - "value" : 1.1128715303612036, - "unit" : "U" - }, - { - "date" : "2018-05-15T17:05:00", - "value" : 1.0455507447773233, - "unit" : "U" - }, - { - "value" : 0.98083419238524305, - "date" : "2018-05-15T17:10:00", - "unit" : "U" - }, - { - "value" : 0.91876116745355696, - "unit" : "U", - "date" : "2018-05-15T17:15:00" - }, - { - "unit" : "U", - "value" : 0.85934964141471826, - "date" : "2018-05-15T17:20:00" - }, - { - "date" : "2018-05-15T17:25:00", - "unit" : "U", - "value" : 0.80259918069043423 - }, - { - "unit" : "U", - "date" : "2018-05-15T17:30:00", - "value" : 0.74849355502689308 - }, - { - "date" : "2018-05-15T17:35:00", - "value" : 0.69700306566874226, - "unit" : "U" - }, - { - "date" : "2018-05-15T17:40:00", - "value" : 0.64808662008946216, - "unit" : "U" - }, - { - "date" : "2018-05-15T17:45:00", - "value" : 0.60169357760826792, - "unit" : "U" - }, - { - "value" : 0.55776538804123588, - "unit" : "U", - "date" : "2018-05-15T17:50:00" - }, - { - "unit" : "U", - "value" : 0.51623704353979327, - "date" : "2018-05-15T17:55:00" - }, - { - "date" : "2018-05-15T18:00:00", - "unit" : "U", - "value" : 0.47703836194731364 - }, - { - "value" : 0.44009511833982601, - "date" : "2018-05-15T18:05:00", - "unit" : "U" - }, - { - "value" : 0.40533003989653815, - "unit" : "U", - "date" : "2018-05-15T18:10:00" - }, - { - "value" : 0.37266367785781856, - "date" : "2018-05-15T18:15:00", - "unit" : "U" - }, - { - "value" : 0.34201516906129603, - "unit" : "U", - "date" : "2018-05-15T18:20:00" - }, - { - "unit" : "U", - "value" : 0.31330289839060693, - "date" : "2018-05-15T18:25:00" - }, - { - "date" : "2018-05-15T18:30:00", - "unit" : "U", - "value" : 0.28644507241663808 - }, - { - "date" : "2018-05-15T18:35:00", - "value" : 0.26136021354927008, - "unit" : "U" - }, - { - "date" : "2018-05-15T18:40:00", - "unit" : "U", - "value" : 0.2379675831407321 - }, - { - "date" : "2018-05-15T18:45:00", - "value" : 0.21618754118248495, - "unit" : "U" - }, - { - "value" : 0.19594184950942245, - "unit" : "U", - "date" : "2018-05-15T18:50:00" - }, - { - "value" : 0.17715392476204106, - "unit" : "U", - "date" : "2018-05-15T18:55:00" - }, - { - "date" : "2018-05-15T19:00:00", - "unit" : "U", - "value" : 0.15974904675349527 - }, - { - "date" : "2018-05-15T19:05:00", - "value" : 0.1436545273390194, - "unit" : "U" - }, - { - "date" : "2018-05-15T19:10:00", - "value" : 0.12879984438538891, - "unit" : "U" - }, - { - "date" : "2018-05-15T19:15:00", - "unit" : "U", - "value" : 0.1151167449836045 - }, - { - "unit" : "U", - "date" : "2018-05-15T19:20:00", - "value" : 0.10253932163491067 - }, - { - "date" : "2018-05-15T19:25:00", - "value" : 0.091004064764979464, - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0.080449894580340228, - "date" : "2018-05-15T19:30:00" - }, - { - "date" : "2018-05-15T19:35:00", - "value" : 0.070818174971862144, - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0.062052711889583244, - "date" : "2018-05-15T19:40:00" - }, - { - "unit" : "U", - "value" : 0.054099738358855592, - "date" : "2018-05-15T19:45:00" - }, - { - "value" : 0.046907888077367434, - "unit" : "U", - "date" : "2018-05-15T19:50:00" - }, - { - "date" : "2018-05-15T19:55:00", - "unit" : "U", - "value" : 0.040428159323969523 - }, - { - "date" : "2018-05-15T20:00:00", - "value" : 0.034613870721459654, - "unit" : "U" - }, - { - "value" : 0.02942061022476937, - "unit" : "U", - "date" : "2018-05-15T20:05:00" - }, - { - "unit" : "U", - "value" : 0.024806178551778087, - "date" : "2018-05-15T20:10:00" - }, - { - "unit" : "U", - "value" : 0.020730528134717138, - "date" : "2018-05-15T20:15:00" - }, - { - "unit" : "U", - "date" : "2018-05-15T20:20:00", - "value" : 0.017155698544521571 - }, - { - "value" : 0.014045749227269059, - "date" : "2018-05-15T20:25:00", - "unit" : "U" - }, - { - "date" : "2018-05-15T20:30:00", - "value" : 0.011366690289902354, - "unit" : "U" - }, - { - "date" : "2018-05-15T20:35:00", - "value" : 0.0090864119807336687, - "unit" : "U" - }, - { - "value" : 0.0071746134278282614, - "unit" : "U", - "date" : "2018-05-15T20:40:00" - }, - { - "date" : "2018-05-15T20:45:00", - "value" : 0.005601486619560345, - "unit" : "U" - }, - { - "value" : 0.0043292756256765753, - "date" : "2018-05-15T20:50:00", - "unit" : "U" - }, - { - "date" : "2018-05-15T20:55:00", - "unit" : "U", - "value" : 0.0033207103391380516 - }, - { - "value" : 0.0025219498401522779, - "unit" : "U", - "date" : "2018-05-15T21:00:00" - }, - { - "date" : "2018-05-15T21:05:00", - "value" : 0.0018871576711575945, - "unit" : "U" - }, - { - "date" : "2018-05-15T21:10:00", - "value" : 0.0013853687199656571, - "unit" : "U" - }, - { - "value" : 0.0009882554300828959, - "unit" : "U", - "date" : "2018-05-15T21:15:00" - }, - { - "date" : "2018-05-15T21:20:00", - "value" : 0.00067942868037322579, - "unit" : "U" - }, - { - "value" : 0.00044576159190715673, - "date" : "2018-05-15T21:25:00", - "unit" : "U" - }, - { - "date" : "2018-05-15T21:30:00", - "value" : 0.00027508208129293219, - "unit" : "U" - }, - { - "value" : 0.00015612214944180913, - "date" : "2018-05-15T21:35:00", - "unit" : "U" - }, - { - "value" : 7.8468909425874486e-05, - "unit" : "U", - "date" : "2018-05-15T21:40:00" - }, - { - "value" : 3.2517376900698111e-05, - "unit" : "U", - "date" : "2018-05-15T21:45:00" - }, - { - "value" : 9.4250347901891896e-06, - "unit" : "U", - "date" : "2018-05-15T21:50:00" - }, - { - "value" : 1.0681736302808885e-06, - "unit" : "U", - "date" : "2018-05-15T21:55:00" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-15T22:00:00" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-15T22:05:00" - }, - { - "date" : "2018-05-15T22:10:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "date" : "2018-05-15T22:15:00", - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-15T22:20:00" - }, - { - "value" : 0, - "date" : "2018-05-15T22:25:00", - "unit" : "U" - }, - { - "value" : 0, - "date" : "2018-05-15T22:30:00", - "unit" : "U" - }, - { - "date" : "2018-05-15T22:35:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-15T22:40:00", - "unit" : "U", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2018-05-15T22:45:00", - "value" : 0 - }, - { - "date" : "2018-05-15T22:50:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-15T22:55:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-15T23:00:00", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2018-05-15T23:05:00", - "value" : 0 - }, - { - "date" : "2018-05-15T23:10:00", - "unit" : "U", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2018-05-15T23:15:00", - "value" : 0 - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-15T23:20:00" - }, - { - "unit" : "U", - "date" : "2018-05-15T23:25:00", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2018-05-15T23:30:00", - "value" : 0 - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-15T23:35:00" - }, - { - "date" : "2018-05-15T23:40:00", - "unit" : "U", - "value" : 0 - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-15T23:45:00" - }, - { - "value" : 0, - "date" : "2018-05-15T23:50:00", - "unit" : "U" - }, - { - "value" : 0, - "date" : "2018-05-15T23:55:00", - "unit" : "U" - }, - { - "value" : 0, - "date" : "2018-05-16T00:00:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T00:05:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T00:10:00", - "value" : 0 - }, - { - "date" : "2018-05-16T00:15:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T00:20:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T00:25:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T00:30:00", - "unit" : "U", - "value" : 0 - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T00:35:00" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T00:40:00" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T00:45:00" - }, - { - "date" : "2018-05-16T00:50:00", - "unit" : "U", - "value" : 0 - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T00:55:00" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T01:00:00" - }, - { - "date" : "2018-05-16T01:05:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T01:10:00", - "value" : 0 - }, - { - "date" : "2018-05-16T01:15:00", - "unit" : "U", - "value" : 0 - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T01:20:00" - }, - { - "value" : 0, - "date" : "2018-05-16T01:25:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T01:30:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T01:35:00" - }, - { - "value" : 0, - "date" : "2018-05-16T01:40:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T01:45:00", - "unit" : "U", - "value" : 0 - }, - { - "value" : 0, - "date" : "2018-05-16T01:50:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T01:55:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T02:00:00" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T02:05:00" - }, - { - "value" : 0, - "date" : "2018-05-16T02:10:00", - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T02:15:00", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2018-05-16T02:20:00", - "value" : 0 - }, - { - "date" : "2018-05-16T02:25:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T02:30:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T02:35:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T02:40:00", - "unit" : "U", - "value" : 0 - }, - { - "date" : "2018-05-16T02:45:00", - "unit" : "U", - "value" : 0 - }, - { - "date" : "2018-05-16T02:50:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T02:55:00" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T03:00:00" - }, - { - "date" : "2018-05-16T03:05:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T03:10:00" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T03:15:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T03:20:00", - "value" : 0 - }, - { - "value" : 0, - "date" : "2018-05-16T03:25:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T03:30:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T03:35:00", - "value" : 0 - }, - { - "date" : "2018-05-16T03:40:00", - "unit" : "U", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2018-05-16T03:45:00", - "value" : 0 - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T03:50:00" - }, - { - "date" : "2018-05-16T03:55:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T04:00:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T04:05:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T04:10:00" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T04:15:00" - }, - { - "value" : 0, - "date" : "2018-05-16T04:20:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T04:25:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T04:30:00" - }, - { - "date" : "2018-05-16T04:35:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T04:40:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T04:45:00", - "value" : 0 - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T04:50:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T04:55:00", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2018-05-16T05:00:00", - "value" : 0 - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T05:05:00" - }, - { - "date" : "2018-05-16T05:10:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T05:15:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T05:20:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T05:25:00" - }, - { - "date" : "2018-05-16T05:30:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T05:35:00", - "value" : 0 - }, - { - "value" : 0, - "date" : "2018-05-16T05:40:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T05:45:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T05:50:00", - "value" : 0 - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T05:55:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T06:00:00", - "value" : 0 - }, - { - "date" : "2018-05-16T06:05:00", - "unit" : "U", - "value" : 0 - }, - { - "date" : "2018-05-16T06:10:00", - "unit" : "U", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2018-05-16T06:15:00", - "value" : 0 - }, - { - "date" : "2018-05-16T06:20:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T06:25:00" - }, - { - "date" : "2018-05-16T06:30:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T06:35:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T06:40:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T06:45:00" - }, - { - "date" : "2018-05-16T06:50:00", - "unit" : "U", - "value" : 0 - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T06:55:00" - }, - { - "value" : 0, - "date" : "2018-05-16T07:00:00", - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T07:05:00", - "value" : 0 - }, - { - "date" : "2018-05-16T07:10:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T07:15:00", - "unit" : "U", - "value" : 0 - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T07:20:00" - }, - { - "date" : "2018-05-16T07:25:00", - "unit" : "U", - "value" : 0 - }, - { - "value" : 0, - "date" : "2018-05-16T07:30:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T07:35:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T07:40:00" - }, - { - "date" : "2018-05-16T07:45:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T07:50:00", - "unit" : "U", - "value" : 0 - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T07:55:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T08:00:00", - "value" : 0 - }, - { - "date" : "2018-05-16T08:05:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "date" : "2018-05-16T08:10:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T08:15:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T08:20:00" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T08:25:00" - }, - { - "date" : "2018-05-16T08:30:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T08:35:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T08:40:00", - "unit" : "U", - "value" : 0 - }, - { - "date" : "2018-05-16T08:45:00", - "unit" : "U", - "value" : 0 - }, - { - "date" : "2018-05-16T08:50:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T08:55:00", - "unit" : "U", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2018-05-16T09:00:00", - "value" : 0 - }, - { - "date" : "2018-05-16T09:05:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T09:10:00" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T09:15:00" - }, - { - "date" : "2018-05-16T09:20:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T09:25:00", - "unit" : "U", - "value" : 0 - }, - { - "date" : "2018-05-16T09:30:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T09:35:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T09:40:00", - "value" : 0 - }, - { - "date" : "2018-05-16T09:45:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T09:50:00", - "value" : 0 - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T09:55:00" - }, - { - "value" : 0, - "date" : "2018-05-16T10:00:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T10:05:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T10:10:00", - "value" : 0 - }, - { - "date" : "2018-05-16T10:15:00", - "unit" : "U", - "value" : 0 - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T10:20:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T10:25:00", - "value" : 0 - }, - { - "value" : 0, - "date" : "2018-05-16T10:30:00", - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T10:35:00" - }, - { - "value" : 0, - "date" : "2018-05-16T10:40:00", - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T10:45:00", - "value" : 0 - }, - { - "value" : 0, - "date" : "2018-05-16T10:50:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T10:55:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T11:00:00", - "unit" : "U", - "value" : 0 - }, - { - "date" : "2018-05-16T11:05:00", - "unit" : "U", - "value" : 0 - }, - { - "date" : "2018-05-16T11:10:00", - "unit" : "U", - "value" : 0 - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T11:15:00" - }, - { - "value" : 0, - "date" : "2018-05-16T11:20:00", - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T11:25:00" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T11:30:00" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T11:35:00" - }, - { - "date" : "2018-05-16T11:40:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T11:45:00" - }, - { - "date" : "2018-05-16T11:50:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T11:55:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T12:00:00" - }, - { - "value" : 0, - "date" : "2018-05-16T12:05:00", - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T12:10:00" - }, - { - "date" : "2018-05-16T12:15:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T12:20:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T12:25:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T12:30:00", - "value" : 0 - }, - { - "value" : 0, - "date" : "2018-05-16T12:35:00", - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T12:40:00" - }, - { - "date" : "2018-05-16T12:45:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T12:50:00" - }, - { - "date" : "2018-05-16T12:55:00", - "unit" : "U", - "value" : 0 - }, - { - "value" : 0, - "date" : "2018-05-16T13:00:00", - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T13:05:00", - "value" : 0 - }, - { - "date" : "2018-05-16T13:10:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "date" : "2018-05-16T13:15:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T13:20:00", - "unit" : "U", - "value" : 0 - }, - { - "value" : 0, - "date" : "2018-05-16T13:25:00", - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T13:30:00" - }, - { - "date" : "2018-05-16T13:35:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T13:40:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T13:45:00", - "value" : 0 - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T13:50:00" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T13:55:00" - }, - { - "date" : "2018-05-16T14:00:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T14:05:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "date" : "2018-05-16T14:10:00", - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T14:15:00", - "value" : 0 - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T14:20:00" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T14:25:00" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T14:30:00" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T14:35:00" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T14:40:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T14:45:00", - "value" : 0 - }, - { - "date" : "2018-05-16T14:50:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T14:55:00", - "value" : 0 - }, - { - "date" : "2018-05-16T15:00:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T15:05:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T15:10:00" - }, - { - "value" : 0, - "date" : "2018-05-16T15:15:00", - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T15:20:00", - "value" : 0 - }, - { - "date" : "2018-05-16T15:25:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T15:30:00", - "value" : 0 - }, - { - "date" : "2018-05-16T15:35:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "date" : "2018-05-16T15:40:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T15:45:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T15:50:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T15:55:00", - "value" : 0 - }, - { - "date" : "2018-05-16T16:00:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T16:05:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T16:10:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T16:15:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T16:20:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "date" : "2018-05-16T16:25:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T16:30:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T16:35:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T16:40:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T16:45:00", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2018-05-16T16:50:00", - "value" : 0 - }, - { - "date" : "2018-05-16T16:55:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T17:00:00", - "value" : 0 - }, - { - "value" : 0, - "date" : "2018-05-16T17:05:00", - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T17:10:00" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T17:15:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T17:20:00", - "value" : 0 - }, - { - "date" : "2018-05-16T17:25:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "date" : "2018-05-16T17:30:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T17:35:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T17:40:00", - "value" : 0 - }, - { - "date" : "2018-05-16T17:45:00", - "unit" : "U", - "value" : 0 - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T17:50:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T17:55:00", - "value" : 0 - }, - { - "date" : "2018-05-16T18:00:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T18:05:00", - "value" : 0 - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T18:10:00" - }, - { - "value" : 0, - "date" : "2018-05-16T18:15:00", - "unit" : "U" - }, - { - "date" : "2018-05-16T18:20:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T18:25:00", - "unit" : "U", - "value" : 0 - }, - { - "value" : 0, - "date" : "2018-05-16T18:30:00", - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T18:35:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T18:40:00", - "value" : 0 - }, - { - "date" : "2018-05-16T18:45:00", - "unit" : "U", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2018-05-16T18:50:00", - "value" : 0 - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T18:55:00" - }, - { - "value" : 0, - "date" : "2018-05-16T19:00:00", - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T19:05:00", - "value" : 0 - }, - { - "value" : 0, - "date" : "2018-05-16T19:10:00", - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2018-05-16T19:15:00" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T19:20:00" - }, - { - "date" : "2018-05-16T19:25:00", - "unit" : "U", - "value" : 0 - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T19:30:00" - }, - { - "value" : 0, - "date" : "2018-05-16T19:35:00", - "unit" : "U" - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T19:40:00" - }, - { - "unit" : "U", - "date" : "2018-05-16T19:45:00", - "value" : 0 - }, - { - "date" : "2018-05-16T19:50:00", - "value" : 0, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T19:55:00", - "value" : 0 - }, - { - "value" : 0, - "date" : "2018-05-16T20:00:00", - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T20:05:00", - "value" : 0 - }, - { - "date" : "2018-05-16T20:10:00", - "unit" : "U", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2018-05-16T20:15:00", - "value" : 0 - }, - { - "unit" : "U", - "date" : "2018-05-16T20:20:00", - "value" : 0 - }, - { - "value" : 0, - "unit" : "U", - "date" : "2018-05-16T20:25:00" - }, - { - "date" : "2018-05-16T20:30:00", - "unit" : "U", - "value" : 0 - }, - { - "date" : "2018-05-16T20:35:00", - "unit" : "U", - "value" : 0 - }, - { - "date" : "2018-05-16T20:40:00", - "value" : 0, - "unit" : "U" - }, - { - "date" : "2018-05-16T20:45:00", - "value" : 0, - "unit" : "U" - }, - { - "value" : 0, - "date" : "2018-05-16T20:50:00", - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2018-05-16T20:55:00", - "value" : 0 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_reservoir_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_reservoir_output.json deleted file mode 100644 index 99afe3947..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/iob_from_reservoir_output.json +++ /dev/null @@ -1,557 +0,0 @@ -[ - { - "date" : "2016-01-30T15:40:00", - "unit" : "U", - "value" : 0 - }, - { - "date" : "2016-01-30T15:45:00", - "unit" : "U", - "value" : 0.15000000000000002 - }, - { - "value" : 0.10000000000000002, - "unit" : "U", - "date" : "2016-01-30T15:50:00" - }, - { - "value" : 0.099212976798720806, - "unit" : "U", - "date" : "2016-01-30T15:55:00" - }, - { - "value" : 0.098275712826063788, - "unit" : "U", - "date" : "2016-01-30T16:00:00" - }, - { - "unit" : "U", - "date" : "2016-01-30T16:05:00", - "value" : 0.047111306714195639 - }, - { - "date" : "2016-01-30T16:10:00", - "unit" : "U", - "value" : 0.045731884143539986 - }, - { - "date" : "2016-01-30T16:15:00", - "value" : 0.0944248098461625, - "unit" : "U" - }, - { - "date" : "2016-01-30T16:20:00", - "value" : 0.14307152431242381, - "unit" : "U" - }, - { - "value" : 0.14140322499818203, - "date" : "2016-01-30T16:25:00", - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2016-01-30T16:30:00", - "value" : 0.23929144671351077 - }, - { - "value" : 0.33689236145012552, - "unit" : "U", - "date" : "2016-01-30T16:35:00" - }, - { - "date" : "2016-01-30T16:40:00", - "value" : 0.53369507799347149, - "unit" : "U" - }, - { - "value" : 0.67945279146619619, - "date" : "2016-01-30T16:45:00", - "unit" : "U" - }, - { - "date" : "2016-01-30T16:50:00", - "value" : 0.82341112661509519, - "unit" : "U" - }, - { - "unit" : "U", - "value" : 1.1653613246974353, - "date" : "2016-01-30T16:55:00" - }, - { - "value" : 1.1550154635179453, - "date" : "2016-01-30T17:00:00", - "unit" : "U" - }, - { - "value" : 4.9919716879629608, - "date" : "2016-01-30T17:05:00", - "unit" : "U" - }, - { - "value" : 4.9759173333425126, - "unit" : "U", - "date" : "2016-01-30T17:10:00" - }, - { - "date" : "2016-01-30T17:15:00", - "value" : 4.9869526017280821, - "unit" : "U" - }, - { - "date" : "2016-01-30T17:20:00", - "unit" : "U", - "value" : 4.9852734216473804 - }, - { - "date" : "2016-01-30T17:25:00", - "unit" : "U", - "value" : 4.9220825913241857 - }, - { - "value" : 4.9481169462951646, - "date" : "2016-01-30T17:30:00", - "unit" : "U" - }, - { - "date" : "2016-01-30T17:35:00", - "value" : 4.9643705746846809, - "unit" : "U" - }, - { - "value" : 4.9211486492010215, - "unit" : "U", - "date" : "2016-01-30T17:40:00" - }, - { - "unit" : "U", - "date" : "2016-01-30T17:45:00", - "value" : 4.918987317244099 - }, - { - "value" : 4.8587077617807841, - "date" : "2016-01-30T17:50:00", - "unit" : "U" - }, - { - "value" : 4.7407114687577394, - "date" : "2016-01-30T17:55:00", - "unit" : "U" - }, - { - "unit" : "U", - "value" : 4.6657861569808405, - "date" : "2016-01-30T18:00:00" - }, - { - "value" : 5.8848456307767343, - "unit" : "U", - "date" : "2016-01-30T18:05:00" - }, - { - "unit" : "U", - "date" : "2016-01-30T18:10:00", - "value" : 5.7483797680036268 - }, - { - "unit" : "U", - "date" : "2016-01-30T18:15:00", - "value" : 5.5499516909461653 - }, - { - "value" : 5.3939229728549725, - "date" : "2016-01-30T18:20:00", - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2016-01-30T18:25:00", - "value" : 5.2816375827464555 - }, - { - "unit" : "U", - "value" : 5.1638524940542636, - "date" : "2016-01-30T18:30:00" - }, - { - "unit" : "U", - "date" : "2016-01-30T18:35:00", - "value" : 5.0411404269275355 - }, - { - "date" : "2016-01-30T18:40:00", - "unit" : "U", - "value" : 4.8641815683419072 - }, - { - "unit" : "U", - "date" : "2016-01-30T18:45:00", - "value" : 4.6836334412005076 - }, - { - "value" : 4.4504010554461315, - "unit" : "U", - "date" : "2016-01-30T18:50:00" - }, - { - "value" : 4.2152279852041419, - "unit" : "U", - "date" : "2016-01-30T18:55:00" - }, - { - "date" : "2016-01-30T19:00:00", - "value" : 4.0790887846505832, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2016-01-30T19:05:00", - "value" : 3.9427860003935589 - }, - { - "value" : 3.7565304133616957, - "unit" : "U", - "date" : "2016-01-30T19:10:00" - }, - { - "date" : "2016-01-30T19:15:00", - "value" : 3.6207640502302314, - "unit" : "U" - }, - { - "date" : "2016-01-30T19:20:00", - "value" : 3.4861815101235218, - "unit" : "U" - }, - { - "value" : 3.3030459114866639, - "unit" : "U", - "date" : "2016-01-30T19:25:00" - }, - { - "date" : "2016-01-30T19:30:00", - "value" : 3.6717180682888264, - "unit" : "U" - }, - { - "date" : "2016-01-30T19:35:00", - "value" : 3.4928061170868649, - "unit" : "U" - }, - { - "value" : 4.065271058621029, - "unit" : "U", - "date" : "2016-01-30T19:40:00" - }, - { - "date" : "2016-01-30T19:45:00", - "unit" : "U", - "value" : 3.9387762111087592 - }, - { - "value" : 3.81046193022304, - "date" : "2016-01-30T19:50:00", - "unit" : "U" - }, - { - "unit" : "U", - "value" : 3.7826889015104634, - "date" : "2016-01-30T19:55:00" - }, - { - "date" : "2016-01-30T20:00:00", - "value" : 3.7069366647513555, - "unit" : "U" - }, - { - "value" : 3.7314277995846412, - "unit" : "U", - "date" : "2016-01-30T20:05:00" - }, - { - "value" : 3.7069262823043241, - "unit" : "U", - "date" : "2016-01-30T20:10:00" - }, - { - "unit" : "U", - "value" : 3.7330370660528502, - "date" : "2016-01-30T20:15:00" - }, - { - "date" : "2016-01-30T20:20:00", - "value" : 4.7096124199656568, - "unit" : "U" - }, - { - "date" : "2016-01-30T20:25:00", - "value" : 4.5368958492533569, - "unit" : "U" - }, - { - "date" : "2016-01-30T20:30:00", - "value" : 4.4099977039342413, - "unit" : "U" - }, - { - "date" : "2016-01-30T20:35:00", - "unit" : "U", - "value" : 4.2824072403281432 - }, - { - "value" : 4.1042321771307764, - "unit" : "U", - "date" : "2016-01-30T20:40:00" - }, - { - "date" : "2016-01-30T20:45:00", - "value" : 3.9266321726654048, - "unit" : "U" - }, - { - "date" : "2016-01-30T20:50:00", - "unit" : "U", - "value" : 3.7502782110768567 - }, - { - "value" : 3.5762931893501637, - "unit" : "U", - "date" : "2016-01-30T20:55:00" - }, - { - "value" : 3.4045716142676059, - "unit" : "U", - "date" : "2016-01-30T21:00:00" - }, - { - "value" : 3.2354173648740034, - "unit" : "U", - "date" : "2016-01-30T21:05:00" - }, - { - "value" : 3.0692526347093336, - "unit" : "U", - "date" : "2016-01-30T21:10:00" - }, - { - "date" : "2016-01-30T21:15:00", - "value" : 2.9101305920579263, - "unit" : "U" - }, - { - "value" : 2.7829837717824413, - "unit" : "U", - "date" : "2016-01-30T21:20:00" - }, - { - "value" : 2.6558048319781347, - "date" : "2016-01-30T21:25:00", - "unit" : "U" - }, - { - "value" : 2.5293635555857814, - "unit" : "U", - "date" : "2016-01-30T21:30:00" - }, - { - "unit" : "U", - "date" : "2016-01-30T21:35:00", - "value" : 2.4039355639260558 - }, - { - "value" : 2.279552286353701, - "unit" : "U", - "date" : "2016-01-30T21:40:00" - }, - { - "value" : 2.157306896835876, - "unit" : "U", - "date" : "2016-01-30T21:45:00" - }, - { - "value" : 2.0373612181004273, - "unit" : "U", - "date" : "2016-01-30T21:50:00" - }, - { - "date" : "2016-01-30T21:55:00", - "value" : 1.9195964887598369, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2016-01-30T22:00:00", - "value" : 1.8045534385638062 - }, - { - "value" : 1.6919578965434179, - "date" : "2016-01-30T22:05:00", - "unit" : "U" - }, - { - "date" : "2016-01-30T22:10:00", - "value" : 1.5816478930177089, - "unit" : "U" - }, - { - "date" : "2016-01-30T22:15:00", - "value" : 1.4756794813350154, - "unit" : "U" - }, - { - "value" : 1.3826944382452513, - "date" : "2016-01-30T22:20:00", - "unit" : "U" - }, - { - "value" : 1.2915868325050057, - "date" : "2016-01-30T22:25:00", - "unit" : "U" - }, - { - "value" : 1.2022117827604497, - "unit" : "U", - "date" : "2016-01-30T22:30:00" - }, - { - "date" : "2016-01-30T22:35:00", - "value" : 1.1152075034750257, - "unit" : "U" - }, - { - "value" : 1.0311054096416641, - "unit" : "U", - "date" : "2016-01-30T22:40:00" - }, - { - "date" : "2016-01-30T22:45:00", - "unit" : "U", - "value" : 0.95000927138722213 - }, - { - "unit" : "U", - "date" : "2016-01-30T22:50:00", - "value" : 0.87194528135366922 - }, - { - "date" : "2016-01-30T22:55:00", - "unit" : "U", - "value" : 0.79659633124504581 - }, - { - "date" : "2016-01-30T23:00:00", - "value" : 0.72398544796560949, - "unit" : "U" - }, - { - "date" : "2016-01-30T23:05:00", - "value" : 0.65379136023632267, - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2016-01-30T23:10:00", - "value" : 0.58620542363529282 - }, - { - "unit" : "U", - "date" : "2016-01-30T23:15:00", - "value" : 0.5220501678714512 - }, - { - "unit" : "U", - "date" : "2016-01-30T23:20:00", - "value" : 0.46124830226547026 - }, - { - "date" : "2016-01-30T23:25:00", - "unit" : "U", - "value" : 0.40343493383713092 - }, - { - "unit" : "U", - "date" : "2016-01-30T23:30:00", - "value" : 0.34896941109471025 - }, - { - "unit" : "U", - "date" : "2016-01-30T23:35:00", - "value" : 0.29772685092637907 - }, - { - "value" : 0.2495521869785764, - "unit" : "U", - "date" : "2016-01-30T23:40:00" - }, - { - "value" : 0.2065039898047587, - "date" : "2016-01-30T23:45:00", - "unit" : "U" - }, - { - "unit" : "U", - "date" : "2016-01-30T23:50:00", - "value" : 0.16889255072667728 - }, - { - "date" : "2016-01-30T23:55:00", - "unit" : "U", - "value" : 0.139358411188471 - }, - { - "value" : 0.11198960864727414, - "unit" : "U", - "date" : "2016-01-31T00:00:00" - }, - { - "value" : 0.086819976677948246, - "date" : "2016-01-31T00:05:00", - "unit" : "U" - }, - { - "date" : "2016-01-31T00:10:00", - "value" : 0.064470070526203294, - "unit" : "U" - }, - { - "value" : 0.044519638347126529, - "unit" : "U", - "date" : "2016-01-31T00:15:00" - }, - { - "unit" : "U", - "date" : "2016-01-31T00:20:00", - "value" : 0.02754941281752275 - }, - { - "date" : "2016-01-31T00:25:00", - "value" : 0.013052294206175645, - "unit" : "U" - }, - { - "date" : "2016-01-31T00:30:00", - "value" : 0.0023879865475950504, - "unit" : "U" - }, - { - "date" : "2016-01-31T00:35:00", - "value" : 0.001341333728700539, - "unit" : "U" - }, - { - "unit" : "U", - "value" : 0.00041835727435857731, - "date" : "2016-01-31T00:40:00" - }, - { - "unit" : "U", - "value" : 0, - "date" : "2016-01-31T00:45:00" - }, - { - "date" : "2016-01-31T00:50:00", - "value" : 0, - "unit" : "U" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalize_edge_case_doses_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalize_edge_case_doses_input.json deleted file mode 100644 index 5f1b6aba6..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalize_edge_case_doses_input.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "type": "TempBasal", - "start_at": "2015-07-12T23:59:59", - "end_at": "2015-07-13T07:54:00", - "amount": 2.0, - "unit": "U/hour" - }, - { - "type": "Bolus", - "start_at": "2015-07-13T11:00:00", - "end_at": "2015-07-13T11:00:00", - "amount": 3.0, - "unit": "U" - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalize_edge_case_doses_mutable_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalize_edge_case_doses_mutable_input.json deleted file mode 100644 index 329f46b2c..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalize_edge_case_doses_mutable_input.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "type": "TempBasal", - "start_at": "2015-07-12T23:59:59", - "end_at": "2015-07-13T07:54:00", - "amount": 2.0, - "unit": "U/hour", - "isMutable": true - }, - { - "type": "Bolus", - "start_at": "2015-07-13T11:00:00", - "end_at": "2015-07-13T11:00:00", - "amount": 3.0, - "unit": "U", - "isMutable": true - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalize_edge_case_doses_mutable_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalize_edge_case_doses_mutable_output.json deleted file mode 100644 index 583c312a8..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalize_edge_case_doses_mutable_output.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { - "type": "TempBasal", - "start_at": "2015-07-12T23:59:59", - "end_at": "2015-07-13T00:00:00", - "amount": 1.1, - "unit": "U/hour", - "isMutable": true - }, - { - "type": "TempBasal", - "start_at": "2015-07-13T00:00:00", - "end_at": "2015-07-13T04:00:00", - "amount": 1.1, - "unit": "U/hour", - "isMutable": true - }, - { - "type": "TempBasal", - "start_at": "2015-07-13T04:00:00", - "end_at": "2015-07-13T07:00:00", - "amount": 1.075, - "unit": "U/hour", - "isMutable": true - }, - { - "type": "TempBasal", - "start_at": "2015-07-13T07:00:00", - "end_at": "2015-07-13T07:54:00", - "amount": 1.15, - "unit": "U/hour", - "isMutable": true - }, - { - "type": "Bolus", - "start_at": "2015-07-13T11:00:00", - "end_at": "2015-07-13T11:00:00", - "amount": 3.0, - "unit": "U", - "isMutable": true - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalize_edge_case_doses_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalize_edge_case_doses_output.json deleted file mode 100644 index 52f09439e..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalize_edge_case_doses_output.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "type": "TempBasal", - "start_at": "2015-07-12T23:59:59", - "end_at": "2015-07-13T00:00:00", - "amount": 1.1, - "unit": "U/hour" - }, - { - "type": "TempBasal", - "start_at": "2015-07-13T00:00:00", - "end_at": "2015-07-13T04:00:00", - "amount": 1.1, - "unit": "U/hour" - }, - { - "type": "TempBasal", - "start_at": "2015-07-13T04:00:00", - "end_at": "2015-07-13T07:00:00", - "amount": 1.075, - "unit": "U/hour" - }, - { - "type": "TempBasal", - "start_at": "2015-07-13T07:00:00", - "end_at": "2015-07-13T07:54:00", - "amount": 1.15, - "unit": "U/hour" - }, - { - "type": "Bolus", - "start_at": "2015-07-13T11:00:00", - "end_at": "2015-07-13T11:00:00", - "amount": 3.0, - "unit": "U" - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalized_doses.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalized_doses.json deleted file mode 100644 index 127adea5d..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalized_doses.json +++ /dev/null @@ -1,171 +0,0 @@ -[ - { - "amount": 3.225, - "start_at": "2015-10-15T22:00:00", - "description": "TempBasal: 3.125U/hour over 30min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T22:29:50", - "scheduled": 1.0, - "isMutable": true - }, - { - "amount": 3.325, - "start_at": "2015-10-15T21:59:50", - "description": "TempBasal: 3.125U/hour over 30min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T22:00:00", - "scheduled": 1.0 - }, - { - "amount": 1.09999999999999998, - "start_at": "2015-10-15T21:39:49", - "description": "TempBasal: 0.9U/hour over 4min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T21:43:49", - "scheduled": 1.0 - }, - { - "start_at": "2015-10-15T21:35:12", - "description": "Normal bolus: 4.0U", - "end_at": "2015-10-15T21:35:12", - "amount": 4.0, - "type": "Bolus", - "unit": "U" - }, - { - "amount": 2.075, - "start_at": "2015-10-15T21:04:34", - "description": "TempBasal: 1.875U/hour over 10min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T21:14:34", - "scheduled": 1.0 - }, - { - "amount": 2.7, - "start_at": "2015-10-15T21:00:04", - "description": "TempBasal: 2.5U/hour over 4min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T21:04:04", - "scheduled": 1.0 - }, - { - "amount": 0.0, - "start_at": "2015-10-15T20:39:52", - "description": "TempBasal: 0.0U/hour over 20min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T20:59:52", - "scheduled": 0.8 - }, - { - "amount": 0.05, - "start_at": "2015-10-15T20:34:34", - "description": "TempBasal: 0.05U/hour over 5min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T20:39:34", - "scheduled": 0.8 - }, - { - "amount": 0.95, - "start_at": "2015-10-15T20:29:51", - "description": "TempBasal: 0.75U/hour over 4min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T20:33:51", - "scheduled": 1.0 - }, - { - "amount": 1.375, - "start_at": "2015-10-15T20:14:37", - "description": "TempBasal: 1.175U/hour over 5min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T20:19:37", - "scheduled": 1.0 - }, - { - "amount": 2.075, - "start_at": "2015-10-15T20:09:52", - "description": "TempBasal: 1.875U/hour over 4min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T20:13:52", - "scheduled": 1.0 - }, - { - "start_at": "2015-10-15T20:05:10", - "description": "Normal bolus: 3.3U", - "end_at": "2015-10-15T20:05:10", - "amount": 3.3, - "type": "Bolus", - "unit": "U" - }, - { - "amount": 3.7, - "start_at": "2015-10-15T19:54:51", - "description": "TempBasal: 3.5U/hour over 15min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T20:09:51", - "scheduled": 1.0 - }, - { - "start_at": "2015-10-15T19:25:54", - "description": "Normal bolus: 5.0U", - "end_at": "2015-10-15T19:25:54", - "amount": 5.0, - "type": "Bolus", - "unit": "U" - }, - { - "amount": 3.7, - "start_at": "2015-10-15T19:24:52", - "description": "TempBasal: 3.5U/hour over 29min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T19:53:52", - "scheduled": 1.0 - }, - { - "amount": 0.4, - "start_at": "2015-10-15T19:19:39", - "description": "TempBasal: 0.2U/hour over 5min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T19:24:39", - "scheduled": 1.0 - }, - { - "amount": 0.2, - "start_at": "2015-10-15T19:00:07", - "description": "TempBasal: 0.0U/hour over 19min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T19:19:07", - "scheduled": 1.0 - }, - { - "amount": 0.0, - "start_at": "2015-10-15T18:14:54", - "description": "TempBasal: 0.0U/hour over 30min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T18:44:54", - "scheduled": 0.8 - }, - { - "amount": 0.775, - "start_at": "2015-10-15T18:09:35", - "description": "TempBasal: 0.575U/hour over 5min", - "type": "TempBasal", - "unit": "U/hour", - "end_at": "2015-10-15T18:14:35", - "scheduled": 1.0 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalized_reservoir_history_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalized_reservoir_history_output.json deleted file mode 100644 index 131d0cc93..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/normalized_reservoir_history_output.json +++ /dev/null @@ -1,434 +0,0 @@ -[ - { - "start_at" : "2016-01-30T20:30:43", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:35:41", - "type" : "TempBasal", - "amount" : 0.90604026845637575, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T20:25:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:30:43", - "type" : "TempBasal", - "amount" : 0.89700996677740863, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T20:20:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:25:42", - "type" : "TempBasal", - "amount" : 0.60000000000000009, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T20:15:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:20:42", - "type" : "TempBasal", - "amount" : 14.352159468438538, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T20:10:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:15:41", - "type" : "TempBasal", - "amount" : 3.0100334448160533, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T20:05:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:10:42", - "type" : "TempBasal", - "amount" : 2.4000000000000004, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T20:00:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:05:42", - "type" : "TempBasal", - "amount" : 2.9900332225913622, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T19:55:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T20:00:41", - "type" : "TempBasal", - "amount" : 1.8, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T19:50:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:55:41", - "type" : "TempBasal", - "amount" : 2.4000000000000004, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T19:45:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:50:41", - "type" : "TempBasal", - "amount" : 1.2000000000000002, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T19:40:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:45:41", - "type" : "TempBasal", - "amount" : 0.90000000000000002, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T19:35:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:40:41", - "type" : "TempBasal", - "amount" : 9.6321070234113702, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T19:25:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:35:42", - "type" : "TempBasal", - "amount" : 4.2000000000000002, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T19:20:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:25:42", - "type" : "TempBasal", - "amount" : 0.60000000000000009, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T19:15:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:20:42", - "type" : "TempBasal", - "amount" : 0.90000000000000002, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T19:10:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:15:42", - "type" : "TempBasal", - "amount" : 0.89700996677740863, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T19:05:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:10:41", - "type" : "TempBasal", - "amount" : 0.60200668896321063, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T19:00:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:05:42", - "type" : "TempBasal", - "amount" : 0.90000000000000002, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T18:55:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T19:00:42", - "type" : "TempBasal", - "amount" : 0.89700996677740863, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T18:50:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:55:41", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T18:45:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:50:41", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T18:40:43", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:45:41", - "type" : "TempBasal", - "amount" : 0.30201342281879195, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T18:35:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:40:43", - "type" : "TempBasal", - "amount" : 0.59602649006622521, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T18:30:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:35:41", - "type" : "TempBasal", - "amount" : 0.9030100334448159, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T18:25:43", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:30:42", - "type" : "TempBasal", - "amount" : 0.9030100334448159, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T18:20:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:25:43", - "type" : "TempBasal", - "amount" : 0.89700996677740863, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T18:10:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:15:44", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T18:05:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:10:42", - "type" : "TempBasal", - "amount" : 0.30000000000000004, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T18:00:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:05:42", - "type" : "TempBasal", - "amount" : 16.5, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T17:55:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T18:00:42", - "type" : "TempBasal", - "amount" : 0.90000000000000002, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T17:50:44", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:55:42", - "type" : "TempBasal", - "amount" : 0.60402684563758391, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T17:45:44", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:50:44", - "type" : "TempBasal", - "amount" : 0.90000000000000002, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T17:40:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:45:44", - "type" : "TempBasal", - "amount" : 1.7880794701986755, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T17:35:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:40:42", - "type" : "TempBasal", - "amount" : 1.2000000000000002, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T17:30:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:35:42", - "type" : "TempBasal", - "amount" : 1.7940199335548173, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T17:25:43", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:30:41", - "type" : "TempBasal", - "amount" : 1.8120805369127515, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T17:20:44", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:25:43", - "type" : "TempBasal", - "amount" : 0.60200668896321063, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T17:15:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:20:44", - "type" : "TempBasal", - "amount" : 0.89403973509933776, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T17:10:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:15:42", - "type" : "TempBasal", - "amount" : 0.89700996677740863, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T17:05:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:10:41", - "type" : "TempBasal", - "amount" : 0.60200668896321063, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T17:00:45", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:05:42", - "type" : "TempBasal", - "amount" : 46.969696969696969, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T16:50:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T17:00:45", - "type" : "TempBasal", - "amount" : 2.9850746268656714, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T16:45:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:50:42", - "type" : "TempBasal", - "amount" : 2.4000000000000004, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T16:40:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:45:42", - "type" : "TempBasal", - "amount" : 2.4000000000000004, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T16:35:43", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:40:42", - "type" : "TempBasal", - "amount" : 3.0100334448160533, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T16:30:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:35:43", - "type" : "TempBasal", - "amount" : 1.7940199335548173, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T16:25:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:30:42", - "type" : "TempBasal", - "amount" : 1.8, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T16:20:41", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:25:42", - "type" : "TempBasal", - "amount" : 0.59800664451827246, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T16:15:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:20:41", - "type" : "TempBasal", - "amount" : 0.9030100334448159, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T16:10:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:15:42", - "type" : "TempBasal", - "amount" : 0.90000000000000002, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T16:05:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:10:42", - "type" : "TempBasal", - "amount" : 0.60000000000000009, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T16:00:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T16:05:42", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T15:45:42", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T15:50:42", - "type" : "TempBasal", - "amount" : 0, - "unit" : "U/hour" - }, - { - "start_at" : "2016-01-30T15:40:49", - "scheduled" : 0.80000000000000004, - "end_at" : "2016-01-30T15:45:42", - "type" : "TempBasal", - "amount" : 2.4573378839590441, - "unit" : "U/hour" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reconcile_history_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reconcile_history_input.json deleted file mode 100644 index 90a5c3742..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reconcile_history_input.json +++ /dev/null @@ -1,409 +0,0 @@ -[ - { - "amount": 15, - "description": "JournalEntryMealMarker: 15g", - "end_at": "2016-02-15T14:55:49", - "start_at": "2016-02-15T14:55:49", - "type": "Meal", - "unit": "g" - }, - { - "amount": 3.5, - "description": "TempBasal: 3.5U/hour over 30min", - "end_at": "2016-02-15T15:28:02", - "start_at": "2016-02-15T14:58:02", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB0" - }, - { - "amount": 3.5, - "description": "TempBasal: 3.5U/hour over 30min", - "end_at": "2016-02-15T15:36:05", - "start_at": "2016-02-15T15:06:05", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB1" - }, - { - "amount": 2.15, - "description": "Normal bolus: 2.15U", - "end_at": "2016-02-15T15:18:56", - "start_at": "2016-02-15T15:18:56", - "type": "Bolus", - "unit": "U", - "raw": "B2" - }, - { - "amount": 2.25, - "description": "TempBasal: 2.25U/hour over 30min", - "end_at": "2016-02-15T15:51:06", - "start_at": "2016-02-15T15:21:06", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB3" - }, - { - "amount": 2.6, - "description": "TempBasal: 2.6U/hour over 30min", - "end_at": "2016-02-15T15:56:05", - "start_at": "2016-02-15T15:26:05", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB4" - }, - { - "amount": 2.825, - "description": "TempBasal: 2.825U/hour over 30min", - "end_at": "2016-02-15T16:01:06", - "start_at": "2016-02-15T15:31:06", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB5" - }, - { - "amount": 2.475, - "description": "TempBasal: 2.475U/hour over 30min", - "end_at": "2016-02-15T16:06:05", - "start_at": "2016-02-15T15:36:05", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB6" - }, - { - "amount": 1.95, - "description": "TempBasal: 1.95U/hour over 30min", - "end_at": "2016-02-15T16:11:05", - "start_at": "2016-02-15T15:41:05", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB7" - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 0min", - "end_at": "2016-02-15T15:46:05", - "start_at": "2016-02-15T15:46:05", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB8" - }, - { - "amount": 24, - "description": "BolusWizard: 24g", - "end_at": "2016-02-15T15:50:08", - "start_at": "2016-02-15T15:50:08", - "type": "Meal", - "unit": "g" - }, - { - "amount": 2.4, - "description": "Normal bolus: 2.4U", - "end_at": "2016-02-15T15:50:08", - "start_at": "2016-02-15T15:50:08", - "type": "Bolus", - "unit": "U", - "raw": "B9" - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 30min", - "end_at": "2016-02-15T16:31:07", - "start_at": "2016-02-15T16:01:07", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB10" - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 30min", - "end_at": "2016-02-15T16:51:11", - "start_at": "2016-02-15T16:21:11", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB11" - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 30min", - "end_at": "2016-02-15T17:11:09", - "start_at": "2016-02-15T16:41:09", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB12" - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 30min", - "end_at": "2016-02-15T17:31:08", - "start_at": "2016-02-15T17:01:08", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB13" - }, - { - "amount": 18, - "description": "BolusWizard: 18g", - "end_at": "2016-02-15T17:05:39", - "start_at": "2016-02-15T17:05:39", - "type": "Meal", - "unit": "g" - }, - { - "amount": 1.1, - "description": "Normal bolus: 1.1U", - "end_at": "2016-02-15T17:05:39", - "start_at": "2016-02-15T17:05:39", - "type": "Bolus", - "unit": "U", - "raw": "B14" - }, - { - "amount": 3.475, - "description": "TempBasal: 3.475U/hour over 30min", - "end_at": "2016-02-15T17:41:08", - "start_at": "2016-02-15T17:11:08", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB15" - }, - { - "amount": 25, - "description": "BolusWizard: 25g", - "end_at": "2016-02-15T17:36:40", - "start_at": "2016-02-15T17:36:40", - "type": "Meal", - "unit": "g" - }, - { - "amount": 2.5, - "description": "Normal bolus: 2.5U", - "end_at": "2016-02-15T17:36:40", - "start_at": "2016-02-15T17:36:40", - "type": "Bolus", - "unit": "U", - "raw": "B16" - }, - { - "amount": 3.5, - "description": "TempBasal: 3.5U/hour over 30min", - "end_at": "2016-02-15T18:26:17", - "start_at": "2016-02-15T17:56:17", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB17" - }, - { - "amount": 3.325, - "description": "TempBasal: 3.325U/hour over 30min", - "end_at": "2016-02-15T18:31:09", - "start_at": "2016-02-15T18:01:09", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB18" - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 30min", - "end_at": "2016-02-15T18:51:11", - "start_at": "2016-02-15T18:21:11", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB19" - }, - { - "amount": 20, - "description": "BolusWizard: 20g", - "end_at": "2016-02-15T18:41:27", - "start_at": "2016-02-15T18:41:27", - "type": "Meal", - "unit": "g" - }, - { - "amount": 2.2, - "description": "Normal bolus: 2.2U", - "end_at": "2016-02-15T18:41:27", - "start_at": "2016-02-15T18:41:27", - "type": "Bolus", - "unit": "U", - "raw": "B20" - }, - { - "amount": 8, - "description": "BolusWizard: 8g", - "end_at": "2016-02-15T18:45:17", - "start_at": "2016-02-15T18:45:17", - "type": "Meal", - "unit": "g" - }, - { - "amount": 1.15, - "description": "Normal bolus: 1.15U", - "end_at": "2016-02-15T18:45:17", - "start_at": "2016-02-15T18:45:17", - "type": "Bolus", - "unit": "U", - "raw": "B21" - }, - { - "amount": 0.05, - "description": "TempBasal: 0.05U/hour over 30min", - "end_at": "2016-02-15T19:21:07", - "start_at": "2016-02-15T18:51:07", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB22" - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 30min", - "end_at": "2016-02-15T19:26:08", - "start_at": "2016-02-15T18:56:08", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB23" - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 0min", - "end_at": "2016-02-15T19:01:09", - "start_at": "2016-02-15T19:01:09", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB24" - }, - { - "amount": 0.05, - "description": "TempBasal: 0.05U/hour over 30min", - "end_at": "2016-02-15T20:01:08", - "start_at": "2016-02-15T19:31:08", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB25" - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 0min", - "end_at": "2016-02-15T19:36:11", - "start_at": "2016-02-15T19:36:11", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB26" - }, - { - "amount": 1.425, - "description": "TempBasal: 1.425U/hour over 30min", - "end_at": "2016-02-15T20:11:07", - "start_at": "2016-02-15T19:41:07", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB27" - }, - { - "amount": 1.675, - "description": "TempBasal: 1.675U/hour over 30min", - "end_at": "2016-02-15T20:16:07", - "start_at": "2016-02-15T19:46:07", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB28" - }, - { - "amount": 1.75, - "description": "TempBasal: 1.75U/hour over 30min", - "end_at": "2016-02-15T20:21:07", - "start_at": "2016-02-15T19:51:07", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB29" - }, - { - "amount": 1.95, - "description": "TempBasal: 1.95U/hour over 30min", - "end_at": "2016-02-15T20:26:09", - "start_at": "2016-02-15T19:56:09", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB30" - }, - { - "amount": 2.0, - "description": "TempBasal: 2.0U/hour over 30min", - "end_at": "2016-02-15T20:36:08", - "start_at": "2016-02-15T20:06:08", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB31" - }, - { - "amount": 2.0, - "description": "TempBasal: 2.0U/hour over 30min", - "end_at": "2016-02-15T20:41:15", - "start_at": "2016-02-15T20:11:15", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB32" - }, - { - "amount": 2.5, - "description": "TempBasal: 2.5U/hour over 30min", - "end_at": "2016-02-15T20:46:08", - "start_at": "2016-02-15T20:16:08", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB33" - }, - { - "amount": 0, - "description": "Pump Suspend", - "end_at": "2016-02-15T20:19:21", - "start_at": "2016-02-15T20:19:21", - "type": "PumpSuspend", - "unit": "U/hour", - "raw": "S34" - }, - { - "amount": 0.65, - "description": "Normal bolus: 1.15U", - "end_at": "2016-02-15T20:18:54", - "start_at": "2016-02-15T20:18:54", - "type": "Bolus", - "unit": "U", - "raw": "B35" - }, - { - "amount": 0, - "description": "Pump Resume", - "end_at": "2016-02-15T20:25:01", - "start_at": "2016-02-15T20:25:01", - "type": "PumpResume", - "unit": "U/hour", - "raw": "R36" - }, - { - "amount": 2.875, - "description": "TempBasal: 2.875U/hour over 30min", - "end_at": "2016-02-15T21:06:08", - "start_at": "2016-02-15T20:36:08", - "type": "TempBasal", - "unit": "U/hour", - "raw": "TB37" - }, - { - "amount": 2.975, - "description": "TempBasal: 2.975U/hour over 30min", - "end_at": "2016-02-15T21:11:10", - "start_at": "2016-02-15T20:41:10", - "type": "TempBasal", - "unit": "U/hour" - }, - { - "amount": 2.125, - "description": "TempBasal: 2.125U/hour over 30min", - "end_at": "2016-02-15T21:16:09", - "start_at": "2016-02-15T20:46:09", - "type": "TempBasal", - "unit": "U/hour", - "isMutable": true - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reconcile_history_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reconcile_history_output.json deleted file mode 100644 index bf0a2d842..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reconcile_history_output.json +++ /dev/null @@ -1,416 +0,0 @@ -[ - { - "amount": 15, - "description": "JournalEntryMealMarker: 15g", - "end_at": "2016-02-15T14:55:49", - "start_at": "2016-02-15T14:55:49", - "type": "Meal", - "unit": "g" - }, - { - "amount": 3.5, - "description": "TempBasal: 3.5U/hour over 30min", - "end_at": "2016-02-15T15:06:05", - "start_at": "2016-02-15T14:58:02", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB0", - "delivered": 0.45 - }, - { - "amount": 3.5, - "description": "TempBasal: 3.5U/hour over 30min", - "end_at": "2016-02-15T15:21:06", - "start_at": "2016-02-15T15:06:05", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB1", - "delivered": 0.9 - }, - { - "amount": 2.15, - "description": "Normal bolus: 2.15U", - "end_at": "2016-02-15T15:18:56", - "start_at": "2016-02-15T15:18:56", - "type": "Bolus", - "unit": "U", - "raw" : "B2", - "delivered": 2.15 - }, - { - "amount": 2.25, - "description": "TempBasal: 2.25U/hour over 30min", - "end_at": "2016-02-15T15:26:05", - "start_at": "2016-02-15T15:21:06", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB3", - "delivered": 0.2 - }, - { - "amount": 2.6, - "description": "TempBasal: 2.6U/hour over 30min", - "end_at": "2016-02-15T15:31:06", - "start_at": "2016-02-15T15:26:05", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB4", - "delivered": 0.2 - }, - { - "amount": 2.825, - "description": "TempBasal: 2.825U/hour over 30min", - "end_at": "2016-02-15T15:36:05", - "start_at": "2016-02-15T15:31:06", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB5", - "delivered": 0.25 - }, - { - "amount": 2.475, - "description": "TempBasal: 2.475U/hour over 30min", - "end_at": "2016-02-15T15:41:05", - "start_at": "2016-02-15T15:36:05", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB6", - "delivered": 0.2 - }, - { - "amount": 1.95, - "description": "TempBasal: 1.95U/hour over 30min", - "end_at": "2016-02-15T15:46:05", - "start_at": "2016-02-15T15:41:05", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB7", - "delivered": 0.15 - }, - { - "amount": 24, - "description": "BolusWizard: 24g", - "end_at": "2016-02-15T15:50:08", - "start_at": "2016-02-15T15:50:08", - "type": "Meal", - "unit": "g" - }, - { - "amount": 2.4, - "description": "Normal bolus: 2.4U", - "end_at": "2016-02-15T15:50:08", - "start_at": "2016-02-15T15:50:08", - "type": "Bolus", - "unit": "U", - "raw" : "B9", - "delivered": 2.4 - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 30min", - "end_at": "2016-02-15T16:21:11", - "start_at": "2016-02-15T16:01:07", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB10", - "delivered": 0.0 - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 30min", - "end_at": "2016-02-15T16:41:09", - "start_at": "2016-02-15T16:21:11", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB11", - "delivered": 0.0 - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 30min", - "end_at": "2016-02-15T17:01:08", - "start_at": "2016-02-15T16:41:09", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB12", - "delivered": 0.0 - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 30min", - "end_at": "2016-02-15T17:11:08", - "start_at": "2016-02-15T17:01:08", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB13", - "delivered": 0.0 - }, - { - "amount": 18, - "description": "BolusWizard: 18g", - "end_at": "2016-02-15T17:05:39", - "start_at": "2016-02-15T17:05:39", - "type": "Meal", - "unit": "g" - }, - { - "amount": 1.1, - "description": "Normal bolus: 1.1U", - "end_at": "2016-02-15T17:05:39", - "start_at": "2016-02-15T17:05:39", - "type": "Bolus", - "unit": "U", - "raw" : "B14", - "delivered": 1.1 - }, - { - "amount": 3.475, - "description": "TempBasal: 3.475U/hour over 30min", - "end_at": "2016-02-15T17:41:08", - "start_at": "2016-02-15T17:11:08", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB15", - "delivered": 1.75 - }, - { - "amount": 25, - "description": "BolusWizard: 25g", - "end_at": "2016-02-15T17:36:40", - "start_at": "2016-02-15T17:36:40", - "type": "Meal", - "unit": "g" - }, - { - "amount": 2.5, - "description": "Normal bolus: 2.5U", - "end_at": "2016-02-15T17:36:40", - "start_at": "2016-02-15T17:36:40", - "type": "Bolus", - "unit": "U", - "raw" : "B16", - "delivered": 2.5 - }, - { - "amount": 3.5, - "description": "TempBasal: 3.5U/hour over 30min", - "end_at": "2016-02-15T18:01:09", - "start_at": "2016-02-15T17:56:17", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB17", - "delivered": 0.3 - }, - { - "amount": 3.325, - "description": "TempBasal: 3.325U/hour over 30min", - "end_at": "2016-02-15T18:21:11", - "start_at": "2016-02-15T18:01:09", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB18", - "delivered": 1.1 - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 30min", - "end_at": "2016-02-15T18:51:07", - "start_at": "2016-02-15T18:21:11", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB19", - "delivered": 0.0 - }, - { - "amount": 20, - "description": "BolusWizard: 20g", - "end_at": "2016-02-15T18:41:27", - "start_at": "2016-02-15T18:41:27", - "type": "Meal", - "unit": "g" - }, - { - "amount": 2.2, - "description": "Normal bolus: 2.2U", - "end_at": "2016-02-15T18:41:27", - "start_at": "2016-02-15T18:41:27", - "type": "Bolus", - "unit": "U", - "raw" : "B20", - "delivered": 2.2 - }, - { - "amount": 8, - "description": "BolusWizard: 8g", - "end_at": "2016-02-15T18:45:17", - "start_at": "2016-02-15T18:45:17", - "type": "Meal", - "unit": "g" - }, - { - "amount": 1.15, - "description": "Normal bolus: 1.15U", - "end_at": "2016-02-15T18:45:17", - "start_at": "2016-02-15T18:45:17", - "type": "Bolus", - "unit": "U", - "raw" : "B21", - "delivered": 1.15 - }, - { - "amount": 0.05, - "description": "TempBasal: 0.05U/hour over 30min", - "end_at": "2016-02-15T18:56:08", - "start_at": "2016-02-15T18:51:07", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB22", - "delivered": 0.0 - }, - { - "amount": 0.0, - "description": "TempBasal: 0.0U/hour over 30min", - "end_at": "2016-02-15T19:01:09", - "start_at": "2016-02-15T18:56:08", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB23", - "delivered": 0.0 - }, - { - "amount": 0.05, - "description": "TempBasal: 0.05U/hour over 30min", - "end_at": "2016-02-15T19:36:11", - "start_at": "2016-02-15T19:31:08", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB25", - "delivered": 0.0 - }, - { - "amount": 1.425, - "description": "TempBasal: 1.425U/hour over 30min", - "end_at": "2016-02-15T19:46:07", - "start_at": "2016-02-15T19:41:07", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB27", - "delivered": 0.1 - }, - { - "amount": 1.675, - "description": "TempBasal: 1.675U/hour over 30min", - "end_at": "2016-02-15T19:51:07", - "start_at": "2016-02-15T19:46:07", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB28", - "delivered": 0.15 - }, - { - "amount": 1.75, - "description": "TempBasal: 1.75U/hour over 30min", - "end_at": "2016-02-15T19:56:09", - "start_at": "2016-02-15T19:51:07", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB29", - "delivered": 0.15 - }, - { - "amount": 1.95, - "description": "TempBasal: 1.95U/hour over 30min", - "end_at": "2016-02-15T20:06:08", - "start_at": "2016-02-15T19:56:09", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB30", - "delivered": 0.3 - }, - { - "amount": 2.0, - "description": "TempBasal: 2.0U/hour over 30min", - "end_at": "2016-02-15T20:11:15", - "start_at": "2016-02-15T20:06:08", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB31", - "delivered": 0.15 - }, - { - "amount": 2.0, - "description": "TempBasal: 2.0U/hour over 30min", - "end_at": "2016-02-15T20:16:08", - "start_at": "2016-02-15T20:11:15", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB32", - "delivered": 0.15 - }, - { - "amount": 2.5, - "description": "TempBasal: 2.5U/hour over 30min", - "end_at": "2016-02-15T20:19:21", - "start_at": "2016-02-15T20:16:08", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB33", - "delivered": 0.15 - }, - { - "amount": 0, - "description": "Pump Suspend", - "end_at": "2016-02-15T20:25:01", - "start_at": "2016-02-15T20:19:21", - "type": "PumpSuspend", - "unit": "U/hour", - "raw" : "S34" - }, - { - "amount": 2.5, - "description": "TempBasal: 2.5U/hour over 30min", - "end_at": "2016-02-15T20:36:08", - "start_at": "2016-02-15T20:25:01", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "R36", - "delivered": 0.45 - }, - { - "amount": 0.65, - "description": "Normal bolus: 1.15U", - "end_at": "2016-02-15T20:18:54", - "start_at": "2016-02-15T20:18:54", - "type": "Bolus", - "unit": "U", - "raw" : "B35", - "delivered": 0.65 - }, - { - "amount": 2.875, - "description": "TempBasal: 2.875U/hour over 30min", - "end_at": "2016-02-15T20:41:10", - "start_at": "2016-02-15T20:36:08", - "type": "TempBasal", - "unit": "U/hour", - "raw" : "TB37", - "delivered": 0.25 - }, - { - "amount": 2.975, - "description": "TempBasal: 2.975U/hour over 30min", - "end_at": "2016-02-15T20:46:09", - "start_at": "2016-02-15T20:41:10", - "type": "TempBasal", - "unit": "U/hour", - "delivered": 0.25 - }, - { - "amount": 2.125, - "description": "TempBasal: 2.125U/hour over 30min", - "end_at": "2016-02-15T21:16:09", - "start_at": "2016-02-15T20:46:09", - "type": "TempBasal", - "unit": "U/hour" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reconcile_resume_before_rewind_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reconcile_resume_before_rewind_input.json deleted file mode 100644 index ed03d1b62..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reconcile_resume_before_rewind_input.json +++ /dev/null @@ -1,67 +0,0 @@ -[ - { - "unit": "U/hour", - "type": "BasalProfileStart", - "description": "BasalProfileStartPumpEvent(length: 10, rawData: 10 bytes, timestamp: calendar: gregorian (fixed) year: 2017 month: 9 day: 21 hour: 6 minute: 51 second: 28 isLeapMonth: false , scheduleEntry: MinimedKi", - "start_at": "2017-09-21T06:51:28", - "end_at": "2017-09-22T06:51:28", - "amount": 1.05 - }, - { - "unit": "U/hour", - "type": "TempBasal", - "description": "TempBasalDurationPumpEvent(length: 7, rawData: 7 bytes, duration: 30, timestamp: calendar: gregorian (fixed) year: 2017 month: 9 day: 21 hour: 7 minute: 11 second: 29 isLeapMonth: false )", - "start_at": "2017-09-21T07:11:29", - "end_at": "2017-09-21T07:41:29", - "amount": 1.85 - }, - { - "unit": "U", - "type": "PumpSuspend", - "description": "SuspendPumpEvent(length: 7, rawData: 7 bytes, timestamp: calendar: gregorian (fixed) year: 2017 month: 9 day: 21 hour: 7 minute: 16 second: 48 isLeapMonth: false )", - "start_at": "2017-09-21T07:16:48", - "end_at": "2017-09-21T07:16:48", - "amount": 0 - }, - { - "unit": "U", - "type": "PumpResume", - "description": "ResumePumpEvent(length: 7, rawData: 7 bytes, timestamp: calendar: gregorian (fixed) year: 2017 month: 9 day: 21 hour: 7 minute: 23 second: 34 isLeapMonth: false )", - "start_at": "2017-09-21T07:23:34", - "end_at": "2017-09-21T07:23:34", - "amount": 0 - }, - { - "unit": "U", - "type": "PumpSuspend", - "description": "RewindPumpEvent(length: 7, rawData: 7 bytes, timestamp: calendar: gregorian (fixed) year: 2017 month: 9 day: 21 hour: 7 minute: 23 second: 40 isLeapMonth: false )", - "start_at": "2017-09-21T07:23:40", - "end_at": "2017-09-21T07:23:40", - "amount": 0 - }, - { - "unit": "U", - "type": "PumpResume", - "description": "PrimePumpEvent(length: 10, rawData: 10 bytes, timestamp: calendar: gregorian (fixed) year: 2017 month: 9 day: 21 hour: 7 minute: 25 second: 16 isLeapMonth: false , amount: 14.199999999999999, primeTyp", - "start_at": "2017-09-21T07:25:16", - "end_at": "2017-09-21T07:25:16", - "amount": 0 - }, - { - "unit": "U/hour", - "type": "BasalProfileStart", - "description": "BasalProfileStartPumpEvent(length: 10, rawData: 10 bytes, timestamp: calendar: gregorian (fixed) year: 2017 month: 9 day: 21 hour: 7 minute: 41 second: 29 isLeapMonth: false , scheduleEntry: MinimedKi", - "start_at": "2017-09-21T07:41:29", - "end_at": "2017-09-22T07:41:29", - "amount": 1.05 - }, - { - "unit": "U/hour", - "type": "TempBasal", - "description": "TempBasalDurationPumpEvent(length: 7, rawData: 7 bytes, duration: 30, timestamp: calendar: gregorian (fixed) year: 2017 month: 9 day: 21 hour: 7 minute: 42 second: 1 isLeapMonth: false )", - "start_at": "2017-09-21T07:42:01", - "end_at": "2017-09-22T08:12:01", - "amount": 2.025, - "isMutable": true - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reconcile_resume_before_rewind_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reconcile_resume_before_rewind_output.json deleted file mode 100644 index 452936598..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reconcile_resume_before_rewind_output.json +++ /dev/null @@ -1,66 +0,0 @@ -[ - { - "start_at" : "2017-09-21T06:51:28", - "end_at" : "2017-09-21T07:11:29", - "type" : "BasalProfileStart", - "amount" : 1.05, - "unit" : "U\/hour", - "delivered": 0.35029166666666667 - }, - { - "start_at" : "2017-09-21T07:11:29", - "end_at" : "2017-09-21T07:16:48", - "type" : "TempBasal", - "amount" : 1.85, - "unit" : "U\/hour", - "delivered": 0.15 - }, - { - "start_at" : "2017-09-21T07:16:48", - "end_at" : "2017-09-21T07:23:34", - "type" : "PumpSuspend", - "amount" : 0, - "unit" : "U", - "delivered": 0.0 - }, - { - "start_at" : "2017-09-21T07:23:34", - "end_at" : "2017-09-21T07:23:40", - "type" : "TempBasal", - "amount" : 1.85, - "unit" : "U\/hour", - "delivered": 0.0 - }, - { - "start_at" : "2017-09-21T07:23:40", - "end_at" : "2017-09-21T07:25:16", - "type" : "PumpSuspend", - "amount" : 0, - "unit" : "U", - "delivered": 0.0 - }, - { - "start_at" : "2017-09-21T07:25:16", - "end_at" : "2017-09-21T07:41:29", - "type" : "TempBasal", - "amount" : 1.85, - "unit" : "U\/hour", - "delivered": 0.5 - }, - { - "start_at" : "2017-09-21T07:41:29", - "end_at" : "2017-09-21T07:42:01", - "type" : "BasalProfileStart", - "amount" : 1.05, - "unit" : "U\/hour", - "delivered": 0.009333333333333334 - }, - { - "start_at" : "2017-09-21T07:42:01", - "end_at" : "2017-09-22T08:12:01", - "type" : "TempBasal", - "amount" : 2.025, - "unit" : "U\/hour", - "isMutable": true - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_for_iob_missing.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_for_iob_missing.json deleted file mode 100644 index c59a379be..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_for_iob_missing.json +++ /dev/null @@ -1,28 +0,0 @@ -[ -{ "date": "2023-01-08T17:18:14", "amount": 133.475, "unit": "U"}, -{ "date": "2023-01-08T17:13:14", "amount": 133.525, "unit": "U"}, -{ "date": "2023-01-08T17:08:14", "amount": 135.4, "unit": "U"}, -{ "date": "2023-01-08T17:03:13", "amount": 140.3, "unit": "U"}, -{ "date": "2023-01-08T16:58:13", "amount": 140.35, "unit": "U"}, -{ "date": "2023-01-08T16:53:13", "amount": 140.4, "unit": "U"}, -{ "date": "2023-01-08T16:48:14", "amount": 140.5, "unit": "U"}, -{ "date": "2023-01-08T16:43:14", "amount": 140.55, "unit": "U"}, -{ "date": "2023-01-08T16:38:14", "amount": 140.65, "unit": "U"}, -{ "date": "2023-01-08T16:33:14", "amount": 140.75, "unit": "U"}, -{ "date": "2023-01-08T16:28:14", "amount": 140.85, "unit": "U"}, -{ "date": "2023-01-08T16:23:14", "amount": 140.9, "unit": "U"}, -{ "date": "2023-01-08T16:18:14", "amount": 141.0, "unit": "U"}, -{ "date": "2023-01-08T16:13:14", "amount": 141.1, "unit": "U"}, -{ "date": "2023-01-08T16:08:14", "amount": 141.2, "unit": "U"}, -{ "date": "2023-01-08T16:03:14", "amount": 141.25, "unit": "U"}, -{ "date": "2023-01-08T15:58:14", "amount": 141.35, "unit": "U"}, -{ "date": "2023-01-08T15:53:14", "amount": 141.45, "unit": "U"}, -{ "date": "2023-01-08T15:48:14", "amount": 141.55, "unit": "U"}, -{ "date": "2023-01-08T15:43:14", "amount": 141.6, "unit": "U"}, -{ "date": "2023-01-08T15:38:14", "amount": 141.7, "unit": "U"}, -{ "date": "2023-01-08T15:33:14", "amount": 141.8, "unit": "U"}, -{ "date": "2023-01-08T15:28:14", "amount": 141.95, "unit": "U"}, -{ "date": "2023-01-08T15:23:14", "amount": 142.125, "unit": "U"}, -{ "date": "2023-01-08T15:18:14", "amount": 142.4, "unit": "U"}, -{ "date": "2023-01-08T15:13:14", "amount": 142.5, "unit": "U"} -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_history_with_continuity_holes.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_history_with_continuity_holes.json deleted file mode 100644 index 7dc9768e4..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_history_with_continuity_holes.json +++ /dev/null @@ -1,177 +0,0 @@ -[ - { - "date": "2016-01-30T15:40:49", - "amount": 0.2, - "unit": "U" - }, - { - "date": "2016-01-30T15:45:42", - "amount": 0.0, - "unit": "U" - }, - { - "date": "2016-01-30T15:50:42", - "amount": 0.0, - "unit": "U" - }, - { - "date": "2016-01-30T15:55:41", - "amount": 294.0, - "unit": "U" - }, - { - "date": "2016-01-30T16:00:42", - "amount": 145.75, - "unit": "U" - }, - { - "date": "2016-01-30T16:05:42", - "amount": 145.75, - "unit": "U" - }, - { - "date": "2016-01-30T16:10:42", - "amount": 145.7, - "unit": "U" - }, - { - "date": "2016-01-30T16:15:42", - "amount": 145.625, - "unit": "U" - }, - { - "date": "2016-01-30T16:20:41", - "amount": 145.55, - "unit": "U" - }, - { - "date": "2016-01-30T16:25:42", - "amount": 145.5, - "unit": "U" - }, - { - "date": "2016-01-30T16:30:42", - "amount": 145.35, - "unit": "U" - }, - { - "date": "2016-01-30T16:35:43", - "amount": 145.2, - "unit": "U" - }, - { - "date": "2016-01-30T16:40:42", - "amount": 144.95, - "unit": "U" - }, - { - "date": "2016-01-30T16:45:42", - "amount": 144.75, - "unit": "U" - }, - { - "date": "2016-01-30T16:50:42", - "amount": 144.55, - "unit": "U" - }, - { - "date": "2016-01-30T17:00:45", - "amount": 144.05, - "unit": "U" - }, - { - "date": "2016-01-30T17:05:42", - "amount": 140.175, - "unit": "U" - }, - { - "date": "2016-01-30T17:10:41", - "amount": 140.125, - "unit": "U" - }, - { - "date": "2016-01-30T17:15:42", - "amount": 140.05, - "unit": "U" - }, - { - "date": "2016-01-30T17:20:44", - "amount": 139.975, - "unit": "U" - }, - { - "date": "2016-01-30T17:25:43", - "amount": 139.925, - "unit": "U" - }, - { - "date": "2016-01-30T17:30:41", - "amount": 139.775, - "unit": "U" - }, - { - "date": "2016-01-30T17:35:42", - "amount": 139.625, - "unit": "U" - }, - { - "date": "2016-01-30T17:40:42", - "amount": 139.525, - "unit": "U" - }, - { - "date": "2016-01-30T18:15:44", - "amount": 137.775, - "unit": "U" - }, - { - "date": "2016-01-30T18:20:42", - "amount": 137.775, - "unit": "U" - }, - { - "date": "2016-01-30T18:25:43", - "amount": 137.725, - "unit": "U" - }, - { - "date": "2016-01-30T18:30:42", - "amount": 137.65, - "unit": "U" - }, - { - "date": "2016-01-30T19:00:42", - "amount": 137.425, - "unit": "U" - }, - { - "date": "2016-01-30T19:10:41", - "amount": 137.3, - "unit": "U" - }, - { - "date": "2016-01-30T19:35:42", - "amount": 136.4, - "unit": "U" - }, - { - "date": "2016-01-30T20:00:41", - "amount": 135.075, - "unit": "U" - }, - { - "date": "2016-01-30T20:25:42", - "amount": 133.125, - "unit": "U" - }, - { - "date": "2016-01-30T20:30:43", - "amount": 133.05, - "unit": "U" - }, - { - "date": "2016-01-30T20:35:41", - "amount": 132.975, - "unit": "U" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_history_with_rewind_and_prime_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_history_with_rewind_and_prime_input.json deleted file mode 100644 index 77165e508..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_history_with_rewind_and_prime_input.json +++ /dev/null @@ -1,292 +0,0 @@ -[ - { - "date": "2016-01-30T15:40:49", - "amount": 0.4, - "unit": "U" - }, - { - "date": "2016-01-30T15:45:42", - "amount": 0.2, - "unit": "U" - }, - { - "date": "2016-01-30T15:50:42", - "amount": 0.2, - "unit": "U" - }, - { - "date": "2016-01-30T15:55:41", - "amount": 294.0, - "unit": "U" - }, - { - "date": "2016-01-30T16:00:42", - "amount": 145.75, - "unit": "U" - }, - { - "date": "2016-01-30T16:05:42", - "amount": 145.75, - "unit": "U" - }, - { - "date": "2016-01-30T16:10:42", - "amount": 145.7, - "unit": "U" - }, - { - "date": "2016-01-30T16:15:42", - "amount": 145.625, - "unit": "U" - }, - { - "date": "2016-01-30T16:20:41", - "amount": 145.55, - "unit": "U" - }, - { - "date": "2016-01-30T16:25:42", - "amount": 145.5, - "unit": "U" - }, - { - "date": "2016-01-30T16:30:42", - "amount": 145.35, - "unit": "U" - }, - { - "date": "2016-01-30T16:35:43", - "amount": 145.2, - "unit": "U" - }, - { - "date": "2016-01-30T16:40:42", - "amount": 144.95, - "unit": "U" - }, - { - "date": "2016-01-30T16:45:42", - "amount": 144.75, - "unit": "U" - }, - { - "date": "2016-01-30T16:50:42", - "amount": 144.55, - "unit": "U" - }, - { - "date": "2016-01-30T17:00:45", - "amount": 144.05, - "unit": "U" - }, - { - "date": "2016-01-30T17:05:42", - "amount": 140.175, - "unit": "U" - }, - { - "date": "2016-01-30T17:10:41", - "amount": 140.125, - "unit": "U" - }, - { - "date": "2016-01-30T17:15:42", - "amount": 140.05, - "unit": "U" - }, - { - "date": "2016-01-30T17:20:44", - "amount": 139.975, - "unit": "U" - }, - { - "date": "2016-01-30T17:25:43", - "amount": 139.925, - "unit": "U" - }, - { - "date": "2016-01-30T17:30:41", - "amount": 139.775, - "unit": "U" - }, - { - "date": "2016-01-30T17:35:42", - "amount": 139.625, - "unit": "U" - }, - { - "date": "2016-01-30T17:40:42", - "amount": 139.525, - "unit": "U" - }, - { - "date": "2016-01-30T17:45:44", - "amount": 139.375, - "unit": "U" - }, - { - "date": "2016-01-30T17:50:44", - "amount": 139.3, - "unit": "U" - }, - { - "date": "2016-01-30T17:55:42", - "amount": 139.25, - "unit": "U" - }, - { - "date": "2016-01-30T18:00:42", - "amount": 139.175, - "unit": "U" - }, - { - "date": "2016-01-30T18:05:42", - "amount": 137.8, - "unit": "U" - }, - { - "date": "2016-01-30T18:10:42", - "amount": 137.775, - "unit": "U" - }, - { - "date": "2016-01-30T18:15:44", - "amount": 137.775, - "unit": "U" - }, - { - "date": "2016-01-30T18:20:42", - "amount": 137.8, - "unit": "U" - }, - { - "date": "2016-01-30T18:25:43", - "amount": 137.725, - "unit": "U" - }, - { - "date": "2016-01-30T18:30:42", - "amount": 137.65, - "unit": "U" - }, - { - "date": "2016-01-30T18:35:41", - "amount": 137.575, - "unit": "U" - }, - { - "date": "2016-01-30T18:40:43", - "amount": 137.525, - "unit": "U" - }, - { - "date": "2016-01-30T18:45:41", - "amount": 137.5, - "unit": "U" - }, - { - "date": "2016-01-30T18:50:41", - "amount": 137.5, - "unit": "U" - }, - { - "date": "2016-01-30T18:55:41", - "amount": 137.5, - "unit": "U" - }, - { - "date": "2016-01-30T19:00:42", - "amount": 137.425, - "unit": "U" - }, - { - "date": "2016-01-30T19:05:42", - "amount": 137.35, - "unit": "U" - }, - { - "date": "2016-01-30T19:10:41", - "amount": 137.3, - "unit": "U" - }, - { - "date": "2016-01-30T19:15:42", - "amount": 137.225, - "unit": "U" - }, - { - "date": "2016-01-30T19:20:42", - "amount": 137.15, - "unit": "U" - }, - { - "date": "2016-01-30T19:25:42", - "amount": 137.1, - "unit": "U" - }, - { - "date": "2016-01-30T19:35:42", - "amount": 136.4, - "unit": "U" - }, - { - "date": "2016-01-30T19:40:41", - "amount": 135.6, - "unit": "U" - }, - { - "date": "2016-01-30T19:45:41", - "amount": 135.525, - "unit": "U" - }, - { - "date": "2016-01-30T19:50:41", - "amount": 135.425, - "unit": "U" - }, - { - "date": "2016-01-30T19:55:41", - "amount": 135.225, - "unit": "U" - }, - { - "date": "2016-01-30T20:00:41", - "amount": 135.075, - "unit": "U" - }, - { - "date": "2016-01-30T20:05:42", - "amount": 134.825, - "unit": "U" - }, - { - "date": "2016-01-30T20:10:42", - "amount": 134.625, - "unit": "U" - }, - { - "date": "2016-01-30T20:15:41", - "amount": 134.375, - "unit": "U" - }, - { - "date": "2016-01-30T20:20:42", - "amount": 133.175, - "unit": "U" - }, - { - "date": "2016-01-30T20:25:42", - "amount": 133.125, - "unit": "U" - }, - { - "date": "2016-01-30T20:30:43", - "amount": 133.05, - "unit": "U" - }, - { - "date": "2016-01-30T20:35:41", - "amount": 132.975, - "unit": "U" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_history_with_rewind_and_prime_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_history_with_rewind_and_prime_output.json deleted file mode 100644 index ff5dbd2ae..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_history_with_rewind_and_prime_output.json +++ /dev/null @@ -1,434 +0,0 @@ -[ - { - "amount": 0.075, - "start_at": "2016-01-30T20:30:43", - "description": "Reservoir decreased 0.075U over 4.97min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T20:35:41" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T20:25:42", - "description": "Reservoir decreased 0.075U over 5.02min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T20:30:43" - }, - { - "amount": 0.05, - "start_at": "2016-01-30T20:20:42", - "description": "Reservoir decreased 0.05U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T20:25:42" - }, - { - "amount": 1.2, - "start_at": "2016-01-30T20:15:41", - "description": "Reservoir decreased 1.2U over 5.02min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T20:20:42" - }, - { - "amount": 0.25, - "start_at": "2016-01-30T20:10:42", - "description": "Reservoir decreased 0.25U over 4.98min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T20:15:41" - }, - { - "amount": 0.2, - "start_at": "2016-01-30T20:05:42", - "description": "Reservoir decreased 0.2U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T20:10:42" - }, - { - "amount": 0.25, - "start_at": "2016-01-30T20:00:41", - "description": "Reservoir decreased 0.25U over 5.02min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T20:05:42" - }, - { - "amount": 0.15, - "start_at": "2016-01-30T19:55:41", - "description": "Reservoir decreased 0.15U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T20:00:41" - }, - { - "amount": 0.2, - "start_at": "2016-01-30T19:50:41", - "description": "Reservoir decreased 0.2U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T19:55:41" - }, - { - "amount": 0.1, - "start_at": "2016-01-30T19:45:41", - "description": "Reservoir decreased 0.1U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T19:50:41" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T19:40:41", - "description": "Reservoir decreased 0.075U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T19:45:41" - }, - { - "amount": 0.80, - "start_at": "2016-01-30T19:35:42", - "description": "Reservoir decreased 0.80U over 4.98min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T19:40:41" - }, - { - "amount": 0.7, - "start_at": "2016-01-30T19:25:42", - "description": "Reservoir decreased 0.7U over 10.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T19:35:42" - }, - { - "amount": 0.05, - "start_at": "2016-01-30T19:20:42", - "description": "Reservoir decreased 0.05U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T19:25:42" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T19:15:42", - "description": "Reservoir decreased 0.075U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T19:20:42" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T19:10:41", - "description": "Reservoir decreased 0.075U over 5.02min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T19:15:42" - }, - { - "amount": 0.05, - "start_at": "2016-01-30T19:05:42", - "description": "Reservoir decreased 0.05U over 4.98min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T19:10:41" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T19:00:42", - "description": "Reservoir decreased 0.075U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T19:05:42" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T18:55:41", - "description": "Reservoir decreased 0.075U over 5.02min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T19:00:42" - }, - { - "amount": 0.0, - "start_at": "2016-01-30T18:50:41", - "description": "Reservoir decreased 0.0U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T18:55:41" - }, - { - "amount": 0.0, - "start_at": "2016-01-30T18:45:41", - "description": "Reservoir decreased 0.0U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T18:50:41" - }, - { - "amount": 0.025, - "start_at": "2016-01-30T18:40:43", - "description": "Reservoir decreased 0.025U over 4.97min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T18:45:41" - }, - { - "amount": 0.05, - "start_at": "2016-01-30T18:35:41", - "description": "Reservoir decreased 0.05U over 5.03min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T18:40:43" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T18:30:42", - "description": "Reservoir decreased 0.075U over 4.98min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T18:35:41" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T18:25:43", - "description": "Reservoir decreased 0.075U over 4.98min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T18:30:42" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T18:20:42", - "description": "Reservoir decreased 0.075U over 5.02min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T18:25:43" - }, - { - "amount": 0.0, - "start_at": "2016-01-30T18:10:42", - "description": "Reservoir decreased 0.0U over 5.03min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T18:15:44" - }, - { - "amount": 0.025, - "start_at": "2016-01-30T18:05:42", - "description": "Reservoir decreased 0.025U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T18:10:42" - }, - { - "amount": 1.375, - "start_at": "2016-01-30T18:00:42", - "description": "Reservoir decreased 1.375U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T18:05:42" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T17:55:42", - "description": "Reservoir decreased 0.075U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T18:00:42" - }, - { - "amount": 0.05, - "start_at": "2016-01-30T17:50:44", - "description": "Reservoir decreased 0.05U over 4.97min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T17:55:42" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T17:45:44", - "description": "Reservoir decreased 0.075U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T17:50:44" - }, - { - "amount": 0.15, - "start_at": "2016-01-30T17:40:42", - "description": "Reservoir decreased 0.15U over 5.03min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T17:45:44" - }, - { - "amount": 0.1, - "start_at": "2016-01-30T17:35:42", - "description": "Reservoir decreased 0.1U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T17:40:42" - }, - { - "amount": 0.15, - "start_at": "2016-01-30T17:30:41", - "description": "Reservoir decreased 0.15U over 5.02min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T17:35:42" - }, - { - "amount": 0.15, - "start_at": "2016-01-30T17:25:43", - "description": "Reservoir decreased 0.15U over 4.97min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T17:30:41" - }, - { - "amount": 0.05, - "start_at": "2016-01-30T17:20:44", - "description": "Reservoir decreased 0.05U over 4.98min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T17:25:43" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T17:15:42", - "description": "Reservoir decreased 0.075U over 5.03min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T17:20:44" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T17:10:41", - "description": "Reservoir decreased 0.075U over 5.02min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T17:15:42" - }, - { - "amount": 0.05, - "start_at": "2016-01-30T17:05:42", - "description": "Reservoir decreased 0.05U over 4.98min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T17:10:41" - }, - { - "amount": 3.875, - "start_at": "2016-01-30T17:00:45", - "description": "Reservoir decreased 3.875U over 4.95min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T17:05:42" - }, - { - "amount": 0.5, - "start_at": "2016-01-30T16:50:42", - "description": "Reservoir decreased 0.5U over 10.05min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T17:00:45" - }, - { - "amount": 0.2, - "start_at": "2016-01-30T16:45:42", - "description": "Reservoir decreased 0.2U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T16:50:42" - }, - { - "amount": 0.2, - "start_at": "2016-01-30T16:40:42", - "description": "Reservoir decreased 0.2U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T16:45:42" - }, - { - "amount": 0.25, - "start_at": "2016-01-30T16:35:43", - "description": "Reservoir decreased 0.25U over 4.98min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T16:40:42" - }, - { - "amount": 0.15, - "start_at": "2016-01-30T16:30:42", - "description": "Reservoir decreased 0.15U over 5.02min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T16:35:43" - }, - { - "amount": 0.15, - "start_at": "2016-01-30T16:25:42", - "description": "Reservoir decreased 0.15U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T16:30:42" - }, - { - "amount": 0.05, - "start_at": "2016-01-30T16:20:41", - "description": "Reservoir decreased 0.05U over 5.02min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T16:25:42" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T16:15:42", - "description": "Reservoir decreased 0.075U over 4.98min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T16:20:41" - }, - { - "amount": 0.075, - "start_at": "2016-01-30T16:10:42", - "description": "Reservoir decreased 0.075U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T16:15:42" - }, - { - "amount": 0.05, - "start_at": "2016-01-30T16:05:42", - "description": "Reservoir decreased 0.05U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T16:10:42" - }, - { - "amount": 0.0, - "start_at": "2016-01-30T16:00:42", - "description": "Reservoir decreased 0.0U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T16:05:42" - }, - { - "amount": 0.0, - "start_at": "2016-01-30T15:45:42", - "description": "Reservoir decreased 0.0U over 5.00min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T15:50:42" - }, - { - "amount": 0.2, - "start_at": "2016-01-30T15:40:49", - "description": "Reservoir decreased 0.2U over 4.88min", - "type": "TempBasal", - "unit": "U", - "end_at": "2016-01-30T15:45:42" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_iob_test.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_iob_test.json deleted file mode 100644 index c878ce1f6..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/reservoir_iob_test.json +++ /dev/null @@ -1,58 +0,0 @@ -[ -{ "date": "2022-09-05T02:00:22", "amount": 41.1, "unit": "U" }, -{ "date": "2022-09-05T01:55:16", "amount": 41.1, "unit": "U" }, -{ "date": "2022-09-05T01:50:03", "amount": 43.1, "unit": "U" }, -{ "date": "2022-09-05T01:45:17", "amount": 43.5, "unit": "U" }, -{ "date": "2022-09-05T01:36:13", "amount": 43.5, "unit": "U" }, -{ "date": "2022-09-05T01:25:25", "amount": 43.5, "unit": "U" }, -{ "date": "2022-09-05T01:20:15", "amount": 43.5, "unit": "U" }, -{ "date": "2022-09-05T01:15:15", "amount": 43.5, "unit": "U" }, -{ "date": "2022-09-05T01:05:31", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T01:05:24", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T01:00:24", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:55:19", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:55:15", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:50:20", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:50:16", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:45:22", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:40:18", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:35:22", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:30:19", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:25:15", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:20:13", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:15:27", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:15:24", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:10:21", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:10:17", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:05:15", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-05T00:00:59", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-04T23:54:49", "amount": 43.6, "unit": "U" }, -{ "date": "2022-09-04T23:50:15", "amount": 44.1, "unit": "U" }, -{ "date": "2022-09-04T23:45:16", "amount": 44.2, "unit": "U" }, -{ "date": "2022-09-04T23:40:18", "amount": 44.2, "unit": "U" }, -{ "date": "2022-09-04T23:35:15", "amount": 44.3, "unit": "U" }, -{ "date": "2022-09-04T23:30:27", "amount": 44.5, "unit": "U" }, -{ "date": "2022-09-04T23:30:24", "amount": 44.5, "unit": "U" }, -{ "date": "2022-09-04T23:25:19", "amount": 44.5, "unit": "U" }, -{ "date": "2022-09-04T23:25:15", "amount": 44.5, "unit": "U" }, -{ "date": "2022-09-04T23:20:03", "amount": 44.9, "unit": "U" }, -{ "date": "2022-09-04T23:15:17", "amount": 47.9, "unit": "U" }, -{ "date": "2022-09-04T23:10:17", "amount": 47.9, "unit": "U" }, -{ "date": "2022-09-04T23:05:15", "amount": 47.9, "unit": "U" }, -{ "date": "2022-09-04T23:00:15", "amount": 47.9, "unit": "U" }, -{ "date": "2022-09-04T22:55:17", "amount": 48.0, "unit": "U" }, -{ "date": "2022-09-04T22:55:13", "amount": 48.0, "unit": "U" }, -{ "date": "2022-09-04T22:50:15", "amount": 48.0, "unit": "U" }, -{ "date": "2022-09-04T22:45:19", "amount": 48.1, "unit": "U" }, -{ "date": "2022-09-04T22:45:15", "amount": 48.1, "unit": "U" }, -{ "date": "2022-09-04T22:40:02", "amount": 48.9, "unit": "U" }, -{ "date": "2022-09-04T22:35:15", "amount": 49.1, "unit": "U" }, -{ "date": "2022-09-04T22:30:15", "amount": 49.1, "unit": "U" }, -{ "date": "2022-09-04T22:25:13", "amount": 49.1, "unit": "U" }, -{ "date": "2022-09-04T22:20:19", "amount": 49.1, "unit": "U" }, -{ "date": "2022-09-04T22:15:16", "amount": 49.1, "unit": "U" }, -{ "date": "2022-09-04T22:10:15", "amount": 49.1, "unit": "U" }, -{ "date": "2022-09-04T22:05:25", "amount": 49.1, "unit": "U" }, -{ "date": "2022-09-04T22:05:22", "amount": 49.1, "unit": "U" }, -{ "date": "2022-09-04T22:00:04", "amount": 49.1, "unit": "U" } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/short_basal_dose.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/short_basal_dose.json deleted file mode 100644 index 35ce6f1a0..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/short_basal_dose.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "type": "TempBasal", - "start_at": "2015-07-13T12:01:32", - "end_at": "2015-07-13T12:06:32", - "amount": 18.0, - "unit": "U/hour", - "scheduled": 0.0 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/suspend_dose.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/suspend_dose.json deleted file mode 100644 index 513f3c68b..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/suspend_dose.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "type": "PumpSuspend", - "start_at": "2015-07-13T12:00:00", - "end_at": "2015-07-13T12:00:00", - "amount": 0.0, - "unit": "U" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/suspend_dose_reconciled.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/suspend_dose_reconciled.json deleted file mode 100644 index 513f3c68b..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/suspend_dose_reconciled.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "type": "PumpSuspend", - "start_at": "2015-07-13T12:00:00", - "end_at": "2015-07-13T12:00:00", - "amount": 0.0, - "unit": "U" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/suspend_dose_reconciled_normalized.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/suspend_dose_reconciled_normalized.json deleted file mode 100644 index 5d59b54ed..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/suspend_dose_reconciled_normalized.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "type": "TempBasal", - "start_at": "2015-07-13T12:00:00", - "end_at": "2015-07-13T12:00:00", - "amount": -0.75, - "unit": "U/hour" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/suspend_dose_reconciled_normalized_iob.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/suspend_dose_reconciled_normalized_iob.json deleted file mode 100644 index 2b0f383a4..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/InsulinKit/suspend_dose_reconciled_normalized_iob.json +++ /dev/null @@ -1 +0,0 @@ -[{"unit":"U","date":"2015-07-13T12:00:00","value":0},{"unit":"U","date":"2015-07-13T12:05:00","value":0},{"unit":"U","date":"2015-07-13T12:10:00","value":0},{"unit":"U","date":"2015-07-13T12:15:00","value":0},{"unit":"U","date":"2015-07-13T12:20:00","value":0},{"unit":"U","date":"2015-07-13T12:25:00","value":0},{"unit":"U","date":"2015-07-13T12:30:00","value":0},{"unit":"U","date":"2015-07-13T12:35:00","value":0},{"unit":"U","date":"2015-07-13T12:40:00","value":0},{"unit":"U","date":"2015-07-13T12:45:00","value":0},{"unit":"U","date":"2015-07-13T12:50:00","value":0},{"unit":"U","date":"2015-07-13T12:55:00","value":0},{"unit":"U","date":"2015-07-13T13:00:00","value":0},{"unit":"U","date":"2015-07-13T13:05:00","value":0},{"unit":"U","date":"2015-07-13T13:10:00","value":0},{"unit":"U","date":"2015-07-13T13:15:00","value":0},{"unit":"U","date":"2015-07-13T13:20:00","value":0},{"unit":"U","date":"2015-07-13T13:25:00","value":0},{"unit":"U","date":"2015-07-13T13:30:00","value":0},{"unit":"U","date":"2015-07-13T13:35:00","value":0},{"unit":"U","date":"2015-07-13T13:40:00","value":0},{"unit":"U","date":"2015-07-13T13:45:00","value":0},{"unit":"U","date":"2015-07-13T13:50:00","value":0},{"unit":"U","date":"2015-07-13T13:55:00","value":0},{"unit":"U","date":"2015-07-13T14:00:00","value":0},{"unit":"U","date":"2015-07-13T14:05:00","value":0},{"unit":"U","date":"2015-07-13T14:10:00","value":0},{"unit":"U","date":"2015-07-13T14:15:00","value":0},{"unit":"U","date":"2015-07-13T14:20:00","value":0},{"unit":"U","date":"2015-07-13T14:25:00","value":0},{"unit":"U","date":"2015-07-13T14:30:00","value":0},{"unit":"U","date":"2015-07-13T14:35:00","value":0},{"unit":"U","date":"2015-07-13T14:40:00","value":0},{"unit":"U","date":"2015-07-13T14:45:00","value":0},{"unit":"U","date":"2015-07-13T14:50:00","value":0},{"unit":"U","date":"2015-07-13T14:55:00","value":0},{"unit":"U","date":"2015-07-13T15:00:00","value":0},{"unit":"U","date":"2015-07-13T15:05:00","value":0},{"unit":"U","date":"2015-07-13T15:10:00","value":0},{"unit":"U","date":"2015-07-13T15:15:00","value":0},{"unit":"U","date":"2015-07-13T15:20:00","value":0},{"unit":"U","date":"2015-07-13T15:25:00","value":0},{"unit":"U","date":"2015-07-13T15:30:00","value":0},{"unit":"U","date":"2015-07-13T15:35:00","value":0},{"unit":"U","date":"2015-07-13T15:40:00","value":0},{"unit":"U","date":"2015-07-13T15:45:00","value":0},{"unit":"U","date":"2015-07-13T15:50:00","value":0},{"unit":"U","date":"2015-07-13T15:55:00","value":0},{"unit":"U","date":"2015-07-13T16:00:00","value":0},{"unit":"U","date":"2015-07-13T16:05:00","value":0},{"unit":"U","date":"2015-07-13T16:10:00","value":0}] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/basal.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/basal.json deleted file mode 100644 index 98f572dce..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/basal.json +++ /dev/null @@ -1,44 +0,0 @@ -[ - { - "i": 0, - "start": "00:00:00", - "rate": 0.9, - "minutes": 0 - }, - { - "i": 1, - "start": "04:00:00", - "rate": 0.925, - "minutes": 240 - }, - { - "i": 2, - "start": "07:00:00", - "rate": 0.85, - "minutes": 420 - }, - { - "i": 3, - "start": "10:00:00", - "rate": 0.85, - "minutes": 600 - }, - { - "i": 4, - "start": "12:00:00", - "rate": 0.75, - "minutes": 720 - }, - { - "i": 5, - "start": "15:00:00", - "rate": 0.8, - "minutes": 900 - }, - { - "i": 6, - "start": "22:00:00", - "rate": 0.9, - "minutes": 1320 - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_carb_effect_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_carb_effect_input.json deleted file mode 100644 index c72bb9901..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_carb_effect_input.json +++ /dev/null @@ -1,467 +0,0 @@ -[ - { - "date": "2015-10-16T05:55:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:00:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:05:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:10:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:15:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:20:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:25:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:30:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:35:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:40:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:45:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:50:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:55:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:00:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:05:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:10:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:15:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:20:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:25:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:30:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:35:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:40:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:45:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:50:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:55:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:00:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:05:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:10:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:15:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:20:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:25:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:30:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:35:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:40:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:45:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:50:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:55:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:00:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:05:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:10:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:15:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:20:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:25:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:30:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:35:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:40:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:45:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:50:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:55:00", - "amount": 0.08920096021947878, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:00:00", - "amount": 0.6130692729766802, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:05:00", - "amount": 1.6060733882030176, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:10:00", - "amount": 3.0682133058984906, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:15:00", - "amount": 4.999489026063102, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:20:00", - "amount": 7.399900548696846, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:25:00", - "amount": 10.269447873799727, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:30:00", - "amount": 13.608131001371746, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:35:00", - "amount": 17.415949931412896, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:40:00", - "amount": 21.692904663923187, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:45:00", - "amount": 26.438995198902607, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:50:00", - "amount": 31.65422153635116, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:55:00", - "amount": 37.33858367626886, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:00:00", - "amount": 43.49208161865569, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:05:00", - "amount": 50.11471536351166, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:10:00", - "amount": 57.20648491083676, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:15:00", - "amount": 64.767390260631, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:20:00", - "amount": 72.79743141289437, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:25:00", - "amount": 81.11820644718794, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:30:00", - "amount": 89.03878257887516, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:35:00", - "amount": 96.49022290809329, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:40:00", - "amount": 103.47252743484226, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:45:00", - "amount": 109.98569615912207, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:50:00", - "amount": 116.02972908093281, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:55:00", - "amount": 121.60462620027438, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:00:00", - "amount": 126.71038751714674, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:05:00", - "amount": 131.34701303155006, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:10:00", - "amount": 135.51450274348426, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:15:00", - "amount": 139.21285665294928, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:20:00", - "amount": 142.44207475994514, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:25:00", - "amount": 145.20215706447186, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:30:00", - "amount": 147.4931035665295, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:35:00", - "amount": 149.31491426611802, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:40:00", - "amount": 150.66758916323732, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:45:00", - "amount": 151.5511282578875, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:50:00", - "amount": 151.9655315500686, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:55:00", - "amount": 152.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:00:00", - "amount": 152.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:05:00", - "amount": 152.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:10:00", - "amount": 152.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:15:00", - "amount": 152.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:20:00", - "amount": 152.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:25:00", - "amount": 152.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:30:00", - "amount": 152.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:35:00", - "amount": 152.0, - "unit": "mg/dL" - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_glucose_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_glucose_input.json deleted file mode 100644 index bc74b5624..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_glucose_input.json +++ /dev/null @@ -1,6 +0,0 @@ -[{ - "trend_arrow": "FLAT", - "system_time": "2015-10-16T16:51:46", - "display_time": "2015-10-16T09:51:08", - "glucose": 147 -}] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_insulin_effect_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_insulin_effect_input.json deleted file mode 100644 index 244bb036d..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_insulin_effect_input.json +++ /dev/null @@ -1,527 +0,0 @@ -[ - { - "date": "2015-10-16T05:55:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:00:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:05:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:10:00", - "amount": -0.05116973249986715, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:15:00", - "amount": -0.05789217482631093, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:20:00", - "amount": -0.07771134754398137, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:25:00", - "amount": -0.09750451603513274, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:30:00", - "amount": -0.12203773711068157, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:35:00", - "amount": -0.15095055115286835, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:40:00", - "amount": -0.1838927275472713, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:45:00", - "amount": -0.22052426468279615, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:50:00", - "amount": -0.24717183578216545, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T06:55:00", - "amount": -0.2893144242175132, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:00:00", - "amount": -0.2589871828832556, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:05:00", - "amount": -0.29857264308450326, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:10:00", - "amount": -0.22330600448031762, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:15:00", - "amount": -0.24340112507542233, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:20:00", - "amount": -0.25058050652147246, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:25:00", - "amount": -0.24254143594819094, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:30:00", - "amount": -0.21749871628061584, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:35:00", - "amount": -0.1772099748720401, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:40:00", - "amount": -0.12373296368553532, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:45:00", - "amount": -0.05800053902807922, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:50:00", - "amount": 0.019065916806689343, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T07:55:00", - "amount": 0.10656982887179145, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:00:00", - "amount": 0.5814672957555429, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:05:00", - "amount": 0.6964983023063709, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:10:00", - "amount": 0.839841951080192, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:15:00", - "amount": 1.017714433545975, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:20:00", - "amount": 1.2358473523026858, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:25:00", - "amount": 1.4990738388257407, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:30:00", - "amount": 2.4424187692212054, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:35:00", - "amount": 2.803912423996154, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:40:00", - "amount": 3.2220002596052173, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:45:00", - "amount": 3.700352667321728, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:50:00", - "amount": 4.242235634301219, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T08:55:00", - "amount": 4.850524811081413, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:00:00", - "amount": 5.5277195790822375, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:05:00", - "amount": 6.275957118105808, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:10:00", - "amount": 7.092719849613544, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:15:00", - "amount": 7.966122324754094, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:20:00", - "amount": 8.889869513880269, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:25:00", - "amount": 9.55106827366706, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:30:00", - "amount": 10.536493085687397, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:35:00", - "amount": 10.93556951143635, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:40:00", - "amount": 11.890699805221772, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:45:00", - "amount": 12.81049769931439, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:50:00", - "amount": 13.681466188886816, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:55:00", - "amount": 13.910708100083081, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:00:00", - "amount": 13.508961468585511, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:05:00", - "amount": 12.466684146484779, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:10:00", - "amount": 10.781837253440187, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:15:00", - "amount": 9.0846795883076, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:20:00", - "amount": 7.013205180933435, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:25:00", - "amount": 4.568371172724007, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:30:00", - "amount": 1.767024244038235, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:35:00", - "amount": -1.3622394338251143, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:40:00", - "amount": -4.785438162555244, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:45:00", - "amount": -8.475077970817363, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:50:00", - "amount": -12.404320524954366, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:55:00", - "amount": -16.54706904749455, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:00:00", - "amount": -20.880282108817163, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:05:00", - "amount": -25.378865830960304, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:10:00", - "amount": -30.02894037283888, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:15:00", - "amount": -34.80866756164933, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:20:00", - "amount": -39.69232924579666, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:25:00", - "amount": -44.65904560451495, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:30:00", - "amount": -49.687928735135834, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:35:00", - "amount": -54.75929582600946, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:40:00", - "amount": -59.84482763266896, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:45:00", - "amount": -64.92715822050762, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:50:00", - "amount": -69.98976050270197, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T11:55:00", - "amount": -75.01694624021185, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:00:00", - "amount": -79.9932139266723, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:05:00", - "amount": -84.89974475270296, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:10:00", - "amount": -89.7546057953877, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:15:00", - "amount": -94.54389486544915, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:20:00", - "amount": -99.25471446517622, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:25:00", - "amount": -103.87808111694163, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:30:00", - "amount": -108.39054448779835, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:35:00", - "amount": -112.79562633788349, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:40:00", - "amount": -117.0769986742359, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:45:00", - "amount": -121.23136988437481, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:50:00", - "amount": -125.25210996088262, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T12:55:00", - "amount": -129.13368784015748, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:00:00", - "amount": -132.87168546991376, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:05:00", - "amount": -136.46281187668208, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:10:00", - "amount": -139.91076109601062, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:15:00", - "amount": -143.1920024921548, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:20:00", - "amount": -146.2986738071368, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:25:00", - "amount": -149.23710482648195, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:30:00", - "amount": -152.01257516166288, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:35:00", - "amount": -154.5675135333564, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:40:00", - "amount": -156.9226367135027, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:45:00", - "amount": -159.09407074832978, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:50:00", - "amount": -161.0914402564, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T13:55:00", - "amount": -163.0926823408534, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T14:00:00", - "amount": -163.39678416635502, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T14:05:00", - "amount": -163.65380824473786, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T14:10:00", - "amount": -163.86314957675157, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T14:15:00", - "amount": -164.02799500404936, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T14:20:00", - "amount": -164.15136192522291, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T14:25:00", - "amount": -164.2348489355287, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T14:30:00", - "amount": -164.28097710009604, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T14:35:00", - "amount": -164.2833333333333, - "unit": "mg/dL" - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_blend_glucose_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_blend_glucose_input.json deleted file mode 100644 index 4ee65995d..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_blend_glucose_input.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "trend_arrow": "FLAT", - "system_time": "2015-10-30T17:16:36", - "display_time": "2015-10-30T09:17:27", - "glucose": 111 - }, - { - "trend_arrow": "FLAT", - "system_time": "2015-10-30T17:11:36", - "display_time": "2015-10-30T09:12:27", - "glucose": 111 - }, - { - "trend_arrow": "FLAT", - "system_time": "2015-10-30T17:06:36", - "display_time": "2015-10-30T09:07:28", - "glucose": 113 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_blend_insulin_effect_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_blend_insulin_effect_input.json deleted file mode 100644 index 4d2a4a55e..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_blend_insulin_effect_input.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "date": "2015-10-30T09:15:00", - "amount": -96.64432176805616, - "unit": "mg/dL" - }, - { - "date": "2015-10-30T09:20:00", - "amount": -96.91899878577772, - "unit": "mg/dL" - }, - { - "date": "2015-10-30T09:25:00", - "amount": -97.14706680030386, - "unit": "mg/dL" - }, - { - "date": "2015-10-30T09:30:00", - "amount": -97.30954106615258, - "unit": "mg/dL" - }, - { - "date": "2015-10-30T09:35:00", - "amount": -97.40780654695538, - "unit": "mg/dL" - }, - { - "date": "2015-10-30T09:40:00", - "amount": -97.44702440741187, - "unit": "mg/dL" - }, - { - "date": "2015-10-30T09:45:00", - "amount": -97.428432128785, - "unit": "mg/dL" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_blend_momentum_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_blend_momentum_input.json deleted file mode 100644 index e58c38192..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_blend_momentum_input.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - {"amount": -0.00, "date": "2015-10-30T09:15:00", "unit": "mg/dL"}, - {"amount": -0.51, "date": "2015-10-30T09:20:00", "unit": "mg/dL"}, - {"amount": -1.51, "date": "2015-10-30T09:25:00", "unit": "mg/dL"}, - {"amount": -2.51, "date": "2015-10-30T09:30:00", "unit": "mg/dL"}, - {"amount": -3.51, "date": "2015-10-30T09:35:00", "unit": "mg/dL"} -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_blend_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_blend_output.json deleted file mode 100644 index a28bd15c5..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_blend_output.json +++ /dev/null @@ -1 +0,0 @@ -[{"date": "2015-10-30T09:17:27", "amount": 111.0, "unit": "mg/dL"}, {"date": "2015-10-30T09:20:00", "amount": 110.49, "unit": "mg/dL"}, {"date": "2015-10-30T09:25:00", "amount": 109.62122843753055, "unit": "mg/dL"}, {"date": "2015-10-30T09:30:00", "amount": 109.04278305705336, "unit": "mg/dL"}, {"date": "2015-10-30T09:35:00", "amount": 108.79723427144835, "unit": "mg/dL"}, {"date": "2015-10-30T09:40:00", "amount": 108.75801641099186, "unit": "mg/dL"}, {"date": "2015-10-30T09:45:00", "amount": 108.77660868961873, "unit": "mg/dL"}] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_down_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_down_input.json deleted file mode 100644 index b7247a157..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_down_input.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "date": "2015-10-16T09:50:00", - "amount": -11.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:55:00", - "amount": -14.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:00:00", - "amount": -17.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:05:00", - "amount": -20.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:10:00", - "amount": -23.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:15:00", - "amount": -26.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:20:00", - "amount": -29.0, - "unit": "mg/dL" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_down_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_down_output.json deleted file mode 100644 index 8da0604e8..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_down_output.json +++ /dev/null @@ -1 +0,0 @@ -[{"date": "2015-10-16T09:51:08", "amount": 147.0, "unit": "mg/dL"}, {"date": "2015-10-16T09:55:00", "amount": 144.0, "unit": "mg/dL"}, {"date": "2015-10-16T10:00:00", "amount": 141.48288815336815, "unit": "mg/dL"}, {"date": "2015-10-16T10:05:00", "amount": 139.52941258933004, "unit": "mg/dL"}, {"date": "2015-10-16T10:10:00", "amount": 138.06988445366972, "unit": "mg/dL"}, {"date": "2015-10-16T10:15:00", "amount": 137.51056554586722, "unit": "mg/dL"}, {"date": "2015-10-16T10:20:00", "amount": 137.68859084523504, "unit": "mg/dL"}, {"date": "2015-10-16T10:25:00", "amount": 138.1133041621285, "unit": "mg/dL"}, {"date": "2015-10-16T10:30:00", "amount": 138.65064036101472, "unit": "mg/dL"}, {"date": "2015-10-16T10:35:00", "amount": 139.32919561319252, "unit": "mg/dL"}, {"date": "2015-10-16T10:40:00", "amount": 140.18295161697267, "unit": "mg/dL"}, {"date": "2015-10-16T10:45:00", "amount": 141.23940234368996, "unit": "mg/dL"}, {"date": "2015-10-16T10:50:00", "amount": 142.5253861270015, "unit": "mg/dL"}, {"date": "2015-10-16T10:55:00", "amount": 144.06699974437902, "unit": "mg/dL"}, {"date": "2015-10-16T11:00:00", "amount": 145.88728462544324, "unit": "mg/dL"}, {"date": "2015-10-16T11:05:00", "amount": 148.01133464815607, "unit": "mg/dL"}, {"date": "2015-10-16T11:10:00", "amount": 150.45302965360258, "unit": "mg/dL"}, {"date": "2015-10-16T11:15:00", "amount": 153.23420781458637, "unit": "mg/dL"}, {"date": "2015-10-16T11:20:00", "amount": 156.3805872827024, "unit": "mg/dL"}, {"date": "2015-10-16T11:25:00", "amount": 159.7346459582777, "unit": "mg/dL"}, {"date": "2015-10-16T11:30:00", "amount": 162.62633895934403, "unit": "mg/dL"}, {"date": "2015-10-16T11:35:00", "amount": 165.00641219768852, "unit": "mg/dL"}, {"date": "2015-10-16T11:40:00", "amount": 166.903184917778, "unit": "mg/dL"}, {"date": "2015-10-16T11:45:00", "amount": 168.33402305421913, "unit": "mg/dL"}, {"date": "2015-10-16T11:50:00", "amount": 169.31545369383554, "unit": "mg/dL"}, {"date": "2015-10-16T11:55:00", "amount": 169.8631650756672, "unit": "mg/dL"}, {"date": "2015-10-16T12:00:00", "amount": 169.9926587060791, "unit": "mg/dL"}, {"date": "2015-10-16T12:05:00", "amount": 169.7227533944518, "unit": "mg/dL"}, {"date": "2015-10-16T12:10:00", "amount": 169.03538206370123, "unit": "mg/dL"}, {"date": "2015-10-16T12:15:00", "amount": 167.94444690310482, "unit": "mg/dL"}, {"date": "2015-10-16T12:20:00", "amount": 166.4628454103736, "unit": "mg/dL"}, {"date": "2015-10-16T12:25:00", "amount": 164.5995610631349, "unit": "mg/dL"}, {"date": "2015-10-16T12:30:00", "amount": 162.3780441943358, "unit": "mg/dL"}, {"date": "2015-10-16T12:35:00", "amount": 159.7947730438392, "unit": "mg/dL"}, {"date": "2015-10-16T12:40:00", "amount": 156.8660756046061, "unit": "mg/dL"}, {"date": "2015-10-16T12:45:00", "amount": 153.59524348911737, "unit": "mg/dL"}, {"date": "2015-10-16T12:50:00", "amount": 149.98890670479062, "unit": "mg/dL"}, {"date": "2015-10-16T12:55:00", "amount": 146.14179727544717, "unit": "mg/dL"}, {"date": "2015-10-16T13:00:00", "amount": 142.4037996456909, "unit": "mg/dL"}, {"date": "2015-10-16T13:05:00", "amount": 138.81267323892257, "unit": "mg/dL"}, {"date": "2015-10-16T13:10:00", "amount": 135.36472401959404, "unit": "mg/dL"}, {"date": "2015-10-16T13:15:00", "amount": 132.08348262344984, "unit": "mg/dL"}, {"date": "2015-10-16T13:20:00", "amount": 128.97681130846786, "unit": "mg/dL"}, {"date": "2015-10-16T13:25:00", "amount": 126.0383802891227, "unit": "mg/dL"}, {"date": "2015-10-16T13:30:00", "amount": 123.26290995394177, "unit": "mg/dL"}, {"date": "2015-10-16T13:35:00", "amount": 120.70797158224826, "unit": "mg/dL"}, {"date": "2015-10-16T13:40:00", "amount": 118.35284840210196, "unit": "mg/dL"}, {"date": "2015-10-16T13:45:00", "amount": 116.18141436727487, "unit": "mg/dL"}, {"date": "2015-10-16T13:50:00", "amount": 114.18404485920465, "unit": "mg/dL"}, {"date": "2015-10-16T13:55:00", "amount": 112.18280277475125, "unit": "mg/dL"}, {"date": "2015-10-16T14:00:00", "amount": 111.87870094924963, "unit": "mg/dL"}, {"date": "2015-10-16T14:05:00", "amount": 111.62167687086679, "unit": "mg/dL"}, {"date": "2015-10-16T14:10:00", "amount": 111.41233553885309, "unit": "mg/dL"}, {"date": "2015-10-16T14:15:00", "amount": 111.2474901115553, "unit": "mg/dL"}, {"date": "2015-10-16T14:20:00", "amount": 111.12412319038174, "unit": "mg/dL"}, {"date": "2015-10-16T14:25:00", "amount": 111.04063618007595, "unit": "mg/dL"}, {"date": "2015-10-16T14:30:00", "amount": 110.99450801550861, "unit": "mg/dL"}, {"date": "2015-10-16T14:35:00", "amount": 110.99215178227135, "unit": "mg/dL"}] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_flat_glucose_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_flat_glucose_input.json deleted file mode 100644 index 2ca9fb4ea..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_flat_glucose_input.json +++ /dev/null @@ -1,6 +0,0 @@ -[{ - "trend_arrow": "FLAT", - "system_time": "2015-10-16T16:54:46", - "display_time": "2015-10-16T09:54:08", - "glucose": 147 -}] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_flat_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_flat_input.json deleted file mode 100644 index 3b4fbe03b..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_flat_input.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "date": "2015-10-16T09:50:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:55:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:00:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:05:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:10:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:15:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:20:00", - "amount": 0.0, - "unit": "mg/dL" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_flat_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_flat_output.json deleted file mode 100644 index d622b6966..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_flat_output.json +++ /dev/null @@ -1 +0,0 @@ -[{"date": "2015-10-16T09:54:08", "amount": 147.0, "unit": "mg/dL"}, {"date": "2015-10-16T09:55:00", "amount": 147.0, "unit": "mg/dL"}, {"date": "2015-10-16T10:00:00", "amount": 147.004233551617, "unit": "mg/dL"}, {"date": "2015-10-16T10:05:00", "amount": 146.9926707724038, "unit": "mg/dL"}, {"date": "2015-10-16T10:10:00", "amount": 146.8958674737854, "unit": "mg/dL"}, {"date": "2015-10-16T10:15:00", "amount": 147.04445439937905, "unit": "mg/dL"}, {"date": "2015-10-16T10:20:00", "amount": 147.31900724491572, "unit": "mg/dL"}, {"date": "2015-10-16T10:25:00", "amount": 147.74372056180917, "unit": "mg/dL"}, {"date": "2015-10-16T10:30:00", "amount": 148.2810567606954, "unit": "mg/dL"}, {"date": "2015-10-16T10:35:00", "amount": 148.9596120128732, "unit": "mg/dL"}, {"date": "2015-10-16T10:40:00", "amount": 149.81336801665336, "unit": "mg/dL"}, {"date": "2015-10-16T10:45:00", "amount": 150.86981874337064, "unit": "mg/dL"}, {"date": "2015-10-16T10:50:00", "amount": 152.15580252668218, "unit": "mg/dL"}, {"date": "2015-10-16T10:55:00", "amount": 153.6974161440597, "unit": "mg/dL"}, {"date": "2015-10-16T11:00:00", "amount": 155.51770102512393, "unit": "mg/dL"}, {"date": "2015-10-16T11:05:00", "amount": 157.64175104783675, "unit": "mg/dL"}, {"date": "2015-10-16T11:10:00", "amount": 160.08344605328327, "unit": "mg/dL"}, {"date": "2015-10-16T11:15:00", "amount": 162.86462421426705, "unit": "mg/dL"}, {"date": "2015-10-16T11:20:00", "amount": 166.0110036823831, "unit": "mg/dL"}, {"date": "2015-10-16T11:25:00", "amount": 169.36506235795838, "unit": "mg/dL"}, {"date": "2015-10-16T11:30:00", "amount": 172.2567553590247, "unit": "mg/dL"}, {"date": "2015-10-16T11:35:00", "amount": 174.6368285973692, "unit": "mg/dL"}, {"date": "2015-10-16T11:40:00", "amount": 176.53360131745868, "unit": "mg/dL"}, {"date": "2015-10-16T11:45:00", "amount": 177.96443945389981, "unit": "mg/dL"}, {"date": "2015-10-16T11:50:00", "amount": 178.9458700935162, "unit": "mg/dL"}, {"date": "2015-10-16T11:55:00", "amount": 179.49358147534787, "unit": "mg/dL"}, {"date": "2015-10-16T12:00:00", "amount": 179.62307510575977, "unit": "mg/dL"}, {"date": "2015-10-16T12:05:00", "amount": 179.35316979413244, "unit": "mg/dL"}, {"date": "2015-10-16T12:10:00", "amount": 178.6657984633819, "unit": "mg/dL"}, {"date": "2015-10-16T12:15:00", "amount": 177.57486330278547, "unit": "mg/dL"}, {"date": "2015-10-16T12:20:00", "amount": 176.09326181005426, "unit": "mg/dL"}, {"date": "2015-10-16T12:25:00", "amount": 174.22997746281555, "unit": "mg/dL"}, {"date": "2015-10-16T12:30:00", "amount": 172.00846059401647, "unit": "mg/dL"}, {"date": "2015-10-16T12:35:00", "amount": 169.42518944351986, "unit": "mg/dL"}, {"date": "2015-10-16T12:40:00", "amount": 166.49649200428675, "unit": "mg/dL"}, {"date": "2015-10-16T12:45:00", "amount": 163.22565988879802, "unit": "mg/dL"}, {"date": "2015-10-16T12:50:00", "amount": 159.61932310447128, "unit": "mg/dL"}, {"date": "2015-10-16T12:55:00", "amount": 155.77221367512783, "unit": "mg/dL"}, {"date": "2015-10-16T13:00:00", "amount": 152.03421604537155, "unit": "mg/dL"}, {"date": "2015-10-16T13:05:00", "amount": 148.44308963860323, "unit": "mg/dL"}, {"date": "2015-10-16T13:10:00", "amount": 144.9951404192747, "unit": "mg/dL"}, {"date": "2015-10-16T13:15:00", "amount": 141.7138990231305, "unit": "mg/dL"}, {"date": "2015-10-16T13:20:00", "amount": 138.6072277081485, "unit": "mg/dL"}, {"date": "2015-10-16T13:25:00", "amount": 135.66879668880335, "unit": "mg/dL"}, {"date": "2015-10-16T13:30:00", "amount": 132.89332635362243, "unit": "mg/dL"}, {"date": "2015-10-16T13:35:00", "amount": 130.33838798192892, "unit": "mg/dL"}, {"date": "2015-10-16T13:40:00", "amount": 127.98326480178261, "unit": "mg/dL"}, {"date": "2015-10-16T13:45:00", "amount": 125.81183076695552, "unit": "mg/dL"}, {"date": "2015-10-16T13:50:00", "amount": 123.8144612588853, "unit": "mg/dL"}, {"date": "2015-10-16T13:55:00", "amount": 121.81321917443191, "unit": "mg/dL"}, {"date": "2015-10-16T14:00:00", "amount": 121.50911734893029, "unit": "mg/dL"}, {"date": "2015-10-16T14:05:00", "amount": 121.25209327054745, "unit": "mg/dL"}, {"date": "2015-10-16T14:10:00", "amount": 121.04275193853374, "unit": "mg/dL"}, {"date": "2015-10-16T14:15:00", "amount": 120.87790651123595, "unit": "mg/dL"}, {"date": "2015-10-16T14:20:00", "amount": 120.7545395900624, "unit": "mg/dL"}, {"date": "2015-10-16T14:25:00", "amount": 120.6710525797566, "unit": "mg/dL"}, {"date": "2015-10-16T14:30:00", "amount": 120.62492441518927, "unit": "mg/dL"}, {"date": "2015-10-16T14:35:00", "amount": 120.622568181952, "unit": "mg/dL"}] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_up_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_up_input.json deleted file mode 100644 index 8d069d1c8..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_up_input.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "date": "2015-10-16T09:50:00", - "amount": 0.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T09:55:00", - "amount": 3.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:00:00", - "amount": 6.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:05:00", - "amount": 9.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:10:00", - "amount": 12.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:15:00", - "amount": 15.0, - "unit": "mg/dL" - }, - { - "date": "2015-10-16T10:20:00", - "amount": 18.0, - "unit": "mg/dL" - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_up_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_up_output.json deleted file mode 100644 index c7c957cc1..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_momentum_up_output.json +++ /dev/null @@ -1 +0,0 @@ -[{"date": "2015-10-16T09:51:08", "amount": 147.0, "unit": "mg/dL"}, {"date": "2015-10-16T09:55:00", "amount": 150.0, "unit": "mg/dL"}, {"date": "2015-10-16T10:00:00", "amount": 152.55488815336815, "unit": "mg/dL"}, {"date": "2015-10-16T10:05:00", "amount": 154.47341258933002, "unit": "mg/dL"}, {"date": "2015-10-16T10:10:00", "amount": 155.6858844536697, "unit": "mg/dL"}, {"date": "2015-10-16T10:15:00", "amount": 156.5985655458672, "unit": "mg/dL"}, {"date": "2015-10-16T10:20:00", "amount": 157.048590845235, "unit": "mg/dL"}, {"date": "2015-10-16T10:25:00", "amount": 157.47330416212844, "unit": "mg/dL"}, {"date": "2015-10-16T10:30:00", "amount": 158.01064036101468, "unit": "mg/dL"}, {"date": "2015-10-16T10:35:00", "amount": 158.68919561319248, "unit": "mg/dL"}, {"date": "2015-10-16T10:40:00", "amount": 159.54295161697263, "unit": "mg/dL"}, {"date": "2015-10-16T10:45:00", "amount": 160.59940234368992, "unit": "mg/dL"}, {"date": "2015-10-16T10:50:00", "amount": 161.88538612700145, "unit": "mg/dL"}, {"date": "2015-10-16T10:55:00", "amount": 163.42699974437897, "unit": "mg/dL"}, {"date": "2015-10-16T11:00:00", "amount": 165.2472846254432, "unit": "mg/dL"}, {"date": "2015-10-16T11:05:00", "amount": 167.37133464815602, "unit": "mg/dL"}, {"date": "2015-10-16T11:10:00", "amount": 169.81302965360254, "unit": "mg/dL"}, {"date": "2015-10-16T11:15:00", "amount": 172.59420781458633, "unit": "mg/dL"}, {"date": "2015-10-16T11:20:00", "amount": 175.74058728270236, "unit": "mg/dL"}, {"date": "2015-10-16T11:25:00", "amount": 179.09464595827765, "unit": "mg/dL"}, {"date": "2015-10-16T11:30:00", "amount": 181.98633895934398, "unit": "mg/dL"}, {"date": "2015-10-16T11:35:00", "amount": 184.36641219768848, "unit": "mg/dL"}, {"date": "2015-10-16T11:40:00", "amount": 186.26318491777795, "unit": "mg/dL"}, {"date": "2015-10-16T11:45:00", "amount": 187.6940230542191, "unit": "mg/dL"}, {"date": "2015-10-16T11:50:00", "amount": 188.6754536938355, "unit": "mg/dL"}, {"date": "2015-10-16T11:55:00", "amount": 189.22316507566717, "unit": "mg/dL"}, {"date": "2015-10-16T12:00:00", "amount": 189.35265870607907, "unit": "mg/dL"}, {"date": "2015-10-16T12:05:00", "amount": 189.08275339445174, "unit": "mg/dL"}, {"date": "2015-10-16T12:10:00", "amount": 188.3953820637012, "unit": "mg/dL"}, {"date": "2015-10-16T12:15:00", "amount": 187.30444690310478, "unit": "mg/dL"}, {"date": "2015-10-16T12:20:00", "amount": 185.82284541037356, "unit": "mg/dL"}, {"date": "2015-10-16T12:25:00", "amount": 183.95956106313486, "unit": "mg/dL"}, {"date": "2015-10-16T12:30:00", "amount": 181.73804419433577, "unit": "mg/dL"}, {"date": "2015-10-16T12:35:00", "amount": 179.15477304383916, "unit": "mg/dL"}, {"date": "2015-10-16T12:40:00", "amount": 176.22607560460605, "unit": "mg/dL"}, {"date": "2015-10-16T12:45:00", "amount": 172.95524348911732, "unit": "mg/dL"}, {"date": "2015-10-16T12:50:00", "amount": 169.34890670479058, "unit": "mg/dL"}, {"date": "2015-10-16T12:55:00", "amount": 165.50179727544713, "unit": "mg/dL"}, {"date": "2015-10-16T13:00:00", "amount": 161.76379964569085, "unit": "mg/dL"}, {"date": "2015-10-16T13:05:00", "amount": 158.17267323892253, "unit": "mg/dL"}, {"date": "2015-10-16T13:10:00", "amount": 154.724724019594, "unit": "mg/dL"}, {"date": "2015-10-16T13:15:00", "amount": 151.4434826234498, "unit": "mg/dL"}, {"date": "2015-10-16T13:20:00", "amount": 148.33681130846782, "unit": "mg/dL"}, {"date": "2015-10-16T13:25:00", "amount": 145.39838028912266, "unit": "mg/dL"}, {"date": "2015-10-16T13:30:00", "amount": 142.62290995394173, "unit": "mg/dL"}, {"date": "2015-10-16T13:35:00", "amount": 140.06797158224822, "unit": "mg/dL"}, {"date": "2015-10-16T13:40:00", "amount": 137.7128484021019, "unit": "mg/dL"}, {"date": "2015-10-16T13:45:00", "amount": 135.54141436727483, "unit": "mg/dL"}, {"date": "2015-10-16T13:50:00", "amount": 133.5440448592046, "unit": "mg/dL"}, {"date": "2015-10-16T13:55:00", "amount": 131.5428027747512, "unit": "mg/dL"}, {"date": "2015-10-16T14:00:00", "amount": 131.2387009492496, "unit": "mg/dL"}, {"date": "2015-10-16T14:05:00", "amount": 130.98167687086675, "unit": "mg/dL"}, {"date": "2015-10-16T14:10:00", "amount": 130.77233553885304, "unit": "mg/dL"}, {"date": "2015-10-16T14:15:00", "amount": 130.60749011155525, "unit": "mg/dL"}, {"date": "2015-10-16T14:20:00", "amount": 130.4841231903817, "unit": "mg/dL"}, {"date": "2015-10-16T14:25:00", "amount": 130.4006361800759, "unit": "mg/dL"}, {"date": "2015-10-16T14:30:00", "amount": 130.35450801550857, "unit": "mg/dL"}, {"date": "2015-10-16T14:35:00", "amount": 130.3521517822713, "unit": "mg/dL"}] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_no_momentum_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_no_momentum_output.json deleted file mode 100644 index 2e372eb85..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_no_momentum_output.json +++ /dev/null @@ -1 +0,0 @@ -[{"date": "2015-10-16T09:51:08", "amount": 147.0, "unit": "mg/dL"}, {"date": "2015-10-16T09:55:00", "amount": 147.31844287141575, "unit": "mg/dL"}, {"date": "2015-10-16T10:00:00", "amount": 147.4405645526754, "unit": "mg/dL"}, {"date": "2015-10-16T10:05:00", "amount": 147.391291345801, "unit": "mg/dL"}, {"date": "2015-10-16T10:10:00", "amount": 147.16858437045187, "unit": "mg/dL"}, {"date": "2015-10-16T10:15:00", "amount": 147.40270242548388, "unit": "mg/dL"}, {"date": "2015-10-16T10:20:00", "amount": 147.73163954074346, "unit": "mg/dL"}, {"date": "2015-10-16T10:25:00", "amount": 148.1563528576369, "unit": "mg/dL"}, {"date": "2015-10-16T10:30:00", "amount": 148.69368905652314, "unit": "mg/dL"}, {"date": "2015-10-16T10:35:00", "amount": 149.37224430870094, "unit": "mg/dL"}, {"date": "2015-10-16T10:40:00", "amount": 150.2260003124811, "unit": "mg/dL"}, {"date": "2015-10-16T10:45:00", "amount": 151.28245103919838, "unit": "mg/dL"}, {"date": "2015-10-16T10:50:00", "amount": 152.56843482250991, "unit": "mg/dL"}, {"date": "2015-10-16T10:55:00", "amount": 154.11004843988744, "unit": "mg/dL"}, {"date": "2015-10-16T11:00:00", "amount": 155.93033332095166, "unit": "mg/dL"}, {"date": "2015-10-16T11:05:00", "amount": 158.05438334366448, "unit": "mg/dL"}, {"date": "2015-10-16T11:10:00", "amount": 160.496078349111, "unit": "mg/dL"}, {"date": "2015-10-16T11:15:00", "amount": 163.2772565100948, "unit": "mg/dL"}, {"date": "2015-10-16T11:20:00", "amount": 166.42363597821083, "unit": "mg/dL"}, {"date": "2015-10-16T11:25:00", "amount": 169.7776946537861, "unit": "mg/dL"}, {"date": "2015-10-16T11:30:00", "amount": 172.66938765485244, "unit": "mg/dL"}, {"date": "2015-10-16T11:35:00", "amount": 175.04946089319694, "unit": "mg/dL"}, {"date": "2015-10-16T11:40:00", "amount": 176.9462336132864, "unit": "mg/dL"}, {"date": "2015-10-16T11:45:00", "amount": 178.37707174972755, "unit": "mg/dL"}, {"date": "2015-10-16T11:50:00", "amount": 179.35850238934393, "unit": "mg/dL"}, {"date": "2015-10-16T11:55:00", "amount": 179.9062137711756, "unit": "mg/dL"}, {"date": "2015-10-16T12:00:00", "amount": 180.0357074015875, "unit": "mg/dL"}, {"date": "2015-10-16T12:05:00", "amount": 179.76580208996018, "unit": "mg/dL"}, {"date": "2015-10-16T12:10:00", "amount": 179.07843075920962, "unit": "mg/dL"}, {"date": "2015-10-16T12:15:00", "amount": 177.9874955986132, "unit": "mg/dL"}, {"date": "2015-10-16T12:20:00", "amount": 176.505894105882, "unit": "mg/dL"}, {"date": "2015-10-16T12:25:00", "amount": 174.6426097586433, "unit": "mg/dL"}, {"date": "2015-10-16T12:30:00", "amount": 172.4210928898442, "unit": "mg/dL"}, {"date": "2015-10-16T12:35:00", "amount": 169.8378217393476, "unit": "mg/dL"}, {"date": "2015-10-16T12:40:00", "amount": 166.90912430011448, "unit": "mg/dL"}, {"date": "2015-10-16T12:45:00", "amount": 163.63829218462575, "unit": "mg/dL"}, {"date": "2015-10-16T12:50:00", "amount": 160.031955400299, "unit": "mg/dL"}, {"date": "2015-10-16T12:55:00", "amount": 156.18484597095556, "unit": "mg/dL"}, {"date": "2015-10-16T13:00:00", "amount": 152.44684834119928, "unit": "mg/dL"}, {"date": "2015-10-16T13:05:00", "amount": 148.85572193443096, "unit": "mg/dL"}, {"date": "2015-10-16T13:10:00", "amount": 145.40777271510242, "unit": "mg/dL"}, {"date": "2015-10-16T13:15:00", "amount": 142.12653131895823, "unit": "mg/dL"}, {"date": "2015-10-16T13:20:00", "amount": 139.01986000397625, "unit": "mg/dL"}, {"date": "2015-10-16T13:25:00", "amount": 136.0814289846311, "unit": "mg/dL"}, {"date": "2015-10-16T13:30:00", "amount": 133.30595864945016, "unit": "mg/dL"}, {"date": "2015-10-16T13:35:00", "amount": 130.75102027775665, "unit": "mg/dL"}, {"date": "2015-10-16T13:40:00", "amount": 128.39589709761034, "unit": "mg/dL"}, {"date": "2015-10-16T13:45:00", "amount": 126.22446306278326, "unit": "mg/dL"}, {"date": "2015-10-16T13:50:00", "amount": 124.22709355471304, "unit": "mg/dL"}, {"date": "2015-10-16T13:55:00", "amount": 122.22585147025964, "unit": "mg/dL"}, {"date": "2015-10-16T14:00:00", "amount": 121.92174964475802, "unit": "mg/dL"}, {"date": "2015-10-16T14:05:00", "amount": 121.66472556637518, "unit": "mg/dL"}, {"date": "2015-10-16T14:10:00", "amount": 121.45538423436147, "unit": "mg/dL"}, {"date": "2015-10-16T14:15:00", "amount": 121.29053880706368, "unit": "mg/dL"}, {"date": "2015-10-16T14:20:00", "amount": 121.16717188589013, "unit": "mg/dL"}, {"date": "2015-10-16T14:25:00", "amount": 121.08368487558434, "unit": "mg/dL"}, {"date": "2015-10-16T14:30:00", "amount": 121.037556711017, "unit": "mg/dL"}, {"date": "2015-10-16T14:35:00", "amount": 121.03520047777974, "unit": "mg/dL"}] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_non_zero_carb_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_non_zero_carb_input.json deleted file mode 100644 index 5eb68caeb..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_non_zero_carb_input.json +++ /dev/null @@ -1,157 +0,0 @@ -[ - { - "value": 345.692710028959, - "startDate": "2016-03-05T00:05:00-0800", - "unit": "mg/dL" - }, - { - "value": 357.4968709800336, - "startDate": "2016-03-05T00:10:00-0800", - "unit": "mg/dL" - }, - { - "value": 368.2585079256211, - "startDate": "2016-03-05T00:15:00-0800", - "unit": "mg/dL" - }, - { - "value": 377.9776208657216, - "startDate": "2016-03-05T00:20:00-0800", - "unit": "mg/dL" - }, - { - "value": 386.6542098003353, - "startDate": "2016-03-05T00:25:00-0800", - "unit": "mg/dL" - }, - { - "value": 394.2882747294619, - "startDate": "2016-03-05T00:30:00-0800", - "unit": "mg/dL" - }, - { - "value": 400.9472251181222, - "startDate": "2016-03-05T00:35:00-0800", - "unit": "mg/dL" - }, - { - "value": 406.9048840115836, - "startDate": "2016-03-05T00:40:00-0800", - "unit": "mg/dL" - }, - { - "value": 412.1903892699285, - "startDate": "2016-03-05T00:45:00-0800", - "unit": "mg/dL" - }, - { - "value": 416.8037408931565, - "startDate": "2016-03-05T00:50:00-0800", - "unit": "mg/dL" - }, - { - "value": 420.7449388812682, - "startDate": "2016-03-05T00:55:00-0800", - "unit": "mg/dL" - }, - { - "value": 424.013983234263, - "startDate": "2016-03-05T01:00:00-0800", - "unit": "mg/dL" - }, - { - "value": 426.6108739521414, - "startDate": "2016-03-05T01:05:00-0800", - "unit": "mg/dL" - }, - { - "value": 428.5356110349032, - "startDate": "2016-03-05T01:10:00-0800", - "unit": "mg/dL" - }, - { - "value": 429.7881944825484, - "startDate": "2016-03-05T01:15:00-0800", - "unit": "mg/dL" - }, - { - "value": 430.461332114007, - "startDate": "2016-03-05T01:20:00-0800", - "unit": "mg/dL" - }, - { - "value": 430.885657674135, - "startDate": "2016-03-05T01:25:00-0800", - "unit": "mg/dL" - }, - { - "value": 431.0905044962657, - "startDate": "2016-03-05T01:30:00-0800", - "unit": "mg/dL" - }, - { - "value": 431.1111111111111, - "startDate": "2016-03-05T01:35:00-0800", - "unit": "mg/dL" - }, - { - "value": 431.1111111111111, - "startDate": "2016-03-05T01:40:00-0800", - "unit": "mg/dL" - }, - { - "value": 431.1111111111111, - "startDate": "2016-03-05T01:45:00-0800", - "unit": "mg/dL" - }, - { - "value": 431.1111111111111, - "startDate": "2016-03-05T01:50:00-0800", - "unit": "mg/dL" - }, - { - "value": 431.1111111111111, - "startDate": "2016-03-05T01:55:00-0800", - "unit": "mg/dL" - }, - { - "value": 431.1111111111111, - "startDate": "2016-03-05T02:00:00-0800", - "unit": "mg/dL" - }, - { - "value": 431.1111111111111, - "startDate": "2016-03-05T02:05:00-0800", - "unit": "mg/dL" - }, - { - "value": 431.1111111111111, - "startDate": "2016-03-05T02:10:00-0800", - "unit": "mg/dL" - }, - { - "value": 431.1111111111111, - "startDate": "2016-03-05T02:15:00-0800", - "unit": "mg/dL" - }, - { - "value": 431.1111111111111, - "startDate": "2016-03-05T02:20:00-0800", - "unit": "mg/dL" - }, - { - "value": 431.1111111111111, - "startDate": "2016-03-05T02:25:00-0800", - "unit": "mg/dL" - }, - { - "value": 431.1111111111111, - "startDate": "2016-03-05T02:30:00-0800", - "unit": "mg/dL" - }, - { - "value": 431.1111111111111, - "startDate": "2016-03-05T02:35:00-0800", - "unit": "mg/dL" - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_non_zero_glucose_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_non_zero_glucose_input.json deleted file mode 100644 index 238d95133..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_non_zero_glucose_input.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - { - "value": 178, - "startDate": "2016-03-05T00:03:14-0800", - "unit": "mg/dL" - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_non_zero_insulin_input.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_non_zero_insulin_input.json deleted file mode 100644 index af6d5fdf8..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_non_zero_insulin_input.json +++ /dev/null @@ -1,272 +0,0 @@ -[ - { - "value": -262.7985192241191, - "startDate": "2016-03-05T00:05:00-0800", - "unit": "mg/dL" - }, - { - "value": -270.8286417720012, - "startDate": "2016-03-05T00:10:00-0800", - "unit": "mg/dL" - }, - { - "value": -278.8133758667809, - "startDate": "2016-03-05T00:15:00-0800", - "unit": "mg/dL" - }, - { - "value": -286.7284576274255, - "startDate": "2016-03-05T00:20:00-0800", - "unit": "mg/dL" - }, - { - "value": -294.5582531285091, - "startDate": "2016-03-05T00:25:00-0800", - "unit": "mg/dL" - }, - { - "value": -302.5967010990278, - "startDate": "2016-03-05T00:30:00-0800", - "unit": "mg/dL" - }, - { - "value": -310.381943957302, - "startDate": "2016-03-05T00:35:00-0800", - "unit": "mg/dL" - }, - { - "value": -316.6257775805158, - "startDate": "2016-03-05T00:40:00-0800", - "unit": "mg/dL" - }, - { - "value": -322.0179315638999, - "startDate": "2016-03-05T00:45:00-0800", - "unit": "mg/dL" - }, - { - "value": -327.3554504781727, - "startDate": "2016-03-05T00:50:00-0800", - "unit": "mg/dL" - }, - { - "value": -332.5782130464361, - "startDate": "2016-03-05T00:55:00-0800", - "unit": "mg/dL" - }, - { - "value": -337.6793353886575, - "startDate": "2016-03-05T01:00:00-0800", - "unit": "mg/dL" - }, - { - "value": -342.7443165330539, - "startDate": "2016-03-05T01:05:00-0800", - "unit": "mg/dL" - }, - { - "value": -347.7575443621537, - "startDate": "2016-03-05T01:10:00-0800", - "unit": "mg/dL" - }, - { - "value": -352.7116703841897, - "startDate": "2016-03-05T01:15:00-0800", - "unit": "mg/dL" - }, - { - "value": -357.6053319159832, - "startDate": "2016-03-05T01:20:00-0800", - "unit": "mg/dL" - }, - { - "value": -362.4252842472219, - "startDate": "2016-03-05T01:25:00-0800", - "unit": "mg/dL" - }, - { - "value": -367.1551449645343, - "startDate": "2016-03-05T01:30:00-0800", - "unit": "mg/dL" - }, - { - "value": -371.7924658623842, - "startDate": "2016-03-05T01:35:00-0800", - "unit": "mg/dL" - }, - { - "value": -376.3227442729362, - "startDate": "2016-03-05T01:40:00-0800", - "unit": "mg/dL" - }, - { - "value": -380.7370617907551, - "startDate": "2016-03-05T01:45:00-0800", - "unit": "mg/dL" - }, - { - "value": -385.0276152484062, - "startDate": "2016-03-05T01:50:00-0800", - "unit": "mg/dL" - }, - { - "value": -389.187729956454, - "startDate": "2016-03-05T01:55:00-0800", - "unit": "mg/dL" - }, - { - "value": -393.2118729434634, - "startDate": "2016-03-05T02:00:00-0800", - "unit": "mg/dL" - }, - { - "value": -397.0956661959993, - "startDate": "2016-03-05T02:05:00-0800", - "unit": "mg/dL" - }, - { - "value": -400.8358998986266, - "startDate": "2016-03-05T02:10:00-0800", - "unit": "mg/dL" - }, - { - "value": -404.4305456739103, - "startDate": "2016-03-05T02:15:00-0800", - "unit": "mg/dL" - }, - { - "value": -407.8711913354906, - "startDate": "2016-03-05T02:20:00-0800", - "unit": "mg/dL" - }, - { - "value": -411.1887683152845, - "startDate": "2016-03-05T02:25:00-0800", - "unit": "mg/dL" - }, - { - "value": -414.2483273403853, - "startDate": "2016-03-05T02:30:00-0800", - "unit": "mg/dL" - }, - { - "value": -417.237074474721, - "startDate": "2016-03-05T02:35:00-0800", - "unit": "mg/dL" - }, - { - "value": -419.3124522762179, - "startDate": "2016-03-05T02:40:00-0800", - "unit": "mg/dL" - }, - { - "value": -421.1959605419546, - "startDate": "2016-03-05T02:45:00-0800", - "unit": "mg/dL" - }, - { - "value": -422.9152625517117, - "startDate": "2016-03-05T02:50:00-0800", - "unit": "mg/dL" - }, - { - "value": -424.4368282040283, - "startDate": "2016-03-05T02:55:00-0800", - "unit": "mg/dL" - }, - { - "value": -425.7898805619185, - "startDate": "2016-03-05T03:00:00-0800", - "unit": "mg/dL" - }, - { - "value": -426.9822978697815, - "startDate": "2016-03-05T03:05:00-0800", - "unit": "mg/dL" - }, - { - "value": -428.0219419720182, - "startDate": "2016-03-05T03:10:00-0800", - "unit": "mg/dL" - }, - { - "value": -428.9115794359523, - "startDate": "2016-03-05T03:15:00-0800", - "unit": "mg/dL" - }, - { - "value": -429.7051332223956, - "startDate": "2016-03-05T03:20:00-0800", - "unit": "mg/dL" - }, - { - "value": -430.3667421802121, - "startDate": "2016-03-05T03:25:00-0800", - "unit": "mg/dL" - }, - { - "value": -430.9039751398021, - "startDate": "2016-03-05T03:30:00-0800", - "unit": "mg/dL" - }, - { - "value": -431.3241726915655, - "startDate": "2016-03-05T03:35:00-0800", - "unit": "mg/dL" - }, - { - "value": -431.629368308826, - "startDate": "2016-03-05T03:40:00-0800", - "unit": "mg/dL" - }, - { - "value": -431.8675074813201, - "startDate": "2016-03-05T03:45:00-0800", - "unit": "mg/dL" - }, - { - "value": -432.0478052203234, - "startDate": "2016-03-05T03:50:00-0800", - "unit": "mg/dL" - }, - { - "value": -432.128033449624, - "startDate": "2016-03-05T03:55:00-0800", - "unit": "mg/dL" - }, - { - "value": -432.1503561538819, - "startDate": "2016-03-05T04:00:00-0800", - "unit": "mg/dL" - }, - { - "value": -432.1593079386333, - "startDate": "2016-03-05T04:05:00-0800", - "unit": "mg/dL" - }, - { - "value": -432.1559703692269, - "startDate": "2016-03-05T04:10:00-0800", - "unit": "mg/dL" - }, - { - "value": -432.1487180963159, - "startDate": "2016-03-05T04:15:00-0800", - "unit": "mg/dL" - }, - { - "value": -432.1204246460239, - "startDate": "2016-03-05T04:20:00-0800", - "unit": "mg/dL" - }, - { - "value": -432.1333333333329, - "startDate": "2016-03-05T04:25:00-0800", - "unit": "mg/dL" - }, - { - "value": -432.1333333333329, - "startDate": "2016-03-05T04:30:00-0800", - "unit": "mg/dL" - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_non_zero_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_non_zero_output.json deleted file mode 100644 index 12e9d005b..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/glucose_from_effects_non_zero_output.json +++ /dev/null @@ -1,277 +0,0 @@ -[ - { - "startDate": "2016-03-05T00:03:14-0800", - "unit": "mg/dL", - "value": 178 - }, - { - "startDate": "2016-03-05T00:05:00-0800", - "unit": "mg/dL", - "value": 178 - }, - { - "startDate": "2016-03-05T00:10:00-0800", - "unit": "mg/dL", - "value": 181.7740384031924 - }, - { - "startDate": "2016-03-05T00:15:00-0800", - "unit": "mg/dL", - "value": 184.5509412540002 - }, - { - "startDate": "2016-03-05T00:20:00-0800", - "unit": "mg/dL", - "value": 186.3549724334562 - }, - { - "startDate": "2016-03-05T00:25:00-0800", - "unit": "mg/dL", - "value": 187.2017658669863 - }, - { - "startDate": "2016-03-05T00:30:00-0800", - "unit": "mg/dL", - "value": 186.7973828255941 - }, - { - "startDate": "2016-03-05T00:35:00-0800", - "unit": "mg/dL", - "value": 185.6710903559803 - }, - { - "startDate": "2016-03-05T00:40:00-0800", - "unit": "mg/dL", - "value": 185.3849156262279 - }, - { - "startDate": "2016-03-05T00:45:00-0800", - "unit": "mg/dL", - "value": 185.2782669011887 - }, - { - "startDate": "2016-03-05T00:50:00-0800", - "unit": "mg/dL", - "value": 184.5540996101439 - }, - { - "startDate": "2016-03-05T00:55:00-0800", - "unit": "mg/dL", - "value": 183.2725350299922 - }, - { - "startDate": "2016-03-05T01:00:00-0800", - "unit": "mg/dL", - "value": 181.4404570407656 - }, - { - "startDate": "2016-03-05T01:05:00-0800", - "unit": "mg/dL", - "value": 178.9723666142475 - }, - { - "startDate": "2016-03-05T01:10:00-0800", - "unit": "mg/dL", - "value": 175.8838758679096 - }, - { - "startDate": "2016-03-05T01:15:00-0800", - "unit": "mg/dL", - "value": 172.1823332935188 - }, - { - "startDate": "2016-03-05T01:20:00-0800", - "unit": "mg/dL", - "value": 167.9618093931839 - }, - { - "startDate": "2016-03-05T01:25:00-0800", - "unit": "mg/dL", - "value": 163.5661826220732 - }, - { - "startDate": "2016-03-05T01:30:00-0800", - "unit": "mg/dL", - "value": 159.0411687268914 - }, - { - "startDate": "2016-03-05T01:35:00-0800", - "unit": "mg/dL", - "value": 154.424454443887 - }, - { - "startDate": "2016-03-05T01:40:00-0800", - "unit": "mg/dL", - "value": 149.894176033335 - }, - { - "startDate": "2016-03-05T01:45:00-0800", - "unit": "mg/dL", - "value": 145.4798585155161 - }, - { - "startDate": "2016-03-05T01:50:00-0800", - "unit": "mg/dL", - "value": 141.189305057865 - }, - { - "startDate": "2016-03-05T01:55:00-0800", - "unit": "mg/dL", - "value": 137.0291903498172 - }, - { - "startDate": "2016-03-05T02:00:00-0800", - "unit": "mg/dL", - "value": 133.0050473628078 - }, - { - "startDate": "2016-03-05T02:05:00-0800", - "unit": "mg/dL", - "value": 129.1212541102719 - }, - { - "startDate": "2016-03-05T02:10:00-0800", - "unit": "mg/dL", - "value": 125.3810204076446 - }, - { - "startDate": "2016-03-05T02:15:00-0800", - "unit": "mg/dL", - "value": 121.786374632361 - }, - { - "startDate": "2016-03-05T02:20:00-0800", - "unit": "mg/dL", - "value": 118.3457289707806 - }, - { - "startDate": "2016-03-05T02:25:00-0800", - "unit": "mg/dL", - "value": 115.0281519909867 - }, - { - "startDate": "2016-03-05T02:30:00-0800", - "unit": "mg/dL", - "value": 111.968592965886 - }, - { - "startDate": "2016-03-05T02:35:00-0800", - "unit": "mg/dL", - "value": 108.9798458315503 - }, - { - "startDate": "2016-03-05T02:40:00-0800", - "unit": "mg/dL", - "value": 106.9044680300533 - }, - { - "startDate": "2016-03-05T02:45:00-0800", - "unit": "mg/dL", - "value": 105.0209597643166 - }, - { - "startDate": "2016-03-05T02:50:00-0800", - "unit": "mg/dL", - "value": 103.3016577545596 - }, - { - "startDate": "2016-03-05T02:55:00-0800", - "unit": "mg/dL", - "value": 101.7800921022429 - }, - { - "startDate": "2016-03-05T03:00:00-0800", - "unit": "mg/dL", - "value": 100.4270397443528 - }, - { - "startDate": "2016-03-05T03:05:00-0800", - "unit": "mg/dL", - "value": 99.23462243648973 - }, - { - "startDate": "2016-03-05T03:10:00-0800", - "unit": "mg/dL", - "value": 98.19497833425302 - }, - { - "startDate": "2016-03-05T03:15:00-0800", - "unit": "mg/dL", - "value": 97.30534087031887 - }, - { - "startDate": "2016-03-05T03:20:00-0800", - "unit": "mg/dL", - "value": 96.51178708387565 - }, - { - "startDate": "2016-03-05T03:25:00-0800", - "unit": "mg/dL", - "value": 95.85017812605915 - }, - { - "startDate": "2016-03-05T03:30:00-0800", - "unit": "mg/dL", - "value": 95.31294516646912 - }, - { - "startDate": "2016-03-05T03:35:00-0800", - "unit": "mg/dL", - "value": 94.89274761470577 - }, - { - "startDate": "2016-03-05T03:40:00-0800", - "unit": "mg/dL", - "value": 94.58755199744527 - }, - { - "startDate": "2016-03-05T03:45:00-0800", - "unit": "mg/dL", - "value": 94.34941282495114 - }, - { - "startDate": "2016-03-05T03:50:00-0800", - "unit": "mg/dL", - "value": 94.16911508594782 - }, - { - "startDate": "2016-03-05T03:55:00-0800", - "unit": "mg/dL", - "value": 94.08888685664724 - }, - { - "startDate": "2016-03-05T04:00:00-0800", - "unit": "mg/dL", - "value": 94.06656415238936 - }, - { - "startDate": "2016-03-05T04:05:00-0800", - "unit": "mg/dL", - "value": 94.05761236763797 - }, - { - "startDate": "2016-03-05T04:10:00-0800", - "unit": "mg/dL", - "value": 94.06094993704434 - }, - { - "startDate": "2016-03-05T04:15:00-0800", - "unit": "mg/dL", - "value": 94.06820220995527 - }, - { - "startDate": "2016-03-05T04:20:00-0800", - "unit": "mg/dL", - "value": 94.09649566024731 - }, - { - "startDate": "2016-03-05T04:25:00-0800", - "unit": "mg/dL", - "value": 94.08358697293832 - }, - { - "startDate": "2016-03-05T04:30:00-0800", - "unit": "mg/dL", - "value": 94.08358697293832 - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/ice_minus_carb_effect_with_gaps_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/ice_minus_carb_effect_with_gaps_output.json deleted file mode 100644 index 72af9c800..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/ice_minus_carb_effect_with_gaps_output.json +++ /dev/null @@ -1,112 +0,0 @@ -[ - { - "unit" : "mg\/dL", - "date" : "2018-08-16 01:13:44 +0000", - "value" : -7.9146779853452083 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 01:18:44 +0000", - "value" : -5.9281656186007314 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 01:23:44 +0000", - "value" : 1.2296261019331554 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 01:28:43 +0000", - "value" : 1.4065989188792711 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 02:03:43 +0000", - "value" : 6.0711968367636908 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 03:13:44 +0000", - "value" : 1.7358764710254451 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 03:18:44 +0000", - "value" : 0.5343295138009645 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 03:23:43 +0000", - "value" : 1.4847123043985215 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 03:28:44 +0000", - "value" : 1.6893378641238699 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 03:33:43 +0000", - "value" : 6.042541334805744 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 03:38:43 +0000", - "value" : -9.6914450613633392 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 03:43:44 +0000", - "value" : 0.58142124976613774 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 03:48:43 +0000", - "value" : -7.1923719688531209 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 03:53:44 +0000", - "value" : -2.9941217788457295 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 03:58:43 +0000", - "value" : -11.960291314911359 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 04:03:43 +0000", - "value" : -1.2512705141339 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 04:08:43 +0000", - "value" : -0.0014915619982254213 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 04:13:44 +0000", - "value" : -0.0056015222217293825 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 04:18:43 +0000", - "value" : 0.0052760433631586778 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 04:23:44 +0000", - "value" : -0.0051133014060256166 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 04:28:44 +0000", - "value" : 0.0025222980026429198 - }, - { - "unit" : "mg\/dL", - "date" : "2018-08-16 04:33:43 +0000", - "value" : -1.7950225310593533 - } -] diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/ice_minus_flat_carb_effect_output.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/ice_minus_flat_carb_effect_output.json deleted file mode 100644 index fbd68a30a..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/ice_minus_flat_carb_effect_output.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { - "value" : 3.6517114683289944, - "date" : "2018-08-26 00:48:28 +0000", - "unit" : "mg\/dL" - }, - { - "value" : 3.5831456523646765, - "date" : "2018-08-26 00:53:28 +0000", - "unit" : "mg\/dL" - }, - { - "value" : 1.4811396601622886, - "date" : "2018-08-26 00:58:28 +0000", - "unit" : "mg\/dL" - }, - { - "value" : 1.3650980083318285, - "date" : "2018-08-26 01:03:27 +0000", - "unit" : "mg\/dL" - }, - { - "value" : 2.230280467937936, - "date" : "2018-08-26 01:08:28 +0000", - "unit" : "mg\/dL" - }, - { - "value" : 2.1065985817633233, - "date" : "2018-08-26 01:13:28 +0000", - "unit" : "mg\/dL" - }, - { - "value" : 4.9741468447377066, - "date" : "2018-08-26 01:18:27 +0000", - "unit" : "mg\/dL" - }, - { - "value" : 4.8261191053223191, - "date" : "2018-08-26 01:23:28 +0000", - "unit" : "mg\/dL" - } -] \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitTests/Fixtures/read_carb_ratios.json b/Dependencies/LoopKit/LoopKitTests/Fixtures/read_carb_ratios.json deleted file mode 100644 index 86dd63c1b..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Fixtures/read_carb_ratios.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "first": 1, - "schedule": [ - { - "i": 0, - "offset": 0, - "q": 0, - "r": 100, - "ratio": 10.0, - "start": "00:00:00", - "x": 0 - }, - { - "i": 23, - "offset": 690, - "q": 0, - "r": 80, - "ratio": 9.0, - "start": "11:30:00", - "x": 1 - }, - { - "i": 36, - "offset": 1080, - "q": 0, - "r": 80, - "ratio": 8.0, - "start": "18:00:00", - "x": 2 - }, - { - "i": 45, - "offset": 1350, - "q": 0, - "r": 90, - "ratio": 9.0, - "start": "22:30:00", - "x": 3 - } - ], - "units": "grams" -} diff --git a/Dependencies/LoopKit/LoopKitTests/GlucoseMathTests.swift b/Dependencies/LoopKit/LoopKitTests/GlucoseMathTests.swift deleted file mode 100644 index f7e46a320..000000000 --- a/Dependencies/LoopKit/LoopKitTests/GlucoseMathTests.swift +++ /dev/null @@ -1,316 +0,0 @@ -// -// GlucoseMathTests.swift -// GlucoseKitTests -// -// Created by Nathan Racklyeft on 1/24/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import LoopKit -import HealthKit - - -public struct GlucoseFixtureValue: GlucoseSampleValue { - public let startDate: Date - public let quantity: HKQuantity - public let isDisplayOnly: Bool - public let wasUserEntered: Bool - public let provenanceIdentifier: String - public let condition: GlucoseCondition? - public let trendRate: HKQuantity? - - public init(startDate: Date, quantity: HKQuantity, isDisplayOnly: Bool, wasUserEntered: Bool, provenanceIdentifier: String?, condition: GlucoseCondition?, trendRate: HKQuantity?) { - self.startDate = startDate - self.quantity = quantity - self.isDisplayOnly = isDisplayOnly - self.wasUserEntered = wasUserEntered - self.provenanceIdentifier = provenanceIdentifier ?? "com.loopkit.LoopKitTests" - self.condition = condition - self.trendRate = trendRate - } -} - - -extension GlucoseFixtureValue: Comparable { - public static func <(lhs: GlucoseFixtureValue, rhs: GlucoseFixtureValue) -> Bool { - return lhs.startDate < rhs.startDate - } - - public static func ==(lhs: GlucoseFixtureValue, rhs: GlucoseFixtureValue) -> Bool { - return lhs.startDate == rhs.startDate && - lhs.quantity == rhs.quantity && - lhs.isDisplayOnly == rhs.isDisplayOnly && - lhs.wasUserEntered == rhs.wasUserEntered && - lhs.provenanceIdentifier == rhs.provenanceIdentifier && - lhs.condition == rhs.condition && - lhs.trendRate == rhs.trendRate - } -} - - -class GlucoseMathTests: XCTestCase { - - private func printFixture(_ effectVelocity: [GlucoseEffectVelocity]) { - let formatter = ISO8601DateFormatter.localTimeDate() - let unit = HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) - - print("\n\n") - print(String(data: try! JSONSerialization.data( - withJSONObject: effectVelocity.map({ (value) -> [String: Any] in - return [ - "startDate": formatter.string(from: value.startDate), - "endDate": formatter.string(from: value.endDate), - "value": value.quantity.doubleValue(for: unit), - "unit": unit.unitString - ] - }), - options: .prettyPrinted), encoding: .utf8)!) - print("\n\n") - } - - func loadInputFixture(_ resourceName: String) -> [GlucoseFixtureValue] { - let fixture: [JSONDictionary] = loadFixture(resourceName) - let dateFormatter = ISO8601DateFormatter.localTimeDate() - - return fixture.map { - return GlucoseFixtureValue( - startDate: dateFormatter.date(from: $0["date"] as! String)!, - quantity: HKQuantity(unit: HKUnit.milligramsPerDeciliter, doubleValue: $0["amount"] as! Double), - isDisplayOnly: ($0["display_only"] as? Bool) ?? false, - wasUserEntered: ($0["user_entered"] as? Bool) ?? false, - provenanceIdentifier: $0["provenance_identifier"] as? String, - condition: ($0["condition"] as? String).flatMap { GlucoseCondition(rawValue: $0) }, - trendRate: ($0["trend_rate"] as? Double).flatMap { HKQuantity(unit: .milligramsPerDeciliter, doubleValue: $0) } - ) - } - } - - func loadOutputFixture(_ resourceName: String) -> [GlucoseEffect] { - let fixture: [JSONDictionary] = loadFixture(resourceName) - let dateFormatter = ISO8601DateFormatter.localTimeDate() - - return fixture.map { - return GlucoseEffect(startDate: dateFormatter.date(from: $0["date"] as! String)!, quantity: HKQuantity(unit: HKUnit(from: $0["unit"] as! String), doubleValue: $0["amount"] as! Double)) - } - } - - func loadEffectVelocityFixture(_ resourceName: String) -> [GlucoseEffectVelocity] { - let fixture: [JSONDictionary] = loadFixture(resourceName) - let dateFormatter = ISO8601DateFormatter.localTimeDate() - - return fixture.map { - return GlucoseEffectVelocity(startDate: dateFormatter.date(from: $0["startDate"] as! String)!, endDate: dateFormatter.date(from: $0["endDate"] as! String)!, quantity: HKQuantity(unit: HKUnit(from: $0["unit"] as! String), doubleValue:$0["value"] as! Double)) - } - } - - func testMomentumEffectForBouncingGlucose() { - let input = loadInputFixture("momentum_effect_bouncing_glucose_input") - let output = loadOutputFixture("momentum_effect_bouncing_glucose_output") - - let effects = input.linearMomentumEffect() - let unit = HKUnit.milligramsPerDeciliter - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: unit), calculated.quantity.doubleValue(for: unit), accuracy: Double(Float.ulpOfOne)) - } - } - - func testMomentumEffectForRisingGlucose() { - let input = loadInputFixture("momentum_effect_rising_glucose_input") - let output = loadOutputFixture("momentum_effect_rising_glucose_output") - - let effects = input.linearMomentumEffect() - let unit = HKUnit.milligramsPerDeciliter - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: unit), calculated.quantity.doubleValue(for: unit), accuracy: Double(Float.ulpOfOne)) - } - } - - func testMomentumEffectForRisingGlucoseDoubles() { - let input = loadInputFixture("momentum_effect_rising_glucose_double_entries_input") - let output = loadOutputFixture("momentum_effect_rising_glucose_output") - - let effects = input.linearMomentumEffect() - let unit = HKUnit.milligramsPerDeciliter - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: unit), calculated.quantity.doubleValue(for: unit), accuracy: Double(Float.ulpOfOne)) - } - } - - func testMomentumEffectForFallingGlucose() { - let input = loadInputFixture("momentum_effect_falling_glucose_input") - let output = loadOutputFixture("momentum_effect_falling_glucose_output") - - let effects = input.linearMomentumEffect() - let unit = HKUnit.milligramsPerDeciliter - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: unit), calculated.quantity.doubleValue(for: unit), accuracy: Double(Float.ulpOfOne)) - } - } - - func testMomentumEffectForFallingGlucoseDuplicates() { - var input = loadInputFixture("momentum_effect_falling_glucose_input") - let output = loadOutputFixture("momentum_effect_falling_glucose_output") - input.append(contentsOf: input) - input.sort(by: <) - - let effects = input.linearMomentumEffect() - let unit = HKUnit.milligramsPerDeciliter - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: unit), calculated.quantity.doubleValue(for: unit), accuracy: Double(Float.ulpOfOne)) - } - } - - func testMomentumEffectForStableGlucose() { - let input = loadInputFixture("momentum_effect_stable_glucose_input") - let output = loadOutputFixture("momentum_effect_stable_glucose_output") - - let effects = input.linearMomentumEffect() - let unit = HKUnit.milligramsPerDeciliter - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: unit), calculated.quantity.doubleValue(for: unit), accuracy: Double(Float.ulpOfOne)) - } - } - - func testMomentumEffectForDuplicateGlucose() { - let input = loadInputFixture("momentum_effect_duplicate_glucose_input") - let effects = input.linearMomentumEffect() - - XCTAssertEqual(0, effects.count) - } - - func testMomentumEffectForEmptyGlucose() { - let input = [GlucoseFixtureValue]() - let effects = input.linearMomentumEffect() - - XCTAssertEqual(0, effects.count) - } - - func testMomentumEffectForSpacedOutGlucose() { - let input = loadInputFixture("momentum_effect_incomplete_glucose_input") - let effects = input.linearMomentumEffect() - - XCTAssertEqual(0, effects.count) - } - - func testMomentumEffectForTooFewGlucose() { - let input = loadInputFixture("momentum_effect_bouncing_glucose_input")[0...1] - let effects = input.linearMomentumEffect() - - XCTAssertEqual(0, effects.count) - } - - func testMomentumEffectForDisplayOnlyGlucose() { - let input = loadInputFixture("momentum_effect_display_only_glucose_input") - let effects = input.linearMomentumEffect() - - XCTAssertEqual(0, effects.count) - } - - func testMomentumEffectForMixedProvenanceGlucose() { - let input = loadInputFixture("momentum_effect_mixed_provenance_glucose_input") - let effects = input.linearMomentumEffect() - - XCTAssertEqual(0, effects.count) - } - - func testCounteractionEffectsForFallingGlucose() { - let input = loadInputFixture("counteraction_effect_falling_glucose_input") - let insulinEffect = loadOutputFixture("counteraction_effect_falling_glucose_insulin") - let output = loadEffectVelocityFixture("counteraction_effect_falling_glucose_output") - - let effects = input.counteractionEffects(to: insulinEffect) - let unit = HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: unit), calculated.quantity.doubleValue(for: unit), accuracy: Double(Float.ulpOfOne)) - } - } - - func testCounteractionEffectsForFallingGlucoseDuplicates() { - var input = loadInputFixture("counteraction_effect_falling_glucose_input") - input.append(contentsOf: input) - input.sort(by: <) - let insulinEffect = loadOutputFixture("counteraction_effect_falling_glucose_insulin") - let output = loadEffectVelocityFixture("counteraction_effect_falling_glucose_output") - - let effects = input.counteractionEffects(to: insulinEffect) - let unit = HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: unit), calculated.quantity.doubleValue(for: unit), accuracy: Double(Float.ulpOfOne)) - } - } - - func testCounteractionEffectsForFallingGlucoseAlmostDuplicates() { - let input = loadInputFixture("counteraction_effect_falling_glucose_almost_duplicates_input") - let insulinEffect = loadOutputFixture("counteraction_effect_falling_glucose_insulin") - let output = loadEffectVelocityFixture("counteraction_effect_falling_glucose_almost_duplicates_output") - - let effects = input.counteractionEffects(to: insulinEffect) - let unit = HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.endDate, calculated.endDate) - XCTAssertEqual(expected.quantity.doubleValue(for: unit), calculated.quantity.doubleValue(for: unit), accuracy: Double(Float.ulpOfOne)) - } - } - - func testCounteractionEffectsForNoGlucose() { - let input = [GlucoseFixtureValue]() - let insulinEffect = loadOutputFixture("counteraction_effect_falling_glucose_insulin") - let output = [GlucoseEffectVelocity]() - - let effects = input.counteractionEffects(to: insulinEffect) - - XCTAssertEqual(output.count, effects.count) - } - - func testMomentumEffectWithVelocityLimit() { - let input = loadInputFixture("momentum_effect_impossible_rising_glucose_input") - let output = loadOutputFixture("momentum_effect_impossible_rising_glucose_output") - - let effects = input.linearMomentumEffect() - let unit = HKUnit.milligramsPerDeciliter - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: unit), calculated.quantity.doubleValue(for: unit), accuracy: Double(Float.ulpOfOne)) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/GlucoseRangeScheduleTests.swift b/Dependencies/LoopKit/LoopKitTests/GlucoseRangeScheduleTests.swift deleted file mode 100644 index fffce3421..000000000 --- a/Dependencies/LoopKit/LoopKitTests/GlucoseRangeScheduleTests.swift +++ /dev/null @@ -1,268 +0,0 @@ -// -// GlucoseRangeScheduleTests.swift -// LoopKitTests -// -// Created by Nathaniel Hamming on 2021-03-09. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit - -@testable import LoopKit - -class GlucoseRangeScheduleTests: XCTestCase { - - func testInitializer() { - let glucoseRangeSchedule = GlucoseRangeSchedule( - unit: .milligramsPerDeciliter, - dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: DoubleRange(minValue: 75.0, maxValue: 90.0)), - RepeatingScheduleValue(startTime: 3000, value: DoubleRange(minValue: 100.0, maxValue: 120.0)), - RepeatingScheduleValue(startTime: 6000, value: DoubleRange(minValue: 130.0, maxValue: 150.0)) - ], - timeZone: TimeZone(secondsFromGMT: -14400)) - XCTAssertNotNil(glucoseRangeSchedule) - XCTAssertEqual(glucoseRangeSchedule!.unit, .milligramsPerDeciliter) - XCTAssertEqual(glucoseRangeSchedule!.rangeSchedule.items.count, 3) - XCTAssertEqual(glucoseRangeSchedule!.rangeSchedule.items[0].startTime, 0) - XCTAssertEqual(glucoseRangeSchedule!.rangeSchedule.items[0].value, DoubleRange(minValue: 75.0, maxValue: 90.0)) - XCTAssertEqual(glucoseRangeSchedule!.rangeSchedule.items[1].startTime, 3000) - XCTAssertEqual(glucoseRangeSchedule!.rangeSchedule.items[1].value, DoubleRange(minValue: 100.0, maxValue: 120.0)) - XCTAssertEqual(glucoseRangeSchedule!.rangeSchedule.items[2].startTime, 6000) - XCTAssertEqual(glucoseRangeSchedule!.rangeSchedule.items[2].value, DoubleRange(minValue: 130.0, maxValue: 150.0)) - XCTAssertEqual(glucoseRangeSchedule!.timeZone, TimeZone(secondsFromGMT: -14400)) - XCTAssertEqual(glucoseRangeSchedule!.minLowerBound(), HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 75)) - XCTAssertEqual(glucoseRangeSchedule!.scheduleRange(), HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 75)...HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 150)) - } - - func testInitializerWithOverride() { - let schedule = DailyQuantitySchedule( - unit: .milligramsPerDeciliter, - dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: DoubleRange(minValue: 75.0, maxValue: 90.0)), - RepeatingScheduleValue(startTime: 3000, value: DoubleRange(minValue: 100.0, maxValue: 120.0)), - RepeatingScheduleValue(startTime: 6000, value: DoubleRange(minValue: 130.0, maxValue: 150.0)) - ])! - let override = GlucoseRangeSchedule.Override( - value: DoubleRange(minValue: 90.0, maxValue: 110.0), - start: Date()) - - let glucoseRangeSchedule = GlucoseRangeSchedule( - rangeSchedule: schedule, - override: override) - XCTAssertNotNil(glucoseRangeSchedule) - XCTAssertEqual(glucoseRangeSchedule.unit, .milligramsPerDeciliter) - XCTAssertEqual(glucoseRangeSchedule.rangeSchedule.items.count, 3) - XCTAssertEqual(glucoseRangeSchedule.rangeSchedule.items[0].startTime, 0) - XCTAssertEqual(glucoseRangeSchedule.rangeSchedule.items[0].value, DoubleRange(minValue: 75.0, maxValue: 90.0)) - XCTAssertEqual(glucoseRangeSchedule.rangeSchedule.items[1].startTime, 3000) - XCTAssertEqual(glucoseRangeSchedule.rangeSchedule.items[1].value, DoubleRange(minValue: 100.0, maxValue: 120.0)) - XCTAssertEqual(glucoseRangeSchedule.rangeSchedule.items[2].startTime, 6000) - XCTAssertEqual(glucoseRangeSchedule.rangeSchedule.items[2].value, DoubleRange(minValue: 130.0, maxValue: 150.0)) - XCTAssertEqual(glucoseRangeSchedule.override, override) - } - - func testRawValue() { - let glucoseRangeSchedule = GlucoseRangeSchedule( - unit: .milligramsPerDeciliter, - dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: DoubleRange(minValue: 75.0, maxValue: 90.0)) - ]) - XCTAssertNotNil(glucoseRangeSchedule) - XCTAssertEqual(glucoseRangeSchedule!.rawValue["unit"] as! String, "mg/dL") - XCTAssertEqual((glucoseRangeSchedule!.rawValue["items"] as! [[String: Any]]).count, 1) - XCTAssertEqual((glucoseRangeSchedule!.rawValue["items"] as! [[String: Any]])[0]["value"] as! [Double], [75.0, 90.0]) - XCTAssertEqual((glucoseRangeSchedule!.rawValue["items"] as! [[String: Any]])[0]["startTime"] as! Double, 0.0) - } - - func testInitializerWithRawValueValid() { - let rawValue: GlucoseRangeSchedule.RawValue = [ - "timeZone": -14400, - "unit": "mg/dL", - "items": [ - [ - "startTime": 0.0, - "value": [ - 75.0, - 90.0 - ] - ] - ] - ] - - let glucoseRangeSchedule = GlucoseRangeSchedule(rawValue: rawValue) - XCTAssertNotNil(glucoseRangeSchedule) - XCTAssertEqual(glucoseRangeSchedule!.items, [RepeatingScheduleValue(startTime: 0, value: DoubleRange(minValue: 75.0, maxValue: 90.0))]) - XCTAssertEqual(glucoseRangeSchedule!.unit, .milligramsPerDeciliter) - XCTAssertEqual(glucoseRangeSchedule!.timeZone, TimeZone(secondsFromGMT: -14400)) - } - - func testInitializerWithRawValueWithValueMissing() { - let rawValue: GlucoseRangeSchedule.RawValue = [ - "timeZone": -14400, - "unit": "mg/dL" - ] - - XCTAssertNil(GlucoseRangeSchedule(rawValue: rawValue)) - } - - func testInitializerWithRawValueWithWrongType() { - let rawValue: GlucoseRangeSchedule.RawValue = [ - "units": "g", - "timeZone": "g", - "items": [ - [ - "startTime": 0, - "value": [ - 75, - 90 - ] - ] - ] - ] - XCTAssertNil(GlucoseRangeSchedule(rawValue: rawValue)) - } - - func testInitializerWithRawValueWithUnitMissing() { - let rawValue: GlucoseRangeSchedule.RawValue = [ - "timeZone": -14400, - "items": [ - [ - "startTime": 0.0, - "value": [ - 75.0, - 90.0 - ] - ] - ] - ] - XCTAssertNil(GlucoseRangeSchedule(rawValue: rawValue)) - } - - func testBetweenStartEnd() { - let therapyTimeZone = TimeZone(secondsFromGMT: -4*60*60)! - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = therapyTimeZone - let glucoseRangeSchedule = GlucoseRangeSchedule( - unit: .milligramsPerDeciliter, - dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: DoubleRange(minValue: 75.0, maxValue: 90.0)), - RepeatingScheduleValue(startTime: 3000, value: DoubleRange(minValue: 100.0, maxValue: 120.0)), - RepeatingScheduleValue(startTime: 6000, value: DoubleRange(minValue: 130.0, maxValue: 150.0)) - ], timeZone: therapyTimeZone) - let start = calendar.startOfDay(for: Date()) - let end = start.addingTimeInterval(TimeInterval.minutes(30)) - let expected = [AbsoluteScheduleValue(startDate: start, endDate: start.addingTimeInterval(TimeInterval.minutes(50)), value: DoubleRange(minValue: 75.0, maxValue: 90.0))] - - XCTAssertEqual(glucoseRangeSchedule!.between(start: start, end: end), expected) - } - - func testQuantityBetweenStartEnd() { - let therapyTimeZone = TimeZone(secondsFromGMT: -4*60*60)! - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = therapyTimeZone - let glucoseRangeSchedule = GlucoseRangeSchedule( - unit: .millimolesPerLiter, - dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: DoubleRange(minValue: 75.0, maxValue: 90.0)), - RepeatingScheduleValue(startTime: 3000, value: DoubleRange(minValue: 100.0, maxValue: 120.0)), - RepeatingScheduleValue(startTime: 6000, value: DoubleRange(minValue: 130.0, maxValue: 150.0)) - ], timeZone: therapyTimeZone) - let start = calendar.startOfDay(for: Date()) - let end = start.addingTimeInterval(TimeInterval.minutes(30)) - let expected = [AbsoluteScheduleValue(startDate: start, endDate: start.addingTimeInterval(TimeInterval.minutes(50)), value: DoubleRange(minValue: 75.0, maxValue: 90.0).quantityRange(for: .millimolesPerLiter))] - - XCTAssertEqual(glucoseRangeSchedule!.quantityBetween(start: start, end: end), expected) - } - - func testValueAtDate() { - let therapyTimeZone = TimeZone(secondsFromGMT: -4*60*60)! - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = therapyTimeZone - let glucoseRangeSchedule = GlucoseRangeSchedule( - unit: .milligramsPerDeciliter, - dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: DoubleRange(minValue: 75.0, maxValue: 90.0)), - RepeatingScheduleValue(startTime: 3000, value: DoubleRange(minValue: 100.0, maxValue: 120.0)), - RepeatingScheduleValue(startTime: 6000, value: DoubleRange(minValue: 130.0, maxValue: 150.0)) - ], timeZone: therapyTimeZone) - let inDay30Min = calendar.startOfDay(for: Date()).addingTimeInterval(TimeInterval.minutes(30)) - let inDay1Hour = inDay30Min.addingTimeInterval(TimeInterval.minutes(30)) - let inDay2Hours = inDay1Hour.addingTimeInterval(TimeInterval.minutes(60)) - - XCTAssertEqual(glucoseRangeSchedule!.value(at: inDay30Min), DoubleRange(minValue: 75.0, maxValue: 90.0)) - XCTAssertEqual(glucoseRangeSchedule!.value(at: inDay1Hour), DoubleRange(minValue: 100.0, maxValue: 120.0)) - XCTAssertEqual(glucoseRangeSchedule!.value(at: inDay2Hours), DoubleRange(minValue: 130.0, maxValue: 150.0)) - } - - func testQuantityRangeAtDate() { - let therapyTimeZone = TimeZone(secondsFromGMT: -4*60*60)! - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = therapyTimeZone - let glucoseRangeSchedule = GlucoseRangeSchedule( - unit: .milligramsPerDeciliter, - dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: DoubleRange(minValue: 75.0, maxValue: 90.0)), - RepeatingScheduleValue(startTime: 3000, value: DoubleRange(minValue: 100.0, maxValue: 120.0)), - RepeatingScheduleValue(startTime: 6000, value: DoubleRange(minValue: 130.0, maxValue: 150.0)) - ], timeZone: therapyTimeZone) - let inDay30Min = calendar.startOfDay(for: Date()).addingTimeInterval(TimeInterval.minutes(30)) - let inDay1Hour = inDay30Min.addingTimeInterval(TimeInterval.minutes(30)) - let inDay2Hours = inDay1Hour.addingTimeInterval(TimeInterval.minutes(60)) - - XCTAssertEqual(glucoseRangeSchedule!.quantityRange(at: inDay30Min), HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 75.0)...HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 90.0)) - XCTAssertEqual(glucoseRangeSchedule!.quantityRange(at: inDay1Hour), HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 100.0)...HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 120.0)) - XCTAssertEqual(glucoseRangeSchedule!.quantityRange(at: inDay2Hours), HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 130.0)...HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 150.0)) - } - - func testScheduleFor() { - let therapyTimeZone = TimeZone(secondsFromGMT: -4*60*60)! - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = therapyTimeZone - let glucoseRangeScheduleMGDL = GlucoseRangeSchedule( - unit: .milligramsPerDeciliter, - dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: DoubleRange(minValue: 75.0, maxValue: 90.0)) - ], timeZone: therapyTimeZone) - let glucoseRangeScheduleMMOLL = glucoseRangeScheduleMGDL?.schedule(for: .millimolesPerLiter) - let expected = DoubleRange(minValue: 75.0, maxValue: 90.0).quantityRange(for: .milligramsPerDeciliter).doubleRange(for: .millimolesPerLiter) - - XCTAssertNotNil(glucoseRangeScheduleMMOLL) - XCTAssertEqual(glucoseRangeScheduleMMOLL!.unit, .millimolesPerLiter) - XCTAssertEqual(glucoseRangeScheduleMMOLL!.rangeSchedule.items[0].value, expected) - } - - func testInitializeClosedHKQuantityRange() throws { - let dailyItems = [ - RepeatingScheduleValue(startTime: 0, value: DoubleRange(minValue: 75.0, maxValue: 90.0)), - RepeatingScheduleValue(startTime: 3000, value: DoubleRange(minValue: 100.0, maxValue: 120.0)), - RepeatingScheduleValue(startTime: 6000, value: DoubleRange(minValue: 130.0, maxValue: 150.0)) - ] - let dailyQuantities = dailyItems.map { - RepeatingScheduleValue(startTime: $0.startTime, - value: $0.value.quantityRange(for: .milligramsPerDeciliter)) - } - let rangeSchedule = DailyQuantitySchedule( - unit: .milligramsPerDeciliter, - dailyQuantities: dailyQuantities)! - let glucoseTargetRangeSchedule = GlucoseRangeSchedule(rangeSchedule: rangeSchedule) - - XCTAssertEqual(glucoseTargetRangeSchedule.rangeSchedule, rangeSchedule) - } - - func testQuantityRanges() throws { - let dailyItems = [ - RepeatingScheduleValue(startTime: 0, value: DoubleRange(minValue: 75.0, maxValue: 90.0)), - RepeatingScheduleValue(startTime: 3000, value: DoubleRange(minValue: 100.0, maxValue: 120.0)), - RepeatingScheduleValue(startTime: 6000, value: DoubleRange(minValue: 130.0, maxValue: 150.0)) - ] - let dailyQuantities = dailyItems.map { - RepeatingScheduleValue(startTime: $0.startTime, - value: $0.value.quantityRange(for: .milligramsPerDeciliter)) - } - let glucoseTargetRangeSchedule = GlucoseRangeSchedule(unit: .milligramsPerDeciliter, dailyItems: dailyItems)! - XCTAssertEqual(glucoseTargetRangeSchedule.quantityRanges, dailyQuantities) - } -} - diff --git a/Dependencies/LoopKit/LoopKitTests/GlucoseRangeTests.swift b/Dependencies/LoopKit/LoopKitTests/GlucoseRangeTests.swift deleted file mode 100644 index f97c57373..000000000 --- a/Dependencies/LoopKit/LoopKitTests/GlucoseRangeTests.swift +++ /dev/null @@ -1,118 +0,0 @@ -// -// GlucoseRangeTests.swift -// LoopKitTests -// -// Created by Nathaniel Hamming on 2021-03-16. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit - -@testable import LoopKit - -class GlucoseRangeTests: XCTestCase { - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() - - func testInitializerDouble() throws { - let unit = HKUnit.milligramsPerDeciliter - let glucoseRange = GlucoseRange( - minValue: 75, - maxValue: 90, - unit: unit) - let expectedRange = DoubleRange(minValue: 75, maxValue: 90) - - XCTAssertEqual(glucoseRange.range, expectedRange) - XCTAssertEqual(glucoseRange.unit, unit) - } - - func testInitializerGlucoseRange() throws { - let unit = HKUnit.milligramsPerDeciliter - let expectedRange = DoubleRange(minValue: 75, maxValue: 90) - let glucoseRange = GlucoseRange( - range: expectedRange, - unit: unit) - - XCTAssertEqual(glucoseRange.range, expectedRange) - XCTAssertEqual(glucoseRange.unit, unit) - } - - func testQuantityRange() throws { - let unit = HKUnit.milligramsPerDeciliter - let range = DoubleRange(minValue: 75, maxValue: 90) - let glucoseRange = GlucoseRange( - range: range, - unit: unit) - let expectedQuantityRange = range.quantityRange(for: unit) - XCTAssertEqual(glucoseRange.quantityRange, expectedQuantityRange) - } - - let encodedString = """ - { - "bloodGlucoseUnit" : "mg/dL", - "range" : { - "maxValue" : 90, - "minValue" : 75 - } - } - """ - - func testEncoding() throws { - let glucoseRange = GlucoseRange( - minValue: 75, - maxValue: 90, - unit: .milligramsPerDeciliter) - - let data = try encoder.encode(glucoseRange) - XCTAssertEqual(encodedString, String(data: data, encoding: .utf8)!) - } - - func testDecoding() throws { - let data = encodedString.data(using: .utf8)! - let decoded = try decoder.decode(GlucoseRange.self, from: data) - let expected = GlucoseRange( - minValue: 75, - maxValue: 90, - unit: .milligramsPerDeciliter) - - XCTAssertEqual(expected, decoded) - XCTAssertEqual(decoded.range, expected.range) - XCTAssertEqual(decoded.unit, expected.unit) - } - - func testRawValue() throws { - let glucoseRange = GlucoseRange( - minValue: 75, - maxValue: 90, - unit: .milligramsPerDeciliter) - var expectedRawValue: [String:Any] = [:] - expectedRawValue["bloodGlucoseUnit"] = "mg/dL" - expectedRawValue["range"] = DoubleRange(minValue: 75, maxValue: 90).rawValue - - XCTAssertEqual(glucoseRange.rawValue["bloodGlucoseUnit"] as? String, expectedRawValue["bloodGlucoseUnit"] as? String) - XCTAssertEqual(glucoseRange.rawValue["range"] as? DoubleRange.RawValue, expectedRawValue["range"] as? DoubleRange.RawValue) - } - - func testInitializeFromRawValue() throws { - var rawValue: [String:Any] = [:] - rawValue["bloodGlucoseUnit"] = "mg/dL" - rawValue["range"] = DoubleRange(minValue: 80, maxValue: 100).rawValue - - let glucoseRange = GlucoseRange(rawValue: rawValue) - let expectedRange = DoubleRange(minValue: 80, maxValue: 100) - XCTAssertEqual(glucoseRange?.range, expectedRange) - XCTAssertEqual(glucoseRange?.unit, .milligramsPerDeciliter) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/GlucoseStoreTests.swift b/Dependencies/LoopKit/LoopKitTests/GlucoseStoreTests.swift deleted file mode 100644 index 25ecac190..000000000 --- a/Dependencies/LoopKit/LoopKitTests/GlucoseStoreTests.swift +++ /dev/null @@ -1,426 +0,0 @@ -// -// GlucoseStoreTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 12/30/19. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -import CoreData -@testable import LoopKit - - -class GlucoseStoreTests: PersistenceControllerTestCase { - var healthStore: HKHealthStoreMock! - var glucoseStore: GlucoseStore! - - override func setUp() { - super.setUp() - - healthStore = HKHealthStoreMock() - glucoseStore = GlucoseStore(healthStore: healthStore, - cacheStore: cacheStore, - provenanceIdentifier: Bundle.main.bundleIdentifier!) - let semaphore = DispatchSemaphore(value: 0) - cacheStore.onReady { (error) in - semaphore.signal() - } - semaphore.wait() - } - - override func tearDown() { - glucoseStore = nil - healthStore = nil - - super.tearDown() - } - - func testLatestGlucoseIsSetAfterStoreAndClearedAfterPurge() { - let storeCompletion = expectation(description: "Storage completion") - let storedQuantity = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 80) - let device = HKDevice(name: "Unit Test Mock CGM", - manufacturer: "Device Manufacturer", - model: "Device Model", - hardwareVersion: "Device Hardware Version", - firmwareVersion: "Device Firmware Version", - softwareVersion: "Device Software Version", - localIdentifier: "Device Local Identifier", - udiDeviceIdentifier: "Device UDI Device Identifier") - let sample = NewGlucoseSample(date: Date(), quantity: storedQuantity, condition: nil, trend: nil, trendRate: nil, isDisplayOnly: false, wasUserEntered: false, syncIdentifier: "random", device: device) - glucoseStore.addGlucoseSamples([sample]) { (result) in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let samples): - XCTAssertEqual(storedQuantity, samples.first!.quantity) - } - storeCompletion.fulfill() - } - wait(for: [storeCompletion], timeout: 2) - XCTAssertEqual(storedQuantity, self.glucoseStore.latestGlucose?.quantity) - - let purgeCompletion = expectation(description: "Storage completion") - - let predicate = HKQuery.predicateForObjects(from: [device]) - glucoseStore.purgeAllGlucoseSamples(healthKitPredicate: predicate) { (error) in - if let error = error { - XCTFail("Unexpected failure: \(error)") - } - purgeCompletion.fulfill() - } - wait(for: [purgeCompletion], timeout: 2) - XCTAssertNil(self.glucoseStore.latestGlucose) - } -} - -class GlucoseStoreRemoteDataServiceQueryAnchorTests: XCTestCase { - var rawValue: GlucoseStore.QueryAnchor.RawValue = [ - "modificationCounter": Int64(123) - ] - - func testInitializerDefault() { - let queryAnchor = GlucoseStore.QueryAnchor() - XCTAssertEqual(queryAnchor.modificationCounter, 0) - } - - func testInitializerRawValue() { - let queryAnchor = GlucoseStore.QueryAnchor(rawValue: rawValue) - XCTAssertNotNil(queryAnchor) - XCTAssertEqual(queryAnchor?.modificationCounter, 123) - } - - func testInitializerRawValueMissingModificationCounter() { - rawValue["modificationCounter"] = nil - XCTAssertNil(GlucoseStore.QueryAnchor(rawValue: rawValue)) - } - - func testInitializerRawValueInvalidModificationCounter() { - rawValue["modificationCounter"] = "123" - XCTAssertNil(GlucoseStore.QueryAnchor(rawValue: rawValue)) - } - - func testRawValueWithDefault() { - let rawValue = GlucoseStore.QueryAnchor().rawValue - XCTAssertEqual(rawValue.count, 1) - XCTAssertEqual(rawValue["modificationCounter"] as? Int64, Int64(0)) - } - - func testRawValueWithNonDefault() { - var queryAnchor = GlucoseStore.QueryAnchor() - queryAnchor.modificationCounter = 123 - let rawValue = queryAnchor.rawValue - XCTAssertEqual(rawValue.count, 1) - XCTAssertEqual(rawValue["modificationCounter"] as? Int64, Int64(123)) - } -} - -class GlucoseStoreRemoteDataServiceQueryTests: PersistenceControllerTestCase { - var healthStore: HKHealthStoreMock! - var glucoseStore: GlucoseStore! - var completion: XCTestExpectation! - var queryAnchor: GlucoseStore.QueryAnchor! - var limit: Int! - - override func setUp() { - super.setUp() - - healthStore = HKHealthStoreMock() - glucoseStore = GlucoseStore(healthStore: healthStore, - cacheStore: cacheStore, - provenanceIdentifier: Bundle.main.bundleIdentifier!) - let semaphore = DispatchSemaphore(value: 0) - cacheStore.onReady { (error) in - semaphore.signal() - } - semaphore.wait() - completion = expectation(description: "Completion") - queryAnchor = GlucoseStore.QueryAnchor() - limit = Int.max - } - - override func tearDown() { - limit = nil - queryAnchor = nil - completion = nil - glucoseStore = nil - healthStore = nil - - super.tearDown() - } - - func testEmptyWithDefaultQueryAnchor() { - glucoseStore.executeGlucoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 0) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testEmptyWithMissingQueryAnchor() { - queryAnchor = nil - - glucoseStore.executeGlucoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 0) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testEmptyWithNonDefaultQueryAnchor() { - queryAnchor.modificationCounter = 1 - - glucoseStore.executeGlucoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 1) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithUnusedQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - glucoseStore.executeGlucoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(data.count, 3) - for (index, syncIdentifier) in syncIdentifiers.enumerated() { - XCTAssertEqual(data[index].syncIdentifier, syncIdentifier) - XCTAssertEqual(data[index].syncVersion, index) - } - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithStaleQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - queryAnchor.modificationCounter = 2 - - glucoseStore.executeGlucoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(data.count, 1) - XCTAssertEqual(data[0].syncIdentifier, syncIdentifiers[2]) - XCTAssertEqual(data[0].syncVersion, 2) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithCurrentQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - queryAnchor.modificationCounter = 3 - - glucoseStore.executeGlucoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithLimitZero() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - limit = 0 - - glucoseStore.executeGlucoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 0) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithLimitCoveredByData() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - limit = 2 - - glucoseStore.executeGlucoseQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 2) - XCTAssertEqual(data.count, 2) - XCTAssertEqual(data[0].syncIdentifier, syncIdentifiers[0]) - XCTAssertEqual(data[0].syncVersion, 0) - XCTAssertEqual(data[1].syncIdentifier, syncIdentifiers[1]) - XCTAssertEqual(data[1].syncVersion, 1) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - private func addData(withSyncIdentifiers syncIdentifiers: [String]) { - cacheStore.managedObjectContext.performAndWait { - for (index, syncIdentifier) in syncIdentifiers.enumerated() { - let cachedGlucoseObject = CachedGlucoseObject(context: self.cacheStore.managedObjectContext) - cachedGlucoseObject.uuid = UUID() - cachedGlucoseObject.provenanceIdentifier = syncIdentifier - cachedGlucoseObject.syncIdentifier = syncIdentifier - cachedGlucoseObject.syncVersion = index - cachedGlucoseObject.value = 123 - cachedGlucoseObject.unitString = HKUnit.milligramsPerDeciliter.unitString - cachedGlucoseObject.startDate = Date() - self.cacheStore.save() - } - } - } - - private func generateSyncIdentifier() -> String { - return UUID().uuidString - } -} - -class GlucoseStoreCriticalEventLogExportTests: PersistenceControllerTestCase { - var glucoseStore: GlucoseStore! - var outputStream: MockOutputStream! - var progress: Progress! - - override func setUp() { - super.setUp() - - let samples = [NewGlucoseSample(date: dateFormatter.date(from: "2100-01-02T03:08:00Z")!, quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 111), condition: nil, trend: nil, trendRate: nil, isDisplayOnly: false, wasUserEntered: false, syncIdentifier: "18CF3948-0B3D-4B12-8BFE-14986B0E6784", syncVersion: 1), - NewGlucoseSample(date: dateFormatter.date(from: "2100-01-02T03:10:00Z")!, quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 112), condition: nil, trend: .up, trendRate: HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: 1.0), isDisplayOnly: false, wasUserEntered: false, syncIdentifier: "C86DEB61-68E9-464E-9DD5-96A9CB445FD3", syncVersion: 2), - NewGlucoseSample(date: dateFormatter.date(from: "2100-01-02T03:04:00Z")!, quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 113), condition: nil, trend: .up, trendRate: HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: 1.0), isDisplayOnly: false, wasUserEntered: false, syncIdentifier: "2B03D96C-6F5D-4140-99CD-80C3E64D6010", syncVersion: 3), - NewGlucoseSample(date: dateFormatter.date(from: "2100-01-02T03:06:00Z")!, quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 114), condition: nil, trend: .up, trendRate: HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: 1.0), isDisplayOnly: false, wasUserEntered: false, syncIdentifier: "FF1C4F01-3558-4FB2-957E-FA1522C4735E", syncVersion: 4), - NewGlucoseSample(date: dateFormatter.date(from: "2100-01-02T03:02:00Z")!, quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 400), condition: .aboveRange, trend: .upUpUp, trendRate: HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: 1.0), isDisplayOnly: false, wasUserEntered: false, syncIdentifier: "71B699D7-0E8F-4B13-B7A1-E7751EB78E74", syncVersion: 5)] - - glucoseStore = GlucoseStore(healthStore: HKHealthStoreMock(), - cacheStore: cacheStore, - provenanceIdentifier: Bundle.main.bundleIdentifier!) - - let dispatchGroup = DispatchGroup() - dispatchGroup.enter() - glucoseStore.addNewGlucoseSamples(samples: samples) { error in - XCTAssertNil(error) - dispatchGroup.leave() - } - dispatchGroup.wait() - - outputStream = MockOutputStream() - progress = Progress() - } - - override func tearDown() { - glucoseStore = nil - - super.tearDown() - } - - func testExportProgressTotalUnitCount() { - switch glucoseStore.exportProgressTotalUnitCount(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!) { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let progressTotalUnitCount): - XCTAssertEqual(progressTotalUnitCount, 3 * 1) - } - } - - func testExportProgressTotalUnitCountEmpty() { - switch glucoseStore.exportProgressTotalUnitCount(startDate: dateFormatter.date(from: "2100-01-02T03:00:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:01:00Z")!) { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let progressTotalUnitCount): - XCTAssertEqual(progressTotalUnitCount, 0) - } - } - - func testExport() { - XCTAssertNil(glucoseStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!, - to: outputStream, - progress: progress)) - XCTAssertEqual(outputStream.string, """ - [ - {"isDisplayOnly":false,"modificationCounter":1,"provenanceIdentifier":"com.apple.dt.xctest.tool","startDate":"2100-01-02T03:08:00.000Z","syncIdentifier":"18CF3948-0B3D-4B12-8BFE-14986B0E6784","syncVersion":1,"unitString":"mg/dL","value":111,"wasUserEntered":false}, - {"isDisplayOnly":false,"modificationCounter":3,"provenanceIdentifier":"com.apple.dt.xctest.tool","startDate":"2100-01-02T03:04:00.000Z","syncIdentifier":"2B03D96C-6F5D-4140-99CD-80C3E64D6010","syncVersion":3,"trend":3,"trendRateUnit":"mg/min·dL","trendRateValue":1,"unitString":"mg/dL","value":113,"wasUserEntered":false}, - {"isDisplayOnly":false,"modificationCounter":4,"provenanceIdentifier":"com.apple.dt.xctest.tool","startDate":"2100-01-02T03:06:00.000Z","syncIdentifier":"FF1C4F01-3558-4FB2-957E-FA1522C4735E","syncVersion":4,"trend":3,"trendRateUnit":"mg/min·dL","trendRateValue":1,"unitString":"mg/dL","value":114,"wasUserEntered":false} - ] - """ - ) - XCTAssertEqual(progress.completedUnitCount, 3 * 1) - } - - func testExportEmpty() { - XCTAssertNil(glucoseStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:00:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:01:00Z")!, - to: outputStream, - progress: progress)) - XCTAssertEqual(outputStream.string, "[]") - XCTAssertEqual(progress.completedUnitCount, 0) - } - - func testExportCancelled() { - progress.cancel() - XCTAssertEqual(glucoseStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!, - to: outputStream, - progress: progress) as? CriticalEventLogError, CriticalEventLogError.cancelled) - } - - private let dateFormatter = ISO8601DateFormatter() -} diff --git a/Dependencies/LoopKit/LoopKitTests/GlucoseThresholdTests.swift b/Dependencies/LoopKit/LoopKitTests/GlucoseThresholdTests.swift deleted file mode 100644 index 801e05275..000000000 --- a/Dependencies/LoopKit/LoopKitTests/GlucoseThresholdTests.swift +++ /dev/null @@ -1,120 +0,0 @@ -// -// GlucoseThresholdTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 8/24/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit - -@testable import LoopKit - -class GlucoseThresholdTests: XCTestCase { - - func testInitializer() { - let glucoseThreshold = GlucoseThreshold(unit: HKUnit.gram(), value: 1.23) - XCTAssertEqual(glucoseThreshold.value, 1.23) - XCTAssertEqual(glucoseThreshold.unit, HKUnit.gram()) - } - - func testInitializerWithRawValueValid() { - let rawValue: GlucoseThreshold.RawValue = [ - "units": "g", - "value": 1.23 - ] - let glucoseThreshold = GlucoseThreshold(rawValue: rawValue) - XCTAssertNotNil(glucoseThreshold) - XCTAssertEqual(glucoseThreshold!.value, 1.23) - XCTAssertEqual(glucoseThreshold!.unit, HKUnit.gram()) - } - - func testInitializerWithRawValueWithValueMissing() { - let rawValue: GlucoseThreshold.RawValue = [ - "units": "g" - ] - XCTAssertNil(GlucoseThreshold(rawValue: rawValue)) - } - - func testInitializerWithRawValueWithValueNotDouble() { - let rawValue: GlucoseThreshold.RawValue = [ - "units": "g", - "value": "g" - ] - XCTAssertNil(GlucoseThreshold(rawValue: rawValue)) - } - - func testInitializerWithRawValueWithUnitMissing() { - let rawValue: GlucoseThreshold.RawValue = [ - "value": 1.23 - ] - XCTAssertNil(GlucoseThreshold(rawValue: rawValue)) - } - - func testInitializerWithRawValueWithUnitNotString() { - let rawValue: GlucoseThreshold.RawValue = [ - "units": 1.23, - "value": 1.23 - ] - XCTAssertNil(GlucoseThreshold(rawValue: rawValue)) - } - - func testQuantity() { - let glucoseThreshold = GlucoseThreshold(unit: HKUnit.gram(), value: 1.23) - XCTAssertEqual(glucoseThreshold.quantity, HKQuantity(unit: HKUnit.gram(), doubleValue: 1.23)) - } - - func testRawValue() { - let glucoseThreshold = GlucoseThreshold(unit: HKUnit.gram(), value: 1.23) - XCTAssertEqual(glucoseThreshold.rawValue.count, 2) - XCTAssertEqual(glucoseThreshold.rawValue["units"] as! String, "g") - XCTAssertEqual(glucoseThreshold.rawValue["value"] as! Double, 1.23) - } - - func testConvertTo() { - let glucoseThresholdMMOLL = GlucoseThreshold(unit: .millimolesPerLiter, value: 4.4) - let glucoseThresholdMGDL = glucoseThresholdMMOLL.convertTo(unit: .milligramsPerDeciliter) - XCTAssertEqual(glucoseThresholdMGDL.unit, .milligramsPerDeciliter) - XCTAssertEqual(glucoseThresholdMGDL.value, HKQuantity(unit: .millimolesPerLiter, doubleValue: glucoseThresholdMMOLL.value).doubleValue(for: .milligramsPerDeciliter)) - } -} - -class GlucoseThresholdCodableTests: XCTestCase { - func testCodableMilligramsPerDeciliter() throws { - try assertGlucoseThresholdCodable(GlucoseThreshold(unit: .milligramsPerDeciliter, value: 123), - encodesJSON: """ -{ - "unit" : "mg/dL", - "value" : 123 -} -""" - ) - } - - func testCodableMillimolesPerLiter() throws { - try assertGlucoseThresholdCodable(GlucoseThreshold(unit: .millimolesPerLiter, value: 6.5), - encodesJSON: """ -{ - "unit" : "mmol<180.1558800000541>/L", - "value" : 6.5 -} -""" - ) - } - - private func assertGlucoseThresholdCodable(_ original: GlucoseThreshold, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(GlucoseThreshold.self, from: data) - XCTAssertEqual(decoded, original) - } - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - return encoder - }() - - private let decoder = JSONDecoder() -} diff --git a/Dependencies/LoopKit/LoopKitTests/GlucoseValueTests.swift b/Dependencies/LoopKit/LoopKitTests/GlucoseValueTests.swift deleted file mode 100644 index 1c6553e62..000000000 --- a/Dependencies/LoopKit/LoopKitTests/GlucoseValueTests.swift +++ /dev/null @@ -1,157 +0,0 @@ -// -// GlucoseValueTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 5/4/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit - -@testable import LoopKit - -class SimpleGlucoseValueTests: XCTestCase { - func testInitializerMilligramsPerDeciliter() { - let startDate = Date() - let endDate = Date().addingTimeInterval(.hours(1)) - let quantity = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 234.5) - let simpleGlucoseValue = SimpleGlucoseValue(startDate: startDate, endDate: endDate, quantity: quantity) - XCTAssertEqual(simpleGlucoseValue.startDate, startDate) - XCTAssertEqual(simpleGlucoseValue.endDate, endDate) - XCTAssertEqual(simpleGlucoseValue.quantity, quantity) - } - - func testInitializerMillimolesPerLiter() { - let startDate = Date() - let endDate = Date().addingTimeInterval(.hours(1)) - let quantity = HKQuantity(unit: .millimolesPerLiter, doubleValue: 12.3) - let simpleGlucoseValue = SimpleGlucoseValue(startDate: startDate, endDate: endDate, quantity: quantity) - XCTAssertEqual(simpleGlucoseValue.startDate, startDate) - XCTAssertEqual(simpleGlucoseValue.endDate, endDate) - XCTAssertEqual(simpleGlucoseValue.quantity, quantity) - } - - func testInitializerMissingEndDate() { - let startDate = Date() - let quantity = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 234.5) - let simpleGlucoseValue = SimpleGlucoseValue(startDate: startDate, quantity: quantity) - XCTAssertEqual(simpleGlucoseValue.startDate, startDate) - XCTAssertEqual(simpleGlucoseValue.endDate, startDate) - XCTAssertEqual(simpleGlucoseValue.quantity, quantity) - } - - func testInitializerGlucoseValue() { - let startDate = Date() - let endDate = Date().addingTimeInterval(.hours(1)) - let quantity = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 234.5) - let simpleGlucoseValue = SimpleGlucoseValue(SimpleGlucoseValue(startDate: startDate, endDate: endDate, quantity: quantity)) - XCTAssertEqual(simpleGlucoseValue.startDate, startDate) - XCTAssertEqual(simpleGlucoseValue.endDate, endDate) - XCTAssertEqual(simpleGlucoseValue.quantity, quantity) - } -} - -class SimpleGlucoseValueCodableTests: XCTestCase { - func testCodableMilligramsPerDeciliter() throws { - try assertSimpleGlucoseValueCodable(SimpleGlucoseValue(startDate: dateFormatter.date(from: "2020-05-14T22:00:03Z")!, - endDate: dateFormatter.date(from: "2020-05-14T23:00:03Z")!, - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 234.5)), - encodesJSON: """ -{ - "endDate" : "2020-05-14T23:00:03Z", - "quantity" : 234.5, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T22:00:03Z" -} -""" - ) - } - - func testCodableMillimolesPerLiter() throws { - try assertSimpleGlucoseValueCodable(SimpleGlucoseValue(startDate: dateFormatter.date(from: "2020-05-14T14:05:03Z")!, - endDate: dateFormatter.date(from: "2020-05-14T15:05:03Z")!, - quantity: HKQuantity(unit: .millimolesPerLiter, doubleValue: 13.2)), - encodesJSON: """ -{ - "endDate" : "2020-05-14T15:05:03Z", - "quantity" : 237.80576160007135, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T14:05:03Z" -} -""" - ) - } - - private func assertSimpleGlucoseValueCodable(_ original: SimpleGlucoseValue, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(SimpleGlucoseValue.self, from: data) - XCTAssertEqual(decoded, original) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() -} - -class PredictedGlucoseValueCodableTests: XCTestCase { - func testCodableMilligramsPerDeciliter() throws { - try assertPredictedGlucoseValueCodable(PredictedGlucoseValue(startDate: dateFormatter.date(from: "2020-05-14T22:38:26Z")!, - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 234.5)), - encodesJSON: """ -{ - "quantity" : 234.5, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T22:38:26Z" -} -""" - ) - } - - func testCodableMillimolesPerLiter() throws { - try assertPredictedGlucoseValueCodable(PredictedGlucoseValue(startDate: dateFormatter.date(from: "2020-05-14T21:23:33Z")!, - quantity: HKQuantity(unit: .millimolesPerLiter, doubleValue: 12.3)), - encodesJSON: """ -{ - "quantity" : 221.59173240006652, - "quantityUnit" : "mg/dL", - "startDate" : "2020-05-14T21:23:33Z" -} -""" - ) - } - - private func assertPredictedGlucoseValueCodable(_ original: PredictedGlucoseValue, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(PredictedGlucoseValue.self, from: data) - XCTAssertEqual(decoded, original) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() -} diff --git a/Dependencies/LoopKit/LoopKitTests/GuardrailTests.swift b/Dependencies/LoopKit/LoopKitTests/GuardrailTests.swift deleted file mode 100644 index f48f38a63..000000000 --- a/Dependencies/LoopKit/LoopKitTests/GuardrailTests.swift +++ /dev/null @@ -1,304 +0,0 @@ -// -// GuardrailTests.swift -// GuardrailTests -// -// Created by Michael Pangburn on 7/30/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class GuardrailTests: XCTestCase { - let correctionRangeSchedule120 = GlucoseRangeSchedule(unit: .milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: 0, value: DoubleRange(120...130))]) - let preMealTargetRange120 = DoubleRange(120...130).quantityRange(for: .milligramsPerDeciliter) - let workoutTargetRange120 = DoubleRange(120...130).quantityRange(for: .milligramsPerDeciliter) - let correctionRangeSchedule80 = GlucoseRangeSchedule(unit: .milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: 0, value: DoubleRange(80...100))]) - let preMealTargetRange85 = DoubleRange(85...100).quantityRange(for: .milligramsPerDeciliter) - let workoutTargetRange90 = DoubleRange(90...100).quantityRange(for: .milligramsPerDeciliter) - - func testSuspendThresholdUnits() { - XCTAssertTrue(Guardrail.suspendThreshold.absoluteBounds.contains(HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 67))) - XCTAssertTrue(Guardrail.suspendThreshold.absoluteBounds.contains(HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 110))) - XCTAssertTrue(Guardrail.suspendThreshold.absoluteBounds.contains(HKQuantity(unit: .millimolesPerLiter, doubleValue: 6.1))) - XCTAssertTrue(Guardrail.suspendThreshold.recommendedBounds.contains(HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 74))) - XCTAssertTrue(Guardrail.suspendThreshold.recommendedBounds.contains(HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 80))) - XCTAssertTrue(Guardrail.suspendThreshold.absoluteBounds.contains(HKQuantity(unit: .millimolesPerLiter, doubleValue: 4.44))) - } - - func testMaxSuspensionThresholdValue() { - let correctionRangeInputs = [ nil, correctionRangeSchedule120, correctionRangeSchedule80 ] - let preMealInputs = [ nil, preMealTargetRange120, preMealTargetRange85 ] - let workoutInputs = [ nil, workoutTargetRange120, workoutTargetRange90 ] - let expected: [Double] = [ 110, 110, 90, - 110, 110, 90, - 85, 85, 85, - 110, 110, 90, - 110, 110, 90, - 85, 85, 85, - 80, 80, 80, - 80, 80, 80, - 80, 80, 80 ] - var index = 0 - for correctionRange in correctionRangeInputs { - for preMeal in preMealInputs { - for workout in workoutInputs { - let maxSuspendThresholdValue = Guardrail.maxSuspendThresholdValue(correctionRangeSchedule: correctionRange, preMealTargetRange: preMeal, workoutTargetRange: workout).doubleValue(for: .milligramsPerDeciliter) - XCTAssertEqual(expected[index], maxSuspendThresholdValue, "Index \(index) failed") - index += 1 - } - } - } - } - - func testMinCorrectionRangeValue() { - let suspendThresholdInputs: [Double?] = [ nil, 80, 88 ] - let expected: [Double] = [ 87, 87, 88 ] - for (index, suspendThreshold) in suspendThresholdInputs.enumerated() { - XCTAssertEqual(expected[index], Guardrail.minCorrectionRangeValue(suspendThreshold: suspendThreshold.map { GlucoseThreshold(unit: .milligramsPerDeciliter, value: $0) }).doubleValue(for: .milligramsPerDeciliter), "Index \(index) failed") - } - } - - func testCorrectionRange() { - let guardrail = Guardrail.correctionRange - let expectedAndTest: [(SafetyClassification, Double)] = [ - (SafetyClassification.withinRecommendedRange, 100), - (SafetyClassification.withinRecommendedRange, 115), - (SafetyClassification.outsideRecommendedRange(.belowRecommended), 100.nextDown), - (SafetyClassification.outsideRecommendedRange(.aboveRecommended), 115.nextUp), - (SafetyClassification.outsideRecommendedRange(.maximum), 180), - (SafetyClassification.outsideRecommendedRange(.minimum), 87), - ] - - for test in expectedAndTest { - XCTAssertEqual(test.0, guardrail.classification(for: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: test.1)), "for \(test.1)") - } - } - - func testWorkoutCorrectionRange() { - let correctionRangeInputs = [ 70...80, 70...85, 70...90 ] - let suspendThresholdInputs: [Double?] = [ nil, 81, 91 ] - let expectedLow: [Double] = [ 87, 87, 91, - 87, 87, 91, - 90, 90, 91 ] - let expectedMin: [Double] = [ 87, 87, 91, 87, 87, 91, 87, 87, 91 ] - - var index = 0 - for correctionRange in correctionRangeInputs { - for suspendThreshold in suspendThresholdInputs { - let guardrail = Guardrail.correctionRangeOverride(for: .workout, correctionRangeScheduleRange: correctionRange.range(withUnit: .milligramsPerDeciliter), suspendThreshold: suspendThreshold.map { GlucoseThreshold(unit: .milligramsPerDeciliter, value: $0) }) - XCTAssertEqual(expectedLow[index], guardrail.recommendedBounds.lowerBound.doubleValue(for: .milligramsPerDeciliter), "Index \(index) failed") - XCTAssertEqual(expectedMin[index], guardrail.absoluteBounds.lowerBound.doubleValue(for: .milligramsPerDeciliter), "Index \(index) failed") - index += 1 - } - } - } - - func testPreMealCorrectionRange() { - let correctionRangeInputs = [ 60...80, 100...110, 150...180 ] - let suspendThresholdInputs: [Double?] = [ nil, 90 ] - let expectedRecommendedHigh: [Double] = [ 67, 90, - 100, 100, - 130, 130 ] - let expectedMin: [Double] = [ 67, 90, 67, 90, 67, 90 ] - - var index = 0 - for correctionRange in correctionRangeInputs { - for suspendThreshold in suspendThresholdInputs { - let guardrail = Guardrail.correctionRangeOverride(for: .preMeal, correctionRangeScheduleRange: correctionRange.range(withUnit: .milligramsPerDeciliter), suspendThreshold: suspendThreshold.map { GlucoseThreshold(unit: .milligramsPerDeciliter, value: $0) }) - XCTAssertEqual(expectedRecommendedHigh[index], guardrail.recommendedBounds.upperBound.doubleValue(for: .milligramsPerDeciliter), "Index \(index) failed") - XCTAssertEqual(expectedMin[index], guardrail.absoluteBounds.lowerBound.doubleValue(for: .milligramsPerDeciliter), "Index \(index) failed") - XCTAssertEqual(guardrail.absoluteBounds.lowerBound.doubleValue(for: .milligramsPerDeciliter), - guardrail.recommendedBounds.lowerBound.doubleValue(for: .milligramsPerDeciliter), "Index \(index) failed") - index += 1 - } - } - } - - func testCarbRatioGuardrail() { - XCTAssertEqual(2.0...150.0, Guardrail.carbRatio.absoluteBounds.range(withUnit: .gramsPerUnit)) - XCTAssertEqual(4...28, Guardrail.carbRatio.recommendedBounds.range(withUnit: .gramsPerUnit)) - } - - func testBasalRateGuardrail() { - let supportedBasalRates = (2...600).map { Double($0) / 20 } - let guardrail = Guardrail.basalRate(supportedBasalRates: supportedBasalRates) - XCTAssertEqual(0.1...30.0, guardrail.absoluteBounds.range(withUnit: .internationalUnitsPerHour)) - XCTAssertEqual(0.1...30.0, guardrail.recommendedBounds.range(withUnit: .internationalUnitsPerHour)) - } - - func testBasalRateGuardrailClampedLow() { - let supportedBasalRates = [-1, 0.01, 1.0, 30.0] - let guardrail = Guardrail.basalRate(supportedBasalRates: supportedBasalRates) - XCTAssertEqual(0.01...30.0, guardrail.absoluteBounds.range(withUnit: .internationalUnitsPerHour)) - XCTAssertEqual(0.01...30.0, guardrail.recommendedBounds.range(withUnit: .internationalUnitsPerHour)) - } - - func testBasalRateGuardrailClampedHigh() { - let supportedBasalRates = (2...800).map { Double($0) / 20 } - let guardrail = Guardrail.basalRate(supportedBasalRates: supportedBasalRates) - XCTAssertEqual(guardrail.absoluteBounds.range(withUnit: .internationalUnitsPerHour), 0.1...30.0) - XCTAssertEqual(guardrail.recommendedBounds.range(withUnit: .internationalUnitsPerHour), 0.1...30.0) - } - - func testBasalRateGuardrailZeroDropsFirst() { - let supportedBasalRates = [-1, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0] - let guardrail = Guardrail.basalRate(supportedBasalRates: supportedBasalRates) - XCTAssertEqual(guardrail.absoluteBounds.range(withUnit: .internationalUnitsPerHour), 0.0...5.0) - XCTAssertEqual(guardrail.recommendedBounds.range(withUnit: .internationalUnitsPerHour), 0.0...5.0) - } - - func testMaxBasalRateGuardrail() { - let supportedBasalRates = (1...600).map { Double($0) / 20 } - let scheduledBasalRange = 0.05...0.78125 - let lowestCarbRatio = 10.0 - let guardrail = Guardrail.maximumBasalRate(supportedBasalRates: supportedBasalRates, scheduledBasalRange: scheduledBasalRange, lowestCarbRatio: lowestCarbRatio) - XCTAssertEqual(guardrail.absoluteBounds.range(withUnit: .internationalUnitsPerHour), 0.78125...7.0) - XCTAssertEqual(guardrail.recommendedBounds.range(withUnit: .internationalUnitsPerHour), 1.6...5.0) - } - - func testMaxBasalRateGuardrailHighCarbRatio() { - let supportedBasalRates = (1...600).map { Double($0) / 20 } - let scheduledBasalRange = 0.05...0.78125 - let lowestCarbRatio = 150.0 - let guardrail = Guardrail.maximumBasalRate(supportedBasalRates: supportedBasalRates, scheduledBasalRange: scheduledBasalRange, lowestCarbRatio: lowestCarbRatio) - XCTAssertEqual(guardrail.absoluteBounds.range(withUnit: .internationalUnitsPerHour), 0.78125...5.0) - XCTAssertEqual(guardrail.recommendedBounds.range(withUnit: .internationalUnitsPerHour), 1.6...5.0) - } - - func testMaxBasalRateGuardrailHigherCarbRatioClampsRecommendedBounds() { - let supportedBasalRates = (1...600).map { Double($0) / 20 } - let scheduledBasalRange = 0.05...0.78125 - let lowestCarbRatio = 15.0 - let guardrail = Guardrail.maximumBasalRate(supportedBasalRates: supportedBasalRates, scheduledBasalRange: scheduledBasalRange, lowestCarbRatio: lowestCarbRatio) - XCTAssertEqual(guardrail.absoluteBounds.range(withUnit: .internationalUnitsPerHour), 0.78125...5.0) - XCTAssertEqual(guardrail.recommendedBounds.range(withUnit: .internationalUnitsPerHour), 1.6...5.0) - } - - func testMaxBasalRateGuardrailNoCarbRatio() { - let supportedBasalRates = (1...600).map { Double($0) / 20 } - let scheduledBasalRange = 0.05...0.78125 - let guardrail = Guardrail.maximumBasalRate(supportedBasalRates: supportedBasalRates, scheduledBasalRange: scheduledBasalRange, lowestCarbRatio: nil) - XCTAssertEqual(guardrail.absoluteBounds.range(withUnit: .internationalUnitsPerHour), 0.78125...30.0) - XCTAssertEqual(guardrail.recommendedBounds.range(withUnit: .internationalUnitsPerHour), 1.6...5.0) - } - - func testMaxBasalRateGuardrailFewSupportedBasalRates() { - let supportedBasalRates = [0.05, 1.0] - let scheduledBasalRange = 0.05...0.78125 - let lowestCarbRatio = 10.0 - let guardrail = Guardrail.maximumBasalRate(supportedBasalRates: supportedBasalRates, scheduledBasalRange: scheduledBasalRange, lowestCarbRatio: lowestCarbRatio) - XCTAssertEqual(guardrail.absoluteBounds.range(withUnit: .internationalUnitsPerHour), 0.78125...1.0) - XCTAssertEqual(guardrail.recommendedBounds.range(withUnit: .internationalUnitsPerHour), 1.0...1.0) - } - - func testMaxBasalRateGuardrailHighestScheduledBasalZero() { - let supportedBasalRates = [0.0, 1.0] - let scheduledBasalRange = 0.0...0.0 - let lowestCarbRatio = 10.0 - let guardrail = Guardrail.maximumBasalRate(supportedBasalRates: supportedBasalRates, scheduledBasalRange: scheduledBasalRange, lowestCarbRatio: lowestCarbRatio) - XCTAssertEqual(guardrail.absoluteBounds.range(withUnit: .internationalUnitsPerHour), 0.0...1.0) - XCTAssertEqual(guardrail.recommendedBounds.range(withUnit: .internationalUnitsPerHour), 0.0...0.0) - } - - func testMaxBasalRateGuardrailNoScheduledBasalRates() { - let supportedBasalRates = [0, 0.05, 1.0] - let lowestCarbRatio = 10.0 - let guardrail = Guardrail.maximumBasalRate(supportedBasalRates: supportedBasalRates, scheduledBasalRange: nil, lowestCarbRatio: lowestCarbRatio) - XCTAssertEqual(guardrail.absoluteBounds.range(withUnit: .internationalUnitsPerHour), 0.05...1.0) - XCTAssertEqual(guardrail.recommendedBounds.range(withUnit: .internationalUnitsPerHour), 0.05...1.0) - } - - func testSelectableBasalRatesGuardrail() { - let supportedBasalRates = [0, 0.05, 1.0] - let scheduledBasalRange = 0.05...0.78125 - let lowestCarbRatio = 10.0 - let selectableMaxBasalRates = Guardrail.selectableMaxBasalRates(supportedBasalRates: supportedBasalRates, scheduledBasalRange: scheduledBasalRange, lowestCarbRatio: lowestCarbRatio) - XCTAssertEqual([1.0], selectableMaxBasalRates) - } - - func testSelectableBasalRatesGuardrailNoScheduledBasalRates() { - let supportedBasalRates = [0, 0.05, 1.0] - let lowestCarbRatio = 10.0 - let selectableMaxBasalRates = Guardrail.selectableMaxBasalRates(supportedBasalRates: supportedBasalRates, scheduledBasalRange: nil, lowestCarbRatio: lowestCarbRatio) - XCTAssertEqual([0.05, 1.0], selectableMaxBasalRates) - } - - func testMaxBolusGuardrailInsideLimits() { - let supportedBolusVolumes = [0.05, 1.0, 2.0] - let guardrail = Guardrail.maximumBolus(supportedBolusVolumes: supportedBolusVolumes) - XCTAssertEqual(guardrail.absoluteBounds.range(withUnit: .internationalUnit()), 0.05...2.0) - XCTAssertEqual(guardrail.recommendedBounds.range(withUnit: .internationalUnit()), 1.0...2.0) - } - - func testMaxBolusGuardrailClamped() { - let supportedBolusVolumes = [0.05, 1.0, 2.0, 20.0.nextDown, 20.0, 25.0, 30.0, 30.0.nextUp] - let guardrail = Guardrail.maximumBolus(supportedBolusVolumes: supportedBolusVolumes) - XCTAssertEqual(guardrail.absoluteBounds.range(withUnit: .internationalUnit()), 0.05...30.0) - XCTAssertEqual(guardrail.recommendedBounds.range(withUnit: .internationalUnit()), 1.0...20.0.nextDown) - } - - func testMaxBolusGuardrailDropsZeroVolume() { - let supportedBolusVolumes = [0.0, 0.05, 1.0, 2.0, 20.0.nextDown, 20.0, 25.0, 30.0, 30.0.nextUp] - let guardrail = Guardrail.maximumBolus(supportedBolusVolumes: supportedBolusVolumes) - XCTAssertEqual(guardrail.absoluteBounds.range(withUnit: .internationalUnit()), 0.05...30.0) - XCTAssertEqual(guardrail.recommendedBounds.range(withUnit: .internationalUnit()), 1.0...20.0.nextDown) - } - - func testMaxBolusGuardrailDropsAllZeroVolumes() { - let supportedBolusVolumes = [0.0, 0.0, 0.05, 1.0, 2.0, 20.0.nextDown, 20.0, 25.0, 30.0, 30.0.nextUp] - let guardrail = Guardrail.maximumBolus(supportedBolusVolumes: supportedBolusVolumes) - XCTAssertEqual(guardrail.absoluteBounds.range(withUnit: .internationalUnit()), 0.05...30.0) - XCTAssertEqual(guardrail.recommendedBounds.range(withUnit: .internationalUnit()), 1.0...20.0.nextDown) - } - - func testMaxBolusGuardrailDropsNegatives() { - let supportedBolusVolumes = [-2.0, -1.0, 0.05, 1.0, 2.0, 20.0.nextDown, 20.0, 25.0, 30.0, 30.0.nextUp] - let guardrail = Guardrail.maximumBolus(supportedBolusVolumes: supportedBolusVolumes) - XCTAssertEqual(guardrail.absoluteBounds.range(withUnit: .internationalUnit()), 0.05...30.0) - XCTAssertEqual(guardrail.recommendedBounds.range(withUnit: .internationalUnit()), 1.0...20.0.nextDown) - } - - func testSelectableBolusVolumes() { - let supportedBolusVolumes = [0.0, 0.05, 1.0, 2.0, 30.nextUp] - let selectableBolusVolumes = Guardrail.selectableBolusVolumes(supportedBolusVolumes: supportedBolusVolumes) - XCTAssertEqual([0.05, 1.0, 2.0], selectableBolusVolumes) - } - - func testAllValuesOfQuantity() { - var guardrail = Guardrail.carbRatio - var allValues = guardrail.allValues( - stridingBy: HKQuantity(unit: .gramsPerUnit, doubleValue: 0.1), - unit: .gramsPerUnit) - var expectedValues = Array(stride( - from: guardrail.absoluteBounds.lowerBound.doubleValue(for: .gramsPerUnit, withRounding: true), - through: guardrail.absoluteBounds.upperBound.doubleValue(for: .gramsPerUnit, withRounding: true), - by: 0.1 - )) - XCTAssertEqual(allValues, expectedValues) - - guardrail = Guardrail.insulinSensitivity - allValues = guardrail.allValues( - stridingBy: HKQuantity(unit: HKUnit.milligramsPerDeciliter.unitDivided(by: .internationalUnit()), doubleValue: 1), - unit: HKUnit.milligramsPerDeciliter.unitDivided(by: .internationalUnit())) - expectedValues = Array(stride( - from: guardrail.absoluteBounds.lowerBound.doubleValue(for: HKUnit.milligramsPerDeciliter.unitDivided(by: .internationalUnit()), withRounding: true), - through: guardrail.absoluteBounds.upperBound.doubleValue(for: HKUnit.milligramsPerDeciliter.unitDivided(by: .internationalUnit()), withRounding: true), - by: 1 - )) - XCTAssertEqual(allValues, expectedValues) - } -} - -fileprivate extension ClosedRange where Bound == HKQuantity { - func range(withUnit unit: HKUnit) -> ClosedRange { - lowerBound.doubleValue(for: unit)...upperBound.doubleValue(for: unit) - } -} - -fileprivate extension ClosedRange where Bound == Int { - func range(withUnit unit: HKUnit) -> ClosedRange { - HKQuantity(unit: unit, doubleValue: Double(lowerBound))...HKQuantity(unit: unit, doubleValue: Double(upperBound)) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/HKDeviceCodableTests.swift b/Dependencies/LoopKit/LoopKitTests/HKDeviceCodableTests.swift deleted file mode 100644 index cbbd2bfb7..000000000 --- a/Dependencies/LoopKit/LoopKitTests/HKDeviceCodableTests.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// HKDeviceCodableTests.swift -// LoopKitTests -// -// Created by Rick Pasetto on 8/6/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import HealthKit -import XCTest -@testable import LoopKit - -class HKDeviceCodableTests: XCTestCase { - let device1 = HKDevice(name: "NAME1", manufacturer: "MANUFACTURER", model: "MODEL", hardwareVersion: "HARDWAREVERSION", firmwareVersion: "FIRMWAREVERSION", softwareVersion: "SOFTWAREVERSION", localIdentifier: "LOCALIDENTIFIER", udiDeviceIdentifier: "UDIDEVICEIDENTIFIER") - let device1JSON = """ - { - "firmwareVersion" : "FIRMWAREVERSION", - "hardwareVersion" : "HARDWAREVERSION", - "localIdentifier" : "LOCALIDENTIFIER", - "manufacturer" : "MANUFACTURER", - "model" : "MODEL", - "name" : "NAME1", - "softwareVersion" : "SOFTWAREVERSION", - "udiDeviceIdentifier" : "UDIDEVICEIDENTIFIER" - } - """ - let device2 = HKDevice(name: "NAME2", manufacturer: "MANUFACTURER", model: "MODEL", hardwareVersion: "HARDWAREVERSION", firmwareVersion: "FIRMWAREVERSION", softwareVersion: "SOFTWAREVERSION", localIdentifier: "LOCALIDENTIFIER", udiDeviceIdentifier: "UDIDEVICEIDENTIFIER") - let device2JSON = """ - { - "firmwareVersion" : "FIRMWAREVERSION", - "hardwareVersion" : "HARDWAREVERSION", - "localIdentifier" : "LOCALIDENTIFIER", - "manufacturer" : "MANUFACTURER", - "model" : "MODEL", - "name" : "NAME2", - "softwareVersion" : "SOFTWAREVERSION", - "udiDeviceIdentifier" : "UDIDEVICEIDENTIFIER" - } - """ - let device3 = HKDevice(name: "NAME3", manufacturer: nil, model: nil, hardwareVersion: nil, firmwareVersion: nil, softwareVersion: nil, localIdentifier: nil, udiDeviceIdentifier: nil) - let device3JSON = """ - { - "name" : "NAME3" - } - """ - - let jsonEncoder: JSONEncoder = { - let val = JSONEncoder() - val.outputFormatting = [.prettyPrinted, .sortedKeys] - return val - }() - let plistEncoder: PropertyListEncoder = { - let val = PropertyListEncoder() - val.outputFormat = .xml - return val - }() - - func testEncode() throws { - XCTAssertEqual(device1JSON, String(data: try jsonEncoder.encode(device1), encoding: .utf8)) - XCTAssertEqual(device2JSON, String(data: try jsonEncoder.encode(device2), encoding: .utf8)) - XCTAssertEqual(device3JSON, String(data: try jsonEncoder.encode(device3), encoding: .utf8)) - XCTAssertNotEqual(device2JSON, String(data: try jsonEncoder.encode(device1), encoding: .utf8)) - } - - func testDecodeJSON() throws { - XCTAssertEqual(device1, try HKDevice(from: device1JSON.data(using: .utf8)!)) - XCTAssertEqual(device2, try HKDevice(from: device2JSON.data(using: .utf8)!)) - XCTAssertEqual(device3, try HKDevice(from: device3JSON.data(using: .utf8)!)) - } - - func testDecodePropertyList() throws { - XCTAssertEqual(device1, try HKDevice(from: plistEncoder.encode(device1))) - XCTAssertEqual(device2, try HKDevice(from: plistEncoder.encode(device2))) - XCTAssertEqual(device3, try HKDevice(from: plistEncoder.encode(device3))) - XCTAssertNotEqual(device3, try HKDevice(from: plistEncoder.encode(device1))) - } - - func testDecodeInvalidData() throws { - XCTAssertThrowsError(try HKDevice(from: Data())) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/HKUnitTests.swift b/Dependencies/LoopKit/LoopKitTests/HKUnitTests.swift deleted file mode 100644 index 2e3d277aa..000000000 --- a/Dependencies/LoopKit/LoopKitTests/HKUnitTests.swift +++ /dev/null @@ -1,67 +0,0 @@ -// -// HKUnitTests.swift -// LoopKitTests -// -// Created by Nathaniel Hamming on 2021-03-18. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit - -@testable import LoopKit - -class HKUnitTests: XCTestCase { - - func testPreferredFractionDigits() throws { - XCTAssertEqual(HKUnit.millimolesPerLiter.preferredFractionDigits, 1) - XCTAssertEqual(HKUnit.millimolesPerLiter.unitDivided(by: .internationalUnit()).preferredFractionDigits, 1) - XCTAssertEqual(HKUnit.millimolesPerLiter.unitDivided(by: .minute()).preferredFractionDigits, 1) - - XCTAssertEqual(HKUnit.gram().preferredFractionDigits, 0) - XCTAssertEqual(HKUnit.gram().unitDivided(by: .internationalUnit()).preferredFractionDigits, 0) - XCTAssertEqual(HKUnit.milligramsPerDeciliter.preferredFractionDigits, 0) - XCTAssertEqual(HKUnit.milligramsPerDeciliter.unitDivided(by: .internationalUnit()).preferredFractionDigits, 0) - XCTAssertEqual(HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()).preferredFractionDigits, 0) - XCTAssertEqual(HKUnit.internationalUnit().preferredFractionDigits, 0) - XCTAssertEqual(HKUnit.internationalUnit().unitDivided(by: .hour()).preferredFractionDigits, 0) - } - - func testRoundValue() throws { - XCTAssertEqual(HKUnit.millimolesPerLiter.roundForPreferredDigits(value: 1.34), 1.3) - XCTAssertEqual(HKUnit.millimolesPerLiter.roundForPicker(value: 2.56), 2.6) - - XCTAssertEqual(HKUnit.milligramsPerDeciliter.roundForPreferredDigits(value: 1.34), 1) - XCTAssertEqual(HKUnit.milligramsPerDeciliter.roundForPicker(value: 2.56), 3) - } - - func testMaxFractionDigits() throws { - XCTAssertEqual(HKUnit.internationalUnit().maxFractionDigits, 3) - XCTAssertEqual(HKUnit.internationalUnit().unitDivided(by: .hour()).maxFractionDigits, 3) - - XCTAssertEqual(HKUnit.millimolesPerLiter.maxFractionDigits, 1) - XCTAssertEqual(HKUnit.millimolesPerLiter.unitDivided(by: .internationalUnit()).maxFractionDigits, 1) - XCTAssertEqual(HKUnit.millimolesPerLiter.unitDivided(by: .minute()).maxFractionDigits, 1) - XCTAssertEqual(HKUnit.gram().unitDivided(by: .internationalUnit()).maxFractionDigits, 1) - - XCTAssertEqual(HKUnit.gram().maxFractionDigits, 0) - XCTAssertEqual(HKUnit.milligramsPerDeciliter.maxFractionDigits, 0) - XCTAssertEqual(HKUnit.milligramsPerDeciliter.unitDivided(by: .internationalUnit()).maxFractionDigits, 0) - XCTAssertEqual(HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()).maxFractionDigits, 0) - } - - func testPickerFractionDigits() throws { - XCTAssertEqual(HKUnit.internationalUnit().pickerFractionDigits, 3) - XCTAssertEqual(HKUnit.internationalUnit().unitDivided(by: .hour()).pickerFractionDigits, 3) - - XCTAssertEqual(HKUnit.millimolesPerLiter.pickerFractionDigits, 1) - XCTAssertEqual(HKUnit.millimolesPerLiter.unitDivided(by: .internationalUnit()).pickerFractionDigits, 1) - XCTAssertEqual(HKUnit.millimolesPerLiter.unitDivided(by: .minute()).pickerFractionDigits, 1) - XCTAssertEqual(HKUnit.gram().unitDivided(by: .internationalUnit()).pickerFractionDigits, 1) - - XCTAssertEqual(HKUnit.gram().pickerFractionDigits, 0) - XCTAssertEqual(HKUnit.milligramsPerDeciliter.pickerFractionDigits, 0) - XCTAssertEqual(HKUnit.milligramsPerDeciliter.unitDivided(by: .internationalUnit()).pickerFractionDigits, 0) - XCTAssertEqual(HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()).pickerFractionDigits, 0) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/Info.plist b/Dependencies/LoopKit/LoopKitTests/Info.plist deleted file mode 100644 index f7fe54e8c..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 3.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - - diff --git a/Dependencies/LoopKit/LoopKitTests/InsulinMathTests.swift b/Dependencies/LoopKit/LoopKitTests/InsulinMathTests.swift deleted file mode 100644 index 290ac9b2e..000000000 --- a/Dependencies/LoopKit/LoopKitTests/InsulinMathTests.swift +++ /dev/null @@ -1,1298 +0,0 @@ -// -// InsulinMathTests.swift -// InsulinMathTests -// -// Created by Nathan Racklyeft on 1/27/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - - -struct NewReservoirValue: ReservoirValue { - let startDate: Date - let unitVolume: Double -} - -extension DoseUnit { - var unit: HKUnit { - switch self { - case .units: - return .internationalUnit() - case .unitsPerHour: - return HKUnit(from: "IU/hr") - } - } -} - -class InsulinMathTests: XCTestCase { - - var fixtureDateformatter: DateFormatter! - - private let fixtureTimeZone = TimeZone(secondsFromGMT: -0 * 60 * 60)! - - private let model = WalshInsulinModel(actionDuration: TimeInterval(hours: 4)) - - private let insulinType: InsulinType = .novolog - - private let exponentialModel = ExponentialInsulinModel(actionDuration: TimeInterval(minutes: 360), peakActivityTime: TimeInterval(minutes: 75)) - - let insulinModelSettings = StaticInsulinModelProvider(ExponentialInsulinModelPreset.rapidActingAdult) - let insulinModelDuration = ExponentialInsulinModelPreset.rapidActingAdult.effectDuration - - let walshModelSettings = StaticInsulinModelProvider( WalshInsulinModel(actionDuration: TimeInterval(hours: 4))) - let walshModelDuration = WalshInsulinModel(actionDuration: TimeInterval(hours: 4)).effectDuration - - - private func fixtureDate(_ input: String) -> Date { - return fixtureDateformatter.date(from: input)! - } - - override func setUp() { - fixtureDateformatter = DateFormatter.descriptionFormatter - fixtureDateformatter.timeZone = fixtureTimeZone - } - - private func printInsulinValues(_ insulinValues: [InsulinValue]) { - print("\n\n") - print(String(data: try! JSONSerialization.data( - withJSONObject: insulinValues.map({ (value) -> [String: Any] in - return [ - "date": ISO8601DateFormatter.localTimeDate(timeZone: fixtureTimeZone).string(from: value.startDate), - "value": value.value, - "unit": "U" - ] - }), - options: .prettyPrinted), encoding: .utf8)!) - print("\n\n") - } - - private func printDoses(_ doses: [DoseEntry]) { - print("\n\n") - print(String(data: try! JSONSerialization.data( - withJSONObject: doses.map({ (value) -> [String: Any] in - var obj: [String: Any] = [ - "type": value.type.pumpEventType.rawValue, - "start_at": ISO8601DateFormatter.localTimeDate(timeZone: fixtureTimeZone).string(from: value.startDate), - "end_at": ISO8601DateFormatter.localTimeDate(timeZone: fixtureTimeZone).string(from: value.endDate), - "amount": value.value, - "unit": value.unit.rawValue - ] - - if let syncIdentifier = value.syncIdentifier { - obj["raw"] = syncIdentifier - } - - if let scheduledBasalRate = value.scheduledBasalRate { - obj["scheduled"] = scheduledBasalRate.doubleValue(for: HKUnit(from: "IU/hr")) - } - - return obj - }), - options: .prettyPrinted), encoding: .utf8)!) - print("\n\n") - } - - func loadReservoirFixture(_ resourceName: String) -> [NewReservoirValue] { - - let fixture: [JSONDictionary] = loadFixture(resourceName) - let dateFormatter = ISO8601DateFormatter.localTimeDate(timeZone: fixtureTimeZone) - - return fixture.map { - return NewReservoirValue(startDate: dateFormatter.date(from: $0["date"] as! String)!, unitVolume: $0["amount"] as! Double) - } - } - - func loadDoseFixture(_ resourceName: String, insulinType: InsulinType? = .novolog) -> [DoseEntry] { - let fixture: [JSONDictionary] = loadFixture(resourceName) - let dateFormatter = ISO8601DateFormatter.localTimeDate(timeZone: fixtureTimeZone) - - return fixture.compactMap { - guard let unit = DoseUnit(rawValue: $0["unit"] as! String), - let pumpType = PumpEventType(rawValue: $0["type"] as! String), - let type = DoseType(pumpEventType: pumpType) - else { - return nil - } - - var dose = DoseEntry( - type: type, - startDate: dateFormatter.date(from: $0["start_at"] as! String)!, - endDate: dateFormatter.date(from: $0["end_at"] as! String)!, - value: $0["amount"] as! Double, - unit: unit, - deliveredUnits: $0["delivered"] as? Double, - description: $0["description"] as? String, - syncIdentifier: $0["raw"] as? String, - insulinType: insulinType, - automatic: $0["automatic"] as? Bool, - manuallyEntered: $0["manuallyEntered"] as? Bool ?? false, - isMutable: $0["isMutable"] as? Bool ?? false - ) - - if let scheduled = $0["scheduled"] as? Double { - dose.scheduledBasalRate = HKQuantity(unit: unit.unit, doubleValue: scheduled) - } - - return dose - } - } - - func loadInsulinValueFixture(_ resourceName: String) -> [InsulinValue] { - let fixture: [JSONDictionary] = loadFixture(resourceName) - let dateFormatter = ISO8601DateFormatter.localTimeDate(timeZone: fixtureTimeZone) - - return fixture.map { - return InsulinValue(startDate: dateFormatter.date(from: $0["date"] as! String)!, value: $0["value"] as! Double) - } - } - - func loadGlucoseEffectFixture(_ resourceName: String) -> [GlucoseEffect] { - let fixture: [JSONDictionary] = loadFixture(resourceName) - let dateFormatter = ISO8601DateFormatter.localTimeDate(timeZone: fixtureTimeZone) - - return fixture.map { - return GlucoseEffect(startDate: dateFormatter.date(from: $0["date"] as! String)!, quantity: HKQuantity(unit: HKUnit(from: $0["unit"] as! String), doubleValue:$0["amount"] as! Double)) - } - } - - func loadBasalRateScheduleFixture(_ resourceName: String) -> BasalRateSchedule { - let fixture: [JSONDictionary] = loadFixture(resourceName) - - let items = fixture.map { - return RepeatingScheduleValue(startTime: TimeInterval(minutes: $0["minutes"] as! Double), value: $0["rate"] as! Double) - } - - return BasalRateSchedule(dailyItems: items, timeZone: fixtureTimeZone)! - } - - var insulinSensitivitySchedule: InsulinSensitivitySchedule { - return InsulinSensitivitySchedule(unit: HKUnit.milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: 0.0, value: 40.0)], timeZone: fixtureTimeZone)! - } - - func testDoseEntriesFromReservoirValues() { - let input = loadReservoirFixture("reservoir_history_with_rewind_and_prime_input") - let output = loadDoseFixture("reservoir_history_with_rewind_and_prime_output").reversed() - - let doses = input.doseEntries - - XCTAssertEqual(output.count, doses.count) - - for (expected, calculated) in zip(output, doses) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.endDate, calculated.endDate) - XCTAssertEqual(expected.value, calculated.value, accuracy: Double(Float.ulpOfOne)) - XCTAssertEqual(expected.unit, calculated.unit) - } - } - - func testContinuousReservoirValues() { - var input = loadReservoirFixture("reservoir_history_with_rewind_and_prime_input") - let within = TimeInterval(minutes: 30) - let dateFormatter = ISO8601DateFormatter.localTimeDate(timeZone: fixtureTimeZone) - XCTAssertTrue(input.isContinuous(from: dateFormatter.date(from: "2016-01-30T16:40:00")!, to: dateFormatter.date(from: "2016-01-30T20:40:00")!, within: within)) - - // We don't assert whether it's "stale". - XCTAssertTrue(input.isContinuous(from: dateFormatter.date(from: "2016-01-30T16:40:00")!, to: dateFormatter.date(from: "2016-01-30T22:40:00")!, within: within)) - XCTAssertTrue(input.isContinuous(from: dateFormatter.date(from: "2016-01-30T16:40:00")!, to: Date(), within: within)) - - // The values must extend the startDate boundary - XCTAssertFalse(input.isContinuous(from: dateFormatter.date(from: "2016-01-30T15:00:00")!, to: dateFormatter.date(from: "2016-01-30T20:40:00")!, within: within)) - - // (the boundary condition is GTE) - XCTAssertTrue(input.isContinuous(from: dateFormatter.date(from: "2016-01-30T16:00:42")!, to: dateFormatter.date(from: "2016-01-30T20:40:00")!, within: within)) - - // Rises in reservoir volume taint the entire range - XCTAssertFalse(input.isContinuous(from: dateFormatter.date(from: "2016-01-30T15:55:00")!, to: dateFormatter.date(from: "2016-01-30T20:40:00")!, within: within)) - - // Any values of 0 taint the entire range - input.append(NewReservoirValue(startDate: dateFormatter.date(from: "2016-01-30T20:37:00")!, unitVolume: 0)) - - XCTAssertFalse(input.isContinuous(from: dateFormatter.date(from: "2016-01-30T16:40:00")!, to: dateFormatter.date(from: "2016-01-30T20:40:00")!, within: within)) - - // As long as the 0 is within the date interval bounds - XCTAssertTrue(input.isContinuous(from: dateFormatter.date(from: "2016-01-30T16:40:00")!, to: dateFormatter.date(from: "2016-01-30T19:40:00")!, within: within)) - } - - func testNonContinuousReservoirValues() { - let input = loadReservoirFixture("reservoir_history_with_continuity_holes") - - let dateFormatter = ISO8601DateFormatter.localTimeDate(timeZone: fixtureTimeZone) - XCTAssertTrue(input.isContinuous(from: dateFormatter.date(from: "2016-01-30T18:30:00")!, to: dateFormatter.date(from: "2016-01-30T20:40:00")!, within: .minutes(30))) - - XCTAssertFalse(input.isContinuous(from: dateFormatter.date(from: "2016-01-30T17:30:00")!, to: dateFormatter.date(from: "2016-01-30T20:40:00")!, within: .minutes(30))) - } - - func testIOBFromSuspend() { - let input = loadDoseFixture("suspend_dose") - let reconciledOutput = loadDoseFixture("suspend_dose_reconciled") - let normalizedOutput = loadDoseFixture("suspend_dose_reconciled_normalized") - let iobOutput = loadInsulinValueFixture("suspend_dose_reconciled_normalized_iob") - let basals = loadBasalRateScheduleFixture("basal") - - let reconciled = input.reconciled() - - XCTAssertEqual(reconciledOutput.count, reconciled.count) - - for (expected, calculated) in zip(reconciledOutput, reconciled) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.endDate, calculated.endDate) - XCTAssertEqual(expected.value, calculated.value) - XCTAssertEqual(expected.unit, calculated.unit) - } - - let normalized = reconciled.annotated(with: basals) - - XCTAssertEqual(normalizedOutput.count, normalized.count) - - for (expected, calculated) in zip(normalizedOutput, normalized) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.endDate, calculated.endDate) - XCTAssertEqual(expected.value, calculated.netBasalUnitsPerHour, accuracy: Double(Float.ulpOfOne)) - } - - let iob = normalized.insulinOnBoard(insulinModelProvider: walshModelSettings, longestEffectDuration: walshModelDuration) - - XCTAssertEqual(iobOutput.count, iob.count) - - for (expected, calculated) in zip(iobOutput, iob) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.value, calculated.value, accuracy: Double(Float.ulpOfOne)) - } - } - - func testIOBFromDoses() { - let input = loadDoseFixture("normalized_doses", insulinType: .novolog) - let output = loadInsulinValueFixture("iob_from_doses_output") - - measure { - _ = input.insulinOnBoard(insulinModelProvider: walshModelSettings, longestEffectDuration: walshModelDuration) - } - - let iob = input.insulinOnBoard(insulinModelProvider: walshModelSettings, longestEffectDuration: walshModelDuration) - - XCTAssertEqual(output.count, iob.count) - - for (expected, calculated) in zip(output, iob) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.value, calculated.value, accuracy: 0.5) - } - } - - func testIOBFromNoDoses() { - let input: [DoseEntry] = [] - - let iob = input.insulinOnBoard(insulinModelProvider: insulinModelSettings, longestEffectDuration: insulinModelDuration) - - XCTAssertEqual(0, iob.count) - } - - func testInsulinOnBoardLimitsForExponentialModel() { - let insulinModel = ExponentialInsulinModel(actionDuration: TimeInterval(minutes: 360), peakActivityTime: TimeInterval(minutes: 75), delay: TimeInterval(minutes: 0)) - let childModel = ExponentialInsulinModel(actionDuration: TimeInterval(minutes: 360), peakActivityTime: TimeInterval(minutes: 65), delay: TimeInterval(minutes: 0)) - - XCTAssertEqual(1, insulinModel.percentEffectRemaining(at: .minutes(-1)), accuracy: 0.001) - XCTAssertEqual(1, insulinModel.percentEffectRemaining(at: .minutes(0)), accuracy: 0.001) - XCTAssertEqual(0, insulinModel.percentEffectRemaining(at: .minutes(360)), accuracy: 0.001) - XCTAssertEqual(0, insulinModel.percentEffectRemaining(at: .minutes(361)), accuracy: 0.001) - - // Test random point - XCTAssertEqual(0.5110493617156, insulinModel.percentEffectRemaining(at: .minutes(108)), accuracy: 0.001) - - // Test for child curve - XCTAssertEqual(0.6002510111374046, childModel.percentEffectRemaining(at: .minutes(82)), accuracy: 0.001) - - } - - func testIOBFromDosesExponential() { - let input = loadDoseFixture("normalized_doses", insulinType: .novolog) - let output = loadInsulinValueFixture("iob_from_doses_exponential_output") - - measure { - _ = input.insulinOnBoard(insulinModelProvider: insulinModelSettings, longestEffectDuration: insulinModelDuration) - } - - let iob = input.insulinOnBoard(insulinModelProvider: insulinModelSettings, longestEffectDuration: insulinModelDuration) - - XCTAssertEqual(output.count, iob.count) - - for (expected, calculated) in zip(output, iob) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.value, calculated.value, accuracy: 0.5) - } - } - - func testIOBFromBolusExponential() { - let input = loadDoseFixture("bolus_dose", insulinType: .novolog) - let output = loadInsulinValueFixture("iob_from_bolus_exponential_output") - - let iob = input.insulinOnBoard(insulinModelProvider: insulinModelSettings, longestEffectDuration: insulinModelDuration) - - XCTAssertEqual(output.count, iob.count) - - for (expected, calculated) in zip(output, iob) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.value, calculated.value, accuracy: Double(Float.ulpOfOne)) - } - } - - - func testIOBFromBolus() { - for hours in [2, 3, 4, 5, 5.2, 6, 7] as [Double] { - let actionDuration = TimeInterval(hours: hours) - let model = WalshInsulinModel(actionDuration: actionDuration) - let insulinModelProvider = StaticInsulinModelProvider( model) - let input = loadDoseFixture("bolus_dose", insulinType: .novolog) - let output = loadInsulinValueFixture("iob_from_bolus_\(Int(actionDuration.minutes))min_output") - - let iob = input.insulinOnBoard(insulinModelProvider: insulinModelProvider, longestEffectDuration: model.effectDuration) - - XCTAssertEqual(output.count, iob.count) - - for (expected, calculated) in zip(output, iob) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.value, calculated.value, accuracy: Double(Float.ulpOfOne)) - } - } - } - - func testIOBFromDosesWithDifferentInsulinCurves() { - let formatter = DateFormatter.descriptionFormatter - let f = { (input) in - return formatter.date(from: input)! - } - let output = loadInsulinValueFixture("iob_from_multiple_curves_output") - - let doses = [ - DoseEntry(type: .basal, startDate: f("2018-05-15 14:42:36 +0000"), endDate: f("2018-05-16 14:42:36 +0000"), value: 0.84999999999999998, unit: .unitsPerHour, syncIdentifier: "7b02646a070f120e2200", scheduledBasalRate: nil), - DoseEntry(type: .bolus, startDate: f("2018-05-15 14:44:46 +0000"), endDate: f("2018-05-15 14:44:46 +0000"), value: 0.9, unit: .units, syncIdentifier: "01004a004a006d006e22354312", scheduledBasalRate: nil), - DoseEntry(type: .tempBasal, startDate: f("2018-05-15 14:42:36 +0000"), endDate: f("2018-05-15 14:42:36 +0000"), value: 0.0, unit: .unitsPerHour, syncIdentifier: "1600646a074f12", scheduledBasalRate: nil), - DoseEntry(type: .tempBasal, startDate: f("2018-05-15 14:32:51 +0000"), endDate: f("2018-05-15 15:02:51 +0000"), value: 1.8999999999999999, unit: .unitsPerHour, syncIdentifier: "16017360074f12", scheduledBasalRate: nil), - DoseEntry(type: .bolus, startDate: f("2018-05-15 14:52:51 +0000"), endDate: f("2018-05-15 15:52:51 +0000"), value: 0.9, unit: .units, syncIdentifier: "01004a004a006d006e22354312", scheduledBasalRate: nil), - ] - - let iobWithoutModel = doses.insulinOnBoard(insulinModelProvider: insulinModelSettings, longestEffectDuration: insulinModelDuration) - - let dosesWithModel = [ - DoseEntry(type: .basal, startDate: f("2018-05-15 14:42:36 +0000"), endDate: f("2018-05-16 14:42:36 +0000"), value: 0.84999999999999998, unit: .unitsPerHour, syncIdentifier: "7b02646a070f120e2200", scheduledBasalRate: nil), - DoseEntry(type: .bolus, startDate: f("2018-05-15 14:44:46 +0000"), endDate: f("2018-05-15 14:44:46 +0000"), value: 0.9, unit: .units, syncIdentifier: "01004a004a006d006e22354312", scheduledBasalRate: nil, insulinType: .fiasp), - DoseEntry(type: .tempBasal, startDate: f("2018-05-15 14:42:36 +0000"), endDate: f("2018-05-15 14:42:36 +0000"), value: 0.0, unit: .unitsPerHour, syncIdentifier: "1600646a074f12", scheduledBasalRate: nil), - DoseEntry(type: .tempBasal, startDate: f("2018-05-15 14:32:51 +0000"), endDate: f("2018-05-15 15:02:51 +0000"), value: 1.8999999999999999, unit: .unitsPerHour, syncIdentifier: "16017360074f12", scheduledBasalRate: nil), - DoseEntry(type: .bolus, startDate: f("2018-05-15 14:52:51 +0000"), endDate: f("2018-05-15 15:52:51 +0000"), value: 0.9, unit: .units, syncIdentifier: "01004a004a006d006e22354312", scheduledBasalRate: nil, insulinType: .novolog), - ] - - let insulinModelProvider = PresetInsulinModelProvider(defaultRapidActingModel: ExponentialInsulinModelPreset.rapidActingChild) - let iobWithModel = dosesWithModel.insulinOnBoard(insulinModelProvider: insulinModelProvider, longestEffectDuration: ExponentialInsulinModelPreset.rapidActingChild.effectDuration) - - XCTAssertEqual(iobWithoutModel.count, iobWithModel.count) - - for (expected, calculated) in zip(output, iobWithModel) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.value, calculated.value, accuracy: Double(Float.ulpOfOne)) - } - - } - - func testIOBFromReservoirDoses() { - let input = loadDoseFixture("normalized_reservoir_history_output") - let output = loadInsulinValueFixture("iob_from_reservoir_output") - - measure { - _ = input.insulinOnBoard(insulinModelProvider: walshModelSettings, longestEffectDuration: walshModelDuration) - } - - let iob = input.insulinOnBoard(insulinModelProvider: walshModelSettings, longestEffectDuration: walshModelDuration) - - XCTAssertEqual(output.count, iob.count) - - for (expected, calculated) in zip(output, iob) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.value, calculated.value, accuracy: 0.4) - } - } - - func testNormalizeReservoirDoses() { - let input = loadDoseFixture("reservoir_history_with_rewind_and_prime_output") - let output = loadDoseFixture("normalized_reservoir_history_output") - let basals = loadBasalRateScheduleFixture("basal") - - measure { - _ = input.annotated(with: basals) - } - - let doses = input.annotated(with: basals) - - XCTAssertEqual(output.count, doses.count) - - // Total delivery on split doses should add up to delivery from original doses - XCTAssertEqual( - input.map {$0.unitsInDeliverableIncrements}.reduce(0,+), - doses.map {$0.unitsInDeliverableIncrements}.reduce(0,+), - accuracy: Double(Float.ulpOfOne)) - - for (expected, calculated) in zip(output, doses) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.endDate, calculated.endDate) - XCTAssertEqual(expected.value, calculated.unitsPerHour, accuracy: Double(Float.ulpOfOne)) - XCTAssertEqual(expected.scheduledBasalRate, calculated.scheduledBasalRate) - } - } - - func testNormalizeEdgeCaseDoses() { - let input = loadDoseFixture("normalize_edge_case_doses_input") - let output = loadDoseFixture("normalize_edge_case_doses_output") - let basals = loadBasalRateScheduleFixture("basal") - - measure { - _ = input.annotated(with: basals) - } - - let doses = input.annotated(with: basals) - - XCTAssertEqual(output.count, doses.count) - - for (expected, calculated) in zip(output, doses) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.endDate, calculated.endDate) - XCTAssertEqual(expected.value, calculated.unit == .units ? calculated.netBasalUnits : calculated.netBasalUnitsPerHour) - XCTAssertEqual(expected.unit, calculated.unit) - } - } - - func testNormalizeEdgeCaseDosesMutable() { - let input = loadDoseFixture("normalize_edge_case_doses_mutable_input") - let output = loadDoseFixture("normalize_edge_case_doses_mutable_output") - let basals = loadBasalRateScheduleFixture("basal") - - measure { - _ = input.annotated(with: basals) - } - - let doses = input.annotated(with: basals) - - XCTAssertEqual(output.count, doses.count) - - for (expected, calculated) in zip(output, doses) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.endDate, calculated.endDate) - XCTAssertEqual(expected.value, calculated.unit == .units ? calculated.netBasalUnits : calculated.netBasalUnitsPerHour) - XCTAssertEqual(expected.unit, calculated.unit) - XCTAssertEqual(expected.isMutable, calculated.isMutable) - XCTAssertEqual(expected.deliveredUnits, calculated.deliveredUnits) - } - } - - func testReconcileTempBasals() { - // Fixture contains numerous overlapping temp basals, as well as a Suspend event interleaved with a temp basal - let input = loadDoseFixture("reconcile_history_input") - let output = loadDoseFixture("reconcile_history_output").sorted { $0.startDate < $1.startDate } - - let doses = input.reconciled().sorted { $0.startDate < $1.startDate } - - XCTAssertEqual(output.count, doses.count) - - for (expected, calculated) in zip(output, doses) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.endDate, calculated.endDate) - XCTAssertEqual(expected.value, calculated.value) - XCTAssertEqual(expected.unit, calculated.unit) - XCTAssertEqual(expected.syncIdentifier, calculated.syncIdentifier) - XCTAssertEqual(expected.deliveredUnits, calculated.deliveredUnits) - } - } - - func testReconcileResumeBeforeRewind() { - let input = loadDoseFixture("reconcile_resume_before_rewind_input") - let output = loadDoseFixture("reconcile_resume_before_rewind_output") - - let doses = input.reconciled() - - XCTAssertEqual(output.count, doses.count) - - for (expected, calculated) in zip(output, doses) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.endDate, calculated.endDate) - XCTAssertEqual(expected.value, calculated.value) - XCTAssertEqual(expected.unit, calculated.unit) - XCTAssertEqual(expected.syncIdentifier, calculated.syncIdentifier) - XCTAssertEqual(expected.deliveredUnits, calculated.deliveredUnits) - } - } - - func testGlucoseEffectFromBolus() { - let input = loadDoseFixture("bolus_dose") - let output = loadGlucoseEffectFixture("effect_from_bolus_output") - let insulinSensitivitySchedule = self.insulinSensitivitySchedule - - measure { - _ = input.glucoseEffects(insulinModelProvider: walshModelSettings, longestEffectDuration: walshModelDuration, insulinSensitivity: insulinSensitivitySchedule) - } - - let effects = input.glucoseEffects(insulinModelProvider: walshModelSettings, longestEffectDuration: walshModelDuration, insulinSensitivity: insulinSensitivitySchedule) - - XCTAssertEqual(Float(output.count), Float(effects.count), accuracy: 1.0) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: .milligramsPerDeciliter), calculated.quantity.doubleValue(for: .milligramsPerDeciliter), accuracy: 1.0) - } - } - - func testGlucoseEffectFromShortTempBasal() { - let input = loadDoseFixture("short_basal_dose") - let output = loadGlucoseEffectFixture("effect_from_bolus_output") - let insulinSensitivitySchedule = self.insulinSensitivitySchedule - - measure { - _ = input.glucoseEffects(insulinModelProvider: walshModelSettings, longestEffectDuration: walshModelDuration, insulinSensitivity: insulinSensitivitySchedule) - } - - let effects = input.glucoseEffects(insulinModelProvider: walshModelSettings, longestEffectDuration: walshModelDuration, insulinSensitivity: insulinSensitivitySchedule) - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: .milligramsPerDeciliter), calculated.quantity.doubleValue(for: .milligramsPerDeciliter), accuracy: Double(Float.ulpOfOne)) - } - } - - func testGlucoseEffectFromTempBasal() { - let input = loadDoseFixture("basal_dose") - let output = loadGlucoseEffectFixture("effect_from_basal_output") - let insulinSensitivitySchedule = self.insulinSensitivitySchedule - - measure { - _ = input.glucoseEffects(insulinModelProvider: walshModelSettings, longestEffectDuration: walshModelDuration, insulinSensitivity: insulinSensitivitySchedule) - } - - let effects = input.glucoseEffects(insulinModelProvider: walshModelSettings, longestEffectDuration: walshModelDuration, insulinSensitivity: insulinSensitivitySchedule) - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), calculated.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), accuracy: 1.0, String(describing: expected.startDate)) - } - } - - func testGlucoseEffectFromTempBasalExponential() { - let input = loadDoseFixture("basal_dose_with_delivered", insulinType: .novolog) - let output = loadGlucoseEffectFixture("effect_from_basal_output_exponential") - - let effects = input.glucoseEffects(insulinModelProvider: insulinModelSettings, longestEffectDuration: insulinModelDuration, insulinSensitivity: insulinSensitivitySchedule) - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), calculated.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), accuracy: 1.0, String(describing: expected.startDate)) - print(expected.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), calculated.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter)) - } - } - - func testGlucoseEffectFromHistory() { - let input = loadDoseFixture("normalized_doses") - let output = loadGlucoseEffectFixture("effect_from_history_output") - let insulinSensitivitySchedule = self.insulinSensitivitySchedule - - measure { - _ = input.glucoseEffects(insulinModelProvider: walshModelSettings, longestEffectDuration: walshModelDuration, insulinSensitivity: insulinSensitivitySchedule) - } - - let effects = input.glucoseEffects(insulinModelProvider: walshModelSettings, longestEffectDuration: walshModelDuration, insulinSensitivity: insulinSensitivitySchedule) - - XCTAssertEqual(output.count, effects.count) - - for (expected, calculated) in zip(output, effects) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), calculated.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), accuracy: 3.0) - } - } - - func testGlucoseEffectFromNoDoses() { - let input: [DoseEntry] = [] - let insulinSensitivitySchedule = self.insulinSensitivitySchedule - - let effects = input.glucoseEffects(insulinModelProvider: insulinModelSettings, longestEffectDuration: insulinModelDuration, insulinSensitivity: insulinSensitivitySchedule) - - XCTAssertEqual(0, effects.count) - } - - func testTotalDelivery() { - let input = loadDoseFixture("normalize_edge_case_doses_input") - let output = input.totalDelivery - - XCTAssertEqual(18.8, output, accuracy: 0.01) - } - - func testTrimContinuingDoses() { - let dateFormatter = ISO8601DateFormatter.localTimeDate(timeZone: fixtureTimeZone) - let input = loadDoseFixture("normalized_doses").reversed() - - // Last temp ends at 2015-10-15T22:29:50 - let endDate = dateFormatter.date(from: "2015-10-15T22:25:50")! - let trimmed = input.map { $0.trimmed(to: endDate) } - - print(input, "\n\n\n") - print(trimmed) - - XCTAssertEqual(endDate, trimmed.last!.endDate) - XCTAssertEqual(input.count, trimmed.count) - } - - func testTrimmedMaintainsMutability() { - let dateFormatter = ISO8601DateFormatter.localTimeDate(timeZone: fixtureTimeZone) - let input = loadDoseFixture("normalized_doses").reversed() - - // Last temp ends at 2015-10-15T22:29:50 - let endDate = dateFormatter.date(from: "2015-10-15T22:25:50")! - let trimmed = input.map { $0.trimmed(to: endDate) } - - XCTAssertTrue(trimmed.last!.isMutable) - } - - func testDosesOverlayBasalProfile() { - let dateFormatter = ISO8601DateFormatter.localTimeDate(timeZone: fixtureTimeZone) - let input = loadDoseFixture("reconcile_history_output").sorted { $0.startDate < $1.startDate } - let output = loadDoseFixture("doses_overlay_basal_profile_output") - let basals = loadBasalRateScheduleFixture("basal") - - let doses = input.annotated(with: basals).overlayBasalSchedule( - basals, - // A start date before the first entry should generate a basal - startingAt: dateFormatter.date(from: "2016-02-15T14:01:04")!, - endingAt: Date(), - insertingBasalEntries: true - ) - - XCTAssertEqual(output.count, doses.count) - - XCTAssertEqual(doses.first?.startDate, dateFormatter.date(from: "2016-02-15T14:01:04")!) - - for (expected, calculated) in zip(output, doses) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.endDate, calculated.endDate) - XCTAssertEqual(expected.value, calculated.value) - XCTAssertEqual(expected.unit, calculated.unit) - - if let syncID = expected.syncIdentifier { - XCTAssertEqual(syncID, calculated.syncIdentifier!) - } - } - - // Test trimming end - let dosesTrimmedEnd = input[0.. DoseEntry in - let startDate = self.fixtureDate("2018-07-16 03:49:00 +0000") - let endDate = startDate.addingTimeInterval(TimeInterval(minutes: 5)) - - let tempBasalRate = 1.0 - - return DoseEntry( - type: .tempBasal, - startDate: startDate, - endDate: endDate, - value: tempBasalRate, - unit: .unitsPerHour, - deliveredUnits: deliveredUnits) - } - - XCTAssertEqual(0.1, makeDose(nil).unitsInDeliverableIncrements, accuracy: .ulpOfOne) - XCTAssertEqual(0.05, makeDose(0.05).unitsInDeliverableIncrements, accuracy: .ulpOfOne) - } - - func testDoseEntryAnnotateShouldSplitDosesProportionally() { - let startDate = self.fixtureDate("2018-07-16 11:59:00 +0000") - let endDate = startDate.addingTimeInterval(TimeInterval(minutes: 5)) - - let tempBasalRate = 1.0 - - let dose = DoseEntry( - type: .tempBasal, - startDate: startDate, - endDate: endDate, - value: tempBasalRate, - unit: .unitsPerHour, - deliveredUnits: 0.1 - ) - - let delivery = dose.unitsInDeliverableIncrements - - let basals = loadBasalRateScheduleFixture("basal") - - let splitDoses = [dose].annotated(with: basals) - - XCTAssertEqual(2, splitDoses.count) - - // A 5 minute dose starting one minute before midnight, split at midnight, means split should be 1/5, 4/5 - XCTAssertEqual(delivery * 1.0/5.0, splitDoses[0].unitsInDeliverableIncrements, accuracy: .ulpOfOne) - XCTAssertEqual(delivery * 4.0/5.0, splitDoses[1].unitsInDeliverableIncrements, accuracy: .ulpOfOne) - } - - func testDoseEntryWithoutDeliveredUnitsShouldSplitDosesProportionally() { - let startDate = self.fixtureDate("2018-07-16 11:59:00 +0000") - let endDate = startDate.addingTimeInterval(TimeInterval(minutes: 5)) - - let tempBasalRate = 1.0 - - let dose = DoseEntry( - type: .tempBasal, - startDate: startDate, - endDate: endDate, - value: tempBasalRate, - unit: .unitsPerHour, - deliveredUnits: 0.05 - ) - - let delivery = dose.unitsInDeliverableIncrements - - let basals = loadBasalRateScheduleFixture("basal") - - let splitDoses = [dose].annotated(with: basals) - - XCTAssertEqual(2, splitDoses.count) - - // A 5 minute dose starting one minute before midnight, split at midnight, means split should be 1/5, 4/5 - XCTAssertEqual(delivery * 1.0/5.0, splitDoses[0].unitsInDeliverableIncrements, accuracy: .ulpOfOne) - XCTAssertEqual(delivery * 4.0/5.0, splitDoses[1].unitsInDeliverableIncrements, accuracy: .ulpOfOne) - } - -} diff --git a/Dependencies/LoopKit/LoopKitTests/InsulinSensitivityScheduleTests.swift b/Dependencies/LoopKit/LoopKitTests/InsulinSensitivityScheduleTests.swift deleted file mode 100644 index fe2b3d019..000000000 --- a/Dependencies/LoopKit/LoopKitTests/InsulinSensitivityScheduleTests.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// InsulinSensitivityScheduleTests.swift -// LoopKitTests -// -// Created by Nathaniel Hamming on 2021-03-18. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit - -@testable import LoopKit - -class InsulinSensitivityScheduleTests: XCTestCase { - - func testScheduleFor() { - let value1 = 15.0 - let value2 = 40.0 - let insulinSensitivityScheduleMGDL = InsulinSensitivitySchedule( - unit: .milligramsPerDeciliter, - dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: value1), - RepeatingScheduleValue(startTime: 1000, value: value2) - ]) - let insulinSensitivityScheduleMMOLL = InsulinSensitivitySchedule( - unit: .millimolesPerLiter, - dailyItems: [ - RepeatingScheduleValue(startTime: 0, - value: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: value1).doubleValue(for: .millimolesPerLiter)), - RepeatingScheduleValue(startTime: 1000, - value: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: value2).doubleValue(for: .millimolesPerLiter)) - ]) - XCTAssertEqual(insulinSensitivityScheduleMGDL!.schedule(for: .millimolesPerLiter), insulinSensitivityScheduleMMOLL!) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/JSONStreamEncoderTests.swift b/Dependencies/LoopKit/LoopKitTests/JSONStreamEncoderTests.swift deleted file mode 100644 index e2cadf855..000000000 --- a/Dependencies/LoopKit/LoopKitTests/JSONStreamEncoderTests.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// JSONStreamEncoderTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 8/26/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import LoopKit - -class JSONStreamEncoderTests: XCTestCase { - var outputStream: MockOutputStream! - var encoder: JSONStreamEncoder! - - override func setUp() { - outputStream = MockOutputStream() - encoder = JSONStreamEncoder(stream: outputStream) - } - - func testEmpty() { - XCTAssertNil(encoder.close()) - XCTAssertEqual(outputStream.string, "[]") - } - - func testMultipleClose() { - XCTAssertNil(encoder.close()) - XCTAssertNil(encoder.close()) - } - - func testCloseError() { - let mockError = MockError() - outputStream.error = mockError - XCTAssertEqual(encoder.close() as! MockError, mockError) - } - - func testEncode() { - let values = [MockValue(left: "Alpha", center: 1, right: dateFormatter.date(from: "2020-01-02T03:02:00Z")!), - MockValue(left: "Bravo", center: 2, right: dateFormatter.date(from: "2020-01-02T03:04:00Z")!), - MockValue(left: "Charlie", center: 3, right: dateFormatter.date(from: "2020-01-02T03:06:00Z")!)] - XCTAssertNoThrow(try encoder.encode(values)) - XCTAssertNil(encoder.close()) - XCTAssertEqual(outputStream.string, """ -[ -{"center":1,"left":"Alpha","right":"2020-01-02T03:02:00.000Z"}, -{"center":2,"left":"Bravo","right":"2020-01-02T03:04:00.000Z"}, -{"center":3,"left":"Charlie","right":"2020-01-02T03:06:00.000Z"} -] -""" - ) - } - - func testEncodeEmpty() { - XCTAssertNoThrow(try encoder.encode([MockValue]())) - XCTAssertNil(encoder.close()) - XCTAssertEqual(outputStream.string, "[]") - } - - func testEncodeClosed() { - let values = [MockValue(left: "Alpha", center: 1, right: dateFormatter.date(from: "2020-01-02T03:02:00Z")!)] - XCTAssertNil(encoder.close()) - XCTAssertThrowsError(try encoder.encode(values)) { error in - XCTAssertEqual(error as! JSONStreamEncoderError, JSONStreamEncoderError.encoderClosed) - } - } - - func testEncodeError() { - let values = [MockValue(left: "Alpha", center: 1, right: dateFormatter.date(from: "2020-01-02T03:02:00Z")!)] - let mockError = MockError() - outputStream.error = mockError - XCTAssertThrowsError(try encoder.encode(values)) { error in - XCTAssertEqual(error as! MockError, mockError) - } - } - - private let dateFormatter = ISO8601DateFormatter() -} - -fileprivate struct MockValue: Codable { - let left: String - let center: Int - let right: Date -} - -fileprivate struct MockError: Error, Equatable {} diff --git a/Dependencies/LoopKit/LoopKitTests/LoopKitTests.swift b/Dependencies/LoopKit/LoopKitTests/LoopKitTests.swift deleted file mode 100644 index fe6699484..000000000 --- a/Dependencies/LoopKit/LoopKitTests/LoopKitTests.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// LoopKitTests.swift -// LoopKitTests -// -// Created by Nathan Racklyeft on 1/18/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -import Foundation - -public typealias JSONDictionary = [String: Any] - - -extension XCTestCase { - public var bundle: Bundle { - return Bundle(for: type(of: self)) - } - - public func loadFixture(_ resourceName: String) -> T { - let path = bundle.path(forResource: resourceName, ofType: "json")! - return try! JSONSerialization.jsonObject(with: Data(contentsOf: URL(fileURLWithPath: path)), options: []) as! T - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/LoopMathTests.swift b/Dependencies/LoopKit/LoopKitTests/LoopMathTests.swift deleted file mode 100644 index 9c675af7b..000000000 --- a/Dependencies/LoopKit/LoopKitTests/LoopMathTests.swift +++ /dev/null @@ -1,495 +0,0 @@ -// -// LoopMathTests.swift -// LoopKit -// -// Created by Nathan Racklyeft on 3/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - - -typealias RecentGlucoseValue = PredictedGlucoseValue - - -class LoopMathTests: XCTestCase { - - func loadGlucoseEffectFixture(_ resourceName: String, formatter: ISO8601DateFormatter) -> [GlucoseEffect] { - let fixture: [JSONDictionary] = loadFixture(resourceName) - - return fixture.map { - return GlucoseEffect(startDate: formatter.date(from: $0["date"] as! String)!, quantity: HKQuantity(unit: HKUnit(from: $0["unit"] as! String), doubleValue:$0["amount"] as! Double)) - } - } - - func loadGlucoseEffectFixture(_ resourceName: String, formatter: DateFormatter) -> [GlucoseEffect] { - let fixture: [JSONDictionary] = loadFixture(resourceName) - - return fixture.map { - return GlucoseEffect(startDate: formatter.date(from: $0["date"] as! String)!, quantity: HKQuantity(unit: HKUnit(from: $0["unit"] as! String), doubleValue: $0["value"] as! Double)) - } - } - - private func printFixture(_ glucoseEffect: [GlucoseEffect]) { - let unit = HKUnit.milligramsPerDeciliter - - print("\n\n") - print(String(data: try! JSONSerialization.data( - withJSONObject: glucoseEffect.map({ (value) -> [String: Any] in - return [ - "date": String(describing: value.startDate), - "value": value.quantity.doubleValue(for: unit), - "unit": unit.unitString - ] - }), - options: .prettyPrinted), encoding: .utf8)!) - print("\n\n") - } - - func loadSampleValueFixture(_ resourceName: String) -> [(startDate: Date, quantity: HKQuantity)] { - let fixture: [JSONDictionary] = loadFixture(resourceName) - let dateFormatter = ISO8601DateFormatter() - - return fixture.map { - (dateFormatter.date(from: $0["startDate"] as! String)!, HKQuantity(unit: HKUnit(from: $0["unit"] as! String), doubleValue: $0["value"] as! Double)) - } - } - - func loadGlucoseHistoryFixture(_ resourceName: String) -> RecentGlucoseValue { - let fixture: [JSONDictionary] = loadFixture(resourceName) - let dateFormatter = ISO8601DateFormatter.localTimeDate() - - return fixture.map { - return RecentGlucoseValue(startDate: dateFormatter.date(from: $0["display_time"] as! String)!, quantity: HKQuantity(unit: HKUnit.milligramsPerDeciliter, doubleValue:$0["glucose"] as! Double)) - }.first! - } - - func loadGlucoseValueFixture(_ resourceName: String) -> [PredictedGlucoseValue] { - let fixture: [JSONDictionary] = loadFixture(resourceName) - let dateFormatter = ISO8601DateFormatter.localTimeDate() - - return fixture.map { - return PredictedGlucoseValue(startDate: dateFormatter.date(from: $0["date"] as! String)!, quantity: HKQuantity(unit: HKUnit(from: $0["unit"] as! String), doubleValue:$0["amount"] as! Double)) - } - } - - lazy var carbEffect: [GlucoseEffect] = { - return self.loadGlucoseEffectFixture("glucose_from_effects_carb_effect_input", formatter: ISO8601DateFormatter.localTimeDate()) - }() - - lazy var insulinEffect: [GlucoseEffect] = { - return self.loadGlucoseEffectFixture("glucose_from_effects_insulin_effect_input", formatter: ISO8601DateFormatter.localTimeDate()) - }() - - func testPredictGlucoseNoMomentum() { - let glucose = loadGlucoseHistoryFixture("glucose_from_effects_glucose_input") - - let expected = loadGlucoseValueFixture("glucose_from_effects_no_momentum_output") - - let calculated = LoopMath.predictGlucose(startingAt: glucose, effects: carbEffect, insulinEffect) - - XCTAssertEqual(expected.count, calculated.count) - - for (expected, calculated) in zip(expected, calculated) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), calculated.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), accuracy: Double(Float.ulpOfOne)) - } - } - - func testPredictGlucoseFlatMomentum() { - let glucose = loadGlucoseHistoryFixture("glucose_from_effects_momentum_flat_glucose_input") - let momentum = loadGlucoseEffectFixture("glucose_from_effects_momentum_flat_input", formatter: ISO8601DateFormatter.localTimeDate()) - let expected = loadGlucoseValueFixture("glucose_from_effects_momentum_flat_output") - - let calculated = LoopMath.predictGlucose(startingAt: glucose, momentum: momentum, effects: carbEffect, insulinEffect) - - XCTAssertEqual(expected.count, calculated.count) - - for (expected, calculated) in zip(expected, calculated) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), calculated.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), accuracy: Double(Float.ulpOfOne)) - } - } - - func testPredictGlucoseUpMomentum() { - let glucose = loadGlucoseHistoryFixture("glucose_from_effects_glucose_input") - let momentum = loadGlucoseEffectFixture("glucose_from_effects_momentum_up_input", formatter: ISO8601DateFormatter.localTimeDate()) - let expected = loadGlucoseValueFixture("glucose_from_effects_momentum_up_output") - - let calculated = LoopMath.predictGlucose(startingAt: glucose, momentum: momentum, effects: carbEffect, insulinEffect) - - XCTAssertEqual(expected.count, calculated.count) - - for (expected, calculated) in zip(expected, calculated) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), calculated.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), accuracy: Double(Float.ulpOfOne)) - } - } - - func testPredictGlucoseDownMomentum() { - let glucose = loadGlucoseHistoryFixture("glucose_from_effects_glucose_input") - let momentum = loadGlucoseEffectFixture("glucose_from_effects_momentum_down_input", formatter: ISO8601DateFormatter.localTimeDate()) - let expected = loadGlucoseValueFixture("glucose_from_effects_momentum_down_output") - - let calculated = LoopMath.predictGlucose(startingAt: glucose, momentum: momentum, effects: carbEffect, insulinEffect) - - XCTAssertEqual(expected.count, calculated.count) - - for (expected, calculated) in zip(expected, calculated) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), calculated.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), accuracy: Double(Float.ulpOfOne)) - } - } - - func testPredictGlucoseBlendMomentum() { - let glucose = loadGlucoseHistoryFixture("glucose_from_effects_momentum_blend_glucose_input") - let momentum = loadGlucoseEffectFixture("glucose_from_effects_momentum_blend_momentum_input", formatter: ISO8601DateFormatter.localTimeDate()) - let insulinEffect = loadGlucoseEffectFixture("glucose_from_effects_momentum_blend_insulin_effect_input", formatter: ISO8601DateFormatter.localTimeDate()) - let expected = loadGlucoseValueFixture("glucose_from_effects_momentum_blend_output") - - let calculated = LoopMath.predictGlucose(startingAt: glucose, momentum: momentum, effects: insulinEffect) - - XCTAssertEqual(expected.count, calculated.count) - - for (expected, calculated) in zip(expected, calculated) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), calculated.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), accuracy: Double(Float.ulpOfOne)) - } - } - - func testPredictGlucoseStartingEffectsNonZero() { - let glucose = loadSampleValueFixture("glucose_from_effects_non_zero_glucose_input").first! - let insulinEffect = loadSampleValueFixture("glucose_from_effects_non_zero_insulin_input").map { - GlucoseEffect(startDate: $0.startDate, quantity: $0.quantity) - } - let carbEffect = loadSampleValueFixture("glucose_from_effects_non_zero_carb_input").map { - GlucoseEffect(startDate: $0.startDate, quantity: $0.quantity) - } - let expected = loadSampleValueFixture("glucose_from_effects_non_zero_output").map { - GlucoseEffect(startDate: $0.startDate, quantity: $0.quantity) - } - - let calculated = LoopMath.predictGlucose(startingAt: RecentGlucoseValue(startDate: glucose.startDate, quantity: glucose.quantity), - effects: insulinEffect, carbEffect - ) - - XCTAssertEqual(expected.count, calculated.count) - - for (expected, calculated) in zip(expected, calculated) { - XCTAssertEqual(expected.startDate, calculated.startDate) - XCTAssertEqual(expected.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), calculated.quantity.doubleValue(for: HKUnit.milligramsPerDeciliter), accuracy: Double(Float.ulpOfOne)) - } - } - - func testDecayEffect() { - let calendar = Calendar(identifier: Calendar.Identifier.gregorian) - let glucoseDate = calendar.date(from: DateComponents(year: 2016, month: 2, day: 1, hour: 10, minute: 13, second: 20))! - let type = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.bloodGlucose)! - let unit = HKUnit.milligramsPerDeciliter - let glucose = HKQuantitySample(type: type, quantity: HKQuantity(unit: unit, doubleValue: 100), start: glucoseDate, end: glucoseDate) - - var startingEffect = HKQuantity(unit: unit.unitDivided(by: HKUnit.minute()), doubleValue: 2) - - var effects = glucose.decayEffect(atRate: startingEffect, for: .minutes(30)) - - XCTAssertEqual([100, 110, 118, 124, 128, 130, 130], effects.map { $0.quantity.doubleValue(for: unit) }) - - let startDate = effects.first!.startDate - XCTAssertEqual([0, 5, 10, 15, 20, 25, 30], effects.map { $0.startDate.timeIntervalSince(startDate).minutes }) - - startingEffect = HKQuantity(unit: unit.unitDivided(by: HKUnit.minute()), doubleValue: -0.5) - effects = glucose.decayEffect(atRate: startingEffect, for: .minutes(30)) - XCTAssertEqual([100, 97.5, 95.5, 94, 93, 92.5, 92.5], effects.map { $0.quantity.doubleValue(for: unit) }) - } - - func testDecayEffectWithEvenGlucose() { - let calendar = Calendar(identifier: Calendar.Identifier.gregorian) - let glucoseDate = calendar.date(from: DateComponents(year: 2016, month: 2, day: 1, hour: 10, minute: 15, second: 0))! - let type = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.bloodGlucose)! - let unit = HKUnit.milligramsPerDeciliter - let glucose = HKQuantitySample(type: type, quantity: HKQuantity(unit: unit, doubleValue: 100), start: glucoseDate, end: glucoseDate) - - var startingEffect = HKQuantity(unit: unit.unitDivided(by: HKUnit.minute()), doubleValue: 2) - - var effects = glucose.decayEffect(atRate: startingEffect, for: .minutes(30)) - - XCTAssertEqual([100, 110, 118, 124, 128, 130], effects.map { $0.quantity.doubleValue(for: unit) }) - - let startDate = effects.first!.startDate - XCTAssertEqual([0, 5, 10, 15, 20, 25], effects.map { $0.startDate.timeIntervalSince(startDate).minutes }) - - startingEffect = HKQuantity(unit: unit.unitDivided(by: HKUnit.minute()), doubleValue: -0.5) - effects = glucose.decayEffect(atRate: startingEffect, for: .minutes(30)) - XCTAssertEqual([100, 97.5, 95.5, 94, 93, 92.5], effects.map { $0.quantity.doubleValue(for: unit) }) - } - - func testSubtractingCarbEffectFromICEWithGaps() { - let perMinute = HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) - let mgdl = HKUnit.milligramsPerDeciliter - - let formatter = DateFormatter.descriptionFormatter - let f = { (input) in - return formatter.date(from: input)! - } - - let insulinCounteractionEffects = [ - GlucoseEffectVelocity(startDate: f("2018-08-16 01:03:43 +0000"), endDate: f("2018-08-16 01:08:43 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: -0.0063630385383878375)), - GlucoseEffectVelocity(startDate: f("2018-08-16 01:08:43 +0000"), endDate: f("2018-08-16 01:13:44 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.3798225216554212)), - GlucoseEffectVelocity(startDate: f("2018-08-16 01:13:44 +0000"), endDate: f("2018-08-16 01:18:44 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.5726970790754702)), - GlucoseEffectVelocity(startDate: f("2018-08-16 01:18:44 +0000"), endDate: f("2018-08-16 01:23:44 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.7936837738660198)), - GlucoseEffectVelocity(startDate: f("2018-08-16 01:23:44 +0000"), endDate: f("2018-08-16 01:28:43 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 1.2143200509835315)), - GlucoseEffectVelocity(startDate: f("2018-08-16 01:28:43 +0000"), endDate: f("2018-08-16 02:03:43 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 1.214239367352738)), - GlucoseEffectVelocity(startDate: f("2018-08-16 02:03:43 +0000"), endDate: f("2018-08-16 03:13:44 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.64964443000756)), - GlucoseEffectVelocity(startDate: f("2018-08-16 03:13:44 +0000"), endDate: f("2018-08-16 03:18:44 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.40933503856266396)), - GlucoseEffectVelocity(startDate: f("2018-08-16 03:18:44 +0000"), endDate: f("2018-08-16 03:23:43 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.5994115966821696)), - GlucoseEffectVelocity(startDate: f("2018-08-16 03:23:43 +0000"), endDate: f("2018-08-16 03:28:44 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.640336708627245)), - GlucoseEffectVelocity(startDate: f("2018-08-16 03:28:44 +0000"), endDate: f("2018-08-16 03:33:43 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 1.5109774027636143)), - GlucoseEffectVelocity(startDate: f("2018-08-16 03:33:43 +0000"), endDate: f("2018-08-16 03:38:43 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: -1.6358198764701966)), - GlucoseEffectVelocity(startDate: f("2018-08-16 03:38:43 +0000"), endDate: f("2018-08-16 03:43:44 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.4187533857556986)), - GlucoseEffectVelocity(startDate: f("2018-08-16 03:43:44 +0000"), endDate: f("2018-08-16 03:48:43 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: -1.136005257968153)), - GlucoseEffectVelocity(startDate: f("2018-08-16 03:48:43 +0000"), endDate: f("2018-08-16 03:53:44 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: -0.29635521996668046)), - GlucoseEffectVelocity(startDate: f("2018-08-16 03:53:44 +0000"), endDate: f("2018-08-16 03:58:43 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: -1.070285990192832)), - GlucoseEffectVelocity(startDate: f("2018-08-16 03:58:43 +0000"), endDate: f("2018-08-16 04:03:43 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: -0.25025410282677996)), - GlucoseEffectVelocity(startDate: f("2018-08-16 04:03:43 +0000"), endDate: f("2018-08-16 04:08:43 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.5598990284715561)), - GlucoseEffectVelocity(startDate: f("2018-08-16 04:08:43 +0000"), endDate: f("2018-08-16 04:13:44 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 1.9616378142801167)), - GlucoseEffectVelocity(startDate: f("2018-08-16 04:13:44 +0000"), endDate: f("2018-08-16 04:18:43 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 1.7593854114682483)), - GlucoseEffectVelocity(startDate: f("2018-08-16 04:18:43 +0000"), endDate: f("2018-08-16 04:23:44 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.5467358931981837)), - GlucoseEffectVelocity(startDate: f("2018-08-16 04:23:44 +0000"), endDate: f("2018-08-16 04:28:44 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.9335047268082058)), - GlucoseEffectVelocity(startDate: f("2018-08-16 04:28:44 +0000"), endDate: f("2018-08-16 04:33:43 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: -0.2823274349191665)), - ] - - let carbEffects = [ - GlucoseEffect(startDate: f("2018-08-16 01:00:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 69.38642455065255)), - GlucoseEffect(startDate: f("2018-08-16 01:05:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 69.38642455065255)), - GlucoseEffect(startDate: f("2018-08-16 01:10:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 72.18741125500856)), - GlucoseEffect(startDate: f("2018-08-16 01:15:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 82.00120184863087)), - GlucoseEffect(startDate: f("2018-08-16 01:20:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 90.79285286260895)), - GlucoseEffect(startDate: f("2018-08-16 01:25:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 93.5316456300059)), - GlucoseEffect(startDate: f("2018-08-16 01:30:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 98.19664696604428)), - GlucoseEffect(startDate: f("2018-08-16 01:35:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 98.5800323225078)), - GlucoseEffect(startDate: f("2018-08-16 01:40:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 100.09237800152016)), - GlucoseEffect(startDate: f("2018-08-16 01:45:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 101.60472368053252)), - GlucoseEffect(startDate: f("2018-08-16 01:50:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 103.11706935954487)), - GlucoseEffect(startDate: f("2018-08-16 01:55:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 104.6294150385572)), - GlucoseEffect(startDate: f("2018-08-16 02:00:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 129.38642455065255)), - GlucoseEffect(startDate: f("2018-08-16 02:05:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 129.38642455065255)), - GlucoseEffect(startDate: f("2018-08-16 02:10:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 132.18741125500856)), - GlucoseEffect(startDate: f("2018-08-16 02:15:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 142.00120184863087)), - GlucoseEffect(startDate: f("2018-08-16 02:20:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 150.79285286260895)), - GlucoseEffect(startDate: f("2018-08-16 02:25:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 153.5316456300059)), - GlucoseEffect(startDate: f("2018-08-16 02:30:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 158.19664696604428)), - GlucoseEffect(startDate: f("2018-08-16 02:35:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 158.5800323225078)), - GlucoseEffect(startDate: f("2018-08-16 02:40:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 160.09237800152016)), - GlucoseEffect(startDate: f("2018-08-16 02:45:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 161.60472368053252)), - GlucoseEffect(startDate: f("2018-08-16 02:50:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 163.11706935954487)), - GlucoseEffect(startDate: f("2018-08-16 02:55:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 164.6294150385572)), - GlucoseEffect(startDate: f("2018-08-16 03:00:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 166.14176071756955)), - GlucoseEffect(startDate: f("2018-08-16 03:05:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 167.65410639658188)), - GlucoseEffect(startDate: f("2018-08-16 03:10:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 169.16645207559424)), - GlucoseEffect(startDate: f("2018-08-16 03:15:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 170.6787977546066)), - GlucoseEffect(startDate: f("2018-08-16 03:20:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 172.19114343361895)), - GlucoseEffect(startDate: f("2018-08-16 03:25:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 173.70348911263127)), - GlucoseEffect(startDate: f("2018-08-16 03:30:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 175.21583479164363)), - GlucoseEffect(startDate: f("2018-08-16 03:35:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 176.72818047065596)), - GlucoseEffect(startDate: f("2018-08-16 03:40:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 178.2405261496683)), - GlucoseEffect(startDate: f("2018-08-16 03:45:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 179.75287182868067)), - GlucoseEffect(startDate: f("2018-08-16 03:50:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 181.26521750769302)), - GlucoseEffect(startDate: f("2018-08-16 03:55:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 182.77756318670535)), - GlucoseEffect(startDate: f("2018-08-16 04:00:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 189.38642455065255)), - GlucoseEffect(startDate: f("2018-08-16 04:05:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 189.38642455065255)), - GlucoseEffect(startDate: f("2018-08-16 04:10:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 192.18741125500856)), - GlucoseEffect(startDate: f("2018-08-16 04:15:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 202.00120184863087)), - GlucoseEffect(startDate: f("2018-08-16 04:20:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 210.79285286260895)), - GlucoseEffect(startDate: f("2018-08-16 04:25:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 213.5316456300059)), - GlucoseEffect(startDate: f("2018-08-16 04:30:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 218.19664696604428)), - GlucoseEffect(startDate: f("2018-08-16 04:35:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 218.5800323225078)), - GlucoseEffect(startDate: f("2018-08-16 04:40:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 220.09237800152016)), - GlucoseEffect(startDate: f("2018-08-16 04:45:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 221.60472368053252)), - GlucoseEffect(startDate: f("2018-08-16 04:50:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 223.11706935954487)), - GlucoseEffect(startDate: f("2018-08-16 04:55:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 224.6294150385572)), - GlucoseEffect(startDate: f("2018-08-16 05:00:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 226.14176071756955)), - GlucoseEffect(startDate: f("2018-08-16 05:05:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 227.65410639658188)), - GlucoseEffect(startDate: f("2018-08-16 05:10:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 229.16645207559424)), - GlucoseEffect(startDate: f("2018-08-16 05:15:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 230.6787977546066)), - GlucoseEffect(startDate: f("2018-08-16 05:20:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 232.19114343361895)), - GlucoseEffect(startDate: f("2018-08-16 05:25:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 233.70348911263127)), - GlucoseEffect(startDate: f("2018-08-16 05:30:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 235.21583479164363)), - GlucoseEffect(startDate: f("2018-08-16 05:35:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 236.72818047065596)), - GlucoseEffect(startDate: f("2018-08-16 05:40:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 238.2405261496683)), - GlucoseEffect(startDate: f("2018-08-16 05:45:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 239.75287182868067)), - GlucoseEffect(startDate: f("2018-08-16 05:50:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 241.26521750769302)), - GlucoseEffect(startDate: f("2018-08-16 05:55:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 242.77756318670535)), - GlucoseEffect(startDate: f("2018-08-16 06:00:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 244.28990886571768)), - GlucoseEffect(startDate: f("2018-08-16 06:05:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 245.80225454473003)), - GlucoseEffect(startDate: f("2018-08-16 06:10:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 247.3146002237424)), - GlucoseEffect(startDate: f("2018-08-16 06:15:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 248.82694590275474)), - GlucoseEffect(startDate: f("2018-08-16 06:20:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 250.33929158176707)), - GlucoseEffect(startDate: f("2018-08-16 06:25:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 251.85163726077943)), - GlucoseEffect(startDate: f("2018-08-16 06:30:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 253.16666666666669)), - GlucoseEffect(startDate: f("2018-08-16 06:35:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 253.16666666666669)), - GlucoseEffect(startDate: f("2018-08-16 06:40:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 253.16666666666669)), - ] - - let calculated = insulinCounteractionEffects.subtracting(carbEffects, withUniformInterval: .minutes(5)) - - let expected = loadGlucoseEffectFixture("ice_minus_carb_effect_with_gaps_output", formatter: DateFormatter.descriptionFormatter) - - XCTAssertEqual(expected, calculated) - } - - func testSubtractingFlatCarbEffectFromICE() { - let perMinute = HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) - let mgdl = HKUnit.milligramsPerDeciliter - - let formatter = DateFormatter.descriptionFormatter - let f = { (input) in - return formatter.date(from: input)! - } - - let insulinCounteractionEffects = [ - GlucoseEffectVelocity(startDate: f("2018-08-26 00:23:27 +0000"), endDate: f("2018-08-26 00:28:28 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.3711911901542791)), - GlucoseEffectVelocity(startDate: f("2018-08-26 00:28:28 +0000"), endDate: f("2018-08-26 00:33:27 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: -0.4382943196158106)), - GlucoseEffectVelocity(startDate: f("2018-08-26 00:33:27 +0000"), endDate: f("2018-08-26 00:38:27 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: -0.24797050925219474)), - GlucoseEffectVelocity(startDate: f("2018-08-26 00:38:27 +0000"), endDate: f("2018-08-26 00:43:28 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: -0.05800368381887202)), - GlucoseEffectVelocity(startDate: f("2018-08-26 00:43:28 +0000"), endDate: f("2018-08-26 00:48:28 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.7303422936657988)), - GlucoseEffectVelocity(startDate: f("2018-08-26 00:48:28 +0000"), endDate: f("2018-08-26 00:53:28 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.7166291304729353)), - GlucoseEffectVelocity(startDate: f("2018-08-26 00:53:28 +0000"), endDate: f("2018-08-26 00:58:28 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.2962279320324577)), - GlucoseEffectVelocity(startDate: f("2018-08-26 00:58:28 +0000"), endDate: f("2018-08-26 01:03:27 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.2730196016663657)), - GlucoseEffectVelocity(startDate: f("2018-08-26 01:03:27 +0000"), endDate: f("2018-08-26 01:08:28 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.44605609358758713)), - GlucoseEffectVelocity(startDate: f("2018-08-26 01:08:28 +0000"), endDate: f("2018-08-26 01:13:28 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.42131971635266463)), - GlucoseEffectVelocity(startDate: f("2018-08-26 01:13:28 +0000"), endDate: f("2018-08-26 01:18:27 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.9948293689475411)), - GlucoseEffectVelocity(startDate: f("2018-08-26 01:18:27 +0000"), endDate: f("2018-08-26 01:23:28 +0000"), quantity: HKQuantity(unit: perMinute, doubleValue: 0.9652238210644638)), - ] - - let carbEffects = [ - GlucoseEffect(startDate: f("2018-08-26 00:45:00 +0000"), quantity: HKQuantity(unit: mgdl, doubleValue: 385.8235294117647)) - ] - - let calculated = insulinCounteractionEffects.subtracting(carbEffects, withUniformInterval: .minutes(5)) - - let expected = loadGlucoseEffectFixture("ice_minus_flat_carb_effect_output", formatter: DateFormatter.descriptionFormatter) - - XCTAssertEqual(expected, calculated) - } - - func testCombinedSumsWithGaps() { - let input = loadGlucoseEffectFixture("ice_minus_carb_effect_with_gaps_output", formatter: DateFormatter.descriptionFormatter) - let unit = HKUnit.milligramsPerDeciliter - - let formatter = DateFormatter.descriptionFormatter - let f = { (input) in - return formatter.date(from: input)! - } - - let expected = [ - GlucoseChange(startDate: f("2018-08-16 01:13:44 +0000"), endDate: f("2018-08-16 01:13:44 +0000"), quantity: HKQuantity(unit: unit, doubleValue: -7.914677985345208)), - GlucoseChange(startDate: f("2018-08-16 01:13:44 +0000"), endDate: f("2018-08-16 01:18:44 +0000"), quantity: HKQuantity(unit: unit, doubleValue: -13.84284360394594)), - GlucoseChange(startDate: f("2018-08-16 01:13:44 +0000"), endDate: f("2018-08-16 01:23:44 +0000"), quantity: HKQuantity(unit: unit, doubleValue: -12.613217502012784)), - GlucoseChange(startDate: f("2018-08-16 01:13:44 +0000"), endDate: f("2018-08-16 01:28:43 +0000"), quantity: HKQuantity(unit: unit, doubleValue: -11.206618583133514)), - GlucoseChange(startDate: f("2018-08-16 02:03:43 +0000"), endDate: f("2018-08-16 02:03:43 +0000"), quantity: HKQuantity(unit: unit, doubleValue: 6.071196836763691)), - GlucoseChange(startDate: f("2018-08-16 03:13:44 +0000"), endDate: f("2018-08-16 03:13:44 +0000"), quantity: HKQuantity(unit: unit, doubleValue: 1.735876471025445)), - GlucoseChange(startDate: f("2018-08-16 03:13:44 +0000"), endDate: f("2018-08-16 03:18:44 +0000"), quantity: HKQuantity(unit: unit, doubleValue: 2.2702059848264096)), - GlucoseChange(startDate: f("2018-08-16 03:13:44 +0000"), endDate: f("2018-08-16 03:23:43 +0000"), quantity: HKQuantity(unit: unit, doubleValue: 3.754918289224931)), - GlucoseChange(startDate: f("2018-08-16 03:13:44 +0000"), endDate: f("2018-08-16 03:28:44 +0000"), quantity: HKQuantity(unit: unit, doubleValue: 5.444256153348801)), - GlucoseChange(startDate: f("2018-08-16 03:13:44 +0000"), endDate: f("2018-08-16 03:33:43 +0000"), quantity: HKQuantity(unit: unit, doubleValue: 11.486797488154545)), - GlucoseChange(startDate: f("2018-08-16 03:13:44 +0000"), endDate: f("2018-08-16 03:38:43 +0000"), quantity: HKQuantity(unit: unit, doubleValue: 1.7953524267912058)), - GlucoseChange(startDate: f("2018-08-16 03:13:44 +0000"), endDate: f("2018-08-16 03:43:44 +0000"), quantity: HKQuantity(unit: unit, doubleValue: 2.376773676557343)), - GlucoseChange(startDate: f("2018-08-16 03:18:44 +0000"), endDate: f("2018-08-16 03:48:43 +0000"), quantity: HKQuantity(unit: unit, doubleValue: -6.551474763321222)), - GlucoseChange(startDate: f("2018-08-16 03:28:44 +0000"), endDate: f("2018-08-16 03:53:44 +0000"), quantity: HKQuantity(unit: unit, doubleValue: -11.56463836036644)), - GlucoseChange(startDate: f("2018-08-16 03:28:44 +0000"), endDate: f("2018-08-16 03:58:43 +0000"), quantity: HKQuantity(unit: unit, doubleValue: -23.524929675277797)), - GlucoseChange(startDate: f("2018-08-16 03:33:43 +0000"), endDate: f("2018-08-16 04:03:43 +0000"), quantity: HKQuantity(unit: unit, doubleValue: -26.46553805353557)), - GlucoseChange(startDate: f("2018-08-16 03:38:43 +0000"), endDate: f("2018-08-16 04:08:43 +0000"), quantity: HKQuantity(unit: unit, doubleValue: -32.50957095033954)), - GlucoseChange(startDate: f("2018-08-16 03:43:44 +0000"), endDate: f("2018-08-16 04:13:44 +0000"), quantity: HKQuantity(unit: unit, doubleValue: -22.823727411197925)), - GlucoseChange(startDate: f("2018-08-16 03:48:43 +0000"), endDate: f("2018-08-16 04:18:43 +0000"), quantity: HKQuantity(unit: unit, doubleValue: -23.399872617600906)), - GlucoseChange(startDate: f("2018-08-16 03:53:44 +0000"), endDate: f("2018-08-16 04:23:44 +0000"), quantity: HKQuantity(unit: unit, doubleValue: -16.21261395015381)), - GlucoseChange(startDate: f("2018-08-16 04:03:43 +0000"), endDate: f("2018-08-16 04:28:44 +0000"), quantity: HKQuantity(unit: unit, doubleValue: -1.2556785583940788)), - GlucoseChange(startDate: f("2018-08-16 04:03:43 +0000"), endDate: f("2018-08-16 04:33:43 +0000"), quantity: HKQuantity(unit: unit, doubleValue: -3.0507010894534323)) - ] - - let calculated = input.combinedSums(of: .minutes(30)) - - XCTAssertEqual(expected, calculated) - } - - - func testNetEffect() { - let formatter = DateFormatter.descriptionFormatter - let f = { (input) in - return formatter.date(from: input)! - } - - let unit = HKUnit.milligramsPerDeciliter - - let input = [ - GlucoseEffect(startDate: f("2018-08-16 01:00:00 +0000"), quantity: HKQuantity(unit: unit, doubleValue: 25)), - GlucoseEffect(startDate: f("2018-08-16 01:05:00 +0000"), quantity: HKQuantity(unit: unit, doubleValue: 26)), - GlucoseEffect(startDate: f("2018-08-16 01:10:00 +0000"), quantity: HKQuantity(unit: unit, doubleValue: 27)) - ] - - let calculated = input.netEffect() - - let expected = GlucoseChange( - startDate: f("2018-08-16 01:00:00 +0000"), - endDate: f("2018-08-16 01:10:00 +0000"), - quantity: HKQuantity(unit: unit, doubleValue: 2)) - - XCTAssertEqual(expected, calculated) - } - - func testDateRange() { - let formatter = DateFormatter.descriptionFormatter - let f = { (input) in - return formatter.date(from: input)! - } - - let expected = [ - f("2018-08-16 01:00:00 +0000"), - f("2018-08-16 01:05:00 +0000"), - f("2018-08-16 01:10:00 +0000"), - f("2018-08-16 01:15:00 +0000"), - f("2018-08-16 01:20:00 +0000"), - f("2018-08-16 01:25:00 +0000"), - f("2018-08-16 01:30:00 +0000"), - f("2018-08-16 01:35:00 +0000"), - f("2018-08-16 01:40:00 +0000"), - f("2018-08-16 01:45:00 +0000"), - f("2018-08-16 01:50:00 +0000"), - f("2018-08-16 01:55:00 +0000"), - f("2018-08-16 02:00:00 +0000"), - f("2018-08-16 02:05:00 +0000"), - f("2018-08-16 02:10:00 +0000"), - f("2018-08-16 02:15:00 +0000"), - f("2018-08-16 02:20:00 +0000"), - f("2018-08-16 02:25:00 +0000"), - f("2018-08-16 02:30:00 +0000"), - f("2018-08-16 02:35:00 +0000"), - f("2018-08-16 02:40:00 +0000"), - f("2018-08-16 02:45:00 +0000"), - f("2018-08-16 02:50:00 +0000"), - f("2018-08-16 02:55:00 +0000"), - f("2018-08-16 03:00:00 +0000"), - f("2018-08-16 03:05:00 +0000"), - f("2018-08-16 03:10:00 +0000") - ] - - let roundedStartDate = f("2018-08-16 01:00:00 +0000") - let unroundedStartDate = f("2018-08-16 01:04:13 +0000") - - let roundedEndDate = f("2018-08-16 03:10:00 +0000") - let unroundedEndDate = f("2018-08-16 03:06:29 +0000") - - let roundedOutput = LoopMath.simulationDateRange(from: roundedStartDate, to: roundedEndDate, delta: .minutes(5)) - XCTAssertEqual(expected, roundedOutput) - - let unroundedOutput = LoopMath.simulationDateRange(from: unroundedStartDate, to: unroundedEndDate, delta: .minutes(5)) - XCTAssertEqual(expected, unroundedOutput) - - let differentDeltaExpected = expected - .enumerated() - .compactMap { $0.offset.isMultiple(of: 2) ? $0.element : nil } - let differentDeltaOutput = LoopMath.simulationDateRange(from: unroundedStartDate, to: unroundedEndDate, delta: .minutes(10)) - XCTAssertEqual(differentDeltaExpected, differentDeltaOutput) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/NSDateTests.swift b/Dependencies/LoopKit/LoopKitTests/NSDateTests.swift deleted file mode 100644 index df32078da..000000000 --- a/Dependencies/LoopKit/LoopKitTests/NSDateTests.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// NSDateTests.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/18/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import LoopKit - -class NSDateTests: XCTestCase { - - func testDateCeiledToInterval() { - let calendar = Calendar.current - - let five01 = calendar.nextDate(after: Date(), matching: DateComponents(hour: 5, minute: 0, second: 1), matchingPolicy: .nextTime)! - - let five05 = calendar.nextDate(after: five01, matching: DateComponents(hour: 5, minute: 5, second: 0), matchingPolicy: .nextTime)! - - XCTAssertEqual(five05, five01.dateCeiledToTimeInterval(TimeInterval(minutes: 5))) - - let six = calendar.nextDate(after: five01, matching: DateComponents(hour: 6, minute: 0, second: 0), matchingPolicy: .nextTime)! - - XCTAssertEqual(six, five01.dateCeiledToTimeInterval(TimeInterval(minutes: 60))) - - XCTAssertEqual(five05, five05.dateCeiledToTimeInterval(TimeInterval(minutes: 5))) - - let five47 = calendar.nextDate(after: five01, matching: DateComponents(hour: 5, minute: 47, second: 58), matchingPolicy: .nextTime)! - - let five50 = calendar.nextDate(after: five01, matching: DateComponents(hour: 5, minute: 50, second: 0), matchingPolicy: .nextTime)! - - XCTAssertEqual(five50, five47.dateCeiledToTimeInterval(TimeInterval(minutes: 5))) - - let twentyThree59 = calendar.nextDate(after: five01, matching: DateComponents(hour: 23, minute: 59, second: 0), matchingPolicy: .nextTime)! - - let tomorrowMidnight = calendar.nextDate(after: five01, matching: DateComponents(hour: 0, minute: 0, second: 0), matchingPolicy: .nextTime)! - - XCTAssertEqual(tomorrowMidnight, twentyThree59.dateCeiledToTimeInterval(TimeInterval(minutes: 5))) - - XCTAssertEqual(five01, five01.dateCeiledToTimeInterval(TimeInterval(0))) - } - - func testDateFlooredToInterval() { - let calendar = Calendar.current - - let five01 = calendar.nextDate(after: Date(), matching: DateComponents(hour: 5, minute: 0, second: 1), matchingPolicy: .nextTime)! - - let five = calendar.nextDate(after: five01, matching: DateComponents(hour: 5, minute: 0, second: 0), matchingPolicy: .nextTime, direction: .backward)! - - XCTAssertEqual(five, five01.dateFlooredToTimeInterval(TimeInterval(minutes: 5))) - - let five59 = calendar.nextDate(after: five01, matching: DateComponents(hour: 5, minute: 59, second: 0), matchingPolicy: .nextTime)! - - XCTAssertEqual(five, five59.dateFlooredToTimeInterval(TimeInterval(minutes: 60))) - - let five55 = calendar.nextDate(after: five01, matching: DateComponents(hour: 5, minute: 55, second: 0), matchingPolicy: .nextTime)! - - XCTAssertEqual(five55, five59.dateFlooredToTimeInterval(TimeInterval(minutes: 5))) - - - XCTAssertEqual(five, five.dateFlooredToTimeInterval(TimeInterval(minutes: 5))) - - XCTAssertEqual(five01, five01.dateFlooredToTimeInterval(TimeInterval(0))) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/NewGlucoseSampleTests.swift b/Dependencies/LoopKit/LoopKitTests/NewGlucoseSampleTests.swift deleted file mode 100644 index 40173487f..000000000 --- a/Dependencies/LoopKit/LoopKitTests/NewGlucoseSampleTests.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// NewGlucoseSampleTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 9/7/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class NewGlucoseSampleTests: XCTestCase { - func testQuantitySample() { - let date = Date() - let quantity = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 145.3) - let trendRate = HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: 1.1) - let device = HKDevice(name: "Device Name", - manufacturer: "Device Manufacturer", - model: "Device Model", - hardwareVersion: "Device Hardware Version", - firmwareVersion: "Device Firmware Version", - softwareVersion: "Device Software Version", - localIdentifier: "Device Local Identifier", - udiDeviceIdentifier: "Device UDI Device Identifier") - let syncIdentifier = UUID().uuidString - let newGlucoseSample = NewGlucoseSample(date: date, - quantity: quantity, - condition: .aboveRange, - trend: .up, - trendRate: trendRate, - isDisplayOnly: false, - wasUserEntered: true, - syncIdentifier: syncIdentifier, - syncVersion: 3, - device: device) - let quantitySample = newGlucoseSample.quantitySample - XCTAssertEqual(quantitySample.quantityType, HKQuantityType.quantityType(forIdentifier: .bloodGlucose)!) - XCTAssertEqual(quantitySample.quantity, quantity) - XCTAssertEqual(quantitySample.startDate, date) - XCTAssertEqual(quantitySample.endDate, date) - XCTAssertEqual(quantitySample.device, device) - XCTAssertEqual(quantitySample.metadata?[HKMetadataKeySyncIdentifier] as? String, syncIdentifier) - XCTAssertEqual(quantitySample.metadata?[HKMetadataKeySyncVersion] as? Int, 3) - XCTAssertEqual(quantitySample.metadata?[MetadataKeyGlucoseCondition] as? String, "aboveRange") - XCTAssertEqual(quantitySample.metadata?[MetadataKeyGlucoseTrend] as? String, GlucoseTrend.up.symbol) - XCTAssertEqual(quantitySample.metadata?[MetadataKeyGlucoseTrendRateUnit] as? String, HKUnit.milligramsPerDeciliterPerMinute.unitString) - XCTAssertEqual(quantitySample.metadata?[MetadataKeyGlucoseTrendRateValue] as? Double, 1.1) - XCTAssertNil(quantitySample.metadata?[MetadataKeyGlucoseIsDisplayOnly]) - XCTAssertEqual(quantitySample.metadata?[HKMetadataKeyWasUserEntered] as? Bool, true) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/NewPumpEventTests.swift b/Dependencies/LoopKit/LoopKitTests/NewPumpEventTests.swift deleted file mode 100644 index 9fa94d17b..000000000 --- a/Dependencies/LoopKit/LoopKitTests/NewPumpEventTests.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// NewPumpEventTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 1/13/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class NewPumpEventRawRepresentableTests: XCTestCase { - func testNewPumpEventRawRepresentable() { - let original = NewPumpEvent(date: Date(), - dose: DoseEntry(type: .tempBasal, - startDate: Date(), - endDate: Date().addingTimeInterval(.minutes(30)), - value: 1.5, - unit: .unitsPerHour, - deliveredUnits: 0.5, - description: "Test Dose Entry", - syncIdentifier: UUID().uuidString, - scheduledBasalRate: HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 2.0), - insulinType: .fiasp, - automatic: true, - manuallyEntered: false, - isMutable: true, - wasProgrammedByPumpUI: true), - raw: Data(UUID().uuidString.utf8), - title: "Test Pump Event", - type: .tempBasal, - alarmType: .occlusion) - let actual = NewPumpEvent(rawValue: original.rawValue) - XCTAssertEqual(actual, original) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/NotificationSettingsTests.swift b/Dependencies/LoopKit/LoopKitTests/NotificationSettingsTests.swift deleted file mode 100644 index 0d0574259..000000000 --- a/Dependencies/LoopKit/LoopKitTests/NotificationSettingsTests.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// NotificationSettingsTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 9/17/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import Foundation -@testable import LoopKit - -class NotificationSettingsCodableTests: XCTestCase { - func testCodable() throws { - try assertNotificationSettingsCodable(NotificationSettings.test, encodesJSON: """ -{ - "alertSetting" : "disabled", - "alertStyle" : "banner", - "announcementSetting" : "enabled", - "authorizationStatus" : "authorized", - "badgeSetting" : "enabled", - "carPlaySetting" : "notSupported", - "criticalAlertSetting" : "enabled", - "lockScreenSetting" : "disabled", - "notificationCenterSetting" : "notSupported", - "providesAppNotificationSettings" : true, - "scheduledDeliverySetting" : "disabled", - "showPreviewsSetting" : "whenAuthenticated", - "soundSetting" : "enabled", - "temporaryMuteAlertsSetting" : { - "enabled" : { - "_0" : 1800 - } - }, - "timeSensitiveSetting" : "enabled" -} -""" - ) - } - - func testMigration() throws { - let oldSettingsString = """ -{ - "alertSetting" : "disabled", - "alertStyle" : "banner", - "announcementSetting" : "enabled", - "authorizationStatus" : "authorized", - "badgeSetting" : "enabled", - "carPlaySetting" : "notSupported", - "criticalAlertSetting" : "enabled", - "lockScreenSetting" : "disabled", - "notificationCenterSetting" : "notSupported", - "providesAppNotificationSettings" : true, - "showPreviewsSetting" : "whenAuthenticated", - "soundSetting" : "enabled" -} -""" - let _ = try decoder.decode(NotificationSettings.self, from: oldSettingsString.data(using: .utf8)!) - } - - private func assertNotificationSettingsCodable(_ original: NotificationSettings, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(NotificationSettings.self, from: data) - XCTAssertEqual(decoded, original) - } - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() -} - -fileprivate extension NotificationSettings { - static var test: NotificationSettings { - return NotificationSettings(authorizationStatus: .authorized, - soundSetting: .enabled, - badgeSetting: .enabled, - alertSetting: .disabled, - notificationCenterSetting: .notSupported, - lockScreenSetting: .disabled, - carPlaySetting: .notSupported, - alertStyle: .banner, - showPreviewsSetting: .whenAuthenticated, - criticalAlertSetting: .enabled, - providesAppNotificationSettings: true, - announcementSetting: .enabled, - timeSensitiveSetting: .enabled, - scheduledDeliverySetting: .disabled, - temporaryMuteAlertsSetting: .enabled(.minutes(30))) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/OutputStreamTests.swift b/Dependencies/LoopKit/LoopKitTests/OutputStreamTests.swift deleted file mode 100644 index 5d19ca988..000000000 --- a/Dependencies/LoopKit/LoopKitTests/OutputStreamTests.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// OutputStreamTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 9/17/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import Foundation -@testable import LoopKit - -class OutputStreamTests: XCTestCase { - private let string = "The quick brown fox jumps over the lazy dog" - - func testWriteString() { - let outputStream = MockOutputStream() - XCTAssertNoThrow(try outputStream.write(string)) - XCTAssertEqual(outputStream.string, string) - } - - func testWriteStringThrowsError() { - let outputStream = MockOutputStream() - outputStream.error = MockError() - XCTAssertThrowsError(try outputStream.write(string)) { error in - XCTAssertEqual(error as! MockError, outputStream.error as! MockError) - } - } - - func testWriteData() { - let data = string.data(using: .utf8)! - let outputStream = MockOutputStream() - XCTAssertNoThrow(try outputStream.write(data)) - XCTAssertEqual(outputStream.data, data) - } - - func testWriteDataThrowsError() { - let data = string.data(using: .utf8)! - let outputStream = MockOutputStream() - outputStream.error = MockError() - XCTAssertThrowsError(try outputStream.write(data)) { error in - XCTAssertEqual(error as! MockError, outputStream.error as! MockError) - } - } -} - -fileprivate struct MockError: Error, Equatable {} diff --git a/Dependencies/LoopKit/LoopKitTests/OverrideTests.swift b/Dependencies/LoopKit/LoopKitTests/OverrideTests.swift deleted file mode 100644 index 61e1cfa61..000000000 --- a/Dependencies/LoopKit/LoopKitTests/OverrideTests.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// OverrideTests.swift -// LoopKitTests -// -// Created by Nathaniel Hamming on 2021-03-09. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest - -@testable import LoopKit - -class OverrideTests: XCTestCase { - - func testInitizer() { - let now = Date() - var override = GlucoseRangeSchedule.Override( - value: DoubleRange(minValue: 70, maxValue: 80), - start: now, - end: now.addingTimeInterval(TimeInterval.minutes(30))) - XCTAssertEqual(override.value, DoubleRange(minValue: 70, maxValue: 80)) - XCTAssertEqual(override.start, now) - XCTAssertEqual(override.end, now.addingTimeInterval(TimeInterval.minutes(30))) - - override = GlucoseRangeSchedule.Override( - value: DoubleRange(minValue: 70, maxValue: 80), - start: now) - XCTAssertEqual(override.end, .distantFuture) - } - - func testActiveDates() { - let duration = TimeInterval.hours(24) - let start = Date() - let end = start.addingTimeInterval(duration) - - let override = GlucoseRangeSchedule.Override( - value: DoubleRange(minValue: 70, maxValue: 80), - start: start, - end: end) - - XCTAssertEqual(override.activeDates.start, start) - XCTAssertEqual(override.activeDates.end, end) - XCTAssertEqual(override.activeDates.duration, duration) - } - - func testIsActiveAtDate() { - let duration = TimeInterval.hours(24) - let start = Date() - let end = start.addingTimeInterval(duration) - - let override = GlucoseRangeSchedule.Override( - value: DoubleRange(minValue: 70, maxValue: 80), - start: start, - end: end) - - XCTAssertTrue(override.isActive(at: start.addingTimeInterval(duration/2))) - XCTAssertFalse(override.isActive(at: start.addingTimeInterval(duration*2))) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/Persistence/CachedCarbObjectTests.swift b/Dependencies/LoopKit/LoopKitTests/Persistence/CachedCarbObjectTests.swift deleted file mode 100644 index a489c9e82..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Persistence/CachedCarbObjectTests.swift +++ /dev/null @@ -1,140 +0,0 @@ -// -// CachedCarbObjectTests.swift -// LoopKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import LoopKit - -class CachedCarbObjectTests: PersistenceControllerTestCase { - func testSaveWithDefaultValues() { - cacheStore.managedObjectContext.performAndWait { - let object1 = CachedCarbObject(context: cacheStore.managedObjectContext) - object1.setDefaultValues() - - try! cacheStore.managedObjectContext.save() - - let object2 = CachedCarbObject(context: cacheStore.managedObjectContext) - object2.setDefaultValues() - - try! cacheStore.managedObjectContext.save() - - let objects: [CachedCarbObject] = cacheStore.managedObjectContext.all() - XCTAssertEqual(2, objects.count) - } - } -} - -class CachedCarbObjectEncodableTests: PersistenceControllerTestCase { - func testEncodable() throws { - let semaphore = DispatchSemaphore(value: 0) - - cacheStore.onReady { error in - semaphore.signal() - } - semaphore.wait() - cacheStore.managedObjectContext.performAndWait { - let cachedCarbObject = CachedCarbObject(context: cacheStore.managedObjectContext) - cachedCarbObject.absorptionTime = 18000 - cachedCarbObject.createdByCurrentApp = true - cachedCarbObject.foodType = "Pizza" - cachedCarbObject.grams = 45 - cachedCarbObject.startDate = dateFormatter.date(from: "2020-05-14T22:38:14Z")! - cachedCarbObject.uuid = UUID(uuidString: "2A67A303-5203-4CB8-8263-79498265368E")! - cachedCarbObject.provenanceIdentifier = "238E41EA-9576-4981-A1A4-51E10228584F" - cachedCarbObject.syncIdentifier = "7723A0EE-F6D5-46E0-BBFE-1DEEBF8ED6F2" - cachedCarbObject.syncVersion = 2 - cachedCarbObject.userCreatedDate = dateFormatter.date(from: "2020-05-14T22:28:12Z")! - cachedCarbObject.userUpdatedDate = dateFormatter.date(from: "2020-05-14T22:33:47Z")! - cachedCarbObject.userDeletedDate = nil - cachedCarbObject.operation = .update - cachedCarbObject.addedDate = dateFormatter.date(from: "2020-05-14T22:33:48Z")! - cachedCarbObject.supercededDate = nil - cachedCarbObject.anchorKey = 123 - try! assertCachedCarbObjectEncodable(cachedCarbObject, encodesJSON: """ -{ - "absorptionTime" : 18000, - "addedDate" : "2020-05-14T22:33:48Z", - "anchorKey" : 123, - "createdByCurrentApp" : true, - "foodType" : "Pizza", - "grams" : 45, - "operation" : 1, - "provenanceIdentifier" : "238E41EA-9576-4981-A1A4-51E10228584F", - "startDate" : "2020-05-14T22:38:14Z", - "syncIdentifier" : "7723A0EE-F6D5-46E0-BBFE-1DEEBF8ED6F2", - "syncVersion" : 2, - "userCreatedDate" : "2020-05-14T22:28:12Z", - "userUpdatedDate" : "2020-05-14T22:33:47Z", - "uuid" : "2A67A303-5203-4CB8-8263-79498265368E" -} -""" - ) - } - } - - func testEncodableOptional() throws { - cacheStore.managedObjectContext.performAndWait { - let cachedCarbObject = CachedCarbObject(context: cacheStore.managedObjectContext) - cachedCarbObject.createdByCurrentApp = false - cachedCarbObject.grams = 34 - cachedCarbObject.startDate = dateFormatter.date(from: "2020-05-15T22:38:14Z")! - cachedCarbObject.provenanceIdentifier = "238E41EA-9576-4981-A1A4-51E10228584F" - cachedCarbObject.operation = .create - cachedCarbObject.anchorKey = 234 - try! assertCachedCarbObjectEncodable(cachedCarbObject, encodesJSON: """ -{ - "anchorKey" : 234, - "createdByCurrentApp" : false, - "grams" : 34, - "operation" : 0, - "provenanceIdentifier" : "238E41EA-9576-4981-A1A4-51E10228584F", - "startDate" : "2020-05-15T22:38:14Z" -} -""" - ) - } - } - - private func assertCachedCarbObjectEncodable(_ original: CachedCarbObject, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() -} - -extension CachedCarbObject { - fileprivate func setDefaultValues() { - self.absorptionTime = .hours(3) - self.createdByCurrentApp = true - self.foodType = "Breakfast" - self.grams = 45.6 - self.startDate = Date() - self.uuid = UUID() - self.provenanceIdentifier = "CachedCarbObjectTests" - self.syncIdentifier = UUID().uuidString - self.syncVersion = 1 - self.userCreatedDate = Date() - self.userUpdatedDate = nil - self.userDeletedDate = nil - self.operation = .create - self.addedDate = Date() - self.supercededDate = nil - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/Persistence/CachedGlucoseObjectTests.swift b/Dependencies/LoopKit/LoopKitTests/Persistence/CachedGlucoseObjectTests.swift deleted file mode 100644 index d53c15969..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Persistence/CachedGlucoseObjectTests.swift +++ /dev/null @@ -1,291 +0,0 @@ -// -// CachedGlucoseObjectTests.swift -// LoopKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class CachedGlucoseObjectTests: PersistenceControllerTestCase { - func testSyncVersionGet() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object.primitiveSyncVersion = NSNumber(integerLiteral: 3) - XCTAssertEqual(object.syncVersion, 3) - } - } - - func testSyncVersionGetNil() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object.primitiveSyncVersion = nil - XCTAssertNil(object.syncVersion) - } - } - - func testSyncVersionSet() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object.syncVersion = 5 - XCTAssertEqual(object.primitiveSyncVersion, NSNumber(integerLiteral: 5)) - } - } - - func testSyncVersionSetNil() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object.syncVersion = nil - XCTAssertNil(object.primitiveSyncVersion) - } - } -} - -class CachedGlucoseObjectModificationTests: PersistenceControllerTestCase { - func testHasUpdatedModificationCounter() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object.setDefaultValues() - XCTAssertTrue(object.hasUpdatedModificationCounter) - try! cacheStore.managedObjectContext.save() - XCTAssertFalse(object.hasUpdatedModificationCounter) - } - } - - func testUpdateModificationCounter() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object.modificationCounter = -1 - object.updateModificationCounter() - XCTAssertNotEqual(object.modificationCounter, -1) - } - } - - func testAwakeFromInsertUpdatesModificationCounter() { - func testHasUpdatedModificationCounter() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedGlucoseObject(context: cacheStore.managedObjectContext) - XCTAssertTrue(object.hasUpdatedModificationCounter) - } - } - } - - func testWillSaveUpdatesModificationCounter() { - func testHasUpdatedModificationCounter() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedGlucoseObject(context: cacheStore.managedObjectContext) - XCTAssertTrue(object.hasUpdatedModificationCounter) - object.setDefaultValues() - object.modificationCounter = -1 - try! cacheStore.managedObjectContext.save() - XCTAssertEqual(object.modificationCounter, -1) - object.uuid = UUID() - try! cacheStore.managedObjectContext.save() - XCTAssertNotEqual(object.modificationCounter, -1) - } - } - } - - func testWillSaveDoesNotUpdateModificationCounterIfManuallyUpdated() { - func testHasUpdatedModificationCounter() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedGlucoseObject(context: cacheStore.managedObjectContext) - XCTAssertTrue(object.hasUpdatedModificationCounter) - object.setDefaultValues() - object.modificationCounter = -1 - try! cacheStore.managedObjectContext.save() - XCTAssertEqual(object.modificationCounter, -1) - object.uuid = UUID() - object.modificationCounter = -2 - try! cacheStore.managedObjectContext.save() - XCTAssertEqual(object.modificationCounter, -2) - } - } - } -} - -class CachedGlucoseObjectConstraintTests: PersistenceControllerTestCase { - func testUUIDUniqueConstraint() { - cacheStore.managedObjectContext.performAndWait { - let uuid = UUID() - - let object1 = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object1.setDefaultValues() - object1.uuid = uuid - - try! cacheStore.managedObjectContext.save() - - let object2 = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object2.setDefaultValues() - object2.uuid = uuid - - try! cacheStore.managedObjectContext.save() - - let objects: [CachedGlucoseObject] = cacheStore.managedObjectContext.all() - XCTAssertEqual(1, objects.count) - } - } - - func testSyncIdentifierUniqueConstraint() { - cacheStore.managedObjectContext.performAndWait { - let uuid = UUID() - - let object1 = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object1.setDefaultValues() - object1.syncIdentifier = uuid.uuidString - - try! cacheStore.managedObjectContext.save() - - let object2 = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object2.setDefaultValues() - object2.syncIdentifier = uuid.uuidString - - try! cacheStore.managedObjectContext.save() - - let objects: [CachedGlucoseObject] = cacheStore.managedObjectContext.all() - XCTAssertEqual(1, objects.count) - } - } - - func testAllUniqueConstraints() { - cacheStore.managedObjectContext.performAndWait { - let uuid = UUID() - - let object1 = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object1.setDefaultValues() - object1.uuid = uuid - object1.syncIdentifier = uuid.uuidString - - try! cacheStore.managedObjectContext.save() - - let object2 = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object2.setDefaultValues() - object2.uuid = uuid - object2.syncIdentifier = uuid.uuidString - - try! cacheStore.managedObjectContext.save() - - let objects: [CachedGlucoseObject] = cacheStore.managedObjectContext.all() - XCTAssertEqual(1, objects.count) - } - } - - func testSaveWithDefaultValues() { - cacheStore.managedObjectContext.performAndWait { - let object1 = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object1.setDefaultValues() - - try! cacheStore.managedObjectContext.save() - - let object2 = CachedGlucoseObject(context: cacheStore.managedObjectContext) - object2.setDefaultValues() - - try! cacheStore.managedObjectContext.save() - - let objects: [CachedGlucoseObject] = cacheStore.managedObjectContext.all() - XCTAssertEqual(2, objects.count) - } - } -} - -class CachedGlucoseObjectQuantityTests: PersistenceControllerTestCase { - func testQuantity() throws { - cacheStore.managedObjectContext.performAndWait { - let cachedGlucoseObject = CachedGlucoseObject(context: cacheStore.managedObjectContext) - cachedGlucoseObject.value = 123.45 - cachedGlucoseObject.unitString = HKUnit.milligramsPerDeciliter.unitString - XCTAssertEqual(cachedGlucoseObject.quantity, HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 123.45)) - } - } -} - -class CachedGlucoseObjectEncodableTests: PersistenceControllerTestCase { - func testEncodable() throws { - cacheStore.managedObjectContext.performAndWait { - let cachedGlucoseObject = CachedGlucoseObject(context: cacheStore.managedObjectContext) - cachedGlucoseObject.uuid = UUID(uuidString: "2A67A303-5203-4CB8-8263-79498265368E")! - cachedGlucoseObject.provenanceIdentifier = "238E41EA-9576-4981-A1A4-51E10228584F" - cachedGlucoseObject.syncIdentifier = "7723A0EE-F6D5-46E0-BBFE-1DEEBF8ED6F2" - cachedGlucoseObject.syncVersion = 2 - cachedGlucoseObject.value = 98.7 - cachedGlucoseObject.unitString = HKUnit.milligramsPerDeciliter.unitString - cachedGlucoseObject.startDate = dateFormatter.date(from: "2020-05-14T22:38:14Z")! - cachedGlucoseObject.isDisplayOnly = false - cachedGlucoseObject.wasUserEntered = true - cachedGlucoseObject.modificationCounter = 123 - try! assertCachedGlucoseObjectEncodable(cachedGlucoseObject, encodesJSON: """ -{ - "isDisplayOnly" : false, - "modificationCounter" : 123, - "provenanceIdentifier" : "238E41EA-9576-4981-A1A4-51E10228584F", - "startDate" : "2020-05-14T22:38:14Z", - "syncIdentifier" : "7723A0EE-F6D5-46E0-BBFE-1DEEBF8ED6F2", - "syncVersion" : 2, - "unitString" : "mg/dL", - "uuid" : "2A67A303-5203-4CB8-8263-79498265368E", - "value" : 98.700000000000003, - "wasUserEntered" : true -} -""" - ) - } - } - - func testEncodableOptional() throws { - cacheStore.managedObjectContext.performAndWait { - let cachedGlucoseObject = CachedGlucoseObject(context: cacheStore.managedObjectContext) - cachedGlucoseObject.provenanceIdentifier = "238E41EA-9576-4981-A1A4-51E10228584F" - cachedGlucoseObject.value = 87.6 - cachedGlucoseObject.unitString = HKUnit.milligramsPerDeciliter.unitString - cachedGlucoseObject.startDate = dateFormatter.date(from: "2020-05-14T22:38:14Z")! - cachedGlucoseObject.isDisplayOnly = true - cachedGlucoseObject.wasUserEntered = false - cachedGlucoseObject.modificationCounter = 234 - try! assertCachedGlucoseObjectEncodable(cachedGlucoseObject, encodesJSON: """ -{ - "isDisplayOnly" : true, - "modificationCounter" : 234, - "provenanceIdentifier" : "238E41EA-9576-4981-A1A4-51E10228584F", - "startDate" : "2020-05-14T22:38:14Z", - "unitString" : "mg/dL", - "value" : 87.599999999999994, - "wasUserEntered" : false -} -""" - ) - } - } - - private func assertCachedGlucoseObjectEncodable(_ original: CachedGlucoseObject, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() -} - -extension CachedGlucoseObject { - fileprivate func setDefaultValues() { - self.uuid = UUID() - self.provenanceIdentifier = "CachedGlucoseObjectTests" - self.syncIdentifier = UUID().uuidString - self.syncVersion = 2 - self.value = 99.9 - self.unitString = HKUnit.milligramsPerDeciliter.unitString - self.startDate = Date() - self.isDisplayOnly = false - self.wasUserEntered = false - self.condition = nil - self.trend = .up - self.trendRate = HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: 1.0) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/Persistence/CachedInsulinDeliveryObjectTests.swift b/Dependencies/LoopKit/LoopKitTests/Persistence/CachedInsulinDeliveryObjectTests.swift deleted file mode 100644 index ca9d15f68..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Persistence/CachedInsulinDeliveryObjectTests.swift +++ /dev/null @@ -1,514 +0,0 @@ -// -// CachedInsulinDeliveryObjectTests.swift -// LoopKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class CachedInsulinDeliveryObjectTests: PersistenceControllerTestCase { - func testReasonGet() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.primitiveReason = NSNumber(integerLiteral: 2) - XCTAssertEqual(object.reason, .bolus) - } - } - - func testReasonSet() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.reason = .basal - XCTAssertEqual(object.primitiveReason, NSNumber(integerLiteral: 1)) - } - } - - func testScheduledBasalRateGet() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.primitiveScheduledBasalRate = NSNumber(floatLiteral: 1.23) - XCTAssertEqual(object.scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.23)) - } - } - - func testScheduledBasalRateGetNil() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.primitiveScheduledBasalRate = nil - XCTAssertNil(object.scheduledBasalRate) - } - } - - func testScheduledBasalRateSet() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.scheduledBasalRate = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 2.34) - XCTAssertEqual(object.primitiveScheduledBasalRate, NSNumber(floatLiteral: 2.34)) - } - } - - func testScheduledBasalRateSetNil() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.scheduledBasalRate = nil - XCTAssertNil(object.primitiveScheduledBasalRate) - } - } - - func testPrimitiveProgrammedTempBasalRateGet() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.primitiveProgrammedTempBasalRate = NSNumber(floatLiteral: 1.23) - XCTAssertEqual(object.programmedTempBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.23)) - } - } - - func testPrimitiveProgrammedTempBasalRateGetNil() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.primitiveProgrammedTempBasalRate = nil - XCTAssertNil(object.programmedTempBasalRate) - } - } - - func testPrimitiveProgrammedTempBasalRateSet() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.programmedTempBasalRate = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 2.34) - XCTAssertEqual(object.primitiveProgrammedTempBasalRate, NSNumber(floatLiteral: 2.34)) - } - } - - func testPrimitiveProgrammedTempBasalRateSetNil() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.programmedTempBasalRate = nil - XCTAssertNil(object.primitiveProgrammedTempBasalRate) - } - } -} - -class CachedInsulinDeliveryObjectDoseTests: PersistenceControllerTestCase { - func testDoseBasal() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.provenanceIdentifier = Bundle.main.bundleIdentifier! - object.hasLoopKitOrigin = true - object.startDate = dateFormatter.date(from: "2020-01-02T03:04:05Z")! - object.endDate = dateFormatter.date(from: "2020-01-02T04:04:05Z")! - object.syncIdentifier = "876DDBF9-CC47-45ED-B0D7-AD77B77913C4" - object.value = 0.5 - object.scheduledBasalRate = nil - object.programmedTempBasalRate = nil - object.reason = .basal - object.createdAt = dateFormatter.date(from: "2020-01-02T04:04:06Z")! - object.wasProgrammedByPumpUI = true - let dose = object.dose - XCTAssertNotNil(dose) - XCTAssertEqual(dose!.type, .basal) - XCTAssertEqual(dose!.startDate, dateFormatter.date(from: "2020-01-02T03:04:05Z")!) - XCTAssertEqual(dose!.endDate, dateFormatter.date(from: "2020-01-02T04:04:05Z")!) - XCTAssertEqual(dose!.value, 0.5) - XCTAssertEqual(dose!.unit, .units) - XCTAssertEqual(dose!.deliveredUnits, nil) - XCTAssertEqual(dose!.description, nil) - XCTAssertEqual(dose!.syncIdentifier, "876DDBF9-CC47-45ED-B0D7-AD77B77913C4") - XCTAssertEqual(dose!.scheduledBasalRate, nil) - XCTAssertFalse(dose!.isMutable) - XCTAssertTrue(dose!.wasProgrammedByPumpUI) - } - } - - func testDoseTempBasal() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.provenanceIdentifier = Bundle.main.bundleIdentifier! - object.hasLoopKitOrigin = false - object.startDate = dateFormatter.date(from: "2020-01-02T03:04:06Z")! - object.endDate = dateFormatter.date(from: "2020-01-02T03:34:06Z")! - object.syncIdentifier = nil - object.value = 0.75 - object.scheduledBasalRate = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0) - object.programmedTempBasalRate = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.5) - object.reason = .basal - object.createdAt = dateFormatter.date(from: "2020-01-02T04:04:07Z")! - object.isSuspend = false - object.wasProgrammedByPumpUI = true - let dose = object.dose - XCTAssertNotNil(dose) - XCTAssertEqual(dose!.type, .tempBasal) - XCTAssertEqual(dose!.startDate, dateFormatter.date(from: "2020-01-02T03:04:06Z")!) - XCTAssertEqual(dose!.endDate, dateFormatter.date(from: "2020-01-02T03:34:06Z")!) - XCTAssertEqual(dose!.value, 1.5) - XCTAssertEqual(dose!.unit, .unitsPerHour) - XCTAssertEqual(dose!.deliveredUnits, 0.75) - XCTAssertEqual(dose!.description, nil) - XCTAssertEqual(dose!.syncIdentifier, nil) - XCTAssertEqual(dose!.scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0)) - XCTAssertFalse(dose!.isMutable) - XCTAssertTrue(dose!.wasProgrammedByPumpUI) - } - } - - func testDoseTempBasalIsSuspend() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.provenanceIdentifier = Bundle.main.bundleIdentifier! - object.hasLoopKitOrigin = false - object.startDate = dateFormatter.date(from: "2020-01-02T03:04:06Z")! - object.endDate = dateFormatter.date(from: "2020-01-02T03:34:06Z")! - object.syncIdentifier = nil - object.value = 0.75 - object.scheduledBasalRate = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0) - object.programmedTempBasalRate = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.5) - object.reason = .basal - object.createdAt = dateFormatter.date(from: "2020-01-02T04:04:07Z")! - object.isSuspend = true - object.wasProgrammedByPumpUI = true - let dose = object.dose - XCTAssertNotNil(dose) - XCTAssertEqual(dose!.type, .suspend) - XCTAssertEqual(dose!.startDate, dateFormatter.date(from: "2020-01-02T03:04:06Z")!) - XCTAssertEqual(dose!.endDate, dateFormatter.date(from: "2020-01-02T03:34:06Z")!) - XCTAssertEqual(dose!.value, 1.5) - XCTAssertEqual(dose!.unit, .unitsPerHour) - XCTAssertEqual(dose!.deliveredUnits, 0.75) - XCTAssertEqual(dose!.description, nil) - XCTAssertEqual(dose!.syncIdentifier, nil) - XCTAssertEqual(dose!.scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0)) - XCTAssertFalse(dose!.isMutable) - XCTAssertTrue(dose!.wasProgrammedByPumpUI) - } - } - - func testDoseTempBasalIsMutable() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.provenanceIdentifier = Bundle.main.bundleIdentifier! - object.hasLoopKitOrigin = false - object.startDate = dateFormatter.date(from: "2020-01-02T03:04:06Z")! - object.endDate = dateFormatter.date(from: "2020-01-02T03:34:06Z")! - object.syncIdentifier = nil - object.value = 0.75 - object.scheduledBasalRate = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0) - object.programmedTempBasalRate = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.5) - object.reason = .basal - object.createdAt = dateFormatter.date(from: "2020-01-02T04:04:07Z")! - object.isSuspend = false - object.isMutable = true - object.wasProgrammedByPumpUI = true - let dose = object.dose - XCTAssertNotNil(dose) - XCTAssertEqual(dose!.type, .tempBasal) - XCTAssertEqual(dose!.startDate, dateFormatter.date(from: "2020-01-02T03:04:06Z")!) - XCTAssertEqual(dose!.endDate, dateFormatter.date(from: "2020-01-02T03:34:06Z")!) - XCTAssertEqual(dose!.value, 1.5) - XCTAssertEqual(dose!.unit, .unitsPerHour) - XCTAssertNil(dose!.deliveredUnits) - XCTAssertEqual(dose!.description, nil) - XCTAssertEqual(dose!.syncIdentifier, nil) - XCTAssertEqual(dose!.scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0)) - XCTAssertTrue(dose!.isMutable) - XCTAssertTrue(dose!.wasProgrammedByPumpUI) - } - } - - func testDoseTempBasalDeleted() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.provenanceIdentifier = Bundle.main.bundleIdentifier! - object.hasLoopKitOrigin = false - object.startDate = dateFormatter.date(from: "2020-01-02T03:04:06Z")! - object.endDate = dateFormatter.date(from: "2020-01-02T03:34:06Z")! - object.syncIdentifier = nil - object.value = 0.75 - object.scheduledBasalRate = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0) - object.programmedTempBasalRate = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.5) - object.reason = .basal - object.createdAt = dateFormatter.date(from: "2020-01-02T04:04:07Z")! - object.deletedAt = dateFormatter.date(from: "2020-01-02T04:34:06Z")! - object.isSuspend = false - object.wasProgrammedByPumpUI = true - let dose = object.dose - XCTAssertNotNil(dose) - XCTAssertEqual(dose!.type, .tempBasal) - XCTAssertEqual(dose!.startDate, dateFormatter.date(from: "2020-01-02T03:04:06Z")!) - XCTAssertEqual(dose!.endDate, dateFormatter.date(from: "2020-01-02T03:34:06Z")!) - XCTAssertEqual(dose!.value, 1.5) - XCTAssertEqual(dose!.unit, .unitsPerHour) - XCTAssertEqual(dose!.deliveredUnits, 0.75) - XCTAssertEqual(dose!.description, nil) - XCTAssertEqual(dose!.syncIdentifier, nil) - XCTAssertEqual(dose!.scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0)) - XCTAssertFalse(dose!.isMutable) - XCTAssertTrue(dose!.wasProgrammedByPumpUI) - } - } - - func testDoseBolus() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.provenanceIdentifier = Bundle.main.bundleIdentifier! - object.hasLoopKitOrigin = true - object.startDate = dateFormatter.date(from: "2020-01-02T05:04:05Z")! - object.endDate = dateFormatter.date(from: "2020-01-02T05:05:05Z")! - object.syncIdentifier = "9AA61454-EED5-476F-8E57-4BA63D0267C1" - object.value = 2.25 - object.scheduledBasalRate = nil - object.programmedTempBasalRate = nil - object.reason = .bolus - object.createdAt = dateFormatter.date(from: "2020-01-02T05:05:06Z")! - object.wasProgrammedByPumpUI = true - let dose = object.dose - XCTAssertNotNil(dose) - XCTAssertEqual(dose!.type, .bolus) - XCTAssertEqual(dose!.startDate, dateFormatter.date(from: "2020-01-02T05:04:05Z")!) - XCTAssertEqual(dose!.endDate, dateFormatter.date(from: "2020-01-02T05:05:05Z")!) - XCTAssertEqual(dose!.value, 2.25) - XCTAssertEqual(dose!.unit, .units) - XCTAssertEqual(dose!.deliveredUnits, nil) - XCTAssertEqual(dose!.description, nil) - XCTAssertEqual(dose!.syncIdentifier, "9AA61454-EED5-476F-8E57-4BA63D0267C1") - XCTAssertEqual(dose!.scheduledBasalRate, nil) - XCTAssertFalse(dose!.isMutable) - XCTAssertTrue(dose!.wasProgrammedByPumpUI) - } - } - - func testDoseBolusIsMutable() { - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.provenanceIdentifier = Bundle.main.bundleIdentifier! - object.hasLoopKitOrigin = true - object.startDate = dateFormatter.date(from: "2020-01-02T05:04:05Z")! - object.endDate = dateFormatter.date(from: "2020-01-02T05:05:05Z")! - object.syncIdentifier = "9AA61454-EED5-476F-8E57-4BA63D0267C1" - object.value = 2.25 - object.scheduledBasalRate = nil - object.programmedTempBasalRate = nil - object.reason = .bolus - object.createdAt = dateFormatter.date(from: "2020-01-02T05:05:06Z")! - object.isMutable = true - object.wasProgrammedByPumpUI = true - let dose = object.dose - XCTAssertNotNil(dose) - XCTAssertEqual(dose!.type, .bolus) - XCTAssertEqual(dose!.startDate, dateFormatter.date(from: "2020-01-02T05:04:05Z")!) - XCTAssertEqual(dose!.endDate, dateFormatter.date(from: "2020-01-02T05:05:05Z")!) - XCTAssertEqual(dose!.value, 2.25) - XCTAssertEqual(dose!.unit, .units) - XCTAssertEqual(dose!.deliveredUnits, nil) - XCTAssertEqual(dose!.description, nil) - XCTAssertEqual(dose!.syncIdentifier, "9AA61454-EED5-476F-8E57-4BA63D0267C1") - XCTAssertEqual(dose!.scheduledBasalRate, nil) - XCTAssertTrue(dose!.isMutable) - XCTAssertTrue(dose!.wasProgrammedByPumpUI) - } - } - - private let dateFormatter = ISO8601DateFormatter() -} - -class CachedInsulinDeliveryObjectOperationsTests: PersistenceControllerTestCase { - func testCreateWithUUIDAndWithoutOptional() { - let metadata: [String: Any] = [ - HKMetadataKeyInsulinDeliveryReason: HKInsulinDeliveryReason.bolus.rawValue, - ] - let sample = HKQuantitySample(type: HKQuantityType.quantityType(forIdentifier: .insulinDelivery)!, - quantity: HKQuantity(unit: .internationalUnit(), doubleValue: 2.25), - start: dateFormatter.date(from: "2020-02-03T04:05:06Z")!, - end: dateFormatter.date(from: "2020-02-03T04:05:36Z")!, - metadata: metadata) - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object.create(fromExisting: sample, on: dateFormatter.date(from: "2020-02-03T04:05:37Z")!) - XCTAssertEqual(object.uuid, sample.uuid) - XCTAssertEqual(object.provenanceIdentifier, "") // Not yet persisted so HealthKit reports as empty string - XCTAssertEqual(object.hasLoopKitOrigin, false) - XCTAssertEqual(object.startDate, dateFormatter.date(from: "2020-02-03T04:05:06Z")!) - XCTAssertEqual(object.endDate, dateFormatter.date(from: "2020-02-03T04:05:36Z")!) - XCTAssertEqual(object.syncIdentifier, sample.uuid.uuidString) - XCTAssertEqual(object.value, 2.25) - XCTAssertNil(object.scheduledBasalRate) - XCTAssertNil(object.programmedTempBasalRate) - XCTAssertEqual(object.reason, .bolus) - XCTAssertEqual(object.createdAt, dateFormatter.date(from: "2020-02-03T04:05:37Z")!) - XCTAssertFalse(object.isSuspend) - } - } - - func testCreateAndUpdateFromEntry() { - let createEntry = DoseEntry(type: .tempBasal, - startDate: dateFormatter.date(from: "2020-02-03T04:05:06Z")!, - endDate: dateFormatter.date(from: "2020-02-03T04:35:06Z")!, - value: 1.5, - unit: .unitsPerHour, - deliveredUnits: nil, - description: "Create Dose Entry", - syncIdentifier: "A1F8E29B-33D6-4B38-B4CD-D84F14744871", - scheduledBasalRate: HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0), - insulinType: .apidra, - automatic: true, - manuallyEntered: true, - isMutable: true) - let updateEntry = DoseEntry(type: .tempBasal, - startDate: dateFormatter.date(from: "2020-02-03T04:05:06Z")!, - endDate: dateFormatter.date(from: "2020-02-03T04:10:06Z")!, - value: 3.0, - unit: .unitsPerHour, - deliveredUnits: 0.25, - description: "Update Dose Entry", - syncIdentifier: "A1F8E29B-33D6-4B38-B4CD-D84F14744871", - scheduledBasalRate: HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.5), - insulinType: .fiasp, - automatic: false, - manuallyEntered: false, - isMutable: false) - cacheStore.managedObjectContext.performAndWait { - let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - - object.create(from: createEntry, by: "Test Providence Identifier", at: dateFormatter.date(from: "2020-02-03T04:06:06Z")!) - XCTAssertNil(object.uuid) - XCTAssertEqual(object.provenanceIdentifier, "Test Providence Identifier") - XCTAssertTrue(object.hasLoopKitOrigin) - XCTAssertEqual(object.startDate, dateFormatter.date(from: "2020-02-03T04:05:06Z")!) - XCTAssertEqual(object.endDate, dateFormatter.date(from: "2020-02-03T04:35:06Z")!) - XCTAssertEqual(object.syncIdentifier, "A1F8E29B-33D6-4B38-B4CD-D84F14744871") - XCTAssertEqual(object.value, 0.75) - XCTAssertEqual(object.scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0)) - XCTAssertEqual(object.programmedTempBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.5)) - XCTAssertEqual(object.reason, .basal) - XCTAssertEqual(object.createdAt, dateFormatter.date(from: "2020-02-03T04:06:06Z")!) - XCTAssertNil(object.deletedAt) - XCTAssertEqual(object.insulinType, .apidra) - XCTAssertEqual(object.automaticallyIssued, true) - XCTAssertEqual(object.manuallyEntered, true) - XCTAssertEqual(object.isSuspend, false) - XCTAssertEqual(object.isMutable, true) - - object.update(from: updateEntry) - XCTAssertNil(object.uuid) - XCTAssertEqual(object.provenanceIdentifier, "Test Providence Identifier") - XCTAssertTrue(object.hasLoopKitOrigin) - XCTAssertEqual(object.startDate, dateFormatter.date(from: "2020-02-03T04:05:06Z")!) - XCTAssertEqual(object.endDate, dateFormatter.date(from: "2020-02-03T04:10:06Z")!) - XCTAssertEqual(object.syncIdentifier, "A1F8E29B-33D6-4B38-B4CD-D84F14744871") - XCTAssertEqual(object.value, 0.25) - XCTAssertEqual(object.scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0.5)) - XCTAssertEqual(object.programmedTempBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 3.0)) - XCTAssertEqual(object.reason, .basal) - XCTAssertEqual(object.createdAt, dateFormatter.date(from: "2020-02-03T04:06:06Z")!) - XCTAssertNil(object.deletedAt) - XCTAssertEqual(object.insulinType, .fiasp) - XCTAssertEqual(object.automaticallyIssued, false) - XCTAssertEqual(object.manuallyEntered, false) - XCTAssertEqual(object.isSuspend, false) - XCTAssertEqual(object.isMutable, false) - } - } - - private let dateFormatter = ISO8601DateFormatter() -} - -class CachedInsulinDeliveryObjectConstraintTests: PersistenceControllerTestCase { - func testUUIDUniqueConstraintPreSave() { - cacheStore.managedObjectContext.performAndWait { - let uuid = UUID() - - let object1 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object1.setDefaultValues() - object1.uuid = uuid - object1.syncIdentifier = "object1" - - let object2 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object2.setDefaultValues() - object2.uuid = uuid - object2.syncIdentifier = "object2" - - try! cacheStore.managedObjectContext.save() - - let objects: [CachedInsulinDeliveryObject] = cacheStore.managedObjectContext.all() - XCTAssertEqual(1, objects.count) - } - } - - func testUUIDUniqueConstraintPostSave() { - cacheStore.managedObjectContext.performAndWait { - let uuid = UUID() - - let object1 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object1.setDefaultValues() - object1.uuid = uuid - - try! cacheStore.managedObjectContext.save() - - let object2 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object2.setDefaultValues() - object2.uuid = uuid - - try! cacheStore.managedObjectContext.save() - - let objects: [CachedInsulinDeliveryObject] = cacheStore.managedObjectContext.all() - XCTAssertEqual(1, objects.count) - } - } - - func testSyncIdentifierUniqueConstraint() { - cacheStore.managedObjectContext.performAndWait { - let uuid = UUID() - - let object1 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object1.setDefaultValues() - object1.syncIdentifier = uuid.uuidString - - try! cacheStore.managedObjectContext.save() - - let object2 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object2.setDefaultValues() - object2.syncIdentifier = uuid.uuidString - - try! cacheStore.managedObjectContext.save() - - let objects: [CachedInsulinDeliveryObject] = cacheStore.managedObjectContext.all() - XCTAssertEqual(1, objects.count) - } - } - - func testSaveWithDefaultValues() { - cacheStore.managedObjectContext.performAndWait { - let object1 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object1.setDefaultValues() - - try! cacheStore.managedObjectContext.save() - - let object2 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext) - object2.setDefaultValues() - - try! cacheStore.managedObjectContext.save() - - let objects: [CachedInsulinDeliveryObject] = cacheStore.managedObjectContext.all() - XCTAssertEqual(2, objects.count) - } - } -} - -extension CachedInsulinDeliveryObject { - fileprivate func setDefaultValues() { - self.uuid = UUID() - self.provenanceIdentifier = "CachedInsulinDeliveryObjectTests" - self.hasLoopKitOrigin = true - self.startDate = Date() - self.endDate = Date() - self.syncIdentifier = UUID().uuidString - self.value = 3.5 - self.scheduledBasalRate = nil - self.programmedTempBasalRate = nil - self.isSuspend = false - self.reason = .basal - self.createdAt = Date() - } -} - diff --git a/Dependencies/LoopKit/LoopKitTests/Persistence/DeviceLogEntryTests.swift b/Dependencies/LoopKit/LoopKitTests/Persistence/DeviceLogEntryTests.swift deleted file mode 100644 index 93ef14ccc..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Persistence/DeviceLogEntryTests.swift +++ /dev/null @@ -1,95 +0,0 @@ -// -// DeviceLogEntryTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 8/26/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import CoreData -@testable import LoopKit - -class DeviceLogEntryEncodableTests: XCTestCase { - private var persistentContainer: NSPersistentContainer! - private var managedObjectContext: NSManagedObjectContext! - - override func setUp() { - super.setUp() - - let persistentStoreDescription = NSPersistentStoreDescription() - persistentStoreDescription.type = NSInMemoryStoreType - - persistentContainer = PersistentContainer(name: "DeviceLog") - persistentContainer.persistentStoreDescriptions = [persistentStoreDescription] - persistentContainer.loadPersistentStores { (_, _) in } - - managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) - managedObjectContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy - managedObjectContext.automaticallyMergesChangesFromParent = true - managedObjectContext.persistentStoreCoordinator = persistentContainer.persistentStoreCoordinator - } - - override func tearDown() { - managedObjectContext = nil - persistentContainer = nil - - super.tearDown() - } - - func testEncodable() throws { - managedObjectContext.performAndWait { - let deviceLogEntry = DeviceLogEntry(context: managedObjectContext) - deviceLogEntry.type = .connection - deviceLogEntry.managerIdentifier = "238E41EA-9576-4981-A1A4-51E10228584F" - deviceLogEntry.deviceIdentifier = "7723A0EE-F6D5-46E0-BBFE-1DEEBF8ED6F2" - deviceLogEntry.message = "This is the message" - deviceLogEntry.timestamp = dateFormatter.date(from: "2020-05-14T22:38:14Z")! - deviceLogEntry.modificationCounter = 123 - try! assertDeviceLogEntryEncodable(deviceLogEntry, encodesJSON: """ -{ - "deviceIdentifier" : "7723A0EE-F6D5-46E0-BBFE-1DEEBF8ED6F2", - "managerIdentifier" : "238E41EA-9576-4981-A1A4-51E10228584F", - "message" : "This is the message", - "modificationCounter" : 123, - "timestamp" : "2020-05-14T22:38:14Z", - "type" : "connection" -} -""" - ) - } - } - - func testEncodableOptional() throws { - managedObjectContext.performAndWait { - let deviceLogEntry = DeviceLogEntry(context: managedObjectContext) - deviceLogEntry.modificationCounter = 234 - try! assertDeviceLogEntryEncodable(deviceLogEntry, encodesJSON: """ -{ - "modificationCounter" : 234 -} -""" - ) - } - } - - private func assertDeviceLogEntryEncodable(_ original: DeviceLogEntry, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() -} diff --git a/Dependencies/LoopKit/LoopKitTests/Persistence/PersistenceControllerTestCase.swift b/Dependencies/LoopKit/LoopKitTests/Persistence/PersistenceControllerTestCase.swift deleted file mode 100644 index 054992076..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Persistence/PersistenceControllerTestCase.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// PersistenceControllerTestCase.swift -// LoopKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import LoopKit - -class PersistenceControllerTestCase: XCTestCase { - - var cacheStore: PersistenceController! - - override func setUp() { - super.setUp() - - cacheStore = PersistenceController(directoryURL: URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent(UUID().uuidString, isDirectory: true)) - } - - override func tearDown() { - cacheStore.tearDown() - cacheStore = nil - - super.tearDown() - } - - deinit { - cacheStore?.tearDown() - } - -} diff --git a/Dependencies/LoopKit/LoopKitTests/Persistence/PersistenceControllerTests.swift b/Dependencies/LoopKit/LoopKitTests/Persistence/PersistenceControllerTests.swift deleted file mode 100644 index 351f4c4d6..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Persistence/PersistenceControllerTests.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// PersistenceControllerTests.swift -// LoopKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import XCTest -import CoreData -import HealthKit -@testable import LoopKit - -class PersistenceControllerTests: PersistenceControllerTestCase { - - func testPurgeObjectsBeforeSave() { - cacheStore.managedObjectContext.performAndWait { - for value in stride(from: 95, to: 105, by: 1) { - let glucose = CachedGlucoseObject(context: cacheStore.managedObjectContext) - glucose.uuid = UUID() - glucose.provenanceIdentifier = "PersistenceControllerTests" - glucose.syncIdentifier = "foo\(value)" - glucose.syncVersion = 1 - glucose.value = Double(value) - glucose.unitString = HKUnit.milligramsPerDeciliter.unitString - glucose.startDate = Date() - glucose.isDisplayOnly = false - glucose.wasUserEntered = false - } - - let predicate = NSPredicate(format: "value < %d", 100) - let count = try! cacheStore.managedObjectContext.purgeObjects(of: CachedGlucoseObject.self, matching: predicate) - - XCTAssertEqual(0, count) - - try! cacheStore.managedObjectContext.save() - - let all: [CachedGlucoseObject] = cacheStore.managedObjectContext.all() - - XCTAssertEqual(10, all.count) - } - } - - func testPurgeObjectsAfterSave() { - cacheStore.managedObjectContext.performAndWait { - for value in stride(from: 95, to: 105, by: 1) { - let glucose = CachedGlucoseObject(context: cacheStore.managedObjectContext) - glucose.uuid = UUID() - glucose.provenanceIdentifier = "PersistenceControllerTests" - glucose.syncIdentifier = "foo\(value)" - glucose.syncVersion = 1 - glucose.value = Double(value) - glucose.unitString = HKUnit.milligramsPerDeciliter.unitString - glucose.startDate = Date() - glucose.isDisplayOnly = false - glucose.wasUserEntered = false - } - - try! cacheStore.managedObjectContext.save() - - let predicate = NSPredicate(format: "value < %d", 100) - let count = try! cacheStore.managedObjectContext.purgeObjects(of: CachedGlucoseObject.self, matching: predicate) - - XCTAssertEqual(5, count) - - let all: [CachedGlucoseObject] = cacheStore.managedObjectContext.all() - - XCTAssertEqual(5, all.count) - } - } - -} diff --git a/Dependencies/LoopKit/LoopKitTests/Persistence/PumpEventTests.swift b/Dependencies/LoopKit/LoopKitTests/Persistence/PumpEventTests.swift deleted file mode 100644 index 5e965d504..000000000 --- a/Dependencies/LoopKit/LoopKitTests/Persistence/PumpEventTests.swift +++ /dev/null @@ -1,103 +0,0 @@ -// -// PumpEventTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 8/26/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import LoopKit - -class PumpEventEncodableTests: PersistenceControllerTestCase { - func testEncodable() throws { - cacheStore.managedObjectContext.performAndWait { - let pumpEvent = PumpEvent(context: cacheStore.managedObjectContext) - pumpEvent.createdAt = dateFormatter.date(from: "2020-05-14T22:33:48Z")! - pumpEvent.date = dateFormatter.date(from: "2020-05-14T22:38:14Z")! - pumpEvent.doseType = .tempBasal - pumpEvent.duration = .minutes(30) - pumpEvent.type = .tempBasal - pumpEvent.unit = .unitsPerHour - pumpEvent.uploaded = false - pumpEvent.value = 1.23 - pumpEvent.deliveredUnits = 0.56 - pumpEvent.mutable = true - pumpEvent.raw = Data(base64Encoded: "MTIzNDU2Nzg5MA==")! - pumpEvent.title = "This is the title" - pumpEvent.insulinType = .fiasp - pumpEvent.automatic = false - pumpEvent.alarmType = .other("An Alarm") - pumpEvent.modificationCounter = 123 - pumpEvent.wasProgrammedByPumpUI = true - try! assertPumpEventEncodable(pumpEvent, encodesJSON: """ -{ - "alarmType" : "An Alarm", - "automatic" : false, - "createdAt" : "2020-05-14T22:33:48Z", - "date" : "2020-05-14T22:38:14Z", - "deliveredUnits" : 0.56000000000000005, - "doseType" : "tempBasal", - "duration" : 1800, - "insulinType" : 3, - "modificationCounter" : 123, - "mutable" : true, - "raw" : "MTIzNDU2Nzg5MA==", - "title" : "This is the title", - "type" : "TempBasal", - "unit" : "U/hour", - "uploaded" : false, - "value" : 1.23, - "wasProgrammedByPumpUI" : true -} -""" - ) - } - } - - func testEncodableOptional() throws { - cacheStore.managedObjectContext.performAndWait { - let pumpEvent = PumpEvent(context: cacheStore.managedObjectContext) - pumpEvent.createdAt = dateFormatter.date(from: "2020-05-13T22:33:48Z")! - pumpEvent.date = dateFormatter.date(from: "2020-05-13T22:38:14Z")! - pumpEvent.duration = .minutes(60) - pumpEvent.uploaded = true - pumpEvent.mutable = false - pumpEvent.modificationCounter = 234 - pumpEvent.wasProgrammedByPumpUI = true - try! assertPumpEventEncodable(pumpEvent, encodesJSON: """ -{ - "createdAt" : "2020-05-13T22:33:48Z", - "date" : "2020-05-13T22:38:14Z", - "duration" : 3600, - "insulinType" : 0, - "modificationCounter" : 234, - "mutable" : false, - "uploaded" : true, - "wasProgrammedByPumpUI" : true -} -""" - ) - } - } - - private func assertPumpEventEncodable(_ original: PumpEvent, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() -} diff --git a/Dependencies/LoopKit/LoopKitTests/PersistentDeviceLogTests.swift b/Dependencies/LoopKit/LoopKitTests/PersistentDeviceLogTests.swift deleted file mode 100644 index 4ca859aa1..000000000 --- a/Dependencies/LoopKit/LoopKitTests/PersistentDeviceLogTests.swift +++ /dev/null @@ -1,93 +0,0 @@ -// -// PersistentDeviceLogTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 8/26/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import LoopKit - -class PersistentDeviceLogCriticalEventLogTests: XCTestCase { - var persistentDeviceLog: PersistentDeviceLog! - var outputStream: MockOutputStream! - var progress: Progress! - - override func setUp() { - super.setUp() - - let entries = [StoredDeviceLogEntry(type: .delegateResponse, managerIdentifier: "m1", deviceIdentifier: "d1", message: "Message 1", timestamp: dateFormatter.date(from: "2100-01-02T03:08:00Z")!), - StoredDeviceLogEntry(type: .receive, managerIdentifier: "m2", deviceIdentifier: "d2", message: "Message 2", timestamp: dateFormatter.date(from: "2100-01-02T03:10:00Z")!), - StoredDeviceLogEntry(type: .send, managerIdentifier: "m3", deviceIdentifier: "d3", message: "Message 3", timestamp: dateFormatter.date(from: "2100-01-02T03:04:00Z")!), - StoredDeviceLogEntry(type: .delegate, managerIdentifier: "m4", deviceIdentifier: "d4", message: "Message 4", timestamp: dateFormatter.date(from: "2100-01-02T03:06:00Z")!), - StoredDeviceLogEntry(type: .connection, managerIdentifier: "m5", deviceIdentifier: "d5", message: "Message 5", timestamp: dateFormatter.date(from: "2100-01-02T03:02:00Z")!)] - - persistentDeviceLog = PersistentDeviceLog(storageFile: URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString), maxEntryAge: .hours(1)) - XCTAssertNil(persistentDeviceLog.addStoredDeviceLogEntries(entries: entries)) - - outputStream = MockOutputStream() - progress = Progress() - } - - override func tearDown() { - persistentDeviceLog = nil - - super.tearDown() - } - - func testExportProgressTotalUnitCount() { - switch persistentDeviceLog.exportProgressTotalUnitCount(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!) { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let progressTotalUnitCount): - XCTAssertEqual(progressTotalUnitCount, 3 * 1) - } - } - - func testExportProgressTotalUnitCountEmpty() { - switch persistentDeviceLog.exportProgressTotalUnitCount(startDate: dateFormatter.date(from: "2100-01-02T03:00:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:01:00Z")!) { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let progressTotalUnitCount): - XCTAssertEqual(progressTotalUnitCount, 0) - } - } - - func testExport() { - XCTAssertNil(persistentDeviceLog.export(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!, - to: outputStream, - progress: progress)) - XCTAssertEqual(outputStream.string, """ -[ -{"deviceIdentifier":"d1","managerIdentifier":"m1","message":"Message 1","modificationCounter":1,"timestamp":"2100-01-02T03:08:00.000Z","type":"delegateResponse"}, -{"deviceIdentifier":"d3","managerIdentifier":"m3","message":"Message 3","modificationCounter":3,"timestamp":"2100-01-02T03:04:00.000Z","type":"send"}, -{"deviceIdentifier":"d4","managerIdentifier":"m4","message":"Message 4","modificationCounter":4,"timestamp":"2100-01-02T03:06:00.000Z","type":"delegate"} -] -""" - ) - XCTAssertEqual(progress.completedUnitCount, 3 * 1) - } - - func testExportEmpty() { - XCTAssertNil(persistentDeviceLog.export(startDate: dateFormatter.date(from: "2100-01-02T03:00:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:01:00Z")!, - to: outputStream, - progress: progress)) - XCTAssertEqual(outputStream.string, "[]") - XCTAssertEqual(progress.completedUnitCount, 0) - } - - func testExportCancelled() { - progress.cancel() - XCTAssertEqual(persistentDeviceLog.export(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!, - to: outputStream, - progress: progress) as? CriticalEventLogError, CriticalEventLogError.cancelled) - } - - private let dateFormatter = ISO8601DateFormatter() -} diff --git a/Dependencies/LoopKit/LoopKitTests/PumpManagerStatusTests.swift b/Dependencies/LoopKit/LoopKitTests/PumpManagerStatusTests.swift deleted file mode 100644 index 3b904e974..000000000 --- a/Dependencies/LoopKit/LoopKitTests/PumpManagerStatusTests.swift +++ /dev/null @@ -1,326 +0,0 @@ -// -// PumpManagerStatusTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 5/4/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit - -@testable import LoopKit - -class PumpManagerStatusCodableTests: XCTestCase { - func testCodable() throws { - let device = HKDevice(name: "Acme Best Device", - manufacturer: "Acme", - model: "Best", - hardwareVersion: "0.1.2", - firmwareVersion: "1.2.3", - softwareVersion: "2.3.4", - localIdentifier: "Locally Identified", - udiDeviceIdentifier: "U0D1I2") - try assertPumpManagerStatusCodable(PumpManagerStatus(timeZone: TimeZone(identifier: "America/Los_Angeles")!, - device: device, - pumpBatteryChargeRemaining: 0.75, - basalDeliveryState: .active(dateFormatter.date(from: "2020-05-14T15:56:09Z")!), - bolusState: .noBolus, - insulinType: .novolog, - deliveryIsUncertain: true), - encodesJSON: """ -{ - "basalDeliveryState" : { - "active" : { - "at" : "2020-05-14T15:56:09Z" - } - }, - "bolusState" : "noBolus", - "deliveryIsUncertain" : true, - "device" : { - "firmwareVersion" : "1.2.3", - "hardwareVersion" : "0.1.2", - "localIdentifier" : "Locally Identified", - "manufacturer" : "Acme", - "model" : "Best", - "name" : "Acme Best Device", - "softwareVersion" : "2.3.4", - "udiDeviceIdentifier" : "U0D1I2" - }, - "insulinType" : 0, - "pumpBatteryChargeRemaining" : 0.75, - "timeZone" : { - "identifier" : "America/Los_Angeles" - } -} -""" - ) - } - - func testCodableRequiredOnly() throws { - let device = HKDevice(name: nil, - manufacturer: nil, - model: nil, - hardwareVersion: nil, - firmwareVersion: nil, - softwareVersion: nil, - localIdentifier: nil, - udiDeviceIdentifier: "U0D1I2") - try assertPumpManagerStatusCodable(PumpManagerStatus(timeZone: TimeZone(identifier: "America/Los_Angeles")!, - device: device, - pumpBatteryChargeRemaining: nil, - basalDeliveryState: nil, - bolusState: .noBolus, - insulinType: nil, - deliveryIsUncertain: true), - encodesJSON: """ -{ - "bolusState" : "noBolus", - "deliveryIsUncertain" : true, - "device" : { - "udiDeviceIdentifier" : "U0D1I2" - }, - "timeZone" : { - "identifier" : "America/Los_Angeles" - } -} -""" - ) - } - - private func assertPumpManagerStatusCodable(_ original: PumpManagerStatus, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(PumpManagerStatus.self, from: data) - XCTAssertEqual(decoded, original) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() -} - -class PumpManagerStatusBasalDeliveryStateCodableTests: XCTestCase { - func testCodableActive() throws { - try assertPumpManagerStatusBasalDeliveryStateCodable(.active(dateFormatter.date(from: "2020-05-14T12:18:09Z")!), encodesJSON: """ -{ - "basalDeliveryState" : { - "active" : { - "at" : "2020-05-14T12:18:09Z" - } - } -} -""" - ) - } - - func testCodableInitiatingTempBasal() throws { - try assertPumpManagerStatusBasalDeliveryStateCodable(.initiatingTempBasal, encodesJSON: """ -{ - "basalDeliveryState" : "initiatingTempBasal" -} -""" - ) - } - - func testCodableTempBasal() throws { - let dose = DoseEntry(type: .tempBasal, - startDate: dateFormatter.date(from: "2020-05-14T13:13:14Z")!, - endDate: dateFormatter.date(from: "2020-05-14T13:43:14Z")!, - value: 1.25, - unit: .unitsPerHour, - deliveredUnits: 0.5, - description: "Temporary Basal", - syncIdentifier: "238E41EA-9576-4981-A1A4-51E10228584F", - scheduledBasalRate: HKQuantity(unit: DoseEntry.unitsPerHour, doubleValue: 1.0)) - try assertPumpManagerStatusBasalDeliveryStateCodable(.tempBasal(dose), encodesJSON: """ -{ - "basalDeliveryState" : { - "tempBasal" : { - "dose" : { - "deliveredUnits" : 0.5, - "description" : "Temporary Basal", - "endDate" : "2020-05-14T13:43:14Z", - "isMutable" : false, - "manuallyEntered" : false, - "scheduledBasalRate" : 1, - "scheduledBasalRateUnit" : "IU/hr", - "startDate" : "2020-05-14T13:13:14Z", - "syncIdentifier" : "238E41EA-9576-4981-A1A4-51E10228584F", - "type" : "tempBasal", - "unit" : "U/hour", - "value" : 1.25, - "wasProgrammedByPumpUI" : false - } - } - } -} -""" - ) - } - - func testCodableCancelingTempBasal() throws { - try assertPumpManagerStatusBasalDeliveryStateCodable(.cancelingTempBasal, encodesJSON: """ -{ - "basalDeliveryState" : "cancelingTempBasal" -} -""" - ) - } - - func testCodableSuspending() throws { - try assertPumpManagerStatusBasalDeliveryStateCodable(.suspending, encodesJSON: """ -{ - "basalDeliveryState" : "suspending" -} -""" - ) - } - - func testCodableSuspended() throws { - try assertPumpManagerStatusBasalDeliveryStateCodable(.suspended(dateFormatter.date(from: "2020-05-14T22:38:19Z")!), encodesJSON: """ -{ - "basalDeliveryState" : { - "suspended" : { - "at" : "2020-05-14T22:38:19Z" - } - } -} -""" - ) - } - - func testCodableResuming() throws { - try assertPumpManagerStatusBasalDeliveryStateCodable(.resuming, encodesJSON: """ -{ - "basalDeliveryState" : "resuming" -} -""" - ) - } - - private func assertPumpManagerStatusBasalDeliveryStateCodable(_ original: PumpManagerStatus.BasalDeliveryState, encodesJSON string: String) throws { - let data = try encoder.encode(TestContainer(basalDeliveryState: original)) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(TestContainer.self, from: data) - XCTAssertEqual(decoded.basalDeliveryState, original) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() - - private struct TestContainer: Codable, Equatable { - let basalDeliveryState: PumpManagerStatus.BasalDeliveryState - } -} - -class PumpManagerStatusBolusStateCodableTests: XCTestCase { - func testCodableNone() throws { - try assertPumpManagerStatusBolusStateCodable(.noBolus, encodesJSON: """ -{ - "bolusState" : "noBolus" -} -""" - ) - } - - func testCodableInitiating() throws { - try assertPumpManagerStatusBolusStateCodable(.initiating, encodesJSON: """ -{ - "bolusState" : "initiating" -} -""" - ) - } - - func testCodableInProgress() throws { - let dose = DoseEntry(type: .bolus, - startDate: dateFormatter.date(from: "2020-05-14T22:38:16Z")!, - value: 2.5, - unit: .units, - deliveredUnits: 1.0, - description: "Bolus", - syncIdentifier: "2A67A303-5203-4CB8-8123-79498265368E", - isMutable: true) - try assertPumpManagerStatusBolusStateCodable(.inProgress(dose), encodesJSON: """ -{ - "bolusState" : { - "inProgress" : { - "dose" : { - "deliveredUnits" : 1, - "description" : "Bolus", - "endDate" : "2020-05-14T22:38:16Z", - "isMutable" : true, - "manuallyEntered" : false, - "startDate" : "2020-05-14T22:38:16Z", - "syncIdentifier" : "2A67A303-5203-4CB8-8123-79498265368E", - "type" : "bolus", - "unit" : "U", - "value" : 2.5, - "wasProgrammedByPumpUI" : false - } - } - } -} -""" - ) - } - - func testCodableCancelling() throws { - try assertPumpManagerStatusBolusStateCodable(.canceling, encodesJSON: """ -{ - "bolusState" : "canceling" -} -""" - ) - } - - private func assertPumpManagerStatusBolusStateCodable(_ original: PumpManagerStatus.BolusState, encodesJSON string: String) throws { - let data = try encoder.encode(TestContainer(bolusState: original)) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(TestContainer.self, from: data) - XCTAssertEqual(decoded.bolusState, original) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() - - private struct TestContainer: Codable, Equatable { - let bolusState: PumpManagerStatus.BolusState - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/QuantityFormatterTests.swift b/Dependencies/LoopKit/LoopKitTests/QuantityFormatterTests.swift deleted file mode 100644 index 99ae63b6e..000000000 --- a/Dependencies/LoopKit/LoopKitTests/QuantityFormatterTests.swift +++ /dev/null @@ -1,211 +0,0 @@ -// -// QuantityFormatterTests.swift -// LoopKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class QuantityFormatterTests: XCTestCase { - - var formatter: QuantityFormatter! - - override func setUp() { - super.setUp() - - formatter = QuantityFormatter() - formatter.locale = Locale(identifier: "en_US") - formatter.unitStyle = .medium - formatter.avoidLineBreaking = false - } - - func testInsulin() { - let unit = HKUnit.internationalUnit() - - XCTAssertEqual("U", formatter.string(from: unit)) - XCTAssertEqual("10 U", formatter.string(from: HKQuantity(unit: unit, doubleValue: 10), for: unit)!) - - formatter.unitStyle = .short - - XCTAssertEqual("U", formatter.string(from: unit)) - XCTAssertEqual("10U", formatter.string(from: HKQuantity(unit: unit, doubleValue: 10), for: unit)!) - - formatter.unitStyle = .long - - XCTAssertEqual("Units", formatter.string(from: unit)) - XCTAssertEqual("10 Units", formatter.string(from: HKQuantity(unit: unit, doubleValue: 10), for: unit)!) - } - - func testInsulinRates() { - let unit = HKUnit.internationalUnit().unitDivided(by: .hour()) - - XCTAssertEqual("U/hr", formatter.string(from: unit)) - XCTAssertEqual("10 U/hr", formatter.string(from: HKQuantity(unit: unit, doubleValue: 10), for: unit)!) - - formatter.unitStyle = .short - - XCTAssertEqual("U/hr", formatter.string(from: unit)) - XCTAssertEqual("10U/hr", formatter.string(from: HKQuantity(unit: unit, doubleValue: 10), for: unit)!) - - formatter.unitStyle = .long - - XCTAssertEqual("Units/hour", formatter.string(from: unit)) - XCTAssertEqual("10 Units/hour", formatter.string(from: HKQuantity(unit: unit, doubleValue: 10), for: unit)!) - - XCTAssertEqual("1 Unit/hour", formatter.string(from: HKQuantity(unit: unit, doubleValue: 1), for: unit)!) - } - - func testCarbs() { - let unit = HKUnit.gram() - - XCTAssertEqual("g", formatter.string(from: unit)) - XCTAssertEqual("10 g", formatter.string(from: HKQuantity(unit: unit, doubleValue: 10), for: unit)!) - - formatter.unitStyle = .short - - XCTAssertEqual("g", formatter.string(from: unit)) - XCTAssertEqual("10g", formatter.string(from: HKQuantity(unit: unit, doubleValue: 10), for: unit)!) - - formatter.unitStyle = .long - - XCTAssertEqual("grams", formatter.string(from: unit)) - XCTAssertEqual("10 grams", formatter.string(from: HKQuantity(unit: unit, doubleValue: 10), for: unit)!) - XCTAssertEqual("0 grams", formatter.string(from: HKQuantity(unit: unit, doubleValue: 0), for: unit)!) - XCTAssertEqual("1 gram", formatter.string(from: HKQuantity(unit: unit, doubleValue: 1), for: unit)!) - - formatter.numberFormatter.formattingContext = .standalone - - XCTAssertEqual("10 grams", formatter.string(from: HKQuantity(unit: unit, doubleValue: 10), for: unit)!) - } - - func testGlucoseMGDL() { - let unit = HKUnit.milligramsPerDeciliter - - XCTAssertEqual("mg/dL", formatter.string(from: unit)) - XCTAssertEqual("60 mg/dL", formatter.string(from: HKQuantity(unit: unit, doubleValue: 60), for: unit)!) - XCTAssertEqual("180 mg/dL", formatter.string(from: HKQuantity(unit: unit, doubleValue: 180), for: unit)!) - - formatter.unitStyle = .short - - XCTAssertEqual("mg/dL", formatter.string(from: unit)) - XCTAssertEqual("60mg/dL", formatter.string(from: HKQuantity(unit: unit, doubleValue: 60), for: unit)!) - XCTAssertEqual("180mg/dL", formatter.string(from: HKQuantity(unit: unit, doubleValue: 180), for: unit)!) - - formatter.unitStyle = .long - - XCTAssertEqual("milligrams per deciliter", formatter.string(from: unit)) - XCTAssertEqual("180 milligrams per deciliter", formatter.string(from: HKQuantity(unit: unit, doubleValue: 180), for: unit)!) - XCTAssertEqual("0 milligrams per deciliter", formatter.string(from: HKQuantity(unit: unit, doubleValue: 0), for: unit)!) - XCTAssertEqual("1 milligrams per deciliter", formatter.string(from: HKQuantity(unit: unit, doubleValue: 1), for: unit)!) - } - - func testGlucoseMMOLL() { - let unit = HKUnit.millimolesPerLiter - formatter.setPreferredNumberFormatter(for: unit) - - XCTAssertEqual("mmol/L", formatter.string(from: unit)) - XCTAssertEqual("6.0 mmol/L", formatter.string(from: HKQuantity(unit: unit, doubleValue: 6), for: unit)!) - XCTAssertEqual("7.8 mmol/L", formatter.string(from: HKQuantity(unit: unit, doubleValue: 7.84), for: unit)!) - XCTAssertEqual("12.0 mmol/L", formatter.string(from: HKQuantity(unit: unit, doubleValue: 12), for: unit)!) - - formatter.unitStyle = .short - - XCTAssertEqual("mmol/L", formatter.string(from: unit)) - XCTAssertEqual("6.0mmol/L", formatter.string(from: HKQuantity(unit: unit, doubleValue: 6), for: unit)!) - XCTAssertEqual("7.8mmol/L", formatter.string(from: HKQuantity(unit: unit, doubleValue: 7.8), for: unit)!) - - formatter.unitStyle = .long - - XCTAssertEqual("millimoles per liter", formatter.string(from: unit)) - XCTAssertEqual("5.5 millimoles per liter", formatter.string(from: HKQuantity(unit: unit, doubleValue: 5.5), for: unit)!) - XCTAssertEqual("0.0 millimoles per liter", formatter.string(from: HKQuantity(unit: unit, doubleValue: 0), for: unit)!) - XCTAssertEqual("1.0 millimoles per liter", formatter.string(from: HKQuantity(unit: unit, doubleValue: 1), for: unit)!) - } - - func testAvoidLineBreaking() { - formatter.avoidLineBreaking = true - XCTAssertEqual("U", formatter.string(from: HKUnit.internationalUnit())) - XCTAssertEqual("10\(String.nonBreakingSpace)U", formatter.string(from: HKQuantity(unit: HKUnit.internationalUnit(), doubleValue: 10), for: HKUnit.internationalUnit())!) - formatter.unitStyle = .short - XCTAssertEqual("10\(String.wordJoiner)U", formatter.string(from: HKQuantity(unit: HKUnit.internationalUnit(), doubleValue: 10), for: HKUnit.internationalUnit())!) - formatter.unitStyle = .long - XCTAssertEqual("Units", formatter.string(from: HKUnit.internationalUnit())) - XCTAssertEqual("10 Units", formatter.string(from: HKQuantity(unit: HKUnit.internationalUnit(), doubleValue: 10), for: HKUnit.internationalUnit())!) - - formatter.unitStyle = .medium - formatter.setPreferredNumberFormatter(for: HKUnit.milligramsPerDeciliter) - XCTAssertEqual("mg\(String.wordJoiner)/\(String.wordJoiner)dL", formatter.string(from: HKUnit.milligramsPerDeciliter)) - XCTAssertEqual("60\(String.nonBreakingSpace)mg\(String.wordJoiner)/\(String.wordJoiner)dL", formatter.string(from: HKQuantity(unit: HKUnit.milligramsPerDeciliter, doubleValue: 60), for: HKUnit.milligramsPerDeciliter)!) - XCTAssertEqual("180\(String.nonBreakingSpace)mg\(String.wordJoiner)/\(String.wordJoiner)dL", formatter.string(from: HKQuantity(unit: HKUnit.milligramsPerDeciliter, doubleValue: 180), for: HKUnit.milligramsPerDeciliter)!) - formatter.unitStyle = .short - XCTAssertEqual("mg\(String.wordJoiner)/\(String.wordJoiner)dL", formatter.string(from: HKUnit.milligramsPerDeciliter)) - XCTAssertEqual("60\(String.wordJoiner)mg\(String.wordJoiner)/\(String.wordJoiner)dL", formatter.string(from: HKQuantity(unit: HKUnit.milligramsPerDeciliter, doubleValue: 60), for: HKUnit.milligramsPerDeciliter)!) - XCTAssertEqual("180\(String.wordJoiner)mg\(String.wordJoiner)/\(String.wordJoiner)dL", formatter.string(from: HKQuantity(unit: HKUnit.milligramsPerDeciliter, doubleValue: 180), for: HKUnit.milligramsPerDeciliter)!) - formatter.unitStyle = .long - XCTAssertEqual("milligrams per deciliter", formatter.string(from: HKUnit.milligramsPerDeciliter)) - XCTAssertEqual("180 milligrams per deciliter", formatter.string(from: HKQuantity(unit: HKUnit.milligramsPerDeciliter, doubleValue: 180), for: HKUnit.milligramsPerDeciliter)!) - XCTAssertEqual("0 milligrams per deciliter", formatter.string(from: HKQuantity(unit: HKUnit.milligramsPerDeciliter, doubleValue: 0), for: HKUnit.milligramsPerDeciliter)!) - XCTAssertEqual("1 milligrams per deciliter", formatter.string(from: HKQuantity(unit: HKUnit.milligramsPerDeciliter, doubleValue: 1), for: HKUnit.milligramsPerDeciliter)!) - - formatter.unitStyle = .medium - formatter.setPreferredNumberFormatter(for: HKUnit.millimolesPerLiter) - XCTAssertEqual("mmol\(String.wordJoiner)/\(String.wordJoiner)L", formatter.string(from: HKUnit.millimolesPerLiter)) - XCTAssertEqual("6.0\(String.nonBreakingSpace)mmol\(String.wordJoiner)/\(String.wordJoiner)L", formatter.string(from: HKQuantity(unit: HKUnit.millimolesPerLiter, doubleValue: 6), for: HKUnit.millimolesPerLiter)!) - XCTAssertEqual("7.8\(String.nonBreakingSpace)mmol\(String.wordJoiner)/\(String.wordJoiner)L", formatter.string(from: HKQuantity(unit: HKUnit.millimolesPerLiter, doubleValue: 7.84), for: HKUnit.millimolesPerLiter)!) - XCTAssertEqual("12.0\(String.nonBreakingSpace)mmol\(String.wordJoiner)/\(String.wordJoiner)L", formatter.string(from: HKQuantity(unit: HKUnit.millimolesPerLiter, doubleValue: 12), for: HKUnit.millimolesPerLiter)!) - formatter.unitStyle = .short - XCTAssertEqual("mmol\(String.wordJoiner)/\(String.wordJoiner)L", formatter.string(from: HKUnit.millimolesPerLiter)) - XCTAssertEqual("6.0\(String.wordJoiner)mmol\(String.wordJoiner)/\(String.wordJoiner)L", formatter.string(from: HKQuantity(unit: HKUnit.millimolesPerLiter, doubleValue: 6), for: HKUnit.millimolesPerLiter)!) - XCTAssertEqual("7.8\(String.wordJoiner)mmol\(String.wordJoiner)/\(String.wordJoiner)L", formatter.string(from: HKQuantity(unit: HKUnit.millimolesPerLiter, doubleValue: 7.8), for: HKUnit.millimolesPerLiter)!) - formatter.unitStyle = .long - XCTAssertEqual("millimoles per liter", formatter.string(from: HKUnit.millimolesPerLiter)) - XCTAssertEqual("5.5 millimoles per liter", formatter.string(from: HKQuantity(unit: HKUnit.millimolesPerLiter, doubleValue: 5.5), for: HKUnit.millimolesPerLiter)!) - XCTAssertEqual("0.0 millimoles per liter", formatter.string(from: HKQuantity(unit: HKUnit.millimolesPerLiter, doubleValue: 0), for: HKUnit.millimolesPerLiter)!) - XCTAssertEqual("1.0 millimoles per liter", formatter.string(from: HKQuantity(unit: HKUnit.millimolesPerLiter, doubleValue: 1), for: HKUnit.millimolesPerLiter)!) - } - - func testUnitRounding() { - let value = 1.2345 - var unit: HKUnit = .milligramsPerDeciliter - XCTAssertEqual(unit.roundForPreferredDigits(value: value), 1) - - unit = unit.unitDivided(by: .internationalUnit()) - XCTAssertEqual(unit.roundForPreferredDigits(value: value), 1) - - unit = unit.unitDivided(by: .minute()) - XCTAssertEqual(unit.roundForPreferredDigits(value: value), 1) - - unit = .millimolesPerLiter - XCTAssertEqual(unit.roundForPreferredDigits(value: value), 1.2) - - unit = HKUnit.millimolesPerLiter.unitDivided(by: .internationalUnit()) - XCTAssertEqual(unit.roundForPreferredDigits(value: value), 1.2) - - unit = HKUnit.millimolesPerLiter.unitDivided(by: .minute()) - XCTAssertEqual(unit.roundForPreferredDigits(value: value), 1.2) - } - - func testQuantityRounding() { - let value = 1.2345 - var unit: HKUnit = .milligramsPerDeciliter - XCTAssertEqual(HKQuantity(unit: unit, doubleValue: value).doubleValue(for: unit, withRounding: true), 1) - - unit = unit.unitDivided(by: .internationalUnit()) - XCTAssertEqual(HKQuantity(unit: unit, doubleValue: value).doubleValue(for: unit, withRounding: true), 1) - - unit = unit.unitDivided(by: .minute()) - XCTAssertEqual(HKQuantity(unit: unit, doubleValue: value).doubleValue(for: unit, withRounding: true), 1) - - unit = .millimolesPerLiter - XCTAssertEqual(HKQuantity(unit: unit, doubleValue: value).doubleValue(for: unit, withRounding: true), 1.2) - - unit = HKUnit.millimolesPerLiter.unitDivided(by: .internationalUnit()) - XCTAssertEqual(HKQuantity(unit: unit, doubleValue: value).doubleValue(for: unit, withRounding: true), 1.2) - - unit = HKUnit.millimolesPerLiter.unitDivided(by: .minute()) - XCTAssertEqual(HKQuantity(unit: unit, doubleValue: value).doubleValue(for: unit, withRounding: true), 1.2) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/QuantityScheduleTests.swift b/Dependencies/LoopKit/LoopKitTests/QuantityScheduleTests.swift deleted file mode 100644 index 5e6f1c9c5..000000000 --- a/Dependencies/LoopKit/LoopKitTests/QuantityScheduleTests.swift +++ /dev/null @@ -1,98 +0,0 @@ -// -// QuantityScheduleTests.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/18/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class QuantityScheduleTests: XCTestCase { - - var items: [RepeatingScheduleValue]! - - override func setUp() { - super.setUp() - - let path = Bundle(for: type(of: self)).path(forResource: "read_carb_ratios", ofType: "json")! - let fixture = try! JSONSerialization.jsonObject(with: Data(contentsOf: URL(fileURLWithPath: path)), options: []) as! JSONDictionary - let schedule = fixture["schedule"] as! [JSONDictionary] - - items = schedule.map { - return RepeatingScheduleValue(startTime: TimeInterval(minutes: $0["offset"] as! Double), value: $0["ratio"] as! Double) - } - } - - func testCarbRatioScheduleLocalTimeZone() { - let therapyTimeZone = TimeZone(secondsFromGMT: -6*60*60)! - let schedule = CarbRatioSchedule(unit: HKUnit.gram(), dailyItems: items, timeZone: therapyTimeZone)! - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = therapyTimeZone - - let midnight = calendar.startOfDay(for: Date()) - - XCTAssertEqual(HKQuantity(unit: HKUnit.gram(), doubleValue: 10), schedule.quantity(at: midnight)) - XCTAssertEqual(9, - schedule.quantity(at: midnight.addingTimeInterval(-1)).doubleValue(for: schedule.unit) - ) - XCTAssertEqual(10, - schedule.quantity(at: midnight.addingTimeInterval(TimeInterval(hours: 24))).doubleValue(for: schedule.unit) - ) - - let midMorning = calendar.nextDate(after: Date(), matching: DateComponents(hour: 10, minute: 29, second: 4), matchingPolicy: .nextTime)! - - XCTAssertEqual(10, schedule.quantity(at: midMorning).doubleValue(for: schedule.unit)) - - let lunch = calendar.nextDate(after: midMorning, matching: DateComponents(hour: 12, minute: 01, second: 01), matchingPolicy: .nextTime)! - - XCTAssertEqual(9, schedule.quantity(at: lunch).doubleValue(for: schedule.unit)) - - let dinner = calendar.nextDate(after: midMorning, matching: DateComponents(hour: 19, minute: 0, second: 0), matchingPolicy: .nextTime)! - - XCTAssertEqual(8, schedule.quantity(at: dinner).doubleValue(for: schedule.unit)) - } - - func testCarbRatioScheduleUTC() { - let schedule = CarbRatioSchedule(unit: HKUnit.gram(), dailyItems: items, timeZone: TimeZone(secondsFromGMT: 0))! - var calendar = Calendar.current - - calendar.timeZone = TimeZone(identifier: "America/Los_Angeles")! - - let june1 = calendar.nextDate(after: Date(), matching: DateComponents(month: 5), matchingPolicy: .nextTime)! - - XCTAssertEqual(-7 * 60 * 60, calendar.timeZone.secondsFromGMT(for: june1)) - - - let midnight = calendar.startOfDay(for: june1) - - // This is 7 AM the next day in the Schedule's time zone - XCTAssertEqual(HKQuantity(unit: HKUnit.gram(), doubleValue: 10), schedule.quantity(at: midnight)) - XCTAssertEqual(10, - schedule.quantity(at: midnight.addingTimeInterval(-1)).doubleValue(for: schedule.unit) - ) - XCTAssertEqual(10, - schedule.quantity(at: midnight.addingTimeInterval(TimeInterval(hours: 24))).doubleValue(for: schedule.unit) - ) - - // 10:29:04 AM -> 5:29:04 PM - let midMorning = calendar.nextDate(after: june1, matching: DateComponents(hour: 10, minute: 29, second: 4), matchingPolicy: .nextTime)! - - XCTAssertEqual(9, schedule.quantity(at: midMorning).doubleValue(for: schedule.unit)) - - // 12:01:01 PM -> 7:01:01 PM - let lunch = calendar.nextDate(after: midMorning, matching: DateComponents(hour: 12, minute: 01, second: 01), matchingPolicy: .nextTime)! - - XCTAssertEqual(8, schedule.quantity(at: lunch).doubleValue(for: schedule.unit)) - - // 7:00 PM -> 2:00 AM - let dinner = calendar.nextDate(after: midMorning, matching: DateComponents(hour: 19, minute: 0, second: 0), matchingPolicy: .nextTime)! - - XCTAssertEqual(10, schedule.quantity(at: dinner).doubleValue(for: schedule.unit)) - } - - - -} diff --git a/Dependencies/LoopKit/LoopKitTests/ServiceTests.swift b/Dependencies/LoopKit/LoopKitTests/ServiceTests.swift deleted file mode 100644 index e25157103..000000000 --- a/Dependencies/LoopKit/LoopKitTests/ServiceTests.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// ServiceTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 9/15/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import XCTest - -@testable import LoopKit - -class ServiceTests: XCTestCase { - - fileprivate var testService: TestService! - - override func setUp() { - testService = TestService() - } - - override func tearDown() { - testService = nil - } - - func testServiceIdentifier() { - XCTAssertEqual(testService.serviceIdentifier, "TestService") - } - - func testLocalizedTitle() { - XCTAssertEqual(testService.localizedTitle, "Test Service") - } - -} - -fileprivate class TestError: Error {} - -fileprivate class TestService: Service { - - static var serviceIdentifier: String { return "TestService" } - - static var localizedTitle: String { return "Test Service" } - - public weak var serviceDelegate: ServiceDelegate? - - init() {} - - required init?(rawState: RawStateValue) { return nil } - - var rawState: RawStateValue { return [:] } - - var isOnboarded = true - -} diff --git a/Dependencies/LoopKit/LoopKitTests/SettingsStoreTests.swift b/Dependencies/LoopKit/LoopKitTests/SettingsStoreTests.swift deleted file mode 100644 index a680c0549..000000000 --- a/Dependencies/LoopKit/LoopKitTests/SettingsStoreTests.swift +++ /dev/null @@ -1,1125 +0,0 @@ -// -// SettingsStoreTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 1/2/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class SettingsStorePersistenceTests: PersistenceControllerTestCase, SettingsStoreDelegate { - - var settingsStore: SettingsStore! - - override func setUp() { - super.setUp() - - settingsStoreHasUpdatedSettingsDataHandler = nil - settingsStore = SettingsStore(store: cacheStore, expireAfter: .hours(1)) - settingsStore.delegate = self - } - - override func tearDown() { - settingsStore.delegate = nil - settingsStore = nil - settingsStoreHasUpdatedSettingsDataHandler = nil - - super.tearDown() - } - - // MARK: - SettingsStoreDelegate - - var settingsStoreHasUpdatedSettingsDataHandler: ((_ : SettingsStore) -> Void)? - - func settingsStoreHasUpdatedSettingsData(_ settingsStore: SettingsStore) { - settingsStoreHasUpdatedSettingsDataHandler?(settingsStore) - } - - // MARK: - - - func testStoreSettings() { - let storeSettingsHandler = expectation(description: "Store settings handler") - let storeSettingsCompletion = expectation(description: "Store settings completion") - - var handlerInvocation = 0 - - settingsStoreHasUpdatedSettingsDataHandler = { settingsStore in - handlerInvocation += 1 - - switch handlerInvocation { - case 1: - storeSettingsHandler.fulfill() - default: - XCTFail("Unexpected handler invocation") - } - } - - settingsStore.storeSettings(StoredSettings()) { _ in - storeSettingsCompletion.fulfill() - } - - wait(for: [storeSettingsHandler, storeSettingsCompletion], timeout: 2, enforceOrder: true) - } - - func testStoreSettingsMultiple() { - let storeSettingsHandler1 = expectation(description: "Store settings handler 1") - let storeSettingsHandler2 = expectation(description: "Store settings handler 2") - let storeSettingsCompletion1 = expectation(description: "Store settings completion 1") - let storeSettingsCompletion2 = expectation(description: "Store settings completion 2") - - var handlerInvocation = 0 - - settingsStoreHasUpdatedSettingsDataHandler = { settingsStore in - handlerInvocation += 1 - - switch handlerInvocation { - case 1: - storeSettingsHandler1.fulfill() - case 2: - storeSettingsHandler2.fulfill() - default: - XCTFail("Unexpected handler invocation") - } - } - - settingsStore.storeSettings(StoredSettings()) { _ in - storeSettingsCompletion1.fulfill() - } - - settingsStore.storeSettings(StoredSettings()) { _ in - storeSettingsCompletion2.fulfill() - } - - wait(for: [storeSettingsHandler1, storeSettingsCompletion1, storeSettingsHandler2, storeSettingsCompletion2], timeout: 2, enforceOrder: true) - } - - // MARK: - - - func testSettingsObjectEncodable() throws { - cacheStore.managedObjectContext.performAndWait { - do { - let object = SettingsObject(context: cacheStore.managedObjectContext) - object.data = try PropertyListEncoder().encode(StoredSettings.test) - object.date = dateFormatter.date(from: "2100-01-02T03:03:00Z")! - object.modificationCounter = 123 - try assertSettingsObjectEncodable(object, encodesJSON: """ -{ - "data" : { - "automaticDosingStrategy" : 1, - "basalRateSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : 1 - }, - { - "startTime" : 21600, - "value" : 1.5 - }, - { - "startTime" : 64800, - "value" : 1.25 - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "GMT-0700" - } - }, - "bloodGlucoseUnit" : "mg/dL", - "carbRatioSchedule" : { - "unit" : "g", - "valueSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : 15 - }, - { - "startTime" : 32400, - "value" : 14 - }, - { - "startTime" : 72000, - "value" : 18 - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "GMT-0700" - } - } - }, - "cgmDevice" : { - "firmwareVersion" : "CGM Firmware Version", - "hardwareVersion" : "CGM Hardware Version", - "localIdentifier" : "CGM Local Identifier", - "manufacturer" : "CGM Manufacturer", - "model" : "CGM Model", - "name" : "CGM Name", - "softwareVersion" : "CGM Software Version", - "udiDeviceIdentifier" : "CGM UDI Device Identifier" - }, - "controllerDevice" : { - "model" : "Controller Model", - "modelIdentifier" : "Controller Model Identifier", - "name" : "Controller Name", - "systemName" : "Controller System Name", - "systemVersion" : "Controller System Version" - }, - "controllerTimeZone" : { - "identifier" : "America/Los_Angeles" - }, - "date" : "2020-05-14T22:48:15Z", - "defaultRapidActingModel" : { - "actionDuration" : 21600, - "delay" : 600, - "modelType" : "rapidAdult", - "peakActivity" : 10800 - }, - "deviceToken" : "Device Token String", - "dosingEnabled" : true, - "glucoseTargetRangeSchedule" : { - "override" : { - "end" : "2020-05-14T14:48:15Z", - "start" : "2020-05-14T12:48:15Z", - "value" : { - "maxValue" : 115, - "minValue" : 105 - } - }, - "rangeSchedule" : { - "unit" : "mg/dL", - "valueSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : { - "maxValue" : 110, - "minValue" : 100 - } - }, - { - "startTime" : 25200, - "value" : { - "maxValue" : 100, - "minValue" : 90 - } - }, - { - "startTime" : 75600, - "value" : { - "maxValue" : 120, - "minValue" : 110 - } - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "GMT-0700" - } - } - } - }, - "insulinSensitivitySchedule" : { - "unit" : "mg/dL", - "valueSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : 45 - }, - { - "startTime" : 10800, - "value" : 40 - }, - { - "startTime" : 54000, - "value" : 50 - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "GMT-0700" - } - } - }, - "insulinType" : 1, - "maximumBasalRatePerHour" : 3.5, - "maximumBolus" : 10, - "notificationSettings" : { - "alertSetting" : "disabled", - "alertStyle" : "banner", - "announcementSetting" : "enabled", - "authorizationStatus" : "authorized", - "badgeSetting" : "enabled", - "carPlaySetting" : "notSupported", - "criticalAlertSetting" : "enabled", - "lockScreenSetting" : "disabled", - "notificationCenterSetting" : "notSupported", - "providesAppNotificationSettings" : true, - "scheduledDeliverySetting" : "disabled", - "showPreviewsSetting" : "whenAuthenticated", - "soundSetting" : "enabled", - "temporaryMuteAlertsSetting" : { - "disabled" : { - - } - }, - "timeSensitiveSetting" : "enabled" - }, - "overridePresets" : [ - { - "duration" : { - "finite" : { - "duration" : 3600 - } - }, - "id" : "2A67A303-5203-4CB8-8263-79498265368E", - "name" : "Apple", - "settings" : { - "insulinNeedsScaleFactor" : 2, - "targetRangeInMgdl" : { - "maxValue" : 140, - "minValue" : 130 - } - }, - "symbol" : "🍎" - } - ], - "preMealOverride" : { - "actualEnd" : { - "type" : "natural" - }, - "context" : "preMeal", - "duration" : "indefinite", - "enactTrigger" : "local", - "settings" : { - "insulinNeedsScaleFactor" : 0.5, - "targetRangeInMgdl" : { - "maxValue" : 90, - "minValue" : 80 - } - }, - "startDate" : "2020-05-14T14:38:39Z", - "syncIdentifier" : "2A67A303-5203-1234-8263-79498265368E" - }, - "preMealTargetRange" : { - "maxValue" : 90, - "minValue" : 80 - }, - "pumpDevice" : { - "firmwareVersion" : "Pump Firmware Version", - "hardwareVersion" : "Pump Hardware Version", - "localIdentifier" : "Pump Local Identifier", - "manufacturer" : "Pump Manufacturer", - "model" : "Pump Model", - "name" : "Pump Name", - "softwareVersion" : "Pump Software Version", - "udiDeviceIdentifier" : "Pump UDI Device Identifier" - }, - "scheduleOverride" : { - "actualEnd" : { - "type" : "natural" - }, - "context" : "preMeal", - "duration" : { - "finite" : { - "duration" : 3600 - } - }, - "enactTrigger" : { - "remote" : { - "address" : "127.0.0.1" - } - }, - "settings" : { - "insulinNeedsScaleFactor" : 1.5, - "targetRangeInMgdl" : { - "maxValue" : 120, - "minValue" : 110 - } - }, - "startDate" : "2020-05-14T14:48:19Z", - "syncIdentifier" : "2A67A303-1234-4CB8-8263-79498265368E" - }, - "suspendThreshold" : { - "unit" : "mg/dL", - "value" : 75 - }, - "syncIdentifier" : "2A67A303-1234-4CB8-1234-79498265368E", - "workoutTargetRange" : { - "maxValue" : 160, - "minValue" : 150 - } - }, - "date" : "2100-01-02T03:03:00Z", - "modificationCounter" : 123 -} -""" - ) - } catch let error { - XCTFail("Unexpected failure: \(error)") - } - } - } - - private func assertSettingsObjectEncodable(_ original: SettingsObject, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() -} - -class SettingsStoreQueryAnchorTests: XCTestCase { - - var rawValue: SettingsStore.QueryAnchor.RawValue = [ - "modificationCounter": Int64(123) - ] - - func testInitializerDefault() { - let queryAnchor = SettingsStore.QueryAnchor() - XCTAssertEqual(queryAnchor.modificationCounter, 0) - } - - func testInitializerRawValue() { - let queryAnchor = SettingsStore.QueryAnchor(rawValue: rawValue) - XCTAssertNotNil(queryAnchor) - XCTAssertEqual(queryAnchor?.modificationCounter, 123) - } - - func testInitializerRawValueMissingModificationCounter() { - rawValue["modificationCounter"] = nil - XCTAssertNil(SettingsStore.QueryAnchor(rawValue: rawValue)) - } - - func testInitializerRawValueInvalidModificationCounter() { - rawValue["modificationCounter"] = "123" - XCTAssertNil(SettingsStore.QueryAnchor(rawValue: rawValue)) - } - - func testRawValueWithDefault() { - let rawValue = SettingsStore.QueryAnchor().rawValue - XCTAssertEqual(rawValue.count, 1) - XCTAssertEqual(rawValue["modificationCounter"] as? Int64, Int64(0)) - } - - func testRawValueWithNonDefault() { - var queryAnchor = SettingsStore.QueryAnchor() - queryAnchor.modificationCounter = 123 - let rawValue = queryAnchor.rawValue - XCTAssertEqual(rawValue.count, 1) - XCTAssertEqual(rawValue["modificationCounter"] as? Int64, Int64(123)) - } - -} - -class SettingsStoreQueryTests: PersistenceControllerTestCase { - - var settingsStore: SettingsStore! - var completion: XCTestExpectation! - var queryAnchor: SettingsStore.QueryAnchor! - var limit: Int! - - override func setUp() { - super.setUp() - - settingsStore = SettingsStore(store: cacheStore, expireAfter: .hours(1)) - completion = expectation(description: "Completion") - queryAnchor = SettingsStore.QueryAnchor() - limit = Int.max - } - - override func tearDown() { - limit = nil - queryAnchor = nil - completion = nil - settingsStore = nil - - super.tearDown() - } - - // MARK: - - - func testEmptyWithDefaultQueryAnchor() { - settingsStore.executeSettingsQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 0) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testEmptyWithMissingQueryAnchor() { - queryAnchor = nil - - settingsStore.executeSettingsQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 0) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testEmptyWithNonDefaultQueryAnchor() { - queryAnchor.modificationCounter = 1 - - settingsStore.executeSettingsQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 1) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithUnusedQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - settingsStore.executeSettingsQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(data.count, 3) - for (index, syncIdentifier) in syncIdentifiers.enumerated() { - XCTAssertEqual(data[index].syncIdentifier, syncIdentifier) - } - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithStaleQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - queryAnchor.modificationCounter = 2 - - settingsStore.executeSettingsQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(data.count, 1) - XCTAssertEqual(data[0].syncIdentifier, syncIdentifiers[2]) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithCurrentQueryAnchor() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - queryAnchor.modificationCounter = 3 - - settingsStore.executeSettingsQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 3) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithLimitZero() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - limit = 0 - - settingsStore.executeSettingsQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 0) - XCTAssertEqual(data.count, 0) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - func testDataWithLimitCoveredByData() { - let syncIdentifiers = [generateSyncIdentifier(), generateSyncIdentifier(), generateSyncIdentifier()] - - addData(withSyncIdentifiers: syncIdentifiers) - - limit = 2 - - settingsStore.executeSettingsQuery(fromQueryAnchor: queryAnchor, limit: limit) { result in - switch result { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let anchor, let data): - XCTAssertEqual(anchor.modificationCounter, 2) - XCTAssertEqual(data.count, 2) - XCTAssertEqual(data[0].syncIdentifier, syncIdentifiers[0]) - XCTAssertEqual(data[1].syncIdentifier, syncIdentifiers[1]) - } - self.completion.fulfill() - } - - wait(for: [completion], timeout: 2, enforceOrder: true) - } - - private func addData(withSyncIdentifiers syncIdentifiers: [UUID]) { - let semaphore = DispatchSemaphore(value: 0) - for syncIdentifier in syncIdentifiers { - self.settingsStore.storeSettings(StoredSettings(syncIdentifier: syncIdentifier)) { _ in semaphore.signal() } - } - for _ in syncIdentifiers { semaphore.wait() } - } - - private func generateSyncIdentifier() -> UUID { UUID() } -} - -class SettingsStoreCriticalEventLogTests: PersistenceControllerTestCase { - var settingsStore: SettingsStore! - var outputStream: MockOutputStream! - var progress: Progress! - - override func setUp() { - super.setUp() - - let settings = [StoredSettings(date: dateFormatter.date(from: "2100-01-02T03:08:00Z")!, controllerTimeZone: TimeZone(identifier: "America/Los_Angeles")!, syncIdentifier: UUID(uuidString: "18CF3948-0B3D-4B12-8BFE-14986B0E6784")!), - StoredSettings(date: dateFormatter.date(from: "2100-01-02T03:10:00Z")!, controllerTimeZone: TimeZone(identifier: "America/Los_Angeles")!, syncIdentifier: UUID(uuidString: "C86DEB61-68E9-464E-9DD5-96A9CB445FD3")!), - StoredSettings(date: dateFormatter.date(from: "2100-01-02T03:04:00Z")!, controllerTimeZone: TimeZone(identifier: "America/Los_Angeles")!, syncIdentifier: UUID(uuidString: "2B03D96C-6F5D-4140-99CD-80C3E64D6010")!), - StoredSettings(date: dateFormatter.date(from: "2100-01-02T03:06:00Z")!, controllerTimeZone: TimeZone(identifier: "America/Los_Angeles")!, syncIdentifier: UUID(uuidString: "FF1C4F01-3558-4FB2-957E-FA1522C4735E")!), - StoredSettings(date: dateFormatter.date(from: "2100-01-02T03:02:00Z")!, controllerTimeZone: TimeZone(identifier: "America/Los_Angeles")!, syncIdentifier: UUID(uuidString: "71B699D7-0E8F-4B13-B7A1-E7751EB78E74")!)] - - settingsStore = SettingsStore(store: cacheStore, expireAfter: .hours(1)) - - let dispatchGroup = DispatchGroup() - dispatchGroup.enter() - settingsStore.addStoredSettings(settings: settings) { error in - XCTAssertNil(error) - dispatchGroup.leave() - } - dispatchGroup.wait() - - outputStream = MockOutputStream() - progress = Progress() - } - - override func tearDown() { - settingsStore = nil - - super.tearDown() - } - - func testExportProgressTotalUnitCount() { - switch settingsStore.exportProgressTotalUnitCount(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!) { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let progressTotalUnitCount): - XCTAssertEqual(progressTotalUnitCount, 3 * 11) - } - } - - func testExportProgressTotalUnitCountEmpty() { - switch settingsStore.exportProgressTotalUnitCount(startDate: dateFormatter.date(from: "2100-01-02T03:00:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:01:00Z")!) { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let progressTotalUnitCount): - XCTAssertEqual(progressTotalUnitCount, 0) - } - } - - func testExport() { - XCTAssertNil(settingsStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!, - to: outputStream, - progress: progress)) - XCTAssertEqual(outputStream.string, """ -[ -{"data":{"automaticDosingStrategy":0,"bloodGlucoseUnit":"mg/dL","controllerTimeZone":{"identifier":"America/Los_Angeles"},"date":"2100-01-02T03:08:00.000Z","dosingEnabled":false,"syncIdentifier":"18CF3948-0B3D-4B12-8BFE-14986B0E6784"},"date":"2100-01-02T03:08:00.000Z","modificationCounter":1}, -{"data":{"automaticDosingStrategy":0,"bloodGlucoseUnit":"mg/dL","controllerTimeZone":{"identifier":"America/Los_Angeles"},"date":"2100-01-02T03:04:00.000Z","dosingEnabled":false,"syncIdentifier":"2B03D96C-6F5D-4140-99CD-80C3E64D6010"},"date":"2100-01-02T03:04:00.000Z","modificationCounter":3}, -{"data":{"automaticDosingStrategy":0,"bloodGlucoseUnit":"mg/dL","controllerTimeZone":{"identifier":"America/Los_Angeles"},"date":"2100-01-02T03:06:00.000Z","dosingEnabled":false,"syncIdentifier":"FF1C4F01-3558-4FB2-957E-FA1522C4735E"},"date":"2100-01-02T03:06:00.000Z","modificationCounter":4} -] -""" - ) - XCTAssertEqual(progress.completedUnitCount, 3 * 11) - } - - func testExportEmpty() { - XCTAssertNil(settingsStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:00:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:01:00Z")!, - to: outputStream, - progress: progress)) - XCTAssertEqual(outputStream.string, "[]") - XCTAssertEqual(progress.completedUnitCount, 0) - } - - func testExportCancelled() { - progress.cancel() - XCTAssertEqual(settingsStore.export(startDate: dateFormatter.date(from: "2100-01-02T03:03:00Z")!, - endDate: dateFormatter.date(from: "2100-01-02T03:09:00Z")!, - to: outputStream, - progress: progress) as? CriticalEventLogError, CriticalEventLogError.cancelled) - } - - private let dateFormatter = ISO8601DateFormatter() -} - -class StoredSettingsCodableTests: XCTestCase { - func testStoredSettingsCodable() throws { - try assertStoredSettingsCodable(StoredSettings.test, encodesJSON: """ -{ - "automaticDosingStrategy" : 1, - "basalRateSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : 1 - }, - { - "startTime" : 21600, - "value" : 1.5 - }, - { - "startTime" : 64800, - "value" : 1.25 - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "GMT-0700" - } - }, - "bloodGlucoseUnit" : "mg/dL", - "carbRatioSchedule" : { - "unit" : "g", - "valueSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : 15 - }, - { - "startTime" : 32400, - "value" : 14 - }, - { - "startTime" : 72000, - "value" : 18 - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "GMT-0700" - } - } - }, - "cgmDevice" : { - "firmwareVersion" : "CGM Firmware Version", - "hardwareVersion" : "CGM Hardware Version", - "localIdentifier" : "CGM Local Identifier", - "manufacturer" : "CGM Manufacturer", - "model" : "CGM Model", - "name" : "CGM Name", - "softwareVersion" : "CGM Software Version", - "udiDeviceIdentifier" : "CGM UDI Device Identifier" - }, - "controllerDevice" : { - "model" : "Controller Model", - "modelIdentifier" : "Controller Model Identifier", - "name" : "Controller Name", - "systemName" : "Controller System Name", - "systemVersion" : "Controller System Version" - }, - "controllerTimeZone" : { - "identifier" : "America/Los_Angeles" - }, - "date" : "2020-05-14T22:48:15Z", - "defaultRapidActingModel" : { - "actionDuration" : 21600, - "delay" : 600, - "modelType" : "rapidAdult", - "peakActivity" : 10800 - }, - "deviceToken" : "Device Token String", - "dosingEnabled" : true, - "glucoseTargetRangeSchedule" : { - "override" : { - "end" : "2020-05-14T14:48:15Z", - "start" : "2020-05-14T12:48:15Z", - "value" : { - "maxValue" : 115, - "minValue" : 105 - } - }, - "rangeSchedule" : { - "unit" : "mg/dL", - "valueSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : { - "maxValue" : 110, - "minValue" : 100 - } - }, - { - "startTime" : 25200, - "value" : { - "maxValue" : 100, - "minValue" : 90 - } - }, - { - "startTime" : 75600, - "value" : { - "maxValue" : 120, - "minValue" : 110 - } - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "GMT-0700" - } - } - } - }, - "insulinSensitivitySchedule" : { - "unit" : "mg/dL", - "valueSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : 45 - }, - { - "startTime" : 10800, - "value" : 40 - }, - { - "startTime" : 54000, - "value" : 50 - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "GMT-0700" - } - } - }, - "insulinType" : 1, - "maximumBasalRatePerHour" : 3.5, - "maximumBolus" : 10, - "notificationSettings" : { - "alertSetting" : "disabled", - "alertStyle" : "banner", - "announcementSetting" : "enabled", - "authorizationStatus" : "authorized", - "badgeSetting" : "enabled", - "carPlaySetting" : "notSupported", - "criticalAlertSetting" : "enabled", - "lockScreenSetting" : "disabled", - "notificationCenterSetting" : "notSupported", - "providesAppNotificationSettings" : true, - "scheduledDeliverySetting" : "disabled", - "showPreviewsSetting" : "whenAuthenticated", - "soundSetting" : "enabled", - "temporaryMuteAlertsSetting" : { - "disabled" : { - - } - }, - "timeSensitiveSetting" : "enabled" - }, - "overridePresets" : [ - { - "duration" : { - "finite" : { - "duration" : 3600 - } - }, - "id" : "2A67A303-5203-4CB8-8263-79498265368E", - "name" : "Apple", - "settings" : { - "insulinNeedsScaleFactor" : 2, - "targetRangeInMgdl" : { - "maxValue" : 140, - "minValue" : 130 - } - }, - "symbol" : "🍎" - } - ], - "preMealOverride" : { - "actualEnd" : { - "type" : "natural" - }, - "context" : "preMeal", - "duration" : "indefinite", - "enactTrigger" : "local", - "settings" : { - "insulinNeedsScaleFactor" : 0.5, - "targetRangeInMgdl" : { - "maxValue" : 90, - "minValue" : 80 - } - }, - "startDate" : "2020-05-14T14:38:39Z", - "syncIdentifier" : "2A67A303-5203-1234-8263-79498265368E" - }, - "preMealTargetRange" : { - "maxValue" : 90, - "minValue" : 80 - }, - "pumpDevice" : { - "firmwareVersion" : "Pump Firmware Version", - "hardwareVersion" : "Pump Hardware Version", - "localIdentifier" : "Pump Local Identifier", - "manufacturer" : "Pump Manufacturer", - "model" : "Pump Model", - "name" : "Pump Name", - "softwareVersion" : "Pump Software Version", - "udiDeviceIdentifier" : "Pump UDI Device Identifier" - }, - "scheduleOverride" : { - "actualEnd" : { - "type" : "natural" - }, - "context" : "preMeal", - "duration" : { - "finite" : { - "duration" : 3600 - } - }, - "enactTrigger" : { - "remote" : { - "address" : "127.0.0.1" - } - }, - "settings" : { - "insulinNeedsScaleFactor" : 1.5, - "targetRangeInMgdl" : { - "maxValue" : 120, - "minValue" : 110 - } - }, - "startDate" : "2020-05-14T14:48:19Z", - "syncIdentifier" : "2A67A303-1234-4CB8-8263-79498265368E" - }, - "suspendThreshold" : { - "unit" : "mg/dL", - "value" : 75 - }, - "syncIdentifier" : "2A67A303-1234-4CB8-1234-79498265368E", - "workoutTargetRange" : { - "maxValue" : 160, - "minValue" : 150 - } -} -""" - ) - } - - private func assertStoredSettingsCodable(_ original: StoredSettings, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(StoredSettings.self, from: data) - XCTAssertEqual(decoded, original) - } - - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() -} - -fileprivate extension StoredSettings { - static var test: StoredSettings { - let controllerTimeZone = TimeZone(identifier: "America/Los_Angeles")! - let scheduleTimeZone = TimeZone(secondsFromGMT: TimeZone(identifier: "America/Phoenix")!.secondsFromGMT())! - let dosingEnabled = true - let glucoseTargetRangeSchedule = GlucoseRangeSchedule(rangeSchedule: DailyQuantitySchedule(unit: .milligramsPerDeciliter, - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: DoubleRange(minValue: 100.0, maxValue: 110.0)), - RepeatingScheduleValue(startTime: .hours(7), value: DoubleRange(minValue: 90.0, maxValue: 100.0)), - RepeatingScheduleValue(startTime: .hours(21), value: DoubleRange(minValue: 110.0, maxValue: 120.0))], - timeZone: scheduleTimeZone)!, - override: GlucoseRangeSchedule.Override(value: DoubleRange(minValue: 105.0, maxValue: 115.0), - start: dateFormatter.date(from: "2020-05-14T12:48:15Z")!, - end: dateFormatter.date(from: "2020-05-14T14:48:15Z")!)) - let preMealTargetRange = DoubleRange(minValue: 80.0, maxValue: 90.0).quantityRange(for: .milligramsPerDeciliter) - let workoutTargetRange = DoubleRange(minValue: 150.0, maxValue: 160.0).quantityRange(for: .milligramsPerDeciliter) - let overridePresets = [TemporaryScheduleOverridePreset(id: UUID(uuidString: "2A67A303-5203-4CB8-8263-79498265368E")!, - symbol: "🍎", - name: "Apple", - settings: TemporaryScheduleOverrideSettings(unit: .milligramsPerDeciliter, - targetRange: DoubleRange(minValue: 130.0, maxValue: 140.0), - insulinNeedsScaleFactor: 2.0), - duration: .finite(.minutes(60)))] - let scheduleOverride = TemporaryScheduleOverride(context: .preMeal, - settings: TemporaryScheduleOverrideSettings(unit: .milligramsPerDeciliter, - targetRange: DoubleRange(minValue: 110.0, maxValue: 120.0), - insulinNeedsScaleFactor: 1.5), - startDate: dateFormatter.date(from: "2020-05-14T14:48:19Z")!, - duration: .finite(.minutes(60)), - enactTrigger: .remote("127.0.0.1"), - syncIdentifier: UUID(uuidString: "2A67A303-1234-4CB8-8263-79498265368E")!) - let preMealOverride = TemporaryScheduleOverride(context: .preMeal, - settings: TemporaryScheduleOverrideSettings(unit: .milligramsPerDeciliter, - targetRange: DoubleRange(minValue: 80.0, maxValue: 90.0), - insulinNeedsScaleFactor: 0.5), - startDate: dateFormatter.date(from: "2020-05-14T14:38:39Z")!, - duration: .indefinite, - enactTrigger: .local, - syncIdentifier: UUID(uuidString: "2A67A303-5203-1234-8263-79498265368E")!) - let maximumBasalRatePerHour = 3.5 - let maximumBolus = 10.0 - let suspendThreshold = GlucoseThreshold(unit: .milligramsPerDeciliter, value: 75.0) - let deviceToken = "Device Token String" - let insulinType = InsulinType.humalog - let defaultRapidActingModel = StoredInsulinModel(modelType: .rapidAdult, delay: .minutes(10), actionDuration: .hours(6), peakActivity: .hours(3)) - let basalRateSchedule = BasalRateSchedule(dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 1.0), - RepeatingScheduleValue(startTime: .hours(6), value: 1.5), - RepeatingScheduleValue(startTime: .hours(18), value: 1.25)], - timeZone: scheduleTimeZone) - let insulinSensitivitySchedule = InsulinSensitivitySchedule(unit: .milligramsPerDeciliter, - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 45.0), - RepeatingScheduleValue(startTime: .hours(3), value: 40.0), - RepeatingScheduleValue(startTime: .hours(15), value: 50.0)], - timeZone: scheduleTimeZone) - let carbRatioSchedule = CarbRatioSchedule(unit: .gram(), - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 15.0), - RepeatingScheduleValue(startTime: .hours(9), value: 14.0), - RepeatingScheduleValue(startTime: .hours(20), value: 18.0)], - timeZone: scheduleTimeZone) - let notificationSettings = NotificationSettings(authorizationStatus: .authorized, - soundSetting: .enabled, - badgeSetting: .enabled, - alertSetting: .disabled, - notificationCenterSetting: .notSupported, - lockScreenSetting: .disabled, - carPlaySetting: .notSupported, - alertStyle: .banner, - showPreviewsSetting: .whenAuthenticated, - criticalAlertSetting: .enabled, - providesAppNotificationSettings: true, - announcementSetting: .enabled, - timeSensitiveSetting: .enabled, - scheduledDeliverySetting: .disabled, - temporaryMuteAlertsSetting: .disabled) - let controllerDevice = StoredSettings.ControllerDevice(name: "Controller Name", - systemName: "Controller System Name", - systemVersion: "Controller System Version", - model: "Controller Model", - modelIdentifier: "Controller Model Identifier") - let cgmDevice = HKDevice(name: "CGM Name", - manufacturer: "CGM Manufacturer", - model: "CGM Model", - hardwareVersion: "CGM Hardware Version", - firmwareVersion: "CGM Firmware Version", - softwareVersion: "CGM Software Version", - localIdentifier: "CGM Local Identifier", - udiDeviceIdentifier: "CGM UDI Device Identifier") - let pumpDevice = HKDevice(name: "Pump Name", - manufacturer: "Pump Manufacturer", - model: "Pump Model", - hardwareVersion: "Pump Hardware Version", - firmwareVersion: "Pump Firmware Version", - softwareVersion: "Pump Software Version", - localIdentifier: "Pump Local Identifier", - udiDeviceIdentifier: "Pump UDI Device Identifier") - let bloodGlucoseUnit = HKUnit.milligramsPerDeciliter - - return StoredSettings(date: dateFormatter.date(from: "2020-05-14T22:48:15Z")!, - controllerTimeZone: controllerTimeZone, - dosingEnabled: dosingEnabled, - glucoseTargetRangeSchedule: glucoseTargetRangeSchedule, - preMealTargetRange: preMealTargetRange, - workoutTargetRange: workoutTargetRange, - overridePresets: overridePresets, - scheduleOverride: scheduleOverride, - preMealOverride: preMealOverride, - maximumBasalRatePerHour: maximumBasalRatePerHour, - maximumBolus: maximumBolus, - suspendThreshold: suspendThreshold, - deviceToken: deviceToken, - insulinType: insulinType, - defaultRapidActingModel: defaultRapidActingModel, - basalRateSchedule: basalRateSchedule, - insulinSensitivitySchedule: insulinSensitivitySchedule, - carbRatioSchedule: carbRatioSchedule, - notificationSettings: notificationSettings, - controllerDevice: controllerDevice, - cgmDevice: cgmDevice, - pumpDevice: pumpDevice, - bloodGlucoseUnit: bloodGlucoseUnit, - automaticDosingStrategy: .automaticBolus, - syncIdentifier: UUID(uuidString: "2A67A303-1234-4CB8-1234-79498265368E")!) - } - - private static let dateFormatter = ISO8601DateFormatter() -} diff --git a/Dependencies/LoopKit/LoopKitTests/StoredCarbEntryTests.swift b/Dependencies/LoopKit/LoopKitTests/StoredCarbEntryTests.swift deleted file mode 100644 index bf8733c52..000000000 --- a/Dependencies/LoopKit/LoopKitTests/StoredCarbEntryTests.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// StoredCarbEntryTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 10/6/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class StoredCarbEntryCodableTests: XCTestCase { - func testCodable() throws { - let storedCarbEntry = StoredCarbEntry(uuid: UUID(uuidString: "18CF3948-0B3D-4B12-8BFE-14986B0E6784")!, - provenanceIdentifier: "com.loopkit.loop", - syncIdentifier: "2B03D96C-6F5D-4140-99CD-80C3E64D6010", - syncVersion: 2, - startDate: dateFormatter.date(from: "2020-01-02T03:00:23Z")!, - quantity: HKQuantity(unit: .gram(), doubleValue: 19), - foodType: "Pizza", - absorptionTime: .hours(5), - createdByCurrentApp: true, - userCreatedDate: dateFormatter.date(from: "2020-01-02T03:03:34Z")!, - userUpdatedDate: dateFormatter.date(from: "2020-01-02T03:05:45Z")!) - try! assertStoredCarbEntryCodable(storedCarbEntry, encodesJSON: """ -{ - "absorptionTime" : 18000, - "createdByCurrentApp" : true, - "foodType" : "Pizza", - "provenanceIdentifier" : "com.loopkit.loop", - "quantity" : 19, - "startDate" : "2020-01-02T03:00:23Z", - "syncIdentifier" : "2B03D96C-6F5D-4140-99CD-80C3E64D6010", - "syncVersion" : 2, - "userCreatedDate" : "2020-01-02T03:03:34Z", - "userUpdatedDate" : "2020-01-02T03:05:45Z", - "uuid" : "18CF3948-0B3D-4B12-8BFE-14986B0E6784" -} -""" - ) - } - - func testCodableOptional() throws { - let storedCarbEntry = StoredCarbEntry(uuid: nil, - provenanceIdentifier: "com.loopkit.loop", - syncIdentifier: nil, - syncVersion: nil, - startDate: dateFormatter.date(from: "2020-02-03T04:16:18Z")!, - quantity: HKQuantity(unit: .gram(), doubleValue: 19), - foodType: nil, - absorptionTime: nil, - createdByCurrentApp: false, - userCreatedDate: nil, - userUpdatedDate: nil) - - try! assertStoredCarbEntryCodable(storedCarbEntry, encodesJSON: """ -{ - "createdByCurrentApp" : false, - "provenanceIdentifier" : "com.loopkit.loop", - "quantity" : 19, - "startDate" : "2020-02-03T04:16:18Z" -} -""" - ) - } - - private func assertStoredCarbEntryCodable(_ original: StoredCarbEntry, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(StoredCarbEntry.self, from: data) - XCTAssertEqual(decoded, original) - } - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() - - private let dateFormatter = ISO8601DateFormatter() -} diff --git a/Dependencies/LoopKit/LoopKitTests/StoredGlucoseSampleTests.swift b/Dependencies/LoopKit/LoopKitTests/StoredGlucoseSampleTests.swift deleted file mode 100644 index ba70241f5..000000000 --- a/Dependencies/LoopKit/LoopKitTests/StoredGlucoseSampleTests.swift +++ /dev/null @@ -1,172 +0,0 @@ -// -// StoredGlucoseSampleTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 10/12/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class StoredGlucoseSampleInitializerTests: XCTestCase { - func testQuantitySampleInitializer() { - let type = HKQuantityType.quantityType(forIdentifier: .bloodGlucose)! - let startDate = dateFormatter.date(from: "2020-01-02T03:04:05Z")! - let quantity = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 123.4) - let metadata: [String: Any] = [ - HKMetadataKeySyncIdentifier: "3A95BED9-2633-4D6A-9229-70B07521C561", - HKMetadataKeySyncVersion: 2, - MetadataKeyGlucoseIsDisplayOnly: true, - HKMetadataKeyWasUserEntered: true - ] - let quantitySample = HKQuantitySample(type: type, quantity: quantity, start: startDate, end: startDate, metadata: metadata) - let sample = StoredGlucoseSample(sample: quantitySample) - XCTAssertNotNil(sample.uuid) - XCTAssertEqual(sample.provenanceIdentifier, "") - XCTAssertEqual(sample.syncIdentifier, "3A95BED9-2633-4D6A-9229-70B07521C561") - XCTAssertEqual(sample.syncVersion, 2) - XCTAssertEqual(sample.startDate, startDate) - XCTAssertEqual(sample.quantity, quantity) - XCTAssertEqual(sample.isDisplayOnly, true) - XCTAssertEqual(sample.wasUserEntered, true) - } - - func testFullInitializer() { - let uuid = UUID() - let startDate = dateFormatter.date(from: "2020-02-03T04:05:06Z")! - let quantity = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 134.5) - let trendRate = HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: 0.0) - let device = HKDevice(name: "NAME", manufacturer: "MANUFACTURER", model: "MODEL", hardwareVersion: "HARDWAREVERSION", firmwareVersion: "FIRMWAREVERSION", softwareVersion: "SOFTWAREVERSION", localIdentifier: "LOCALIDENTIFIER", udiDeviceIdentifier: "UDIDEVICEIDENTIFIER") - let sample = StoredGlucoseSample(uuid: uuid, - provenanceIdentifier: "8A1333E7-79CB-413F-AB7A-5413F14D4531", - syncIdentifier: "E7D34EED-CFEE-48FD-810F-5C8C41FACA83", - syncVersion: 3, - startDate: startDate, - quantity: quantity, - condition: .aboveRange, - trend: .flat, - trendRate: trendRate, - isDisplayOnly: true, - wasUserEntered: false, - device: device, - healthKitEligibleDate: startDate.addingTimeInterval(.hours(3))) - XCTAssertEqual(sample.uuid, uuid) - XCTAssertEqual(sample.provenanceIdentifier, "8A1333E7-79CB-413F-AB7A-5413F14D4531") - XCTAssertEqual(sample.syncIdentifier, "E7D34EED-CFEE-48FD-810F-5C8C41FACA83") - XCTAssertEqual(sample.syncVersion, 3) - XCTAssertEqual(sample.startDate, startDate) - XCTAssertEqual(sample.quantity, quantity) - XCTAssertEqual(sample.condition, .aboveRange) - XCTAssertEqual(sample.trend, .flat) - XCTAssertEqual(sample.trendRate, trendRate) - XCTAssertEqual(sample.isDisplayOnly, true) - XCTAssertEqual(sample.wasUserEntered, false) - XCTAssertEqual(sample.device, device) - XCTAssertEqual(sample.healthKitEligibleDate, startDate.addingTimeInterval(.hours(3))) - } - - func testFullInitializerOptional() { - let startDate = dateFormatter.date(from: "2020-03-04T05:06:07Z")! - let quantity = HKQuantity(unit: .millimolesPerLiter, doubleValue: 6.5) - let sample = StoredGlucoseSample(uuid: nil, - provenanceIdentifier: "95F800A3-A59D-4419-B8F2-611BED0962CF", - syncIdentifier: nil, - syncVersion: nil, - startDate: startDate, - quantity: quantity, - condition: nil, - trend: nil, - trendRate: nil, - isDisplayOnly: false, - wasUserEntered: true, - device: nil, - healthKitEligibleDate: nil) - XCTAssertNil(sample.uuid) - XCTAssertEqual(sample.provenanceIdentifier, "95F800A3-A59D-4419-B8F2-611BED0962CF") - XCTAssertNil(sample.syncIdentifier) - XCTAssertNil(sample.syncVersion) - XCTAssertEqual(sample.startDate, startDate) - XCTAssertEqual(sample.quantity, quantity) - XCTAssertNil(sample.condition) - XCTAssertNil(sample.trend) - XCTAssertNil(sample.trendRate) - XCTAssertEqual(sample.isDisplayOnly, false) - XCTAssertEqual(sample.wasUserEntered, true) - XCTAssertNil(sample.device) - XCTAssertNil(sample.healthKitEligibleDate) - } - - private let dateFormatter = ISO8601DateFormatter() -} - -class StoredGlucoseSampleManagedObjectInitializerTests: PersistenceControllerTestCase { - func testManagedObjectInitializer() { - cacheStore.managedObjectContext.performAndWait { - let uuid = UUID() - let startDate = dateFormatter.date(from: "2020-04-05T06:07:08Z")! - let managedObject = CachedGlucoseObject(context: cacheStore.managedObjectContext) - let device = HKDevice(name: "NAME", manufacturer: "MANUFACTURER", model: "MODEL", hardwareVersion: "HARDWAREVERSION", firmwareVersion: "FIRMWAREVERSION", softwareVersion: "SOFTWAREVERSION", localIdentifier: "LOCALIDENTIFIER", udiDeviceIdentifier: "UDIDEVICEIDENTIFIER") - managedObject.uuid = uuid - managedObject.provenanceIdentifier = "C198186D-F15C-4D0F-B8A1-83B28626DB3A" - managedObject.syncIdentifier = "A313021C-4B11-448A-9266-B01321CA0BCC" - managedObject.syncVersion = 4 - managedObject.value = 145.6 - managedObject.unitString = HKUnit.milligramsPerDeciliter.unitString - managedObject.startDate = startDate - managedObject.isDisplayOnly = true - managedObject.wasUserEntered = true - managedObject.device = device - managedObject.condition = .aboveRange - managedObject.trend = .downDownDown - managedObject.trendRateUnit = HKUnit.milligramsPerDeciliterPerMinute.unitString - managedObject.trendRateValue = -4.0 - managedObject.healthKitEligibleDate = startDate.addingTimeInterval(.hours(3)) - let sample = StoredGlucoseSample(managedObject: managedObject) - XCTAssertEqual(sample.uuid, uuid) - XCTAssertEqual(sample.provenanceIdentifier, "C198186D-F15C-4D0F-B8A1-83B28626DB3A") - XCTAssertEqual(sample.syncIdentifier, "A313021C-4B11-448A-9266-B01321CA0BCC") - XCTAssertEqual(sample.syncVersion, 4) - XCTAssertEqual(sample.startDate, startDate) - XCTAssertEqual(sample.quantity, HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 145.6)) - XCTAssertEqual(sample.isDisplayOnly, true) - XCTAssertEqual(sample.wasUserEntered, true) - XCTAssertEqual(sample.device, device) - XCTAssertEqual(sample.condition, .aboveRange) - XCTAssertEqual(sample.trend, .downDownDown) - XCTAssertEqual(sample.trendRate, HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: -4.0)) - XCTAssertEqual(sample.healthKitEligibleDate, startDate.addingTimeInterval(.hours(3))) - } - } - - func testManagedObjectOptional() { - cacheStore.managedObjectContext.performAndWait { - let quantity = HKQuantity(unit: .millimolesPerLiter, doubleValue: 7.6) - let startDate = dateFormatter.date(from: "2020-05-06T07:08:09Z")! - let managedObject = CachedGlucoseObject(context: cacheStore.managedObjectContext) - managedObject.provenanceIdentifier = "9A6AF580-7584-4FB1-90A2-ACCB96DF1D58" - managedObject.value = quantity.doubleValue(for: .millimolesPerLiter) - managedObject.unitString = HKUnit.millimolesPerLiter.unitString - managedObject.startDate = startDate - managedObject.isDisplayOnly = true - managedObject.wasUserEntered = true - let sample = StoredGlucoseSample(managedObject: managedObject) - XCTAssertNil(sample.uuid) - XCTAssertEqual(sample.provenanceIdentifier, "9A6AF580-7584-4FB1-90A2-ACCB96DF1D58") - XCTAssertNil(sample.syncIdentifier) - XCTAssertNil(sample.syncVersion) - XCTAssertEqual(sample.startDate, startDate) - XCTAssertEqual(sample.quantity, HKQuantity(unit: .millimolesPerLiter, doubleValue: 7.6)) - XCTAssertEqual(sample.isDisplayOnly, true) - XCTAssertEqual(sample.wasUserEntered, true) - XCTAssertNil(sample.device) - XCTAssertNil(sample.condition) - XCTAssertNil(sample.trend) - XCTAssertNil(sample.trendRate) - XCTAssertNil(sample.healthKitEligibleDate) - } - } - - private let dateFormatter = ISO8601DateFormatter() -} diff --git a/Dependencies/LoopKit/LoopKitTests/TempBasalRecommendationTests.swift b/Dependencies/LoopKit/LoopKitTests/TempBasalRecommendationTests.swift deleted file mode 100644 index e09442fa7..000000000 --- a/Dependencies/LoopKit/LoopKitTests/TempBasalRecommendationTests.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// TempBasalRecommendationTests.swift -// LoopKitTests -// -// Created by Darin Krauss on 7/27/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import XCTest - -@testable import LoopKit - -class TempBasalRecommendationTests: XCTestCase { - - func testCancel() { - let cancel = TempBasalRecommendation.cancel - XCTAssertEqual(cancel.unitsPerHour, 0) - XCTAssertEqual(cancel.duration, 0) - } - - func testInitializer() { - let tempBasalRecommendation = TempBasalRecommendation(unitsPerHour: 1.23, duration: 4.56) - XCTAssertEqual(tempBasalRecommendation.unitsPerHour, 1.23) - XCTAssertEqual(tempBasalRecommendation.duration, 4.56) - } - -} diff --git a/Dependencies/LoopKit/LoopKitTests/TemporaryScheduleOverrideHistoryTests.swift b/Dependencies/LoopKit/LoopKitTests/TemporaryScheduleOverrideHistoryTests.swift deleted file mode 100644 index 61d3e5386..000000000 --- a/Dependencies/LoopKit/LoopKitTests/TemporaryScheduleOverrideHistoryTests.swift +++ /dev/null @@ -1,280 +0,0 @@ -// -// TemporaryScheduleOverrideHistoryTests.swift -// LoopKitTests -// -// Created by Michael Pangburn on 3/25/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import LoopKit - - -final class TemporaryScheduleOverrideHistoryTests: XCTestCase { - // Midnight of an arbitrary date - let referenceDate = Calendar.current.startOfDay(for: Date(timeIntervalSinceReferenceDate: .hours(100_000))) - - let basalRateSchedule = BasalRateSchedule( - dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ], - timeZone: Calendar.current.timeZone - )! - - let history = TemporaryScheduleOverrideHistory() - - private func recordOverride( - beginningAt offset: TimeInterval, - duration: TemporaryScheduleOverride.Duration, - insulinNeedsScaleFactor scaleFactor: Double, - recordedAt enableDateOffset: TimeInterval? = nil - ) { - let settings = TemporaryScheduleOverrideSettings(unit: .milligramsPerDeciliter, targetRange: nil, insulinNeedsScaleFactor: scaleFactor) - let override = TemporaryScheduleOverride(context: .custom, settings: settings, startDate: referenceDate + offset, duration: duration, enactTrigger: .local, syncIdentifier: UUID()) - let enableDate: Date - if let enableDateOffset = enableDateOffset { - enableDate = referenceDate + enableDateOffset - } else { - enableDate = override.startDate - } - history.recordOverride(override, at: enableDate) - } - - private func recordOverrideDisable(at offset: TimeInterval) { - history.recordOverride(nil, at: referenceDate + offset) - } - - private func historyResolves(to expected: BasalRateSchedule, referenceDateOffset: TimeInterval = 0) -> Bool { - let referenceDate = self.referenceDate + referenceDateOffset - let actual = history.resolvingRecentBasalSchedule(basalRateSchedule, relativeTo: referenceDate) - return actual.equals(expected, accuracy: 1e-6) - } - - override func setUp() { - history.wipeHistory() - } - - func testEmptyHistory() { - XCTAssert(historyResolves(to: basalRateSchedule)) - } - - func testSingleOverrideNaturalEnd() { - recordOverride(beginningAt: .hours(2), duration: .finite(.hours(3)), insulinNeedsScaleFactor: 1.5) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(2), value: 1.8), - RepeatingScheduleValue(startTime: .hours(5), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ])! - - XCTAssert(historyResolves(to: expected, referenceDateOffset: .hours(3))) - } - - func testSingleOverrideEarlyEnd() { - recordOverride(beginningAt: .hours(2), duration: .finite(.hours(3)), insulinNeedsScaleFactor: 1.5) - recordOverrideDisable(at: .hours(3)) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(2), value: 1.8), - RepeatingScheduleValue(startTime: .hours(3), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ])! - - XCTAssert(historyResolves(to: expected, referenceDateOffset: .hours(3))) - } - - func testSingleIndefiniteOverrideEarlyEnd() { - recordOverride(beginningAt: .hours(2), duration: .indefinite, insulinNeedsScaleFactor: 1.5) - recordOverrideDisable(at: .hours(3)) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(2), value: 1.8), - RepeatingScheduleValue(startTime: .hours(3), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ])! - - XCTAssert(historyResolves(to: expected, referenceDateOffset: .hours(3))) - } - - func testTwoOverrides() { - recordOverride(beginningAt: .hours(2), duration: .finite(.hours(3)), insulinNeedsScaleFactor: 1.5) - recordOverride(beginningAt: .hours(6), duration: .finite(.hours(4)), insulinNeedsScaleFactor: 2.0) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(2), value: 1.8), - RepeatingScheduleValue(startTime: .hours(5), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 2.8), - RepeatingScheduleValue(startTime: .hours(10), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ])! - - XCTAssert(historyResolves(to: expected, referenceDateOffset: .hours(10))) - } - - func testThreeOverrides() { - recordOverride(beginningAt: .hours(5), duration: .finite(.hours(3)), insulinNeedsScaleFactor: 1.5) - recordOverrideDisable(at: .hours(6)) - recordOverride(beginningAt: .hours(10), duration: .finite(.hours(1)), insulinNeedsScaleFactor: 2.0) - recordOverride(beginningAt: .hours(12), duration: .finite(.hours(2)), insulinNeedsScaleFactor: 1.5) - recordOverrideDisable(at: .hours(13)) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(5), value: 1.8), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(10), value: 2.8), - RepeatingScheduleValue(startTime: .hours(11), value: 1.4), - RepeatingScheduleValue(startTime: .hours(12), value: 2.1), - RepeatingScheduleValue(startTime: .hours(13), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ])! - - XCTAssert(historyResolves(to: expected, referenceDateOffset: .hours(13))) - } - - func testOldOverrideRemoval() { - recordOverride(beginningAt: .hours(-1000), duration: .finite(.hours(1)), insulinNeedsScaleFactor: 2.0) - recordOverride(beginningAt: .hours(2), duration: .finite(.hours(3)), insulinNeedsScaleFactor: 1.5) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(2), value: 1.8), - RepeatingScheduleValue(startTime: .hours(5), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ])! - - XCTAssert(historyResolves(to: expected)) - } - - func testActiveIndefiniteOverride() { - recordOverride(beginningAt: .hours(2), duration: .finite(.hours(3)), insulinNeedsScaleFactor: 1.5) - recordOverride(beginningAt: .hours(6), duration: .indefinite, insulinNeedsScaleFactor: 2.0) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(2), value: 1.8), - RepeatingScheduleValue(startTime: .hours(5), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 2.8), - RepeatingScheduleValue(startTime: .hours(10), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ])! - - XCTAssert(historyResolves(to: expected)) - } - - func testEditActiveOverride() { - recordOverride(beginningAt: .hours(1), duration: .finite(.hours(1)), insulinNeedsScaleFactor: 1.5, recordedAt: .hours(0)) - recordOverride(beginningAt: .hours(1), duration: .finite(.hours(1)), insulinNeedsScaleFactor: 2.0, recordedAt: .hours(0.5)) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(1), value: 2.4), - RepeatingScheduleValue(startTime: .hours(2), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ])! - - XCTAssert(historyResolves(to: expected)) - } - - func testRemoveFutureOverride() { - recordOverride(beginningAt: .hours(2), duration: .finite(.hours(3)), insulinNeedsScaleFactor: 1.5, recordedAt: .hours(1)) - recordOverride(beginningAt: .hours(1), duration: .finite(.hours(1)), insulinNeedsScaleFactor: 2.0) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(1), value: 2.4), - RepeatingScheduleValue(startTime: .hours(2), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ])! - - XCTAssert(historyResolves(to: expected)) - } - - func testCancelFutureOverride() { - recordOverride(beginningAt: .hours(2), duration: .finite(.hours(3)), insulinNeedsScaleFactor: 1.5, recordedAt: .hours(1)) - recordOverrideDisable(at: .hours(1.5)) - let expected = basalRateSchedule - XCTAssert(historyResolves(to: expected)) - } - - func testMultiDayOverride() { - recordOverride(beginningAt: .hours(2), duration: .finite(.hours(68)), insulinNeedsScaleFactor: 1.5) - - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.8), - RepeatingScheduleValue(startTime: .hours(6), value: 2.1), - RepeatingScheduleValue(startTime: .hours(12), value: 1.4), - RepeatingScheduleValue(startTime: .hours(16), value: 2.1), - RepeatingScheduleValue(startTime: .hours(20), value: 1.5) - ])! - - XCTAssert(historyResolves(to: expected, referenceDateOffset: .hours(26))) - } - - func testClampedPastOverride() { - recordOverride(beginningAt: .hours(-4), duration: .finite(.hours(8)), insulinNeedsScaleFactor: 1.5) - - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.8), - RepeatingScheduleValue(startTime: .hours(4), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.5), - ])! - - XCTAssert(historyResolves(to: expected, referenceDateOffset: .hours(6))) - } - - func testCancelSequence() { - recordOverride(beginningAt: .hours(2), duration: .finite(.hours(8)), insulinNeedsScaleFactor: 1.5) - recordOverrideDisable(at: .hours(4)) - recordOverride(beginningAt: .hours(7), duration: .finite(.hours(1)), insulinNeedsScaleFactor: 1.5) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(2), value: 1.8), - RepeatingScheduleValue(startTime: .hours(4), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(7), value: 2.1), - RepeatingScheduleValue(startTime: .hours(8), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ])! - - XCTAssert(historyResolves(to: expected, referenceDateOffset: .hours(6))) - } - - func testQuery() { - var (overrides, deletedOverrides, newAnchor) = history.queryByAnchor(nil) - - XCTAssertEqual(0, overrides.count) - XCTAssertEqual(0, deletedOverrides.count) - - recordOverride(beginningAt: .hours(2), duration: .finite(.hours(8)), insulinNeedsScaleFactor: 1.5) - recordOverrideDisable(at: .hours(4)) - recordOverride(beginningAt: .hours(7), duration: .finite(.hours(1)), insulinNeedsScaleFactor: 1.5) - - (overrides, deletedOverrides, newAnchor) = history.queryByAnchor(newAnchor) - - XCTAssertEqual(0, deletedOverrides.count) - XCTAssertEqual(2, overrides.count) - - XCTAssertEqual(TimeInterval(hours: 2), overrides[0].duration.timeInterval, accuracy: 1) - } - - func testQueryOfDeletedOverrides() { - var (overrides, deletedOverrides, newAnchor) = history.queryByAnchor(nil) - - XCTAssertEqual(0, overrides.count) - XCTAssertEqual(0, deletedOverrides.count) - - recordOverride(beginningAt: .hours(2), duration: .finite(.hours(8)), insulinNeedsScaleFactor: 1.5) - recordOverrideDisable(at: .hours(1)) - - (overrides, deletedOverrides, newAnchor) = history.queryByAnchor(newAnchor) - - XCTAssertEqual(0, overrides.count) - XCTAssertEqual(1, deletedOverrides.count) - } - -} diff --git a/Dependencies/LoopKit/LoopKitTests/TemporaryScheduleOverrideTests.swift b/Dependencies/LoopKit/LoopKitTests/TemporaryScheduleOverrideTests.swift deleted file mode 100644 index afb5d72da..000000000 --- a/Dependencies/LoopKit/LoopKitTests/TemporaryScheduleOverrideTests.swift +++ /dev/null @@ -1,515 +0,0 @@ -// -// TemporaryScheduleOverrideTests.swift -// LoopKitTests -// -// Created by Michael Pangburn on 1/2/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import LoopKit - -extension TimeZone { - static var fixtureTimeZone: TimeZone { - return TimeZone(secondsFromGMT: 25200)! // -0700 - } - - static var utcTimeZone: TimeZone { - return TimeZone(secondsFromGMT: 0)! - } -} - -extension ISO8601DateFormatter { - static func fixtureFormatter(timeZone: TimeZone = .fixtureTimeZone) -> Self { - let formatter = self.init() - - formatter.formatOptions = .withInternetDateTime - formatter.formatOptions.subtract(.withTimeZone) - formatter.timeZone = timeZone - - return formatter - } -} - -class TemporaryScheduleOverrideTests: XCTestCase { - - let dateFormatter = ISO8601DateFormatter.localTimeDate() - let epsilon = 1e-6 - - let basalRateSchedule = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ])! - - private func date(at time: String) -> Date { - return dateFormatter.date(from: "2019-01-01T\(time):00")! - } - - private func basalUpOverride(start: String, end: String) -> TemporaryScheduleOverride { - return TemporaryScheduleOverride( - context: .custom, - settings: TemporaryScheduleOverrideSettings( - unit: .milligramsPerDeciliter, - targetRange: nil, - insulinNeedsScaleFactor: 1.5 - ), - startDate: date(at: start), - duration: .finite(date(at: end).timeIntervalSince(date(at: start))), - enactTrigger: .local, - syncIdentifier: UUID() - ) - } - - private func applyingActiveBasalOverride(from start: String, to end: String, on schedule: BasalRateSchedule, referenceDate: Date? = nil) -> BasalRateSchedule { - let override = basalUpOverride(start: start, end: end) - let referenceDate = referenceDate ?? override.startDate - return schedule.applyingBasalRateMultiplier(from: override, relativeTo: referenceDate) - } - - // Override start aligns with schedule item start - func testBasalRateScheduleOverrideStartTimeMatch() { - let overrideBasalSchedule = applyingActiveBasalOverride(from: "00:00", to: "01:00", on: basalRateSchedule) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.8), - RepeatingScheduleValue(startTime: .hours(1), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ])! - - XCTAssert(overrideBasalSchedule.equals(expected, accuracy: epsilon)) - } - - // Override contained fully within a schedule item - func testBasalRateScheduleOverrideContained() { - let overridden = applyingActiveBasalOverride(from: "02:00", to: "04:00", on: basalRateSchedule) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(2), value: 1.8), - RepeatingScheduleValue(startTime: .hours(4), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ])! - - XCTAssert(overridden.equals(expected, accuracy: epsilon)) - } - - // Override end aligns with schedule item start - func testBasalRateScheduleOverrideEndTimeMatch() { - let overridden = applyingActiveBasalOverride(from: "02:00", to: "06:00", on: basalRateSchedule) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(2), value: 1.8), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0) - ])! - - XCTAssert(overridden.equals(expected, accuracy: epsilon)) - } - - // Override completely encapsulates schedule item - func testBasalRateScheduleOverrideEncapsulate() { - let overridden = applyingActiveBasalOverride(from: "02:00", to: "22:00", on: basalRateSchedule) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.2), - RepeatingScheduleValue(startTime: .hours(2), value: 1.8), - RepeatingScheduleValue(startTime: .hours(6), value: 2.1), - RepeatingScheduleValue(startTime: .hours(20), value: 1.5), - RepeatingScheduleValue(startTime: .hours(22), value: 1.0), - ])! - - XCTAssert(overridden.equals(expected, accuracy: epsilon)) - } - - func testSingleBasalRateSchedule() { - let basalRateSchedule = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.0) - ])! - let overridden = applyingActiveBasalOverride(from: "08:00", to: "12:00", on: basalRateSchedule) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.0), - RepeatingScheduleValue(startTime: .hours(8), value: 1.5), - RepeatingScheduleValue(startTime: .hours(12), value: 1.0) - ])! - - XCTAssert(overridden.equals(expected, accuracy: epsilon)) - } - - func testOverrideCrossingMidnight() { - var override = basalUpOverride(start: "22:00", end: "23:00") - override.duration += .hours(5) // override goes from 10pm to 4am of the next day - - let overridden = basalRateSchedule.applyingBasalRateMultiplier(from: override, relativeTo: date(at: "22:00")) - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.8), - RepeatingScheduleValue(startTime: .hours(4), value: 1.2), - RepeatingScheduleValue(startTime: .hours(6), value: 1.4), - RepeatingScheduleValue(startTime: .hours(20), value: 1.0), - RepeatingScheduleValue(startTime: .hours(22), value: 1.5) - ])! - - XCTAssert(overridden.equals(expected, accuracy: epsilon)) - } - - func testMultiDayOverride() { - var override = basalUpOverride(start: "02:00", end: "22:00") - override.duration += .hours(48) // override goes from 2am until 10pm two days later - - let overridden = basalRateSchedule.applyingBasalRateMultiplier( - from: override, - relativeTo: date(at: "02:00") + .hours(24) - ) - - // expect full schedule override; start/end dates are too distant to have an effect - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.8), - RepeatingScheduleValue(startTime: .hours(6), value: 2.1), - RepeatingScheduleValue(startTime: .hours(20), value: 1.5) - ])! - - XCTAssert(overridden.equals(expected, accuracy: epsilon)) - } - - func testOutdatedOverride() { - let overridden = applyingActiveBasalOverride(from: "02:00", to: "04:00", on: basalRateSchedule, - referenceDate: date(at: "12:00").addingTimeInterval(.hours(24))) - let expected = basalRateSchedule - - XCTAssert(overridden.equals(expected, accuracy: epsilon)) - } - - func testFarFutureOverride() { - let overridden = applyingActiveBasalOverride(from: "10:00", to: "12:00", on: basalRateSchedule, - referenceDate: date(at: "02:00").addingTimeInterval(-.hours(24))) - let expected = basalRateSchedule - - XCTAssert(overridden.equals(expected, accuracy: epsilon)) - } - - func testIndefiniteOverride() { - var override = basalUpOverride(start: "02:00", end: "22:00") - override.duration = .indefinite - let overridden = basalRateSchedule.applyingBasalRateMultiplier(from: override, relativeTo: date(at: "02:00")) - - // expect full schedule overridden - let expected = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: .hours(0), value: 1.8), - RepeatingScheduleValue(startTime: .hours(6), value: 2.1), - RepeatingScheduleValue(startTime: .hours(20), value: 1.5) - ])! - - XCTAssert(overridden.equals(expected, accuracy: epsilon)) - } - - func testDurationIsInfinite() { - let tempOverride = TemporaryScheduleOverride(context: .legacyWorkout, - settings: .init(unit: .milligramsPerDeciliter, targetRange: DoubleRange(minValue: 120, maxValue: 150)), - startDate: Date(), - duration: .indefinite, - enactTrigger: .local, - syncIdentifier: UUID()) - XCTAssertTrue(tempOverride.duration.isInfinite) - } - - func testOverrideScheduleAnnotatingReservoirSplitsDose() { - let schedule = BasalRateSchedule(dailyItems: [ - RepeatingScheduleValue(startTime: 0, value: 0.225), - RepeatingScheduleValue(startTime: 3600.0, value: 0.18000000000000002), - RepeatingScheduleValue(startTime: 10800.0, value: 0.135), - RepeatingScheduleValue(startTime: 12689.855275034904, value: 0.15), - RepeatingScheduleValue(startTime: 21600.0, value: 0.2), - RepeatingScheduleValue(startTime: 32400.0, value: 0.2), - RepeatingScheduleValue(startTime: 50400.0, value: 0.2), - RepeatingScheduleValue(startTime: 52403.79680299759, value: 0.16000000000000003), - RepeatingScheduleValue(startTime: 63743.58014559746, value: 0.2), - RepeatingScheduleValue(startTime: 63743.58014583588, value: 0.16000000000000003), - RepeatingScheduleValue(startTime: 69968.05249071121, value: 0.2), - RepeatingScheduleValue(startTime: 69968.05249094963, value: 0.18000000000000002), - RepeatingScheduleValue(startTime: 79200.0, value: 0.225), - ])! - - let dose = DoseEntry( - type: .tempBasal, - startDate: date(at: "19:25"), - endDate: date(at: "19:30"), - value: 0.8, - unit: .units - ) - - let annotated = [dose].annotated(with: schedule) - - XCTAssertEqual(3, annotated.count) - XCTAssertEqual(dose.programmedUnits, annotated.map { $0.unitsInDeliverableIncrements }.reduce(0, +)) - } - - // MARK: - Target range tests - - func testActiveTargetRangeOverride() { - let overrideRange = DoubleRange(minValue: 120, maxValue: 140) - let overrideStart = Date() - let overrideDuration = TimeInterval(hours: 4) - let settings = TemporaryScheduleOverrideSettings(unit: .milligramsPerDeciliter, targetRange: overrideRange) - let override = TemporaryScheduleOverride(context: .custom, settings: settings, startDate: overrideStart, duration: .finite(overrideDuration), enactTrigger: .local, syncIdentifier: UUID()) - let normalRange = DoubleRange(minValue: 95, maxValue: 105) - let rangeSchedule = GlucoseRangeSchedule(unit: .milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: 0, value: normalRange)])!.applyingOverride(override) - - XCTAssertEqual(rangeSchedule.value(at: overrideStart), overrideRange) - XCTAssertEqual(rangeSchedule.value(at: overrideStart + overrideDuration / 2), overrideRange) - XCTAssertEqual(rangeSchedule.value(at: overrideStart + overrideDuration), overrideRange) - XCTAssertEqual(rangeSchedule.value(at: overrideStart + overrideDuration + .hours(2)), overrideRange) - } - - func testFutureTargetRangeOverride() { - let overrideRange = DoubleRange(minValue: 120, maxValue: 140) - let overrideStart = Date() + .hours(2) - let overrideDuration = TimeInterval(hours: 4) - let settings = TemporaryScheduleOverrideSettings(unit: .milligramsPerDeciliter, targetRange: overrideRange) - let futureOverride = TemporaryScheduleOverride(context: .custom, settings: settings, startDate: overrideStart, duration: .finite(overrideDuration), enactTrigger: .local, syncIdentifier: UUID()) - let normalRange = DoubleRange(minValue: 95, maxValue: 105) - let rangeSchedule = GlucoseRangeSchedule(unit: .milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: 0, value: normalRange)])!.applyingOverride(futureOverride) - - XCTAssertEqual(rangeSchedule.value(at: overrideStart + .minutes(-5)), normalRange) - XCTAssertEqual(rangeSchedule.value(at: overrideStart), overrideRange) - XCTAssertEqual(rangeSchedule.value(at: overrideStart + overrideDuration), overrideRange) - XCTAssertEqual(rangeSchedule.value(at: overrideStart + overrideDuration + .hours(2)), overrideRange) - } -} - -class TemporaryScheduleOverrideContextCodableTests: XCTestCase { - func testCodablePreMeal() throws { - try assertTemporaryScheduleOverrideContextCodable(.preMeal, encodesJSON: """ -{ - "context" : "preMeal" -} -""" - ) - } - - func testCodableLegacyWorkout() throws { - try assertTemporaryScheduleOverrideContextCodable(.legacyWorkout, encodesJSON: """ -{ - "context" : "legacyWorkout" -} -""" - ) - } - - func testCodablePreset() throws { - let preset = TemporaryScheduleOverridePreset(id: UUID(uuidString: "238E41EA-9576-4981-A1A4-51E10228584F")!, - symbol: "🚀", - name: "Rocket", - settings: TemporaryScheduleOverrideSettings(unit: .milligramsPerDeciliter, - targetRange: DoubleRange(minValue: 90, maxValue: 100)), - duration: .indefinite) - try assertTemporaryScheduleOverrideContextCodable(.preset(preset), encodesJSON: """ -{ - "context" : { - "preset" : { - "preset" : { - "duration" : "indefinite", - "id" : "238E41EA-9576-4981-A1A4-51E10228584F", - "name" : "Rocket", - "settings" : { - "targetRangeInMgdl" : { - "maxValue" : 100, - "minValue" : 90 - } - }, - "symbol" : "🚀" - } - } - } -} -""" - ) - } - - func testCodableCustom() throws { - try assertTemporaryScheduleOverrideContextCodable(.custom, encodesJSON: """ -{ - "context" : "custom" -} -""" - ) - } - - private func assertTemporaryScheduleOverrideContextCodable(_ original: TemporaryScheduleOverride.Context, encodesJSON string: String) throws { - let data = try encoder.encode(TestContainer(context: original)) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(TestContainer.self, from: data) - XCTAssertEqual(decoded.context, original) - } - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - return encoder - }() - - private let decoder = JSONDecoder() - - private struct TestContainer: Codable, Equatable { - let context: TemporaryScheduleOverride.Context - } -} - -class TemporaryScheduleOverrideEnactTriggerCodableTests: XCTestCase { - func testCodableLocal() throws { - try assertTemporaryScheduleOverrideEnactTriggerCodable(.local, encodesJSON: """ -{ - "enactTrigger" : "local" -} -""" - ) - } - - func testCodableRemote() throws { - try assertTemporaryScheduleOverrideEnactTriggerCodable(.remote("address"), encodesJSON: """ -{ - "enactTrigger" : { - "remote" : { - "address" : "address" - } - } -} -""" - ) - } - - private func assertTemporaryScheduleOverrideEnactTriggerCodable(_ original: TemporaryScheduleOverride.EnactTrigger, encodesJSON string: String) throws { - let data = try encoder.encode(TestContainer(enactTrigger: original)) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(TestContainer.self, from: data) - XCTAssertEqual(decoded.enactTrigger, original) - } - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - return encoder - }() - - private let decoder = JSONDecoder() - - private struct TestContainer: Codable, Equatable { - let enactTrigger: TemporaryScheduleOverride.EnactTrigger - } -} - -class TemporaryScheduleOverrideDurationCodableTests: XCTestCase { - func testCodableFinite() throws { - try assertTemporaryScheduleOverrideDurationCodable(.finite(.hours(2.5)), encodesJSON: """ -{ - "duration" : { - "finite" : { - "duration" : 9000 - } - } -} -""" - ) - } - - func testCodableIndefinite() throws { - try assertTemporaryScheduleOverrideDurationCodable(.indefinite, encodesJSON: """ -{ - "duration" : "indefinite" -} -""" - ) - } - - private func assertTemporaryScheduleOverrideDurationCodable(_ original: TemporaryScheduleOverride.Duration, encodesJSON string: String) throws { - let data = try encoder.encode(TestContainer(duration: original)) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(TestContainer.self, from: data) - XCTAssertEqual(decoded.duration, original) - } - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - return encoder - }() - - private let decoder = JSONDecoder() - - private struct TestContainer: Codable, Equatable { - let duration: TemporaryScheduleOverride.Duration - } -} - -private extension TemporaryScheduleOverride.Duration { - static func += (lhs: inout TemporaryScheduleOverride.Duration, rhs: TimeInterval) { - switch lhs { - case .finite(let interval): - lhs = .finite(interval + rhs) - case .indefinite: - return - } - } -} - -class TemporaryOverrideEndCodableTests: XCTestCase { - var dateFormatter = ISO8601DateFormatter.fixtureFormatter() - - private func date(at time: String) -> Date { - return dateFormatter.date(from: "2019-01-01T\(time):00")! - } - - func testCodableOverrideEarlyEnd() throws { - let end = End.early(date(at: "02:00")) - try assertEndCodable(end, encodesJSON: """ -{ - "end" : { - "date" : 567975600, - "type" : "early" - } -} -""" - ) - } - - func testCodableOverrideNaturalEnd() throws { - let end = End.natural - try assertEndCodable(end, encodesJSON: """ -{ - "end" : { - "type" : "natural" - } -} -""" - ) - } - - func testCodableOverrideDeleted() throws { - let end = End.deleted - try assertEndCodable(end, encodesJSON: """ -{ - "end" : { - "type" : "deleted" - } -} -""" - ) - } - - private func assertEndCodable(_ original: End, encodesJSON string: String) throws { - let data = try encoder.encode(TestContainer(end: original)) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - let decoded = try decoder.decode(TestContainer.self, from: data) - XCTAssertEqual(decoded.end, original) - } - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - return encoder - }() - - private let decoder = JSONDecoder() - - private struct TestContainer: Codable, Equatable { - let end: End - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/TherapySettingsTests.swift b/Dependencies/LoopKit/LoopKitTests/TherapySettingsTests.swift deleted file mode 100644 index 0ae51b6e0..000000000 --- a/Dependencies/LoopKit/LoopKitTests/TherapySettingsTests.swift +++ /dev/null @@ -1,331 +0,0 @@ -// -// TherapySettingsTests.swift -// LoopKitTests -// -// Created by Anna Quinlan on 7/27/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import HealthKit -@testable import LoopKit - -class TherapySettingsCodableTests: XCTestCase { - private let dateFormatter = ISO8601DateFormatter() - - private let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - encoder.dateEncodingStrategy = .iso8601 - return encoder - }() - - private let decoder: JSONDecoder = { - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return decoder - }() - - let encodedString = """ - { - "basalRateSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : 1 - }, - { - "startTime" : 28800, - "value" : 1.125 - }, - { - "startTime" : 36000, - "value" : 1.25 - }, - { - "startTime" : 43200, - "value" : 1.5 - }, - { - "startTime" : 50400, - "value" : 1.25 - }, - { - "startTime" : 57600, - "value" : 1.5 - }, - { - "startTime" : 64800, - "value" : 1.25 - }, - { - "startTime" : 75600, - "value" : 1 - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "GMT-0700" - } - }, - "carbRatioSchedule" : { - "unit" : "g", - "valueSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : 10 - }, - { - "startTime" : 28800, - "value" : 12 - }, - { - "startTime" : 36000, - "value" : 9 - }, - { - "startTime" : 43200, - "value" : 10 - }, - { - "startTime" : 50400, - "value" : 11 - }, - { - "startTime" : 57600, - "value" : 12 - }, - { - "startTime" : 64800, - "value" : 8 - }, - { - "startTime" : 75600, - "value" : 10 - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "GMT-0700" - } - } - }, - "correctionRangeOverrides" : { - "preMealRange" : { - "bloodGlucoseUnit" : "mg/dL", - "range" : { - "maxValue" : 90, - "minValue" : 80 - } - }, - "workoutRange" : { - "bloodGlucoseUnit" : "mg/dL", - "range" : { - "maxValue" : 140, - "minValue" : 130 - } - } - }, - "defaultRapidActingModel" : "rapidActingAdult", - "glucoseTargetRangeSchedule" : { - "rangeSchedule" : { - "unit" : "mg/dL", - "valueSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : { - "maxValue" : 110, - "minValue" : 100 - } - }, - { - "startTime" : 28800, - "value" : { - "maxValue" : 105, - "minValue" : 95 - } - }, - { - "startTime" : 50400, - "value" : { - "maxValue" : 105, - "minValue" : 95 - } - }, - { - "startTime" : 57600, - "value" : { - "maxValue" : 110, - "minValue" : 100 - } - }, - { - "startTime" : 64800, - "value" : { - "maxValue" : 100, - "minValue" : 90 - } - }, - { - "startTime" : 75600, - "value" : { - "maxValue" : 120, - "minValue" : 110 - } - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "GMT-0700" - } - } - } - }, - "insulinSensitivitySchedule" : { - "unit" : "mg/dL", - "valueSchedule" : { - "items" : [ - { - "startTime" : 0, - "value" : 45 - }, - { - "startTime" : 28800, - "value" : 40 - }, - { - "startTime" : 36000, - "value" : 35 - }, - { - "startTime" : 43200, - "value" : 30 - }, - { - "startTime" : 50400, - "value" : 35 - }, - { - "startTime" : 57600, - "value" : 40 - } - ], - "referenceTimeInterval" : 0, - "repeatInterval" : 86400, - "timeZone" : { - "identifier" : "GMT-0700" - } - } - }, - "maximumBasalRatePerHour" : 3, - "maximumBolus" : 5, - "suspendThreshold" : { - "unit" : "mg/dL", - "value" : 80 - } - } - """ - - func testInsulinModelEncoding() throws { - let adult = ExponentialInsulinModelPreset.rapidActingAdult - let child = ExponentialInsulinModelPreset.rapidActingChild - - XCTAssertEqual(""" - "rapidActingAdult" - """, String(data: try encoder.encode(adult), encoding: .utf8)!) - XCTAssertEqual(""" - "rapidActingChild" - """, String(data: try encoder.encode(child), encoding: .utf8)!) - } - - func testTherapySettingEncoding() throws { - let original = TherapySettings.test - let data = try encoder.encode(original) - XCTAssertEqual(encodedString, String(data: data, encoding: .utf8)!) - } - - func testTherapySettingDecoding() throws { - let data = encodedString.data(using: .utf8)! - let decoded = try decoder.decode(TherapySettings.self, from: data) - let expected = TherapySettings.test - - XCTAssertEqual(expected, decoded) - - XCTAssertEqual(decoded.basalRateSchedule, expected.basalRateSchedule) - XCTAssertEqual(decoded.insulinSensitivitySchedule, expected.insulinSensitivitySchedule) - XCTAssertEqual(decoded.correctionRangeOverrides, expected.correctionRangeOverrides) - XCTAssertEqual(decoded.maximumBolus, expected.maximumBolus) - XCTAssertEqual(decoded.maximumBasalRatePerHour, expected.maximumBasalRatePerHour) - XCTAssertEqual(decoded.suspendThreshold, expected.suspendThreshold) - XCTAssertEqual(decoded.carbRatioSchedule, expected.carbRatioSchedule) - XCTAssertEqual(decoded.defaultRapidActingModel, expected.defaultRapidActingModel) - XCTAssertEqual(decoded.glucoseTargetRangeSchedule, expected.glucoseTargetRangeSchedule) - } -} - -fileprivate extension TherapySettings { - static var test: TherapySettings { - let timeZone = TimeZone(secondsFromGMT: -25200) - let glucoseTargetRangeSchedule = GlucoseRangeSchedule( - rangeSchedule: DailyQuantitySchedule(unit: .milligramsPerDeciliter, - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: DoubleRange(minValue: 100.0, maxValue: 110.0)), - RepeatingScheduleValue(startTime: .hours(8), value: DoubleRange(minValue: 95.0, maxValue: 105.0)), - RepeatingScheduleValue(startTime: .hours(14), value: DoubleRange(minValue: 95.0, maxValue: 105.0)), - RepeatingScheduleValue(startTime: .hours(16), value: DoubleRange(minValue: 100.0, maxValue: 110.0)), - RepeatingScheduleValue(startTime: .hours(18), value: DoubleRange(minValue: 90.0, maxValue: 100.0)), - RepeatingScheduleValue(startTime: .hours(21), value: DoubleRange(minValue: 110.0, maxValue: 120.0))], - timeZone: timeZone)!) - let basalRateSchedule = BasalRateSchedule( - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 1.0), - RepeatingScheduleValue(startTime: .hours(8), value: 1.125), - RepeatingScheduleValue(startTime: .hours(10), value: 1.25), - RepeatingScheduleValue(startTime: .hours(12), value: 1.5), - RepeatingScheduleValue(startTime: .hours(14), value: 1.25), - RepeatingScheduleValue(startTime: .hours(16), value: 1.5), - RepeatingScheduleValue(startTime: .hours(18), value: 1.25), - RepeatingScheduleValue(startTime: .hours(21), value: 1.0)], - timeZone: timeZone)! - let insulinSensitivitySchedule = InsulinSensitivitySchedule( - unit: .milligramsPerDeciliter, - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 45.0), - RepeatingScheduleValue(startTime: .hours(8), value: 40.0), - RepeatingScheduleValue(startTime: .hours(10), value: 35.0), - RepeatingScheduleValue(startTime: .hours(12), value: 30.0), - RepeatingScheduleValue(startTime: .hours(14), value: 35.0), - RepeatingScheduleValue(startTime: .hours(16), value: 40.0)], - timeZone: timeZone)! - let carbRatioSchedule = CarbRatioSchedule( - unit: .gram(), - - dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 10.0), - RepeatingScheduleValue(startTime: .hours(8), value: 12.0), - RepeatingScheduleValue(startTime: .hours(10), value: 9.0), - RepeatingScheduleValue(startTime: .hours(12), value: 10.0), - RepeatingScheduleValue(startTime: .hours(14), value: 11.0), - RepeatingScheduleValue(startTime: .hours(16), value: 12.0), - RepeatingScheduleValue(startTime: .hours(18), value: 8.0), - RepeatingScheduleValue(startTime: .hours(21), value: 10.0)], - timeZone: timeZone)! - let correctionRangeOverrides = CorrectionRangeOverrides( - preMeal: DoubleRange(minValue: 80.0, maxValue: 90.0), - workout: DoubleRange(minValue: 130.0, maxValue: 140.0), - unit: .milligramsPerDeciliter) - - return TherapySettings( - glucoseTargetRangeSchedule: glucoseTargetRangeSchedule, - correctionRangeOverrides: correctionRangeOverrides, - maximumBasalRatePerHour: 3, - maximumBolus: 5, - suspendThreshold: GlucoseThreshold(unit: .milligramsPerDeciliter, value: 80), - insulinSensitivitySchedule: insulinSensitivitySchedule, - carbRatioSchedule: carbRatioSchedule, - basalRateSchedule: basalRateSchedule, - defaultRapidActingModel: ExponentialInsulinModelPreset.rapidActingAdult - ) - } -} diff --git a/Dependencies/LoopKit/LoopKitTests/VersionCheckServiceTests.swift b/Dependencies/LoopKit/LoopKitTests/VersionCheckServiceTests.swift deleted file mode 100644 index 8e1b7797b..000000000 --- a/Dependencies/LoopKit/LoopKitTests/VersionCheckServiceTests.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// VersionCheckServiceTests.swift -// LoopKitTests -// -// Created by Rick Pasetto on 9/13/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import LoopKit - -class VersionCheckServiceTests: XCTestCase { - - func testVersionUpdateOrder() throws { - // Comparable order is important for VersionUpdate. Do not reorder! - XCTAssertGreaterThan(VersionUpdate.required, VersionUpdate.recommended) - XCTAssertGreaterThan(VersionUpdate.recommended, VersionUpdate.available) - XCTAssertGreaterThan(VersionUpdate.available, VersionUpdate.none) - } - -} diff --git a/Dependencies/LoopKit/LoopKitUI/CGMManagerUI.swift b/Dependencies/LoopKit/LoopKitUI/CGMManagerUI.swift deleted file mode 100644 index a734741cd..000000000 --- a/Dependencies/LoopKit/LoopKitUI/CGMManagerUI.swift +++ /dev/null @@ -1,86 +0,0 @@ -// -// CGMManagerUI.swift -// LoopKitUI -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import HealthKit -import SwiftUI -import LoopKit - -public struct CGMManagerDescriptor { - public let identifier: String - public let localizedTitle: String - - public init(identifier: String, localizedTitle: String) { - self.identifier = identifier - self.localizedTitle = localizedTitle - } -} - -public protocol CGMStatusIndicator { - /// a message from the cgm that needs to be brought to the user's attention in the status bar - var cgmStatusHighlight: DeviceStatusHighlight? { get } - - /// the completed percent of the progress bar to display in the status bar - var cgmLifecycleProgress: DeviceLifecycleProgress? { get } - - /// a badge from the cgm that needs to be brought to the user's attention in the status bar - var cgmStatusBadge: DeviceStatusBadge? { get } - - /// gets the range category of a glucose sample using the CGM manager managed glucose thresholds - func glucoseRangeCategory(for glucose: GlucoseSampleValue) -> GlucoseRangeCategory? -} - -public typealias CGMManagerViewController = (UIViewController & CGMManagerOnboarding & CompletionNotifying) - -public protocol CGMManagerUI: CGMManager, DeviceManagerUI, DisplayGlucoseUnitObserver, CGMStatusIndicator { - /// Create and onboard a new CGM manager. - /// - /// - Parameters: - /// - bluetoothProvider: The provider of Bluetooth functionality. - /// - displayGlucoseUnitObservable: The glucose units to use for display. - /// - colorPalette: Color palette to use for any UI. - /// - Returns: Either a conforming view controller to create and onboard the CGM manager or a newly created and onboarded CGM manager. - static func setupViewController(bluetoothProvider: BluetoothProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) -> SetupUIResult - - /// Configure settings for an existing CGM manager. - /// - /// - Parameters: - /// - bluetoothProvider: The provider of Bluetooth functionality. - /// - displayGlucoseUnitObservable: The glucose units to use for display. - /// - colorPalette: Color palette to use for any UI. - /// - Returns: A view controller to configure an existing CGM manager. - func settingsViewController(bluetoothProvider: BluetoothProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) -> CGMManagerViewController -} - -extension CGMManagerUI { - public func glucoseRangeCategory(for glucose: GlucoseSampleValue) -> GlucoseRangeCategory? { - return nil - } - - /// When conformance to the DisplayGlucoseUnitObserver is desired, use this function to be notified when the user display glucose unit changes - public func displayGlucoseUnitDidChange(to displayGlucoseUnit: HKUnit) { - // optional - } -} - -public protocol CGMManagerOnboardingDelegate: AnyObject { - /// Informs the delegate that the specified CGM manager was created. - /// - /// - Parameters: - /// - cgmManager: The CGM manager created. - func cgmManagerOnboarding(didCreateCGMManager cgmManager: CGMManagerUI) - - /// Informs the delegate that the specified CGM manager was onboarded. - /// - /// - Parameters: - /// - cgmManager: The CGM manager onboarded. - func cgmManagerOnboarding(didOnboardCGMManager cgmManager: CGMManagerUI) -} - -public protocol CGMManagerOnboarding { - /// Delegate to notify about CGM manager onboarding. - var cgmManagerOnboardingDelegate: CGMManagerOnboardingDelegate? { get set } -} diff --git a/Dependencies/LoopKit/LoopKitUI/CarbKit/CustomInputTextField.swift b/Dependencies/LoopKit/LoopKitUI/CarbKit/CustomInputTextField.swift deleted file mode 100644 index befaa986d..000000000 --- a/Dependencies/LoopKit/LoopKitUI/CarbKit/CustomInputTextField.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// CustomInputTextField.swift -// LoopKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import UIKit - -public class CustomInputTextField: UITextField { - - public var customInput: UIInputViewController? - - public override var inputViewController: UIInputViewController? { - return customInput - } - -} diff --git a/Dependencies/LoopKit/LoopKitUI/CarbKit/DateAndDurationSteppableTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/CarbKit/DateAndDurationSteppableTableViewCell.swift deleted file mode 100644 index 2cee56696..000000000 --- a/Dependencies/LoopKit/LoopKitUI/CarbKit/DateAndDurationSteppableTableViewCell.swift +++ /dev/null @@ -1,95 +0,0 @@ -// -// DateAndDurationSteppableTableViewCell.swift -// LoopKitUI -// -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import UIKit - -public class DateAndDurationSteppableTableViewCell: DatePickerTableViewCell { - - public weak var delegate: DatePickerTableViewCellDelegate? - - @IBOutlet public weak var titleLabel: UILabel! - - @IBOutlet public weak var dateLabel: UILabel! { - didSet { - dateLabel.textColor = .secondaryLabel - } - } - - @IBOutlet weak var incrementButton: UIButton! - - @IBOutlet weak var decrementButton: UIButton! - - public var timeStepSize: TimeInterval = .minutes(15) - - public override var isDatePickerHidden: Bool { - didSet { - dateLabel.textColor = isDatePickerHidden ? .secondaryLabel : window?.tintColor - } - } - - private lazy var durationFormatter: DateComponentsFormatter = { - let formatter = DateComponentsFormatter() - - formatter.allowedUnits = [.hour, .minute] - formatter.unitsStyle = .short - - return formatter - }() - - private lazy var dateFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - dateFormatter.doesRelativeDateFormatting = true - dateFormatter.dateStyle = .none - dateFormatter.timeStyle = .short - - return dateFormatter - }() - - public override func updateDateLabel() { - if dateFormatter.doesRelativeDateFormatting { - dateFormatter.dateStyle = Calendar.current.isDateInToday(date) ? .none : .short - } - - switch datePicker.datePickerMode { - case .countDownTimer: - dateLabel.text = durationFormatter.string(from: duration) - case .date, .dateAndTime, .time: - dateLabel.text = dateFormatter.string(from: date) - @unknown default: - break // Do nothing - } - - updateButtonState() - } - - public override func dateChanged(_ sender: UIDatePicker) { - super.dateChanged(sender) - - delegate?.datePickerTableViewCellDidUpdateDate(self) - } - - @IBAction func incrementTime(_ sender: UIButton) { - date = date.addingTimeInterval(timeStepSize) - } - - @IBAction func decrementTime(_ sender: UIButton) { - date = date.addingTimeInterval(-timeStepSize) - } - - private func updateButtonState() { - // since the picker sets the seconds to 0, compare in the same way - if let maximumDate = datePicker.maximumDate { - let order = Calendar.current.compare(date, to: maximumDate, toGranularity: .minute) - incrementButton.isEnabled = order == .orderedAscending - } - - if let minimumDate = datePicker.minimumDate { - let order = Calendar.current.compare(date, to: minimumDate, toGranularity: .minute) - decrementButton.isEnabled = order == .orderedDescending - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/CarbKit/DateAndDurationSteppableTableViewCell.xib b/Dependencies/LoopKit/LoopKitUI/CarbKit/DateAndDurationSteppableTableViewCell.xib deleted file mode 100644 index eba7bc624..000000000 --- a/Dependencies/LoopKit/LoopKitUI/CarbKit/DateAndDurationSteppableTableViewCell.xib +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/CarbKit/DateAndDurationTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/CarbKit/DateAndDurationTableViewCell.swift deleted file mode 100644 index 5a69ec7d3..000000000 --- a/Dependencies/LoopKit/LoopKitUI/CarbKit/DateAndDurationTableViewCell.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// DateAndDurationTableViewCell.swift -// LoopKitUI -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - -public class DateAndDurationTableViewCell: DatePickerTableViewCell { - - public weak var delegate: DatePickerTableViewCellDelegate? - - @IBOutlet public weak var titleLabel: UILabel! - - @IBOutlet public weak var dateLabel: UILabel! { - didSet { - // Setting this color in code because the nib isn't being applied correctly - dateLabel.textColor = .secondaryLabel - } - } - - private lazy var durationFormatter: DateComponentsFormatter = { - let formatter = DateComponentsFormatter() - - formatter.allowedUnits = [.hour, .minute] - formatter.unitsStyle = .short - - return formatter - }() - - public override func updateDateLabel() { - switch datePicker.datePickerMode { - case .countDownTimer: - dateLabel.text = durationFormatter.string(from: duration) - case .date: - dateLabel.text = DateFormatter.localizedString(from: date, dateStyle: .medium, timeStyle: .none) - case .dateAndTime: - dateLabel.text = DateFormatter.localizedString(from: date, dateStyle: .short, timeStyle: .short) - case .time: - dateLabel.text = DateFormatter.localizedString(from: date, dateStyle: .none, timeStyle: .medium) - @unknown default: - break // Do nothing - } - } - - public override func dateChanged(_ sender: UIDatePicker) { - super.dateChanged(sender) - - delegate?.datePickerTableViewCellDidUpdateDate(self) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/CarbKit/DateAndDurationTableViewCell.xib b/Dependencies/LoopKit/LoopKitUI/CarbKit/DateAndDurationTableViewCell.xib deleted file mode 100644 index ba9acbbef..000000000 --- a/Dependencies/LoopKit/LoopKitUI/CarbKit/DateAndDurationTableViewCell.xib +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/CarbKit/DecimalTextFieldTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/CarbKit/DecimalTextFieldTableViewCell.swift deleted file mode 100644 index d4612259f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/CarbKit/DecimalTextFieldTableViewCell.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// DecimalTextFieldTableViewCell.swift -// CarbKit -// -// Created by Nathan Racklyeft on 1/15/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - -public class DecimalTextFieldTableViewCell: TextFieldTableViewCell { - - @IBOutlet weak var titleLabel: UILabel! - - var numberFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - - return formatter - }() - - public var number: NSNumber? { - get { - return numberFormatter.number(from: textField.text ?? "") - } - set { - if let value = newValue { - textField.text = numberFormatter.string(from: value) - } else { - textField.text = nil - } - } - } - - // MARK: - UITextFieldDelegate - - public override func textFieldDidEndEditing(_ textField: UITextField) { - if let number = number { - textField.text = numberFormatter.string(from: number) - } else { - textField.text = nil - } - - super.textFieldDidEndEditing(textField) - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/CarbKit/FoodEmojiDataSource.swift b/Dependencies/LoopKit/LoopKitUI/CarbKit/FoodEmojiDataSource.swift deleted file mode 100644 index 03cfe9511..000000000 --- a/Dependencies/LoopKit/LoopKitUI/CarbKit/FoodEmojiDataSource.swift +++ /dev/null @@ -1,198 +0,0 @@ -// -// FoodEmojiDataSource.swift -// LoopKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -public func CarbAbsorptionInputController() -> EmojiInputController { - return EmojiInputController.instance(withEmojis: FoodEmojiDataSource()) -} - - -private class FoodEmojiDataSource: EmojiDataSource { - private static let fast: [String] = { - var fast = [ - "🍭", // lollipop - "🧃", // juice box - "🥤", // cup with straw (soda) - "🍬", // candy - "🍯", // honey pot - "🍇", // grapes - "🫐", // blueberries - "🍈", // melon - "🍉", // watermelon - "🍊", // tangerine - "🍋", // lemon - "🍌", // banana - "🍍", // pineapple - "🍎", // red apple - "🍏", // green apple - "🍐", // pear - "🍑", // peach - "🍒", // cherries - "🍓", // strawberry - "🥝", // kiwi fruit - "🥭", // mango - "🌽", // ear of corn - "🍿", // popcorn - "🍘", // rice cracker - "🍡", // dango - "🍦", // soft ice cream - "🍧", // shaved ice - "🎂", // birthday cake - "🥠", // fortune cookie - "☕️", // coffee - "🫖" // tea - ] - - return fast - }() - - private static let medium: [String] = { - var medium = [ - "🌮", // taco - "🍟", // french fries - "🍳", // cooking - "🍲", // pot of food - "🥘", // pan of food - "🍱", // bento box - "🍛", // curry rice - "🍜", // steaming bowl (ramen / noodle soup) - "🍠", // roasted sweet potato - "🍤", // fried shrimp - "🦪", // oyster - "🍥", // fish cake with swirl - "🥪", // sandwich - "🥙", // pita sandwich - "🧆", // falafel - "🫔", // tamale - "🥫", // canned food - "🥟", // dumpling - "🥡", // takeout box - "🍢", // oden - "🍣", // sushi - "🍅", // tomato - "🥔", // potato - "🥕", // carrot - "🌶", // hot pepper - "🫑", // bell pepper - "🧅", // onion - "🧄", // garlic - "🥔", // potato - "🥒", // cucumber - "🥗", // green salad - "🥬", // leafy green - "🍄", // mushroom - "🥦", // broccoli - "🍆", // eggplant - "🫘", // beans - "🥥", // coconut - "🍞", // bread - "🥐", // croissant - "🥖", // baguette bread - "🥯", // bagel - "🫓", // flat bread - "🥨", // pretzel - "🥞", // pancakes - "🧇", // waffle - "🍙", // rice ball - "🍚", // cooked rice - "🍼", // baby bottle - "🥛", // glass of milk - "🍮", // custard - "🥧", // pie - "🍨", // ice cream - "🍩", // doughnut - "🍪", // cookie - "🧁", // cupcake - "🥮", // moon cake - "🍰", // shortcake - "🍫", // chocolate bar - "🧋", // bubble tea - ] - - return medium - }() - - private static let slow: [String] = { - var slow = [ - "🍕", // pizza - "🥑", // avocado - "🥚", // egg - "🥜", // peanuts - "🌰", // chestnut - "🧀", // cheese wedge - "🫕", // fondue - "🍖", // meat on bone - "🍗", // poultry leg - "🥓", // bacon - "🍔", // hamburger - "🌭", // hot dog - "🌯", // burrito - "🍝", // spaghetti - "🥩", // cut of meat - "🧈", // butter - "🦴", // bone - ] - - return slow - }() - - private static let other: [String] = { - var other = [ - "🍶", // sake - "🍾", // bottle with popping cork - "🍷", // wine glass - "🍸", // cocktail glass - "🍺", // beer mug - "🍻", // clinking beer mugs - "🥂", // clinking glasses - "🥃", // tumbler glass - "🍹", // tropical drink - "🧉", // mate - "🫗", // pouring liquid - "🥣", // bowl with spoon - "🥤", // cup with straw - "🥢", // chopsticks - "🍵", // teacup without handle - "🍴", // fork and knife - "🍽", // fork and knife with plate - "🥄", // spoon - "🫙", // jar - "🧊", // ice cube - "🧂", // salt - "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", - "6️⃣", "7️⃣", "8️⃣", "9️⃣", "🔟" - ] - - return other - }() - - let sections: [EmojiSection] - - init() { - sections = [ - EmojiSection( - title: LocalizedString("Fast", comment: "Section title for fast absorbing food"), - items: type(of: self).fast, - indexSymbol: " 🍭 " - ), - EmojiSection( - title: LocalizedString("Medium", comment: "Section title for medium absorbing food"), - items: type(of: self).medium, - indexSymbol: "🌮" - ), - EmojiSection( - title: LocalizedString("Slow", comment: "Section title for slow absorbing food"), - items: type(of: self).slow, - indexSymbol: "🍕" - ), - EmojiSection( - title: LocalizedString("Other", comment: "Section title for no-carb food"), - items: type(of: self).other, - indexSymbol: "⋯ " - ) - ] - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/CarbKit/FoodTypeShortcutCell.swift b/Dependencies/LoopKit/LoopKitUI/CarbKit/FoodTypeShortcutCell.swift deleted file mode 100644 index ddf320519..000000000 --- a/Dependencies/LoopKit/LoopKitUI/CarbKit/FoodTypeShortcutCell.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// FoodTypeShortcutCell.swift -// LoopKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import UIKit - -public protocol FoodTypeShortcutCellDelegate: AnyObject { - func foodTypeShortcutCellDidUpdateSelection(_ cell: FoodTypeShortcutCell) -} - - -public class FoodTypeShortcutCell: UITableViewCell { - - @IBOutlet var buttonStack: UIStackView! - - public enum SelectionState: Int { - case fast - case medium - case slow - case custom - } - - public var selectionState = SelectionState.medium { - didSet { - updateButtons() - } - } - - public weak var delegate: FoodTypeShortcutCellDelegate? - - public var selectedEmoji: String { - let selectedButton = buttonStack.arrangedSubviews[selectionState.rawValue] as! UIButton - return selectedButton.title(for: .normal)! - } - - public override func layoutSubviews() { - super.layoutSubviews() - - contentView.layoutMargins.left = separatorInset.left - contentView.layoutMargins.right = separatorInset.left - } - - func updateButtons() { - for case (let index, let button as UIButton) in buttonStack.arrangedSubviews.enumerated() { - button.isSelected = (index == selectionState.rawValue) - } - } - - @IBAction func buttonTapped(_ sender: UIButton) { - guard let index = buttonStack.arrangedSubviews.firstIndex(of: sender), - let selection = SelectionState(rawValue: index) - else { - return - } - - selectionState = selection - delegate?.foodTypeShortcutCellDidUpdateSelection(self) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/ChartColorPalette.swift b/Dependencies/LoopKit/LoopKitUI/ChartColorPalette.swift deleted file mode 100644 index 086e15e40..000000000 --- a/Dependencies/LoopKit/LoopKitUI/ChartColorPalette.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// ChartColorPalette.swift -// LoopKitUI -// -// Created by Bharat Mediratta on 3/29/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import UIKit - -/// A palette of colors for displaying charts -public struct ChartColorPalette { - public let axisLine: UIColor - public let axisLabel: UIColor - public let grid: UIColor - public let glucoseTint: UIColor - public let insulinTint: UIColor - - public init(axisLine: UIColor, axisLabel: UIColor, grid: UIColor, glucoseTint: UIColor, insulinTint: UIColor) { - self.axisLine = axisLine - self.axisLabel = axisLabel - self.grid = grid - self.glucoseTint = glucoseTint - self.insulinTint = insulinTint - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Charts/GlucoseChart.swift b/Dependencies/LoopKit/LoopKitUI/Charts/GlucoseChart.swift deleted file mode 100644 index 009ca80db..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Charts/GlucoseChart.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// GlucoseChart.swift -// LoopUI -// -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit -import LoopKit -import SwiftCharts - -open class GlucoseChart { - public init() { - } - - public var glucoseUnit: HKUnit = .milligramsPerDeciliter { - didSet { - if glucoseUnit != oldValue { - // Regenerate the glucose display points - let oldRange = glucoseDisplayRange - glucoseDisplayRange = oldRange - } - } - } - - public var glucoseDisplayRange: ClosedRange? { - didSet { - if let range = glucoseDisplayRange { - glucoseDisplayRangePoints = [ - ChartPoint(x: ChartAxisValue(scalar: 0), y: ChartAxisValueDouble(range.lowerBound.doubleValue(for: glucoseUnit))), - ChartPoint(x: ChartAxisValue(scalar: 0), y: ChartAxisValueDouble(range.upperBound.doubleValue(for: glucoseUnit))) - ] - } else { - glucoseDisplayRangePoints = [] - } - } - } - - public private(set) var glucoseDisplayRangePoints: [ChartPoint] = [] - - public func glucosePointsFromValues(_ glucoseValues: [GlucoseValue]) -> [ChartPoint] { - let unitFormatter = QuantityFormatter() - unitFormatter.unitStyle = .short - unitFormatter.setPreferredNumberFormatter(for: glucoseUnit) - let unitString = unitFormatter.string(from: glucoseUnit) - let dateFormatter = DateFormatter(timeStyle: .short) - - return glucoseValues.map { - return ChartPoint( - x: ChartAxisValueDate(date: $0.startDate, formatter: dateFormatter), - y: ChartAxisValueDoubleUnit($0.quantity.doubleValue(for: glucoseUnit), unitString: unitString, formatter: unitFormatter.numberFormatter) - ) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Charts/InsulinModelChart.swift b/Dependencies/LoopKit/LoopKitUI/Charts/InsulinModelChart.swift deleted file mode 100644 index 5fc421eec..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Charts/InsulinModelChart.swift +++ /dev/null @@ -1,140 +0,0 @@ -// -// InsulinModelChart.swift -// LoopKitUI -// -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit -import SwiftCharts -import UIKit - -public class InsulinModelChart: GlucoseChart, ChartProviding { - /// The chart points for the selected model - public private(set) var selectedInsulinModelChartPoints: [ChartPoint] = [] { - didSet { - if let lastDate = selectedInsulinModelChartPoints.last?.x as? ChartAxisValueDate { - updateEndDate(lastDate.date) - } - } - } - - public private(set) var unselectedInsulinModelChartPoints: [[ChartPoint]] = [] { - didSet { - for points in unselectedInsulinModelChartPoints { - if let lastDate = points.last?.x as? ChartAxisValueDate { - updateEndDate(lastDate.date) - } - } - } - } - - public private(set) var endDate: Date? - - private func updateEndDate(_ date: Date) { - if endDate == nil || date > endDate! { - self.endDate = date - } - } -} - -extension InsulinModelChart { - public func didReceiveMemoryWarning() { - - } - - public func generate(withFrame frame: CGRect, xAxisModel: ChartAxisModel, xAxisValues: [ChartAxisValue], axisLabelSettings: ChartLabelSettings, guideLinesLayerSettings: ChartGuideLinesLayerSettings, colors: ChartColorPalette, chartSettings: ChartSettings, labelsWidthY: CGFloat, gestureRecognizer: UIGestureRecognizer?, traitCollection: UITraitCollection) -> Chart - { - let yAxisValues = ChartAxisValuesStaticGenerator.generateYAxisValuesWithChartPoints(glucoseDisplayRangePoints, - minSegmentCount: 2, - maxSegmentCount: 5, - multiple: glucoseUnit.chartableIncrement / 2, - axisValueGenerator: { - ChartAxisValueDouble(round($0), labelSettings: axisLabelSettings) - }, - addPaddingSegmentIfEdge: false - ) - - let yAxisModel = ChartAxisModel(axisValues: yAxisValues, lineColor: colors.axisLine, labelSpaceReservationMode: .fixed(labelsWidthY)) - - let coordsSpace = ChartCoordsSpaceLeftBottomSingleAxis( - chartSettings: chartSettings, - chartFrame: frame, - xModel: xAxisModel, - yModel: yAxisModel - ) - - // Grid lines - let gridLayer = ChartGuideLinesForValuesLayer( - xAxis: coordsSpace.xAxisLayer.axis, - yAxis: coordsSpace.yAxisLayer.axis, - settings: guideLinesLayerSettings, - axisValuesX: Array(xAxisValues.dropFirst().dropLast()), - axisValuesY: yAxisValues - ) - - // Selected line - var selectedLayer: ChartLayer? - - if selectedInsulinModelChartPoints.count > 1 { - let lineModel = ChartLineModel.predictionLine( - points: selectedInsulinModelChartPoints, - color: colors.glucoseTint, - width: 2 - ) - - selectedLayer = ChartPointsLineLayer( - xAxis: coordsSpace.xAxisLayer.axis, - yAxis: coordsSpace.yAxisLayer.axis, - lineModels: [lineModel] - ) - } - - var unselectedLineModels = [ChartLineModel]() - - for points in unselectedInsulinModelChartPoints where points.count > 1 { - unselectedLineModels.append(ChartLineModel.predictionLine( - points: points, - color: UIColor.secondaryLabel, - width: 1 - )) - } - - // Unselected lines - var unselectedLayer: ChartLayer? - - if !unselectedLineModels.isEmpty { - unselectedLayer = ChartPointsLineLayer( - xAxis: coordsSpace.xAxisLayer.axis, - yAxis: coordsSpace.yAxisLayer.axis, - lineModels: unselectedLineModels - ) - } - - let layers: [ChartLayer?] = [ - gridLayer, - coordsSpace.xAxisLayer, - coordsSpace.yAxisLayer, - unselectedLayer, - selectedLayer - ] - - return Chart( - frame: frame, - innerFrame: coordsSpace.chartInnerFrame, - settings: chartSettings, - layers: layers.compactMap { $0 } - ) - } -} - -extension InsulinModelChart { - public func setSelectedInsulinModelValues(_ values: [GlucoseValue]) { - self.selectedInsulinModelChartPoints = glucosePointsFromValues(values) - } - - public func setUnselectedInsulinModelValues(_ values: [[GlucoseValue]]) { - self.unselectedInsulinModelChartPoints = values.map(glucosePointsFromValues) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/CompletionNotifying.swift b/Dependencies/LoopKit/LoopKitUI/CompletionNotifying.swift deleted file mode 100644 index 39fa06e1d..000000000 --- a/Dependencies/LoopKit/LoopKitUI/CompletionNotifying.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// CompletionNotifying.swift -// LoopKitUI -// -// Created by Pete Schwamb on 1/29/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - -public protocol CompletionDelegate: AnyObject { - func completionNotifyingDidComplete(_ object: CompletionNotifying) -} - -public protocol CompletionNotifying { - var completionDelegate: CompletionDelegate? { set get } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/DeviceManagerUI.swift b/Dependencies/LoopKit/LoopKitUI/DeviceManagerUI.swift deleted file mode 100644 index b7a98d1da..000000000 --- a/Dependencies/LoopKit/LoopKitUI/DeviceManagerUI.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// DeviceManagerUI.swift -// LoopKitUI -// -// Created by Rick Pasetto on 6/30/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import LoopKit -import UIKit - -public protocol DeviceManagerUI: DeviceManager { - /// An image representing a generalized device. Used during onboarding. - static var onboardingImage: UIImage? { get } - - /// An image representing a device configuration after it is set up - var smallImage: UIImage? { get } -} diff --git a/Dependencies/LoopKit/LoopKitUI/DeviceStatusBadge.swift b/Dependencies/LoopKit/LoopKitUI/DeviceStatusBadge.swift deleted file mode 100644 index 8755ef4e1..000000000 --- a/Dependencies/LoopKit/LoopKitUI/DeviceStatusBadge.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// DeviceStatusBadge.swift -// LoopKit -// -// Created by Nathaniel Hamming on 2021-02-16. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit - -public protocol DeviceStatusBadge { - - /// the image to present as the badge - var image: UIImage? { get } - - /// the state of the status badge (guides presentation) - var state: DeviceStatusBadgeState { get } -} - -public typealias DeviceStatusBadgeState = DeviceStatusElementState diff --git a/Dependencies/LoopKit/LoopKitUI/DisplayGlucoseUnitObserver.swift b/Dependencies/LoopKit/LoopKitUI/DisplayGlucoseUnitObserver.swift deleted file mode 100644 index 09c6a11e4..000000000 --- a/Dependencies/LoopKit/LoopKitUI/DisplayGlucoseUnitObserver.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// DisplayGlucoseUnitObserver.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2021-01-13. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - -public protocol DisplayGlucoseUnitObserver { - func displayGlucoseUnitDidChange(to displayGlucoseUnit: HKUnit) -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/Binding.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/Binding.swift deleted file mode 100644 index c85f16b7d..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/Binding.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// Binding.swift -// LoopKitUI -// -// Created by Michael Pangburn on 5/13/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit - - -extension Binding where Value == Double { - func withUnit(_ unit: HKUnit) -> Binding { - Binding( - get: { HKQuantity(unit: unit, doubleValue: self.wrappedValue) }, - set: { self.wrappedValue = $0.doubleValue(for: unit) } - ) - } -} - -extension Binding where Value == HKQuantity { - func doubleValue(for unit: HKUnit) -> Binding { - Binding( - get: { self.wrappedValue.doubleValue(for: unit) }, - set: { self.wrappedValue = HKQuantity(unit: unit, doubleValue: $0) } - ) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/ChartLineModel+LoopKitUI.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/ChartLineModel+LoopKitUI.swift deleted file mode 100644 index 20e5fe826..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/ChartLineModel+LoopKitUI.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// ChartLineModel.swift -// Loop -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import SwiftCharts -import UIKit - -extension ChartLineModel { - /// Creates a model configured with the dashed prediction line style - /// - /// - Parameters: - /// - points: The points to construct the line - /// - color: The line color - /// - width: The line width - /// - Returns: A new line model - static func predictionLine(points: [T], color: UIColor, width: CGFloat) -> ChartLineModel { - // TODO: Bug in ChartPointsLineLayer requires a non-zero animation to draw the dash pattern - return self.init(chartPoints: points, lineColor: color, lineWidth: width, animDuration: 0.0001, animDelay: 0, dashPattern: [6, 5]) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/ChartSettings+LoopKitUI.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/ChartSettings+LoopKitUI.swift deleted file mode 100644 index 08b92caa1..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/ChartSettings+LoopKitUI.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// ChartSettings+LoopKitUI.swift -// LoopKitUI -// -// Created by Anna Quinlan on 7/20/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftCharts - - -extension ChartSettings { - static var `default`: ChartSettings { - var settings = ChartSettings() - settings.top = 12 - settings.bottom = 0 - settings.trailing = 8 - settings.axisTitleLabelsToLabelsSpacing = 0 - settings.labelsToAxisSpacingX = 6 - settings.clipInnerFrame = false - return settings - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/Collection.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/Collection.swift deleted file mode 100644 index c37a84c4e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/Collection.swift +++ /dev/null @@ -1,98 +0,0 @@ -// -// Collection.swift -// LoopKit -// -// Created by Michael Pangburn on 2/14/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -/// Returns the cartesian product of a sequence and a collection. -/// -/// O(1), but O(_n_*_m_) on iteration. -/// - Note: Don't mind the scary return type; it's just a lazy sequence. -func product(_ s: S, _ c: C) -> LazySequence>>> { - return s.lazy.flatMap { first in - c.lazy.map { second in - (first, second) - } - } -} - -extension Collection { - /// Returns a sequence containing adjacent pairs of elements in the ordered collection. - func adjacentPairs() -> Zip2Sequence { - return zip(self, dropFirst()) - } -} - -extension Collection { - func chunked(into size: Int) -> [SubSequence] { - precondition(size > 0, "Chunk size must be greater than zero") - var start = startIndex - return stride(from: 0, to: count, by: size).map {_ in - let end = index(start, offsetBy: size, limitedBy: endIndex) ?? endIndex - defer { start = end } - return self[start.. LazyMapSequence>>>, (Element, Element)> { - return product(indices, indices).filter(<).map { - (self[$0], self[$1]) - } - } -} - -extension RangeReplaceableCollection where Index: Hashable { - /// Removes the elements at all of the given indices. - /// - /// O(_n_*_m_) - mutating func removeAll(at indices: S) where S.Element == Index { - let arranged = Set(indices).sorted(by: >) - for index in arranged { - remove(at: index) - } - } -} - -// Source: https://github.com/apple/swift/blob/master/stdlib/public/core/CollectionAlgorithms.swift#L476 -extension Collection { - /// Returns the index of the first element in the collection that matches - /// the predicate. - /// - /// The collection must already be partitioned according to the predicate. - /// That is, there should be an index `i` where for every element in - /// `collection[.. Bool - ) rethrows -> Index { - var n = count - var l = startIndex - - while n > 0 { - let half = n / 2 - let mid = index(l, offsetBy: half) - if try predicate(self[mid]) { - n = half - } else { - l = index(after: mid) - n -= half + 1 - } - } - return l - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/Color.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/Color.swift deleted file mode 100644 index 5f23f3ace..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/Color.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// Color.swift -// LoopKitUI -// -// Created by Pete Schwamb on 1/3/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -private class LocalBundle { - /// Returns the resource bundle associated with the current Swift module. - static var main: Bundle = { - if let mainResourceURL = Bundle.main.resourceURL, - let bundle = Bundle(url: mainResourceURL.appendingPathComponent("LoopKitUI_LoopKitUI.bundle")) - { - return bundle - } - return Bundle(for: LocalBundle.self) - }() -} - -extension Color { - init?(frameworkColor name: String) { - self.init(name, bundle: LocalBundle.main) - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/Comparable.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/Comparable.swift deleted file mode 100644 index 8ffc4dcaa..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/Comparable.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// Comparable.swift -// LoopKit -// -// Created by Michael Pangburn on 11/20/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -extension Comparable { - func clamped(to range: ClosedRange) -> Self { - if self < range.lowerBound { - return range.lowerBound - } else if self > range.upperBound { - return range.upperBound - } else { - return self - } - } - - mutating func clamp(to range: ClosedRange) { - self = clamped(to: range) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/Data.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/Data.swift deleted file mode 100644 index e92db3921..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/Data.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// NSData.swift -// LoopKit -// -// Created by Nate Racklyeft on 8/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -// String conversion methods, adapted from https://stackoverflow.com/questions/40276322/hex-binary-string-conversion-in-swift/40278391#40278391 -extension Data { - init?(hexadecimalString: String) { - self.init(capacity: hexadecimalString.utf16.count / 2) - - // Convert 0 ... 9, a ... f, A ...F to their decimal value, - // return nil for all other input characters - func decodeNibble(u: UInt16) -> UInt8? { - switch u { - case 0x30 ... 0x39: // '0'-'9' - return UInt8(u - 0x30) - case 0x41 ... 0x46: // 'A'-'F' - return UInt8(u - 0x41 + 10) // 10 since 'A' is 10, not 0 - case 0x61 ... 0x66: // 'a'-'f' - return UInt8(u - 0x61 + 10) // 10 since 'a' is 10, not 0 - default: - return nil - } - } - - var even = true - var byte: UInt8 = 0 - for c in hexadecimalString.utf16 { - guard let val = decodeNibble(u: c) else { return nil } - if even { - byte = val << 4 - } else { - byte += val - self.append(byte) - } - even = !even - } - guard even else { return nil } - } - - var hexadecimalString: String { - return map { String(format: "%02hhx", $0) }.joined() - } -} - -extension Data { - static func newPumpEventIdentifier() -> Data { - return Data(UUID().uuidString.utf8) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/DateFormatter.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/DateFormatter.swift deleted file mode 100644 index 155a65b43..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/DateFormatter.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// DateFormatter.swift -// LoopKitUI -// -// Created by Anna Quinlan on 7/7/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension DateFormatter { - convenience init(dateStyle: Style = .none, timeStyle: Style = .none) { - self.init() - self.dateStyle = dateStyle - self.timeStyle = timeStyle - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/Dictionary.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/Dictionary.swift deleted file mode 100644 index f114786c7..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/Dictionary.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// Dictionary.swift -// LoopKitUI -// -// Created by Michael Pangburn on 7/7/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -extension Dictionary { - func compactMapValuesWithKeys(_ transform: (Element) throws -> NewValue?) rethrows -> [Key: NewValue] { - try reduce(into: [:]) { result, element in - if let newValue = try transform(element) { - result[element.key] = newValue - } - } - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/Environment+AppName.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/Environment+AppName.swift deleted file mode 100644 index cbfc88f72..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/Environment+AppName.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// Environment+AppName.swift -// LoopUI -// -// Created by Rick Pasetto on 7/1/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -private struct AppNameKey: EnvironmentKey { - // Reasonable default value, but the expectation is that this is overridden by the clients of LoopKit, e.g. - // MyView().environment(\.appName, Bundle.main.bundleDisplayName) - static let defaultValue = "Loop" -} - -public extension EnvironmentValues { - var appName: String { - get { self[AppNameKey.self] } - set { self[AppNameKey.self] = newValue } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/Environment+Authenticate.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/Environment+Authenticate.swift deleted file mode 100644 index 8dff88ded..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/Environment+Authenticate.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// Environment+Authenticate.swift -// LoopKitUI -// -// Created by Rick Pasetto on 8/3/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import LocalAuthentication -import SwiftUI - -public typealias AuthenticationChallenge = (_ description: String, _ completion: @escaping (Result) -> Void) -> Void - -fileprivate struct UnknownError: Swift.Error { } - -public struct LocalAuthentication { - public static let deviceOwnerCheck: AuthenticationChallenge = { authenticationChallengeDescription, completion in - let context = LAContext() - var error: NSError? - if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) { - context.evaluatePolicy(.deviceOwnerAuthentication, - localizedReason: authenticationChallengeDescription, - reply: { (success, error) in - DispatchQueue.main.async { - assert(success || error != nil) - completion(success ? .success(()) : .failure(error ?? UnknownError())) - } - }) - } else { - // The logic here is to not fail to execute completion just because there is no authentication set up on the iPhone - completion(.success(())) - } - } -} - -private struct AuthenticationChallengeKey: EnvironmentKey { - static let defaultValue: AuthenticationChallenge = LocalAuthentication.deviceOwnerCheck -} - -extension EnvironmentValues { - public var authenticate: AuthenticationChallenge { - get { self[AuthenticationChallengeKey.self] } - set { self[AuthenticationChallengeKey.self] = newValue } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/Environment+Colors.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/Environment+Colors.swift deleted file mode 100644 index 092c5bf9f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/Environment+Colors.swift +++ /dev/null @@ -1,121 +0,0 @@ -// -// Environment+Colors.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-07-29. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - -private struct ColorPaletteKey: EnvironmentKey { - static let defaultValue: LoopUIColorPalette = LoopUIColorPalette(guidanceColors: GuidanceColorsKey.defaultValue, - carbTintColor: CarbTintColorKey.defaultValue, - glucoseTintColor: GlucoseTintColorKey.defaultValue, - insulinTintColor: InsulinTintColorKey.defaultValue, - loopStatusColorPalette: LoopStatusColorPaletteKey.defaultValue, - chartColorPalette: ChartColorPaletteKey.defaultValue) -} - -public extension EnvironmentValues { - var colorPalette: LoopUIColorPalette { - get { self[ColorPaletteKey.self] } - set { self[ColorPaletteKey.self] = newValue } - } -} - -private struct GuidanceColorsKey: EnvironmentKey { - static let defaultValue: GuidanceColors = GuidanceColors() -} - -public extension EnvironmentValues { - var guidanceColors: GuidanceColors { - get { self[GuidanceColorsKey.self] } - set { self[GuidanceColorsKey.self] = newValue } - } -} - -private struct CarbTintColorKey: EnvironmentKey { - static let defaultValue: Color = .green -} - -public extension EnvironmentValues { - var carbTintColor: Color { - get { self[CarbTintColorKey.self] } - set { self[CarbTintColorKey.self] = newValue } - } -} - -private struct GlucoseTintColorKey: EnvironmentKey { - static let defaultValue: Color = Color(.systemTeal) -} - -public extension EnvironmentValues { - var glucoseTintColor: Color { - get { self[GlucoseTintColorKey.self] } - set { self[GlucoseTintColorKey.self] = newValue } - } -} - -private struct InsulinTintColorKey: EnvironmentKey { - static let defaultValue: Color = .orange -} - -public extension EnvironmentValues { - var insulinTintColor: Color { - get { self[InsulinTintColorKey.self] } - set { self[InsulinTintColorKey.self] = newValue } - } -} - -private struct LightInsulinTintColorKey: EnvironmentKey { - static let defaultValue: UIColor = .lightenedInsulin -} - -public extension EnvironmentValues { - var lightenedInsulinTintColor: UIColor { - get { self[LightInsulinTintColorKey.self] } - set { self[LightInsulinTintColorKey.self] = newValue } - } -} - -private struct DarkInsulinTintColorKey: EnvironmentKey { - static let defaultValue: UIColor = .darkenedInsulin -} - -public extension EnvironmentValues { - var darkenedInsulinTintColor: UIColor { - get { self[DarkInsulinTintColorKey.self] } - set { self[DarkInsulinTintColorKey.self] = newValue } - } -} - -private struct LoopStatusColorPaletteKey: EnvironmentKey { - static let defaultValue: StateColorPalette = StateColorPalette(unknown: .systemGray4, - normal: .green, - warning: .yellow, - error: .red) -} - -public extension EnvironmentValues { - var loopStatusColorPalette: StateColorPalette { - get { self[LoopStatusColorPaletteKey.self] } - set { self[LoopStatusColorPaletteKey.self] = newValue } - } -} - -private struct ChartColorPaletteKey: EnvironmentKey { - static let defaultValue: ChartColorPalette = ChartColorPalette(axisLine: .clear, - axisLabel: .secondaryLabel, - grid: .systemGray3, - glucoseTint: .systemTeal, - insulinTint: .orange) -} - -public extension EnvironmentValues { - var chartColorPalette: ChartColorPalette { - get { self[ChartColorPaletteKey.self] } - set { self[ChartColorPaletteKey.self] = newValue } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/Environment+Dismiss.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/Environment+Dismiss.swift deleted file mode 100644 index 86e778c6f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/Environment+Dismiss.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// Environment+Dismiss.swift -// Loop -// -// Created by Michael Pangburn on 4/15/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -private struct PresentationDismissalKey: EnvironmentKey { - static let defaultValue = {} -} - - -extension EnvironmentValues { - public var dismissAction: () -> Void { - get { self[PresentationDismissalKey.self] } - set { self[PresentationDismissalKey.self] = newValue } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/GlucoseTrend.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/GlucoseTrend.swift deleted file mode 100644 index 27baa1f5d..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/GlucoseTrend.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// GlucoseTrend.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-07-15. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - -extension GlucoseTrend { - public var image: UIImage? { - switch self { - case .upUpUp: - return UIImage(frameworkImage: "arrow.double.up.circle") - case .upUp: - return UIImage(systemName: "arrow.up.circle") - case .up: - return UIImage(systemName: "arrow.up.right.circle") - case .flat: - return UIImage(systemName: "arrow.right.circle") - case .down: - return UIImage(systemName: "arrow.down.right.circle") - case .downDown: - return UIImage(systemName: "arrow.down.circle") - case .downDownDown: - return UIImage(frameworkImage: "arrow.double.down.circle") - } - } - - public var filledImage: Image { - switch self { - case .upUpUp: - return Image(frameworkImage: "arrow.double.up.fill") - case .upUp: - return Image(systemName: "arrow.up.circle.fill") - case .up: - return Image(systemName: "arrow.up.right.circle.fill") - case .flat: - return Image(systemName: "arrow.right.circle.fill") - case .down: - return Image(systemName: "arrow.down.right.circle.fill") - case .downDown: - return Image(systemName: "arrow.down.circle.fill") - case .downDownDown: - return Image(frameworkImage: "arrow.double.down.fill") - } - } - -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/Guardrail+UI.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/Guardrail+UI.swift deleted file mode 100644 index 913f8865f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/Guardrail+UI.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// Guardrail+UI.swift -// LoopKitUI -// -// Created by Michael Pangburn on 7/15/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - - -extension Guardrail where Value == HKQuantity { - func color(for quantity: HKQuantity, - guidanceColors: GuidanceColors) -> Color - { - switch classification(for: quantity) { - case .withinRecommendedRange: - return guidanceColors.acceptable - case .outsideRecommendedRange(let threshold): - switch threshold { - case .minimum, .maximum: - return guidanceColors.critical - case .belowRecommended, .aboveRecommended: - return guidanceColors.warning - } - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/HKUnit.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/HKUnit.swift deleted file mode 100644 index a5f77cdd0..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/HKUnit.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// HKUnit.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/17/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -extension HKUnit { - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: .literUnit(with: .deci)) - }() - - static let millimolesPerLiter: HKUnit = { - return HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: .liter()) - }() - - static let milligramsPerDeciliterPerMinute: HKUnit = { - return HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) - }() - - static let millimolesPerLiterPerMinute: HKUnit = { - return HKUnit.millimolesPerLiter.unitDivided(by: .minute()) - }() - - static let internationalUnitsPerHour: HKUnit = { - return HKUnit.internationalUnit().unitDivided(by: .hour()) - }() - - static let gramsPerUnit: HKUnit = { - return HKUnit.gram().unitDivided(by: .internationalUnit()) - }() - - var foundationUnit: Unit? { - if self == HKUnit.milligramsPerDeciliter { - return UnitConcentrationMass.milligramsPerDeciliter - } - - if self == HKUnit.millimolesPerLiter { - return UnitConcentrationMass.millimolesPerLiter(withGramsPerMole: HKUnitMolarMassBloodGlucose) - } - - if self == HKUnit.gram() { - return UnitMass.grams - } - - return nil - } - - /// The smallest value expected to be visible on a chart - var chartableIncrement: Double { - if self == .milligramsPerDeciliter { - return 1 - } else { - return 1 / 25 - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/IdentifiableClass.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/IdentifiableClass.swift deleted file mode 100644 index d0bf7f297..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/IdentifiableClass.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// IdentifiableClass.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -protocol IdentifiableClass: AnyObject { - static var className: String { get } -} - - -extension IdentifiableClass { - static var className: String { - return NSStringFromClass(self).components(separatedBy: ".").last! - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/Image.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/Image.swift deleted file mode 100644 index 2e7dc84f4..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/Image.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// Image.swift -// DashKitUI -// -// Created by Pete Schwamb on 2/7/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -private class LocalBundle { - /// Returns the resource bundle associated with the current Swift module. - static var main: Bundle = { - if let mainResourceURL = Bundle.main.resourceURL, - let bundle = Bundle(url: mainResourceURL.appendingPathComponent("LoopKitUI_LoopKitUI.bundle")) - { - return bundle - } - return Bundle(for: LocalBundle.self) - }() -} - -extension Image { - init(frameworkImage name: String, decorative: Bool = false) { - if decorative { - self.init(decorative: name, bundle: LocalBundle.main) - } else { - self.init(name, bundle: LocalBundle.main) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/Keyboard.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/Keyboard.swift deleted file mode 100644 index 182217e4c..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/Keyboard.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// Keyboard.swift -// LoopKitUI -// -// Created by Michael Pangburn on 7/18/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Combine -import UIKit - - -public final class Keyboard: ObservableObject { - public struct State { - public var height: CGFloat = 0 - public var animationDuration: TimeInterval = 0.25 - } - - @Published var state = State() - private var keyboardFrameChangeCancellable: AnyCancellable? - - static let shared = Keyboard() - - private init() { - keyboardFrameChangeCancellable = NotificationCenter.default - .publisher(for: UIResponder.keyboardWillChangeFrameNotification) - .receive(on: DispatchQueue.main) - .sink { [weak self] notification in - guard let self = self, let userInfo = notification.userInfo else { - return - } - - let height: CGFloat - if let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect { - height = UIScreen.main.bounds.intersection(keyboardFrame).height - } else { - height = 0 - } - - let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double ?? 0.25 - - self.state = State(height: height, animationDuration: animationDuration) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/Math.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/Math.swift deleted file mode 100644 index 4cef8fd6e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/Math.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// Math.swift -// LoopKitUI -// -// Created by Michael Pangburn on 3/23/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - - -func fractionThrough( - _ value: Metric, - in range: ClosedRange, - using transform: (Metric) -> Metric = { $0 } -) -> Metric { - let transformedLowerBound = transform(range.lowerBound) - return (transform(value) - transformedLowerBound) / (transform(range.upperBound) - transformedLowerBound) -} - -func interpolatedValue( - at fraction: Metric, - through range: ClosedRange -) -> Metric { - fraction * (range.upperBound - range.lowerBound) + range.lowerBound -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/NSTimeInterval.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/NSTimeInterval.swift deleted file mode 100644 index a568b77b8..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/NSTimeInterval.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// NSTimeInterval.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension TimeInterval { - static func minutes(_ minutes: Double) -> TimeInterval { - return self.init(minutes: minutes) - } - - static func hours(_ hours: Double) -> TimeInterval { - return self.init(hours: hours) - } - - init(minutes: Double) { - self.init(minutes * 60) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - var minutes: Double { - return self / 60.0 - } - - var hours: Double { - return minutes / 60.0 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/NibLoadable.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/NibLoadable.swift deleted file mode 100644 index 475c0f988..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/NibLoadable.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// NibLoadable.swift -// LoopKit -// -// Created by Nate Racklyeft on 7/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -protocol NibLoadable: IdentifiableClass { - static func nib() -> UINib -} - - -extension NibLoadable { - static func nib() -> UINib { - return UINib(nibName: className, bundle: Bundle(for: self)) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/NumberFormatter.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/NumberFormatter.swift deleted file mode 100644 index 6d9d3ab78..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/NumberFormatter.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// NSNumberFormatter.swift -// Loop -// -// Created by Nate Racklyeft on 9/5/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -extension NumberFormatter { - func string(from number: Double) -> String? { - return string(from: NSNumber(value: number)) - } - - func string(from number: Double, unit: String, style: Formatter.UnitStyle = .medium, avoidLineBreaking: Bool = true) -> String? { - guard let stringValue = string(from: number) else { - return nil - } - - let separator: String - switch style { - case .long: - separator = " " - case .medium: - separator = avoidLineBreaking ? .nonBreakingSpace : " " - case .short: - fallthrough - @unknown default: - separator = avoidLineBreaking ? .wordJoiner : "" - } - - let unit = avoidLineBreaking ? unit.replacingOccurrences(of: "/", with: "\(String.wordJoiner)/\(String.wordJoiner)") : unit - - return String( - format: LocalizedString("%1$@%2$@%3$@", comment: "String format for value with units (1: value, 2: separator, 3: units)"), - stringValue, - separator, - unit - ) - } -} - -public extension String { - static let nonBreakingSpace = "\u{00a0}" - static let wordJoiner = "\u{2060}" -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/OrientationLock.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/OrientationLock.swift deleted file mode 100644 index 92ca29231..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/OrientationLock.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// OrientationLock.swift -// LoopKitUI -// -// Created by Michael Pangburn on 7/28/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -public protocol DeviceOrientationController: AnyObject { - var supportedInterfaceOrientations: UIInterfaceOrientationMask { get set } - func setDefaultSupportedInferfaceOrientations() -} - -/// Use the `supportedInterfaceOrientations` modifier on a SwiftUI view to lock its orientation. -/// To function, `OrientationLock.deviceOrientationController` must be assigned prior to use. -public final class OrientationLock { - /// The global controller for device orientation. - /// The property must be assigned prior to instantiating any OrientationLock. - public static weak var deviceOrientationController: DeviceOrientationController? - - fileprivate init(_ supportedInterfaceOrientations: UIInterfaceOrientationMask) { - guard let deviceOrientationController = Self.deviceOrientationController else { - assertionFailure("OrientationLock.deviceOrientationController must be assigned prior to constructing an OrientationLock") - return - } - - deviceOrientationController.supportedInterfaceOrientations = supportedInterfaceOrientations - } - - func setDefaultSupportedInferfaceOrientations() { - Self.deviceOrientationController?.setDefaultSupportedInferfaceOrientations() - } -} - -extension View { - /// Use the `supportedInterfaceOrientations` modifier on a SwiftUI view to lock its orientation. - /// To function, `OrientationLock.deviceOrientationController` must be assigned prior to use. - public func supportedInterfaceOrientations(_ supportedInterfaceOrientations: UIInterfaceOrientationMask) -> some View { - OrientationLocked(supportedInterfaceOrientations: supportedInterfaceOrientations, content: self) - } -} - -private struct OrientationLocked: View { - // Annotated with `@State` to ensure SwiftUI keeps the object alive for the duration of the view's lifetime - @State var orientationLock: OrientationLock - var content: Content - - init(supportedInterfaceOrientations: UIInterfaceOrientationMask, content: Content) { - self._orientationLock = State(wrappedValue: OrientationLock(supportedInterfaceOrientations)) - self.content = content - } - - // when view disappears, it reverts to the originally support orientations - var body: some View { - content - .onDisappear { orientationLock.setDefaultSupportedInferfaceOrientations() } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/QuantityFormatter+Guardrails.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/QuantityFormatter+Guardrails.swift deleted file mode 100644 index 59c16c747..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/QuantityFormatter+Guardrails.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// QuantityFormatter+Guardrails.swift -// LoopKitUI -// -// Created by Rick Pasetto on 11/30/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import HealthKit -import LoopKit - -fileprivate let mgdLFormatter = QuantityFormatter() -fileprivate let mmolLFormatter: QuantityFormatter = { - let result = QuantityFormatter() - result.numberFormatter.maximumFractionDigits = 1 - return result -}() - -extension HKQuantity { - // TODO: pass in preferredUnit instead of having both units. - var bothUnitsString: String { - String(format: "%1$@ (%2$@)", - mgdLFormatter.string(from: self, for: .milligramsPerDeciliter)!, - mmolLFormatter.string(from: self, for: .millimolesPerLiter)!) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/TimeZone.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/TimeZone.swift deleted file mode 100644 index 4b912b912..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/TimeZone.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// TimeZone.swift -// LoopKit -// -// Created by Nate Racklyeft on 10/2/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - - -extension TimeZone { - static var currentFixed: TimeZone { - return TimeZone(secondsFromGMT: TimeZone.current.secondsFromGMT())! - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/UIFont.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/UIFont.swift deleted file mode 100644 index e7d40cace..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/UIFont.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// UIFont.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-01-17. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import UIKit - -extension UIFont { - public static var titleFontGroupedInset: UIFont { - return UIFontMetrics(forTextStyle: .title1).scaledFont(for: systemFont(ofSize: 28, weight: .semibold)) - } - - public static var sectionHeaderFontGroupedInset: UIFont { - return UIFontMetrics(forTextStyle: .headline).scaledFont(for: systemFont(ofSize: 19, weight: .semibold)) - } - - public static var footnote: UIFont { - return preferredFont(forTextStyle: .footnote) - } - - public static var instructionTitle: UIFont { - return preferredFont(forTextStyle: .headline) - } - - public static var instructionStep: UIFont { - return UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: systemFont(ofSize: 14)) - } - - public static var instructionNumber: UIFont { - return preferredFont(forTextStyle: .subheadline) - } - - public static var inputValue: UIFont { - return UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: systemFont(ofSize: 48)) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/UIImage.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/UIImage.swift deleted file mode 100644 index fbf28cc6a..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/UIImage.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// UIImage.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-07-15. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import UIKit - -private class LocalBundle { - /// Returns the resource bundle associated with the current Swift module. - static var main: Bundle = { - if let mainResourceURL = Bundle.main.resourceURL, - let bundle = Bundle(url: mainResourceURL.appendingPathComponent("LoopKitUI_LoopKitUI.bundle")) - { - return bundle - } - return Bundle(for: LocalBundle.self) - }() -} - -extension UIImage { - convenience init?(frameworkImage name: String) { - self.init(named: name, in: LocalBundle.main, with: nil) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/UITableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/UITableViewCell.swift deleted file mode 100644 index dd26055d0..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/UITableViewCell.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// UITableViewCell.swift -// CarbKit -// -// Created by Nathan Racklyeft on 1/15/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -extension UITableViewCell: IdentifiableClass, NibLoadable { -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/UITextField.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/UITextField.swift deleted file mode 100644 index 25f8d64a6..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/UITextField.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// UITextField.swift -// LoopKitUI -// -// Created by Rick Pasetto on 9/17/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import UIKit - -extension UITextField { - - func selectAll() { - dispatchPrecondition(condition: .onQueue(.main)) - self.selectedTextRange = self.textRange(from: self.beginningOfDocument, to: self.endOfDocument) - } - - func moveCursorToEnd() { - dispatchPrecondition(condition: .onQueue(.main)) - let newPosition = self.endOfDocument - self.selectedTextRange = self.textRange(from: newPosition, to: newPosition) - } - - func moveCursorToBeginning() { - dispatchPrecondition(condition: .onQueue(.main)) - let newPosition = self.beginningOfDocument - self.selectedTextRange = self.textRange(from: newPosition, to: newPosition) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/View+InsetGroupedListStyle.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/View+InsetGroupedListStyle.swift deleted file mode 100644 index 2e8675418..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/View+InsetGroupedListStyle.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// View+InsetGroupedListStyle.swift -// LoopKitUI -// -// Created by Rick Pasetto on 11/25/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -extension View { - - public func insetGroupedListStyle() -> some View { - modifier(CustomInsetGroupedListStyle()) - } -} - -fileprivate struct CustomInsetGroupedListStyle: ViewModifier, HorizontalSizeClassOverride { - - @ViewBuilder func body(content: Content) -> some View { - // For compact sizes (e.g. iPod Touch), don't inset, in order to more efficiently utilize limited real estate - if horizontalOverride == .compact { - content - .listStyle(GroupedListStyle()) - .environment(\.horizontalSizeClass, horizontalOverride) - } else { - content - .listStyle(InsetGroupedListStyle()) - .environment(\.horizontalSizeClass, horizontalOverride) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Extensions/View+KeyboardAware.swift b/Dependencies/LoopKit/LoopKitUI/Extensions/View+KeyboardAware.swift deleted file mode 100644 index d0b77d447..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Extensions/View+KeyboardAware.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// View+KeyboardAware.swift -// LoopKitUI -// -// Created by Michael Pangburn on 7/22/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -// NOTE: In iOS 14, keyboard management is handled automatically in SwiftUI. -extension View { - public func onKeyboardStateChange(perform updateForKeyboardState: @escaping (_ keyboardHeight: Keyboard.State) -> Void) -> some View { - onReceive(Keyboard.shared.$state, perform: updateForKeyboardState) - } - - public func keyboardAware() -> some View { - modifier(KeyboardAware()) - } -} - -fileprivate struct KeyboardAware: ViewModifier { - @State var keyboardHeight: CGFloat = 0 - - func body(content: Content) -> some View { - content - .padding(.bottom, keyboardHeight) - .edgesIgnoringSafeArea(keyboardHeight > 0 ? .bottom : []) - .onKeyboardStateChange { state in - if state.height == 0 { - // Only animate the transition as the keyboard comes up; animating the opposite direction is jittery. - self.keyboardHeight = 0 - } else { - withAnimation(.easeInOut(duration: state.animationDuration)) { - self.keyboardHeight = state.height - } - } - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/HUDProvider.swift b/Dependencies/LoopKit/LoopKitUI/HUDProvider.swift deleted file mode 100644 index eb32657ce..000000000 --- a/Dependencies/LoopKit/LoopKitUI/HUDProvider.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// HUDProvider.swift -// LoopKitUI -// -// Created by Pete Schwamb on 1/29/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import UIKit - -public enum HUDTapAction { - case presentViewController(UIViewController & CompletionNotifying) - case openAppURL(URL) - case setupNewPump - case setupNewCGM - case takeNoAction -} - -public protocol HUDProvider: AnyObject { - var managerIdentifier: String { get } - - typealias HUDViewRawState = [String: Any] - - // Creates the initial view (typically reservoir volume) to be shown in Loop HUD. - func createHUDView() -> BaseHUDView? - - // Returns the action that should be taken when the view is tapped - func didTapOnHUDView(_ view: BaseHUDView, allowDebugFeatures: Bool) -> HUDTapAction? - - // The current, serializable state of the HUD views - var hudViewRawState: HUDViewRawState { get } - - // This notifies the HUDProvider whether hud views are offscreen or - // backgrounded. When not visible, updates should be deferred to better - // inform the user when they are returning to the views. Showing - // changed state via animations might be appropriate when becoming - // visible. When not visible, the HUDProvider should limit work done to - // save cpu resources while backgrounded. - var visible: Bool { get set } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/HorizontalSizeClassOverride.swift b/Dependencies/LoopKit/LoopKitUI/HorizontalSizeClassOverride.swift deleted file mode 100644 index 88aadb4d3..000000000 --- a/Dependencies/LoopKit/LoopKitUI/HorizontalSizeClassOverride.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// HorizontalSizeClassOverride.swift -// LoopKitUI -// -// Created by Rick Pasetto on 6/5/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public protocol HorizontalSizeClassOverride { - var horizontalOverride: UserInterfaceSizeClass { get } -} - -public extension HorizontalSizeClassOverride { - var horizontalOverride: UserInterfaceSizeClass { - if UIScreen.main.bounds.height <= 640 { - return .compact - } else { - return .regular - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Info.plist b/Dependencies/LoopKit/LoopKitUI/Info.plist deleted file mode 100644 index 33bb8a7d8..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Info.plist +++ /dev/null @@ -1,31 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - CFBundleLocalizations - - en - es - zh_CN - fr - de - nl - - - diff --git a/Dependencies/LoopKit/LoopKitUI/InsulinKit/ErrorBackgroundView.swift b/Dependencies/LoopKit/LoopKitUI/InsulinKit/ErrorBackgroundView.swift deleted file mode 100644 index 73f7382b0..000000000 --- a/Dependencies/LoopKit/LoopKitUI/InsulinKit/ErrorBackgroundView.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// ErrorBackgroundView.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/15/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - -public class ErrorBackgroundView: UIView { - - @IBOutlet var errorDescriptionLabel: UILabel! - - public func setErrorDescriptionLabel(with label: String?) { - guard let label = label else { - return - } - - errorDescriptionLabel.text = label - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/InsulinKit/LegacyInsulinDeliveryTableViewController.swift b/Dependencies/LoopKit/LoopKitUI/InsulinKit/LegacyInsulinDeliveryTableViewController.swift deleted file mode 100644 index 52f736e39..000000000 --- a/Dependencies/LoopKit/LoopKitUI/InsulinKit/LegacyInsulinDeliveryTableViewController.swift +++ /dev/null @@ -1,554 +0,0 @@ -// -// LegacyInsulinDeliveryTableViewController.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/30/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// -import UIKit -import LoopKit - -private let ReuseIdentifier = "Right Detail" - - -public final class LegacyInsulinDeliveryTableViewController: UITableViewController { - - @IBOutlet var needsConfigurationMessageView: ErrorBackgroundView! - - @IBOutlet weak var iobValueLabel: UILabel! { - didSet { - iobValueLabel.textColor = headerValueLabelColor - } - } - - @IBOutlet weak var iobDateLabel: UILabel! - - @IBOutlet weak var totalValueLabel: UILabel! { - didSet { - totalValueLabel.textColor = headerValueLabelColor - } - } - - @IBOutlet weak var totalDateLabel: UILabel! - - @IBOutlet weak var dataSourceSegmentedControl: UISegmentedControl! { - didSet { - let titleFont = UIFont.systemFont(ofSize: 15, weight: .semibold) - dataSourceSegmentedControl.setTitleTextAttributes([NSAttributedString.Key.font: titleFont], for: .normal) - dataSourceSegmentedControl.setTitle(LocalizedString("Event History", comment: "Segmented button title for insulin delivery log event history"), forSegmentAt: 0) - dataSourceSegmentedControl.setTitle(LocalizedString("Reservoir", comment: "Segmented button title for insulin delivery log reservoir history"), forSegmentAt: 1) - } - } - - public var enableEntryDeletion: Bool = true - - public var doseStore: DoseStore? { - didSet { - if let doseStore = doseStore { - doseStoreObserver = NotificationCenter.default.addObserver(forName: nil, object: doseStore, queue: OperationQueue.main, using: { [weak self] (note) -> Void in - - switch note.name { - case DoseStore.valuesDidChange: - if self?.isViewLoaded == true { - self?.reloadData() - } - default: - break - } - }) - } else { - doseStoreObserver = nil - } - } - } - - public var headerValueLabelColor: UIColor = .label - - private var updateTimer: Timer? { - willSet { - if let timer = updateTimer { - timer.invalidate() - } - } - } - - public override func viewDidLoad() { - super.viewDidLoad() - - state = .display - } - - public override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - updateTimelyStats(nil) - } - - public override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - let updateInterval = TimeInterval(minutes: 5) - let timer = Timer( - fireAt: Date().dateCeiledToTimeInterval(updateInterval).addingTimeInterval(2), - interval: updateInterval, - target: self, - selector: #selector(updateTimelyStats(_:)), - userInfo: nil, - repeats: true - ) - updateTimer = timer - - RunLoop.current.add(timer, forMode: RunLoop.Mode.default) - } - - public override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - - updateTimer = nil - } - - public override func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - - if tableView.isEditing { - tableView.endEditing(true) - } - } - - deinit { - if let observer = doseStoreObserver { - NotificationCenter.default.removeObserver(observer) - } - } - - public override func setEditing(_ editing: Bool, animated: Bool) { - super.setEditing(editing, animated: animated) - - if editing && enableEntryDeletion { - let item = UIBarButtonItem( - title: LocalizedString("Delete All", comment: "Button title to delete all objects"), - style: .plain, - target: self, - action: #selector(confirmDeletion(_:)) - ) - navigationItem.setLeftBarButton(item, animated: true) - } else { - navigationItem.setLeftBarButton(nil, animated: true) - } - } - - // MARK: - Data - private enum State { - case unknown - case unavailable(Error?) - case display - } - - private var state = State.unknown { - didSet { - if isViewLoaded { - reloadData() - } - } - } - - private enum DataSourceSegment: Int { - case history = 0 - case reservoir - } - - private enum Values { - case reservoir([ReservoirValue]) - case history([PersistedPumpEvent]) - } - - // Not thread-safe - private var values = Values.reservoir([]) { - didSet { - let count: Int - - switch values { - case .reservoir(let values): - count = values.count - case .history(let values): - count = values.count - } - - if count > 0 && enableEntryDeletion { - navigationItem.rightBarButtonItem = self.editButtonItem - } - } - } - - private func reloadData() { - switch state { - case .unknown: - break - case .unavailable(let error): - self.tableView.tableHeaderView?.isHidden = true - self.tableView.tableFooterView = UIView() - tableView.backgroundView = needsConfigurationMessageView - - if let error = error { - needsConfigurationMessageView.errorDescriptionLabel.text = String(describing: error) - } else { - needsConfigurationMessageView.errorDescriptionLabel.text = nil - } - case .display: - self.tableView.backgroundView = nil - self.tableView.tableHeaderView?.isHidden = false - self.tableView.tableFooterView = nil - - switch DataSourceSegment(rawValue: dataSourceSegmentedControl.selectedSegmentIndex)! { - case .reservoir: - doseStore?.getReservoirValues(since: Date.distantPast) { (result) in - DispatchQueue.main.async { () -> Void in - switch result { - case .failure(let error): - self.state = .unavailable(error) - case .success(let reservoirValues): - self.values = .reservoir(reservoirValues) - self.tableView.reloadData() - } - } - - self.updateTimelyStats(nil) - self.updateTotal() - } - case .history: - doseStore?.getPumpEventValues(since: Date.distantPast) { (result) in - DispatchQueue.main.async { () -> Void in - switch result { - case .failure(let error): - self.state = .unavailable(error) - case .success(let pumpEventValues): - self.values = .history(pumpEventValues) - self.tableView.reloadData() - } - } - - self.updateTimelyStats(nil) - self.updateTotal() - } - } - } - } - - @objc func updateTimelyStats(_: Timer?) { - updateIOB() - } - - private lazy var iobNumberFormatter: NumberFormatter = { - let formatter = NumberFormatter() - - formatter.numberStyle = .decimal - formatter.maximumFractionDigits = 2 - - return formatter - }() - - private lazy var timeFormatter: DateFormatter = { - let formatter = DateFormatter() - - formatter.dateStyle = .none - formatter.timeStyle = .short - - return formatter - }() - - private func updateIOB() { - if case .display = state { - doseStore?.insulinOnBoard(at: Date()) { (result) -> Void in - DispatchQueue.main.async { - switch result { - case .failure: - self.iobValueLabel.text = "…" - self.iobDateLabel.text = nil - case .success(let iob): - self.iobValueLabel.text = self.iobNumberFormatter.string(from: iob.value) - self.iobDateLabel.text = String(format: LocalizedString("com.loudnate.InsulinKit.IOBDateLabel", value: "at %1$@", comment: "The format string describing the date of an IOB value. The first format argument is the localized date."), self.timeFormatter.string(from: iob.startDate)) - } - } - } - } - } - - private func updateTotal() { - if case .display = state { - let midnight = Calendar.current.startOfDay(for: Date()) - - doseStore?.getTotalUnitsDelivered(since: midnight) { (result) in - DispatchQueue.main.async { - switch result { - case .failure: - self.totalValueLabel.text = "…" - self.totalDateLabel.text = nil - case .success(let result): - self.totalValueLabel.text = NumberFormatter.localizedString(from: NSNumber(value: result.value), number: .none) - self.totalDateLabel.text = String(format: LocalizedString("com.loudnate.InsulinKit.totalDateLabel", value: "since %1$@", comment: "The format string describing the starting date of a total value. The first format argument is the localized date."), DateFormatter.localizedString(from: result.startDate, dateStyle: .none, timeStyle: .short)) - } - } - } - } - } - - private var doseStoreObserver: Any? { - willSet { - if let observer = doseStoreObserver { - NotificationCenter.default.removeObserver(observer) - } - } - } - - @IBAction func selectedSegmentChanged(_ sender: Any) { - reloadData() - } - - @IBAction func confirmDeletion(_ sender: Any) { - guard !deletionPending else { - return - } - - let confirmMessage: String - - switch DataSourceSegment(rawValue: dataSourceSegmentedControl.selectedSegmentIndex)! { - case .reservoir: - confirmMessage = LocalizedString("Are you sure you want to delete all reservoir values?", comment: "Action sheet confirmation message for reservoir deletion") - case .history: - confirmMessage = LocalizedString("Are you sure you want to delete all history entries?", comment: "Action sheet confirmation message for pump history deletion") - } - - let sheet = UIAlertController(deleteAllConfirmationMessage: confirmMessage) { - self.deleteAllObjects() - } - present(sheet, animated: true) - } - - private var deletionPending = false - - private func deleteAllObjects() { - guard !deletionPending else { - return - } - - deletionPending = true - - let completion = { (_: DoseStore.DoseStoreError?) -> Void in - DispatchQueue.main.async { - self.deletionPending = false - self.setEditing(false, animated: true) - } - } - - switch DataSourceSegment(rawValue: dataSourceSegmentedControl.selectedSegmentIndex)! { - case .reservoir: - doseStore?.deleteAllReservoirValues(completion) - case .history: - doseStore?.deleteAllPumpEvents(completion) - } - } - - // MARK: - Table view data source - public override func numberOfSections(in tableView: UITableView) -> Int { - switch state { - case .unknown, .unavailable: - return 0 - case .display: - return 1 - } - } - - public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch values { - case .reservoir(let values): - return values.count - case .history(let values): - return values.count - } - } - - public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: ReuseIdentifier, for: indexPath) - - if case .display = state { - switch self.values { - case .reservoir(let values): - let entry = values[indexPath.row] - let volume = NumberFormatter.localizedString(from: NSNumber(value: entry.unitVolume), number: .decimal) - let time = timeFormatter.string(from: entry.startDate) - - cell.textLabel?.text = String(format: LocalizedString("%1$@ U", comment: "Reservoir entry (1: volume value)"), volume) - cell.textLabel?.textColor = .label - cell.detailTextLabel?.text = time - cell.accessoryType = .none - cell.selectionStyle = .none - case .history(let values): - let entry = values[indexPath.row] - let time = timeFormatter.string(from: entry.date) - - if let attributedText = entry.dose?.localizedAttributedDescription { - cell.textLabel?.attributedText = attributedText - } else { - cell.textLabel?.text = entry.title - } - - cell.detailTextLabel?.text = time - cell.accessoryType = entry.isUploaded ? .checkmark : .none - cell.selectionStyle = .default - } - } - - return cell - } - - public override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - return enableEntryDeletion - } - - public override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { - if editingStyle == .delete, case .display = state { - switch values { - case .reservoir(let reservoirValues): - var reservoirValues = reservoirValues - let value = reservoirValues.remove(at: indexPath.row) - self.values = .reservoir(reservoirValues) - - tableView.deleteRows(at: [indexPath], with: .automatic) - - doseStore?.deleteReservoirValue(value) { (_, error) -> Void in - if let error = error { - DispatchQueue.main.async { - self.present(UIAlertController(with: error), animated: true) - self.reloadData() - } - } - } - case .history(let historyValues): - var historyValues = historyValues - let value = historyValues.remove(at: indexPath.row) - self.values = .history(historyValues) - - tableView.deleteRows(at: [indexPath], with: .automatic) - - doseStore?.deletePumpEvent(value) { (error) -> Void in - if let error = error { - DispatchQueue.main.async { - self.present(UIAlertController(with: error), animated: true) - self.reloadData() - } - } - } - } - } - } - - public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - if case .display = state, case .history(let history) = values { - let entry = history[indexPath.row] - - let vc = CommandResponseViewController(command: { (completionHandler) -> String in - var description = [String]() - - description.append(self.timeFormatter.string(from: entry.date)) - - if let title = entry.title { - description.append(title) - } - - if let dose = entry.dose { - description.append(String(describing: dose)) - } - - if let raw = entry.raw { - description.append(raw.hexadecimalString) - } - - return description.joined(separator: "\n\n") - }) - - vc.title = LocalizedString("Pump Event", comment: "The title of the screen displaying a pump event") - - show(vc, sender: indexPath) - } - } - -} - -fileprivate extension UIAlertController { - convenience init(deleteAllConfirmationMessage: String, confirmationHandler handler: @escaping () -> Void) { - self.init( - title: nil, - message: deleteAllConfirmationMessage, - preferredStyle: .actionSheet - ) - - addAction(UIAlertAction( - title: LocalizedString("Delete All", comment: "Button title to delete all objects"), - style: .destructive, - handler: { (_) in handler() } - )) - - addAction(UIAlertAction( - title: LocalizedString("Cancel", comment: "The title of the cancel action in an action sheet"), - style: .cancel - )) - } -} - -extension DoseEntry { - - fileprivate var numberFormatter: NumberFormatter { - let numberFormatter = NumberFormatter() - numberFormatter.maximumFractionDigits = DoseEntry.unitsPerHour.maxFractionDigits - return numberFormatter - } - - fileprivate var localizedAttributedDescription: NSAttributedString? { - let font = UIFont.preferredFont(forTextStyle: .body) - - switch type { - case .bolus: - let description: String - if let deliveredUnits = deliveredUnits, - deliveredUnits != programmedUnits - { - description = String(format: LocalizedString("Interrupted %1$@: %2$@ of %3$@ %4$@", comment: "Description of an interrupted bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: programmed value (? if no value), 4: unit)"), type.localizedDescription, numberFormatter.string(from: deliveredUnits) ?? "?", numberFormatter.string(from: programmedUnits) ?? "?", DoseEntry.units.shortLocalizedUnitString()) - } else { - description = String(format: LocalizedString("%1$@: %2$@ %3$@", comment: "Description of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit)"), type.localizedDescription, numberFormatter.string(from: programmedUnits) ?? "?", DoseEntry.units.shortLocalizedUnitString()) - } - - return createAttributedDescription(from: description, with: font) - case .basal, .tempBasal: - let description = String(format: LocalizedString("%1$@: %2$@ %3$@", comment: "Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit)"), type.localizedDescription, numberFormatter.string(from: unitsPerHour) ?? "?", DoseEntry.unitsPerHour.shortLocalizedUnitString()) - return createAttributedDescription(from: description, with: font) - case .suspend, .resume: - let attributes: [NSAttributedString.Key: Any] = [ - .font: font, - .foregroundColor: UIColor.secondaryLabel - ] - return NSAttributedString(string: type.localizedDescription, attributes: attributes) - } - } - - fileprivate func createAttributedDescription(from description: String, with font: UIFont) -> NSAttributedString? { - let descriptionWithFont = String(format:"%@", description) - - guard let attributedDescription = try? NSMutableAttributedString(data: Data(descriptionWithFont.utf8), options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: NSNumber(value: String.Encoding.utf8.rawValue)], documentAttributes: nil) - else { - return nil - } - - attributedDescription.enumerateAttribute(.font, in: NSRange(location: 0, length: attributedDescription.length)) { value, range, stop in - // bold font items have a dominate colour - if let font = value as? UIFont, - font.fontDescriptor.symbolicTraits.contains(.traitBold) - { - attributedDescription.addAttributes([.foregroundColor: UIColor.label], range: range) - } else { - attributedDescription.addAttributes([.foregroundColor: UIColor.secondaryLabel], range: range) - } - } - - return attributedDescription - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/InsulinModelSettings+LoopKitUI.swift b/Dependencies/LoopKit/LoopKitUI/InsulinModelSettings+LoopKitUI.swift deleted file mode 100644 index 02bc034af..000000000 --- a/Dependencies/LoopKit/LoopKitUI/InsulinModelSettings+LoopKitUI.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// InsulinModelSettings+Loop.swift -// LoopKitUI -// -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import LoopKit - -public extension ExponentialInsulinModelPreset { - var title: String { - switch self { - case .rapidActingAdult: - return LocalizedString("Rapid-Acting – Adults", comment: "Title of insulin model preset - rapid acting adult") - case .rapidActingChild: - return LocalizedString("Rapid-Acting – Children", comment: "Title of insulin model preset - rapid acting children") - case .fiasp: - return LocalizedString("Fiasp", comment: "Title of insulin model preset - fiasp") - case .lyumjev: - return LocalizedString("Lyumjev", comment: "Title of insulin model preset - lyumjev") - case .afrezza: - return LocalizedString("Afrezza", comment: "Title of insulin model preset - afrezza") - } - } - - var subtitle: String { - switch self { - case .rapidActingAdult: - return LocalizedString("This model assumes peak insulin activity at 75 minutes.", comment: "Subtitle of Rapid-Acting – Adult preset") - case .rapidActingChild: - return LocalizedString("This model assumes peak insulin activity at 65 minutes.", comment: "Subtitle of Rapid-Acting – Children preset") - case .fiasp: - return LocalizedString("This model assumes peak insulin activity at 55 minutes.", comment: "Subtitle of Fiasp preset") - case .lyumjev: - return LocalizedString("This model assumes peak insulin activity at 55 minutes.", comment: "Subtitle of Lyumjev preset") - case .afrezza: - return LocalizedString("This model assumes peak insulin activity at 19 minutes.", comment: "Subtitle of afrezza preset") - } - } -} - - -public extension WalshInsulinModel { - static var title: String { - return LocalizedString("Walsh", comment: "Title of insulin model setting") - } - - var title: String { - return Self.title - } - - static var subtitle: String { - return LocalizedString("The legacy model used by Loop, allowing customization of action duration.", comment: "Subtitle description of Walsh insulin model setting") - } - - var subtitle: String { - return Self.subtitle - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/LocalizedString.swift b/Dependencies/LoopKit/LoopKitUI/LocalizedString.swift deleted file mode 100644 index c6ad455c4..000000000 --- a/Dependencies/LoopKit/LoopKitUI/LocalizedString.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// LocalizedString.swift -// LoopKit -// -// Created by Retina15 on 8/6/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -private class LocalBundle { - /// Returns the resource bundle associated with the current Swift module. - static var main: Bundle = { - if let mainResourceURL = Bundle.main.resourceURL, - let bundle = Bundle(url: mainResourceURL.appendingPathComponent("LoopKitUI_LoopKitUI.bundle")) - { - return bundle - } - return Bundle(for: LocalBundle.self) - }() -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, comment: comment) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/LoopKitUI.h b/Dependencies/LoopKit/LoopKitUI/LoopKitUI.h deleted file mode 100644 index 6804772d5..000000000 --- a/Dependencies/LoopKit/LoopKitUI/LoopKitUI.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// LoopKitUI.h -// LoopKitUI -// -// Created by Nathan Racklyeft on 1/28/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -#import - -//! Project version number for LoopKitUI. -FOUNDATION_EXPORT double LoopKitUIVersionNumber; - -//! Project version string for LoopKitUI. -FOUNDATION_EXPORT const unsigned char LoopKitUIVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/LoopKit/LoopKitUI/LoopUIColorPalette.swift b/Dependencies/LoopKit/LoopKitUI/LoopUIColorPalette.swift deleted file mode 100644 index 1092b7719..000000000 --- a/Dependencies/LoopKit/LoopKitUI/LoopUIColorPalette.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// LoopUIColorPalette.swift -// LoopKitUI -// -// Created by Darin Krauss on 1/14/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct LoopUIColorPalette { - public let guidanceColors: GuidanceColors - public let carbTintColor: Color - public let glucoseTintColor: Color - public let insulinTintColor: Color - public let loopStatusColorPalette: StateColorPalette - public let chartColorPalette: ChartColorPalette - - public init(guidanceColors: GuidanceColors, carbTintColor: Color, glucoseTintColor: Color, insulinTintColor: Color, loopStatusColorPalette: StateColorPalette, chartColorPalette: ChartColorPalette) { - self.guidanceColors = guidanceColors - self.carbTintColor = carbTintColor - self.glucoseTintColor = glucoseTintColor - self.insulinTintColor = insulinTintColor - self.loopStatusColorPalette = loopStatusColorPalette - self.chartColorPalette = chartColorPalette - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/LoopUIPlugin.swift b/Dependencies/LoopKit/LoopKitUI/LoopUIPlugin.swift deleted file mode 100644 index 140853f6f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/LoopUIPlugin.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// LoopUIPlugin.swift -// LoopKitUI -// -// Created by Pete Schwamb on 7/24/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -public protocol PumpManagerUIPlugin { - var pumpManagerType: PumpManagerUI.Type? { get } -} - -public protocol CGMManagerUIPlugin { - var cgmManagerType: CGMManagerUI.Type? { get } -} - -public protocol ServiceUIPlugin { - var serviceType: ServiceUI.Type? { get } -} - -public protocol OnboardingUIPlugin { - var onboardingType: OnboardingUI.Type? { get } -} - -public protocol SupportUIPlugin { - var support: SupportUI { get } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Models/ChartAxisValueDoubleUnit.swift b/Dependencies/LoopKit/LoopKitUI/Models/ChartAxisValueDoubleUnit.swift deleted file mode 100644 index 77e3e6dc4..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Models/ChartAxisValueDoubleUnit.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// ChartAxisValueDoubleUnit.swift -// LoopKitUI -// -// Created by Nate Racklyeft on 7/16/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import SwiftCharts - - -public final class ChartAxisValueDoubleUnit: ChartAxisValueDouble { - let unitString: String - - public init(_ double: Double, unitString: String, formatter: NumberFormatter) { - self.unitString = unitString - - super.init(double, formatter: formatter) - } - - init(_ double: Double, unitString: String) { - self.unitString = unitString - - super.init(double) - } - - override public var description: String { - return formatter.string(from: scalar, unit: unitString) ?? "" - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Models/GuidanceColors.swift b/Dependencies/LoopKit/LoopKitUI/Models/GuidanceColors.swift deleted file mode 100644 index 312ba7d8b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Models/GuidanceColors.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// GuidanceColors.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-07-31. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct GuidanceColors { - public var acceptable: Color - public var warning: Color - public var critical: Color - - public init(acceptable: Color, warning: Color, critical: Color) - { - self.acceptable = acceptable - self.warning = warning - self.critical = critical - } - - public init() { - self.acceptable = .primary - self.warning = .yellow - self.critical = .red - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/OnboardingUI.swift b/Dependencies/LoopKit/LoopKitUI/OnboardingUI.swift deleted file mode 100644 index e2700debb..000000000 --- a/Dependencies/LoopKit/LoopKitUI/OnboardingUI.swift +++ /dev/null @@ -1,204 +0,0 @@ -// -// OnboardingUI.swift -// LoopKitUI -// -// Created by Darin Krauss on 12/10/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - -public enum NotificationAuthorization: Int { - /// User has not yet made a choice regarding whether the application may schedule or receive user notifications. - case notDetermined - - /// User has explicitly denied this application from scheduling or receiving user notifications. - case denied - - /// User has authorized this application to schedule or receive non-interruptive user notifications. - case provisional - - /// User has authorized this application to schedule or receive any user notifications. - case authorized -} - -public protocol NotificationAuthorizationProvider: AnyObject { - /// The current notification authorization. - /// - /// - Parameters: - /// - completion: Invoked when notification authorization is available. - func getNotificationAuthorization(_ completion: @escaping (NotificationAuthorization) -> Void) - - /// Authorize notification. Should only be invoked if notificationAuthorization is .notDetermined. - /// - /// - Parameters: - /// - completion: Invoked when notification authorization is complete along with the resulting authorization. - func authorizeNotification(_ completion: @escaping (NotificationAuthorization) -> Void) -} - -public enum HealthStoreAuthorization: Int { - /// User has not yet made a choice regarding permissions for one or more health store data types. - case notDetermined - - /// User has explicitly chosen permissions for each health store data type. - case determined -} - -public protocol HealthStoreAuthorizationProvider: AnyObject { - /// The current health store authorization. - /// - /// - Parameters: - /// - completion: Invoked when health store authorization is available. - func getHealthStoreAuthorization(_ completion: @escaping (HealthStoreAuthorization) -> Void) - - /// Authorize health store. Should only be invoked if healthStoreAuthorization is .notDetermined. - /// - /// - Parameters: - /// - completion: Invoked when health store authorization is complete along with the resulting authorization. - func authorizeHealthStore(_ completion: @escaping (HealthStoreAuthorization) -> Void) -} - -public typealias OnboardingResult = SetupUIResult - -public protocol CGMManagerProvider: AnyObject { - /// The active CGM manager. - var activeCGMManager: CGMManager? { get } - - /// The descriptor list of available CGM managers. - var availableCGMManagers: [CGMManagerDescriptor] { get } - - /// An image for the CGM manager with the specified identifier. - /// - /// - Parameters: - /// - identifier: The identifier of the CGM manager. - /// - Returns: An image for the CGM manager with the specified identifier. - func imageForCGMManager(withIdentifier identifier: String) -> UIImage? - - /// Onboard the CGM manager with the specified identifier. - /// - /// - Parameters: - /// - identifier: The identifier of the CGM manager to onboard. - /// - Returns: Either a conforming view controller to onboard the CGM manager, a newly onboarded CGM manager, or an error. - func onboardCGMManager(withIdentifier identifier: String) -> Result, Error> -} - -public protocol PumpManagerProvider: AnyObject { - /// The active pump manager. - var activePumpManager: PumpManager? { get } - - /// The descriptor list of available pump managers. - var availablePumpManagers: [PumpManagerDescriptor] { get } - - /// An image for the pump manager with the specified identifier. - /// - /// - Parameters: - /// - identifier: The identifier of the pump manager. - /// - Returns: An image for the pump manager with the specified identifier. - func imageForPumpManager(withIdentifier identifier: String) -> UIImage? - - /// An supported increments for the pump manager with the specified identifier. - /// - /// - Parameters: - /// - identifier: The identifier of the pump manager. - /// - Returns: An supported increments for the pump manager with the specified identifier. - func supportedIncrementsForPumpManager(withIdentifier identifier: String) -> PumpSupportedIncrements? - - /// Onboard the pump manager with the specified identifier. - /// - /// - Parameters: - /// - identifier: The identifier of the pump manager to onboard. - /// - Returns: Either a conforming view controller to onboard the pump manager, a newly onboarded pump manager, or an error. - func onboardPumpManager(withIdentifier identifier: String, initialSettings settings: PumpManagerSetupSettings) -> Result, Error> -} - -public protocol ServiceProvider: AnyObject { - /// The active services. - var activeServices: [Service] { get } - - /// The descriptor list of available services. - var availableServices: [ServiceDescriptor] { get } - - /// Onboard the service with the specified identifier. - /// - /// - Parameters: - /// - identifier: The identifier of the service to onboard. - /// - Returns: Either a conforming view controller to onboard the service, a newly onboarded service, or an error. - func onboardService(withIdentifier identifier: String) -> Result, Error> -} - -public protocol TherapySettingsProvider { - var onboardingTherapySettings: TherapySettings { get } -} - -public protocol OnboardingProvider: NotificationAuthorizationProvider, HealthStoreAuthorizationProvider, BluetoothProvider, CGMManagerProvider, PumpManagerProvider, ServiceProvider, TherapySettingsProvider { - var allowDebugFeatures: Bool { get } // NOTE: DEBUG FEATURES - DEBUG AND TEST ONLY -} - -public protocol OnboardingDelegate: AnyObject { - /// Informs the delegate that the state of the onboarding was updated and the delegate should persist the onboarding. May - /// be invoked prior to the onboarding being fully complete. - /// - /// - Parameters: - /// - onboarding: The onboarding that updated state. - func onboardingDidUpdateState(_ onboarding: OnboardingUI) - - /// Informs the delegate that onboarding has new therapy settings that should be persisted. - /// - /// - Parameters: - /// - onboarding: The onboarding that has new therapy settings. - /// - therapySettings: The new therapy settings. - func onboarding(_ onboarding: OnboardingUI, hasNewTherapySettings therapySettings: TherapySettings) - - /// Informs the delegate that onboarding has new dosing enabled that should be persisted. - /// - /// - Parameters: - /// - onboarding: The onboarding that has new dosing enabled. - /// - isClosedLoop: The new dosing enabled. - func onboarding(_ onboarding: OnboardingUI, hasNewDosingEnabled dosingEnabled: Bool) - - /// Informs the delegate the onboarding has suspended. - /// - /// - Parameters: - /// - onboarding: The onboarding that has suspended. - func onboardingDidSuspend(_ onboarding: OnboardingUI) -} - -public typealias OnboardingViewController = (UIViewController & CGMManagerOnboarding & PumpManagerOnboarding & ServiceOnboarding & CompletionNotifying) - -public protocol OnboardingUI: AnyObject { - typealias RawState = [String: Any] - - /// Create a new onboarding. - /// - /// - Returns: A newly created onboarding. - static func createOnboarding() -> OnboardingUI - - /// Delegate to notify about onboarding changes. - var onboardingDelegate: OnboardingDelegate? { get set } - - /// The unique identifier of this type of onboarding. - var onboardingIdentifier: String { get } - - /// Initializes the onboarding with the previously-serialized state. - /// - /// - Parameters: - /// - rawState: The previously-serialized state of the onboarding. - init?(rawState: RawState) - - /// The current, serializable state of the onboarding. - var rawState: RawState { get } - - /// Is the onboarding complete? - var isOnboarded: Bool { get } - - /// Provides a view controller to configure onboarding, if needed. - /// - /// - Parameters: - /// - onboardingProvider: The provider of auxillary services that support onboarding. - /// - displayGlucoseUnitObservable: The glucose unit to use for display. - /// - colorPalette: The colors to use in any UI, - /// - Returns: A view controller to create and configure a new onboarding. - func onboardingViewController(onboardingProvider: OnboardingProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette) -> OnboardingViewController -} diff --git a/Dependencies/LoopKit/LoopKitUI/OverrideEmojiDataSource.swift b/Dependencies/LoopKit/LoopKitUI/OverrideEmojiDataSource.swift deleted file mode 100644 index 5cec052f8..000000000 --- a/Dependencies/LoopKit/LoopKitUI/OverrideEmojiDataSource.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// OverrideEmojiDataSource.swift -// LoopKitUI -// -// Created by Michael Pangburn on 1/7/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -func OverrideSymbolInputController() -> EmojiInputController { - return EmojiInputController.instance(withEmojis: OverrideEmojiDataSource()) -} - - -private final class OverrideEmojiDataSource: EmojiDataSource { - - private static let activity = [ - "🚶‍♀️", "🚶‍♂️", "🏃‍♀️", "🏃‍♂️", "💃", "🕺", - "⚽️", "🏀", "🏈", "⚾️", "🥎", "🎾", - "🏐", "🏉", "🥏", "🎳", "🏓", "🏸", - "🏒", "🏑", "🥍", "🏏", "⛳️", "🏹", - "🥊", "🥋", "🛹", "⛸", "🥌", "🛷", - "⛷", "🏂", "🏋️‍♀️", "🏋️‍♂️", "🤼‍♀️", "🤼‍♂️", - "🤸‍♀️", "🤸‍♂️", "⛹️‍♀️", "⛹️‍♂️", "🤺", "🤾‍♀️", - "🤾‍♂️", "🏌️‍♀️", "🏌️‍♂️", "🏇", "🧘‍♀️", "🧘‍♂️", - "🏄‍♀️", "🏄‍♂️", "🏊‍♀️", "🏊‍♂️", "🤽‍♀️", "🤽‍♂️", - "🚣‍♀️", "🚣‍♂️", "🧗‍♀️", "🧗‍♂️", "🚵‍♀️", "🚵‍♂️", - "🚴‍♀️", "🚴‍♂️", "🎪", "🤹‍♀️", "🤹‍♂️", "🎭", - "🎤", "🎯", "🎳", "🥾", "⛺️", "🐕", - ] - - private static let condition = [ - "🤒", "🤢", "🤮", "😷", "🤕", "😰", - "🥵", "🥶", "😘", "🧟‍♀️", "🧟‍♂️", "📅", - "💊", "🍸", "🎉","⛰", "🏔", "🚗", - "✈️", "🎢", - ] - - private static let other = [ - "➕", "➖", "⬆️", "⬇️", - "❗️", "❓", "‼️", "⁉️", "❌", "⚠️", - "0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", - "6️⃣", "7️⃣", "8️⃣", "9️⃣", "🔟", - ] - - let sections: [EmojiSection] - - init() { - sections = [ - EmojiSection( - title: LocalizedString("Activity", comment: "The title for the custom preset emoji activity section"), - items: type(of: self).activity, - indexSymbol: " 🏃‍♀️ " - ), - EmojiSection( - title: LocalizedString("Condition", comment: "The title for the custom preset emoji condition section"), - items: type(of: self).condition, - indexSymbol: "🤒" - ), - EmojiSection( - title: LocalizedString("Other", comment: "The title for custom preset emoji miscellaneous section"), - items: type(of: self).other, - indexSymbol: "⋯ " - ) - ] - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/PumpManagerUI.swift b/Dependencies/LoopKit/LoopKitUI/PumpManagerUI.swift deleted file mode 100644 index 325aa2868..000000000 --- a/Dependencies/LoopKit/LoopKitUI/PumpManagerUI.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// PumpManagerUI.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import SwiftUI -import LoopKit - -public struct PumpManagerDescriptor { - public let identifier: String - public let localizedTitle: String - - public init(identifier: String, localizedTitle: String) { - self.identifier = identifier - self.localizedTitle = localizedTitle - } -} - -public struct PumpManagerSetupSettings { - public var maxBasalRateUnitsPerHour: Double - public var maxBolusUnits: Double - public var basalSchedule: BasalRateSchedule - - public init(maxBasalRateUnitsPerHour: Double, maxBolusUnits: Double, basalSchedule: BasalRateSchedule) { - self.maxBasalRateUnitsPerHour = maxBasalRateUnitsPerHour - self.maxBolusUnits = maxBolusUnits - self.basalSchedule = basalSchedule - } -} - -public protocol PumpStatusIndicator { - /// a message from the pump that needs to be brought to the user's attention in the status bar - var pumpStatusHighlight: DeviceStatusHighlight? { get } - - /// the completed percent of the progress bar to display in the status bar - var pumpLifecycleProgress: DeviceLifecycleProgress? { get } - - /// a badge from the pump that needs to be brought to the user's attention in the status bar - var pumpStatusBadge: DeviceStatusBadge? { get } -} - -public typealias PumpManagerViewController = (UIViewController & PumpManagerOnboarding & CompletionNotifying) - -public protocol PumpManagerUI: DeviceManagerUI, PumpStatusIndicator, PumpManager { - - /// Create and onboard a new pump manager. - /// - /// - Parameters: - /// - settings: Settings used to configure the pump manager. - /// - bluetoothProvider: The provider of Bluetooth functionality. - /// - colorPalette: Color palette to use for any UI. - /// - allowedInsulinTypes: Types that the caller allows to be selected. - /// - Returns: Either a conforming view controller to create and onboard the pump manager or a newly created and onboarded pump manager. - static func setupViewController(initialSettings settings: PumpManagerSetupSettings, bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool, allowedInsulinTypes: [InsulinType]) -> SetupUIResult - - /// Configure settings for an existing pump manager. - /// - /// - Parameters: - /// - bluetoothProvider: The provider of Bluetooth functionality. - /// - colorPalette: Color palette to use for any UI. - /// - Returns: A view controller to configure an existing pump manager. - func settingsViewController(bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool, allowedInsulinTypes: [InsulinType]) -> PumpManagerViewController - - // View for recovering from delivery uncertainty - func deliveryUncertaintyRecoveryViewController(colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) -> (UIViewController & CompletionNotifying) - - // Returns a class that can provide HUD views - func hudProvider(bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowedInsulinTypes: [InsulinType]) -> HUDProvider? - - // Instantiates HUD view (typically reservoir volume) from the raw state returned by hudViewRawState - static func createHUDView(rawValue: HUDProvider.HUDViewRawState) -> BaseHUDView? -} - -public protocol PumpManagerOnboardingDelegate: AnyObject { - /// Informs the delegate that the specified pump manager was created. - /// - /// - Parameters: - /// - pumpManager: The pump manager created. - func pumpManagerOnboarding(didCreatePumpManager pumpManager: PumpManagerUI) - - /// Informs the delegate that the specified pump manager was onboarded. - /// - /// - Parameters: - /// - pumpManager: The pump manager onboarded. - func pumpManagerOnboarding(didOnboardPumpManager pumpManager: PumpManagerUI) - - /// Informs the delegate that the specified pump manager wishes to pause onboarding - /// - /// - Parameters: - /// - pumpManager: The pump manager onboarded. - func pumpManagerOnboarding(didPauseOnboarding pumpManager: PumpManagerUI) -} - -public protocol PumpManagerOnboarding { - /// Delegate to notify about pump manager onboarding. - var pumpManagerOnboardingDelegate: PumpManagerOnboardingDelegate? { get set } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Apidra.colorset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Apidra.colorset/Contents.json deleted file mode 100644 index 9f0fecee8..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Apidra.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "0.592", - "green" : "0.333", - "red" : "0.206" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Checkmark.imageset/Checkmark.pdf b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Checkmark.imageset/Checkmark.pdf deleted file mode 100644 index cdc1dbe97..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Checkmark.imageset/Checkmark.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Checkmark.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Checkmark.imageset/Contents.json deleted file mode 100644 index 5f64d5a99..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Checkmark.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "Checkmark.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Darkened Insulin.colorset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Darkened Insulin.colorset/Contents.json deleted file mode 100644 index 9d6e49382..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Darkened Insulin.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - }, - "colors" : [ - { - "idiom" : "universal", - "color" : { - "color-space" : "srgb", - "components" : { - "red" : "1.000", - "alpha" : "1.000", - "blue" : "0.000", - "green" : "0.435" - } - } - } - ] -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Delete-Left.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Delete-Left.imageset/Contents.json deleted file mode 100644 index 526b332af..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Delete-Left.imageset/Contents.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x", - "language-direction" : "left-to-right" - }, - { - "idiom" : "universal", - "filename" : "Delete@2x.png", - "language-direction" : "left-to-right", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "Delete@3x.png", - "language-direction" : "left-to-right", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template" - } -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Delete-Left.imageset/Delete@2x.png b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Delete-Left.imageset/Delete@2x.png deleted file mode 100644 index 3c63d3a35..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Delete-Left.imageset/Delete@2x.png and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Delete-Left.imageset/Delete@3x.png b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Delete-Left.imageset/Delete@3x.png deleted file mode 100644 index 673cca061..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Delete-Left.imageset/Delete@3x.png and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Delete.colorset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Delete.colorset/Contents.json deleted file mode 100644 index 89094da12..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Delete.colorset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - }, - "colors" : [ - { - "idiom" : "universal", - "color" : { - "platform" : "ios", - "reference" : "systemRedColor" - } - } - ] -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Fiasp.colorset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Fiasp.colorset/Contents.json deleted file mode 100644 index 96e62e936..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Fiasp.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "0.306", - "green" : "0.922", - "red" : "0.972" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "0.249", - "green" : "0.729", - "red" : "0.763" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Humalog.colorset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Humalog.colorset/Contents.json deleted file mode 100644 index c18dc6dfe..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Humalog.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "0.302", - "green" : "0.142", - "red" : "0.690" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "0.231", - "green" : "0.107", - "red" : "0.517" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Invalid.colorset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Invalid.colorset/Contents.json deleted file mode 100644 index 89094da12..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Invalid.colorset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - }, - "colors" : [ - { - "idiom" : "universal", - "color" : { - "platform" : "ios", - "reference" : "systemRedColor" - } - } - ] -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Lightened Insulin.colorset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Lightened Insulin.colorset/Contents.json deleted file mode 100644 index 52b9533f7..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Lightened Insulin.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - }, - "colors" : [ - { - "idiom" : "universal", - "color" : { - "color-space" : "srgb", - "components" : { - "red" : "1.000", - "alpha" : "1.000", - "blue" : "0.000", - "green" : "0.749" - } - } - } - ] -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Lyumjev.colorset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Lyumjev.colorset/Contents.json deleted file mode 100644 index 591993c0f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Lyumjev.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x82", - "green" : "0x53", - "red" : "0x3A" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Novolog.colorset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Novolog.colorset/Contents.json deleted file mode 100644 index 6724a6b76..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Novolog.colorset/Contents.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "platform" : "ios", - "reference" : "systemOrangeColor" - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "0.197", - "green" : "0.516", - "red" : "0.755" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Oval Selection.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Oval Selection.imageset/Contents.json deleted file mode 100644 index 7bff2dbe3..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Oval Selection.imageset/Contents.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "Oval Selection.pdf", - "resizing" : { - "mode" : "9-part", - "center" : { - "mode" : "tile", - "width" : 1, - "height" : 1 - }, - "cap-insets" : { - "bottom" : 10, - "top" : 10, - "right" : 10, - "left" : 10 - } - } - }, - { - "idiom" : "universal", - "filename" : "Oval Selection Dark.pdf", - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "resizing" : { - "mode" : "9-part", - "center" : { - "mode" : "tile", - "width" : 1, - "height" : 1 - }, - "cap-insets" : { - "bottom" : 10, - "top" : 10, - "right" : 10, - "left" : 10 - } - } - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Oval Selection.imageset/Oval Selection Dark.pdf b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Oval Selection.imageset/Oval Selection Dark.pdf deleted file mode 100644 index a67042ecb..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Oval Selection.imageset/Oval Selection Dark.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Oval Selection.imageset/Oval Selection.pdf b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Oval Selection.imageset/Oval Selection.pdf deleted file mode 100644 index 13056f028..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Oval Selection.imageset/Oval Selection.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Pre-Meal.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Pre-Meal.imageset/Contents.json deleted file mode 100644 index 4c526a9f3..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Pre-Meal.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "Pre-Meal.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Pre-Meal.imageset/Pre-Meal.pdf b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Pre-Meal.imageset/Pre-Meal.pdf deleted file mode 100644 index 0992a4a28..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Pre-Meal.imageset/Pre-Meal.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Warning.colorset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Warning.colorset/Contents.json deleted file mode 100644 index 5e4840ce2..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/Warning.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - }, - "colors" : [ - { - "idiom" : "universal", - "color" : { - "color-space" : "srgb", - "components" : { - "red" : "255", - "alpha" : "1.000", - "blue" : "0", - "green" : "204" - } - } - } - ] -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/play-button.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/play-button.imageset/Contents.json deleted file mode 100644 index 12ecf3eff..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/play-button.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "play-button.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/play-button.imageset/play-button.pdf b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/play-button.imageset/play-button.pdf deleted file mode 100644 index 32d051a08..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/play-button.imageset/play-button.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial.imageset/Contents.json deleted file mode 100644 index d5c468cdf..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial.imageset/Contents.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "images" : [ - { - "filename" : "vial_stroke_light.svg", - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "vial_stroke_dark.svg", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial.imageset/vial_stroke_dark.svg b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial.imageset/vial_stroke_dark.svg deleted file mode 100644 index 20e662198..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial.imageset/vial_stroke_dark.svg +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - -image/svg+xml - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial.imageset/vial_stroke_light.svg b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial.imageset/vial_stroke_light.svg deleted file mode 100644 index c17a7abaf..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial.imageset/vial_stroke_light.svg +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - -image/svg+xml - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial_color.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial_color.imageset/Contents.json deleted file mode 100644 index 367a2f16d..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial_color.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "vial_color.svg", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial_color.imageset/vial_color.svg b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial_color.imageset/vial_color.svg deleted file mode 100644 index ebbdcd630..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/vial_color.imageset/vial_color.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - -]> - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/workout.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/workout.imageset/Contents.json deleted file mode 100644 index 6255f94f8..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/workout.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "workout.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/workout.imageset/workout.pdf b/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/workout.imageset/workout.pdf deleted file mode 100644 index 251c7b3b3..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Resources/Assets.xcassets/workout.imageset/workout.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Base.lproj/InsulinKit.storyboard b/Dependencies/LoopKit/LoopKitUI/Resources/Base.lproj/InsulinKit.storyboard deleted file mode 100644 index 76f60035e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Base.lproj/InsulinKit.storyboard +++ /dev/null @@ -1,204 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Base.lproj/LegacyInsulinDeliveryTableViewController.storyboard b/Dependencies/LoopKit/LoopKitUI/Resources/Base.lproj/LegacyInsulinDeliveryTableViewController.storyboard deleted file mode 100644 index 8b619853f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Base.lproj/LegacyInsulinDeliveryTableViewController.storyboard +++ /dev/null @@ -1,209 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/Base.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/Base.lproj/Localizable.strings deleted file mode 100644 index bbc497d99..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/Base.lproj/Localizable.strings +++ /dev/null @@ -1,252 +0,0 @@ -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% of normal insulin"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Absorption Time"; - -/* The title for the override emoji activity section */ -"Activity" = "Activity"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Are you sure you want to delete all history entries?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Are you sure you want to delete all reservoir values?"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Add Account"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Delete Account"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Basal, bolus, and correction insulin dose amounts are decreased by %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Basal, bolus, and correction insulin dose amounts are increased by %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Basal, bolus, and correction insulin dose amounts are unaffected."; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancel"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Cancel Override"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Canceling Temp Basal"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Add Carb Entry"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Edit Carb Entry"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Changes will only apply this time you enable the override. The default settings of %@ will not be affected."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact."; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "at %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "since %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "at %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "since %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* The title for the override emoji condition section */ -"Condition" = "Condition"; - -/* Title of the setup button to continue */ -"Continue" = "Continue"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "Correction range is the blood glucose range that you would like Loop to correct to."; - -/* The text for a custom override */ -"Custom" = "Custom"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Custom Override"; - -/* Title of the carb entry date picker cell */ -"Date" = "Date"; - -/* Button title to delete all objects */ -"Delete All" = "Delete All"; - -/* The text for the override duration setting */ -"Duration" = "Duration"; - -/* The title for the override editing screen */ -"Edit Override" = "Edit Override"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "Editing affects only the active override. The default settings of %@ will not be affected."; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Enable Indefinitely"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Enabled"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Enter a number of units"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Enter a rate in units per hour"; - -/* Section title for fast absorbing food */ -"Fast" = "Fast"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose."; - -/* Placeholder for maximum value in glucose range */ -"max" = "max"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Maximum Basal Rate"; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Maximum Bolus"; - -/* Section title for medium absorbing food */ -"Medium" = "Medium"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* Alert action title to open error help */ -"More Info" = "More Info"; - -/* The text for the override preset name setting */ -"Name" = "Name"; - -/* The title for the new override preset entry screen */ -"New Preset" = "New Preset"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Other"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Overall Insulin Needs"; - -/* The title text for the override presets screen */ -"Override Presets" = "Override Presets"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Override presets can be set up under the 'Configuration' section of the settings screen."; - -/* The section title of glucose overrides */ -"Overrides" = "Overrides"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Pre-Meal"; - -/* The section header text override presets */ -"PRESETS" = "PRESETS"; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Pump Event"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Resume Delivery"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Resuming"; - -/* The text for the override preset name field placeholder */ -"Running" = "Running"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Save"; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "SCHEDULED OVERRIDE"; - -/* Section title for slow absorbing food */ -"Slow" = "Slow"; - -/* The text for the override start time */ -"Start Time" = "Start Time"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starting Temp Basal"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspending"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Symbol"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Tap to set"; - -/* The text for the override target range setting */ -"Target Range" = "Target Range"; - -/* The title for the override selection screen */ -"Temporary Override" = "Temporary Override"; - -/* The default placeholder string for a credential */ -"Required" = "Required"; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "The maximum absorption time is %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "The maximum allowed amount is %@ grams"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Times in %1$@%2$@%3$@"; - -/* The unit string for units per hour */ -"U/hour" = "U/hour"; - -/* The unit string for units */ -"Units" = "Units"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Unknown"; - -/* Label indicating validation is occurring */ -"Verifying" = "Verifying"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Warning"; - -/* Title for the workout override range */ -"Workout" = "Workout"; diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/EmojiInputController.storyboard b/Dependencies/LoopKit/LoopKitUI/Resources/EmojiInputController.storyboard deleted file mode 100644 index 3ba76ad26..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/EmojiInputController.storyboard +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/OverrideSelectionViewController.storyboard b/Dependencies/LoopKit/LoopKitUI/Resources/OverrideSelectionViewController.storyboard deleted file mode 100644 index 63f4253cf..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/OverrideSelectionViewController.storyboard +++ /dev/null @@ -1,341 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/ar.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/ar.lproj/InsulinKit.strings deleted file mode 100644 index 66d8a03c8..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/ar.lproj/InsulinKit.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "عنوان"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "تفاصيل"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "الخزان"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "توصيل الأنسولين"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/ar.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/ar.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 66d8a03c8..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/ar.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "عنوان"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "تفاصيل"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "الخزان"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "توصيل الأنسولين"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/ar.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/ar.lproj/Localizable.strings deleted file mode 100644 index 3a2f27236..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/ar.lproj/Localizable.strings +++ /dev/null @@ -1,67 +0,0 @@ -/* The detail text representing no value */ -"–" = "—"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Add Carb Entry"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "الضخ المستمر"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "إلغاء"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "معاملات الكارب"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "موافق"; - -/* The title for the custom override entry screen */ -"Custom Override" = "تجاوز مخصص"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "حدود الضخ"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Title text for insulin model */ -"Insulin Model" = "نوع الأنسولين"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "حساسية الأنسولين"; - -/* The title text for the override presets screen */ -"Override Presets" = "تخطي الإعدادات المسبقة"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Pre-Meal"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "التأثيرالسريع - كبار"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "التأثيرالسريع - أطفال"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "الخزان"; - -/* The text for the override preset name field placeholder */ -"Running" = "Running"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "النموذج المستخدم بالتطبيق، يسمح بتخصيص مدة الفعالية."; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Unknown"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title for the workout override range */ -"Workout" = "التمارين"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/cs.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/cs.lproj/Localizable.strings deleted file mode 100644 index 3372566f8..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/cs.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Separator between min and max glucose values */ -"-" = "-"; - -/* Information about insulin action duration (1: app name) */ -"%1$@ assumes that the insulin it has delivered is actively working to lower your glucose for 6 hours. This setting cannot be changed." = "%1$@ předpokládá, že inzulín, který podal, aktivně pracuje na snížení hladiny glukózy po dobu 6 hodin. Toto nastavení nelze změnit."; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Přidat účet"; - -/* Back navigation button title */ -"Back" = "Zpět"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Úrovně bazálu"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Zrušit"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* Title of the setup button to continue */ -"Continue" = "Pokračovat"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Smazat účet"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Limity podávání"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Hotovo"; - -/* Information about maximum basal rate (1: app name) */ -"Maximum Basal Rate is the maximum automatically adjusted basal rate that %1$@ is allowed to enact to help reach your correction range." = "Maximální bazální dávka je maximální automaticky upravená bazální dávka, kterou může %1$@ podat, aby vás dostal do vašeho korekčního rozsahu."; - -/* Information about maximum bolus (1: app name) */ -"Maximum Bolus is the highest bolus amount that you will allow %1$@ to recommend at one time to cover carbs or bring down high glucose." = "Maximální bolus je nejvyšší hodnota bolusu, kterou umožníte %1$@ najednou doporučit na pokrytí sacharidů nebo snížení vysoké hladiny glukózy."; - -/* The text for the override preset name setting */ -"Name" = "Název"; - -/* The default placeholder string for a credential */ -"Required" = "Povinné"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Uložit"; - -/* The button text during saving on a configuration page */ -"Saving..." = "Ukládám..."; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Klepnutím nastavit"; - -/* Information about insulin model (1: app name) */ -"You can choose how %1$@ measures rapid acting insulin's peak activity according to one of these two insulin models." = "Můžete si vybrat, jak %1$@ měří nejvyšší aktivitu rychle působícího inzulínu podle jednoho z těchto dvou inzulínových modelů."; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/da.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/da.lproj/InsulinKit.strings deleted file mode 100644 index b36cc0fcc..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/da.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Titel"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detalje"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "E IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "Ingen pumpe konfigureret"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "E Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Hændelseshistorik"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Ikke-pumpe insulin"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulintilførsel"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/da.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/da.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 25a0610a5..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/da.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Titel"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detalje"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "E IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "Ingen pumpe konfigureret"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "E Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Hændelseshistorik"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulintilførsel"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/da.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/da.lproj/Localizable.strings deleted file mode 100644 index decc22994..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/da.lproj/Localizable.strings +++ /dev/null @@ -1,715 +0,0 @@ -/* Information about workout range relative to correction range */ -" higher " = " højere "; - -/* Information about pre-meal range relative to correction range */ -" lower " = " lavere "; - -/* Separator between min and max glucose values */ -"-" = "-"; - -/* No comment provided by engineer. */ -"-" = "-"; - -/* The detail text representing no value */ -"–" = "–"; - -/* No comment provided by engineer. */ -"···" = "···"; - -/* No comment provided by engineer. */ -"%@" = "%@"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% of normal insulin"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Information about insulin action duration (1: app name) */ -"%1$@ assumes that the insulin it has delivered is actively working to lower your glucose for 6 hours. This setting cannot be changed." = "%1$@ antager, at den insulin, der er leveret, arbejder aktivt på at sænke din glukose i 6 timer. Denne indstilling kan ikke ændres."; - -/* Lower bound workout information text format (1: app name) */ -"%1$@ or your Glucose Safety Limit, whichever is higher" = "%1$@ eller din glukose sikkerhedsgrænse afhængigt af, hvad der er højest"; - -/* Reservoir entry (1: volume value) */ -"%1$@ U" = "%1$@ E"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ enheder tilbage på %2$@"; - -/* Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) - Description of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) */ -"%1$@: %2$@ %3$@" = "%1$@: %2$@ %3$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"🍽" = "🍽"; - -/* Premeal override preset title */ -"🍽 Pre-Meal" = "🍽 før-måltid"; - -/* No comment provided by engineer. */ -"🏃‍♂️" = "🏃‍♂️"; - -/* Workout override preset title */ -"🏃‍♂️ Workout" = "🏃‍♂️ Træning"; - -/* No comment provided by engineer. */ -"A card whose text will wrap onto multiple lines if I continue to type for long enough—this length should do" = "Et kort hvis tekst vil ombryde til flere linjer, hvis jeg fortsætter med at skrive længe nok - denne længde bør gøre"; - -/* Information about differences between target range and correction range */ -"A Correction Range is different. This will be a narrower range." = "Et korrektionsområde er anderledes. Dette vil være et snævere interval."; - -/* No comment provided by engineer. */ -"A simple card" = "Et simpelt kort"; - -/* Warning text for basal rate of 0 U/hr */ -"A value of 0 U/hr means you will be scheduled to receive no basal insulin." = "En værdi på 0 E/time betyder, at du ikke vil modtage basal i den angivende tidesperiode."; - -/* No comment provided by engineer. */ -"Above the save button" = "Over gem knappen"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Absorptionstid"; - -/* No comment provided by engineer. */ -"Action Button" = "Handlingsknap"; - -/* The text for the override history duration */ -"Active Duration" = "Aktiv varighed"; - -/* The title for the override emoji activity section */ -"Activity" = "Aktivitet"; - -/* Button text to confirm adding a new schedule item */ -"Add" = "Tilføj"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Tilføj konto"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Tilføj kulhydrater"; - -/* Title of insulin model preset - afrezza */ -"Afrezza" = "Afrezza"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Er du sikker på at du vil slette alle gamle indtastninger?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Er du sikker på at du vil slette alle reservoirværdier?"; - -/* Authentication hint string for therapy settings */ -"Authenticate to save therapy setting" = "Godkend for at gemme behandlingsindstilling"; - -/* Back navigation button title */ -"Back" = "Tilbage"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Basalrater"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Basal-, bolus- og korrektionsinsulindoser er sænket med %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Basal-, bolus- og korrektionsinsulindoser er forøget med %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Basal-, bolus- og korrektionsinsulindoser er uændrede."; - -/* No comment provided by engineer. */ -"Bottom component" = "Nederst komponent"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuller"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Annuller Override"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Annuller midlertidig basal"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Kulhydratforhold"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Ændringer gælder kun ved denne Override. Standardindstillingerne af %@ bliver ikke påvirket."; - -/* Footer text for customizing from a preset (1: preset name) */ -"Changes will only apply this time you enable the preset. The default settings of %@ will not be affected." = "Ændringerne gælder kun denne Override. Standardindstillingerne af %@ bliver ikke påvirket."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Vælg en længere absorptionstid ved større måltider, eller dem med fedt og proteiner. Det er blot hjælp til algoritmen og behøver ikke være nøjagtig."; - -/* Button text to close a modal - Text to close informational page */ -"Close" = "Luk"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "ved %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "siden %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "ved %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "siden %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Completed." = "Fuldført."; - -/* The title for the override emoji condition section */ -"Condition" = "Tilstand"; - -/* The button text for confirming the setting */ -"Confirm Setting" = "Bekræft indstillingerne"; - -/* No comment provided by engineer. */ -"content" = "indhold"; - -/* Title of the setup button to continue */ -"Continue" = "Fortsæt"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "Korrektionsinterval er det blodsukkerinterval, du gerne vil have Loop til at korrigere imod."; - -/* Title text for multi-value correction value warning */ -"Correction Values" = "Korrektionværdier"; - -/* The text for a custom override */ -"Custom" = "Brugerdefineret"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Brugerdefineret Override"; - -/* The title for the custom preset entry screen - The title for the custom preset selection screen */ -"Custom Preset" = "Brugerdefineret forudindstilling"; - -/* Title of the carb entry date picker cell */ -"Date" = "Dato"; - -/* Delete values for Pre-Meal, inactivates Pre-Meal icon - Test for table cell delete button - The title of the button to remove the credentials for a service */ -"Delete" = "Slet"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Slet konto"; - -/* Button title to delete all objects */ -"Delete All" = "Slet alle"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Insulingrænser"; - -/* Information about delivery limits */ -"Delivery Limits are safety guardrails for your insulin delivery." = "Insulingrænser er sikkerhedsgrænser for insulinafgivelsen."; - -/* The text for the custom preset disable button */ -"Disable Preset" = "Deaktiver forudindstilling"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Udført"; - -/* The text for the override duration setting */ -"Duration" = "Varighed"; - -/* Text for edit button - The title for the enabled custom preset editing screen */ -"Edit" = "Rediger"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Rediger kulhydrater"; - -/* The title for the override editing screen */ -"Edit Override" = "Rediger Override"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "Ændringer gælder kun den aktuelle Override. Standardindstillingerne af %@ bliver ikke påvirket."; - -/* Footer text for editing an enabled custom preset (1: preset name) */ -"Edits persist only until the preset is disabled. The default settings of %@ will not be affected." = "Ændringer forbliver kun gældende, indtil forindstillingen deaktiveres. Standardindstillingerne for %@ påvirkes ikke."; - -/* The button text for enabling a temporary override */ -"Enable" = "Aktiver"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Aktiver på ubestemt tid"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Aktiveret"; - -/* The text for the override start time */ -"End Time" = "Sluttidstid"; - -/* Format string for accessibility label for value entry. (1: value label) */ -"Enter %1$@ value" = "Angiv %1$@ værdi"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Indtast antal enheder"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Indtast en mængde i enheder pr time"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Hændelseshistorik"; - -/* No comment provided by engineer. */ -"Example" = "Eksempel"; - -/* Section title for fast absorbing food */ -"Fast" = "Hurtig"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Insulin model setting description (1: app name) (2: number of models) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from %2$@ different models for how the app measures the insulin’s peak activity." = "%1$@ antager, at insulin er aktivt i 6 timer. Du kan vælge mellem %2$@ forskellige modeller for, hvordan Loop bruger insulinets maksimale effekt i sine beregninger."; - -/* Information about correction range format (1: app name) */ -"For this range, choose the specific glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin." = "For dette område skal du vælge det specifikke blodsukker (eller interval), som du vil have %1$@ til at sigte efter, når din basal justeres."; - -/* Support button for Therapy Settings */ -"Get help with Therapy Settings" = "Få hjælp til indstillinger"; - -/* Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range - Text for go back action on confirmation alert */ -"Go Back" = "Gå tilbage"; - -/* Title text for the high basal rate warning */ -"High Basal Rate" = "Høj basalrate"; - -/* Title text for the high carb ratio warning */ -"High Carb Ratio" = "Høj kulhydratforhold"; - -/* Title text for the high correction value warning */ -"High Correction Value" = "Høj korrektionsværdi"; - -/* Title text for the high glucose safety limit warning */ -"High Glucose Safety Limit" = "Høj sikkerhedsgrænse for blodsukker"; - -/* Title text for the high insulin sensitivity warning */ -"High Insulin Sensitivity" = "Høj insulinfølsomhed"; - -/* Title text for high maximum basal rate warning */ -"High Maximum Basal Rate" = "Høj maksimal basalrate"; - -/* Title text for high maximum bolus warning */ -"High Maximum Bolus" = "Maksimal bolus"; - -/* Title text for the low pre-meal value warning */ -"High Pre-Meal Value" = "Høj før-måltid værdi"; - -/* Title text for the high workout value warning */ -"High Workout Value" = "Høj træningsværdi"; - -/* The text for the override history */ -"History" = "Historik"; - -/* Description of how to interact with summary screen */ -"If these settings look good to you, tap Save Settings to continue." = "Hvis indstillingerne er korrekte, skal du trykke på \"Gem indstillinger\" for at fortsætte."; - -/* Information about target range */ -"If you've used a CGM before, you're likely familiar with target range as a wide range of values you'd like for your glucose notification alerts, such as 70-180 mg/dL or 90-200 mg/dL." = "Hvis du har brugt en CGM tidligere, er du sandsynligvis bekendt med at få advarsler ud fra et blodsukkerinterval, såsom 5-10 mmol/L eller 6-12 mmol/L."; - -/* Title text for insulin model */ -"Insulin Model" = "Insulinmodel"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Insulinfølsomheder"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "Insulinfølsomhed beskriver hvordan dit blodsukker påvirkes af 1 enhed insulin. Mindre værdier betyder, at mere insulin vil blive givet, når blodsukkeret er over målet. Værdier der er for små, kan forårsage faretruende lavt blodsukker."; - -/* Description of an interrupted bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: programmed value (? if no value), 4: unit) */ -"Interrupted %1$@: %2$@ of %3$@ %4$@" = "Afbrudt %1$@: %2$@ af %3$@ %4$@"; - -/* Guardrail info text format */ -"It can be set as low as %1$@. It can be set as high as %2$@." = "Det kan sættes så lavt som %1$@. Det kan sættes så højt som %2$@."; - -/* Title text for the low basal rate warning */ -"Low Basal Rate" = "Lav basalrate"; - -/* Title text for the low carb ratio warning */ -"Low Carb Ratio" = "Lav kulhydratforhold"; - -/* Title text for the low correction value warning */ -"Low Correction Value" = "Lav korrektionsværdi"; - -/* Title text for the low glucose safety limit warning */ -"Low Glucose Safety Limit" = "Lav sikkerhedsgrænse for blodsukker"; - -/* Title text for the low insulin sensitivity warning */ -"Low Insulin Sensitivity" = "Lav insulinfølsomhed"; - -/* Title text for low maximum basal rate warning */ -"Low Maximum Basal Rate" = "Lav maksimal basalrate"; - -/* Title text for low maximum bolus warning */ -"Low Maximum Bolus" = "Lav maksimal bolus"; - -/* Title text for the low pre-meal value warning */ -"Low Pre-Meal Value" = "Lav før-måltid værdi"; - -/* Title text for the low workout value warning */ -"Low Workout Value" = "Lav træningsværdi"; - -/* Title of insulin model preset - lyumjev */ -"Lyumjev" = "Lyumjev"; - -/* Placeholder for maximum value in glucose range */ -"max" = "max"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Maksimal basalrate"; - -/* Information about maximum basal rate (1: app name) */ -"Maximum Basal Rate is the maximum automatically adjusted basal rate that %1$@ is allowed to enact to help reach your correction range." = "Maksimal basalrate er den maksimale automatisk justerede basalrate, som %1$@ har lov til at sætte for at hjælpe med at nå dit korrektionsområde."; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Maksimal bolus"; - -/* Information about maximum bolus (1: app name) */ -"Maximum Bolus is the highest bolus amount that you will allow %1$@ to recommend at one time to cover carbs or bring down high glucose." = "Maksimal bolus er den højeste bolus, som du vil tillade %1$@ at anbefale på én gang for at dække kulhydrater eller nedbringe højt blodsukker."; - -/* Section title for medium absorbing food */ -"Medium" = "Medium"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* No comment provided by engineer. */ -"more content" = "yderligere indhold"; - -/* Alert action title to open error help */ -"More Info" = "Mere Info"; - -/* The text for the override preset name setting */ -"Name" = "Navn"; - -/* Title for mini-modal to add a new schedule entry */ -"New Entry" = "Ny indtastning"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Ny Forudindstilling"; - -/* Title text for the zero basal rate warning */ -"No Basal Insulin" = "Ingen basalinsulin"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Anden"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Totalt Insulinbehov"; - -/* Title for override history view */ -"Override History" = "Override historik"; - -/* The title text for the override presets screen */ -"Override Presets" = "Override forudindstillinger"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Forudindstillinger for Overrides kan sættes op i 'Konfigurations\"-delen af Indstillingsskærmen."; - -/* The section title of glucose overrides */ -"Overrides" = "Overrides"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Før-måltid"; - -/* Title text for multi-value pre-meal value warning */ -"Pre-Meal Values" = "Værdier før-måltid"; - -/* title for prescription section */ -"Prescription" = "Recept"; - -/* The section header text override presets */ -"PRESETS" = "FORUDINSTILLINGER"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Progressing." = "Status."; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Pumpe-hændelse"; - -/* Title text for suspend resume button when the basal delivery state is not set */ -"Pump Inoperable" = "Pumpe ubrugelig"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Hurtigt-virkende (Rapid) – Voksne"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Hurtigt-virkende (Rapid) – Børn"; - -/* The default placeholder string for a credential */ -"Required" = "Påkrævet"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Reservoir"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Fortsæt indgivelse"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Fortsætter"; - -/* title for summary description section */ -"Review and Save Settings" = "Gennemse og gem indstillinger"; - -/* Description of how to interact with summary screen */ -"Review your therapy settings below. If you’d like to edit any of these settings, tap Back to go back to that screen." = "Gennemgå dine behandlingsindstillinger nedenfor. Hvis du vil redigere en af disse indstillinger, skal du trykke på \"Tilbage\" for at gå tilbage til denne skærm."; - -/* The text for the override preset name field placeholder */ -"Running" = "Løber"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Gem"; - -/* Alert title for confirming basal rates outside the recommended range */ -"Save Basal Rates?" = "Gem basalrater?"; - -/* Alert title for confirming carb ratios outside the recommended range */ -"Save Carb Ratios?" = "Gem kulhydratforhold?"; - -/* Alert title for confirming correction ranges outside the recommended range */ -"Save Correction Range(s)?" = "Gem korrektionsområde(er)?"; - -/* Alert title for confirming delivery limits outside the recommended range */ -"Save Delivery Limits?" = "Gem insulin-grænser?"; - -/* Alert title for confirming a glucose safety limit outside the recommended range */ -"Save Glucose Safety Limit?" = "Gem sikkerhedsgrænse for blodsukker?"; - -/* Alert title for confirming insulin sensitivities outside the recommended range */ -"Save Insulin Sensitivities?" = "Gem insulinfølsomheder?"; - -/* Alert title for confirming pre-meal range overrides outside the recommended range */ -"Save Pre-Meal Range?" = "Gem før-måltid område?"; - -/* Alert title for confirming workout range overrides outside the recommended range */ -"Save Workout Range?" = "Vil du gemme træningsområdet?"; - -/* The button text during saving on a configuration page */ -"Saving..." = "Gemmer..."; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "PLANLAGT OVERRIDE"; - -/* The section header text for a scheduled custom preset */ -"SCHEDULED PRESET" = "PLANLAGT FORUDINDSTILLING"; - -/* Section title for slow absorbing food */ -"Slow" = "Langsom"; - -/* Information about typical maximum basal rates */ -"Some users choose a value 2, 3, or 4 times their highest scheduled basal rate." = "Nogle brugere vælger en værdi 2, 3 eller 4 gange deres højeste basalrate."; - -/* The text for the override start time */ -"Start Time" = "Starttidspunkt"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starter midlertidig basal"; - -/* Format for prescription descriptive text (1: providerName, 2: datePrescribed) */ -"Submitted by %1$@, %2$@" = "Indsendt af %1$@, %2$@"; - -/* Title for support section */ -"Support" = "Support"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Afbryd insulintilførsel"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Afbryder"; - -/* No comment provided by engineer. */ -"Switch Preview State" = "Skift forhåndsvisningstilstand"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Symbol"; - -/* Text directing the user to configure their first custom preset */ -"Tap '+' to create a new custom preset." = "Tryk på '+' for at oprette en ny brugerdefineret forudindstilling."; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Tryk for at gemme"; - -/* The text for the override target range setting */ -"Target Range" = "Målområde"; - -/* Description of pre-meal mode */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Sænker midlertidigt dit blodsukker mål før et måltid for at modvirke stigning i blodsukker efter måltidet."; - -/* Description of workout mode */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Hæver midlertidigt dit blodsukkermål før, under eller efter fysisk aktivitet for at reducere risikoen for lavt blodsukker."; - -/* The title for the override selection screen */ -"Temporary Override" = "Midlertidig Override"; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"than your Correction Range." = "end dit korrektionsområde."; - -/* Description for selection when no insulin type is selected. */ -"The currently selected fast acting insulin model will be used as a default." = "Den aktuelt valgte hurtigtvirkende insulinmodel anvendes som standard."; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Ældre model, der bruges af Loop, og som gør det muligt at tilpasse insulinens varighed."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "Den maksimale absorptionstid er %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "Den maksimalt tilladte mængde er %@ gram"; - -/* Information about adult insulin model */ -"The rapid-acting adult model assumes peak activity at 75 minutes." = "Den hurtigvirkende insulinmodel for voksne antager maksimal effekt ved 75 minutter."; - -/* Information about child insulin model */ -"The rapid-acting child model assumes peak activity at 65 minutes." = "Den hurtigvirkende insulinmodel for voksne antager maksimal effekt ved 65 minutter."; - -/* Information about basal rate scheduling */ -"The schedule starts at midnight and cannot contain a rate of 0 U/hr." = "Tidsplanen starter ved midnat og kan ikke indeholde en dosis på 0 E/time."; - -/* Therapy Settings screen title */ -"Therapy Settings" = "Behandlingsindstillinger"; - -/* No comment provided by engineer. */ -"Therapy Settings Support Placeholder" = "Placeholder for behandlingsindstillinger"; - -/* Subtitle of afrezza preset */ -"This model assumes peak insulin activity at 19 minutes." = "Denne model forudsætter peak insulinaktivitet på 19 minutter."; - -/* Subtitle of Fiasp preset - Subtitle of Lyumjev preset */ -"This model assumes peak insulin activity at 55 minutes." = "Denne model forudsætter peak insulinaktivitet på 55 minutter."; - -/* Subtitle of Rapid-Acting – Children preset */ -"This model assumes peak insulin activity at 65 minutes." = "Denne model forudsætter maksimal effekt ved 65 minutter."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"This model assumes peak insulin activity at 75 minutes." = "Denne model forudsætter maksimal effekt ved 75 minutter."; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"This will typically be" = "Dette vil typisk være"; - -/* Label for offset from midnight picker */ -"Time" = "Tid"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Tider i %1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"To be implemented" = "Ikke implementeret"; - -/* No comment provided by engineer. */ -"Top component" = "Top-komponent"; - -/* The text indicating Total for Daily Schedule Basal */ -"Total" = "Total"; - -/* The text indicating U/day for Daily Schedule Basal */ -"U/day" = "E/dag"; - -/* The unit string for units per hour */ -"U/hour" = "E/time"; - -/* Alert title when error occurs while saving a schedule */ -"Unable to Save" = "Kunne ikke gemme"; - -/* The unit string for units */ -"Units" = "Enheder"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Ukendt"; - -/* Title for selection when no insulin type is selected. */ -"Unset" = "Ikke-indstillet"; - -/* Placeholder text until value is entered */ -"Value" = "Værdi"; - -/* Label indicating validation is occurring */ -"Verifying" = "Validerer"; - -/* The title for the override editing screen */ -"View Override" = "Vis override"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Advarsel"; - -/* Disclaimer */ -"Work with your healthcare provider to choose a value that is higher than your highest scheduled basal rate, but as conservative or aggressive as you feel comfortable." = "Arbejd sammen med sundhedspersonalet om at vælge en værdi, der er højere end din højeste planlagte basalrate, men så konservativ eller aggressiv som du føler dig tryg ved."; - -/* Title for the workout override range */ -"Workout" = "Motion"; - -/* Information about workout range format (1: app name) */ -"Workout Range is the glucose value or range of values you want %1$@ to target during activity. This range will be in effect when you activate the Workout Preset button." = "Træningsområde er den blodsukkerværdi eller værdiinterval, du ønsker %1$@ at målrette under aktivitet. Dette interval vil bruges, når du aktiverer knappen som Preset for træning."; - -/* Title text for multi-value workout value warning */ -"Workout Values" = "Værdier for træning"; - -/* Description of how to add a ratio */ -"You can add different carb ratios for different times of day by using the ➕." = "Du kan tilføje forskellige kulhydratforhold for forskellige tidspunkter af dagen ved hjælp af ➕."; - -/* Description of how to add a ratio */ -"You can add different insulin sensitivities for different times of day by using the ➕." = "Du kan tilføje forskellige insulinfølsomheder for forskellige tidspunkter af dagen ved at bruge ➕."; - -/* Description of how to add a configuration range */ -"You can add different ranges for different times of day by using the ➕." = "Du kan tilføje forskellige intervaller for forskellige tidspunkter af dagen ved at bruge ➕."; - -/* Description of how to add a range */ -"You can add entries for different times of day by using the ➕." = "Du kan tilføje forskellige poster for forskellige tidspunkter af dagen ved at bruge ➕."; - -/* Information about insulin model (1: app name) */ -"You can choose how %1$@ measures rapid acting insulin's peak activity according to one of these two insulin models." = "Du kan vælge, hvordan %1$@ måler hurtigtvirkende insulins maksimale aktivitet i henhold til en af disse to insulinmodeller."; - -/* Description of how to edit setting */ -"You can edit a setting by tapping into any line item." = "Du kan redigere en indstilling ved at trykke på en linje."; - -/* Description of how to edit setting */ -"You can edit the setting by tapping into the line item." = "Du kan redigere indstillingen ved at trykke på linjen."; - -/* Information about basal rates */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "En basalrate, er det antal af enheder i timen, som du skal bruge for at dække dit basale insulinbehov."; - -/* Lower bound pre-meal information text */ -"your Glucose Safety Limit" = "din sikkerhedsgrænse for blodsukker"; - -/* Disclaimer */ -"Your healthcare provider can help you choose a Correction Range that's right for you." = "Din læge kan hjælpe dig med at vælge et korrektionsområde, der passer til dig."; - -/* Description of insulin sensitivity factor */ -"Your Insulin Sensitivity Factor (ISF) is the drop in glucose expected from one unit of insulin." = "Insulinfølsomhed (ISF) henviser til det fald i blodsukkeret, der forventes fra én insulinenhed."; - -/* Information about pre-meal range format (1: app name) */ -"Your Pre-Meal Range should be the glucose value (or range of values) you want %1$@ to target by the time you take your first bite of your meal. This range will be in effect when you activate the Pre-Meal Preset button." = "Dit før-måltid-område bør være den glukoseværdi (eller værdiinterval), du vil have %1$@ til at målrette efter det tidspunkt, du starter med at spise. Dette interval vil bruges, når du aktiverer knappen før-måltid."; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/de.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/de.lproj/InsulinKit.strings deleted file mode 100644 index bd02fdf3f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/de.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Titel"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "IE IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "IE Gesamt"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Ereignisverlauf"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Externes Insulin"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/de.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/de.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 11ac3138c..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/de.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Titel"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "IE IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Ereignisverlauf"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/de.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/de.lproj/Localizable.strings deleted file mode 100644 index f89d914a0..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/de.lproj/Localizable.strings +++ /dev/null @@ -1,721 +0,0 @@ -/* Information about workout range relative to correction range */ -" higher " = " höher "; - -/* Information about pre-meal range relative to correction range */ -" lower " = " niedriger "; - -/* Separator between min and max glucose values */ -"-" = "-"; - -/* No comment provided by engineer. */ -"-" = "-"; - -/* The detail text representing no value */ -"–" = "–"; - -/* No comment provided by engineer. */ -"···" = "···"; - -/* No comment provided by engineer. */ -"%@" = "%@"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% von normalem Insulin"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Information about insulin action duration (1: app name) */ -"%1$@ assumes that the insulin it has delivered is actively working to lower your glucose for 6 hours. This setting cannot be changed." = "%1$@ nimmt an, dass das abgegebene Insulin für 6 Stunden wirkt, um den Blutzucker zu senken. Diese Einstellung kann nicht geändert werden."; - -/* Lower bound workout information text format (1: app name) */ -"%1$@ or your Glucose Safety Limit, whichever is higher" = "%1$@ oder Deine Sicherheitsgrenze, je nachdem, welcher Wert höher ist"; - -/* Information about max number of basal rates (1: app name) (2: maximum schedule entry count) */ -"%1$@ supports 1 to %2$@ rates per day." = "%1$@ unterstützt 1 bis %2$@ Raten pro Tag."; - -/* Reservoir entry (1: volume value) */ -"%1$@ U" = "%1$@ IE"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ IE verbleibend bei %2$@"; - -/* Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) - Description of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) */ -"%1$@: %2$@ %3$@" = "%1$@: %2$@ %3$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"🍽" = "🍽"; - -/* Premeal override preset title */ -"🍽 Pre-Meal" = "🍽 Vor dem Essen"; - -/* No comment provided by engineer. */ -"🏃‍♂️" = "🏃‍♂️"; - -/* Workout override preset title */ -"🏃‍♂️ Workout" = "🏃‍♂️ Training"; - -/* No comment provided by engineer. */ -"A card whose text will wrap onto multiple lines if I continue to type for long enough—this length should do" = "Eine Karte, deren Text in mehrere Zeilen umbrochen wird, wenn ich lange genug einsetze – diese Länge sollte"; - -/* Information about differences between target range and correction range */ -"A Correction Range is different. This will be a narrower range." = "Der Korrekturbereich ist anders als der Zielbereich und wird enger sein."; - -/* No comment provided by engineer. */ -"A simple card" = "Eine einfache Karte"; - -/* Warning text for basal rate of 0 U/hr */ -"A value of 0 U/hr means you will be scheduled to receive no basal insulin." = "Ein Wert von 0 IE/h heißt, dass Sie in dieser Zeit kein Basalinsulin erhalten."; - -/* No comment provided by engineer. */ -"Above the save button" = "Über dem Speichern-Knopf"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Resorptionsdauer"; - -/* No comment provided by engineer. */ -"Action Button" = "Aktions-Knopf"; - -/* The text for the override history duration */ -"Active Duration" = "Dauer"; - -/* The title for the override emoji activity section */ -"Activity" = "Aktivität"; - -/* Button text to confirm adding a new schedule item */ -"Add" = "Hinzufügen"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Konto hinzufügen"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Kohlenhydrate hinzufügen"; - -/* Title of insulin model preset - afrezza */ -"Afrezza" = "Afrezza"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Möchtest Du wirklich alle Verlaufseinträge löschen?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Möchtest Du wirklich alle Reservoirwerte löschen?"; - -/* Authentication hint string for therapy settings */ -"Authenticate to save therapy setting" = "Authentisiere Dich zum Speichern der Therapieeinstellungen"; - -/* Back navigation button title */ -"Back" = "Zurück"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Basalrate"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Basal-, Bolus- und Korrekturinsulinmengen werden verringert um %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Basal-, Bolus- und Korrekturinsulinmengen werden erhöht um %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Basal-, Bolus- und Korrekturinsulindosismengen bleiben unverändert."; - -/* No comment provided by engineer. */ -"Bottom component" = "Unterseitenkomponente"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Abbrechen"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Override abbrechen"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Temporäre Basalrate abbrechen"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "KH-Verhältnis"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Änderungen werden nur dann wirksam, wenn Du die Voreinstellung aktivierst. Die Standardeinstellungen von %@ werden nicht beeinflusst."; - -/* Footer text for customizing from a preset (1: preset name) */ -"Changes will only apply this time you enable the preset. The default settings of %@ will not be affected." = "Änderungen gelten nur, wenn Sie die Voreinstellung aktivieren. Die Standardeinstellungen von %@ werden nicht beeinflusst."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Wähle eine längere Resorptionsdauer für größere Mahlzeiten, oder welche die viel Fett und Proteine beinhalten. Dies ist eine Unterstützung für den Algorithmus und muss nicht genau sein."; - -/* Button text to close a modal - Text to close informational page */ -"Close" = "Schliessen"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "um %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "seit %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "um %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "seit %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Completed." = "Fertig."; - -/* The title for the override emoji condition section */ -"Condition" = "Bedingung"; - -/* The button text for confirming the setting */ -"Confirm Setting" = "Bestätige die Einstellungen"; - -/* No comment provided by engineer. */ -"content" = "Inhalt"; - -/* Title of the setup button to continue */ -"Continue" = "Weiter"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "Der Korrekturbereich ist der Blutzuckerbereich, auf den Loop korrigieren soll."; - -/* Title text for multi-value correction value warning */ -"Correction Values" = "Korrekturwerte"; - -/* The text for a custom override */ -"Custom" = "Benutzerdefiniert"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Benutzerdefinierter Override"; - -/* The title for the custom preset entry screen - The title for the custom preset selection screen */ -"Custom Preset" = "Voreinstellung"; - -/* Title of the carb entry date picker cell */ -"Date" = "Datum"; - -/* Delete values for Pre-Meal, inactivates Pre-Meal icon - Test for table cell delete button - The title of the button to remove the credentials for a service */ -"Delete" = "Löschen"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Konto löschen"; - -/* Button title to delete all objects */ -"Delete All" = "Alle löschen"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Abgabelimits"; - -/* Information about delivery limits */ -"Delivery Limits are safety guardrails for your insulin delivery." = "Abgabelimits sind Leitplanken für Deine Insulinabgabe."; - -/* The text for the custom preset disable button */ -"Disable Preset" = "Deaktiviere Voreinstellung"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Fertig"; - -/* The text for the override duration setting */ -"Duration" = "Dauer"; - -/* Text for edit button - The title for the enabled custom preset editing screen */ -"Edit" = "Bearbeiten"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "KH-Eintrag bearbeiten"; - -/* The title for the override editing screen */ -"Edit Override" = "Bearbeite Voreinstellung"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "Die Bearbeitung wirkt sich nur auf die aktive Voreinstellung aus. Die Standardeinstellungen von %@ werden nicht beeinflusst."; - -/* Footer text for editing an enabled custom preset (1: preset name) */ -"Edits persist only until the preset is disabled. The default settings of %@ will not be affected." = "Änderungen bleiben nur bestehen, bis die Voreinstellung deaktiviert wird. Die Standardeinstellungen von %@ werden nicht beeinflusst."; - -/* The button text for enabling a temporary override */ -"Enable" = "Aktivieren"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Aktiviere unbegrenzt"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Aktiviert"; - -/* The text for the override start time */ -"End Time" = "Endzeit"; - -/* Format string for accessibility label for value entry. (1: value label) */ -"Enter %1$@ value" = "Wert für %1$@"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Eingabe der Einheiten"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Eingabe Rate in Einheiten pro Stunde"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Ereignisverlauf"; - -/* No comment provided by engineer. */ -"Example" = "Beispiel"; - -/* Section title for fast absorbing food */ -"Fast" = "Schnell"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Insulin model setting description (1: app name) (2: number of models) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from %2$@ different models for how the app measures the insulin’s peak activity." = "Bei schnell wirkendem Insulin geht %1$@ davon aus, dass es 6 Stunden lang wirkt. Du kannst aus %2$@ verschiedenen Modellen wählen, wie die App die Spitzenaktivität des Insulins misst."; - -/* Information about correction range format (1: app name) */ -"For this range, choose the specific glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin." = "Wähle für diesen Bereich den spezifischen Blutzucker (oder Wertebereich) aus, den %1$@ bei der Anpassung Deines Basalinsulins anstreben soll."; - -/* Support button for Therapy Settings */ -"Get help with Therapy Settings" = "Bekomme Unterstützung bei den Therapieeinstellungen"; - -/* Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range - Text for go back action on confirmation alert */ -"Go Back" = "Zurück"; - -/* Title text for the high basal rate warning */ -"High Basal Rate" = "Hohe Basalrate"; - -/* Title text for the high carb ratio warning */ -"High Carb Ratio" = "Hohes Kohlenhydratverhältnis"; - -/* Title text for the high correction value warning */ -"High Correction Value" = "Hoher Korrekturwert"; - -/* Title text for the high glucose safety limit warning */ -"High Glucose Safety Limit" = "Hohe Blutzuckersicherheitsgrenze"; - -/* Title text for the high insulin sensitivity warning */ -"High Insulin Sensitivity" = "Hohe Insulinempfindlichkeit"; - -/* Title text for high maximum basal rate warning */ -"High Maximum Basal Rate" = "Hohe maximale Basalrate"; - -/* Title text for high maximum bolus warning */ -"High Maximum Bolus" = "Hoher maximaler Bolus"; - -/* Title text for the low pre-meal value warning */ -"High Pre-Meal Value" = "Hoher Vor dem Essen Wert"; - -/* Title text for the high workout value warning */ -"High Workout Value" = "Hoher Trainings Wert"; - -/* The text for the override history */ -"History" = "Historie"; - -/* Description of how to interact with summary screen */ -"If these settings look good to you, tap Save Settings to continue." = "Wenn diese Einstellungen für Dich gut aussehen, tippe auf Einstellungen speichern, um fortzufahren."; - -/* Information about target range */ -"If you've used a CGM before, you're likely familiar with target range as a wide range of values you'd like for your glucose notification alerts, such as 70-180 mg/dL or 90-200 mg/dL." = "Wenn Du bereits ein CGM verwendest, bist Du wahrscheinlich mit einem Zielbereich vertraut, den Du für Deinen Blutzuckeralarm verwendest, z. B. 70–180 mg/dL oder 90–200 mg/dL."; - -/* Title text for insulin model */ -"Insulin Model" = "Insulin-Modell"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Insulinempfindlichkeit"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "Die Insulinempfindlichkeit beschreibt, wie Dein Blutzucker auf die Insulindosis von 1 Einheit reagiert. Kleinere Werte bedeuten, dass mehr Insulin verabreicht wird, wenn der Blutzucker über dem Ziel liegt. Zu kleine Werte können gefährlich niedrige Blutzuckerwerte verursachen."; - -/* Description of an interrupted bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: programmed value (? if no value), 4: unit) */ -"Interrupted %1$@: %2$@ of %3$@ %4$@" = "%1$@ unterbrochen: %2$@ von %3$@ %4$@"; - -/* Guardrail info text format */ -"It can be set as low as %1$@. It can be set as high as %2$@." = "Es kann auf %1$@ eingestellt werden. Es kann bis zu %2$@ eingestellt werden."; - -/* Title text for the low basal rate warning */ -"Low Basal Rate" = "Niedrige Basalrate"; - -/* Title text for the low carb ratio warning */ -"Low Carb Ratio" = "Niedriges Kohlenhydratverhältnis"; - -/* Title text for the low correction value warning */ -"Low Correction Value" = "Niedriger Korrekturwert"; - -/* Title text for the low glucose safety limit warning */ -"Low Glucose Safety Limit" = "Niedrige Blutzuckersicherheistgrenze"; - -/* Title text for the low insulin sensitivity warning */ -"Low Insulin Sensitivity" = "Niedrige Insulinempfindlichkeit"; - -/* Title text for low maximum basal rate warning */ -"Low Maximum Basal Rate" = "Niedrige maximale Basalrate"; - -/* Title text for low maximum bolus warning */ -"Low Maximum Bolus" = "Niedriger maximaler Bolus"; - -/* Title text for the low pre-meal value warning */ -"Low Pre-Meal Value" = "Niedriger Vor dem Essen Wert"; - -/* Title text for the low workout value warning */ -"Low Workout Value" = "Niedriger Trainings Wert"; - -/* Title of insulin model preset - lyumjev */ -"Lyumjev" = "Lyumjev"; - -/* Placeholder for maximum value in glucose range */ -"max" = "max"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Maximale Basalrate"; - -/* Information about maximum basal rate (1: app name) */ -"Maximum Basal Rate is the maximum automatically adjusted basal rate that %1$@ is allowed to enact to help reach your correction range." = "Die maximale Basalrate ist die maximale automatisch angepasste Basalrate, die %1$@ anwenden darf, um Deinen Korrekturbereich zu erreichen."; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Maximaler Bolus"; - -/* Information about maximum bolus (1: app name) */ -"Maximum Bolus is the highest bolus amount that you will allow %1$@ to recommend at one time to cover carbs or bring down high glucose." = "Maximaler Bolus ist die höchste Bolusmenge, die Du %1$@ auf einmal erlaubst zu geben, um Kohlenhydrate abzudecken oder hohe Glukosewerte zu senken."; - -/* Section title for medium absorbing food */ -"Medium" = "Mittlere"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* No comment provided by engineer. */ -"more content" = "mehr Inhalt"; - -/* Alert action title to open error help */ -"More Info" = "Weitere Info"; - -/* The text for the override preset name setting */ -"Name" = "Name"; - -/* Title for mini-modal to add a new schedule entry */ -"New Entry" = "Neuer Eintrag"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Neue Voreinstellung"; - -/* Title text for the zero basal rate warning */ -"No Basal Insulin" = "Kein Basal Insulin"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Andere"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Gesamtinsulinbedarf"; - -/* Title for override history view */ -"Override History" = "Historie"; - -/* The title text for the override presets screen */ -"Override Presets" = "Voreinstellungen"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Voreinstellungen der Overrides können im Abschnitt Konfiguration des Einstellungsbildschirms eingerichtet werden."; - -/* The section title of glucose overrides */ -"Overrides" = "Overrides"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Vor dem Essen"; - -/* Title text for multi-value pre-meal value warning */ -"Pre-Meal Values" = "Vor dem Essen Wert"; - -/* title for prescription section */ -"Prescription" = "Verschreibung"; - -/* The section header text override presets */ -"PRESETS" = "VOREINSTELLUNGEN"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Progressing." = "Verarbeite…"; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Pumpen-Ereignis"; - -/* Title text for suspend resume button when the basal delivery state is not set */ -"Pump Inoperable" = "Pumpe funktionsunfähig"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Schnellwirkend - Erwachsene"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Schnellwirkend - Kinder"; - -/* The default placeholder string for a credential */ -"Required" = "Erforderlich"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Reservoir"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Abgabe fortsetzen"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Fortsetzen"; - -/* title for summary description section */ -"Review and Save Settings" = "Überprüfen und Speichern"; - -/* Description of how to interact with summary screen */ -"Review your therapy settings below. If you’d like to edit any of these settings, tap Back to go back to that screen." = "Überprüfe Deine Therapieeinstellungen. Wenn Du eine dieser Einstellungen bearbeiten möchtest, tippe auf Zurück, um zum Bearbeiten-Bildschirm zurückzukehren."; - -/* The text for the override preset name field placeholder */ -"Running" = "Laufen"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Speichern"; - -/* Alert title for confirming basal rates outside the recommended range */ -"Save Basal Rates?" = "Basalrate speichern?"; - -/* Alert title for confirming carb ratios outside the recommended range */ -"Save Carb Ratios?" = "Kohlenhydrateverhältnis speichern?"; - -/* Alert title for confirming correction ranges outside the recommended range */ -"Save Correction Range(s)?" = "Korrekturbereich(e) speichern?"; - -/* Alert title for confirming delivery limits outside the recommended range */ -"Save Delivery Limits?" = "Abgabelimits speichern?"; - -/* Alert title for confirming a glucose safety limit outside the recommended range */ -"Save Glucose Safety Limit?" = "Blutzuckersicherheitsgrenze speichern?"; - -/* Alert title for confirming insulin sensitivities outside the recommended range */ -"Save Insulin Sensitivities?" = "Insulinempfindlöichkeit speichern?"; - -/* Alert title for confirming pre-meal range overrides outside the recommended range */ -"Save Pre-Meal Range?" = "Vor dem Essen speichern?"; - -/* Alert title for confirming workout range overrides outside the recommended range */ -"Save Workout Range?" = "Trainingsbereich speichern?"; - -/* The button text during saving on a configuration page */ -"Saving..." = "Speichere…"; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "GEPLANTER OVERRIDE"; - -/* The section header text for a scheduled custom preset */ -"SCHEDULED PRESET" = "GEPLANTE VOREINSTELLUNG"; - -/* Section title for slow absorbing food */ -"Slow" = "Langsam"; - -/* Information about typical maximum basal rates */ -"Some users choose a value 2, 3, or 4 times their highest scheduled basal rate." = "Manche Benutzer wählen einen Wert, der dem 2-, 3- oder 4-fachen ihrer höchsten geplanten Basalrate entspricht."; - -/* The text for the override start time */ -"Start Time" = "Startzeit"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starten der temporären Basalrate"; - -/* Format for prescription descriptive text (1: providerName, 2: datePrescribed) */ -"Submitted by %1$@, %2$@" = "Abgegeben von %1$@, %2$@"; - -/* Title for support section */ -"Support" = "Unterstützung"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Abgabe unterbrechen"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Unterbrechen"; - -/* No comment provided by engineer. */ -"Switch Preview State" = "Vorschaustatus wechseln"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Symbol"; - -/* Text directing the user to configure their first custom preset */ -"Tap '+' to create a new custom preset." = "Tippe '+' um eine Benutzer definierte Voreinstellung zu erstellen."; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Klicken zum setzten"; - -/* The text for the override target range setting */ -"Target Range" = "Zielbereich"; - -/* Description of pre-meal mode */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Senke Deinen Blutzuckerziel vor einer Mahlzeit vorübergehend ab, um Blutzuckerspitzen nach der Mahlzeit auszugleichen."; - -/* Description of workout mode */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Erhöhe Dein Blutzuckerziel vorübergehend vor, während oder nach körperlicher Aktivität, um das Risiko von Ereignissen mit niedrigem Blutzucker zu verringern."; - -/* The title for the override selection screen */ -"Temporary Override" = "Vorübergehende Override"; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"than your Correction Range." = "als Ihr Korrekturbereich."; - -/* Description for selection when no insulin type is selected. */ -"The currently selected fast acting insulin model will be used as a default." = "Das aktuell ausgewählte schnell wirkende Insulinmodell wird als Standard verwendet."; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Das von Loop verwendete Legacy-Modell, das die Anpassung der Aktionsdauer ermöglicht."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "Die maximale Resorptionszeit beträgt %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "Die maximale Anzahl an Gramm is %@ grams"; - -/* Information about adult insulin model */ -"The rapid-acting adult model assumes peak activity at 75 minutes." = "Das schnell wirkende Erwachsenenmodell geht von einer maximalen Aktivität nach 75 Minuten aus."; - -/* Information about child insulin model */ -"The rapid-acting child model assumes peak activity at 65 minutes." = "Das schnell wirkende Kindermodell geht von einer Spitzenaktivität nach 65 Minuten aus."; - -/* Information about basal rate scheduling */ -"The schedule starts at midnight and cannot contain a rate of 0 U/hr." = "Der Zeitplan beginnt um Mitternacht und darf keine Rate von 0 IE/h enthalten."; - -/* Therapy Settings screen title */ -"Therapy Settings" = "Therapieeinstellungen"; - -/* No comment provided by engineer. */ -"Therapy Settings Support Placeholder" = "Therapieeinstellungen"; - -/* Subtitle of afrezza preset */ -"This model assumes peak insulin activity at 19 minutes." = "Dieses Modell geht von einer maximalen Insulinaktivität nach 19 Minuten aus."; - -/* Subtitle of Fiasp preset - Subtitle of Lyumjev preset */ -"This model assumes peak insulin activity at 55 minutes." = "Dieses Modell geht von einer maximalen Insulinaktivität nach 55 Minuten aus."; - -/* Subtitle of Rapid-Acting – Children preset */ -"This model assumes peak insulin activity at 65 minutes." = "Dieses Modell geht von einer maximalen Insulinaktivität nach 65 Minuten aus."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"This model assumes peak insulin activity at 75 minutes." = "Dieses Modell geht von einer maximalen Insulinaktivität nach 75 Minuten aus."; - -/* Information about maximum automated insulin on board (1: app name) */ -"This setting will also determine a safety limit for automatic dosing. %1$@ will limit automatic delivery to keep the amount of active insulin below twice your maximum bolus." = "Diese Einstellung bestimmt auch eine Sicherheitsgrenze für die automatische Dosierung. %1$@ begrenzt die automatische Abgabe, um die Menge an aktivem Insulin unter dem Doppelten Deines maximalen Bolus zu halten."; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"This will typically be" = "Ist in der Regel "; - -/* Label for offset from midnight picker */ -"Time" = "Zeit"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Zeit in %1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"To be implemented" = "Zu implementieren"; - -/* No comment provided by engineer. */ -"Top component" = "Oben Komponente"; - -/* The text indicating Total for Daily Schedule Basal */ -"Total" = "Gesamt"; - -/* The text indicating U/day for Daily Schedule Basal */ -"U/day" = "IE/Tag"; - -/* The unit string for units per hour */ -"U/hour" = "IE/Stunde"; - -/* Alert title when error occurs while saving a schedule */ -"Unable to Save" = "Speichern fehlgeschlagen"; - -/* The unit string for units */ -"Units" = "Einheiten"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Unbekannt"; - -/* Title for selection when no insulin type is selected. */ -"Unset" = "nicht gesetzt"; - -/* Placeholder text until value is entered */ -"Value" = "Wert"; - -/* Label indicating validation is occurring */ -"Verifying" = "Überprüfen"; - -/* The title for the override editing screen */ -"View Override" = "Zeige Voreinstellung"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Warnung"; - -/* Disclaimer */ -"Work with your healthcare provider to choose a value that is higher than your highest scheduled basal rate, but as conservative or aggressive as you feel comfortable." = "Arbeite mit Deinem medizinischen Betreuer zusammen, um einen Wert zu finden, der höher ist als Deine höchste geplante Basalrate, aber so konservativ oder aggressiv, sodass Du Dich damit wohlfühlst."; - -/* Title for the workout override range */ -"Workout" = "Training"; - -/* Information about workout range format (1: app name) */ -"Workout Range is the glucose value or range of values you want %1$@ to target during activity. This range will be in effect when you activate the Workout Preset button." = "Trainingsbereich ist der Blutzuckerzielbereich, den %1$@ während der Aktivität anstreben soll. Dieser Bereich wird wirksam, wenn Du die Trainingsvoreinstellungstaste aktivierst."; - -/* Title text for multi-value workout value warning */ -"Workout Values" = "Trainingswerte"; - -/* Description of how to add a ratio */ -"You can add different carb ratios for different times of day by using the ➕." = "Mit ➕ kannst Du unterschiedliche Kohlenhydratverhältnisse für verschiedene Tageszeiten hinzufügen."; - -/* Description of how to add a ratio */ -"You can add different insulin sensitivities for different times of day by using the ➕." = "Mit ➕ kannst Du unterschiedliche Insulinempfindlichkeiten für verschiedene Tageszeiten hinzufügen."; - -/* Description of how to add a configuration range */ -"You can add different ranges for different times of day by using the ➕." = "Mit ➕ kannst Du unterschiedliche Bereiche für verschiedene Tageszeiten hinzufügen."; - -/* Description of how to add a range */ -"You can add entries for different times of day by using the ➕." = "Mit ➕ kannst Du Einträge für verschieden Tageszeiten hinzufügen."; - -/* Information about insulin model (1: app name) */ -"You can choose how %1$@ measures rapid acting insulin's peak activity according to one of these two insulin models." = "Du kannst wählen, wie %1$@ die Spitzenaktivität des schnell wirkenden Insulins gemäß einem dieser beiden Insulinmodelle misst."; - -/* Description of how to edit setting */ -"You can edit a setting by tapping into any line item." = "Du kannst eine Einstellung bearbeiten, indem Du auf eine beliebige Zeile tippst."; - -/* Description of how to edit setting */ -"You can edit the setting by tapping into the line item." = "Du kannst die Einstellung bearbeiten, indem Du auf die Zeile tippst."; - -/* Information about basal rates */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Deine Basalrate ist die Anzahl der Einheiten pro Stunde, die Du verwenden möchtest, um Deinen Hintergrund-Insulinbedarf zu decken."; - -/* Lower bound pre-meal information text */ -"your Glucose Safety Limit" = "Deine Blutzuckersicherheitsgrenze"; - -/* Disclaimer */ -"Your healthcare provider can help you choose a Correction Range that's right for you." = "Ihr medizinischer Betreuer kann Ihnen bei der Auswahl eines für Sie geeigneten Korrekturbereichs behilflich sein."; - -/* Description of insulin sensitivity factor */ -"Your Insulin Sensitivity Factor (ISF) is the drop in glucose expected from one unit of insulin." = "Der Insulinempfindlichkeitsfaktor (ISF) ist der Blutzuckerabfall, der von einer Einheit Insulin erwartet wird."; - -/* Information about pre-meal range format (1: app name) */ -"Your Pre-Meal Range should be the glucose value (or range of values) you want %1$@ to target by the time you take your first bite of your meal. This range will be in effect when you activate the Pre-Meal Preset button." = "Der Bereich vor dem Essen sollte der Blutzucker sein, den %1$@ bis zum ersten Bissen Deiner Mahlzeit anstreben soll. Dieser Bereich wird wirksam, wenn Du die Voreinstellungstaste vor dem Essen aktivierst."; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/en.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/en.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index d0c49cd62..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/en.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/en.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/en.lproj/Localizable.strings deleted file mode 100644 index 9099ee8b0..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/en.lproj/Localizable.strings +++ /dev/null @@ -1,8 +0,0 @@ -/* - Localizable.strings - LoopKit - - Created by Pete Schwamb on 3/19/23. - Copyright © 2023 LoopKit Authors. All rights reserved. -*/ - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/es.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/es.lproj/InsulinKit.strings deleted file mode 100644 index 348dd7270..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/es.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Título"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detalle"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservorio"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Historial de Eventos"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Insulina sin bomba"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/es.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/es.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 838e3c9ff..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/es.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Título"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detalle"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservorio"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Historial de Eventos"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/es.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/es.lproj/Localizable.strings deleted file mode 100644 index 56eef4bad..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/es.lproj/Localizable.strings +++ /dev/null @@ -1,703 +0,0 @@ -/* Information about workout range relative to correction range */ -" higher " = "más alta"; - -/* Information about pre-meal range relative to correction range */ -" lower " = " inferior "; - -/* Separator between min and max glucose values */ -"-" = "-"; - -/* No comment provided by engineer. */ -"-" = "-"; - -/* The detail text representing no value */ -"–" = "–"; - -/* No comment provided by engineer. */ -"···" = "···"; - -/* No comment provided by engineer. */ -"%@" = "%@"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% de insulina normal"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Information about insulin action duration (1: app name) */ -"%1$@ assumes that the insulin it has delivered is actively working to lower your glucose for 6 hours. This setting cannot be changed." = "%1$@ asume que la insulina que ha administrado está trabajando activamente para reducir el nivel de glucosa durante 6 horas. Esta configuración no se puede cambiar."; - -/* Lower bound workout information text format (1: app name) */ -"%1$@ or your Glucose Safety Limit, whichever is higher" = "%1$@ o su Límite de Seguridad de Glucosa, el que sea mayor"; - -/* Reservoir entry (1: volume value) */ -"%1$@ U" = "%1$@ U"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "quedan %1$@ unidades a las %2$@"; - -/* Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) - Description of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) */ -"%1$@: %2$@ %3$@" = "%1$@: %2$@ %3$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"🍽" = "🍽"; - -/* Premeal override preset title */ -"🍽 Pre-Meal" = "🍽 Pre-Comida"; - -/* No comment provided by engineer. */ -"🏃‍♂️" = "🏃‍♂️"; - -/* Workout override preset title */ -"🏃‍♂️ Workout" = "🏃‍♂️ Ejercicio"; - -/* Information about differences between target range and correction range */ -"A Correction Range is different. This will be a narrower range." = "Un Rango de Corrección es diferente. Este será un rango más estrecho."; - -/* Warning text for basal rate of 0 U/hr */ -"A value of 0 U/hr means you will be scheduled to receive no basal insulin." = "Un valor de 0 U/hora significa que se programará que no reciba insulina basal."; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Tiempo de Absorción"; - -/* No comment provided by engineer. */ -"Action Button" = "Botón de acción"; - -/* The text for the override history duration */ -"Active Duration" = "Duración activa"; - -/* The title for the override emoji activity section */ -"Activity" = "Actividad"; - -/* Button text to confirm adding a new schedule item */ -"Add" = "Agregar"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Agregar Cuenta"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Agregar Entrada de Carb"; - -/* Title of insulin model preset - afrezza */ -"Afrezza" = "Afrezza"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "¿Estás seguro de querer eliminar todos las entradas históricas?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "¿Estás seguro de querer eliminar todos los datos del reservorio?"; - -/* Authentication hint string for therapy settings */ -"Authenticate to save therapy setting" = "Autenticarse para guardar la configuración de la terapia"; - -/* Back navigation button title */ -"Back" = "Atrás"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Tasas basales"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Basal, bolos y cantidades de corrección de insulina serán reducidos de %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Basal, bolos y cantidades de corrección de insulina serán aumentados de %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Basal, bolos y cantidades de corrección de insulina sin cambio."; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancelar"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Cancelar de Sobreescritura"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Cancelación de basal temporal"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Ratios de carbohidratos"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Los cambios sólo se aplicarán cuando habilite la sobreescritura. Los valores por defecto de %@ no seran afectados."; - -/* Footer text for customizing from a preset (1: preset name) */ -"Changes will only apply this time you enable the preset. The default settings of %@ will not be affected." = "Los cambios sólo se aplicarán esta vez cuando habilite el Ajuste Preestablecido. Los valores por defecto de %@ no seran afectados."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Elija un tiempo de absorción más largo para comidas más grandes, o aquellas que contienen grasas y proteínas. Esta es solo una guía para el algoritmo y no necesita ser exacta."; - -/* Button text to close a modal - Text to close informational page */ -"Close" = "Cerrar"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "a %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "hace %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "a %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "hace %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Completed." = "Completado."; - -/* The title for the override emoji condition section */ -"Condition" = "Condición"; - -/* The button text for confirming the setting */ -"Confirm Setting" = "Confirmar ajuste"; - -/* No comment provided by engineer. */ -"content" = "contenido"; - -/* Title of the setup button to continue */ -"Continue" = "Continuar"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "El rango de corrección es el rango de glucosa en sangre al que usted le gustaría que Loop corrigiera."; - -/* Title text for multi-value correction value warning */ -"Correction Values" = "Valores de corrección"; - -/* The text for a custom override */ -"Custom" = "Personalizado"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Sobreescritura personalizada"; - -/* The title for the custom preset entry screen - The title for the custom preset selection screen */ -"Custom Preset" = "Ajuste Preestablecido personalizado"; - -/* Title of the carb entry date picker cell */ -"Date" = "Fecha"; - -/* Delete values for Pre-Meal, inactivates Pre-Meal icon - Test for table cell delete button - The title of the button to remove the credentials for a service */ -"Delete" = "Eliminar"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Eliminar Cuenta"; - -/* Button title to delete all objects */ -"Delete All" = "Eliminar Todos"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Límites de Administración de Insulina"; - -/* Information about delivery limits */ -"Delivery Limits are safety guardrails for your insulin delivery." = "Los límites de administración es un mecanismo de seguridad para la administración de su insulina."; - -/* The text for the custom preset disable button */ -"Disable Preset" = "Desactivar preselección"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Completado"; - -/* The text for the override duration setting */ -"Duration" = "Duración"; - -/* Text for edit button - The title for the enabled custom preset editing screen */ -"Edit" = "Editar"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Editar Entrada de Carb"; - -/* The title for the override editing screen */ -"Edit Override" = "Editar sobreescritura"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "La edición afecta sólo a la sobreescritura activa. Los ajustes preestablecidos de %@ no se modificarán."; - -/* Footer text for editing an enabled custom preset (1: preset name) */ -"Edits persist only until the preset is disabled. The default settings of %@ will not be affected." = "Las ediciones persisten solo hasta que se deshabilita el ajuste preestablecido. La configuración predeterminada de %@ no se verá afectada."; - -/* The button text for enabling a temporary override */ -"Enable" = "Activar"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Habilitar indefinidamente"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Habilitado"; - -/* The text for the override start time */ -"End Time" = "Hora de finalización"; - -/* Format string for accessibility label for value entry. (1: value label) */ -"Enter %1$@ value" = "Introduzca el valor %1$@"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Ingrese una cantidad de unidades"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Ingrese una tasa de unidade por hora"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Historial de Eventos"; - -/* No comment provided by engineer. */ -"Example" = "Ejemplo"; - -/* Section title for fast absorbing food */ -"Fast" = "Rápido"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Insulin model setting description (1: app name) (2: number of models) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from %2$@ different models for how the app measures the insulin’s peak activity." = "En el caso de la insulina de acción rápida, %1$@ asume que actúa activamente durante 6 horas. Puedes elegir entre %2$@ modelos diferentes para que la aplicación mida el pico de actividad de la insulina."; - -/* Information about correction range format (1: app name) */ -"For this range, choose the specific glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin." = "Para este rango, elija el valor de glucosa específico (o el rango de valores) que desea que %1$@ tenga como objetivo para ajustar su insulina basal."; - -/* Support button for Therapy Settings */ -"Get help with Therapy Settings" = "Obtener ayuda con la Configuración de la Terapia"; - -/* Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range - Text for go back action on confirmation alert */ -"Go Back" = "Volver atrás"; - -/* Title text for the high basal rate warning */ -"High Basal Rate" = "Tasa basal alta"; - -/* Title text for the high carb ratio warning */ -"High Carb Ratio" = "Alto ratio de carbohidratos"; - -/* Title text for the high correction value warning */ -"High Correction Value" = "Alto valor de corrección"; - -/* Title text for the high glucose safety limit warning */ -"High Glucose Safety Limit" = "Límite de seguridad de glucosa alta"; - -/* Title text for the high insulin sensitivity warning */ -"High Insulin Sensitivity" = "Alta sensibilidad a la insulina"; - -/* Title text for high maximum basal rate warning */ -"High Maximum Basal Rate" = "Tasa basal máxima alta"; - -/* Title text for high maximum bolus warning */ -"High Maximum Bolus" = "Bolo máximo alto"; - -/* Title text for the low pre-meal value warning */ -"High Pre-Meal Value" = "Alto valor antes de la comida"; - -/* Title text for the high workout value warning */ -"High Workout Value" = "Alto valor para actividad física"; - -/* The text for the override history */ -"History" = "Historial"; - -/* Description of how to interact with summary screen */ -"If these settings look good to you, tap Save Settings to continue." = "Si estos ajustes le parecen bien, pulse Guardar configuración para continuar."; - -/* Information about target range */ -"If you've used a CGM before, you're likely familiar with target range as a wide range of values you'd like for your glucose notification alerts, such as 70-180 mg/dL or 90-200 mg/dL." = "Si ha usado un CGM anteriormente, probablemente esté familiarizado con el rango objetivo como un amplio rango de valores que le gustaría para sus alertas de notificación de glucosa, como 70-180 mg/dL o 90-200 mg/dL."; - -/* Title text for insulin model */ -"Insulin Model" = "Modelo de Insulina"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Sensibilidad a la insulina"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "La sensibilidad a la insulina describe cómo responde su glucemia a 1 unidad de insulina. Valores menores implican que se administrará más insulina."; - -/* Description of an interrupted bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: programmed value (? if no value), 4: unit) */ -"Interrupted %1$@: %2$@ of %3$@ %4$@" = "%1$@ interrumpido: %2$@ de %3$@ %4$@"; - -/* Guardrail info text format */ -"It can be set as low as %1$@. It can be set as high as %2$@." = "Se puede configurar tan bajo como %1$@. \nSe puede configurar tan alto como %2$@."; - -/* Title text for the low basal rate warning */ -"Low Basal Rate" = "Tasa basal baja"; - -/* Title text for the low carb ratio warning */ -"Low Carb Ratio" = "Ratio bajo para carbohidratos"; - -/* Title text for the low correction value warning */ -"Low Correction Value" = "El Valor de Corrección es bajo"; - -/* Title text for the low glucose safety limit warning */ -"Low Glucose Safety Limit" = "El valor de Límite de seguridad de Glucosa es bajo"; - -/* Title text for the low insulin sensitivity warning */ -"Low Insulin Sensitivity" = "El valor de Sensibilidad a la Insulina es bajo"; - -/* Title text for low maximum basal rate warning */ -"Low Maximum Basal Rate" = "Tasa basal máxima baja"; - -/* Title text for low maximum bolus warning */ -"Low Maximum Bolus" = "El valor de Bolo Máximo es bajo"; - -/* Title text for the low pre-meal value warning */ -"Low Pre-Meal Value" = "El valor de Pre-Comidas es bajo"; - -/* Title text for the low workout value warning */ -"Low Workout Value" = "El valor para actividad física es bajo"; - -/* Title of insulin model preset - lyumjev */ -"Lyumjev" = "Lyumjev"; - -/* Placeholder for maximum value in glucose range */ -"max" = "max"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Perfil Basal Máximo"; - -/* Information about maximum basal rate (1: app name) */ -"Maximum Basal Rate is the maximum automatically adjusted basal rate that %1$@ is allowed to enact to help reach your correction range." = "La Tasa Basal Máxima es el máximo ajuste automático que %1$@ tiene permitido habilitar para ayudar a alcanzar tu rango de corrección."; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Bolo Máximo"; - -/* Information about maximum bolus (1: app name) */ -"Maximum Bolus is the highest bolus amount that you will allow %1$@ to recommend at one time to cover carbs or bring down high glucose." = "El Bolo Máximo es la cantidad de bolo más alta que permitirá que %1$@ recomiende de una sola vez para cubrir los carbohidratos o reducir los niveles altos de glucosa."; - -/* Section title for medium absorbing food */ -"Medium" = "Medio"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* No comment provided by engineer. */ -"more content" = "más contenido"; - -/* Alert action title to open error help */ -"More Info" = "Más Info"; - -/* The text for the override preset name setting */ -"Name" = "Nombre"; - -/* Title for mini-modal to add a new schedule entry */ -"New Entry" = "Nueva entrada"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Nueva sobreescritura preestablecida"; - -/* Title text for the zero basal rate warning */ -"No Basal Insulin" = "Sin insulina basal"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Otro"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Necesidades de insulina"; - -/* Title for override history view */ -"Override History" = "Historial de sobreescrituras"; - -/* The title text for the override presets screen */ -"Override Presets" = "Sobreescrituras preestablecidas"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Las sobreescrituras preestablecidas pueden configurarse en la sección de Configuración de la pantalla de ajustes."; - -/* The section title of glucose overrides */ -"Overrides" = "Sobreescrituras"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Pre-Comida"; - -/* Title text for multi-value pre-meal value warning */ -"Pre-Meal Values" = "Valores Pre-Comidas"; - -/* title for prescription section */ -"Prescription" = "Prescripción"; - -/* The section header text override presets */ -"PRESETS" = "PREESTABLECIDAS"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Progressing." = "Progresando."; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Evento de microinfusadora"; - -/* Title text for suspend resume button when the basal delivery state is not set */ -"Pump Inoperable" = "Bomba inoperable"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Acción Rápida — Adultos"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Acción Rápida — Niños"; - -/* The default placeholder string for a credential */ -"Required" = "Requerido"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Reservorio"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Resumir la infusión"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Resumiendo"; - -/* title for summary description section */ -"Review and Save Settings" = "Revisar y guardar la configuración"; - -/* Description of how to interact with summary screen */ -"Review your therapy settings below. If you’d like to edit any of these settings, tap Back to go back to that screen." = "Revisa los ajustes de tu terapia a continuación. Si desea modificar alguno de estos ajustes, pulse Atrás para volver a esa pantalla."; - -/* The text for the override preset name field placeholder */ -"Running" = "Correr"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Agregar"; - -/* Alert title for confirming basal rates outside the recommended range */ -"Save Basal Rates?" = "¿Guardar tasas de insulina basal?"; - -/* Alert title for confirming carb ratios outside the recommended range */ -"Save Carb Ratios?" = "¿Guardar ratios de carbohidratos?"; - -/* Alert title for confirming correction ranges outside the recommended range */ -"Save Correction Range(s)?" = "¿Guardar rango(s) de corrección?"; - -/* Alert title for confirming delivery limits outside the recommended range */ -"Save Delivery Limits?" = "¿Guardar límites de administración?"; - -/* Alert title for confirming a glucose safety limit outside the recommended range */ -"Save Glucose Safety Limit?" = "¿Guardar límite de seguridad de glucosa?"; - -/* Alert title for confirming insulin sensitivities outside the recommended range */ -"Save Insulin Sensitivities?" = "¿Guardar sensibilidades a la insulina?"; - -/* Alert title for confirming pre-meal range overrides outside the recommended range */ -"Save Pre-Meal Range?" = "¿Guardar rango antes de las comidas?"; - -/* Alert title for confirming workout range overrides outside the recommended range */ -"Save Workout Range?" = "¿Guardar rango para actividad física?"; - -/* The button text during saving on a configuration page */ -"Saving..." = "Guardando..."; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "SOBREESCRITURA PROGRAMADA"; - -/* The section header text for a scheduled custom preset */ -"SCHEDULED PRESET" = "PRESELECCIÓN PROGRAMADA"; - -/* Section title for slow absorbing food */ -"Slow" = "Lento"; - -/* Information about typical maximum basal rates */ -"Some users choose a value 2, 3, or 4 times their highest scheduled basal rate." = "Algunos usuarios eligen un valor 2, 3 o 4 veces su tasa basal programada más alta."; - -/* The text for the override start time */ -"Start Time" = "Tiempo de inicio"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Inicio de basal temporal"; - -/* Format for prescription descriptive text (1: providerName, 2: datePrescribed) */ -"Submitted by %1$@, %2$@" = "Enviado por %1$@, %2$@"; - -/* Title for support section */ -"Support" = "Ayuda"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspender la infusión"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspendiendo"; - -/* No comment provided by engineer. */ -"Switch Preview State" = "Cambiar Estado de Vista Previa"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Símbolo"; - -/* Text directing the user to configure their first custom preset */ -"Tap '+' to create a new custom preset." = "Pulsa \"+\" para crear un nuevo preajuste personalizado."; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Toca para definir"; - -/* The text for the override target range setting */ -"Target Range" = "Rango objetivo"; - -/* Description of pre-meal mode */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Reduzca temporalmente su objetivo de glucosa antes de una comida para reducir los picos de glucosa después de las comidas."; - -/* Description of workout mode */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Aumente temporalmente su objetivo de glucosa antes, durante o después de la actividad física para reducir el riesgo de tener eventos de glucosa baja."; - -/* The title for the override selection screen */ -"Temporary Override" = "Sobreescritura temporal"; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"than your Correction Range." = "que su Rango de Corrección."; - -/* Description for selection when no insulin type is selected. */ -"The currently selected fast acting insulin model will be used as a default." = "Se utilizará por defecto el modelo de insulina de acción rápida actualmente seleccionado."; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "El modelo heredado utilizado por Loop, que permite personalizar la duración de la acción de la insulina."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "El tiempo máximo de absorción es %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "La cantidad máxima permitida es %@ gramos"; - -/* Information about adult insulin model */ -"The rapid-acting adult model assumes peak activity at 75 minutes." = "El modelo de adultos de acción rápida supone un pico de efecto a los 75 minutos."; - -/* Information about child insulin model */ -"The rapid-acting child model assumes peak activity at 65 minutes." = "El modelo para niños de acción rápida supone un pico de efecto a los 65 minutos."; - -/* Information about basal rate scheduling */ -"The schedule starts at midnight and cannot contain a rate of 0 U/hr." = "El horario comienza a medianoche y no puede contener una tasa de 0 U/h."; - -/* Therapy Settings screen title */ -"Therapy Settings" = "Ajustes de la Terapia"; - -/* No comment provided by engineer. */ -"Therapy Settings Support Placeholder" = "Marcador de ayuda para la configuracion de terapia"; - -/* Subtitle of afrezza preset */ -"This model assumes peak insulin activity at 19 minutes." = "Este modelo asume la actividad máxima de la insulina a los 19 minutos."; - -/* Subtitle of Fiasp preset - Subtitle of Lyumjev preset */ -"This model assumes peak insulin activity at 55 minutes." = "Este modelo asume la actividad máxima de la insulina a los 55 minutos."; - -/* Subtitle of Rapid-Acting – Children preset */ -"This model assumes peak insulin activity at 65 minutes." = "Este modelo asume la actividad máxima de la insulina a los 65 minutos."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"This model assumes peak insulin activity at 75 minutes." = "Este modelo asume como pico de la insulina a los 75 minutos."; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"This will typically be" = "Esto será típicamente"; - -/* Label for offset from midnight picker */ -"Time" = "Hora"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Horario in %1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"To be implemented" = "Por desarrollarse"; - -/* No comment provided by engineer. */ -"Top component" = "Componente superior"; - -/* The text indicating Total for Daily Schedule Basal */ -"Total" = "Total"; - -/* The text indicating U/day for Daily Schedule Basal */ -"U/day" = "U/día"; - -/* The unit string for units per hour */ -"U/hour" = "U/hora"; - -/* Alert title when error occurs while saving a schedule */ -"Unable to Save" = "No se puede guardar"; - -/* The unit string for units */ -"Units" = "Unidades"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Desconocido"; - -/* Title for selection when no insulin type is selected. */ -"Unset" = "Sin configurar"; - -/* Placeholder text until value is entered */ -"Value" = "Valor"; - -/* Label indicating validation is occurring */ -"Verifying" = "Verificando"; - -/* The title for the override editing screen */ -"View Override" = "Ver la sobreescritura"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Aviso"; - -/* Disclaimer */ -"Work with your healthcare provider to choose a value that is higher than your highest scheduled basal rate, but as conservative or aggressive as you feel comfortable." = "Trabaje con su proveedor de atención médica para elegir un valor que sea más alto que su tasa basal programada más alta, pero que sea tan conservadora o agresiva segun su preferencia."; - -/* Title for the workout override range */ -"Workout" = "Ejercicio"; - -/* Information about workout range format (1: app name) */ -"Workout Range is the glucose value or range of values you want %1$@ to target during activity. This range will be in effect when you activate the Workout Preset button." = "Rango de ejercicio físico es el valor de glucosa o el rango de valores que desea que %1$@ tenga como objetivo durante la realización de ejercicio físico. Este rango entrará en vigencia cuando active el botón Preajuste de Ejercicio Físico."; - -/* Title text for multi-value workout value warning */ -"Workout Values" = "Valores de ejercicio físico"; - -/* Description of how to add a ratio */ -"You can add different carb ratios for different times of day by using the ➕." = "Puede añadir diferentes proporciones de carbohidratos para diferentes momentos del día utilizando la ➕."; - -/* Description of how to add a ratio */ -"You can add different insulin sensitivities for different times of day by using the ➕." = "Puede agregar diferentes sensibilidades de insulina para diferentes momentos del día usando el ➕."; - -/* Description of how to add a configuration range */ -"You can add different ranges for different times of day by using the ➕." = "Puede agregar diferentes rangos para diferentes momentos del día usando el ➕."; - -/* Description of how to add a range */ -"You can add entries for different times of day by using the ➕." = "Puede agregar entradas para diferentes momentos del día usando el ➕."; - -/* Information about insulin model (1: app name) */ -"You can choose how %1$@ measures rapid acting insulin's peak activity according to one of these two insulin models." = "Puedes elegir cómo %1$@ mide el pico del efecto de la insulina de acción rápida en función de uno de estos dos modelos de insulina."; - -/* Description of how to edit setting */ -"You can edit a setting by tapping into any line item." = "Puede editar una configuración tocando cualquier elemento de línea."; - -/* Description of how to edit setting */ -"You can edit the setting by tapping into the line item." = "Puede editar la configuración pulsando sobre la linea."; - -/* Information about basal rates */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Su tasa basal de insulina es la cantidad de unidades por hora que desea usar para cubrir sus necesidades de insulina de fondo, no relacionadas con las comidas."; - -/* Lower bound pre-meal information text */ -"your Glucose Safety Limit" = "su Límite de Seguridad de Glucosa"; - -/* Disclaimer */ -"Your healthcare provider can help you choose a Correction Range that's right for you." = "Su proveedor de atención médica puede ayudarlo a elegir un rango de corrección adecuado para usted."; - -/* Description of insulin sensitivity factor */ -"Your Insulin Sensitivity Factor (ISF) is the drop in glucose expected from one unit of insulin." = "Su Factor de Sensibilidad a la Insulina (ISF, por sus siglas en inglés) es la caída de glucosa que se espera por la administracion de una unidad de insulina."; - -/* Information about pre-meal range format (1: app name) */ -"Your Pre-Meal Range should be the glucose value (or range of values) you want %1$@ to target by the time you take your first bite of your meal. This range will be in effect when you activate the Pre-Meal Preset button." = "Su rango previo a la comida debe ser el valor de glucosa (o el rango de valores) que desea que %1$@ tenga como objetivo para cuando tome su primer bocado de su comida. Este rango entrará en vigencia cuando active el botón Pre-Comida Preajuste."; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/fi.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/fi.lproj/InsulinKit.strings deleted file mode 100644 index d21f234c4..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/fi.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Säiliö"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Tapahtumahistoria"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Non-Pump Insulin"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/fi.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/fi.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 663d86623..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/fi.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Säiliö"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Tapahtumahistoria"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/fi.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/fi.lproj/Localizable.strings deleted file mode 100644 index 4e26c8792..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/fi.lproj/Localizable.strings +++ /dev/null @@ -1,679 +0,0 @@ -/* Information about workout range relative to correction range */ -" higher " = " korkeampi "; - -/* Information about pre-meal range relative to correction range */ -" lower " = " matalampi "; - -/* Separator between min and max glucose values */ -"-" = "-"; - -/* No comment provided by engineer. */ -"-" = "-"; - -/* The detail text representing no value */ -"–" = "–"; - -/* No comment provided by engineer. */ -"···" = "···"; - -/* No comment provided by engineer. */ -"%@" = "%@"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% norm. insuliinista"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@ U"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Lower bound workout information text format (1: app name) */ -"%1$@ or your Glucose Safety Limit, whichever is higher" = "%1$@ tai glukoosin turvaraja riippuen siitä, kumpi on korkeampi"; - -/* Reservoir entry (1: volume value) */ -"%1$@ U" = "%1$@ U"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ yksikköä jäljellä klo %2$@"; - -/* Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) - Description of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) */ -"%1$@: %2$@ %3$@" = "%1$@: %2$@ %3$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"🍽" = "🍽"; - -/* Premeal override preset title */ -"🍽 Pre-Meal" = "🍽 Ennen ateriaa"; - -/* No comment provided by engineer. */ -"🏃‍♂️" = "🏃‍♂️"; - -/* Workout override preset title */ -"🏃‍♂️ Workout" = "🏃‍♂️ Liikunta"; - -/* No comment provided by engineer. */ -"A card whose text will wrap onto multiple lines if I continue to type for long enough—this length should do" = "Kortti, jonka teksti rivittyy usealle riville, jos jatkan kirjoittamista riittävän kauan – tämän pituuden pitäisi riittää"; - -/* Information about differences between target range and correction range */ -"A Correction Range is different. This will be a narrower range." = "Korjausalue tarkoittaa eri asiaa. Se on kapeampi alue."; - -/* No comment provided by engineer. */ -"A simple card" = "Yksinkertainen kortti"; - -/* Warning text for basal rate of 0 U/hr */ -"A value of 0 U/hr means you will be scheduled to receive no basal insulin." = "Arvo 0 U/t tarkoittaa, että et saa lainkaan basaali-insuliinia."; - -/* No comment provided by engineer. */ -"Above the save button" = "Tallenna-painikkeen yläpuolella"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Imeytymisaika"; - -/* No comment provided by engineer. */ -"Action Button" = "Toimintopainike"; - -/* The text for the override history duration */ -"Active Duration" = "Aktiivinen kesto"; - -/* The title for the override emoji activity section */ -"Activity" = "Liikunta"; - -/* Button text to confirm adding a new schedule item */ -"Add" = "Lisää"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Lisää tili"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Lisää hiilihydraatteja"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Haluatko varmasti poistaa kaikki historiatiedot?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Haluatko varmasti poistaa kaikki säiliön arvot?"; - -/* Authentication hint string for therapy settings */ -"Authenticate to save therapy setting" = "Varmenna tallentaaksesi hoitoasetukset"; - -/* Back navigation button title */ -"Back" = "Takaisin"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Basaalitasot"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Basaalin, boluksen ja korjaavan insuliiniannoksen määriä vähennetään %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Basaalin, boluksen ja korjaavan insuliiniannoksen määriä lisätään %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Basaalin, boluksen ja korjaavan insuliiniannoksen määrät pysyvät ennallaan."; - -/* No comment provided by engineer. */ -"Bottom component" = "Alaosan komponentti"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Kumoa"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Kumoa tilapäisasetus"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Kumotaan tilapäinen basaali"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Hiilihydraattisuhteet"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Muutokset otetaan käyttöön vain tällä kertaa, kun otat tilapäisasetuksen käyttöön. Alkuperäiset %@-asetukset pysyvät ennallaan."; - -/* Footer text for customizing from a preset (1: preset name) */ -"Changes will only apply this time you enable the preset. The default settings of %@ will not be affected." = "Muutokset ovat voimassa vain tällä kertaa, kun esiasetus otetaan käyttöön. Tämä ei vaikuta alkuperäisiin %@ -asetuksiin."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Valitse pidempi imeytymisaika isoille tai paljon rasvaa ja proteiineja sisältäville aterioille. Tämä on suuntaa antava ohje, eikä sen tarvitse olla tarkka."; - -/* Button text to close a modal - Text to close informational page */ -"Close" = "Sulje"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "klo %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "%1$@ jälkeen"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "klo %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "%1$@ jälkeen"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Completed." = "Valmis."; - -/* The title for the override emoji condition section */ -"Condition" = "Vointi"; - -/* The button text for confirming the setting */ -"Confirm Setting" = "Vahvista asetus"; - -/* No comment provided by engineer. */ -"content" = "sisältö"; - -/* Title of the setup button to continue */ -"Continue" = "Jatka"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "Korjausalue on glukoositavoitealue, johon haluat Loopin korjaavan."; - -/* Title text for multi-value correction value warning */ -"Correction Values" = "Korjausarvot"; - -/* The text for a custom override */ -"Custom" = "Mukautettu"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Mukautettu tilapäisasetus"; - -/* The title for the custom preset entry screen - The title for the custom preset selection screen */ -"Custom Preset" = "Mukautettu esiasetus"; - -/* Title of the carb entry date picker cell */ -"Date" = "Aika"; - -/* Delete values for Pre-Meal, inactivates Pre-Meal icon - Test for table cell delete button - The title of the button to remove the credentials for a service */ -"Delete" = "Poista"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Poista tili"; - -/* Button title to delete all objects */ -"Delete All" = "Poista kaikki"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Annostelurajat"; - -/* Information about delivery limits */ -"Delivery Limits are safety guardrails for your insulin delivery." = "Annostelurajoilla tarkoitetaan insuliinin annostelun turvarajoja."; - -/* The text for the custom preset disable button */ -"Disable Preset" = "Poista esiasetus käytöstä"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Valmis"; - -/* The text for the override duration setting */ -"Duration" = "Kesto"; - -/* Text for edit button - The title for the enabled custom preset editing screen */ -"Edit" = "Muokkaa"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Muokkaa hiilihydraatteja"; - -/* The title for the override editing screen */ -"Edit Override" = "Muokkaa tilapäisasetusta"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "Muokkaus vaikuttaa vain aktiiviseen tilapäisasetukseen. Alkuperäiset %@-asetukset säilyvät ennallaan."; - -/* Footer text for editing an enabled custom preset (1: preset name) */ -"Edits persist only until the preset is disabled. The default settings of %@ will not be affected." = "Muokkaukset säilyvät siihen asti, kun esiasetus poistetaan käytöstä. Tämä ei vaikuta alkuperäisiin %@ -asetuksiin."; - -/* The button text for enabling a temporary override */ -"Enable" = "Ota käyttöön"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Ilman aikarajaa"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Käytössä"; - -/* The text for the override start time */ -"End Time" = "Päättymisaika"; - -/* Format string for accessibility label for value entry. (1: value label) */ -"Enter %1$@ value" = "Syötä %1$@ arvo"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Syötä yksikkömäärä"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Syötä nopeus yksiköinä tunnissa"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Tapahtumahistoria"; - -/* No comment provided by engineer. */ -"Example" = "Esimerkki"; - -/* Section title for fast absorbing food */ -"Fast" = "Nopea"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Insulin model setting description (1: app name) (2: number of models) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from %2$@ different models for how the app measures the insulin’s peak activity." = "%1$@ olettaa, että nopeavaikutteinen insuliini vaikuttaa aktiivisesti 6 tuntia. Valittavana on %2$@ eri mallia siitä, miten sovellus mittaa insuliinin vaikutushuipun."; - -/* Information about correction range format (1: app name) */ -"For this range, choose the specific glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin." = "Valitse tähän glukoosiarvo (tai arvoalue), jota %1$@ tavoittelee säätäessään basaalin määrää."; - -/* Support button for Therapy Settings */ -"Get help with Therapy Settings" = "Apua hoitoasetuksiin"; - -/* Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range - Text for go back action on confirmation alert */ -"Go Back" = "Takaisin"; - -/* Title text for the high basal rate warning */ -"High Basal Rate" = "Korkea basaalitaso"; - -/* Title text for the high carb ratio warning */ -"High Carb Ratio" = "Korkea hiilihydraattisuhde"; - -/* Title text for the high correction value warning */ -"High Correction Value" = "Korkea korjausarvo"; - -/* Title text for the high glucose safety limit warning */ -"High Glucose Safety Limit" = "Korkea glukoosin turvaraja"; - -/* Title text for the high insulin sensitivity warning */ -"High Insulin Sensitivity" = "Korkea insuliiniherkkyys"; - -/* Title text for high maximum basal rate warning */ -"High Maximum Basal Rate" = "Korkea suurin sallittu basaalitaso"; - -/* Title text for high maximum bolus warning */ -"High Maximum Bolus" = "Korkea suurin sallittu bolus"; - -/* Title text for the low pre-meal value warning */ -"High Pre-Meal Value" = "Korkea Ennen ateriaa -arvo"; - -/* Title text for the high workout value warning */ -"High Workout Value" = "Korkea liikuntatilan arvo"; - -/* The text for the override history */ -"History" = "Historia"; - -/* Description of how to interact with summary screen */ -"If these settings look good to you, tap Save Settings to continue." = "Jos nämä asetukset näyttävät sopivilta, jatka napauttamalla Tallenna asetukset."; - -/* Information about target range */ -"If you've used a CGM before, you're likely familiar with target range as a wide range of values you'd like for your glucose notification alerts, such as 70-180 mg/dL or 90-200 mg/dL." = "Jos olet käyttänyt jatkuvaa glukoosinseurantaa aiemmin, tavoitealue on todennäköisesti tuttu laajana glukoosiarvoalueena, jonka haluat hälytyksille, esimerkiksi 4–10 mmol/L tai 5–11 mmol/L."; - -/* Title text for insulin model */ -"Insulin Model" = "Insuliinimalli"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Insuliiniherkkyydet"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "Insuliiniherkkyys kuvaa sitä, kuinka paljon verensokerisi laskee yhdellä insuliiniyksiköllä. Liian pienet arvot voivat johtaa vaarallisen matalaan verensokeriin."; - -/* Description of an interrupted bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: programmed value (? if no value), 4: unit) */ -"Interrupted %1$@: %2$@ of %3$@ %4$@" = "Keskeytetty %1$@: %2$@ / %3$@ %4$@"; - -/* Guardrail info text format */ -"It can be set as low as %1$@. It can be set as high as %2$@." = "Se voidaan asettaa alimmillaan %1$@ ja korkeimmillaan %2$@."; - -/* Title text for the low basal rate warning */ -"Low Basal Rate" = "Matala basaalitaso"; - -/* Title text for the low carb ratio warning */ -"Low Carb Ratio" = "Matala hiilihydraattisuhde"; - -/* Title text for the low correction value warning */ -"Low Correction Value" = "Matala korjausarvo"; - -/* Title text for the low glucose safety limit warning */ -"Low Glucose Safety Limit" = "Matala glukoosin turvaraja"; - -/* Title text for the low insulin sensitivity warning */ -"Low Insulin Sensitivity" = "Matala insuliiniherkkyys"; - -/* Title text for low maximum basal rate warning */ -"Low Maximum Basal Rate" = "Matala suurin sallittu basaalitaso"; - -/* Title text for low maximum bolus warning */ -"Low Maximum Bolus" = "Matala suurin sallittu bolus"; - -/* Title text for the low pre-meal value warning */ -"Low Pre-Meal Value" = "Matala Ennen ateriaa -arvo"; - -/* Title text for the low workout value warning */ -"Low Workout Value" = "Matala liikuntatilan arvo"; - -/* Placeholder for maximum value in glucose range */ -"max" = "maks."; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Suurin sallittu basaalitaso"; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Suurin sallittu bolus"; - -/* Section title for medium absorbing food */ -"Medium" = "Keskiverto"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min."; - -/* No comment provided by engineer. */ -"more content" = "lisää sisältöä"; - -/* Alert action title to open error help */ -"More Info" = "Lisätietoa"; - -/* The text for the override preset name setting */ -"Name" = "Nimi"; - -/* Title for mini-modal to add a new schedule entry */ -"New Entry" = "Uusi merkintä"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Uusi esiasetus"; - -/* Title text for the zero basal rate warning */ -"No Basal Insulin" = "Ei basaali-insuliinia"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Muu"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Kokonaisinsuliinitarve"; - -/* Title for override history view */ -"Override History" = "Tilapäisasetushistoria"; - -/* The title text for the override presets screen */ -"Override Presets" = "Tilapäisasetukset"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Tilapäisasetuksia voidaan luoda Asetukset-näkymän Määritykset-osiossa."; - -/* The section title of glucose overrides */ -"Overrides" = "Tilapäisasetukset"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Ennen ateriaa"; - -/* Title text for multi-value pre-meal value warning */ -"Pre-Meal Values" = "Ennen ateriaa -arvot"; - -/* title for prescription section */ -"Prescription" = "Resepti"; - -/* The section header text override presets */ -"PRESETS" = "ESIASETUKSET"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Progressing." = "Edistyminen."; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Pumpputapahtuma"; - -/* Title text for suspend resume button when the basal delivery state is not set */ -"Pump Inoperable" = "Pumppu ei toiminnassa"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Nopeavaikutteinen – aikuiset"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Nopeavaikutteinen – lapset"; - -/* The default placeholder string for a credential */ -"Required" = "Pakollinen"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Säiliö"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Jatka annostelua"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Jatketaan"; - -/* title for summary description section */ -"Review and Save Settings" = "Tarkista ja tallenna asetukset"; - -/* Description of how to interact with summary screen */ -"Review your therapy settings below. If you’d like to edit any of these settings, tap Back to go back to that screen." = "Tarkista alla olevat hoitoasetukset. Jos haluat muokata jotakin näistä asetuksista, napauta Takaisin."; - -/* The text for the override preset name field placeholder */ -"Running" = "Juoksu"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Tallenna"; - -/* Alert title for confirming basal rates outside the recommended range */ -"Save Basal Rates?" = "Tallenna basaalitasot?"; - -/* Alert title for confirming carb ratios outside the recommended range */ -"Save Carb Ratios?" = "Tallenna hiilihydraattisuhteet?"; - -/* Alert title for confirming correction ranges outside the recommended range */ -"Save Correction Range(s)?" = "Tallenna korjausalue(et)?"; - -/* Alert title for confirming delivery limits outside the recommended range */ -"Save Delivery Limits?" = "Tallenna annostelurajat?"; - -/* Alert title for confirming a glucose safety limit outside the recommended range */ -"Save Glucose Safety Limit?" = "Tallenna glukoosin turvaraja?"; - -/* Alert title for confirming insulin sensitivities outside the recommended range */ -"Save Insulin Sensitivities?" = "Tallenna insuliiniherkkyydet?"; - -/* Alert title for confirming pre-meal range overrides outside the recommended range */ -"Save Pre-Meal Range?" = "Tallenna Ennen ateriaa -alue?"; - -/* Alert title for confirming workout range overrides outside the recommended range */ -"Save Workout Range?" = "Tallenna liikuntatila-alue?"; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "AJASTETTU TILAPÄISASETUS"; - -/* The section header text for a scheduled custom preset */ -"SCHEDULED PRESET" = "AJASTETTU ESIASETUS"; - -/* Section title for slow absorbing food */ -"Slow" = "Hidas"; - -/* Information about typical maximum basal rates */ -"Some users choose a value 2, 3, or 4 times their highest scheduled basal rate." = "Useimmat käyttäjät valitsevat omaa korkeinta basaalitasoa 2, 3 tai 4 kertaa suuremman arvon."; - -/* The text for the override start time */ -"Start Time" = "Alkaa"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Aloitetaan tilapäinen basaali"; - -/* Format for prescription descriptive text (1: providerName, 2: datePrescribed) */ -"Submitted by %1$@, %2$@" = "Lähettänyt %1$@, %2$@"; - -/* Title for support section */ -"Support" = "Tuki"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Pysäytä annostelu"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Pysäytetään"; - -/* No comment provided by engineer. */ -"Switch Preview State" = "Vaihda esikatselutila"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Symboli"; - -/* Text directing the user to configure their first custom preset */ -"Tap '+' to create a new custom preset." = "Luo uusi mukautettu esiasetus napauttamalla '+'."; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Napauta asettaaksesi"; - -/* The text for the override target range setting */ -"Target Range" = "Tavoitealue"; - -/* Description of pre-meal mode */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Laske glukoositavoitetta väliaikaisesti ennen ateriaa vaikuttaaksesi aterian jälkeiseen glukoosin nousuun."; - -/* Description of workout mode */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Nosta glukoositavoitetta väliaikaisesti ennen liikuntaa, sen aikana tai sen jälkeen, jotta matalan glukoosin riski pienenee."; - -/* The title for the override selection screen */ -"Temporary Override" = "Tilapäisasetus"; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"than your Correction Range." = "kuin korjausalue."; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Loopin vanha insuliinimalli, jossa voi muokata insuliinin vaikutusaikaa."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "Pisin sallittu imeytymisaika on %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "Suurin sallittu määrä on %@ grammaa"; - -/* Information about adult insulin model */ -"The rapid-acting adult model assumes peak activity at 75 minutes." = "Nopeavaikutteinen aikuisten malli olettaa vaikutushuippua 75 minuutissa."; - -/* Information about child insulin model */ -"The rapid-acting child model assumes peak activity at 65 minutes." = "Nopeavaikutteinen lasten malli olettaa vaikutushuippua 65 minuutissa."; - -/* Information about basal rate scheduling */ -"The schedule starts at midnight and cannot contain a rate of 0 U/hr." = "Aikataulu alkaa keskiyöstä, eikä se voi sisältää basaalitasoa 0 U/t."; - -/* Therapy Settings screen title */ -"Therapy Settings" = "Hoitoasetukset"; - -/* No comment provided by engineer. */ -"Therapy Settings Support Placeholder" = "Hoitoasetusten tuen paikkamerkki"; - -/* Subtitle of Fiasp preset - Subtitle of Lyumjev preset */ -"This model assumes peak insulin activity at 55 minutes." = "Tässä mallissa oletetaan, että insuliinin vaikutushuippu on 55 minuutissa."; - -/* Subtitle of Rapid-Acting – Children preset */ -"This model assumes peak insulin activity at 65 minutes." = "Tässä mallissa oletetaan, että insuliinin vaikutushuippu on 65 minuutissa."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"This model assumes peak insulin activity at 75 minutes." = "Tässä mallissa oletetaan, että insuliinin vaikutushuippu on 75 minuutissa."; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"This will typically be" = "Tämä on yleensä"; - -/* Label for offset from midnight picker */ -"Time" = "Aika"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Aika %1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"To be implemented" = "Toteutettava"; - -/* No comment provided by engineer. */ -"Top component" = "Ylin komponentti"; - -/* The unit string for units per hour */ -"U/hour" = "U/tunti"; - -/* Alert title when error occurs while saving a schedule */ -"Unable to Save" = "Ei voitu tallentaa"; - -/* The unit string for units */ -"Units" = "Yksikköä"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Tuntematon"; - -/* Placeholder text until value is entered */ -"Value" = "Arvo"; - -/* Label indicating validation is occurring */ -"Verifying" = "Tarkistetaan"; - -/* The title for the override editing screen */ -"View Override" = "Näytä tilapäisasetus"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Varoitus"; - -/* Disclaimer */ -"Work with your healthcare provider to choose a value that is higher than your highest scheduled basal rate, but as conservative or aggressive as you feel comfortable." = "Keskustele terveydenhuollon ammattilaisen kanssa valitaksesi arvon, joka on korkeampi kuin korkein ohjelmoitu basaalitasosi, mutta niin konservatiivinen tai aggressiivinen, että tunnet olosi mukavaksi."; - -/* Title for the workout override range */ -"Workout" = "Liikunta"; - -/* Information about workout range format (1: app name) */ -"Workout Range is the glucose value or range of values you want %1$@ to target during activity. This range will be in effect when you activate the Workout Preset button." = "Liikuntatila on glukoosiarvo tai arvoalue, johon %1$@ tähtää liikunnan aikana. Tämä alue tulee voimaan, kun aktivoit Liikuntatila-painikkeen."; - -/* Title text for multi-value workout value warning */ -"Workout Values" = "Liikuntatilan arvot"; - -/* Description of how to add a ratio */ -"You can add different carb ratios for different times of day by using the ➕." = "Voit lisätä erilaisia hiilihydraattisuhteita eri aikoihin päivästä napauttamalla ➕."; - -/* Description of how to add a ratio */ -"You can add different insulin sensitivities for different times of day by using the ➕." = "Voit lisätä erilaisia insuliiniherkkyyksiä eri aikoihin päivästä napauttamalla ➕."; - -/* Description of how to add a configuration range */ -"You can add different ranges for different times of day by using the ➕." = "Voit lisätä erilaisia korjausalueita eri aikoihin päivästä napauttamalla ➕."; - -/* Description of how to add a range */ -"You can add entries for different times of day by using the ➕." = "Voit lisätä merkintöjä eri aikoihin päivästä napauttamalla ➕."; - -/* Description of how to edit setting */ -"You can edit a setting by tapping into any line item." = "Voit muokata asetusta napauttamalla mitä tahansa riviä."; - -/* Description of how to edit setting */ -"You can edit the setting by tapping into the line item." = "Voit muokata asetusta napauttamalla riviä."; - -/* Information about basal rates */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Basaalitaso tarkoittaa sitä yksikkömäärää insuliinia tunnissa, jonka tarvitset insuliinin perustarpeen kattamiseen."; - -/* Lower bound pre-meal information text */ -"your Glucose Safety Limit" = "glukoosin turvarajasi"; - -/* Disclaimer */ -"Your healthcare provider can help you choose a Correction Range that's right for you." = "Terveydenhuollon ammattilainen voi auttaa sinua valitsemaan sinulle sopivan korjausalueen."; - -/* Description of insulin sensitivity factor */ -"Your Insulin Sensitivity Factor (ISF) is the drop in glucose expected from one unit of insulin." = "Insuliiniherkkyys (ISF) tarkoittaa sitä, kuinka paljon glukoosin odotetaan laskevan yhdellä insuliiniyksiköllä."; - -/* Information about pre-meal range format (1: app name) */ -"Your Pre-Meal Range should be the glucose value (or range of values) you want %1$@ to target by the time you take your first bite of your meal. This range will be in effect when you activate the Pre-Meal Preset button." = "Ennen ateriaa -alueen tulisi olla glukoosiarvo (tai arvoalue), johon %1$@ tähtää insuliinin annosteluhetkestä aterian alkuun. Tämä alue tulee voimaan, kun aktivoit Ennen ateriaa -painikkeen."; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/fr.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/fr.lproj/InsulinKit.strings deleted file mode 100644 index 3db74fd11..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/fr.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Détail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Totaux"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Réservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Historique des événements"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Insuline ne venant pas de la pompe"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Administration de l'insuline"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/fr.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/fr.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 9ab00e1af..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/fr.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Détail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Réservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Historique des événements"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Administration de l'insuline"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/fr.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/fr.lproj/Localizable.strings deleted file mode 100644 index 264c0402b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/fr.lproj/Localizable.strings +++ /dev/null @@ -1,700 +0,0 @@ -/* Information about workout range relative to correction range */ -" higher " = " plus élevé "; - -/* Information about pre-meal range relative to correction range */ -" lower " = " moins élevé "; - -/* Separator between min and max glucose values */ -"-" = "-"; - -/* No comment provided by engineer. */ -"-" = "-"; - -/* The detail text representing no value */ -"–" = "–"; - -/* No comment provided by engineer. */ -"···" = "···"; - -/* No comment provided by engineer. */ -"%@" = "%@"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% de l’insuline de base"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Lower bound workout information text format (1: app name) */ -"%1$@ or your Glucose Safety Limit, whichever is higher" = "%1$@ ou votre limite de sécurité pour la glycémie, la valeur la plus élevée étant retenue"; - -/* Reservoir entry (1: volume value) */ -"%1$@ U" = "%1$@ U"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unités restantes à %2$@"; - -/* Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) - Description of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) */ -"%1$@: %2$@ %3$@" = "%1$@: %2$@ %3$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"🍽" = "🍽"; - -/* Premeal override preset title */ -"🍽 Pre-Meal" = "🍽 Pré-Repas"; - -/* No comment provided by engineer. */ -"🏃‍♂️" = "🏃‍♂️"; - -/* Workout override preset title */ -"🏃‍♂️ Workout" = "Exercice"; - -/* No comment provided by engineer. */ -"A card whose text will wrap onto multiple lines if I continue to type for long enough—this length should do" = "Une carte dont le texte va retourner sur plusieurs lignes si je continue à tapper assez longtemps. Ceci devrait suffire."; - -/* Information about differences between target range and correction range */ -"A Correction Range is different. This will be a narrower range." = "Une plage de correction est différente. Il s'agit d'une plage plus étroite."; - -/* No comment provided by engineer. */ -"A simple card" = "Une carte simple"; - -/* Warning text for basal rate of 0 U/hr */ -"A value of 0 U/hr means you will be scheduled to receive no basal insulin." = "Une valeur de 0 U/hr veut dire que vous ne recevrez aucune insuline basale."; - -/* No comment provided by engineer. */ -"Above the save button" = "Au dessus du bouton sauvegarder"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Durée d’absorption"; - -/* No comment provided by engineer. */ -"Action Button" = "Bouton Action"; - -/* The text for the override history duration */ -"Active Duration" = "Durée active"; - -/* The title for the override emoji activity section */ -"Activity" = "Activité"; - -/* Button text to confirm adding a new schedule item */ -"Add" = "Ajouter"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Ajouter un compte"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Ajouter des glucides"; - -/* Title of insulin model preset - afrezza */ -"Afrezza" = "Afrezza"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Voulez-vous vraiment supprimer toutes les entrées de l’historique?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Voulez-vous vraiment supprimer toutes les valeurs de réservoir?"; - -/* Authentication hint string for therapy settings */ -"Authenticate to save therapy setting" = "Authentifier pour enregistrer les paramètres thérapeutiques"; - -/* Back navigation button title */ -"Back" = "Retour"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Débits basaux"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Le débit basal, les bolus, et le niveau de l’insuline de correction sont diminués par %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Le débit de basal, les bolus, et le niveau de l’insuline de correction sont augmentés par %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Le débit de basal, les bolus, et le niveau de l’insuline de correction ne sont pas affectés."; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuler"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Annuler l'ajustement"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Annulation du débit basal temporaire"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Ratios Insuline-Glucides"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Les modifications effectuées que la fois où vous activerez l'ajustement. Les réglages par défaut de %@ ne seront pas affectés."; - -/* Footer text for customizing from a preset (1: preset name) */ -"Changes will only apply this time you enable the preset. The default settings of %@ will not be affected." = "Les modifications effectuées que la fois où vous activerez préréglage. Les réglages par défaut de %@ ne seront pas affectés."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Choisissez un temps d’absorption plus long pour les gros repas ou ceux contenant des graisses et des protéines. Ceci est seulement un guide pour l'algorithme et n'a pas besoin d'être exact."; - -/* Button text to close a modal - Text to close informational page */ -"Close" = "Fermer"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "à %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "depuis %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "à %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "depuis %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Completed." = "Terminé."; - -/* The title for the override emoji condition section */ -"Condition" = "Condition"; - -/* The button text for confirming the setting */ -"Confirm Setting" = "Confirmer le réglage"; - -/* No comment provided by engineer. */ -"content" = "contenu"; - -/* Title of the setup button to continue */ -"Continue" = "Continuer"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "La plage de correction est la plage de glycémie vers laquelle vous voudriez que Loop vous corrige."; - -/* Title text for multi-value correction value warning */ -"Correction Values" = "Valeurs de correction"; - -/* The text for a custom override */ -"Custom" = "Personnalisé"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Ajustement personnalisé"; - -/* The title for the custom preset entry screen - The title for the custom preset selection screen */ -"Custom Preset" = "Préréglage personnalisé"; - -/* Title of the carb entry date picker cell */ -"Date" = "Date"; - -/* Delete values for Pre-Meal, inactivates Pre-Meal icon - Test for table cell delete button - The title of the button to remove the credentials for a service */ -"Delete" = "Supprimer"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Supprimer le compte"; - -/* Button title to delete all objects */ -"Delete All" = "Supprimer tout"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Limites d'Administration"; - -/* Information about delivery limits */ -"Delivery Limits are safety guardrails for your insulin delivery." = "Les limites d'administration sont des garde-fous de sécurité de l'administration de l’insuline."; - -/* The text for the custom preset disable button */ -"Disable Preset" = "Désactiver le préréglage"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Terminé"; - -/* The text for the override duration setting */ -"Duration" = "Durée"; - -/* Text for edit button - The title for the enabled custom preset editing screen */ -"Edit" = "Éditer"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Modifier l’entrée des glucides"; - -/* The title for the override editing screen */ -"Edit Override" = "Éditer l'ajustement"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "La modification n'affecte que l'ajustement actuel. Les réglages par défaut de %@ ne seront pas affectés."; - -/* Footer text for editing an enabled custom preset (1: preset name) */ -"Edits persist only until the preset is disabled. The default settings of %@ will not be affected." = "Les modifications ne persistent que jusqu'à ce que le préréglage soit désactivé. Les réglages par défaut de %@ ne seront pas affectés."; - -/* The button text for enabling a temporary override */ -"Enable" = "Activer"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Activer indéfiniment"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Activé"; - -/* The text for the override start time */ -"End Time" = "Heure de fin"; - -/* Format string for accessibility label for value entry. (1: value label) */ -"Enter %1$@ value" = "Entrez la valeur %1$@"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Entrez un nombre d'unités"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Entrez un débit en unités par heure"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Historique des événements"; - -/* No comment provided by engineer. */ -"Example" = "Exemple"; - -/* Section title for fast absorbing food */ -"Fast" = "Rapide"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Insulin model setting description (1: app name) (2: number of models) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from %2$@ different models for how the app measures the insulin’s peak activity." = "Pour l'insuline à action rapide, %1$@ suppose qu'elle agit activement pendant 6 heures. Vous pouvez choisir parmi différents modèles pour le pic d'activité mesuré par l'application."; - -/* Information about correction range format (1: app name) */ -"For this range, choose the specific glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin." = "Pour cette plage, choisissez la valeur de glycémie (ou la plage de valeurs) spécifique que %1$@ va viser en ajustant votre insuline basale."; - -/* Support button for Therapy Settings */ -"Get help with Therapy Settings" = "Obtenir de l'aide avec les paramètres de thérapie"; - -/* Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range - Text for go back action on confirmation alert */ -"Go Back" = "Retour"; - -/* Title text for the high basal rate warning */ -"High Basal Rate" = "Débit basal élevé"; - -/* Title text for the high carb ratio warning */ -"High Carb Ratio" = "Ratio de glucide élevé"; - -/* Title text for the high correction value warning */ -"High Correction Value" = "Valeur de correction élevée"; - -/* Title text for the high glucose safety limit warning */ -"High Glucose Safety Limit" = "Limite de sécurité pour la glycémie élevé"; - -/* Title text for the high insulin sensitivity warning */ -"High Insulin Sensitivity" = "Sensibilité à l'insuline élevée"; - -/* Title text for high maximum basal rate warning */ -"High Maximum Basal Rate" = "Débit basal maximum élevé"; - -/* Title text for high maximum bolus warning */ -"High Maximum Bolus" = "Bolus maximum élevé"; - -/* Title text for the low pre-meal value warning */ -"High Pre-Meal Value" = "Valeur pré-repas élevée"; - -/* Title text for the high workout value warning */ -"High Workout Value" = "Valeur d'exercice haute"; - -/* The text for the override history */ -"History" = "Historique"; - -/* Description of how to interact with summary screen */ -"If these settings look good to you, tap Save Settings to continue." = "Si ces paramètres vous semblent bons, appuyez sur Enregistrer les paramètres pour continuer."; - -/* Information about target range */ -"If you've used a CGM before, you're likely familiar with target range as a wide range of values you'd like for your glucose notification alerts, such as 70-180 mg/dL or 90-200 mg/dL." = "Si vous avez déjà utilisé un CGM, vous êtes probablement familiers avec la plage cible comme étant une large plage de valeurs pour lesquelles vous voudriez recevoir des notifications d'alertes, tel que 70-180 mg/dl ou 90-200 mg/dl."; - -/* Title text for insulin model */ -"Insulin Model" = "Modèle d'insuline"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Facteurs de sensibilité à l'insuline"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "Le facteur de sensibilité à l’insuline décrit comment votre taux de glycémie doit réagir à 1 unité d’insuline. Les valeurs plus petites signifie que davantage d’insuline sera administrée quand votre taux de glycémie est au-dessus de la cible. Des valeurs trop faibles peuvent entraîner des hypoglycémies dangereuses."; - -/* Description of an interrupted bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: programmed value (? if no value), 4: unit) */ -"Interrupted %1$@: %2$@ of %3$@ %4$@" = "Interrompu %1$@: %2$@ de %3$@ %4$@"; - -/* Guardrail info text format */ -"It can be set as low as %1$@. It can be set as high as %2$@." = "Il peut être défini aussi bas que %1$@. Il peut être défini aussi haut que %2$@ ."; - -/* Title text for the low basal rate warning */ -"Low Basal Rate" = "Valeur débit basal basse"; - -/* Title text for the low carb ratio warning */ -"Low Carb Ratio" = "Ratios insuline-glucides bas"; - -/* Title text for the low correction value warning */ -"Low Correction Value" = "Valeur correction basse"; - -/* Title text for the low glucose safety limit warning */ -"Low Glucose Safety Limit" = "Valeur de Glycémie basse"; - -/* Title text for the low insulin sensitivity warning */ -"Low Insulin Sensitivity" = "Sensibilité à l'insuline faible"; - -/* Title text for low maximum basal rate warning */ -"Low Maximum Basal Rate" = "Valeur Max débit basal basse"; - -/* Title text for low maximum bolus warning */ -"Low Maximum Bolus" = "Valeur Bolus basse"; - -/* Title text for the low pre-meal value warning */ -"Low Pre-Meal Value" = "Valeur de pré-repas basse"; - -/* Title text for the low workout value warning */ -"Low Workout Value" = "Valeur basse exercice"; - -/* Title of insulin model preset - lyumjev */ -"Lyumjev" = "Lyumjev"; - -/* Placeholder for maximum value in glucose range */ -"max" = "max"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Débit Basal Maximum"; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Bolus Maximum"; - -/* Section title for medium absorbing food */ -"Medium" = "Moyen"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* No comment provided by engineer. */ -"more content" = "plus de contenu"; - -/* Alert action title to open error help */ -"More Info" = "Plus d'informations"; - -/* The text for the override preset name setting */ -"Name" = "Nom"; - -/* Title for mini-modal to add a new schedule entry */ -"New Entry" = "Ajout"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Nouveau préréglage"; - -/* Title text for the zero basal rate warning */ -"No Basal Insulin" = "Pas d'insuline Basal"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Autre"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Besoin total en insuline"; - -/* Title for override history view */ -"Override History" = "Remplacer l'historique"; - -/* The title text for the override presets screen */ -"Override Presets" = "Préréglages ajustement"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Les préréglages d'ajustement peuvent être ajoutés dans la section “Configuration” de l’écran des réglages."; - -/* The section title of glucose overrides */ -"Overrides" = "Ajustements"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Pré-Repas"; - -/* Title text for multi-value pre-meal value warning */ -"Pre-Meal Values" = "Objectif de Pré-Repas"; - -/* title for prescription section */ -"Prescription" = "Prescription"; - -/* The section header text override presets */ -"PRESETS" = "PRÉRÉGLAGES"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Progressing." = "En cours de traitement."; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Événement pompe"; - -/* Title text for suspend resume button when the basal delivery state is not set */ -"Pump Inoperable" = "Pompe inutilisable"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Action rapide - Adulte"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Action rapide - Enfant"; - -/* The default placeholder string for a credential */ -"Required" = "Obligatoire"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Réservoir"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Reprendre l'administration"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Reprise en cours"; - -/* title for summary description section */ -"Review and Save Settings" = "Vérifier et enregistrer les paramètres"; - -/* Description of how to interact with summary screen */ -"Review your therapy settings below. If you’d like to edit any of these settings, tap Back to go back to that screen." = "Vérifiez vos réglages de thérapie ci-dessous. Si vous souhaitez modifier l'un de ces paramètres, appuyez sur Retour pour revenir à cet écran."; - -/* The text for the override preset name field placeholder */ -"Running" = "En marche"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Sauvegarder"; - -/* Alert title for confirming basal rates outside the recommended range */ -"Save Basal Rates?" = "Enregistrer les débits basaux ?"; - -/* Alert title for confirming carb ratios outside the recommended range */ -"Save Carb Ratios?" = "Enregistrer les Ratios ?"; - -/* Alert title for confirming correction ranges outside the recommended range */ -"Save Correction Range(s)?" = "Enregistrer les plages de correction?"; - -/* Alert title for confirming delivery limits outside the recommended range */ -"Save Delivery Limits?" = "Enregistrer les limites d'injection ?"; - -/* Alert title for confirming a glucose safety limit outside the recommended range */ -"Save Glucose Safety Limit?" = "Enregistrer la limite de sécurité de la glycémie ?"; - -/* Alert title for confirming insulin sensitivities outside the recommended range */ -"Save Insulin Sensitivities?" = "Enregistrer les paramètres de sensibilité à l'insuline ?"; - -/* Alert title for confirming pre-meal range overrides outside the recommended range */ -"Save Pre-Meal Range?" = "Enregistrer la zone de pré-repas?"; - -/* Alert title for confirming workout range overrides outside the recommended range */ -"Save Workout Range?" = "Enregistrer la fourchette exercice ?"; - -/* The button text during saving on a configuration page */ -"Saving..." = "Sauvegarde en cours..."; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "AJUSTEMENT PROGRAMMÉ"; - -/* The section header text for a scheduled custom preset */ -"SCHEDULED PRESET" = "PRÉRÉGLAGE PROGRAMMÉ"; - -/* Section title for slow absorbing food */ -"Slow" = "Lent"; - -/* Information about typical maximum basal rates */ -"Some users choose a value 2, 3, or 4 times their highest scheduled basal rate." = "Certains utilisateurs choisissent une valeur 2, 3 ou 4 fois supérieure à leur débit basal programmé le plus élevé."; - -/* The text for the override start time */ -"Start Time" = "Heure de début"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Démarrage basal temporaire"; - -/* Format for prescription descriptive text (1: providerName, 2: datePrescribed) */ -"Submitted by %1$@, %2$@" = "Soumis par %1$@, %2$@"; - -/* Title for support section */ -"Support" = "Support"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspendre l'administration"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspension en cours"; - -/* No comment provided by engineer. */ -"Switch Preview State" = "Changer l'état d'aperçu"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Symbole"; - -/* Text directing the user to configure their first custom preset */ -"Tap '+' to create a new custom preset." = "Appuyez sur '+' pour créer un nouveau préréglage personnalisé."; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Appuyez pour définir"; - -/* The text for the override target range setting */ -"Target Range" = "Plage cible"; - -/* Description of pre-meal mode */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Diminue temporairement votre cible de glycémie avant un repas pour influer sur les pics d'hyperglycémie post-repas."; - -/* Description of workout mode */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Augmente temporairement votre cible de glycémie avant, pendant ou après l'activité physique pour réduire le risque d'hypoglycémie."; - -/* The title for the override selection screen */ -"Temporary Override" = "Ajustement temporaire"; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"than your Correction Range." = "que votre plage de correction."; - -/* Description for selection when no insulin type is selected. */ -"The currently selected fast acting insulin model will be used as a default." = "Le modèle d'insuline à action rapide actuellement sélectionné sera utilisé par défaut."; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Le modèle original utilisé par Loop, permettant de gérer la durée d'action de l'insuline."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "Le temps d'absorption maximum est de %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "La quantité maximale autorisée est de %@ grammes"; - -/* Information about adult insulin model */ -"The rapid-acting adult model assumes peak activity at 75 minutes." = "Ce modèle \"Action rapide-Adulte\" est basé sur une activité maximale de l’insuline vers 75 minutes."; - -/* Information about child insulin model */ -"The rapid-acting child model assumes peak activity at 65 minutes." = "Ce modèle \"Action rapide-Enfant\" est basé sur une activité maximale de l’insuline vers 65 minutes."; - -/* Information about basal rate scheduling */ -"The schedule starts at midnight and cannot contain a rate of 0 U/hr." = "La définition de l'horaire commence à minuit et ne peut pas contenir un taux de 0 U/hr."; - -/* Therapy Settings screen title */ -"Therapy Settings" = "Réglages Thérapeutique"; - -/* No comment provided by engineer. */ -"Therapy Settings Support Placeholder" = "Therapy Settings Support Placeholder"; - -/* Subtitle of afrezza preset */ -"This model assumes peak insulin activity at 19 minutes." = "Ce modèle est basé sur un pic d'activité de l’insuline à 19 minutes."; - -/* Subtitle of Fiasp preset - Subtitle of Lyumjev preset */ -"This model assumes peak insulin activity at 55 minutes." = "Ce modèle est basé sur un pic d'activité de l’insuline à 55 minutes."; - -/* Subtitle of Rapid-Acting – Children preset */ -"This model assumes peak insulin activity at 65 minutes." = "Ce modèle est basé sur un pic d'activité de l’insuline à 65 minutes."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"This model assumes peak insulin activity at 75 minutes." = "Ce modèle est basé sur un pic d'activité de l’insuline à 75 minutes."; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"This will typically be" = "Il s'agit généralement"; - -/* Label for offset from midnight picker */ -"Time" = "Heure"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Temps dans %1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"To be implemented" = "Pas encore implémenté"; - -/* No comment provided by engineer. */ -"Top component" = "Composant supérieur"; - -/* The text indicating Total for Daily Schedule Basal */ -"Total" = "Total"; - -/* The text indicating U/day for Daily Schedule Basal */ -"U/day" = "U/jour"; - -/* The unit string for units per hour */ -"U/hour" = "U/heure"; - -/* Alert title when error occurs while saving a schedule */ -"Unable to Save" = "Impossible d'enregistrer"; - -/* The unit string for units */ -"Units" = "Unités"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Inconnu"; - -/* Title for selection when no insulin type is selected. */ -"Unset" = "Non sélectionné"; - -/* Placeholder text until value is entered */ -"Value" = "Valeur"; - -/* Label indicating validation is occurring */ -"Verifying" = "En train de vérifier"; - -/* The title for the override editing screen */ -"View Override" = "Voir les ajustements"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Attention"; - -/* Disclaimer */ -"Work with your healthcare provider to choose a value that is higher than your highest scheduled basal rate, but as conservative or aggressive as you feel comfortable." = "Travaillez avec votre prestataire de soins pour choisir une valeur supérieure à votre débit basal le plus élevé prévu, mais aussi conservatrice ou agressive que vous le souhaitez."; - -/* Title for the workout override range */ -"Workout" = "Exercice"; - -/* Information about workout range format (1: app name) */ -"Workout Range is the glucose value or range of values you want %1$@ to target during activity. This range will be in effect when you activate the Workout Preset button." = "La plage exercice est la valeur de glycémie ou la fourchette de valeurs que vous souhaitez que %1$@ cible pendant l'activité. Cette plage sera effective lorsque vous activez le préréglage exercice."; - -/* Title text for multi-value workout value warning */ -"Workout Values" = "Valeurs exercice"; - -/* Description of how to add a ratio */ -"You can add different carb ratios for different times of day by using the ➕." = "Vous pouvez ajouter différents ratios insuline-glucides pour différentes périodes de la journée en utilisant le ➕."; - -/* Description of how to add a ratio */ -"You can add different insulin sensitivities for different times of day by using the ➕." = "Vous pouvez ajouter différentes sensibilités à l'insuline pour différents moments de la journée en utilisant ➕."; - -/* Description of how to add a configuration range */ -"You can add different ranges for different times of day by using the ➕." = "Vous pouvez ajouter différentes plages pour différentes périodes de la journée en utilisant le ➕."; - -/* Description of how to add a range */ -"You can add entries for different times of day by using the ➕." = "Vous pouvez ajouter différentes entrées pour différentes périodes de la journée en utilisant le ➕."; - -/* Description of how to edit setting */ -"You can edit a setting by tapping into any line item." = "Vous pouvez modifier une paramètre de l'élément en appuyant n'importe ou sur sa ligne."; - -/* Description of how to edit setting */ -"You can edit the setting by tapping into the line item." = "Vous pouvez modifier la valeur de l'élément en appuyant n'importe ou sur sa ligne."; - -/* Information about basal rates */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Votre débit basal d'insuline est le nombre d'unités par heure que vous souhaitez utiliser pour couvrir vos besoins vitaux d'insuline."; - -/* Lower bound pre-meal information text */ -"your Glucose Safety Limit" = "votre seuil de suspension glycémique"; - -/* Disclaimer */ -"Your healthcare provider can help you choose a Correction Range that's right for you." = "Votre professionnel de soins de santé peut vous aider à choisir une plage de correction qui vous convient."; - -/* Description of insulin sensitivity factor */ -"Your Insulin Sensitivity Factor (ISF) is the drop in glucose expected from one unit of insulin." = "Votre facteur de sensibilité à l’insuline (ISF) est la baisse de glycémie attendue avec une unité d’insuline."; - -/* Information about pre-meal range format (1: app name) */ -"Your Pre-Meal Range should be the glucose value (or range of values) you want %1$@ to target by the time you take your first bite of your meal. This range will be in effect when you activate the Pre-Meal Preset button." = "Votre plage pré-repas doit correspondre à la valeur (ou fourchette de valeurs) de glycémie que vous souhaitez que %1$@ cible au moment où vous commencez. Cette plage sera en vigueur lorsque vous activerez le préréglage pré-repas."; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/he.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/he.lproj/InsulinKit.strings deleted file mode 100644 index cb3cba99e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/he.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Event History"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Non-Pump Insulin"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/he.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/he.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 64e6c3284..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/he.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Event History"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/he.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/he.lproj/Localizable.strings deleted file mode 100644 index 8e0368596..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/he.lproj/Localizable.strings +++ /dev/null @@ -1,307 +0,0 @@ -/* Separator between min and max glucose values */ -"-" = "-"; - -/* The detail text representing no value */ -"–" = "-"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% of normal insulin"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for progress accessibility label (1: duration in seconds) */ -"%1$d percent complete." = "%1$d אחוז בוצע"; - -/* No comment provided by engineer. */ -"🍽" = "🍽"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Absorption Time"; - -/* The title for the override emoji activity section */ -"Activity" = "Activity"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Add Account"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Add Carb Entry"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Are you sure you want to delete all history entries?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Are you sure you want to delete all reservoir values?"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Basal Rates"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Basal, bolus, and correction insulin dose amounts are decreased by %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Basal, bolus, and correction insulin dose amounts are increased by %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Basal, bolus, and correction insulin dose amounts are unaffected."; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancel"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Cancel Override"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Canceling Temp Basal"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Carb Ratios"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Changes will only apply this time you enable the override. The default settings of %@ will not be affected."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact."; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "at %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "since %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "at %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "since %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* The title for the override emoji condition section */ -"Condition" = "Condition"; - -/* Title of the setup button to continue */ -"Continue" = "Continue"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "Correction range is the blood glucose range that you would like Loop to correct to."; - -/* The text for a custom override */ -"Custom" = "Custom"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Custom Override"; - -/* Title of the carb entry date picker cell */ -"Date" = "Date"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Delete Account"; - -/* Button title to delete all objects */ -"Delete All" = "Delete All"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Delivery Limits"; - -/* The text for the override duration setting */ -"Duration" = "Duration"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Edit Carb Entry"; - -/* The title for the override editing screen */ -"Edit Override" = "Edit Override"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "Editing affects only the active override. The default settings of %@ will not be affected."; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Enable Indefinitely"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Enabled"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Enter a number of units"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Enter a rate in units per hour"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Event History"; - -/* Section title for fast absorbing food */ -"Fast" = "Fast"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Title text for insulin model */ -"Insulin Model" = "Insulin Model"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Insulin Sensitivities"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose."; - -/* Placeholder for maximum value in glucose range */ -"max" = "max"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Maximum Basal Rate"; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Maximum Bolus"; - -/* Section title for medium absorbing food */ -"Medium" = "Medium"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* Alert action title to open error help */ -"More Info" = "More Info"; - -/* The text for the override preset name setting */ -"Name" = "Name"; - -/* The title for the new override preset entry screen */ -"New Preset" = "New Preset"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Other"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Overall Insulin Needs"; - -/* The title text for the override presets screen */ -"Override Presets" = "Override Presets"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Override presets can be set up under the 'Configuration' section of the settings screen."; - -/* The section title of glucose overrides */ -"Overrides" = "Overrides"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Pre-Meal"; - -/* The section header text override presets */ -"PRESETS" = "PRESETS"; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Pump Event"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Rapid-Acting – Adults"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Rapid-Acting – Children"; - -/* The default placeholder string for a credential */ -"Required" = "Required"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Reservoir"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Resume Delivery"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Resuming"; - -/* The text for the override preset name field placeholder */ -"Running" = "Running"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Save"; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "SCHEDULED OVERRIDE"; - -/* Section title for slow absorbing food */ -"Slow" = "Slow"; - -/* The text for the override start time */ -"Start Time" = "Start Time"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starting Temp Basal"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspending"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Symbol"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Tap to set"; - -/* The text for the override target range setting */ -"Target Range" = "Target Range"; - -/* The title for the override selection screen */ -"Temporary Override" = "Temporary Override"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "The legacy model used by Loop, allowing customization of action duration."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "The maximum absorption time is %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "The maximum allowed amount is %@ grams"; - -/* Label for offset from midnight picker */ -"Time" = "שעה"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Times in %1$@%2$@%3$@"; - -/* The unit string for units per hour */ -"U/hour" = "U/hour"; - -/* The unit string for units */ -"Units" = "Units"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Unknown"; - -/* Label indicating validation is occurring */ -"Verifying" = "Verifying"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Warning"; - -/* Title for the workout override range */ -"Workout" = "Workout"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/hi.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/hi.lproj/Localizable.strings deleted file mode 100644 index 79b913118..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/hi.lproj/Localizable.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* The title of the cancel action in an action sheet */ -"Cancel" = "निरस्त"; - -/* Title of the setup button to continue */ -"Continue" = "जारी"; - -/* The text for the override preset name setting */ -"Name" = "नाम"; - -/* Label for offset from midnight picker */ -"Time" = "समय"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/hu.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/hu.lproj/InsulinKit.strings deleted file mode 100644 index 3f6fac54d..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/hu.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ - -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Event History"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Non-Pump Insulin"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/hu.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/hu.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 6db3b2d32..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/hu.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ - -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Event History"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Tutal"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/hu.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/hu.lproj/Localizable.strings deleted file mode 100644 index bbc497d99..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/hu.lproj/Localizable.strings +++ /dev/null @@ -1,252 +0,0 @@ -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% of normal insulin"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Absorption Time"; - -/* The title for the override emoji activity section */ -"Activity" = "Activity"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Are you sure you want to delete all history entries?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Are you sure you want to delete all reservoir values?"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Add Account"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Delete Account"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Basal, bolus, and correction insulin dose amounts are decreased by %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Basal, bolus, and correction insulin dose amounts are increased by %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Basal, bolus, and correction insulin dose amounts are unaffected."; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancel"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Cancel Override"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Canceling Temp Basal"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Add Carb Entry"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Edit Carb Entry"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Changes will only apply this time you enable the override. The default settings of %@ will not be affected."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact."; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "at %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "since %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "at %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "since %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* The title for the override emoji condition section */ -"Condition" = "Condition"; - -/* Title of the setup button to continue */ -"Continue" = "Continue"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "Correction range is the blood glucose range that you would like Loop to correct to."; - -/* The text for a custom override */ -"Custom" = "Custom"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Custom Override"; - -/* Title of the carb entry date picker cell */ -"Date" = "Date"; - -/* Button title to delete all objects */ -"Delete All" = "Delete All"; - -/* The text for the override duration setting */ -"Duration" = "Duration"; - -/* The title for the override editing screen */ -"Edit Override" = "Edit Override"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "Editing affects only the active override. The default settings of %@ will not be affected."; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Enable Indefinitely"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Enabled"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Enter a number of units"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Enter a rate in units per hour"; - -/* Section title for fast absorbing food */ -"Fast" = "Fast"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose."; - -/* Placeholder for maximum value in glucose range */ -"max" = "max"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Maximum Basal Rate"; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Maximum Bolus"; - -/* Section title for medium absorbing food */ -"Medium" = "Medium"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* Alert action title to open error help */ -"More Info" = "More Info"; - -/* The text for the override preset name setting */ -"Name" = "Name"; - -/* The title for the new override preset entry screen */ -"New Preset" = "New Preset"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Other"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Overall Insulin Needs"; - -/* The title text for the override presets screen */ -"Override Presets" = "Override Presets"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Override presets can be set up under the 'Configuration' section of the settings screen."; - -/* The section title of glucose overrides */ -"Overrides" = "Overrides"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Pre-Meal"; - -/* The section header text override presets */ -"PRESETS" = "PRESETS"; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Pump Event"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Resume Delivery"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Resuming"; - -/* The text for the override preset name field placeholder */ -"Running" = "Running"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Save"; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "SCHEDULED OVERRIDE"; - -/* Section title for slow absorbing food */ -"Slow" = "Slow"; - -/* The text for the override start time */ -"Start Time" = "Start Time"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starting Temp Basal"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspending"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Symbol"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Tap to set"; - -/* The text for the override target range setting */ -"Target Range" = "Target Range"; - -/* The title for the override selection screen */ -"Temporary Override" = "Temporary Override"; - -/* The default placeholder string for a credential */ -"Required" = "Required"; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "The maximum absorption time is %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "The maximum allowed amount is %@ grams"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Times in %1$@%2$@%3$@"; - -/* The unit string for units per hour */ -"U/hour" = "U/hour"; - -/* The unit string for units */ -"Units" = "Units"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Unknown"; - -/* Label indicating validation is occurring */ -"Verifying" = "Verifying"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Warning"; - -/* Title for the workout override range */ -"Workout" = "Workout"; diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/it.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/it.lproj/InsulinKit.strings deleted file mode 100644 index 0033d608b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/it.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Titolo"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Dettaglio"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Totali"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Serbatoio"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Storia degli Eventi"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Insulina senza Microinfusore"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulina Somministrata"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/it.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/it.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 4deb78e70..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/it.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Titolo"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Dettaglio"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Serbatoio"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Storia degli Eventi"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulina Somministrata"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/it.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/it.lproj/Localizable.strings deleted file mode 100644 index 440425f86..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/it.lproj/Localizable.strings +++ /dev/null @@ -1,703 +0,0 @@ -/* Information about workout range relative to correction range */ -" higher " = "più alto"; - -/* Information about pre-meal range relative to correction range */ -" lower " = "minore"; - -/* Separator between min and max glucose values */ -"-" = "-"; - -/* No comment provided by engineer. */ -"-" = "-"; - -/* The detail text representing no value */ -"–" = "–"; - -/* No comment provided by engineer. */ -"···" = "···"; - -/* No comment provided by engineer. */ -"%@" = "%@"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@ %% d'insulina normale"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Lower bound workout information text format (1: app name) */ -"%1$@ or your Glucose Safety Limit, whichever is higher" = "%1$@ o il limite di sicurezza del glucosio, a seconda di quale sia il più alto"; - -/* Reservoir entry (1: volume value) */ -"%1$@ U" = "%1$@ U"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unità rimanenti alle ore %2$@"; - -/* Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) - Description of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) */ -"%1$@: %2$@ %3$@" = "%1$@ : %2$@ %3$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* No comment provided by engineer. */ -"🍽" = "🍽"; - -/* Premeal override preset title */ -"🍽 Pre-Meal" = "🍽 Pre-Pasto"; - -/* No comment provided by engineer. */ -"🏃‍♂️" = "🏃‍♂️"; - -/* Workout override preset title */ -"🏃‍♂️ Workout" = "🏃‍♂️ Allenamento"; - -/* No comment provided by engineer. */ -"A card whose text will wrap onto multiple lines if I continue to type for long enough—this length should do" = "Una carta il cui testo andrà a capo su più righe se continuo a digitare abbastanza a lungo: questa lunghezza dovrebbe andare bene"; - -/* Information about differences between target range and correction range */ -"A Correction Range is different. This will be a narrower range." = "Un intervallo di correzione è diverso. Questo sarà un intervallo più ristretto."; - -/* No comment provided by engineer. */ -"A simple card" = "Una carta semplice"; - -/* Warning text for basal rate of 0 U/hr */ -"A value of 0 U/hr means you will be scheduled to receive no basal insulin." = "Un valore di 0 U/ora significa che il paziente non riceverà insulina basale."; - -/* No comment provided by engineer. */ -"Above the save button" = "Sopra il pulsante Salva"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Tempo di assorbimento"; - -/* No comment provided by engineer. */ -"Action Button" = "Pulsante di azione"; - -/* The text for the override history duration */ -"Active Duration" = "Durata attiva"; - -/* The title for the override emoji activity section */ -"Activity" = "Attività"; - -/* Button text to confirm adding a new schedule item */ -"Add" = "Aggiungi"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Aggiungi Account"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Agg. Carb. Assunti"; - -/* Title of insulin model preset - afrezza */ -"Afrezza" = "Afrezza"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Sei sicuro di voler eliminare tutte le voci della cronologia?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Sei sicuro di voler eliminare tutti i valori del serbatoio?"; - -/* Authentication hint string for therapy settings */ -"Authenticate to save therapy setting" = "Eseguire l'autenticazione per salvare le Impostazioni di Terapia"; - -/* Back navigation button title */ -"Back" = "Indietro"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Velocità basali"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Le dosi basali, di bolo e di correzione dell’insulina sono calate del %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Le dosi basali, di bolo e di correzione dell’insulina sono aumentate del %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Le dosi basali, di bolo e di correzione dell’insulina sono rimaste invariate."; - -/* No comment provided by engineer. */ -"Bottom component" = "Componente inferiore"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annulla"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Annulla Programma Alternativo"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Annullamento Basale Temp"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Rapporti carboidrati"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Le modifiche saranno applicate solo all’attivazione del programma alternativo. Le impostazioni predefinite di %@ rimarranno invariate."; - -/* Footer text for customizing from a preset (1: preset name) */ -"Changes will only apply this time you enable the preset. The default settings of %@ will not be affected." = "Le modifiche saranno applicate solo quando si attiva la preimpostazione. Le impostazioni predefinite di %@ non vengono modificate."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Scegli un tempo di assorbimento piu lungo per i pasti piu grandi o quelli contenenti grassi e proteine. Questa e solo una guida all’algoritmo e non e necessario che sia esatta."; - -/* Button text to close a modal - Text to close informational page */ -"Close" = "Chiudi"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "a %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "in %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "a %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "in %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Completed." = "Completato."; - -/* The title for the override emoji condition section */ -"Condition" = "Condizione"; - -/* The button text for confirming the setting */ -"Confirm Setting" = "Conferma impostazione"; - -/* No comment provided by engineer. */ -"content" = "contenuto"; - -/* Title of the setup button to continue */ -"Continue" = "Continua"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "L’intervallo di correzione è l’intervallo di glicemia al quale vuoi che si regoli Loop."; - -/* Title text for multi-value correction value warning */ -"Correction Values" = "Valori di correzione"; - -/* The text for a custom override */ -"Custom" = "Programma"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Progr. Alternativo"; - -/* The title for the custom preset entry screen - The title for the custom preset selection screen */ -"Custom Preset" = "Programmazione"; - -/* Title of the carb entry date picker cell */ -"Date" = "Data"; - -/* Delete values for Pre-Meal, inactivates Pre-Meal icon - Test for table cell delete button - The title of the button to remove the credentials for a service */ -"Delete" = "Cancella"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Cancella Account"; - -/* Button title to delete all objects */ -"Delete All" = "Cancella tutto"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Limiti Erogazione"; - -/* Information about delivery limits */ -"Delivery Limits are safety guardrails for your insulin delivery." = "I limiti di consegna sono barriere di sicurezza per la somministrazione di insulina."; - -/* The text for the custom preset disable button */ -"Disable Preset" = "Disabilita preimpostazione"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Fine"; - -/* The text for the override duration setting */ -"Duration" = "Durata"; - -/* Text for edit button - The title for the enabled custom preset editing screen */ -"Edit" = "Modifica"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Mod. Carb Assunti"; - -/* The title for the override editing screen */ -"Edit Override" = "Mod. Progr. Alternativo"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "La modifica riguarda solo il programma alternativo attivo. Le impostazioni predefinite di %@ resteranno invariate."; - -/* Footer text for editing an enabled custom preset (1: preset name) */ -"Edits persist only until the preset is disabled. The default settings of %@ will not be affected." = "Le modifiche persistono solo finché la preimpostazione non viene disattivata. Le impostazioni predefinite di %@ non vengono modificate."; - -/* The button text for enabling a temporary override */ -"Enable" = "Abilita"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Abilita a tempo indeterminato"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Abilitato"; - -/* The text for the override start time */ -"End Time" = "Tempo scaduto"; - -/* Format string for accessibility label for value entry. (1: value label) */ -"Enter %1$@ value" = "Inserisci il valore %1$@"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Inserisci un numero di unità"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Inserisci velocità U/ora"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Storia degli Eventi"; - -/* No comment provided by engineer. */ -"Example" = "Esempio"; - -/* Section title for fast absorbing food */ -"Fast" = "Veloce"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Insulin model setting description (1: app name) (2: number of models) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from %2$@ different models for how the app measures the insulin’s peak activity." = "Per l'insulina ad azione rapida, %1$@ presuppone che funzioni attivamente per 6 ore. Puoi scegliere tra %2$@ diversi modelli per il modo in cui l'app misura il picco di attività dell'insulina."; - -/* Information about correction range format (1: app name) */ -"For this range, choose the specific glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin." = "Per questo intervallo, scegli il valore glicemico specifico (o l'intervallo di valori) a cui vuoi che %1$@ miri per regolare la tua insulina basale."; - -/* Support button for Therapy Settings */ -"Get help with Therapy Settings" = "Ottieni assistenza per le impostazioni della terapia"; - -/* Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range - Text for go back action on confirmation alert */ -"Go Back" = "Torna indietro"; - -/* Title text for the high basal rate warning */ -"High Basal Rate" = "Velocità Basale Alta"; - -/* Title text for the high carb ratio warning */ -"High Carb Ratio" = "Rapporto Carboidrati Alto"; - -/* Title text for the high correction value warning */ -"High Correction Value" = "Valore di Correzione Alto"; - -/* Title text for the high glucose safety limit warning */ -"High Glucose Safety Limit" = "Limite glicemico di sicurezza alto"; - -/* Title text for the high insulin sensitivity warning */ -"High Insulin Sensitivity" = "Sensibilità all’insulina Alta"; - -/* Title text for high maximum basal rate warning */ -"High Maximum Basal Rate" = "Velocità Basale Massima Alta"; - -/* Title text for high maximum bolus warning */ -"High Maximum Bolus" = "Bolo Massimo Alto"; - -/* Title text for the low pre-meal value warning */ -"High Pre-Meal Value" = "Valore Pre-Pasto Alto"; - -/* Title text for the high workout value warning */ -"High Workout Value" = "Valore Alto Allenamento"; - -/* The text for the override history */ -"History" = "Storia"; - -/* Description of how to interact with summary screen */ -"If these settings look good to you, tap Save Settings to continue." = "Se queste impostazioni ti sembrano valide, tocca Salva impostazioni per continuare."; - -/* Information about target range */ -"If you've used a CGM before, you're likely familiar with target range as a wide range of values you'd like for your glucose notification alerts, such as 70-180 mg/dL or 90-200 mg/dL." = "Se hai già utilizzato un CGM, probabilmente conosci l'intervallo target come un'ampia gamma di valori che desideri per gli avvisi di notifica del glucosio, ad esempio 70-180 mg/dL o 90-200 mg/dL."; - -/* Title text for insulin model */ -"Insulin Model" = "Modello di azione dell'Insulina"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Sensibilità Insulinica"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "La sensibilità all’insulina descrive il modo in cui la tua glicemia dovrebbe rispondere a una dose di insulina pari a 1 Unità. In caso di valori inferiori, al superamento del target verrà somministrata più insulina. Valori troppo bassi possono causare livelli di glicemia pericolosamente bassi."; - -/* Description of an interrupted bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: programmed value (? if no value), 4: unit) */ -"Interrupted %1$@: %2$@ of %3$@ %4$@" = "Interrotto %1$@ : %2$@ di %3$@ %4$@"; - -/* Guardrail info text format */ -"It can be set as low as %1$@. It can be set as high as %2$@." = "Può essere impostato a partire da %1$@ . Può essere impostato fino a %2$@ ."; - -/* Title text for the low basal rate warning */ -"Low Basal Rate" = "Velocità basale bassa"; - -/* Title text for the low carb ratio warning */ -"Low Carb Ratio" = "Rapporto Carboidrati basso"; - -/* Title text for the low correction value warning */ -"Low Correction Value" = "Valore Inferiore di Correzione "; - -/* Title text for the low glucose safety limit warning */ -"Low Glucose Safety Limit" = "Limite Inferiore di Salvezza della Glicemia"; - -/* Title text for the low insulin sensitivity warning */ -"Low Insulin Sensitivity" = "Sensibilità all’insulina bassa"; - -/* Title text for low maximum basal rate warning */ -"Low Maximum Basal Rate" = "Velocità Basale Massima Bassa"; - -/* Title text for low maximum bolus warning */ -"Low Maximum Bolus" = "Bolo Massimo Basso"; - -/* Title text for the low pre-meal value warning */ -"Low Pre-Meal Value" = "Valore Pre-Pasto basso"; - -/* Title text for the low workout value warning */ -"Low Workout Value" = "Valore Basso Allenamento"; - -/* Title of insulin model preset - lyumjev */ -"Lyumjev" = "Lyumjev"; - -/* Placeholder for maximum value in glucose range */ -"max" = "max"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Profilo Basale Massimo"; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Bolo Massimo"; - -/* Section title for medium absorbing food */ -"Medium" = "Medio"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* No comment provided by engineer. */ -"more content" = "più contenuti"; - -/* Alert action title to open error help */ -"More Info" = "Piu info"; - -/* The text for the override preset name setting */ -"Name" = "Nome"; - -/* Title for mini-modal to add a new schedule entry */ -"New Entry" = "Nuovo accesso"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Nuove impostazioni predefinite"; - -/* Title text for the zero basal rate warning */ -"No Basal Insulin" = "Nessuna insulina basale"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Altro"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Fabbisogno complessivo di insulina"; - -/* Title for override history view */ -"Override History" = "Storia Programma"; - -/* The title text for the override presets screen */ -"Override Presets" = "Programma Alternativo"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "È possibile configurare le impostazioni predefinite del programma alternativo nella sezione ‘Configurazione' della schermata impostazioni."; - -/* The section title of glucose overrides */ -"Overrides" = "Programmi alternativi"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Pre-Pasto"; - -/* Title text for multi-value pre-meal value warning */ -"Pre-Meal Values" = "Valori Pre-Pasto"; - -/* title for prescription section */ -"Prescription" = "Prescrizione"; - -/* The section header text override presets */ -"PRESETS" = "IMPOSTAZIONI PREDEFINITE"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Progressing." = "Avanzamento."; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Evento Microinfusore"; - -/* Title text for suspend resume button when the basal delivery state is not set */ -"Pump Inoperable" = "Pompa non funzionante"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Insulina ultrarapida – Adulti"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Insulina ultrarapida – Bambini"; - -/* The default placeholder string for a credential */ -"Required" = "Necessario"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Serbatoio"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Riprendi erogazione"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Ripresa in corso"; - -/* title for summary description section */ -"Review and Save Settings" = "Rivedi e salva le impostazioni"; - -/* Description of how to interact with summary screen */ -"Review your therapy settings below. If you’d like to edit any of these settings, tap Back to go back to that screen." = "Controlla le impostazioni della terapia. Se desideri modificare una di queste impostazioni, tocca Indietro per tornare a quella schermata."; - -/* The text for the override preset name field placeholder */ -"Running" = "Corsa"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Salva"; - -/* Alert title for confirming basal rates outside the recommended range */ -"Save Basal Rates?" = "Salva i valori basali?"; - -/* Alert title for confirming carb ratios outside the recommended range */ -"Save Carb Ratios?" = "Salva Rapporti carboidrati?"; - -/* Alert title for confirming correction ranges outside the recommended range */ -"Save Correction Range(s)?" = "Salva intervallo/i di correzione?"; - -/* Alert title for confirming delivery limits outside the recommended range */ -"Save Delivery Limits?" = "Salva i limiti di erogazione?"; - -/* Alert title for confirming a glucose safety limit outside the recommended range */ -"Save Glucose Safety Limit?" = "Salva il limite di sicurezza del glucosio?"; - -/* Alert title for confirming insulin sensitivities outside the recommended range */ -"Save Insulin Sensitivities?" = "Salva la sensibilità insulinica?"; - -/* Alert title for confirming pre-meal range overrides outside the recommended range */ -"Save Pre-Meal Range?" = "Salva l'intervallo Pre-Pasto?"; - -/* Alert title for confirming workout range overrides outside the recommended range */ -"Save Workout Range?" = "Salvare l'intervallo di allenamento?"; - -/* The button text during saving on a configuration page */ -"Saving..." = "Salvataggio..."; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "PROGRAMMA ALTERNATIVO PIANIFICATO"; - -/* The section header text for a scheduled custom preset */ -"SCHEDULED PRESET" = "Regolazione Manuale Programmata"; - -/* Section title for slow absorbing food */ -"Slow" = "Lento"; - -/* Information about typical maximum basal rates */ -"Some users choose a value 2, 3, or 4 times their highest scheduled basal rate." = "Alcuni utenti scelgono un valore pari a 2, 3 o 4 volte la velocità basale pianificata massima."; - -/* The text for the override start time */ -"Start Time" = "Ora di inizio"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Attivazione velocità basale temporanea in corso"; - -/* Format for prescription descriptive text (1: providerName, 2: datePrescribed) */ -"Submitted by %1$@, %2$@" = "Inviato da %1$@ , %2$@"; - -/* Title for support section */ -"Support" = "Supporto"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Sospendi erogazione"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Sospensione in corso"; - -/* No comment provided by engineer. */ -"Switch Preview State" = "Cambia Stato Anteprima"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Simbolo"; - -/* Text directing the user to configure their first custom preset */ -"Tap '+' to create a new custom preset." = "Tocca \"+\" per creare una nuova programmazione."; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Imposta"; - -/* The text for the override target range setting */ -"Target Range" = "Intervallo Obiettivo"; - -/* Description of pre-meal mode */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Abbassa temporaneamente il tuo target glicemico prima di un pasto per influenzare i picchi glicemici postprandiali."; - -/* Description of workout mode */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Aumentare temporaneamente il target glicemico prima, durante o dopo l'attività fisica per ridurre il rischio di eventi ipoglicemici."; - -/* The title for the override selection screen */ -"Temporary Override" = "Programma alternativo temporaneo"; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"than your Correction Range." = "Il tuo intervallo di correzione"; - -/* Description for selection when no insulin type is selected. */ -"The currently selected fast acting insulin model will be used as a default." = "Il modello di insulina ad azione rapida attualmente selezionato verrà utilizzato come predefinito."; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "ll modello antecedente usato da Loop, che consente la personalizzazione della durata dell'azione."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "Il tempo di assorbimento massimo e %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "La massima quantita permessa %@ grams"; - -/* Information about adult insulin model */ -"The rapid-acting adult model assumes peak activity at 75 minutes." = "Il modello adulto ad azione rapida assume il picco di attività a 75 minuti."; - -/* Information about child insulin model */ -"The rapid-acting child model assumes peak activity at 65 minutes." = "Il modello del bambino ad azione rapida assume il picco di attività a 65 minuti."; - -/* Information about basal rate scheduling */ -"The schedule starts at midnight and cannot contain a rate of 0 U/hr." = "Il programma inizia a mezzanotte e non può contenere una velocità di 0 U/ora."; - -/* Therapy Settings screen title */ -"Therapy Settings" = "Impostazioni Terapia"; - -/* No comment provided by engineer. */ -"Therapy Settings Support Placeholder" = "Segnaposto di supporto per le impostazioni di terapia"; - -/* Subtitle of afrezza preset */ -"This model assumes peak insulin activity at 19 minutes." = "Questo modello presuppone il picco di attività insulinica a 19 minuti."; - -/* Subtitle of Fiasp preset - Subtitle of Lyumjev preset */ -"This model assumes peak insulin activity at 55 minutes." = "Questo modello presuppone il picco di attività insulinica a 55 minuti."; - -/* Subtitle of Rapid-Acting – Children preset */ -"This model assumes peak insulin activity at 65 minutes." = "Questo modello presuppone il picco di attività insulinica a 65 minuti."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"This model assumes peak insulin activity at 75 minutes." = "Questo modello presuppone il picco di attività insulinica a 75 minuti."; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"This will typically be" = "Questo in genere sara'"; - -/* Label for offset from midnight picker */ -"Time" = "Tempo"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Times in %1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"To be implemented" = "Da implementare"; - -/* No comment provided by engineer. */ -"Top component" = "Componente Principale"; - -/* The text indicating Total for Daily Schedule Basal */ -"Total" = "Totale"; - -/* The text indicating U/day for Daily Schedule Basal */ -"U/day" = "U/giorno"; - -/* The unit string for units per hour */ -"U/hour" = "U/ora"; - -/* Alert title when error occurs while saving a schedule */ -"Unable to Save" = "incapace salvare "; - -/* The unit string for units */ -"Units" = "Unità"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Sconosciuto"; - -/* Title for selection when no insulin type is selected. */ -"Unset" = "Tempo di azione iniziale"; - -/* Placeholder text until value is entered */ -"Value" = "Valore"; - -/* Label indicating validation is occurring */ -"Verifying" = "Sto verificando"; - -/* The title for the override editing screen */ -"View Override" = "Vedere il programma alternativo"; - -/* Title of insulin model setting */ -"Walsh" = "modello mimetico modificabile di insulina "; - -/* Title of an alert containing a validation warning */ -"Warning" = "Avvertimento"; - -/* Disclaimer */ -"Work with your healthcare provider to choose a value that is higher than your highest scheduled basal rate, but as conservative or aggressive as you feel comfortable." = "Collabora con il tuo medico per scegliere un valore superiore alla velocità basale programmata più alta, ma conservativo o aggressivo quanto ti senti a tuo agio."; - -/* Title for the workout override range */ -"Workout" = "Allenarsi"; - -/* Information about workout range format (1: app name) */ -"Workout Range is the glucose value or range of values you want %1$@ to target during activity. This range will be in effect when you activate the Workout Preset button." = "L'intervallo di allenamento è il valore glicemico o l'intervallo di valori che vuoi che %1$@ abbia come target durante l'attività. Questo intervallo sarà effettivo quando si attiva il pulsante Preimpostazione allenamento."; - -/* Title text for multi-value workout value warning */ -"Workout Values" = "Valori Allenamento"; - -/* Description of how to add a ratio */ -"You can add different carb ratios for different times of day by using the ➕." = "Puoi aggiungere diversi rapporti di carboidrati per diversi momenti della giornata utilizzando ➕."; - -/* Description of how to add a ratio */ -"You can add different insulin sensitivities for different times of day by using the ➕." = "È possibile aggiungere diverse sensibilità all'insulina per diversi momenti della giornata utilizzando ➕."; - -/* Description of how to add a configuration range */ -"You can add different ranges for different times of day by using the ➕." = "È possibile aggiungere diversi intervalli per diverse ore del giorno utilizzando ➕."; - -/* Description of how to add a range */ -"You can add entries for different times of day by using the ➕." = "È possibile aggiungere valori per le diverse ore del giorno utilizzando ➕."; - -/* Description of how to edit setting */ -"You can edit a setting by tapping into any line item." = "Per redigere qualsiasi impostazioni basta toccare la linea relativa dell'articolo desiderato "; - -/* Description of how to edit setting */ -"You can edit the setting by tapping into the line item." = "Per redigerne le impostazioni basta toccare la linea dell'articolo desiderato "; - -/* Information about basal rates */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "La velocità basale d'insulina è il numero di unità all'ora che si desidera utilizzare per coprire il tuo fabbisogno d'insulina basale."; - -/* Lower bound pre-meal information text */ -"your Glucose Safety Limit" = "il tuo limite di sicurezza del glucosio"; - -/* Disclaimer */ -"Your healthcare provider can help you choose a Correction Range that's right for you." = "Il tuo medico può aiutarti a scegliere la gamma di correzione adatto a te."; - -/* Description of insulin sensitivity factor */ -"Your Insulin Sensitivity Factor (ISF) is the drop in glucose expected from one unit of insulin." = "Il fattore di sensibilità all'insulina (ISF) è il calo di glicemia previsto da un'unità di insulina."; - -/* Information about pre-meal range format (1: app name) */ -"Your Pre-Meal Range should be the glucose value (or range of values) you want %1$@ to target by the time you take your first bite of your meal. This range will be in effect when you activate the Pre-Meal Preset button." = "Il tuo Intervallo pre-prasto dovrebbe essere il valore glicemico (o l'intervallo di valori) che vuoi che %1$@ abbia come target prima che tu assuma il primo boccone del tuo pasto. Questo intervallo sarà effettivo quando si attiva il pulsante pre-pasto preimpostato."; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/ja.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/ja.lproj/InsulinKit.strings deleted file mode 100644 index cb3cba99e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/ja.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Event History"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Non-Pump Insulin"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/ja.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/ja.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 64e6c3284..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/ja.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Event History"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/ja.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/ja.lproj/Localizable.strings deleted file mode 100644 index b5b4c69f7..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/ja.lproj/Localizable.strings +++ /dev/null @@ -1,298 +0,0 @@ -/* Separator between min and max glucose values */ -"-" = "-"; - -/* The detail text representing no value */ -"–" = "—"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% of normal insulin"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%2$@の時点で %1$@ U 残っています"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "吸収時間"; - -/* The title for the override emoji activity section */ -"Activity" = "アクティビティ"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "アカウントを追加"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "糖質の記入を追加"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "入力履歴をすべて削除しますか?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "リザーバの値をすべて削除しますか?"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "基礎レート"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "基礎、ボーラス、補正注入の量が %@%%減ります。"; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "基礎、ボーラス、補正注入の量が %@%%増えます。"; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "基礎、ボーラス、補正注入の量は変わりません。"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "キャンセル"; - -/* The text for the override cancellation button */ -"Cancel Override" = "オーバーライドをキャンセル"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "一時基礎レートをキャンセルします"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Carb Ratios"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "オーバーライドの有効化は今回のみ適用されます。%@ の初期設定は変わりません。"; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "量の多い食事や脂質やたんぱく質を含んだ食事には長い吸収時間を選んでください。これはアルゴリズムのための参考で、厳密である必要はありません。"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "%1$@ 時点"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "%1$@ より"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "%1$@ 時点"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "%1$@ より"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* The title for the override emoji condition section */ -"Condition" = "コンディション"; - -/* Title of the setup button to continue */ -"Continue" = "次へ"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "目標グルコース範囲は、血糖値がこの範囲内に補正されるようループに設定する範囲です。"; - -/* The text for a custom override */ -"Custom" = "カスタム"; - -/* The title for the custom override entry screen */ -"Custom Override" = "カスタムオーバーライド"; - -/* Title of the carb entry date picker cell */ -"Date" = "日付"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "アカウントを削除"; - -/* Button title to delete all objects */ -"Delete All" = "すべて削除"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "注入限度"; - -/* The text for the override duration setting */ -"Duration" = "期間"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "糖質の記入を編集"; - -/* The title for the override editing screen */ -"Edit Override" = "オーバーライドを編集"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "オーバーライドの編集は今回のみ適用されます。%@ の初期設定は変わりません。"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "無期限を有効にする"; - -/* The detail text describing an enabled setting */ -"Enabled" = "有効"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "単位数を入力"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "毎時単位(U/h)を入力"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Event History"; - -/* Section title for fast absorbing food */ -"Fast" = "速め"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Title text for insulin model */ -"Insulin Model" = "インスリンモデル"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "インスリン効果値"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "インスリン効果値は、1単位のインスリンによって血糖値がどれだけ反応するかを表します。この値が小さいほど、測定値がターゲットを超えたときに注入されるインスリンの量が多くなります。値を小さく設定しすぎると低血糖の原因となり危険です。"; - -/* Placeholder for maximum value in glucose range */ -"max" = "max"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "最大基礎レート"; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "最大ボーラス"; - -/* Section title for medium absorbing food */ -"Medium" = "中"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* Alert action title to open error help */ -"More Info" = "詳細"; - -/* The text for the override preset name setting */ -"Name" = "プリセット名"; - -/* The title for the new override preset entry screen */ -"New Preset" = "プリセットを設定する"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "その他"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "総インスリン必要量"; - -/* The title text for the override presets screen */ -"Override Presets" = "オーバーライドプリセット"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "オーバーライドプリセットは、設定画面のコンフィグレーションで設定できます。"; - -/* The section title of glucose overrides */ -"Overrides" = "オーバーライド"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "食前"; - -/* The section header text override presets */ -"PRESETS" = "プリセット"; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "ポンプイベント"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "超速攻型 - 大人"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "超速攻型 - 子供"; - -/* The default placeholder string for a credential */ -"Required" = "必須"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Reservoir"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "注入を再開"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "再開中"; - -/* The text for the override preset name field placeholder */ -"Running" = "動作中"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "保存"; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "SCHEDULED OVERRIDE"; - -/* Section title for slow absorbing food */ -"Slow" = "遅め"; - -/* The text for the override start time */ -"Start Time" = "開始時間"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "一時基礎を開始"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "注入を一時停止"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "一時停止中"; - -/* The text for the override preset symbol setting */ -"Symbol" = "シンボル"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "タップして確定"; - -/* The text for the override target range setting */ -"Target Range" = "ターゲット範囲"; - -/* The title for the override selection screen */ -"Temporary Override" = "一時的オーバーライト"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "ループのレガシーモデルで、作用期間をカスタマイズできます。"; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "最大吸収時間: %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "最大量: %@ g"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "時間帯 %1$@%2$@%3$@"; - -/* The unit string for units per hour */ -"U/hour" = "U/時"; - -/* The unit string for units */ -"Units" = "単位"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "不明"; - -/* Label indicating validation is occurring */ -"Verifying" = "確認中"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "警告"; - -/* Title for the workout override range */ -"Workout" = "運動"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/nb.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/nb.lproj/InsulinKit.strings deleted file mode 100644 index e7ce06111..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/nb.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Tittel"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detalj"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "E totalt"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoar"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Hendelseshistorie"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Ikke-pumpe insulin"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/nb.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/nb.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 3befcb5c0..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/nb.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Tittel"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detalj"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoar"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Hendelseshistorie"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/nb.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/nb.lproj/Localizable.strings deleted file mode 100644 index b4481ae94..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/nb.lproj/Localizable.strings +++ /dev/null @@ -1,733 +0,0 @@ -/* Information about workout range relative to correction range */ -" higher " = "høyere"; - -/* Information about pre-meal range relative to correction range */ -" lower " = " nedre "; - -/* Separator between min and max glucose values */ -"-" = "-"; - -/* No comment provided by engineer. */ -"-" = "–"; - -/* The detail text representing no value */ -"–" = "–"; - -/* No comment provided by engineer. */ -"···" = "···"; - -/* No comment provided by engineer. */ -"%@" = "%@"; - -/* Appends a full-stop to a statement */ -"%@." = "%@ ."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% av normalt insulin"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Information about insulin action duration (1: app name) */ -"%1$@ assumes that the insulin it has delivered is actively working to lower your glucose for 6 hours. This setting cannot be changed." = "%1$@ antar at insulinet den har levert, jobber aktivt med å senke blodsukkeret i 6 timer. Denne innstillingen kan ikke endres."; - -/* Lower bound workout information text format (1: app name) */ -"%1$@ or your Glucose Safety Limit, whichever is higher" = "%1$@ eller din sikkerhetsgrense for blodsukker, avhengig av hva som er høyest"; - -/* Information about max number of basal rates (1: app name) (2: maximum schedule entry count) */ -"%1$@ supports 1 to %2$@ rates per day." = "%1$@ støtter 1 til %2$@ rater per dag."; - -/* Reservoir entry (1: volume value) */ -"%1$@ U" = "%1$@ E"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ enheter gjenstår ved %2$@"; - -/* Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) - Description of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) */ -"%1$@: %2$@ %3$@" = "%1$@ : %2$@ %3$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* No comment provided by engineer. */ -"🍽" = "🍽"; - -/* Premeal override preset title */ -"🍽 Pre-Meal" = "🍽 Før måltid"; - -/* No comment provided by engineer. */ -"🏃‍♂️" = "🏃‍♂️"; - -/* Workout override preset title */ -"🏃‍♂️ Workout" = "🏃 ♂️ Treningsøkt"; - -/* No comment provided by engineer. */ -"A card whose text will wrap onto multiple lines if I continue to type for long enough—this length should do" = "Et kort hvis tekst vil pakkes inn på flere linjer hvis jeg fortsetter å skrive lenge nok – denne lengden bør gjøre det"; - -/* Information about differences between target range and correction range */ -"A Correction Range is different. This will be a narrower range." = "Et korreksjonsområde er annerledes. Dette vil være et smalere område."; - -/* No comment provided by engineer. */ -"A simple card" = "Et enkelt kort"; - -/* Warning text for basal rate of 0 U/hr */ -"A value of 0 U/hr means you will be scheduled to receive no basal insulin." = "En verdi på 0 E/time betyr at du ikke vil få noe basalinsulin."; - -/* No comment provided by engineer. */ -"Above the save button" = "Over lagre-knappen"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Absorbsjonstid"; - -/* No comment provided by engineer. */ -"Action Button" = "Handling-knapp"; - -/* The text for the override history duration */ -"Active Duration" = "Aktiv varighet"; - -/* The title for the override emoji activity section */ -"Activity" = "Aktivitet"; - -/* Button text to confirm adding a new schedule item */ -"Add" = "Legg til"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Legg Til Konto"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Legg til karbohydrater"; - -/* Title of insulin model preset - afrezza */ -"Afrezza" = "Afrezza"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Er du sikker på at du vil slette alle historiske innslag?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Er du sikker på at du vil slette alle reservoarverdier?"; - -/* Authentication hint string for therapy settings */ -"Authenticate to save therapy setting" = "Autentiser for å lagre behandlingsinnstillingen"; - -/* Back navigation button title */ -"Back" = "Tilbake"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Basal-satser"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Insulindoser for basal, bolus og korreksjon er redusert med %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Insulindoser for bassal, bolus og korreksjon er økt med %@%%"; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Insulindoser for basal, bolus og korreksjon er uendret."; - -/* No comment provided by engineer. */ -"Bottom component" = "Nederste komponent"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Avbryt"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Avbryt overstyring"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Avbryter midlertidig basal"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Karb forhold"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Endringer vil kun gjelde for denne gangen du aktiverer overstyring. Standardinstillinger for %@ vil ikke bli påvirket."; - -/* Footer text for customizing from a preset (1: preset name) */ -"Changes will only apply this time you enable the preset. The default settings of %@ will not be affected." = "Endringer vil kun gjelde for denne gangen du aktiverer forhåndsinnstillingen. Standardinnstillingene til %@ vil ikke bli påvirket."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Velg en lengre absorpsjonstid for større måltider, eller de som inneholder fett og proteiner. Dette er bare veiledning til algoritmen og trenger ikke å være nøyaktig."; - -/* Button text to close a modal - Text to close informational page */ -"Close" = "Lukk"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "kl. %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "siden %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "kl. %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "siden %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "Ok"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Completed." = "Fullført."; - -/* The title for the override emoji condition section */ -"Condition" = "Betingelse"; - -/* The button text for confirming the setting */ -"Confirm Setting" = "Bekreft"; - -/* No comment provided by engineer. */ -"content" = "innhold"; - -/* Title of the setup button to continue */ -"Continue" = "Fortsett"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "Korreksjonsområde er området du ønsker at Loop skal korrigere blodsukker til."; - -/* Title text for multi-value correction value warning */ -"Correction Values" = "Korreksjonsverdier"; - -/* The text for a custom override */ -"Custom" = "Tilpasset"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Tilpasset overstyring"; - -/* The title for the custom preset entry screen - The title for the custom preset selection screen */ -"Custom Preset" = "Egendefinert forhåndsinnstilling"; - -/* Title of the carb entry date picker cell */ -"Date" = "Dato"; - -/* Delete values for Pre-Meal, inactivates Pre-Meal icon - Test for table cell delete button - The title of the button to remove the credentials for a service */ -"Delete" = "Slett"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Slett Konto"; - -/* Button title to delete all objects */ -"Delete All" = "Slett alle"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Leveringsgrenser"; - -/* Information about delivery limits */ -"Delivery Limits are safety guardrails for your insulin delivery." = "Leveringsgrenser er sikkerhetsrekkverk for insulinleveringen."; - -/* The text for the custom preset disable button */ -"Disable Preset" = "Deaktiver forhåndsinnstilling"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Ferdig"; - -/* The text for the override duration setting */ -"Duration" = "Varighet"; - -/* Text for edit button - The title for the enabled custom preset editing screen */ -"Edit" = "Rediger"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Rediger karbohydrater"; - -/* The title for the override editing screen */ -"Edit Override" = "Rediger overstyring"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "Redigering påvirker kun den aktive overstyringen. Standardinnstillingen %@ vil ikke bbli påvirket."; - -/* Footer text for editing an enabled custom preset (1: preset name) */ -"Edits persist only until the preset is disabled. The default settings of %@ will not be affected." = "Endringer gjelder kun til forhåndsinnstillingen er deaktivert. Standardinnstillingene til %@ vil ikke bli påvirket."; - -/* The button text for enabling a temporary override */ -"Enable" = "Aktiver"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Aktiver på ubestemt tid"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Aktivert"; - -/* The text for the override start time */ -"End Time" = "Sluttid"; - -/* Format string for accessibility label for value entry. (1: value label) */ -"Enter %1$@ value" = "Skriv inn %1$@ verdi"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Skriv inn antall enheter"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Velg en grense for maks enheter per time"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Hendelseshistorie"; - -/* No comment provided by engineer. */ -"Example" = "Eksempel"; - -/* Section title for fast absorbing food */ -"Fast" = "Rask"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Insulin model setting description (1: app name) (2: number of models) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from %2$@ different models for how the app measures the insulin’s peak activity." = "For hurtigvirkende insulin antar %1$@ at det virker aktivt i 6 timer. Du kan velge mellom %2$@ forskjellige modeller for hvordan appen måler insulinets toppaktivitet."; - -/* Information about correction range format (1: app name) */ -"For this range, choose the specific glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin." = "For dette området, velg den spesifikke sikkerhets grenseverdien (eller verdiområdet) som du vil at %1$@ skal sikte på for å justere basalinsulinet."; - -/* Support button for Therapy Settings */ -"Get help with Therapy Settings" = "Få hjelp med behandlingsinnstillinger"; - -/* Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range - Text for go back action on confirmation alert */ -"Go Back" = "Gå tilbake"; - -/* Title text for the high basal rate warning */ -"High Basal Rate" = "Høy basalrate"; - -/* Title text for the high carb ratio warning */ -"High Carb Ratio" = "Høyt karbohydratforhold"; - -/* Title text for the high correction value warning */ -"High Correction Value" = "Høy korreksjonsverdi"; - -/* Title text for the high glucose safety limit warning */ -"High Glucose Safety Limit" = "Sikkerhetsgrense for høyt blodsukker"; - -/* Title text for the high insulin sensitivity warning */ -"High Insulin Sensitivity" = "Høy insulinfølsomhet"; - -/* Title text for high maximum basal rate warning */ -"High Maximum Basal Rate" = "Høy maksimal basalrate"; - -/* Title text for high maximum bolus warning */ -"High Maximum Bolus" = "Høy maksimal bolus"; - -/* Title text for the low pre-meal value warning */ -"High Pre-Meal Value" = "Høy verdi før måltid"; - -/* Title text for the high workout value warning */ -"High Workout Value" = "Høy treningsverdi"; - -/* The text for the override history */ -"History" = "Historie"; - -/* Description of how to interact with summary screen */ -"If these settings look good to you, tap Save Settings to continue." = "Hvis disse innstillingene ser bra ut, trykk på Lagre innstillingene for å fortsette."; - -/* Information about target range */ -"If you've used a CGM before, you're likely familiar with target range as a wide range of values you'd like for your glucose notification alerts, such as 70-180 mg/dL or 90-200 mg/dL." = "Hvis du har brukt en CGM før, er du sannsynligvis kjent med målområdet som et bredt spekter av verdier du vil ha for blodsukkervarslene dine, for eksempel 70-180 mg/dL eller 90-200 mg/dL."; - -/* No comment provided by engineer. */ -"info" = "info"; - -/* Title text for insulin model */ -"Insulin Model" = "Insulin modell"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Insulinsensitivitet"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "Insulinfølsomhet beskriver hvordan blodsukkeret responderer på 1 enhet insulin. Mindre verdier betyr at mer insulin vil bli gitt når man er over målområdet. Verdier som er for små kan føre til farlig lavt blodsukker."; - -/* Description of an interrupted bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: programmed value (? if no value), 4: unit) */ -"Interrupted %1$@: %2$@ of %3$@ %4$@" = "Avbrutt %1$@: %2$@ av %3$@ %4$@"; - -/* Guardrail info text format */ -"It can be set as low as %1$@. It can be set as high as %2$@." = "Den kan stilles inn så lavt som %1$@. Den kan settes så høyt som %2$@."; - -/* Title text for the low basal rate warning */ -"Low Basal Rate" = "Lav basalrate"; - -/* Title text for the low carb ratio warning */ -"Low Carb Ratio" = "Lavt karbohydratforhold"; - -/* Title text for the low correction value warning */ -"Low Correction Value" = "Lav korreksjonsverdi"; - -/* Title text for the low glucose safety limit warning */ -"Low Glucose Safety Limit" = "Sikkerhetsgrense for lavt blodsukker"; - -/* Title text for the low insulin sensitivity warning */ -"Low Insulin Sensitivity" = "Lav insulinfølsomhet"; - -/* Title text for low maximum basal rate warning */ -"Low Maximum Basal Rate" = "Lav maksimal basalrate"; - -/* Title text for low maximum bolus warning */ -"Low Maximum Bolus" = "Lav maksimal bolus-dose"; - -/* Title text for the low pre-meal value warning */ -"Low Pre-Meal Value" = "Lav verdi før måltid"; - -/* Title text for the low workout value warning */ -"Low Workout Value" = "Lav treningsverdi"; - -/* Title of insulin model preset - lyumjev */ -"Lyumjev" = "Lyumjev"; - -/* Placeholder for maximum value in glucose range */ -"max" = "max"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Maks basalgrense"; - -/* Information about maximum basal rate (1: app name) */ -"Maximum Basal Rate is the maximum automatically adjusted basal rate that %1$@ is allowed to enact to help reach your correction range." = "Maksimal basaldose er den maksimale automatisk justerte basaldosen som %1$@ har lov til å aktivere for å hjelpe deg med å nå ditt korreksjonsområde."; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Maks bolus"; - -/* Information about maximum bolus (1: app name) */ -"Maximum Bolus is the highest bolus amount that you will allow %1$@ to recommend at one time to cover carbs or bring down high glucose." = "Maksimal bolus er den høyeste bolusmengden du vil tillate %1$@ å anbefale på en gang for å dekke karbohydrater eller redusere høyt blodsukker."; - -/* Section title for medium absorbing food */ -"Medium" = "Medium"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* No comment provided by engineer. */ -"more content" = "mer innhold"; - -/* Alert action title to open error help */ -"More Info" = "Mer info"; - -/* The text for the override preset name setting */ -"Name" = "Navn"; - -/* Title for mini-modal to add a new schedule entry */ -"New Entry" = "Ny oppføring"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Ny forhåndsinstilling"; - -/* Title text for the zero basal rate warning */ -"No Basal Insulin" = "Ingen basal insulin"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Annet"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Insulinbehov totalt sett"; - -/* Title for override history view */ -"Override History" = "Overstyr historikk"; - -/* The title text for the override presets screen */ -"Override Presets" = "Egendefinerte overstyringer"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Egendefinerte overstyringer kan settes opp under Konfigurasjons-delen av innstillingsskjermen"; - -/* The section title of glucose overrides */ -"Overrides" = "Overstyringer"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Pre-måltid"; - -/* Title text for multi-value pre-meal value warning */ -"Pre-Meal Values" = "Pre-måltids verdier"; - -/* title for prescription section */ -"Prescription" = "Resept"; - -/* The section header text override presets */ -"PRESETS" = "FORHÅNDSINSTILLINGER"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Progressing." = "Fremdrift."; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Pumpehendelse"; - -/* Title text for suspend resume button when the basal delivery state is not set */ -"Pump Inoperable" = "Pumpe er ute av drift"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Hurtigvirkende - Voksen"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Hurtigvirkende - Barn"; - -/* The default placeholder string for a credential */ -"Required" = "Påkrevd"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Reservoar"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Gjenoppta leveranse"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Gjenopptar"; - -/* title for summary description section */ -"Review and Save Settings" = "Se gjennom og lagre innstillinger"; - -/* Description of how to interact with summary screen */ -"Review your therapy settings below. If you’d like to edit any of these settings, tap Back to go back to that screen." = "Se gjennom innstillingene dine nedenfor. Om du vil endre noen av disse, trykk \"Tilbake\" for å gå til det skjermbildet."; - -/* The text for the override preset name field placeholder */ -"Running" = "Løper"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Lagre"; - -/* Alert title for confirming basal rates outside the recommended range */ -"Save Basal Rates?" = "Lagre Basalrate?"; - -/* Alert title for confirming carb ratios outside the recommended range */ -"Save Carb Ratios?" = "Lagre Karbo forhold?"; - -/* Alert title for confirming correction ranges outside the recommended range */ -"Save Correction Range(s)?" = "Lagre korrigeringsområde(er)?"; - -/* Alert title for confirming delivery limits outside the recommended range */ -"Save Delivery Limits?" = "Lagre leveringsgrenser?"; - -/* Alert title for confirming a glucose safety limit outside the recommended range */ -"Save Glucose Safety Limit?" = "Lagre sikkerhetsbegrensning for blodsukker?"; - -/* Alert title for confirming insulin sensitivities outside the recommended range */ -"Save Insulin Sensitivities?" = "Lagre Insulinsensitivitet?"; - -/* Alert title for confirming pre-meal range overrides outside the recommended range */ -"Save Pre-Meal Range?" = "Lagre forhåndsmåltid?"; - -/* Alert title for confirming workout range overrides outside the recommended range */ -"Save Workout Range?" = "Lagre treningsområde?"; - -/* The button text during saving on a configuration page */ -"Saving..." = "Lagrer..."; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "PLANLAGT OVERSTYRING"; - -/* The section header text for a scheduled custom preset */ -"SCHEDULED PRESET" = "PLANLAGT OVERRIDE"; - -/* No comment provided by engineer. */ -"Selected" = "Valgt"; - -/* Section title for slow absorbing food */ -"Slow" = "Langsom"; - -/* Information about typical maximum basal rates */ -"Some users choose a value 2, 3, or 4 times their highest scheduled basal rate." = "Noen brukere velger en verdi 2, 3 eller 4 ganger den høyeste planlagte basaldosen."; - -/* The text for the override start time */ -"Start Time" = "Starttidspunkt"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starter temp-basal"; - -/* Format for prescription descriptive text (1: providerName, 2: datePrescribed) */ -"Submitted by %1$@, %2$@" = "Innsendt av %1$@, %2$@"; - -/* Title for support section */ -"Support" = "Support"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Pause leveranse"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Pauser"; - -/* No comment provided by engineer. */ -"Switch Preview State" = "Bytt forhåndsvisningsstatus"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Symbol"; - -/* Text directing the user to configure their first custom preset */ -"Tap '+' to create a new custom preset." = "Trykk på '+' for å opprette en ny 'Override'."; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Trykk for å angi"; - -/* The text for the override target range setting */ -"Target Range" = "Målområde"; - -/* Description of pre-meal mode */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Reduser blodsukkermålet ditt midlertidig før et måltid for å påvirke blodsukkertoppene etter måltidet."; - -/* Description of workout mode */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Øk blodsukkermålet ditt midlertidig før, under eller etter fysisk aktivitet for å redusere risikoen for hendelser med lavt blodsukker."; - -/* The title for the override selection screen */ -"Temporary Override" = "Midlertidig overstyring"; - -/* No comment provided by engineer. */ -"Test" = "Test"; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"than your Correction Range." = "enn ditt korreksjonsområde."; - -/* Description for selection when no insulin type is selected. */ -"The currently selected fast acting insulin model will be used as a default." = "Den for øyeblikket valgte hurtigvirkende insulinmodellen vil bli brukt som standard."; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Den eldre modellen som brukes av Loop, tillater tilpasning av handlingsvarighet."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "Maks absorbsjonstid er %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "Maks tillatt mengde er %@ gram"; - -/* Information about adult insulin model */ -"The rapid-acting adult model assumes peak activity at 75 minutes." = "Den hurtigvirkende modellen for voksne antar maksimal insulinaktivitet etter 75 minutter."; - -/* Information about child insulin model */ -"The rapid-acting child model assumes peak activity at 65 minutes." = "Den hurtigvirkende modellen for barn antar maksimal insulinaktivitet etter 65 minutter."; - -/* Information about basal rate scheduling */ -"The schedule starts at midnight and cannot contain a rate of 0 U/hr." = "Tidsplanen starter ved midnatt, og kan ikke inneholde en basalrate på 0 E/time."; - -/* Therapy Settings screen title */ -"Therapy Settings" = "Behandlingsinnstillinger"; - -/* No comment provided by engineer. */ -"Therapy Settings Support Placeholder" = "Therapy Settings Support Placeholder"; - -/* Subtitle of afrezza preset */ -"This model assumes peak insulin activity at 19 minutes." = "Denne modellen antar topp insulinaktivitet etter 19 minutter."; - -/* Subtitle of Fiasp preset - Subtitle of Lyumjev preset */ -"This model assumes peak insulin activity at 55 minutes." = "Denne modellen antar maksimal insulinaktivitet etter 55 minutter."; - -/* Subtitle of Rapid-Acting – Children preset */ -"This model assumes peak insulin activity at 65 minutes." = "Denne modellen antar maksimal insulinaktivitet etter 65 minutter."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"This model assumes peak insulin activity at 75 minutes." = "Denne modellen antar maksimal insulinaktivitet etter 75 minutter."; - -/* Information about maximum automated insulin on board (1: app name) */ -"This setting will also determine a safety limit for automatic dosing. %1$@ will limit automatic delivery to keep the amount of active insulin below twice your maximum bolus." = "Denne innstillingen vil også bestemme en sikkerhetsgrense for automatisk dosering. %1$@ vil begrense automatisk tilførsel for å holde mengden aktivt insulin under det dobbelte av maksimal bolus."; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"This will typically be" = "Dette vil typisk være"; - -/* Label for offset from midnight picker */ -"Time" = "Tid"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Tider i %1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"To be implemented" = "Skal implementeres"; - -/* No comment provided by engineer. */ -"Top component" = "Topp komponent"; - -/* The text indicating Total for Daily Schedule Basal */ -"Total" = "Total"; - -/* The text indicating U/day for Daily Schedule Basal */ -"U/day" = "E/dag"; - -/* The unit string for units per hour */ -"U/hour" = "E/timen"; - -/* Alert title when error occurs while saving a schedule */ -"Unable to Save" = "Kunne ikke lagre"; - -/* The unit string for units */ -"Units" = "Enheter"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Ukjent"; - -/* No comment provided by engineer. */ -"Unselected" = "Ikke valgt"; - -/* Title for selection when no insulin type is selected. */ -"Unset" = "Fjern"; - -/* Placeholder text until value is entered */ -"Value" = "Verdi"; - -/* Label indicating validation is occurring */ -"Verifying" = "Bekrefter"; - -/* The title for the override editing screen */ -"View Override" = "Vis overstyring"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Advarsel"; - -/* Disclaimer */ -"Work with your healthcare provider to choose a value that is higher than your highest scheduled basal rate, but as conservative or aggressive as you feel comfortable." = "Samarbeid med helsepersonell for å velge en verdi som er høyere enn din høyeste planlagte basalrate, men så konservativ eller aggressiv som du føler deg komfortabel."; - -/* Title for the workout override range */ -"Workout" = "Trening"; - -/* Information about workout range format (1: app name) */ -"Workout Range is the glucose value or range of values you want %1$@ to target during activity. This range will be in effect when you activate the Workout Preset button." = "Treningsområde er blodsukkerverdien eller verdiområdet du vil at %1$@ skal målrettes mot under aktivitet. Dette området trer i kraft når du aktiverer knappen Forhåndsinnstilling for treningsøkt."; - -/* Title text for multi-value workout value warning */ -"Workout Values" = "Verdier for treningsøkt"; - -/* Description of how to add a ratio */ -"You can add different carb ratios for different times of day by using the ➕." = "Du kan legge til forskjellige karbohydratforhold for forskjellige tider på dagen ved å bruke ➕."; - -/* Description of how to add a ratio */ -"You can add different insulin sensitivities for different times of day by using the ➕." = "Du kan legge til forskjellige insulinfølsomheter for forskjellige tider på dagen ved å bruke ➕."; - -/* Description of how to add a configuration range */ -"You can add different ranges for different times of day by using the ➕." = "Du kan legge til forskjellige områder for forskjellige tider på dagen ved å bruke ➕."; - -/* Description of how to add a range */ -"You can add entries for different times of day by using the ➕." = "Du kan legge til oppføringer for forskjellige tider på dagen ved å bruke ➕."; - -/* Information about insulin model (1: app name) */ -"You can choose how %1$@ measures rapid acting insulin's peak activity according to one of these two insulin models." = "Du kan velge hvordan %1$@ måler hurtigvirkende insulins toppaktivitet i henhold til en av disse to insulinmodellene."; - -/* Description of how to edit setting */ -"You can edit a setting by tapping into any line item." = "Du kan redigere en innstilling ved å trykke på et hvilket som helst linjeelement."; - -/* Description of how to edit setting */ -"You can edit the setting by tapping into the line item." = "Du kan redigere innstillingen ved å trykke på linjeelementet."; - -/* Information about basal rates */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Din basaldose av insulin er antall enheter per time du vil bruke for å dekke ditt bakgrunnsinsulinbehov."; - -/* Lower bound pre-meal information text */ -"your Glucose Safety Limit" = "din sikkerhetsgrense for blodsukker"; - -/* Disclaimer */ -"Your healthcare provider can help you choose a Correction Range that's right for you." = "Helsepersonellet kan hjelpe deg med å velge et korrigeringsområde som er riktig for deg."; - -/* Description of insulin sensitivity factor */ -"Your Insulin Sensitivity Factor (ISF) is the drop in glucose expected from one unit of insulin." = "Din insulinsensitivitetsfaktor (ISF) er fallet i blodsukker som forventes fra én enhet insulin."; - -/* Information about pre-meal range format (1: app name) */ -"Your Pre-Meal Range should be the glucose value (or range of values) you want %1$@ to target by the time you take your first bite of your meal. This range will be in effect when you activate the Pre-Meal Preset button." = "Pre-Meal Range bør være blodsukkerverdien (eller verdiområdet) du vil at %1$@ skal målrettes mot når du tar din første bit av måltidet. Dette området vil være i kraft når du aktiverer forhåndsinnstillingsknappen før måltid."; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/nl.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/nl.lproj/InsulinKit.strings deleted file mode 100644 index 21f451bf3..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/nl.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Titel"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "E IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "Geen pomp geconfigureerd"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "E Totaal"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Logboek"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Niet-pompinsuline"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulinetoediening"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/nl.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/nl.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 044006280..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/nl.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Titel"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "E IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "Geen pomp geconfigureerd"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "E Totaal"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Logboek"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulinetoediening"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/nl.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/nl.lproj/Localizable.strings deleted file mode 100644 index 75af39d9b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/nl.lproj/Localizable.strings +++ /dev/null @@ -1,745 +0,0 @@ -/* Information about workout range relative to correction range */ -" higher " = " hoger "; - -/* Information about pre-meal range relative to correction range */ -" lower " = " lager "; - -/* Separator between min and max glucose values */ -"-" = "-"; - -/* No comment provided by engineer. */ -"-" = "-"; - -/* The detail text representing no value */ -"–" = "–"; - -/* No comment provided by engineer. */ -"···" = "···"; - -/* No comment provided by engineer. */ -"%@" = "%@"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% van normale insuline"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Information about insulin action duration (1: app name) */ -"%1$@ assumes that the insulin it has delivered is actively working to lower your glucose for 6 hours. This setting cannot be changed." = "%1$@ gaat ervan uit dat de toegediende insuline actief bezig is om uw glucose gedurende 6 uur te verlagen. Deze instelling kan niet worden gewijzigd."; - -/* Lower bound workout information text format (1: app name) */ -"%1$@ or your Glucose Safety Limit, whichever is higher" = "%1$@ of je Glucoseveiligheidslimiet, afhankelijk van welke hoger is"; - -/* Information about max number of basal rates (1: app name) (2: maximum schedule entry count) */ -"%1$@ supports 1 to %2$@ rates per day." = "%1$@ ondersteunt 1 tot %2$@ snelheden per dag."; - -/* Reservoir entry (1: volume value) */ -"%1$@ U" = "%1$@ E"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ eenheden over om %2$@"; - -/* Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) - Description of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) */ -"%1$@: %2$@ %3$@" = "%1$@: %2$@ %3$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for progress accessibility label (1: duration in seconds) */ -"%1$d percent complete." = "%1$d procent voltooid."; - -/* No comment provided by engineer. */ -"%lld" = "%lld"; - -/* No comment provided by engineer. */ -"%lld, " = "%lld, "; - -/* No comment provided by engineer. */ -"🍽" = "🍽"; - -/* Premeal override preset title */ -"🍽 Pre-Meal" = "🍽 Pre-Meal"; - -/* No comment provided by engineer. */ -"🏃‍♂️" = "🏃‍♂️"; - -/* Workout override preset title */ -"🏃‍♂️ Workout" = "🏃‍♂️ Training"; - -/* No comment provided by engineer. */ -"A card whose text will wrap onto multiple lines if I continue to type for long enough—this length should do" = "Een kaart waarvan de tekst op meerdere regels wordt teruggedrongen als ik lang genoeg blijf typen- Dit zou voldoende moeten zijn"; - -/* Information about differences between target range and correction range */ -"A Correction Range is different. This will be a narrower range." = "Een Correctiebereik is anders. Dit zal een kleiner bereik zijn."; - -/* No comment provided by engineer. */ -"A simple card" = "Een eenvoudige kaart"; - -/* Warning text for basal rate of 0 U/hr */ -"A value of 0 U/hr means you will be scheduled to receive no basal insulin." = "Een waarde van 0 E/uur betekent dat u geen basale insuline ontvangt."; - -/* No comment provided by engineer. */ -"Above the save button" = "Boven de knop Opslaan"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Opnametijd"; - -/* No comment provided by engineer. */ -"Action Button" = "Actieknop"; - -/* The text for the override history duration */ -"Active Duration" = "Actieduur"; - -/* The title for the override emoji activity section */ -"Activity" = "Activiteit"; - -/* Button text to confirm adding a new schedule item */ -"Add" = "Toevoegen"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Voeg account toe"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Kh. Inv. Toevoegen"; - -/* Title of insulin model preset - afrezza */ -"Afrezza" = "Afrezza"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Weet je zeker dat je de gehele pompgeschiedenis wilt verwijderen?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Weet je zeker dat je alle waarden van het reservoir wilt verwijderen?"; - -/* Authentication hint string for therapy settings */ -"Authenticate to save therapy setting" = "Authenticeer om therapieinstellingen op te slaan"; - -/* Back navigation button title */ -"Back" = "Terug"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Basaalsnelheden"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Basaal-, bolus- en insulinecorrectiehoeveelheden zijn gereduceerd met %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Basaal-, bolus- en insulinecorrectiehoeveelheden zijn verhoogd met %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Basaal-, bolus- en insulinecorrectiehoeveelheden zijn onveranderd."; - -/* No comment provided by engineer. */ -"Bottom component" = "Onderste component"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuleer"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Annuleer Override"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Tijdelijk Basaal Annuleren"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Koolhydraatratio's"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Wijzigingen worden alleen nu toegepast wanneer je de override inschakelt. De standaard instellingen van %@ worden niet beïnvloed."; - -/* Footer text for customizing from a preset (1: preset name) */ -"Changes will only apply this time you enable the preset. The default settings of %@ will not be affected." = "Wijzigingen gelden alleen als je het tijdelijk programma activeert. De standaard instellingen van %@ worden niet veranderd."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Kies een langere opnametijd voor grotere maaltijden of voor maaltijden die vetten en eiwitten bevatten. Dit is alleen een leidraad voor het algoritme en hoeft niet exact te zijn."; - -/* Button text to close a modal - Text to close informational page */ -"Close" = "Sluiten"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "om %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "sinds %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "om %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "sinds %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "Ok"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Completed." = "Voltooid."; - -/* The title for the override emoji condition section */ -"Condition" = "Gesteldheid"; - -/* The button text for confirming the setting */ -"Confirm Setting" = "Bevestig instelling"; - -/* No comment provided by engineer. */ -"content" = "inhoud"; - -/* Title of the setup button to continue */ -"Continue" = "Ga Verder"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "Correctiebereik is het bloedglucosebereik waar je Loop naartoe wilt laten corrigeren."; - -/* Title text for multi-value correction value warning */ -"Correction Values" = "Correctiewaarden"; - -/* The text for a custom override */ -"Custom" = "Aangepast"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Aangepaste Override"; - -/* The title for the custom preset entry screen - The title for the custom preset selection screen */ -"Custom Preset" = "Aangepast Programma"; - -/* Title of the carb entry date picker cell */ -"Date" = "Datum"; - -/* Delete values for Pre-Meal, inactivates Pre-Meal icon - Test for table cell delete button - The title of the button to remove the credentials for a service */ -"Delete" = "Verwijderen"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Verwijder Account"; - -/* Button title to delete all objects */ -"Delete All" = "Verwijder Alles"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Toedieningslimieten"; - -/* Information about delivery limits */ -"Delivery Limits are safety guardrails for your insulin delivery." = "Toedieningslimieten zijn de beveiliging voor je insulinetoevoer."; - -/* The text for the custom preset disable button */ -"Disable Preset" = "Programma Uitschakelen"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Gereed"; - -/* The text for the override duration setting */ -"Duration" = "Duur"; - -/* No comment provided by engineer. */ -"Dynamic component #%lld" = "Dynamische component #%lld"; - -/* Text for edit button - The title for the enabled custom preset editing screen */ -"Edit" = "Bewerken"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Kh. Inv. Bewerken"; - -/* The title for the override editing screen */ -"Edit Override" = "Override Aanpassen"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "Veranderingen hebben alleen effect op de actieve override. De standaard instellingen van %@ worden niet beïnvloed."; - -/* Footer text for editing an enabled custom preset (1: preset name) */ -"Edits persist only until the preset is disabled. The default settings of %@ will not be affected." = "Aanpassingen blijven van kracht totdat het programma wordt uitgeschakeld. De standaardinstellingen van %@ worden niet beïnvloed."; - -/* The button text for enabling a temporary override */ -"Enable" = "Inschakelen"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Voor onbepaalde tijd inschakelen"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Ingeschakeld"; - -/* The text for the override start time */ -"End Time" = "Eindtijd"; - -/* Format string for accessibility label for value entry. (1: value label) */ -"Enter %1$@ value" = "Voer %1$@ waarde in"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Voer aantal eenheden in"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Voer aantal eenheden per uur in"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Logboek"; - -/* No comment provided by engineer. */ -"Example" = "Voorbeeld"; - -/* Section title for fast absorbing food */ -"Fast" = "Snel"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Insulin model setting description (1: app name) (2: number of models) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from %2$@ different models for how the app measures the insulin’s peak activity." = "Voor snelwerkende insuline gaat %1$@ ervan uit dat het gedurende 6 uur actief werkt. Je kunt kiezen uit %2$@ verschillende modellen voor hoe de app de piekactiviteit van de insuline meet."; - -/* Information about correction range format (1: app name) */ -"For this range, choose the specific glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin." = "Kies voor dit bereik de specifieke glucosewaarde (of bereik van waarden) waar je wilt dat %1$@ naar streeft bij het aanpassen van je basale insuline."; - -/* Support button for Therapy Settings */ -"Get help with Therapy Settings" = "Krijg hulp bij Therapieinstellingen"; - -/* Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range - Text for go back action on confirmation alert */ -"Go Back" = "Ga Terug"; - -/* Title text for the high basal rate warning */ -"High Basal Rate" = "Hoge Basaalsnelheid"; - -/* Title text for the high carb ratio warning */ -"High Carb Ratio" = "Hoge Koolhydraatratio"; - -/* Title text for the high correction value warning */ -"High Correction Value" = "Hoge Correctiewaarde"; - -/* Title text for the high glucose safety limit warning */ -"High Glucose Safety Limit" = "Hoge Glucoseveiligheidslimiet"; - -/* Title text for the high insulin sensitivity warning */ -"High Insulin Sensitivity" = "Hoge Insulinegevoeligheid"; - -/* Title text for high maximum basal rate warning */ -"High Maximum Basal Rate" = "Hoge Maximale Basaalsnelheid"; - -/* Title text for high maximum bolus warning */ -"High Maximum Bolus" = "Hoge Maximale Bolus"; - -/* Title text for the low pre-meal value warning */ -"High Pre-Meal Value" = "Hoge Pre-Meal Waarde"; - -/* Title text for the high workout value warning */ -"High Workout Value" = "Hoge Trainingswaarde"; - -/* The text for the override history */ -"History" = "Geschiedenis"; - -/* Description of how to interact with summary screen */ -"If these settings look good to you, tap Save Settings to continue." = "Als deze instellingen er goed uitzien, tik op Instellingen Opslaan om verder te gaan."; - -/* Information about target range */ -"If you've used a CGM before, you're likely familiar with target range as a wide range of values you'd like for your glucose notification alerts, such as 70-180 mg/dL or 90-200 mg/dL." = "Als je al eerder een CGM hebt gebruikt, ben je waarschijnlijk bekend met een streefbereik met een grote spreidingsbreedte die je wilt voor je glucosemeldingswaarschuwingen, zoals 3,9-10,0 mmol/L of 5,0-11,1 mmol/L."; - -/* No comment provided by engineer. */ -"info" = "Informatie"; - -/* Title text for insulin model */ -"Insulin Model" = "Insulinemodel"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Insulinegevoeligheden"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "Insulinegevoeligheid beschrijft hoe de bloedglucose reageert op 1 eenheid insuline. Lagere waarden betekent dat meer insuline gegeven wordt wanneer je boven streefbereik bent. Een te laag ingestelde insulinegevoeligheid kan leiden tot gevaarlijk lage bloedglucosewaarden."; - -/* Description of an interrupted bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: programmed value (? if no value), 4: unit) */ -"Interrupted %1$@: %2$@ of %3$@ %4$@" = "Onderbroken %1$@: %2$@ van %3$@ %4$@"; - -/* Guardrail info text format */ -"It can be set as low as %1$@. It can be set as high as %2$@." = "Het kan zo laag worden ingesteld als %1$@. Het kan zo hoog worden ingesteld als %2$@."; - -/* Title text for the low basal rate warning */ -"Low Basal Rate" = "Lage Basaalsnelheid"; - -/* Title text for the low carb ratio warning */ -"Low Carb Ratio" = "Lage Koolhydraatratio"; - -/* Title text for the low correction value warning */ -"Low Correction Value" = "Lage Correctiewaarde"; - -/* Title text for the low glucose safety limit warning */ -"Low Glucose Safety Limit" = "Lage Glucoseveiligheidslimiet"; - -/* Title text for the low insulin sensitivity warning */ -"Low Insulin Sensitivity" = "Lage Insulinegevoeligheid"; - -/* Title text for low maximum basal rate warning */ -"Low Maximum Basal Rate" = "Lage Maximale Basaalsnelheid"; - -/* Title text for low maximum bolus warning */ -"Low Maximum Bolus" = "Lage Maximale Bolus"; - -/* Title text for the low pre-meal value warning */ -"Low Pre-Meal Value" = "Lage Pre-Meal Waarde"; - -/* Title text for the low workout value warning */ -"Low Workout Value" = "Lage Trainingswaarde"; - -/* Title of insulin model preset - lyumjev */ -"Lyumjev" = "Lyumjev"; - -/* Placeholder for maximum value in glucose range */ -"max" = "max"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Maximale Basaalsnelheid"; - -/* Information about maximum basal rate (1: app name) */ -"Maximum Basal Rate is the maximum automatically adjusted basal rate that %1$@ is allowed to enact to help reach your correction range." = "Maximale Basaalsnelheid is de maximale automatisch aangepaste basaalsnelheid die %1$@ mag toedienen om te helpen binnen je correctiebereik te komen."; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Maximale Bolus"; - -/* Information about maximum bolus (1: app name) */ -"Maximum Bolus is the highest bolus amount that you will allow %1$@ to recommend at one time to cover carbs or bring down high glucose." = "Maximale bolus is de hoogste bolus die %1$@ je kan geven om koolhydraten te dekken of hoge bloed glucose te verlagen."; - -/* Section title for medium absorbing food */ -"Medium" = "Middel"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* No comment provided by engineer. */ -"more content" = "meer inhoud"; - -/* Alert action title to open error help */ -"More Info" = "Meer Informatie"; - -/* The text for the override preset name setting */ -"Name" = "Naam"; - -/* Title for mini-modal to add a new schedule entry */ -"New Entry" = "Nieuwe Invoer"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Nieuw Programma"; - -/* Title text for the zero basal rate warning */ -"No Basal Insulin" = "Geen Basale Insuline"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Anders"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Totale Insulinebehoefte"; - -/* Title for override history view */ -"Override History" = "Overridegeschiedenis"; - -/* The title text for the override presets screen */ -"Override Presets" = "Override Programma's"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Override programma's kunnen ingesteld worden via het onderdeel 'Instellingen' in het instellingenscherm."; - -/* The section title of glucose overrides */ -"Overrides" = "Override's"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Pre-Meal"; - -/* Title text for multi-value pre-meal value warning */ -"Pre-Meal Values" = "Pre-Meal Waarden"; - -/* title for prescription section */ -"Prescription" = "Recepten"; - -/* The section header text override presets */ -"PRESETS" = "PROGRAMMA'S"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Progressing." = "Voortgang."; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Pompgebeurtenis"; - -/* Title text for suspend resume button when the basal delivery state is not set */ -"Pump Inoperable" = "Pomp Werkt Niet"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Snelwerkend - Volwassenen"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Snelwerkend - Kinderen"; - -/* The default placeholder string for a credential */ -"Required" = "Vereist"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Reservoir"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Hervat Toediening"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Hervat"; - -/* title for summary description section */ -"Review and Save Settings" = "Bekijk en Instellingen Opslaan"; - -/* Description of how to interact with summary screen */ -"Review your therapy settings below. If you’d like to edit any of these settings, tap Back to go back to that screen." = "Bekijk hieronder je therapieinstellingen. Als je een van deze instellingen wilt aanpassen, tik je op Terug om terug te gaan naar dat scherm."; - -/* The text for the override preset name field placeholder */ -"Running" = "Hardlopen"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Opslaan"; - -/* Alert title for confirming basal rates outside the recommended range */ -"Save Basal Rates?" = "Basaalsnelheden Opslaan?"; - -/* Alert title for confirming carb ratios outside the recommended range */ -"Save Carb Ratios?" = "Koolhydraatratio Opslaan?"; - -/* Alert title for confirming correction ranges outside the recommended range */ -"Save Correction Range(s)?" = "Correctiebereik(en) Opslaan?"; - -/* Alert title for confirming delivery limits outside the recommended range */ -"Save Delivery Limits?" = "Toedieningslimieten opslaan?"; - -/* Alert title for confirming a glucose safety limit outside the recommended range */ -"Save Glucose Safety Limit?" = "Glucoseveiligheidlimiet Opslaan?"; - -/* Alert title for confirming insulin sensitivities outside the recommended range */ -"Save Insulin Sensitivities?" = "Insulinegevoeligheden opslaan?"; - -/* Alert title for confirming pre-meal range overrides outside the recommended range */ -"Save Pre-Meal Range?" = "Pre-Meal Bereik Opslaan?"; - -/* Alert title for confirming workout range overrides outside the recommended range */ -"Save Workout Range?" = "Trainingsbereik Opslaan?"; - -/* The button text during saving on a configuration page */ -"Saving..." = "Opslaan..."; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "GEPLANDE OVERRIDE"; - -/* The section header text for a scheduled custom preset */ -"SCHEDULED PRESET" = "GEPLAND PROGRAMMA"; - -/* No comment provided by engineer. */ -"Selected" = "Geselecteerd"; - -/* Section title for slow absorbing food */ -"Slow" = "Langzaam"; - -/* Information about typical maximum basal rates */ -"Some users choose a value 2, 3, or 4 times their highest scheduled basal rate." = "Sommige gebruikers kiezen een waarde 2, 3 of 4 keer hoger dan hun hoogste ingestelde basaalsnelheid."; - -/* The text for the override start time */ -"Start Time" = "Starttijd"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Tijdelijk Basaal Starten"; - -/* Format for prescription descriptive text (1: providerName, 2: datePrescribed) */ -"Submitted by %1$@, %2$@" = "Ingediend door %1$@, %2$@"; - -/* Title for support section */ -"Support" = "Ondersteuning"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Onderbreek Toediening"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Onderbreken"; - -/* No comment provided by engineer. */ -"Switch Preview State" = "Omschakelen naar Voorbeeldstand"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Symbool"; - -/* Text directing the user to configure their first custom preset */ -"Tap '+' to create a new custom preset." = "Tik op '+' om een nieuw override programma aan te maken."; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Instellen…"; - -/* The text for the override target range setting */ -"Target Range" = "Streefbereik"; - -/* Description of pre-meal mode */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Tijdelijk verlagen van je glucosedoel vóór de maaltijd om de kans op post-maaltijd glucosepieken te verkleinen."; - -/* Description of workout mode */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Verhoog tijdelijk je glucosedoel voor, gedurende of na fysieke activiteit om het risico van lage glucosewaarden te verminderen."; - -/* The title for the override selection screen */ -"Temporary Override" = "Tijdelijke Override"; - -/* No comment provided by engineer. */ -"Test" = "Test"; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"than your Correction Range." = "zijn dan je Correctiebereik."; - -/* Description for selection when no insulin type is selected. */ -"The currently selected fast acting insulin model will be used as a default." = "Het momenteel geselecteerde snelwerkende insulinemodel wordt als standaard gebruikt."; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Het model gebruikt bij Loop, staat verandering van actieduur toe."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "De maximale opnametijd is %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "De maximale toegestane waarde is %@ gram"; - -/* Information about adult insulin model */ -"The rapid-acting adult model assumes peak activity at 75 minutes." = "Het snelwerkende model voor volwassenen gaat uit van een piekactiviteit op 75 minuten."; - -/* Information about child insulin model */ -"The rapid-acting child model assumes peak activity at 65 minutes." = "Het snelwerkende model voor kinderen gaat uit van een piekactiviteit op 65 minuten."; - -/* Information about basal rate scheduling */ -"The schedule starts at midnight and cannot contain a rate of 0 U/hr." = "Het schema begint om middernacht en mag geen snelheid van 0 E/uur hebben."; - -/* Therapy Settings screen title */ -"Therapy Settings" = "Therapieinstellingen"; - -/* No comment provided by engineer. */ -"Therapy Settings Support Placeholder" = "Tijdelijke aanduiding voor Ondersteuning van Therapie-instellingen"; - -/* Subtitle of afrezza preset */ -"This model assumes peak insulin activity at 19 minutes." = "Dit model gaat uit van een piek in de insulineactiviteit op 19 minuten."; - -/* Subtitle of Fiasp preset - Subtitle of Lyumjev preset */ -"This model assumes peak insulin activity at 55 minutes." = "Dit model gaat uit van een piek in de insulineactiviteit op 55 minuten."; - -/* Subtitle of Rapid-Acting – Children preset */ -"This model assumes peak insulin activity at 65 minutes." = "Dit model gaat uit van een piek in de insulineactiviteit op 65 minuten."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"This model assumes peak insulin activity at 75 minutes." = "Dit model gaat uit van een piek in de insulineactiviteit op 75 minuten."; - -/* Information about maximum automated insulin on board (1: app name) */ -"This setting will also determine a safety limit for automatic dosing. %1$@ will limit automatic delivery to keep the amount of active insulin below twice your maximum bolus." = "Deze instelling bepaalt ook een veiligheidslimiet voor automatische dosering. %1$@ beperkt de automatische toediening om de hoeveelheid actieve insuline onder tweemaal uw maximale bolus te houden."; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"This will typically be" = "Over het algemeen is dit"; - -/* Label for offset from midnight picker */ -"Time" = "Tijd"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Tijd in %1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"To be implemented" = "Te implementeren"; - -/* No comment provided by engineer. */ -"Top component" = "Bovenste component"; - -/* The text indicating Total for Daily Schedule Basal */ -"Total" = "Totaal"; - -/* The text indicating U/day for Daily Schedule Basal */ -"U/day" = "E/dag"; - -/* The unit string for units per hour */ -"U/hour" = "E/uur"; - -/* Alert title when error occurs while saving a schedule */ -"Unable to Save" = "Kan Niet Opslaan"; - -/* The unit string for units */ -"Units" = "Eenheden"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Onbekend"; - -/* No comment provided by engineer. */ -"Unselected" = "Niet Geselecteerd"; - -/* Title for selection when no insulin type is selected. */ -"Unset" = "Niet Ingesteld"; - -/* Placeholder text until value is entered */ -"Value" = "Waarde"; - -/* Label indicating validation is occurring */ -"Verifying" = "Verifiëren"; - -/* The title for the override editing screen */ -"View Override" = "Bekijk Override"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Waarschuwing"; - -/* Disclaimer */ -"Work with your healthcare provider to choose a value that is higher than your highest scheduled basal rate, but as conservative or aggressive as you feel comfortable." = "Werk samen met je zorgverlener om een waarde te kiezen die hoger is dan je hoogst ingestelde basaalsnelheid, maar zo conservatief of agressief waarbij je jezelf prettig voelt."; - -/* Title for the workout override range */ -"Workout" = "Training"; - -/* Information about workout range format (1: app name) */ -"Workout Range is the glucose value or range of values you want %1$@ to target during activity. This range will be in effect when you activate the Workout Preset button." = "Trainingsbereik is de glucosewaarde of bereik van waarden waar je wilt dat %1$@ naar streeft tijdens activiteit. Dit bereik geldt wanneer je met de knop het Trainingsprogramma activeert."; - -/* Title text for multi-value workout value warning */ -"Workout Values" = "Trainingswaarden"; - -/* Description of how to add a ratio */ -"You can add different carb ratios for different times of day by using the ➕." = "Je kunt verschillende koolhydraatratio's voor verschillende tijdstippen op de dag toevoegen met de ➕."; - -/* Description of how to add a ratio */ -"You can add different insulin sensitivities for different times of day by using the ➕." = "Je kunt verschillende insulinegevoeligheden voor verschillende tijdstippen op de dag toevoegen met de ➕."; - -/* Description of how to add a configuration range */ -"You can add different ranges for different times of day by using the ➕." = "Je kunt verschillende bereiken voor verschillende tijdstippen op de dag toevoegen met de ➕."; - -/* Description of how to add a range */ -"You can add entries for different times of day by using the ➕." = "Je kunt invoergegevens voor verschillende tijdstippen op de dag toevoegen met de ➕."; - -/* Information about insulin model (1: app name) */ -"You can choose how %1$@ measures rapid acting insulin's peak activity according to one of these two insulin models." = "Je kunt kiezen hoe %1$@ de piekactiviteit van snelwerkende insuline meet volgens een van deze twee insulinemodellen."; - -/* Description of how to edit setting */ -"You can edit a setting by tapping into any line item." = "Je kunt een instelling bewerken door op een regelitem te tikken."; - -/* Description of how to edit setting */ -"You can edit the setting by tapping into the line item." = "Je kunt de instelling bewerken door op het regelitem te tikken."; - -/* Information about basal rates */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Je basale insulinesnelheid is het aantal eenheden per uur dat je wilt toedienen om in je basale insulinebehoefte te voorzien."; - -/* Lower bound pre-meal information text */ -"your Glucose Safety Limit" = "je Glucoseveiligheidslimiet"; - -/* Disclaimer */ -"Your healthcare provider can help you choose a Correction Range that's right for you." = "Je zorgverlener kan je helpen bij het kiezen van een correctiebereik dat bij je past."; - -/* Description of insulin sensitivity factor */ -"Your Insulin Sensitivity Factor (ISF) is the drop in glucose expected from one unit of insulin." = "Je Insulinegevoeligheidsfactor (ISF) is de daling van de glucosewaarde uitgaande van één eenheid insuline."; - -/* Information about pre-meal range format (1: app name) */ -"Your Pre-Meal Range should be the glucose value (or range of values) you want %1$@ to target by the time you take your first bite of your meal. This range will be in effect when you activate the Pre-Meal Preset button." = "Je Pre-Meal Bereik zou de glucosewaarde moeten zijn (of een bereik van waarden) waar je wilt dat %1$@ naar dat streeft tegen de tijd dat je je eerste hap van je maaltijd neemt. Dit bereik wordt actief wanneer je het Pre-Meal Programma met de knop activeert."; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/pl.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/pl.lproj/InsulinKit.strings deleted file mode 100644 index 07c933035..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/pl.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "J łącznie"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Zbiorniczek"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Historia zdarzeń"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Insulina bez pompy"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/pl.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/pl.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 8f36c0f6b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/pl.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "J łącznie"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Zbiorniczek"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Historia zdarzeń"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/pl.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/pl.lproj/Localizable.strings deleted file mode 100644 index b82bc1871..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/pl.lproj/Localizable.strings +++ /dev/null @@ -1,745 +0,0 @@ -/* Information about workout range relative to correction range */ -" higher " = "wyżej"; - -/* Information about pre-meal range relative to correction range */ -" lower " = " niżej "; - -/* Separator between min and max glucose values */ -"-" = "-"; - -/* No comment provided by engineer. */ -"-" = "-"; - -/* The detail text representing no value */ -"–" = "–"; - -/* No comment provided by engineer. */ -"···" = "···"; - -/* No comment provided by engineer. */ -"%@" = "%@"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% normalnej insuliny"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@J"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Information about insulin action duration (1: app name) */ -"%1$@ assumes that the insulin it has delivered is actively working to lower your glucose for 6 hours. This setting cannot be changed." = "%1$@ przyjmuje, że podana insulina obniża poziom glukozy przez 6 godzin. Nie można zmienić tego ustawienia."; - -/* Lower bound workout information text format (1: app name) */ -"%1$@ or your Glucose Safety Limit, whichever is higher" = "%1$@ lub bezpieczny limit stężenia glukozy, w zależności od tego, która wartość jest wyższa."; - -/* Information about max number of basal rates (1: app name) (2: maximum schedule entry count) */ -"%1$@ supports 1 to %2$@ rates per day." = "%1$@ obsługuje od 1 do %2$@ dawek dziennie."; - -/* Reservoir entry (1: volume value) */ -"%1$@ U" = "%1$@ J"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ jednostek pozostaje w %2$@"; - -/* Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) - Description of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) */ -"%1$@: %2$@ %3$@" = "%1$@: %2$@ %3$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for progress accessibility label (1: duration in seconds) */ -"%1$d percent complete." = "Ukończono %1$d procent."; - -/* No comment provided by engineer. */ -"%lld" = "%lld"; - -/* No comment provided by engineer. */ -"%lld, " = "%lld, "; - -/* No comment provided by engineer. */ -"🍽" = "🍽"; - -/* Premeal override preset title */ -"🍽 Pre-Meal" = "🍽 Przed posiłkiem"; - -/* No comment provided by engineer. */ -"🏃‍♂️" = "🏃‍♂️"; - -/* Workout override preset title */ -"🏃‍♂️ Workout" = "🏃‍♂️ Trening"; - -/* No comment provided by engineer. */ -"A card whose text will wrap onto multiple lines if I continue to type for long enough—this length should do" = "Karta, której tekst zawija się w wiele wierszy, jeśli będę pisać wystarczająco długo — ta długość powinna wystarczyć"; - -/* Information about differences between target range and correction range */ -"A Correction Range is different. This will be a narrower range." = "Obecna skala została ograniczona bezpieczniejszą wartością."; - -/* No comment provided by engineer. */ -"A simple card" = "Prosta karta"; - -/* Warning text for basal rate of 0 U/hr */ -"A value of 0 U/hr means you will be scheduled to receive no basal insulin." = "Wartość 0 jedn./godz. oznacza, że nie zaplanowano podawania insuliny bazowej."; - -/* No comment provided by engineer. */ -"Above the save button" = "Nad przyciskiem zapisz"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Czas absorpcji"; - -/* No comment provided by engineer. */ -"Action Button" = "Przycisk akcji"; - -/* The text for the override history duration */ -"Active Duration" = "Aktywny czas trwania"; - -/* The title for the override emoji activity section */ -"Activity" = "Aktywność"; - -/* Button text to confirm adding a new schedule item */ -"Add" = "Dodaj"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Dodaj konto"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Wprowadź węglowodany"; - -/* Title of insulin model preset - afrezza */ -"Afrezza" = "Afrezza"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Czy jesteś pewien, że chcesz usunąć z Loop wszystkie dane historyczne pompy?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Czy jesteś pewien, że chcesz usunąć wszystkie wartości zbiornika?"; - -/* Authentication hint string for therapy settings */ -"Authenticate to save therapy setting" = "Uwierzytelnij, aby zapisać ustawienia terapii"; - -/* Back navigation button title */ -"Back" = "Powrót"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Dawka Podstawowa (Baza)"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Dawka podstawowa, bolus i korygująca dawka insuliny zostały zmniejszone o %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Dawka podstawowa, bolus i korygująca dawka insuliny zostały zwiększone o %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Dawka podstawowa, bolus i korygująca dawka insuliny bez zmian."; - -/* No comment provided by engineer. */ -"Bottom component" = "Dolny element"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Anuluj"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Anuluj pominięcie"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Anulowanie tymczasowej dawki podstawowej"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Współczynniki węglowodanowe"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Zmiany będą obowiązywać wyłącznie podczas tego pominięcia. Domyślne ustawienia %@ nie zostaną zmienione."; - -/* Footer text for customizing from a preset (1: preset name) */ -"Changes will only apply this time you enable the preset. The default settings of %@ will not be affected." = "Zmiany zostaną zastosowane tylko wtedy, gdy włączysz ustawienie wstępne. Domyślne ustawienia %@ nie zostaną naruszone."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Wybierz dłuższy czas absorpcji dla większych, bogatobiałkowych lub wysokotłuszczowych posiłków. To tylko wskazówka dla algorytmu i nie musi być bardzo dokładna."; - -/* Button text to close a modal - Text to close informational page */ -"Close" = "Zamknij"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "o %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "od %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "o %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "od %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Completed." = "Zakończony."; - -/* The title for the override emoji condition section */ -"Condition" = "Warunek"; - -/* The button text for confirming the setting */ -"Confirm Setting" = "Potwierdź ustawienia"; - -/* No comment provided by engineer. */ -"content" = "treść"; - -/* Title of the setup button to continue */ -"Continue" = "Kontynuuj"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "Zakres korekty to zakres stężenia glukozy we krwi, względem którego chcesz skorygować algorytm Loop."; - -/* Title text for multi-value correction value warning */ -"Correction Values" = "Wartości korekty"; - -/* The text for a custom override */ -"Custom" = "Cel na teraz"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Custom Override"; - -/* The title for the custom preset entry screen - The title for the custom preset selection screen */ -"Custom Preset" = "Cel Tymczasowy"; - -/* Title of the carb entry date picker cell */ -"Date" = "Data"; - -/* Delete values for Pre-Meal, inactivates Pre-Meal icon - Test for table cell delete button - The title of the button to remove the credentials for a service */ -"Delete" = "Usunąć"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Usuń konto"; - -/* Button title to delete all objects */ -"Delete All" = "Usuń wszystko"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Limity podawania"; - -/* Information about delivery limits */ -"Delivery Limits are safety guardrails for your insulin delivery." = "Limity podaży są barierami bezpieczeństwa dla podawania insuliny."; - -/* The text for the custom preset disable button */ -"Disable Preset" = "Wyłącz ustawienie wstępne"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Gotowe"; - -/* The text for the override duration setting */ -"Duration" = "Czas trwania"; - -/* No comment provided by engineer. */ -"Dynamic component #%lld" = "Składnik dynamiczny #%lld"; - -/* Text for edit button - The title for the enabled custom preset editing screen */ -"Edit" = "Edytuj"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Edytuj wprowadzone węglowodany"; - -/* The title for the override editing screen */ -"Edit Override" = "Edytuj pominięcie"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = " Edycja wpływa wyłącznie na aktywne pominięcie. Domyślne ustawienia %@ nie zostaną zmienione."; - -/* Footer text for editing an enabled custom preset (1: preset name) */ -"Edits persist only until the preset is disabled. The default settings of %@ will not be affected." = "Zmiany są zachowywane tylko do momentu wyłączenia ustawienia wstępnego. Domyślne ustawienia %@ nie zostaną naruszone."; - -/* The button text for enabling a temporary override */ -"Enable" = "Włącz"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Włącz na czas nieokreślony"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Włączony"; - -/* The text for the override start time */ -"End Time" = "Koniec czasu"; - -/* Format string for accessibility label for value entry. (1: value label) */ -"Enter %1$@ value" = "Wprowadź wartość %1$@"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Wprowadź liczbę jednostek"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Maksymalna dawka w jednostkach na godzinę"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Historia zdarzeń"; - -/* No comment provided by engineer. */ -"Example" = "Przykład"; - -/* Section title for fast absorbing food */ -"Fast" = "Szybko"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Insulin model setting description (1: app name) (2: number of models) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from %2$@ different models for how the app measures the insulin’s peak activity." = "W przypadku szybko działającej insuliny %1$@ zakłada, że działa aktywnie przez 6 godzin. Możesz wybierać spośród %2$@ różnych modeli pomiaru szczytowej aktywności insuliny przez aplikację."; - -/* Information about correction range format (1: app name) */ -"For this range, choose the specific glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin." = "Dla tego zakresu wybierz konkretną wartość glukozy (lub zakres wartości), do której chce dążyć %1$@ podczas dostosowywania insuliny bazowej."; - -/* Support button for Therapy Settings */ -"Get help with Therapy Settings" = "Uzyskaj pomoc dotyczącą ustawień terapii"; - -/* Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range - Text for go back action on confirmation alert */ -"Go Back" = "Wróć"; - -/* Title text for the high basal rate warning */ -"High Basal Rate" = "Wysoka dawka podstawowa"; - -/* Title text for the high carb ratio warning */ -"High Carb Ratio" = "Wysoki współczynnik węglowodanowy"; - -/* Title text for the high correction value warning */ -"High Correction Value" = "Wysoka wartość korekty"; - -/* Title text for the high glucose safety limit warning */ -"High Glucose Safety Limit" = "Limit bezpieczeństwa wysokiego stężenia glukozy"; - -/* Title text for the high insulin sensitivity warning */ -"High Insulin Sensitivity" = "Wysoki Współczynnik Wrażliwości"; - -/* Title text for high maximum basal rate warning */ -"High Maximum Basal Rate" = "Wysoka maksymalna dawka podstawowa"; - -/* Title text for high maximum bolus warning */ -"High Maximum Bolus" = "Wysoki maksymalny bolus"; - -/* Title text for the low pre-meal value warning */ -"High Pre-Meal Value" = "Wysoka wartość przed posiłkiem"; - -/* Title text for the high workout value warning */ -"High Workout Value" = "Wysoka wartość treningu"; - -/* The text for the override history */ -"History" = "Historia"; - -/* Description of how to interact with summary screen */ -"If these settings look good to you, tap Save Settings to continue." = "Jeśli te ustawienia Ci odpowiadają, stuknij Zapisz ustawienia, aby kontynuować."; - -/* Information about target range */ -"If you've used a CGM before, you're likely familiar with target range as a wide range of values you'd like for your glucose notification alerts, such as 70-180 mg/dL or 90-200 mg/dL." = "Jeśli korzystałeś już z CGM, prawdopodobnie znasz zakres docelowy jako szeroki zakres wartości, które chcesz wyświetlać w alertach powiadomień o poziomie glukozy, na przykład 70-180 mg/dl lub 90-200 mg/dl."; - -/* No comment provided by engineer. */ -"info" = "info"; - -/* Title text for insulin model */ -"Insulin Model" = "Model insuliny"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Wrażliwość na insulinę (ISF)"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "Insulinowrażliwość opisuje, w jaki sposób stężenie glukozy we krwi powinno reagować na 1 jednostkę insuliny. Mniejsze wartości oznaczają podanie większej ilości insuliny w przypadku wartości powyżej zakresu. Zbyt małe wartości mogą spowodować niebezpiecznie niskie stężenie glukozy we krwi."; - -/* Description of an interrupted bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: programmed value (? if no value), 4: unit) */ -"Interrupted %1$@: %2$@ of %3$@ %4$@" = "Przerwane %1$@ : %2$@ z %3$@ %4$@"; - -/* Guardrail info text format */ -"It can be set as low as %1$@. It can be set as high as %2$@." = "Można go ustawić w zakresie od %1$@ do %2$@."; - -/* Title text for the low basal rate warning */ -"Low Basal Rate" = "Niska dawka podstawowa"; - -/* Title text for the low carb ratio warning */ -"Low Carb Ratio" = "Niski współczynnik węglowodanów"; - -/* Title text for the low correction value warning */ -"Low Correction Value" = "Niska wartość korekty"; - -/* Title text for the low glucose safety limit warning */ -"Low Glucose Safety Limit" = "Limit bezpieczeństwa niskiego poziomu glukozy"; - -/* Title text for the low insulin sensitivity warning */ -"Low Insulin Sensitivity" = "Niski Współczynnik Wrażliwości"; - -/* Title text for low maximum basal rate warning */ -"Low Maximum Basal Rate" = "Niska maksymalna dawka podstawowa"; - -/* Title text for low maximum bolus warning */ -"Low Maximum Bolus" = "Niski maksymalny bolus"; - -/* Title text for the low pre-meal value warning */ -"Low Pre-Meal Value" = "Niska wartość przed posiłkiem"; - -/* Title text for the low workout value warning */ -"Low Workout Value" = "Niska wartość treningu"; - -/* Title of insulin model preset - lyumjev */ -"Lyumjev" = "Lyumjev"; - -/* Placeholder for maximum value in glucose range */ -"max" = "maks."; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Maksymalna dawka podstawowa"; - -/* Information about maximum basal rate (1: app name) */ -"Maximum Basal Rate is the maximum automatically adjusted basal rate that %1$@ is allowed to enact to help reach your correction range." = "Maksymalna dawka podstawowa to maksymalna automatycznie dostosowana baza, którą %1$@ może wprowadzić, aby pomóc osiągnąć zakres docelowy."; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Maksymalny bolus"; - -/* Information about maximum bolus (1: app name) */ -"Maximum Bolus is the highest bolus amount that you will allow %1$@ to recommend at one time to cover carbs or bring down high glucose." = "Maksymalny bolus to największa wartość bolusa, jaką %1$@ można podać w jednorazowo, aby zrekompensować węglowodany lub obniżyć wysoki poziom glukozy."; - -/* Section title for medium absorbing food */ -"Medium" = "Średnia"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min."; - -/* No comment provided by engineer. */ -"more content" = "więcej treści"; - -/* Alert action title to open error help */ -"More Info" = "Więcej informacji"; - -/* The text for the override preset name setting */ -"Name" = "Nazwa"; - -/* Title for mini-modal to add a new schedule entry */ -"New Entry" = "Nowy wpis"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Nowy Cel Tymczasowy"; - -/* Title text for the zero basal rate warning */ -"No Basal Insulin" = "Bez insuliny bazowej"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Inne"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Ogólne zapotrzebowanie na insulinę"; - -/* Title for override history view */ -"Override History" = "Historia Celu Tymczasowego"; - -/* The title text for the override presets screen */ -"Override Presets" = "Override Presets"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Wstępne ustawienia pominięcia można skonfigurować w części „Konfiguracja” na ekranie ustawień."; - -/* The section title of glucose overrides */ -"Overrides" = "Pominięcia"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Przed posiłkiem"; - -/* Title text for multi-value pre-meal value warning */ -"Pre-Meal Values" = "Wartości przed posiłkiem"; - -/* title for prescription section */ -"Prescription" = "Recepta"; - -/* The section header text override presets */ -"PRESETS" = "USTAWIENIA WSTĘPNE"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Progressing." = "Postęp."; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Zdarzenie pompy"; - -/* Title text for suspend resume button when the basal delivery state is not set */ -"Pump Inoperable" = "Pompa nie działa"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Szybko działające – dorośli"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Szybko działająca – dzieci"; - -/* The default placeholder string for a credential */ -"Required" = "Wymagane"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Zbiorniczek"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Wznów podawanie"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Wznawianie"; - -/* title for summary description section */ -"Review and Save Settings" = "Przejrzyj i zapisz ustawienia"; - -/* Description of how to interact with summary screen */ -"Review your therapy settings below. If you’d like to edit any of these settings, tap Back to go back to that screen." = "Przejrzyj ustawienia terapii. Jeśli chcesz edytować dowolne z tych ustawień, kliknij Wróć, aby przejść do poprzedniego ekranu."; - -/* The text for the override preset name field placeholder */ -"Running" = "Pracuje"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Zapisz"; - -/* Alert title for confirming basal rates outside the recommended range */ -"Save Basal Rates?" = "Zapisać Dawkę Podstawową?"; - -/* Alert title for confirming carb ratios outside the recommended range */ -"Save Carb Ratios?" = "Zapisać współczynniki węglowodanowe?"; - -/* Alert title for confirming correction ranges outside the recommended range */ -"Save Correction Range(s)?" = "Zapisz Zakres Docelowy?"; - -/* Alert title for confirming delivery limits outside the recommended range */ -"Save Delivery Limits?" = "Zapisać limity podaży?"; - -/* Alert title for confirming a glucose safety limit outside the recommended range */ -"Save Glucose Safety Limit?" = "Zapisać bezpieczny limit glukozy?"; - -/* Alert title for confirming insulin sensitivities outside the recommended range */ -"Save Insulin Sensitivities?" = "Zapisać Współczynnik Wrażliwości na insulinę?"; - -/* Alert title for confirming pre-meal range overrides outside the recommended range */ -"Save Pre-Meal Range?" = "Zapisać zakres przedposiłkowy?"; - -/* Alert title for confirming workout range overrides outside the recommended range */ -"Save Workout Range?" = "Zapisać zakres treningu?"; - -/* The button text during saving on a configuration page */ -"Saving..." = "Zapisywanie..."; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "ZAPLANOWANE POMINIĘCIE"; - -/* The section header text for a scheduled custom preset */ -"SCHEDULED PRESET" = "Lista Celów"; - -/* No comment provided by engineer. */ -"Selected" = "Wybrany"; - -/* Section title for slow absorbing food */ -"Slow" = "Wolna"; - -/* Information about typical maximum basal rates */ -"Some users choose a value 2, 3, or 4 times their highest scheduled basal rate." = "Niektórzy użytkownicy wybierają wartość 2, 3 lub 4 razy większą niż ich najwyższa zaplanowana dawka podstawowa."; - -/* The text for the override start time */ -"Start Time" = "Czas rozpoczęcia"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Rozpoczynanie tymczasowej dawki podstawowej"; - -/* Format for prescription descriptive text (1: providerName, 2: datePrescribed) */ -"Submitted by %1$@, %2$@" = "Wprowadzone przez %1$@, %2$@"; - -/* Title for support section */ -"Support" = "Wsparcie"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Wstrzymaj podawanie"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Wstrzymywanie"; - -/* No comment provided by engineer. */ -"Switch Preview State" = "Przełącz podgląd"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Symbol"; - -/* Text directing the user to configure their first custom preset */ -"Tap '+' to create a new custom preset." = "Stuknij „+”, aby utworzyć nowy Cel Tymczasowy"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Kliknij, aby ustawić"; - -/* The text for the override target range setting */ -"Target Range" = "Zakres docelowy"; - -/* Description of pre-meal mode */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Tymczasowo obniż docelowy poziom glukozy przed posiłkiem, aby ograniczyć gwałtowny wzrost glukozy po posiłku."; - -/* Description of workout mode */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Tymczasowo zwiększ docelowy poziom glukozy przed, w trakcie lub po aktywności fizycznej, aby zmniejszyć ryzyko wystąpienia niskiego poziomu glukozy (Hipoglikemia)."; - -/* The title for the override selection screen */ -"Temporary Override" = "Pominięcie tymczasowe"; - -/* No comment provided by engineer. */ -"Test" = "Test"; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"than your Correction Range." = "niż twój zakres docelowy."; - -/* Description for selection when no insulin type is selected. */ -"The currently selected fast acting insulin model will be used as a default." = "Aktualnie wybrany model insuliny szybko działającej zostanie użyty jako domyślny."; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Model umożliwiający dostosowanie czasu działania insuliny."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "Maksymalny czas absorpcji wynosi %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "Maksymalna dozwolona ilość wynosi %@ gramów"; - -/* Information about adult insulin model */ -"The rapid-acting adult model assumes peak activity at 75 minutes." = "Szybko działający model dla dorosłych zakłada szczytową aktywność po 75 minutach."; - -/* Information about child insulin model */ -"The rapid-acting child model assumes peak activity at 65 minutes." = "Szybko działający model dziecka zakłada szczytową aktywność po 65 minutach."; - -/* Information about basal rate scheduling */ -"The schedule starts at midnight and cannot contain a rate of 0 U/hr." = "Harmonogram rozpoczyna się o północy i nie może zawierać dawki 0 J/godz."; - -/* Therapy Settings screen title */ -"Therapy Settings" = "Ustawienia terapii"; - -/* No comment provided by engineer. */ -"Therapy Settings Support Placeholder" = "Opis ustawień terapii"; - -/* Subtitle of afrezza preset */ -"This model assumes peak insulin activity at 19 minutes." = "Model ten zakłada szczytową aktywność insuliny po 19 minutach."; - -/* Subtitle of Fiasp preset - Subtitle of Lyumjev preset */ -"This model assumes peak insulin activity at 55 minutes." = "Model ten zakłada szczytową aktywność insuliny po 55 minutach."; - -/* Subtitle of Rapid-Acting – Children preset */ -"This model assumes peak insulin activity at 65 minutes." = "Model ten zakłada szczytową aktywność insuliny po 65 minutach."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"This model assumes peak insulin activity at 75 minutes." = "Model ten zakłada szczytową aktywność insuliny po 75 minutach."; - -/* Information about maximum automated insulin on board (1: app name) */ -"This setting will also determine a safety limit for automatic dosing. %1$@ will limit automatic delivery to keep the amount of active insulin below twice your maximum bolus." = "Te ustawienia będą dodatkowo określać bezpieczny limit automatycznych dawek. %1$@ ograniczy automatyczne podawanie, do dwukrotności Twojego maksymalnego bolusa."; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"This will typically be" = "Zazwyczaj będzie to "; - -/* Label for offset from midnight picker */ -"Time" = "Czas"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Czas w %1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"To be implemented" = "Być realizowane"; - -/* No comment provided by engineer. */ -"Top component" = "Górny składnik"; - -/* The text indicating Total for Daily Schedule Basal */ -"Total" = "Łącznie"; - -/* The text indicating U/day for Daily Schedule Basal */ -"U/day" = "J/dzień"; - -/* The unit string for units per hour */ -"U/hour" = "J/godzinę"; - -/* Alert title when error occurs while saving a schedule */ -"Unable to Save" = "Nie można zapisać"; - -/* The unit string for units */ -"Units" = "Jednostki"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Nieznany"; - -/* No comment provided by engineer. */ -"Unselected" = "Niezaznaczone"; - -/* Title for selection when no insulin type is selected. */ -"Unset" = "Niewybrano"; - -/* Placeholder text until value is entered */ -"Value" = "Wartość"; - -/* Label indicating validation is occurring */ -"Verifying" = "Weryfikuję"; - -/* The title for the override editing screen */ -"View Override" = "Podgląd Celu Tymczasowego"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Ostrzeżenie"; - -/* Disclaimer */ -"Work with your healthcare provider to choose a value that is higher than your highest scheduled basal rate, but as conservative or aggressive as you feel comfortable." = "Współpracuj z lekarzem przy ustalaniu limitu podaży. Limit powinien ustawiony być tak, abyś czuł się bezpiecznie."; - -/* Title for the workout override range */ -"Workout" = "Wysiłek fizyczny"; - -/* Information about workout range format (1: app name) */ -"Workout Range is the glucose value or range of values you want %1$@ to target during activity. This range will be in effect when you activate the Workout Preset button." = "Zakres treningu to wartość glukozy lub zakres wartości, do których chcesz dążyć %1$@ podczas aktywności. Ten zakres będzie obowiązywać po aktywowaniu przycisku ustawienia wstępnego treningu."; - -/* Title text for multi-value workout value warning */ -"Workout Values" = "Wartości treningu"; - -/* Description of how to add a ratio */ -"You can add different carb ratios for different times of day by using the ➕." = "Możesz dodać różne współczynniki węglowodanowe dla różnych pór dnia, używając ➕."; - -/* Description of how to add a ratio */ -"You can add different insulin sensitivities for different times of day by using the ➕." = "Możesz dodać różne wrażliwości na insulinę dla różnych pór dnia za pomocą ➕."; - -/* Description of how to add a configuration range */ -"You can add different ranges for different times of day by using the ➕." = "Możesz dodać różne zakresy dla różnych pór dnia, używając ➕."; - -/* Description of how to add a range */ -"You can add entries for different times of day by using the ➕." = "Możesz dodać różne współczynniki węglowodanowe dla różnych pór dnia, używając ➕."; - -/* Information about insulin model (1: app name) */ -"You can choose how %1$@ measures rapid acting insulin's peak activity according to one of these two insulin models." = "Możesz wybrać jak %1$@ prognozuje szczyt działania insuliny szybko działającej spośród dwóch dostępnych modeli insulinowych."; - -/* Description of how to edit setting */ -"You can edit a setting by tapping into any line item." = "Możesz edytować ustawienie, stukając w pozycję mg/dL"; - -/* Description of how to edit setting */ -"You can edit the setting by tapping into the line item." = "Możesz edytować ustawienie, stukając w pozycję mg/dL"; - -/* Information about basal rates */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Dawka podstawowa insuliny to liczba jednostek na godzinę, którą chcesz wykorzystać do pokrycia podstawowego zapotrzebowania na insulinę."; - -/* Lower bound pre-meal information text */ -"your Glucose Safety Limit" = "Bezpieczny Limit Glukozy"; - -/* Disclaimer */ -"Your healthcare provider can help you choose a Correction Range that's right for you." = "Twój lekarz może pomóc Ci wybrać zakres docelowy odpowiedni dla Ciebie."; - -/* Description of insulin sensitivity factor */ -"Your Insulin Sensitivity Factor (ISF) is the drop in glucose expected from one unit of insulin." = "Twój współczynnik wrażliwości na insulinę (ISF) to oczekiwany spadek glukozy po podaniu jednej jednostki insuliny."; - -/* Information about pre-meal range format (1: app name) */ -"Your Pre-Meal Range should be the glucose value (or range of values) you want %1$@ to target by the time you take your first bite of your meal. This range will be in effect when you activate the Pre-Meal Preset button." = "Twój zakres przed posiłkiem powinien być wartością glukozy (lub zakresem wartości), do którego chcesz dążyć %1$@, zanim zaczniesz spożywać posiłek. Ten zakres będzie obowiązywał po aktywowaniu przycisku Przed Posiłkiem."; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/pt-BR.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/pt-BR.lproj/InsulinKit.strings deleted file mode 100644 index cb3cba99e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/pt-BR.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Event History"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Non-Pump Insulin"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/pt-BR.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/pt-BR.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 64e6c3284..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/pt-BR.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Event History"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/pt-BR.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/pt-BR.lproj/Localizable.strings deleted file mode 100644 index f286125e6..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,295 +0,0 @@ -/* The detail text representing no value */ -"–" = "—"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% de insulina normal"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unidades restantes em %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Tempo de Absorção"; - -/* The title for the override emoji activity section */ -"Activity" = "Atividade"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Adicionar Conta"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Adicionar Carb"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Tem certeza de que deseja excluir todas as entradas do histórico?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Tem certeza de que deseja excluir todos os valores do reservatório?"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Taxas Basais"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "As quantidades basais, de bolus e de dose de insulina de correção diminuem em %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "As quantidades basais, de bolus e de dose de insulina de correção aumentam em %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "As quantidades basais, de bolus e de dose de insulina de correção não são alteradas."; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancelar"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Cancelar Sobreposição"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Cancelar Basal Temporária"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Taxas de Carbs"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "As alterações serão aplicadas apenas desta vez que você ativar a sobreposição. As configurações padrão de %@ não serão afetadas."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Escolha um tempo de absorção mais longo para refeições maiores ou aquelas que contenham gorduras e proteínas. Esta é apenas uma orientação para o algoritmo e não precisa ser exata."; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "em %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "desde %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "em %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "desde %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* The title for the override emoji condition section */ -"Condition" = "Estado"; - -/* Title of the setup button to continue */ -"Continue" = "Continuar"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "A faixa de correção é o intervalo de glicose no sangue que você gostaria que o Loop corrigisse para."; - -/* The text for a custom override */ -"Custom" = "Personalizado"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Sobreposição Personalizada"; - -/* Title of the carb entry date picker cell */ -"Date" = "Data"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Remover Conta"; - -/* Button title to delete all objects */ -"Delete All" = "Remover Todos"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Limites de Entrega"; - -/* The text for the override duration setting */ -"Duration" = "Duração"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Editar Carb"; - -/* The title for the override editing screen */ -"Edit Override" = "Editar Sobreposição"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "A edição afeta apenas a sobreposição ativa. As configurações padrão de %@ não serão afetadas."; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Ativar Indefinidamente"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Ativado"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Digite um número de unidades"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Insira uma taxa em unidades por hora"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Event History"; - -/* Section title for fast absorbing food */ -"Fast" = "Rápida"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Title text for insulin model */ -"Insulin Model" = "Modelo de Insulina"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Sensibilidades a Insulina"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "A sensibilidade à insulina descreve como a glicose no sangue deve responder a uma dose unitária de insulina. Valores menores significam que mais insulina será administrada quando acima do objetivo. Valores muito pequenos podem causar hipoglicemia."; - -/* Placeholder for maximum value in glucose range */ -"max" = "max"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Taxa Basal Máxima"; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Bolus Máximo"; - -/* Section title for medium absorbing food */ -"Medium" = "Média"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* Alert action title to open error help */ -"More Info" = "Mais Info"; - -/* The text for the override preset name setting */ -"Name" = "Nome"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Nova Predefinição"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Outra"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Necessidades Gerais de Insulina"; - -/* The title text for the override presets screen */ -"Override Presets" = "Sobreposições Predefinidas"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "As predefinições de sobreposição podem ser configuradas na seção 'Configuração' da tela de configurações."; - -/* The section title of glucose overrides */ -"Overrides" = "Sobreposições"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Pré-Refeição"; - -/* The section header text override presets */ -"PRESETS" = "PREDEFINIDAS"; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Eventos da Bomba"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Ação-Rápida – Adultos"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Ação-Rapida – Crianças"; - -/* The default placeholder string for a credential */ -"Required" = "Obrigatório"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Reservoir"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Retomar Entrega"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Retomando"; - -/* The text for the override preset name field placeholder */ -"Running" = "Executando"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Salvar"; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "SOBREPOSIÇÃO AGENDADA"; - -/* Section title for slow absorbing food */ -"Slow" = "Lenta"; - -/* The text for the override start time */ -"Start Time" = "Hora de Início"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Iniciando Temp Basal"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspender Entrega"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspendendo"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Símbolo"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Toque para Definir"; - -/* The text for the override target range setting */ -"Target Range" = "Intervalo Meta"; - -/* The title for the override selection screen */ -"Temporary Override" = "Sobreposição Temporária"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "O modelo antigo utilizado pelo Loop permitindo personalização da duração da ação."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "O tempo máximo de absorção é %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "A quantidade máxima permitida é %@ gramas"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Hora em %1$@%2$@%3$@"; - -/* The unit string for units per hour */ -"U/hour" = "U/houra"; - -/* The unit string for units */ -"Units" = "Unidades"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Desconhecido"; - -/* Label indicating validation is occurring */ -"Verifying" = "Verificando"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Aviso"; - -/* Title for the workout override range */ -"Workout" = "Exercício"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/ro.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/ro.lproj/InsulinKit.strings deleted file mode 100644 index aa34af1cb..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/ro.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Rezervor"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Istoric evenimente"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Non-Pump Insulin"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/ro.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/ro.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index d58b62b0f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/ro.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Rezervor"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Istoric evenimente"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/ro.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/ro.lproj/Localizable.strings deleted file mode 100644 index e7853e614..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/ro.lproj/Localizable.strings +++ /dev/null @@ -1,745 +0,0 @@ -/* Information about workout range relative to correction range */ -" higher " = " mai mare "; - -/* Information about pre-meal range relative to correction range */ -" lower " = " mai mic "; - -/* Separator between min and max glucose values */ -"-" = "-"; - -/* No comment provided by engineer. */ -"-" = "-"; - -/* The detail text representing no value */ -"–" = "–"; - -/* No comment provided by engineer. */ -"···" = "···"; - -/* No comment provided by engineer. */ -"%@" = "%@"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% din insulină normală"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Information about insulin action duration (1: app name) */ -"%1$@ assumes that the insulin it has delivered is actively working to lower your glucose for 6 hours. This setting cannot be changed." = "%1$@ presupune că insulina pe care a livrat-o acționează pentru a vă scădea glicemia timp de 6 ore. Această setare nu poate fi schimbată."; - -/* Lower bound workout information text format (1: app name) */ -"%1$@ or your Glucose Safety Limit, whichever is higher" = "%1$@ sau limita dvs. de siguranță, oricare dintre acestea este mai mare"; - -/* Information about max number of basal rates (1: app name) (2: maximum schedule entry count) */ -"%1$@ supports 1 to %2$@ rates per day." = "%1$@ acceptă rate de la 1 la %2$@ pe zi."; - -/* Reservoir entry (1: volume value) */ -"%1$@ U" = "%1$@ U"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unități rămase la %2$@"; - -/* Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) - Description of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) */ -"%1$@: %2$@ %3$@" = "%1$@: %2$@ %3$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for progress accessibility label (1: duration in seconds) */ -"%1$d percent complete." = "%1$d la sută complet."; - -/* No comment provided by engineer. */ -"%lld" = "%lld"; - -/* No comment provided by engineer. */ -"%lld, " = "%lld, "; - -/* No comment provided by engineer. */ -"🍽" = "🍽"; - -/* Premeal override preset title */ -"🍽 Pre-Meal" = "🍽 Preprandial"; - -/* No comment provided by engineer. */ -"🏃‍♂️" = "🏃‍♂️"; - -/* Workout override preset title */ -"🏃‍♂️ Workout" = "🏃‍♂️ Activitate sportivă"; - -/* No comment provided by engineer. */ -"A card whose text will wrap onto multiple lines if I continue to type for long enough—this length should do" = "Un card al cărui text se va întinde pe mai multe linii dacă continui să tastez pentru o perioadă suficient de lungă — această lungime ar trebui să o facă"; - -/* Information about differences between target range and correction range */ -"A Correction Range is different. This will be a narrower range." = "Un interval de corecție este diferit. Acesta ar trebui sa fie un interval mai îngust."; - -/* No comment provided by engineer. */ -"A simple card" = "Un card simplu"; - -/* Warning text for basal rate of 0 U/hr */ -"A value of 0 U/hr means you will be scheduled to receive no basal insulin." = "O valoare de 0 U/oră înseamnă că nu vei primi insulină bazală."; - -/* No comment provided by engineer. */ -"Above the save button" = "Deasupra butonului de salvare"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Timp de absorbție"; - -/* No comment provided by engineer. */ -"Action Button" = "Buton acțiune"; - -/* The text for the override history duration */ -"Active Duration" = "Durata activă"; - -/* The title for the override emoji activity section */ -"Activity" = "Activitate"; - -/* Button text to confirm adding a new schedule item */ -"Add" = "Adaugă"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Adaugă cont"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Adaugă carbohidrați"; - -/* Title of insulin model preset - afrezza */ -"Afrezza" = "Afrezza"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Sigur doriți să ștergeți toate înregistrările din istoric?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Sigur doriți să ștergeți toate valorile de rezervor?"; - -/* Authentication hint string for therapy settings */ -"Authenticate to save therapy setting" = "Autentifică-te pentru a salva setările terapiei"; - -/* Back navigation button title */ -"Back" = "Înapoi"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Rate bazale"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Dozele de insulină bazale, de bolus și de corecție sunt scăzute cu %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Dozele de insulină bazale, de bolus și de corecție sunt crescute cu %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Dozele de insulină bazale, de bolus și de corecție sunt neafectate."; - -/* No comment provided by engineer. */ -"Bottom component" = "Componenta de jos"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Renunță"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Oprește înlocuirea"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Oprește bazala temporară"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Raport carbohidrați/insulină"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Modificările se vor aplica doar pe durata înlocuirii. Setările implicite de %@ nu vor fi afectate."; - -/* Footer text for customizing from a preset (1: preset name) */ -"Changes will only apply this time you enable the preset. The default settings of %@ will not be affected." = "Modificările se vor aplica numai de această dată când activați presetarea. Setările implicite %@ nu vor fi afectate."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Alegeți o durată mai lungă de absorbție pentru mese mai mari sau pentru cele care conțin grăsimi și proteine. Nu e necesară o valoare exactă, scopul e să oferim doar o ghidare pentru algoritm."; - -/* Button text to close a modal - Text to close informational page */ -"Close" = "Închide"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "la %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "de la %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "la %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "de la %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Completed." = "Finalizat."; - -/* The title for the override emoji condition section */ -"Condition" = "Condiție"; - -/* The button text for confirming the setting */ -"Confirm Setting" = "Confirmați setările"; - -/* No comment provided by engineer. */ -"content" = "conținut"; - -/* Title of the setup button to continue */ -"Continue" = "Continuă"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "Correction range is the blood glucose range that you would like Loop to correct to."; - -/* Title text for multi-value correction value warning */ -"Correction Values" = "Valori corecție"; - -/* The text for a custom override */ -"Custom" = "Personalizată"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Modificare personalizată"; - -/* The title for the custom preset entry screen - The title for the custom preset selection screen */ -"Custom Preset" = "Presetare particularizată"; - -/* Title of the carb entry date picker cell */ -"Date" = "Data"; - -/* Delete values for Pre-Meal, inactivates Pre-Meal icon - Test for table cell delete button - The title of the button to remove the credentials for a service */ -"Delete" = "Șterge"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Șterge cont"; - -/* Button title to delete all objects */ -"Delete All" = "Șterge tot"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Limite de livrare"; - -/* Information about delivery limits */ -"Delivery Limits are safety guardrails for your insulin delivery." = "Limitele de livrare sunt măsuri de siguranță pentru administrarea insulinei."; - -/* The text for the custom preset disable button */ -"Disable Preset" = "Dezactivează presetarea"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Realizat"; - -/* The text for the override duration setting */ -"Duration" = "Durată"; - -/* No comment provided by engineer. */ -"Dynamic component #%lld" = "Componenta dinamică #%lld"; - -/* Text for edit button - The title for the enabled custom preset editing screen */ -"Edit" = "Editare"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Editează carbohidrați"; - -/* The title for the override editing screen */ -"Edit Override" = "Editează înlocuirea"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "Editarea afectează doar înlocuirea activă. Setările implicite de %@ nu vor fi afectate."; - -/* Footer text for editing an enabled custom preset (1: preset name) */ -"Edits persist only until the preset is disabled. The default settings of %@ will not be affected." = "Modificările persistă numai până când presetarea este dezactivată. Setările implicite %@ nu vor fi afectate."; - -/* The button text for enabling a temporary override */ -"Enable" = "Activează"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Activează pe termen nedeterminat"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Activat"; - -/* The text for the override start time */ -"End Time" = "Timp de încheiere"; - -/* Format string for accessibility label for value entry. (1: value label) */ -"Enter %1$@ value" = "Introduceți valoarea %1$@"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Introduceți un număr de unități"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Introduceți o rată exprimată în unități per oră"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Istoric evenimente"; - -/* No comment provided by engineer. */ -"Example" = "Exemplu"; - -/* Section title for fast absorbing food */ -"Fast" = "Rapidă"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Insulin model setting description (1: app name) (2: number of models) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from %2$@ different models for how the app measures the insulin’s peak activity." = "Pentru insulina cu acțiune rapida, %1$@ presupune că acționează timp de 6 ore. Puteți alege din %2$@ modele diferite pentru modul în care aplicația determina vârful de acțiune al insulinei."; - -/* Information about correction range format (1: app name) */ -"For this range, choose the specific glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin." = "Pentru acest interval, alegeți valoarea specifică a glicemiei (sau intervalul de valori) spre care doriți ca %1$@ să țintească în ajustarea insulinei bazale."; - -/* Support button for Therapy Settings */ -"Get help with Therapy Settings" = "Obțineți ajutor cu Setările Terapiei"; - -/* Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range - Text for go back action on confirmation alert */ -"Go Back" = "Inapoi"; - -/* Title text for the high basal rate warning */ -"High Basal Rate" = "Rată bazală ridicată"; - -/* Title text for the high carb ratio warning */ -"High Carb Ratio" = "Raport carbohidrați/insulina ridicat"; - -/* Title text for the high correction value warning */ -"High Correction Value" = "Valoare de corecție ridicată"; - -/* Title text for the high glucose safety limit warning */ -"High Glucose Safety Limit" = "Limita superioara de siguranță a glicemiei"; - -/* Title text for the high insulin sensitivity warning */ -"High Insulin Sensitivity" = "Factor de sensibilitate la insulină ridicat"; - -/* Title text for high maximum basal rate warning */ -"High Maximum Basal Rate" = "Rată bazală maximă ridicata"; - -/* Title text for high maximum bolus warning */ -"High Maximum Bolus" = "Bolus maxim ridicat"; - -/* Title text for the low pre-meal value warning */ -"High Pre-Meal Value" = "Valoare mare preprandiala"; - -/* Title text for the high workout value warning */ -"High Workout Value" = "Valoare mare antrenament"; - -/* The text for the override history */ -"History" = "Istoric"; - -/* Description of how to interact with summary screen */ -"If these settings look good to you, tap Save Settings to continue." = "Dacă aceste setări arată bine pentru tine, apasă pe Salvează Setări pentru a continua."; - -/* Information about target range */ -"If you've used a CGM before, you're likely familiar with target range as a wide range of values you'd like for your glucose notification alerts, such as 70-180 mg/dL or 90-200 mg/dL." = "Dacă ați folosit anterior un CGM, probabil sunteți familiarizat cu intervalul țintă ca o gamă largă de valori pe care le-ați dori pentru alertele de notificare, cum sunt 70-180 mg/dl sau 90-200 mg/dl."; - -/* No comment provided by engineer. */ -"info" = "info"; - -/* Title text for insulin model */ -"Insulin Model" = "Modelul de insulină"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Factor de sensibilitate la insulină"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "Factorul de sensibilitate la insulină descrie felul în care glicemia ar trebui să răspundă la 1 unitate de insulină. Valori mai mici determină administrarea unor doze mai mari de insulină pentru a scădea glicemia la intervalul țintă."; - -/* Description of an interrupted bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: programmed value (? if no value), 4: unit) */ -"Interrupted %1$@: %2$@ of %3$@ %4$@" = "Întrerupere %1$@: %2$@ din %3$@ %4$@"; - -/* Guardrail info text format */ -"It can be set as low as %1$@. It can be set as high as %2$@." = "Poate fi setat la minim %1$@. Poate fi setat până la %2$@."; - -/* Title text for the low basal rate warning */ -"Low Basal Rate" = "Rată bazală scăzută"; - -/* Title text for the low carb ratio warning */ -"Low Carb Ratio" = "Raport Carbohidrați/Insulina scăzut"; - -/* Title text for the low correction value warning */ -"Low Correction Value" = "Valoare de corecție scăzută"; - -/* Title text for the low glucose safety limit warning */ -"Low Glucose Safety Limit" = "Limita inferioara de siguranță a glicemiei"; - -/* Title text for the low insulin sensitivity warning */ -"Low Insulin Sensitivity" = "Factor de sensibilitate la insulină scăzut"; - -/* Title text for low maximum basal rate warning */ -"Low Maximum Basal Rate" = "Rată bazală maximă scăzută"; - -/* Title text for low maximum bolus warning */ -"Low Maximum Bolus" = "Bolus maxim scăzut"; - -/* Title text for the low pre-meal value warning */ -"Low Pre-Meal Value" = "Valoare mica preprandiala"; - -/* Title text for the low workout value warning */ -"Low Workout Value" = "Valoare mica antrenament"; - -/* Title of insulin model preset - lyumjev */ -"Lyumjev" = "Lyumjev"; - -/* Placeholder for maximum value in glucose range */ -"max" = "max"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Rată bazală maximă"; - -/* Information about maximum basal rate (1: app name) */ -"Maximum Basal Rate is the maximum automatically adjusted basal rate that %1$@ is allowed to enact to help reach your correction range." = "Rata bazală maximă este rata bazală maximă ajustată automat pe care %1$@ are voie să o activeze pentru a vă ajuta să atingeți intervalul de corecție."; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Bolus maxim"; - -/* Information about maximum bolus (1: app name) */ -"Maximum Bolus is the highest bolus amount that you will allow %1$@ to recommend at one time to cover carbs or bring down high glucose." = "Bolusul maxim este cea mai mare cantitate de insulină pe care o permiteți %1$@ să o recomande dintr-odată pentru a acoperi carbohidrați sau pentru a scădea o glicemie mare."; - -/* Section title for medium absorbing food */ -"Medium" = "Medie"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* No comment provided by engineer. */ -"more content" = "mai mult conținut"; - -/* Alert action title to open error help */ -"More Info" = "Detalii"; - -/* The text for the override preset name setting */ -"Name" = "Nume"; - -/* Title for mini-modal to add a new schedule entry */ -"New Entry" = "Înregistrare nouă"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Presetare nouă"; - -/* Title text for the zero basal rate warning */ -"No Basal Insulin" = "Fără insulină bazală"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Altele"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Necesar de insulină total"; - -/* Title for override history view */ -"Override History" = "Suprascrie istoricul"; - -/* The title text for the override presets screen */ -"Override Presets" = "Presetări de înlocuire"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Presetările de înlocuire pot fi setate în secțiunea 'Configurație' din ecranul de setări."; - -/* The section title of glucose overrides */ -"Overrides" = "Înlocuiri"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Preprandial"; - -/* Title text for multi-value pre-meal value warning */ -"Pre-Meal Values" = "Valori preprandiale"; - -/* title for prescription section */ -"Prescription" = "Prescripție"; - -/* The section header text override presets */ -"PRESETS" = "PRESETĂRI"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Progressing." = "Progresează."; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Eveniment de pompă"; - -/* Title text for suspend resume button when the basal delivery state is not set */ -"Pump Inoperable" = "Pompă inoperabilă"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Acțiune rapidă – Adulți"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Acțiune rapidă - Copii"; - -/* The default placeholder string for a credential */ -"Required" = "Necesar"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Rezervor"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Reia administrarea"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Se reia"; - -/* title for summary description section */ -"Review and Save Settings" = "Revizuiește și Salvează Setările"; - -/* Description of how to interact with summary screen */ -"Review your therapy settings below. If you’d like to edit any of these settings, tap Back to go back to that screen." = "Revizuiți setările de terapie de mai jos. Dacă doriți să editați oricare dintre aceste setări, apăsați Înapoi pentru a reveni la acel ecran."; - -/* The text for the override preset name field placeholder */ -"Running" = "Se rulează"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Salvează"; - -/* Alert title for confirming basal rates outside the recommended range */ -"Save Basal Rates?" = "Salvați ratele bazale?"; - -/* Alert title for confirming carb ratios outside the recommended range */ -"Save Carb Ratios?" = "Salvați rațiile insulina carbohidrați?"; - -/* Alert title for confirming correction ranges outside the recommended range */ -"Save Correction Range(s)?" = "Salvați intervalul (intervalele) de corecție?"; - -/* Alert title for confirming delivery limits outside the recommended range */ -"Save Delivery Limits?" = "Salvați limitele de administrare?"; - -/* Alert title for confirming a glucose safety limit outside the recommended range */ -"Save Glucose Safety Limit?" = "Salvați limita de siguranță pentru glicemie?"; - -/* Alert title for confirming insulin sensitivities outside the recommended range */ -"Save Insulin Sensitivities?" = "Salvați sensibilitatea la insulină?"; - -/* Alert title for confirming pre-meal range overrides outside the recommended range */ -"Save Pre-Meal Range?" = "Salvează Interval preprandial?"; - -/* Alert title for confirming workout range overrides outside the recommended range */ -"Save Workout Range?" = "Salvați intervalul țintă pentru antrenament?"; - -/* The button text during saving on a configuration page */ -"Saving..." = "Salvare..."; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "ÎNLOCUIRE PLANIFICATĂ"; - -/* The section header text for a scheduled custom preset */ -"SCHEDULED PRESET" = "PRESETARE PROGRAMATĂ"; - -/* No comment provided by engineer. */ -"Selected" = "Selectat"; - -/* Section title for slow absorbing food */ -"Slow" = "Lentă"; - -/* Information about typical maximum basal rates */ -"Some users choose a value 2, 3, or 4 times their highest scheduled basal rate." = "Unii utilizatori aleg o valoare de 2, 3 sau 4 ori cea mai mare rată bazală programată."; - -/* The text for the override start time */ -"Start Time" = "Oră începere"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Pornire bazală temporară"; - -/* Format for prescription descriptive text (1: providerName, 2: datePrescribed) */ -"Submitted by %1$@, %2$@" = "Trimis de %1$@, %2$@"; - -/* Title for support section */ -"Support" = "Asistenţă"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspendă administrarea"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Se suspendă"; - -/* No comment provided by engineer. */ -"Switch Preview State" = "Schimbă către Stare Previzualizare"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Simbol"; - -/* Text directing the user to configure their first custom preset */ -"Tap '+' to create a new custom preset." = "Apasă '+' pentru a crea o nouă presetare personalizată."; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Apăsați pentru setare"; - -/* The text for the override target range setting */ -"Target Range" = "Interval țintă"; - -/* Description of pre-meal mode */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Reduceți temporar glicemia țintă înainte de masă pentru a avea un impact asupra vârfurilor postprandiale."; - -/* Description of workout mode */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Creșteți temporar valoarea ținta a glicemiei înainte, în timpul sau după activitatea fizică pentru a reduce riscul de apariție a hipoglicemiei."; - -/* The title for the override selection screen */ -"Temporary Override" = "Înlocuire temporară"; - -/* No comment provided by engineer. */ -"Test" = "Test"; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"than your Correction Range." = "față de intervalul de corecții."; - -/* Description for selection when no insulin type is selected. */ -"The currently selected fast acting insulin model will be used as a default." = "Modelul de insulină cu acțiune rapidă selectat în prezent va fi utilizat ca implicit."; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Modelul vechi utilizat de Loop, permite personalizarea duratei de acțiune."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "Durata maximă de absorbție este de %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "Cantitatea maximă admisă este de %@ grame"; - -/* Information about adult insulin model */ -"The rapid-acting adult model assumes peak activity at 75 minutes." = "Modelul pentru adulți de acțiune rapidă presupune vârful de acțiune la 75 de minute."; - -/* Information about child insulin model */ -"The rapid-acting child model assumes peak activity at 65 minutes." = "Modelul pentru copii de acțiune rapidă presupune vârful de acțiune la 65 de minute."; - -/* Information about basal rate scheduling */ -"The schedule starts at midnight and cannot contain a rate of 0 U/hr." = "Programul începe la miezul nopții și nu poate conține o rată bazala de 0 U/oră."; - -/* Therapy Settings screen title */ -"Therapy Settings" = "Setări Terapie"; - -/* No comment provided by engineer. */ -"Therapy Settings Support Placeholder" = "Suport Setări de Terapie Substituent"; - -/* Subtitle of afrezza preset */ -"This model assumes peak insulin activity at 19 minutes." = "Acest model presupune vârful de acțiune al insulinei la 19 minute."; - -/* Subtitle of Fiasp preset - Subtitle of Lyumjev preset */ -"This model assumes peak insulin activity at 55 minutes." = "Acest model presupune activitatea maximă a insulinei la 55 minute."; - -/* Subtitle of Rapid-Acting – Children preset */ -"This model assumes peak insulin activity at 65 minutes." = "Acest model presupune activitatea maximă a insulinei la 65 minute."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"This model assumes peak insulin activity at 75 minutes." = "Acest model presupune activitatea maximă a insulinei la 75 minute."; - -/* Information about maximum automated insulin on board (1: app name) */ -"This setting will also determine a safety limit for automatic dosing. %1$@ will limit automatic delivery to keep the amount of active insulin below twice your maximum bolus." = "Această setare va determina, de asemenea, o limită de siguranță pentru administrarea automată. %1$@ va limita administrarea automată pentru a menține cantitatea de insulină activă sub dublul bolusului maxim."; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"This will typically be" = "Acesta va fi de obicei"; - -/* Label for offset from midnight picker */ -"Time" = "Timp"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Orele în %1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"To be implemented" = "Va fi implementat"; - -/* No comment provided by engineer. */ -"Top component" = "Componenta superioara"; - -/* The text indicating Total for Daily Schedule Basal */ -"Total" = "Total"; - -/* The text indicating U/day for Daily Schedule Basal */ -"U/day" = "U/zi"; - -/* The unit string for units per hour */ -"U/hour" = "U/oră"; - -/* Alert title when error occurs while saving a schedule */ -"Unable to Save" = "Nu se poate salva"; - -/* The unit string for units */ -"Units" = "Unități"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Necunoscut"; - -/* No comment provided by engineer. */ -"Unselected" = "Neselectat"; - -/* Title for selection when no insulin type is selected. */ -"Unset" = "Nealeasă"; - -/* Placeholder text until value is entered */ -"Value" = "Valoare"; - -/* Label indicating validation is occurring */ -"Verifying" = "Se verifică"; - -/* The title for the override editing screen */ -"View Override" = "Vizualizare suprascriere"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Avertizare"; - -/* Disclaimer */ -"Work with your healthcare provider to choose a value that is higher than your highest scheduled basal rate, but as conservative or aggressive as you feel comfortable." = "Consultați-va cu medicul pentru a alege o valoare mai mare decât cea mai mare rată bazală programată, dar suficient de prudenta sau agresiva pe cât vă simțiți confortabil."; - -/* Title for the workout override range */ -"Workout" = "Activitate sportivă"; - -/* Information about workout range format (1: app name) */ -"Workout Range is the glucose value or range of values you want %1$@ to target during activity. This range will be in effect when you activate the Workout Preset button." = "Intervalul ținta pentru antrenament este valoarea glicemiei sau intervalul de valori pe care vrei să le țintești %1$@ în timpul activității. Acest interval va fi în vigoare atunci când activați butonul de presetare a antrenamentului."; - -/* Title text for multi-value workout value warning */ -"Workout Values" = "Valori activitate sportivă"; - -/* Description of how to add a ratio */ -"You can add different carb ratios for different times of day by using the ➕." = "Poți adăuga diferite rații carbohidrați/insulina pentru diferite momente ale zilei folosind ➕."; - -/* Description of how to add a ratio */ -"You can add different insulin sensitivities for different times of day by using the ➕." = "Puteți adăuga valori pentru sensibilitatea la insulină pentru diferite momente ale zilei utilizând ➕."; - -/* Description of how to add a configuration range */ -"You can add different ranges for different times of day by using the ➕." = "Poți adăuga diferite intervale pentru diferite momente ale zilei folosind ➕."; - -/* Description of how to add a range */ -"You can add entries for different times of day by using the ➕." = "Poți adăuga intrări pentru diferite momente ale zilei folosind ➕."; - -/* Information about insulin model (1: app name) */ -"You can choose how %1$@ measures rapid acting insulin's peak activity according to one of these two insulin models." = "Puteți alege modul în care %1$@ măsoară momentul de vârf al insulinei cu acțiune rapidă în funcție de unul dintre aceste două modele de insulină."; - -/* Description of how to edit setting */ -"You can edit a setting by tapping into any line item." = "Puteți edita o setare apăsând pe orice linie."; - -/* Description of how to edit setting */ -"You can edit the setting by tapping into the line item." = "Puteți edita setarea apăsând pe linie."; - -/* Information about basal rates */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Rata bazală de insulină este numărul de unități pe oră pe care doriți să le utilizați pentru a acoperi necesarul bazal de insulina al organismului."; - -/* Lower bound pre-meal information text */ -"your Glucose Safety Limit" = "limita de siguranță a glicemiei"; - -/* Disclaimer */ -"Your healthcare provider can help you choose a Correction Range that's right for you." = "Medicul dvs. vă poate ajuta să alegeți un interval de corecție potrivit pentru dvs."; - -/* Description of insulin sensitivity factor */ -"Your Insulin Sensitivity Factor (ISF) is the drop in glucose expected from one unit of insulin." = "Factorul de sensibilitate la insulină (ISF) este scăderea glicemiei determinata de o unitate de insulină."; - -/* Information about pre-meal range format (1: app name) */ -"Your Pre-Meal Range should be the glucose value (or range of values) you want %1$@ to target by the time you take your first bite of your meal. This range will be in effect when you activate the Pre-Meal Preset button." = "Intervalul ținta preparandial trebuie să fie valoarea glicemiei (sau intervalul de valori) pe care doriți %1$@ să o vizați până la prima mușcătură a mesei. Acest interval va fi în vigoare atunci când activați butonul Presetare înainte de masă."; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/ru.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/ru.lproj/InsulinKit.strings deleted file mode 100644 index d81d5c7e4..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/ru.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "ед Всего"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "История событий"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Инсулин не из помпы (ручка)"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/ru.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/ru.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 8d42fdccc..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/ru.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "История событий"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/ru.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/ru.lproj/Localizable.strings deleted file mode 100644 index 50ebfa294..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/ru.lproj/Localizable.strings +++ /dev/null @@ -1,715 +0,0 @@ -/* Information about workout range relative to correction range */ -" higher " = " выше "; - -/* Information about pre-meal range relative to correction range */ -" lower " = " ниже "; - -/* Separator between min and max glucose values */ -"-" = "-"; - -/* No comment provided by engineer. */ -"-" = "-"; - -/* The detail text representing no value */ -"–" = "–"; - -/* No comment provided by engineer. */ -"···" = "---"; - -/* No comment provided by engineer. */ -"%@" = "%@"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% нормального инсулина"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@Ед"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Information about insulin action duration (1: app name) */ -"%1$@ assumes that the insulin it has delivered is actively working to lower your glucose for 6 hours. This setting cannot be changed." = "%1$@ предполагает, что доставленный им инсулин активно работает над снижением уровня глюкозы в течение 6 часов. Эта настройка не может быть изменена."; - -/* Lower bound workout information text format (1: app name) */ -"%1$@ or your Glucose Safety Limit, whichever is higher" = "%1$@ или ваш безопасный предел ГК, в зависимости от того, что выше"; - -/* Information about max number of basal rates (1: app name) (2: maximum schedule entry count) */ -"%1$@ supports 1 to %2$@ rates per day." = "%1$@ поддерживает от 1 до %2$@ изменений в день."; - -/* Reservoir entry (1: volume value) */ -"%1$@ U" = "%1$@ U"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ ед остается в %2$@"; - -/* Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) - Description of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) */ -"%1$@: %2$@ %3$@" = "%1$@:%2$@ %3$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"🍽" = "🍽"; - -/* Premeal override preset title */ -"🍽 Pre-Meal" = "До еды"; - -/* No comment provided by engineer. */ -"🏃‍♂️" = "🏃‍"; - -/* Workout override preset title */ -"🏃‍♂️ Workout" = "🏃‍♂️ Тренировки"; - -/* No comment provided by engineer. */ -"A card whose text will wrap onto multiple lines if I continue to type for long enough—this length should do" = "Карточка, текст которой будет переноситься на несколько строк, если я буду продолжать печатать достаточно долго — такой длины должно хватить."; - -/* Information about differences between target range and correction range */ -"A Correction Range is different. This will be a narrower range." = "Диапазон коррекции слишком широкий. Это должен быть более узкий диапазон."; - -/* No comment provided by engineer. */ -"A simple card" = "Простая карта"; - -/* Warning text for basal rate of 0 U/hr */ -"A value of 0 U/hr means you will be scheduled to receive no basal insulin." = "Значение 0 Ед/час означает, что Вы не будете получать базальный инсулин."; - -/* No comment provided by engineer. */ -"Above the save button" = "Над кнопкой сохранения"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Длительность усвоения"; - -/* No comment provided by engineer. */ -"Action Button" = "Кнопка действия"; - -/* The text for the override history duration */ -"Active Duration" = "Активная продолжительность"; - -/* The title for the override emoji activity section */ -"Activity" = "Нагрузка"; - -/* Button text to confirm adding a new schedule item */ -"Add" = "Добавить"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Добавить пользователя"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Добавить запись углеводов"; - -/* Title of insulin model preset - afrezza */ -"Afrezza" = "Afrezza"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Подтвердите удаление всех записей истории?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Подтвердите удаление всех записей резервуара?"; - -/* Authentication hint string for therapy settings */ -"Authenticate to save therapy setting" = "Аутентификация для сохранения настроек терапии"; - -/* Back navigation button title */ -"Back" = "Назад"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Скорости базала"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "База, болюсы и болюсы на коррекцию снижены на%@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "База, болюсы и болюсы на коррекцию увеличены на %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "BБаза, болюсы и болюсы на коррекцию не изменились."; - -/* No comment provided by engineer. */ -"Bottom component" = "Нижний компонент"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Отмена"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Отмена ручного контроля"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Отмена врем базала"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Соотношения углеводов"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Изменения будут действительны только на время ручного контроля."; - -/* Footer text for customizing from a preset (1: preset name) */ -"Changes will only apply this time you enable the preset. The default settings of %@ will not be affected." = "Изменения будут применяться только при включении пресета. Настройки по умолчанию %@ не будут затронуты."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Выберите более высокую длительность усвоения для обильной пищи или для пищи с белками и протеинами. Это единственное указание для алгоритма не нуждается в дополнительных уточнениях."; - -/* Button text to close a modal - Text to close informational page */ -"Close" = "Закрыть"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "В %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "после %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "В %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "после %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Completed." = "Завершено."; - -/* The title for the override emoji condition section */ -"Condition" = "Условие"; - -/* The button text for confirming the setting */ -"Confirm Setting" = "Подтвердить настройки"; - -/* No comment provided by engineer. */ -"content" = "содержание"; - -/* Title of the setup button to continue */ -"Continue" = "Продолжить"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "Диапазон коррекции это желательный диапазон значений ГК для обработки алгоритмом петли."; - -/* Title text for multi-value correction value warning */ -"Correction Values" = "Значения коррекции"; - -/* The text for a custom override */ -"Custom" = "Настраиваемый"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Настраиваемое ручное управление"; - -/* The title for the custom preset entry screen - The title for the custom preset selection screen */ -"Custom Preset" = "Пользовательский пресет"; - -/* Title of the carb entry date picker cell */ -"Date" = "Дата"; - -/* Delete values for Pre-Meal, inactivates Pre-Meal icon - Test for table cell delete button - The title of the button to remove the credentials for a service */ -"Delete" = "Удалить"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Удалить аккаунт"; - -/* Button title to delete all objects */ -"Delete All" = "Стереть все"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Пределы подачи"; - -/* Information about delivery limits */ -"Delivery Limits are safety guardrails for your insulin delivery." = "Пределы подачи - это защита от ввода лишнего инсулина."; - -/* The text for the custom preset disable button */ -"Disable Preset" = "Выключить пресет"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Готово"; - -/* The text for the override duration setting */ -"Duration" = "Продолжительность"; - -/* Text for edit button - The title for the enabled custom preset editing screen */ -"Edit" = "Редактировать"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Редактировать запись углеводов"; - -/* The title for the override editing screen */ -"Edit Override" = "Редактировать ручной контроль"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "Изменения затронут только активную версию. Значения по умолчанию %@ не изменятся."; - -/* Footer text for editing an enabled custom preset (1: preset name) */ -"Edits persist only until the preset is disabled. The default settings of %@ will not be affected." = "Изменения сохраняются только до отключения пресета. Настройки по умолчанию %@ не будут затронуты."; - -/* The button text for enabling a temporary override */ -"Enable" = "Включить"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Активировать на неопределенное время"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Активировано"; - -/* The text for the override start time */ -"End Time" = "Время окончания"; - -/* Format string for accessibility label for value entry. (1: value label) */ -"Enter %1$@ value" = "Введите %1$@ значение"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Введите кол-во единиц"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Введите скорость в ед/час"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "История событий"; - -/* No comment provided by engineer. */ -"Example" = "Пример"; - -/* Section title for fast absorbing food */ -"Fast" = "Быстрая"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Insulin model setting description (1: app name) (2: number of models) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from %2$@ different models for how the app measures the insulin’s peak activity." = "Для быстродействующего инсулина %1$@ предполагается, что он активно работает в течение 6 часов. Вы можете выбрать из %2$@ различных моделей того, как приложение измеряет пиковую активность инсулина."; - -/* Information about correction range format (1: app name) */ -"For this range, choose the specific glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin." = "Для этого диапазона выберите конкретное значение глюкозы (или диапазон значений), к которому вы хотите стремиться %1$@ при корректировке с помощью ВБС."; - -/* Support button for Therapy Settings */ -"Get help with Therapy Settings" = "Получить помощь в настройках терапии"; - -/* Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range - Text for go back action on confirmation alert */ -"Go Back" = "Вернуться назад"; - -/* Title text for the high basal rate warning */ -"High Basal Rate" = "Слишком большая база"; - -/* Title text for the high carb ratio warning */ -"High Carb Ratio" = "Слишком высокое соотношение углеводов"; - -/* Title text for the high correction value warning */ -"High Correction Value" = "Слишком высокая настройка диапазона коррекции"; - -/* Title text for the high glucose safety limit warning */ -"High Glucose Safety Limit" = "Слишком высокий порог безопасности ГК"; - -/* Title text for the high insulin sensitivity warning */ -"High Insulin Sensitivity" = "Слишком высокая чувствительность к инсулину"; - -/* Title text for high maximum basal rate warning */ -"High Maximum Basal Rate" = "Слишком большая максимальная база"; - -/* Title text for high maximum bolus warning */ -"High Maximum Bolus" = "Слишком большой максимальный болюс"; - -/* Title text for the low pre-meal value warning */ -"High Pre-Meal Value" = "Слишком высокая настройка до еды"; - -/* Title text for the high workout value warning */ -"High Workout Value" = "Слишком высокая настройка для физнагрузки"; - -/* The text for the override history */ -"History" = "История"; - -/* Description of how to interact with summary screen */ -"If these settings look good to you, tap Save Settings to continue." = "Если эти настройки вас устраивают, нажмите Сохранить настройки, чтобы продолжить."; - -/* Information about target range */ -"If you've used a CGM before, you're likely familiar with target range as a wide range of values you'd like for your glucose notification alerts, such as 70-180 mg/dL or 90-200 mg/dL." = "Если вы уже пользовались CGM, вы, скорее всего, знакомы с целевым диапазоном как широким диапазоном значений, которые вы хотели бы видеть в уведомлениях о глюкозе, например, 3,9 ммоль/л - 10 ммоль/л или 5 - 11,1 ммоль/л."; - -/* Title text for insulin model */ -"Insulin Model" = "Модель инсулина"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Факторы чувствительности инсулина"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "Чувствительность к инсулину показывает как ГК отреагирует на 1 ед. Инсулина. Меньшие величины означают подачу большего количества инсулина при ГК выше целевой. Слишком низкие величины могут привести к слишком низкой ГК."; - -/* Description of an interrupted bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: programmed value (? if no value), 4: unit) */ -"Interrupted %1$@: %2$@ of %3$@ %4$@" = "Прервано %1$@:%2$@ из %3$@ %4$@"; - -/* Guardrail info text format */ -"It can be set as low as %1$@. It can be set as high as %2$@." = "Его можно установить на уровне %1$@. Он может быть установлен до %2$@."; - -/* Title text for the low basal rate warning */ -"Low Basal Rate" = "Слишком низкая база"; - -/* Title text for the low carb ratio warning */ -"Low Carb Ratio" = "Слишком низкое соотношение углеводов"; - -/* Title text for the low correction value warning */ -"Low Correction Value" = "Слишком низкое значение для коррекции"; - -/* Title text for the low glucose safety limit warning */ -"Low Glucose Safety Limit" = "Слишком низкий предел безопасности ГК"; - -/* Title text for the low insulin sensitivity warning */ -"Low Insulin Sensitivity" = "Низкая чувствительность к инсулину"; - -/* Title text for low maximum basal rate warning */ -"Low Maximum Basal Rate" = "Слишком низкая максимальная база"; - -/* Title text for low maximum bolus warning */ -"Low Maximum Bolus" = "Слишком маленький максимальный болюс"; - -/* Title text for the low pre-meal value warning */ -"Low Pre-Meal Value" = "Слишком низкая настройка до еды"; - -/* Title text for the low workout value warning */ -"Low Workout Value" = "Слишком низкая настрйка для физнагрузки"; - -/* Title of insulin model preset - lyumjev */ -"Lyumjev" = "Lyumjev"; - -/* Placeholder for maximum value in glucose range */ -"max" = "макс"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Максимальная скорость базала"; - -/* Information about maximum basal rate (1: app name) */ -"Maximum Basal Rate is the maximum automatically adjusted basal rate that %1$@ is allowed to enact to help reach your correction range." = "Максимальная базальная скорость - это максимальная базальная скорость, которую %1$@ разрешено использовать для достижения диапазона коррекции в автоматическом режиме."; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Максимальный Болюс"; - -/* Information about maximum bolus (1: app name) */ -"Maximum Bolus is the highest bolus amount that you will allow %1$@ to recommend at one time to cover carbs or bring down high glucose." = "Максимальный болюс - это наибольший размер болюса, котороый вы позволите %1$@ рекомендовать за один раз для покрытия углеводов или снижения высокого уровня глюкозы."; - -/* Section title for medium absorbing food */ -"Medium" = "Средняя"; - -/* Placeholder for minimum value in glucose range */ -"min" = "мин"; - -/* No comment provided by engineer. */ -"more content" = "дополнительное содержание"; - -/* Alert action title to open error help */ -"More Info" = "Доп. инфо"; - -/* The text for the override preset name setting */ -"Name" = "Имя"; - -/* Title for mini-modal to add a new schedule entry */ -"New Entry" = "Новая запись"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Новый параметр"; - -/* Title text for the zero basal rate warning */ -"No Basal Insulin" = "Без базального инсулина"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Другая"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Общая потребность в инсулине"; - -/* Title for override history view */ -"Override History" = "История временных целей"; - -/* The title text for the override presets screen */ -"Override Presets" = "Редактировать параметры"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Редактирование параметров может задаваться в разделе “Конфигурация” экрана настройки."; - -/* The section title of glucose overrides */ -"Overrides" = "Изменить"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "До еды"; - -/* Title text for multi-value pre-meal value warning */ -"Pre-Meal Values" = "Значения до еды"; - -/* title for prescription section */ -"Prescription" = "Рецепт"; - -/* The section header text override presets */ -"PRESETS" = "НАСТРОЙКИ"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Progressing." = "Прогресс."; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Событие помпы"; - -/* Title text for suspend resume button when the basal delivery state is not set */ -"Pump Inoperable" = "Неисправность помпы"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Быстродействующий - взрослые"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Быстродействующий - дети"; - -/* The default placeholder string for a credential */ -"Required" = "обязательный"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Reservoir"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Возобновить подачу"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Возобновляется"; - -/* title for summary description section */ -"Review and Save Settings" = "Просмотр и сохранение настроек"; - -/* Description of how to interact with summary screen */ -"Review your therapy settings below. If you’d like to edit any of these settings, tap Back to go back to that screen." = "Просмотрите настройки терапии ниже. Если вы хотите изменить какие-либо из этих настроек, нажмите Назад"; - -/* The text for the override preset name field placeholder */ -"Running" = "Выполнение"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Сохранить"; - -/* Alert title for confirming basal rates outside the recommended range */ -"Save Basal Rates?" = "Сохранить базальные дозы?"; - -/* Alert title for confirming carb ratios outside the recommended range */ -"Save Carb Ratios?" = "Сохранить соотношение углеводов?"; - -/* Alert title for confirming correction ranges outside the recommended range */ -"Save Correction Range(s)?" = "Сохранить диапазон(ы) коррекции?"; - -/* Alert title for confirming delivery limits outside the recommended range */ -"Save Delivery Limits?" = "Сохранить пределы подачи?"; - -/* Alert title for confirming a glucose safety limit outside the recommended range */ -"Save Glucose Safety Limit?" = "Сохранить безопасный предел глюкозы?"; - -/* Alert title for confirming insulin sensitivities outside the recommended range */ -"Save Insulin Sensitivities?" = "Сохранить чувствительность к инсулину?"; - -/* Alert title for confirming pre-meal range overrides outside the recommended range */ -"Save Pre-Meal Range?" = "Сохранить диапазон до еды?"; - -/* Alert title for confirming workout range overrides outside the recommended range */ -"Save Workout Range?" = "Сохранить диапазон для физнагрузки?"; - -/* The button text during saving on a configuration page */ -"Saving..." = "Сохранение..."; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "ЗАПЛАНИРОВАННОЕ ВЫПОЛНЕНИЕ ИЗМЕНЕНИЙ"; - -/* The section header text for a scheduled custom preset */ -"SCHEDULED PRESET" = "ПРЕДУСТАНОВКА ПО РАСПИСАНИЮ"; - -/* Section title for slow absorbing food */ -"Slow" = "Медленная"; - -/* Information about typical maximum basal rates */ -"Some users choose a value 2, 3, or 4 times their highest scheduled basal rate." = "Некоторые пользователи выбирают значение, в 2, 3 или 4 раза превышающее их самую высокую запланированную базальную скорость."; - -/* The text for the override start time */ -"Start Time" = "Время начала"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Время начала временного базала"; - -/* Format for prescription descriptive text (1: providerName, 2: datePrescribed) */ -"Submitted by %1$@, %2$@" = "Представлено %1$@, %2$@"; - -/* Title for support section */ -"Support" = "Поддержка"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Остановить подачу"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Выполняется остановка"; - -/* No comment provided by engineer. */ -"Switch Preview State" = "Состояние переключателя просмотра"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Значок"; - -/* Text directing the user to configure their first custom preset */ -"Tap '+' to create a new custom preset." = "Нажмите «+», чтобы создать новый пользовательский пресет."; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Щелкнуть для ввода"; - -/* The text for the override target range setting */ -"Target Range" = "Целевой диапазон"; - -/* Description of pre-meal mode */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Временно понизьте целевое значение уровня глюкозы перед едой, чтобы уменьшить пики глюкозы после еды."; - -/* Description of workout mode */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Временно повышайте целевой уровень глюкозы до, во время или после физической активности, чтобы снизить риск развития событий, связанных с низким уровнем глюкозы."; - -/* The title for the override selection screen */ -"Temporary Override" = "Временный"; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"than your Correction Range." = "чем ваш диапазон коррекции."; - -/* Description for selection when no insulin type is selected. */ -"The currently selected fast acting insulin model will be used as a default." = "Выбранная в данный момент модель быстродействующего инсулина будет использоваться по умолчанию."; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Устаревшая модель, используемая Loop, позволяющая настраивать продолжительность действия."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "Максимальная длительность усвоения %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "Максимальное допустимое количество %@ грамм"; - -/* Information about adult insulin model */ -"The rapid-acting adult model assumes peak activity at 75 minutes." = "Быстродействующая взрослая модель предполагает пик активности через 75 минут."; - -/* Information about child insulin model */ -"The rapid-acting child model assumes peak activity at 65 minutes." = "Быстродействующая детская модель предполагает пиковую активность через 65 минут."; - -/* Information about basal rate scheduling */ -"The schedule starts at midnight and cannot contain a rate of 0 U/hr." = "Расписание начинается в полночь и не может содержать скорость 0 Ед/ч."; - -/* Therapy Settings screen title */ -"Therapy Settings" = "Настройки терапии"; - -/* No comment provided by engineer. */ -"Therapy Settings Support Placeholder" = "Заполнитель поддержки настроек терапии"; - -/* Subtitle of afrezza preset */ -"This model assumes peak insulin activity at 19 minutes." = "Эта модель предполагает пик активности инсулина на 19 минуте."; - -/* Subtitle of Fiasp preset - Subtitle of Lyumjev preset */ -"This model assumes peak insulin activity at 55 minutes." = "Эта модель предполагает пик активности инсулина на 55 минуте."; - -/* Subtitle of Rapid-Acting – Children preset */ -"This model assumes peak insulin activity at 65 minutes." = "Эта модель предполагает пик активности инсулина на 65 минуте."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"This model assumes peak insulin activity at 75 minutes." = "Эта модель предполагает пик активности инсулина на 75 минуте."; - -/* Information about maximum automated insulin on board (1: app name) */ -"This setting will also determine a safety limit for automatic dosing. %1$@ will limit automatic delivery to keep the amount of active insulin below twice your maximum bolus." = "Эта настройка также определяет предел безопасности для автоматического введения инсулина. %1$@ ограничит автоматический ввод инсулина, чтобы количество активного инсулина не превышало удвоенного максимального болюса."; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"This will typically be" = "Как правило, это "; - -/* Label for offset from midnight picker */ -"Time" = "Время"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Хронометраж %1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"To be implemented" = "Будет применено"; - -/* No comment provided by engineer. */ -"Top component" = "Верхний компонент"; - -/* The text indicating Total for Daily Schedule Basal */ -"Total" = "Всего"; - -/* The text indicating U/day for Daily Schedule Basal */ -"U/day" = "Ед/сутки"; - -/* The unit string for units per hour */ -"U/hour" = "ед/ч"; - -/* Alert title when error occurs while saving a schedule */ -"Unable to Save" = "Невозможно сохранить"; - -/* The unit string for units */ -"Units" = "Единицы"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Неизвестно"; - -/* Title for selection when no insulin type is selected. */ -"Unset" = "Не выбрано"; - -/* Placeholder text until value is entered */ -"Value" = "Значение"; - -/* Label indicating validation is occurring */ -"Verifying" = "Верифицируется"; - -/* The title for the override editing screen */ -"View Override" = "Просмотреть оверрайд"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Предостережение"; - -/* Disclaimer */ -"Work with your healthcare provider to choose a value that is higher than your highest scheduled basal rate, but as conservative or aggressive as you feel comfortable." = "Вместе с вашим лечащим врачом выберите значение, которое будет выше, чем ваша самая высокая запланированная база, но на столько, на сколько вам удобно."; - -/* Title for the workout override range */ -"Workout" = "Физическая нагрузка"; - -/* Title text for multi-value workout value warning */ -"Workout Values" = "Настройки физнагрузок"; - -/* Description of how to add a ratio */ -"You can add different carb ratios for different times of day by using the ➕." = "Вы можете добавлять различные соотношения углеводов для разного времени суток с помощью ➕."; - -/* Description of how to add a ratio */ -"You can add different insulin sensitivities for different times of day by using the ➕." = "Вы можете добавить различные показатели чувствительности к инсулину для разного времени суток с помощью кнопки ➕."; - -/* Description of how to add a configuration range */ -"You can add different ranges for different times of day by using the ➕." = "Вы можете добавить различные диапазоны для разного времени суток с помощью кнопки ➕."; - -/* Description of how to add a range */ -"You can add entries for different times of day by using the ➕." = "Можно добавлять записи для разного времени суток с помощью кнопки ➕."; - -/* Information about insulin model (1: app name) */ -"You can choose how %1$@ measures rapid acting insulin's peak activity according to one of these two insulin models." = "Вы можете выбрать, как %1$@ измеряет пиковую активность быстродействующего инсулина в соответствии с одной из этих двух моделей инсулина."; - -/* Description of how to edit setting */ -"You can edit a setting by tapping into any line item." = "Вы можете изменить настройку, коснувшись самой строки."; - -/* Description of how to edit setting */ -"You can edit the setting by tapping into the line item." = "Вы можете изменить настройку, коснувшись самой строки."; - -/* Information about basal rates */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Ваша базальная норма инсулина - это количество единиц в час, которое вы хотите использовать для покрытия своих фоновых потребностей в инсулине."; - -/* Lower bound pre-meal information text */ -"your Glucose Safety Limit" = "Ваш безопасный предел ГК"; - -/* Disclaimer */ -"Your healthcare provider can help you choose a Correction Range that's right for you." = "Ваш лечащий врач поможет вам выбрать подходящий для Вас диапазон коррекции."; - -/* Description of insulin sensitivity factor */ -"Your Insulin Sensitivity Factor (ISF) is the drop in glucose expected from one unit of insulin." = "Ваш фактор чувствительности к инсулину (ISF) - это снижение уровня глюкозы, ожидаемое от одной единицы инсулина."; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/sk.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/sk.lproj/InsulinKit.strings deleted file mode 100644 index 3bd552b9b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/sk.lproj/InsulinKit.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Názov"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Rezervoár"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Podávanie inzulínu"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/sk.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/sk.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 3bd552b9b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/sk.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Názov"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Rezervoár"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Podávanie inzulínu"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/sk.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/sk.lproj/Localizable.strings deleted file mode 100644 index b0d2613a6..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/sk.lproj/Localizable.strings +++ /dev/null @@ -1,88 +0,0 @@ -/* Separator between min and max glucose values */ -"-" = "-"; - -/* Appends a full-stop to a statement */ -"%@." = "%@ ."; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@ j"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ jednotiek zostávajúcich na %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* The title for the override emoji activity section */ -"Activity" = "Aktivita"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Pridať účet"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Zadať sacharidy"; - -/* Back navigation button title */ -"Back" = "Späť"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Bazálne dávky"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Zrušiť"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Inzulínovo sacharidový pomer"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* Title of the setup button to continue */ -"Continue" = "Pokračovať"; - -/* Title of the carb entry date picker cell */ -"Date" = "Dátum"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Odstrániť účet"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Limity podávania"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Hotovo"; - -/* Title text for insulin model */ -"Insulin Model" = "Inzulínový model"; - -/* The text for the override preset name setting */ -"Name" = "Názov"; - -/* The default placeholder string for a credential */ -"Required" = "Povinné"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Rezervoár"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Uložiť"; - -/* The button text during saving on a configuration page */ -"Saving..." = "Ukladá sa..."; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Ťuknutím nastavte"; - -/* Label for offset from midnight picker */ -"Time" = "Čas"; - -/* The unit string for units */ -"Units" = "jednotky"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Neznáme"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/sv.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/sv.lproj/InsulinKit.strings deleted file mode 100644 index 8379cc014..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/sv.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoar"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Händelsehistorik"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Non-Pump Insulin"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/sv.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/sv.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index e3478b9b9..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/sv.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoar"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Händelsehistorik"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/sv.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/sv.lproj/Localizable.strings deleted file mode 100644 index 87a3ec062..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/sv.lproj/Localizable.strings +++ /dev/null @@ -1,679 +0,0 @@ -/* Information about workout range relative to correction range */ -" higher " = " högre "; - -/* Information about pre-meal range relative to correction range */ -" lower " = " lägre "; - -/* Separator between min and max glucose values */ -"-" = "-"; - -/* No comment provided by engineer. */ -"-" = "-"; - -/* The detail text representing no value */ -"–" = "–"; - -/* No comment provided by engineer. */ -"···" = "···"; - -/* No comment provided by engineer. */ -"%@" = "%@"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% of normal insulin"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Lower bound workout information text format (1: app name) */ -"%1$@ or your Glucose Safety Limit, whichever is higher" = "%1$@ eller ditt Tröskelvärde, beroende på vilket som är högst"; - -/* Reservoir entry (1: volume value) */ -"%1$@ U" = "%1$@ E"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ enheter återstår kl. %2$@"; - -/* Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) - Description of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) */ -"%1$@: %2$@ %3$@" = "%1$@: %2$@ %3$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"🍽" = "🍽"; - -/* Premeal override preset title */ -"🍽 Pre-Meal" = "🍽 Före måltid"; - -/* No comment provided by engineer. */ -"🏃‍♂️" = "🏃‍♂️"; - -/* Workout override preset title */ -"🏃‍♂️ Workout" = "🏃‍♂️ Träning"; - -/* No comment provided by engineer. */ -"A card whose text will wrap onto multiple lines if I continue to type for long enough—this length should do" = "Ett kort vars text kommer att hamna på flera rader om jag fortsätter att skriva tillräckligt länge - denna längd bör räcka"; - -/* Information about differences between target range and correction range */ -"A Correction Range is different. This will be a narrower range." = "Detta målvärde är annorlunda än det du är van vid. Detta är ett snävare intervall."; - -/* No comment provided by engineer. */ -"A simple card" = "Ett enkelt kort"; - -/* Warning text for basal rate of 0 U/hr */ -"A value of 0 U/hr means you will be scheduled to receive no basal insulin." = "Ett värde på 0 / h innebär att du inte kommer få någon basal insulintillförsel."; - -/* No comment provided by engineer. */ -"Above the save button" = "Ovanför spara-knappen"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Absorptionstid"; - -/* No comment provided by engineer. */ -"Action Button" = "Åtgärdsknapp"; - -/* The text for the override history duration */ -"Active Duration" = "Aktiv varaktighet"; - -/* The title for the override emoji activity section */ -"Activity" = "Aktivitet"; - -/* Button text to confirm adding a new schedule item */ -"Add" = "Lägg till"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Lägg till konto"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Lägg till kolhydrater"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Säkert att du vill radera all händelsehistorik?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Säkert att du vill radera alla reservoarvärden?"; - -/* Authentication hint string for therapy settings */ -"Authenticate to save therapy setting" = "Autentisera för att spara behandlingsinställningar"; - -/* Back navigation button title */ -"Back" = "Tillbaka"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Basaldoser"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Basal, bolus, och korrigeringsdoser är minskade med %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Basal, bolus, och korrigeringsdoser är ökade med %@%%"; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Basal, bolus, och korrigeringsdoser är oförändrade."; - -/* No comment provided by engineer. */ -"Bottom component" = "Nedre komponent"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Avbryt"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Avbryt Override"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Avbryt temporär basal"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Insulinkvoter"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Ändringarna kommer endast att utföras denna gång du använder override. De ordinarie inställingarna på %@ kommer inte att påverkas. "; - -/* Footer text for customizing from a preset (1: preset name) */ -"Changes will only apply this time you enable the preset. The default settings of %@ will not be affected." = "Ändringarna kommer endast att gälla denna gång du använder undantag. De ordinarie inställningarna på %@ kommer inte att påverkas."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Välj en längre absorptionstid för måltid med mycket fett eller protein. Ofta är det bäst att dela upp måltiden i snabba och långsamma kolhydrater och mata in dessa var för sig."; - -/* Button text to close a modal - Text to close informational page */ -"Close" = "Stäng"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "kl %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "sedan %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "kl %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "sedan %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Completed." = "Klart."; - -/* The title for the override emoji condition section */ -"Condition" = "Tillstånd"; - -/* The button text for confirming the setting */ -"Confirm Setting" = "Bekräfta inställning"; - -/* No comment provided by engineer. */ -"content" = "innehåll"; - -/* Title of the setup button to continue */ -"Continue" = "Fortsätt"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "Målvärden är det blodglukosintervall du vill att Loop ska korrigera blodsockret till."; - -/* Title text for multi-value correction value warning */ -"Correction Values" = "Målvärden"; - -/* The text for a custom override */ -"Custom" = "Anpassad"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Anpassad Override"; - -/* The title for the custom preset entry screen - The title for the custom preset selection screen */ -"Custom Preset" = "Anpassad förinställning"; - -/* Title of the carb entry date picker cell */ -"Date" = "Tid"; - -/* Delete values for Pre-Meal, inactivates Pre-Meal icon - Test for table cell delete button - The title of the button to remove the credentials for a service */ -"Delete" = "Ta bort"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Radera konto"; - -/* Button title to delete all objects */ -"Delete All" = "Radera allt"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Maxdoser"; - -/* Information about delivery limits */ -"Delivery Limits are safety guardrails for your insulin delivery." = "Maxdoser är säkerhetsgränser för din insulintillförsel."; - -/* The text for the custom preset disable button */ -"Disable Preset" = "Inaktivera förval"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Färdig"; - -/* The text for the override duration setting */ -"Duration" = "Duration"; - -/* Text for edit button - The title for the enabled custom preset editing screen */ -"Edit" = "Ändra"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Ändra kolhydrater"; - -/* The title for the override editing screen */ -"Edit Override" = "Ändra Override"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "Ändringar ändrar endast aktiv Override. De ordinarie inställningarna på %@ kommer inte att påverkas"; - -/* Footer text for editing an enabled custom preset (1: preset name) */ -"Edits persist only until the preset is disabled. The default settings of %@ will not be affected." = "Ändringar gäller endast tills förinställningen är inaktiverad. Standardinställningarna för %@ påverkas inte."; - -/* The button text for enabling a temporary override */ -"Enable" = "Aktivera"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Sätt på oändligt"; - -/* The detail text describing an enabled setting */ -"Enabled" = "På"; - -/* The text for the override start time */ -"End Time" = "Sluttid"; - -/* Format string for accessibility label for value entry. (1: value label) */ -"Enter %1$@ value" = "Ange %1$@värde"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Ange antal eheter"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Ange värde i enheter per timme"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Händelsehistorik"; - -/* No comment provided by engineer. */ -"Example" = "Exempel"; - -/* Section title for fast absorbing food */ -"Fast" = "Snabb"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Insulin model setting description (1: app name) (2: number of models) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from %2$@ different models for how the app measures the insulin’s peak activity." = "Får snabbverkande insulin, antar %1$@ ett insulin med 6 timmars verkan. Du kan välja mellan %2$@ olika modeller för hur appen mäter insulinets maximala aktivitet."; - -/* Information about correction range format (1: app name) */ -"For this range, choose the specific glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin." = "För detta intervall ska du välja det blodsockervärde (eller det målvärdesintervall) som du vill att %1$@ ska sträva efter genom justering av basalinsulin."; - -/* Support button for Therapy Settings */ -"Get help with Therapy Settings" = "Få hjälp med behandlingsinställningar"; - -/* Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range - Text for go back action on confirmation alert */ -"Go Back" = "Gå tillbaka"; - -/* Title text for the high basal rate warning */ -"High Basal Rate" = "Hög basaldos"; - -/* Title text for the high carb ratio warning */ -"High Carb Ratio" = "Hög insulinkvot"; - -/* Title text for the high correction value warning */ -"High Correction Value" = "Högt målvärde"; - -/* Title text for the high glucose safety limit warning */ -"High Glucose Safety Limit" = "Säkerhetsgräns för högt blodsocker"; - -/* Title text for the high insulin sensitivity warning */ -"High Insulin Sensitivity" = "Hög insulinkänslighet"; - -/* Title text for high maximum basal rate warning */ -"High Maximum Basal Rate" = "Hög maximal basaldos"; - -/* Title text for high maximum bolus warning */ -"High Maximum Bolus" = "Hög maximal bolus"; - -/* Title text for the low pre-meal value warning */ -"High Pre-Meal Value" = "Högt värde före måltid"; - -/* Title text for the high workout value warning */ -"High Workout Value" = "Högt träningsvärde"; - -/* The text for the override history */ -"History" = "Historik"; - -/* Description of how to interact with summary screen */ -"If these settings look good to you, tap Save Settings to continue." = "Om inställningarna ser bra ut, tryck på Spara inställningar för att fortsätta."; - -/* Information about target range */ -"If you've used a CGM before, you're likely familiar with target range as a wide range of values you'd like for your glucose notification alerts, such as 70-180 mg/dL or 90-200 mg/dL." = "Om du använt en CGM tidigare är du förmodligen van vid ett brett målvärdesintervall för varningsnotiser, som 70-180 mg/dl eller 90-200 mg/dl."; - -/* Title text for insulin model */ -"Insulin Model" = "Insulinmodell"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Insulinkänslighet"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "Insulinkänslighet beskriver hur ditt blodglukos svarar på 1 enhet insulin.Mindre värden innebär att mer insulin kommer att ges när över målvärde. Värden som är för små kan orsaka farligt lågt blodsocker. "; - -/* Description of an interrupted bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: programmed value (? if no value), 4: unit) */ -"Interrupted %1$@: %2$@ of %3$@ %4$@" = "Avbruten %1$@: %2$@ av %3$@ %4$@"; - -/* Guardrail info text format */ -"It can be set as low as %1$@. It can be set as high as %2$@." = "Det kan ställas in så lågt som %1$@. Det kan ställas in så högt som %2$@."; - -/* Title text for the low basal rate warning */ -"Low Basal Rate" = "Låg basaldos"; - -/* Title text for the low carb ratio warning */ -"Low Carb Ratio" = "Låg insulinkvot"; - -/* Title text for the low correction value warning */ -"Low Correction Value" = "Lågt målvärde"; - -/* Title text for the low glucose safety limit warning */ -"Low Glucose Safety Limit" = "Säkerhetsgräns för lågt blodsocker"; - -/* Title text for the low insulin sensitivity warning */ -"Low Insulin Sensitivity" = "Låg insulinkänslighet"; - -/* Title text for low maximum basal rate warning */ -"Low Maximum Basal Rate" = "Låg maximal basaldos"; - -/* Title text for low maximum bolus warning */ -"Low Maximum Bolus" = "Låg maximal bolus"; - -/* Title text for the low pre-meal value warning */ -"Low Pre-Meal Value" = "Lågt värde före måltid"; - -/* Title text for the low workout value warning */ -"Low Workout Value" = "Lågt träningsvärde"; - -/* Placeholder for maximum value in glucose range */ -"max" = "max"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Maximal basaldos"; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Maximal bolus"; - -/* Section title for medium absorbing food */ -"Medium" = "Medium"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* No comment provided by engineer. */ -"more content" = "mer innehåll"; - -/* Alert action title to open error help */ -"More Info" = "Mer info"; - -/* The text for the override preset name setting */ -"Name" = "Namn"; - -/* Title for mini-modal to add a new schedule entry */ -"New Entry" = "Ny post"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Ny förinställning"; - -/* Title text for the zero basal rate warning */ -"No Basal Insulin" = "Inget basalinsulin"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Annan"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Totalt insulinbehov"; - -/* Title for override history view */ -"Override History" = "Historik av Undantag"; - -/* The title text for the override presets screen */ -"Override Presets" = "Override förinställningar"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Override förinställningar kan ställas in under ‘Konfiguration’ i menyn inställningar."; - -/* The section title of glucose overrides */ -"Overrides" = "Overrides"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Före måltid"; - -/* Title text for multi-value pre-meal value warning */ -"Pre-Meal Values" = "Värden för 'Före måltid'"; - -/* title for prescription section */ -"Prescription" = "Recept"; - -/* The section header text override presets */ -"PRESETS" = "FÖRINSTÄLLNINGAR"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Progressing." = "Behandlas."; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Pumphändelse"; - -/* Title text for suspend resume button when the basal delivery state is not set */ -"Pump Inoperable" = "Pump obrukbar"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Snabbverkande – vuxna"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Snabbverkande – barn"; - -/* The default placeholder string for a credential */ -"Required" = "Krävs"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Reservoar"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Återuppta insulindosering"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Återupptar"; - -/* title for summary description section */ -"Review and Save Settings" = "Granska och spara inställningar"; - -/* Description of how to interact with summary screen */ -"Review your therapy settings below. If you’d like to edit any of these settings, tap Back to go back to that screen." = "Granska dina behandlingsinställningar nedan. Om du behöver ändra någon av dessa, tryck Tillbaka för att gå tillbaka till det fönstret."; - -/* The text for the override preset name field placeholder */ -"Running" = "Löpning"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Spara"; - -/* Alert title for confirming basal rates outside the recommended range */ -"Save Basal Rates?" = "Spara basaldoser?"; - -/* Alert title for confirming carb ratios outside the recommended range */ -"Save Carb Ratios?" = "Spara insulinkvoter?"; - -/* Alert title for confirming correction ranges outside the recommended range */ -"Save Correction Range(s)?" = "Spara målvärde(n)?"; - -/* Alert title for confirming delivery limits outside the recommended range */ -"Save Delivery Limits?" = "Spara Maxdoser?"; - -/* Alert title for confirming a glucose safety limit outside the recommended range */ -"Save Glucose Safety Limit?" = "Spara tröskelvärde för blodsocker?"; - -/* Alert title for confirming insulin sensitivities outside the recommended range */ -"Save Insulin Sensitivities?" = "Spara insulinkänslighet?"; - -/* Alert title for confirming pre-meal range overrides outside the recommended range */ -"Save Pre-Meal Range?" = "Spara intervall för 'Före måltid'?"; - -/* Alert title for confirming workout range overrides outside the recommended range */ -"Save Workout Range?" = "Spara målvärde för träning?"; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "SCHEMALAGD OVERRIDE"; - -/* The section header text for a scheduled custom preset */ -"SCHEDULED PRESET" = "SCHEMALAGD FÖRINSTÄLLNING"; - -/* Section title for slow absorbing food */ -"Slow" = "Långsam"; - -/* Information about typical maximum basal rates */ -"Some users choose a value 2, 3, or 4 times their highest scheduled basal rate." = "Vissa användare väljer ett värde 2, 3 eller 4 gånger sin högsta schemalagda basaldos."; - -/* The text for the override start time */ -"Start Time" = "Starttid"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Börjar temporär basal"; - -/* Format for prescription descriptive text (1: providerName, 2: datePrescribed) */ -"Submitted by %1$@, %2$@" = "Skickad av %1$@, %2$@"; - -/* Title for support section */ -"Support" = "Support"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Pausa insulintillförsel"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Pausar"; - -/* No comment provided by engineer. */ -"Switch Preview State" = "Byt förhandsvisningsläge"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Symbol"; - -/* Text directing the user to configure their first custom preset */ -"Tap '+' to create a new custom preset." = "Tryck på '+' för att skapa en ny anpassad förinställning."; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Klicka för att ange"; - -/* The text for the override target range setting */ -"Target Range" = "Målvärden"; - -/* Description of pre-meal mode */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Sänker tillfälligt ditt målvärde före en måltid för att motverka postprandiella hyperglykemier (stegrade blodsocker efter en måltid)."; - -/* Description of workout mode */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Höj tillfälligt ditt målvärde före, under eller efter fysisk aktivitet för att minska risken för låga blodsockervärden."; - -/* The title for the override selection screen */ -"Temporary Override" = "Temporär Override"; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"than your Correction Range." = "än ditt målvärde."; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Äldre modell använd av Loop, vilken tillåter anpassning av insulinets verkningstid."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "Maximala absorptionstiden är %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "Maximala mängd är %@ gram"; - -/* Information about adult insulin model */ -"The rapid-acting adult model assumes peak activity at 75 minutes." = "Den snabbverkande vuxenmodellen antar en maximal aktivitet vid 75 minuter."; - -/* Information about child insulin model */ -"The rapid-acting child model assumes peak activity at 65 minutes." = "Den snabbverkande vuxenmodellen antar en maximal aktivitet vid 65 minuter."; - -/* Information about basal rate scheduling */ -"The schedule starts at midnight and cannot contain a rate of 0 U/hr." = "Schemat startar vid midnatt och får inte innehålla en dos på 0 E/timme."; - -/* Therapy Settings screen title */ -"Therapy Settings" = "Behandlingsinställningar"; - -/* No comment provided by engineer. */ -"Therapy Settings Support Placeholder" = "Behandlingsinställningar Support"; - -/* Subtitle of Fiasp preset - Subtitle of Lyumjev preset */ -"This model assumes peak insulin activity at 55 minutes." = "Denna modell antar en maximal aktivitet vid 55 minuter."; - -/* Subtitle of Rapid-Acting – Children preset */ -"This model assumes peak insulin activity at 65 minutes." = "Denna modell antar en maximal aktivitet vid 65 minuter."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"This model assumes peak insulin activity at 75 minutes." = "Denna modell antar en maximal aktivitet vid 75 minuter."; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"This will typically be" = "Detta kommer vanligtvis att vara"; - -/* Label for offset from midnight picker */ -"Time" = "Tid"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Tid i %1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"To be implemented" = "Att bli implementerat"; - -/* No comment provided by engineer. */ -"Top component" = "Översta komponenten"; - -/* The unit string for units per hour */ -"U/hour" = "E/timme"; - -/* Alert title when error occurs while saving a schedule */ -"Unable to Save" = "Kunde inte spara"; - -/* The unit string for units */ -"Units" = "Eheter"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Okänd"; - -/* Placeholder text until value is entered */ -"Value" = "Värde"; - -/* Label indicating validation is occurring */ -"Verifying" = "Verifierar"; - -/* The title for the override editing screen */ -"View Override" = "Visa Undantag"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Varning"; - -/* Disclaimer */ -"Work with your healthcare provider to choose a value that is higher than your highest scheduled basal rate, but as conservative or aggressive as you feel comfortable." = "Rådgör med din vårdgivare för att bestämma ett värde som är högre än din högsta schemalagda basaldos, men så konservativ eller aggressiv som du känner dig bekväm med."; - -/* Title for the workout override range */ -"Workout" = "Träning"; - -/* Information about workout range format (1: app name) */ -"Workout Range is the glucose value or range of values you want %1$@ to target during activity. This range will be in effect when you activate the Workout Preset button." = "Målvärde för träning är det blodsocker eller det målvärdesintervall som du vill att %1$@ ska använda under fysik aktivitet. Detta målvärde används när du aktiverar knappen 'Träningsförval'."; - -/* Title text for multi-value workout value warning */ -"Workout Values" = "Träningsärden"; - -/* Description of how to add a ratio */ -"You can add different carb ratios for different times of day by using the ➕." = "Du kan lägga till olika insulinkvoter för olika tider på dagen med hjälp av ➕."; - -/* Description of how to add a ratio */ -"You can add different insulin sensitivities for different times of day by using the ➕." = "Du kan lägga till olika värden för insulinkänslighet för olika tider på dagen med hjälp av ➕."; - -/* Description of how to add a configuration range */ -"You can add different ranges for different times of day by using the ➕." = "Du kan lägga till olika målvärden för olika tider på dagen med hjälp av ➕."; - -/* Description of how to add a range */ -"You can add entries for different times of day by using the ➕." = "Du kan lägga till inmatningar för olika tider på dagen med hjälp av ➕."; - -/* Description of how to edit setting */ -"You can edit a setting by tapping into any line item." = "Du kan ändra en inställning genom att trycka på ett objekt på en av raderna."; - -/* Description of how to edit setting */ -"You can edit the setting by tapping into the line item." = "Du kan ändra en inställning genom att trycka på ett objekt på raden."; - -/* Information about basal rates */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Din bassaldos är det antal enheter insulin per timme som krävs för din basala ämnesomsättning."; - -/* Lower bound pre-meal information text */ -"your Glucose Safety Limit" = "säkerhetsgräns för blodsocker"; - -/* Disclaimer */ -"Your healthcare provider can help you choose a Correction Range that's right for you." = "Din vårdgivare kan hjälpa dig att välja ett målvärde som passar dig."; - -/* Description of insulin sensitivity factor */ -"Your Insulin Sensitivity Factor (ISF) is the drop in glucose expected from one unit of insulin." = "Insulinkänslighet (ISF) är ett mått på hur många enheter din blodsocker sjunker av en enhet insulin."; - -/* Information about pre-meal range format (1: app name) */ -"Your Pre-Meal Range should be the glucose value (or range of values) you want %1$@ to target by the time you take your first bite of your meal. This range will be in effect when you activate the Pre-Meal Preset button." = "Ditt målvärde för 'Före måltid' ska vara det blodsockervärde (eller målvärdesintervall) som du vill att %1$@ ska sikta på när du tar din första tugga av din måltid. Detta målvärde kommer börja gälla när du aktiverar knappen 'Före måltid'."; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/tr.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/tr.lproj/InsulinKit.strings deleted file mode 100644 index da7b4951e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/tr.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Başlık"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detay"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "Ü AİNS"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "Yapılandırılmış pompa yok"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "Ü Toplam"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Rezervuar"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Etkinlik Geçmişi"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Pompasız İnsülin"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "İnsulin İletimi"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/tr.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/tr.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 449b89de0..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/tr.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Başlık"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detay"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "Ü AİNS"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "Yapılandırılmış pompa yok"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "Ü Toplam"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Rezervuar"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Etkinlik Geçmişi"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "İnsulin İletimi"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/tr.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/tr.lproj/Localizable.strings deleted file mode 100644 index cc73a2421..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/tr.lproj/Localizable.strings +++ /dev/null @@ -1,691 +0,0 @@ -/* Information about workout range relative to correction range */ -" higher " = " daha yüksek "; - -/* Information about pre-meal range relative to correction range */ -" lower " = " daha düşük "; - -/* Separator between min and max glucose values */ -"-" = "-"; - -/* No comment provided by engineer. */ -"-" = "-"; - -/* The detail text representing no value */ -"–" = "–"; - -/* No comment provided by engineer. */ -"···" = "···"; - -/* No comment provided by engineer. */ -"%@" = "%@"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% normal insulin"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@Ü"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Lower bound workout information text format (1: app name) */ -"%1$@ or your Glucose Safety Limit, whichever is higher" = "%1$@ veya KŞ Güvenlik Limitiniz, hangisi daha yüksekse"; - -/* Reservoir entry (1: volume value) */ -"%1$@ U" = "%1$@ Ü"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ ünite kaldı %2$@"; - -/* Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) - Description of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit) */ -"%1$@: %2$@ %3$@" = "%1$@: %2$@ %3$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"🍽" = "🍽"; - -/* Premeal override preset title */ -"🍽 Pre-Meal" = "🍽 Yemek Öncesi"; - -/* No comment provided by engineer. */ -"🏃‍♂️" = "🏃‍♂️"; - -/* Workout override preset title */ -"🏃‍♂️ Workout" = "🏃‍♂️ Egzersiz"; - -/* Information about differences between target range and correction range */ -"A Correction Range is different. This will be a narrower range." = "Düzeltme Aralığı farklıdır. Bu daha dar bir aralık olacaktır."; - -/* Warning text for basal rate of 0 U/hr */ -"A value of 0 U/hr means you will be scheduled to receive no basal insulin." = "0 Ü/saat değeri, bazal insülin almayacağınız anlamına gelir."; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Emilim Süresi"; - -/* No comment provided by engineer. */ -"Action Button" = "Eylem Butonu"; - -/* The text for the override history duration */ -"Active Duration" = "Aktif Süre"; - -/* The title for the override emoji activity section */ -"Activity" = "Aktivite"; - -/* Button text to confirm adding a new schedule item */ -"Add" = "Ekle"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Hesap Ekle"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Karb Girişi Ekle"; - -/* Title of insulin model preset - afrezza */ -"Afrezza" = "Afrezza"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Tüm geçmiş girişlerini silmek istediğinizden emin misiniz?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Tüm rezervuar değerlerini silmek istediğinizden emin misiniz?"; - -/* Authentication hint string for therapy settings */ -"Authenticate to save therapy setting" = "Tedavi ayarını kaydetmek için kimlik doğrulama"; - -/* Back navigation button title */ -"Back" = "Geri"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Bazal Oranlar"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Bazal, bolus ve düzeltme insülin doz miktarları %@%% azaltılır."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Bazal, bolus ve düzeltme insülin doz miktarları %@%% oranında artırılır."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Bazal, bolus ve düzeltme insülin doz miktarları etkilenmez."; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "İptal"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Geçersiz Kılma İptal"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Geçici Bazalı İptal Et"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Karbonhidrat Oranları"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Değişiklikler yalnızca geçersiz kılmayı etkinleştirdiğiniz bu sefer uygulanacaktır. %@ varsayılan ayarları etkilenmeyecektir."; - -/* Footer text for customizing from a preset (1: preset name) */ -"Changes will only apply this time you enable the preset. The default settings of %@ will not be affected." = "Değişiklikler yalnızca ön ayarı bu kez etkinleştirdiğinizde geçerli olacaktır. Varsayılan %@ ayarları etkilenmeyecektir."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Daha büyük öğünler veya yağ ve protein içeren besinler için daha uzun bir emilim süresi seçin. Bu değer yalnızca algoritmaya rehberlik eder ve kesin olması gerekmez."; - -/* Button text to close a modal - Text to close informational page */ -"Close" = "Kapat"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "%1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "%1$@ den beri"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "%1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "%1$@ den beri"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "Tamam"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Completed." = "Tamamlandı."; - -/* The title for the override emoji condition section */ -"Condition" = "Kondisyon"; - -/* The button text for confirming the setting */ -"Confirm Setting" = "Ayarı Onaylayın"; - -/* No comment provided by engineer. */ -"content" = "içerik"; - -/* Title of the setup button to continue */ -"Continue" = "Devam et"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "Düzeltme aralığı, Loop'un düzeltmesini istediğiniz kan şekeri aralığıdır."; - -/* Title text for multi-value correction value warning */ -"Correction Values" = "Düzeltme Değerleri"; - -/* The text for a custom override */ -"Custom" = "Özel"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Özel Geçersiz kılma"; - -/* The title for the custom preset entry screen - The title for the custom preset selection screen */ -"Custom Preset" = "Özel Ön Ayar"; - -/* Title of the carb entry date picker cell */ -"Date" = "Tarih"; - -/* Delete values for Pre-Meal, inactivates Pre-Meal icon - Test for table cell delete button - The title of the button to remove the credentials for a service */ -"Delete" = "Sil"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Hesabı sil"; - -/* Button title to delete all objects */ -"Delete All" = "Hepsini sil"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "İletim Limitleri"; - -/* Information about delivery limits */ -"Delivery Limits are safety guardrails for your insulin delivery." = "İletim Limitleri, insülin iletiminiz için güvenlik korkuluklarıdır."; - -/* The text for the custom preset disable button */ -"Disable Preset" = "Ön Ayarı Devre Dışı Bırak"; - -/* Text for dismiss button - Text for done button - Video player done button label */ -"Done" = "Tamamlandı"; - -/* The text for the override duration setting */ -"Duration" = "Süre"; - -/* Text for edit button - The title for the enabled custom preset editing screen */ -"Edit" = "Düzenle"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Karb Girişini Düzenle"; - -/* The title for the override editing screen */ -"Edit Override" = "Geçersiz Kılmayı Düzenle"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "Düzenleme yalnızca etkin geçersiz kılmayı etkiler. %@ varsayılan ayarlar etkilenmeyecektir."; - -/* Footer text for editing an enabled custom preset (1: preset name) */ -"Edits persist only until the preset is disabled. The default settings of %@ will not be affected." = "Düzenlemeler yalnızca ön ayar devre dışı bırakılana kadar devam eder. %@ varsayılan ayarları etkilenmeyecektir."; - -/* The button text for enabling a temporary override */ -"Enable" = "Etkinleştir"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Süresiz Olarak Etkinleştir"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Etkin"; - -/* The text for the override start time */ -"End Time" = "Bitiş zamanı"; - -/* Format string for accessibility label for value entry. (1: value label) */ -"Enter %1$@ value" = "%1$@ değer girin"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Ünite değeri girin"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Her saat için ünite oranı girin"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Etkinlik Geçmişi"; - -/* No comment provided by engineer. */ -"Example" = "Örnek"; - -/* Section title for fast absorbing food */ -"Fast" = "Hızlı"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Insulin model setting description (1: app name) (2: number of models) */ -"For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from %2$@ different models for how the app measures the insulin’s peak activity." = "Hızlı etkili insülin için, %1$@ 6 saat boyunca aktif olarak çalıştığını varsayar. Uygulamanın insülinin en yüksek etkisini nasıl ölçtüğüne ilişkin %2$@ farklı model arasından seçim yapabilirsiniz."; - -/* Information about correction range format (1: app name) */ -"For this range, choose the specific glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin." = "Bu aralık için, %1$@ bazal insülininizi ayarlarken hedeflemesini istediğiniz belirli KŞ değerini (veya değer aralığını) seçin."; - -/* Support button for Therapy Settings */ -"Get help with Therapy Settings" = "Tedavi Ayarları ile ilgili yardım alın"; - -/* Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range - Text for go back action on confirmation alert */ -"Go Back" = "Geri dön"; - -/* Title text for the high basal rate warning */ -"High Basal Rate" = "Yüksek Bazal Oran"; - -/* Title text for the high carb ratio warning */ -"High Carb Ratio" = "Yüksek Karb Oranı"; - -/* Title text for the high correction value warning */ -"High Correction Value" = "Yüksek Düzeltme Değeri"; - -/* Title text for the high glucose safety limit warning */ -"High Glucose Safety Limit" = "Yüksek KŞ Güvenlik Limiti"; - -/* Title text for the high insulin sensitivity warning */ -"High Insulin Sensitivity" = "Yüksek İnsülin Duyarlılığı"; - -/* Title text for high maximum basal rate warning */ -"High Maximum Basal Rate" = "Yüksek Maksimum Bazal Oranı"; - -/* Title text for high maximum bolus warning */ -"High Maximum Bolus" = "Yüksek Maksimum Bolus"; - -/* Title text for the low pre-meal value warning */ -"High Pre-Meal Value" = "Yüksek Yemek Öncesi Değeri"; - -/* Title text for the high workout value warning */ -"High Workout Value" = "Yüksek Egzersiz Değeri"; - -/* The text for the override history */ -"History" = "Geçmiş"; - -/* Description of how to interact with summary screen */ -"If these settings look good to you, tap Save Settings to continue." = "Bu ayarlar size uygun görünüyorsa, devam etmek için Ayarları Kaydet'e dokunun."; - -/* Information about target range */ -"If you've used a CGM before, you're likely familiar with target range as a wide range of values you'd like for your glucose notification alerts, such as 70-180 mg/dL or 90-200 mg/dL." = "Daha önce bir CGM kullandıysanız, KŞ bildirim uyarılarınız için 70-180 mg/dL veya 90-200 mg/dL gibi geniş bir hedef aralığına aşinasınızdır."; - -/* Title text for insulin model */ -"Insulin Model" = "İnsülin Modeli"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "İnsülin Duyarlılığı"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "İnsülin duyarlılığı, (İDF) kan şekerinizin 1 Ünite insülin dozuna nasıl tepki vermesi gerektiğini tanımlar. Daha küçük değerler, hedefin üzerindeyken daha fazla insülin verileceği anlamına gelir. Çok küçük değerler tehlikeli derecede düşük kan şekerine neden olabilir."; - -/* Description of an interrupted bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: programmed value (? if no value), 4: unit) */ -"Interrupted %1$@: %2$@ of %3$@ %4$@" = "%1$@ kesintiye uğradı: %3$@ %4$@'nın %2$@ 'si"; - -/* Guardrail info text format */ -"It can be set as low as %1$@. It can be set as high as %2$@." = "%1$@ kadar düşük bir değere ayarlanabilir. %2$@ kadar yükseğe ayarlanabilir."; - -/* Title text for the low basal rate warning */ -"Low Basal Rate" = "Düşük Bazal Oran"; - -/* Title text for the low carb ratio warning */ -"Low Carb Ratio" = "Düşük Karb Oranı"; - -/* Title text for the low correction value warning */ -"Low Correction Value" = "Düşük Düzeltme Değeri"; - -/* Title text for the low glucose safety limit warning */ -"Low Glucose Safety Limit" = "Düşük KŞ Güvenlik Limiti"; - -/* Title text for the low insulin sensitivity warning */ -"Low Insulin Sensitivity" = "Düşük İnsülin Duyarlılığı"; - -/* Title text for low maximum basal rate warning */ -"Low Maximum Basal Rate" = "Düşük Maksimum Bazal Oranı"; - -/* Title text for low maximum bolus warning */ -"Low Maximum Bolus" = "Düşük Maksimum Bolus"; - -/* Title text for the low pre-meal value warning */ -"Low Pre-Meal Value" = "Düşük Yemek Öncesi Değer"; - -/* Title text for the low workout value warning */ -"Low Workout Value" = "Düşük Egzersiz Değeri"; - -/* Title of insulin model preset - lyumjev */ -"Lyumjev" = "Lyumjev"; - -/* Placeholder for maximum value in glucose range */ -"max" = "maks"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Maksimum Bazal Oranı"; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Maksimum Bolus"; - -/* Section title for medium absorbing food */ -"Medium" = "Orta"; - -/* Placeholder for minimum value in glucose range */ -"min" = "min"; - -/* No comment provided by engineer. */ -"more content" = "daha fazla içerik"; - -/* Alert action title to open error help */ -"More Info" = "Daha fazla bilgi"; - -/* The text for the override preset name setting */ -"Name" = "İsim"; - -/* Title for mini-modal to add a new schedule entry */ -"New Entry" = "Yeni giriş"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Yeni Ön Ayar"; - -/* Title text for the zero basal rate warning */ -"No Basal Insulin" = "Bazal İnsülin Yok"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Diğer"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Genel İnsülin İhtiyaçları"; - -/* Title for override history view */ -"Override History" = "Geçmişi geçersiz kılma"; - -/* The title text for the override presets screen */ -"Override Presets" = "Geçersiz Kılma Ön Ayarları"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Geçersiz kılma ön ayarları, ayarlar ekranının 'Konfigürsayon' bölümü altında ayarlanabilir."; - -/* The section title of glucose overrides */ -"Overrides" = "Geçersiz kılmalar"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Yemek öncesi"; - -/* Title text for multi-value pre-meal value warning */ -"Pre-Meal Values" = "Yemek Öncesi Değerler"; - -/* title for prescription section */ -"Prescription" = "Reçete"; - -/* The section header text override presets */ -"PRESETS" = "ÖN AYARLAR"; - -/* Accessibility label for ProgressIndicatorView when showIndeterminantProgress */ -"Progressing." = "İlerliyor."; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Pompa Etkinliği"; - -/* Title text for suspend resume button when the basal delivery state is not set */ -"Pump Inoperable" = "Pompa Çalışmıyor"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Hızlı Etkili – Yetişkinler"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Hızlı Etkili – Çocuklar"; - -/* The default placeholder string for a credential */ -"Required" = "Gerekli"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Rezervuar"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "İletimi Devam Ettir"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Devam ediyor"; - -/* title for summary description section */ -"Review and Save Settings" = "Ayarları Gözden Geçir ve Kaydet"; - -/* Description of how to interact with summary screen */ -"Review your therapy settings below. If you’d like to edit any of these settings, tap Back to go back to that screen." = "Aşağıdaki tedavi ayarlarınızı gözden geçirin. Bu ayarlardan herhangi birini düzenlemek isterseniz, o ekrana geri dönmek için Geri'ye dokunun."; - -/* The text for the override preset name field placeholder */ -"Running" = "Çalışıyor"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Kaydet"; - -/* Alert title for confirming basal rates outside the recommended range */ -"Save Basal Rates?" = "Bazal Oranlar Kaydedilsin mi?"; - -/* Alert title for confirming carb ratios outside the recommended range */ -"Save Carb Ratios?" = "Karb Oranlarını Kaydet?"; - -/* Alert title for confirming correction ranges outside the recommended range */ -"Save Correction Range(s)?" = "Düzeltme Aralığı/Aralıkları Kaydedilsin mi?"; - -/* Alert title for confirming delivery limits outside the recommended range */ -"Save Delivery Limits?" = "İletim Limitleri Kaydedilsin mi?"; - -/* Alert title for confirming a glucose safety limit outside the recommended range */ -"Save Glucose Safety Limit?" = "KŞ Güvenlik Limiti Kaydedilsin mi?"; - -/* Alert title for confirming insulin sensitivities outside the recommended range */ -"Save Insulin Sensitivities?" = "İnsülin Hassasiyeti Kaydedilsin mi?"; - -/* Alert title for confirming pre-meal range overrides outside the recommended range */ -"Save Pre-Meal Range?" = "Yemek Öncesi Aralığı Kaydedilsin mi?"; - -/* Alert title for confirming workout range overrides outside the recommended range */ -"Save Workout Range?" = "Egzersiz Aralığını Kaydet?"; - -/* The button text during saving on a configuration page */ -"Saving..." = "Kaydediliyor..."; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "PLANLANMIŞ GEÇERSİZ KILMA"; - -/* The section header text for a scheduled custom preset */ -"SCHEDULED PRESET" = "PLANLANMIŞ ÖN AYAR"; - -/* Section title for slow absorbing food */ -"Slow" = "Yavaş"; - -/* Information about typical maximum basal rates */ -"Some users choose a value 2, 3, or 4 times their highest scheduled basal rate." = "Bazı kullanıcılar, planlanan en yüksek bazal oranının 2, 3 veya 4 katı bir değer seçer."; - -/* The text for the override start time */ -"Start Time" = "Başlangıç zamanı"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Geçici Bazal başlatılıyor"; - -/* Format for prescription descriptive text (1: providerName, 2: datePrescribed) */ -"Submitted by %1$@, %2$@" = "%2$@, %1$@ tarafından gönderildi"; - -/* Title for support section */ -"Support" = "Destek"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "İletimi Askıya Al"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Askıya alınıyor"; - -/* No comment provided by engineer. */ -"Switch Preview State" = "Önizleme Durumunu Değiştir"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Sembol"; - -/* Text directing the user to configure their first custom preset */ -"Tap '+' to create a new custom preset." = "Yeni bir özel ön ayar oluşturmak için '+' düğmesine dokunun."; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Ayarlamak için dokunun"; - -/* The text for the override target range setting */ -"Target Range" = "Hedef Aralığı"; - -/* Description of pre-meal mode */ -"Temporarily lower your glucose target before a meal to impact post-meal glucose spikes." = "Yemek sonrası KŞ artışlarını engellemek için yemekten önce KŞ hedefinizi geçici olarak düşürün."; - -/* Description of workout mode */ -"Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events." = "Düşük KŞ riskini azaltmak için fiziksel aktivite öncesinde, sırasında veya sonrasında KŞ hedefinizi geçici olarak yükseltin."; - -/* The title for the override selection screen */ -"Temporary Override" = "Geçici Geçersiz Kılma"; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"than your Correction Range." = "düzeltme Aralığınızdan daha fazla."; - -/* Description for selection when no insulin type is selected. */ -"The currently selected fast acting insulin model will be used as a default." = "Şu anda seçili olan hızlı etkili insülin modeli varsayılan olarak kullanılacaktır."; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Loop tarafından kullanılan ve eylem süresinin özelleştirilmesine izin veren eski model."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "Maksimum emilim süresi %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "İzin verilen maksimum miktar %@ gramdır"; - -/* Information about adult insulin model */ -"The rapid-acting adult model assumes peak activity at 75 minutes." = "Hızlı etkili yetişkin modeli, 75 dakikada en yüksek etkiyi varsayar."; - -/* Information about child insulin model */ -"The rapid-acting child model assumes peak activity at 65 minutes." = "Hızlı etkili çocuk modeli, 65 dakikada en yüksek etkiyi varsayar."; - -/* Information about basal rate scheduling */ -"The schedule starts at midnight and cannot contain a rate of 0 U/hr." = "Program gece yarısı başlar ve 0 Ü/sa bir oran içeremez."; - -/* Therapy Settings screen title */ -"Therapy Settings" = "Tedavi Ayarları"; - -/* No comment provided by engineer. */ -"Therapy Settings Support Placeholder" = "Tedavi Ayarları Destek Yer Tutucusu"; - -/* Subtitle of afrezza preset */ -"This model assumes peak insulin activity at 19 minutes." = "Bu model, 19. dakikada en yüksek insülin aktivitesini varsayar."; - -/* Subtitle of Fiasp preset - Subtitle of Lyumjev preset */ -"This model assumes peak insulin activity at 55 minutes." = "Bu model, 55. dakikada en yüksek insülin aktivitesini varsayar."; - -/* Subtitle of Rapid-Acting – Children preset */ -"This model assumes peak insulin activity at 65 minutes." = "Bu model, 65 dakikada en yüksek insülin aktivitesini varsayar."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"This model assumes peak insulin activity at 75 minutes." = "Bu model, 75 dakikada en yüksek insülin aktivitesini varsayar."; - -/* Information about pre-meal range relative to correction range - Information about workout range relative to correction range */ -"This will typically be" = "Bu genellikle şu şekilde olacaktır"; - -/* Label for offset from midnight picker */ -"Time" = "Zaman"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Saat dilimi %1$@%2$@%3$@"; - -/* No comment provided by engineer. */ -"To be implemented" = "Uygulanacak"; - -/* No comment provided by engineer. */ -"Top component" = "Üst bileşen"; - -/* The text indicating Total for Daily Schedule Basal */ -"Total" = "Toplam"; - -/* The text indicating U/day for Daily Schedule Basal */ -"U/day" = "Ü/gün"; - -/* The unit string for units per hour */ -"U/hour" = "Ü/saat"; - -/* Alert title when error occurs while saving a schedule */ -"Unable to Save" = "Kaydedilemiyor"; - -/* The unit string for units */ -"Units" = "Ünite"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Bilinmeyen"; - -/* Title for selection when no insulin type is selected. */ -"Unset" = "Ayarlanmamış"; - -/* Placeholder text until value is entered */ -"Value" = "Değer"; - -/* Label indicating validation is occurring */ -"Verifying" = "Doğrulanıyor"; - -/* The title for the override editing screen */ -"View Override" = "Geçersiz Kılmayı Görüntüle"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Uyarı"; - -/* Disclaimer */ -"Work with your healthcare provider to choose a value that is higher than your highest scheduled basal rate, but as conservative or aggressive as you feel comfortable." = "Planlanan en yüksek bazal oranınızdan daha yüksek, ancak kendinizi rahat hissettiğiniz ölçüde tutucu veya agresif bir değer seçmek için sağlık uzmanınızla birlikte çalışın."; - -/* Title for the workout override range */ -"Workout" = "Egzersiz"; - -/* Information about workout range format (1: app name) */ -"Workout Range is the glucose value or range of values you want %1$@ to target during activity. This range will be in effect when you activate the Workout Preset button." = "Egzersiz Aralığı, aktivite sırasında %1$@ değerinin hedeflenmesini istediğiniz KŞ değeri veya değer aralığıdır. Bu aralık, Egzersiz Ön Ayarı butonunu etkinleştirdiğinizde geçerli olacaktır."; - -/* Title text for multi-value workout value warning */ -"Workout Values" = "Egzersiz Değerleri"; - -/* Description of how to add a ratio */ -"You can add different carb ratios for different times of day by using the ➕." = "➕ butonunu kullanarak günün farklı saatleri için farklı karbonhidrat oranları ekleyebilirsiniz."; - -/* Description of how to add a ratio */ -"You can add different insulin sensitivities for different times of day by using the ➕." = "➕ butonunu kullanarak günün farklı saatleri için farklı insülin duyarlılıkları ekleyebilirsiniz."; - -/* Description of how to add a configuration range */ -"You can add different ranges for different times of day by using the ➕." = "➕ butonunu kullanarak günün farklı saatleri için farklı aralıklar ekleyebilirsiniz."; - -/* Description of how to add a range */ -"You can add entries for different times of day by using the ➕." = "➕ butonunu kullanarak günün farklı saatleri için girişler ekleyebilirsiniz."; - -/* Description of how to edit setting */ -"You can edit a setting by tapping into any line item." = "Herhangi bir satır öğesine dokunarak bir ayarı düzenleyebilirsiniz."; - -/* Description of how to edit setting */ -"You can edit the setting by tapping into the line item." = "Satır öğesine dokunarak ayarı düzenleyebilirsiniz."; - -/* Information about basal rates */ -"Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs." = "Bazal İnsülin Oranınız, arka plan insülin ihtiyaçlarınızı karşılamak için kullanmak istediğiniz saat başına ünite miktarıdır."; - -/* Lower bound pre-meal information text */ -"your Glucose Safety Limit" = "KŞ Güvenlik Limitiniz"; - -/* Disclaimer */ -"Your healthcare provider can help you choose a Correction Range that's right for you." = "Sağlık uzmanınız sizin için doğru olan Düzeltme Aralığını seçmenize yardımcı olabilir."; - -/* Description of insulin sensitivity factor */ -"Your Insulin Sensitivity Factor (ISF) is the drop in glucose expected from one unit of insulin." = "İnsülin Duyarlılık faktörünüz (İDF), bir ünite insülinden beklenen KŞ düşüşünü ifade eder."; - -/* Information about pre-meal range format (1: app name) */ -"Your Pre-Meal Range should be the glucose value (or range of values) you want %1$@ to target by the time you take your first bite of your meal. This range will be in effect when you activate the Pre-Meal Preset button." = "Yemek Öncesi Aralığınız, yemeğinizden ilk lokmanızı aldığınız zaman %1$@ 'un hedeflemesini istediğiniz KŞ değeri (veya değer aralığı) olmalıdır. Bu aralık, Yemek Öncesi Ön Ayar butonunu etkinleştirdiğinizde etkin olacaktır."; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/vi.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/vi.lproj/InsulinKit.strings deleted file mode 100644 index cb3cba99e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/vi.lproj/InsulinKit.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Event History"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[2] = "Non-Pump Insulin"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[2]" = "Non-Pump Insulin"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/vi.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/vi.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 64e6c3284..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/vi.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Event History"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/vi.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/vi.lproj/Localizable.strings deleted file mode 100644 index 9be07067f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/vi.lproj/Localizable.strings +++ /dev/null @@ -1,295 +0,0 @@ -/* The detail text representing no value */ -"–" = "—"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% của insulin bình thường"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit) */ -"%1$@ – %2$@ %3$@" = "%1$@ – %2$@ %3$@"; - -/* The format for an override preset cell. (1: symbol)(2: name) - The format for an override symbol and name (1: symbol)(2: name) */ -"%1$@ %2$@" = "%1$@ %2$@"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units vẫn đang còn lúc %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "Thời gian Hấp thụ"; - -/* The title for the override emoji activity section */ -"Activity" = "Hoạt động"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Thêm Tài khoản"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "Khai báo Carb"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "Bạn có chắc muốn xóa hết các dữ liệu cũ?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "Bạn có chắc muốn xóa hết mọi giá trị của ngăn chứa insulin?"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "Lịch biểu tiêm liều nền"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "Liều Basal, bolus, và liều bổ sung đang giảm bằng %@%%."; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "Liều Basal, bolus, và liều bổ sung đang tăng bằng %@%%."; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "Liều Basal, bolus, và liều bổ sung không bị thay đổi."; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Hủy bỏ"; - -/* The text for the override cancellation button */ -"Cancel Override" = "Hủy Chồng liều"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Đang hủy liều Basal tạm thời"; - -/* Title text for multi-value carb ratio warning */ -"Carb Ratios" = "Carb Ratios"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "Các thay đổi sẽ chỉ áp dụng thời điểm này khi bạn cho phép chồng liều. Các cài đặt gốc %@ sẽ không bị ảnh hưởng."; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "Lựa chọn khoảng thời gian tiêu hóa dài hơn cho các bữa ăn no, hoặc những bữa ăn nhiều chất béo và protein. Đây chỉ là hướng dẫn cho thuật toán Algorithm và không cần phải chính xác."; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "lúc %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "từ lúc %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "lúc %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "từ lúc %1$@"; - -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - -/* The title for the override emoji condition section */ -"Condition" = "Điều kiện"; - -/* Title of the setup button to continue */ -"Continue" = "Tiếp tục"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "Phạm vi điều chỉnh là phạm vi của đường huyết mà bạn muốn Loop hướng đến."; - -/* The text for a custom override */ -"Custom" = "Thói quen"; - -/* The title for the custom override entry screen */ -"Custom Override" = "Thói quen Chồng liều"; - -/* Title of the carb entry date picker cell */ -"Date" = "Ngày"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Xóa Tài khoản"; - -/* Button title to delete all objects */ -"Delete All" = "Xóa hết"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "Giới hạn liều tiêm"; - -/* The text for the override duration setting */ -"Duration" = "Khoảng thời gian"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "Chỉnh sửa Carb"; - -/* The title for the override editing screen */ -"Edit Override" = "Hiệu chỉnh chồng liều"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "Việc hiệu chỉnh chỉ ảnh hưởng đến chồng liều đang hoạt động. Các cài đặt gốc của %@ sẽ không bị ảnh hưởng."; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "Cấp phép không giới hạn"; - -/* The detail text describing an enabled setting */ -"Enabled" = "Được cấp quyền"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "Nhập số lượng của đơn vị/units"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "Nhập tỉ lệ của đơn vị/units trên giờ"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "Event History"; - -/* Section title for fast absorbing food */ -"Fast" = "Nhanh"; - -/* Title of insulin model preset - fiasp */ -"Fiasp" = "Fiasp"; - -/* Title text for insulin model */ -"Insulin Model" = "Chủng loại Insulin"; - -/* Title text for multi-value insulin sensitivity warning */ -"Insulin Sensitivities" = "Độ nhạy của Insulin"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "Độ nhạy của Insulin biểu thị đường huyết của bạn phản ứng với 1 unit insulin. Giá trị phản ứng nhỏ hơn nghĩa là bạn cần thêm insulin để đạt mục tiêu ở trên. Các giá trị quá nhỏ có thể dẫn đến tình trạng hạ đường huyết nghiêm trọng."; - -/* Placeholder for maximum value in glucose range */ -"max" = "tối đa"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "Lượng Basal tối đa"; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "Liều Bolus tối đa"; - -/* Section title for medium absorbing food */ -"Medium" = "Trung bình"; - -/* Placeholder for minimum value in glucose range */ -"min" = "tối thiểu"; - -/* Alert action title to open error help */ -"More Info" = "Thêm thông tin"; - -/* The text for the override preset name setting */ -"Name" = "Tên"; - -/* The title for the new override preset entry screen */ -"New Preset" = "Cài đặt mới"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "Khác"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "Nhu cầu Insulin tổng thể"; - -/* The title text for the override presets screen */ -"Override Presets" = "Cài đặt chồng liều"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "Cài đặt chồng liều có thể được khai báo dưới mục 'Configuration' của phần cấu hình."; - -/* The section title of glucose overrides */ -"Overrides" = "Chồng liều"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "Trước bữa ăn"; - -/* The section header text override presets */ -"PRESETS" = "CÀI ĐẶT SĂN"; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "Pump Event"; - -/* Title of insulin model preset - rapid acting adult */ -"Rapid-Acting – Adults" = "Thuốc tác động nhanh cho người lớn"; - -/* Title of insulin model preset - rapid acting children */ -"Rapid-Acting – Children" = "Thuốc tác động nhanh cho trẻ em"; - -/* The default placeholder string for a credential */ -"Required" = "Bắt buộc"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "Reservoir"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Tiếp tục lại việc tiêm insulin"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Đang tiếp tục lại"; - -/* The text for the override preset name field placeholder */ -"Running" = "Đang chạy"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "Lưu"; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "SCHEDULED OVERRIDE"; - -/* Section title for slow absorbing food */ -"Slow" = "chậm"; - -/* The text for the override start time */ -"Start Time" = "Giờ bắt đầu"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Đang bắt đầu liều Basal tạm thời"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Tạm ngưng liều insulin"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Đang tạm ngưng"; - -/* The text for the override preset symbol setting */ -"Symbol" = "Symbol"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Chạm để cài đặt"; - -/* The text for the override target range setting */ -"Target Range" = "Phạm vi Mục tiêu"; - -/* The title for the override selection screen */ -"Temporary Override" = "Chồng liều tạm thời"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Mô hình cũ được Loop sử dụng, cho phép tùy chỉnh thời lượng hành động."; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "Thời gian tiêu hóa tối đa là %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "Khối lượng cho phép tối đa là %@ grams"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "Thời gian trong %1$@%2$@%3$@"; - -/* The unit string for units per hour */ -"U/hour" = "U/giờ"; - -/* The unit string for units */ -"Units" = "Units"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "Không nhận ra"; - -/* Label indicating validation is occurring */ -"Verifying" = "Đang kiểm tra"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - -/* Title of an alert containing a validation warning */ -"Warning" = "Cảnh báo"; - -/* Title for the workout override range */ -"Workout" = "Workout"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/zh-Hans.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/Resources/zh-Hans.lproj/InsulinKit.strings deleted file mode 100644 index af69ddf95..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/zh-Hans.lproj/InsulinKit.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "标题"; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "详情"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "单位 活性胰岛素"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "没有泵配置"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "单位 总计"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "胰岛素容量"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "历史事件"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "已输注胰岛素"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/zh-Hans.lproj/LegacyInsulinDeliveryTableViewController.strings b/Dependencies/LoopKit/LoopKitUI/Resources/zh-Hans.lproj/LegacyInsulinDeliveryTableViewController.strings deleted file mode 100644 index 251c7e700..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/zh-Hans.lproj/LegacyInsulinDeliveryTableViewController.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Tutal"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "胰岛素容量"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "历史事件"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; - diff --git a/Dependencies/LoopKit/LoopKitUI/Resources/zh-Hans.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/Resources/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index c60f7f6f1..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Resources/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,258 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The format for an insulin needs percentage. */ -"%@%% of normal insulin" = "%@%% 胰岛素"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Title of the carb entry absorption time cell */ -"Absorption Time" = "吸收时间"; - -/* The title for the override emoji activity section */ -"Activity" = "活动"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "添加账户"; - -/* The title of the view controller to create a new carb entry */ -"Add Carb Entry" = "添加碳水"; - -/* Action sheet confirmation message for pump history deletion */ -"Are you sure you want to delete all history entries?" = "确定要删除所有输入的历史数据吗?"; - -/* Action sheet confirmation message for reservoir deletion */ -"Are you sure you want to delete all reservoir values?" = "确定要删除所有的储药器数据吗?"; - -/* Title text for multi-value basal rate warning */ -"Basal Rates" = "基础率"; - -/* Describes a percentage decrease in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are decreased by %@%%." = "基础率,大剂量及追加剂量将以%@%%减少"; - -/* Describes a percentage increase in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are increased by %@%%." = "基础率,大剂量及追加剂量将以%@%%增加"; - -/* Describes a lack of change in overall insulin needs */ -"Basal, bolus, and correction insulin dose amounts are unaffected." = "基础率,大剂量及追加剂量将不受该设置影响"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "取消"; - -/* The text for the override cancellation button */ -"Cancel Override" = "取消覆盖"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "取消临时基础率"; - -/* Footer text for customizing an override from a preset (1: preset name) */ -"Changes will only apply this time you enable the override. The default settings of %@ will not be affected." = "将仅会在启用时覆盖该设置,默认设置%@ 不受影响"; - -/* Carb entry section footer text explaining absorption time */ -"Choose a longer absorption time for larger meals, or those containing fats and proteins. This is only guidance to the algorithm and need not be exact." = "如果吃大餐请选择比较长的吸收时间,或者是以脂肪和蛋白为主的食物。该设置仅为算法的一般原则,具体请根据自身情况调整"; - -/* The format string describing the date of a COB value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.COBDateLabel" = "在 %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.CarbKit.totalDateLabel" = "自从 %1$@"; - -/* The format string describing the date of an IOB value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.IOBDateLabel" = "在 %1$@"; - -/* The format string describing the starting date of a total value. The first format argument is the localized date. */ -"com.loudnate.InsulinKit.totalDateLabel" = "自从 %1$@"; - -/* The title for the override emoji condition section */ -"Condition" = "条件"; - -/* Title of the setup button to continue */ -"Continue" = "继续"; - -/* The section footer of correction range schedule */ -"Correction range is the blood glucose range that you would like Loop to correct to." = "校正范围指Loop系统会主动调整胰岛素输注并将血糖保持在该范围内"; - -/* The text for a custom override */ -"Custom" = "自定义"; - -/* The title for the custom override entry screen */ -"Custom Override" = "自定义覆盖"; - -/* Title of the carb entry date picker cell */ -"Date" = "日期"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "删除账户"; - -/* Button title to delete all objects */ -"Delete All" = "删除所有"; - -/* Title text for crossed thresholds guardrail warning */ -"Delivery Limits" = "输注限制"; - -/* The text for the override duration setting */ -"Duration" = "持续时间"; - -/* The title of the view controller to edit an existing carb entry */ -"Edit Carb Entry" = "编辑碳水"; - -/* The title for the override editing screen */ -"Edit Override" = "编辑新设置"; - -/* Footer text for editing an active override (1: preset name) */ -"Editing affects only the active override. The default settings of %@ will not be affected." = "编辑仅会影响正在使用的“覆盖”设置,默认设置%@不受影响"; - -/* The text for the indefinite override duration setting */ -"Enable Indefinitely" = "一直使用"; - -/* The detail text describing an enabled setting */ -"Enabled" = "已启用"; - -/* The placeholder text instructing users how to enter a maximum bolus */ -"Enter a number of units" = "输入单位量"; - -/* The placeholder text instructing users how to enter a maximum basal rate */ -"Enter a rate in units per hour" = "输入每小时基础率"; - -/* Segmented button title for insulin delivery log event history */ -"Event History" = "历史事件"; - -/* Section title for fast absorbing food */ -"Fast" = "快速"; - -/* The description shown on the insulin sensitivity schedule interface. */ -"Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose." = "胰岛素敏感系数指每单位胰岛素可以造成的血糖变化.比较小的值意味着当血糖高于目标时需要更多的胰岛素,如果该值设置太小可能会造成严重低血糖,请谨慎设置该参数"; - -/* Placeholder for maximum value in glucose range */ -"max" = "最大"; - -/* The title text for the maximum basal rate value */ -"Maximum Basal Rate" = "最大基础率限制"; - -/* The title text for the maximum bolus value */ -"Maximum Bolus" = "最大大剂量限制"; - -/* Section title for medium absorbing food */ -"Medium" = "中等"; - -/* Placeholder for minimum value in glucose range */ -"min" = "分钟"; - -/* Alert action title to open error help */ -"More Info" = "更多信息"; - -/* The text for the override preset name setting */ -"Name" = "名称"; - -/* The title for the new override preset entry screen */ -"New Preset" = "新配置"; - -/* Section title for no-carb food - The title for override emoji miscellaneous section */ -"Other" = "其他"; - -/* The title text for the insulin sensitivity scaling setting */ -"Overall Insulin Needs" = "全部胰岛素需要"; - -/* The title text for the override presets screen */ -"Override Presets" = "覆盖预设值"; - -/* Text directing the user to configure override presets */ -"Override presets can be set up under the 'Configuration' section of the settings screen." = "覆盖预设置可以通过”设置”的”配置”来完成"; - -/* The section title of glucose overrides */ -"Overrides" = "覆盖"; - -/* Title for the pre-meal override range */ -"Pre-Meal" = "餐前模式"; - -/* The section header text override presets */ -"PRESETS" = "预设"; - -/* The title of the screen displaying a pump event */ -"Pump Event" = "胰岛素泵事件"; - -/* The default placeholder string for a credential */ -"Required" = "需要"; - -/* Segmented button title for insulin delivery log reservoir history */ -"Reservoir" = "胰岛素容量"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "恢复输注"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "恢复中"; - -/* The text for the override preset name field placeholder */ -"Running" = "运行中"; - -/* Button text for saving glucose correction range schedule - Button text for saving insulin sensitivity schedule */ -"Save" = "保存"; - -/* The section header text for a scheduled override */ -"SCHEDULED OVERRIDE" = "计划覆盖"; - -/* Section title for slow absorbing food */ -"Slow" = "慢"; - -/* The text for the override start time */ -"Start Time" = "启动时间"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "启动临时寄出"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "暂停输注"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "正在暂停"; - -/* The text for the override preset symbol setting */ -"Symbol" = "符号"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "点击设置"; - -/* The text for the override target range setting */ -"Target Range" = "目标范围"; - -/* The title for the override selection screen */ -"Temporary Override" = "临时覆盖"; - -/* Alert body displayed absorption time greater than max (1: maximum absorption time) */ -"The maximum absorption time is %@" = "最大吸收时间为 %@"; - -/* Alert body displayed for quantity greater than max (1: maximum quantity in grams) */ -"The maximum allowed amount is %@ grams" = "允许的最大量为 %@ g"; - -/* The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval) */ -"Times in %1$@%2$@%3$@" = "时间 %1$@%2$@%3$@"; - -/* The unit string for units per hour */ -"U/hour" = "单位/小时"; - -/* The unit string for units */ -"Units" = "单位"; - -/* Accessibility value for an unknown value - The default title to use when an entry has none */ -"Unknown" = "未知"; - -/* Label indicating validation is occurring */ -"Verifying" = "验证"; - -/* Title of an alert containing a validation warning */ -"Warning" = "警告"; - -/* Title for the workout override range */ -"Workout" = "锻炼/运动模式"; - diff --git a/Dependencies/LoopKit/LoopKitUI/ServiceAuthenticationUI.swift b/Dependencies/LoopKit/LoopKitUI/ServiceAuthenticationUI.swift deleted file mode 100644 index e4a56ea18..000000000 --- a/Dependencies/LoopKit/LoopKitUI/ServiceAuthenticationUI.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// ServiceAuthenticationUI.swift -// LoopKitUI -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import LoopKit - - -public protocol ServiceAuthenticationUI: ServiceAuthentication { - // The indexed credentials (e.g. username, password) used to authenticate - var credentialFormFields: [ServiceCredential] { get } - //Form field helper text displayed when completing form - var credentialFormFieldHelperMessage: String? { get } -} - - -public extension ServiceAuthenticationUI { - var credentials: [(field: ServiceCredential, value: String?)] { - return zip(credentialFormFields, credentialValues).map { (field, value) in - return (field: field, value: value) - } - } - - func resetCredentials() { - for (index, field) in credentialFormFields.enumerated() { - credentialValues[index] = field.options?.first?.value - } - - reset() - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/ServiceCredential.swift b/Dependencies/LoopKit/LoopKitUI/ServiceCredential.swift deleted file mode 100644 index 39f42acf0..000000000 --- a/Dependencies/LoopKit/LoopKitUI/ServiceCredential.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// ServiceCredential.swift -// Loop -// -// Created by Nate Racklyeft on 7/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -/// Represents the input method for a service credential -public struct ServiceCredential { - /// The localized title of the credential (e.g. "Username") - public let title: String - - /// The localized placeholder text to assist text input - public let placeholder: String? - - /// Whether the credential is considered secret. Correponds to the `secureTextEntry` trait. - public let isSecret: Bool - - /// The type of keyboard to use to enter the credential - public let keyboardType: UIKeyboardType - - /// A set of valid values for presenting a selection. The first item is the default. - public let options: [(title: String, value: String)]? - - public init(title: String, placeholder: String? = nil, isSecret: Bool, keyboardType: UIKeyboardType = .asciiCapable, options: [(title: String, value: String)]? = nil) { - self.title = title - self.placeholder = placeholder - self.isSecret = isSecret - self.keyboardType = keyboardType - self.options = options - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/ServiceUI.swift b/Dependencies/LoopKit/LoopKitUI/ServiceUI.swift deleted file mode 100644 index 2be6caeec..000000000 --- a/Dependencies/LoopKit/LoopKitUI/ServiceUI.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// ServiceUI.swift -// LoopKitUI -// -// Created by Darin Krauss on 5/17/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - -public struct ServiceDescriptor { - public let identifier: String - public let localizedTitle: String - - public init(identifier: String, localizedTitle: String) { - self.identifier = identifier - self.localizedTitle = localizedTitle - } -} - -public typealias ServiceViewController = (UIViewController & ServiceOnboarding & CompletionNotifying) - -public protocol ServiceUI: Service { - /// The image for this type of service. - static var image: UIImage? { get } - - /// Create and onboard a new service. - /// - /// - Parameters: - /// - colorPalette: Color palette to use for any UI. - /// - Returns: Either a conforming view controller to create and onboard the service or a newly created and onboarded service. - static func setupViewController(colorPalette: LoopUIColorPalette, pluginHost: PluginHost) -> SetupUIResult - - /// Configure settings for an existing service. - /// - /// - Parameters: - /// - colorPalette: Color palette to use for any UI. - /// - Returns: A view controller to configure an existing service. - func settingsViewController(colorPalette: LoopUIColorPalette) -> ServiceViewController -} - -public extension ServiceUI { - var image: UIImage? { return type(of: self).image } -} - -public protocol ServiceOnboardingDelegate: AnyObject { - /// Informs the delegate that the specified service was created. - /// - /// - Parameters: - /// - service: The service created. - func serviceOnboarding(didCreateService service: Service) - - /// Informs the delegate that the specified service was onboarded. - /// - /// - Parameters: - /// - service: The service onboarded. - func serviceOnboarding(didOnboardService service: Service) -} - -public protocol ServiceOnboarding { - /// Delegate to notify about service onboarding. - var serviceOnboardingDelegate: ServiceOnboardingDelegate? { get set } -} diff --git a/Dependencies/LoopKit/LoopKitUI/SetupUIResult.swift b/Dependencies/LoopKit/LoopKitUI/SetupUIResult.swift deleted file mode 100644 index 8d89f5fb4..000000000 --- a/Dependencies/LoopKit/LoopKitUI/SetupUIResult.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// SetupUIResult.swift -// LoopKitUI -// -// Created by Darin Krauss on 1/21/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -public enum SetupUIResult { - case userInteractionRequired(UserInteractionRequired) - case createdAndOnboarded(CreatedAndOnboarded) -} diff --git a/Dependencies/LoopKit/LoopKitUI/StateColorPalette.swift b/Dependencies/LoopKit/LoopKitUI/StateColorPalette.swift deleted file mode 100644 index 39ea06953..000000000 --- a/Dependencies/LoopKit/LoopKitUI/StateColorPalette.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// StateColorPalette.swift -// Loop -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import UIKit - - -/// A collection of colors for displaying state -public struct StateColorPalette { - public let unknown: UIColor - public let normal: UIColor - public let warning: UIColor - public let error: UIColor - - public init(unknown: UIColor, normal: UIColor, warning: UIColor, error: UIColor) { - self.unknown = unknown - self.normal = normal - self.warning = warning - self.error = error - } -} - - diff --git a/Dependencies/LoopKit/LoopKitUI/SupportUI.swift b/Dependencies/LoopKit/LoopKitUI/SupportUI.swift deleted file mode 100644 index bfa4b84d6..000000000 --- a/Dependencies/LoopKit/LoopKitUI/SupportUI.swift +++ /dev/null @@ -1,84 +0,0 @@ -// -// SupportUI.swift -// LoopKitUI -// -// Created by Darin Krauss on 12/10/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - -public protocol SupportInfoProvider { - var pumpStatus: PumpManagerStatus? { get } - var cgmStatus: CGMManagerStatus? { get } - var localizedAppNameAndVersion: String { get } - func generateIssueReport(completion: @escaping (String) -> Void) -} - -public protocol SupportUIDelegate: AlertIssuer { } - -public protocol SupportUI: AnyObject { - typealias RawStateValue = [String: Any] - - /// The unique identifier of this type of support. - static var supportIdentifier: String { get } - - /// Provides support menu item. - /// - /// - Parameters: - /// - supportInfoProvider: A provider of additional support information. - /// - urlHandler: A handler to open any URLs. - /// - Returns: A view that will be used in a support menu for providing user support. - func supportMenuItem(supportInfoProvider: SupportInfoProvider, urlHandler: @escaping (URL) -> Void) -> AnyView? - - /// Provides configuration menu items. - /// - /// - Parameters: - /// - supportInfoProvider: A provider of additional support information. - /// - urlHandler: A handler to open any URLs. - /// - Returns: An array of views that will be added to the configuration section of settings. - func configurationMenuItems() -> [AnyView] - - /// - /// Check whether the given app version for the given `bundleIdentifier` needs an update. Services should return their last result, if known. - /// - /// - Parameters: - /// - bundleIdentifier: The host app's `bundleIdentifier` (a.k.a. `CFBundleIdentifier`) string. - /// - currentVersion: The host app's current version (i.e. `CFBundleVersion`). - /// - completion: The completion function to call with any success result (or `nil` if not known) or failure. - func checkVersion(bundleIdentifier: String, currentVersion: String, completion: @escaping (Result) -> Void) - - /// Provides screen for software update UI. - /// - /// - Parameters: - /// - bundleIdentifier: The host app's bundle identifier (e.g. `Bundle.main.bundleIdentifier`). - /// - currentVersion: The host app's current version (i.e. `CFBundleVersion`). - /// - guidanceColors: Colors to use for warnings, etc. - /// - openAppStore: Function to open up the App Store for the host app. - /// - Returns: A view that will be opened when a software update is available from this service. - func softwareUpdateView(bundleIdentifier: String, - currentVersion: String, - guidanceColors: GuidanceColors, - openAppStore: (() -> Void)? - ) -> AnyView? - - /// Initializes the support with the previously-serialized state. - /// - /// - Parameters: - /// - rawState: The previously-serialized state of the support. - init?(rawState: RawStateValue) - - /// The current, serializable state of the support. - var rawState: RawStateValue { get } - - /// A delegate for SupportUI to use (see `SupportUIDelegate`). - var delegate: SupportUIDelegate? { get set } -} - -extension SupportUI { - public var identifier: String { - return Self.supportIdentifier - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/UIActivityIndicatorView.swift b/Dependencies/LoopKit/LoopKitUI/UIActivityIndicatorView.swift deleted file mode 100644 index d947d0eff..000000000 --- a/Dependencies/LoopKit/LoopKitUI/UIActivityIndicatorView.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// UIActivityIndicatorView.swift -// LoopKitUI -// -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit - - -extension UIActivityIndicatorView.Style { - static var `default`: UIActivityIndicatorView.Style { - return .medium - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/UIAlertController.swift b/Dependencies/LoopKit/LoopKitUI/UIAlertController.swift deleted file mode 100644 index 1ac8d4ca7..000000000 --- a/Dependencies/LoopKit/LoopKitUI/UIAlertController.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// UIAlertController.swift -// LoopKitUI -// -// Created by Pete Schwamb on 1/22/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import UIKit - -extension UIAlertController { - /// Convenience method to initialize an alert controller to display an error - /// - /// - Parameters: - /// - error: The error to display - /// - title: The title of the alert. If nil, the error description will be used. - /// - helpAnchorHandler: An optional closure to be executed when a user taps to open the error's `helpAnchor` - /// - url: A URL created from the error's helpAnchor property - public convenience init(with error: Error, title: String? = nil, helpAnchorHandler: ((_ url: URL) -> Void)? = nil) { - var actions: [UIAlertAction] = [] - let errorTitle: String - let message: String - - if let error = error as? LocalizedError { - - let sentenceFormat = LocalizedString("%@.", comment: "Appends a full-stop to a statement") - let messageWithRecovery = [error.failureReason, error.recoverySuggestion].compactMap({ $0 }).map({ - String(format: sentenceFormat, $0) - }).joined(separator: "\n") - - if messageWithRecovery.isEmpty { - message = error.localizedDescription - } else { - message = messageWithRecovery - } - - if let helpAnchor = error.helpAnchor, let url = URL(string: helpAnchor), let helpAnchorHandler = helpAnchorHandler { - actions.append(UIAlertAction( - title: LocalizedString("More Info", comment: "Alert action title to open error help"), - style: .default, - handler: { (_) in helpAnchorHandler(url) } - )) - } - - errorTitle = (error.errorDescription ?? error.localizedDescription).localizedCapitalized - - } else { - - // See: https://forums.developer.apple.com/thread/17431 - // The compiler automatically emits the code necessary to translate between any ErrorType and NSError. - let castedError = error as NSError - errorTitle = error.localizedDescription.localizedCapitalized - message = castedError.localizedRecoverySuggestion ?? String(describing: error) - } - - self.init(title: title ?? errorTitle, message: message, preferredStyle: .alert) - - let action = UIAlertAction( - title: LocalizedString("com.loudnate.LoopKit.errorAlertActionTitle", value: "OK", comment: "The title of the action used to dismiss an error alert"), style: .default) - addAction(action) - self.preferredAction = action - - for action in actions { - addAction(action) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/UIColor.swift b/Dependencies/LoopKit/LoopKitUI/UIColor.swift deleted file mode 100644 index 5abd284f9..000000000 --- a/Dependencies/LoopKit/LoopKitUI/UIColor.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// UIColor.swift -// LoopKitUI -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// -import UIKit - -private class LocalBundle { - /// Returns the resource bundle associated with the current Swift module. - static var main: Bundle = { - if let mainResourceURL = Bundle.main.resourceURL, - let bundle = Bundle(url: mainResourceURL.appendingPathComponent("LoopKitUI_LoopKitUI.bundle")) - { - return bundle - } - return Bundle(for: LocalBundle.self) - }() -} - -private func BundleColor(_ name: String, compatibleWith traitCollection: UITraitCollection? = nil) -> UIColor? { - return UIColor(named: name, in: LocalBundle.main, compatibleWith: traitCollection) -} - -extension UIColor { - @nonobjc static let lightenedInsulin = BundleColor("Lightened Insulin") ?? systemOrange - - @nonobjc static let darkenedInsulin = BundleColor("Darkened Insulin") ?? systemOrange - - static func interpolatingBetween(_ first: UIColor, _ second: UIColor, biasTowardSecondColor bias: CGFloat = 0.5) -> UIColor { - let (r1, g1, b1, a1) = first.components - let (r2, g2, b2, a2) = second.components - return UIColor( - red: (r2 - r1) * bias + r1, - green: (g2 - g1) * bias + g1, - blue: (b2 - b1) * bias + b1, - alpha: (a2 - a1) * bias + a1 - ) - } - - var components: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { - var r, g, b, a: CGFloat - (r, g, b, a) = (0, 0, 0, 0) - getRed(&r, green: &g, blue: &b, alpha: &a) - return (red: r, green: g, blue: b, alpha: a) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/AddEditOverrideTableViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/AddEditOverrideTableViewController.swift deleted file mode 100644 index 046d88f36..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/AddEditOverrideTableViewController.swift +++ /dev/null @@ -1,710 +0,0 @@ -// -// AddEditOverrideTableViewController.swift -// Loop -// -// Created by Michael Pangburn on 1/2/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit -import HealthKit -import LoopKit - - -public protocol AddEditOverrideTableViewControllerDelegate: AnyObject { - func addEditOverrideTableViewController(_ vc: AddEditOverrideTableViewController, didSavePreset preset: TemporaryScheduleOverridePreset) - func addEditOverrideTableViewController(_ vc: AddEditOverrideTableViewController, didSaveOverride override: TemporaryScheduleOverride) - func addEditOverrideTableViewController(_ vc: AddEditOverrideTableViewController, didCancelOverride override: TemporaryScheduleOverride) -} - -// MARK: - Default Implementations -extension AddEditOverrideTableViewControllerDelegate { - public func addEditOverrideTableViewController(_ vc: AddEditOverrideTableViewController, didSavePreset preset: TemporaryScheduleOverridePreset) { } - public func addEditOverrideTableViewController(_ vc: AddEditOverrideTableViewController, didSaveOverride override: TemporaryScheduleOverride) { } - public func addEditOverrideTableViewController(_ vc: AddEditOverrideTableViewController, didCancelOverride override: TemporaryScheduleOverride) { } -} - - -private extension TimeInterval { - static let defaultOverrideDuration: TimeInterval = .hours(1) -} - -public final class AddEditOverrideTableViewController: UITableViewController { - - // MARK: - Public configuration API - - public enum InputMode { - case newPreset // Creating a new preset - case editPreset(TemporaryScheduleOverridePreset) // Editing an existing preset - case customizePresetOverride(TemporaryScheduleOverridePreset) // Defining an override relative to an existing preset - case customOverride // Defining a one-off custom override - case editOverride(TemporaryScheduleOverride) // Editing an active override - case viewOverride(TemporaryScheduleOverride) // Viewing an override - } - - public enum DismissalMode { - case dismissModal - case popViewController - } - - public var inputMode: InputMode = .newPreset { - didSet { - switch inputMode { - case .newPreset: - symbol = nil - name = nil - targetRange = nil - insulinNeedsScaleFactor = 1.0 - duration = .finite(.defaultOverrideDuration) - case .editPreset(let preset), .customizePresetOverride(let preset): - symbol = preset.symbol - name = preset.name - configure(with: preset.settings) - duration = preset.duration - case .customOverride: - symbol = nil - name = nil - targetRange = nil - insulinNeedsScaleFactor = 1.0 - startDate = Date() - duration = .finite(.defaultOverrideDuration) - case .editOverride(let override): - if case .preset(let preset) = override.context { - symbol = preset.symbol - name = preset.name - } else { - symbol = nil - name = nil - } - configure(with: override.settings) - startDate = override.startDate - duration = override.duration - enactTrigger = override.enactTrigger - syncIdentifier = override.syncIdentifier - case .viewOverride(let override): - if case .preset(let preset) = override.context { - symbol = preset.symbol - name = preset.name - } else { - symbol = nil - name = nil - } - configure(with: override.settings) - startDate = override.startDate - duration = override.duration - syncIdentifier = override.syncIdentifier - } - } - } - - public var customDismissalMode: DismissalMode? - - public weak var delegate: AddEditOverrideTableViewControllerDelegate? - - // MARK: - Override properties - - private let glucoseUnit: HKUnit - - private var symbol: String? { didSet { updateSaveButtonEnabled() } } - - private var name: String? { didSet { updateSaveButtonEnabled() } } - - private var targetRange: DoubleRange? { didSet { updateSaveButtonEnabled() } } - - private var insulinNeedsScaleFactor = 1.0 { didSet { updateSaveButtonEnabled() }} - - private var startDate = Date() - - private var duration: TemporaryScheduleOverride.Duration = .finite(.defaultOverrideDuration) - - private var enactTrigger: TemporaryScheduleOverride.EnactTrigger = .local - - private var syncIdentifier = UUID() - - private var isConfiguringPreset: Bool { - switch inputMode { - case .newPreset, .editPreset: - return true - case .customizePresetOverride, .customOverride, .editOverride, .viewOverride: - return false - } - } - - private func configure(with settings: TemporaryScheduleOverrideSettings) { - if let targetRange = settings.targetRange { - self.targetRange = DoubleRange(minValue: targetRange.lowerBound.doubleValue(for: glucoseUnit), maxValue: targetRange.upperBound.doubleValue(for: glucoseUnit)) - } else { - self.targetRange = nil - } - insulinNeedsScaleFactor = settings.effectiveInsulinNeedsScaleFactor - } - - // MARK: - Initialization & view life cycle - - public init(glucoseUnit: HKUnit) { - self.glucoseUnit = glucoseUnit - super.init(style: .grouped) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public override func viewDidLoad() { - super.viewDidLoad() - - setupTitle() - setupBarButtonItems() - - tableView.register(LabeledTextFieldTableViewCell.nib(), forCellReuseIdentifier: LabeledTextFieldTableViewCell.className) - tableView.register(DoubleRangeTableViewCell.nib(), forCellReuseIdentifier: DoubleRangeTableViewCell.className) - tableView.register(DecimalTextFieldTableViewCell.nib(), forCellReuseIdentifier: DecimalTextFieldTableViewCell.className) - tableView.register(InsulinSensitivityScalingTableViewCell.nib(), forCellReuseIdentifier: InsulinSensitivityScalingTableViewCell.className) - tableView.register(DateAndDurationTableViewCell.nib(), forCellReuseIdentifier: DateAndDurationTableViewCell.className) - tableView.register(SwitchTableViewCell.self, forCellReuseIdentifier: SwitchTableViewCell.className) - tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className) - } - - // MARK: - UITableViewDataSource - - private enum Section: Int, CaseIterable { - case properties = 0 - case cancel - } - - private enum PropertyRow: Int, CaseIterable { - case symbol - case name - case insulinNeeds - case targetRange - case startDate - case endDate - case durationFiniteness - case duration - } - - private var propertyRows: [PropertyRow] { - var rows: [PropertyRow] = { - if isConfiguringPreset { - return [.symbol, .name, .insulinNeeds, .targetRange, .durationFiniteness] - } else if case let .viewOverride(override) = inputMode, override.hasFinished() { - return [.insulinNeeds, .targetRange, .startDate, .endDate] - } else { - return [.insulinNeeds, .targetRange, .startDate, .durationFiniteness] - } - }() - - if duration.isFinite { - rows.append(.duration) - } - - rows.sort(by: { $0.rawValue < $1.rawValue }) - return rows - } - - private func propertyRow(for indexPath: IndexPath) -> PropertyRow { - return propertyRows[indexPath.row] - } - - private func indexPath(for row: PropertyRow) -> IndexPath? { - guard let rowIndex = propertyRows.firstIndex(of: row) else { - return nil - } - return IndexPath(row: rowIndex, section: 0) - } - - public override func numberOfSections(in tableView: UITableView) -> Int { - if case .editOverride = inputMode { - return Section.allCases.count - } else { - // No cancel button available unless override is already set - return Section.allCases.count - 1 - } - } - - public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch Section(rawValue: section)! { - case .properties: - return propertyRows.count - case .cancel: - return 1 - } - } - - private lazy var quantityFormatter: QuantityFormatter = { - let formatter = QuantityFormatter() - formatter.setPreferredNumberFormatter(for: glucoseUnit) - return formatter - }() - - private lazy var overrideSymbolKeyboard: EmojiInputController = { - let keyboard = OverrideSymbolInputController() - keyboard.delegate = self - return keyboard - }() - - public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch Section(rawValue: indexPath.section)! { - case .properties: - switch propertyRow(for: indexPath) { - case .symbol: - let cell = tableView.dequeueReusableCell(withIdentifier: LabeledTextFieldTableViewCell.className, for: indexPath) as! LabeledTextFieldTableViewCell - cell.titleLabel.text = LocalizedString("Symbol", comment: "The text for the custom preset symbol setting") - cell.textField.text = symbol - cell.textField.placeholder = SettingsTableViewCell.NoValueString - cell.maximumTextLength = 2 - cell.customInput = overrideSymbolKeyboard - cell.delegate = self - return cell - case .name: - let cell = tableView.dequeueReusableCell(withIdentifier: LabeledTextFieldTableViewCell.className, for: indexPath) as! LabeledTextFieldTableViewCell - cell.titleLabel.text = LocalizedString("Name", comment: "The text for the custom preset name setting") - cell.textField.text = name - cell.textField.placeholder = LocalizedString("Running", comment: "The text for the custom preset name field placeholder") - cell.delegate = self - return cell - case .insulinNeeds: - let cell = tableView.dequeueReusableCell(withIdentifier: InsulinSensitivityScalingTableViewCell.className, for: indexPath) as! InsulinSensitivityScalingTableViewCell - cell.scaleFactor = insulinNeedsScaleFactor - cell.delegate = self - return cell - case .targetRange: - let cell = tableView.dequeueReusableCell(withIdentifier: DoubleRangeTableViewCell.className, for: indexPath) as! DoubleRangeTableViewCell - cell.numberFormatter = quantityFormatter.numberFormatter - cell.titleLabel.text = LocalizedString("Target Range", comment: "The text for the custom preset target range setting") - cell.range = targetRange - cell.unitLabel.text = quantityFormatter.string(from: glucoseUnit) - cell.delegate = self - return cell - case .startDate: - let cell = tableView.dequeueReusableCell(withIdentifier: DateAndDurationTableViewCell.className, for: indexPath) as! DateAndDurationTableViewCell - cell.titleLabel.text = LocalizedString("Start Time", comment: "The text for the custom preset start time") - cell.datePicker.datePickerMode = .dateAndTime - cell.datePicker.preferredDatePickerStyle = .wheels - cell.datePicker.minimumDate = min(startDate, Date()) - cell.date = startDate - cell.delegate = self - return cell - case .endDate: - guard case let .viewOverride(override) = inputMode else { - fatalError("endDate should only be used when viewing override history") - } - - let cell = tableView.dequeueReusableCell(withIdentifier: DateAndDurationTableViewCell.className, for: indexPath) as! DateAndDurationTableViewCell - cell.titleLabel.text = LocalizedString("End Time", comment: "The text for the override start time") - cell.datePicker.datePickerMode = .dateAndTime - cell.date = override.actualEndDate - return cell - case .durationFiniteness: - let cell = tableView.dequeueReusableCell(withIdentifier: SwitchTableViewCell.className, for: indexPath) as! SwitchTableViewCell - cell.selectionStyle = .none - cell.textLabel?.text = LocalizedString("Enable Indefinitely", comment: "The text for the indefinite custom preset duration setting") - cell.switch?.isOn = !duration.isFinite - cell.switch?.addTarget(self, action: #selector(durationFinitenessChanged), for: .valueChanged) - return cell - case .duration: - let cell = tableView.dequeueReusableCell(withIdentifier: DateAndDurationTableViewCell.className, for: indexPath) as! DateAndDurationTableViewCell - cell.titleLabel.text = LocalizedString("Duration", comment: "The text for the custom preset duration setting") - cell.datePicker.datePickerMode = .countDownTimer - guard case .finite(let duration) = duration else { - preconditionFailure("Duration should only be selectable when duration is finite") - } - // Use the actual duration if we're retrospectively viewing overrides - if case let .viewOverride(override) = inputMode { - cell.titleLabel.text = LocalizedString("Active Duration", comment: "The text for the override history duration") - cell.datePicker.minuteInterval = 1 - cell.duration = override.actualEndDate.timeIntervalSince(override.startDate) - } else { - cell.titleLabel.text = LocalizedString("Duration", comment: "The text for the override duration setting") - cell.datePicker.minuteInterval = 15 - cell.duration = duration - } - cell.maximumDuration = .hours(24) - cell.delegate = self - return cell - } - case .cancel: - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell - if startDate > Date() { - cell.textLabel?.text = LocalizedString("Cancel", comment: "The text for the scheduled custom preset cancel button") - } else { - cell.textLabel?.text = LocalizedString("Disable Preset", comment: "The text for the custom preset disable button") - } - cell.textLabel?.textAlignment = .center - cell.tintColor = .defaultButtonTextColor - return cell - } - } - - @objc private func durationFinitenessChanged(_ sender: UISwitch) { - if sender.isOn { - setDurationIndefinite() - } else { - setDurationFinite() - } - } - - private func setDurationIndefinite() { - guard let durationIndexPath = indexPath(for: .duration) else { - assertionFailure("Unable to locate duration row") - return - } - duration = .indefinite - tableView.deleteRows(at: [durationIndexPath], with: .automatic) - } - - private func setDurationFinite() { - switch inputMode { - case .newPreset, .customOverride: - duration = .finite(.defaultOverrideDuration) - case .editPreset(let preset), .customizePresetOverride(let preset): - switch preset.duration { - case .finite(let interval): - duration = .finite(interval) - case .indefinite: - duration = .finite(.defaultOverrideDuration) - } - case .editOverride(let override), .viewOverride(let override): - if case .preset(let preset) = override.context, - case .finite(let interval) = preset.duration { - duration = .finite(interval) - } else { - switch override.duration { - case .finite(let interval): - duration = .finite(interval) - case .indefinite: - duration = .finite(.defaultOverrideDuration) - } - } - } - - guard let durationIndexPath = indexPath(for: .duration) else { - assertionFailure("Unable to locate duration row") - return - } - tableView.insertRows(at: [durationIndexPath], with: .automatic) - } - - public override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - guard section == 0 else { - return nil - } - - switch inputMode { - case .customizePresetOverride(let preset): - return String(format: LocalizedString("Changes will only apply this time you enable the preset. The default settings of %@ will not be affected.", comment: "Footer text for customizing from a preset (1: preset name)"), preset.name) - case .editOverride(let override): - guard case .preset(let preset) = override.context else { - return nil - } - return String(format: LocalizedString("Edits persist only until the preset is disabled. The default settings of %@ will not be affected.", comment: "Footer text for editing an enabled custom preset (1: preset name)"), preset.name) - default: - return nil - } - } - - // MARK: - UITableViewDelegate - - public override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { - switch Section(rawValue: indexPath.section)! { - case .properties: - tableView.endEditing(false) - tableView.beginUpdates() - collapseExpandableCells(excluding: indexPath) - case .cancel: - break - } - - return indexPath - } - - public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - switch Section(rawValue: indexPath.section)! { - case .properties: - tableView.endUpdates() - tableView.deselectRow(at: indexPath, animated: true) - - if let cell = tableView.cellForRow(at: indexPath) as? LabeledTextFieldTableViewCell, !cell.isFirstResponder { - cell.textField.becomeFirstResponder() - } - case .cancel: - guard case .editOverride(let override) = inputMode else { - assertionFailure("Only an already-set override can be canceled") - return - } - delegate?.addEditOverrideTableViewController(self, didCancelOverride: override) - dismiss() - } - } - - private func collapseExpandableCells(excluding indexPath: IndexPath? = nil) { - tableView.beginUpdates() - hideDatePickerCells(excluding: indexPath) - collapseInsulinSensitivityScalingCells(excluding: indexPath) - tableView.endUpdates() - } -} - -// MARK: - Navigation item configuration - -extension AddEditOverrideTableViewController { - private func setupTitle() { - if let symbol = symbol, let name = name { - let format = LocalizedString("%1$@ %2$@", comment: "The format for a preset symbol and name (1: symbol)(2: name)") - title = String(format: format, symbol, name) - } else { - switch inputMode { - case .newPreset: - title = LocalizedString("New Preset", comment: "The title for the new custom preset entry screen") - case .editPreset, .customizePresetOverride: - assertionFailure("Editing or customizing a preset means we'll have a symbol and a name") - case .customOverride: - title = LocalizedString("Custom Preset", comment: "The title for the custom preset entry screen") - case .editOverride: - title = LocalizedString("Edit", comment: "The title for the enabled custom preset editing screen") - case .viewOverride: - title = LocalizedString("View Override", comment: "The title for the override editing screen") - } - } - } - - private func setupBarButtonItems() { - switch inputMode { - case .newPreset, .editPreset, .editOverride: - navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(save)) - case .customizePresetOverride, .customOverride: - navigationItem.rightBarButtonItem = UIBarButtonItem(title: LocalizedString("Enable", comment: "The button text for enabling a temporary override"), style: .done, target: self, action: #selector(save)) - case .viewOverride: break - } - - updateSaveButtonEnabled() - - switch inputMode { - case .newPreset: - navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancel)) - default: - break - } - } - - private var configuredSettings: TemporaryScheduleOverrideSettings? { - if let targetRange = targetRange { - guard targetRange.maxValue >= targetRange.minValue else { - return nil - } - } else { - guard insulinNeedsScaleFactor != 1.0 else { - return nil - } - } - - return TemporaryScheduleOverrideSettings( - unit: glucoseUnit, - targetRange: targetRange, - insulinNeedsScaleFactor: insulinNeedsScaleFactor == 1.0 ? nil : insulinNeedsScaleFactor - ) - } - - private var configuredPreset: TemporaryScheduleOverridePreset? { - guard - let symbol = symbol, !symbol.isEmpty, - let name = name, !name.isEmpty, - let settings = configuredSettings - else { - return nil - } - - let id: UUID - if case .editPreset(let preset) = inputMode { - id = preset.id - } else { - id = UUID() - } - - return TemporaryScheduleOverridePreset(id: id, symbol: symbol, name: name, settings: settings, duration: duration) - } - - private var configuredOverride: TemporaryScheduleOverride? { - guard let settings = configuredSettings else { - return nil - } - - let context: TemporaryScheduleOverride.Context - switch inputMode { - case .customizePresetOverride(let preset): - let customizedPreset = TemporaryScheduleOverridePreset( - symbol: preset.symbol, - name: preset.name, - settings: settings, - duration: duration - ) - context = .preset(customizedPreset) - case .editOverride(let override), .viewOverride(let override): - context = override.context - case .customOverride: - context = .custom - case .newPreset, .editPreset: - assertionFailure() - return nil - } - - return TemporaryScheduleOverride(context: context, settings: settings, startDate: startDate, duration: duration, enactTrigger: enactTrigger, syncIdentifier: syncIdentifier) - } - - private func updateSaveButtonEnabled() { - navigationItem.rightBarButtonItem?.isEnabled = { - switch inputMode { - case .newPreset, .editPreset: - return configuredPreset != nil - case .customizePresetOverride, .customOverride, .editOverride: - return configuredOverride != nil - case .viewOverride: - return false - } - }() - } - - @objc private func save() { - switch inputMode { - case .newPreset, .editPreset: - guard let configuredPreset = configuredPreset else { - assertionFailure("Save button cannot be tapped when preset is invalid") - break - } - delegate?.addEditOverrideTableViewController(self, didSavePreset: configuredPreset) - case .customizePresetOverride, .customOverride, .editOverride: - guard let configuredOverride = configuredOverride else { - assertionFailure("Save button cannot be tapped when override is invalid") - break - } - delegate?.addEditOverrideTableViewController(self, didSaveOverride: configuredOverride) - case .viewOverride: break - } - dismiss() - } - - @objc private func cancel() { - dismiss() - } - - private func dismiss() { - if let customDismissalMode = customDismissalMode { - dismiss(with: customDismissalMode) - } else { - switch inputMode { - case .newPreset, .customizePresetOverride, .customOverride: - dismiss(with: .dismissModal) - case .editPreset, .editOverride, .viewOverride: - dismiss(with: .popViewController) - } - } - } - - private func dismiss(with mode: DismissalMode) { - switch mode { - case .dismissModal: - dismiss(animated: true) - case .popViewController: - assert(navigationController != nil) - navigationController?.popViewController(animated: true) - } - } -} - -// MARK: - Delegation - -extension AddEditOverrideTableViewController: TextFieldTableViewCellDelegate { - public func textFieldTableViewCellDidBeginEditing(_ cell: TextFieldTableViewCell) { - collapseExpandableCells() - } - - public func textFieldTableViewCellDidEndEditing(_ cell: TextFieldTableViewCell) { - updateWithText(from: cell) - } - - public func textFieldTableViewCellDidChangeEditing(_ cell: TextFieldTableViewCell) { - updateWithText(from: cell) - } - - private func updateWithText(from cell: TextFieldTableViewCell) { - guard let indexPath = tableView.indexPath(for: cell) else { - return - } - - switch propertyRow(for: indexPath) { - case .symbol: - symbol = cell.textField.text - case .name: - name = cell.textField.text - default: - assertionFailure() - } - } -} - -extension AddEditOverrideTableViewController: EmojiInputControllerDelegate { - public func emojiInputControllerDidAdvanceToStandardInputMode(_ controller: EmojiInputController) { - guard - let indexPath = indexPath(for: .symbol), - let cell = tableView.cellForRow(at: indexPath) as? LabeledTextFieldTableViewCell, - let textField = cell.textField as? CustomInputTextField - else { - return - } - - let customInput = textField.customInput - textField.customInput = nil - textField.resignFirstResponder() - textField.becomeFirstResponder() - textField.customInput = customInput - } -} - -extension AddEditOverrideTableViewController: InsulinSensitivityScalingTableViewCellDelegate { - func insulinSensitivityScalingTableViewCellDidUpdateScaleFactor(_ cell: InsulinSensitivityScalingTableViewCell) { - insulinNeedsScaleFactor = cell.scaleFactor - } -} - -extension AddEditOverrideTableViewController: DatePickerTableViewCellDelegate { - public func datePickerTableViewCellDidUpdateDate(_ cell: DatePickerTableViewCell) { - guard let indexPath = tableView.indexPath(for: cell) else { return } - switch propertyRow(for: indexPath) { - case .startDate: - startDate = cell.date - case .duration: - duration = .finite(cell.duration) - default: - assertionFailure() - } - } -} - -extension AddEditOverrideTableViewController: DoubleRangeTableViewCellDelegate { - func doubleRangeTableViewCellDidBeginEditing(_ cell: DoubleRangeTableViewCell) { - collapseExpandableCells() - } - - func doubleRangeTableViewCellDidUpdateRange(_ cell: DoubleRangeTableViewCell) { - guard let indexPath = tableView.indexPath(for: cell) else { return } - switch propertyRow(for: indexPath) { - case .targetRange: - targetRange = cell.range - default: - assertionFailure() - } - } -} - -private extension UIColor { - static let defaultButtonTextColor = UIButton(type: .system).titleColor(for: .normal) -} - -private extension UIFont { - func bold() -> UIFont? { - guard let descriptor = fontDescriptor.withSymbolicTraits(.traitBold) else { - return nil - } - return UIFont(descriptor: descriptor, size: pointSize) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/AuthenticationViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/AuthenticationViewController.swift deleted file mode 100644 index 4e4253152..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/AuthenticationViewController.swift +++ /dev/null @@ -1,260 +0,0 @@ -// -// AuthenticationViewController.swift -// Loop -// -// Created by Nate Racklyeft on 7/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import LoopKit - - -public final class AuthenticationViewController: UITableViewController, UITextFieldDelegate { - - public typealias AuthenticationObserver = (_ authentication: T) -> Void - - public var authenticationObserver: AuthenticationObserver? - - public let authentication: T - - private var state: AuthenticationState = .empty { - didSet { - switch (oldValue, state) { - case let (x, y) where x == y: - break - case (_, .verifying): - let titleView = ValidatingIndicatorView(frame: CGRect.zero) - UIView.animate(withDuration: 0.25, animations: { - self.navigationItem.hidesBackButton = true - self.navigationItem.titleView = titleView - }) - - tableView.reloadSections(IndexSet(integersIn: 0...1), with: .automatic) - authentication.verify { (success, error) in - DispatchQueue.main.async { - UIView.animate(withDuration: 0.25, animations: { - self.navigationItem.titleView = nil - self.navigationItem.hidesBackButton = false - }) - - if let error = error { - let alert = UIAlertController(with: error) - self.present(alert, animated: true) - } - - if success { - self.state = .authorized - } else { - self.state = .unauthorized - } - } - } - case (_, .authorized), (_, .unauthorized): - authentication.isAuthorized = (state == .authorized) - - authenticationObserver?(authentication) - tableView.reloadSections(IndexSet(integersIn: 0...1), with: .automatic) - default: - break - } - } - } - - var credentials: [(field: ServiceCredential, value: String?)] { - return authentication.credentials - } - - public init(authentication: T) { - self.authentication = authentication - - state = authentication.isAuthorized ? .authorized : .unauthorized - - super.init(style: .grouped) - - title = authentication.title - } - - required public init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override public func viewDidLoad() { - super.viewDidLoad() - - tableView.register(AuthenticationTableViewCell.nib(), forCellReuseIdentifier: AuthenticationTableViewCell.className) - tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className) - } - - // MARK: - Table view data source - - override public func numberOfSections(in tableView: UITableView) -> Int { - return Section.count - } - - override public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch Section(rawValue: section)! { - case .credentials: - return credentials.count - case .button: - return 1 - } - } - - override public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch Section(rawValue: indexPath.section)! { - case .button: - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell - - cell.textLabel?.textAlignment = .center - - switch state { - case .authorized: - cell.textLabel?.text = LocalizedString("Delete", comment: "The title of the button to remove the credentials for a service") - cell.tintColor = .systemRed - case .empty, .unauthorized, .verifying: - cell.textLabel?.text = LocalizedString("Add Account", comment: "The title of the button to add the credentials for a service") - cell.tintColor = nil - } - - if case .verifying = state { - cell.isEnabled = false - } else { - cell.isEnabled = true - } - - return cell - case .credentials: - let cell = tableView.dequeueReusableCell(withIdentifier: AuthenticationTableViewCell.className, for: indexPath) as! AuthenticationTableViewCell - - let credentials = self.credentials - let credential = credentials[indexPath.row] - - cell.titleLabel.text = credential.field.title - cell.textField.keyboardType = credential.field.keyboardType - cell.textField.isSecureTextEntry = credential.field.isSecret - cell.textField.returnKeyType = (indexPath.row < credentials.count - 1) ? .next : .done - cell.textField.text = credential.value - cell.textField.placeholder = credential.field.placeholder ?? LocalizedString("Required", comment: "The default placeholder string for a credential") - - if let options = credential.field.options { - let picker = CredentialOptionPicker(options: options) - picker.value = credential.value - authentication.credentialValues[indexPath.row] = credential.value ?? options.first?.value - - cell.credentialOptionPicker = picker - } - - cell.textField.delegate = self - - switch state { - case .authorized, .verifying, .empty: - cell.textField.isEnabled = false - case .unauthorized: - cell.textField.isEnabled = true - } - - return cell - } - } - - public override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - switch Section(rawValue: section)! { - case .credentials: - return authentication.credentialFormFieldHelperMessage - case .button: - return nil - } - } - - // MARK: - Table view delegate - - public override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { - switch Section(rawValue: indexPath.section)! { - case .credentials: - return false - case .button: - return true - } - } - - public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - switch Section(rawValue: indexPath.section)! { - case .credentials: - break - case .button: - switch state { - case .authorized: - tableView.endEditing(false) - authentication.resetCredentials() - state = .unauthorized - case .unauthorized: - tableView.endEditing(false) - validate() - case .verifying: - break - case .empty: - break - } - } - - tableView.deselectRow(at: indexPath, animated: true) - } - - fileprivate func validate() { - state = .verifying - } - - // MARK: - Actions - - // MARK: - UITextFieldDelegate - - public func textFieldDidEndEditing(_ textField: UITextField) { - let point = tableView.convert(textField.frame.origin, from: textField.superview) - - guard case .unauthorized = state, - let indexPath = tableView.indexPathForRow(at: point), - let cell = tableView.cellForRow(at: IndexPath(row: indexPath.row, section: indexPath.section)) as? AuthenticationTableViewCell - else { - return - } - - authentication.credentialValues[indexPath.row] = cell.value - } - - public func textFieldShouldReturn(_ textField: UITextField) -> Bool { - if textField.returnKeyType == .done { - textField.resignFirstResponder() - validate() - } else { - let point = tableView.convert(textField.frame.origin, from: textField.superview) - if let indexPath = tableView.indexPathForRow(at: point), - let cell = tableView.cellForRow(at: IndexPath(row: indexPath.row + 1, section: indexPath.section)) as? AuthenticationTableViewCell - { - cell.textField.becomeFirstResponder() - } - } - - return true - } - - public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - return textField.inputView == nil - } -} - - -private enum Section: Int { - case credentials - case button - - static let count = 2 -} - - -private enum AuthenticationState { - case empty - case authorized - case verifying - case unauthorized -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/ChartsManager.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/ChartsManager.swift deleted file mode 100644 index eda1ffab4..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/ChartsManager.swift +++ /dev/null @@ -1,240 +0,0 @@ -// -// Chart.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/19/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit -import LoopKit -import SwiftCharts -import UIKit - - -open class ChartsManager { - - private lazy var timeFormatter: DateFormatter = { - let formatter = DateFormatter() - let dateFormat = DateFormatter.dateFormat(fromTemplate: "j", options: 0, locale: Locale.current)! - let isAmPmTimeFormat = dateFormat.firstIndex(of: "a") != nil - formatter.dateFormat = isAmPmTimeFormat - ? "h a" - : "H:mm" - return formatter - }() - - public init( - colors: ChartColorPalette, - settings: ChartSettings, - axisLabelFont: UIFont = .systemFont(ofSize: 14), // caption1, but hard-coded until axis can scale with type preference - charts: [ChartProviding], - traitCollection: UITraitCollection - ) { - self.colors = colors - self.chartSettings = settings - self.charts = charts - self.traitCollection = traitCollection - self.chartsCache = Array(repeating: nil, count: charts.count) - - axisLabelSettings = ChartLabelSettings(font: axisLabelFont, fontColor: colors.axisLabel) - - guideLinesLayerSettings = ChartGuideLinesLayerSettings(linesColor: colors.grid) - } - - // MARK: - Configuration - - private let colors: ChartColorPalette - - private let chartSettings: ChartSettings - - private let labelsWidthY: CGFloat = 30 - - public let charts: [ChartProviding] - - /// The amount of horizontal space reserved for fixed margins - public var fixedHorizontalMargin: CGFloat { - return chartSettings.leading + chartSettings.trailing + labelsWidthY + chartSettings.labelsToAxisSpacingY - } - - private let axisLabelSettings: ChartLabelSettings - - private let guideLinesLayerSettings: ChartGuideLinesLayerSettings - - public var gestureRecognizer: UIGestureRecognizer? - - // MARK: - UITraitEnvironment - - public var traitCollection: UITraitCollection - - public func didReceiveMemoryWarning() { - - for chart in charts { - chart.didReceiveMemoryWarning() - } - - xAxisValues = nil - } - - // MARK: - Data - - /// The earliest date on the X-axis - public var startDate = Date() { - didSet { - if startDate != oldValue { - xAxisValues = nil - - // Set a new minimum end date - endDate = startDate.addingTimeInterval(.hours(3)) - } - } - } - - /// The latest date on the X-axis - private var endDate = Date() { - didSet { - if endDate != oldValue { - xAxisValues = nil - } - } - } - - /// The latest allowed date on the X-axis - public var maxEndDate = Date.distantFuture { - didSet { - endDate = min(endDate, maxEndDate) - } - } - - /// Updates the endDate using a new candidate date - /// - /// Dates are rounded up to the next hour. - /// - /// - Parameter date: The new candidate date - public func updateEndDate(_ date: Date) { - if date > endDate { - let components = DateComponents(minute: 0) - endDate = min( - maxEndDate, - Calendar.current.nextDate( - after: date, - matching: components, - matchingPolicy: .strict, - direction: .forward - ) ?? date - ) - } - } - - // MARK: - State - - private var xAxisValues: [ChartAxisValue]? { - didSet { - if let xAxisValues = xAxisValues, xAxisValues.count > 1 { - xAxisModel = ChartAxisModel(axisValues: xAxisValues, lineColor: colors.axisLine, labelSpaceReservationMode: .fixed(20)) - } else { - xAxisModel = nil - } - - chartsCache.replaceAllElements(with: nil) - } - } - - private var xAxisModel: ChartAxisModel? - - private var chartsCache: [Chart?] - - // MARK: - Generators - - public func chart(atIndex index: Int, frame: CGRect) -> Chart? { - if let chart = chartsCache[index], chart.frame != frame { - chartsCache[index] = nil - } - - if chartsCache[index] == nil, let xAxisModel = xAxisModel, let xAxisValues = xAxisValues { - chartsCache[index] = charts[index].generate(withFrame: frame, xAxisModel: xAxisModel, xAxisValues: xAxisValues, axisLabelSettings: axisLabelSettings, guideLinesLayerSettings: guideLinesLayerSettings, colors: colors, chartSettings: chartSettings, labelsWidthY: labelsWidthY, gestureRecognizer: gestureRecognizer, traitCollection: traitCollection) - } - - return chartsCache[index] - } - - public func invalidateChart(atIndex index: Int) { - chartsCache[index] = nil - } - - // MARK: - Shared Axis - - private func generateXAxisValues() { - if let endDate = charts.compactMap({ $0.endDate }).max() { - updateEndDate(endDate) - } - - let points = [ - ChartPoint( - x: ChartAxisValueDate(date: startDate, formatter: timeFormatter), - y: ChartAxisValue(scalar: 0) - ), - ChartPoint( - x: ChartAxisValueDate(date: endDate, formatter: timeFormatter), - y: ChartAxisValue(scalar: 0) - ) - ] - - let segments = ceil(endDate.timeIntervalSince(startDate).hours) - - let xAxisValues = ChartAxisValuesStaticGenerator.generateXAxisValuesWithChartPoints(points, - minSegmentCount: segments - 1, - maxSegmentCount: segments + 1, - multiple: TimeInterval(hours: 1), - axisValueGenerator: { - ChartAxisValueDate( - date: ChartAxisValueDate.dateFromScalar($0), - formatter: timeFormatter, - labelSettings: self.axisLabelSettings - ) - }, - addPaddingSegmentIfEdge: false - ) - xAxisValues.first?.hidden = true - xAxisValues.last?.hidden = true - - self.xAxisValues = xAxisValues - } - - /// Runs any necessary steps before rendering charts - public func prerender() { - if xAxisValues == nil { - generateXAxisValues() - } - } -} - -fileprivate extension Array { - mutating func replaceAllElements(with element: Element) { - self = Array(repeating: element, count: count) - } -} - -public protocol ChartProviding { - /// Instructs the chart to clear its non-critical resources like caches - func didReceiveMemoryWarning() - - /// The last date represented in the chart data - var endDate: Date? { get } - - /// Creates a chart from the current data - /// - /// - Returns: A new chart object - func generate(withFrame frame: CGRect, - xAxisModel: ChartAxisModel, - xAxisValues: [ChartAxisValue], - axisLabelSettings: ChartLabelSettings, - guideLinesLayerSettings: ChartGuideLinesLayerSettings, - colors: ChartColorPalette, - chartSettings: ChartSettings, - labelsWidthY: CGFloat, - gestureRecognizer: UIGestureRecognizer?, - traitCollection: UITraitCollection - ) -> Chart -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/ChartsTableViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/ChartsTableViewController.swift deleted file mode 100644 index aed5c2c99..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/ChartsTableViewController.swift +++ /dev/null @@ -1,180 +0,0 @@ -// -// ChartsTableViewController.swift -// LoopKitUI -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import UIKit -import Combine -import HealthKit - -/// Abstract class providing boilerplate setup for chart-based table view controllers -open class ChartsTableViewController: UITableViewController, UIGestureRecognizerDelegate { - - public var displayGlucoseUnitObservable: DisplayGlucoseUnitObservable? { - didSet { - guard let displayGlucoseUnitObservable = displayGlucoseUnitObservable else { return } - - displayGlucoseUnitObservable.$displayGlucoseUnit - .sink { [weak self] displayGlucoseUnit in self?.unitPreferencesDidChange(to: displayGlucoseUnit) } - .store(in: &cancellables) - } - } - - private lazy var cancellables = Set() - - open override func viewDidLoad() { - super.viewDidLoad() - - if let unit = displayGlucoseUnitObservable?.displayGlucoseUnit { - self.charts.setGlucoseUnit(unit) - } - - let gestureRecognizer = UILongPressGestureRecognizer() - gestureRecognizer.delegate = self - gestureRecognizer.minimumPressDuration = 0.3 - gestureRecognizer.addTarget(self, action: #selector(handlePan(_:))) - charts.gestureRecognizer = gestureRecognizer - - NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification, object: nil) - .receive(on: RunLoop.main) - .sink { [weak self] _ in - self?.active = true - if self?.visible == true { - self?.reloadData() - } - } - .store(in: &cancellables) - - NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification, object: nil) - .receive(on: RunLoop.main) - .sink { [weak self] _ in - self?.active = false - } - .store(in: &cancellables) - - } - - open override func didReceiveMemoryWarning() { - super.didReceiveMemoryWarning() - - if !visible { - charts.didReceiveMemoryWarning() - } - } - - open override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - visible = true - } - - open override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - - visible = false - } - - open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { - super.viewWillTransition(to: size, with: coordinator) - - reloadData(animated: false) - } - - open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { - super.traitCollectionDidChange(previousTraitCollection) - - charts.traitCollection = traitCollection - } - - // MARK: - State - // This function should only be called from the main thread - public func unitPreferencesDidChange(to unit: HKUnit?) { - if let unit = unit { - self.charts.setGlucoseUnit(unit) - self.glucoseUnitDidChange() - } - self.reloadData() - } - - open func glucoseUnitDidChange() { - // To override. - } - - open func createChartsManager() -> ChartsManager { - fatalError("Subclasses must implement \(#function)") - } - - lazy public private(set) var charts = createChartsManager() - - // References to registered notification center observers - public var notificationObservers: [Any] = [] - - open var active: Bool = true { - didSet { - reloadData() - } - } - - public var visible = false { - didSet { - reloadData() - } - } - - // MARK: - Data loading - - /// Refetches all data and updates the views. Must be called on the main queue. - /// - /// - Parameters: - /// - animated: Whether the updating should be animated if possible - open func reloadData(animated: Bool = false) { - - } - - // MARK: - UIGestureRecognizer - - public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { - /// Only start the long-press recognition when it starts in a chart cell - let point = gestureRecognizer.location(in: tableView) - if let indexPath = tableView.indexPathForRow(at: point) { - if let cell = tableView.cellForRow(at: indexPath), cell is ChartTableViewCell { - return true - } - } - - return false - } - - public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { - return true - } - - @objc func handlePan(_ gestureRecognizer: UIGestureRecognizer) { - switch gestureRecognizer.state { - case .possible, .changed: - // Follow your dreams! - break - case .began, .cancelled, .ended, .failed: - for case let row as ChartTableViewCell in self.tableView.visibleCells { - let forwards = gestureRecognizer.state == .began - UIView.animate(withDuration: forwards ? 0.2 : 0.5, delay: forwards ? 0 : 1, animations: { - let alpha: CGFloat = forwards ? 0 : 1 - row.titleLabel?.alpha = alpha - row.subtitleLabel?.alpha = alpha - }) - } - @unknown default: - break - } - } -} - -fileprivate extension ChartsManager { - func setGlucoseUnit(_ unit: HKUnit) { - for case let chart as GlucoseChart in charts { - chart.glucoseUnit = unit - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/CommandResponseViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/CommandResponseViewController.swift deleted file mode 100644 index ba61b795f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/CommandResponseViewController.swift +++ /dev/null @@ -1,114 +0,0 @@ -// -// CommandResponseViewController.swift -// LoopKit -// -// Created by Nate Racklyeft on 8/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import os.log - - -public class CommandResponseViewController: UIViewController { - public typealias Command = (_ completionHandler: @escaping (_ responseText: String) -> Void) -> String - - public init(command: @escaping Command) { - self.command = command - - super.init(nibName: nil, bundle: nil) - } - - required public init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public var fileName: String? - - private let uuid = UUID() - - private let command: Command - - fileprivate lazy var textView = UITextView() - - public override func loadView() { - self.view = textView - } - - public override func viewDidLoad() { - super.viewDidLoad() - - textView.contentInsetAdjustmentBehavior = .always - - let font = UIFont(name: "Menlo-Regular", size: 14) - if let font = font { - let metrics = UIFontMetrics(forTextStyle: .body) - textView.font = metrics.scaledFont(for: font) - } else { - textView.font = font - } - - textView.text = command { [weak self] (responseText) -> Void in - var newText = self?.textView.text ?? "" - newText += "\n\n" - newText += responseText - self?.textView.text = newText - } - textView.isEditable = false - - navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(shareText(_:))) - } - - @objc func shareText(_: Any?) { - let title = fileName ?? "\(self.title ?? uuid.uuidString).txt" - - guard let item = SharedResponse(text: textView.text, title: title) else { - return - } - - let activityVC = UIActivityViewController(activityItems: [item], applicationActivities: nil) - - present(activityVC, animated: true, completion: nil) - } -} - - -private class SharedResponse: NSObject, UIActivityItemSource { - - let title: String - let fileURL: URL - - init?(text: String, title: String) { - self.title = title - - var url = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true) - url.appendPathComponent(title, isDirectory: false) - - do { - try text.write(to: url, atomically: true, encoding: .utf8) - } catch let error { - os_log("Failed to write to file %{public}@: %{public}@", log: .default, type: .error, title, String(describing: error)) - return nil - } - - fileURL = url - - super.init() - } - - public func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any { - return fileURL - } - - public func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? { - return fileURL - } - - public func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivity.ActivityType?) -> String { - return title - } - - public func activityViewController(_ activityViewController: UIActivityViewController, dataTypeIdentifierForActivityType activityType: UIActivity.ActivityType?) -> String { - return "public.utf8-plain-text" - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/DailyQuantityScheduleTableViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/DailyQuantityScheduleTableViewController.swift deleted file mode 100644 index 2ce6def36..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/DailyQuantityScheduleTableViewController.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// DailyQuantityScheduleTableViewController.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/13/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import HealthKit - - -public class DailyQuantityScheduleTableViewController: SingleValueScheduleTableViewController { - - public var unit: HKUnit = HKUnit.gram() { - didSet { - unitDisplayString = unit.unitDivided(by: .internationalUnit()).shortLocalizedUnitString() - } - } - - override var preferredValueFractionDigits: Int { - return unit.preferredFractionDigits - } - -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/DailyValueScheduleTableViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/DailyValueScheduleTableViewController.swift deleted file mode 100644 index 5d20ffa04..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/DailyValueScheduleTableViewController.swift +++ /dev/null @@ -1,285 +0,0 @@ -// -// DailyValueScheduleTableViewController.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/6/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import LoopKit - - -public protocol DailyValueScheduleTableViewControllerDelegate: AnyObject { - func dailyValueScheduleTableViewControllerWillFinishUpdating(_ controller: DailyValueScheduleTableViewController) -} - - -func insertableIndices(for scheduleItems: [RepeatingScheduleValue], removing row: Int, with interval: TimeInterval) -> [Bool] { - - let insertableIndices = scheduleItems.enumerated().map { (enumeration) -> Bool in - let (index, item) = enumeration - - if row == index { - return true - } else if index == 0 { - return false - } else if index == scheduleItems.endIndex - 1 { - return item.startTime < TimeInterval(hours: 24) - interval - } else if index > row { - return scheduleItems[index + 1].startTime - item.startTime > interval - } else { - return item.startTime - scheduleItems[index - 1].startTime > interval - } - } - - return insertableIndices -} - - -open class DailyValueScheduleTableViewController: UITableViewController, DatePickerTableViewCellDelegate { - - private var keyboardWillShowNotificationObserver: Any? - - public convenience init() { - self.init(style: .plain) - } - - open override func viewDidLoad() { - super.viewDidLoad() - - tableView.rowHeight = UITableView.automaticDimension - tableView.estimatedRowHeight = 44 - - if !isReadOnly { - navigationItem.rightBarButtonItems = [insertButtonItem, editButtonItem] - } - - tableView.keyboardDismissMode = .onDrag - - keyboardWillShowNotificationObserver = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: OperationQueue.main, using: { [weak self] (note) -> Void in - guard let strongSelf = self else { - return - } - - guard note.userInfo?[UIResponder.keyboardIsLocalUserInfoKey] as? Bool == true else { - return - } - - let animated = note.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double ?? 0 > 0 - - if let indexPath = strongSelf.tableView.indexPathForSelectedRow { - strongSelf.tableView.beginUpdates() - strongSelf.tableView.deselectRow(at: indexPath, animated: animated) - strongSelf.tableView.endUpdates() - } - }) - } - - open override func setEditing(_ editing: Bool, animated: Bool) { - if let indexPath = tableView.indexPathForSelectedRow { - tableView.beginUpdates() - tableView.deselectRow(at: indexPath, animated: animated) - tableView.endUpdates() - } - - tableView.endEditing(false) - - navigationItem.rightBarButtonItems?[0].isEnabled = !editing - - super.setEditing(editing, animated: animated) - } - - deinit { - if let observer = keyboardWillShowNotificationObserver { - NotificationCenter.default.removeObserver(observer) - } - } - - open override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - - tableView.endEditing(true) - } - - public weak var delegate: DailyValueScheduleTableViewControllerDelegate? - - public private(set) lazy var insertButtonItem: UIBarButtonItem = { - return UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addScheduleItem(_:))) - }() - - // MARK: - State - - public var timeZone = TimeZone.currentFixed { - didSet { - calendar.timeZone = timeZone - - let localTimeZone = TimeZone.current - let timeZoneDiff = TimeInterval(timeZone.secondsFromGMT() - localTimeZone.secondsFromGMT()) - - if timeZoneDiff != 0 { - let localTimeZoneName = localTimeZone.abbreviation() ?? localTimeZone.identifier - let formatter = DateComponentsFormatter() - formatter.allowedUnits = [.hour, .minute] - let diffString = formatter.string(from: abs(timeZoneDiff)) ?? String(abs(timeZoneDiff)) - - navigationItem.prompt = String( - format: LocalizedString("Times in %1$@%2$@%3$@", comment: "The schedule table view header describing the configured time zone difference from the default time zone. The substitution parameters are: (1: time zone name)(2: +/-)(3: time interval)"), - localTimeZoneName, timeZoneDiff < 0 ? "-" : "+", diffString - ) - } - } - } - - public var unitDisplayString: String = "U/hour" - - public var isReadOnly: Bool = false { - didSet { - if isReadOnly { - isEditing = false - } - - if isViewLoaded { - navigationItem.setRightBarButtonItems(isReadOnly ? [] : [insertButtonItem, editButtonItem], animated: true) - } - } - } - - private var calendar = Calendar.current - - var midnight: Date { - return calendar.startOfDay(for: Date()) - } - - @objc func addScheduleItem(_ sender: Any?) { - guard !isReadOnly else { - return - } - // Updates the table view state. Subclasses should update their data model before calling super - - tableView.insertRows(at: [IndexPath(row: tableView.numberOfRows(inSection: 0), section: 0)], with: .automatic) - } - - func insertableIndiciesByRemovingRow(_ row: Int, withInterval timeInterval: TimeInterval) -> [Bool] { - fatalError("Subclasses must override \(#function)") - } - - // MARK: - UITableViewDataSource - - open override func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - fatalError("Subclasses must override \(#function)") - } - - open override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - return !isReadOnly && indexPath.section == 0 && indexPath.row > 0 - } - - open override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { - return self.tableView(tableView, canEditRowAt: indexPath) - } - - open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - fatalError("Subclasses must override \(#function)") - } - - open override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { - if editingStyle == .delete { - // Updates the table view state. Subclasses should update their data model before calling super - - tableView.deleteRows(at: [indexPath], with: .automatic) - } - } - - // MARK: - UITableViewDelegate - - open override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { - guard indexPath.section == 0 else { - return true - } - - return !isReadOnly && indexPath.row > 0 - } - - open override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { - guard self.tableView(tableView, shouldHighlightRowAt: indexPath) else { - return nil - } - - tableView.endEditing(false) - tableView.beginUpdates() - hideDatePickerCells(excluding: indexPath) - return indexPath - } - - open override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { - tableView.beginUpdates() - tableView.endUpdates() - } - - open override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - tableView.endEditing(false) - tableView.endUpdates() - tableView.deselectRow(at: indexPath, animated: true) - } - - open override func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath { - - guard sourceIndexPath.section == proposedDestinationIndexPath.section else { - return sourceIndexPath - } - - guard sourceIndexPath != proposedDestinationIndexPath, let cell = tableView.cellForRow(at: sourceIndexPath) as? RepeatingScheduleValueTableViewCell else { - return proposedDestinationIndexPath - } - - let interval = cell.datePickerInterval - let indices = insertableIndiciesByRemovingRow(sourceIndexPath.row, withInterval: interval) - - let closestDestinationRow = indices.insertableIndex(closestTo: proposedDestinationIndexPath.row, from: sourceIndexPath.row) - return IndexPath(row: closestDestinationRow, section: proposedDestinationIndexPath.section) - } - - // MARK: - DatePickerTableViewCellDelegate - - public func datePickerTableViewCellDidUpdateDate(_ cell: DatePickerTableViewCell) { - - // Updates the TableView state. Subclasses should update their data model - if let indexPath = tableView.indexPath(for: cell) { - - var indexPaths: [IndexPath] = [] - - if indexPath.row > 0 { - indexPaths.append(IndexPath(row: indexPath.row - 1, section: indexPath.section)) - } - - if indexPath.row < tableView.numberOfRows(inSection: 0) - 1 { - indexPaths.append(IndexPath(row: indexPath.row + 1, section: indexPath.section)) - } - - DispatchQueue.main.async { - self.tableView.reloadRows(at: indexPaths, with: .none) - } - } - } -} - -extension Array where Element == Bool { - func insertableIndex(closestTo destination: Int, from source: Int) -> Int { - if self[destination] { - return destination - } else { - var closestRow = source - for (index, valid) in self.enumerated() where valid { - if abs(destination - index) < abs(destination - closestRow) { - closestRow = index - } - } - return closestRow - } - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/DateAndDurationTableViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/DateAndDurationTableViewController.swift deleted file mode 100644 index 2c3e986e2..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/DateAndDurationTableViewController.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// DateAndDurationTableViewController.swift -// LoopKitUI -// -// Created by Michael Pangburn on 11/24/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - - -public protocol DateAndDurationTableViewControllerDelegate: AnyObject { - func dateAndDurationTableViewControllerDidChangeDate(_ controller: DateAndDurationTableViewController) -} - -public class DateAndDurationTableViewController: UITableViewController { - public enum InputMode { - case date(Date, mode: UIDatePicker.Mode) - case duration(TimeInterval) - } - - public var inputMode: InputMode = .date(Date(), mode: .dateAndTime) { - didSet { - delegate?.dateAndDurationTableViewControllerDidChangeDate(self) - } - } - - public var titleText: String? - - public var contextHelp: String? - - public var indexPath: IndexPath? - - public weak var delegate: DateAndDurationTableViewControllerDelegate? - - public convenience init() { - self.init(style: .grouped) - } - - public override func viewDidLoad() { - super.viewDidLoad() - - tableView.register(DateAndDurationTableViewCell.nib(), forCellReuseIdentifier: DateAndDurationTableViewCell.className) - } - - private var completion: ((InputMode) -> Void)? - - public func onSave(_ completion: @escaping (InputMode) -> Void) { - let saveBarButtonItem = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(save)) - navigationItem.rightBarButtonItem = saveBarButtonItem - self.completion = completion - } - - @objc private func save() { - completion?(inputMode) - dismiss(animated: true) - } - - public override func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return 1 - } - - public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: DateAndDurationTableViewCell.className, for: indexPath) as! DateAndDurationTableViewCell - switch inputMode { - case .date(let date, mode: let mode): - cell.datePicker.datePickerMode = mode - cell.date = date - case .duration(let duration): - cell.datePicker.datePickerMode = .countDownTimer - cell.maximumDuration = .hours(24) - cell.duration = duration - } - cell.titleLabel.text = titleText - cell.isDatePickerHidden = false - cell.selectionStyle = .none - cell.delegate = self - return cell - } - - public override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - return contextHelp - } -} - -extension DateAndDurationTableViewController: DatePickerTableViewCellDelegate { - public func datePickerTableViewCellDidUpdateDate(_ cell: DatePickerTableViewCell) { - switch inputMode { - case .date(_, mode: let mode): - inputMode = .date(cell.date, mode: mode) - case .duration(_): - inputMode = .duration(cell.duration) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/DismissibleHostingController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/DismissibleHostingController.swift deleted file mode 100644 index b0d087f95..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/DismissibleHostingController.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// DismissibleHostingController.swift -// LoopKitUI -// -// Created by Michael Pangburn on 5/7/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public class DismissibleHostingController: UIHostingController { - public enum DismissalMode { - case modalDismiss - case pop(to: UIViewController.Type) - } - - private var onDisappear: () -> Void = {} - - public convenience init ( - rootView: Content, - dismissalMode: DismissalMode = .modalDismiss, - isModalInPresentation: Bool = true, - onDisappear: @escaping () -> Void = {}, - colorPalette: LoopUIColorPalette - ) { - self.init(rootView: rootView, - dismissalMode: dismissalMode, - isModalInPresentation: isModalInPresentation, - onDisappear: onDisappear, - guidanceColors: colorPalette.guidanceColors, - carbTintColor: colorPalette.carbTintColor, - glucoseTintColor: colorPalette.glucoseTintColor, - insulinTintColor: colorPalette.insulinTintColor) - } - - public convenience init( - rootView: Content, - dismissalMode: DismissalMode = .modalDismiss, - isModalInPresentation: Bool = true, - onDisappear: @escaping () -> Void = {}, - guidanceColors: GuidanceColors = GuidanceColors(), - carbTintColor: Color = .green, - glucoseTintColor: Color = Color(.systemTeal), - insulinTintColor: Color = .orange - ) { - // Delay initialization of dismissal closure pushed into SwiftUI Environment until after calling the designated initializer - var dismiss = {} - self.init(rootView: AnyView(rootView.environment(\.dismissAction, { dismiss() }) - .environment(\.guidanceColors, guidanceColors) - .environment(\.carbTintColor, carbTintColor) - .environment(\.glucoseTintColor, glucoseTintColor) - .environment(\.insulinTintColor, insulinTintColor))) - - switch dismissalMode { - case .modalDismiss: - dismiss = { [weak self] in self?.dismiss(animated: true) } - case .pop(to: let PredecessorViewController): - dismiss = { [weak self] in - guard - let navigationController = self?.navigationController, - let predecessor = navigationController.viewControllers.last(where: { $0.isKind(of: PredecessorViewController) }) - else { - return - } - - navigationController.popToViewController(predecessor, animated: true) - } - } - - self.onDisappear = onDisappear - self.isModalInPresentation = isModalInPresentation - } - - public override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - onDisappear() - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/EmojiInputController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/EmojiInputController.swift deleted file mode 100644 index c29f588ad..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/EmojiInputController.swift +++ /dev/null @@ -1,153 +0,0 @@ -// -// EmojiInputController.swift -// LoopKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import UIKit - - -public class EmojiInputController: UIInputViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, IdentifiableClass { - - @IBOutlet private weak var collectionView: UICollectionView! - - @IBOutlet private weak var sectionIndex: UIStackView! - - public weak var delegate: EmojiInputControllerDelegate? - - var emojis: EmojiDataSource! - - static func instance(withEmojis emojis: EmojiDataSource) -> EmojiInputController { - let bundle = Bundle(for: self) - let storyboard = UIStoryboard(name: className, bundle: bundle) - let controller = storyboard.instantiateInitialViewController() as! EmojiInputController - controller.emojis = emojis - return controller - } - - public override func viewDidLoad() { - super.viewDidLoad() - - inputView = view as? UIInputView - inputView?.allowsSelfSizing = true - view.translatesAutoresizingMaskIntoConstraints = false - - if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout { - layout.sectionHeadersPinToVisibleBounds = true - layout.sectionFootersPinToVisibleBounds = true - } - - setupSectionIndex() - - // Scroll to medium absorption - DispatchQueue.main.async { - self.collectionView.scrollToItem(at: IndexPath(row: 0, section: 1), at: .left, animated: false) - } - } - - private func setupSectionIndex() { - sectionIndex.removeAllArrangedSubviews() - - for section in emojis.sections { - let label = UILabel(frame: .zero) - label.text = section.indexSymbol - sectionIndex.addArrangedSubview(label) - } - } - - @IBOutlet weak var deleteButton: UIButton! { - didSet { - let image = UIImage(systemName: "delete.left", compatibleWith: traitCollection) - deleteButton.setImage(image, for: .normal) - } - } - - // MARK: - Actions - - @IBAction func switchKeyboard(_ sender: Any) { - delegate?.emojiInputControllerDidAdvanceToStandardInputMode(self) - } - - @IBAction func deleteBackward(_ sender: Any) { - inputView?.playInputClick​() - textDocumentProxy.deleteBackward() - } - - @IBAction func indexTouched(_ sender: UIGestureRecognizer) { - let xLocation = max(0, sender.location(in: sectionIndex).x / sectionIndex.frame.width) - let items = sectionIndex.arrangedSubviews.count - let section = min(items - 1, Int(xLocation * CGFloat(items))) - - collectionView.scrollToItem(at: IndexPath(item: 0, section: section), at: .left, animated: false) - } - - // MARK: - UICollectionViewDataSource - - public func numberOfSections(in collectionView: UICollectionView) -> Int { - return emojis.sections.count - } - - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return emojis.sections[section].items.count - } - - public func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { - let cell = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: kind == UICollectionView.elementKindSectionHeader ? EmojiInputHeaderView.className : "Footer", for: indexPath) - - if let cell = cell as? EmojiInputHeaderView { - cell.titleLabel.text = emojis.sections[indexPath.section].title.localizedUppercase - } - - return cell - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: EmojiInputCell.className, for: indexPath) as! EmojiInputCell - - cell.label.text = emojis.sections[indexPath.section].items[indexPath.row] - - return cell - } - - // MARK: - UICollectionViewDelegateFlowLayout - - // MARK: - UICollectionViewDelegate - - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - collectionView.deselectItem(at: indexPath, animated: true) - inputView?.playInputClick​() - textDocumentProxy.insertText(emojis.sections[indexPath.section].items[indexPath.row]) - - delegate?.emojiInputControllerDidSelectItemInSection(indexPath.section) - } -} - - -public protocol EmojiInputControllerDelegate: AnyObject { - func emojiInputControllerDidAdvanceToStandardInputMode(_ controller: EmojiInputController) - - func emojiInputControllerDidSelectItemInSection(_ section: Int) -} - -// MARK: - Default Implementations -extension EmojiInputControllerDelegate { - public func emojiInputControllerDidSelectItemInSection(_ section: Int) { } -} - -extension UIInputView: UIInputViewAudioFeedback { - public var enableInputClicksWhenVisible: Bool { return true } - - func playInputClick​() { - let device = UIDevice.current - device.playInputClick() - } -} - -private extension UIStackView { - func removeAllArrangedSubviews() { - for view in arrangedSubviews { - view.removeFromSuperview() - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/GlucoseEntryTableViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/GlucoseEntryTableViewController.swift deleted file mode 100644 index 33ef4711a..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/GlucoseEntryTableViewController.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// GlucoseEntryTableViewController.swift -// LoopKitUI -// -// Created by Michael Pangburn on 11/24/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import HealthKit -import LoopKit - - -public protocol GlucoseEntryTableViewControllerDelegate: AnyObject { - func glucoseEntryTableViewControllerDidChangeGlucose(_ controller: GlucoseEntryTableViewController) -} - -public class GlucoseEntryTableViewController: TextFieldTableViewController { - - let glucoseUnit: HKUnit - - private lazy var glucoseFormatter: NumberFormatter = { - let quantityFormatter = QuantityFormatter() - quantityFormatter.setPreferredNumberFormatter(for: glucoseUnit) - return quantityFormatter.numberFormatter - }() - - public var glucose: HKQuantity? { - get { - guard let value = value, let doubleValue = Double(value) else { - return nil - } - return HKQuantity(unit: glucoseUnit, doubleValue: doubleValue) - } - set { - if let newValue = newValue { - value = glucoseFormatter.string(from: newValue.doubleValue(for: glucoseUnit)) - } else { - value = nil - } - } - } - - public weak var glucoseEntryDelegate: GlucoseEntryTableViewControllerDelegate? - - public init(glucoseUnit: HKUnit) { - self.glucoseUnit = glucoseUnit - super.init(style: .grouped) - unit = glucoseUnit.shortLocalizedUnitString() - keyboardType = .decimalPad - placeholder = "Enter glucose value" - delegate = self - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -extension GlucoseEntryTableViewController: TextFieldTableViewControllerDelegate { - public func textFieldTableViewControllerDidEndEditing(_ controller: TextFieldTableViewController) { - glucoseEntryDelegate?.glucoseEntryTableViewControllerDidChangeGlucose(self) - } - - public func textFieldTableViewControllerDidReturn(_ controller: TextFieldTableViewController) { - glucoseEntryDelegate?.glucoseEntryTableViewControllerDidChangeGlucose(self) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/GlucoseRangeScheduleTableViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/GlucoseRangeScheduleTableViewController.swift deleted file mode 100644 index 4d76bdad1..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/GlucoseRangeScheduleTableViewController.swift +++ /dev/null @@ -1,536 +0,0 @@ -// -// GlucoseRangeScheduleTableViewController.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/13/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import HealthKit -import LoopKit - -public enum SaveGlucoseRangeScheduleResult { - case success - case failure(Error) -} - -public protocol GlucoseRangeScheduleStorageDelegate { - func saveSchedule(for viewController: GlucoseRangeScheduleTableViewController, completion: @escaping (_ result: SaveGlucoseRangeScheduleResult) -> Void) -} - -private struct EditableRange { - public let minValue: Double? - public let maxValue: Double? - - init(minValue: Double?, maxValue: Double?) { - self.minValue = minValue - self.maxValue = maxValue - } -} - -public class GlucoseRangeScheduleTableViewController: UITableViewController { - - public init(allowedValues: [Double], unit: HKUnit, minimumTimeInterval: TimeInterval = TimeInterval(30 * 60)) { - self.allowedValues = allowedValues - self.unit = unit - self.minimumTimeInterval = minimumTimeInterval - - super.init(style: .grouped) - } - - public required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public override func viewDidLoad() { - super.viewDidLoad() - - tableView.register(GlucoseRangeTableViewCell.nib(), forCellReuseIdentifier: GlucoseRangeTableViewCell.className) - tableView.register(GlucoseRangeOverrideTableViewCell.nib(), forCellReuseIdentifier: GlucoseRangeOverrideTableViewCell.className) - tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className) - - navigationItem.rightBarButtonItems = [insertButtonItem, editButtonItem] - - updateEditButton() - } - - @objc private func cancel(_ sender: Any?) { - self.navigationController?.popViewController(animated: true) - } - - public private(set) lazy var insertButtonItem: UIBarButtonItem = { - return UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addScheduleItem(_:))) - }() - - private func updateInsertButton() { - guard let lastItem = editableItems.last else { - return - } - insertButtonItem.isEnabled = !isEditing && lastItem.startTime < lastValidStartTime - } - - open override func setEditing(_ editing: Bool, animated: Bool) { - tableView.beginUpdates() - hideGlucoseRangeCells() - tableView.endUpdates() - - super.setEditing(editing, animated: animated) - - updateInsertButton() - updateSaveButton() - } - - - private func updateSaveButton() { - if let section = sections.firstIndex(of: .save), let cell = tableView.cellForRow(at: IndexPath(row: 0, section: section)) as? TextButtonTableViewCell { - cell.isEnabled = !isEditing && isScheduleModified && isScheduleValid - } - } - - private var isScheduleValid: Bool { - return !editableItems.isEmpty && - editableItems.allSatisfy { isValid($0.value) } - } - - private func updateEditButton() { - editButtonItem.isEnabled = editableItems.endIndex > 1 - } - - public func setSchedule(_ schedule: GlucoseRangeSchedule, withOverrideRanges overrides: [TemporaryScheduleOverride.Context: DoubleRange]) { - unit = schedule.unit - editableItems = schedule.items.map({ (item) -> RepeatingScheduleValue in - let range = EditableRange(minValue: item.value.minValue, maxValue: item.value.maxValue) - return RepeatingScheduleValue(startTime: item.startTime, value: range) - }) - - editableOverrideRanges.removeAll() - for (context, range) in overrides { - editableOverrideRanges[context] = EditableRange(minValue: range.minValue, maxValue: range.maxValue) - } - - isScheduleModified = false - } - - private func isValid(_ range: EditableRange) -> Bool { - guard let max = range.maxValue, let min = range.minValue, min <= max else { - return false - } - return allowedValues.contains(max) && allowedValues.contains(min) - } - - @IBAction func addScheduleItem(_ sender: Any?) { - - guard let allowedTimeRange = allowedTimeRange(for: editableItems.count) else { - return - } - - editableItems.append( - RepeatingScheduleValue( - startTime: allowedTimeRange.lowerBound, - value: editableItems.last?.value ?? EditableRange(minValue: nil, maxValue: nil) - ) - ) - - tableView.beginUpdates() - - tableView.insertRows(at: [IndexPath(row: editableItems.count - 1, section: Section.schedule.rawValue)], with: .automatic) - - if editableItems.count == 1 { - tableView.insertSections(IndexSet(integer: Section.override.rawValue), with: .automatic) - } - - tableView.endUpdates() - } - - private func updateTimeLimits(for index: Int) { - let indexPath = IndexPath(row: index, section: Section.schedule.rawValue) - if let allowedTimeRange = allowedTimeRange(for: index), let cell = tableView.cellForRow(at: indexPath) as? GlucoseRangeTableViewCell { - cell.allowedTimeRange = allowedTimeRange - } - } - - private func allowedTimeRange(for index: Int) -> ClosedRange? { - let minTime: TimeInterval - let maxTime: TimeInterval - if index == 0 { - maxTime = TimeInterval(0) - } else if index+1 < editableItems.endIndex { - maxTime = editableItems[index+1].startTime - minimumTimeInterval - } else { - maxTime = lastValidStartTime - } - if index > 0 { - minTime = editableItems[index-1].startTime + minimumTimeInterval - if minTime > lastValidStartTime { - return nil - } - } else { - minTime = TimeInterval(0) - } - return minTime...maxTime - } - - func insertableIndices(removing row: Int) -> [Bool] { - - let insertableIndices = editableItems.enumerated().map { (enumeration) -> Bool in - let (index, item) = enumeration - - if row == index { - return true - } else if index == 0 { - return false - } else if index == editableItems.endIndex - 1 { - return item.startTime < TimeInterval(hours: 24) - minimumTimeInterval - } else if index > row { - return editableItems[index + 1].startTime - item.startTime > minimumTimeInterval - } else { - return item.startTime - editableItems[index - 1].startTime > minimumTimeInterval - } - } - - return insertableIndices - } - - - - // MARK: - State - - public var delegate: GlucoseRangeScheduleStorageDelegate? - - let allowedValues: [Double] - let minimumTimeInterval: TimeInterval - - var lastValidStartTime: TimeInterval { - return TimeInterval.hours(24) - minimumTimeInterval - } - - public var timeZone = TimeZone.currentFixed - - private var unit: HKUnit = HKUnit.milligramsPerDeciliter - - private var isScheduleModified = false { - didSet { - if isScheduleModified { - self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancel(_:))) - } else { - self.navigationItem.leftBarButtonItem = nil - } - updateSaveButton() - } - } - - private var editableItems: [RepeatingScheduleValue] = [] { - didSet { - isScheduleModified = true - updateInsertButton() - updateEditButton() - } - } - - public var schedule: GlucoseRangeSchedule? { - get { - let dailyItems = editableItems.compactMap { (item) -> RepeatingScheduleValue? in - guard isValid(item.value) else { - return nil - } - guard let min = item.value.minValue, let max = item.value.maxValue else { - return nil - } - let range = DoubleRange(minValue: min, maxValue: max) - return RepeatingScheduleValue(startTime: item.startTime, value: range) - } - return GlucoseRangeSchedule(unit: unit, dailyItems: dailyItems) - } - } - - public var overrideContexts: [TemporaryScheduleOverride.Context] = [.preMeal, .legacyWorkout] - - private var editableOverrideRanges: [TemporaryScheduleOverride.Context: EditableRange] = [:] { - didSet { - isScheduleModified = true - } - } - - public var overrideRanges: [TemporaryScheduleOverride.Context: DoubleRange] { - get { - var setRanges: [TemporaryScheduleOverride.Context: DoubleRange] = [:] - for (context, range) in editableOverrideRanges { - if let minValue = range.minValue, let maxValue = range.maxValue, isValid(range) { - setRanges[context] = DoubleRange(minValue: minValue, maxValue: maxValue) - } - } - return setRanges - } - } - - - // MARK: - UITableViewDataSource - - private enum Section: Int, CaseIterable { - case schedule = 0 - case override - case save - } - - private var showOverrides: Bool { - return !editableItems.isEmpty - } - - private var sections: [Section] { - if !showOverrides { - return [.schedule, .save] - } else { - return Section.allCases - } - } - - public override func numberOfSections(in tableView: UITableView) -> Int { - return sections.count - } - - public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch sections[section] { - case .schedule: - return editableItems.count - case .override: - return overrideContexts.count - case .save: - return 1 - } - } - - public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch sections[indexPath.section] { - case .schedule: - let cell = tableView.dequeueReusableCell(withIdentifier: GlucoseRangeTableViewCell.className, for: indexPath) as! GlucoseRangeTableViewCell - - let item = editableItems[indexPath.row] - - cell.timeZone = timeZone - cell.startTime = item.startTime - - cell.allowedValues = allowedValues - - cell.valueNumberFormatter.minimumFractionDigits = unit.preferredFractionDigits - cell.valueNumberFormatter.maximumFractionDigits = unit.preferredFractionDigits - - cell.minValue = item.value.minValue - cell.maxValue = item.value.maxValue - cell.unitString = unit.shortLocalizedUnitString() - cell.delegate = self - - if let allowedTimeRange = allowedTimeRange(for: indexPath.row) { - cell.allowedTimeRange = allowedTimeRange - } - - return cell - case .override: - let cell = tableView.dequeueReusableCell(withIdentifier: GlucoseRangeOverrideTableViewCell.className, for: indexPath) as! GlucoseRangeOverrideTableViewCell - - cell.valueNumberFormatter.minimumFractionDigits = unit.preferredFractionDigits - cell.valueNumberFormatter.maximumFractionDigits = unit.preferredFractionDigits - cell.allowedValues = allowedValues - - let context = overrideContexts[indexPath.row] - - if let range = overrideRanges[context], !range.isZero { - cell.minValue = range.minValue - cell.maxValue = range.maxValue - } - - let bundle = Bundle(for: type(of: self)) - let titleText: String - let image: UIImage? - - switch context { - case .legacyWorkout: - titleText = LocalizedString("Workout", comment: "Title for the workout override range") - image = UIImage(named: "workout", in: bundle, compatibleWith: traitCollection) - case .preMeal: - titleText = LocalizedString("Pre-Meal", comment: "Title for the pre-meal override range") - image = UIImage(named: "Pre-Meal", in: bundle, compatibleWith: traitCollection) - default: - preconditionFailure("Unexpected override context \(context)") - } - - cell.dateLabel.text = titleText - cell.iconImageView.image = image - - cell.unitString = unit.shortLocalizedUnitString() - cell.delegate = self - - return cell - case .save: - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell - - cell.textLabel?.text = LocalizedString("Save", comment: "Button text for saving glucose correction range schedule") - cell.isEnabled = isScheduleModified - return cell - } - } - - public override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { - if editingStyle == .delete, let overrideSectionIndex = sections.firstIndex(of: .override) { - editableItems.remove(at: indexPath.row) - - tableView.performBatchUpdates({ - tableView.deleteRows(at: [indexPath], with: .automatic) - - if editableItems.isEmpty { - tableView.deleteSections(IndexSet(integer: overrideSectionIndex), with: .automatic) - } - }, completion: nil) - - if editableItems.count == 1 { - setEditing(false, animated: true) - } - - updateSaveButton() - } - } - - public override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { - if sourceIndexPath != destinationIndexPath { - switch sections[destinationIndexPath.section] { - case .schedule: - let item = editableItems.remove(at: sourceIndexPath.row) - editableItems.insert(item, at: destinationIndexPath.row) - - guard destinationIndexPath.row > 0 else { - return - } - - let startTime = editableItems[destinationIndexPath.row - 1].startTime + minimumTimeInterval - - editableItems[destinationIndexPath.row] = RepeatingScheduleValue(startTime: startTime, value: editableItems[destinationIndexPath.row].value) - - // Since the valid date ranges of neighboring cells are affected, the lazy solution is to just reload the entire table view - DispatchQueue.main.async { - tableView.reloadData() - } - case .override, .save: - break - } - } - } - - public override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - switch sections[indexPath.section] { - case .schedule: - return indexPath.row > 0 - default: - return false - } - } - - public override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { - switch sections[indexPath.section] { - case .schedule: - return true - default: - return false - } - } - - public override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - switch sections[section] { - case .override: - return LocalizedString("Overrides", comment: "The section title of glucose overrides") - default: - return nil - } - } - - public override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - switch sections[section] { - case .schedule: - return LocalizedString("Correction range is the blood glucose range that you would like Loop to correct to.", comment: "The section footer of correction range schedule") - default: - return nil - } - } - - // MARK: - UITableViewDelegate - - public override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { - return true - } - - public override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { - tableView.beginUpdates() - switch sections[indexPath.section] { - case .schedule: - updateTimeLimits(for: indexPath.row) - hideGlucoseRangeCells(excluding: indexPath) - case .override: - hideGlucoseRangeCells(excluding: indexPath) - default: - break - } - tableView.endEditing(false) - - return indexPath - } - - public override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { - tableView.beginUpdates() - tableView.endUpdates() - } - - public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - switch sections[indexPath.section] { - case .save: - delegate?.saveSchedule(for: self, completion: { (result) in - switch result { - case .success: - self.isScheduleModified = false - self.updateInsertButton() - case .failure(let error): - self.present(UIAlertController(with: error), animated: true) - } - }) - default: - break - } - tableView.endEditing(false) - tableView.endUpdates() - tableView.deselectRow(at: indexPath, animated: true) - } - - public override func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath { - - guard sourceIndexPath.section == proposedDestinationIndexPath.section else { - return sourceIndexPath - } - - guard sourceIndexPath != proposedDestinationIndexPath else { - return proposedDestinationIndexPath - } - - let indices = insertableIndices(removing: sourceIndexPath.row) - - let closestDestinationRow = indices.insertableIndex(closestTo: proposedDestinationIndexPath.row, from: sourceIndexPath.row) - return IndexPath(row: closestDestinationRow, section: proposedDestinationIndexPath.section) - } - -} - -extension GlucoseRangeScheduleTableViewController : GlucoseRangeTableViewCellDelegate { - func glucoseRangeTableViewCellDidUpdate(_ cell: GlucoseRangeTableViewCell) { - if let indexPath = tableView.indexPath(for: cell) { - switch sections[indexPath.section] { - case .schedule: - editableItems[indexPath.row] = RepeatingScheduleValue( - startTime: cell.startTime, - value: EditableRange(minValue: cell.minValue, maxValue: cell.maxValue) - ) - case .override: - let context = overrideContexts[indexPath.row] - editableOverrideRanges[context] = EditableRange(minValue: cell.minValue, maxValue: cell.maxValue) - default: - break - } - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/HistoricalOverrideDetailView.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/HistoricalOverrideDetailView.swift deleted file mode 100644 index 791b131b1..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/HistoricalOverrideDetailView.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// HistoricalOverrideDetailView.swift -// LoopKitUI -// -// Created by Anna Quinlan on 8/4/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// -import SwiftUI -import LoopKit -import HealthKit - - -public struct HistoricalOverrideDetailView: UIViewControllerRepresentable { - public var override: TemporaryScheduleOverride - public var glucoseUnit: HKUnit - public weak var delegate: AddEditOverrideTableViewControllerDelegate? - - public init( - override: TemporaryScheduleOverride, - glucoseUnit: HKUnit, - delegate: AddEditOverrideTableViewControllerDelegate? - ) { - self.override = override - self.glucoseUnit = glucoseUnit - self.delegate = delegate - } - - public func makeUIViewController(context: Context) -> AddEditOverrideTableViewController { - let viewController = AddEditOverrideTableViewController(glucoseUnit: glucoseUnit) - viewController.inputMode = .viewOverride(override) - viewController.delegate = delegate - viewController.view.isUserInteractionEnabled = false // disable interactions while viewing historical data - - return viewController - } - - public func updateUIViewController(_ viewController: AddEditOverrideTableViewController, context: Context) { } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/InsulinSensitivityScheduleViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/InsulinSensitivityScheduleViewController.swift deleted file mode 100644 index b10cdd3a3..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/InsulinSensitivityScheduleViewController.swift +++ /dev/null @@ -1,387 +0,0 @@ -// -// InsulinSensitivityScheduleViewController.swift -// LoopKitUI -// -// Created by Pete Schwamb on 7/2/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit -import HealthKit -import LoopKit - -public enum SaveInsulinSensitivityScheduleResult { - case success - case failure(Error) -} - -public protocol InsulinSensitivityScheduleStorageDelegate { - func saveSchedule(_ schedule: InsulinSensitivitySchedule, for viewController: InsulinSensitivityScheduleViewController, completion: @escaping (_ result: SaveInsulinSensitivityScheduleResult) -> Void) -} - -public class InsulinSensitivityScheduleViewController : DailyValueScheduleTableViewController { - - public init(allowedValues: [Double], unit: HKUnit, minimumTimeInterval: TimeInterval = TimeInterval(30 * 60)) { - self.allowedValues = allowedValues - self.minimumTimeInterval = minimumTimeInterval - self.unit = unit - - super.init(style: .grouped) - } - - public required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - open override func viewDidLoad() { - super.viewDidLoad() - - tableView.register(SetConstrainedScheduleEntryTableViewCell.nib(), forCellReuseIdentifier: SetConstrainedScheduleEntryTableViewCell.className) - tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className) - updateEditButton() - } - - @objc private func cancel(_ sender: Any?) { - self.navigationController?.popViewController(animated: true) - } - - // MARK: - State - - public var insulinSensitivityScheduleStorageDelegate: InsulinSensitivityScheduleStorageDelegate? - - public var unit: HKUnit = HKUnit.milligramsPerDeciliter.unitDivided(by: .internationalUnit()) - - public var schedule: InsulinSensitivitySchedule? { - get { - let validEntries = internalItems.compactMap { (item) -> RepeatingScheduleValue? in - guard let value = item.value else { - return nil - } - return RepeatingScheduleValue(startTime: item.startTime, value: value) - } - return InsulinSensitivitySchedule(unit: unit, dailyItems: validEntries, timeZone: timeZone) - } - set { - if let newValue = newValue { - unit = newValue.unit - internalItems = newValue.items.map { (entry) -> RepeatingScheduleValue in - RepeatingScheduleValue(startTime: entry.startTime, value: entry.value) - } - isScheduleModified = false - } else { - internalItems = [] - } - } - } - - private var internalItems: [RepeatingScheduleValue] = [] { - didSet { - isScheduleModified = true - updateInsertButton() - } - } - - let allowedValues: [Double] - let minimumTimeInterval: TimeInterval - - var lastValidStartTime: TimeInterval { - return TimeInterval.hours(24) - minimumTimeInterval - } - - private var isScheduleModified = false { - didSet { - updateCancelButton() - updateSaveButton() - } - } - - private func isValid(_ value: Double?) -> Bool { - guard let value = value else { - return false - } - return allowedValues.contains(value) - } - - public var isScheduleValid: Bool { - return !internalItems.isEmpty && - internalItems.allSatisfy { isValid($0.value) } - } - - private func updateCancelButton() { - if isScheduleModified { - self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancel(_:))) - } else { - self.navigationItem.leftBarButtonItem = nil - } - } - - private func updateSaveButton() { - if let cell = tableView.cellForRow(at: IndexPath(row: 0, section: Section.save.rawValue)) as? TextButtonTableViewCell { - cell.isEnabled = !isEditing && isScheduleModified && isScheduleValid - } - } - - private func updateEditButton() { - editButtonItem.isEnabled = internalItems.endIndex > 1 - } - - private func updateInsertButton() { - guard let lastItem = internalItems.last else { - return - } - insertButtonItem.isEnabled = !isEditing && lastItem.startTime < lastValidStartTime - } - - override func addScheduleItem(_ sender: Any?) { - tableView.endEditing(false) - - let startTime: TimeInterval - let value: Double? - - if let lastItem = internalItems.last { - startTime = lastItem.startTime + minimumTimeInterval - value = lastItem.value - - if startTime > lastValidStartTime { - return - } - } else { - startTime = TimeInterval(0) - value = nil - } - - internalItems.append( - RepeatingScheduleValue( - startTime: startTime, - value: value - ) - ) - updateTimeLimitsForItemsAdjacent(to: internalItems.endIndex-1) - - super.addScheduleItem(sender) - - if internalItems.count == 1 { - let index = IndexPath(row: 0, section: Section.schedule.rawValue) - tableView.beginUpdates() - tableView.selectRow(at: index, animated: true, scrollPosition: .top) - tableView.deselectRow(at: index, animated: true) - tableView.endUpdates() - } else { - tableView.beginUpdates() - hideSetConstrainedScheduleEntryCells() - tableView.endUpdates() - } - - updateEditButton() - } - - override func insertableIndiciesByRemovingRow(_ row: Int, withInterval timeInterval: TimeInterval) -> [Bool] { - return insertableIndices(for: internalItems, removing: row, with: timeInterval) - } - - open override func setEditing(_ editing: Bool, animated: Bool) { - tableView.beginUpdates() - hideSetConstrainedScheduleEntryCells() - tableView.endUpdates() - - super.setEditing(editing, animated: animated) - updateInsertButton() - updateSaveButton() - } - - - private func updateTimeLimitsFor(itemAt index: Int) { - guard internalItems.indices.contains(index) else { - return - } - let indexPath = IndexPath(row: index, section: Section.schedule.rawValue) - if let cell = tableView.cellForRow(at: indexPath) as? SetConstrainedScheduleEntryTableViewCell { - if index+1 < internalItems.endIndex { - cell.maximumStartTime = internalItems[index+1].startTime - minimumTimeInterval - } else { - cell.maximumStartTime = lastValidStartTime - } - if index > 1 { - cell.minimumStartTime = internalItems[index-1].startTime + minimumTimeInterval - } - } - } - - private func updateTimeLimitsForItemsAdjacent(to index: Int) { - updateTimeLimitsFor(itemAt: index-1) - updateTimeLimitsFor(itemAt: index+1) - } - - - // MARK: - UITableViewDataSource - - private enum Section: Int, CaseIterable { - case schedule - case save - } - - open override func numberOfSections(in tableView: UITableView) -> Int { - return Section.allCases.count - } - - open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch Section(rawValue: section)! { - case .schedule: - return internalItems.endIndex - case .save: - return 1 - } - } - - open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch Section(rawValue: indexPath.section)! { - case .schedule: - let cell = tableView.dequeueReusableCell(withIdentifier: SetConstrainedScheduleEntryTableViewCell.className, for: indexPath) as! SetConstrainedScheduleEntryTableViewCell - - cell.unit = unit.unitDivided(by: .internationalUnit()) - - let item = internalItems[indexPath.row] - - cell.allowedValues = allowedValues - cell.minimumTimeInterval = minimumTimeInterval - cell.isReadOnly = false - cell.isPickerHidden = true - cell.delegate = self - cell.timeZone = timeZone - - if indexPath.row > 0 { - let lastItem = internalItems[indexPath.row - 1] - - cell.minimumStartTime = lastItem.startTime + minimumTimeInterval - } - - if indexPath.row == 0 { - cell.maximumStartTime = 0 - } else if indexPath.row < internalItems.endIndex - 1 { - let nextItem = internalItems[indexPath.row + 1] - cell.maximumStartTime = nextItem.startTime - minimumTimeInterval - } else { - cell.maximumStartTime = lastValidStartTime - } - - cell.value = item.value - cell.startTime = item.startTime - cell.emptySelectionType = .lastIndex - - return cell - case .save: - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell - cell.textLabel?.text = LocalizedString("Save", comment: "Button text for saving insulin sensitivity schedule") - cell.isEnabled = isScheduleModified && isScheduleValid - - return cell - } - } - - open override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - switch Section(rawValue: section)! { - case .schedule: - return LocalizedString("Insulin sensitivity describes how your blood glucose should respond to a 1 Unit dose of insulin. Smaller values mean more insulin will be given when above target. Values that are too small can cause dangerously low blood glucose.", comment: "The description shown on the insulin sensitivity schedule interface.") - case .save: - return nil - } - } - - open override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { - if editingStyle == .delete { - internalItems.remove(at: indexPath.row) - - super.tableView(tableView, commit: editingStyle, forRowAt: indexPath) - - if internalItems.count == 1 { - self.isEditing = false - } - - updateInsertButton() - updateEditButton() - updateTimeLimitsFor(itemAt: indexPath.row-1) - updateTimeLimitsFor(itemAt: indexPath.row) - updateSaveButton() - } - } - - open override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { - if sourceIndexPath != destinationIndexPath { - let item = internalItems.remove(at: sourceIndexPath.row) - internalItems.insert(item, at: destinationIndexPath.row) - - let startTime = internalItems[destinationIndexPath.row - 1].startTime + minimumTimeInterval - - internalItems[destinationIndexPath.row] = RepeatingScheduleValue(startTime: startTime, value: internalItems[destinationIndexPath.row].value) - - DispatchQueue.main.async { - tableView.reloadRows(at: [destinationIndexPath], with: .none) - self.updateTimeLimitsForItemsAdjacent(to: destinationIndexPath.row) - } - } - } - - // MARK: - UITableViewDelegate - - open override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { - guard indexPath.section == Section.schedule.rawValue else { - return super.tableView(tableView, shouldHighlightRowAt: indexPath) - } - - return !isReadOnly - } - - open override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { - tableView.beginUpdates() - hideSetConstrainedScheduleEntryCells(excluding: indexPath) - tableView.endUpdates() - return super.tableView(tableView, willSelectRowAt: indexPath) - } - - open override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - super.tableView(tableView, didSelectRowAt: indexPath) - - switch Section(rawValue: indexPath.section)! { - case .schedule: - break - case .save: - if let schedule = schedule { - insulinSensitivityScheduleStorageDelegate?.saveSchedule(schedule, for: self, completion: { (result) in - switch result { - case .success: - self.delegate?.dailyValueScheduleTableViewControllerWillFinishUpdating(self) - self.isScheduleModified = false - self.updateInsertButton() - case .failure(let error): - self.present(UIAlertController(with: error), animated: true) - } - }) - } - } - } - - open override func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath { - - guard sourceIndexPath != proposedDestinationIndexPath, let cell = tableView.cellForRow(at: sourceIndexPath) as? SetConstrainedScheduleEntryTableViewCell else { - return proposedDestinationIndexPath - } - - let interval = cell.minimumTimeInterval - let indices = insertableIndices(for: internalItems, removing: sourceIndexPath.row, with: interval) - - let closestDestinationRow = indices.insertableIndex(closestTo: proposedDestinationIndexPath.row, from: sourceIndexPath.row) - return IndexPath(row: closestDestinationRow, section: proposedDestinationIndexPath.section) - } -} - -extension InsulinSensitivityScheduleViewController: SetConstrainedScheduleEntryTableViewCellDelegate { - func setConstrainedScheduleEntryTableViewCellDidUpdate(_ cell: SetConstrainedScheduleEntryTableViewCell) { - if let indexPath = tableView.indexPath(for: cell) { - internalItems[indexPath.row] = RepeatingScheduleValue( - startTime: cell.startTime, - value: cell.value - ) - updateTimeLimitsForItemsAdjacent(to: indexPath.row) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/OverrideSelectionViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/OverrideSelectionViewController.swift deleted file mode 100644 index c340089f7..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/OverrideSelectionViewController.swift +++ /dev/null @@ -1,513 +0,0 @@ -// -// OverrideSelectionViewController.swift -// Loop -// -// Created by Michael Pangburn on 1/2/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit -import HealthKit -import LoopKit -import SwiftUI -import Intents -import os.log - - -public protocol OverrideSelectionViewControllerDelegate: AnyObject { - func overrideSelectionViewController(_ vc: OverrideSelectionViewController, didUpdatePresets presets: [TemporaryScheduleOverridePreset]) - func overrideSelectionViewController(_ vc: OverrideSelectionViewController, didConfirmPreset preset: TemporaryScheduleOverridePreset) - func overrideSelectionViewController(_ vc: OverrideSelectionViewController, didConfirmOverride override: TemporaryScheduleOverride) - func overrideSelectionViewController(_ vc: OverrideSelectionViewController, didCancelOverride override: TemporaryScheduleOverride) -} - -public final class OverrideSelectionViewController: UICollectionViewController, IdentifiableClass { - - public var glucoseUnit: HKUnit! - - public var scheduledOverride: TemporaryScheduleOverride? - - public var presets: [TemporaryScheduleOverridePreset] = [] { - didSet { - delegate?.overrideSelectionViewController(self, didUpdatePresets: presets) - } - } - - public var overrideHistory: [TemporaryScheduleOverride] = [] - - public weak var delegate: OverrideSelectionViewControllerDelegate? - - private lazy var saveButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addNewPreset)) - private lazy var editButton = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(beginEditing)) - private lazy var doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(endEditing)) - private lazy var cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancel)) - - public override func viewDidLoad() { - super.viewDidLoad() - - title = LocalizedString("Custom Preset", comment: "The title for the custom preset selection screen") - collectionView?.backgroundColor = .systemGroupedBackground - navigationItem.rightBarButtonItems = [saveButton, editButton] - navigationItem.leftBarButtonItem = cancelButton - } - - @objc private func cancel() { - dismiss(animated: true) - } - - enum Section: Int, CaseIterable { - case scheduledOverride = 0 - case presets - } - - private var sections: [Section] { - var sections = Section.allCases - if scheduledOverride == nil { - sections.remove(.scheduledOverride) - } - return sections - } - - private var presetSection: Int { - sections.firstIndex(of: .presets)! - } - - private func section(for sectionIndex: Int) -> Section { - return sections[sectionIndex] - } - - private enum CellContent { - case scheduledOverride(TemporaryScheduleOverride) - case preset(TemporaryScheduleOverridePreset) - case customOverride - case history - } - - private func cellContent(for indexPath: IndexPath) -> CellContent { - switch section(for: indexPath.section) { - case .scheduledOverride: - guard let scheduledOverride = scheduledOverride else { - preconditionFailure("`sections` must contain `.scheduledOverride`") - } - return .scheduledOverride(scheduledOverride) - case .presets: - if presets.indices.contains(indexPath.row) { - return .preset(presets[indexPath.row]) - } else if indexPathOfCustomOverride().row == indexPath.row { - return .customOverride - } else { - return .history - } - } - } - - private func indexPathOfCustomOverride() -> IndexPath { - let section = sections.firstIndex(of: .presets)! - let row = self.collectionView(collectionView, numberOfItemsInSection: section) - 2 - return IndexPath(row: row, section: section) - } - - public override func numberOfSections(in collectionView: UICollectionView) -> Int { - return sections.count - } - - public override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - switch self.section(for: section) { - case .scheduledOverride: - return 1 - case .presets: - // +1 for custom override and +1 for history - return presets.count + 2 - } - } - - public override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { - switch kind { - case UICollectionView.elementKindSectionHeader: - let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: OverrideSelectionHeaderView.className, for: indexPath) as! OverrideSelectionHeaderView - switch section(for: indexPath.section) { - case .scheduledOverride: - header.titleLabel.text = LocalizedString("SCHEDULED PRESET", comment: "The section header text for a scheduled custom preset") - case .presets: - if scheduledOverride != nil { - header.titleLabel.text = LocalizedString("PRESETS", comment: "The section header text for custom presets") - } else { - header.titleLabel.text?.removeAll() - } - } - return header - case UICollectionView.elementKindSectionFooter: - let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: OverrideSelectionFooterView.className, for: indexPath) as! OverrideSelectionFooterView - footer.textLabel.text = LocalizedString("Tap '+' to create a new custom preset.", comment: "Text directing the user to configure their first custom preset") - return footer - default: - fatalError("Unexpected supplementary element kind \(kind)") - } - } - - public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { - let height: CGFloat = section == 0 && scheduledOverride == nil ? 8 : 50 - return CGSize(width: collectionView.bounds.width, height: height) - } - - private lazy var quantityFormatter: QuantityFormatter = { - let quantityFormatter = QuantityFormatter() - quantityFormatter.setPreferredNumberFormatter(for: glucoseUnit) - return quantityFormatter - }() - - private lazy var glucoseNumberFormatter = quantityFormatter.numberFormatter - - private lazy var durationFormatter: DateComponentsFormatter = { - let formatter = DateComponentsFormatter() - formatter.allowedUnits = [.hour, .minute] - formatter.unitsStyle = .abbreviated - return formatter - }() - - public override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - let customSymbol = "⋯" - let customName = LocalizedString("Custom", comment: "The text for a custom preset") - let historyLabel = LocalizedString("History", comment: "The text for the override history") - - switch cellContent(for: indexPath) { - case .scheduledOverride(let override): - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: OverridePresetCollectionViewCell.className, for: indexPath) as! OverridePresetCollectionViewCell - cell.delegate = self - if case .preset(let preset) = override.context { - cell.symbolLabel.text = preset.symbol - cell.nameLabel.text = preset.name - } else { - cell.symbolLabel.text = customSymbol - cell.nameLabel.text = customName - } - - cell.startTimeLabel.text = DateFormatter.localizedString(from: override.startDate, dateStyle: .none, timeStyle: .short) - configure(cell, with: override.settings, duration: override.duration) - cell.scheduleButton.isHidden = true - if isEditingPresets { - cell.applyOverlayToFade(animated: false) - } - - return cell - case .preset(let preset): - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: OverridePresetCollectionViewCell.className, for: indexPath) as! OverridePresetCollectionViewCell - cell.delegate = self - cell.symbolLabel.text = preset.symbol - cell.nameLabel.text = preset.name - configure(cell, with: preset.settings, duration: preset.duration) - if isEditingPresets { - cell.configureForEditing(animated: false) - } - - return cell - case .customOverride: - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CustomOverrideCollectionViewCell.className, for: indexPath) as! CustomOverrideCollectionViewCell - cell.titleLabel.text = customName - if isEditingPresets { - cell.applyOverlayToFade(animated: false) - } - - return cell - case .history: - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: OverrideHistoryCollectionViewCell.className, for: indexPath) as! OverrideHistoryCollectionViewCell - cell.titleLabel.text = historyLabel - cell.titleLabel.accessibilityLabel = historyLabel - if isEditingPresets { - cell.applyOverlayToFade(animated: false) - } - - return cell - } - } - - private func configure(_ cell: OverridePresetCollectionViewCell, with settings: TemporaryScheduleOverrideSettings, duration: TemporaryScheduleOverride.Duration) { - if let targetRange = settings.targetRange { - cell.targetRangeLabel.text = makeTargetRangeText(from: targetRange) - } else { - cell.targetRangeLabel.isHidden = true - } - - if let insulinNeedsScaleFactor = settings.insulinNeedsScaleFactor { - cell.insulinNeedsBar.progress = insulinNeedsScaleFactor - } else { - cell.insulinNeedsBar.isHidden = true - } - - switch duration { - case .finite(let interval): - cell.durationLabel.text = durationFormatter.string(from: interval) - case .indefinite: - cell.durationLabel.text = "∞" - } - } - - private func makeTargetRangeText(from targetRange: ClosedRange) -> String { - guard - let minTarget = glucoseNumberFormatter.string(from: targetRange.lowerBound.doubleValue(for: glucoseUnit)), - let maxTarget = glucoseNumberFormatter.string(from: targetRange.upperBound.doubleValue(for: glucoseUnit)) - else { - return "" - } - - return String(format: LocalizedString("%1$@ – %2$@ %3$@", comment: "The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit)"), minTarget, maxTarget, quantityFormatter.string(from: glucoseUnit)) - } - - public override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - if isEditingPresets { - switch cellContent(for: indexPath) { - case .scheduledOverride, .customOverride, .history: - break - case .preset(let preset): - let editVC = AddEditOverrideTableViewController(glucoseUnit: glucoseUnit) - editVC.inputMode = .editPreset(preset) - editVC.delegate = self - show(editVC, sender: collectionView.cellForItem(at: indexPath)) - } - } else { - switch cellContent(for: indexPath) { - case .scheduledOverride(let override): - let editOverrideVC = AddEditOverrideTableViewController(glucoseUnit: glucoseUnit) - editOverrideVC.inputMode = .editOverride(override) - editOverrideVC.customDismissalMode = .dismissModal - editOverrideVC.delegate = self - show(editOverrideVC, sender: collectionView.cellForItem(at: indexPath)) - case .preset(let preset): - delegate?.overrideSelectionViewController(self, didConfirmPreset: preset) - dismiss(animated: true) - case .customOverride: - let customOverrideVC = AddEditOverrideTableViewController(glucoseUnit: glucoseUnit) - customOverrideVC.inputMode = .customOverride - customOverrideVC.delegate = self - show(customOverrideVC, sender: collectionView.cellForItem(at: indexPath)) - case .history: - let model = OverrideHistoryViewModel( - overrides: overrideHistory, - glucoseUnit: glucoseUnit - ) - let overrideHistoryView = OverrideSelectionHistory(model: model) - let hostedView = UIHostingController(rootView: overrideHistoryView) - hostedView.title = LocalizedString("Override History", comment: "Title for override history view") // Hack to fix animations - navigationController?.pushViewController(hostedView, animated: true) - } - } - } - - @objc private func addNewPreset() { - let addVC = AddEditOverrideTableViewController(glucoseUnit: glucoseUnit) - addVC.inputMode = .newPreset - addVC.delegate = self - - let navigationWrapper = UINavigationController(rootViewController: addVC) - present(navigationWrapper, animated: true) - } - - private var isEditingPresets = false { - didSet { - saveButton.isEnabled = !isEditingPresets - cancelButton.isEnabled = !isEditingPresets - } - } - - @objc private func beginEditing() { - isEditingPresets = true - navigationItem.setRightBarButtonItems([saveButton, doneButton], animated: true) - configureCellsForEditingChanged() - - if let scheduledOverrideSection = sections.firstIndex(of: .scheduledOverride) { - let scheduledOverrideIndexPath = IndexPath(row: 0, section: scheduledOverrideSection) - guard let scheduledOverrideCell = collectionView.cellForItem(at: scheduledOverrideIndexPath) as? OverridePresetCollectionViewCell else { - return - } - - scheduledOverrideCell.applyOverlayToFade(animated: true) - } - - if let customOverrideCell = collectionView.cellForItem(at: indexPathOfCustomOverride()) as? CustomOverrideCollectionViewCell { - customOverrideCell.applyOverlayToFade(animated: true) - } - } - - @objc private func endEditing() { - isEditingPresets = false - navigationItem.setRightBarButtonItems([saveButton, editButton], animated: true) - configureCellsForEditingChanged() - - if let scheduledOverrideSection = sections.firstIndex(of: .scheduledOverride) { - let scheduledOverrideIndexPath = IndexPath(row: 0, section: scheduledOverrideSection) - guard let scheduledOverrideCell = collectionView.cellForItem(at: scheduledOverrideIndexPath) as? OverridePresetCollectionViewCell else { - return - } - - scheduledOverrideCell.removeOverlay(animated: true) - } - - if let customOverrideCell = collectionView.cellForItem(at: indexPathOfCustomOverride()) as? CustomOverrideCollectionViewCell { - customOverrideCell.removeOverlay(animated: true) - } - } - - private func configureCellsForEditingChanged() { - for indexPath in collectionView.indexPathsForVisibleItems where indexPath.section == presetSection { - if let cell = collectionView.cellForItem(at: indexPath) as? OverridePresetCollectionViewCell { - if isEditingPresets { - cell.configureForEditing(animated: true) - } else { - cell.configureForStandard(animated: true) - } - } - } - } - - public override func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool { - if !isEditingPresets { - return true - } - - switch cellContent(for: indexPath) { - case .scheduledOverride, .customOverride, .history: - return false - case .preset: - return true - } - } - - public override func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool { - isEditingPresets - && indexPath.section == presetSection - && indexPath != indexPathOfCustomOverride() - - } - - public override func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { - let movedPreset = presets.remove(at: sourceIndexPath.row) - presets.insert(movedPreset, at: destinationIndexPath.row) - } - - public override func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath { - guard proposedIndexPath.section == sections.firstIndex(of: .presets) else { - return originalIndexPath - } - - return proposedIndexPath == indexPathOfCustomOverride() - ? originalIndexPath - : proposedIndexPath - - } -} - -extension OverrideSelectionViewController: UICollectionViewDelegateFlowLayout { - private var sectionInsets: UIEdgeInsets { - return UIEdgeInsets(top: 0, left: 12, bottom: 12, right: 12) - } - - public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { - guard presets.isEmpty else { return .zero } - return CGSize(width: collectionView.frame.width, height: 50) - } - - public func collectionView( - _ collectionView: UICollectionView, - layout collectionViewLayout: UICollectionViewLayout, - sizeForItemAt indexPath: IndexPath - ) -> CGSize { - let paddingSpace = sectionInsets.left * 2 - let width = view.frame.width - paddingSpace - let height: CGFloat - switch cellContent(for: indexPath) { - case .scheduledOverride, .preset: - height = 76 - case .customOverride, .history: - height = 52 - } - - return CGSize(width: width, height: height) - } - - public func collectionView( - _ collectionView: UICollectionView, - layout collectionViewLayout: UICollectionViewLayout, - insetForSectionAt section: Int - ) -> UIEdgeInsets { - return sectionInsets - } - - public func collectionView( - _ collectionView: UICollectionView, - layout collectionViewLayout: UICollectionViewLayout, - minimumLineSpacingForSectionAt section: Int - ) -> CGFloat { - return sectionInsets.left - } -} - -extension OverrideSelectionViewController: AddEditOverrideTableViewControllerDelegate { - public func addEditOverrideTableViewController(_ vc: AddEditOverrideTableViewController, didSavePreset preset: TemporaryScheduleOverridePreset) { - if let selectedIndexPath = collectionView.indexPathsForSelectedItems?.first { - presets[selectedIndexPath.row] = preset - collectionView.reloadItems(at: [selectedIndexPath]) - collectionView.deselectItem(at: selectedIndexPath, animated: true) - } else { - presets.append(preset) - collectionView.insertItems(at: [IndexPath(row: presets.endIndex - 1, section: presetSection)]) - delegate?.overrideSelectionViewController(self, didUpdatePresets: presets) - } - } - - public func addEditOverrideTableViewController(_ vc: AddEditOverrideTableViewController, didSaveOverride override: TemporaryScheduleOverride) { - delegate?.overrideSelectionViewController(self, didConfirmOverride: override) - } - - public func addEditOverrideTableViewController(_ vc: AddEditOverrideTableViewController, didCancelOverride override: TemporaryScheduleOverride) { - delegate?.overrideSelectionViewController(self, didCancelOverride: override) - } -} - -extension OverrideSelectionViewController: OverridePresetCollectionViewCellDelegate { - func overridePresetCollectionViewCellDidScheduleOverride(_ cell: OverridePresetCollectionViewCell) { - guard - let indexPath = collectionView.indexPath(for: cell), - case .preset(let preset) = cellContent(for: indexPath) - else { - return - } - - let customizePresetVC = AddEditOverrideTableViewController(glucoseUnit: glucoseUnit) - customizePresetVC.inputMode = .customizePresetOverride(preset) - customizePresetVC.delegate = self - show(customizePresetVC, sender: nil) - } - - func overridePresetCollectionViewCellDidPerformFirstDeletionStep(_ cell: OverridePresetCollectionViewCell) { - for case let visibleCell as OverridePresetCollectionViewCell in collectionView.visibleCells - where visibleCell !== cell && visibleCell.isShowingFinalDeleteConfirmation - { - visibleCell.configureForEditing(animated: true) - } - } - - func overridePresetCollectionViewCellDidDeletePreset(_ cell: OverridePresetCollectionViewCell) { - guard let indexPath = collectionView.indexPath(for: cell) else { - return - } - - presets.remove(at: indexPath.row) - if let name = cell.nameLabel.text { - INInteraction.delete(with: name) { (error) in - if let error = error { - os_log(.error, "Failed to delete intent: %{public}@", String(describing: error)) - } - } - } - - collectionView.deleteItems(at: [indexPath]) - } -} - -private extension Array where Element: Equatable { - mutating func remove(_ element: Element) { - if let index = self.firstIndex(of: element) { - remove(at: index) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/PercentageTextFieldTableViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/PercentageTextFieldTableViewController.swift deleted file mode 100644 index 7ae6f2d1f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/PercentageTextFieldTableViewController.swift +++ /dev/null @@ -1,67 +0,0 @@ -// -// PercentageTextFieldTableViewController.swift -// LoopKitUI -// -// Created by Michael Pangburn on 11/23/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - - -public protocol PercentageTextFieldTableViewControllerDelegate: AnyObject { - func percentageTextFieldTableViewControllerDidChangePercentage(_ controller: PercentageTextFieldTableViewController) -} - -public class PercentageTextFieldTableViewController: TextFieldTableViewController { - - public var percentage: Double? { - get { - if let doubleValue = value.flatMap(Double.init) { - return doubleValue / 100 - } else { - return nil - } - } - set { - if let percentage = newValue { - value = percentageFormatter.string(from: percentage * 100) - } else { - value = nil - } - } - } - - public weak var percentageDelegate: PercentageTextFieldTableViewControllerDelegate? - - var maximumFractionDigits: Int = 1 { - didSet { - percentageFormatter.maximumFractionDigits = maximumFractionDigits - } - } - - private lazy var percentageFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.minimumIntegerDigits = 1 - formatter.maximumFractionDigits = maximumFractionDigits - return formatter - }() - - public convenience init() { - self.init(style: .grouped) - unit = "%" - keyboardType = .decimalPad - placeholder = "Enter percentage" - delegate = self - } -} - -extension PercentageTextFieldTableViewController: TextFieldTableViewControllerDelegate { - public func textFieldTableViewControllerDidEndEditing(_ controller: TextFieldTableViewController) { - percentageDelegate?.percentageTextFieldTableViewControllerDidChangePercentage(self) - } - - public func textFieldTableViewControllerDidReturn(_ controller: TextFieldTableViewController) { - percentageDelegate?.percentageTextFieldTableViewControllerDidChangePercentage(self) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/RadioSelectionTableViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/RadioSelectionTableViewController.swift deleted file mode 100644 index 2773be56d..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/RadioSelectionTableViewController.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// RadioSelectionTableViewController.swift -// Loop -// -// Created by Nate Racklyeft on 8/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - -public protocol RadioSelectionTableViewControllerDelegate: AnyObject { - func radioSelectionTableViewControllerDidChangeSelectedIndex(_ controller: RadioSelectionTableViewController) -} - - -open class RadioSelectionTableViewController: UITableViewController { - - open var options = [String]() - - open var selectedIndex: Int? { - didSet { - if let oldValue = oldValue, oldValue != selectedIndex { - tableView.cellForRow(at: IndexPath(row: oldValue, section: 0))?.accessoryType = .none - } - - if let selectedIndex = selectedIndex, oldValue != selectedIndex { - tableView.cellForRow(at: IndexPath(row: selectedIndex, section: 0))?.accessoryType = .checkmark - - delegate?.radioSelectionTableViewControllerDidChangeSelectedIndex(self) - } - } - } - - open var contextHelp: String? - - weak open var delegate: RadioSelectionTableViewControllerDelegate? - - convenience public init() { - self.init(style: .grouped) - } - - // MARK: - Table view data source - - override open func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - override open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return options.count - } - - override open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell(style: .default, reuseIdentifier: "Cell") - - cell.textLabel?.text = options[indexPath.row] - cell.accessoryType = selectedIndex == indexPath.row ? .checkmark : .none - - return cell - } - - override open func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - return contextHelp - } - - override open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - selectedIndex = indexPath.row - - tableView.deselectRow(at: indexPath, animated: true) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/ServiceNavigationController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/ServiceNavigationController.swift deleted file mode 100644 index c007886d3..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/ServiceNavigationController.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// ServiceNavigationController.swift -// LoopKitUI -// -// Created by Darin Krauss on 5/23/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import LoopKit -import UIKit - -open class ServiceNavigationController: UINavigationController, ServiceOnboarding, CompletionNotifying { - public weak var serviceOnboardingDelegate: ServiceOnboardingDelegate? - public weak var completionDelegate: CompletionDelegate? - - public func notifyServiceCreated(_ service: Service) { - serviceOnboardingDelegate?.serviceOnboarding(didCreateService: service) - } - - public func notifyServiceOnboarded(_ service: Service) { - serviceOnboardingDelegate?.serviceOnboarding(didOnboardService: service) - } - - public func notifyServiceCreatedAndOnboarded(_ service: ServiceUI) { - notifyServiceCreated(service) - notifyServiceOnboarded(service) - } - - public func notifyComplete() { - completionDelegate?.completionNotifyingDidComplete(self) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/SettingsNavigationViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/SettingsNavigationViewController.swift deleted file mode 100644 index 663bae138..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/SettingsNavigationViewController.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// SettingsNavigationViewController.swift -// LoopKitUI -// -// Created by Pete Schwamb on 1/29/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import HealthKit -import LoopKit -import UIKit - -open class SettingsNavigationViewController: UINavigationController, CompletionNotifying { - - open weak var completionDelegate: CompletionDelegate? - - open func notifyComplete() { - completionDelegate?.completionNotifyingDidComplete(self) - } - -} - -open class CGMManagerSettingsNavigationViewController: SettingsNavigationViewController, CGMManagerOnboarding { - - open weak var cgmManagerOnboardingDelegate: CGMManagerOnboardingDelegate? - -} - -open class PumpManagerSettingsNavigationViewController: SettingsNavigationViewController, PumpManagerOnboarding { - - open weak var pumpManagerOnboardingDelegate: PumpManagerOnboardingDelegate? - -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/SetupTableViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/SetupTableViewController.swift deleted file mode 100644 index dcaa77ed5..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/SetupTableViewController.swift +++ /dev/null @@ -1,116 +0,0 @@ -// -// SetupTableViewController.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - -public protocol SetupTableViewControllerDelegate: AnyObject { - func setupTableViewControllerCancelButtonPressed(_ viewController: SetupTableViewController) -} - -open class SetupTableViewController: UITableViewController { - - private(set) open lazy var footerView = SetupTableFooterView(frame: .zero) - - private var lastContentHeight: CGFloat = 0 - - public var padFooterToBottom: Bool = true - - public weak var delegate: SetupTableViewControllerDelegate? - - open override func viewDidLoad() { - super.viewDidLoad() - - navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelButtonPressed(_:))) - - footerView.primaryButton.addTarget(self, action: #selector(continueButtonPressed(_:)), for: .touchUpInside) - } - - open override func viewDidLayoutSubviews() { - super.viewDidLayoutSubviews() - - // Reposition footer view if necessary - if tableView.contentSize.height != lastContentHeight { - lastContentHeight = tableView.contentSize.height - tableView.tableFooterView = nil - - var footerSize = footerView.systemLayoutSizeFitting(CGSize(width: tableView.frame.size.width, height: UIView.layoutFittingCompressedSize.height)) - let visibleHeight = tableView.bounds.size.height - (tableView.adjustedContentInset.top + tableView.adjustedContentInset.bottom) - let footerHeight = padFooterToBottom ? max(footerSize.height, visibleHeight - tableView.contentSize.height) : footerSize.height - - footerSize.height = footerHeight - footerView.frame.size = footerSize - tableView.tableFooterView = footerView - } - } - - @IBAction open func cancelButtonPressed(_: Any) { - delegate?.setupTableViewControllerCancelButtonPressed(self) - } - - @IBAction open func continueButtonPressed(_ sender: Any) { - if shouldPerformSegue(withIdentifier: "Continue", sender: sender) { - performSegue(withIdentifier: "Continue", sender: sender) - } - } - - // MARK: - UITableViewDelegate - - open override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { - return UITableView.automaticDimension - } - - open override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - return UITableView.automaticDimension - } - - open override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return UITableView.automaticDimension - } -} - - -open class SetupTableFooterView: UIView { - - public let primaryButton = SetupButton(type: .custom) - - public override init(frame: CGRect) { - let buttonStack = UIStackView(arrangedSubviews: [primaryButton]) - - super.init(frame: frame) - - autoresizingMask = [.flexibleWidth] - primaryButton.resetTitle() - - buttonStack.alignment = .center - buttonStack.axis = .vertical - buttonStack.distribution = .fillEqually - buttonStack.translatesAutoresizingMaskIntoConstraints = false - - addSubview(buttonStack) - - NSLayoutConstraint.activate([ - primaryButton.leadingAnchor.constraint(equalTo: buttonStack.leadingAnchor), - primaryButton.trailingAnchor.constraint(equalTo: buttonStack.trailingAnchor), - - buttonStack.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor), - buttonStack.leadingAnchor.constraint(equalToSystemSpacingAfter: layoutMarginsGuide.leadingAnchor, multiplier: 1), - layoutMarginsGuide.trailingAnchor.constraint(equalToSystemSpacingAfter: buttonStack.trailingAnchor, multiplier: 1), - safeAreaLayoutGuide.bottomAnchor.constraint(equalToSystemSpacingBelow: buttonStack.bottomAnchor, multiplier: 2), - ]) - } - - public required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - - -public extension SetupButton { - func resetTitle() { - setTitle(LocalizedString("Continue", comment: "Title of the setup button to continue"), for: .normal) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/SingleValueScheduleTableViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/SingleValueScheduleTableViewController.swift deleted file mode 100644 index 91295382c..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/SingleValueScheduleTableViewController.swift +++ /dev/null @@ -1,300 +0,0 @@ -// -// SingleValueScheduleTableViewController.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/13/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import LoopKit - - -public enum RepeatingScheduleValueResult { - case success(scheduleItems: [RepeatingScheduleValue], timeZone: TimeZone) - case failure(Error) -} - - -public protocol SingleValueScheduleTableViewControllerSyncSource: AnyObject { - func syncScheduleValues(for viewController: SingleValueScheduleTableViewController, completion: @escaping (_ result: RepeatingScheduleValueResult) -> Void) - - func syncButtonTitle(for viewController: SingleValueScheduleTableViewController) -> String - - func syncButtonDetailText(for viewController: SingleValueScheduleTableViewController) -> String? - - func singleValueScheduleTableViewControllerIsReadOnly(_ viewController: SingleValueScheduleTableViewController) -> Bool -} - - -open class SingleValueScheduleTableViewController: DailyValueScheduleTableViewController, RepeatingScheduleValueTableViewCellDelegate { - - open override func viewDidLoad() { - super.viewDidLoad() - - tableView.register(RepeatingScheduleValueTableViewCell.nib(), forCellReuseIdentifier: RepeatingScheduleValueTableViewCell.className) - tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className) - } - - open override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - - if syncSource == nil { - delegate?.dailyValueScheduleTableViewControllerWillFinishUpdating(self) - } - } - - // MARK: - State - - public var scheduleItems: [RepeatingScheduleValue] = [] - - override func addScheduleItem(_ sender: Any?) { - guard !isReadOnly && !isSyncInProgress else { - return - } - - tableView.endEditing(false) - - var startTime = TimeInterval(0) - var value = 0.0 - - if scheduleItems.count > 0, let cell = tableView.cellForRow(at: IndexPath(row: scheduleItems.count - 1, section: 0)) as? RepeatingScheduleValueTableViewCell { - let lastItem = scheduleItems.last! - let interval = cell.datePickerInterval - - startTime = lastItem.startTime + interval - value = lastItem.value - - if startTime >= TimeInterval(hours: 24) { - return - } - } - - scheduleItems.append( - RepeatingScheduleValue( - startTime: min(TimeInterval(hours: 23.5), startTime), - value: value - ) - ) - - super.addScheduleItem(sender) - } - - override func insertableIndiciesByRemovingRow(_ row: Int, withInterval timeInterval: TimeInterval) -> [Bool] { - return insertableIndices(for: scheduleItems, removing: row, with: timeInterval) - } - - var preferredValueFractionDigits: Int { - return 1 - } - - public weak var syncSource: SingleValueScheduleTableViewControllerSyncSource? { - didSet { - isReadOnly = syncSource?.singleValueScheduleTableViewControllerIsReadOnly(self) ?? false - - if isViewLoaded { - tableView.reloadData() - } - } - } - - private var isSyncInProgress = false { - didSet { - for cell in tableView.visibleCells { - switch cell { - case let cell as TextButtonTableViewCell: - cell.isEnabled = !isSyncInProgress - cell.isLoading = isSyncInProgress - case let cell as RepeatingScheduleValueTableViewCell: - cell.isReadOnly = isReadOnly || isSyncInProgress - default: - break - } - } - - for item in navigationItem.rightBarButtonItems ?? [] { - item.isEnabled = !isSyncInProgress - } - - navigationItem.hidesBackButton = isSyncInProgress - } - } - - // MARK: - UITableViewDataSource - - private enum Section: Int { - case schedule - case sync - } - - open override func numberOfSections(in tableView: UITableView) -> Int { - if syncSource != nil { - return 2 - } - - return 1 - } - - open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch Section(rawValue: section)! { - case .schedule: - return scheduleItems.count - case .sync: - return 1 - } - } - - open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch Section(rawValue: indexPath.section)! { - case .schedule: - let cell = tableView.dequeueReusableCell(withIdentifier: RepeatingScheduleValueTableViewCell.className, for: indexPath) as! RepeatingScheduleValueTableViewCell - - let item = scheduleItems[indexPath.row] - let interval = cell.datePickerInterval - - cell.timeZone = timeZone - cell.date = midnight.addingTimeInterval(item.startTime) - - cell.valueNumberFormatter.minimumFractionDigits = preferredValueFractionDigits - - cell.value = item.value - cell.unitString = unitDisplayString - cell.isReadOnly = isReadOnly || isSyncInProgress - cell.delegate = self - - if indexPath.row > 0 { - let lastItem = scheduleItems[indexPath.row - 1] - - cell.datePicker.minimumDate = midnight.addingTimeInterval(lastItem.startTime).addingTimeInterval(interval) - } - - if indexPath.row < scheduleItems.endIndex - 1 { - let nextItem = scheduleItems[indexPath.row + 1] - - cell.datePicker.maximumDate = midnight.addingTimeInterval(nextItem.startTime).addingTimeInterval(-interval) - } else { - cell.datePicker.maximumDate = midnight.addingTimeInterval(TimeInterval(hours: 24) - interval) - } - - return cell - case .sync: - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell - - cell.textLabel?.text = syncSource?.syncButtonTitle(for: self) - cell.isEnabled = !isSyncInProgress - cell.isLoading = isSyncInProgress - - return cell - } - } - - open override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - switch Section(rawValue: section)! { - case .schedule: - return nil - case .sync: - return syncSource?.syncButtonDetailText(for: self) - } - } - - open override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { - if editingStyle == .delete { - scheduleItems.remove(at: indexPath.row) - - super.tableView(tableView, commit: editingStyle, forRowAt: indexPath) - } - } - - open override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { - if sourceIndexPath != destinationIndexPath { - let item = scheduleItems.remove(at: sourceIndexPath.row) - scheduleItems.insert(item, at: destinationIndexPath.row) - - guard destinationIndexPath.row > 0, let cell = tableView.cellForRow(at: destinationIndexPath) as? RepeatingScheduleValueTableViewCell else { - return - } - - let interval = cell.datePickerInterval - let startTime = scheduleItems[destinationIndexPath.row - 1].startTime + interval - - scheduleItems[destinationIndexPath.row] = RepeatingScheduleValue(startTime: startTime, value: scheduleItems[destinationIndexPath.row].value) - - // Since the valid date ranges of neighboring cells are affected, the lazy solution is to just reload the entire table view - DispatchQueue.main.async { - tableView.reloadData() - } - } - } - - // MARK: - UITableViewDelegate - - open override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - return super.tableView(tableView, canEditRowAt: indexPath) && !isSyncInProgress - } - - open override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - super.tableView(tableView, didSelectRowAt: indexPath) - - switch Section(rawValue: indexPath.section)! { - case .schedule: - break - case .sync: - if let syncSource = syncSource, !isSyncInProgress { - isSyncInProgress = true - syncSource.syncScheduleValues(for: self) { (result) in - DispatchQueue.main.async { - switch result { - case .success(let items, let timeZone): - self.scheduleItems = items - self.timeZone = timeZone - self.tableView.reloadSections([Section.schedule.rawValue], with: .fade) - self.isSyncInProgress = false - self.delegate?.dailyValueScheduleTableViewControllerWillFinishUpdating(self) - case .failure(let error): - self.present(UIAlertController(with: error), animated: true) { - self.isSyncInProgress = false - } - } - } - } - } - } - } - - open override func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath { - - guard sourceIndexPath != proposedDestinationIndexPath, let cell = tableView.cellForRow(at: sourceIndexPath) as? RepeatingScheduleValueTableViewCell else { - return proposedDestinationIndexPath - } - - let interval = cell.datePickerInterval - let indices = insertableIndices(for: scheduleItems, removing: sourceIndexPath.row, with: interval) - - let closestDestinationRow = indices.insertableIndex(closestTo: proposedDestinationIndexPath.row, from: sourceIndexPath.row) - return IndexPath(row: closestDestinationRow, section: proposedDestinationIndexPath.section) - } - - // MARK: - RepeatingScheduleValueTableViewCellDelegate - - override public func datePickerTableViewCellDidUpdateDate(_ cell: DatePickerTableViewCell) { - if let indexPath = tableView.indexPath(for: cell) { - let currentItem = scheduleItems[indexPath.row] - - scheduleItems[indexPath.row] = RepeatingScheduleValue( - startTime: cell.date.timeIntervalSince(midnight), - value: currentItem.value - ) - } - - super.datePickerTableViewCellDidUpdateDate(cell) - } - - func repeatingScheduleValueTableViewCellDidUpdateValue(_ cell: RepeatingScheduleValueTableViewCell) { - if let indexPath = tableView.indexPath(for: cell) { - let currentItem = scheduleItems[indexPath.row] - - scheduleItems[indexPath.row] = RepeatingScheduleValue(startTime: currentItem.startTime, value: cell.value) - } - } - -} diff --git a/Dependencies/LoopKit/LoopKitUI/View Controllers/TextFieldTableViewController.swift b/Dependencies/LoopKit/LoopKitUI/View Controllers/TextFieldTableViewController.swift deleted file mode 100644 index e2b585659..000000000 --- a/Dependencies/LoopKit/LoopKitUI/View Controllers/TextFieldTableViewController.swift +++ /dev/null @@ -1,113 +0,0 @@ -// -// TextFieldTableViewController.swift -// Naterade -// -// Created by Nathan Racklyeft on 8/30/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -public protocol TextFieldTableViewControllerDelegate: AnyObject { - func textFieldTableViewControllerDidEndEditing(_ controller: TextFieldTableViewController) - - func textFieldTableViewControllerDidReturn(_ controller: TextFieldTableViewController) -} - - -open class TextFieldTableViewController: UITableViewController, UITextFieldDelegate { - - private weak var textField: UITextField? - - public var indexPath: IndexPath? - - public var placeholder: String? - - public var unit: String? - - public var value: String? { - didSet { - delegate?.textFieldTableViewControllerDidEndEditing(self) - } - } - - public var contextHelp: String? - - public var keyboardType = UIKeyboardType.default - - public var autocapitalizationType = UITextAutocapitalizationType.sentences - - open weak var delegate: TextFieldTableViewControllerDelegate? - - public convenience init() { - self.init(style: .grouped) - } - - open override func viewDidLoad() { - super.viewDidLoad() - - tableView.cellLayoutMarginsFollowReadableWidth = true - tableView.register(TextFieldTableViewCell.nib(), forCellReuseIdentifier: TextFieldTableViewCell.className) - } - - open override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - textField?.becomeFirstResponder() - } - - // MARK: - UITableViewDataSource - - open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return 1 - } - - open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: TextFieldTableViewCell.className, for: indexPath) as! TextFieldTableViewCell - - textField = cell.textField - - cell.textField.delegate = self - cell.textField.text = value - cell.textField.keyboardType = keyboardType - cell.textField.placeholder = placeholder - cell.textField.autocapitalizationType = autocapitalizationType - cell.unitLabel?.text = unit - - return cell - } - - open override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - return contextHelp - } - - open override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - if indexPath == IndexPath(row: 0, section: 0), let textField = textField { - if textField.isFirstResponder { - textField.resignFirstResponder() - } else { - textField.becomeFirstResponder() - } - } - - tableView.deselectRow(at: indexPath, animated: true) - } - - // MARK: - UITextFieldDelegate - - open func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { - value = textField.text - - return true - } - - open func textFieldShouldReturn(_ textField: UITextField) -> Bool { - value = textField.text - - textField.delegate = nil - delegate?.textFieldTableViewControllerDidReturn(self) - - return false - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/ViewModels/CorrectionRangeOverridesEditorViewModel.swift b/Dependencies/LoopKit/LoopKitUI/ViewModels/CorrectionRangeOverridesEditorViewModel.swift deleted file mode 100644 index 65b08cede..000000000 --- a/Dependencies/LoopKit/LoopKitUI/ViewModels/CorrectionRangeOverridesEditorViewModel.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// CorrectionRangeOverridesEditorViewModel.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2021-03-15. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit -import LoopKit - -struct CorrectionRangeOverridesEditorViewModel { - - let correctionRangeOverrides: CorrectionRangeOverrides - - let suspendThreshold: GlucoseThreshold? - - let correctionRangeScheduleRange: ClosedRange - - let preset: CorrectionRangeOverrides.Preset - - let guardrail: Guardrail - - var saveCorrectionRangeOverride: (_ correctionRangeOverrides: CorrectionRangeOverrides) -> Void - - public init(therapySettingsViewModel: TherapySettingsViewModel, - preset: CorrectionRangeOverrides.Preset, - didSave: (() -> Void)? = nil) - { - self.correctionRangeOverrides = therapySettingsViewModel.correctionRangeOverrides - self.suspendThreshold = therapySettingsViewModel.suspendThreshold - self.correctionRangeScheduleRange = therapySettingsViewModel.correctionRangeScheduleRange - self.guardrail = Guardrail.correctionRangeOverride( - for: preset, - correctionRangeScheduleRange: therapySettingsViewModel.correctionRangeScheduleRange, - suspendThreshold: therapySettingsViewModel.suspendThreshold) - self.preset = preset - - self.saveCorrectionRangeOverride = { [weak therapySettingsViewModel] correctionRangeOverrides in - guard let therapySettingsViewModel = therapySettingsViewModel else { - return - } - therapySettingsViewModel.saveCorrectionRangeOverride(preset: preset, - correctionRangeOverrides: correctionRangeOverrides) - didSave?() - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/ViewModels/CorrectionRangeScheduleEditorViewModel.swift b/Dependencies/LoopKit/LoopKitUI/ViewModels/CorrectionRangeScheduleEditorViewModel.swift deleted file mode 100644 index 49c5d2c19..000000000 --- a/Dependencies/LoopKit/LoopKitUI/ViewModels/CorrectionRangeScheduleEditorViewModel.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// CorrectionRangeScheduleEditorViewModel.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2021-03-19. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit -import LoopKit - -struct CorrectionRangeScheduleEditorViewModel { - - let guardrail = Guardrail.correctionRange - - let glucoseTargetRangeSchedule: GlucoseRangeSchedule? - - let minValue: HKQuantity? - - var saveGlucoseTargetRangeSchedule: (_ glucoseTargetRangeSchedule: GlucoseRangeSchedule) -> Void - - init( - mode: SettingsPresentationMode, - therapySettingsViewModel: TherapySettingsViewModel, - didSave: (() -> Void)? = nil - ) { - if mode == .acceptanceFlow { - self.glucoseTargetRangeSchedule = therapySettingsViewModel.glucoseTargetRangeSchedule?.safeSchedule(with: therapySettingsViewModel.suspendThreshold?.quantity) - } - else { - self.glucoseTargetRangeSchedule = therapySettingsViewModel.glucoseTargetRangeSchedule - } - self.minValue = Guardrail.minCorrectionRangeValue(suspendThreshold: therapySettingsViewModel.suspendThreshold) - self.saveGlucoseTargetRangeSchedule = { [weak therapySettingsViewModel] glucoseTargetRangeSchedule in - guard let therapySettingsViewModel = therapySettingsViewModel else { - return - } - - therapySettingsViewModel.saveCorrectionRange(range: glucoseTargetRangeSchedule) - didSave?() - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/ViewModels/DisplayGlucoseUnitObservable.swift b/Dependencies/LoopKit/LoopKitUI/ViewModels/DisplayGlucoseUnitObservable.swift deleted file mode 100644 index ff555b1b7..000000000 --- a/Dependencies/LoopKit/LoopKitUI/ViewModels/DisplayGlucoseUnitObservable.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// DisplayGlucoseUnitObservable.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2021-03-10. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit - -public class DisplayGlucoseUnitObservable: ObservableObject { - @Published public private(set) var displayGlucoseUnit: HKUnit - - public init(displayGlucoseUnit: HKUnit) { - self.displayGlucoseUnit = displayGlucoseUnit - } -} - -extension DisplayGlucoseUnitObservable: DisplayGlucoseUnitObserver { - public func displayGlucoseUnitDidChange(to displayGlucoseUnit: HKUnit) { - self.displayGlucoseUnit = displayGlucoseUnit - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/ViewModels/InsulinSensitivityScheduleEditorViewModel.swift b/Dependencies/LoopKit/LoopKitUI/ViewModels/InsulinSensitivityScheduleEditorViewModel.swift deleted file mode 100644 index 29cd3ef23..000000000 --- a/Dependencies/LoopKit/LoopKitUI/ViewModels/InsulinSensitivityScheduleEditorViewModel.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// InsulinSensitivityScheduleEditorViewModel.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2021-03-15. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit -import LoopKit - -struct InsulinSensitivityScheduleEditorViewModel { - - let insulinSensitivitySchedule: InsulinSensitivitySchedule? - - var saveInsulinSensitivitySchedule: (_ insulinSensitivitySchedule: InsulinSensitivitySchedule) -> Void - - init(therapySettingsViewModel: TherapySettingsViewModel, - didSave: (() -> Void)? = nil) - { - self.insulinSensitivitySchedule = therapySettingsViewModel.insulinSensitivitySchedule - self.saveInsulinSensitivitySchedule = { [weak therapySettingsViewModel] insulinSensitivitySchedule in - guard let therapySettingsViewModel = therapySettingsViewModel else { - return - } - - therapySettingsViewModel.saveInsulinSensitivitySchedule(insulinSensitivitySchedule: insulinSensitivitySchedule) - didSave?() - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/ViewModels/SuspendThresholdEditorViewModel.swift b/Dependencies/LoopKit/LoopKitUI/ViewModels/SuspendThresholdEditorViewModel.swift deleted file mode 100644 index 01e7a6271..000000000 --- a/Dependencies/LoopKit/LoopKitUI/ViewModels/SuspendThresholdEditorViewModel.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// SuspendThresholdEditorViewModel.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2021-03-01. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit -import LoopKit - -struct SuspendThresholdEditorViewModel { - let guardrail = Guardrail.suspendThreshold - - let suspendThreshold: HKQuantity? - - let suspendThresholdUnit: HKUnit - - let maxSuspendThresholdValue: HKQuantity - - var saveSuspendThreshold: (_ suspendThreshold: HKQuantity, _ displayGlucoseUnit: HKUnit) -> Void - - public init(therapySettingsViewModel: TherapySettingsViewModel, - mode: SettingsPresentationMode, - didSave: (() -> Void)? = nil) - { - self.suspendThreshold = therapySettingsViewModel.suspendThreshold?.quantity - self.suspendThresholdUnit = therapySettingsViewModel.suspendThreshold?.unit ?? .milligramsPerDeciliter - - if mode == .acceptanceFlow { - // During a review/acceptance flow, do not limit suspend threshold by other targets - self.maxSuspendThresholdValue = Guardrail.suspendThreshold.absoluteBounds.upperBound - } else { - self.maxSuspendThresholdValue = Guardrail.maxSuspendThresholdValue( - correctionRangeSchedule: therapySettingsViewModel.glucoseTargetRangeSchedule, - preMealTargetRange: therapySettingsViewModel.correctionRangeOverrides.preMeal, - workoutTargetRange: therapySettingsViewModel.correctionRangeOverrides.workout) - } - - self.saveSuspendThreshold = { [weak therapySettingsViewModel] suspendThreshold, displayGlucoseUnit in - guard let therapySettingsViewModel = therapySettingsViewModel else { - return - } - therapySettingsViewModel.saveSuspendThreshold(quantity: suspendThreshold, withDisplayGlucoseUnit: displayGlucoseUnit) - didSave?() - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/ViewModels/TherapySettingsViewModel.swift b/Dependencies/LoopKit/LoopKitUI/ViewModels/TherapySettingsViewModel.swift deleted file mode 100644 index 3650ef60c..000000000 --- a/Dependencies/LoopKit/LoopKitUI/ViewModels/TherapySettingsViewModel.swift +++ /dev/null @@ -1,197 +0,0 @@ -// -// TherapySettingsViewModel.swift -// LoopKitUI -// -// Created by Rick Pasetto on 7/13/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Combine -import LoopKit -import HealthKit -import SwiftUI - -public protocol TherapySettingsViewModelDelegate: AnyObject { - func syncBasalRateSchedule(items: [RepeatingScheduleValue], completion: @escaping (Result) -> Void) - func syncDeliveryLimits(deliveryLimits: DeliveryLimits, completion: @escaping (Result) -> Void) - func saveCompletion(therapySettings: TherapySettings) - func pumpSupportedIncrements() -> PumpSupportedIncrements? -} - -public class TherapySettingsViewModel: ObservableObject { - - @Published public var therapySettings: TherapySettings - private let initialTherapySettings: TherapySettings - let sensitivityOverridesEnabled: Bool - let adultChildInsulinModelSelectionEnabled: Bool - public var prescription: Prescription? - - private weak var delegate: TherapySettingsViewModelDelegate? - - public init(therapySettings: TherapySettings, - pumpSupportedIncrements: (() -> PumpSupportedIncrements?)? = nil, - sensitivityOverridesEnabled: Bool = false, - adultChildInsulinModelSelectionEnabled: Bool = false, - prescription: Prescription? = nil, - delegate: TherapySettingsViewModelDelegate? = nil) { - self.therapySettings = therapySettings - self.initialTherapySettings = therapySettings - self.sensitivityOverridesEnabled = sensitivityOverridesEnabled - self.adultChildInsulinModelSelectionEnabled = adultChildInsulinModelSelectionEnabled - self.prescription = prescription - self.delegate = delegate - } - - var deliveryLimits: DeliveryLimits { - return DeliveryLimits(maximumBasalRate: therapySettings.maximumBasalRatePerHour.map { HKQuantity(unit: .internationalUnitsPerHour, doubleValue: $0) }, - maximumBolus: therapySettings.maximumBolus.map { HKQuantity(unit: .internationalUnit(), doubleValue: $0) } ) - } - - var suspendThreshold: GlucoseThreshold? { - return therapySettings.suspendThreshold - } - - var glucoseTargetRangeSchedule: GlucoseRangeSchedule? { - return therapySettings.glucoseTargetRangeSchedule - } - - func glucoseTargetRangeSchedule(for glucoseUnit: HKUnit) -> GlucoseRangeSchedule? { - return glucoseTargetRangeSchedule?.schedule(for: glucoseUnit) - } - - var correctionRangeOverrides: CorrectionRangeOverrides { - return CorrectionRangeOverrides(preMeal: therapySettings.correctionRangeOverrides?.preMeal, - workout: therapySettings.correctionRangeOverrides?.workout) - } - - var correctionRangeScheduleRange: ClosedRange { - precondition(therapySettings.glucoseTargetRangeSchedule != nil) - return therapySettings.glucoseTargetRangeSchedule!.scheduleRange() - } - - var insulinSensitivitySchedule: InsulinSensitivitySchedule? { - return therapySettings.insulinSensitivitySchedule - } - - func insulinSensitivitySchedule(for glucoseUnit: HKUnit) -> InsulinSensitivitySchedule? { - return insulinSensitivitySchedule?.schedule(for: glucoseUnit) - } - - /// Reset to initial - public func reset() { - therapySettings = initialTherapySettings - } -} - -// MARK: Passing along to the delegate -extension TherapySettingsViewModel { - - public var maximumBasalScheduleEntryCount: Int? { - pumpSupportedIncrements()?.maximumBasalScheduleEntryCount - } - - public func pumpSupportedIncrements() -> PumpSupportedIncrements? { - return delegate?.pumpSupportedIncrements() - } - - public func syncBasalRateSchedule(items: [RepeatingScheduleValue], completion: @escaping (Result) -> Void) { - delegate?.syncBasalRateSchedule(items: items, completion: completion) - } - - public func syncDeliveryLimits(deliveryLimits: DeliveryLimits, completion: @escaping (Result) -> Void) { - delegate?.syncDeliveryLimits(deliveryLimits: deliveryLimits, completion: completion) - } -} - -// MARK: Saving -extension TherapySettingsViewModel { - - public func saveCorrectionRange(range: GlucoseRangeSchedule) { - therapySettings.glucoseTargetRangeSchedule = range - delegate?.saveCompletion(therapySettings: therapySettings) - } - - public func saveCorrectionRangeOverride(preset: CorrectionRangeOverrides.Preset, - correctionRangeOverrides: CorrectionRangeOverrides) { - therapySettings.correctionRangeOverrides = correctionRangeOverrides - delegate?.saveCompletion(therapySettings: therapySettings) - } - - public func saveSuspendThreshold(quantity: HKQuantity, withDisplayGlucoseUnit displayGlucoseUnit: HKUnit) { - therapySettings.suspendThreshold = GlucoseThreshold(unit: displayGlucoseUnit, value: quantity.doubleValue(for: displayGlucoseUnit)) - - // TODO: Eventually target editors should support conflicting initial values - // But for now, ensure target ranges do not conflict with suspend threshold. - if let targetSchedule = therapySettings.glucoseTargetRangeSchedule { - let threshold = quantity.doubleValue(for: targetSchedule.unit) - let newItems = targetSchedule.items.map { item in - return RepeatingScheduleValue.init( - startTime: item.startTime, - value: DoubleRange( - minValue: max(threshold, item.value.minValue), - maxValue: max(threshold, item.value.maxValue))) - } - therapySettings.glucoseTargetRangeSchedule = GlucoseRangeSchedule(unit: targetSchedule.unit, dailyItems: newItems) - } - - if let overrides = therapySettings.correctionRangeOverrides { - let adjusted = [overrides.preMeal, overrides.workout].map { item -> ClosedRange? in - guard let item = item else { - return nil - } - return ClosedRange.init( - uncheckedBounds: ( - lower: max(quantity, item.lowerBound), - upper: max(quantity, item.upperBound))) - } - therapySettings.correctionRangeOverrides = CorrectionRangeOverrides( - preMeal: adjusted[0], - workout: adjusted[1]) - } - - if let presets = therapySettings.overridePresets { - therapySettings.overridePresets = presets.map { preset in - if let targetRange = preset.settings.targetRange { - var newPreset = preset - newPreset.settings = TemporaryScheduleOverrideSettings( - targetRange: ClosedRange.init( - uncheckedBounds: ( - lower: max(quantity, targetRange.lowerBound), - upper: max(quantity, targetRange.upperBound))), - insulinNeedsScaleFactor: preset.settings.insulinNeedsScaleFactor) - return newPreset - } else { - return preset - } - } - } - - delegate?.saveCompletion(therapySettings: therapySettings) - } - - public func saveBasalRates(basalRates: BasalRateSchedule) { - therapySettings.basalRateSchedule = basalRates - delegate?.saveCompletion(therapySettings: therapySettings) - } - - public func saveDeliveryLimits(limits: DeliveryLimits) { - therapySettings.maximumBasalRatePerHour = limits.maximumBasalRate?.doubleValue(for: .internationalUnitsPerHour) - therapySettings.maximumBolus = limits.maximumBolus?.doubleValue(for: .internationalUnit()) - delegate?.saveCompletion(therapySettings: therapySettings) - } - - public func saveInsulinModel(insulinModelPreset: ExponentialInsulinModelPreset) { - therapySettings.defaultRapidActingModel = insulinModelPreset - delegate?.saveCompletion(therapySettings: therapySettings) - } - - public func saveCarbRatioSchedule(carbRatioSchedule: CarbRatioSchedule) { - therapySettings.carbRatioSchedule = carbRatioSchedule - delegate?.saveCompletion(therapySettings: therapySettings) - } - - public func saveInsulinSensitivitySchedule(insulinSensitivitySchedule: InsulinSensitivitySchedule) { - therapySettings.insulinSensitivitySchedule = insulinSensitivitySchedule - delegate?.saveCompletion(therapySettings: therapySettings) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ActionButton.swift b/Dependencies/LoopKit/LoopKitUI/Views/ActionButton.swift deleted file mode 100644 index 1de54d2b8..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ActionButton.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// ActionButton.swift -// LoopKitUI -// -// Created by Pete Schwamb on 2020-03-04. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -// TODO: Migrate use sites to ActionButtonStyle -public struct ActionButton: ViewModifier { - private let fontColor: Color - private let backgroundColor: Color - private let edgeColor: Color - private let cornerRadius: CGFloat = 10 - - public enum ButtonType { - case primary - case secondary - case destructive - case deactivated - case plain - } - - init(_ style: ButtonType = .primary) { - switch style { - case .primary: - fontColor = .white - backgroundColor = .accentColor - edgeColor = .clear - case .destructive: - fontColor = .white - backgroundColor = .red - edgeColor = .clear - case .secondary: - fontColor = .accentColor - backgroundColor = .clear - edgeColor = .accentColor - case .deactivated: - fontColor = .white - backgroundColor = .gray - edgeColor = .clear - case .plain: - fontColor = .accentColor - backgroundColor = .clear - edgeColor = .clear - } - } - - public func body(content: Content) -> some View { - content - .padding(.all) - .foregroundColor(fontColor) - .font(.headline) - .frame(maxWidth: .infinity) - .background(backgroundColor) - .cornerRadius(cornerRadius) - .overlay(RoundedRectangle(cornerRadius: cornerRadius) - .stroke(edgeColor)) - } -} - -public extension View { - func actionButtonStyle(_ style: ActionButton.ButtonType = .primary) -> some View { - ModifiedContent(content: self, modifier: ActionButton(style)) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ActionButtonStyle.swift b/Dependencies/LoopKit/LoopKitUI/Views/ActionButtonStyle.swift deleted file mode 100644 index d01d4fc3d..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ActionButtonStyle.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// ActionButtonStyle.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/15/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -public struct ActionButtonStyle: ButtonStyle { - public enum ButtonType { - case primary - case secondary - case destructive - } - - private let fontColor: Color - private let backgroundColor: Color - private let edgeColor: Color - private let cornerRadius: CGFloat = 10 - private let squidge: CGFloat = 1 - - public init(_ style: ButtonType = .primary) { - switch style { - case .primary: - fontColor = .white - backgroundColor = .accentColor - edgeColor = .clear - case .destructive: - fontColor = .white - backgroundColor = .red - edgeColor = .clear - case .secondary: - fontColor = .accentColor - backgroundColor = .clear - edgeColor = .accentColor - } - } - - public func makeBody(configuration: Configuration) -> some View { - configuration.label - .padding(configuration.isPressed ? -squidge : 0) - .padding() - .foregroundColor(fontColor) - .font(.headline) - .frame(maxWidth: .infinity) - .background(backgroundColor) - .overlay(Color(.secondarySystemBackground).opacity(configuration.isPressed ? 0.35 : 0)) - .cornerRadius(cornerRadius) - .padding(configuration.isPressed ? squidge : 0) - .overlay(RoundedRectangle(cornerRadius: cornerRadius) - .stroke(edgeColor)) - .contentShape(Rectangle()) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ActivityIndicator.swift b/Dependencies/LoopKit/LoopKitUI/Views/ActivityIndicator.swift deleted file mode 100644 index dce7036f7..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ActivityIndicator.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// ActivityIndicator.swift -// DashKitUI -// -// Created by Pete Schwamb on 2/10/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct ActivityIndicator: UIViewRepresentable { - - @Binding var isAnimating: Bool - let style: UIActivityIndicatorView.Style - let color: UIColor? - - public init(isAnimating: Binding, style: UIActivityIndicatorView.Style, color: UIColor? = nil) { - self._isAnimating = isAnimating - self.style = style - self.color = color - } - - public func makeUIView(context: UIViewRepresentableContext) -> UIActivityIndicatorView { - let activityIndicator = UIActivityIndicatorView(style: style) - activityIndicator.color = color - return activityIndicator - } - - public func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext) { - isAnimating ? uiView.startAnimating() : uiView.stopAnimating() - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/AlertContent.swift b/Dependencies/LoopKit/LoopKitUI/Views/AlertContent.swift deleted file mode 100644 index bcefb389b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/AlertContent.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// AlertContent.swift -// LoopKitUI -// -// Created by Michael Pangburn on 5/7/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -public struct AlertContent { - public var title: Text - public var message: Text - public var cancel: Text? - public var ok: Text? -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/AuthenticationTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/AuthenticationTableViewCell.swift deleted file mode 100644 index a1a9df3d1..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/AuthenticationTableViewCell.swift +++ /dev/null @@ -1,133 +0,0 @@ -// -// AuthenticationTableViewCell.swift -// Loop -// -// Created by Nate Racklyeft on 7/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -public final class AuthenticationTableViewCell: UITableViewCell { - - @IBOutlet public weak var titleLabel: UILabel! - - @IBOutlet public weak var textField: UITextField! - - public override func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - if selected { - textField.becomeFirstResponder() - } - } - - public override func prepareForReuse() { - super.prepareForReuse() - - textField.delegate = nil - credentialOptionPicker = nil - } - - var credentialOptionPicker: CredentialOptionPicker? { - didSet { - if let picker = credentialOptionPicker { - picker.delegate = self - - textField.text = picker.selectedOption.title - textField.inputView = picker.view - textField.tintColor = .clear // Makes the cursor invisible - } else { - textField.inputView = nil - textField.tintColor = nil - } - } - } - - var value: String? { - if let picker = credentialOptionPicker { - return picker.value - } else { - return textField.text - } - } -} - -extension AuthenticationTableViewCell: CredentialOptionPickerDelegate { - func credentialOptionDataSourceDidUpdateValue(_ picker: CredentialOptionPicker) { - textField.text = picker.selectedOption.title - textField.delegate?.textFieldDidEndEditing?(textField) - } -} - - -protocol CredentialOptionPickerDelegate: AnyObject { - func credentialOptionDataSourceDidUpdateValue(_ picker: CredentialOptionPicker) -} - - -class CredentialOptionPicker: NSObject, UIPickerViewDataSource, UIPickerViewDelegate { - let options: [(title: String, value: String)] - - weak var delegate: CredentialOptionPickerDelegate? - - let view = UIPickerView() - - var selectedOption: (title: String, value: String) { - let index = view.selectedRow(inComponent: 0) - guard index >= options.startIndex && index < options.endIndex else { - return options[0] - } - - return options[index] - } - - var value: String? { - get { - return selectedOption.value - } - set { - let index: Int - - if let value = newValue, let optionIndex = options.firstIndex(where: { $0.value == value }) { - index = optionIndex - } else { - index = 0 - } - - view.selectRow(index, inComponent: 0, animated: view.superview != nil) - } - } - - init(options: [(title: String, value: String)]) { - assert(options.count > 0, "At least one option must be specified") - - self.options = options - - super.init() - - view.dataSource = self - view.delegate = self - } - - // MARK: - UIPickerViewDataSource - - func numberOfComponents(in pickerView: UIPickerView) -> Int { - return 1 - } - - func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { - return options.count - } - - // MARK: - UIPickerViewDelegate - - func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { - return options[row].title - } - - func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { - delegate?.credentialOptionDataSourceDidUpdateValue(self) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/AuthenticationTableViewCell.xib b/Dependencies/LoopKit/LoopKitUI/Views/AuthenticationTableViewCell.xib deleted file mode 100644 index 27796269f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/AuthenticationTableViewCell.xib +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/BaseHUDView.swift b/Dependencies/LoopKit/LoopKitUI/Views/BaseHUDView.swift deleted file mode 100644 index 99a4bf0a3..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/BaseHUDView.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// HUDView.swift -// Naterade -// -// Created by Nathan Racklyeft on 5/1/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - -public typealias HUDViewOrderPriority = Int - -@objc open class BaseHUDView: UIView { - - @IBOutlet weak public var caption: UILabel! { - didSet { - caption?.text = "–" - // TODO: Setting this color in code because the nib isn't being applied correctly. Review at a later date. - caption?.textColor = .label - } - } - - public var stateColors: StateColorPalette? { - didSet { - stateColorsDidUpdate() - } - } - - open func stateColorsDidUpdate() { - } - - open var orderPriority: HUDViewOrderPriority { - return 10 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/BatteryLevelHUDView.swift b/Dependencies/LoopKit/LoopKitUI/Views/BatteryLevelHUDView.swift deleted file mode 100644 index fe8e77965..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/BatteryLevelHUDView.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// BatteryLevelHUDView.swift -// Naterade -// -// Created by Nathan Racklyeft on 5/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -public final class BatteryLevelHUDView: LevelHUDView, NibLoadable { - - override public var orderPriority: HUDViewOrderPriority { - return 5 - } - - public class func instantiate() -> BatteryLevelHUDView { - return nib().instantiate(withOwner: nil, options: nil)[0] as! BatteryLevelHUDView - } - - private lazy var numberFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .percent - - return formatter - }() - - public var batteryLevel: Double? { - didSet { - if let value = batteryLevel, let level = numberFormatter.string(from: value) { - caption.text = level - accessibilityValue = level - } else { - caption.text = nil - accessibilityValue = nil - } - - level = batteryLevel - } - } - -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/BatteryLevelHUDView.xib b/Dependencies/LoopKit/LoopKitUI/Views/BatteryLevelHUDView.xib deleted file mode 100644 index 8a382c161..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/BatteryLevelHUDView.xib +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/CardList/Card.swift b/Dependencies/LoopKit/LoopKitUI/Views/CardList/Card.swift deleted file mode 100644 index 348a15491..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/CardList/Card.swift +++ /dev/null @@ -1,148 +0,0 @@ -// -// Card.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/14/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -/// A platter displaying a number of components over a rounded background tile. -/// -/// In a `CardStackBuilder`, a single-component `Card` is implicitly created from any expression conforming to `View`. -/// A multi-component `Card` can be constructed using one of `Card`'s initializers. -/// -/// A multi-component card may consist of purely static components: -/// ``` -/// Card { -/// Text("Top") -/// Text("Middle") -/// Text("Bottom") -/// } -/// ``` -/// -/// Cards of a dynamic number of components can be constructed from identifiable data: -/// ``` -/// Card(of: 1...5, id: \.self) { value in -/// Text("\(value)") -/// } -/// ``` -/// -/// Finally, dynamic components can be unrolled to intermix with static components via `Splat`: -/// ``` -/// Card { -/// Text("Above dynamic data") -/// Splat(1...5, id: \.self) { value in -/// Text("Dynamic data \(value)") -/// } -/// Text("Below dynamic data") -/// } -/// ``` -public struct Card: View { - var parts: [AnyView?] - var backgroundColor: Color = Color(.secondarySystemGroupedBackground) - - public var body: some View { - VStack { - ForEach(parts.indices, id: \.self) { index in - Group { - if self.parts[index] != nil { - VStack { - self.parts[index]! - .padding(.top, 4) - - if index != self.parts.indices.last! { - CardSectionDivider() - } - } - .transition(AnyTransition.move(edge: .top).combined(with: .opacity)) - } - } - } - } - .frame(maxWidth: .infinity) - .padding() - .background(CardBackground(color: backgroundColor)) - .padding(.horizontal) - } -} - -extension Card { - init(_ other: Self, backgroundColor: Color? = nil) { - self.parts = other.parts - self.backgroundColor = backgroundColor ?? other.backgroundColor - } - - func backgroundColor(_ color: Color?) -> Self { Self(self, backgroundColor: color) } -} - -extension Card { - public enum Component { - case `static`(AnyView) - case dynamic([(view: AnyView, id: AnyHashable)]) - } - - public init(@CardBuilder card: () -> Card) { - self = card() - } - - public init( - of data: Data, - id: KeyPath, - rowContent: (Data.Element) -> Content - ) { - self.init(components: [.dynamic(Splat(data, id: id, rowContent: rowContent).identifiedViews)]) - } - - public init( - of data: Data, - @ViewBuilder rowContent: (Data.Element) -> Content - ) where Data.Element: Identifiable { - self.init(of: data, id: \.id, rowContent: rowContent) - } - - init(reducing cards: [Card]) { - self.parts = cards.flatMap { $0.parts } - } - - /// `nil` values denote placeholder positions where a view may become visible upon state change. - init(components: [Component?]) { - self.parts = components.map { component in - switch component { - case .static(let view): - return view - case .dynamic(let identifiedViews): - return AnyView( - ForEach(identifiedViews, id: \.id) { view, id in - VStack { - view - if id != identifiedViews.last?.id { - CardSectionDivider() - } - } - } - ) - case nil: - return nil - } - } - } -} - -private struct CardBackground: View { - var color: Color = Color(.secondarySystemGroupedBackground) - - var body: some View { - RoundedRectangle(cornerRadius: 10) - .foregroundColor(color) - } -} - -private struct CardSectionDivider: View { - var body: some View { - Divider() - .padding(.trailing, -16) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/CardList/CardBuilder.swift b/Dependencies/LoopKit/LoopKitUI/Views/CardList/CardBuilder.swift deleted file mode 100644 index ce83b1425..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/CardList/CardBuilder.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// CardBuilder.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/15/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -/// A function builder designed to construct a `Card`. -/// -/// Transformations are applied as follows: -/// - An expression conforming to `View` becomes one component of one card. -/// - An instance of `Splat` is unrolled into a dynamic number of components within one card. -/// -/// Any number of components (individual or splatted) can be sequenced and combined into a single card. -@resultBuilder -public struct CardBuilder { - public typealias Component = Card - - public static func buildIf(_ component: Component?) -> Component { - // If `nil` (i.e. a condition is `false`), leave a placeholder `nil` view to enable smooth insertion when the condition becomes `true`. - component ?? Card(parts: [nil]) - } - - public static func buildBlock(_ v: V) -> Component { - toCard(v) - } - - public static func buildBlock(_ v0: V0, _ v1: V1) -> Component { - Card(reducing: [toCard(v0), toCard(v1)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2) -> Component { - Card(reducing: [toCard(v0), toCard(v1), toCard(v2)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3) -> Component { - Card(reducing: [toCard(v0), toCard(v1), toCard(v2), toCard(v3)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4) -> Component { - Card(reducing: [toCard(v0), toCard(v1), toCard(v2), toCard(v3), toCard(v4)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5) -> Component { - Card(reducing: [toCard(v0), toCard(v1), toCard(v2), toCard(v3), toCard(v4), toCard(v5)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5, _ v6: V6) -> Component { - Card(reducing: [toCard(v0), toCard(v1), toCard(v2), toCard(v3), toCard(v4), toCard(v5), toCard(v6)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5, _ v6: V6, _ v7: V7) -> Component { - Card(reducing: [toCard(v0), toCard(v1), toCard(v2), toCard(v3), toCard(v4), toCard(v5), toCard(v6), toCard(v7)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5, _ v6: V6, _ v7: V7, _ v8: V8) -> Component { - Card(reducing: [toCard(v0), toCard(v1), toCard(v2), toCard(v3), toCard(v4), toCard(v5), toCard(v6), toCard(v7), toCard(v8)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5, _ v6: V6, _ v7: V7, _ v8: V8, _ v9: V9) -> Component { - Card(reducing: [toCard(v0), toCard(v1), toCard(v2), toCard(v3), toCard(v4), toCard(v5), toCard(v6), toCard(v7), toCard(v8), toCard(v9)]) - } - - // TODO: Simplify using `buildExpression` when Swift 5.2 is available. - private static func toCard(_ v: V) -> Card { - if let card = v as? Card { - return card - } else if let splat = v as? Splat { - return Card(components: [.dynamic(splat.identifiedViews)]) - } else { - return Card(components: [.static(AnyView(v))]) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/CardList/CardList.swift b/Dependencies/LoopKit/LoopKitUI/Views/CardList/CardList.swift deleted file mode 100644 index 14ed0aeee..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/CardList/CardList.swift +++ /dev/null @@ -1,107 +0,0 @@ -// -// CardList.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/10/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -public struct CardListSection: View { - var title: Text? - var stack: CardStack - - public init(title: Text? = nil, @CardStackBuilder cards: () -> CardStack) { - self.title = title - self.stack = cards() - } - - public var body: some View { - VStack(spacing: 6) { - if let title = title { - HStack { - title - .font(Font(UIFont.preferredFont(forTextStyle: .title3))) - .bold() - Spacer() - } - .padding(.leading) - } - stack - } - } -} - -public enum CardListStyle { - case simple(CardStack) - case sectioned([CardListSection]) -} - -/// Displays a list of cards similar to a `List` with an inset grouped style, -/// but without the baggage of `UITableViewCell` resizing, enabling cells to expand smoothly. -public struct CardList: View { - var title: Text? - var style: CardListStyle - var trailer: Trailer? - - public init(title: Text? = nil, style: CardListStyle, trailer: Trailer) { - self.title = title - self.style = style - self.trailer = trailer - } - - public init(title: Text? = nil, style: CardListStyle) where Trailer == EmptyView { - self.title = title - self.style = style - self.trailer = nil - } - - public var body: some View { - ScrollView { - VStack(spacing: 4) { - titleText - .fixedSize(horizontal: false, vertical: true) - - cards - if let trailer = trailer { - trailer - } - } - } - .background(Color(.systemGroupedBackground)) - } - - @ViewBuilder - private var titleText: some View { - if let title = title { - HStack { - title - .font(.largeTitle) - .bold() - Spacer() - } - .padding() - .padding(.bottom, 4) - .background(Color(.systemGroupedBackground)) - } else { - Spacer() - } - } - - private var cards: some View { - switch style { - case .simple(let stack): - return AnyView(stack) - case .sectioned(let sections): - return AnyView( - VStack(spacing: 16) { - ForEach(Array(sections.enumerated()), id: \.offset) { index, section in - section - } - } - ) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/CardList/CardStack.swift b/Dependencies/LoopKit/LoopKitUI/Views/CardList/CardStack.swift deleted file mode 100644 index f61d6d51e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/CardList/CardStack.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// CardStack.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/16/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -public struct CardStack: View { - var cards: [Card?] - var spacing: CGFloat? - - public init(cards: [Card?], spacing: CGFloat? = nil) { - self.cards = cards - self.spacing = spacing - } - - public var body: some View { - VStack(spacing: spacing) { - ForEach(self.cards.indices, id: \.self) { index in - self.cards[index] - } - } - .padding(.bottom) - } -} - -extension CardStack { - init(reducing stacks: [CardStack]) { - self.cards = stacks.flatMap { $0.cards } - self.spacing = nil - } -} - -extension CardStack { - private init(_ other: Self, spacing: CGFloat? = nil) { - self.cards = other.cards - self.spacing = spacing ?? other.spacing - } - - func spacing(_ spacing: CGFloat?) -> Self { Self(self, spacing: spacing) } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/CardList/CardStackBuilder.swift b/Dependencies/LoopKit/LoopKitUI/Views/CardList/CardStackBuilder.swift deleted file mode 100644 index ceb8f94a5..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/CardList/CardStackBuilder.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// CardStackBuilder.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/15/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -/// Constructs an array of `Card` views from arbitrary `View` instances. -/// -/// A multi-component card can be constructed using one of `Card`'s initializers. -@resultBuilder -public struct CardStackBuilder { - public typealias Component = CardStack - - public static func buildIf(_ component: Component?) -> Component { - // If `nil` (i.e. a condition is `false`), leave a placeholder `nil` view to enable smooth insertion when the condition becomes `true`. - component ?? CardStack(cards: [nil]) - } - - public static func buildBlock(_ v: V) -> Component { - toCardStack(v) - } - - public static func buildBlock(_ v0: V0, _ v1: V1) -> Component { - CardStack(reducing: [toCardStack(v0), toCardStack(v1)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2) -> Component { - CardStack(reducing: [toCardStack(v0), toCardStack(v1), toCardStack(v2)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3) -> Component { - CardStack(reducing: [toCardStack(v0), toCardStack(v1), toCardStack(v2), toCardStack(v3)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4) -> Component { - CardStack(reducing: [toCardStack(v0), toCardStack(v1), toCardStack(v2), toCardStack(v3), toCardStack(v4)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5) -> Component { - CardStack(reducing: [toCardStack(v0), toCardStack(v1), toCardStack(v2), toCardStack(v3), toCardStack(v4), toCardStack(v5)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5, _ v6: V6) -> Component { - CardStack(reducing: [toCardStack(v0), toCardStack(v1), toCardStack(v2), toCardStack(v3), toCardStack(v4), toCardStack(v5), toCardStack(v6)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5, _ v6: V6, _ v7: V7) -> Component { - CardStack(reducing: [toCardStack(v0), toCardStack(v1), toCardStack(v2), toCardStack(v3), toCardStack(v4), toCardStack(v5), toCardStack(v6), toCardStack(v7)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5, _ v6: V6, _ v7: V7, _ v8: V8) -> Component { - CardStack(reducing: [toCardStack(v0), toCardStack(v1), toCardStack(v2), toCardStack(v3), toCardStack(v4), toCardStack(v5), toCardStack(v6), toCardStack(v7), toCardStack(v8)]) - } - - public static func buildBlock(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5, _ v6: V6, _ v7: V7, _ v8: V8, _ v9: V9) -> Component { - CardStack(reducing: [toCardStack(v0), toCardStack(v1), toCardStack(v2), toCardStack(v3), toCardStack(v4), toCardStack(v5), toCardStack(v6), toCardStack(v7), toCardStack(v8), toCardStack(v9)]) - } - - // TODO: Simplify using `buildExpression` when Swift 5.2 is available. - private static func toCardStack(_ v: V) -> CardStack { - if let stack = v as? CardStack { - return stack - } else if let card = v as? Card { - return CardStack(cards: [card]) - } else { - return CardStack(cards: [Card(parts: [AnyView(v)])]) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/CardList/Splat.swift b/Dependencies/LoopKit/LoopKitUI/Views/CardList/Splat.swift deleted file mode 100644 index 04f270754..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/CardList/Splat.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// Splat.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/15/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -/// A structure representing multiple components of one `Card`. -/// -/// Use `Splat` to intermix static and dynamic card components: -/// ``` -/// Card { -/// Text("Above dynamic data") -/// Splat(1...5, id: \.self) { value in -/// Text("Dynamic data \(value)") -/// } -/// Text("Below dynamic data") -/// } -/// ``` -public struct Splat: View { - var identifiedViews: [(view: AnyView, id: AnyHashable)] - - public init( - _ data: Data, - id: KeyPath, - @ViewBuilder rowContent: (Data.Element) -> Content - ) { - identifiedViews = data.map { datum in - (view: AnyView(rowContent(datum)), id: datum[keyPath: id]) - } - } - - public init( - _ data: Data, - @ViewBuilder rowContent: (Data.Element) -> Content - ) where Data.Element: Identifiable { - self.init(data, id: \.id, rowContent: rowContent) - } - - public var body: some View { - Card(components: [.dynamic(identifiedViews)]) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/CardList/TimePicker.swift b/Dependencies/LoopKit/LoopKitUI/Views/CardList/TimePicker.swift deleted file mode 100644 index e4c86f8e9..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/CardList/TimePicker.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// TimePicker.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/23/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -/// Binds a `TimeInterval` describing an offset from midnight to a selected picker value. -/// -/// For example, a value of `0` corresponds to midnight, while a value of `7200` corresponds to 2:00 AM. -/// -/// The offset is not relative to the current date. Use `TimePicker` for selecting the time of a recurring daily event, _not_ for selecting the time at which an alarm should sound later this afternoon. -public struct TimePicker: View { - @Binding private var offsetFromMidnight: TimeInterval - private let allValues: [TimeInterval] - private let fixedMidnight = Calendar.current.startOfDay(for: Date(timeIntervalSinceReferenceDate: 0)) - - private static let dateFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .none - dateFormatter.timeStyle = .short - return dateFormatter - }() - - public init( - offsetFromMidnight: Binding, - bounds: ClosedRange, - stride: TimeInterval, - isTimeExcluded: (TimeInterval) -> Bool = { _ in false } - ) { - self._offsetFromMidnight = offsetFromMidnight - self.allValues = Swift.stride(from: bounds.lowerBound, through: bounds.upperBound, by: stride) - .filter { !isTimeExcluded($0) } - } - - public var body: some View { - Picker(selection: $offsetFromMidnight, label: Text(LocalizedString("Time", comment: "Label for offset from midnight picker"))) { - ForEach(allValues, id: \.self) { time in - self.text(for: time) - } - } - .pickerStyle(.wheel) - .labelsHidden() - } - - private func text(for time: TimeInterval) -> Text { - let dayAtTime = fixedMidnight.addingTimeInterval(time) - return Text("\(dayAtTime, formatter: Self.dateFormatter)") - .foregroundColor(.primary) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ChartContainerView.swift b/Dependencies/LoopKit/LoopKitUI/Views/ChartContainerView.swift deleted file mode 100644 index 436f7b70b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ChartContainerView.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// ChartContainerView.swift -// LoopKitUI -// -// Created by Nate Racklyeft on 9/14/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - -public class ChartContainerView: UIView { - - override public func layoutSubviews() { - super.layoutSubviews() - - if chartView == nil || chartView!.frame != bounds { - // 50 is the smallest height in which we should attempt to redraw a chart. - // Smaller sizes might be requested mid-animation, so ignore them. - if bounds.height > 50 { - chartView = chartGenerator?(bounds) - } - } else if chartView!.superview == nil { - addSubview(chartView!) - } - } - - public func reloadChart() { - chartView = nil - setNeedsLayout() - } - - public var chartGenerator: ((CGRect) -> UIView?)? { - didSet { - chartView = nil - setNeedsLayout() - } - } - - private var chartView: UIView? { - didSet { - if let view = oldValue { - view.removeFromSuperview() - } - - if let view = chartView { - self.addSubview(view) - } - } - } - -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ChartTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/ChartTableViewCell.swift deleted file mode 100644 index 6576fbbcb..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ChartTableViewCell.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// ChartTableViewCell.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/19/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -public final class ChartTableViewCell: UITableViewCell { - - @IBOutlet weak var chartContentView: ChartContainerView! - - @IBOutlet weak var titleLabel: UILabel? - - @IBOutlet weak var subtitleLabel: UILabel? - - @IBOutlet weak var rightArrowHint: UIImageView? { - didSet { - rightArrowHint?.isHidden = !doesNavigate - } - } - - public var doesNavigate: Bool = true { - didSet { - rightArrowHint?.isHidden = !doesNavigate - } - } - - public override func prepareForReuse() { - super.prepareForReuse() - doesNavigate = true - chartContentView.chartGenerator = nil - } - - public func reloadChart() { - chartContentView.reloadChart() - } - - public func setChartGenerator(generator: ((CGRect) -> UIView?)?) { - chartContentView.chartGenerator = generator - } - - public func setTitleLabelText(label: String?) { - titleLabel?.text = label - } - - public func removeTitleLabelText() { - titleLabel?.text?.removeAll() - } - - public func setSubtitleLabel(label: String?) { - subtitleLabel?.text = label - } - - public func removeSubtitleLabelText() { - subtitleLabel?.text?.removeAll() - } - - public func setTitleTextColor(color: UIColor) { - titleLabel?.textColor = color - } - - public func setSubtitleTextColor(color: UIColor) { - subtitleLabel?.textColor = color - } - - public func setAlpha(alpha: CGFloat) { - titleLabel?.alpha = alpha - subtitleLabel?.alpha = alpha - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/CheckmarkListItem.swift b/Dependencies/LoopKit/LoopKitUI/Views/CheckmarkListItem.swift deleted file mode 100644 index 2c8b71fef..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/CheckmarkListItem.swift +++ /dev/null @@ -1,126 +0,0 @@ -// -// CheckmarkListItem.swift -// LoopKitUI -// -// Created by Rick Pasetto on 7/17/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct CheckmarkListItem: View { - - var title: Text - var titleFont: Font - var description: Text - @Binding var isSelected: Bool - let isEnabled: Bool - - public init(title: Text, titleFont: Font = .headline, description: Text, isSelected: Binding, isEnabled: Bool = true) { - self.title = title - self.titleFont = titleFont - self.description = description - self._isSelected = isSelected - self.isEnabled = isEnabled - } - - @ViewBuilder - public var body: some View { - if isEnabled { - Button(action: { self.isSelected = true }) { - content - } - } else { - content - } - } - - private var content: some View { - HStack(spacing: 0) { - VStack(alignment: .leading, spacing: 4) { - title - .font(titleFont) - description - .font(.footnote) - .foregroundColor(.secondary) - .fixedSize(horizontal: false, vertical: true) - .multilineTextAlignment(.leading) - } - - Spacer(minLength: 12) - - selectionIndicator - .accessibility(label: Text(isSelected ? "Selected" : "Unselected")) - } - .animation(nil) - } - - @ViewBuilder - private var selectionIndicator: some View { - if isEnabled { - filledCheckmark - .frame(width: 26, height: 26) - } else { - plainCheckmark - .frame(width: 22, height: 22) - } - } - - @ViewBuilder - private var filledCheckmark: some View { - if isSelected { - Image(systemName: "checkmark.circle.fill") - .resizable() - .background(Circle().stroke()) // Ensure size aligns with open circle - .foregroundColor(.accentColor) - } else { - Circle() - .stroke() - .foregroundColor(Color(.systemGray4)) - } - } - - @ViewBuilder - private var plainCheckmark: some View { - if isSelected { - Image(systemName: "checkmark") - .resizable() - .foregroundColor(.accentColor) - } - } - -} - -public struct DurationBasedCheckmarkListItem: View { - - var title: Text - var titleFont: Font - var description: Text - @Binding var isSelected: Bool - let isEnabled: Bool - @Binding var duration: TimeInterval - var validDurationRange: ClosedRange - - public init(title: Text, titleFont: Font = .headline, description: Text, isSelected: Binding, isEnabled: Bool = true, - duration: Binding, validDurationRange: ClosedRange) { - self.title = title - self.titleFont = titleFont - self.description = description - self._isSelected = isSelected - self.isEnabled = isEnabled - self._duration = duration - self.validDurationRange = validDurationRange - } - - public var body: some View { - VStack(spacing: 0) { - CheckmarkListItem(title: title, titleFont: titleFont, description: description, isSelected: $isSelected, isEnabled: isEnabled) - - if isSelected { - DurationPicker(duration: $duration, validDurationRange: validDurationRange) - .frame(height: 216) - .transition(.fadeInFromTop) - } - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ConfigurationPage.swift b/Dependencies/LoopKit/LoopKitUI/Views/ConfigurationPage.swift deleted file mode 100644 index 13611ce8c..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ConfigurationPage.swift +++ /dev/null @@ -1,140 +0,0 @@ -// -// ConfigurationPage.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/10/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -public enum ConfigurationPageActionButtonState { - case enabled - case loading - case disabled -} - -public struct ConfigurationPage: View { - public typealias ActionButtonState = ConfigurationPageActionButtonState - - var title: Text - var actionButtonTitle: Text - var actionButtonState: ActionButtonState - var cardListStyle: CardListStyle - var actionAreaContent: ActionAreaContent - var action: () -> Void - - public var body: some View { - VStack(spacing: 0) { - CardList(title: title, style: cardListStyle) - - VStack(spacing: 0) { - actionAreaContent - .padding([.top, .horizontal]) - .transition(AnyTransition.opacity.combined(with: .move(edge: .bottom))) - - Button( - action: action, - label: { - HStack(spacing: 12) { - ActivityIndicator(isAnimating: .constant(false), style: .medium) - .opacity(0) // For layout only, to ensure the button text is centered - - actionButtonTitle - .animation(nil) - - ActivityIndicator(isAnimating: .constant(true), style: .medium, color: .white) - .opacity(actionButtonState == .loading ? 1 : 0) - } - } - ) - .buttonStyle(ActionButtonStyle(.primary)) - .disabled(actionButtonState != .enabled) - .padding() - } - .padding(.bottom) // FIXME: unnecessary on iPhone 8 size devices - .background(Color(.secondarySystemGroupedBackground).shadow(radius: 5)) - } - .edgesIgnoringSafeArea(.bottom) - } -} - -extension ConfigurationPage { - public init( - title: Text, - actionButtonTitle: Text, - actionButtonState: ActionButtonState = .enabled, - @CardStackBuilder cards: () -> CardStack, - @ViewBuilder actionAreaContent: () -> ActionAreaContent, - action: @escaping () -> Void - ) { - self.title = title - self.actionButtonTitle = actionButtonTitle - self.actionButtonState = actionButtonState - self.cardListStyle = .simple(cards()) - self.actionAreaContent = actionAreaContent() - self.action = action - } - - /// Convenience initializer for a page whose action is 'Save' - public init( - title: Text, - saveButtonState: ActionButtonState = .enabled, - @CardStackBuilder cards: () -> CardStack, - @ViewBuilder actionAreaContent: () -> ActionAreaContent, - onSave save: @escaping () -> Void - ) { - self.init( - title: title, - actionButtonTitle: Text(LocalizedString("Save", comment: "The button text for saving on a configuration page")), - actionButtonState: saveButtonState, - cards: cards, - actionAreaContent: actionAreaContent, - action: save - ) - } - - /// Convenience initializer for a sectioned page whose action is 'Save' - public init( - title: Text, - saveButtonState: ActionButtonState = .enabled, - sections: [CardListSection], - @ViewBuilder actionAreaContent: () -> ActionAreaContent, - onSave save: @escaping () -> Void - ) { - self.init( - title: title, - actionButtonTitle: Text(LocalizedString("Save", comment: "The button text for saving on a configuration page")), - actionButtonState: saveButtonState, - cardListStyle: .sectioned(sections), - actionAreaContent: actionAreaContent(), - action: save - ) - } -} - -struct ConfigurationPage_Previews: PreviewProvider { - static var previews: some View { - ConfigurationPage( - title: Text("Example"), - cards: { - Text("A simple card") - Text("A card whose text will wrap onto multiple lines if I continue to type for long enough—this length should do") - - Card { - Text("Top component") - Text("Bottom component") - } - - Card(of: 1...3, id: \.self) { value in - Text("Dynamic component #\(value)") - } - }, - actionAreaContent: { - Text("Above the save button") - }, - onSave: {} - ) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ConfigurationPageScrollView.swift b/Dependencies/LoopKit/LoopKitUI/Views/ConfigurationPageScrollView.swift deleted file mode 100644 index 40d9f38db..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ConfigurationPageScrollView.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// ConfigurationPageScrollView.swift -// LoopKitUI -// -// Created by Pete Schwamb on 12/30/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -// ConfigurationPageScrollView is a ScrollView (not List) based configuration page. -// The optional action area is pinned to the bottom, but does not overlay any content - -public struct ConfigurationPageScrollView: View { - - var content: Content - var actionArea: ActionArea? - - public init(@ViewBuilder content: () -> Content, @ViewBuilder actionArea: () -> ActionArea?) { - self.content = content() - self.actionArea = actionArea() - } - - public var body: some View { - GeometryReader { geometry in - ScrollView { - VStack { - content - Spacer() - actionArea - } - .frame(minHeight: geometry.size.height) - } - .background(Color(.systemGroupedBackground)) - .background(ignoresSafeAreaEdges: .bottom) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/CustomOverrideCollectionViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/CustomOverrideCollectionViewCell.swift deleted file mode 100644 index c81c76b08..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/CustomOverrideCollectionViewCell.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// CustomOverrideCollectionViewCell.swift -// LoopKitUI -// -// Created by Michael Pangburn on 11/5/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit - - -final class CustomOverrideCollectionViewCell: UICollectionViewCell, IdentifiableClass { - @IBOutlet weak var titleLabel: UILabel! - - private lazy var overlayDimmerView: UIView = { - let view = UIView() - view.backgroundColor = .systemBackground - view.alpha = 0 - view.translatesAutoresizingMaskIntoConstraints = false - return view - }() - - override func awakeFromNib() { - super.awakeFromNib() - - let selectedBackgroundView = UIView() - self.selectedBackgroundView = selectedBackgroundView - - selectedBackgroundView.backgroundColor = .tertiarySystemFill - - backgroundColor = .secondarySystemGroupedBackground - layer.cornerCurve = .continuous - - layer.cornerRadius = 16 - - addSubview(overlayDimmerView) - NSLayoutConstraint.activate([ - overlayDimmerView.leadingAnchor.constraint(equalTo: leadingAnchor), - overlayDimmerView.trailingAnchor.constraint(equalTo: trailingAnchor), - overlayDimmerView.topAnchor.constraint(equalTo: topAnchor), - overlayDimmerView.bottomAnchor.constraint(equalTo: bottomAnchor) - ]) - } - - override func prepareForReuse() { - removeOverlay(animated: false) - } - - func applyOverlayToFade(animated: Bool) { - if animated { - UIView.animate(withDuration: 0.3, animations: { - self.overlayDimmerView.alpha = 0.5 - }) - } else { - self.overlayDimmerView.alpha = 0.5 - } - } - - func removeOverlay(animated: Bool) { - if animated { - UIView.animate(withDuration: 0.3, animations: { - self.overlayDimmerView.alpha = 0 - }) - } else { - self.overlayDimmerView.alpha = 0 - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/DatePickerTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/DatePickerTableViewCell.swift deleted file mode 100644 index 1ed9603a4..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/DatePickerTableViewCell.swift +++ /dev/null @@ -1,123 +0,0 @@ -// -// DatePickerTableViewCell.swift -// CarbKit -// -// Created by Nathan Racklyeft on 1/15/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - -public protocol DatePickerTableViewCellDelegate: AnyObject { - func datePickerTableViewCellDidUpdateDate(_ cell: DatePickerTableViewCell) -} - - -open class DatePickerTableViewCell: UITableViewCell { - - open var date: Date { - get { - return datePicker.date - } - set { - if let maximumDate = datePicker.maximumDate, - newValue >= maximumDate - { - datePicker.setDate(maximumDate, animated: true) - } else if let minimumDate = datePicker.minimumDate, - newValue <= minimumDate - { - datePicker.setDate(minimumDate, animated: true) - } else { - datePicker.setDate(newValue, animated: true) - } - dateChanged(datePicker) - updateDateLabel() - } - } - - open var duration: TimeInterval { - get { - return datePicker.countDownDuration - } - set { - datePicker.countDownDuration = newValue - updateDateLabel() - } - } - - open var maximumDuration = TimeInterval(hours: 8) { - didSet { - if duration > maximumDuration { - duration = maximumDuration - } - } - } - - @IBOutlet open weak var datePicker: UIDatePicker! - - @IBOutlet open weak var datePickerHeightConstraint: NSLayoutConstraint! - - private var datePickerExpandedHeight: CGFloat = 0 - - open var isDatePickerHidden: Bool { - get { - return datePicker.isHidden || !datePicker.isEnabled - } - set { - if datePicker.isEnabled { - datePicker.isHidden = newValue - datePickerHeightConstraint.constant = newValue ? 0 : datePickerExpandedHeight - - if !newValue, case .countDownTimer = datePicker.datePickerMode { - // Workaround for target-action change notifications not firing if initial value is set while view is hidden - DispatchQueue.main.async { - self.datePicker.date = self.datePicker.date - self.datePicker.countDownDuration = self.datePicker.countDownDuration - } - } - } - } - } - - open override func awakeFromNib() { - super.awakeFromNib() - - datePickerExpandedHeight = datePickerHeightConstraint.constant - - setSelected(true, animated: false) - updateDateLabel() - } - - open override func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - if selected { - isDatePickerHidden = !isDatePickerHidden - } - } - - open func updateDateLabel() { - } - - @IBAction open func dateChanged(_ sender: UIDatePicker) { - if case .countDownTimer = sender.datePickerMode, duration > maximumDuration { - duration = maximumDuration - } else { - updateDateLabel() - } - } -} - - -/// UITableViewController extensions to aid working with DatePickerTableViewCell -extension DatePickerTableViewCellDelegate where Self: UITableViewController { - public func hideDatePickerCells(excluding indexPath: IndexPath? = nil) { - guard isViewLoaded else { - return - } - for case let cell as DatePickerTableViewCell in tableView.visibleCells where tableView.indexPath(for: cell) != indexPath && cell.isDatePickerHidden == false { - cell.isDatePickerHidden = true - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/DecimalTextFieldTableViewCell.xib b/Dependencies/LoopKit/LoopKitUI/Views/DecimalTextFieldTableViewCell.xib deleted file mode 100644 index c02bcb3c6..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/DecimalTextFieldTableViewCell.xib +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Deletable.swift b/Dependencies/LoopKit/LoopKitUI/Views/Deletable.swift deleted file mode 100644 index 3a3b452fb..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Deletable.swift +++ /dev/null @@ -1,119 +0,0 @@ -// -// Deletable.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/30/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -enum TableDeletionState: Equatable { - case disabled - case enabled - case awaitingConfirmation(toDeleteItemAt: Int) - - var isAwaitingConfirmation: Bool { - if case .awaitingConfirmation = self { - return true - } else { - return false - } - } - - var indexAwaitingDeletionConfirmation: Int? { - if case .awaitingConfirmation(toDeleteItemAt: let index) = self { - return index - } else { - return nil - } - } -} - - -/// Mimics the behavior of UITableViewCell deletion. -/// -/// As of Xcode 11.4, SwiftUI's List does not play nicely with resizing cells. -/// CardList solves this issue while retaining the appearance of an inset grouped table. -/// However, by avoiding List, we also lose built-in deletion functionality, requiring this implementation. -struct Deletable: View { - @Binding var tableDeletionState: TableDeletionState - var index: Int - var isDeletable: Bool - var delete: () -> Void - var content: Content - - init( - tableDeletionState: Binding, - index: Int, - isDeletable: Bool, - onDelete delete: @escaping () -> Void, - @ViewBuilder content: () -> Content - ) { - self._tableDeletionState = tableDeletionState - self.index = index - self.isDeletable = isDeletable - self.delete = delete - self.content = content() - } - - var body: some View { - HStack(spacing: 16) { - if isDeletable && - tableDeletionState != .disabled && - tableDeletionState.indexAwaitingDeletionConfirmation != index - { - DeletionIndicator() - .transition(AnyTransition.move(edge: .leading).combined(with: .opacity)) - .onTapGesture { - withAnimation { - self.tableDeletionState = .awaitingConfirmation(toDeleteItemAt: self.index) - } - } - } - - HStack(spacing: 16) { - content - .disabled(tableDeletionState != .disabled) - .contentShape(Rectangle()) - .onTapGesture { - if self.tableDeletionState.isAwaitingConfirmation { - withAnimation { - self.tableDeletionState = .enabled - } - } - } - - if tableDeletionState.indexAwaitingDeletionConfirmation == index { - Text(LocalizedString("Delete", comment: "Test for table cell delete button")) - .lineLimit(1) - .foregroundColor(.white) - .background( - // Expand into margins - Color.red.padding(-12) - ) - .transition(AnyTransition.move(edge: .trailing).combined(with: .opacity)) - .offset(x: 4) // Push into margin - .onTapGesture { - withAnimation { - self.tableDeletionState = .enabled - self.delete() - } - } - } - } - } - } -} - -private struct DeletionIndicator: View { - var body: some View { - Text("-") - .bold() - .foregroundColor(.white) - .padding(1) - .background(Circle().fill(Color.red)) - .padding(-1) // Prevent circle background from affecting layout - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/DescriptiveText.swift b/Dependencies/LoopKit/LoopKitUI/Views/DescriptiveText.swift deleted file mode 100644 index 891dfd77e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/DescriptiveText.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// DescriptiveText.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-02-20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct DescriptiveText: View { - var label: String - let color: Color - - public init(label: String, color: Color = .secondary) { - self.label = label - self.color = color - } - - public var body: some View { - Text(label) - .font(.footnote) - .foregroundColor(color) - } -} - -struct DescriptiveText_Previews: PreviewProvider { - static var previews: some View { - DescriptiveText(label: "Descriptive text is typically lengthly and provides additional details to potentially terse labeled values.") - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/DismissibleKeyboardTextField.swift b/Dependencies/LoopKit/LoopKitUI/Views/DismissibleKeyboardTextField.swift deleted file mode 100644 index 72af17e74..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/DismissibleKeyboardTextField.swift +++ /dev/null @@ -1,142 +0,0 @@ -// -// DismissibleKeyboardTextField.swift -// LoopKitUI -// -// Created by Michael Pangburn on 7/22/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -public struct DismissibleKeyboardTextField: UIViewRepresentable { - @Binding var text: String - var placeholder: String - var font: UIFont - var textColor: UIColor - var textAlignment: NSTextAlignment - var keyboardType: UIKeyboardType - var autocapitalizationType: UITextAutocapitalizationType - var autocorrectionType: UITextAutocorrectionType - var shouldBecomeFirstResponder: Bool - var maxLength: Int? - var doneButtonColor: UIColor - var isDismissible: Bool - var textFieldDidBeginEditing: (() -> Void)? - - public init( - text: Binding, - placeholder: String, - font: UIFont = .preferredFont(forTextStyle: .body), - textColor: UIColor = .label, - textAlignment: NSTextAlignment = .natural, - keyboardType: UIKeyboardType = .default, - autocapitalizationType: UITextAutocapitalizationType = .sentences, - autocorrectionType: UITextAutocorrectionType = .default, - shouldBecomeFirstResponder: Bool = false, - maxLength: Int? = nil, - doneButtonColor: UIColor = .blue, - isDismissible: Bool = true, - textFieldDidBeginEditing: (() -> Void)? = nil - ) { - self._text = text - self.placeholder = placeholder - self.font = font - self.textColor = textColor - self.textAlignment = textAlignment - self.keyboardType = keyboardType - self.autocapitalizationType = autocapitalizationType - self.autocorrectionType = autocorrectionType - self.shouldBecomeFirstResponder = shouldBecomeFirstResponder - self.maxLength = maxLength - self.doneButtonColor = doneButtonColor - self.isDismissible = isDismissible - self.textFieldDidBeginEditing = textFieldDidBeginEditing - } - - public func makeUIView(context: Context) -> UITextField { - let textField = UITextField() - textField.inputAccessoryView = isDismissible ? makeDoneToolbar(for: textField) : nil - textField.addTarget(context.coordinator, action: #selector(Coordinator.textChanged), for: .editingChanged) - textField.addTarget(context.coordinator, action: #selector(Coordinator.editingDidBegin), for: .editingDidBegin) - textField.delegate = context.coordinator - return textField - } - - private func makeDoneToolbar(for textField: UITextField) -> UIToolbar { - let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50)) - let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) - let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: textField, action: #selector(UITextField.resignFirstResponder)) - doneButton.tintColor = doneButtonColor - toolbar.items = [flexibleSpace, doneButton] - toolbar.sizeToFit() - return toolbar - } - - public func updateUIView(_ textField: UITextField, context: Context) { - textField.text = text - textField.placeholder = placeholder - textField.font = font - textField.textColor = textColor - textField.textAlignment = textAlignment - textField.keyboardType = keyboardType - textField.autocapitalizationType = autocapitalizationType - textField.autocorrectionType = autocorrectionType - - if shouldBecomeFirstResponder && !context.coordinator.didBecomeFirstResponder { - // See https://developer.apple.com/documentation/uikit/uiresponder/1621113-becomefirstresponder for why - // we check the window property here (otherwise it might crash) - if textField.window != nil && textField.becomeFirstResponder() { - context.coordinator.didBecomeFirstResponder = true - } - } else if !shouldBecomeFirstResponder && context.coordinator.didBecomeFirstResponder { - context.coordinator.didBecomeFirstResponder = false - } - } - - public func makeCoordinator() -> Coordinator { - Coordinator(self, maxLength: maxLength) - } - - public final class Coordinator: NSObject { - var parent: DismissibleKeyboardTextField - let maxLength: Int? - - // Track in the coordinator to ensure the text field only becomes first responder once, - // rather than on every state change. - var didBecomeFirstResponder = false - - init(_ parent: DismissibleKeyboardTextField, maxLength: Int?) { - self.parent = parent - self.maxLength = maxLength - } - - @objc fileprivate func textChanged(_ textField: UITextField) { - parent.text = textField.text ?? "" - } - - @objc fileprivate func editingDidBegin(_ textField: UITextField) { - // Even though we are likely already on .main, we still need to queue this cursor (selection) change in - // order for it to work - DispatchQueue.main.async { - textField.moveCursorToEnd() - } - } - } -} - -extension DismissibleKeyboardTextField.Coordinator: UITextFieldDelegate { - public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - guard let maxLength = maxLength else { - return true - } - let currentString: NSString = (textField.text ?? "") as NSString - let newString: NSString = - currentString.replacingCharacters(in: range, with: string) as NSString - return newString.length <= maxLength - } - - public func textFieldDidBeginEditing(_ textField: UITextField) { - parent.textFieldDidBeginEditing?() - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/DoubleRangeTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/DoubleRangeTableViewCell.swift deleted file mode 100644 index 2b2f6caa8..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/DoubleRangeTableViewCell.swift +++ /dev/null @@ -1,80 +0,0 @@ -// -// DoubleRangeTableViewCell.swift -// LoopKitUI -// -// Created by Michael Pangburn on 1/3/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit - - -protocol DoubleRangeTableViewCellDelegate: AnyObject { - func doubleRangeTableViewCellDidBeginEditing(_ cell: DoubleRangeTableViewCell) - func doubleRangeTableViewCellDidUpdateRange(_ cell: DoubleRangeTableViewCell) -} - - -class DoubleRangeTableViewCell: UITableViewCell { - - @IBOutlet weak var titleLabel: UILabel! - - @IBOutlet weak var minValueTextField: PaddedTextField! { - didSet { - minValueTextField.delegate = self - minValueTextField.addTarget(self, action: #selector(textFieldEditingChanged), for: .editingChanged) - } - } - - @IBOutlet weak var maxValueTextField: PaddedTextField! { - didSet { - maxValueTextField.delegate = self - maxValueTextField.addTarget(self, action: #selector(textFieldEditingChanged), for: .editingChanged) - } - } - - @IBOutlet weak var unitLabel: UILabel! - - var numberFormatter = NumberFormatter() - - var range: DoubleRange? { - get { - guard - let minValueString = minValueTextField.text, - let minValue = numberFormatter.number(from: minValueString)?.doubleValue, - let maxValueString = maxValueTextField.text, - let maxValue = numberFormatter.number(from: maxValueString)?.doubleValue - else { - return nil - } - - return DoubleRange(minValue: minValue, maxValue: maxValue) - } - set { - guard let newValue = newValue else { - minValueTextField.text = nil - maxValueTextField.text = nil - return - } - minValueTextField.text = numberFormatter.string(from: newValue.minValue) - maxValueTextField.text = numberFormatter.string(from: newValue.maxValue) - } - } - - weak var delegate: DoubleRangeTableViewCellDelegate? - - @objc private func textFieldEditingChanged() { - delegate?.doubleRangeTableViewCellDidUpdateRange(self) - } -} - -extension DoubleRangeTableViewCell: UITextFieldDelegate { - func textFieldDidBeginEditing(_ textField: UITextField) { - delegate?.doubleRangeTableViewCellDidBeginEditing(self) - } - - func textFieldDidEndEditing(_ textField: UITextField) { - delegate?.doubleRangeTableViewCellDidUpdateRange(self) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/DoubleRangeTableViewCell.xib b/Dependencies/LoopKit/LoopKitUI/Views/DoubleRangeTableViewCell.xib deleted file mode 100644 index 2bbb7771b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/DoubleRangeTableViewCell.xib +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/DurationPicker.swift b/Dependencies/LoopKit/LoopKitUI/Views/DurationPicker.swift deleted file mode 100644 index 6b576ccaf..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/DurationPicker.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// DurationPicker.swift -// LoopKitUI -// -// Created by Michael Pangburn on 7/15/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -public struct DurationPicker: UIViewRepresentable { - @Binding public var duration: TimeInterval - public var validDurationRange: ClosedRange - public var minuteInterval: Int - - public init(duration: Binding, validDurationRange: ClosedRange, minuteInterval: Int = 15) { - self._duration = duration - self.validDurationRange = validDurationRange - self.minuteInterval = minuteInterval - } - - public func makeUIView(context: Context) -> UIDatePicker { - let picker = UIDatePicker() - picker.datePickerMode = .countDownTimer - picker.addTarget(context.coordinator, action: #selector(Coordinator.pickerValueChanged(_:)), for: .valueChanged) - return picker - } - - public func updateUIView(_ picker: UIDatePicker, context: Context) { - picker.countDownDuration = duration.clamped(to: validDurationRange) - picker.minuteInterval = minuteInterval - } - - public func makeCoordinator() -> Coordinator { - Coordinator(self) - } - - final public class Coordinator { - var parent: DurationPicker - - init(_ parent: DurationPicker) { - self.parent = parent - } - - @objc func pickerValueChanged(_ picker: UIDatePicker) { - parent.duration = picker.countDownDuration.clamped(to: parent.validDurationRange) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/EmojiDataSource.swift b/Dependencies/LoopKit/LoopKitUI/Views/EmojiDataSource.swift deleted file mode 100644 index 766301fd9..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/EmojiDataSource.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// EmojiDataSource.swift -// LoopKitUI -// -// Created by Michael Pangburn on 1/7/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -struct EmojiSection { - let title: String - let items: [String] - let indexSymbol: String -} - -protocol EmojiDataSource { - var sections: [EmojiSection] { get } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/EmojiInputCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/EmojiInputCell.swift deleted file mode 100644 index c14077c91..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/EmojiInputCell.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// EmojiInputCell.swift -// LoopKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import UIKit - -class EmojiInputCell: UICollectionViewCell, IdentifiableClass { - @IBOutlet var label: UILabel! - - override var isSelected: Bool { - didSet { - updateSelectionState() - } - } - - override var isHighlighted: Bool { - didSet { - updateSelectionState() - } - } - - private func updateSelectionState() { - let highlightColor: UIColor - - highlightColor = .tertiarySystemFill - - backgroundColor = isSelected || isHighlighted ? highlightColor : nil - } - - override func awakeFromNib() { - super.awakeFromNib() - - layer.cornerRadius = 8 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/EmojiInputHeaderView.swift b/Dependencies/LoopKit/LoopKitUI/Views/EmojiInputHeaderView.swift deleted file mode 100644 index 6b4d202ed..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/EmojiInputHeaderView.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// EmojiInputHeaderView.swift -// LoopKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import UIKit - -class EmojiInputHeaderView: UICollectionReusableView, IdentifiableClass { - @IBOutlet var titleLabel: UILabel! -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ExpandableDatePicker.swift b/Dependencies/LoopKit/LoopKitUI/Views/ExpandableDatePicker.swift deleted file mode 100644 index 42813bba9..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ExpandableDatePicker.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// ExpandableDatePicker.swift -// LoopKitUI -// -// Created by Anna Quinlan on 8/12/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct ExpandableDatePicker: View { - @State var dateShouldExpand = false - @Binding var date: Date - let placeholderText: String - let pickerRange: ClosedRange - @State var userDidTap: Bool = false - - public init ( - with date: Binding, - pickerRange: ClosedRange? = nil, - placeholderText: String = "" - ) { - _date = date - self.placeholderText = placeholderText - - let today = Date() - self.pickerRange = pickerRange ?? today.addingTimeInterval(-.hours(24))...today - } - - public var body: some View { - VStack(spacing: 0) { - HStack { - dateFieldText - Spacer() - } - .padding() - .frame(minWidth: 0, maxWidth: .infinity).onTapGesture { - self.userDidTap = true - // Hack to refresh binding - self.date = Date(timeInterval: 0, since: self.date) - self.dateShouldExpand.toggle() - } - if dateShouldExpand { - DatePicker("", selection: $date, in: pickerRange, displayedComponents: .date) - .labelsHidden() - } - } - } - - private var dateFieldText: some View { - if userDidTap { - return Text(dateFormatter.string(from: date)) - // Show the placeholder text if user hasn't interacted with picker - } else { - return Text(placeholderText).foregroundColor(Color(UIColor.lightGray)) - } - } - - private var dateFormatter: DateFormatter { - let formatter = DateFormatter() - formatter.dateStyle = .medium - formatter.timeZone = TimeZone.current - return formatter - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ExpandablePicker.swift b/Dependencies/LoopKit/LoopKitUI/Views/ExpandablePicker.swift deleted file mode 100644 index 887f28b40..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ExpandablePicker.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// ExpandablePicker.swift -// LoopKitUI -// -// Created by Anna Quinlan on 8/13/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public protocol Labeled { - var label: String { get } -} - -public struct ExpandablePicker: View { - @State var pickerShouldExpand = false - var selectedValue: Binding - let label: String - let items: [SelectionType] - - - public init ( - with items: [SelectionType], - selectedValue: Binding, - label: String = "" - ) { - self.items = items - self.selectedValue = selectedValue - self.label = label - } - - public var body: some View { - VStack(alignment: .leading, spacing: 0) { - HStack(alignment: .center) { - Text(label) - Spacer() - Text(selectedValue.wrappedValue.label) - .foregroundColor(.gray) - } - .padding(.vertical, 5) - .frame(minWidth: 0, maxWidth: .infinity).onTapGesture { - self.pickerShouldExpand.toggle() - } - if pickerShouldExpand { - HStack(alignment: .center) { - Picker(selection: selectedValue, label: Text("")) { - ForEach(items, id: \.self) { item in - Text(item.label) - } - } - .pickerStyle(.wheel) - .labelsHidden() - } - } - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ExpandableSetting.swift b/Dependencies/LoopKit/LoopKitUI/Views/ExpandableSetting.swift deleted file mode 100644 index 28981b38a..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ExpandableSetting.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// ExpandableSetting.swift -// LoopKitUI -// -// Created by Michael Pangburn on 5/15/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -public struct ExpandableSetting< - LeadingValueContent: View, - TrailingValueContent: View, - ExpandedContent: View ->: View { - @Binding var isEditing: Bool - var leadingValueContent: LeadingValueContent - var trailingValueContent: TrailingValueContent - var expandedContent: () -> ExpandedContent - - public init( - isEditing: Binding, - @ViewBuilder leadingValueContent: () -> LeadingValueContent, - @ViewBuilder trailingValueContent: () -> TrailingValueContent, - @ViewBuilder expandedContent: @escaping () -> ExpandedContent - ) { - self._isEditing = isEditing - self.leadingValueContent = leadingValueContent() - self.trailingValueContent = trailingValueContent() - self.expandedContent = expandedContent - } - - public var body: some View { - VStack(spacing: 0) { - HStack { - leadingValueContent - - Spacer() - - trailingValueContent - .fixedSize(horizontal: true, vertical: false) - } - .accessibilityElement(children: .combine) - .contentShape(Rectangle()) - .onTapGesture { - withAnimation { - self.isEditing.toggle() - } - } - - if isEditing { - expandedContent() - .padding(.horizontal, -8) - .transition(.fadeInFromTop) - } - } - } -} - -extension ExpandableSetting where LeadingValueContent == EmptyView { - public init( - isEditing: Binding, - @ViewBuilder valueContent: () -> TrailingValueContent, - @ViewBuilder expandedContent: @escaping () -> ExpandedContent - ) { - self.init(isEditing: isEditing, leadingValueContent: EmptyView.init, trailingValueContent: valueContent, expandedContent: expandedContent) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/FractionalQuantityPicker.swift b/Dependencies/LoopKit/LoopKitUI/Views/FractionalQuantityPicker.swift deleted file mode 100644 index 7f1b18351..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/FractionalQuantityPicker.swift +++ /dev/null @@ -1,225 +0,0 @@ -// -// FractionalQuantityPicker.swift -// LoopKitUI -// -// Created by Michael Pangburn on 5/18/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - - -/// Enables selecting the whole and fractional parts of an HKQuantity value in independent pickers. -public struct FractionalQuantityPicker: View { - public enum UsageContext: Equatable { - /// This picker is one component of a larger multi-component picker (e.g. a schedule item picker). - case component(availableWidth: CGFloat) - - /// This picker operates independently. - case independent - } - - @Environment(\.guidanceColors) var guidanceColors - @Binding var whole: Double - @Binding var fraction: Double - var unit: HKUnit - var guardrail: Guardrail - var selectableWholeValues: [Double] - var fractionalValuesByWhole: [Double: [Double]] - var usageContext: UsageContext - - /// The maximum number of decimal places supported by the picker. - private static var maximumSupportedPrecision: Int { 3 } - - private static let wholeFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.minimumIntegerDigits = 1 - formatter.maximumFractionDigits = 0 - return formatter - }() - - private static let fractionalFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.decimalSeparator = "" - formatter.maximumIntegerDigits = 0 - return formatter - }() - - public init( - value: Binding, - unit: HKUnit, - guardrail: Guardrail, - selectableValues: [Double], - usageContext: UsageContext = .independent - ) { - let doubleValue = value.doubleValue(for: unit) - let (selectableWholeValues, fractionalValuesByWhole): ([Double], [Double: [Double]]) = selectableValues.reduce(into: ([], [:])) { pair, selectableValue in - let whole = selectableValue.whole - if pair.0.last != whole { - pair.0.append(whole) - } - pair.1[whole, default: []].append(unit.roundForPicker(value: selectableValue.fraction)) - } - - self._whole = Binding( - get: { doubleValue.wrappedValue.whole }, - set: { newWholeValue in - let newFractionValue = Self.matchingFraction(for: doubleValue.wrappedValue.fraction, from: fractionalValuesByWhole[newWholeValue] ?? [0.0]) - let newDoubleValue = newWholeValue + newFractionValue - let maxValue = guardrail.absoluteBounds.upperBound.doubleValue(for: unit) - doubleValue.wrappedValue = min(newDoubleValue, maxValue) - } - ) - self._fraction = Binding( - get: { doubleValue.wrappedValue.fraction.roundedToNearest(of: fractionalValuesByWhole[doubleValue.wrappedValue.whole] ?? [0.0]) }, - set: { newFractionValue in - let newDoubleValue = doubleValue.wrappedValue.whole + newFractionValue - let minValue = guardrail.absoluteBounds.lowerBound.doubleValue(for: unit) - doubleValue.wrappedValue = max(newDoubleValue, minValue) - } - ) - self.unit = unit - self.guardrail = guardrail - self.selectableWholeValues = selectableWholeValues - self.fractionalValuesByWhole = fractionalValuesByWhole - self.usageContext = usageContext - } - - private static func matchingFraction( - for currentFraction: Double, - from supportedFractionValues: [Double] - ) -> Double { - currentFraction.matchingOrTruncatedValue(from: supportedFractionValues, withinDecimalPlaces: Self.maximumSupportedPrecision) - } - - public var body: some View { - switch usageContext { - case .component(availableWidth: let availableWidth): - return AnyView(body(availableWidth: availableWidth)) - case .independent: - return AnyView( - GeometryReader { geometry in - HStack { - Spacer() - self.body(availableWidth: geometry.size.width) - Spacer() - } - } - .frame(height: 216) - ) - } - } - - func body(availableWidth: CGFloat) -> some View { - HStack(spacing: 0) { - QuantityPicker( - value: $whole.withUnit(unit), - unit: unit, - selectableValues: selectableWholeValues, - formatter: Self.wholeFormatter, - isUnitLabelVisible: false, - colorForValue: colorForWhole - ) - .frame(width: availableWidth / 3) - .overlay( - Text(separator) - .foregroundColor(Color(.secondaryLabel)) - .offset(x: spacing + separatorWidth), - alignment: .trailing - ) - .padding(.leading, usageContext == .independent ? unitLabelWidth + spacing : 0) - .padding(.trailing, spacing + separatorWidth + spacing) - .clipped() - .compositingGroup() - - QuantityPicker( - value: $fraction.withUnit(unit), - unit: unit, - selectableValues: fractionalValuesByWhole[whole] ?? [0.0], - formatter: fractionalFormatter, - colorForValue: colorForFraction - ) - .frame(width: availableWidth / 3) - .padding(.trailing, spacing + unitLabelWidth) - .clipped() - .compositingGroup() - } - } - - private func colorForWhole(_ whole: Double) -> Color { - assert(whole.whole == whole) - - let fractionIfWholeSelected = Self.matchingFraction(for: fraction, from: fractionalValuesByWhole[whole] ?? [0.0]) - let valueIfWholeSelected = whole + fractionIfWholeSelected - let quantityIfWholeSelected = HKQuantity(unit: unit, doubleValue: valueIfWholeSelected) - return guardrail.color(for: quantityIfWholeSelected, guidanceColors: guidanceColors) - } - - private func colorForFraction(_ fraction: Double) -> Color { - assert(fraction.fraction == fraction) - - let valueIfFractionSelected = whole + fraction - let quantityIfFractionSelected = HKQuantity(unit: unit, doubleValue: valueIfFractionSelected) - return guardrail.color(for: quantityIfFractionSelected, guidanceColors: guidanceColors) - } - - private var fractionalFormatter: NumberFormatter { - // Mutate the shared instance to avoid extra allocations. - Self.fractionalFormatter.minimumFractionDigits = (fractionalValuesByWhole[whole] ?? [0.0]) - .lazy - .map { Decimal($0) } - .deltaScale(boundedBy: Self.maximumSupportedPrecision) - return Self.fractionalFormatter - } - - var separator: String { "." } - - var separatorWidth: CGFloat { - let attributedSeparator = NSAttributedString( - string: separator, - attributes: [.font: UIFont.preferredFont(forTextStyle: .body)] - ) - - return attributedSeparator.size().width - } - - var spacing: CGFloat { 4 } - - var unitLabelWidth: CGFloat { - let attributedUnitString = NSAttributedString( - string: unit.shortLocalizedUnitString(), - attributes: [.font: UIFont.preferredFont(forTextStyle: .body)] - ) - - return attributedUnitString.size().width - } -} - -fileprivate extension FloatingPoint { - var whole: Self { modf(self).0 } - var fraction: Self { modf(self).1 } -} - -fileprivate extension Decimal { - func rounded(toPlaces scale: Int, roundingMode: NSDecimalNumber.RoundingMode = .plain) -> Decimal { - var result = Decimal() - var localCopy = self - NSDecimalRound(&result, &localCopy, scale, roundingMode) - return result - } -} - -fileprivate extension Collection where Element == Decimal { - /// Returns the maximum number of decimal places necessary to meaningfully distinguish between adjacent values. - /// - Precondition: The collection is sorted in ascending order. - func deltaScale(boundedBy maxScale: Int) -> Int { - let roundedToMaxScale = lazy.map { $0.rounded(toPlaces: maxScale) } - guard let maxDelta = roundedToMaxScale.adjacentPairs().map(-).map(abs).max() else { - return 0 - } - - return abs(Swift.min(maxDelta.exponent, 0)) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangeOverrideTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangeOverrideTableViewCell.swift deleted file mode 100644 index 98d42ca60..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangeOverrideTableViewCell.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// GlucoseRangeOverrideTableViewCell.swift -// LoopKit -// -// Created by Nate Racklyeft on 7/13/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - -class GlucoseRangeOverrideTableViewCell: GlucoseRangeTableViewCell { - - // MARK: Outlets - @IBOutlet weak var iconImageView: UIImageView! - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - - self.allowTimeSelection = false - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangeOverrideTableViewCell.xib b/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangeOverrideTableViewCell.xib deleted file mode 100644 index d873a0868..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangeOverrideTableViewCell.xib +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangePicker.swift b/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangePicker.swift deleted file mode 100644 index b8fab2300..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangePicker.swift +++ /dev/null @@ -1,162 +0,0 @@ -// -// GlucoseRangePicker.swift -// LoopKitUI -// -// Created by Michael Pangburn on 5/14/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - - -public struct GlucoseRangePicker: View { - public enum UsageContext: Equatable { - /// This picker is one component of a larger multi-component picker (e.g. a schedule item picker). - case component(availableWidth: CGFloat) - - /// This picker operates independently. - case independent - } - - @Binding var lowerBound: HKQuantity - @Binding var upperBound: HKQuantity - var unit: HKUnit - var minValue: HKQuantity? - var maxValue: HKQuantity? - var guardrail: Guardrail - var formatter: NumberFormatter - var usageContext: UsageContext - - public init( - range: Binding>, - unit: HKUnit, - minValue: HKQuantity?, - maxValue: HKQuantity? = nil, - guardrail: Guardrail, - usageContext: UsageContext = .independent - ) { - self._lowerBound = Binding( - get: { range.wrappedValue.lowerBound }, - set: { - if $0 > range.wrappedValue.upperBound { - // Prevent crash if picker gets into state where "lower bound" > "upper bound" - range.wrappedValue = $0...$0 - } - range.wrappedValue = $0...range.wrappedValue.upperBound - - } - ) - self._upperBound = Binding( - get: { range.wrappedValue.upperBound }, - set: { - if range.wrappedValue.lowerBound > $0 { - // Prevent crash if picker gets into state where "lower bound" > "upper bound" - range.wrappedValue = range.wrappedValue.lowerBound...range.wrappedValue.lowerBound - } else { - range.wrappedValue = range.wrappedValue.lowerBound...$0 - } - - } - ) - self.unit = unit - self.minValue = minValue - self.maxValue = maxValue - self.guardrail = guardrail - self.formatter = { - let quantityFormatter = QuantityFormatter() - quantityFormatter.setPreferredNumberFormatter(for: unit) - return quantityFormatter.numberFormatter - }() - self.usageContext = usageContext - } - - public var body: some View { - switch usageContext { - case .component(availableWidth: let availableWidth): - body(availableWidth: availableWidth) - case .independent: - GeometryReader { geometry in - HStack(spacing: 0) { - Spacer() - self.body(availableWidth: geometry.size.width) - Spacer() - } - } - .frame(height: 216) - } - } - - private func body(availableWidth: CGFloat) -> some View { - HStack(spacing: 0) { - GlucoseValuePicker( - value: $lowerBound, - unit: unit, - guardrail: guardrail, - bounds: lowerBoundRange, - isUnitLabelVisible: false - ) - .frame(width: availableWidth / 3) - .overlay( - Text(separator) - .foregroundColor(Color(.secondaryLabel)) - .offset(x: spacing + separatorWidth), - alignment: .trailing - ) - .padding(.leading, usageContext == .independent ? unitLabelWidth : 0) - .padding(.trailing, spacing + separatorWidth + spacing) - .clipped() - .compositingGroup() - .accessibility(identifier: "min_glucose_picker") - - GlucoseValuePicker( - value: $upperBound, - unit: unit, - guardrail: guardrail, - bounds: upperBoundRange - ) - .frame(width: availableWidth / 3) - .padding(.trailing, unitLabelWidth) - .clipped() - .compositingGroup() - .accessibility(identifier: "max_glucose_picker") - } - } - - var separator: String { "–" } - - var separatorWidth: CGFloat { - let attributedSeparator = NSAttributedString( - string: separator, - attributes: [.font: UIFont.preferredFont(forTextStyle: .body)] - ) - - return attributedSeparator.size().width - } - - var spacing: CGFloat { 4 } - - var unitLabelWidth: CGFloat { - let attributedUnitString = NSAttributedString( - string: unit.shortLocalizedUnitString(), - attributes: [.font: UIFont.preferredFont(forTextStyle: .body)] - ) - - return attributedUnitString.size().width - } - - var lowerBoundRange: ClosedRange { - let min = minValue.map { Swift.max(guardrail.absoluteBounds.lowerBound, $0) } - ?? guardrail.absoluteBounds.lowerBound - let max = Swift.min(guardrail.absoluteBounds.upperBound, upperBound) - return min...max - } - - var upperBoundRange: ClosedRange { - let min = max(guardrail.absoluteBounds.lowerBound, lowerBound) - let max = maxValue.map { Swift.min(guardrail.absoluteBounds.upperBound, $0) } - ?? guardrail.absoluteBounds.upperBound - return min...max - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangeTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangeTableViewCell.swift deleted file mode 100644 index 54ddeb5e2..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangeTableViewCell.swift +++ /dev/null @@ -1,369 +0,0 @@ -// -// GlucoseRangeTableViewCell.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/13/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - -protocol GlucoseRangeTableViewCellDelegate: AnyObject { - func glucoseRangeTableViewCellDidUpdate(_ cell: GlucoseRangeTableViewCell) -} - -class GlucoseRangeTableViewCell: UITableViewCell { - - public enum Component: Int, CaseIterable { - case time = 0 - case minValue - case separator - case maxValue - case units - - var placeholderString: String? { - switch self { - case .minValue: - return LocalizedString("min", comment: "Placeholder for minimum value in glucose range") - case .maxValue: - return LocalizedString("max", comment: "Placeholder for maximum value in glucose range") - default: - return nil - } - } - } - - @IBOutlet weak var dateLabel: UILabel! - @IBOutlet open weak var picker: UIPickerView! - @IBOutlet open weak var pickerHeightConstraint: NSLayoutConstraint! - @IBOutlet weak var minValueTextField: UITextField! { - didSet { - // Setting this color in code because the nib isn't being applied correctly - minValueTextField.textColor = .label - } - } - @IBOutlet weak var separatorLabel: UILabel! { - didSet { - // Setting this color in code because the nib isn't being applied correctly - separatorLabel.textColor = .secondaryLabel - } - } - @IBOutlet weak var maxValueTextField: UITextField! { - didSet { - // Setting this color in code because the nib isn't being applied correctly - maxValueTextField.textColor = .label - } - } - @IBOutlet weak var unitLabel: UILabel! { - didSet { - // Setting this color in code because the nib isn't being applied correctly - unitLabel.textColor = .secondaryLabel - } - } - - private var pickerExpandedHeight: CGFloat = 0 - - public var minimumTimeInterval: TimeInterval = .hours(0.5) - - public weak var delegate: GlucoseRangeTableViewCellDelegate? - - var allowTimeSelection: Bool = true - - var minValue: Double? { - didSet { - guard let value = minValue else { - minValueTextField.text = nil - return - } - minValueTextField.text = valueNumberFormatter.string(from: value) - } - } - - var maxValue: Double? { - didSet { - guard let value = maxValue else { - maxValueTextField.text = nil - return - } - maxValueTextField.text = valueNumberFormatter.string(from: value) - } - } - - public var allowedValues: [Double] = [] { - didSet { - picker.reloadAllComponents() - selectPickerValues() - } - } - - private var allowedMaxValues: [Double] { - guard let minValue = minValue else { - return allowedValues - } - return allowedValues.filter( { $0 >= minValue }) - } - - private var allowedMinValues: [Double] { - guard let maxValue = maxValue else { - return allowedValues - } - return allowedValues.filter( { $0 <= maxValue }) - } - - var unitString: String? { - get { - return unitLabel.text - } - set { - unitLabel.text = newValue - } - } - - lazy var valueNumberFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.minimumFractionDigits = 1 - - return formatter - }() - - private lazy var dateFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .none - dateFormatter.timeStyle = .short - - return dateFormatter - }() - - public var timeZone: TimeZone! { - didSet { - dateFormatter.timeZone = timeZone - var calendar = Calendar.current - calendar.timeZone = timeZone - startOfDay = calendar.startOfDay(for: Date()) - } - } - - private lazy var startOfDay = Calendar.current.startOfDay(for: Date()) - - var startTime: TimeInterval = 0 { - didSet { - updateStartTimeSelection() - updateDateLabel() - } - } - - var selectedStartTime: TimeInterval { - let row = picker.selectedRow(inComponent: Component.time.rawValue) - return startTimeForTimeComponent(row: row) - } - - public var allowedTimeRange: ClosedRange = .hours(0)...(.hours(23.5)) { - didSet { - picker.reloadComponent(Component.time.rawValue) - updateStartTimeSelection() - } - } - - var isPickerHidden: Bool { - get { - return picker.isHidden - } - set { - picker.isHidden = newValue - pickerHeightConstraint.constant = newValue ? 0 : pickerExpandedHeight - - if !newValue { - selectPickerValues() - } - } - } - - - private func updateStartTimeSelection() { - let row = Int(round((startTime - allowedTimeRange.lowerBound) / minimumTimeInterval)) - if row >= 0 && row < pickerView(picker, numberOfRowsInComponent: Component.time.rawValue) { - picker.selectRow(row, inComponent: Component.time.rawValue, animated: true) - } - } - - fileprivate func selectPickerValue(for component: Component, with selectedValue: Double?, allowedValues: [Double]) { - guard !allowedValues.isEmpty else { - return - } - let selectedIndex: Int - if let value = selectedValue { - if let row = allowedValues.firstIndex(of: value) { - selectedIndex = row - } else { - // Select next highest value - selectedIndex = allowedValues.enumerated().filter({$0.element >= value}).min(by: { $0.1 < $1.1 })?.offset ?? 0 - } - } else { - selectedIndex = allowedValues.count - } - picker.selectRow(selectedIndex, inComponent: component.rawValue, animated: false) - } - - fileprivate func selectPickerValues() { - selectPickerValue(for: .minValue, with: minValue, allowedValues: allowedMinValues) - selectPickerValue(for: .maxValue, with: maxValue, allowedValues: allowedMaxValues) - } - - fileprivate func updateMinValueFromPicker() { - let index = picker.selectedRow(inComponent: Component.minValue.rawValue) - let value: Double? - if index >= 0 && index < allowedMinValues.count { - value = allowedMinValues[index] - } else { - value = nil - } - minValue = value - } - - fileprivate func updateMaxValueFromPicker() { - let index = picker.selectedRow(inComponent: Component.maxValue.rawValue) - let value: Double? - if index >= 0 && index < allowedMaxValues.count { - value = allowedMaxValues[index] - } else { - value = nil - } - maxValue = value - } - - func updateDateLabel() { - dateLabel.text = stringForStartTime(startTime) - } - - private func startTimeForTimeComponent(row: Int) -> TimeInterval { - return allowedTimeRange.lowerBound + minimumTimeInterval * TimeInterval(row) - } - - private func stringForStartTime(_ time: TimeInterval) -> String { - let date = startOfDay.addingTimeInterval(time) - return dateFormatter.string(from: date) - } - - override func awakeFromNib() { - super.awakeFromNib() - - pickerExpandedHeight = pickerHeightConstraint.constant - - setSelected(true, animated: false) - updateDateLabel() - } - - override func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - if selected { - isPickerHidden.toggle() - } - } -} - -extension GlucoseRangeTableViewCell: UIPickerViewDelegate { - - func pickerView(_ pickerView: UIPickerView, - didSelectRow row: Int, - inComponent componentRaw: Int) { - let component = Component(rawValue: componentRaw)! - switch component { - case .time: - startTime = selectedStartTime - case .minValue: - updateMinValueFromPicker() - picker.reloadComponent(Component.minValue.rawValue) - picker.reloadComponent(Component.maxValue.rawValue) - selectPickerValues() - case .maxValue: - updateMaxValueFromPicker() - picker.reloadComponent(Component.minValue.rawValue) - picker.reloadComponent(Component.maxValue.rawValue) - selectPickerValues() - default: - break - } - - delegate?.glucoseRangeTableViewCellDidUpdate(self) - } - - func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat { - return [33,16,4,16,24][component] / 100.0 * picker.frame.width - } - - func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { - let metrics = UIFontMetrics(forTextStyle: .body) - return metrics.scaledValue(for: 32) - } - - func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? { - - let title: String? - let component = Component(rawValue: component)! - var attributes: [NSAttributedString.Key : Any]? = nil - - switch component { - case .time: - let time = startTimeForTimeComponent(row: row) - title = stringForStartTime(time) - case .minValue: - if row >= allowedMinValues.count { - title = component.placeholderString - attributes = [.foregroundColor: UIColor.lightGray] - } else { - title = valueNumberFormatter.string(from: allowedMinValues[row]) - } - case .maxValue: - if row >= allowedMaxValues.count { - title = component.placeholderString - attributes = [.foregroundColor: UIColor.lightGray] - } else { - title = valueNumberFormatter.string(from: allowedMaxValues[row]) - } - case .separator: - title = LocalizedString("-", comment: "Separator between min and max glucose values") - case .units: - title = unitString - } - if let title = title { - return NSAttributedString(string: title, attributes: attributes) - } else { - return nil - } - } -} - -extension GlucoseRangeTableViewCell: UIPickerViewDataSource { - func numberOfComponents(in pickerView: UIPickerView) -> Int { - return Component.allCases.count - } - - func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { - switch Component(rawValue: component)! { - case .time: - if allowTimeSelection { - return Int(round((allowedTimeRange.upperBound - allowedTimeRange.lowerBound) / minimumTimeInterval) + 1) - } else { - return 0 - } - case .minValue: - return allowedMinValues.count + (minValue != nil ? 0 : 1) - case .maxValue: - return allowedMaxValues.count + (maxValue != nil ? 0 : 1) - case .units, .separator: - return 1 - } - - } -} - -/// UITableViewController extensions to aid working with DatePickerTableViewCell -extension GlucoseRangeTableViewCellDelegate where Self: UITableViewController { - func hideGlucoseRangeCells(excluding indexPath: IndexPath? = nil) { - for case let cell as GlucoseRangeTableViewCell in tableView.visibleCells where tableView.indexPath(for: cell) != indexPath && cell.isPickerHidden == false { - cell.isPickerHidden = true - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangeTableViewCell.xib b/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangeTableViewCell.xib deleted file mode 100644 index 62cf39fe0..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/GlucoseRangeTableViewCell.xib +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/GlucoseValuePicker.swift b/Dependencies/LoopKit/LoopKitUI/Views/GlucoseValuePicker.swift deleted file mode 100644 index e67fd09fd..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/GlucoseValuePicker.swift +++ /dev/null @@ -1,94 +0,0 @@ -// -// GlucoseValuePicker.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/14/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - - -public struct GlucoseValuePicker: View { - @Environment(\.guidanceColors) var guidanceColors - @Binding var value: HKQuantity - var unit: HKUnit - var guardrail: Guardrail - var bounds: ClosedRange - var isUnitLabelVisible: Bool - - public init( - value: Binding, - unit: HKUnit, - guardrail: Guardrail, - bounds: ClosedRange, - isUnitLabelVisible: Bool = true - ) { - self._value = value - self.unit = unit - self.guardrail = guardrail - self.bounds = bounds - self.isUnitLabelVisible = isUnitLabelVisible - } - - public init( - value: Binding, - unit: HKUnit, - guardrail: Guardrail, - isUnitLabelVisible: Bool = true - ) { - self.init(value: value, unit: unit, guardrail: guardrail, bounds: guardrail.absoluteBounds, isUnitLabelVisible: isUnitLabelVisible) - } - - public var body: some View { - QuantityPicker(value: $value, - unit: unit, - guardrail: guardrail, - selectableValues: selectableValues, - isUnitLabelVisible: isUnitLabelVisible, - guidanceColors: guidanceColors) - } - - var selectableValues: [Double] { - Array( - Swift.stride( - from: bounds.lowerBound.doubleValue(for: unit, withRounding: true), - through: bounds.upperBound.doubleValue(for: unit, withRounding: true), - by: stride.doubleValue(for: unit, withRounding: true) - ) - ) - } - - private var stride: HKQuantity { - switch unit { - case .milligramsPerDeciliter: - return HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 1) - case .millimolesPerLiter: - return HKQuantity(unit: .millimolesPerLiter, doubleValue: 0.1) - default: - fatalError("Unsupported glucose unit \(unit)") - } - } -} - -private struct GlucoseValuePickerTester: View { - @State var value = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 80) - - private let guardrail = Guardrail(absoluteBounds: 54...180, recommendedBounds: 71...120, unit: .milligramsPerDeciliter, startingSuggestion: 80) - - var unit: HKUnit - - var body: some View { - GlucoseValuePicker(value: $value, unit: unit, guardrail: guardrail) - } -} - -struct GlucoseValuePicker_Previews: PreviewProvider { - static var previews: some View { - ForEach([HKUnit.milligramsPerDeciliter, .millimolesPerLiter], id: \.self) { unit in - GlucoseValuePickerTester(unit: unit) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/GuardrailConstrainedQuantityRangeView.swift b/Dependencies/LoopKit/LoopKitUI/Views/GuardrailConstrainedQuantityRangeView.swift deleted file mode 100644 index 921747c21..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/GuardrailConstrainedQuantityRangeView.swift +++ /dev/null @@ -1,97 +0,0 @@ -// -// GuardrailConstrainedQuantityRangeView.swift -// LoopKitUI -// -// Created by Michael Pangburn on 5/14/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - - -public struct GuardrailConstrainedQuantityRangeView: View { - var range: ClosedRange? - var unit: HKUnit - var guardrail: Guardrail - var isEditing: Bool - var formatter: NumberFormatter - var forceDisableAnimations: Bool - - @State var hasAppeared = false - - public init( - range: ClosedRange?, - unit: HKUnit, - guardrail: Guardrail, - isEditing: Bool, - forceDisableAnimations: Bool = false - ) { - self.range = range - self.unit = unit - self.guardrail = guardrail - self.isEditing = isEditing - self.formatter = { - let quantityFormatter = QuantityFormatter() - quantityFormatter.setPreferredNumberFormatter(for: unit) - return quantityFormatter.numberFormatter - }() - self.forceDisableAnimations = forceDisableAnimations - } - - public var body: some View { - HStack { - lowerBoundView - - Text("–") - .foregroundColor(Color(.secondaryLabel)) - - upperBoundView - } - .animation(forceDisableAnimations || isEditing || !hasAppeared ? nil : .default) - .onAppear { self.hasAppeared = true } - } - - var lowerBoundView: some View { - Group { - if range != nil { - GuardrailConstrainedQuantityView( - value: range!.lowerBound, - unit: unit, - guardrail: guardrail, - isEditing: isEditing, - iconSpacing: 4, - isUnitLabelVisible: false, - forceDisableAnimations: forceDisableAnimations - ) - } else { - Text(LocalizedString("min", comment: "Placeholder for quantity range lower bound")) - .foregroundColor(Color(.tertiaryLabel)) - } - } - } - - var upperBoundView: some View { - Group { - if range != nil { - GuardrailConstrainedQuantityView( - value: range!.upperBound, - unit: unit, - guardrail: guardrail, - isEditing: isEditing, - iconSpacing: 4, - forceDisableAnimations: forceDisableAnimations - ) - } else { - HStack { - Text(LocalizedString("max", comment: "Placeholder for quantity range upper bound")) - .foregroundColor(Color(.tertiaryLabel)) - - Text(unit.shortLocalizedUnitString()) - .foregroundColor(Color(.secondaryLabel)) - } - } - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/GuardrailConstraintedQuantityView.swift b/Dependencies/LoopKit/LoopKitUI/Views/GuardrailConstraintedQuantityView.swift deleted file mode 100644 index dfe236be6..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/GuardrailConstraintedQuantityView.swift +++ /dev/null @@ -1,115 +0,0 @@ -// -// GuardrailConstraintedQuantityView.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/24/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - - -public struct GuardrailConstrainedQuantityView: View { - @Environment(\.guidanceColors) var guidanceColors - var value: HKQuantity? - var unit: HKUnit - var guardrail: Guardrail - var isEditing: Bool - var formatter: NumberFormatter - var iconSpacing: CGFloat - var isUnitLabelVisible: Bool - var forceDisableAnimations: Bool - - @State private var hasAppeared = false - - public init( - value: HKQuantity?, - unit: HKUnit, - guardrail: Guardrail, - isEditing: Bool, - iconSpacing: CGFloat = 8, - isUnitLabelVisible: Bool = true, - forceDisableAnimations: Bool = false - ) { - self.value = value - self.unit = unit - self.guardrail = guardrail - self.isEditing = isEditing - self.iconSpacing = iconSpacing - self.formatter = { - let quantityFormatter = QuantityFormatter() - quantityFormatter.setPreferredNumberFormatter(for: unit) - return quantityFormatter.numberFormatter - }() - self.isUnitLabelVisible = isUnitLabelVisible - self.forceDisableAnimations = forceDisableAnimations - } - - public var body: some View { - HStack { - HStack(spacing: iconSpacing) { - if value != nil { - if guardrail.classification(for: value!) != .withinRecommendedRange { - Image(systemName: "exclamationmark.triangle.fill") - .foregroundColor(warningColor) - .transition(.springInDisappear) - } - - Text(formatter.string(from: value!.doubleValue(for: unit)) ?? "\(value!.doubleValue(for: unit))") - .foregroundColor(warningColor) - .fixedSize(horizontal: true, vertical: false) - } else { - Text("–") - .foregroundColor(.secondary) - } - } - - if isUnitLabelVisible { - Text(unit.shortLocalizedUnitString()) - .foregroundColor(Color(.secondaryLabel)) - } - } - .accessibilityElement(children: .combine) - .onAppear { self.hasAppeared = true } - .animation(animation) - } - - private var animation: Animation? { - // A conditional implicit animation seems to behave funky on first appearance. - // Disable animations until the view has appeared. - if forceDisableAnimations || !hasAppeared { - return nil - } - - // While editing, the text width is liable to change, which can cause a slow-feeling animation - // of the guardrail warning icon. Disable animations while editing. - return isEditing ? nil : .default - } - - private var warningColor: Color { - guard let value = value else { - return .primary - } - - switch guardrail.classification(for: value) { - case .withinRecommendedRange: - return isEditing ? .accentColor : guidanceColors.acceptable - case .outsideRecommendedRange(let threshold): - switch threshold { - case .minimum, .maximum: - return guidanceColors.critical - case .belowRecommended, .aboveRecommended: - return guidanceColors.warning - } - } - } -} - -fileprivate extension AnyTransition { - static let springInDisappear = asymmetric( - insertion: AnyTransition.scale.animation(.spring(dampingFraction: 0.5)), - removal: .identity - ) -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/GuardrailWarning.swift b/Dependencies/LoopKit/LoopKitUI/Views/GuardrailWarning.swift deleted file mode 100644 index c4f8c9c81..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/GuardrailWarning.swift +++ /dev/null @@ -1,102 +0,0 @@ -// -// GuardrailWarning.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/14/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - - -public struct GuardrailWarning: View { - private enum CrossedThresholds { - case one(SafetyClassification.Threshold) - case oneOrMore([SafetyClassification.Threshold]) - } - - private var therapySetting: TherapySetting - private var title: Text - private var crossedThresholds: CrossedThresholds - private var captionOverride: Text? - - public init( - therapySetting: TherapySetting, - title: Text, - threshold: SafetyClassification.Threshold, - caption: Text? = nil - ) { - self.therapySetting = therapySetting - self.title = title - self.crossedThresholds = .one(threshold) - self.captionOverride = caption - } - - public init( - therapySetting: TherapySetting, - title: Text, - thresholds: [SafetyClassification.Threshold], - caption: Text? = nil - ) { - precondition(!thresholds.isEmpty) - self.therapySetting = therapySetting - self.title = title - self.crossedThresholds = .oneOrMore(thresholds) - self.captionOverride = caption - } - - public var body: some View { - WarningView(title: title, caption: caption, severity: severity) - } - - private var severity: WarningSeverity { - switch crossedThresholds { - case .one(let threshold): - return threshold.severity - case .oneOrMore(let thresholds): - return thresholds.lazy.map({ $0.severity }).max()! - } - } - - private var caption: Text { - if let caption = captionOverride { - return caption - } - - switch crossedThresholds { - case .one(let threshold): - return captionForThreshold(threshold) - case .oneOrMore(let thresholds): - if thresholds.count == 1, let threshold = thresholds.first { - return captionForThreshold(threshold) - } else { - return captionForThresholds() - } - } - } - - private func captionForThreshold(_ threshold: SafetyClassification.Threshold) -> Text { - switch threshold { - case .minimum, .belowRecommended: - return Text(therapySetting.guardrailCaptionForLowValue) - case .aboveRecommended, .maximum: - return Text(therapySetting.guardrailCaptionForHighValue) - } - } - - private func captionForThresholds() -> Text { - return Text(therapySetting.guardrailCaptionForOutsideValues) - } -} - -fileprivate extension SafetyClassification.Threshold { - var severity: WarningSeverity { - switch self { - case .belowRecommended, .aboveRecommended: - return .default - case .minimum, .maximum: - return .critical - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/GuideNavigationButton.swift b/Dependencies/LoopKit/LoopKitUI/Views/GuideNavigationButton.swift deleted file mode 100644 index 3ee367f63..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/GuideNavigationButton.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// GuideNavigationButton.swift -// LoopKitUI -// -// Created by Pete Schwamb on 2020-03-04. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct GuideNavigationButton: View where Destination: View { - @Binding var navigationLinkIsActive: Bool - private let label: String - private let buttonPressedAction: (() -> Void)? - private let buttonStyle: ActionButton.ButtonType - private let destination: () -> Destination - - public init(navigationLinkIsActive: Binding, - label: String, - buttonPressedAction: (() -> Void)? = nil, - buttonStyle: ActionButton.ButtonType = .primary, - @ViewBuilder destination: @escaping () -> Destination) - { - self._navigationLinkIsActive = navigationLinkIsActive - self.label = label - self.buttonPressedAction = buttonPressedAction - self.buttonStyle = buttonStyle - self.destination = destination - } - - public var body: some View { - NavigationLink(destination: destination(), - isActive: self.$navigationLinkIsActive) - { - Button(action: { - self.buttonPressedAction?() - self.navigationLinkIsActive = true - }) { - Text(label) - .actionButtonStyle(buttonStyle) - } - } - .isDetailLink(false) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/GuidePage.swift b/Dependencies/LoopKit/LoopKitUI/Views/GuidePage.swift deleted file mode 100644 index e05bd46a5..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/GuidePage.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// GuidePage.swift -// LoopKitUI -// -// Created by Pete Schwamb on 2020-03-04. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct GuidePage: View where Content: View, ActionAreaContent: View { - let content: Content - let actionAreaContent: ActionAreaContent - - @Environment(\.horizontalSizeClass) var horizontalSizeClass - - public init(@ViewBuilder content: @escaping () -> Content, - @ViewBuilder actionAreaContent: @escaping () -> ActionAreaContent) - { - self.content = content() - self.actionAreaContent = actionAreaContent() - } - - public var body: some View { - VStack(spacing: 0) { - List { - if self.horizontalSizeClass == .compact { - Section(header: EmptyView(), footer: EmptyView()) { - self.content - } - } else { - self.content - } - } - .insetGroupedListStyle() - VStack { - self.actionAreaContent - } - .padding(self.horizontalSizeClass == .regular ? .bottom : []) - .background(Color(UIColor.secondarySystemGroupedBackground).shadow(radius: 5)) - } - .edgesIgnoringSafeArea(.bottom) - } -} - -struct GuidePage_Previews: PreviewProvider { - static var previews: some View { - GuidePage(content: { - Text("content") - Text("more content") - Image(systemName: "circle") - }) { - Button(action: { - print("Button tapped") - }) { - Text("Action Button") - .actionButtonStyle() - } - } - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/Contents.json deleted file mode 100644 index da4a164c9..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/battery.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/battery.imageset/Contents.json deleted file mode 100644 index 898b4aa55..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/battery.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "battery.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template" - } -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/battery.imageset/battery.pdf b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/battery.imageset/battery.pdf deleted file mode 100644 index ca8bffbb6..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/battery.imageset/battery.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/battery_mask.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/battery_mask.imageset/Contents.json deleted file mode 100644 index a089e3549..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/battery_mask.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "battery_mask.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/battery_mask.imageset/battery_mask.pdf b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/battery_mask.imageset/battery_mask.pdf deleted file mode 100644 index a58075369..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/battery/battery_mask.imageset/battery_mask.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/Contents.json deleted file mode 100644 index b39ca8629..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "pod_reservoir.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/pod_reservoir.pdf b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/pod_reservoir.pdf deleted file mode 100644 index ea4c18020..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/pod_reservoir.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/Contents.json deleted file mode 100644 index 7bb4810fb..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "pod_reservoir_mask.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/pod_reservoir_mask.pdf b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/pod_reservoir_mask.pdf deleted file mode 100644 index 940226df6..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/pod_reservoir_mask.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.down.circle.symbolset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.down.circle.symbolset/Contents.json deleted file mode 100644 index 45acaad7e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.down.circle.symbolset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "symbols" : [ - { - "filename" : "arrow.double.down.circle.svg", - "idiom" : "universal" - } - ] -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.down.circle.symbolset/arrow.double.down.circle.svg b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.down.circle.symbolset/arrow.double.down.circle.svg deleted file mode 100644 index 718ee9864..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.down.circle.symbolset/arrow.double.down.circle.svg +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.down.fill.symbolset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.down.fill.symbolset/Contents.json deleted file mode 100644 index 5ec1286c0..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.down.fill.symbolset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "symbols" : [ - { - "filename" : "arrow.double.down.fill.svg", - "idiom" : "universal" - } - ] -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.down.fill.symbolset/arrow.double.down.fill.svg b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.down.fill.symbolset/arrow.double.down.fill.svg deleted file mode 100644 index 9264592d7..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.down.fill.symbolset/arrow.double.down.fill.svg +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.up.circle.symbolset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.up.circle.symbolset/Contents.json deleted file mode 100644 index 1d9f219e5..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.up.circle.symbolset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "symbols" : [ - { - "filename" : "arrow.double.up.circle.svg", - "idiom" : "universal" - } - ] -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.up.circle.symbolset/arrow.double.up.circle.svg b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.up.circle.symbolset/arrow.double.up.circle.svg deleted file mode 100644 index 0c9c8344b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.up.circle.symbolset/arrow.double.up.circle.svg +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.up.fill.symbolset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.up.fill.symbolset/Contents.json deleted file mode 100644 index 182a12dc3..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.up.fill.symbolset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "symbols" : [ - { - "filename" : "arrow.double.up.fill.svg", - "idiom" : "universal" - } - ] -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.up.fill.symbolset/arrow.double.up.fill.svg b/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.up.fill.symbolset/arrow.double.up.fill.svg deleted file mode 100644 index 2dfa2b353..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/HUDAssets.xcassets/status-bar-symbols/arrow.double.up.fill.symbolset/arrow.double.up.fill.svg +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/BasalRatesInformationView.swift b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/BasalRatesInformationView.swift deleted file mode 100644 index 1f961ad92..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/BasalRatesInformationView.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// BasalRatesInformationView.swift -// LoopKitUI -// -// Created by Anna Quinlan on 7/3/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - -public struct BasalRatesInformationView: View { - var onExit: (() -> Void)? - var mode: SettingsPresentationMode - var maximumScheduleEntryCount: Int - - @Environment(\.presentationMode) var presentationMode - @Environment(\.appName) var appName - - public init(onExit: (() -> Void)?, mode: SettingsPresentationMode = .acceptanceFlow, maximumScheduleEntryCount: Int? = nil) { - self.onExit = onExit - self.mode = mode - self.maximumScheduleEntryCount = maximumScheduleEntryCount ?? 48 - } - - public var body: some View { - InformationView( - title: Text(TherapySetting.basalRate.title), - informationalContent: {text}, - onExit: onExit ?? { self.presentationMode.wrappedValue.dismiss() }, - mode: mode - ) - } - - private var text: some View { - VStack(alignment: .leading, spacing: 25) { - Text(LocalizedString("Your Basal Rate of insulin is the number of units per hour that you want to use to cover your background insulin needs.", comment: "Information about basal rates")) - Text(String(format: LocalizedString("%1$@ supports 1 to %2$@ rates per day.", comment: "Information about max number of basal rates (1: app name) (2: maximum schedule entry count)"), appName, String(describing: maximumScheduleEntryCount))) - Text(LocalizedString("The schedule starts at midnight and cannot contain a rate of 0 U/hr.", comment: "Information about basal rate scheduling")) - } - .foregroundColor(.secondary) - } -} - -struct BasalRatesInformationView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - BasalRatesInformationView(onExit: nil) - } - .colorScheme(.light) - .previewDevice(PreviewDevice(rawValue: "iPod touch (7th generation)")) - .previewDisplayName("SE light") - - NavigationView { - BasalRatesInformationView(onExit: nil) - } - .preferredColorScheme(.dark) - .colorScheme(.dark) - .previewDevice(PreviewDevice(rawValue: "iPhone 12 Pro Max")) - .previewDisplayName("12 Pro dark") - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/CarbRatioInformationView.swift b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/CarbRatioInformationView.swift deleted file mode 100644 index e2b85d552..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/CarbRatioInformationView.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// CarbRatioInformationView.swift -// LoopKitUI -// -// Created by Anna Quinlan on 7/28/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - -public struct CarbRatioInformationView: View { - var onExit: (() -> Void)? - var mode: SettingsPresentationMode - - @Environment(\.presentationMode) var presentationMode - @Environment(\.appName) private var appName - - public init( - onExit: (() -> Void)?, - mode: SettingsPresentationMode = .acceptanceFlow - ){ - self.onExit = onExit - self.mode = mode - } - - public var body: some View { - InformationView( - title: Text(TherapySetting.carbRatio.title), - informationalContent: {text}, - onExit: onExit ?? { self.presentationMode.wrappedValue.dismiss() }, - mode: mode - ) - } - - private var text: some View { - VStack(alignment: .leading, spacing: 25) { - Text(TherapySetting.carbRatio.descriptiveText(appName: appName)) - Text(LocalizedString("You can add different carb ratios for different times of day by using the ➕.", comment: "Description of how to add a ratio")) - } - .accentColor(.secondary) - .foregroundColor(.accentColor) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/CorrectionRangeInformationView.swift b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/CorrectionRangeInformationView.swift deleted file mode 100644 index a2f4a1273..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/CorrectionRangeInformationView.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// CorrectionRangeInformationView.swift -// LoopKitUI -// -// Created by Anna Quinlan on 7/1/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - -public struct CorrectionRangeInformationView: View { - var onExit: (() -> Void)? - var mode: SettingsPresentationMode - - @Environment(\.presentationMode) var presentationMode - @Environment(\.appName) var appName - - public init(onExit: (() -> Void)? = nil, mode: SettingsPresentationMode = .acceptanceFlow) { - self.onExit = onExit - self.mode = mode - } - - public var body: some View { - GlucoseTherapySettingInformationView( - therapySetting: .glucoseTargetRange, - onExit: onExit, - mode: mode, - appName: appName, - text: AnyView(text) - ) - } - - private var text: some View { - VStack(alignment: .leading, spacing: 25) { - Text(LocalizedString("If you've used a CGM before, you're likely familiar with target range as a wide range of values you'd like for your glucose notification alerts, such as 70-180 mg/dL or 90-200 mg/dL.", comment: "Information about target range")) - Text(LocalizedString("A Correction Range is different. This will be a narrower range.", comment: "Information about differences between target range and correction range")) - .bold() - Text(String(format: LocalizedString("For this range, choose the specific glucose value (or range of values) that you want %1$@ to aim for in adjusting your basal insulin.", comment: "Information about correction range format (1: app name)"), appName)) - Text(LocalizedString("Your healthcare provider can help you choose a Correction Range that's right for you.", comment: "Disclaimer")) - } - .foregroundColor(.secondary) - } -} - -struct CorrectionRangeInformationView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - CorrectionRangeInformationView() - } - .colorScheme(.light) - .previewDevice(PreviewDevice(rawValue: "iPhone SE 2")) - .previewDisplayName("SE light") - NavigationView { - CorrectionRangeInformationView() - } - .preferredColorScheme(.dark) - .colorScheme(.dark) - .previewDevice(PreviewDevice(rawValue: "iPhone 11 Pro Max")) - .previewDisplayName("11 Pro dark") - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/CorrectionRangeOverrideInformationView.swift b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/CorrectionRangeOverrideInformationView.swift deleted file mode 100644 index 335f12326..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/CorrectionRangeOverrideInformationView.swift +++ /dev/null @@ -1,96 +0,0 @@ -// -// CorrectionRangeOverrideInformationView.swift -// LoopKitUI -// -// Created by Anna Quinlan on 7/2/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import LoopKit -import SwiftUI - -public struct CorrectionRangeOverrideInformationView: View { - let preset: CorrectionRangeOverrides.Preset - var onExit: (() -> Void)? - let mode: SettingsPresentationMode - - @Environment(\.presentationMode) var presentationMode - @Environment(\.carbTintColor) var carbTintColor - @Environment(\.glucoseTintColor) var glucoseTintColor - @Environment(\.appName) var appName - - public init( - preset: CorrectionRangeOverrides.Preset, - onExit: (() -> Void)? = nil, - mode: SettingsPresentationMode = .acceptanceFlow - ) { - self.preset = preset - self.onExit = onExit - self.mode = mode - } - - public var body: some View { - GlucoseTherapySettingInformationView( - therapySetting: preset.therapySetting, - onExit: onExit, - mode: mode, - appName: appName, - text: AnyView(section(for: preset)) - ) - } - - private func section(for preset: CorrectionRangeOverrides.Preset) -> some View { - VStack(alignment: .leading, spacing: 15) { - description(for: preset) - .foregroundColor(.secondary) - } - } - - private func description(for preset: CorrectionRangeOverrides.Preset) -> some View { - switch preset { - case .preMeal: - return VStack(alignment: .leading, spacing: 20) { - Text(String(format: LocalizedString("Your Pre-Meal Range should be the glucose value (or range of values) you want %1$@ to target by the time you take your first bite of your meal. This range will be in effect when you activate the Pre-Meal Preset button.", comment: "Information about pre-meal range format (1: app name)"), appName)) - Text(LocalizedString("This will typically be", comment: "Information about pre-meal range relative to correction range")) + Text(LocalizedString(" lower ", comment: "Information about pre-meal range relative to correction range")).bold().italic() + Text(LocalizedString("than your Correction Range.", comment: "Information about pre-meal range relative to correction range")) - } - .fixedSize(horizontal: false, vertical: true) // prevent text from being cut off - case .workout: - return VStack(alignment: .leading, spacing: 20) { - Text(String(format: LocalizedString("Workout Range is the glucose value or range of values you want %1$@ to target during activity. This range will be in effect when you activate the Workout Preset button.", comment: "Information about workout range format (1: app name)"), appName)) - Text(LocalizedString("This will typically be", comment: "Information about workout range relative to correction range")) + Text(LocalizedString(" higher ", comment: "Information about workout range relative to correction range")).bold().italic() + Text(LocalizedString("than your Correction Range.", comment: "Information about workout range relative to correction range")) - } - .fixedSize(horizontal: false, vertical: true) // prevent text from being cut off - } - } -} - -struct CorrectionRangeOverrideInformationView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - CorrectionRangeOverrideInformationView(preset: .preMeal) - } - .colorScheme(.light) - .previewDevice(PreviewDevice(rawValue: "iPhone SE 2")) - .previewDisplayName("Pre-Meal SE light") - NavigationView { - CorrectionRangeOverrideInformationView(preset: .workout) - } - .colorScheme(.light) - .previewDevice(PreviewDevice(rawValue: "iPhone SE 2")) - .previewDisplayName("Workout SE light") - NavigationView { - CorrectionRangeOverrideInformationView(preset: .preMeal) - } - .preferredColorScheme(.dark) - .colorScheme(.dark) - .previewDevice(PreviewDevice(rawValue: "iPhone 11 Pro Max")) - .previewDisplayName("Pre-Meal 11 Pro dark") - NavigationView { - CorrectionRangeOverrideInformationView(preset: .workout) - } - .preferredColorScheme(.dark) - .colorScheme(.dark) - .previewDevice(PreviewDevice(rawValue: "iPhone 11 Pro Max")) - .previewDisplayName("Workout 11 Pro dark") - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/DeliveryLimitsInformationView.swift b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/DeliveryLimitsInformationView.swift deleted file mode 100644 index 0fe7c1dad..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/DeliveryLimitsInformationView.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// DeliveryLimitsInformationView.swift -// LoopKitUI -// -// Created by Anna Quinlan on 7/3/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - -public struct DeliveryLimitsInformationView: View { - var onExit: (() -> Void)? - var mode: SettingsPresentationMode - - @Environment(\.presentationMode) var presentationMode - @Environment(\.appName) var appName - - public init(onExit: (() -> Void)?, mode: SettingsPresentationMode = .acceptanceFlow) { - self.onExit = onExit - self.mode = mode - } - - public var body: some View { - InformationView( - title: Text(TherapySetting.deliveryLimits.title), - informationalContent: { - VStack (alignment: .leading, spacing: 20) { - deliveryLimitDescription - maxBasalDescription - maxBolusDescription - } - .fixedSize(horizontal: false, vertical: true) // prevent text from being cut off - }, - onExit: onExit ?? { self.presentationMode.wrappedValue.dismiss() }, - mode: mode - ) - } - - private var deliveryLimitDescription: some View { - Text(LocalizedString("Delivery Limits are safety guardrails for your insulin delivery.", comment: "Information about delivery limits")) - .foregroundColor(.secondary) - } - - private var maxBasalDescription: some View { - VStack(alignment: .leading, spacing: 20) { - Text(DeliveryLimits.Setting.maximumBasalRate.title) - .font(.headline) - VStack(alignment: .leading, spacing: 20) { - Text(String(format: LocalizedString("Maximum Basal Rate is the maximum automatically adjusted basal rate that %1$@ is allowed to enact to help reach your correction range.", comment: "Information about maximum basal rate (1: app name)"), appName)) - Text(LocalizedString("Some users choose a value 2, 3, or 4 times their highest scheduled basal rate.", comment: "Information about typical maximum basal rates")) - Text(LocalizedString("Work with your healthcare provider to choose a value that is higher than your highest scheduled basal rate, but as conservative or aggressive as you feel comfortable.", comment: "Disclaimer")) - } - .foregroundColor(.secondary) - } - } - - private var maxBolusDescription: some View { - VStack(alignment: .leading, spacing: 20) { - Text(DeliveryLimits.Setting.maximumBolus.title) - .font(.headline) - VStack(alignment: .leading, spacing: 20) { - Text(String(format: LocalizedString("Maximum Bolus is the highest bolus amount that you will allow %1$@ to recommend at one time to cover carbs or bring down high glucose.", comment: "Information about maximum bolus (1: app name)"), appName)) - Text(String(format: LocalizedString("This setting will also determine a safety limit for automatic dosing. %1$@ will limit automatic delivery to keep the amount of active insulin below twice your maximum bolus.", comment: "Information about maximum automated insulin on board (1: app name)"), appName)) - } - .foregroundColor(.secondary) - } - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/GlucoseTherapySettingInformationView.swift b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/GlucoseTherapySettingInformationView.swift deleted file mode 100644 index c2f794bdb..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/GlucoseTherapySettingInformationView.swift +++ /dev/null @@ -1,102 +0,0 @@ -// -// GlucoseTherapySettingInformationView.swift -// LoopKitUI -// -// Created by Rick Pasetto on 11/16/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import HealthKit -import SwiftUI -import LoopKit - -public struct GlucoseTherapySettingInformationView: View { - var text: AnyView? - let onExit: (() -> Void)? - let mode: SettingsPresentationMode - let therapySetting: TherapySetting - let preferredUnit: HKUnit - let appName: String - - @Environment(\.presentationMode) var presentationMode - - public init( - therapySetting: TherapySetting, - preferredUnit: HKUnit? = nil, - onExit: (() -> Void)?, - mode: SettingsPresentationMode = .acceptanceFlow, - appName: String, - text: AnyView? = nil - ){ - self.therapySetting = therapySetting - self.preferredUnit = preferredUnit ?? .milligramsPerDeciliter - self.onExit = onExit - self.mode = mode - self.appName = appName - self.text = text - } - - public var body: some View { - InformationView( - title: Text(self.therapySetting.title), - informationalContent: { - illustration - bodyText - }, - onExit: onExit ?? { self.presentationMode.wrappedValue.dismiss() }, - mode: mode - ) - } - - private var illustration: some View { - Image(frameworkImage: illustrationImageName) - .renderingMode(.original) - .resizable() - .aspectRatio(contentMode: ContentMode.fit) - } - - private var bodyText: some View { - VStack(alignment: .leading, spacing: 25) { - text ?? AnyView(Text(therapySetting.descriptiveText(appName: appName))) - Text(therapySetting.guardrailInformationText) - } - .accentColor(.secondary) - .foregroundColor(.accentColor) - .fixedSize(horizontal: false, vertical: true) - } - - private var illustrationImageName: String { - return "\(therapySetting) \(preferredUnit.description.replacingOccurrences(of: "/", with: ""))" - } -} - -fileprivate extension TherapySetting { - // TODO: pass in preferredUnit instead of having both units. - var guardrailInformationText: String { - switch self { - case .glucoseTargetRange: - return lowHighText(for: Guardrail.correctionRange) - case .preMealCorrectionRangeOverride: - return lowHighText(lowerBoundString: LocalizedString("your Glucose Safety Limit", comment: "Lower bound pre-meal information text"), - upperBoundString: Guardrail.premealCorrectionRangeMaximum.bothUnitsString) - case .workoutCorrectionRangeOverride: - return lowHighText( - lowerBoundString: String(format: LocalizedString("%1$@ or your Glucose Safety Limit, whichever is higher", comment: "Lower bound workout information text format (1: app name)"), Guardrail.unconstrainedWorkoutCorrectionRange.absoluteBounds.lowerBound.bothUnitsString), - upperBoundString: Guardrail.unconstrainedWorkoutCorrectionRange.absoluteBounds.upperBound.bothUnitsString) - case .suspendThreshold: - return lowHighText(for: Guardrail.suspendThreshold) - case .basalRate, .deliveryLimits, .insulinModel, .carbRatio, .insulinSensitivity, .none: - fatalError("Unexpected") - } - } - - func lowHighText(for guardrail: Guardrail) -> String { - return lowHighText(lowerBoundString: guardrail.absoluteBounds.lowerBound.bothUnitsString, - upperBoundString: guardrail.absoluteBounds.upperBound.bothUnitsString) - } - - func lowHighText(lowerBoundString: String, upperBoundString: String) -> String { - return String(format: LocalizedString("It can be set as low as %1$@. It can be set as high as %2$@.", - comment: "Guardrail info text format"), lowerBoundString, upperBoundString) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/glucoseTargetRange mgdL.imageset/Chart=Correction, Version=V7, Appearance=Dark, Unit=mgdL.pdf b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/glucoseTargetRange mgdL.imageset/Chart=Correction, Version=V7, Appearance=Dark, Unit=mgdL.pdf deleted file mode 100644 index 96425fdf4..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/glucoseTargetRange mgdL.imageset/Chart=Correction, Version=V7, Appearance=Dark, Unit=mgdL.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/glucoseTargetRange mgdL.imageset/Chart=Correction, Version=V7, Appearance=Light, Unit=mgdL.pdf b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/glucoseTargetRange mgdL.imageset/Chart=Correction, Version=V7, Appearance=Light, Unit=mgdL.pdf deleted file mode 100644 index 207761f58..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/glucoseTargetRange mgdL.imageset/Chart=Correction, Version=V7, Appearance=Light, Unit=mgdL.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/glucoseTargetRange mgdL.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/glucoseTargetRange mgdL.imageset/Contents.json deleted file mode 100644 index 2623f02ae..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/glucoseTargetRange mgdL.imageset/Contents.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "images" : [ - { - "filename" : "Chart=Correction, Version=V7, Appearance=Light, Unit=mgdL.pdf", - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "Chart=Correction, Version=V7, Appearance=Dark, Unit=mgdL.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "preserves-vector-representation" : true, - "template-rendering-intent" : "template" - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/preMealCorrectionRangeOverride mgdL.imageset/Chart=Premeal, Version=V7, Appearance=Dark, Unit=mgdL.pdf b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/preMealCorrectionRangeOverride mgdL.imageset/Chart=Premeal, Version=V7, Appearance=Dark, Unit=mgdL.pdf deleted file mode 100644 index ae3913bc7..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/preMealCorrectionRangeOverride mgdL.imageset/Chart=Premeal, Version=V7, Appearance=Dark, Unit=mgdL.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/preMealCorrectionRangeOverride mgdL.imageset/Chart=Premeal, Version=V7, Appearance=Light, Unit=mgdL.pdf b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/preMealCorrectionRangeOverride mgdL.imageset/Chart=Premeal, Version=V7, Appearance=Light, Unit=mgdL.pdf deleted file mode 100644 index ea833fbd4..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/preMealCorrectionRangeOverride mgdL.imageset/Chart=Premeal, Version=V7, Appearance=Light, Unit=mgdL.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/preMealCorrectionRangeOverride mgdL.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/preMealCorrectionRangeOverride mgdL.imageset/Contents.json deleted file mode 100644 index 2578b2293..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/preMealCorrectionRangeOverride mgdL.imageset/Contents.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "images" : [ - { - "filename" : "Chart=Premeal, Version=V7, Appearance=Light, Unit=mgdL.pdf", - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "Chart=Premeal, Version=V7, Appearance=Dark, Unit=mgdL.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "preserves-vector-representation" : true, - "template-rendering-intent" : "template" - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/suspendThreshold mgdL.imageset/Chart=Glucose, Version=V7, Appearance=Dark, Unit=mgdL.pdf b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/suspendThreshold mgdL.imageset/Chart=Glucose, Version=V7, Appearance=Dark, Unit=mgdL.pdf deleted file mode 100644 index 224f60072..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/suspendThreshold mgdL.imageset/Chart=Glucose, Version=V7, Appearance=Dark, Unit=mgdL.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/suspendThreshold mgdL.imageset/Chart=Glucose, Version=V7, Appearance=Light, Unit=mgdL.pdf b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/suspendThreshold mgdL.imageset/Chart=Glucose, Version=V7, Appearance=Light, Unit=mgdL.pdf deleted file mode 100644 index a38ee2328..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/suspendThreshold mgdL.imageset/Chart=Glucose, Version=V7, Appearance=Light, Unit=mgdL.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/suspendThreshold mgdL.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/suspendThreshold mgdL.imageset/Contents.json deleted file mode 100644 index 4719b4693..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/suspendThreshold mgdL.imageset/Contents.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "images" : [ - { - "filename" : "Chart=Glucose, Version=V7, Appearance=Light, Unit=mgdL.pdf", - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "Chart=Glucose, Version=V7, Appearance=Dark, Unit=mgdL.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "preserves-vector-representation" : true, - "template-rendering-intent" : "template" - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/workoutCorrectionRangeOverride mgdL.imageset/Chart=Workout, Version=V7, Appearance=Dark, Unit=mgdL.pdf b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/workoutCorrectionRangeOverride mgdL.imageset/Chart=Workout, Version=V7, Appearance=Dark, Unit=mgdL.pdf deleted file mode 100644 index c502deed5..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/workoutCorrectionRangeOverride mgdL.imageset/Chart=Workout, Version=V7, Appearance=Dark, Unit=mgdL.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/workoutCorrectionRangeOverride mgdL.imageset/Chart=Workout, Version=V7, Appearance=Light, Unit=mgdL.pdf b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/workoutCorrectionRangeOverride mgdL.imageset/Chart=Workout, Version=V7, Appearance=Light, Unit=mgdL.pdf deleted file mode 100644 index 28190a04c..000000000 Binary files a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/workoutCorrectionRangeOverride mgdL.imageset/Chart=Workout, Version=V7, Appearance=Light, Unit=mgdL.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/workoutCorrectionRangeOverride mgdL.imageset/Contents.json b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/workoutCorrectionRangeOverride mgdL.imageset/Contents.json deleted file mode 100644 index 24561cf91..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationScreens.xcassets/workoutCorrectionRangeOverride mgdL.imageset/Contents.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "images" : [ - { - "filename" : "Chart=Workout, Version=V7, Appearance=Light, Unit=mgdL.pdf", - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "Chart=Workout, Version=V7, Appearance=Dark, Unit=mgdL.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "preserves-vector-representation" : true, - "template-rendering-intent" : "template" - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationView.swift b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationView.swift deleted file mode 100644 index 71458e2ae..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InformationView.swift +++ /dev/null @@ -1,108 +0,0 @@ -// -// InformationView.swift -// LoopKitUI -// -// Created by Anna Quinlan on 7/1/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -struct InformationView : View { - var informationalContent: InformationalContent - var title: Text - var buttonText: Text - var onExit: (() -> Void) - let mode: SettingsPresentationMode - - init( - title: Text, - buttonText: Text, - @ViewBuilder informationalContent: () -> InformationalContent, - onExit: @escaping () -> Void, - mode: SettingsPresentationMode - ) { - self.title = title - self.buttonText = buttonText - self.informationalContent = informationalContent() - self.onExit = onExit - self.mode = mode - } - - // Convenience initializer for info view w/next page button - init( - title: Text, - @ViewBuilder informationalContent: () -> InformationalContent, - onExit: @escaping () -> Void, - mode: SettingsPresentationMode = .acceptanceFlow - ) { - self.init( - title: title, - buttonText: Text(LocalizedString("Continue", comment: "Button to advance to setting editor")), - informationalContent: informationalContent, - onExit: onExit, - mode: mode - ) - } - - var body: some View { - GeometryReader { geometry in - ScrollView { - bodyForMode - .padding() - .frame(minHeight: geometry.size.height) - } - } - } - - @ViewBuilder - private var bodyForMode: some View { - switch mode { - case .acceptanceFlow: - bodyForAcceptanceFlow - case .settings: - bodyForSettings - } - } - - private var bodyForAcceptanceFlow: some View { - VStack(alignment: .leading, spacing: 20) { - titleView - Divider() - informationalContent - Spacer() - nextPageButton - } - } - - private var bodyForSettings: some View { - VStack(alignment: .leading, spacing: 20) { - informationalContent - Spacer() - } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - cancelButton - } - } - .navigationBarTitle(title, displayMode: .large) - } - - private var titleView: some View { - title - .font(.largeTitle) - .bold() - .fixedSize(horizontal: false, vertical: true) - } - - private var cancelButton: some View { - Button(action: onExit, label: { Text(LocalizedString("Close", comment: "Text to close informational page")) }) - } - - private var nextPageButton: some View { - Button(action: onExit) { - buttonText - .actionButtonStyle(.primary) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InsulinModelInformationView.swift b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InsulinModelInformationView.swift deleted file mode 100644 index 78efa8264..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InsulinModelInformationView.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// InsulinModelInformationView.swift -// LoopKitUI -// -// Created by Anna Quinlan on 7/6/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - -public struct InsulinModelInformationView: View { - var onExit: (() -> Void)? - var mode: SettingsPresentationMode - - @Environment(\.presentationMode) var presentationMode - @Environment(\.appName) private var appName - - public init(onExit: (() -> Void)?, mode: SettingsPresentationMode = .acceptanceFlow) { - self.onExit = onExit - self.mode = mode - } - - public var body: some View { - InformationView( - title: Text(TherapySetting.insulinModel.title), - informationalContent: { - VStack (alignment: .leading, spacing: 20) { - diaInfo - modelPeakInfo - } - .foregroundColor(.secondary) - }, - onExit: onExit ?? { self.presentationMode.wrappedValue.dismiss() }, - mode: mode - ) - } - - private var diaInfo: Text { - Text(String(format: LocalizedString("%1$@ assumes that the insulin it has delivered is actively working to lower your glucose for 6 hours. This setting cannot be changed.", comment: "Information about insulin action duration (1: app name)"), appName)) - } - - private var modelPeakInfo: some View { - VStack (alignment: .leading, spacing: 20) { - Text(String(format: LocalizedString("You can choose how %1$@ measures rapid acting insulin's peak activity according to one of these two insulin models.", comment: "Information about insulin model (1: app name)"), appName)) - HStack(spacing: 10) { - bulletCircle - Text(LocalizedString("The rapid-acting adult model assumes peak activity at 75 minutes.", comment: "Information about adult insulin model")) - } - HStack(spacing: 10) { - bulletCircle - Text(LocalizedString("The rapid-acting child model assumes peak activity at 65 minutes.", comment: "Information about child insulin model")) - } - } - } - - private var bulletCircle: some View { - Image(systemName: "circle.fill") - .resizable() - .frame(width: 10, height: 10) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InsulinSensitivityInformationView.swift b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InsulinSensitivityInformationView.swift deleted file mode 100644 index 8c2dfa8e7..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/InsulinSensitivityInformationView.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// InsulinSensitivityInformationView.swift -// LoopKitUI -// -// Created by Anna Quinlan on 7/28/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - -public struct InsulinSensitivityInformationView: View { - var onExit: (() -> Void)? - var mode: SettingsPresentationMode - - @Environment(\.presentationMode) var presentationMode - - public init( - onExit: (() -> Void)?, - mode: SettingsPresentationMode = .acceptanceFlow - ){ - self.onExit = onExit - self.mode = mode - } - - public var body: some View { - InformationView( - title: Text(TherapySetting.insulinSensitivity.title), - informationalContent: {text}, - onExit: onExit ?? { self.presentationMode.wrappedValue.dismiss() }, - mode: mode - ) - } - - private var text: some View { - VStack(alignment: .leading, spacing: 25) { - Text(LocalizedString("Your Insulin Sensitivity Factor (ISF) is the drop in glucose expected from one unit of insulin.", comment: "Description of insulin sensitivity factor")) - Text(LocalizedString("You can add different insulin sensitivities for different times of day by using the ➕.", comment: "Description of how to add a ratio")) - } - .accentColor(.secondary) - .foregroundColor(.accentColor) - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/SuspendThresholdInformationView.swift b/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/SuspendThresholdInformationView.swift deleted file mode 100644 index 7026c5fb1..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Information Screens/SuspendThresholdInformationView.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// SuspendThresholdInformationView.swift -// LoopKitUI -// -// Created by Anna Quinlan on 7/2/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import HealthKit -import SwiftUI -import LoopKit - -public struct SuspendThresholdInformationView: View { - var onExit: (() -> Void)? - var mode: SettingsPresentationMode - var preferredUnit: HKUnit = HKUnit.milligramsPerDeciliter - - @Environment(\.presentationMode) var presentationMode - @Environment(\.appName) var appName - - public init( - onExit: (() -> Void)? = nil, - mode: SettingsPresentationMode = .acceptanceFlow - ){ - self.onExit = onExit - self.mode = mode - } - - public var body: some View { - GlucoseTherapySettingInformationView(therapySetting: .suspendThreshold, - preferredUnit: preferredUnit, - onExit: onExit, - mode: mode, - appName: appName) - } -} - -struct SuspendThresholdInformationView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - SuspendThresholdInformationView() - } - .colorScheme(.light) - .previewDevice(PreviewDevice(rawValue: "iPhone SE 2")) - .previewDisplayName("SE light") - NavigationView { - SuspendThresholdInformationView() - } - .preferredColorScheme(.dark) - .colorScheme(.dark) - .previewDevice(PreviewDevice(rawValue: "iPhone 11 Pro Max")) - .previewDisplayName("11 Pro dark") - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/InstructionList.swift b/Dependencies/LoopKit/LoopKitUI/Views/InstructionList.swift deleted file mode 100644 index fe0612ec0..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/InstructionList.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// InstructionList.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-02-20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct InstructionList: View { - struct Instruction { - let text: String - let subtext: String? - } - let instructions: [Instruction] - let startingIndex: Int - let instructionColor: Color - - @Environment(\.isEnabled) var isEnabled - - public init(instructions: [String], startingIndex: Int = 1, instructionColor: Color = .primary) { - self.instructions = instructions.map { Instruction(text: $0, subtext: nil) } - self.startingIndex = startingIndex - self.instructionColor = instructionColor - } - - public init(instructions: [(String, String)], startingIndex: Int = 1, instructionColor: Color = .primary) { - self.instructions = instructions.map { Instruction(text: $0.0, subtext: $0.1) } - self.startingIndex = startingIndex - self.instructionColor = instructionColor - } - - public var body: some View { - VStack(alignment: .leading, spacing: 10) { - ForEach(instructions.indices, id: \.self) { index in - HStack(alignment: .top) { - Text("\(index+startingIndex)") - .opacity(isEnabled ? 1.0 : 0.8) - .padding(6) - .background(Circle().fill(Color.accentColor)) - .foregroundColor(Color.white) - .font(.caption) - .accessibility(label: Text("\(index+1), ")) // Adds a pause after the number - instructionView(instructions[index]) - } - .accessibilityElement(children: .combine) - } - } - } - - @ViewBuilder - private func instructionView(_ instruction: Instruction) -> some View { - VStack(alignment: .leading, spacing: 2) { - Text(instruction.text) - .fixedSize(horizontal: false, vertical: true) - if let subtext = instruction.subtext { - Text(subtext) - .fixedSize(horizontal: false, vertical: true) - .foregroundColor(isEnabled ? instructionColor : Color.secondary) - .font(.caption) - } - } - .padding(2) - .foregroundColor(isEnabled ? instructionColor : Color.secondary) - } -} - -struct InstructionList_Previews: PreviewProvider { - static var previews: some View { - let instructions: [String] = [ - "This is the first step.", - "This second step is a bit more tricky and needs more description to support the user, albeit it could be more concise.", - "With this final step, the task will be accomplished." - ] - return InstructionList(instructions: instructions) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/InsulinSensitivityScalingTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/InsulinSensitivityScalingTableViewCell.swift deleted file mode 100644 index 250f71b76..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/InsulinSensitivityScalingTableViewCell.swift +++ /dev/null @@ -1,195 +0,0 @@ -// -// InsulinSensitivityScalingTableViewCell.swift -// LoopKitUI -// -// Created by Michael Pangburn on 3/22/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit - - -protocol InsulinSensitivityScalingTableViewCellDelegate: AnyObject { - func insulinSensitivityScalingTableViewCellDidUpdateScaleFactor(_ cell: InsulinSensitivityScalingTableViewCell) -} - - -final class InsulinSensitivityScalingTableViewCell: UITableViewCell { - - private let allScaleFactorPercentages = Array(stride(from: 10, through: 200, by: 10)) - - @IBOutlet private weak var titleLabel: UILabel! - - @IBOutlet private weak var valueLabel: UILabel! - - @IBOutlet weak var gaugeBar: SegmentedGaugeBarView! { - didSet { - gaugeBar.backgroundColor = .systemGray6 - - gaugeBar.delegate = self - } - } - - @IBOutlet private weak var scaleFactorPicker: UIPickerView! { - didSet { - scaleFactorPicker.dataSource = self - scaleFactorPicker.delegate = self - } - } - - @IBOutlet private weak var scaleFactorPickerHeightConstraint: NSLayoutConstraint! { - didSet { - pickerExpandedHeight = scaleFactorPickerHeightConstraint.constant - } - } - - private var pickerExpandedHeight: CGFloat = 0 - - @IBOutlet private weak var footerLabel: UILabel! - - private lazy var percentFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .percent - formatter.maximumFractionDigits = 0 - return formatter - }() - - var isPickerHidden: Bool { - get { - return scaleFactorPicker.isHidden - } - set { - scaleFactorPicker.isHidden = newValue - scaleFactorPickerHeightConstraint.constant = newValue ? 0 : pickerExpandedHeight - - if !newValue { - updatePickerRow(animated: false) - } - } - } - - private func updatePickerRow(animated: Bool) { - var selectedRow = allScaleFactorPercentages.firstIndex(of: selectedPercentage) - if selectedRow == nil { - let truncatedPercentage = allScaleFactorPercentages - .adjacentPairs() - .first(where: { lower, upper in - (lower.. 0 { - footerText = String( - format: LocalizedString("Basal, bolus, and correction insulin dose amounts are increased by %@%%.", comment: "Describes a percentage increase in overall insulin needs"), - String(delta) - ) - } else { - footerText = LocalizedString("Basal, bolus, and correction insulin dose amounts are unaffected.", comment: "Describes a lack of change in overall insulin needs") - } - - footerLabel.text = footerText - } - - private func percentageString(from percentage: Int) -> String? { - return percentFormatter.string(from: Double(percentage) / 100) - } -} - -extension InsulinSensitivityScalingTableViewCell: UIPickerViewDataSource { - func numberOfComponents(in pickerView: UIPickerView) -> Int { - return 1 - } - - func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { - return allScaleFactorPercentages.count - } -} - -extension InsulinSensitivityScalingTableViewCell: UIPickerViewDelegate { - func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { - return percentageString(from: allScaleFactorPercentages[row]) - } - - func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { - selectedPercentage = allScaleFactorPercentages[row] - } -} - -extension InsulinSensitivityScalingTableViewCell: SegmentedGaugeBarViewDelegate { - func segmentedGaugeBarView(_ view: SegmentedGaugeBarView, didUpdateProgressFrom oldValue: Double, to newValue: Double) { - scaleFactor = newValue - updatePickerRow(animated: true) - } -} - -extension InsulinSensitivityScalingTableViewCellDelegate where Self: UITableViewController { - func collapseInsulinSensitivityScalingCells(excluding indexPath: IndexPath? = nil) { - for case let cell as InsulinSensitivityScalingTableViewCell in tableView.visibleCells where tableView.indexPath(for: cell) != indexPath && !cell.isPickerHidden { - cell.isPickerHidden = true - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/InsulinSensitivityScalingTableViewCell.xib b/Dependencies/LoopKit/LoopKitUI/Views/InsulinSensitivityScalingTableViewCell.xib deleted file mode 100644 index 3ac775f7a..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/InsulinSensitivityScalingTableViewCell.xib +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/InsulinTypeChooser.swift b/Dependencies/LoopKit/LoopKitUI/Views/InsulinTypeChooser.swift deleted file mode 100644 index 0549cb135..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/InsulinTypeChooser.swift +++ /dev/null @@ -1,92 +0,0 @@ -// -// InsulinTypeChooserView.swift -// LoopKitUI -// -// Created by Pete Schwamb on 12/30/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - -public struct InsulinTypeChooser: View { - - @Binding private var insulinType: InsulinType? - - let supportedInsulinTypes: [InsulinType?] - - public init(insulinType: Binding, supportedInsulinTypes: [InsulinType], allowUnsetInsulinType: Bool = false) { - if allowUnsetInsulinType { - self.supportedInsulinTypes = [InsulinType?](supportedInsulinTypes) + [nil] - } else { - self.supportedInsulinTypes = supportedInsulinTypes - } - self._insulinType = insulinType - } - - public var body: some View { - ForEach(supportedInsulinTypes, id: \.self) { insulinType in - if let insulinType = insulinType { - HStack { - ZStack { - Image(frameworkImage: "vial_color") - .renderingMode(.template) - .resizable() - .scaledToFit() - .foregroundColor(Color(frameworkColor: insulinType.brandName)) - Image(frameworkImage: "vial") - .resizable() - .scaledToFit() - } - .padding([.trailing]) - .frame(height: 70) - CheckmarkListItem( - title: Text(insulinType.title), - description: Text(insulinType.description), - isSelected: Binding( - get: { self.insulinType == insulinType }, - set: { isSelected in - if isSelected { - withAnimation { - self.insulinType = insulinType - } - } - } - ) - ) - } - .padding(.vertical, 4) - } else { - HStack { - CheckmarkListItem( - title: Text(LocalizedString("Unset", comment: "Title for selection when no insulin type is selected.")), - description: Text(LocalizedString("The currently selected fast acting insulin model will be used as a default.", comment: "Description for selection when no insulin type is selected.")), - isSelected: Binding( - get: { self.insulinType == nil }, - set: { isSelected in - if isSelected { - withAnimation { - self.insulinType = nil - } - } - } - ) - ) - } - .padding(.vertical, 4) - } - } - } -} - -struct InsulinTypeChooser_Previews: PreviewProvider { - static var previews: some View { - InsulinTypeChooser(insulinType: .constant(.novolog), supportedInsulinTypes: InsulinType.allCases) - } -} - -extension InsulinType { - var image: UIImage? { - return UIImage(frameworkImage: "vial")?.withTintColor(.red) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/InsulinTypeSetting.swift b/Dependencies/LoopKit/LoopKitUI/Views/InsulinTypeSetting.swift deleted file mode 100644 index 759558808..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/InsulinTypeSetting.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// InsulinTypeSetting.swift -// MockKitUI -// -// Created by Pete Schwamb on 1/1/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - -public struct InsulinTypeSetting: View { - - @State private var insulinType: InsulinType? - private var supportedInsulinTypes: [InsulinType] - private var allowUnsetInsulinType: Bool - private var didChange: (InsulinType?) -> Void - - public init(initialValue: InsulinType?, supportedInsulinTypes: [InsulinType], allowUnsetInsulinType: Bool, didChange: @escaping (InsulinType?) -> Void) { - self._insulinType = State(initialValue: initialValue) - self.supportedInsulinTypes = supportedInsulinTypes - self.allowUnsetInsulinType = allowUnsetInsulinType - self.didChange = didChange - } - - public var body: some View { - List { - Section { - InsulinTypeChooser(insulinType: insulinTypeBinding, supportedInsulinTypes: supportedInsulinTypes, allowUnsetInsulinType: allowUnsetInsulinType) - } - .buttonStyle(PlainButtonStyle()) // Disable row highlighting on selection - } - .insetGroupedListStyle() - - } - - private var insulinTypeBinding: Binding { - Binding( - get: { self.insulinType }, - set: { newValue in - insulinType = newValue - didChange(newValue) - } - ) - } -} - -struct InsulinTypeSetting_Previews: PreviewProvider { - static var previews: some View { - InsulinTypeSetting(initialValue: .humalog, supportedInsulinTypes: InsulinType.allCases, allowUnsetInsulinType: false) { (newType) in - - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/LabeledDateView.swift b/Dependencies/LoopKit/LoopKitUI/Views/LabeledDateView.swift deleted file mode 100644 index 11119c8f7..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/LabeledDateView.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// LabeledDateView.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-02-20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct LabeledDateView: View { - var label: String - var date: Date? - var dateFormatter: DateFormatter - - private var dateString: String? { - guard let date = self.date else { - return nil - } - return self.dateFormatter.string(from: date) - } - - public init(label: String, date: Date?, dateFormatter: DateFormatter) { - self.label = label - self.date = date - self.dateFormatter = dateFormatter - } - - public var body: some View { - LabeledValueView(label: label, - value: dateString) - } -} - -struct LabeledDateView_Previews: PreviewProvider { - static var previews: some View { - var dateFormatter: DateFormatter { - let formatter = DateFormatter() - formatter.dateStyle = .short - formatter.timeStyle = .short - return formatter - } - return LabeledDateView(label: "Last Calibration", - date: Date(), - dateFormatter: dateFormatter) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/LabeledNumberInput.swift b/Dependencies/LoopKit/LoopKitUI/Views/LabeledNumberInput.swift deleted file mode 100644 index 7f23d37f7..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/LabeledNumberInput.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// LabeledNumberInput.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-02-20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct LabeledNumberInput: View { - @Binding var value: Double? - let font: UIFont - let label: String - let placeholder: String - let allowFractions: Bool - let shouldBecomeFirstResponder: Bool - - private var numberFormatter: NumberFormatter { - let numberFormatter = NumberFormatter() - numberFormatter.numberStyle = allowFractions ? .decimal : .none - return numberFormatter - } - - // seems like the TextField doesn't update the formatted binding until return to tapped. This is the workaround. - private var valueString: Binding { - Binding( - get: { () -> String in - guard let value = self.value else { - return "" - } - return self.numberFormatter.string(from: NSNumber(value: value.rawValue)) ?? "" - }, - set: { - if let value = self.numberFormatter.number(from: $0) { - self.value = value.doubleValue - } - } - ) - } - - public init(value: Binding, font: UIFont = .preferredFont(forTextStyle: .largeTitle), label: String, placeholder: String? = nil, allowFractions: Bool = false, shouldBecomeFirstResponder: Bool = false) { - _value = value - self.font = font - self.label = label - self.placeholder = placeholder ?? LocalizedString("Value", comment: "Placeholder text until value is entered") - self.allowFractions = allowFractions - self.shouldBecomeFirstResponder = shouldBecomeFirstResponder - } - - public var body: some View { - GeometryReader { geometry in - HStack(alignment: .bottom, spacing: 5) { - DismissibleKeyboardTextField( - text: valueString, - placeholder: placeholder, - font: font, - textAlignment: .right, - keyboardType: allowFractions ? .decimalPad : .numberPad, - shouldBecomeFirstResponder: true, - isDismissible: false - ) - .accessibility(label: Text(String(format: LocalizedString("Enter %1$@ value", comment: "Format string for accessibility label for value entry. (1: value label)"), label))) - Text(self.label) - .font(.footnote) - .multilineTextAlignment(.leading) - .foregroundColor(.secondary) - .padding(.bottom, 7) - .frame(width: geometry.size.width/2, alignment: .leading) - } - } - } -} - -struct LabeledNumberInput_Previews: PreviewProvider { - static var previews: some View { - LabeledNumberInput( - value: .constant(nil), - label: "mg/dL", - allowFractions: true) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/LabeledTextField.swift b/Dependencies/LoopKit/LoopKitUI/Views/LabeledTextField.swift deleted file mode 100644 index 31e891377..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/LabeledTextField.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// LabeledTextField.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-02-27. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct LabeledTextField: View { - var label: String - var placeholder: String - @Binding var value: String - - public init(label: String, placeholder: String = "", value: Binding) { - self.label = label - self.placeholder = placeholder - _value = value - } - - public var body: some View { - GeometryReader { geometry in - HStack(alignment: .firstTextBaseline, spacing: 0) { - Text(self.label) - .foregroundColor(.primary) - .frame(maxWidth: geometry.size.width/2, alignment: .leading) - Spacer() - TextField(self.placeholder, text: self.$value) - .foregroundColor(.secondary) - .multilineTextAlignment(.trailing) - .keyboardType(.alphabet) - .frame(maxWidth: geometry.size.width/2, alignment: .trailing) - } - } - } -} - -struct LabelTextField_Previews: PreviewProvider { - static var previews: some View { - return Group { - PreviewWrapper() - } - } - - struct PreviewWrapper: View { - @State(initialValue: "Overnight") var value: String - var body: some View { - LabeledTextField(label: "Name", placeholder: "Schedule Name", value: $value) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/LabeledTextFieldTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/LabeledTextFieldTableViewCell.swift deleted file mode 100644 index f20146412..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/LabeledTextFieldTableViewCell.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// LabeledTextFieldTableViewCell.swift -// LoopKitUI -// -// Created by Michael Pangburn on 1/3/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit - - -public class LabeledTextFieldTableViewCell: TextFieldTableViewCell { - @IBOutlet public weak var titleLabel: UILabel! - - private var customInputTextField: CustomInputTextField? { - return textField as? CustomInputTextField - } - - public var customInput: UIInputViewController? { - get { - return customInputTextField?.customInput - } - set { - customInputTextField?.customInput = newValue - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/LabeledTextFieldTableViewCell.xib b/Dependencies/LoopKit/LoopKitUI/Views/LabeledTextFieldTableViewCell.xib deleted file mode 100644 index 66f8a4c72..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/LabeledTextFieldTableViewCell.xib +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/LabeledValueView.swift b/Dependencies/LoopKit/LoopKitUI/Views/LabeledValueView.swift deleted file mode 100644 index de62675c5..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/LabeledValueView.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// LabeledValueView.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-02-20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct LabeledValueView: View { - public static let NoValueString: String = "–" - var label: String - var value: String? - var highlightValue: Bool - - public init(label: String, value: String?, highlightValue: Bool = false) { - self.label = label - self.value = value - self.highlightValue = highlightValue - } - - public var body: some View { - HStack { - Text(label) - .foregroundColor(.primary) - Spacer() - Text(value ?? LabeledValueView.NoValueString) - .foregroundColor(highlightValue ? .accentColor : .secondary) - } - } -} - -struct LabeledValueView_Previews: PreviewProvider { - static var previews: some View { - LabeledValueView(label: "Glucose", value: "80 mg/dL", highlightValue: true) - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/LevelHUDView.swift b/Dependencies/LoopKit/LoopKitUI/Views/LevelHUDView.swift deleted file mode 100644 index 098d7773f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/LevelHUDView.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// LevelHUDView.swift -// Loop -// -// Created by Nate Racklyeft on 2/4/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import UIKit - -open class LevelHUDView: BaseHUDView { - - @IBOutlet public weak var levelMaskView: LevelMaskView! - - override open func awakeFromNib() { - super.awakeFromNib() - - updateColor() - - accessibilityValue = LocalizedString("Unknown", comment: "Accessibility value for an unknown value") - } - - override open func stateColorsDidUpdate() { - super.stateColorsDidUpdate() - updateColor() - } - - open func updateColor() { - levelMaskView.tintColor = nil - - switch level { - case .none: - tintColor = stateColors?.unknown - case let x? where x > 0.25: - tintColor = stateColors?.normal - case let x? where x > 0.10: - tintColor = stateColors?.warning - levelMaskView.tintColor = stateColors?.warning - default: - tintColor = stateColors?.error - } - } - - public var level: Double? { - didSet { - levelMaskView.value = level ?? 1.0 - levelDidChange() - } - } - - open func levelDidChange() { - updateColor() - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/LevelMaskView.swift b/Dependencies/LoopKit/LoopKitUI/Views/LevelMaskView.swift deleted file mode 100644 index d481cda02..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/LevelMaskView.swift +++ /dev/null @@ -1,96 +0,0 @@ -// -// LevelMaskView.swift -// Loop -// -// Created by Nate Racklyeft on 8/28/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - -// Displays a variable-height level indicator, masked by an image. -// Inspired by https://github.com/carekit-apple/CareKit/blob/master/CareKit/CareCard/OCKHeartView.h - -public class LevelMaskView: UIView { - var firstDataUpdate = true - - var value: Double = 1.0 { - didSet { - animateFill(duration: firstDataUpdate ? 0 : 1.25) - firstDataUpdate = false - } - } - - private var clampedValue: Double { - return value.clamped(to: 0...1.0) - } - - @IBInspectable var maskImage: UIImage? { - didSet { - fillView?.removeFromSuperview() - mask?.removeFromSuperview() - maskImageView?.removeFromSuperview() - - guard let maskImage = maskImage else { - fillView = nil - mask = nil - maskImageView = nil - return - } - - mask = UIView() - maskImageView = UIImageView(image: maskImage) - maskImageView!.frame = CGRect(origin: .zero, size: frame.size) - maskImageView!.contentMode = .scaleAspectFit - mask!.addSubview(maskImageView!) - - clipsToBounds = true - - fillView = UIView() - fillView!.backgroundColor = tintColor - addSubview(fillView!) - } - } - - private var fillView: UIView? - - private var maskImageView: UIView? - - override public func layoutSubviews() { - super.layoutSubviews() - - guard let maskImageView = maskImageView else { return } - - let maskImageViewSize = maskImageView.frame.size - - mask?.frame = CGRect(origin: .zero, size: maskImageViewSize) - mask?.center = CGPoint(x: bounds.midX, y: bounds.midY) - self.maskImageView?.frame = mask?.bounds ?? bounds - - if (fillView?.layer.animationKeys()?.count ?? 0) == 0 { - updateFillViewFrame() - } - } - - override public func tintColorDidChange() { - super.tintColorDidChange() - - fillView?.backgroundColor = tintColor - } - - private func animateFill(duration: TimeInterval) { - UIView.animate(withDuration: duration, delay: 0, options: .beginFromCurrentState, animations: { - self.updateFillViewFrame() - }, completion: nil) - } - - private func updateFillViewFrame() { - guard let maskViewFrame = mask?.frame else { return } - - var fillViewFrame = maskViewFrame - fillViewFrame.origin.y = maskViewFrame.maxY - fillViewFrame.size.height = -CGFloat(clampedValue) * maskViewFrame.height - fillView?.frame = fillViewFrame - } - -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/LoadingTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/LoadingTableViewCell.swift deleted file mode 100644 index 00536b017..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/LoadingTableViewCell.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// LoadingTableViewCell.swift -// LoopKitUI -// -// Created by Pete Schwamb on 10/24/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import UIKit - -open class LoadingTableViewCell: UITableViewCell { - - public var isLoading = false { - didSet { - if isLoading { - let indicator = UIActivityIndicatorView(style: .default) - accessoryView = indicator - indicator.startAnimating() - } else { - accessoryView = nil - } - loadingStatusChanged() - } - } - - open func loadingStatusChanged() {} -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ModalHeaderButtonBar.swift b/Dependencies/LoopKit/LoopKitUI/Views/ModalHeaderButtonBar.swift deleted file mode 100644 index cbef619d2..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ModalHeaderButtonBar.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// ModalHeaderButtonBar.swift -// LoopKitUI -// -// Created by Michael Pangburn on 5/7/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -struct ModalHeaderButtonBar: View { - var leading: Leading - var center: Center - var trailing: Trailing - - init( - @ViewBuilder leading: () -> Leading, - @ViewBuilder center: () -> Center, - @ViewBuilder trailing: () -> Trailing - ) { - self.leading = leading() - self.center = center() - self.trailing = trailing() - } - - var body: some View { - VStack(spacing: 0) { - HStack { - HStack { - leading - Spacer() - } - - center - - HStack { - Spacer() - trailing - } - } - .padding() - .background(Color(.defaultNavigationBar)) - .cornerRadius(10, corners: [.topLeft, .topRight]) - - Divider() - } - } -} - -extension UIColor { - static let defaultNavigationBar = UIColor(dynamicProvider: { traitCollection in - if traitCollection.userInterfaceStyle == .dark { - return UIColor(red: 40/255, green: 41/255, blue: 40/255, alpha: 1) - } else { - return UIColor(red: 248/255, green: 248/255, blue: 248/255, alpha: 1) - } - }) -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/MultipleSelectionList.swift b/Dependencies/LoopKit/LoopKitUI/Views/MultipleSelectionList.swift deleted file mode 100644 index 4e2f31a87..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/MultipleSelectionList.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// MultipleSelectionList.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-02-27. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct MultipleSelectionList: View where Item: Hashable { - var items: [Item] - @Binding var selectedItems: Set - var itemToDisplayableString: (Item) -> String - - public init(items: [Item], selectedItems: Binding>, itemToDisplayableString: @escaping (Item) -> String) { - self.items = items - _selectedItems = selectedItems - self.itemToDisplayableString = itemToDisplayableString - } - - public var body: some View { - List(items, id:\.self) { item in - MultipleSelectionRow(item: item, - selectedItems: self.$selectedItems, - itemToDisplayableString: self.itemToDisplayableString) - } - .insetGroupedListStyle() - } -} - -struct MultipleSelectionRow: View where Item: Hashable { - var item: Item - @Binding var selectedItems: Set - var itemToDisplayableString: (Item) -> String - - var isSelected: Bool { - selectedItems.contains(item) - } - - var body: some View { - HStack { - Button(action: { - if self.isSelected { - self.selectedItems.remove(self.item) - } else { - self.selectedItems.insert(self.item) - } - }) { - Text(self.itemToDisplayableString(item)) - .foregroundColor(.primary) - } - Spacer() - if isSelected { - Image(systemName: "checkmark.circle.fill") - .foregroundColor(.accentColor) - } - } - } -} - -struct SelectableList_Previews: PreviewProvider { - static var previews: some View { - PreviewWrapper() - } - - struct PreviewWrapper: View { - static var fruit = ["Orange", "Apple", "Banana", "Peach", "Grape"] - @State(initialValue: [fruit[1], fruit[3]]) var selectedFruit: Set - - var body: some View { - MultipleSelectionList(items: SelectableList_Previews.PreviewWrapper.fruit, - selectedItems: $selectedFruit, - itemToDisplayableString: { String(describing:$0) }) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/NewScheduleItemEditor.swift b/Dependencies/LoopKit/LoopKitUI/Views/NewScheduleItemEditor.swift deleted file mode 100644 index 776f4019c..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/NewScheduleItemEditor.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// NewScheduleItemEditor.swift -// LoopKitUI -// -// Created by Michael Pangburn on 5/7/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - - -struct NewScheduleItemEditor: View { - enum SelectableTimes { - case only(TimeInterval) - case allExcept(Set) - } - - @Binding var isPresented: Bool - @State var item: RepeatingScheduleValue - var initialItem: RepeatingScheduleValue - var selectableTimes: SelectableTimes - var valuePicker: (_ item: Binding>, _ availableWidth: CGFloat) -> ValuePicker - var save: (RepeatingScheduleValue) -> Void - - init( - isPresented: Binding, - initialItem: RepeatingScheduleValue, - selectableTimes: SelectableTimes, - @ViewBuilder valuePicker: @escaping (_ item: Binding>, _ availableWidth: CGFloat) -> ValuePicker, - onSave save: @escaping (RepeatingScheduleValue) -> Void - ) { - self._isPresented = isPresented - self._item = State(initialValue: initialItem) - self.initialItem = initialItem - self.selectableTimes = selectableTimes - self.valuePicker = valuePicker - self.save = save - } - - var body: some View { - VStack(spacing: 0) { - ModalHeaderButtonBar( - leading: { cancelButton }, - center: { - Text(LocalizedString("New Entry", comment: "Title for mini-modal to add a new schedule entry")) - .font(.headline) - }, - trailing: { addButton } - ) - - ScheduleItemPicker( - item: $item, - isTimeSelectable: isTimeSelectable, - valuePicker: { self.valuePicker(self.$item, $0) } - ) - .padding(.horizontal) - .background( - RoundedCorners(radius: 10, corners: [.bottomLeft, .bottomRight]) - .fill(Color(.secondarySystemGroupedBackground)) - ) - } - .padding(.horizontal) - } - - func isTimeSelectable(_ time: TimeInterval) -> Bool { - switch selectableTimes { - case .only(let selectableTime): - return time == selectableTime - case .allExcept(let unavailableTimes): - return !unavailableTimes.contains(time) - } - } - - var addButton: some View { - Button( - action: { - withAnimation { - self.save(self.item) - self.isPresented = false - } - }, label: { - Text(LocalizedString("Add", comment: "Button text to confirm adding a new schedule item")) - } - ) - } - - var cancelButton: some View { - Button( - action: { - withAnimation { - self.isPresented = false - } - }, label: { - Text(LocalizedString("Cancel", comment: "Button text to cancel adding a new schedule item")) - } - ) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/OverrideHistoryCollectionViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/OverrideHistoryCollectionViewCell.swift deleted file mode 100644 index de461df60..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/OverrideHistoryCollectionViewCell.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// OverrideHistoryCollectionViewCell.swift -// LoopKitUI -// -// Created by Anna Quinlan on 8/6/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import UIKit - - -final class OverrideHistoryCollectionViewCell: UICollectionViewCell, IdentifiableClass { - @IBOutlet weak var titleLabel: UILabel! - - private lazy var overlayDimmerView: UIView = { - let view = UIView() - if #available(iOSApplicationExtension 13.0, *) { - view.backgroundColor = .systemBackground - } else { - view.backgroundColor = .white - } - view.alpha = 0 - view.translatesAutoresizingMaskIntoConstraints = false - return view - }() - - override func awakeFromNib() { - super.awakeFromNib() - - let selectedBackgroundView = UIView() - self.selectedBackgroundView = selectedBackgroundView - - if #available(iOSApplicationExtension 13.0, iOS 13.0, *) { - selectedBackgroundView.backgroundColor = .tertiarySystemFill - - backgroundColor = .secondarySystemGroupedBackground - layer.cornerCurve = .continuous - } else { - selectedBackgroundView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.3) - - backgroundColor = .white - } - - layer.cornerRadius = 16 - - addSubview(overlayDimmerView) - NSLayoutConstraint.activate([ - overlayDimmerView.leadingAnchor.constraint(equalTo: leadingAnchor), - overlayDimmerView.trailingAnchor.constraint(equalTo: trailingAnchor), - overlayDimmerView.topAnchor.constraint(equalTo: topAnchor), - overlayDimmerView.bottomAnchor.constraint(equalTo: bottomAnchor) - ]) - } - - override func prepareForReuse() { - removeOverlay(animated: false) - } - - func applyOverlayToFade(animated: Bool) { - if animated { - UIView.animate(withDuration: 0.3, animations: { - self.overlayDimmerView.alpha = 0.5 - }) - } else { - self.overlayDimmerView.alpha = 0.5 - } - } - - func removeOverlay(animated: Bool) { - if animated { - UIView.animate(withDuration: 0.3, animations: { - self.overlayDimmerView.alpha = 0 - }) - } else { - self.overlayDimmerView.alpha = 0 - } - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/OverridePresetCollectionViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/OverridePresetCollectionViewCell.swift deleted file mode 100644 index ec81e1731..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/OverridePresetCollectionViewCell.swift +++ /dev/null @@ -1,192 +0,0 @@ -// -// OverridePresetCollectionViewCell.swift -// Loop -// -// Created by Michael Pangburn on 1/2/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit - - -protocol OverridePresetCollectionViewCellDelegate: AnyObject { - func overridePresetCollectionViewCellDidScheduleOverride(_ cell: OverridePresetCollectionViewCell) - func overridePresetCollectionViewCellDidPerformFirstDeletionStep(_ cell: OverridePresetCollectionViewCell) - func overridePresetCollectionViewCellDidDeletePreset(_ cell: OverridePresetCollectionViewCell) -} - -final class OverridePresetCollectionViewCell: UICollectionViewCell, IdentifiableClass { - @IBOutlet weak var symbolLabel: UILabel! - - @IBOutlet weak var startTimeLabel: UILabel! { - didSet { - startTimeLabel.text?.removeAll() - } - } - - @IBOutlet weak var nameLabel: UILabel! - - @IBOutlet weak var targetRangeLabel: UILabel! { - didSet { - targetRangeLabel.text?.removeAll() - } - } - - @IBOutlet weak var insulinNeedsBar: SegmentedGaugeBarView! { - didSet { - insulinNeedsBar.backgroundColor = .systemGray6 - - insulinNeedsBar.isUserInteractionEnabled = false - } - } - - @IBOutlet private weak var durationStackView: UIStackView! - @IBOutlet weak var durationLabel: UILabel! - - @IBOutlet weak var scheduleButton: UIButton! - - @IBOutlet private weak var editingIndicator: UIImageView! { - didSet { - editingIndicator.alpha = 0 - } - } - - @IBOutlet private weak var deleteButton: UIButton! { - didSet { - deleteButton.layer.cornerRadius = 4 - } - } - - @IBOutlet private weak var deleteButtonWidthConstraint: NSLayoutConstraint! { - didSet { - deleteButtonWidthConstraint.constant = 0 - } - } - - weak var delegate: OverridePresetCollectionViewCellDelegate? - - private lazy var overlayDimmerView: UIView = { - let view = UIView() - view.backgroundColor = .systemBackground - view.alpha = 0 - view.translatesAutoresizingMaskIntoConstraints = false - return view - }() - - override func awakeFromNib() { - super.awakeFromNib() - - let selectedBackgroundView = UIView() - self.selectedBackgroundView = selectedBackgroundView - - selectedBackgroundView.backgroundColor = .tertiarySystemFill - - backgroundColor = .secondarySystemGroupedBackground - layer.cornerCurve = .continuous - - layer.cornerRadius = 16 - - scheduleButton.addTarget(self, action: #selector(scheduleButtonTapped), for: .touchUpInside) - addSubview(overlayDimmerView) - NSLayoutConstraint.activate([ - overlayDimmerView.leadingAnchor.constraint(equalTo: leadingAnchor), - overlayDimmerView.trailingAnchor.constraint(equalTo: trailingAnchor), - overlayDimmerView.topAnchor.constraint(equalTo: topAnchor), - overlayDimmerView.bottomAnchor.constraint(equalTo: bottomAnchor) - ]) - } - - override func prepareForReuse() { - startTimeLabel.text?.removeAll() - targetRangeLabel.isHidden = false - insulinNeedsBar.isHidden = false - configureForStandard(animated: false) - removeOverlay(animated: false) - } - - func configureForEditing(animated: Bool) { - func makeVisualChanges() { - durationStackView.alpha = 0 - scheduleButton.alpha = 0 - editingIndicator.alpha = 1 - deleteButtonWidthConstraint.constant = 32 - deleteButton.setImage(UIImage(systemName: "xmark")!, for: .normal) - deleteButton.setTitle(nil, for: .normal) - } - - if animated { - UIView.animate(withDuration: 0.3, animations: { - makeVisualChanges() - self.layoutIfNeeded() - }) - } else { - makeVisualChanges() - } - - isShowingFinalDeleteConfirmation = false - } - - func configureForStandard(animated: Bool) { - func makeVisualChanges() { - durationStackView.alpha = 1 - scheduleButton.alpha = 1 - editingIndicator.alpha = 0 - deleteButtonWidthConstraint.constant = 0 - deleteButton.setImage(UIImage(systemName: "xmark")!, for: .normal) - deleteButton.setTitle(nil, for: .normal) - } - - if animated { - UIView.animate(withDuration: 0.3, animations: { - makeVisualChanges() - self.layoutIfNeeded() - }) - } else { - makeVisualChanges() - } - - isShowingFinalDeleteConfirmation = false - } - - func applyOverlayToFade(animated: Bool) { - if animated { - UIView.animate(withDuration: 0.3, animations: { - self.overlayDimmerView.alpha = 0.5 - }) - } else { - self.overlayDimmerView.alpha = 0.5 - } - } - - func removeOverlay(animated: Bool) { - if animated { - UIView.animate(withDuration: 0.3, animations: { - self.overlayDimmerView.alpha = 0 - }) - } else { - self.overlayDimmerView.alpha = 0 - } - } - - @objc private func scheduleButtonTapped() { - delegate?.overridePresetCollectionViewCellDidScheduleOverride(self) - } - - private(set) var isShowingFinalDeleteConfirmation = false - - @IBAction private func deleteButtonTapped(_ sender: UIButton) { - if isShowingFinalDeleteConfirmation { - delegate?.overridePresetCollectionViewCellDidDeletePreset(self) - } else { - UIView.animate(withDuration: 0.3, animations: { - self.deleteButton.setImage(nil, for: .normal) - self.deleteButton.setTitle("Delete", for: .normal) - self.deleteButtonWidthConstraint.constant = 72 - self.layoutIfNeeded() - }) - - isShowingFinalDeleteConfirmation = true - delegate?.overridePresetCollectionViewCellDidPerformFirstDeletionStep(self) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/OverrideSelectionFooterView.swift b/Dependencies/LoopKit/LoopKitUI/Views/OverrideSelectionFooterView.swift deleted file mode 100644 index 506dba6cd..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/OverrideSelectionFooterView.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// OverrideSelectionFooterView.swift -// LoopKitUI -// -// Created by Michael Pangburn on 1/27/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit - - -final class OverrideSelectionFooterView: UICollectionReusableView, IdentifiableClass { - @IBOutlet weak var textLabel: UILabel! -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/OverrideSelectionHeaderView.swift b/Dependencies/LoopKit/LoopKitUI/Views/OverrideSelectionHeaderView.swift deleted file mode 100644 index 4cc89b0fb..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/OverrideSelectionHeaderView.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// OverrideSelectionHeaderView.swift -// LoopKitUI -// -// Created by Michael Pangburn on 1/27/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit - - -final class OverrideSelectionHeaderView: UICollectionReusableView, IdentifiableClass { - @IBOutlet weak var titleLabel: UILabel! -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/OverrideSelectionHistory.swift b/Dependencies/LoopKit/LoopKitUI/Views/OverrideSelectionHistory.swift deleted file mode 100644 index 0853ac2d0..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/OverrideSelectionHistory.swift +++ /dev/null @@ -1,166 +0,0 @@ -// -// OverrideSelectionHistory.swift -// LoopUI -// -// Created by Anna Quinlan on 8/1/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import HealthKit - -public class OverrideHistoryViewModel: ObservableObject { - var overrides: [TemporaryScheduleOverride] - var glucoseUnit: HKUnit - var didEditOverride: ((TemporaryScheduleOverride) -> Void)? - var didDeleteOverride: ((TemporaryScheduleOverride) -> Void)? - - public init( - overrides: [TemporaryScheduleOverride], - glucoseUnit: HKUnit - ) { - self.overrides = overrides - self.glucoseUnit = glucoseUnit - } -} - -public struct OverrideSelectionHistory: View { - @ObservedObject var model: OverrideHistoryViewModel - private var quantityFormatter: QuantityFormatter - private var glucoseNumberFormatter: NumberFormatter - private var durationFormatter: DateComponentsFormatter - - public init(model: OverrideHistoryViewModel) { - self.model = model - self.quantityFormatter = { - let quantityFormatter = QuantityFormatter() - quantityFormatter.setPreferredNumberFormatter(for: model.glucoseUnit) - return quantityFormatter - }() - self.glucoseNumberFormatter = quantityFormatter.numberFormatter - self.durationFormatter = { - let formatter = DateComponentsFormatter() - - formatter.allowedUnits = [.hour, .minute] - formatter.unitsStyle = .short - - return formatter - }() - } - - // Style conditionally based on iOS so we get a grouped list style - public var body: some View { - bodyContents - .insetGroupedListStyle() - } - - private var bodyContents: some View { - List { - ForEach(model.overrides, id: \.self) { override in - Group { - // Don't show overrides in history that were never active - if override.actualEnd != .deleted { - Section { - NavigationLink(destination: self.detailView(for: override)) { - self.createCell(for: override) - .padding(EdgeInsets(top: 4, leading: 0, bottom: 4, trailing: 0)) - } - } - } - } - } - } - .navigationBarTitle(Text(LocalizedString("Override History", comment: "Title for override history view")), displayMode: .large) - } - - private func makeTargetRangeText(from targetRange: ClosedRange) -> String { - guard - let minTarget = glucoseNumberFormatter.string(from: targetRange.lowerBound.doubleValue(for: model.glucoseUnit)), - let maxTarget = glucoseNumberFormatter.string(from: targetRange.upperBound.doubleValue(for: model.glucoseUnit)) - else { - return "" - } - - return String(format: LocalizedString("%1$@ – %2$@ %3$@", comment: "The format for a glucose target range. (1: min target)(2: max target)(3: glucose unit)"), minTarget, maxTarget, quantityFormatter.string(from: model.glucoseUnit)) - } - - private func createCell(for override: TemporaryScheduleOverride) -> OverrideViewCell { - let startTime = DateFormatter.localizedString(from: override.startDate, dateStyle: .none, timeStyle: .short) - - var targetRange: String = "" - if let range = override.settings.targetRange { - targetRange = makeTargetRangeText(from: range) - } - - var duration: String { - // Don't use the durationFormatter if the interval is infinite - if !override.duration.isFinite && override.scheduledEndDate == override.actualEndDate { - return "∞" - } - return durationFormatter.string(from: override.startDate, to: override.actualEndDate)! - } - - let insulinNeeds = override.settings.insulinNeedsScaleFactor - - switch override.context { - case .legacyWorkout: - return OverrideViewCell( - symbol: Text("🏃‍♂️"), - name: Text("Workout", comment: "Title for workout override history cell"), - targetRange: Text(targetRange), - duration: Text(duration), - subtitle: Text(startTime), - insulinNeedsScaleFactor: insulinNeeds) - case .preMeal: - return OverrideViewCell( - symbol: Text("🍽"), - name: Text("Pre-Meal", comment: "Title for pre-meal override history cell"), - targetRange: Text(targetRange), - duration: Text(duration), - subtitle: Text(startTime), - insulinNeedsScaleFactor: insulinNeeds) - case .preset(let preset): - return OverrideViewCell( - symbol: Text(preset.symbol), - name: Text(preset.name), - targetRange: Text(targetRange), - duration: Text(duration), - subtitle: Text(startTime), - insulinNeedsScaleFactor: insulinNeeds) - case .custom: - return OverrideViewCell( - symbol: Text("···"), - name: Text("Custom", comment: "Title for custom override history cell"), - targetRange: Text(targetRange), - duration: Text(duration), - subtitle: Text(startTime), - insulinNeedsScaleFactor: insulinNeeds) - } - } - - private func title(for override: TemporaryScheduleOverride) -> String { - switch override.context { - case .legacyWorkout: - return LocalizedString("🏃‍♂️ Workout", comment: "Workout override preset title") - case .preMeal: - return LocalizedString("🍽 Pre-Meal", comment: "Premeal override preset title") - case .preset(let preset): - let symbol = preset.symbol - let name = preset.name - let format = LocalizedString("%1$@ %2$@", comment: "The format for an override symbol and name (1: symbol)(2: name)") - return String(format: format, symbol, name) - case .custom: - return LocalizedString("Custom Override", comment: "Custom override preset title") - } - } - - private func detailView(for override: TemporaryScheduleOverride) -> some View { - let editorTitle = title(for: override) - return HistoricalOverrideDetailView( - override: override, - glucoseUnit: model.glucoseUnit, - delegate: nil - ).navigationBarTitle(editorTitle) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/OverrideViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/OverrideViewCell.swift deleted file mode 100644 index a6f8f9376..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/OverrideViewCell.swift +++ /dev/null @@ -1,88 +0,0 @@ -// -// OverrideViewCell.swift -// LoopKitUI -// -// Created by Anna Quinlan on 8/1/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct OverrideViewCell: View { - @Environment(\.lightenedInsulinTintColor) private var lightInsulin - @Environment(\.darkenedInsulinTintColor) private var darkInsulin - - static let symbolWidth: CGFloat = 40 - - var symbolLabel: Text - var nameLabel: Text - var targetRangeLabel: Text - var durationLabel: Text - var subtitleLabel: Text - var insulinNeedsScaleFactor: Double? - - public init( - symbol: Text, - name: Text, - targetRange: Text, - duration: Text, - subtitle: Text, - insulinNeedsScaleFactor: Double? - ) { - self.symbolLabel = symbol - self.nameLabel = name - self.targetRangeLabel = targetRange - self.durationLabel = duration - self.subtitleLabel = subtitle - self.insulinNeedsScaleFactor = insulinNeedsScaleFactor - } - - public var body: some View { - HStack { - symbolLabel - .font(.largeTitle) - .frame(width: Self.symbolWidth) // for alignment - VStack(alignment: .leading, spacing: 3) { - nameLabel - targetRangeLabel - .font(.caption) - .foregroundColor(Color.gray) - if self.insulinNeedsScaleFactor != nil { - insulinNeedsBar - } - } - Spacer() - VStack { - HStack(spacing: 4) { - timer - durationLabel - .font(.caption) - } - .foregroundColor(Color.gray) - subtitleLabel - .font(.caption) - } - } - .frame(minHeight: 53) - } - - private var insulinNeedsBar: some View { - GeometryReader { geo in - HStack { - Group { - if self.insulinNeedsScaleFactor != nil { - SegmentedGaugeBar(insulinNeedsScaler: self.insulinNeedsScaleFactor!, startColor: lightInsulin, endColor: darkInsulin) - .frame(minHeight: 12) - } - } - Spacer(minLength: geo.size.width * 0.35) // Hack to fix spacing - } - } - } - - var timer: some View { - Image(systemName: "timer") - .resizable() - .frame(width: 12.0, height: 12.0) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/PaddedTextField.swift b/Dependencies/LoopKit/LoopKitUI/Views/PaddedTextField.swift deleted file mode 100644 index 63920dfe2..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/PaddedTextField.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// PaddedTextField.swift -// LoopKitUI -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - -class PaddedTextField: UITextField { - - @IBInspectable var textInset: CGSize = .zero { - didSet { - setNeedsLayout() - invalidateIntrinsicContentSize() - } - } - - private var textInsets: UIEdgeInsets { - return UIEdgeInsets(top: textInset.height, left: textInset.width, bottom: textInset.height, right: textInset.width) - } - - override func editingRect(forBounds bounds: CGRect) -> CGRect { - return bounds.inset(by: textInsets) - } - - override func textRect(forBounds bounds: CGRect) -> CGRect { - return bounds.inset(by: textInsets) - } - - override func placeholderRect(forBounds bounds: CGRect) -> CGRect { - return bounds.inset(by: textInsets) - } - -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/PopoverLink.swift b/Dependencies/LoopKit/LoopKitUI/Views/PopoverLink.swift deleted file mode 100644 index 09f01be4f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/PopoverLink.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// PopoverLink.swift -// -// Created by Manuel Weiel on 09.07.20. -// -// From https://manuel.weiel.eu/bringing-the-simplicity-of-navigationlink-to-popovers/ - -import SwiftUI - -public struct PopoverLink : View where Label : View, Destination : View { - @Environment(\.horizontalSizeClass) var horizontalSizeClass - - private let destination: Destination - private let label: Label - private var isActive: Binding? - private var isFullScreen: Bool = false - @State private var internalIsActive = false - - public init(_ localizedText: Text, destination: Destination) where Label == Text { - self.init(destination: destination, label: { localizedText }) - } - - /// Creates an instance that presents `destination`. - public init(destination: Destination, @ViewBuilder label: () -> Label) { - self.destination = destination - self.label = label() - } - - /// Creates an instance that presents `destination` when active. - public init(destination: Destination, isActive: Binding, @ViewBuilder label: () -> Label) { - self.destination = destination - self.label = label() - self.isActive = isActive - } - - private init(_ other: PopoverLink, isFullScreen: Bool) { - self.destination = other.destination - self.isActive = other.isActive - self.label = other.label - self.isFullScreen = isFullScreen - } - - private func popoverButton() -> some View { - Button { - (isActive ?? _internalIsActive.projectedValue).wrappedValue = true - } label: { - label - } - } - - /// The content and behavior of the view. - public var body: some View { - if isFullScreen { - popoverButton().fullScreenCover(isPresented: (isActive ?? _internalIsActive.projectedValue)) { - destination - } - } else { - if horizontalSizeClass == .compact { - popoverButton().sheet(isPresented: (isActive ?? _internalIsActive.projectedValue)) { - destination - } - } else { - popoverButton().popover(isPresented: (isActive ?? _internalIsActive.projectedValue)) { - destination - } - } - } - } -} - -extension PopoverLink { - public func fullScreen() -> PopoverLink { - PopoverLink(self, isFullScreen: true) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ProgressIndicatorView.swift b/Dependencies/LoopKit/LoopKitUI/Views/ProgressIndicatorView.swift deleted file mode 100644 index 3ae7fb2fa..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ProgressIndicatorView.swift +++ /dev/null @@ -1,152 +0,0 @@ -// -// ProgressIndicatorView.swift -// DashKitUI -// -// Created by Pete Schwamb on 3/2/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import Combine - -public enum ProgressIndicatorState: Equatable { - case hidden - case indeterminantProgress - case timedProgress(finishTime: CFTimeInterval) - case completed -} - -extension ProgressIndicatorState { - - var showProgressBar: Bool { - if case .timedProgress = self { - return true - } - return false - } - - var showIndeterminantProgress: Bool { - if case .indeterminantProgress = self { - return true - } - return false - } - - var showCompletion: Bool { - if case .completed = self { - return true - } - return false - } -} - -public struct ProgressIndicatorView: View { - - private let state: ProgressIndicatorState - - private let fullSize: CGFloat = 35 - - // timed progress - private let timer: Publishers.Autoconnect - @State private var progress: Double = 0 - private let startTime: CFTimeInterval - private var finishTime: CFTimeInterval - - private var duration: TimeInterval { - return max(0, finishTime - startTime) - } - - public init(state: ProgressIndicatorState) { - startTime = CACurrentMediaTime() - self.state = state - timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() - - if case .timedProgress(let finishTime) = state { - self.finishTime = finishTime - } else { - timer.upstream.connect().cancel() - self.finishTime = startTime - } - } - - - - public var body: some View { - ZStack { - ActivityIndicator(isAnimating: .constant(true), style: .large) - .opacity(self.state.showIndeterminantProgress ? 1 : 0) - .frame(height: self.state.showIndeterminantProgress ? fullSize : 0) - - ZStack { - ProgressView(progress: self.state.showProgressBar ? 1 : 0) - .frame(height: fullSize) - .animation(.linear(duration: self.duration)) - } - .opacity(self.state.showProgressBar ? 1 : 0) - .frame(height: self.state.showProgressBar ? fullSize : 0) - - Image(frameworkImage: "Checkmark").foregroundColor(Color.accentColor) - .opacity(self.state.showCompletion ? 1 : 0) - .scaleEffect(self.state.showCompletion ? 1.0 : 0.001) - .animation(.spring(dampingFraction: 0.5)) - .frame(height: self.state.showCompletion ? fullSize : 0) - } - .accessibilityElement(children: .ignore) - .accessibility(label: Text(self.accessibilityLabel)) - .accessibility(hidden: self.state == .hidden) - .onReceive(timer) { time in - let elapsed = CACurrentMediaTime() - self.startTime - self.progress = min(1.0, elapsed / self.duration) - if self.progress >= 1.0 { - self.timer.upstream.connect().cancel() - } - } - } - - var accessibilityLabel: String { - switch self.state { - case .indeterminantProgress: - return LocalizedString("Progressing.", comment: "Accessibility label for ProgressIndicatorView when showIndeterminantProgress") - case .timedProgress: - return String(format: LocalizedString("%1$d percent complete.", comment: "Format string for progress accessibility label (1: duration in seconds)"), Int((self.progress * 100).rounded())) - case .completed: - return LocalizedString("Completed.", comment: "Accessibility label for ProgressIndicatorView when showIndeterminantProgress") - case .hidden: - return "" - } - } -} - -struct ProgressIndicatorView_Previews: PreviewProvider { - static var previews: some View { - ProgressPreviewWrapper() - } - -} - -struct ProgressPreviewWrapper: View { - @State var setupState: ProgressIndicatorState = .hidden - @State private var modeIndex: Int = 0 - - var body: some View { - VStack { - Rectangle().frame(height: 1) - ProgressIndicatorView(state: setupState) - Rectangle().frame(height: 1) - - Button(action: { - let finishTime = TimeInterval(10) - let modes: [ProgressIndicatorState] = [.indeterminantProgress, .timedProgress(finishTime: CACurrentMediaTime() + finishTime), .completed, .hidden] - - self.setupState = modes[self.modeIndex] - self.modeIndex = (self.modeIndex + 1) % modes.count - - }) { - Text("Switch Preview State") - } - Text(String(describing: self.setupState)).foregroundColor(Color.secondary).lineLimit(1) - } - .animation(.default) - .padding() - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ProgressView.swift b/Dependencies/LoopKit/LoopKitUI/Views/ProgressView.swift deleted file mode 100644 index 3ffda13ef..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ProgressView.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// ProgressView.swift -// DashKitUI -// -// Created by Pete Schwamb on 3/2/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -// TODO: SwiftUI now has built in ProgressView to replace this - -public struct ProgressView: View { - - private let progress: CGFloat - - private let barHeight: CGFloat = 8 - - public init(progress: CGFloat) { - self.progress = progress - } - - public var body: some View { - return GeometryReader { geometry in - ZStack(alignment: .leading) { - Rectangle() - .opacity(0.1) - .cornerRadius(self.barHeight/2) - .animation(nil) - Rectangle() - .foregroundColor(Color.accentColor) - .frame(width: geometry.size.width * self.progress) - .cornerRadius(self.barHeight/2) - - } - } - .frame(height: barHeight) - } -} - -struct ProgressTestView: View { - - @State var showDetail: Bool = false - @State var madeProgress: Bool = false - - var body: some View { - VStack { - - ProgressView(progress: madeProgress ? 0.9 : 0.5) - .animation(.linear(duration: 2)) - .padding() - .opacity(showDetail ? 1 : 0) - .animation(.linear(duration: 0.2)) - Button("Test") { - self.showDetail.toggle() - self.madeProgress.toggle() - } - } - .animation(.linear(duration: 0.2)) - } -} - - -struct ProgressView_Previews: PreviewProvider { - @State var showDetail: Bool = false - - static var previews: some View { - ProgressTestView() - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/QuantityPicker.swift b/Dependencies/LoopKit/LoopKitUI/Views/QuantityPicker.swift deleted file mode 100644 index ead44582b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/QuantityPicker.swift +++ /dev/null @@ -1,146 +0,0 @@ -// -// QuantityPicker.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/23/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - - -private struct PickerValueBoundsKey: PreferenceKey { - static let defaultValue: [Anchor] = [] - - static func reduce(value: inout [Anchor], nextValue: () -> [Anchor]) { - value.append(contentsOf: nextValue()) - } -} - -public struct QuantityPicker: View { - @Binding var value: HKQuantity - var unit: HKUnit - var isUnitLabelVisible: Bool - var colorForValue: (_ value: Double) -> Color - - private let selectableValues: [Double] - private let formatter: NumberFormatter - - private let unitLabelSpacing: CGFloat = -6 - - public init( - value: Binding, - unit: HKUnit, - stride: HKQuantity, - guardrail: Guardrail, - formatter: NumberFormatter? = nil, - isUnitLabelVisible: Bool = true, - guidanceColors: GuidanceColors = GuidanceColors() - ) { - let selectableValues = guardrail.allValues(stridingBy: stride, unit: unit) - self.init(value: value, - unit: unit, - guardrail: guardrail, - selectableValues: selectableValues, - formatter: formatter, - isUnitLabelVisible: isUnitLabelVisible, - guidanceColors: guidanceColors) - } - - public init( - value: Binding, - unit: HKUnit, - guardrail: Guardrail, - selectableValues: [Double], - formatter: NumberFormatter? = nil, - isUnitLabelVisible: Bool = true, - guidanceColors: GuidanceColors - ) { - self.init( - value: value, - unit: unit, - selectableValues: selectableValues.map { unit.roundForPicker(value: $0) }, - formatter: formatter, - isUnitLabelVisible: isUnitLabelVisible, - colorForValue: { value in - let quantity = HKQuantity(unit: unit, doubleValue: value) - return guardrail.color(for: quantity, guidanceColors: guidanceColors) - } - ) - } - - public init( - value: Binding, - unit: HKUnit, - selectableValues: [Double], - formatter: NumberFormatter? = nil, - isUnitLabelVisible: Bool = true, - colorForValue: @escaping (_ value: Double) -> Color = { _ in .primary } - ) { - self._value = value - self.unit = unit - self.selectableValues = selectableValues - self.formatter = formatter ?? { - let quantityFormatter = QuantityFormatter() - quantityFormatter.setPreferredNumberFormatter(for: unit) - return quantityFormatter.numberFormatter - }() - self.isUnitLabelVisible = isUnitLabelVisible - self.colorForValue = colorForValue - } - - private var selectedValue: Binding { - Binding( - get: { - unit.roundForPicker(value: value.doubleValue(for: unit)) - }, - set: { newValue in - self.value = HKQuantity(unit: unit, doubleValue: newValue) - } - ) - } - - public var body: some View { - picker - .labelsHidden() - .pickerStyle(.wheel) - .overlayPreferenceValue(PickerValueBoundsKey.self, unitLabel(positionedFrom:)) - .accessibility(identifier: "quantity_picker") - } - - @ViewBuilder - private var picker: some View { - // NOTE: iOS 15.1 introduced an issue where SwiftUI Pickers would not obey the `.clipped()` - // directive when it comes to touchable area. I have submitted a bug (Feedback) to Apple (FB9788944). - // This uses a custom Picker that works around the issue, but not perfectly (it isn't a 1 to 1 match). - // If they ever do fix this, consider restoring the code from the commit prior to this change. - // See LOOP-3870 for more details. - ResizeablePicker(selection: selectedValue, - data: selectableValues, - formatter: { self.formatter.string(from: $0) ?? "\($0)" }, - colorer: colorForValue) - .anchorPreference(key: PickerValueBoundsKey.self, value: .bounds, transform: { [$0] }) - } - - private func unitLabel(positionedFrom pickerValueBounds: [Anchor]) -> some View { - GeometryReader { geometry in - if self.isUnitLabelVisible && !pickerValueBounds.isEmpty { - Text(self.unit.shortLocalizedUnitString()) - .foregroundColor(.gray) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) - .offset(x: pickerValueBounds.union(in: geometry).maxX + unitLabelSpacing) - .animation(.default) - } - } - } -} - -extension Sequence where Element == Anchor { - func union(in geometry: GeometryProxy) -> CGRect { - lazy - .map { geometry[$0] } - .reduce(.null) { $0.union($1) } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/QuantityScheduleEditor.swift b/Dependencies/LoopKit/LoopKitUI/Views/QuantityScheduleEditor.swift deleted file mode 100644 index 9d0638449..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/QuantityScheduleEditor.swift +++ /dev/null @@ -1,227 +0,0 @@ -// -// QuantityScheduleEditor.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/24/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - - -struct QuantityScheduleEditor: View { - enum QuantitySelectionMode { - /// A single picker for selecting quantity values. - case whole - // A two-component picker for selecting the whole and fractional quantity values independently. - case fractional - } - - @Environment(\.guidanceColors) var guidanceColors - - var title: Text - var description: Text - var initialScheduleItems: [RepeatingScheduleValue] - @State var scheduleItems: [RepeatingScheduleValue] - var unit: HKUnit - var selectableValues: [Double] - var quantitySelectionMode: QuantitySelectionMode - var guardrail: Guardrail - var defaultFirstScheduleItemValue: HKQuantity - var scheduleItemLimit: Int - var confirmationAlertContent: AlertContent - var guardrailWarning: (_ crossedThresholds: [SafetyClassification.Threshold]) -> ActionAreaContent - var savingMechanism: SavingMechanism> - var mode: SettingsPresentationMode - var settingType: TherapySetting - - @State private var userDidTap: Bool = false - - var body: some View { - ScheduleEditor( - title: title, - description: description, - scheduleItems: $scheduleItems, - initialScheduleItems: initialScheduleItems, - defaultFirstScheduleItemValue: defaultFirstScheduleItemValue, - scheduleItemLimit: scheduleItemLimit, - saveConfirmation: saveConfirmation, - valueContent: { value, isEditing in - GuardrailConstrainedQuantityView( - value: value, - unit: unit, - guardrail: guardrail, - isEditing: isEditing - ) - }, - valuePicker: { item, availableWidth in - if quantitySelectionMode == .whole { - QuantityPicker( - value: item.value.animation(), - unit: unit, - guardrail: guardrail, - selectableValues: selectableValues, - guidanceColors: guidanceColors - ) - .frame(width: availableWidth / 2) - // Ensure overlaid unit label is not clipped - .padding(.trailing, unitLabelWidth + unitLabelSpacing) - .clipped() - .compositingGroup() - } else { - FractionalQuantityPicker( - value: item.value.animation(), - unit: unit, - guardrail: guardrail, - selectableValues: selectableValues, - usageContext: .component(availableWidth: availableWidth) - ) - } - }, - actionAreaContent: { - instructionalContentIfNecessary - guardrailWarningIfNecessary - }, - savingMechanism: savingMechanism.pullback { quantities in - DailyQuantitySchedule(unit: unit, dailyQuantities: quantities)! - }, - mode: mode, - therapySettingType: settingType - ) - .simultaneousGesture(TapGesture().onEnded { - withAnimation { - userDidTap = true - } - }) - } - - private var saveConfirmation: SaveConfirmation { - crossedThresholds.isEmpty ? .notRequired : .required(confirmationAlertContent) - } - - private var unitLabelWidth: CGFloat { - let attributedUnitString = NSAttributedString( - string: unit.shortLocalizedUnitString(), - attributes: [.font: UIFont.preferredFont(forTextStyle: .body)] - ) - return attributedUnitString.size().width - } - - private var unitLabelSpacing: CGFloat { 8 } - - private var instructionalContentIfNecessary: some View { - return Group { - if mode == .acceptanceFlow && !userDidTap { - instructionalContent - } - } - } - - private var instructionalContent: some View { - HStack { // to align with guardrail warning, if present - VStack (alignment: .leading, spacing: 20) { - Text(LocalizedString("You can edit a setting by tapping into any line item.", comment: "Description of how to edit setting")) - Text(LocalizedString("You can add entries for different times of day by using the ➕.", comment: "Description of how to add a range")) - } - .foregroundColor(.secondary) - .font(.subheadline) - Spacer() - } - } - - private var guardrailWarningIfNecessary: some View { - let crossedThresholds = self.crossedThresholds - return Group { - if !crossedThresholds.isEmpty && (userDidTap || mode == .settings) { - guardrailWarning(crossedThresholds) - } - } - } - - private var crossedThresholds: [SafetyClassification.Threshold] { - scheduleItems.lazy - .map { $0.value } - .compactMap { quantity in - switch guardrail.classification(for: quantity) { - case .withinRecommendedRange: - return nil - case .outsideRecommendedRange(let threshold): - return threshold - } - } - } -} - -// MARK: - Initializers - -extension QuantityScheduleEditor { - init( - title: Text, - description: Text, - schedule: DailyQuantitySchedule?, - unit: HKUnit, - selectableValues: [Double], - guardrail: Guardrail, - quantitySelectionMode: QuantitySelectionMode = .whole, - defaultFirstScheduleItemValue: HKQuantity, - scheduleItemLimit: Int = 48, - confirmationAlertContent: AlertContent, - @ViewBuilder guardrailWarning: @escaping (_ thresholds: [SafetyClassification.Threshold]) -> ActionAreaContent, - onSave savingMechanism: SavingMechanism>, - mode: SettingsPresentationMode = .settings, - settingType: TherapySetting = .none - ) { - self.title = title - self.description = description - self.initialScheduleItems = schedule?.quantities(using: unit) ?? [] - self._scheduleItems = State(initialValue: schedule?.quantities(using: unit) ?? []) - self.unit = unit - self.quantitySelectionMode = quantitySelectionMode - self.selectableValues = selectableValues - self.guardrail = guardrail - self.defaultFirstScheduleItemValue = defaultFirstScheduleItemValue - self.scheduleItemLimit = scheduleItemLimit - self.confirmationAlertContent = confirmationAlertContent - self.guardrailWarning = guardrailWarning - self.savingMechanism = savingMechanism - self.mode = mode - self.settingType = settingType - } - - init( - title: Text, - description: Text, - schedule: DailyQuantitySchedule?, - unit: HKUnit, - guardrail: Guardrail, - selectableValueStride: HKQuantity, - quantitySelectionMode: QuantitySelectionMode = .whole, - defaultFirstScheduleItemValue: HKQuantity, - scheduleItemLimit: Int = 48, - confirmationAlertContent: AlertContent, - @ViewBuilder guardrailWarning: @escaping (_ thresholds: [SafetyClassification.Threshold]) -> ActionAreaContent, - onSave save: @escaping (DailyQuantitySchedule) -> Void, - mode: SettingsPresentationMode = .settings, - settingType: TherapySetting = .none - ) { - let selectableValues = guardrail.allValues(stridingBy: selectableValueStride, unit: unit) - self.init( - title: title, - description: description, - schedule: schedule, - unit: unit, - selectableValues: selectableValues, - guardrail: guardrail, - quantitySelectionMode: quantitySelectionMode, - defaultFirstScheduleItemValue: defaultFirstScheduleItemValue, - scheduleItemLimit: scheduleItemLimit, - confirmationAlertContent: confirmationAlertContent, - guardrailWarning: guardrailWarning, - onSave: .synchronous(save), - mode: mode, - settingType: settingType - ) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/RepeatingScheduleValueTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/RepeatingScheduleValueTableViewCell.swift deleted file mode 100644 index 08fd1f4ff..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/RepeatingScheduleValueTableViewCell.swift +++ /dev/null @@ -1,114 +0,0 @@ -// -// RepeatingScheduleValueTableViewCell.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/6/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -protocol RepeatingScheduleValueTableViewCellDelegate: DatePickerTableViewCellDelegate { - func repeatingScheduleValueTableViewCellDidUpdateValue(_ cell: RepeatingScheduleValueTableViewCell) -} - - -class RepeatingScheduleValueTableViewCell: DatePickerTableViewCell, UITextFieldDelegate { - - weak var delegate: RepeatingScheduleValueTableViewCellDelegate? - - var timeZone: TimeZone! { - didSet { - dateFormatter.timeZone = timeZone - datePicker.timeZone = timeZone - } - } - - private lazy var dateFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .none - dateFormatter.timeStyle = .short - - return dateFormatter - }() - - override func updateDateLabel() { - dateLabel.text = dateFormatter.string(from: date) - } - - override func dateChanged(_ sender: UIDatePicker) { - super.dateChanged(sender) - - delegate?.datePickerTableViewCellDidUpdateDate(self) - } - - var value: Double = 0 { - didSet { - textField.text = valueNumberFormatter.string(from: value) - } - } - - var datePickerInterval: TimeInterval { - return TimeInterval(minutes: Double(datePicker.minuteInterval)) - } - - var isReadOnly = false { - didSet { - if isReadOnly, textField.isFirstResponder { - textField.resignFirstResponder() - } - } - } - - lazy var valueNumberFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.minimumFractionDigits = 1 - - return formatter - }() - - @IBOutlet weak var dateLabel: UILabel! - - @IBOutlet weak var unitLabel: UILabel! { - didSet { - // Setting this color in code because the nib isn't being applied correctly - unitLabel.textColor = .secondaryLabel - } - } - - @IBOutlet weak var textField: UITextField! { - didSet { - // Setting this color in code because the nib isn't being applied correctly - textField.textColor = .label - } - } - - var unitString: String? { - get { - return unitLabel.text - } - set { - unitLabel.text = newValue - } - } - - // MARK: - UITextFieldDelegate - - func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { - return !isReadOnly - } - - func textFieldDidBeginEditing(_ textField: UITextField) { - DispatchQueue.main.async { - textField.selectedTextRange = textField.textRange(from: textField.beginningOfDocument, to: textField.endOfDocument) - } - } - - func textFieldDidEndEditing(_ textField: UITextField) { - value = valueNumberFormatter.number(from: textField.text ?? "")?.doubleValue ?? 0 - - delegate?.repeatingScheduleValueTableViewCellDidUpdateValue(self) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/RepeatingScheduleValueTableViewCell.xib b/Dependencies/LoopKit/LoopKitUI/Views/RepeatingScheduleValueTableViewCell.xib deleted file mode 100644 index feb3d72ab..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/RepeatingScheduleValueTableViewCell.xib +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ReservoirVolumeHUDView.swift b/Dependencies/LoopKit/LoopKitUI/Views/ReservoirVolumeHUDView.swift deleted file mode 100644 index 52f8597e1..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ReservoirVolumeHUDView.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// ReservoirVolumeHUDView.swift -// Naterade -// -// Created by Nathan Racklyeft on 5/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - -public final class ReservoirVolumeHUDView: LevelHUDView, NibLoadable { - - override public var orderPriority: HUDViewOrderPriority { - return 4 - } - - @IBOutlet private weak var volumeLabel: UILabel! - - public class func instantiate() -> ReservoirVolumeHUDView { - return nib().instantiate(withOwner: nil, options: nil)[0] as! ReservoirVolumeHUDView - } - - override public func awakeFromNib() { - super.awakeFromNib() - - volumeLabel.isHidden = true - } - - override public func levelDidChange() { - super.levelDidChange() - - switch level { - case .none: - volumeLabel.isHidden = true - case let x? where x > 0.25: - volumeLabel.isHidden = true - case let x? where x > 0.10: - volumeLabel.textColor = tintColor - volumeLabel.isHidden = false - default: - volumeLabel.textColor = tintColor - volumeLabel.isHidden = false - } - } - - private lazy var timeFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .none - formatter.timeStyle = .short - - return formatter - }() - - private lazy var numberFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.maximumFractionDigits = 0 - - return formatter - }() - - public func setReservoirVolume(volume: Double, at date: Date) { - if let units = numberFormatter.string(from: volume) { - volumeLabel.text = String(format: LocalizedString("%@U", comment: "Format string for reservoir volume. (1: The localized volume)"), units) - let time = timeFormatter.string(from: date) - caption?.text = time - - accessibilityValue = String(format: LocalizedString("%1$@ units remaining at %2$@", comment: "Accessibility format string for (1: localized volume)(2: time)"), units, time) - } - } - - public override func tintColorDidChange() { - super.tintColorDidChange() - - volumeLabel.textColor = tintColor - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ReservoirVolumeHUDView.xib b/Dependencies/LoopKit/LoopKitUI/Views/ReservoirVolumeHUDView.xib deleted file mode 100644 index d2f7d1575..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ReservoirVolumeHUDView.xib +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ResizeablePicker.swift b/Dependencies/LoopKit/LoopKitUI/Views/ResizeablePicker.swift deleted file mode 100644 index 5d33aea08..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ResizeablePicker.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// ResizeablePicker.swift -// LoopKitUI -// -// Created by Rick Pasetto on 12/7/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import UIKit - -public struct ResizeablePicker: UIViewRepresentable where SelectionValue: CustomStringConvertible & Hashable { - private let selection: Binding - private var selectedRow: Int = 0 - // TODO: Would be nice if we could just use `ForEach` and Content, but for now, this'll do - private let data: [SelectionValue] - private let formatter: (SelectionValue) -> String - private let colorer: (SelectionValue) -> Color - - public init(selection: Binding, - data: [SelectionValue], - formatter: @escaping (SelectionValue) -> String = { $0.description }, - colorer: @escaping (SelectionValue) -> Color = { _ in .primary } - ) { - self.selection = selection - self.selectedRow = data.firstIndex(of: selection.wrappedValue) ?? 0 - self.data = data - self.formatter = formatter - self.colorer = colorer - } - - public func makeCoordinator() -> ResizeablePicker.Coordinator { - Coordinator(self) - } - - public func makeUIView(context: UIViewRepresentableContext) -> UIPickerView { - let picker = UIPickerViewResizeable(frame: .zero) - - picker.dataSource = context.coordinator - picker.delegate = context.coordinator - - return picker - } - - public func updateUIView(_ view: UIPickerView, context: UIViewRepresentableContext) { - context.coordinator.updateData(newData: data) - view.reloadAllComponents() - if view.selectedRow(inComponent: 0) != selectedRow { - view.selectRow(selectedRow, inComponent: 0, animated: false) - } - } - - public class Coordinator: NSObject, UIPickerViewDataSource, UIPickerViewDelegate { - private var picker: ResizeablePicker - private var data: [SelectionValue] - - init(_ pickerView: ResizeablePicker) { - self.picker = pickerView - self.data = pickerView.data - } - - func updateData(newData: [SelectionValue]) { - self.data = newData - } - - public func numberOfComponents(in pickerView: UIPickerView) -> Int { - 1 - } - - public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { - data.count - } - - public func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView { - let text = self.picker.formatter(data[row]) - let result = view as? UILabel ?? UILabel() - result.text = text - result.font = UIFont.preferredFont(forTextStyle: .title2) - result.textAlignment = .center - result.textColor = UIColor(picker.colorer(data[row])) - result.accessibilityHint = text - result.lineBreakMode = .byClipping - result.adjustsFontSizeToFitWidth = true - return result - } - - public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { - picker.selectedRow = row - picker.selection.wrappedValue = data[row] - } - } -} - -class UIPickerViewResizeable: UIPickerView { - - override var intrinsicContentSize: CGSize { - return CGSize(width: UIView.noIntrinsicMetric, height: super.intrinsicContentSize.height) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/RoundedCorners.swift b/Dependencies/LoopKit/LoopKitUI/Views/RoundedCorners.swift deleted file mode 100644 index af6af6390..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/RoundedCorners.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// RoundedCorners.swift -// LoopKitUI -// -// Created by Michael Pangburn on 5/7/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -extension View { - func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View { - clipShape(RoundedCorners(radius: radius, corners: corners)) - } -} - -struct RoundedCorners: Shape { - var radius: CGFloat - var corners: UIRectCorner = .allCorners - - func path(in rect: CGRect) -> Path { - let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) - return Path(path.cgPath) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ScheduleEditor.swift b/Dependencies/LoopKit/LoopKitUI/Views/ScheduleEditor.swift deleted file mode 100644 index f7a4e5e99..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ScheduleEditor.swift +++ /dev/null @@ -1,466 +0,0 @@ -// -// ScheduleEditor.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/24/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - -enum SavingMechanism { - case synchronous((_ value: Value) -> Void) - case asynchronous((_ value: Value, _ completion: @escaping (Error?) -> Void) -> Void) - - func pullback(_ transform: @escaping (NewValue) -> Value) -> SavingMechanism { - switch self { - case .synchronous(let save): - return .synchronous { newValue in save(transform(newValue)) } - case .asynchronous(let save): - return .asynchronous { newValue, completion in - save(transform(newValue), completion) - } - } - } -} - -enum SaveConfirmation { - case required(AlertContent) - case notRequired -} - -struct ScheduleEditor: View { - fileprivate enum PresentedAlert { - case saveConfirmation(AlertContent) - case saveError(Error) - } - - var title: Text - var description: Text - var initialScheduleItems: [RepeatingScheduleValue] - @Binding var scheduleItems: [RepeatingScheduleValue] - var defaultFirstScheduleItemValue: Value - var scheduleItemLimit: Int - var saveConfirmation: SaveConfirmation - var valueContent: (_ value: Value, _ isEditing: Bool) -> ValueContent - var valuePicker: (_ item: Binding>, _ availableWidth: CGFloat) -> ValuePicker - var actionAreaContent: ActionAreaContent - var savingMechanism: SavingMechanism<[RepeatingScheduleValue]> - var mode: SettingsPresentationMode - var therapySettingType: TherapySetting - - @State var editingIndex: Int? - - @State var isAddingNewItem = false { - didSet { - if isAddingNewItem { - editingIndex = nil - } - } - } - - @State var tableDeletionState: TableDeletionState = .disabled { - didSet { - if tableDeletionState == .enabled { - editingIndex = nil - } - } - } - - @State var isSyncing = false - - @State private var presentedAlert: PresentedAlert? - - @Environment(\.dismissAction) var dismiss - @Environment(\.authenticate) var authenticate - @Environment(\.presentationMode) var presentationMode - - init( - title: Text, - description: Text, - scheduleItems: Binding<[RepeatingScheduleValue]>, - initialScheduleItems: [RepeatingScheduleValue], - defaultFirstScheduleItemValue: Value, - scheduleItemLimit: Int = 48, - saveConfirmation: SaveConfirmation, - @ViewBuilder valueContent: @escaping (_ value: Value, _ isEditing: Bool) -> ValueContent, - @ViewBuilder valuePicker: @escaping (_ item: Binding>, _ availableWidth: CGFloat) -> ValuePicker, - @ViewBuilder actionAreaContent: () -> ActionAreaContent, - savingMechanism: SavingMechanism<[RepeatingScheduleValue]>, - mode: SettingsPresentationMode = .settings, - therapySettingType: TherapySetting = .none - ) { - self.title = title - self.description = description - self.initialScheduleItems = initialScheduleItems - self._scheduleItems = scheduleItems - self.defaultFirstScheduleItemValue = defaultFirstScheduleItemValue - self.scheduleItemLimit = scheduleItemLimit - self.saveConfirmation = saveConfirmation - self.valueContent = valueContent - self.valuePicker = valuePicker - self.actionAreaContent = actionAreaContent() - self.savingMechanism = savingMechanism - self.mode = mode - self.therapySettingType = therapySettingType - } - - var body: some View { - ZStack { - configurationPage - .disabled(isSyncing || isAddingNewItem) - .zIndex(0) - - if isAddingNewItem { - DarkenedOverlay() - .zIndex(1) - - NewScheduleItemEditor( - isPresented: $isAddingNewItem, - initialItem: initialNewScheduleItem, - selectableTimes: scheduleItems.isEmpty - ? .only(.hours(0)) - : .allExcept(Set(scheduleItems.map { $0.startTime })), - valuePicker: valuePicker, - onSave: { newItem in - self.scheduleItems.append(newItem) - self.scheduleItems.sort(by: { $0.startTime < $1.startTime }) - } - ) - .transition( - AnyTransition - .move(edge: .bottom) - .combined(with: .opacity) - ) - .zIndex(2) - } - } - } - - @ViewBuilder - private var configurationPage: some View { - switch mode { - case .acceptanceFlow: - page - .navigationBarBackButtonHidden(true) - .toolbar { - ToolbarItem(placement: .navigationBarLeading) { - backButton - } - ToolbarItem(placement: .navigationBarTrailing) { - trailingNavigationItems - } - } - case .settings: - page - .navigationBarBackButtonHidden(shouldAddCancelButton) - .toolbar { - ToolbarItem(placement: .navigationBarLeading) { - leadingNavigationBarItem - } - ToolbarItem(placement: .navigationBarTrailing) { - trailingNavigationItems - } - } - .navigationBarTitle("", displayMode: .inline) - } - } - - private var shouldAddCancelButton: Bool { - switch saveButtonState { - case .disabled, .loading: - return false - case .enabled: - return true - } - } - - @ViewBuilder - private var leadingNavigationBarItem: some View { - if shouldAddCancelButton { - cancelButton - } else { - EmptyView() - } - } - - private var page: some View { - ConfigurationPage( - title: title, - actionButtonTitle: Text(mode.buttonText(isSaving: isSyncing)), - actionButtonState: saveButtonState, - cards: { - Card { - SettingDescription(text: description, informationalContent: {self.therapySettingType.helpScreen()}) - Splat(Array(scheduleItems.enumerated()), id: \.element.startTime) { index, item in - self.itemView(for: item, at: index) - } - } - }, - actionAreaContent: { - actionAreaContent - }, - action: { - switch self.saveConfirmation { - case .required(let alertContent): - self.presentedAlert = .saveConfirmation(alertContent) - case .notRequired: - self.startSaving() - } - } - ) - .alert(item: $presentedAlert, content: alert(for:)) - } - - private var saveButtonState: ConfigurationPageActionButtonState { - if isSyncing { - return .loading - } - - let isEnabled = !scheduleItems.isEmpty - && (scheduleItems != initialScheduleItems || mode == .acceptanceFlow) - && tableDeletionState == .disabled - - return isEnabled ? .enabled : .disabled - } - - private func itemView(for item: RepeatingScheduleValue, at index: Int) -> some View { - Deletable( - tableDeletionState: $tableDeletionState, - index: index, - isDeletable: index != 0, - onDelete: { - withAnimation { - self.scheduleItems.remove(at: index) - - if self.scheduleItems.count == 1 { - self.tableDeletionState = .disabled - } - } - } - ) { - ScheduleItemView( - time: item.startTime, - isEditing: isEditing(index), - valueContent: { - valueContent(item.value, isEditing(index).wrappedValue) - }, - expandedContent: { - ScheduleItemPicker( - item: $scheduleItems[index], - isTimeSelectable: { self.isTimeSelectable($0, at: index) }, - valuePicker: { self.valuePicker(self.$scheduleItems[index], $0) } - ) - } - ) - } - .accessibility(identifier: "schedule_item_\(index)") - } - - private func isEditing(_ index: Int) -> Binding { - Binding( - get: { index == self.editingIndex }, - set: { isNowEditing in - self.editingIndex = isNowEditing ? index : nil - } - ) - } - - private func isTimeSelectable(_ time: TimeInterval, at index: Int) -> Bool { - if index == scheduleItems.startIndex { - return time == .hours(0) - } - - let priorTime = scheduleItems[index - 1].startTime - guard time > priorTime else { - return false - } - - if index < scheduleItems.endIndex - 1 { - let nextTime = scheduleItems[index + 1].startTime - guard time < nextTime else { - return false - } - } - - return true - } - - private var initialNewScheduleItem: RepeatingScheduleValue { - assert(scheduleItems.count <= scheduleItemLimit) - - if scheduleItems.isEmpty { - return RepeatingScheduleValue(startTime: .hours(0), value: defaultFirstScheduleItemValue) - } - - if scheduleItems.last!.startTime == .hours(23.5) { - let firstItemFollowedByOpening = scheduleItems.adjacentPairs().first(where: { item, next in - next.startTime - item.startTime > .minutes(30) - })!.0 - return RepeatingScheduleValue( - startTime: firstItemFollowedByOpening.startTime + .minutes(30), - value: firstItemFollowedByOpening.value - ) - } else { - return RepeatingScheduleValue( - startTime: scheduleItems.last!.startTime + .minutes(30), - value: scheduleItems.last!.value - ) - } - } - - private var trailingNavigationItems: some View { - // TODO: SwiftUI's alignment of these buttons in the navigation bar is a little funky. - // Tapping 'Edit' then 'Done' can shift '+' slightly. - HStack(spacing: 24) { - if tableDeletionState == .disabled { - editButton - } else { - doneButton - } - - addButton - } - } - - private var backButton: some View { - Button(action: { presentationMode.wrappedValue.dismiss() }) { - HStack { - Image(systemName: "chevron.left") - .resizable() - .frame(width: 12, height: 20) - Text(backButtonTitle) - .fontWeight(.regular) - } - .offset(x: -6, y: 0) - } - } - - private var backButtonTitle: String { LocalizedString("Back", comment: "Back navigation button title") } - - var cancelButton: some View { - Button(action: { self.dismiss() } ) { Text(LocalizedString("Cancel", comment: "Cancel editing settings button title")) } - } - - var editButton: some View { - Button( - action: { - withAnimation { - self.tableDeletionState = .enabled - } - }, - label: { - Text(LocalizedString("Edit", comment: "Text for edit button")) - } - ) - .disabled(scheduleItems.count == 1) - } - - var doneButton: some View { - Button( - action: { - withAnimation { - self.tableDeletionState = .disabled - } - }, - label: { - Text(LocalizedString("Done", comment: "Text for done button")).bold() - } - ) - } - - var addButton: some View { - Button( - action: { - withAnimation { - self.isAddingNewItem = true - } - }, - label: { - Image(systemName: "plus") - .imageScale(.large) - .contentShape(Rectangle()) - } - ) - .disabled(tableDeletionState != .disabled || scheduleItems.count >= scheduleItemLimit) - } - - private func startSaving() { - guard mode == .settings else { - self.continueSaving() - return - } - - authenticate(therapySettingType.authenticationChallengeDescription) { - switch $0 { - case .success: self.continueSaving() - case .failure: break - } - } - } - - private func continueSaving() { - - switch savingMechanism { - case .synchronous(let save): - save(scheduleItems) - case .asynchronous(let save): - withAnimation { - self.editingIndex = nil - self.isSyncing = true - } - - save(scheduleItems) { error in - DispatchQueue.main.async { - if let error = error { - withAnimation { - self.isSyncing = false - } - self.presentedAlert = .saveError(error) - } - } - } - } - } - - private func alert(for presentedAlert: PresentedAlert) -> SwiftUI.Alert { - switch presentedAlert { - case .saveConfirmation(let content): - return Alert( - title: content.title, - message: content.message, - primaryButton: .cancel(Text(LocalizedString("Go Back", comment: "Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range"))), - secondaryButton: .default( - Text(LocalizedString("Continue", comment: "Button text to confirm saving from alert popup when some schedule values are outside the recommended range")), - action: startSaving - ) - ) - case .saveError(let error): - return Alert( - title: Text(LocalizedString("Unable to Save", comment: "Alert title when error occurs while saving a schedule")), - message: Text(error.localizedDescription) - ) - } - } -} - -struct DarkenedOverlay: View { - var body: some View { - Rectangle() - .fill(Color.black.opacity(0.3)) - .edgesIgnoringSafeArea(.all) - } -} - -extension ScheduleEditor.PresentedAlert: Identifiable { - var id: Int { - switch self { - case .saveConfirmation: - return 0 - case .saveError: - return 1 - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ScheduleItemPicker.swift b/Dependencies/LoopKit/LoopKitUI/Views/ScheduleItemPicker.swift deleted file mode 100644 index 64a5aa8d5..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ScheduleItemPicker.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// ScheduleItemPicker.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/24/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - - -struct ScheduleItemPicker: View { - @Binding var item: RepeatingScheduleValue - var isTimeSelectable: (TimeInterval) -> Bool - var valuePicker: (_ availableWidth: CGFloat) -> ValuePicker - - init( - item: Binding>, - isTimeSelectable: @escaping (TimeInterval) -> Bool, - @ViewBuilder valuePicker: @escaping (_ availableWidth: CGFloat) -> ValuePicker - ) { - self._item = item - self.isTimeSelectable = isTimeSelectable - self.valuePicker = valuePicker - } - - var body: some View { - GeometryReader { geometry in - HStack { - Spacer() - HStack(spacing: 0) { - TimePicker( - offsetFromMidnight: self.$item.startTime, - bounds: 0...TimeInterval(hours: 23.5), - stride: .hours(0.5), - isTimeExcluded: { !self.isTimeSelectable($0) } - ) - .frame(width: geometry.size.width / 3) - .clipped() - .compositingGroup() - .accessibility(identifier: "time_picker") - - self.valuePicker(/* availableWidth: */ 2/3 * geometry.size.width) - } - Spacer() - } - } - .frame(height: 216) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ScheduleItemView.swift b/Dependencies/LoopKit/LoopKitUI/Views/ScheduleItemView.swift deleted file mode 100644 index 04f1c018f..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ScheduleItemView.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// ScheduleItemView.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/24/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -struct ScheduleItemView: View { - var time: TimeInterval - @Binding var isEditing: Bool - var valueContent: ValueContent - var expandedContent: ExpandedContent - - private let fixedMidnight = Calendar.current.startOfDay(for: Date(timeIntervalSinceReferenceDate: 0)) - - init( - time: TimeInterval, - isEditing: Binding, - @ViewBuilder valueContent: () -> ValueContent, - @ViewBuilder expandedContent: () -> ExpandedContent - ) { - self.time = time - self._isEditing = isEditing - self.valueContent = valueContent() - self.expandedContent = expandedContent() - } - - var body: some View { - ExpandableSetting( - isEditing: $isEditing, - leadingValueContent: { timeText }, - trailingValueContent: { valueContent }, - expandedContent: { self.expandedContent } - ) - } - - private var timeText: Text { - let dayAtTime = fixedMidnight.addingTimeInterval(time) - return Text(DateFormatter.localizedString(from: dayAtTime, dateStyle: .none, timeStyle: .short)) - .foregroundColor(isEditing ? .accentColor : Color(.label)) - } -} - -extension AnyTransition { - static let fadeInFromTop = move(edge: .top).combined(with: .opacity) - .delayingInsertion(by: 0.1) - .speedingUpRemoval(by: 1.8) - - func delayingInsertion(by delay: TimeInterval) -> AnyTransition { - .asymmetric(insertion: animation(Animation.default.delay(delay)), removal: self) - } - - func speedingUpRemoval(by factor: Double) -> AnyTransition { - .asymmetric(insertion: self, removal: animation(Animation.default.speed(factor))) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SectionHeader.swift b/Dependencies/LoopKit/LoopKitUI/Views/SectionHeader.swift deleted file mode 100644 index a2869fd4e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SectionHeader.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// SectionHeader.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-02-20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct SectionHeader: View { - var label: String - var style: Style - - public enum Style { - case regular - case tight - } - - public init(label: String, style: Style = .default) { - self.label = label - self.style = style - } - - public var body: some View { - // iOS 14 puts section headers in all-caps by default. This un-does that. - content.textCase(nil) - } - - @ViewBuilder private var content: some View { - Text(label) - .font(.headline) - .foregroundColor(.primary) - .padding(.leading, style == .tight ? -10 : 0) - } -} - -fileprivate struct HorizontalSizeClassOverrideHelper: HorizontalSizeClassOverride {} -public extension SectionHeader.Style { - - static let `default`: SectionHeader.Style = { - return .regular - }() -} - -struct SectionHeader_Previews: PreviewProvider { - static var previews: some View { - SectionHeader(label: "Header Label") - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SegmentedControlTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/SegmentedControlTableViewCell.swift deleted file mode 100644 index 4b3718b20..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SegmentedControlTableViewCell.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// SegmentedControlTableViewCell.swift -// LoopKitUI -// -// Created by Michael Pangburn on 7/14/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import UIKit - - -open class SegmentedControlTableViewCell: UITableViewCell { - public var segmentedControl = UISegmentedControl(frame: .zero) - - public var options: [String] = [] { - didSet { - segmentedControl.removeAllSegments() - for (index, option) in options.enumerated() { - segmentedControl.insertSegment(withTitle: option, at: index, animated: false) - } - } - } - - private var select: (_ index: Int) -> Void = { _ in } - - public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: .value1, reuseIdentifier: Self.className) - - setUp() - } - - required public init?(coder: NSCoder) { - super.init(coder: coder) - - setUp() - } - - private func setUp() { - contentView.addSubview(segmentedControl) - segmentedControl.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - segmentedControl.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor), - segmentedControl.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - segmentedControl.leadingAnchor.constraint(equalTo: textLabel?.trailingAnchor ?? contentView.leadingAnchor) - ]) - } - - override open func layoutSubviews() { - super.layoutSubviews() - - contentView.layoutMargins.left = separatorInset.left - contentView.layoutMargins.right = separatorInset.left - } - - override open func prepareForReuse() { - super.prepareForReuse() - - segmentedControl.removeTarget(nil, action: nil, for: .valueChanged) - select = { _ in } - } - - public func onSelection(_ select: @escaping (_ index: Int) -> Void) { - self.select = select - segmentedControl.addTarget(self, action: #selector(handleSelection), for: .valueChanged) - } - - @objc private func handleSelection() { - select(segmentedControl.selectedSegmentIndex) - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SegmentedGaugeBar.swift b/Dependencies/LoopKit/LoopKitUI/Views/SegmentedGaugeBar.swift deleted file mode 100644 index 4d1a9847e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SegmentedGaugeBar.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// SegmentedGaugeBar.swift -// LoopKitUI -// -// Created by Anna Quinlan on 11/7/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -struct SegmentedGaugeBar: UIViewRepresentable { - let insulinNeedsScaler: Double - let startColor: UIColor - let endColor: UIColor - - init(insulinNeedsScaler: Double, startColor: UIColor, endColor: UIColor) { - self.insulinNeedsScaler = insulinNeedsScaler - self.startColor = startColor - self.endColor = endColor - } - - func makeUIView(context: Context) -> SegmentedGaugeBarView { - let view = SegmentedGaugeBarView() - view.numberOfSegments = 2 - view.startColor = startColor - view.endColor = endColor - view.borderWidth = 1 - view.borderColor = .systemGray - view.progress = insulinNeedsScaler - view.isUserInteractionEnabled = false // Don't allow slider to change value based on user taps - return view - } - - func updateUIView(_ view: SegmentedGaugeBarView, context: Context) { } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SegmentedGaugeBarLayer.swift b/Dependencies/LoopKit/LoopKitUI/Views/SegmentedGaugeBarLayer.swift deleted file mode 100644 index 0201ebd7a..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SegmentedGaugeBarLayer.swift +++ /dev/null @@ -1,214 +0,0 @@ -// -// SegmentedGaugeBarLayer.swift -// LoopKitUI -// -// Created by Michael Pangburn on 3/22/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit - - -class SegmentedGaugeBarLayer: CALayer { - - var numberOfSegments = 1 { - didSet { - setNeedsDisplay() - } - } - - var startColor = UIColor.white.cgColor { - didSet { - setNeedsDisplay() - } - } - - var endColor = UIColor.black.cgColor { - didSet { - setNeedsDisplay() - } - } - - var gaugeBorderWidth: CGFloat = 0 { - didSet { - setNeedsDisplay() - } - } - - var gaugeBorderColor = UIColor.black.cgColor { - didSet { - setNeedsDisplay() - } - } - - @NSManaged var progress: CGFloat - - override class func needsDisplay(forKey key: String) -> Bool { - return key == #keyPath(SegmentedGaugeBarLayer.progress) - || super.needsDisplay(forKey: key) - } - - override func action(forKey event: String) -> CAAction? { - if event == #keyPath(progress) { - let animation = CABasicAnimation(keyPath: event) - animation.fromValue = presentation()?.progress - return animation - } else { - return super.action(forKey: event) - } - } - - override func display() { - contents = contentImage() - } - - private func contentImage() -> CGImage? { - let renderer = UIGraphicsImageRenderer(size: bounds.size) - let uiImage = renderer.image { context in - drawGauge(in: context.cgContext) - } - return uiImage.cgImage - } - - private func drawGauge(in context: CGContext) { - var previousSegmentBorder: (path: UIBezierPath, color: CGColor)? - - func finishPreviousSegment() { - if let (borderPath, borderColor) = previousSegmentBorder { - drawBorder(borderPath, color: borderColor, in: context) - } - } - - let segmentCounts = 1...numberOfSegments - for countFromRight in segmentCounts { - let isRightmostSegment = countFromRight == segmentCounts.lowerBound - let isLeftmostSegment = countFromRight == segmentCounts.upperBound - - let fillFraction = (presentationProgress - CGFloat(numberOfSegments - countFromRight)).clamped(to: 0...1) - - let (segmentSize, roundedCorners): (CGSize, UIRectCorner) = { - if isLeftmostSegment { - return (leftmostSegmentSize, .allCorners) - } else { - return (normalSegmentSize, [.topRight, .bottomRight]) - } - }() - - var originX = bounds.width - gaugeBorderWidth / 2 - CGFloat(countFromRight) * leftmostSegmentSize.width - if !isLeftmostSegment { - originX -= segmentOverlap - } - let segmentOrigin = CGPoint(x: originX, y: bounds.minY + gaugeBorderWidth / 2) - let segmentRect = CGRect(origin: segmentOrigin, size: segmentSize) - - if !isRightmostSegment { - drawOverlapInset(for: segmentRect, in: context) - finishPreviousSegment() - } - - let borderPath = UIBezierPath(roundedRect: segmentRect, byRoundingCorners: roundedCorners, cornerRadii: CGSize(width: cornerRadius, height: cornerRadius)) - let borderColor = fillFraction > 0 - ? gaugeBorderColor - : UIColor(cgColor: gaugeBorderColor).withAlphaComponent(0.5).cgColor - - clearSegmentArea(tracedBy: borderPath, in: context) - previousSegmentBorder = (path: borderPath, color: borderColor) - - guard fillFraction > 0 else { - continue - } - - var segmentFillRect = CGRect(origin: segmentOrigin, size: leftmostSegmentSize).insetBy(dx: fillInset, dy: fillInset) - segmentFillRect.size.width *= fillFraction - if !isLeftmostSegment { - segmentFillRect.size.width += segmentOverlap - } - - drawFilledGradient(over: segmentFillRect, roundingCorners: roundedCorners, in: context) - } - - finishPreviousSegment() - } - - private var fillInset: CGFloat { - return 1.5 * gaugeBorderWidth - } - - private var segmentOverlap: CGFloat { - return cornerRadius - } - - private var presentationProgress: CGFloat { - return presentation()?.progress ?? self.progress - } - - private var leftmostSegmentSize: CGSize { - return CGSize( - width: (bounds.width - gaugeBorderWidth) / CGFloat(numberOfSegments), - height: bounds.height - gaugeBorderWidth - ) - } - - private var normalSegmentSize: CGSize { - return CGSize( - width: leftmostSegmentSize.width + segmentOverlap, - height: leftmostSegmentSize.height - ) - } - - private func clearSegmentArea(tracedBy path: UIBezierPath, in context: CGContext) { - context.addPath(path.cgPath) - context.setFillColor(backgroundColor ?? UIColor.white.cgColor) - context.fillPath() - } - - private func drawFilledGradient(over rect: CGRect, roundingCorners roundedCorners: UIRectCorner, in context: CGContext) { - context.saveGState() - defer { context.restoreGState() } - - let path = UIBezierPath(roundedRect: rect, byRoundingCorners: roundedCorners, cornerRadii: CGSize(width: cornerRadius, height: cornerRadius)) - context.addPath(path.cgPath) - context.clip() - - let pathBounds = path.bounds - let gradient = CGGradient( - colorsSpace: CGColorSpaceCreateDeviceRGB(), - colors: [gradientColor(atX: pathBounds.minX), - gradientColor(atX: pathBounds.maxX)] as CFArray, - locations: [0, 1] - )! - - context.drawLinearGradient( - gradient, - start: CGPoint(x: pathBounds.minX, y: pathBounds.midY), - end: CGPoint(x: pathBounds.maxX, y: pathBounds.midY), - options: [] - ) - } - - private func drawOverlapInset(for segmentRect: CGRect, in context: CGContext) { - var overlapInsetRect = segmentRect - overlapInsetRect.size.width += gaugeBorderWidth - let path = UIBezierPath(roundedRect: overlapInsetRect, cornerRadius: cornerRadius) - context.setStrokeColor(backgroundColor ?? UIColor.white.cgColor) - context.setLineWidth(gaugeBorderWidth) - context.setFillColor(backgroundColor ?? UIColor.white.cgColor) - context.addPath(path.cgPath) - context.drawPath(using: .fillStroke) - } - - private func drawBorder(_ path: UIBezierPath, color: CGColor, in context: CGContext) { - context.addPath(path.cgPath) - context.setLineWidth(gaugeBorderWidth) - context.setStrokeColor(color) - context.strokePath() - } - - private func gradientColor(atX x: CGFloat) -> CGColor { - return UIColor.interpolatingBetween( - UIColor(cgColor: startColor), - UIColor(cgColor: endColor), - biasTowardSecondColor: fractionThrough(x, in: bounds.minX...bounds.maxX) - ).cgColor - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SegmentedGaugeBarView.swift b/Dependencies/LoopKit/LoopKitUI/Views/SegmentedGaugeBarView.swift deleted file mode 100644 index bb60107e9..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SegmentedGaugeBarView.swift +++ /dev/null @@ -1,220 +0,0 @@ -// -// SegmentedGaugeBarView.swift -// LoopKitUI -// -// Created by Michael Pangburn on 3/22/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit - - -public protocol SegmentedGaugeBarViewDelegate: AnyObject { - /// Invoked only when `progress` is updated via gesture. - func segmentedGaugeBarView(_ view: SegmentedGaugeBarView, didUpdateProgressFrom oldValue: Double, to newValue: Double) -} - -@IBDesignable -public class SegmentedGaugeBarView: UIView { - @IBInspectable - public var numberOfSegments: Int { - get { - return gaugeLayer.numberOfSegments - } - set { - gaugeLayer.numberOfSegments = newValue - } - } - - @IBInspectable - public var startColor: UIColor { - get { - return UIColor(cgColor: gaugeLayer.startColor) - } - set { - gaugeLayer.startColor = newValue.cgColor - } - } - - @IBInspectable - public var endColor: UIColor { - get { - return UIColor(cgColor: gaugeLayer.endColor) - } - set { - gaugeLayer.endColor = newValue.cgColor - } - } - - @IBInspectable - public var borderWidth: CGFloat { - get { - return gaugeLayer.gaugeBorderWidth - } - set { - gaugeLayer.gaugeBorderWidth = newValue - } - } - - @IBInspectable - public var borderColor: UIColor { - get { - return UIColor(cgColor: gaugeLayer.gaugeBorderColor) - } - set { - gaugeLayer.gaugeBorderColor = newValue.cgColor - } - } - - @IBInspectable - public var progress: Double { - get { - if displaysThumb { - return Double(fractionThrough(thumb.center.x, in: thumbCenterXRange)) - } else { - return visualProgress - } - } - set { - if displaysThumb { - thumb.center.x = interpolatedValue(at: CGFloat(newValue), through: thumbCenterXRange).clamped(to: thumbCenterXRange) - // Push the gauge progress behind the thumb, ensuring the cap rounding is not visible. - let gaugeX = thumb.center.x + 0.25 * thumb.frame.width - visualProgress = newValue == 0 ? 0 : Double(fractionThrough(gaugeX, in: gaugeXRange)) - } else { - visualProgress = newValue - } - } - } - - private var visualProgress: Double { - get { Double(gaugeLayer.progress) } - set { gaugeLayer.progress = CGFloat(newValue) } - } - - public weak var delegate: SegmentedGaugeBarViewDelegate? - - override public class var layerClass: AnyClass { - return SegmentedGaugeBarLayer.self - } - - private var gaugeLayer: SegmentedGaugeBarLayer { - return layer as! SegmentedGaugeBarLayer - } - - override public init(frame: CGRect) { - super.init(frame: frame) - setupPanGestureRecognizer() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - setupPanGestureRecognizer() - } - - private lazy var thumb = ThumbView() - - public var displaysThumb = false { - didSet { - if displaysThumb { - assert(numberOfSegments == 1, "Thumb only supported for single-segment gauges") - if thumb.superview == nil { - addSubview(thumb) - } - } else { - thumb.removeFromSuperview() - } - } - } - - private var panGestureRecognizer: UIPanGestureRecognizer? - - private func setupPanGestureRecognizer() { - let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:))) - panGestureRecognizer = pan - addGestureRecognizer(pan) - } - - @objc private func handlePan(_ recognizer: UIPanGestureRecognizer) { - switch recognizer.state { - case .began, .changed: - guard recognizer.numberOfTouches == 1 else { - break - } - - let location = recognizer.location(ofTouch: 0, in: self) - let gaugeFillFraction = fractionThrough(location.x, in: gaugeXRange) - let oldValue = progress - let newValue = (Double(gaugeFillFraction) * Double(numberOfSegments)).clamped(to: 0...Double(numberOfSegments)) - CATransaction.withoutActions { - progress = newValue - } - - delegate?.segmentedGaugeBarView(self, didUpdateProgressFrom: oldValue, to: newValue) - case .ended: - uglyWorkaroundToForceRedraw() - default: - break - } - } - - private func uglyWorkaroundToForceRedraw() { - // Resolves an issue--most of the time--where dragging _very_ rapidly then releasing - // can cause the gauge layer to fall behind a cycle in rendering. - // - `setNeedsDisplay()` is insufficient. - // - Adding additional executions (delay times) catches the issue with a greater probability, - // with diminishing returns after four executions (by observation). - for (index, delayMS) in [10, 25, 50, 100].enumerated() { - DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(delayMS)) { - CATransaction.withoutActions { - self.progress = index % 2 == 0 ? self.progress.nextUp : self.progress.nextDown - } - } - } - } - - override public func layoutSubviews() { - super.layoutSubviews() - layer.cornerRadius = frame.height / 2 - - updateThumbPosition() - } - - private var gaugeXRange: ClosedRange { - (bounds.minX + 2 * borderWidth)...(bounds.maxX - 2 * borderWidth) - } - - private var thumbCenterXRange: ClosedRange { - let radius = thumb.bounds.width / 2 - return (gaugeXRange.lowerBound + radius)...(gaugeXRange.upperBound - radius) - } - - private func updateThumbPosition() { - guard displaysThumb else { - return - } - - let diameter = bounds.height - 2 * borderWidth - thumb.bounds.size = CGSize(width: diameter, height: diameter) - let xPosition = interpolatedValue(at: CGFloat(progress), through: thumbCenterXRange) - thumb.center = CGPoint(x: xPosition, y: bounds.midY) - } - - public func cancelActiveTouches() { - guard panGestureRecognizer?.isEnabled == true else { - return - } - - panGestureRecognizer?.isEnabled = false - panGestureRecognizer?.isEnabled = true - } -} - -fileprivate extension CATransaction { - static func withoutActions(_ execute: () -> Void) { - begin() - setValue(true, forKey: kCATransactionDisableActions) - execute() - commit() - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SelectableLabel.swift b/Dependencies/LoopKit/LoopKitUI/Views/SelectableLabel.swift deleted file mode 100644 index ed5513b8a..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SelectableLabel.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// SelectableLabel.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-02-20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct SelectableLabel: View { - var label: String - @Binding var selectedLabel: String? - - public init(label: String, selectedLabel: Binding) { - self.label = label - _selectedLabel = selectedLabel - } - - public var body: some View { - Button(action: { self.selectedLabel = self.label }) { - HStack { - Text(label) - .foregroundColor(.primary) - Spacer() - if selectedLabel == label { - Image(systemName: "checkmark.circle.fill") - .foregroundColor(.accentColor) - } - } - } - } -} - -struct SelectableLabel_Previews: PreviewProvider { - static var previews: some View { - return SelectableLabel(label: "Test", selectedLabel: .constant("Test")) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SetConstrainedScheduleEntryTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/SetConstrainedScheduleEntryTableViewCell.swift deleted file mode 100644 index 350ef4e80..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SetConstrainedScheduleEntryTableViewCell.swift +++ /dev/null @@ -1,318 +0,0 @@ -// -// SetConstrainedScheduleEntryTableViewCell.swift -// LoopKitUI -// -// Created by Pete Schwamb on 2/23/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit -import LoopKit -import UIKit - -protocol SetConstrainedScheduleEntryTableViewCellDelegate: AnyObject { - func setConstrainedScheduleEntryTableViewCellDidUpdate(_ cell: SetConstrainedScheduleEntryTableViewCell) -} - -private enum Component: Int, CaseIterable { - case time = 0 - case value -} - -class SetConstrainedScheduleEntryTableViewCell: UITableViewCell { - - public enum EmptySelectionType { - case none - case firstIndex - case lastIndex - - var rowCount: Int { - if self == .none { - return 0 - } else { - return 1 - } - } - - var rowOffset: Int { - if self == .firstIndex { - return 1 - } else { - return 0 - } - } - } - - @IBOutlet private weak var picker: UIPickerView! - - @IBOutlet private weak var pickerHeightConstraint: NSLayoutConstraint! - - private var pickerExpandedHeight: CGFloat = 0 - - @IBOutlet private weak var dateLabel: UILabel! - - @IBOutlet private weak var valueLabel: UILabel! - - public weak var delegate: SetConstrainedScheduleEntryTableViewCellDelegate? - - public var allowedValues: [Double] = [] { - didSet { - picker.reloadAllComponents() - updateValuePicker() - } - } - - public var emptySelectionType = EmptySelectionType.none { - didSet { - picker.reloadAllComponents() - updateValuePicker() - } - } - - public var unit: HKUnit? { - didSet { - if let unit = unit { - valueQuantityFormatter.setPreferredNumberFormatter(for: unit) - picker.reloadAllComponents() - updateValuePicker() - } - } - } - - public var minimumTimeInterval: TimeInterval = .hours(0.5) - - public var minimumStartTime: TimeInterval = .hours(0) { - didSet { - picker.reloadComponent(Component.time.rawValue) - updateStartTimeSelection() - } - } - public var maximumStartTime: TimeInterval = .hours(23.5) { - didSet { - picker.reloadComponent(Component.time.rawValue) - } - } - - public var timeZone: TimeZone! { - didSet { - dateFormatter.timeZone = timeZone - var calendar = Calendar.current - calendar.timeZone = timeZone - startOfDay = calendar.startOfDay(for: Date()) - } - } - - private lazy var startOfDay = Calendar.current.startOfDay(for: Date()) - - var startTime: TimeInterval = 0 { - didSet { - updateStartTimeSelection() - updateDateLabel() - } - } - - var selectedStartTime: TimeInterval { - let row = picker.selectedRow(inComponent: Component.time.rawValue) - return startTimeForTimeComponent(row: row) - } - - var value: Double? = nil { - didSet { - updateValuePicker() - updateValueLabel() - } - } - - var isPickerHidden: Bool { - get { - return picker.isHidden - } - set { - picker.isHidden = newValue - pickerHeightConstraint.constant = newValue ? 0 : pickerExpandedHeight - - if !newValue { - updateValuePicker() - updateStartTimeSelection() - } - } - } - - var isReadOnly = false - - override func awakeFromNib() { - super.awakeFromNib() - - pickerExpandedHeight = pickerHeightConstraint.constant - - valueLabel.text = nil - setSelected(true, animated: false) - updateDateLabel() - } - - override func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - if selected && !isReadOnly { - isPickerHidden.toggle() - } - } - - private lazy var dateFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .none - dateFormatter.timeStyle = .short - - return dateFormatter - }() - - lazy var valueQuantityFormatter: QuantityFormatter = { - let formatter = QuantityFormatter() - return formatter - }() - - private func startTimeForTimeComponent(row: Int) -> TimeInterval { - return minimumStartTime + minimumTimeInterval * TimeInterval(row) - } - - private func stringForStartTime(_ time: TimeInterval) -> String { - let date = startOfDay.addingTimeInterval(time) - return dateFormatter.string(from: date) - } - - func updateDateLabel() { - dateLabel.text = stringForStartTime(startTime) - } - - func validate() { - if let value = value, allowedValues.contains(value) { - valueLabel.textColor = nil // Default color - } else { - valueLabel.textColor = .systemRed - } - } - - func updateValueFromPicker() { - let index = picker.selectedRow(inComponent: Component.value.rawValue) - emptySelectionType.rowOffset - if index >= 0 && index < allowedValues.count { - value = allowedValues[index] - } else { - value = nil - } - updateValueLabel() - } - - private func updateStartTimeSelection() { - let row = Int(round((startTime - minimumStartTime) / minimumTimeInterval)) - if row >= 0 && row < pickerView(picker, numberOfRowsInComponent: Component.time.rawValue) { - picker.selectRow(row, inComponent: Component.time.rawValue, animated: true) - } - } - - func updateValuePicker() { - guard !allowedValues.isEmpty else { - return - } - let selectedIndex: Int - if let value = value { - if let row = allowedValues.firstIndex(of: value) { - selectedIndex = row + emptySelectionType.rowOffset - } else { - // Select next highest value - selectedIndex = (allowedValues.enumerated().filter({$0.element >= value}).min(by: { $0.1 < $1.1 })?.offset ?? 0) + emptySelectionType.rowOffset - } - } else { - switch emptySelectionType { - case .none: - selectedIndex = allowedValues.count - 1 - case .firstIndex: - selectedIndex = 0 - case .lastIndex: - selectedIndex = allowedValues.count - } - } - picker.selectRow(selectedIndex, inComponent: Component.value.rawValue, animated: true) - } - - func updateValueLabel() { - guard let value = value else { - valueLabel.text = nil - return - } - validate() - valueLabel.text = formatValue(value) - } - - private func formatValue(_ value: Double) -> String? { - if let unit = unit { - let quantity = HKQuantity(unit: unit, doubleValue: value) - return valueQuantityFormatter.string(from: quantity, for: unit) - } else { - return valueQuantityFormatter.numberFormatter.string(from: value) - } - } -} - - -extension SetConstrainedScheduleEntryTableViewCell: UIPickerViewDelegate { - - func pickerView(_ pickerView: UIPickerView, - didSelectRow row: Int, - inComponent component: Int) { - switch Component(rawValue: component)! { - case .time: - startTime = selectedStartTime - case .value: - updateValueFromPicker() - } - - delegate?.setConstrainedScheduleEntryTableViewCellDidUpdate(self) - } - - func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { - let metrics = UIFontMetrics(forTextStyle: .body) - return metrics.scaledValue(for: 32) - } - - func pickerView(_ pickerView: UIPickerView, - titleForRow row: Int, - forComponent component: Int) -> String? { - - switch Component(rawValue: component)! { - case .time: - let time = startTimeForTimeComponent(row: row) - return stringForStartTime(time) - case .value: - let valueRow = row - emptySelectionType.rowOffset - guard valueRow >= 0 && valueRow < allowedValues.count else { - return nil - } - return formatValue(allowedValues[valueRow]) - } - } -} - -extension SetConstrainedScheduleEntryTableViewCell: UIPickerViewDataSource { - func numberOfComponents(in pickerView: UIPickerView) -> Int { - return Component.allCases.count - } - - func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { - switch Component(rawValue: component)! { - case .time: - return Int(round((maximumStartTime - minimumStartTime) / minimumTimeInterval) + 1) - case .value: - return allowedValues.count + emptySelectionType.rowCount - } - } -} - -/// UITableViewController extensions to aid working with DatePickerTableViewCell -extension SetConstrainedScheduleEntryTableViewCellDelegate where Self: UITableViewController { - func hideSetConstrainedScheduleEntryCells(excluding indexPath: IndexPath? = nil) { - for case let cell as SetConstrainedScheduleEntryTableViewCell in tableView.visibleCells where tableView.indexPath(for: cell) != indexPath && cell.isPickerHidden == false { - cell.isPickerHidden = true - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SetConstrainedScheduleEntryTableViewCell.xib b/Dependencies/LoopKit/LoopKitUI/Views/SetConstrainedScheduleEntryTableViewCell.xib deleted file mode 100644 index c801441ea..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SetConstrainedScheduleEntryTableViewCell.xib +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SettingDescription.swift b/Dependencies/LoopKit/LoopKitUI/Views/SettingDescription.swift deleted file mode 100644 index 3da43862a..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SettingDescription.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// SettingDescription.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/15/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct SettingDescription: View { - var text: Text - var informationalContent: InformationalContent - @State var displayHelpPage: Bool = false - - public init( - text: Text, - @ViewBuilder informationalContent: @escaping () -> InformationalContent - ) { - self.text = text - self.informationalContent = informationalContent() - } - - public var body: some View { - HStack(spacing: 8) { - text - .font(.callout) - .foregroundColor(Color(.secondaryLabel)) - .fixedSize(horizontal: false, vertical: true) - - Spacer() - - infoButton - .sheet(isPresented: $displayHelpPage) { - NavigationView { - self.informationalContent - } - } - } - } - - private var infoButton: some View { - Button( - action: { - self.displayHelpPage = true - }, - label: { - Image(systemName: "info.circle") - .font(.system(size: 25)) - .foregroundColor(.accentColor) - } - ) - .accessibilityLabel("info") - .padding(.trailing, 4) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/BasalRateScheduleEditor.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/BasalRateScheduleEditor.swift deleted file mode 100644 index 18dd97624..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/BasalRateScheduleEditor.swift +++ /dev/null @@ -1,176 +0,0 @@ -// -// BasalRateScheduleEditor.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/20/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - -public typealias SyncBasalRateSchedule = (_ items: [RepeatingScheduleValue], _ completion: @escaping (Result) -> Void) -> Void - -public struct BasalRateScheduleEditor: View { - var schedule: DailyQuantitySchedule? - var supportedBasalRates: [Double] - var guardrail: Guardrail - var maximumScheduleEntryCount: Int - var syncBasalRateSchedule: SyncBasalRateSchedule? - var save: (BasalRateSchedule) -> Void - let mode: SettingsPresentationMode - @Environment(\.appName) private var appName - - /// - Precondition: `supportedBasalRates` is nonempty and sorted in ascending order. - public init( - schedule: BasalRateSchedule?, - supportedBasalRates: [Double], - maximumBasalRate: Double?, - maximumScheduleEntryCount: Int, - syncBasalRateSchedule: SyncBasalRateSchedule?, - onSave save: @escaping (BasalRateSchedule) -> Void, - mode: SettingsPresentationMode = .settings - ) { - self.schedule = schedule.map { schedule in - DailyQuantitySchedule( - unit: .internationalUnitsPerHour, - dailyItems: schedule.items - )! - } - - if let maxBasal = maximumBasalRate { - let partitioningIndex = supportedBasalRates.partitioningIndex(where: { $0 > maxBasal }) - self.supportedBasalRates = Array(supportedBasalRates[.. Void)? = nil - ) { - self.init( - schedule: therapySettingsViewModel.therapySettings.basalRateSchedule, - supportedBasalRates: therapySettingsViewModel.pumpSupportedIncrements()?.basalRates ?? [], - maximumBasalRate: therapySettingsViewModel.therapySettings.maximumBasalRatePerHour, - maximumScheduleEntryCount: therapySettingsViewModel.pumpSupportedIncrements()?.maximumBasalScheduleEntryCount ?? 0, - syncBasalRateSchedule: therapySettingsViewModel.syncBasalRateSchedule, - onSave: { [weak therapySettingsViewModel] newBasalRates in - therapySettingsViewModel?.saveBasalRates(basalRates: newBasalRates) - didSave?() - }, - mode: mode - ) - } - - public var body: some View { - QuantityScheduleEditor( - title: Text(TherapySetting.basalRate.title), - description: description, - schedule: schedule, - unit: .internationalUnitsPerHour, - selectableValues: supportedBasalRates, - guardrail: guardrail, - quantitySelectionMode: .fractional, - defaultFirstScheduleItemValue: guardrail.absoluteBounds.lowerBound, - scheduleItemLimit: maximumScheduleEntryCount, - confirmationAlertContent: confirmationAlertContent, - guardrailWarning: { - BasalRateGuardrailWarning( - crossedThresholds: $0, - isZeroUnitRateSelectable: self.supportedBasalRates.first! == 0 - ) - }, - onSave: savingMechanism, - mode: mode, - settingType: .basalRate(maximumScheduleEntryCount) - ) - } - - private var description: Text { - Text(TherapySetting.basalRate.descriptiveText(appName: appName)) - } - - private var confirmationAlertContent: AlertContent { - AlertContent( - title: Text(LocalizedString("Save Basal Rates?", comment: "Alert title for confirming basal rates outside the recommended range")), - message: Text(TherapySetting.basalRate.guardrailSaveWarningCaption) - ) - } - - private var savingMechanism: SavingMechanism> { - switch mode { - case .settings: - return .asynchronous { quantitySchedule, completion in - precondition(self.syncBasalRateSchedule != nil) - self.syncBasalRateSchedule?(quantitySchedule.items) { result in - switch result { - case .success(let syncedSchedule): - DispatchQueue.main.async { - self.save(syncedSchedule) - } - completion(nil) - case .failure(let error): - completion(error) - } - } - } - case .acceptanceFlow: - // TODO: get timezone from pump - return .synchronous { quantitySchedule in - let schedule = BasalRateSchedule(dailyItems: quantitySchedule.items, timeZone: .currentFixed)! - self.save(schedule) - } - } - } -} - -private struct BasalRateGuardrailWarning: View { - var crossedThresholds: [SafetyClassification.Threshold] - var isZeroUnitRateSelectable: Bool - - var body: some View { - assert(!crossedThresholds.isEmpty) - - let caption = self.isZeroUnitRateSelectable && crossedThresholds.allSatisfy({ $0 == .minimum }) - ? Text(LocalizedString("A value of 0 U/hr means you will be scheduled to receive no basal insulin.", comment: "Warning text for basal rate of 0 U/hr")) - : nil - - return GuardrailWarning( - therapySetting: .basalRate, - title: crossedThresholds.count == 1 ? singularWarningTitle(for: crossedThresholds.first!) : multipleWarningTitle, - thresholds: crossedThresholds, - caption: caption - ) - } - - private func singularWarningTitle(for threshold: SafetyClassification.Threshold) -> Text { - switch threshold { - case .minimum where isZeroUnitRateSelectable: - return Text(LocalizedString("No Basal Insulin", comment: "Title text for the zero basal rate warning")) - case .minimum, .belowRecommended: - return Text(LocalizedString("Low Basal Rate", comment: "Title text for the low basal rate warning")) - case .aboveRecommended, .maximum: - return Text(LocalizedString("High Basal Rate", comment: "Title text for the high basal rate warning")) - } - } - - private var multipleWarningTitle: Text { - isZeroUnitRateSelectable && crossedThresholds.allSatisfy({ $0 == .minimum }) - ? Text(LocalizedString("No Basal Insulin", comment: "Title text for the zero basal rate warning")) - : Text(LocalizedString("Basal Rates", comment: "Title text for multi-value basal rate warning")) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CarbRatioScheduleEditor.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CarbRatioScheduleEditor.swift deleted file mode 100644 index 479319423..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CarbRatioScheduleEditor.swift +++ /dev/null @@ -1,114 +0,0 @@ -// -// CarbRatioScheduleEditor.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/20/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - - -fileprivate extension HKUnit { - static let storedCarbRatioScheduleUnit = HKUnit.gram() - static let realCarbRatioScheduleUnit = HKUnit.gramsPerUnit -} - -public struct CarbRatioScheduleEditor: View { - private var schedule: DailyQuantitySchedule? - private var mode: SettingsPresentationMode - private var save: (CarbRatioSchedule) -> Void - @Environment(\.appName) private var appName - - public init( - schedule: CarbRatioSchedule?, - onSave save: @escaping (CarbRatioSchedule) -> Void, - mode: SettingsPresentationMode = .settings - ) { - // CarbRatioSchedule stores only the gram unit. - // For consistency across display & computation, convert to "real" g/U units. - self.schedule = schedule.map { schedule in - DailyQuantitySchedule( - unit: .realCarbRatioScheduleUnit, - dailyItems: schedule.items - )! - } - self.mode = mode - self.save = save - } - - public init( - mode: SettingsPresentationMode, - therapySettingsViewModel: TherapySettingsViewModel, - didSave: (() -> Void)? = nil - ) { - self.init( - schedule: therapySettingsViewModel.therapySettings.carbRatioSchedule, - onSave: { [weak therapySettingsViewModel] in - therapySettingsViewModel?.saveCarbRatioSchedule(carbRatioSchedule: $0) - didSave?() - }, - mode: mode - ) - } - - public var body: some View { - QuantityScheduleEditor( - title: Text(TherapySetting.carbRatio.title), - description: description, - schedule: schedule, - unit: .realCarbRatioScheduleUnit, - guardrail: .carbRatio, - selectableValueStride: HKQuantity(unit: .realCarbRatioScheduleUnit, doubleValue: 0.1), - quantitySelectionMode: .fractional, - defaultFirstScheduleItemValue: Guardrail.carbRatio.startingSuggestion ?? Guardrail.carbRatio.recommendedBounds.upperBound, - confirmationAlertContent: confirmationAlertContent, - guardrailWarning: CarbRatioGuardrailWarning.init(crossedThresholds:), - onSave: { - // Convert back to the expected gram-unit-only schedule. - self.save(DailyQuantitySchedule(unit: .storedCarbRatioScheduleUnit, dailyItems: $0.items)!) - }, - mode: mode, - settingType: .carbRatio - ) - } - - private var description: Text { - Text(TherapySetting.carbRatio.descriptiveText(appName: appName)) - } - - private var confirmationAlertContent: AlertContent { - AlertContent( - title: Text(LocalizedString("Save Carb Ratios?", comment: "Alert title for confirming carb ratios outside the recommended range")), - message: Text(TherapySetting.carbRatio.guardrailSaveWarningCaption) - ) - } -} - -private struct CarbRatioGuardrailWarning: View { - var crossedThresholds: [SafetyClassification.Threshold] - - var body: some View { - assert(!crossedThresholds.isEmpty) - return GuardrailWarning( - therapySetting: .carbRatio, - title: crossedThresholds.count == 1 ? singularWarningTitle(for: crossedThresholds.first!) : multipleWarningTitle, - thresholds: crossedThresholds - ) - } - - private func singularWarningTitle(for threshold: SafetyClassification.Threshold) -> Text { - switch threshold { - case .minimum, .belowRecommended: - return Text(LocalizedString("Low Carb Ratio", comment: "Title text for the low carb ratio warning")) - case .aboveRecommended, .maximum: - return Text(LocalizedString("High Carb Ratio", comment: "Title text for the high carb ratio warning")) - } - } - - private var multipleWarningTitle: Text { - Text(LocalizedString("Carb Ratios", comment: "Title text for multi-value carb ratio warning")) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CorrectionRangeOverridesEditor.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CorrectionRangeOverridesEditor.swift deleted file mode 100644 index b96b11d3b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CorrectionRangeOverridesEditor.swift +++ /dev/null @@ -1,343 +0,0 @@ -// -// CorrectionRangeOverridesEditor.swift -// LoopKitUI -// -// Created by Michael Pangburn on 5/15/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - -public struct CorrectionRangeOverridesEditor: View { - @EnvironmentObject private var displayGlucoseUnitObservable: DisplayGlucoseUnitObservable - @Environment(\.dismissAction) var dismiss - @Environment(\.authenticate) var authenticate - - let mode: SettingsPresentationMode - let viewModel: CorrectionRangeOverridesEditorViewModel - - @State private var userDidTap: Bool = false - - @State var value: CorrectionRangeOverrides - - @State var presetBeingEdited: CorrectionRangeOverrides.Preset? { - didSet { - if let presetBeingEdited = presetBeingEdited, value.ranges[presetBeingEdited] == nil { - value.ranges[presetBeingEdited] = initiallySelectedValue(for: presetBeingEdited) - } - } - } - - @State var showingConfirmationAlert = false - - var initialValue: CorrectionRangeOverrides { - viewModel.correctionRangeOverrides - } - - var preset: CorrectionRangeOverrides.Preset { - viewModel.preset - } - - var displayGlucoseUnit: HKUnit { - displayGlucoseUnitObservable.displayGlucoseUnit - } - - public init( - mode: SettingsPresentationMode, - therapySettingsViewModel: TherapySettingsViewModel, - preset: CorrectionRangeOverrides.Preset, - didSave: (() -> Void)? = nil - ) { - self.mode = mode - let viewModel = CorrectionRangeOverridesEditorViewModel( - therapySettingsViewModel: therapySettingsViewModel, - preset: preset, - didSave: didSave) - self._value = State(initialValue: viewModel.correctionRangeOverrides) - self.viewModel = viewModel - } - - public var body: some View { - switch mode { - case .acceptanceFlow: - content - case .settings: - contentWithCancel - .navigationBarTitle("", displayMode: .inline) - } - } - - private var shouldAddCancelButton: Bool { - return value != initialValue - } - - @ViewBuilder - private var leadingNavigationBarItem: some View { - if shouldAddCancelButton { - cancelButton - } else { - EmptyView() - } - } - - private var contentWithCancel: some View { - content - .navigationBarBackButtonHidden(shouldAddCancelButton) - .toolbar { - ToolbarItem(placement: .navigationBarLeading) { - leadingNavigationBarItem - } - ToolbarItem(placement: .navigationBarTrailing) { - deleteButton - } - } - } - - private var deleteButton: some View { - Button( action: { - value.ranges = [:]; - presetBeingEdited = nil - } ) - { Text(LocalizedString("Delete", comment: "Delete values for Pre-Meal, inactivates Pre-Meal icon")) } - } - - private var cancelButton: some View { - Button(action: { self.dismiss() } ) { Text(LocalizedString("Cancel", comment: "Cancel editing settings button title")) } - } - - private var content: some View { - ConfigurationPage( - title: Text(preset.therapySetting.title), - actionButtonTitle: Text(mode.buttonText()), - actionButtonState: value != initialValue || mode == .acceptanceFlow ? .enabled : .disabled, - cards: { - // TODO: Figure out why I need to explicitly return a CardStack with 1 card here - CardStack(cards: [card(for: preset)]) - }, - actionAreaContent: { - instructionalContentIfNecessary - guardrailWarningIfNecessary - }, - action: { - if self.crossedThresholds.isEmpty { - self.startSaving() - } else { - self.showingConfirmationAlert = true - } - } - ) - .alert(isPresented: $showingConfirmationAlert, content: confirmationAlert) - .simultaneousGesture(TapGesture().onEnded { - withAnimation { - self.userDidTap = true - } - }) - } - - private func card(for preset: CorrectionRangeOverrides.Preset) -> Card { - Card { - SettingDescription(text: description(of: preset), informationalContent: { preset.therapySetting.helpScreen() }) - CorrectionRangeOverridesExpandableSetting( - isEditing: Binding( - get: { presetBeingEdited == preset }, - set: { isEditing in - withAnimation { - presetBeingEdited = isEditing ? preset : nil - } - }), - value: $value, - preset: preset, - unit: displayGlucoseUnit, - suspendThreshold: viewModel.suspendThreshold, - correctionRangeScheduleRange: viewModel.correctionRangeScheduleRange, - expandedContent: { - GlucoseRangePicker( - range: Binding( - get: { value.ranges[preset] ?? initiallySelectedValue(for: preset) }, - set: { newValue in - withAnimation { - value.ranges[preset] = newValue - } - } - ), - unit: - displayGlucoseUnit, - minValue: selectableBounds(for: preset).lowerBound, - maxValue: selectableBounds(for: preset).upperBound, - guardrail: viewModel.guardrail - ) - .accessibility(identifier: "\(accessibilityIdentifier(for: preset))_picker") - }) - } - } - - private func description(of preset: CorrectionRangeOverrides.Preset) -> Text { - switch preset { - case .preMeal: - return Text(preset.descriptiveText) - case .workout: - return Text(preset.descriptiveText) - } - } - - private var instructionalContentIfNecessary: some View { - return Group { - if mode == .acceptanceFlow && !userDidTap { - instructionalContent - } - } - } - - private var instructionalContent: some View { - HStack { // to align with guardrail warning, if present - Text(LocalizedString("You can edit a setting by tapping into any line item.", comment: "Description of how to edit setting")) - .foregroundColor(.secondary) - .font(.subheadline) - Spacer() - } - } - - private func selectableBounds(for preset: CorrectionRangeOverrides.Preset) -> ClosedRange { - viewModel.guardrail.absoluteBounds - } - - private func initiallySelectedValue(for preset: CorrectionRangeOverrides.Preset) -> ClosedRange { - viewModel.guardrail.recommendedBounds.clamped(to: selectableBounds(for: preset)) - } - - private var guardrailWarningIfNecessary: some View { - let crossedThresholds = self.crossedThresholds - return Group { - if !crossedThresholds.isEmpty && (userDidTap || mode == .settings) { - CorrectionRangeOverridesGuardrailWarning(crossedThresholds: crossedThresholds, preset: preset) - } - } - } - - private var crossedThresholds: [SafetyClassification.Threshold] { - guard let range = value.ranges[preset] else { return [] } - - let guardrail = viewModel.guardrail - let thresholds: [SafetyClassification.Threshold] = [range.lowerBound, range.upperBound].compactMap { bound in - switch guardrail.classification(for: bound) { - case .withinRecommendedRange: - return nil - case .outsideRecommendedRange(let threshold): - return threshold - } - } - - return thresholds - } - - private func confirmationAlert() -> SwiftUI.Alert { - let title: Text - switch preset { - case .preMeal: - title = Text(LocalizedString("Save Pre-Meal Range?", comment: "Alert title for confirming pre-meal range overrides outside the recommended range")) - case .workout: - title = Text(LocalizedString("Save Workout Range?", comment: "Alert title for confirming workout range overrides outside the recommended range")) - } - - return SwiftUI.Alert( - title: title, - // For the message, preMeal and workout are the same - message: Text(TherapySetting.preMealCorrectionRangeOverride.guardrailSaveWarningCaption), - primaryButton: .cancel(Text(LocalizedString("Go Back", comment: "Text for go back action on confirmation alert"))), - secondaryButton: .default( - Text(LocalizedString("Continue", comment: "Text for continue action on confirmation alert")), - action: startSaving - ) - ) - } - - private func startSaving() { - guard mode == .settings else { - self.continueSaving() - return - } - authenticate(preset.therapySetting.authenticationChallengeDescription) { - switch $0 { - case .success: self.continueSaving() - case .failure: break - } - } - } - - private func continueSaving() { - viewModel.saveCorrectionRangeOverride(value) - } - - private func accessibilityIdentifier(for preset: CorrectionRangeOverrides.Preset) -> String { - switch preset { - case .preMeal: - return "pre-meal" - case .workout: - return "workout" - } - } -} - -private struct CorrectionRangeOverridesGuardrailWarning: View { - var crossedThresholds: [SafetyClassification.Threshold] - var preset: CorrectionRangeOverrides.Preset - - var body: some View { - assert(!crossedThresholds.isEmpty) - return GuardrailWarning( - therapySetting: preset == .preMeal ? .preMealCorrectionRangeOverride : .workoutCorrectionRangeOverride, - title: title, - thresholds: crossedThresholds) - } - - private var title: Text { - if crossedThresholds.count == 1 { - return singularWarningTitle(for: crossedThresholds.first!) - } else { - return multipleWarningTitle - } - } - - private func singularWarningTitle(for threshold: SafetyClassification.Threshold) -> Text { - switch threshold { - case .minimum, .belowRecommended: - switch preset { - case .preMeal: - return Text(LocalizedString("Low Pre-Meal Value", comment: "Title text for the low pre-meal value warning")) - case .workout: - return Text(LocalizedString("Low Workout Value", comment: "Title text for the low workout value warning")) - } - case .aboveRecommended, .maximum: - switch preset { - case .preMeal: - return Text(LocalizedString("High Pre-Meal Value", comment: "Title text for the low pre-meal value warning")) - case .workout: - return Text(LocalizedString("High Workout Value", comment: "Title text for the high workout value warning")) - } - } - } - - private var multipleWarningTitle: Text { - switch preset { - case .preMeal: - return Text(LocalizedString("Pre-Meal Values", comment: "Title text for multi-value pre-meal value warning")) - case .workout: - return Text(LocalizedString("Workout Values", comment: "Title text for multi-value workout value warning")) - } - } -} - -public extension CorrectionRangeOverrides.Preset { - - var descriptiveText: String { - switch self { - case .preMeal: - return LocalizedString("Temporarily lower your glucose target before a meal to impact post-meal glucose spikes.", comment: "Description of pre-meal mode") - case .workout: - return LocalizedString("Temporarily raise your glucose target before, during, or after physical activity to reduce the risk of low glucose events.", comment: "Description of workout mode") - } - } - -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CorrectionRangeOverridesExpandableSetting.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CorrectionRangeOverridesExpandableSetting.swift deleted file mode 100644 index d524d95c2..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CorrectionRangeOverridesExpandableSetting.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// CorrectionRangeOverridesExpandableSetting.swift -// LoopKitUI -// -// Created by Rick Pasetto on 7/13/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - - -public struct CorrectionRangeOverridesExpandableSetting: View { - @Environment(\.carbTintColor) var carbTintColor - @Environment(\.glucoseTintColor) var glucoseTintColor - @Binding var isEditing: Bool - @Binding var value: CorrectionRangeOverrides - let preset: CorrectionRangeOverrides.Preset - let unit: HKUnit - let suspendThreshold: GlucoseThreshold? - var correctionRangeScheduleRange: ClosedRange - var expandedContent: () -> ExpandedContent - - public var body: some View { - ExpandableSetting( - isEditing: $isEditing, - leadingValueContent: { - HStack { - preset.icon(usingCarbTintColor: carbTintColor, orGlucoseTintColor: glucoseTintColor) - Text(preset.title) - } - }, - trailingValueContent: { - GuardrailConstrainedQuantityRangeView( - range: value.ranges[preset], - unit: unit, - guardrail: self.guardrail(for: preset), - isEditing: isEditing, - forceDisableAnimations: true - ) - }, - expandedContent: expandedContent - ) - } - - private func guardrail(for preset: CorrectionRangeOverrides.Preset) -> Guardrail { - return Guardrail.correctionRangeOverride(for: preset, correctionRangeScheduleRange: correctionRangeScheduleRange, suspendThreshold: suspendThreshold) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CorrectionRangeOverridesExtension.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CorrectionRangeOverridesExtension.swift deleted file mode 100644 index 441a63897..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CorrectionRangeOverridesExtension.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// CorrectionRangeOverridesExtension.swift -// LoopKitUI -// -// Created by Rick Pasetto on 7/15/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import LoopKit -import SwiftUI - -extension CorrectionRangeOverrides.Preset { - public func icon(usingCarbTintColor carbTintColor: Color, - orGlucoseTintColor glucoseTintColor: Color) -> some View - { - switch self { - case .preMeal: - return icon(named: "Pre-Meal", tinted: carbTintColor) - case .workout: - return icon(named: "workout", tinted: glucoseTintColor) - } - } - - private func icon(named name: String, tinted color: Color) -> some View { - Image(name) - .renderingMode(.template) - .foregroundColor(color) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CorrectionRangeScheduleEditor.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CorrectionRangeScheduleEditor.swift deleted file mode 100644 index a2bea6ed1..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/CorrectionRangeScheduleEditor.swift +++ /dev/null @@ -1,202 +0,0 @@ -// -// CorrectionRangeScheduleEditor.swift -// LoopKitUI -// -// Created by Michael Pangburn on 5/14/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - - -public struct CorrectionRangeScheduleEditor: View { - @EnvironmentObject private var displayGlucoseUnitObservable: DisplayGlucoseUnitObservable - @Environment(\.appName) private var appName - - let mode: SettingsPresentationMode - let viewModel: CorrectionRangeScheduleEditorViewModel - - @State var scheduleItems: [RepeatingScheduleValue>] - - @State private var userDidTap: Bool = false - - var displayGlucoseUnit: HKUnit { - displayGlucoseUnitObservable.displayGlucoseUnit - } - - var initialSchedule: GlucoseRangeSchedule? { - viewModel.glucoseTargetRangeSchedule - } - - public init( - mode: SettingsPresentationMode, - therapySettingsViewModel: TherapySettingsViewModel, - didSave: (() -> Void)? = nil - ) { - self.mode = mode - if mode == .acceptanceFlow { - self._scheduleItems = State(initialValue: therapySettingsViewModel.glucoseTargetRangeSchedule?.safeSchedule(with: therapySettingsViewModel.suspendThreshold?.quantity)?.quantityRanges ?? []) - } - else { - self._scheduleItems = State(initialValue: therapySettingsViewModel.glucoseTargetRangeSchedule?.quantityRanges ?? []) - } - self.viewModel = CorrectionRangeScheduleEditorViewModel( - mode: mode, - therapySettingsViewModel: therapySettingsViewModel, - didSave: didSave - ) - } - - public var body: some View { - ScheduleEditor( - title: Text(TherapySetting.glucoseTargetRange.title), - description: description, - scheduleItems: $scheduleItems, - initialScheduleItems: initialSchedule?.quantityRanges ?? [], - defaultFirstScheduleItemValue: defaultFirstScheduleItemValue, - saveConfirmation: saveConfirmation, - valueContent: { range, isEditing in - GuardrailConstrainedQuantityRangeView( - range: range, - unit: displayGlucoseUnit, - guardrail: viewModel.guardrail, - isEditing: isEditing) - }, - valuePicker: { scheduleItem, availableWidth in - GlucoseRangePicker( - range: Binding( - get: { scheduleItem.wrappedValue.value }, - set: { quantityRange in - withAnimation { - scheduleItem.wrappedValue.value = quantityRange - } - } - ), - unit: displayGlucoseUnit, - minValue: viewModel.minValue, - guardrail: viewModel.guardrail, - usageContext: .component(availableWidth: availableWidth) - ) - }, - actionAreaContent: { - instructionalContentIfNecessary - guardrailWarningIfNecessary - }, - savingMechanism: .synchronous { dailyQuantities in - let rangeSchedule = DailyQuantitySchedule( - unit: displayGlucoseUnit, - dailyQuantities: dailyQuantities, - timeZone: initialSchedule?.timeZone)! - let glucoseTargetRangeSchedule = GlucoseRangeSchedule( - rangeSchedule: rangeSchedule, - override: initialSchedule?.override) - viewModel.saveGlucoseTargetRangeSchedule(glucoseTargetRangeSchedule) - }, - mode: mode, - therapySettingType: .glucoseTargetRange - ) - .simultaneousGesture(TapGesture().onEnded { - withAnimation { - userDidTap = true - } - }) - } - - var defaultFirstScheduleItemValue: ClosedRange { - switch displayGlucoseUnit { - case .milligramsPerDeciliter: - return DoubleRange(minValue: 100, maxValue: 115).quantityRange(for: displayGlucoseUnit) - case .millimolesPerLiter: - return DoubleRange(minValue: 5.6, maxValue: 6.7).quantityRange(for: displayGlucoseUnit) - default: - fatalError("Unsupposed glucose unit \(displayGlucoseUnit)") - } - } - - var description: Text { - Text(TherapySetting.glucoseTargetRange.descriptiveText(appName: appName)) - } - - var saveConfirmation: SaveConfirmation { - crossedThresholds.isEmpty ? .notRequired : .required(confirmationAlertContent) - } - - var instructionalContentIfNecessary: some View { - return Group { - if mode == .acceptanceFlow && !userDidTap { - instructionalContent - } - } - } - - var instructionalContent: some View { - HStack { // to align with guardrail warning, if present - VStack(alignment: .leading, spacing: 20) { - Text(LocalizedString("You can edit a setting by tapping into any line item.", comment: "Description of how to edit setting")) - Text(LocalizedString("You can add different ranges for different times of day by using the ➕.", comment: "Description of how to add a configuration range")) - } - .foregroundColor(.secondary) - .font(.subheadline) - Spacer() - } - } - - var guardrailWarningIfNecessary: some View { - let crossedThresholds = self.crossedThresholds - return Group { - if !crossedThresholds.isEmpty && (userDidTap || mode == .settings) { - CorrectionRangeGuardrailWarning(crossedThresholds: crossedThresholds) - } - } - } - - var crossedThresholds: [SafetyClassification.Threshold] { - scheduleItems.flatMap { (item) -> [SafetyClassification.Threshold] in - let lowerBound = item.value.lowerBound - let upperBound = item.value.upperBound - return [lowerBound, upperBound].compactMap { (bound) -> SafetyClassification.Threshold? in - switch viewModel.guardrail.classification(for: bound) { - case .withinRecommendedRange: - return nil - case .outsideRecommendedRange(let threshold): - return threshold - } - } - } - } - - private var confirmationAlertContent: AlertContent { - AlertContent( - title: Text(LocalizedString("Save Correction Range(s)?", comment: "Alert title for confirming correction ranges outside the recommended range")), - message: Text(TherapySetting.glucoseTargetRange.guardrailSaveWarningCaption) - ) - } -} - -private struct CorrectionRangeGuardrailWarning: View { - var crossedThresholds: [SafetyClassification.Threshold] - - var body: some View { - assert(!crossedThresholds.isEmpty) - return GuardrailWarning( - therapySetting: .glucoseTargetRange, - title: crossedThresholds.count == 1 ? singularWarningTitle(for: crossedThresholds.first!) : multipleWarningTitle, - thresholds: crossedThresholds - ) - } - - private func singularWarningTitle(for threshold: SafetyClassification.Threshold) -> Text { - switch threshold { - case .minimum, .belowRecommended: - return Text(LocalizedString("Low Correction Value", comment: "Title text for the low correction value warning")) - case .aboveRecommended, .maximum: - return Text(LocalizedString("High Correction Value", comment: "Title text for the high correction value warning")) - } - } - - private var multipleWarningTitle: Text { - Text(LocalizedString("Correction Values", comment: "Title text for multi-value correction value warning")) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/DeliveryLimitsEditor.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/DeliveryLimitsEditor.swift deleted file mode 100644 index 817d12d59..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/DeliveryLimitsEditor.swift +++ /dev/null @@ -1,462 +0,0 @@ -// -// DeliveryLimitsEditor.swift -// LoopKitUI -// -// Created by Michael Pangburn on 6/22/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - -public typealias SyncDeliveryLimits = (_ deliveryLimits: DeliveryLimits, _ completion: @escaping (Swift.Result) -> Void) -> Void - -public struct DeliveryLimitsEditor: View { - fileprivate enum PresentedAlert: Error { - case saveConfirmation(AlertContent) - case saveError(Error) - } - - let initialValue: DeliveryLimits - let supportedBasalRates: [Double] - let selectableMaximumBasalRates: [Double] - let scheduledBasalRange: ClosedRange? - let supportedMaximumBolusVolumes: [Double] - let selectableMaximumBolusVolumes: [Double] - let syncDeliveryLimits: SyncDeliveryLimits? - let save: (_ deliveryLimits: DeliveryLimits) -> Void - let mode: SettingsPresentationMode - - @State var value: DeliveryLimits - @State private var userDidTap: Bool = false - @State var settingBeingEdited: DeliveryLimits.Setting? - @State private var isSyncing = false - @State private var presentedAlert: PresentedAlert? - - @Environment(\.dismissAction) var dismiss - @Environment(\.authenticate) var authenticate - @Environment(\.appName) var appName - - private let lowestCarbRatio: Double? - - public init( - value: DeliveryLimits, - supportedBasalRates: [Double], - scheduledBasalRange: ClosedRange?, - supportedMaximumBolusVolumes: [Double], - lowestCarbRatio: Double?, - syncDeliveryLimits: @escaping SyncDeliveryLimits, - onSave save: @escaping (_ deliveryLimits: DeliveryLimits) -> Void, - mode: SettingsPresentationMode = .settings - ) { - self._value = State(initialValue: value) - self.initialValue = value - self.supportedBasalRates = supportedBasalRates - self.selectableMaximumBasalRates = Guardrail.selectableMaxBasalRates(supportedBasalRates: supportedBasalRates, scheduledBasalRange: scheduledBasalRange, lowestCarbRatio: lowestCarbRatio) - self.scheduledBasalRange = scheduledBasalRange - self.supportedMaximumBolusVolumes = supportedMaximumBolusVolumes - self.selectableMaximumBolusVolumes = Guardrail.selectableBolusVolumes(supportedBolusVolumes: supportedMaximumBolusVolumes) - self.syncDeliveryLimits = syncDeliveryLimits - self.save = save - self.mode = mode - self.lowestCarbRatio = lowestCarbRatio - } - - public init( - mode: SettingsPresentationMode, - therapySettingsViewModel: TherapySettingsViewModel, - didSave: (() -> Void)? = nil - ) { - precondition(therapySettingsViewModel.pumpSupportedIncrements() != nil) - - let maxBasal = therapySettingsViewModel.therapySettings.maximumBasalRatePerHour.map { - HKQuantity(unit: .internationalUnitsPerHour, doubleValue: $0) - } - - let maxBolus = therapySettingsViewModel.therapySettings.maximumBolus.map { - HKQuantity(unit: .internationalUnit(), doubleValue: $0) - } - - self.init( - value: DeliveryLimits(maximumBasalRate: maxBasal, maximumBolus: maxBolus), - supportedBasalRates: therapySettingsViewModel.pumpSupportedIncrements()?.basalRates ?? [], - scheduledBasalRange: therapySettingsViewModel.therapySettings.basalRateSchedule?.valueRange(), - supportedMaximumBolusVolumes: therapySettingsViewModel.pumpSupportedIncrements()?.maximumBolusVolumes ?? [], - lowestCarbRatio: therapySettingsViewModel.therapySettings.carbRatioSchedule?.lowestValue(), - syncDeliveryLimits: therapySettingsViewModel.syncDeliveryLimits, - onSave: { [weak therapySettingsViewModel] newLimits in - therapySettingsViewModel?.saveDeliveryLimits(limits: newLimits) - didSave?() - }, - mode: mode - ) - } - - public var body: some View { - switch mode { - case .acceptanceFlow: - content - .disabled(isSyncing) - case .settings: - contentWithCancel - .disabled(isSyncing) - .navigationBarTitle("", displayMode: .inline) - } - } - - private var contentWithCancel: some View { - if value == initialValue { - return AnyView(content - .navigationBarBackButtonHidden(false) - .navigationBarItems(leading: EmptyView()) - ) - } else { - return AnyView(content - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: cancelButton) - ) - } - } - - private var cancelButton: some View { - Button(action: { self.dismiss() } ) { Text(LocalizedString("Cancel", comment: "Cancel editing settings button title")) } - } - - private var content: some View { - ConfigurationPage( - title: Text(TherapySetting.deliveryLimits.title), - actionButtonTitle: Text(mode.buttonText(isSaving: isSyncing)), - actionButtonState: saveButtonState, - cards: { - maximumBasalRateCard - maximumBolusCard - }, - actionAreaContent: { - instructionalContentIfNecessary - guardrailWarningIfNecessary - }, - action: { - if self.crossedThresholds.isEmpty { - self.startSaving() - } else { - self.presentedAlert = .saveConfirmation(confirmationAlertContent) - } - } - ) - .alert(item: $presentedAlert, content: alert(for:)) - .simultaneousGesture(TapGesture().onEnded { - withAnimation { - self.userDidTap = true - } - }) - } - - var saveButtonState: ConfigurationPageActionButtonState { - guard value.maximumBasalRate != nil, value.maximumBolus != nil else { - return .disabled - } - - if isSyncing { - return .loading - } - - if mode == .acceptanceFlow { - return .enabled - } - - return value == initialValue && mode != .acceptanceFlow ? .disabled : .enabled - } - - var maximumBasalRateGuardrail: Guardrail { - return Guardrail.maximumBasalRate(supportedBasalRates: supportedBasalRates, scheduledBasalRange: scheduledBasalRange, lowestCarbRatio: lowestCarbRatio) - } - - var maximumBasalRateCard: Card { - Card { - SettingDescription(text: Text(DeliveryLimits.Setting.maximumBasalRate.localizedDescriptiveText(appName: appName)), - informationalContent: { TherapySetting.deliveryLimits.helpScreen() }) - ExpandableSetting( - isEditing: Binding( - get: { self.settingBeingEdited == .maximumBasalRate }, - set: { isEditing in - withAnimation { - self.settingBeingEdited = isEditing ? .maximumBasalRate : nil - } - } - ), - leadingValueContent: { - Text(DeliveryLimits.Setting.maximumBasalRate.title) - }, - trailingValueContent: { - GuardrailConstrainedQuantityView( - value: value.maximumBasalRate, - unit: .internationalUnitsPerHour, - guardrail: maximumBasalRateGuardrail, - isEditing: settingBeingEdited == .maximumBasalRate, - forceDisableAnimations: true - ) - }, - expandedContent: { - FractionalQuantityPicker( - value: Binding( - get: { self.value.maximumBasalRate ?? self.maximumBasalRateGuardrail.startingSuggestion ?? self.maximumBasalRateGuardrail.recommendedBounds.upperBound }, - set: { newValue in - withAnimation { - self.value.maximumBasalRate = newValue - } - } - ), - unit: .internationalUnitsPerHour, - guardrail: self.maximumBasalRateGuardrail, - selectableValues: self.selectableMaximumBasalRates, - usageContext: .independent - ) - .accessibility(identifier: "max_basal_picker") - } - ) - } - } - - var maximumBolusGuardrail: Guardrail { - return Guardrail.maximumBolus(supportedBolusVolumes: supportedMaximumBolusVolumes) - } - - var maximumBolusCard: Card { - Card { - SettingDescription(text: Text(DeliveryLimits.Setting.maximumBolus.localizedDescriptiveText(appName: appName)), - informationalContent: { TherapySetting.deliveryLimits.helpScreen() }) - ExpandableSetting( - isEditing: Binding( - get: { self.settingBeingEdited == .maximumBolus }, - set: { isEditing in - withAnimation { - self.settingBeingEdited = isEditing ? .maximumBolus : nil - } - } - ), - leadingValueContent: { - Text(DeliveryLimits.Setting.maximumBolus.title) - }, - trailingValueContent: { - GuardrailConstrainedQuantityView( - value: value.maximumBolus, - unit: .internationalUnit(), - guardrail: maximumBolusGuardrail, - isEditing: settingBeingEdited == .maximumBolus, - forceDisableAnimations: true - ) - }, - expandedContent: { - FractionalQuantityPicker( - value: Binding( - get: { self.value.maximumBolus ?? self.maximumBolusGuardrail.startingSuggestion ?? self.maximumBolusGuardrail.recommendedBounds.upperBound }, - set: { newValue in - withAnimation { - self.value.maximumBolus = newValue - } - } - ), - unit: .internationalUnit(), - guardrail: self.maximumBolusGuardrail, - selectableValues: self.selectableMaximumBolusVolumes, - usageContext: .independent - ) - .accessibility(identifier: "max_bolus_picker") - } - ) - } - } - - private var instructionalContentIfNecessary: some View { - return Group { - if mode == .acceptanceFlow && !userDidTap { - instructionalContent - } - } - } - - private var instructionalContent: some View { - HStack { // to align with guardrail warning, if present - Text(LocalizedString("You can edit a setting by tapping into any line item.", comment: "Description of how to edit setting")) - .foregroundColor(.secondary) - .font(.subheadline) - Spacer() - } - } - - private var guardrailWarningIfNecessary: some View { - let crossedThresholds = self.crossedThresholds - return Group { - if !crossedThresholds.isEmpty && (userDidTap || mode == .settings) { - DeliveryLimitsGuardrailWarning(crossedThresholds: crossedThresholds, value: value) - } - } - } - - private var crossedThresholds: [DeliveryLimits.Setting: SafetyClassification.Threshold] { - var crossedThresholds: [DeliveryLimits.Setting: SafetyClassification.Threshold] = [:] - - switch value.maximumBasalRate.map(maximumBasalRateGuardrail.classification(for:)) { - case nil, .withinRecommendedRange: - break - case .outsideRecommendedRange(let threshold): - crossedThresholds[.maximumBasalRate] = threshold - } - - switch value.maximumBolus.map(maximumBolusGuardrail.classification(for:)) { - case nil, .withinRecommendedRange: - break - case .outsideRecommendedRange(let threshold): - crossedThresholds[.maximumBolus] = threshold - } - - return crossedThresholds - } - - private func startSaving() { - guard mode == .settings else { - self.monitorSavingMechanism(savingMechanism: .synchronous { deliveryLimits in - save(deliveryLimits) - }) - return - } - authenticate(TherapySetting.deliveryLimits.authenticationChallengeDescription) { - switch $0 { - case .success: - self.monitorSavingMechanism(savingMechanism: .asynchronous { deliveryLimits, completion in - synchronizeDeliveryLimits(deliveryLimits, completion) - }) - case .failure: break - } - } - } - - private func synchronizeDeliveryLimits(_ deliveryLimits: DeliveryLimits, _ completion: @escaping (Error?) -> Void) { - guard let syncDeliveryLimits = self.syncDeliveryLimits else { - actuallySave(deliveryLimits) - return - } - syncDeliveryLimits(deliveryLimits) { result in - switch result { - case .success(let deliveryLimits): - actuallySave(deliveryLimits) - completion(nil) - case .failure(let error): - completion(PresentedAlert.saveError(error)) - } - } - } - - private func actuallySave(_ deliveryLimits: DeliveryLimits) { - DispatchQueue.main.async { - self.save(deliveryLimits) - } - } - - private func monitorSavingMechanism(savingMechanism: SavingMechanism) { - switch savingMechanism { - case .synchronous(let save): - save(value) - case .asynchronous(let save): - withAnimation { - self.isSyncing = true - } - - save(value) { error in - DispatchQueue.main.async { - if let error = error { - withAnimation { - self.isSyncing = false - } - self.presentedAlert = (error as? PresentedAlert) ?? .saveError(error) - } - } - } - } - } - - private func alert(for presentedAlert: PresentedAlert) -> SwiftUI.Alert { - switch presentedAlert { - case .saveConfirmation(let content): - return SwiftUI.Alert( - title: content.title, - message: content.message, - primaryButton: .cancel( - content.cancel ?? - Text(LocalizedString("Go Back", comment: "Button text to return to editing a schedule after from alert popup when some schedule values are outside the recommended range"))), - secondaryButton: .default( - content.ok ?? - Text(LocalizedString("Continue", comment: "Button text to confirm saving from alert popup when some schedule values are outside the recommended range")), - action: startSaving - ) - ) - case .saveError(let error): - return SwiftUI.Alert( - title: Text(LocalizedString("Unable to Save", comment: "Alert title when error occurs while saving a schedule")), - message: Text(error.localizedDescription) - ) - } - } - - private var confirmationAlertContent: AlertContent { - AlertContent( - title: Text(LocalizedString("Save Delivery Limits?", comment: "Alert title for confirming delivery limits outside the recommended range")), - message: Text(TherapySetting.deliveryLimits.guardrailSaveWarningCaption), - cancel: Text(LocalizedString("Go Back", comment: "Text for go back action on confirmation alert")), - ok: Text(LocalizedString("Continue", comment: "Text for continue action on confirmation alert") - ) - ) - } -} - - -struct DeliveryLimitsGuardrailWarning: View { - let crossedThresholds: [DeliveryLimits.Setting: SafetyClassification.Threshold] - let value: DeliveryLimits - var body: some View { - switch crossedThresholds.count { - case 0: - preconditionFailure("A guardrail warning requires at least one crossed threshold") - case 1: - let (setting, threshold) = crossedThresholds.first! - let title: Text - switch setting { - case .maximumBasalRate: - switch threshold { - case .minimum, .belowRecommended: - title = Text(LocalizedString("Low Maximum Basal Rate", comment: "Title text for low maximum basal rate warning")) - case .aboveRecommended, .maximum: - title = Text(LocalizedString("High Maximum Basal Rate", comment: "Title text for high maximum basal rate warning")) - } - case .maximumBolus: - switch threshold { - case .minimum, .belowRecommended: - title = Text(LocalizedString("Low Maximum Bolus", comment: "Title text for low maximum bolus warning")) - case .aboveRecommended, .maximum: - title = Text(LocalizedString("High Maximum Bolus", comment: "Title text for high maximum bolus warning")) - } - } - - return GuardrailWarning(therapySetting: .deliveryLimits, title: title, threshold: threshold) - case 2: - return GuardrailWarning( - therapySetting: .deliveryLimits, - title: Text(LocalizedString("Delivery Limits", comment: "Title text for crossed thresholds guardrail warning")), - thresholds: Array(crossedThresholds.values)) - default: - preconditionFailure("Unreachable: only two delivery limit settings exist") - } - } -} - -extension DeliveryLimitsEditor.PresentedAlert: Identifiable { - var id: Int { - switch self { - case .saveConfirmation: - return 0 - case .saveError: - return 1 - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/InsulinModelChartView.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/InsulinModelChartView.swift deleted file mode 100644 index f0d8f864a..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/InsulinModelChartView.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// InsulinModelChartView.swift -// LoopKitUI -// -// Created by Michael Pangburn on 7/15/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - - -struct InsulinModelChartView: UIViewRepresentable { - let chartManager: ChartsManager - var glucoseUnit: HKUnit - var selectedInsulinModelValues: [GlucoseValue] - var unselectedInsulinModelValues: [[GlucoseValue]] - var glucoseDisplayRange: ClosedRange - - func makeUIView(context: Context) -> ChartContainerView { - let view = ChartContainerView() - view.chartGenerator = { [chartManager] frame in - chartManager.chart(atIndex: 0, frame: frame)?.view - } - return view - } - - func updateUIView(_ chartContainerView: ChartContainerView, context: Context) { - chartManager.invalidateChart(atIndex: 0) - insulinModelChart.glucoseUnit = glucoseUnit - insulinModelChart.setSelectedInsulinModelValues(selectedInsulinModelValues) - insulinModelChart.setUnselectedInsulinModelValues(unselectedInsulinModelValues) - insulinModelChart.glucoseDisplayRange = glucoseDisplayRange - chartManager.prerender() - chartContainerView.reloadChart() - } - - private var insulinModelChart: InsulinModelChart { - guard chartManager.charts.count == 1, let insulinModelChart = chartManager.charts.first as? InsulinModelChart else { - fatalError("Expected exactly one insulin model chart in ChartsManager") - } - - return insulinModelChart - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/InsulinModelSelection.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/InsulinModelSelection.swift deleted file mode 100644 index 63e9eb4cb..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/InsulinModelSelection.swift +++ /dev/null @@ -1,264 +0,0 @@ -// -// InsulinModelSelection.swift -// Loop -// -// Created by Michael Pangburn on 7/14/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import HealthKit -import SwiftUI -import LoopKit - -public struct InsulinModelSelection: View { - @EnvironmentObject private var displayGlucoseUnitObservable: DisplayGlucoseUnitObservable - @Environment(\.appName) private var appName - @Environment(\.dismissAction) private var dismiss - @Environment(\.authenticate) private var authenticate - - @State private var value: ExponentialInsulinModelPreset - @State private var chartManager: ChartsManager - - private let initialValue: ExponentialInsulinModelPreset - private let insulinSensitivitySchedule: InsulinSensitivitySchedule - private let mode: SettingsPresentationMode - private let save: (_ insulinModelPreset: ExponentialInsulinModelPreset) -> Void - - static let defaultInsulinSensitivitySchedule = InsulinSensitivitySchedule(unit: .milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: 0, value: 40)])! - - private var displayGlucoseUnit: HKUnit { - displayGlucoseUnitObservable.displayGlucoseUnit - } - - public init( - value: ExponentialInsulinModelPreset, - insulinSensitivitySchedule: InsulinSensitivitySchedule?, - chartColors: ChartColorPalette, - onSave save: @escaping (_ insulinModelPreset: ExponentialInsulinModelPreset) -> Void, - mode: SettingsPresentationMode - ){ - self._value = State(initialValue: value) - self.initialValue = value - self.insulinSensitivitySchedule = insulinSensitivitySchedule ?? Self.defaultInsulinSensitivitySchedule - self.save = save - self.mode = mode - - let chartManager = ChartsManager( - colors: chartColors, - settings: .default, - axisLabelFont: .systemFont(ofSize: 12), - charts: [InsulinModelChart()], - traitCollection: .current - ) - - chartManager.startDate = Calendar.current.nextDate( - after: Date(), - matching: DateComponents(minute: 0), - matchingPolicy: .strict, - direction: .backward - ) ?? Date() - self._chartManager = State(initialValue: chartManager) - } - - public init( - mode: SettingsPresentationMode, - therapySettingsViewModel: TherapySettingsViewModel, - chartColors: ChartColorPalette, - didSave: (() -> Void)? = nil - ) { - self.init( - value: therapySettingsViewModel.therapySettings.defaultRapidActingModel ?? .rapidActingAdult, - insulinSensitivitySchedule: therapySettingsViewModel.therapySettings.insulinSensitivitySchedule, - chartColors: chartColors, - onSave: { [weak therapySettingsViewModel] insulinModelPreset in - therapySettingsViewModel?.saveInsulinModel(insulinModelPreset: insulinModelPreset) - didSave?() - }, - mode: mode - ) - } - - public var body: some View { - switch mode { - case .acceptanceFlow: - content - case .settings: - contentWithCancel - .navigationBarTitleDisplayMode(.inline) - } - } - - private var contentWithCancel: some View { - if value == initialValue { - return AnyView(content - .navigationBarBackButtonHidden(false) - .navigationBarItems(leading: EmptyView()) - ) - } else { - return AnyView(content - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: cancelButton) - ) - } - } - - private var cancelButton: some View { - Button(action: { dismiss() } ) { Text(LocalizedString("Cancel", comment: "Cancel editing settings button title")) } - } - - private var content: some View { - VStack(spacing: 0) { - CardList(title: Text(LocalizedString("Insulin Model", comment: "Title text for insulin model")), - style: .simple(CardStack(cards: [card]))) - Button(action: { startSaving() }) { - Text(mode.buttonText()) - .actionButtonStyle(.primary) - .padding() - } - .disabled(value == initialValue && mode != .acceptanceFlow) - // Styling to mimic the floating button of a ConfigurationPage - .padding(.bottom) - .background(Color(.secondarySystemGroupedBackground).shadow(radius: 5)) - } - .supportedInterfaceOrientations(.portrait) - .edgesIgnoringSafeArea(.bottom) - } - - private var card: Card { - Card { - Section { - SettingDescription( - text: insulinModelSettingDescription, - informationalContent: { - TherapySetting.insulinModel.helpScreen() - } - ) - .padding(4) - .padding(.top, 4) - - VStack { - InsulinModelChartView( - chartManager: chartManager, - glucoseUnit: displayGlucoseUnit, - selectedInsulinModelValues: selectedInsulinModelValues, - unselectedInsulinModelValues: unselectedInsulinModelValues, - glucoseDisplayRange: endingGlucoseQuantity...startingGlucoseQuantity - ) - .frame(height: 170) - - CheckmarkListItem( - title: Text(ExponentialInsulinModelPreset.rapidActingAdult.title), - description: Text(ExponentialInsulinModelPreset.rapidActingAdult.subtitle), - isSelected: isSelected(ExponentialInsulinModelPreset.rapidActingAdult) - ) - .padding(.vertical, 4) - .contentShape(Rectangle()) - } - - SectionDivider() - CheckmarkListItem( - title: Text(ExponentialInsulinModelPreset.rapidActingChild.title), - description: Text(ExponentialInsulinModelPreset.rapidActingChild.subtitle), - isSelected: isSelected(ExponentialInsulinModelPreset.rapidActingChild) - ) - .padding(.vertical, 4) - .padding(.bottom, 4) - } - .buttonStyle(PlainButtonStyle()) // Disable row highlighting on selection - } - } - - var insulinModelSettingDescription: Text { - let spellOutFormatter = NumberFormatter() - spellOutFormatter.numberStyle = .spellOut - let modelCountString = spellOutFormatter.string(from: selectableInsulinModelSettings.count as NSNumber)! - return Text(String(format: LocalizedString("For fast acting insulin, %1$@ assumes it is actively working for 6 hours. You can choose from %2$@ different models for how the app measures the insulin’s peak activity.", comment: "Insulin model setting description (1: app name) (2: number of models)"), appName, modelCountString)) - } - - var selectableInsulinModelSettings: [ExponentialInsulinModelPreset] { - return [ - .rapidActingAdult, - .rapidActingChild - ] - } - - private var selectedInsulinModelValues: [GlucoseValue] { - oneUnitBolusEffectPrediction(using: value) - } - - private var unselectedInsulinModelValues: [[GlucoseValue]] { - selectableInsulinModelSettings - .filter { $0 != value } - .map { oneUnitBolusEffectPrediction(using: $0) } - } - - private func oneUnitBolusEffectPrediction(using modelPreset: ExponentialInsulinModelPreset) -> [GlucoseValue] { - let bolus = DoseEntry(type: .bolus, startDate: chartManager.startDate, value: 1, unit: .units, insulinType: .novolog) - let startingGlucoseSample = HKQuantitySample(type: HKQuantityType.quantityType(forIdentifier: .bloodGlucose)!, quantity: startingGlucoseQuantity, start: chartManager.startDate, end: chartManager.startDate) - let effects = [bolus].glucoseEffects(insulinModelProvider: StaticInsulinModelProvider(modelPreset), longestEffectDuration: .hours(6), insulinSensitivity: insulinSensitivitySchedule) - return LoopMath.predictGlucose(startingAt: startingGlucoseSample, effects: effects) - } - - private var startingGlucoseQuantity: HKQuantity { - let startingGlucoseValue = insulinSensitivitySchedule.quantity(at: chartManager.startDate).doubleValue(for: displayGlucoseUnit) + displayGlucoseUnit.glucoseExampleTargetValue - return HKQuantity(unit: displayGlucoseUnit, doubleValue: startingGlucoseValue) - } - - private var endingGlucoseQuantity: HKQuantity { - HKQuantity(unit: displayGlucoseUnit, doubleValue: displayGlucoseUnit.glucoseExampleTargetValue) - } - - private func isSelected(_ preset: ExponentialInsulinModelPreset) -> Binding { - Binding( - get: { value == preset }, - set: { isSelected in - if isSelected { - withAnimation { - value = preset - } - } - } - ) - } - - private func startSaving() { - guard mode == .settings else { - continueSaving() - return - } - authenticate(TherapySetting.insulinModel.authenticationChallengeDescription) { - switch $0 { - case .success: continueSaving() - case .failure: break - } - } - } - - private func continueSaving() { - save(value) - } - - var dismissButton: some View { - Button(action: dismiss) { - Text(LocalizedString("Close", comment: "Button text to close a modal")) - } - } -} - -fileprivate extension HKUnit { - /// An example value for the "ideal" target - var glucoseExampleTargetValue: Double { - if self == .milligramsPerDeciliter { - return 100 - } else { - return 5.5 - } - } -} - -fileprivate struct SectionDivider: View { - var body: some View { - Divider() - .padding(.trailing, -16) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/InsulinSensitivityScheduleEditor.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/InsulinSensitivityScheduleEditor.swift deleted file mode 100644 index 4f6979421..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/InsulinSensitivityScheduleEditor.swift +++ /dev/null @@ -1,115 +0,0 @@ -// -// InsulinSensitivityScheduleEditor.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/20/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - - -public struct InsulinSensitivityScheduleEditor: View { - @EnvironmentObject private var displayGlucoseUnitObservable: DisplayGlucoseUnitObservable - @Environment(\.appName) private var appName - - let mode: SettingsPresentationMode - let viewModel: InsulinSensitivityScheduleEditorViewModel - - var displayGlucoseUnit: HKUnit { - displayGlucoseUnitObservable.displayGlucoseUnit - } - - public init( - mode: SettingsPresentationMode, - therapySettingsViewModel: TherapySettingsViewModel, - didSave: (() -> Void)? = nil - ) { - self.mode = mode - self.viewModel = InsulinSensitivityScheduleEditorViewModel( - therapySettingsViewModel: therapySettingsViewModel, - didSave: didSave) - } - - public var body: some View { - QuantityScheduleEditor( - title: Text(TherapySetting.insulinSensitivity.title), - description: description, - schedule: viewModel.insulinSensitivitySchedule?.schedule(for: displayGlucoseUnit), - unit: sensitivityUnit, - guardrail: .insulinSensitivity, - selectableValueStride: stride, - defaultFirstScheduleItemValue: Guardrail.insulinSensitivity.startingSuggestion ?? Guardrail.insulinSensitivity.recommendedBounds.upperBound, - confirmationAlertContent: confirmationAlertContent, - guardrailWarning: InsulinSensitivityGuardrailWarning.init(crossedThresholds:), - onSave: { insulinSensitivitySchedulePerU in - // the sensitivity units are passed as the units to display `/U` - // need to go back to displayGlucoseUnit. This does not affect the value - // force unwrapping since dailyItems are already validated - let insulinSensitivitySchedule = InsulinSensitivitySchedule(unit: displayGlucoseUnit, - dailyItems: insulinSensitivitySchedulePerU.items, - timeZone: insulinSensitivitySchedulePerU.timeZone)! - viewModel.saveInsulinSensitivitySchedule(insulinSensitivitySchedule) - }, - mode: mode, - settingType: .insulinSensitivity - ) - } - - private var description: Text { - Text(TherapySetting.insulinSensitivity.descriptiveText(appName: appName)) - } - - private var sensitivityUnit: HKUnit { - displayGlucoseUnit.unitDivided(by: .internationalUnit()) - } - - private var stride: HKQuantity { - let doubleValue: Double - switch displayGlucoseUnit { - case .milligramsPerDeciliter: - doubleValue = 1 - case .millimolesPerLiter: - doubleValue = 0.1 - case let otherUnit: - fatalError("Unsupported glucose unit \(otherUnit)") - } - - return HKQuantity(unit: sensitivityUnit, doubleValue: doubleValue) - } - - private var confirmationAlertContent: AlertContent { - AlertContent( - title: Text(LocalizedString("Save Insulin Sensitivities?", comment: "Alert title for confirming insulin sensitivities outside the recommended range")), - message: Text(TherapySetting.insulinSensitivity.guardrailSaveWarningCaption) - ) - } -} - -private struct InsulinSensitivityGuardrailWarning: View { - var crossedThresholds: [SafetyClassification.Threshold] - - var body: some View { - assert(!crossedThresholds.isEmpty) - return GuardrailWarning( - therapySetting: .insulinSensitivity, - title: crossedThresholds.count == 1 ? singularWarningTitle(for: crossedThresholds.first!) : multipleWarningTitle, - thresholds: crossedThresholds - ) - } - - private func singularWarningTitle(for threshold: SafetyClassification.Threshold) -> Text { - switch threshold { - case .minimum, .belowRecommended: - return Text(LocalizedString("Low Insulin Sensitivity", comment: "Title text for the low insulin sensitivity warning")) - case .aboveRecommended, .maximum: - return Text(LocalizedString("High Insulin Sensitivity", comment: "Title text for the high insulin sensitivity warning")) - } - } - - private var multipleWarningTitle: Text { - Text(LocalizedString("Insulin Sensitivities", comment: "Title text for multi-value insulin sensitivity warning")) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/PumpSupportedIncrements.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/PumpSupportedIncrements.swift deleted file mode 100644 index c42aaa516..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/PumpSupportedIncrements.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// PumpSupportedIncrements.swift -// LoopKitUI -// -// Created by Rick Pasetto on 7/16/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -public struct PumpSupportedIncrements { - let basalRates: [Double] - let bolusVolumes: [Double] - let maximumBolusVolumes: [Double] - let maximumBasalScheduleEntryCount: Int - public init(basalRates: [Double], bolusVolumes: [Double], maximumBolusVolumes: [Double], maximumBasalScheduleEntryCount: Int) { - self.basalRates = basalRates - self.bolusVolumes = bolusVolumes - self.maximumBolusVolumes = maximumBolusVolumes - self.maximumBasalScheduleEntryCount = maximumBasalScheduleEntryCount - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/SettingsPresentationMode.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/SettingsPresentationMode.swift deleted file mode 100644 index 829a3eaa1..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/SettingsPresentationMode.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// SettingsPresentationMode.swift -// LoopKitUI -// -// Created by Anna Quinlan on 7/21/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -/// Represents the different modes that settings screens might be represented in -public enum SettingsPresentationMode { - /// Presentation is in the onboarding acceptance flow - case acceptanceFlow - /// Presentation is under the settings ("gear icon") screen - case settings -} - -extension SettingsPresentationMode { - /// Text for the button at the bottom of the settings screen - func buttonText(isSaving: Bool = false) -> String { - switch self { - case .acceptanceFlow: - return LocalizedString("Confirm Setting", comment: "The button text for confirming the setting") - case .settings: - if isSaving { - return LocalizedString("Saving...", comment: "The button text during saving on a configuration page") - } else { - return LocalizedString("Save", comment: "The button text for saving on a configuration page") - } - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/SuspendThresholdEditor.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/SuspendThresholdEditor.swift deleted file mode 100644 index d3e67de65..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/SuspendThresholdEditor.swift +++ /dev/null @@ -1,235 +0,0 @@ -// -// SuspendThresholdEditor.swift -// LoopKitUI -// -// Created by Michael Pangburn on 4/10/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import HealthKit -import LoopKit - -// Also known as "Glucose Safety Limit" -public struct SuspendThresholdEditor: View { - @EnvironmentObject private var displayGlucoseUnitObservable: DisplayGlucoseUnitObservable - - @Environment(\.dismissAction) var dismiss - @Environment(\.authenticate) var authenticate - @Environment(\.appName) private var appName - - let mode: SettingsPresentationMode - let viewModel: SuspendThresholdEditorViewModel - - @State private var userDidTap: Bool = false - @State var value: HKQuantity - @State var isEditing = false - @State var showingConfirmationAlert = false - - private var initialValue: HKQuantity? { - viewModel.suspendThreshold - } - - public init( - mode: SettingsPresentationMode, - therapySettingsViewModel: TherapySettingsViewModel, - didSave: (() -> Void)? = nil - ) { - self.mode = mode - let viewModel = SuspendThresholdEditorViewModel(therapySettingsViewModel: therapySettingsViewModel, - mode: mode, - didSave: didSave) - self._value = State(initialValue: viewModel.suspendThreshold ?? Self.defaultValue(for: viewModel.suspendThresholdUnit)) - self.viewModel = viewModel - } - - private static func defaultValue(for unit: HKUnit) -> HKQuantity { - switch unit { - case .milligramsPerDeciliter: - return HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 80) - case .millimolesPerLiter: - return HKQuantity(unit: .millimolesPerLiter, doubleValue: 4.5) - default: - fatalError("Unsupported glucose unit \(unit)") - } - } - - public var body: some View { - switch mode { - case .acceptanceFlow: - content - case .settings: - contentWithCancel - .navigationBarTitle("", displayMode: .inline) - } - } - - private var contentWithCancel: some View { - if value == initialValue { - return AnyView(content - .navigationBarBackButtonHidden(false) - .navigationBarItems(leading: EmptyView()) - ) - } else { - return AnyView(content - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: cancelButton) - ) - } - } - - private var cancelButton: some View { - Button(action: { self.dismiss() } ) { Text(LocalizedString("Cancel", comment: "Cancel editing settings button title")) } - } - - private var picker: GlucoseValuePicker { - GlucoseValuePicker( - value: self.$value.animation(), - unit: displayGlucoseUnitObservable.displayGlucoseUnit, - guardrail: viewModel.guardrail, - bounds: viewModel.guardrail.absoluteBounds.lowerBound...viewModel.maxSuspendThresholdValue - ) - } - - private var content: some View { - ConfigurationPage( - title: Text(TherapySetting.suspendThreshold.title), - actionButtonTitle: Text(mode.buttonText()), - actionButtonState: saveButtonState, - cards: { - Card { - SettingDescription(text: description, informationalContent: { TherapySetting.suspendThreshold.helpScreen() }) - ExpandableSetting( - isEditing: $isEditing, - valueContent: { - GuardrailConstrainedQuantityView( - value: value, - unit: displayGlucoseUnitObservable.displayGlucoseUnit, - guardrail: viewModel.guardrail, - isEditing: isEditing, - // Workaround for strange animation behavior on appearance - forceDisableAnimations: true - ) - }, - expandedContent: { - // Prevent the picker from expanding the card's width on small devices - picker.frame(maxWidth: 200) - } - ) - } - }, - actionAreaContent: { - instructionalContentIfNecessary - if warningThreshold != nil && (userDidTap || mode != .acceptanceFlow) { - SuspendThresholdGuardrailWarning(safetyClassificationThreshold: warningThreshold!) - } - }, - action: { - if self.warningThreshold == nil { - self.startSaving() - } else { - self.showingConfirmationAlert = true - } - } - ) - .alert(isPresented: $showingConfirmationAlert, content: confirmationAlert) - .simultaneousGesture(TapGesture().onEnded { - withAnimation { - self.userDidTap = true - } - }) - } - - var description: Text { - Text(TherapySetting.suspendThreshold.descriptiveText(appName: appName)) - } - - private var instructionalContentIfNecessary: some View { - return Group { - if mode == .acceptanceFlow && !userDidTap { - instructionalContent - } - } - } - - private var instructionalContent: some View { - HStack { // to align with guardrail warning, if present - Text(LocalizedString("You can edit the setting by tapping into the line item.", comment: "Description of how to edit setting")) - .foregroundColor(.secondary) - .font(.subheadline) - Spacer() - } - } - - private var saveButtonState: ConfigurationPageActionButtonState { - let selectableValues = picker.selectableValues - let adjustedBounds = (selectableValues.first!)...(selectableValues.last!) - guard adjustedBounds.contains(value.doubleValue(for: displayGlucoseUnitObservable.displayGlucoseUnit)) else { - return .disabled - } - return initialValue == nil || value != initialValue || mode == .acceptanceFlow ? .enabled : .disabled - } - - private var warningThreshold: SafetyClassification.Threshold? { - switch viewModel.guardrail.classification(for: value) { - case .withinRecommendedRange: - return nil - case .outsideRecommendedRange(let threshold): - return threshold - } - } - - private func confirmationAlert() -> SwiftUI.Alert { - SwiftUI.Alert( - title: Text(LocalizedString("Save Glucose Safety Limit?", comment: "Alert title for confirming a glucose safety limit outside the recommended range")), - message: Text(TherapySetting.suspendThreshold.guardrailSaveWarningCaption), - primaryButton: .cancel(Text(LocalizedString("Go Back", comment: "Text for go back action on confirmation alert"))), - secondaryButton: .default( - Text(LocalizedString("Continue", comment: "Text for continue action on confirmation alert")), - action: startSaving - ) - ) - } - - private func startSaving() { - guard mode == .settings else { - self.continueSaving() - return - } - authenticate(TherapySetting.suspendThreshold.authenticationChallengeDescription) { - switch $0 { - case .success: self.continueSaving() - case .failure: break - } - } - } - - private func continueSaving() { - viewModel.saveSuspendThreshold(self.value, displayGlucoseUnitObservable.displayGlucoseUnit) - } -} - -struct SuspendThresholdGuardrailWarning: View { - var safetyClassificationThreshold: SafetyClassification.Threshold - - var body: some View { - GuardrailWarning(therapySetting: .suspendThreshold, title: title, threshold: safetyClassificationThreshold) - } - - private var title: Text { - switch safetyClassificationThreshold { - case .minimum, .belowRecommended: - return Text(LocalizedString("Low Glucose Safety Limit", comment: "Title text for the low glucose safety limit warning")) - case .aboveRecommended, .maximum: - return Text(LocalizedString("High Glucose Safety Limit", comment: "Title text for the high glucose safety limit warning")) - } - } -} - -struct SuspendThresholdView_Previews: PreviewProvider { - static var previews: some View { - let therapySettingsViewModel = TherapySettingsViewModel(therapySettings: TherapySettings()) - return SuspendThresholdEditor(mode: .settings, therapySettingsViewModel: therapySettingsViewModel, didSave: nil) - .environmentObject(DisplayGlucoseUnitObservable(displayGlucoseUnit: .milligramsPerDeciliter)) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/TherapySetting+Settings.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/TherapySetting+Settings.swift deleted file mode 100644 index 8884eb525..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/TherapySetting+Settings.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// TherapySetting+Settings.swift -// LoopKitUI -// -// Created by Rick Pasetto on 7/14/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import LoopKit -import SwiftUI - -extension TherapySetting { - - public var authenticationChallengeDescription: String { - switch self { - default: - // Currently, this is the same no matter what the setting is. - return LocalizedString("Authenticate to save therapy setting", comment: "Authentication hint string for therapy settings") - } - } - - public func helpScreen() -> some View { - switch self { - case .glucoseTargetRange: - return AnyView(CorrectionRangeInformationView(onExit: nil, mode: .settings)) - case .preMealCorrectionRangeOverride: - return AnyView(CorrectionRangeOverrideInformationView(preset: .preMeal, onExit: nil, mode: .settings)) - case .workoutCorrectionRangeOverride: - return AnyView(CorrectionRangeOverrideInformationView(preset: .workout, onExit: nil, mode: .settings)) - case .suspendThreshold: - return AnyView(SuspendThresholdInformationView(onExit: nil, mode: .settings)) - case .basalRate(let maximumScheduleEntryCount): - return AnyView(BasalRatesInformationView(onExit: nil, mode: .settings, maximumScheduleEntryCount: maximumScheduleEntryCount)) - case .deliveryLimits: - return AnyView(DeliveryLimitsInformationView(onExit: nil, mode: .settings)) - case .insulinModel: - return AnyView(InsulinModelInformationView(onExit: nil, mode: .settings)) - case .carbRatio: - return AnyView(CarbRatioInformationView(onExit: nil, mode: .settings)) - case .insulinSensitivity: - return AnyView(InsulinSensitivityInformationView(onExit: nil, mode: .settings)) - case .none: - return AnyView(Text("To be implemented")) - } - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/TherapySettingsView.swift b/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/TherapySettingsView.swift deleted file mode 100644 index 46c9e0c7b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/Settings Editors/TherapySettingsView.swift +++ /dev/null @@ -1,694 +0,0 @@ -// -// TherapySettingsView.swift -// LoopKitUI -// -// Created by Rick Pasetto on 7/7/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import AVFoundation -import HealthKit -import LoopKit -import SwiftUI - -public struct TherapySettingsView: View { - @EnvironmentObject private var displayGlucoseUnitObservable: DisplayGlucoseUnitObservable - @Environment(\.chartColorPalette) var chartColorPalette - @Environment(\.dismissAction) var dismissAction - @Environment(\.appName) private var appName - - public struct ActionButton { - public init(localizedString: String, action: @escaping () -> Void) { - self.localizedString = localizedString - self.action = action - } - let localizedString: String - let action: () -> Void - } - - private let mode: SettingsPresentationMode - - @ObservedObject var viewModel: TherapySettingsViewModel - - private let actionButton: ActionButton? - - public init(mode: SettingsPresentationMode, - viewModel: TherapySettingsViewModel, - actionButton: ActionButton? = nil) { - self.mode = mode - self.viewModel = viewModel - self.actionButton = actionButton - } - - public var body: some View { - switch mode { - case .acceptanceFlow: - content - case .settings: - navigationViewWrappedContent - } - } - - private var content: some View { - CardList(title: cardListTitle, style: .sectioned(cardListSections), trailer: cardListTrailer) - } - - private var cardListTitle: Text? { mode == .acceptanceFlow ? Text(therapySettingsTitle) : nil } - - private var therapySettingsTitle: String { - return LocalizedString("Therapy Settings", comment: "Therapy Settings screen title") - } - - private var cardListSections: [CardListSection] { - var cardListSections: [CardListSection] = [] - - cardListSections.append(therapySettingsCardListSection) - if mode == .settings { - cardListSections.append(supportCardListSection) - } - - return cardListSections - } - - private var therapySettingsCardListSection: CardListSection { - CardListSection { - therapySettingsCardStack - .spacing(20) - } - } - - private var therapySettingsCardStack: CardStack { - var cards: [Card] = [] - - if mode == .acceptanceFlow { - if viewModel.prescription != nil { - cards.append(prescriptionSection) - } else { - cards.append(summaryHeaderSection) - } - } - cards.append(suspendThresholdSection) - cards.append(correctionRangeSection) - cards.append(preMealCorrectionRangeSection) - if !viewModel.sensitivityOverridesEnabled { - cards.append(workoutCorrectionRangeSection) - } - cards.append(carbRatioSection) - cards.append(basalRatesSection) - cards.append(deliveryLimitsSection) - if viewModel.adultChildInsulinModelSelectionEnabled { - cards.append(insulinModelSection) - } - cards.append(insulinSensitivitiesSection) - - return CardStack(cards: cards) - } - - private var supportCardListSection: CardListSection { - CardListSection(title: Text(LocalizedString("Support", comment: "Title for support section"))) { - supportSection - } - } - - private var navigationViewWrappedContent: some View { - NavigationView { - ZStack { - Color(.systemGroupedBackground) - .edgesIgnoringSafeArea(.all) - content - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - dismissButton - } - } - .navigationBarTitle(therapySettingsTitle, displayMode: .large) - } - } - } - - private var dismissButton: some View { - Button(action: dismissAction) { - Text(LocalizedString("Done", comment: "Text for dismiss button")) - .bold() - } - } - - @ViewBuilder - private var cardListTrailer: some View { - if mode == .acceptanceFlow { - if let actionButton = actionButton { - Button(action: actionButton.action) { - Text(actionButton.localizedString) - } - .buttonStyle(ActionButtonStyle(.primary)) - .padding() - } - } - } -} - -// MARK: Sections -extension TherapySettingsView { - - private var prescriptionSection: Card { - Card { - HStack { - VStack(alignment: .leading) { - Text(LocalizedString("Prescription", comment: "title for prescription section")) - .bold() - Spacer() - DescriptiveText(label: prescriptionDescriptiveText) - } - Spacer() - } - } - } - - private var summaryHeaderSection: Card { - Card { - VStack(alignment: .leading) { - Text(LocalizedString("Review and Save Settings", comment: "title for summary description section")) - .bold() - .foregroundColor(.white) - Spacer() - VStack (alignment: .leading, spacing: 10) { - DescriptiveText(label: summaryHeaderReviewText, color: .white) - .fixedSize(horizontal: false, vertical: true) - DescriptiveText(label: summaryHeaderEditText, color: .white) - .fixedSize(horizontal: false, vertical: true) - } - } - } - .backgroundColor(Color.accentColor) - } - - private var summaryHeaderReviewText: String { - String(format: LocalizedString("Review your therapy settings below. If you’d like to edit any of these settings, tap Back to go back to that screen.", comment: "Description of how to interact with summary screen")) - } - - private var summaryHeaderEditText: String { - String(format: LocalizedString("If these settings look good to you, tap Save Settings to continue.", comment: "Description of how to interact with summary screen")) - } - - private var prescriptionDescriptiveText: String { - guard let prescription = viewModel.prescription else { - return "" - } - return String(format: LocalizedString("Submitted by %1$@, %2$@", comment: "Format for prescription descriptive text (1: providerName, 2: datePrescribed)"), - prescription.providerName, - DateFormatter.localizedString(from: prescription.datePrescribed, dateStyle: .short, timeStyle: .none)) - } - - private var suspendThresholdSection: Card { - card(for: .suspendThreshold) { - SectionDivider() - HStack { - Spacer() - GuardrailConstrainedQuantityView( - value: self.viewModel.suspendThreshold?.quantity, - unit: glucoseUnit, - guardrail: .suspendThreshold, - isEditing: false, - // Workaround for strange animation behavior on appearance - forceDisableAnimations: true - ) - } - } - } - - private var correctionRangeSection: Card { - card(for: .glucoseTargetRange) { - if let items = self.viewModel.glucoseTargetRangeSchedule(for: glucoseUnit)?.items - { - SectionDivider() - ForEach(items.indices, id: \.self) { index in - if index > 0 { - SettingsDivider() - } - ScheduleRangeItem(time: items[index].startTime, - range: items[index].value, - unit: glucoseUnit, - guardrail: .correctionRange) - } - } - } - } - - private var preMealCorrectionRangeSection: Card { - card(for: .preMealCorrectionRangeOverride) { - let correctionRangeOverrides = self.viewModel.correctionRangeOverrides - if let schedule = self.viewModel.glucoseTargetRangeSchedule - { - SectionDivider() - CorrectionRangeOverridesRangeItem( - value: correctionRangeOverrides, - displayGlucoseUnit: glucoseUnit, - preset: CorrectionRangeOverrides.Preset.preMeal, - suspendThreshold: viewModel.suspendThreshold, - correctionRangeScheduleRange: schedule.scheduleRange() - ) - } - } - } - - private var workoutCorrectionRangeSection: Card { - card(for: .workoutCorrectionRangeOverride) { - let correctionRangeOverrides = self.viewModel.correctionRangeOverrides - if let schedule = self.viewModel.glucoseTargetRangeSchedule - { - SectionDivider() - CorrectionRangeOverridesRangeItem( - value: correctionRangeOverrides, - displayGlucoseUnit: glucoseUnit, - preset: CorrectionRangeOverrides.Preset.workout, - suspendThreshold: self.viewModel.suspendThreshold, - correctionRangeScheduleRange: schedule.scheduleRange() - ) - } - } - } - - private var basalRatesSection: Card { - card(for: .basalRate) { - if let schedule = viewModel.therapySettings.basalRateSchedule, - let supportedBasalRates = viewModel.pumpSupportedIncrements()?.basalRates - { - let items = schedule.items - let total = schedule.total() - SectionDivider() - ForEach(items.indices, id: \.self) { index in - if index > 0 { - SettingsDivider() - } - ScheduleValueItem(time: items[index].startTime, - value: items[index].value, - unit: .internationalUnitsPerHour, - guardrail: .basalRate(supportedBasalRates: supportedBasalRates)) - } - SectionDivider() - HStack { - Text(NSLocalizedString("Total", comment: "The text indicating Total for Daily Schedule Basal")) - .bold() - .foregroundColor(.primary) - Spacer() - Text(String(format: "%.2f ",total)) - .foregroundColor(.primary) + - Text(NSLocalizedString("U/day", comment: "The text indicating U/day for Daily Schedule Basal")) - .foregroundColor(.secondary) - } - } - } - } - - private var deliveryLimitsSection: Card { - card(for: .deliveryLimits) { - SectionDivider() - self.maxBasalRateItem - SettingsDivider() - self.maxBolusItem - } - } - - private var maxBasalRateItem: some View { - HStack { - Text(DeliveryLimits.Setting.maximumBasalRate.title) - Spacer() - if let basalRates = self.viewModel.pumpSupportedIncrements()?.basalRates { - GuardrailConstrainedQuantityView( - value: self.viewModel.therapySettings.maximumBasalRatePerHour.map { HKQuantity(unit: .internationalUnitsPerHour, doubleValue: $0) }, - unit: .internationalUnitsPerHour, - guardrail: .maximumBasalRate( - supportedBasalRates: basalRates, - scheduledBasalRange: self.viewModel.therapySettings.basalRateSchedule?.valueRange(), - lowestCarbRatio: self.viewModel.therapySettings.carbRatioSchedule?.lowestValue()), - isEditing: false, - // Workaround for strange animation behavior on appearance - forceDisableAnimations: true - ) - } - } - .accessibilityElement(children: .combine) - } - - private var maxBolusItem: some View { - HStack { - Text(DeliveryLimits.Setting.maximumBolus.title) - Spacer() - if let maximumBolusVolumes = self.viewModel.pumpSupportedIncrements()?.maximumBolusVolumes { - GuardrailConstrainedQuantityView( - value: self.viewModel.therapySettings.maximumBolus.map { HKQuantity(unit: .internationalUnit(), doubleValue: $0) }, - unit: .internationalUnit(), - guardrail: .maximumBolus(supportedBolusVolumes: maximumBolusVolumes), - isEditing: false, - // Workaround for strange animation behavior on appearance - forceDisableAnimations: true - ) - } - } - .accessibilityElement(children: .combine) - } - - private var insulinModelSection: Card { - card(for: .insulinModel) { - if let insulinModelPreset = self.viewModel.therapySettings.defaultRapidActingModel { - SectionDivider() - HStack { - // Spacing and paddings here is my best guess based on the design... - VStack(alignment: .leading, spacing: 4) { - Text(insulinModelPreset.title) - .font(.body) - .padding(.top, 5) - .fixedSize(horizontal: false, vertical: true) - Text(insulinModelPreset.subtitle) - .font(.footnote) - .foregroundColor(.secondary) - .padding(.bottom, 8) - .fixedSize(horizontal: false, vertical: true) - } - Spacer() - Image(systemName: "checkmark") - .font(Font.system(.title2).weight(.semibold)) - .foregroundColor(.accentColor) - } - .accessibilityElement(children: .combine) - } - } - } - - private var carbRatioSection: Card { - card(for: .carbRatio) { - if let items = viewModel.therapySettings.carbRatioSchedule?.items { - SectionDivider() - ForEach(items.indices, id: \.self) { index in - if index > 0 { - SettingsDivider() - } - ScheduleValueItem(time: items[index].startTime, - value: items[index].value, - unit: .gramsPerUnit, - guardrail: .carbRatio) - } - } - } - } - - private var insulinSensitivitiesSection: Card { - card(for: .insulinSensitivity) { - if let items = viewModel.insulinSensitivitySchedule(for: glucoseUnit)?.items { - SectionDivider() - ForEach(items.indices, id: \.self) { index in - if index > 0 { - SettingsDivider() - } - ScheduleValueItem(time: items[index].startTime, - value: items[index].value, - unit: sensitivityUnit, - guardrail: .insulinSensitivity) - } - } - } - } - - private var supportSection: some View { - Section { - NavigationLink(destination: Text("Therapy Settings Support Placeholder")) { - HStack { - Text("Get help with Therapy Settings", comment: "Support button for Therapy Settings") - .foregroundColor(.primary) - Spacer() - Disclosure() - } - } - } - .contentShape(Rectangle()) - } -} - -// MARK: Navigation - -extension TherapySettingsView { - - func screen(for setting: TherapySetting) -> (_ dismiss: @escaping () -> Void) -> AnyView { - switch setting { - case .suspendThreshold: - return { dismiss in - AnyView(SuspendThresholdEditor(mode: mode, therapySettingsViewModel: viewModel, didSave: dismiss).environment(\.dismissAction, dismiss)) - } - case .glucoseTargetRange: - return { dismiss in - AnyView(CorrectionRangeScheduleEditor(mode: mode, therapySettingsViewModel: viewModel, didSave: dismiss).environment(\.dismissAction, dismiss)) - } - case .preMealCorrectionRangeOverride: - return { dismiss in - AnyView(CorrectionRangeOverridesEditor(mode: mode, therapySettingsViewModel: viewModel, preset: .preMeal, didSave: dismiss).environment(\.dismissAction, dismiss)) - } - case .workoutCorrectionRangeOverride: - return { dismiss in - AnyView(CorrectionRangeOverridesEditor(mode: mode, therapySettingsViewModel: viewModel, preset: .workout, didSave: dismiss).environment(\.dismissAction, dismiss)) - } - case .basalRate: - return { dismiss in - AnyView(BasalRateScheduleEditor(mode: mode, therapySettingsViewModel: viewModel, didSave: dismiss).environment(\.dismissAction, dismiss)) - } - case .deliveryLimits: - return { dismiss in - AnyView(DeliveryLimitsEditor(mode: mode, therapySettingsViewModel: viewModel, didSave: dismiss).environment(\.dismissAction, dismiss)) - } - case .insulinModel: - return { dismiss in - AnyView(InsulinModelSelection(mode: mode, therapySettingsViewModel: viewModel, chartColors: chartColorPalette, didSave: dismiss).environment(\.dismissAction, dismiss)) - } - case .carbRatio: - return { dismiss in - AnyView(CarbRatioScheduleEditor(mode: mode, therapySettingsViewModel: viewModel, didSave: dismiss).environment(\.dismissAction, dismiss)) - } - case .insulinSensitivity: - return { dismiss in - AnyView(InsulinSensitivityScheduleEditor(mode: mode, therapySettingsViewModel: viewModel, didSave: dismiss).environment(\.dismissAction, dismiss)) - } - case .none: - break - } - return { _ in AnyView(Text("\(setting.title)")) } - } -} - -// MARK: Utilities -extension TherapySettingsView { - - private var glucoseUnit: HKUnit { - displayGlucoseUnitObservable.displayGlucoseUnit - } - - private var sensitivityUnit: HKUnit { - glucoseUnit.unitDivided(by: .internationalUnit()) - } - - private func card(for therapySetting: TherapySetting, @ViewBuilder content: @escaping () -> Content) -> Card where Content: View { - Card { - SectionWithTapToEdit(isEnabled: mode != .acceptanceFlow, - title: therapySetting.title, - descriptiveText: therapySetting.descriptiveText(appName: appName), - destination: screen(for: therapySetting), - content: content) - } - } -} - -typealias HKQuantityGuardrail = Guardrail - -struct ScheduleRangeItem: View { - let time: TimeInterval - let range: DoubleRange - let unit: HKUnit - let guardrail: HKQuantityGuardrail - - public var body: some View { - ScheduleItemView(time: time, - isEditing: .constant(false), - valueContent: { - GuardrailConstrainedQuantityRangeView(range: range.quantityRange(for: unit), unit: unit, guardrail: guardrail, isEditing: false) - .padding(.leading, 10) - }, - expandedContent: { EmptyView() }) - } -} - -struct ScheduleValueItem: View { - let time: TimeInterval - let value: Double - let unit: HKUnit - let guardrail: HKQuantityGuardrail - - public var body: some View { - ScheduleItemView(time: time, - isEditing: .constant(false), - valueContent: { - GuardrailConstrainedQuantityView(value: HKQuantity(unit: unit, doubleValue: value), unit: unit, guardrail: guardrail, isEditing: false) - .padding(.leading, 10) - }, - expandedContent: { EmptyView() }) - } -} - -struct CorrectionRangeOverridesRangeItem: View { - let value: CorrectionRangeOverrides - let displayGlucoseUnit: HKUnit - let preset: CorrectionRangeOverrides.Preset - let suspendThreshold: GlucoseThreshold? - let correctionRangeScheduleRange: ClosedRange - - public var body: some View { - CorrectionRangeOverridesExpandableSetting( - isEditing: .constant(false), - value: .constant(value), - preset: preset, - unit: displayGlucoseUnit, - suspendThreshold: suspendThreshold, - correctionRangeScheduleRange: correctionRangeScheduleRange, - expandedContent: { EmptyView() }) - } -} - -struct SectionWithTapToEdit: View where Content: View, NavigationDestination: View { - let isEnabled: Bool - let title: String - let descriptiveText: String - let destination: (_ goBack: @escaping () -> Void) -> NavigationDestination - let content: Content - - @State var isActive: Bool = false - - init(isEnabled: Bool, - title: String, - descriptiveText: String, - destination: @escaping (@escaping () -> Void) -> NavigationDestination, - content: () -> Content) - { - self.isEnabled = isEnabled - self.title = title - self.descriptiveText = descriptiveText - self.destination = destination - self.content = content() - } - - private func onFinish() { - // Dispatching here fixes an issue on iOS 14.2 where schedule editors do not dismiss. It does not fix iOS 14.0 and 14.1 - // Added a delay, since recently a similar issue was encountered in a plugin where a delay was also needed. Still uncertain why. - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - self.isActive = false - } - } - - public var body: some View { - Section { - VStack(alignment: .leading) { - Text(title) - .bold() - Spacer() - HStack { - DescriptiveText(label: descriptiveText) - .fixedSize(horizontal: false, vertical: true) - Spacer() - if isEnabled { - NavigationLink(destination: destination(onFinish), isActive: $isActive) { - Disclosure() - } - .frame(width: 10, alignment: .trailing) - } - } - Spacer() - } - content - } - .contentShape(Rectangle()) // make the whole card tappable - .highPriorityGesture( - TapGesture() - .onEnded { _ in - self.isActive = true - }) - } -} - -// MARK: Previews - -public struct TherapySettingsView_Previews: PreviewProvider { - - static let preview_glucoseScheduleItems = [ - RepeatingScheduleValue(startTime: 0, value: DoubleRange(80...90)), - RepeatingScheduleValue(startTime: 1800, value: DoubleRange(90...100)), - RepeatingScheduleValue(startTime: 3600, value: DoubleRange(100...110)) - ] - - static let preview_therapySettings = TherapySettings( - glucoseTargetRangeSchedule: GlucoseRangeSchedule(unit: .milligramsPerDeciliter, dailyItems: preview_glucoseScheduleItems), - correctionRangeOverrides: CorrectionRangeOverrides(preMeal: DoubleRange(88...99), - workout: DoubleRange(99...111), - unit: .milligramsPerDeciliter), - maximumBolus: 4, - suspendThreshold: GlucoseThreshold.init(unit: .milligramsPerDeciliter, value: 60), - insulinSensitivitySchedule: InsulinSensitivitySchedule(unit: HKUnit.milligramsPerDeciliter.unitDivided(by: HKUnit.internationalUnit()), dailyItems: []), - carbRatioSchedule: nil, - basalRateSchedule: BasalRateSchedule(dailyItems: [RepeatingScheduleValue(startTime: 0, value: 0.2), RepeatingScheduleValue(startTime: 1800, value: 0.75)])) - - static let preview_supportedBasalRates = [0.2, 0.5, 0.75, 1.0] - static let preview_supportedBolusVolumes = [1.0, 2.0, 3.0] - static let preview_supportedMaximumBolusVolumes = [5.0, 10.0, 15.0] - - static func preview_viewModel() -> TherapySettingsViewModel { - TherapySettingsViewModel(therapySettings: preview_therapySettings, - pumpSupportedIncrements: { - PumpSupportedIncrements(basalRates: preview_supportedBasalRates, - bolusVolumes: preview_supportedBolusVolumes, - maximumBolusVolumes: preview_supportedMaximumBolusVolumes, - maximumBasalScheduleEntryCount: 24) }) - } - - public static var previews: some View { - Group { - TherapySettingsView(mode: .acceptanceFlow, viewModel: preview_viewModel()) - .colorScheme(.light) - .previewDevice(PreviewDevice(rawValue: "iPhone SE 2")) - .previewDisplayName("SE light (onboarding)") - .environmentObject(DisplayGlucoseUnitObservable(displayGlucoseUnit: .milligramsPerDeciliter)) - TherapySettingsView(mode: .settings, viewModel: preview_viewModel()) - .colorScheme(.light) - .previewDevice(PreviewDevice(rawValue: "iPhone SE 2")) - .previewDisplayName("SE light (settings)") - .environmentObject(DisplayGlucoseUnitObservable(displayGlucoseUnit: .milligramsPerDeciliter)) - TherapySettingsView(mode: .settings, viewModel: preview_viewModel()) - .colorScheme(.dark) - .previewDevice(PreviewDevice(rawValue: "iPhone XS Max")) - .previewDisplayName("XS Max dark (settings)") - TherapySettingsView(mode: .settings, viewModel: TherapySettingsViewModel(therapySettings: TherapySettings())) - .colorScheme(.light) - .previewDevice(PreviewDevice(rawValue: "iPhone SE 2")) - .previewDisplayName("SE light (Empty TherapySettings)") - .environmentObject(DisplayGlucoseUnitObservable(displayGlucoseUnit: .millimolesPerLiter)) - } - } -} - -fileprivate struct SectionDivider: View { - var body: some View { - Divider() - .padding(.trailing, -16) - } -} - -fileprivate struct SettingsDivider: View { - var body: some View { - Divider() - .padding(.trailing, -8) - } -} - -fileprivate struct Disclosure: View { - var body: some View { - Image(systemName: "chevron.right") - .imageScale(.small) - .font(.headline) - .foregroundColor(.secondary) - .opacity(0.5) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SettingsTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/SettingsTableViewCell.swift deleted file mode 100644 index 5c8b60f4e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SettingsTableViewCell.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// SettingsTableViewCell.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - - -public class SettingsTableViewCell: UITableViewCell { - public static let EnabledString = LocalizedString("Enabled", comment: "The detail text describing an enabled setting") - public static let NoValueString = LocalizedString("–", comment: "The detail text representing no value") - public static let TapToSetString = LocalizedString("Tap to set", comment: "The empty-state text for a configuration value") - - public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: .value1, reuseIdentifier: reuseIdentifier) - - setup() - } - - required public init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - - setup() - } - - private func setup() { - textLabel?.adjustsFontForContentSizeCategory = true - textLabel?.font = UIFont.preferredFont(forTextStyle: .body) - detailTextLabel?.adjustsFontForContentSizeCategory = true - detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .body) - } - - override public func prepareForReuse() { - super.prepareForReuse() - accessoryType = .none - textLabel?.text = nil - detailTextLabel?.text = nil - accessoryView = nil - isUserInteractionEnabled = true - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SetupButton.swift b/Dependencies/LoopKit/LoopKitUI/Views/SetupButton.swift deleted file mode 100644 index 860b01fff..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SetupButton.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// SetupButton.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - -public class SetupButton: UIButton { - - public override init(frame: CGRect) { - super.init(frame: frame) - - setup() - } - - public required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - } - - public override func awakeFromNib() { - super.awakeFromNib() - - setup() - } - - private func setup() { - backgroundColor = tintColor - layer.cornerRadius = 6 - - titleLabel?.adjustsFontForContentSizeCategory = true - contentEdgeInsets.top = 14 - contentEdgeInsets.bottom = 14 - setTitleColor(.white, for: .normal) - } - - public override func tintColorDidChange() { - super.tintColorDidChange() - - backgroundColor = tintColor - } - - public override func prepareForInterfaceBuilder() { - super.prepareForInterfaceBuilder() - - tintColor = .blue - tintColorDidChange() - } - - public override var isHighlighted: Bool { - didSet { - alpha = isHighlighted ? 0.5 : 1 - } - } - - public override var isEnabled: Bool { - didSet { - tintAdjustmentMode = isEnabled ? .automatic : .dimmed - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SetupIndicatorView.swift b/Dependencies/LoopKit/LoopKitUI/Views/SetupIndicatorView.swift deleted file mode 100644 index be890ad13..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SetupIndicatorView.swift +++ /dev/null @@ -1,172 +0,0 @@ -// -// SetupIndicatorView.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - -@IBDesignable -public class SetupIndicatorView: UIView { - - public enum State: Equatable { - case hidden - case indeterminantProgress - case timedProgress(finishTime: CFTimeInterval) - case completed - } - - public var state: State = .hidden { - didSet { - animate(from: oldValue, to: state) - - if case let .timedProgress(finishTime) = state { - let duration = finishTime - CACurrentMediaTime() - progressView.progress = 0 - if duration > 0 { - let animator = UIViewPropertyAnimator(duration: duration, curve: .linear) - animator.addAnimations { - self.progressView.setProgress(1, animated: true) - } - animator.startAnimation() - self.progressAnimator = animator - } else { - progressView.progress = 1 - } - } - } - } - - @IBInspectable var animationDuration: Double = 0.5 - - - private func viewUsedInState(_ state: State) -> UIView? { - switch state { - case .hidden: - return nil - case .indeterminantProgress: - return activityIndicatorView - case .timedProgress: - return progressView - case .completed: - return completionImageView - } - } - - private func animate(from oldState: State, to newState: State) { - guard oldState != newState else { - return - } - - if let animator = self.animator, animator.isRunning { - animator.stopAnimation(true) - } - - // Figure out which views are not used in any ongoing animations - var unusedViews: Set = [activityIndicatorView, progressView, completionImageView] - - let viewToHide = viewUsedInState(oldState) - unusedViews.remove(viewToHide) - - let viewToShow = viewUsedInState(newState) - unusedViews.remove(viewToShow) - - for view in unusedViews { - view?.alpha = 0 - } - - if case .timedProgress = oldState { - progressAnimator?.stopAnimation(true) - } - - let animator = UIViewPropertyAnimator(duration: animationDuration, dampingRatio: 0.5) - animator.addAnimations { - - viewToHide?.alpha = 0 - viewToShow?.alpha = 1 - - switch oldState { - case .completed: - self.completionImageView.transform = CGAffineTransform(scaleX: 0.001, y: 0.001) - default: - break - } - - - switch newState { - case .indeterminantProgress: - self.activityIndicatorView.startAnimating() - case .completed: - self.completionImageView.transform = CGAffineTransform.identity - default: - break - } - } - animator.addCompletion { (position) in - if self.state != .indeterminantProgress { - self.activityIndicatorView.stopAnimating() - } - } - animator.startAnimation() - self.animator = animator - } - - private var progressAnimator: UIViewPropertyAnimator? - - private var animator: UIViewPropertyAnimator? - - private let activityIndicatorView = UIActivityIndicatorView(style: .default) - - private let progressView = UIProgressView(progressViewStyle: .default) - - private(set) var completionImageView: UIImageView! - - override init(frame: CGRect) { - super.init(frame: frame) - - setUp() - } - - required public init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - - setUp() - } - - private func setUp() { - let image = UIImage(named: "Checkmark", in: Bundle(for: type(of: self)), compatibleWith: traitCollection)! - completionImageView = UIImageView(image: image) - completionImageView.alpha = 0 - completionImageView.transform = CGAffineTransform(scaleX: 0.001, y: 0.001) - completionImageView.translatesAutoresizingMaskIntoConstraints = false - - activityIndicatorView.alpha = 0 - activityIndicatorView.hidesWhenStopped = true - activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false - - progressView.alpha = 0 - progressView.translatesAutoresizingMaskIntoConstraints = false - - addSubview(activityIndicatorView) - addSubview(progressView) - addSubview(completionImageView) - - NSLayoutConstraint.activate([ - heightAnchor.constraint(equalToConstant: image.size.height), - completionImageView.centerXAnchor.constraint(equalTo: centerXAnchor), - completionImageView.centerYAnchor.constraint(equalTo: centerYAnchor), - activityIndicatorView.centerXAnchor.constraint(equalTo: centerXAnchor), - activityIndicatorView.centerYAnchor.constraint(equalTo: centerYAnchor), - progressView.centerXAnchor.constraint(equalTo: centerXAnchor), - progressView.centerYAnchor.constraint(equalTo: centerYAnchor), - progressView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10), - progressView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10), - ]) - } - - override public var intrinsicContentSize: CGSize { - return completionImageView?.image?.size ?? activityIndicatorView.intrinsicContentSize - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SingleSelectionCheckList.swift b/Dependencies/LoopKit/LoopKitUI/Views/SingleSelectionCheckList.swift deleted file mode 100644 index 19ae7621b..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SingleSelectionCheckList.swift +++ /dev/null @@ -1,80 +0,0 @@ -// -// SingleSelectionCheckList.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2022-09-09. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct SingleSelectionCheckList: View { - let header: String? - let footer: String? - let items: [Item] - @Binding var selectedItem: Item - - public init(header: String? = nil, - footer: String? = nil, - items: [Item], - selectedItem: Binding, - formatter: ((Item) -> Item)? = nil) { - self.header = header - self.footer = footer - self.items = items - _selectedItem = selectedItem - } - - public var body: some View { - Section(header: header.map { Text($0) }, footer: footer.map { Text($0) }) { - ForEach(items, id:\.self) { item in - CheckSelectionRow(item: item, - selectedItem: self.$selectedItem) - } - } - } -} - -struct CheckSelectionRow: View where Item: Hashable { - var item: Item - @Binding var selectedItem: Item - - var isSelected: Bool { - selectedItem == item - } - - var body: some View { - HStack { - Button(action: { selectedItem = item } ) { - Text(String(describing: item)) - .foregroundColor(.primary) - } - Spacer() - if isSelected { - Image(systemName: "checkmark.circle.fill") - .foregroundColor(.accentColor) - } - } - } -} - -struct SingleSelectionCheckList_Previews: PreviewProvider { - static var previews: some View { - PreviewWrapper() - } - - struct PreviewWrapper: View { - enum Shape: String, CaseIterable { - case square = "Square" - case circle = "Circle" - case triangle = "Triangle" - case rectangle = "Rectangle" - } - @State var selectedFruit: Shape = .square - - var body: some View { - SingleSelectionCheckList(items: Shape.allCases, - selectedItem: $selectedFruit) - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SuspendResumeTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/SuspendResumeTableViewCell.swift deleted file mode 100644 index fc9cb87f8..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SuspendResumeTableViewCell.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// SuspendResumeTableViewCell.swift -// LoopKitUI -// -// Created by Pete Schwamb on 11/16/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -public class SuspendResumeTableViewCell: TextButtonTableViewCell { - - public enum Action { - case suspend - case resume - case inoperable - } - - public var shownAction: Action { - switch basalDeliveryState { - case .active, .suspending, .tempBasal, .cancelingTempBasal, .initiatingTempBasal: - return .suspend - case .suspended, .resuming: - return .resume - case .none: - return .inoperable - } - } - - private func updateTextLabel() { - switch self.basalDeliveryState { - case .active, .tempBasal: - textLabel?.text = LocalizedString("Suspend Delivery", comment: "Title text for button to suspend insulin delivery") - case .suspending: - self.textLabel?.text = LocalizedString("Suspending", comment: "Title text for button when insulin delivery is in the process of being stopped") - case .suspended: - textLabel?.text = LocalizedString("Resume Delivery", comment: "Title text for button to resume insulin delivery") - case .resuming: - self.textLabel?.text = LocalizedString("Resuming", comment: "Title text for button when insulin delivery is in the process of being resumed") - case .initiatingTempBasal: - self.textLabel?.text = LocalizedString("Starting Temp Basal", comment: "Title text for suspend resume button when temp basal starting") - case .cancelingTempBasal: - self.textLabel?.text = LocalizedString("Canceling Temp Basal", comment: "Title text for suspend resume button when temp basal canceling") - case .none: - self.textLabel?.text = LocalizedString("Pump Inoperable", comment: "Title text for suspend resume button when the basal delivery state is not set") - } - } - - private func updateLoadingState() { - self.isLoading = { - switch self.basalDeliveryState { - case .suspending, .resuming, .initiatingTempBasal, .cancelingTempBasal: - return true - default: - return false - } - }() - self.isEnabled = !self.isLoading - } - - public var basalDeliveryState: PumpManagerStatus.BasalDeliveryState? = .active(Date()) { - didSet { - updateTextLabel() - updateLoadingState() - } - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/SwitchTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/SwitchTableViewCell.swift deleted file mode 100644 index 7d889be58..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/SwitchTableViewCell.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// SwitchTableViewCell.swift -// Naterade -// -// Created by Nathan Racklyeft on 3/13/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -open class SwitchTableViewCell: UITableViewCell { - - public var `switch`: UISwitch? - - public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: .value1, reuseIdentifier: Self.className) - - setUp() - } - - required public init?(coder: NSCoder) { - super.init(coder: coder) - - setUp() - } - - private func setUp() { - `switch` = UISwitch(frame: .zero) - accessoryView = `switch` - } - - override open func layoutSubviews() { - super.layoutSubviews() - - contentView.layoutMargins.left = separatorInset.left - contentView.layoutMargins.right = separatorInset.left - } - - override open func prepareForReuse() { - super.prepareForReuse() - - self.switch?.removeTarget(nil, action: nil, for: .valueChanged) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/TableViewTitleLabel.swift b/Dependencies/LoopKit/LoopKitUI/Views/TableViewTitleLabel.swift deleted file mode 100644 index 29c029a1e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/TableViewTitleLabel.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// TableViewTitleLabel.swift -// LoopKitUI -// -// Created by Nathaniel Hamming on 2020-01-17. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import UIKit - -public class TableViewTitleLabel: UILabel { - - override public init(frame: CGRect) { - super.init(frame: frame) - initFont() - } - - required public init?(coder: NSCoder) { - super.init(coder: coder) - initFont() - } - - override public func awakeFromNib() { - super.awakeFromNib() - initFont() - } - - public func initFont() { - font = UIFont.titleFontGroupedInset - self.adjustsFontForContentSizeCategory = true - } - -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/TextButtonTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/TextButtonTableViewCell.swift deleted file mode 100644 index 9f5bc28e6..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/TextButtonTableViewCell.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// TextButtonTableViewCell.swift -// LoopKitUI -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - -open class TextButtonTableViewCell: LoadingTableViewCell { - - override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: .default, reuseIdentifier: reuseIdentifier) - - textLabel?.tintAdjustmentMode = .automatic - textLabel?.textColor = tintColor - } - - required public init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - } - - public var isEnabled = true { - didSet { - tintAdjustmentMode = isEnabled ? .normal : .dimmed - selectionStyle = isEnabled ? .default : .none - } - } - - open override func tintColorDidChange() { - super.tintColorDidChange() - - textLabel?.textColor = tintColor - } - - open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { - super.traitCollectionDidChange(previousTraitCollection) - - textLabel?.textColor = tintColor - } - - open override func prepareForReuse() { - super.prepareForReuse() - - textLabel?.textAlignment = .natural - tintColor = nil - isEnabled = true - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/TextFieldTableViewCell.swift b/Dependencies/LoopKit/LoopKitUI/Views/TextFieldTableViewCell.swift deleted file mode 100644 index 65187ce38..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/TextFieldTableViewCell.swift +++ /dev/null @@ -1,90 +0,0 @@ -// -// TextFieldTableViewCell.swift -// Naterade -// -// Created by Nathan Racklyeft on 5/22/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -public protocol TextFieldTableViewCellDelegate: AnyObject { - func textFieldTableViewCellDidBeginEditing(_ cell: TextFieldTableViewCell) - - func textFieldTableViewCellDidEndEditing(_ cell: TextFieldTableViewCell) - - func textFieldTableViewCellDidChangeEditing(_ cell: TextFieldTableViewCell) -} - -// MARK: - Default Implementations - -extension TextFieldTableViewCellDelegate { - public func textFieldTableViewCellDidChangeEditing(_ cell: TextFieldTableViewCell) { } -} - - -public class TextFieldTableViewCell: UITableViewCell, UITextFieldDelegate { - - @IBOutlet public weak var unitLabel: UILabel? { - didSet { - // Setting this color in code because the nib isn't being applied correctly - unitLabel?.textColor = .secondaryLabel - } - } - - @IBOutlet public weak var textField: UITextField! { - didSet { - textField.delegate = self - textField.addTarget(self, action: #selector(textFieldEditingChanged), for: .editingChanged) - - // Setting this color in code because the nib isn't being applied correctly - textField.textColor = .label - } - } - - public var maximumTextLength: Int? - - override public func prepareForReuse() { - super.prepareForReuse() - - textField.delegate = nil - unitLabel?.text = nil - } - - public weak var delegate: TextFieldTableViewCellDelegate? - - @objc private func textFieldEditingChanged() { - delegate?.textFieldTableViewCellDidChangeEditing(self) - } - - // MARK: - UITextFieldDelegate - - public func textFieldDidBeginEditing(_ textField: UITextField) { - // Even though we are likely already on .main, we still need to queue this cursor (selection) change in - // order for it to work - DispatchQueue.main.async { [weak self] in - guard let self = self else { return } - self.textField.moveCursorToEnd() - self.delegate?.textFieldTableViewCellDidBeginEditing(self) - } - } - - public func textFieldDidEndEditing(_ textField: UITextField) { - delegate?.textFieldTableViewCellDidEndEditing(self) - } - - public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - guard let maximumTextLength = maximumTextLength else { - return true - } - let text = textField.text ?? "" - let allText = (text as NSString).replacingCharacters(in: range, with: string) - if allText.count <= maximumTextLength { - return true - } else { - textField.text = String(allText.prefix(maximumTextLength)) - return false - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/TextFieldTableViewCell.xib b/Dependencies/LoopKit/LoopKitUI/Views/TextFieldTableViewCell.xib deleted file mode 100644 index 3583803ad..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/TextFieldTableViewCell.xib +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ThumbView.swift b/Dependencies/LoopKit/LoopKitUI/Views/ThumbView.swift deleted file mode 100644 index 453d9ccba..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ThumbView.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// ThumbView.swift -// LoopKitUI -// -// Created by Michael Pangburn on 2/23/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import UIKit - - -class ThumbView: UIView { - override func layoutSubviews() { - super.layoutSubviews() - - backgroundColor = .white - makeRound() - configureDropShadow() - } - - private func makeRound() { - layer.cornerRadius = min(frame.width, frame.height) / 2 - } - - private func configureDropShadow() { - layer.shadowOpacity = 0.3 - layer.shadowOffset = CGSize(width: -2, height: 0) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/ValidatingIndicatorView.swift b/Dependencies/LoopKit/LoopKitUI/Views/ValidatingIndicatorView.swift deleted file mode 100644 index d34317b63..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/ValidatingIndicatorView.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// ValidatingIndicatorView.swift -// Loop -// -// Created by Nate Racklyeft on 7/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - -private let Margin: CGFloat = 8 - - -public final class ValidatingIndicatorView: UIView { - - let indicatorView = UIActivityIndicatorView(style: .default) - - let label = UILabel() - - public override init(frame: CGRect) { - super.init(frame: frame) - label.font = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.headline) - label.text = LocalizedString("Verifying", comment: "Label indicating validation is occurring") - label.sizeToFit() - - addSubview(indicatorView) - addSubview(label) - - self.frame.size = intrinsicContentSize - - setNeedsLayout() - - indicatorView.startAnimating() - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public override func layoutSubviews() { - super.layoutSubviews() - - // Center the label in the bounds so it appears aligned, then let the indicator view hang from the left side - label.frame = bounds - indicatorView.center.y = bounds.midY - indicatorView.frame.origin.x = -indicatorView.frame.size.width - Margin - } - - public override var intrinsicContentSize : CGSize { - return label.intrinsicContentSize - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/VideoPlayView.swift b/Dependencies/LoopKit/LoopKitUI/Views/VideoPlayView.swift deleted file mode 100644 index 28e802db4..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/VideoPlayView.swift +++ /dev/null @@ -1,106 +0,0 @@ -// -// VideoPlayView.swift -// LoopKitUI -// -// Created by Rick Pasetto on 5/12/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -public struct VideoPlayView: View { - let thumbnail: () -> ThumbnailContent - let includeThumbnailBorder: Bool - let centerThumbnail: Bool - let url: URL? - let hasBeenPlayed: Binding - private var _autoPlay: Bool = true - private var _overrideMuteSwitch: Bool = true - @State private var isActive: Bool = false - - // This from right out of the Design spec - private let frameColor = Color(UIColor(red: 0.784, green: 0.784, blue: 0.784, alpha: 1)) - - public init(url: URL?, thumbnail: @autoclosure @escaping () -> ThumbnailContent, includeThumbnailBorder: Bool = true, centerThumbnail: Bool = true) { - self.url = url - self.thumbnail = thumbnail - self.includeThumbnailBorder = includeThumbnailBorder - self.centerThumbnail = centerThumbnail - self.hasBeenPlayed = .false - } - - public init(url: URL?, thumbnail: @autoclosure @escaping () -> ThumbnailContent, hasBeenPlayed: Binding, includeThumbnailBorder: Bool = true, centerThumbnail: Bool = true) { - self.url = url - self.thumbnail = thumbnail - self.includeThumbnailBorder = includeThumbnailBorder - self.centerThumbnail = centerThumbnail - self.hasBeenPlayed = hasBeenPlayed - } - - private init(_ other: Self, url: URL?? = nil, thumbnail: (() -> ThumbnailContent)? = nil, hasBeenPlayed: Binding? = nil, autoPlay: Bool? = nil, overrideMuteSwitch: Bool? = nil, includeThumbnailBorder: Bool? = nil, centerThumbnail: Bool? = nil) { - self.url = url ?? other.url - self.thumbnail = thumbnail ?? other.thumbnail - self.hasBeenPlayed = hasBeenPlayed ?? other.hasBeenPlayed - self.includeThumbnailBorder = includeThumbnailBorder ?? other.includeThumbnailBorder - self.centerThumbnail = centerThumbnail ?? other.centerThumbnail - self._autoPlay = autoPlay ?? other._autoPlay - self._overrideMuteSwitch = overrideMuteSwitch ?? other._overrideMuteSwitch - } - - public var body: some View { - PopoverLink(destination: videoView, isActive: $isActive) { - if includeThumbnailBorder { - placeholderImage - .padding() - .border(frameColor, width: 1) - } else { - placeholderImage - } - } - .fullScreen() - } - - private var placeholderImage: some View { - HStack { - if centerThumbnail { - Spacer() - } - ZStack { - thumbnail() - Image(frameworkImage: "play-button", decorative: true) - } - if centerThumbnail { - Spacer() - } - } - .aspectRatio(CGSize(width: 16, height: 9), contentMode: .fit) - .frame(maxWidth: .infinity) - } - - @ViewBuilder - private var videoView: some View { - VideoView(url: url, autoPlay: _autoPlay, overrideMuteSwitch: _overrideMuteSwitch, isActive: $isActive) - .onDisappear { hasBeenPlayed.wrappedValue = true } - } - - public func autoPlay(_ enabled: Bool) -> Self { - Self.init(self, autoPlay: enabled) - } - - public func overrideMuteSwitch(_ enabled: Bool) -> Self { - Self.init(self, overrideMuteSwitch: enabled) - } - - public func includeThumbnailBorder(_ value: Bool) -> Self { - Self.init(self, includeThumbnailBorder: value) - } - - public func centerThumbnail(_ value: Bool) -> Self { - Self.init(self, centerThumbnail: value) - } -} - -fileprivate extension Binding where Value == Bool { - static var `true` = Binding(get: { true }, set: { _ in }) - static var `false` = Binding(get: { false }, set: { _ in }) -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/VideoView.swift b/Dependencies/LoopKit/LoopKitUI/Views/VideoView.swift deleted file mode 100644 index b2eeeb094..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/VideoView.swift +++ /dev/null @@ -1,101 +0,0 @@ -// -// VideoView.swift -// LoopKitUI -// -// Created by Rick Pasetto on 4/13/21. -// Copyright © 2021 Tidepool Project. All rights reserved. -// - -import SwiftUI -import AVKit - -/// Opens a Swift `VideoPlayer` on the given URL in a new page -public struct VideoView: View { - @Environment(\.dismissAction) var dismissAction - - let url: URL? - let autoPlay: Bool - public var isActive: Binding? - - private class PlayerHolder { - private let prevCategory: AVAudioSession.Category? - private var player: AVPlayer? - - init(overrideMuteSwitch: Bool) { - if overrideMuteSwitch { - prevCategory = AVAudioSession.sharedInstance().category - } else { - prevCategory = nil - } - } - - func destroy() { - if let prevCategory = prevCategory { - try? AVAudioSession.sharedInstance().setCategory(prevCategory) - } - } - - func player(for url: URL, autoPlay: Bool) -> AVPlayer { - if let player = player { - return player - } else { - let player = AVPlayer(url: url) - if autoPlay, player.timeControlStatus == .paused { - player.play() - } else if !autoPlay, player.timeControlStatus == .playing { - player.pause() - } - if prevCategory != nil { - // Overrides mute switch (Silent mode) on the phone - try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback) - } - self.player = player - return player - } - } - } - private let playerHolder: PlayerHolder - - public init(url: URL?, autoPlay: Bool, overrideMuteSwitch: Bool = false, isActive: Binding? = nil) { - self.url = url - self.autoPlay = autoPlay - self.playerHolder = PlayerHolder(overrideMuteSwitch: overrideMuteSwitch) - self.isActive = isActive - } - - private func dismiss() { - guard isActive != nil else { - dismissAction() - return - } - - isActive?.wrappedValue = false - } - - public var body: some View { - HStack { - Spacer() - Button(LocalizedString("Done", comment: "Video player done button label"), action: dismiss) - } - .padding() - if let url = url { - VideoPlayer(player: playerHolder.player(for: url, autoPlay: autoPlay)) - .onDisappear { - playerHolder.destroy() - } - } else { - Spacer() - Image(systemName: "questionmark.video") - .resizable() - .scaledToFit() - .frame(width: 100, height: 100, alignment: .center) - Spacer() - } - } -} - -struct VideoView_Previews: PreviewProvider { - static var previews: some View { - VideoView(url: nil, autoPlay: true, overrideMuteSwitch: true) - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/WarningView.swift b/Dependencies/LoopKit/LoopKitUI/Views/WarningView.swift deleted file mode 100644 index d8753b22e..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/WarningView.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// WarningView.swift -// LoopKitUI -// -// Created by Michael Pangburn on 7/24/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - - -public enum WarningSeverity: Int, Comparable { - case `default` - case critical - - public static func < (lhs: WarningSeverity, rhs: WarningSeverity) -> Bool { - lhs.rawValue < rhs.rawValue - } -} - -public struct WarningView: View { - @Environment(\.guidanceColors) var guidanceColors - var title: Text - var caption: Text - var severity: WarningSeverity - - public init(title: Text, caption: Text, severity: WarningSeverity = .default) { - self.title = title - self.caption = caption - self.severity = severity - } - - public var body: some View { - HStack { - VStack(alignment: .leading) { - HStack(alignment: .center) { - Image(systemName: "exclamationmark.triangle.fill") - .foregroundColor(warningColor) - - title - .font(Font(UIFont.preferredFont(forTextStyle: .title3))) - .bold() - .fixedSize(horizontal: false, vertical: true) - .animation(nil) - } - .padding(.bottom, 2) - - caption - .font(.callout) - .foregroundColor(Color(.secondaryLabel)) - .fixedSize(horizontal: false, vertical: true) - .animation(nil) - } - .accessibilityElement(children: .combine) - - Spacer() - } - } - - private var warningColor: Color { - switch severity { - case .default: - return guidanceColors.warning - case .critical: - return guidanceColors.critical - } - } -} diff --git a/Dependencies/LoopKit/LoopKitUI/Views/WebView.swift b/Dependencies/LoopKit/LoopKitUI/Views/WebView.swift deleted file mode 100644 index 0ce7a7164..000000000 --- a/Dependencies/LoopKit/LoopKitUI/Views/WebView.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// WebView.swift -// LoopKitUI -// -// Created by Rick Pasetto on 4/13/21. -// Copyright © 2021 Tidepool Project. All rights reserved. -// - -import SwiftUI -import WebKit - -/// Opens a WKWebView on the given `url` in a new page -public struct WebView: UIViewRepresentable { - let url: URL - - public init(url: URL) { - self.url = url - } - - public func makeUIView(context: UIViewRepresentableContext) -> WKWebView { - let webview = WKWebView() - - let request = URLRequest(url: self.url, cachePolicy: .returnCacheDataElseLoad) - webview.load(request) - - return webview - } - - public func updateUIView(_ webview: WKWebView, context: UIViewRepresentableContext) { - let request = URLRequest(url: self.url, cachePolicy: .returnCacheDataElseLoad) - webview.load(request) - } -} - diff --git a/Dependencies/LoopKit/LoopKitUI/en.lproj/CarbKit.strings b/Dependencies/LoopKit/LoopKitUI/en.lproj/CarbKit.strings deleted file mode 100644 index 186714b8a..000000000 --- a/Dependencies/LoopKit/LoopKitUI/en.lproj/CarbKit.strings +++ /dev/null @@ -1,60 +0,0 @@ - -/* Class = "UILabel"; text = "Authorize access to Health to continue"; ObjectID = "7xi-Om-Y53"; */ -"7xi-Om-Y53.text" = "Authorize access to Health to continue"; - -/* Class = "UIButton"; normalTitle = "Authorize"; ObjectID = "8sx-XB-DRV"; */ -"8sx-XB-DRV.normalTitle" = "Authorize"; - -/* Class = "UILabel"; text = "g"; ObjectID = "D2S-2h-yH6"; */ -"D2S-2h-yH6.text" = "g"; - -/* Class = "UILabel"; text = "Amount Consumed"; ObjectID = "K0S-my-3qL"; */ -"K0S-my-3qL.text" = "Amount Consumed"; - -/* Class = "UIButton"; normalTitle = "🍽"; ObjectID = "Mde-by-DTA"; */ -"Mde-by-DTA.normalTitle" = "🍽"; - -/* Class = "UIButton"; normalTitle = "🌮"; ObjectID = "Me5-3D-C34"; */ -"Me5-3D-C34.normalTitle" = "🌮"; - -/* Class = "UILabel"; text = "Food Type"; ObjectID = "NRZ-dT-iqj"; */ -"NRZ-dT-iqj.text" = "Food Type"; - -/* Class = "UILabel"; text = "g COB"; ObjectID = "QZb-e1-xwb"; */ -"QZb-e1-xwb.text" = "g COB"; - -/* Class = "UINavigationItem"; title = "Carbohydrates"; ObjectID = "Qgq-n1-hm4"; */ -"Qgq-n1-hm4.title" = "Carbohydrates"; - -/* Class = "UILabel"; text = "..."; ObjectID = "WZV-l9-Ek1"; */ -"WZV-l9-Ek1.text" = "..."; - -/* Class = "UIButton"; normalTitle = "🍭"; ObjectID = "XaD-wV-oiS"; */ -"XaD-wV-oiS.normalTitle" = "🍭"; - -/* Class = "UINavigationItem"; title = "Add/Edit Carb Entry"; ObjectID = "bM2-yI-YmX"; */ -"bM2-yI-YmX.title" = "Add/Edit Carb Entry"; - -/* Class = "UILabel"; text = "Food Type"; ObjectID = "bdP-2A-DB8"; */ -"bdP-2A-DB8.text" = "Food Type"; - -/* Class = "UIButton"; normalTitle = "🍕"; ObjectID = "dyX-Zv-8wU"; */ -"dyX-Zv-8wU.normalTitle" = "🍕"; - -/* Class = "UILabel"; text = "..."; ObjectID = "lbE-wQ-pFK"; */ -"lbE-wQ-pFK.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "m95-PG-bTq"; */ -"m95-PG-bTq.text" = "Detail"; - -/* Class = "UILabel"; text = "HealthKit is not available on this device"; ObjectID = "nXh-BM-MuC"; */ -"nXh-BM-MuC.text" = "HealthKit is not available on this device"; - -/* Class = "UILabel"; text = "g Total"; ObjectID = "pHI-f4-pJp"; */ -"pHI-f4-pJp.text" = "g Total"; - -/* Class = "UITextField"; placeholder = "0"; ObjectID = "qU9-hG-hMu"; */ -"qU9-hG-hMu.placeholder" = "0"; - -/* Class = "UILabel"; text = "Title"; ObjectID = "vM9-H7-t3C"; */ -"vM9-H7-t3C.text" = "Title"; diff --git a/Dependencies/LoopKit/LoopKitUI/en.lproj/InsulinKit.strings b/Dependencies/LoopKit/LoopKitUI/en.lproj/InsulinKit.strings deleted file mode 100644 index 630c9e83c..000000000 --- a/Dependencies/LoopKit/LoopKitUI/en.lproj/InsulinKit.strings +++ /dev/null @@ -1,30 +0,0 @@ - -/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ -"7Fi-wD-gf2.text" = "Title"; - -/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ -"7Fy-gG-Zof.text" = "..."; - -/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ -"9jm-X6-3QA.text" = "Detail"; - -/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ -"PZQ-gO-084.text" = "..."; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[0]" = "Reservoir"; - -/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ -"TyZ-xm-mVN.segmentTitles[1]" = "Event History"; - -/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ -"dZi-Ta-IHm.text" = "U IOB"; - -/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ -"jSc-64-2tZ.text" = "No pump configured"; - -/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ -"kys-by-14s.text" = "U Total"; - -/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ -"vls-EW-uwI.title" = "Insulin Delivery"; diff --git a/Dependencies/LoopKit/LoopTestingKit/Data.swift b/Dependencies/LoopKit/LoopTestingKit/Data.swift deleted file mode 100644 index e92db3921..000000000 --- a/Dependencies/LoopKit/LoopTestingKit/Data.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// NSData.swift -// LoopKit -// -// Created by Nate Racklyeft on 8/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -// String conversion methods, adapted from https://stackoverflow.com/questions/40276322/hex-binary-string-conversion-in-swift/40278391#40278391 -extension Data { - init?(hexadecimalString: String) { - self.init(capacity: hexadecimalString.utf16.count / 2) - - // Convert 0 ... 9, a ... f, A ...F to their decimal value, - // return nil for all other input characters - func decodeNibble(u: UInt16) -> UInt8? { - switch u { - case 0x30 ... 0x39: // '0'-'9' - return UInt8(u - 0x30) - case 0x41 ... 0x46: // 'A'-'F' - return UInt8(u - 0x41 + 10) // 10 since 'A' is 10, not 0 - case 0x61 ... 0x66: // 'a'-'f' - return UInt8(u - 0x61 + 10) // 10 since 'a' is 10, not 0 - default: - return nil - } - } - - var even = true - var byte: UInt8 = 0 - for c in hexadecimalString.utf16 { - guard let val = decodeNibble(u: c) else { return nil } - if even { - byte = val << 4 - } else { - byte += val - self.append(byte) - } - even = !even - } - guard even else { return nil } - } - - var hexadecimalString: String { - return map { String(format: "%02hhx", $0) }.joined() - } -} - -extension Data { - static func newPumpEventIdentifier() -> Data { - return Data(UUID().uuidString.utf8) - } -} diff --git a/Dependencies/LoopKit/LoopTestingKit/DateRelativeBasalEntry.swift b/Dependencies/LoopKit/LoopTestingKit/DateRelativeBasalEntry.swift deleted file mode 100644 index 3bf9fb6c1..000000000 --- a/Dependencies/LoopKit/LoopTestingKit/DateRelativeBasalEntry.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// DateRelativeBasalEntry.swift -// LoopTestingKit -// -// Created by Michael Pangburn on 4/20/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - - -struct DateRelativeBasalEntry: DateRelativeQuantity, Codable { - var unitsPerHourValue: Double - var dateOffset: TimeInterval - var duration: TimeInterval - - func doseEntry(relativeTo referenceDate: Date) -> DoseEntry { - let startDate = referenceDate.addingTimeInterval(dateOffset) - let endDate = startDate.addingTimeInterval(duration) - return DoseEntry(type: .tempBasal, startDate: startDate, endDate: endDate, value: unitsPerHourValue, unit: .unitsPerHour) - } - - func newPumpEvent(relativeTo referenceDate: Date) -> NewPumpEvent { - let dose = doseEntry(relativeTo: referenceDate) - return NewPumpEvent(date: dose.startDate, dose: dose, raw: .newPumpEventIdentifier(), title: "Basal", type: .tempBasal) - } -} diff --git a/Dependencies/LoopKit/LoopTestingKit/DateRelativeBolusEntry.swift b/Dependencies/LoopKit/LoopTestingKit/DateRelativeBolusEntry.swift deleted file mode 100644 index f696c0a53..000000000 --- a/Dependencies/LoopKit/LoopTestingKit/DateRelativeBolusEntry.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// DateRelativeBolusEntry.swift -// LoopTestingKit -// -// Created by Michael Pangburn on 4/20/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import LoopKit -import Foundation - -struct DateRelativeBolusEntry: DateRelativeQuantity, Codable { - var unitsValue: Double - var dateOffset: TimeInterval - var deliveryDuration: TimeInterval - - func doseEntry(relativeTo referenceDate: Date) -> DoseEntry { - let startDate = referenceDate.addingTimeInterval(dateOffset) - let endDate = startDate.addingTimeInterval(deliveryDuration) - return DoseEntry(type: .bolus, startDate: startDate, endDate: endDate, value: unitsValue, unit: .units) - } - - func newPumpEvent(relativeTo referenceDate: Date) -> NewPumpEvent { - let dose = doseEntry(relativeTo: referenceDate) - return NewPumpEvent(date: dose.startDate, dose: dose, raw: .newPumpEventIdentifier(), title: "Bolus", type: .bolus) - } -} diff --git a/Dependencies/LoopKit/LoopTestingKit/DateRelativeCarbEntry.swift b/Dependencies/LoopKit/LoopTestingKit/DateRelativeCarbEntry.swift deleted file mode 100644 index 1625c51bd..000000000 --- a/Dependencies/LoopKit/LoopTestingKit/DateRelativeCarbEntry.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// DateRelativeCarbEntry.swift -// LoopTestingKit -// -// Created by Michael Pangburn on 4/20/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import HealthKit -import LoopKit - - -struct DateRelativeCarbEntry: DateRelativeQuantity, Codable { - var gramValue: Double - var dateOffset: TimeInterval - var enteredAtOffset: TimeInterval? - var absorptionTime: TimeInterval - - var quantity: HKQuantity { - return HKQuantity(unit: .gram(), doubleValue: gramValue) - } - - func newCarbEntry(relativeTo referenceDate: Date) -> NewCarbEntry { - let startDate = referenceDate.addingTimeInterval(dateOffset) - return NewCarbEntry(quantity: quantity, startDate: startDate, foodType: nil, absorptionTime: absorptionTime) - } - - func enteredAt(relativeTo referenceDate: Date) -> Date { - return referenceDate.addingTimeInterval(enteredAtOffset ?? dateOffset) - } -} diff --git a/Dependencies/LoopKit/LoopTestingKit/DateRelativeGlucoseSample.swift b/Dependencies/LoopKit/LoopTestingKit/DateRelativeGlucoseSample.swift deleted file mode 100644 index cf9b58145..000000000 --- a/Dependencies/LoopKit/LoopTestingKit/DateRelativeGlucoseSample.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// DateRelativeGlucoseSample.swift -// LoopTestingKit -// -// Created by Michael Pangburn on 4/20/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import HealthKit -import LoopKit - - -struct DateRelativeGlucoseSample: DateRelativeQuantity, Codable { - var mgdlValue: Double - var dateOffset: TimeInterval - - var quantity: HKQuantity { - return HKQuantity(unit: .milligramsPerDeciliter, doubleValue: mgdlValue) - } - - func newGlucoseSample(relativeTo referenceDate: Date) -> NewGlucoseSample { - let date = referenceDate.addingTimeInterval(dateOffset) - return NewGlucoseSample(date: date, quantity: quantity, condition: nil, trend: nil, trendRate: nil, isDisplayOnly: false, wasUserEntered: false, syncIdentifier: UUID().uuidString) - } -} diff --git a/Dependencies/LoopKit/LoopTestingKit/DateRelativeQuantity.swift b/Dependencies/LoopKit/LoopTestingKit/DateRelativeQuantity.swift deleted file mode 100644 index d2a3efd88..000000000 --- a/Dependencies/LoopKit/LoopTestingKit/DateRelativeQuantity.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// DateRelativeQuantity.swift -// LoopTestingKit -// -// Created by Michael Pangburn on 4/21/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - - -protocol DateRelativeQuantity { - var dateOffset: TimeInterval { get set } - mutating func shift(by offset: TimeInterval) -} - -extension DateRelativeQuantity { - mutating func shift(by offset: TimeInterval) { - dateOffset += offset - } -} diff --git a/Dependencies/LoopKit/LoopTestingKit/HKUnit.swift b/Dependencies/LoopKit/LoopTestingKit/HKUnit.swift deleted file mode 100644 index a5f77cdd0..000000000 --- a/Dependencies/LoopKit/LoopTestingKit/HKUnit.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// HKUnit.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/17/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -extension HKUnit { - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: .literUnit(with: .deci)) - }() - - static let millimolesPerLiter: HKUnit = { - return HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: .liter()) - }() - - static let milligramsPerDeciliterPerMinute: HKUnit = { - return HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) - }() - - static let millimolesPerLiterPerMinute: HKUnit = { - return HKUnit.millimolesPerLiter.unitDivided(by: .minute()) - }() - - static let internationalUnitsPerHour: HKUnit = { - return HKUnit.internationalUnit().unitDivided(by: .hour()) - }() - - static let gramsPerUnit: HKUnit = { - return HKUnit.gram().unitDivided(by: .internationalUnit()) - }() - - var foundationUnit: Unit? { - if self == HKUnit.milligramsPerDeciliter { - return UnitConcentrationMass.milligramsPerDeciliter - } - - if self == HKUnit.millimolesPerLiter { - return UnitConcentrationMass.millimolesPerLiter(withGramsPerMole: HKUnitMolarMassBloodGlucose) - } - - if self == HKUnit.gram() { - return UnitMass.grams - } - - return nil - } - - /// The smallest value expected to be visible on a chart - var chartableIncrement: Double { - if self == .milligramsPerDeciliter { - return 1 - } else { - return 1 / 25 - } - } -} diff --git a/Dependencies/LoopKit/LoopTestingKit/Info.plist b/Dependencies/LoopKit/LoopTestingKit/Info.plist deleted file mode 100644 index adc94e95f..000000000 --- a/Dependencies/LoopKit/LoopTestingKit/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - - diff --git a/Dependencies/LoopKit/LoopTestingKit/LoopTestingKit.h b/Dependencies/LoopKit/LoopTestingKit/LoopTestingKit.h deleted file mode 100644 index bf81a5849..000000000 --- a/Dependencies/LoopKit/LoopTestingKit/LoopTestingKit.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// LoopTestingKit.h -// LoopTestingKit -// -// Created by Michael Pangburn on 3/5/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -#import - -//! Project version number for LoopTestingKit. -FOUNDATION_EXPORT double LoopTestingKitVersionNumber; - -//! Project version string for LoopTestingKit. -FOUNDATION_EXPORT const unsigned char LoopTestingKitVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/LoopKit/LoopTestingKit/TestingCGMManager.swift b/Dependencies/LoopKit/LoopTestingKit/TestingCGMManager.swift deleted file mode 100644 index 3544cc171..000000000 --- a/Dependencies/LoopKit/LoopTestingKit/TestingCGMManager.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// TestingCGMManager.swift -// LoopTestingKit -// -// Created by Michael Pangburn on 3/5/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import LoopKit - - -public protocol TestingCGMManager: CGMManager, TestingDeviceManager { - func injectGlucoseSamples(_ samples: [NewGlucoseSample]) -} diff --git a/Dependencies/LoopKit/LoopTestingKit/TestingDeviceManager.swift b/Dependencies/LoopKit/LoopTestingKit/TestingDeviceManager.swift deleted file mode 100644 index 7f659b143..000000000 --- a/Dependencies/LoopKit/LoopTestingKit/TestingDeviceManager.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// TestingDeviceManager.swift -// LoopTestingKit -// -// Created by Michael Pangburn on 3/5/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import LoopKit -import HealthKit - - -public protocol TestingDeviceManager: DeviceManager { - var testingDevice: HKDevice { get } -} diff --git a/Dependencies/LoopKit/LoopTestingKit/TestingPumpManager.swift b/Dependencies/LoopKit/LoopTestingKit/TestingPumpManager.swift deleted file mode 100644 index 30368f185..000000000 --- a/Dependencies/LoopKit/LoopTestingKit/TestingPumpManager.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// TestingPumpManager.swift -// LoopTestingKit -// -// Created by Michael Pangburn on 3/5/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import LoopKit - - -public protocol TestingPumpManager: PumpManager, TestingDeviceManager { - var reservoirFillFraction: Double { get set } - func injectPumpEvents(_ pumpEvents: [NewPumpEvent]) -} diff --git a/Dependencies/LoopKit/LoopTestingKit/TestingScenario.swift b/Dependencies/LoopKit/LoopTestingKit/TestingScenario.swift deleted file mode 100644 index 99e07044c..000000000 --- a/Dependencies/LoopKit/LoopTestingKit/TestingScenario.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// TestingScenario.swift -// LoopTestingKit -// -// Created by Michael Pangburn on 4/20/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -public struct TestingScenario { - var dateRelativeGlucoseSamples: [DateRelativeGlucoseSample] - var dateRelativeBasalEntries: [DateRelativeBasalEntry] - var dateRelativeBolusEntries: [DateRelativeBolusEntry] - var dateRelativeCarbEntries: [DateRelativeCarbEntry] - - public func instantiate(relativeTo referenceDate: Date = Date()) -> TestingScenarioInstance { - let glucoseSamples = dateRelativeGlucoseSamples - .map { $0.newGlucoseSample(relativeTo: referenceDate) } - .filter { $0.date <= referenceDate } - let basalEntries = dateRelativeBasalEntries.map { $0.newPumpEvent(relativeTo: referenceDate) } - let bolusEntries = dateRelativeBolusEntries.map { $0.newPumpEvent(relativeTo: referenceDate) } - let pumpEvents = (basalEntries + bolusEntries) - .filter { $0.date <= referenceDate } - .sorted(by: { $0.date < $1.date }) - let carbEntries = dateRelativeCarbEntries - .filter { $0.enteredAt(relativeTo: referenceDate) <= referenceDate } - .map { $0.newCarbEntry(relativeTo: referenceDate) } - return TestingScenarioInstance(glucoseSamples: glucoseSamples, pumpEvents: pumpEvents, carbEntries: carbEntries) - } - - public mutating func stepBackward(by offset: TimeInterval) { - assert(offset > 0) - shift(by: offset) - } - - public mutating func stepForward(by offset: TimeInterval) { - assert(offset > 0) - shift(by: -offset) - } - - public mutating func stepForward( - unitsPerHour: Double, - duration: TimeInterval, - dateOffset: TimeInterval = 0, - loopInterval: TimeInterval = 60 * 5 /* minutes */ - ) { - precondition(duration > 0) - dateRelativeBasalEntries.removeAll(where: { $0.dateOffset >= dateOffset }) - let basal = DateRelativeBasalEntry(unitsPerHourValue: unitsPerHour, dateOffset: dateOffset, duration: duration) - dateRelativeBasalEntries.append(basal) - stepForward(by: loopInterval) - } - - mutating func shift(by offset: TimeInterval) { - dateRelativeGlucoseSamples.mutateEach { $0.shift(by: offset) } - dateRelativeBasalEntries.mutateEach { $0.shift(by: offset) } - dateRelativeBolusEntries.mutateEach { $0.shift(by: offset) } - dateRelativeCarbEntries.mutateEach { $0.shift(by: offset) } - } -} - -extension TestingScenario: Codable { - public enum CodingKeys: String, CodingKey { - case dateRelativeGlucoseSamples = "glucoseValues" - case dateRelativeBasalEntries = "basalDoses" - case dateRelativeBolusEntries = "bolusDoses" - case dateRelativeCarbEntries = "carbEntries" - } -} - -extension TestingScenario { - public init(source: URL) throws { - let decoder = JSONDecoder() - let data = try Data(contentsOf: source) - self = try decoder.decode(TestingScenario.self, from: data) - } -} diff --git a/Dependencies/LoopKit/LoopTestingKit/TestingScenarioInstance.swift b/Dependencies/LoopKit/LoopTestingKit/TestingScenarioInstance.swift deleted file mode 100644 index 78c757291..000000000 --- a/Dependencies/LoopKit/LoopTestingKit/TestingScenarioInstance.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// TestingScenarioInstance.swift -// LoopTestingKit -// -// Created by Michael Pangburn on 4/20/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import LoopKit - - -public struct TestingScenarioInstance { - public var glucoseSamples: [NewGlucoseSample] - public var pumpEvents: [NewPumpEvent] - public var carbEntries: [NewCarbEntry] -} diff --git a/Dependencies/LoopKit/MockKit/Extensions/Collection.swift b/Dependencies/LoopKit/MockKit/Extensions/Collection.swift deleted file mode 100644 index 6b4238bf1..000000000 --- a/Dependencies/LoopKit/MockKit/Extensions/Collection.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// Collection.swift -// LoopKit -// -// Created by Michael Pangburn on 12/4/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Dispatch -import LoopKit - - -extension Collection { - func asyncMap( - _ asyncTransform: ( - _ element: Element, - _ completion: @escaping (NewElement) -> Void - ) -> Void, - notifyingOn queue: DispatchQueue = .global(), - completion: @escaping ([NewElement]) -> Void - ) { - let result = Locked(Array(repeating: nil, count: count)) - let group = DispatchGroup() - - for (resultIndex, element) in enumerated() { - group.enter() - asyncTransform(element) { newElement in - result.value[resultIndex] = newElement - group.leave() - } - } - - group.notify(queue: queue) { - let transformed = result.value.map { $0! } - completion(transformed) - } - } - - /// Returns a sequence containing adjacent pairs of elements in the ordered collection. - func adjacentPairs() -> Zip2Sequence { - return zip(self, dropFirst()) - } -} diff --git a/Dependencies/LoopKit/MockKit/Extensions/HKUnit.swift b/Dependencies/LoopKit/MockKit/Extensions/HKUnit.swift deleted file mode 100644 index a5f77cdd0..000000000 --- a/Dependencies/LoopKit/MockKit/Extensions/HKUnit.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// HKUnit.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/17/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -extension HKUnit { - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: .literUnit(with: .deci)) - }() - - static let millimolesPerLiter: HKUnit = { - return HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: .liter()) - }() - - static let milligramsPerDeciliterPerMinute: HKUnit = { - return HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) - }() - - static let millimolesPerLiterPerMinute: HKUnit = { - return HKUnit.millimolesPerLiter.unitDivided(by: .minute()) - }() - - static let internationalUnitsPerHour: HKUnit = { - return HKUnit.internationalUnit().unitDivided(by: .hour()) - }() - - static let gramsPerUnit: HKUnit = { - return HKUnit.gram().unitDivided(by: .internationalUnit()) - }() - - var foundationUnit: Unit? { - if self == HKUnit.milligramsPerDeciliter { - return UnitConcentrationMass.milligramsPerDeciliter - } - - if self == HKUnit.millimolesPerLiter { - return UnitConcentrationMass.millimolesPerLiter(withGramsPerMole: HKUnitMolarMassBloodGlucose) - } - - if self == HKUnit.gram() { - return UnitMass.grams - } - - return nil - } - - /// The smallest value expected to be visible on a chart - var chartableIncrement: Double { - if self == .milligramsPerDeciliter { - return 1 - } else { - return 1 / 25 - } - } -} diff --git a/Dependencies/LoopKit/MockKit/Extensions/TimeInterval.swift b/Dependencies/LoopKit/MockKit/Extensions/TimeInterval.swift deleted file mode 100644 index a568b77b8..000000000 --- a/Dependencies/LoopKit/MockKit/Extensions/TimeInterval.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// NSTimeInterval.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension TimeInterval { - static func minutes(_ minutes: Double) -> TimeInterval { - return self.init(minutes: minutes) - } - - static func hours(_ hours: Double) -> TimeInterval { - return self.init(hours: hours) - } - - init(minutes: Double) { - self.init(minutes * 60) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - var minutes: Double { - return self / 60.0 - } - - var hours: Double { - return minutes / 60.0 - } -} diff --git a/Dependencies/LoopKit/MockKit/Extensions/TimeZone.swift b/Dependencies/LoopKit/MockKit/Extensions/TimeZone.swift deleted file mode 100644 index 4b912b912..000000000 --- a/Dependencies/LoopKit/MockKit/Extensions/TimeZone.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// TimeZone.swift -// LoopKit -// -// Created by Nate Racklyeft on 10/2/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - - -extension TimeZone { - static var currentFixed: TimeZone { - return TimeZone(secondsFromGMT: TimeZone.current.secondsFromGMT())! - } -} diff --git a/Dependencies/LoopKit/MockKit/Extensions/UIImage.swift b/Dependencies/LoopKit/MockKit/Extensions/UIImage.swift deleted file mode 100644 index 954907de3..000000000 --- a/Dependencies/LoopKit/MockKit/Extensions/UIImage.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// UIImage.swift -// MockKitUI -// -// Created by Nathaniel Hamming on 2021-02-16. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -// TODO: UIKit should not be in MockKit - -import UIKit - -private class FrameworkBundle { - static let main = Bundle(for: FrameworkBundle.self) -} - -extension UIImage { - convenience init?(frameworkImage name: String) { - self.init(named: name, in: FrameworkBundle.main, with: nil) - } -} diff --git a/Dependencies/LoopKit/MockKit/Info.plist b/Dependencies/LoopKit/MockKit/Info.plist deleted file mode 100644 index adc94e95f..000000000 --- a/Dependencies/LoopKit/MockKit/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - - diff --git a/Dependencies/LoopKit/MockKit/LocalizedString.swift b/Dependencies/LoopKit/MockKit/LocalizedString.swift deleted file mode 100644 index a56bbb34f..000000000 --- a/Dependencies/LoopKit/MockKit/LocalizedString.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// LocalizedString.swift -// MockKit -// -// Created by Pete Schwamb on 3/18/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -class LocalBundle { - /// Returns the resource bundle associated with the current Swift module. - static var main: Bundle = { - if let mainResourceURL = Bundle(for: LocalBundle.self).resourceURL, - let bundle = Bundle(url: mainResourceURL.appendingPathComponent("MockKit_MockKit.bundle")) - { - return bundle - } - return Bundle(for: LocalBundle.self) - }() -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, comment: comment) - } -} diff --git a/Dependencies/LoopKit/MockKit/MockCGMDataSource.swift b/Dependencies/LoopKit/MockKit/MockCGMDataSource.swift deleted file mode 100644 index def6a8801..000000000 --- a/Dependencies/LoopKit/MockKit/MockCGMDataSource.swift +++ /dev/null @@ -1,329 +0,0 @@ -// -// MockCGMDataSource.swift -// LoopKit -// -// Created by Michael Pangburn on 11/23/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import HealthKit -import LoopKit - - -public struct MockCGMDataSource { - public enum Model { - public typealias SineCurveParameters = (baseGlucose: HKQuantity, amplitude: HKQuantity, period: TimeInterval, referenceDate: Date) - - case constant(_ glucose: HKQuantity) - case sineCurve(parameters: SineCurveParameters) - case noData - case signalLoss - case unreliableData - - public var isValidSession: Bool { - switch self { - case .noData: - return false - default: - return true - } - } - } - - public struct Effects { - public typealias RandomOutlier = (chance: Double, delta: HKQuantity) - - public var glucoseNoise: HKQuantity? - public var randomLowOutlier: RandomOutlier? - public var randomHighOutlier: RandomOutlier? - public var randomErrorChance: Double? - - public init( - glucoseNoise: HKQuantity? = nil, - randomLowOutlier: RandomOutlier? = nil, - randomHighOutlier: RandomOutlier? = nil, - randomErrorChance: Double? = nil - ) { - self.glucoseNoise = glucoseNoise - self.randomLowOutlier = randomLowOutlier - self.randomHighOutlier = randomHighOutlier - self.randomErrorChance = randomErrorChance - } - } - - static let device = HKDevice( - name: "MockCGMManager", - manufacturer: "LoopKit", - model: "MockCGMManager", - hardwareVersion: nil, - firmwareVersion: nil, - softwareVersion: "1.0", - localIdentifier: nil, - udiDeviceIdentifier: nil - ) - - public var model: Model { - didSet { - glucoseProvider = MockGlucoseProvider(model: model, effects: effects) - } - } - - public var effects: Effects { - didSet { - glucoseProvider = MockGlucoseProvider(model: model, effects: effects) - } - } - - private var glucoseProvider: MockGlucoseProvider - - private var lastFetchedData = Locked(Date.distantPast) - - public var dataPointFrequency: MeasurementFrequency - - public var isValidSession: Bool { - return model.isValidSession - } - - public init( - model: Model, - effects: Effects = .init(), - dataPointFrequency: MeasurementFrequency = .normal - ) { - self.model = model - self.effects = effects - self.glucoseProvider = MockGlucoseProvider(model: model, effects: effects) - self.dataPointFrequency = dataPointFrequency - } - - func fetchNewData(_ completion: @escaping (CGMReadingResult) -> Void) { - let now = Date() - // Give 5% wiggle room for producing data points - let bufferedFrequency = dataPointFrequency.frequency - 0.05 * dataPointFrequency.frequency - if now.timeIntervalSince(lastFetchedData.value) < bufferedFrequency { - completion(.noData) - return - } - - lastFetchedData.value = now - glucoseProvider.fetchData(at: now, completion: completion) - } - - func backfillData(from interval: DateInterval, completion: @escaping (CGMReadingResult) -> Void) { - lastFetchedData.value = interval.end - let request = MockGlucoseProvider.BackfillRequest(datingBack: interval.duration, dataPointFrequency: dataPointFrequency.frequency) - glucoseProvider.backfill(request, endingAt: interval.end, completion: completion) - } -} - -extension MockCGMDataSource: RawRepresentable { - public typealias RawValue = [String: Any] - - public init?(rawValue: RawValue) { - guard - let model = (rawValue["model"] as? Model.RawValue).flatMap(Model.init(rawValue:)), - let effects = (rawValue["effects"] as? Effects.RawValue).flatMap(Effects.init(rawValue:)), - let dataPointFrequency = (rawValue["dataPointFrequency"] as? MeasurementFrequency.RawValue).flatMap(MeasurementFrequency.init(rawValue:)) - else { - return nil - } - - self.init(model: model, effects: effects, dataPointFrequency: dataPointFrequency) - } - - public var rawValue: RawValue { - return [ - "model": model.rawValue, - "effects": effects.rawValue, - "dataPointFrequency": dataPointFrequency.rawValue - ] - } -} - -extension MockCGMDataSource.Model: RawRepresentable { - public typealias RawValue = [String: Any] - - private enum Kind: String { - case constant - case sineCurve - case noData - case signalLoss - case unreliableData - } - - private static let unit = HKUnit.milligramsPerDeciliter - - public init?(rawValue: RawValue) { - guard - let kindRawValue = rawValue["kind"] as? Kind.RawValue, - let kind = Kind(rawValue: kindRawValue) - else { - return nil - } - - let unit = MockCGMDataSource.Model.unit - func glucose(forKey key: String) -> HKQuantity? { - guard let doubleValue = rawValue[key] as? Double else { - return nil - } - return HKQuantity(unit: unit, doubleValue: doubleValue) - } - - switch kind { - case .constant: - guard let quantity = glucose(forKey: "quantity") else { - return nil - } - self = .constant(quantity) - case .sineCurve: - guard - let baseGlucose = glucose(forKey: "baseGlucose"), - let amplitude = glucose(forKey: "amplitude"), - let period = rawValue["period"] as? TimeInterval, - let referenceDateSeconds = rawValue["referenceDate"] as? TimeInterval - else { - return nil - } - - let referenceDate = Date(timeIntervalSince1970: referenceDateSeconds) - self = .sineCurve(parameters: (baseGlucose: baseGlucose, amplitude: amplitude, period: period, referenceDate: referenceDate)) - case .noData: - self = .noData - case .signalLoss: - self = .signalLoss - case .unreliableData: - self = .unreliableData - } - } - - public var rawValue: RawValue { - var rawValue: RawValue = ["kind": kind.rawValue] - - let unit = MockCGMDataSource.Model.unit - switch self { - case .constant(let quantity): - rawValue["quantity"] = quantity.doubleValue(for: unit) - case .sineCurve(parameters: (baseGlucose: let baseGlucose, amplitude: let amplitude, period: let period, referenceDate: let referenceDate)): - rawValue["baseGlucose"] = baseGlucose.doubleValue(for: unit) - rawValue["amplitude"] = amplitude.doubleValue(for: unit) - rawValue["period"] = period - rawValue["referenceDate"] = referenceDate.timeIntervalSince1970 - case .noData, .signalLoss, .unreliableData: - break - } - - return rawValue - } - - private var kind: Kind { - switch self { - case .constant: - return .constant - case .sineCurve: - return .sineCurve - case .noData: - return .noData - case .signalLoss: - return .signalLoss - case .unreliableData: - return .unreliableData - } - } -} - -extension MockCGMDataSource.Effects: RawRepresentable { - public typealias RawValue = [String: Any] - - private static let unit = HKUnit.milligramsPerDeciliter - - public init?(rawValue: RawValue) { - self.init() - - let unit = MockCGMDataSource.Effects.unit - func randomOutlier(forKey key: String) -> RandomOutlier? { - guard - let outlier = rawValue[key] as? [String: Double], - let chance = outlier["chance"], - let delta = outlier["delta"] - else { - return nil - } - - return (chance: chance, delta: HKQuantity(unit: unit, doubleValue: delta)) - } - - if let glucoseNoise = rawValue["glucoseNoise"] as? Double { - self.glucoseNoise = HKQuantity(unit: unit, doubleValue: glucoseNoise) - } - - self.randomLowOutlier = randomOutlier(forKey: "randomLowOutlier") - self.randomHighOutlier = randomOutlier(forKey: "randomHighOutlier") - self.randomErrorChance = rawValue["randomErrorChance"] as? Double - } - - public var rawValue: RawValue { - var rawValue: RawValue = [:] - - let unit = MockCGMDataSource.Effects.unit - func insertOutlier(_ outlier: RandomOutlier, forKey key: String) { - rawValue[key] = [ - "chance": outlier.chance, - "delta": outlier.delta.doubleValue(for: unit) - ] - } - - if let glucoseNoise = glucoseNoise { - rawValue["glucoseNoise"] = glucoseNoise.doubleValue(for: unit) - } - - if let randomLowOutlier = randomLowOutlier { - insertOutlier(randomLowOutlier, forKey: "randomLowOutlier") - } - - if let randomHighOutlier = randomHighOutlier { - insertOutlier(randomHighOutlier, forKey: "randomHighOutlier") - } - - if let randomErrorChance = randomErrorChance { - rawValue["randomErrorChance"] = randomErrorChance - } - - return rawValue - } -} - -extension MockCGMDataSource: CustomDebugStringConvertible { - public var debugDescription: String { - return """ - ## MockCGMDataSource - * model: \(model) - * effects: \(effects) - """ - } -} - -public enum MeasurementFrequency: Int, CaseIterable { - case normal - case fast - case faster - - public var frequency: TimeInterval { - switch self { - case .normal: - return TimeInterval(5*60) - case .fast: - return TimeInterval(60) - case .faster: - return TimeInterval(5) - } - } - public var localizedDescription: String { - switch self { - case .normal: - return "5 minutes" - case .fast: - return "1 minute" - case .faster: - return "5 seconds" - } - } -} diff --git a/Dependencies/LoopKit/MockKit/MockCGMManager.swift b/Dependencies/LoopKit/MockKit/MockCGMManager.swift deleted file mode 100644 index 11cc79961..000000000 --- a/Dependencies/LoopKit/MockKit/MockCGMManager.swift +++ /dev/null @@ -1,881 +0,0 @@ -// -// MockCGMManager.swift -// LoopKit -// -// Created by Michael Pangburn on 11/20/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import HealthKit -import LoopKit -import LoopKitUI // TODO: DeviceStatusBadge references should live in MockKitUI -import LoopTestingKit -import UIKit - -public struct MockCGMState: GlucoseDisplayable { - public var isStateValid: Bool - - public var trendType: GlucoseTrend? - - public var trendRate: HKQuantity? - - public var isLocal: Bool { - return true - } - - public var glucoseRangeCategory: GlucoseRangeCategory? - - public let unit: HKUnit = .milligramsPerDeciliter - - public var glucoseAlertingEnabled: Bool - - public var samplesShouldBeUploaded: Bool - - private var cgmLowerLimitValue: Double - - // HKQuantity isn't codable - public var cgmLowerLimit: HKQuantity { - get { - return HKQuantity.init(unit: unit, doubleValue: cgmLowerLimitValue) - } - set { - var newDoubleValue = newValue.doubleValue(for: unit) - if newDoubleValue >= urgentLowGlucoseThresholdValue { - newDoubleValue = urgentLowGlucoseThresholdValue - 1 - } - cgmLowerLimitValue = newDoubleValue - } - } - - private var urgentLowGlucoseThresholdValue: Double - - public var urgentLowGlucoseThreshold: HKQuantity { - get { - return HKQuantity.init(unit: unit, doubleValue: urgentLowGlucoseThresholdValue) - } - set { - var newDoubleValue = newValue.doubleValue(for: unit) - if newDoubleValue <= cgmLowerLimitValue { - newDoubleValue = cgmLowerLimitValue + 1 - } - if newDoubleValue >= lowGlucoseThresholdValue { - newDoubleValue = lowGlucoseThresholdValue - 1 - } - urgentLowGlucoseThresholdValue = newDoubleValue - } - } - - private var lowGlucoseThresholdValue: Double - - public var lowGlucoseThreshold: HKQuantity { - get { - return HKQuantity.init(unit: unit, doubleValue: lowGlucoseThresholdValue) - } - set { - var newDoubleValue = newValue.doubleValue(for: unit) - if newDoubleValue <= urgentLowGlucoseThresholdValue { - newDoubleValue = urgentLowGlucoseThresholdValue + 1 - } - if newDoubleValue >= highGlucoseThresholdValue { - newDoubleValue = highGlucoseThresholdValue - 1 - } - lowGlucoseThresholdValue = newDoubleValue - } - } - - private var highGlucoseThresholdValue: Double - - public var highGlucoseThreshold: HKQuantity { - get { - return HKQuantity.init(unit: unit, doubleValue: highGlucoseThresholdValue) - } - set { - var newDoubleValue = newValue.doubleValue(for: unit) - if newDoubleValue <= lowGlucoseThresholdValue { - newDoubleValue = lowGlucoseThresholdValue + 1 - } - if newDoubleValue >= cgmUpperLimitValue { - newDoubleValue = cgmUpperLimitValue - 1 - } - highGlucoseThresholdValue = newDoubleValue - } - } - - private var cgmUpperLimitValue: Double - - public var cgmUpperLimit: HKQuantity { - get { - return HKQuantity.init(unit: unit, doubleValue: cgmUpperLimitValue) - } - set { - var newDoubleValue = newValue.doubleValue(for: unit) - if newDoubleValue <= highGlucoseThresholdValue { - newDoubleValue = highGlucoseThresholdValue + 1 - } - cgmUpperLimitValue = newDoubleValue - } - } - - public var cgmStatusHighlight: MockCGMStatusHighlight? - - public var cgmStatusBadge: MockCGMStatusBadge? - - public var cgmLifecycleProgress: MockCGMLifecycleProgress? { - didSet { - if cgmLifecycleProgress != oldValue { - setProgressColor() - } - } - } - - public var progressWarningThresholdPercentValue: Double? { - didSet { - if progressWarningThresholdPercentValue != oldValue { - setProgressColor() - } - } - } - - public var progressCriticalThresholdPercentValue: Double? { - didSet { - if progressCriticalThresholdPercentValue != oldValue { - setProgressColor() - } - } - } - - public var cgmBatteryChargeRemaining: Double? = 1 - - private mutating func setProgressColor() { - guard var cgmLifecycleProgress = cgmLifecycleProgress else { - return - } - - if let progressCriticalThresholdPercentValue = progressCriticalThresholdPercentValue, - cgmLifecycleProgress.percentComplete >= progressCriticalThresholdPercentValue - { - cgmLifecycleProgress.progressState = .critical - } else if let progressWarningThresholdPercentValue = progressWarningThresholdPercentValue, - cgmLifecycleProgress.percentComplete >= progressWarningThresholdPercentValue - { - cgmLifecycleProgress.progressState = .warning - } else { - cgmLifecycleProgress.progressState = .normalCGM - } - - self.cgmLifecycleProgress = cgmLifecycleProgress - } - - public init(isStateValid: Bool = true, - glucoseRangeCategory: GlucoseRangeCategory? = nil, - glucoseAlertingEnabled: Bool = false, - samplesShouldBeUploaded: Bool = false, - urgentLowGlucoseThresholdValue: Double = 55, - lowGlucoseThresholdValue: Double = 80, - highGlucoseThresholdValue: Double = 200, - cgmLowerLimitValue: Double = 40, - cgmUpperLimitValue: Double = 400, - cgmStatusHighlight: MockCGMStatusHighlight? = nil, - cgmLifecycleProgress: MockCGMLifecycleProgress? = nil, - progressWarningThresholdPercentValue: Double? = nil, - progressCriticalThresholdPercentValue: Double? = nil) - { - self.isStateValid = isStateValid - self.glucoseRangeCategory = glucoseRangeCategory - self.glucoseAlertingEnabled = glucoseAlertingEnabled - self.samplesShouldBeUploaded = samplesShouldBeUploaded - self.urgentLowGlucoseThresholdValue = urgentLowGlucoseThresholdValue - self.lowGlucoseThresholdValue = lowGlucoseThresholdValue - self.highGlucoseThresholdValue = highGlucoseThresholdValue - self.cgmLowerLimitValue = cgmLowerLimitValue - self.cgmUpperLimitValue = cgmUpperLimitValue - self.cgmStatusHighlight = cgmStatusHighlight - self.cgmLifecycleProgress = cgmLifecycleProgress - self.progressWarningThresholdPercentValue = progressWarningThresholdPercentValue - self.progressCriticalThresholdPercentValue = progressCriticalThresholdPercentValue - setProgressColor() - } -} - -public struct MockCGMStatusHighlight: DeviceStatusHighlight { - public var localizedMessage: String - - public var imageName: String { - switch alertIdentifier { - case MockCGMManager.submarine.identifier: - return "dot.radiowaves.left.and.right" - case MockCGMManager.buzz.identifier: - return "clock" - default: - return "exclamationmark.circle.fill" - } - } - - public var state: DeviceStatusHighlightState{ - switch alertIdentifier { - case MockCGMManager.submarine.identifier: - return .normalCGM - case MockCGMManager.buzz.identifier: - return .warning - default: - return .critical - } - } - - public var alertIdentifier: Alert.AlertIdentifier -} - -public struct MockCGMStatusBadge: DeviceStatusBadge { - public var image: UIImage? { - return badgeType.image - } - - public var state: DeviceStatusBadgeState { - switch badgeType { - case .lowBattery: - return .critical - case .calibrationRequested: - return .warning - } - } - - public var badgeType: MockCGMStatusBadgeType - - public enum MockCGMStatusBadgeType: Int, CaseIterable { - case lowBattery - case calibrationRequested - - var image: UIImage? { - switch self { - case .lowBattery: - return UIImage(frameworkImage: "battery.circle.fill") - case .calibrationRequested: - return UIImage(frameworkImage: "drop.circle.fill") - } - } - } - - init(badgeType: MockCGMStatusBadgeType) { - self.badgeType = badgeType - } -} - -public struct MockCGMLifecycleProgress: DeviceLifecycleProgress, Equatable { - public var percentComplete: Double - - public var progressState: DeviceLifecycleProgressState - - public init(percentComplete: Double, progressState: DeviceLifecycleProgressState = .normalCGM) { - self.percentComplete = percentComplete - self.progressState = progressState - } -} - -extension MockCGMLifecycleProgress: RawRepresentable { - public typealias RawValue = [String: Any] - - public init?(rawValue: RawValue) { - guard let percentComplete = rawValue["percentComplete"] as? Double, - let progressStateRawValue = rawValue["progressState"] as? DeviceLifecycleProgressState.RawValue, - let progressState = DeviceLifecycleProgressState(rawValue: progressStateRawValue) else - { - return nil - } - - self.percentComplete = percentComplete - self.progressState = progressState - } - - public var rawValue: RawValue { - let rawValue: RawValue = [ - "percentComplete": percentComplete, - "progressState": progressState.rawValue, - ] - - return rawValue - } -} - -public final class MockCGMManager: TestingCGMManager { - - public static let managerIdentifier = "MockCGMManager" - - public var managerIdentifier: String { - return MockCGMManager.managerIdentifier - } - - public static let localizedTitle = "CGM Simulator" - - public var localizedTitle: String { - return MockCGMManager.localizedTitle - } - - public struct MockAlert { - public let sound: Alert.Sound - public let identifier: Alert.AlertIdentifier - public let foregroundContent: Alert.Content - public let backgroundContent: Alert.Content - public let interruptionLevel: Alert.InterruptionLevel - } - let alerts: [Alert.AlertIdentifier: MockAlert] = [ - submarine.identifier: submarine, buzz.identifier: buzz, critical.identifier: critical, signalLoss.identifier: signalLoss - ] - - public static let submarine = MockAlert(sound: .sound(name: "sub.caf"), identifier: "submarine", - foregroundContent: Alert.Content(title: "Alert: FG Title", body: "Alert: Foreground Body", acknowledgeActionButtonLabel: "FG OK"), - backgroundContent: Alert.Content(title: "Alert: BG Title", body: "Alert: Background Body", acknowledgeActionButtonLabel: "BG OK"), - interruptionLevel: .timeSensitive) - public static let critical = MockAlert(sound: .sound(name: "critical.caf"), identifier: "critical", - foregroundContent: Alert.Content(title: "Critical Alert: FG Title", body: "Critical Alert: Foreground Body", acknowledgeActionButtonLabel: "Critical FG OK"), - backgroundContent: Alert.Content(title: "Critical Alert: BG Title", body: "Critical Alert: Background Body", acknowledgeActionButtonLabel: "Critical BG OK"), - interruptionLevel: .critical) - public static let buzz = MockAlert(sound: .vibrate, identifier: "buzz", - foregroundContent: Alert.Content(title: "Alert: FG Title", body: "FG bzzzt", acknowledgeActionButtonLabel: "Buzz"), - backgroundContent: Alert.Content(title: "Alert: BG Title", body: "BG bzzzt", acknowledgeActionButtonLabel: "Buzz"), - interruptionLevel: .active) - public static let signalLoss = MockAlert(sound: .sound(name: "critical.caf"), - identifier: "signalLoss", - foregroundContent: Alert.Content(title: "Signal Loss", body: "CGM simulator signal loss", acknowledgeActionButtonLabel: "Dismiss"), - backgroundContent: Alert.Content(title: "Signal Loss", body: "CGM simulator signal loss", acknowledgeActionButtonLabel: "Dismiss"), - interruptionLevel: .critical) - - private let lockedMockSensorState = Locked(MockCGMState(isStateValid: true)) - public var mockSensorState: MockCGMState { - get { - lockedMockSensorState.value - } - set { - lockedMockSensorState.mutate { $0 = newValue } - self.notifyStatusObservers(cgmManagerStatus: self.cgmManagerStatus) - } - } - - public var glucoseDisplay: GlucoseDisplayable? { - return mockSensorState - } - - public var cgmManagerStatus: CGMManagerStatus { - return CGMManagerStatus(hasValidSensorSession: dataSource.isValidSession, lastCommunicationDate: lastCommunicationDate, device: device) - } - - private var lastCommunicationDate: Date? = nil - - public var testingDevice: HKDevice { - return MockCGMDataSource.device - } - - public var device: HKDevice? { - return testingDevice - } - - public weak var cgmManagerDelegate: CGMManagerDelegate? { - get { - return delegate.delegate - } - set { - delegate.delegate = newValue - } - } - - public var delegateQueue: DispatchQueue! { - get { - return delegate.queue - } - set { - delegate.queue = newValue - } - } - - private let delegate = WeakSynchronizedDelegate() - - private let lockedDataSource = Locked(MockCGMDataSource(model: .noData)) - public var dataSource: MockCGMDataSource { - get { - lockedDataSource.value - } - set { - lockedDataSource.mutate { $0 = newValue } - self.notifyStatusObservers(cgmManagerStatus: self.cgmManagerStatus) - } - } - - private var glucoseUpdateTimer: Timer? - - public init() { - setupGlucoseUpdateTimer() - } - - // MARK: Handling CGM Manager Status observers - - private var statusObservers = WeakSynchronizedSet() - - public func addStatusObserver(_ observer: CGMManagerStatusObserver, queue: DispatchQueue) { - statusObservers.insert(observer, queue: queue) - } - - public func removeStatusObserver(_ observer: CGMManagerStatusObserver) { - statusObservers.removeElement(observer) - } - - private func notifyStatusObservers(cgmManagerStatus: CGMManagerStatus) { - delegate.notify { delegate in - delegate?.cgmManagerDidUpdateState(self) - delegate?.cgmManager(self, didUpdate: self.cgmManagerStatus) - } - statusObservers.forEach { observer in - observer.cgmManager(self, didUpdate: cgmManagerStatus) - } - } - - public init?(rawState: RawStateValue) { - if let mockSensorStateRawValue = rawState["mockSensorState"] as? MockCGMState.RawValue, - let mockSensorState = MockCGMState(rawValue: mockSensorStateRawValue) { - self.lockedMockSensorState.value = mockSensorState - } else { - self.lockedMockSensorState.value = MockCGMState(isStateValid: true) - } - - if let dataSourceRawValue = rawState["dataSource"] as? MockCGMDataSource.RawValue, - let dataSource = MockCGMDataSource(rawValue: dataSourceRawValue) { - self.lockedDataSource.value = dataSource - } else { - self.lockedDataSource.value = MockCGMDataSource(model: .sineCurve(parameters: (baseGlucose: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 110), amplitude: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 20), period: TimeInterval(hours: 6), referenceDate: Date()))) - } - - setupGlucoseUpdateTimer() - } - - deinit { - glucoseUpdateTimer?.invalidate() - } - - public var rawState: RawStateValue { - return [ - "mockSensorState": mockSensorState.rawValue, - "dataSource": dataSource.rawValue - ] - } - - public let isOnboarded = true // No distinction between created and onboarded - - public let appURL: URL? = nil - - public let providesBLEHeartbeat = false - - public let managedDataInterval: TimeInterval? = nil - - public var shouldSyncToRemoteService: Bool { - return self.mockSensorState.samplesShouldBeUploaded - } - - public var healthKitStorageDelayEnabled: Bool { - get { - MockCGMManager.healthKitStorageDelay == fixedHealthKitStorageDelay - } - set { - MockCGMManager.healthKitStorageDelay = newValue ? fixedHealthKitStorageDelay : 0 - } - } - - public let fixedHealthKitStorageDelay: TimeInterval = .minutes(2) - - public static var healthKitStorageDelay: TimeInterval = 0 - - private func logDeviceComms(_ type: DeviceLogEntryType, message: String) { - self.delegate.delegate?.deviceManager(self, logEventForDeviceIdentifier: "mockcgm", type: type, message: message, completion: nil) - } - - private func sendCGMReadingResult(_ result: CGMReadingResult) { - if case .newData(let samples) = result, - let currentValue = samples.first - { - mockSensorState.trendType = currentValue.trend - mockSensorState.trendRate = currentValue.trendRate - mockSensorState.glucoseRangeCategory = glucoseRangeCategory(for: currentValue.quantitySample) - issueAlert(for: currentValue) - } - self.delegate.notify { delegate in - delegate?.cgmManager(self, hasNew: result) - } - } - - public func glucoseRangeCategory(for glucose: GlucoseSampleValue) -> GlucoseRangeCategory? { - switch glucose.quantity { - case ...mockSensorState.cgmLowerLimit: - return glucose.wasUserEntered ? .urgentLow : .belowRange - case mockSensorState.cgmLowerLimit.. Void) { - let now = Date() - logDeviceComms(.send, message: "Fetch new data") - dataSource.fetchNewData { (result) in - switch result { - case .error(let error): - self.logDeviceComms(.error, message: "Error fetching new data: \(error)") - case .newData(let samples): - self.lastCommunicationDate = now - self.logDeviceComms(.receive, message: "New data received: \(samples)") - case .unreliableData: - self.lastCommunicationDate = now - self.logDeviceComms(.receive, message: "Unreliable data received") - case .noData: - self.lastCommunicationDate = now - self.logDeviceComms(.receive, message: "No new data") - } - completion(result) - } - } - - public func backfillData(datingBack duration: TimeInterval) { - let now = Date() - self.logDeviceComms(.send, message: "backfillData(\(duration))") - dataSource.backfillData(from: DateInterval(start: now.addingTimeInterval(-duration), end: now)) { result in - switch result { - case .error(let error): - self.logDeviceComms(.error, message: "Backfill error: \(error)") - case .newData(let samples): - self.logDeviceComms(.receive, message: "Backfill data: \(samples)") - case .unreliableData: - self.logDeviceComms(.receive, message: "Backfill data unreliable") - case .noData: - self.logDeviceComms(.receive, message: "Backfill empty") - } - self.sendCGMReadingResult(result) - } - } - - public func updateGlucoseUpdateTimer() { - glucoseUpdateTimer?.invalidate() - setupGlucoseUpdateTimer() - } - - private func setupGlucoseUpdateTimer() { - glucoseUpdateTimer = Timer.scheduledTimer(withTimeInterval: dataSource.dataPointFrequency.frequency, repeats: true) { [weak self] _ in - guard let self = self else { return } - self.fetchNewDataIfNeeded() { result in - self.sendCGMReadingResult(result) - } - } - } - - public func injectGlucoseSamples(_ samples: [NewGlucoseSample]) { - guard !samples.isEmpty else { return } - sendCGMReadingResult(CGMReadingResult.newData(samples.map { NewGlucoseSample($0, device: device) } )) - } -} - -fileprivate extension NewGlucoseSample { - init(_ other: NewGlucoseSample, device: HKDevice?) { - self.init(date: other.date, - quantity: other.quantity, - condition: other.condition, - trend: other.trend, - trendRate: other.trendRate, - isDisplayOnly: other.isDisplayOnly, - wasUserEntered: other.wasUserEntered, - syncIdentifier: other.syncIdentifier, - syncVersion: other.syncVersion, - device: device) - } -} - -// MARK: Alert Stuff - -extension MockCGMManager { - - public func getSoundBaseURL() -> URL? { - return Bundle(for: type(of: self)).bundleURL - } - - public func getSounds() -> [Alert.Sound] { - return alerts.map { $1.sound } - } - - public var hasRetractableAlert: Bool { - // signal loss alerts can only be removed by switching the CGM data source - return currentAlertIdentifier != nil && currentAlertIdentifier != MockCGMManager.signalLoss.identifier - } - - public var currentAlertIdentifier: Alert.AlertIdentifier? { - return mockSensorState.cgmStatusHighlight?.alertIdentifier - } - - public func issueAlert(identifier: Alert.AlertIdentifier, trigger: Alert.Trigger, delay: TimeInterval?, metadata: Alert.Metadata? = nil) { - guard let alert = alerts[identifier] else { - return - } - delegate.notifyDelayed(by: delay ?? 0) { delegate in - self.logDeviceComms(.delegate, message: "\(#function): \(identifier) \(trigger)") - delegate?.issueAlert(Alert(identifier: Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: identifier), - foregroundContent: alert.foregroundContent, - backgroundContent: alert.backgroundContent, - trigger: trigger, - interruptionLevel: alert.interruptionLevel, - sound: alert.sound, - metadata: metadata)) - } - - // updating the status highlight - setStatusHighlight(MockCGMStatusHighlight(localizedMessage: alert.foregroundContent.title, alertIdentifier: alert.identifier)) - } - - public func issueSignalLossAlert() { - issueAlert(identifier: MockCGMManager.signalLoss.identifier, trigger: .immediate, delay: nil) - } - - public func retractSignalLossAlert() { - retractAlert(identifier: MockCGMManager.signalLoss.identifier) - } - - public func acknowledgeAlert(alertIdentifier: Alert.AlertIdentifier, completion: @escaping (Error?) -> Void) { - self.logDeviceComms(.delegateResponse, message: "\(#function): Alert \(alertIdentifier) acknowledged.") - completion(nil) - } - - public func retractCurrentAlert() { - guard hasRetractableAlert, let identifier = currentAlertIdentifier else { return } - - retractAlert(identifier: identifier) - } - - public func retractAlert(identifier: Alert.AlertIdentifier) { - delegate.notify { $0?.retractAlert(identifier: Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: identifier)) } - - // updating the status highlight - if mockSensorState.cgmStatusHighlight?.alertIdentifier == identifier { - setStatusHighlight(nil) - } - } - - public func setStatusHighlight(_ statusHighlight: MockCGMStatusHighlight?) { - mockSensorState.cgmStatusHighlight = statusHighlight - - if statusHighlight == nil, - case .signalLoss = dataSource.model - { - // restore signal loss status highlight - issueSignalLossAlert() - } - } - - private func issueAlert(for glucose: NewGlucoseSample) { - guard mockSensorState.glucoseAlertingEnabled else { - return - } - - let alertTitle: String - let glucoseAlertIdentifier: String - let interruptionLevel: Alert.InterruptionLevel - switch glucose.quantity { - case ...mockSensorState.urgentLowGlucoseThreshold: - alertTitle = "Urgent Low Glucose Alert" - glucoseAlertIdentifier = "glucose.value.low.urgent" - interruptionLevel = .critical - case mockSensorState.urgentLowGlucoseThreshold.. 0.5 else - { - mockSensorState.cgmStatusBadge = MockCGMStatusBadge(badgeType: .lowBattery) - return - } - - mockSensorState.cgmStatusBadge = nil - } -} - -extension MockCGMManager { - public var debugDescription: String { - return """ - ## MockCGMManager - state: \(mockSensorState) - dataSource: \(dataSource) - """ - } -} - -extension MockCGMState: RawRepresentable { - public typealias RawValue = [String: Any] - - public init?(rawValue: RawValue) { - guard let isStateValid = rawValue["isStateValid"] as? Bool, - let glucoseAlertingEnabled = rawValue["glucoseAlertingEnabled"] as? Bool, - let urgentLowGlucoseThresholdValue = rawValue["urgentLowGlucoseThresholdValue"] as? Double, - let lowGlucoseThresholdValue = rawValue["lowGlucoseThresholdValue"] as? Double, - let highGlucoseThresholdValue = rawValue["highGlucoseThresholdValue"] as? Double, - let cgmLowerLimitValue = rawValue["cgmLowerLimitValue"] as? Double, - let cgmUpperLimitValue = rawValue["cgmUpperLimitValue"] as? Double else - { - return nil - } - - self.isStateValid = isStateValid - self.glucoseAlertingEnabled = glucoseAlertingEnabled - self.samplesShouldBeUploaded = rawValue["samplesShouldBeUploaded"] as? Bool ?? false - self.urgentLowGlucoseThresholdValue = urgentLowGlucoseThresholdValue - self.lowGlucoseThresholdValue = lowGlucoseThresholdValue - self.highGlucoseThresholdValue = highGlucoseThresholdValue - self.cgmLowerLimitValue = cgmLowerLimitValue - self.cgmUpperLimitValue = cgmUpperLimitValue - - if let glucoseRangeCategoryRawValue = rawValue["glucoseRangeCategory"] as? GlucoseRangeCategory.RawValue { - self.glucoseRangeCategory = GlucoseRangeCategory(rawValue: glucoseRangeCategoryRawValue) - } - - if let localizedMessage = rawValue["localizedMessage"] as? String, - let alertIdentifier = rawValue["alertIdentifier"] as? Alert.AlertIdentifier - { - self.cgmStatusHighlight = MockCGMStatusHighlight(localizedMessage: localizedMessage, alertIdentifier: alertIdentifier) - } - - if let statusBadgeTypeRawValue = rawValue["statusBadgeType"] as? MockCGMStatusBadge.MockCGMStatusBadgeType.RawValue, - let statusBadgeType = MockCGMStatusBadge.MockCGMStatusBadgeType(rawValue: statusBadgeTypeRawValue) - { - self.cgmStatusBadge = MockCGMStatusBadge(badgeType: statusBadgeType) - } - - if let cgmLifecycleProgressRawValue = rawValue["cgmLifecycleProgress"] as? MockCGMLifecycleProgress.RawValue { - self.cgmLifecycleProgress = MockCGMLifecycleProgress(rawValue: cgmLifecycleProgressRawValue) - } - - self.progressWarningThresholdPercentValue = rawValue["progressWarningThresholdPercentValue"] as? Double - self.progressCriticalThresholdPercentValue = rawValue["progressCriticalThresholdPercentValue"] as? Double - self.cgmBatteryChargeRemaining = rawValue["cgmBatteryChargeRemaining"] as? Double - - setProgressColor() - } - - public var rawValue: RawValue { - var rawValue: RawValue = [ - "isStateValid": isStateValid, - "glucoseAlertingEnabled": glucoseAlertingEnabled, - "samplesShouldBeUploaded": samplesShouldBeUploaded, - "urgentLowGlucoseThresholdValue": urgentLowGlucoseThresholdValue, - "lowGlucoseThresholdValue": lowGlucoseThresholdValue, - "highGlucoseThresholdValue": highGlucoseThresholdValue, - "cgmLowerLimitValue": cgmLowerLimitValue, - "cgmUpperLimitValue": cgmUpperLimitValue, - ] - - if let glucoseRangeCategory = glucoseRangeCategory { - rawValue["glucoseRangeCategory"] = glucoseRangeCategory.rawValue - } - - if let cgmStatusHighlight = cgmStatusHighlight { - rawValue["localizedMessage"] = cgmStatusHighlight.localizedMessage - rawValue["alertIdentifier"] = cgmStatusHighlight.alertIdentifier - } - - if let cgmStatusBadgeType = cgmStatusBadge?.badgeType { - rawValue["statusBadgeType"] = cgmStatusBadgeType.rawValue - } - - if let cgmLifecycleProgress = cgmLifecycleProgress { - rawValue["cgmLifecycleProgress"] = cgmLifecycleProgress.rawValue - } - - if let progressWarningThresholdPercentValue = progressWarningThresholdPercentValue { - rawValue["progressWarningThresholdPercentValue"] = progressWarningThresholdPercentValue - } - - if let progressCriticalThresholdPercentValue = progressCriticalThresholdPercentValue { - rawValue["progressCriticalThresholdPercentValue"] = progressCriticalThresholdPercentValue - } - - if let cgmBatteryChargeRemaining = cgmBatteryChargeRemaining { - rawValue["cgmBatteryChargeRemaining"] = cgmBatteryChargeRemaining - } - - return rawValue - } -} - -extension MockCGMState: CustomDebugStringConvertible { - public var debugDescription: String { - return """ - ## MockCGMState - * isStateValid: \(isStateValid) - * glucoseAlertingEnabled: \(glucoseAlertingEnabled) - * samplesShouldBeUploaded: \(samplesShouldBeUploaded) - * urgentLowGlucoseThresholdValue: \(urgentLowGlucoseThresholdValue) - * lowGlucoseThresholdValue: \(lowGlucoseThresholdValue) - * highGlucoseThresholdValue: \(highGlucoseThresholdValue) - * cgmLowerLimitValue: \(cgmLowerLimitValue) - * cgmUpperLimitValue: \(cgmUpperLimitValue) - * highGlucoseThresholdValue: \(highGlucoseThresholdValue) - * glucoseRangeCategory: \(glucoseRangeCategory as Any) - * cgmStatusHighlight: \(cgmStatusHighlight as Any) - * cgmStatusBadge: \(cgmStatusBadge as Any) - * cgmLifecycleProgress: \(cgmLifecycleProgress as Any) - * progressWarningThresholdPercentValue: \(progressWarningThresholdPercentValue as Any) - * progressCriticalThresholdPercentValue: \(progressCriticalThresholdPercentValue as Any) - * cgmBatteryChargeRemaining: \(cgmBatteryChargeRemaining as Any) - """ - } -} diff --git a/Dependencies/LoopKit/MockKit/MockDoseProgressEstimator.swift b/Dependencies/LoopKit/MockKit/MockDoseProgressEstimator.swift deleted file mode 100644 index 84ba9e051..000000000 --- a/Dependencies/LoopKit/MockKit/MockDoseProgressEstimator.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// MockDoseProgressEstimator.swift -// MockKit -// -// Created by Pete Schwamb on 3/17/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - - -class MockDoseProgressEstimator: DoseProgressTimerEstimator { - - public let dose: DoseEntry - - override var progress: DoseProgress { - let elapsed = -dose.startDate.timeIntervalSinceNow - let duration = dose.endDate.timeIntervalSince(dose.startDate) - let percentProgress = min(elapsed / duration, 1) - let delivered = round(percentProgress * dose.programmedUnits * 20) / 20 - return DoseProgress(deliveredUnits: delivered, percentComplete: delivered / dose.programmedUnits) - } - - public init(reportingQueue: DispatchQueue, dose: DoseEntry) { - self.dose = dose - super.init(reportingQueue: reportingQueue) - } - - override func timerParameters() -> (delay: TimeInterval, repeating: TimeInterval) { - let timeSinceStart = -dose.startDate.timeIntervalSinceNow - let timeBetweenPulses: TimeInterval - switch dose.type { - case .bolus: - timeBetweenPulses = TimeInterval(2) - case .basal, .tempBasal: - timeBetweenPulses = 0.05 / dose.unitsPerHour * .hours(1) - default: - fatalError("Can only estimate progress on basal rates or boluses.") - } - let delayUntilNextPulse = timeBetweenPulses - timeSinceStart.remainder(dividingBy: timeBetweenPulses) - return (delay: delayUntilNextPulse, repeating: timeBetweenPulses) - } -} diff --git a/Dependencies/LoopKit/MockKit/MockGlucoseProvider.swift b/Dependencies/LoopKit/MockKit/MockGlucoseProvider.swift deleted file mode 100644 index e2b7cc0ae..000000000 --- a/Dependencies/LoopKit/MockKit/MockGlucoseProvider.swift +++ /dev/null @@ -1,280 +0,0 @@ -// -// MockGlucoseProvider.swift -// LoopKit -// -// Created by Michael Pangburn on 11/23/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import HealthKit -import LoopKit - - -/// Returns a value based on the result of a random coin flip. -/// - Parameter chanceOfHeads: The chance of flipping heads. Must be a value in the range `0...1`. Defaults to `0.5`. -/// - Parameter valueIfHeads: An autoclosure producing the value to return if the coin flips heads. -/// - Parameter valueIfTails: An autoclosure producing the value to return if the coin flips tails. -private func coinFlip( - withChanceOfHeads chanceOfHeads: Double = 0.5, - ifHeads valueIfHeads: @autoclosure () -> Output, - ifTails valueIfTails: @autoclosure () -> Output -) -> Output { - precondition((0...1).contains(chanceOfHeads)) - let isHeads = .random(in: 0..<100) < chanceOfHeads * 100 - return isHeads ? valueIfHeads() : valueIfTails() -} - - -struct MockGlucoseProvider { - struct BackfillRequest { - let duration: TimeInterval - let dataPointFrequency: TimeInterval - - var dataPointCount: Int { - return Int(duration / dataPointFrequency) - } - - init(datingBack duration: TimeInterval, dataPointFrequency: TimeInterval) { - self.duration = duration - self.dataPointFrequency = dataPointFrequency - } - } - - /// Given a date, asynchronously produce the CGMReadingResult at that date. - private let fetchDataAt: (_ date: Date, _ completion: @escaping (CGMReadingResult) -> Void) -> Void - - func fetchData(at date: Date, completion: @escaping (CGMReadingResult) -> Void) { - fetchDataAt(date, completion) - } - - func backfill(_ backfill: BackfillRequest, endingAt date: Date, completion: @escaping (CGMReadingResult) -> Void) { - let dataPointDates = (0...backfill.dataPointCount).map { offset in - return date.addingTimeInterval(-backfill.dataPointFrequency * Double(offset)) - } - dataPointDates.asyncMap(fetchDataAt) { allResults in - let allSamples = allResults.flatMap { result -> [NewGlucoseSample] in - if case .newData(let samples) = result { - return samples - } else { - return [] - } - } - let result: CGMReadingResult = allSamples.isEmpty ? .noData : .newData(allSamples.reversed()) - completion(result) - } - } -} - -extension MockGlucoseProvider { - init(model: MockCGMDataSource.Model, effects: MockCGMDataSource.Effects) { - self = effects.transformations.reduce(model.glucoseProvider) { model, transform in transform(model) } - } - - private static func glucoseSample(at date: Date, quantity: HKQuantity, condition: GlucoseCondition?, trend: GlucoseTrend?, trendRate: HKQuantity?) -> NewGlucoseSample { - return NewGlucoseSample( - date: date, - quantity: quantity, - condition: condition, - trend: trend, - trendRate: trendRate, - isDisplayOnly: false, - wasUserEntered: false, - syncIdentifier: UUID().uuidString, - device: MockCGMDataSource.device - ) - } -} - -// MARK: - Models - -extension MockGlucoseProvider { - fileprivate static func constant(_ quantity: HKQuantity) -> MockGlucoseProvider { - return MockGlucoseProvider { date, completion in - let sample = glucoseSample(at: date, quantity: quantity, condition: nil, trend: .flat, trendRate: HKQuantity(unit: .milligramsPerDeciliterPerMinute, doubleValue: 0)) - completion(.newData([sample])) - } - } - - fileprivate static func sineCurve(parameters: MockCGMDataSource.Model.SineCurveParameters) -> MockGlucoseProvider { - let (baseGlucose, amplitude, period, referenceDate) = parameters - precondition(period > 0) - let unit = HKUnit.milligramsPerDeciliter - let trendRateUnit = unit.unitDivided(by: .minute()) - precondition(baseGlucose.is(compatibleWith: unit)) - precondition(amplitude.is(compatibleWith: unit)) - let baseGlucoseValue = baseGlucose.doubleValue(for: unit) - let amplitudeValue = amplitude.doubleValue(for: unit) - let chanceOfNilTrendRate = 1.0/20.0 - var prevGlucoseValue: Double? - - return MockGlucoseProvider { date, completion in - let timeOffset = date.timeIntervalSince1970 - referenceDate.timeIntervalSince1970 - func sine(_ t: TimeInterval) -> Double { - return Double(baseGlucoseValue + amplitudeValue * sin(2 * .pi / period * t)).rounded() - } - let glucoseValue = sine(timeOffset) - var trend: GlucoseTrend? - var trendRate: HKQuantity? - if let prevGlucoseValue = prevGlucoseValue, - let trendRateValue = coinFlip(withChanceOfHeads: chanceOfNilTrendRate, ifHeads: nil, ifTails: glucoseValue - prevGlucoseValue) { - let smallDelta = 0.9 - let mediumDelta = 2.0 - let largeDelta = 5.0 - switch trendRateValue { - case -smallDelta ... smallDelta: - trend = .flat - case -mediumDelta ..< -smallDelta: - trend = .down - case -largeDelta ..< -mediumDelta: - trend = .downDown - case -Double.greatestFiniteMagnitude ..< -largeDelta: - trend = .downDownDown - case smallDelta ... mediumDelta: - trend = .up - case mediumDelta ... largeDelta: - trend = .upUp - case largeDelta ... Double.greatestFiniteMagnitude: - trend = .upUpUp - default: - break - } - trendRate = HKQuantity(unit: trendRateUnit, doubleValue: trendRateValue) - } - let sample = glucoseSample(at: date, quantity: HKQuantity(unit: unit, doubleValue: glucoseValue), condition: nil, trend: trend, trendRate: trendRate) - // capture semantics lets me "stow" the previous glucose value with this static function. A little weird, but it seems to work. - prevGlucoseValue = glucoseValue - completion(.newData([sample])) - } - } - - fileprivate static var noData: MockGlucoseProvider { - return MockGlucoseProvider { _, completion in completion(.noData) } - } - - fileprivate static var signalLoss: MockGlucoseProvider { - return MockGlucoseProvider { _, _ in } - } - - fileprivate static var unreliableData: MockGlucoseProvider { - return MockGlucoseProvider { _, completion in completion(.unreliableData) } - } - - fileprivate static func error(_ error: Error) -> MockGlucoseProvider { - return MockGlucoseProvider { _, completion in completion(.error(error)) } - } -} - -// MARK: - Effects - -private struct MockGlucoseProviderError: Error { } - -extension MockGlucoseProvider { - fileprivate func withRandomNoise(upTo magnitude: HKQuantity) -> MockGlucoseProvider { - let unit = HKUnit.milligramsPerDeciliter - precondition(magnitude.is(compatibleWith: unit)) - let magnitude = magnitude.doubleValue(for: unit) - - return mapGlucoseQuantities { glucose in - let glucoseValue = (glucose.doubleValue(for: unit) + .random(in: -magnitude...magnitude)).rounded() - return HKQuantity(unit: unit, doubleValue: glucoseValue) - } - } - - fileprivate func randomlyProducingLowOutlier(withChance chanceOfOutlier: Double, outlierDelta: HKQuantity) -> MockGlucoseProvider { - return randomlyProducingOutlier(withChance: chanceOfOutlier, outlierDeltaMagnitude: outlierDelta, outlierDeltaSign: -) - } - - fileprivate func randomlyProducingHighOutlier(withChance chanceOfOutlier: Double, outlierDelta: HKQuantity) -> MockGlucoseProvider { - return randomlyProducingOutlier(withChance: chanceOfOutlier, outlierDeltaMagnitude: outlierDelta, outlierDeltaSign: +) - } - - private func randomlyProducingOutlier( - withChance chanceOfOutlier: Double, - outlierDeltaMagnitude: HKQuantity, - outlierDeltaSign: (Double) -> Double - ) -> MockGlucoseProvider { - let unit = HKUnit.milligramsPerDeciliter - precondition(outlierDeltaMagnitude.is(compatibleWith: unit)) - let outlierDelta = outlierDeltaSign(outlierDeltaMagnitude.doubleValue(for: unit)) - return mapGlucoseQuantities { glucose in - return coinFlip( - withChanceOfHeads: chanceOfOutlier, - ifHeads: HKQuantity(unit: unit, doubleValue: (glucose.doubleValue(for: unit) + outlierDelta).rounded()), - ifTails: glucose - ) - } - } - - fileprivate func randomlyErroringOnNewData(withChance chance: Double) -> MockGlucoseProvider { - return mapResult { result in - return coinFlip(withChanceOfHeads: chance, ifHeads: .error(MockGlucoseProviderError()), ifTails: result) - } - } - - private func mapResult(_ transform: @escaping (CGMReadingResult) -> CGMReadingResult) -> MockGlucoseProvider { - return MockGlucoseProvider { date, completion in - self.fetchData(at: date) { result in - completion(transform(result)) - } - } - } - - private func mapGlucoseQuantities(_ transform: @escaping (HKQuantity) -> HKQuantity) -> MockGlucoseProvider { - return mapResult { result in - return result.mapGlucoseQuantities(transform) - } - } -} - -private extension CGMReadingResult { - func mapGlucoseQuantities(_ transform: (HKQuantity) -> HKQuantity) -> CGMReadingResult { - guard case .newData(let samples) = self else { - return self - } - return .newData( - samples.map { sample in - return NewGlucoseSample( - date: sample.date, - quantity: transform(sample.quantity), - condition: sample.condition, - trend: sample.trend, - trendRate: sample.trendRate, - isDisplayOnly: sample.isDisplayOnly, - wasUserEntered: sample.wasUserEntered, - syncIdentifier: sample.syncIdentifier, - syncVersion: sample.syncVersion, - device: sample.device - ) - } - ) - } -} - -private extension MockCGMDataSource.Model { - var glucoseProvider: MockGlucoseProvider { - switch self { - case .constant(let quantity): - return .constant(quantity) - case .sineCurve(parameters: let parameters): - return .sineCurve(parameters: parameters) - case .noData: - return .noData - case .signalLoss: - return .signalLoss - case .unreliableData: - return .unreliableData - } - } -} - -private extension MockCGMDataSource.Effects { - var transformations: [(MockGlucoseProvider) -> MockGlucoseProvider] { - // Each effect maps to a transformation on a MockGlucoseProvider - return [ - glucoseNoise.map { maximumDeltaMagnitude in { $0.withRandomNoise(upTo: maximumDeltaMagnitude) } }, - randomLowOutlier.map { chance, delta in { $0.randomlyProducingLowOutlier(withChance: chance, outlierDelta: delta) } }, - randomHighOutlier.map { chance, delta in { $0.randomlyProducingHighOutlier(withChance: chance, outlierDelta: delta) } }, - randomErrorChance.map { chance in { $0.randomlyErroringOnNewData(withChance: chance) } } - ].compactMap { $0 } - } -} diff --git a/Dependencies/LoopKit/MockKit/MockKit.h b/Dependencies/LoopKit/MockKit/MockKit.h deleted file mode 100644 index 5804e5e4f..000000000 --- a/Dependencies/LoopKit/MockKit/MockKit.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// MockKit.h -// MockKit -// -// Created by Michael Pangburn on 12/20/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -#import - -//! Project version number for MockKit. -FOUNDATION_EXPORT double MockKitVersionNumber; - -//! Project version string for MockKit. -FOUNDATION_EXPORT const unsigned char MockKitVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/LoopKit/MockKit/MockPumpManager.swift b/Dependencies/LoopKit/MockKit/MockPumpManager.swift deleted file mode 100644 index a4a0479f7..000000000 --- a/Dependencies/LoopKit/MockKit/MockPumpManager.swift +++ /dev/null @@ -1,637 +0,0 @@ -// -// MockPumpManager.swift -// LoopKit -// -// Created by Michael Pangburn on 11/20/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import HealthKit -import LoopKit -import LoopTestingKit - -public protocol MockPumpManagerStateObserver { - func mockPumpManager(_ manager: MockPumpManager, didUpdate state: MockPumpManagerState) - func mockPumpManager(_ manager: MockPumpManager, didUpdate status: PumpManagerStatus, oldStatus: PumpManagerStatus) -} - -public enum MockPumpManagerError: LocalizedError { - case pumpSuspended - case communicationFailure - case bolusInProgress - case missingSettings - case pumpError - - - public var failureReason: String? { - switch self { - case .pumpSuspended: - return "Pump is suspended" - case .communicationFailure: - return "Unable to communicate with pump" - case .bolusInProgress: - return "Bolus in progress" - case .missingSettings: - return "Missing Settings" - case .pumpError: - return "Pump is in an error state" - } - } -} - -public final class MockPumpManager: TestingPumpManager { - - public static let managerIdentifier = "MockPumpManager" - - public var managerIdentifier: String { - return MockPumpManager.managerIdentifier - } - - public static let localizedTitle = "Insulin Pump Simulator" - - public var localizedTitle: String { - return MockPumpManager.localizedTitle - } - - public static var onboardingMaximumBasalScheduleEntryCount: Int { - return 48 - } - - public static var onboardingSupportedBasalRates: [Double] { - MockPumpManagerState.DeliverableIncrements.medtronicX22.supportedBasalRates! - } - - public static var onboardingSupportedBolusVolumes: [Double] { - MockPumpManagerState.DeliverableIncrements.medtronicX22.supportedBolusVolumes! - } - - public static var onboardingSupportedMaximumBolusVolumes: [Double] { - self.onboardingSupportedBolusVolumes - } - - private static let device = HKDevice( - name: MockPumpManager.managerIdentifier, - manufacturer: nil, - model: nil, - hardwareVersion: nil, - firmwareVersion: nil, - softwareVersion: "1.0", - localIdentifier: nil, - udiDeviceIdentifier: nil - ) - - private static let deliveryUnitsPerMinute = 1.5 - private static let pumpReservoirCapacity: Double = 200 - - public var pumpReservoirCapacity: Double { - return MockPumpManager.pumpReservoirCapacity - } - - public var reservoirFillFraction: Double { - get { - return state.reservoirUnitsRemaining / pumpReservoirCapacity - } - set { - state.reservoirUnitsRemaining = max(newValue * pumpReservoirCapacity, 0) - } - } - - public var currentBasalRate: HKQuantity? { - switch status.basalDeliveryState { - case .suspending, .suspended(_): - return HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 0) - case .tempBasal(let dose): - return HKQuantity(unit: .internationalUnitsPerHour, doubleValue: dose.unitsPerHour) - case .none: - return nil - default: - guard let scheduledBasalRate = state.basalRateSchedule?.value(at: Date()) else { return nil } - - return HKQuantity(unit: .internationalUnitsPerHour, doubleValue: scheduledBasalRate) - } - } - - public var supportedBolusVolumes: [Double] { - return state.supportedBolusVolumes - } - - public var supportedMaximumBolusVolumes: [Double] { - state.supportedBolusVolumes - } - - public var supportedBasalRates: [Double] { - return state.supportedBasalRates - } - - public var maximumBasalScheduleEntryCount: Int { - return 48 - } - - public var minimumBasalScheduleEntryDuration: TimeInterval { - return .minutes(30) - } - - public var testingDevice: HKDevice { - return type(of: self).device - } - - public var testLastReconciliation: Date? = nil - - public var lastSync: Date? { - return testLastReconciliation ?? Date() - } - - public var insulinType: InsulinType? { - return state.insulinType - } - - private func basalDeliveryState(for state: MockPumpManagerState) -> PumpManagerStatus.BasalDeliveryState? { - if case .suspended(let date) = state.suspendState { - return .suspended(date) - } - if state.occlusionDetected || state.pumpErrorDetected || state.pumpBatteryChargeRemaining == 0 || state.reservoirUnitsRemaining == 0 { - return nil - } - if let temp = state.unfinalizedTempBasal, !temp.finished { - return .tempBasal(DoseEntry(temp)) - } - if case .resumed(let date) = state.suspendState { - return .active(date) - } else { - return .active(Date()) - } - } - - private func bolusState(for state: MockPumpManagerState) -> PumpManagerStatus.BolusState { - if let bolus = state.unfinalizedBolus, !bolus.finished { - return .inProgress(DoseEntry(bolus)) - } else { - return .noBolus - } - } - - public func buildPumpStatusHighlight(for state: MockPumpManagerState) -> PumpStatusHighlight? { - if state.deliveryIsUncertain { - return PumpStatusHighlight(localizedMessage: LocalizedString("Comms Issue", comment: "Status highlight that delivery is uncertain."), - imageName: "exclamationmark.circle.fill", - state: .critical) - } - else if state.reservoirUnitsRemaining == 0 { - return PumpStatusHighlight(localizedMessage: LocalizedString("No Insulin", comment: "Status highlight that a pump is out of insulin."), - imageName: "exclamationmark.circle.fill", - state: .critical) - } else if state.occlusionDetected { - return PumpStatusHighlight(localizedMessage: LocalizedString("Pump Occlusion", comment: "Status highlight that an occlusion was detected."), - imageName: "exclamationmark.circle.fill", - state: .critical) - } else if state.pumpErrorDetected { - return PumpStatusHighlight(localizedMessage: LocalizedString("Pump Error", comment: "Status highlight that a pump error occurred."), - imageName: "exclamationmark.circle.fill", - state: .critical) - } else if pumpBatteryChargeRemaining == 0 { - return PumpStatusHighlight(localizedMessage: LocalizedString("Pump Battery Dead", comment: "Status highlight that pump has a dead battery."), - imageName: "exclamationmark.circle.fill", - state: .critical) - } else if case .suspended = state.suspendState { - return PumpStatusHighlight(localizedMessage: LocalizedString("Insulin Suspended", comment: "Status highlight that insulin delivery was suspended."), - imageName: "pause.circle.fill", - state: .warning) - } - - return nil - } - - public func buildPumpLifecycleProgress(for state: MockPumpManagerState) -> PumpLifecycleProgress? { - guard let progressPercentComplete = state.progressPercentComplete else { - return nil - } - - let progressState: DeviceLifecycleProgressState - if let progressCriticalThresholdPercentValue = state.progressCriticalThresholdPercentValue, - progressPercentComplete >= progressCriticalThresholdPercentValue - { - progressState = .critical - } else if let progressWarningThresholdPercentValue = state.progressWarningThresholdPercentValue, - progressPercentComplete >= progressWarningThresholdPercentValue - { - progressState = .warning - } else { - progressState = .normalPump - } - - return PumpLifecycleProgress(percentComplete: progressPercentComplete, - progressState: progressState) - } - - public var isClockOffset: Bool { - let now = Date() - return TimeZone.current.secondsFromGMT(for: now) != state.timeZone.secondsFromGMT(for: now) - } - - private func status(for state: MockPumpManagerState) -> PumpManagerStatus { - return PumpManagerStatus( - timeZone: state.timeZone, - device: MockPumpManager.device, - pumpBatteryChargeRemaining: state.pumpBatteryChargeRemaining, - basalDeliveryState: basalDeliveryState(for: state), - bolusState: bolusState(for: state), - insulinType: state.insulinType, - deliveryIsUncertain: state.deliveryIsUncertain - ) - } - - public var pumpBatteryChargeRemaining: Double? { - get { - return state.pumpBatteryChargeRemaining - } - set { - state.pumpBatteryChargeRemaining = newValue - } - } - - public var status: PumpManagerStatus { - get { - return status(for: self.state) - } - } - - private func notifyStatusObservers(oldStatus: PumpManagerStatus) { - let status = self.status - delegate.notify { (delegate) in - delegate?.pumpManager(self, didUpdate: status, oldStatus: oldStatus) - } - statusObservers.forEach { (observer) in - observer.pumpManager(self, didUpdate: status, oldStatus: oldStatus) - } - } - - public func estimatedDuration(toBolus units: Double) -> TimeInterval { - .minutes(units / type(of: self).deliveryUnitsPerMinute) - } - - public var state: MockPumpManagerState { - didSet { - let newValue = state - - guard newValue != oldValue else { - return - } - - let oldStatus = status(for: oldValue) - let newStatus = status(for: newValue) - - if oldStatus != newStatus { - notifyStatusObservers(oldStatus: oldStatus) - } - - // stop insulin delivery as pump state requires - if (newValue.occlusionDetected != oldValue.occlusionDetected && newValue.occlusionDetected) || - (newValue.pumpErrorDetected != oldValue.pumpErrorDetected && newValue.pumpErrorDetected) || - (newValue.pumpBatteryChargeRemaining != oldValue.pumpBatteryChargeRemaining && newValue.pumpBatteryChargeRemaining == 0) || - (newValue.reservoirUnitsRemaining != oldValue.reservoirUnitsRemaining && newValue.reservoirUnitsRemaining == 0) - { - stopInsulinDelivery() - } - - stateObservers.forEach { $0.mockPumpManager(self, didUpdate: self.state) } - - delegate.notify { (delegate) in - if newValue.reservoirUnitsRemaining != oldValue.reservoirUnitsRemaining { - delegate?.pumpManager(self, didReadReservoirValue: self.state.reservoirUnitsRemaining, at: Date()) { result in - // nothing to do here - } - } - delegate?.pumpManagerDidUpdateState(self) - - delegate?.pumpManager(self, didUpdate: newStatus, oldStatus: oldStatus) - } - } - } - - public var pumpManagerDelegate: PumpManagerDelegate? { - get { - return delegate.delegate - } - set { - delegate.delegate = newValue - } - } - - public var delegateQueue: DispatchQueue! { - get { - return delegate.queue - } - set { - delegate.queue = newValue - } - } - - private let delegate = WeakSynchronizedDelegate() - - private var statusObservers = WeakSynchronizedSet() - private var stateObservers = WeakSynchronizedSet() - - public init() { - state = MockPumpManagerState(reservoirUnitsRemaining: MockPumpManager.pumpReservoirCapacity) - } - - public init?(rawState: RawStateValue) { - if let state = (rawState["state"] as? MockPumpManagerState.RawValue).flatMap(MockPumpManagerState.init(rawValue:)) { - self.state = state - } else { - self.state = MockPumpManagerState(reservoirUnitsRemaining: MockPumpManager.pumpReservoirCapacity) - } - } - - public var rawState: RawStateValue { - return ["state": state.rawValue] - } - - public let isOnboarded = true // No distinction between created and onboarded - - private func logDeviceCommunication(_ message: String, type: DeviceLogEntryType = .send) { - self.delegate.delegate?.deviceManager(self, logEventForDeviceIdentifier: "MockId", type: type, message: message, completion: nil) - } - - public func createBolusProgressReporter(reportingOn dispatchQueue: DispatchQueue) -> DoseProgressReporter? { - if case .inProgress(let dose) = status.bolusState { - return MockDoseProgressEstimator(reportingQueue: dispatchQueue, dose: dose) - } - return nil - } - - public var pumpRecordsBasalProfileStartEvents: Bool { - return false - } - - public func addStatusObserver(_ observer: PumpManagerStatusObserver, queue: DispatchQueue) { - statusObservers.insert(observer, queue: queue) - } - - public func addStateObserver(_ observer: MockPumpManagerStateObserver, queue: DispatchQueue) { - stateObservers.insert(observer, queue: queue) - } - - public func removeStatusObserver(_ observer: PumpManagerStatusObserver) { - statusObservers.removeElement(observer) - } - - public func ensureCurrentPumpData(completion: ((Date?) -> Void)?) { - // Change this to artificially increase the delay fetching the current pump data - let fetchDelay = 0 - DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(fetchDelay)) { - - self.state.finalizeFinishedDoses() - - self.storePumpEvents { (error) in - guard error == nil else { - completion?(self.lastSync) - return - } - - let totalInsulinUsage = self.state.finalizedDoses.reduce(into: 0 as Double) { total, dose in - total += dose.units - } - - self.state.finalizedDoses = [] - self.state.reservoirUnitsRemaining = max(self.state.reservoirUnitsRemaining - totalInsulinUsage, 0) - - completion?(self.lastSync) - } - } - } - - private func storePumpEvents(completion: @escaping (_ error: Error?) -> Void) { - state.finalizeFinishedDoses() - let pendingPumpEvents = state.pumpEventsToStore - delegate.notify { (delegate) in - delegate?.pumpManager(self, hasNewPumpEvents: pendingPumpEvents, lastReconciliation: self.lastSync) { error in - if error == nil { - self.state.additionalPumpEvents = [] - } - completion(error) - } - } - } - - public func enactTempBasal(unitsPerHour: Double, for duration: TimeInterval, completion: @escaping (PumpManagerError?) -> Void) { - logDeviceComms(.send, message: "Temp Basal \(unitsPerHour) U/hr Duration:\(duration.hours)") - - if state.tempBasalEnactmentShouldError || state.pumpBatteryChargeRemaining == 0 { - let error = PumpManagerError.communication(MockPumpManagerError.communicationFailure) - logDeviceComms(.error, message: "Temp Basal failed with error \(error)") - completion(error) - } else if state.deliveryCommandsShouldTriggerUncertainDelivery { - state.deliveryIsUncertain = true - logDeviceComms(.error, message: "Uncertain delivery for temp basal") - completion(.uncertainDelivery) - } else if state.occlusionDetected || state.pumpErrorDetected { - let error = PumpManagerError.deviceState(MockPumpManagerError.pumpError) - logDeviceComms(.error, message: "Temp Basal failed because the pump is in an error state") - completion(error) - } else if case .suspended = state.suspendState { - let error = PumpManagerError.deviceState(MockPumpManagerError.pumpSuspended) - logDeviceComms(.error, message: "Temp Basal failed because inulin delivery is suspended") - completion(error) - } else if state.reservoirUnitsRemaining == 0 { - let error = PumpManagerError.deviceState(MockPumpManagerError.pumpSuspended) - logDeviceComms(.error, message: "Temp Basal failed because there is no insulin in the reservoir") - completion(error) - } else { - let now = Date() - if let temp = state.unfinalizedTempBasal, temp.finishTime.compare(now) == .orderedDescending { - state.unfinalizedTempBasal?.cancel(at: now) - } - state.finalizeFinishedDoses() - - logDeviceComms(.receive, message: "Temp Basal succeeded") - - if duration < .ulpOfOne { - // Cancel temp basal - storePumpEvents { (error) in - completion(nil) - } - } else { - let temp = UnfinalizedDose(tempBasalRate: unitsPerHour, startTime: now, duration: duration, insulinType: state.insulinType) - state.unfinalizedTempBasal = temp - storePumpEvents { (error) in - completion(nil) - } - } - logDeviceCommunication("enactTempBasal succeeded", type: .receive) - } - } - - private func logDeviceComms(_ type: DeviceLogEntryType, message: String) { - self.delegate.delegate?.deviceManager(self, logEventForDeviceIdentifier: "mockpump", type: type, message: message, completion: nil) - } - - public func enactBolus(units: Double, activationType: BolusActivationType, completion: @escaping (PumpManagerError?) -> Void) { - - logDeviceCommunication("enactBolus(\(units), \(activationType))") - - if state.bolusEnactmentShouldError || state.pumpBatteryChargeRemaining == 0 { - let error = PumpManagerError.communication(MockPumpManagerError.communicationFailure) - logDeviceComms(.error, message: "Bolus failed with error \(error)") - completion(error) - } else if state.deliveryCommandsShouldTriggerUncertainDelivery { - state.deliveryIsUncertain = true - logDeviceComms(.error, message: "Uncertain delivery for bolus") - completion(PumpManagerError.uncertainDelivery) - } else if state.occlusionDetected || state.pumpErrorDetected { - let error = PumpManagerError.deviceState(MockPumpManagerError.pumpError) - logDeviceComms(.error, message: "Bolus failed because the pump is in an error state") - completion(error) - } else if state.reservoirUnitsRemaining == 0 { - let error = PumpManagerError.deviceState(MockPumpManagerError.pumpSuspended) - logDeviceComms(.error, message: "Bolus failed because there is no insulin in the reservoir") - completion(error) - } else { - state.finalizeFinishedDoses() - - if let _ = state.unfinalizedBolus { - logDeviceCommunication("enactBolus failed: bolusInProgress", type: .error) - completion(PumpManagerError.deviceState(MockPumpManagerError.bolusInProgress)) - return - } - - if case .suspended = status.basalDeliveryState { - logDeviceCommunication("enactBolus failed: pumpSuspended", type: .error) - completion(PumpManagerError.deviceState(MockPumpManagerError.pumpSuspended)) - return - } - - - let bolus = UnfinalizedDose(bolusAmount: units, startTime: Date(), duration: .minutes(units / type(of: self).deliveryUnitsPerMinute), insulinType: state.insulinType, automatic: activationType.isAutomatic) - state.unfinalizedBolus = bolus - - logDeviceComms(.receive, message: "Bolus accepted") - - storePumpEvents { (error) in - completion(nil) - self.logDeviceCommunication("enactBolus succeeded", type: .receive) - } - } - } - - public func cancelBolus(completion: @escaping (PumpManagerResult) -> Void) { - logDeviceComms(.send, message: "Cancel") - - if self.state.bolusCancelShouldError { - let error = PumpManagerError.communication(MockPumpManagerError.communicationFailure) - logDeviceComms(.error, message: "Cancel failed with error: \(error)") - completion(.failure(error)) - } else { - state.unfinalizedBolus?.cancel(at: Date()) - - storePumpEvents { (_) in - DispatchQueue.main.async { - self.state.finalizeFinishedDoses() - completion(.success(nil)) - } - } - } - } - - public func setMustProvideBLEHeartbeat(_ mustProvideBLEHeartbeat: Bool) { - // nothing to do here - } - - private func stopInsulinDelivery() { - let now = Date() - state.unfinalizedTempBasal?.cancel(at: now) - state.unfinalizedBolus?.cancel(at: now) - storePumpEvents { _ in } - } - - public func suspendDelivery(completion: @escaping (Error?) -> Void) { - logDeviceComms(.send, message: "Suspend") - - if self.state.deliverySuspensionShouldError { - let error = PumpManagerError.communication(MockPumpManagerError.communicationFailure) - logDeviceComms(.error, message: "Suspend failed with error: \(error)") - completion(error) - } else { - let now = Date() - state.unfinalizedTempBasal?.cancel(at: now) - state.unfinalizedBolus?.cancel(at: now) - - - let suspendDate = Date() - let suspend = UnfinalizedDose(suspendStartTime: suspendDate) - self.state.finalizedDoses.append(suspend) - self.state.suspendState = .suspended(suspendDate) - logDeviceComms(.receive, message: "Suspend accepted") - - storePumpEvents { (error) in - completion(error) - } - logDeviceCommunication("suspendDelivery succeeded", type: .receive) - } - } - - public func resumeDelivery(completion: @escaping (Error?) -> Void) { - logDeviceComms(.send, message: "Resume") - - if self.state.deliveryResumptionShouldError { - let error = PumpManagerError.communication(MockPumpManagerError.communicationFailure) - logDeviceComms(.error, message: "Resume failed with error: \(error)") - completion(error) - } else { - let resumeDate = Date() - let resume = UnfinalizedDose(resumeStartTime: resumeDate, insulinType: state.insulinType) - self.state.finalizedDoses.append(resume) - self.state.suspendState = .resumed(resumeDate) - storePumpEvents { (error) in - completion(error) - } - logDeviceCommunication("resumeDelivery succeeded", type: .receive) - } - } - - public func injectPumpEvents(_ pumpEvents: [NewPumpEvent]) { - state.finalizedDoses += pumpEvents.compactMap { $0.unfinalizedDose } - state.additionalPumpEvents += pumpEvents.filter { $0.dose == nil } - } - - public func setMaximumTempBasalRate(_ rate: Double) { } - - public func syncBasalRateSchedule(items scheduleItems: [RepeatingScheduleValue], completion: @escaping (Result) -> Void) { - state.basalRateSchedule = BasalRateSchedule(dailyItems: scheduleItems, timeZone: self.status.timeZone) - - DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) { - completion(.success(BasalRateSchedule(dailyItems: scheduleItems, timeZone: self.status.timeZone)!)) - } - } - - public func syncDeliveryLimits(limits deliveryLimits: DeliveryLimits, completion: @escaping (Result) -> Void) { - DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) { - completion(.success(deliveryLimits)) - } - } -} - -// MARK: - AlertResponder implementation -extension MockPumpManager { - public func acknowledgeAlert(alertIdentifier: Alert.AlertIdentifier, completion: @escaping (Error?) -> Void) { - completion(nil) - } -} - -// MARK: - AlertSoundVendor implementation -extension MockPumpManager { - public func getSoundBaseURL() -> URL? { return nil } - public func getSounds() -> [Alert.Sound] { return [] } -} - -extension MockPumpManager { - public var debugDescription: String { - return """ - ## MockPumpManager - status: \(status) - state: \(state) - stateObservers.count: \(stateObservers.cleanupDeallocatedElements().count) - statusObservers.count: \(statusObservers.cleanupDeallocatedElements().count) - """ - } -} diff --git a/Dependencies/LoopKit/MockKit/MockPumpManagerState.swift b/Dependencies/LoopKit/MockKit/MockPumpManagerState.swift deleted file mode 100644 index 3edf28b22..000000000 --- a/Dependencies/LoopKit/MockKit/MockPumpManagerState.swift +++ /dev/null @@ -1,438 +0,0 @@ -// -// MockPumpManagerState.swift -// MockKit -// -// Created by Pete Schwamb on 7/31/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -public struct MockPumpManagerState: Equatable { - public enum DeliverableIncrements: String, CaseIterable { - case omnipod - case medtronicX22 - case medtronicX23 - case custom - - var supportedBolusVolumes: [Double]? { - switch self { - case .omnipod: - // 0.05 units for volumes between 0.05-30U - return (1...600).map { Double($0) * 0.05 } - case .medtronicX22: - // 0.1 units for volumes between 0.1-25U - return (1...250).map { Double($0) * 0.1 } - case .medtronicX23: - let breakpoints = [0, 1, 10, 25] - let scales = [40, 20, 10] - let scalingGroups = zip(scales, breakpoints.adjacentPairs().map(...)) - return scalingGroups.flatMap { (scale, range) -> [Double] in - let scaledRanges = (range.lowerBound * scale + 1)...(range.upperBound * scale) - return scaledRanges.map { Double($0) / Double(scale) } - } - case .custom: - return nil - } - } - - var bolusVolumesDescription: String? { - switch self { - case .omnipod: - // 0.05 units for volumes between 0.05-30U - return "0.05-30 by 0.05" - case .medtronicX22: - // 0.1 units for volumes between 0.1-25U - return "0.1-25 by 0.1" - case .medtronicX23: - // 0.025 units for rates between 0.0-0.975 U/h - // 0.05 units for rates between 1-9.95 U/h - // 0.1 units for rates between 10-25 U/h - return "0-1-10-25 by 0.025|0.05|0.1" - case .custom: - return nil - } - } - - var supportedBasalRates: [Double]? { - switch self { - case .omnipod: - // 0.05 units for rates between 0.05-30U/hr - return (1...600).map { Double($0) / 20 } - case .medtronicX22: - // 0.05 units for rates between 0.0-35U/hr - return (0...700).map { Double($0) / 20 } - case .medtronicX23: - // 0.025 units for rates between 0.0-0.975 U/h - let rateGroup1 = (0...39).map { Double($0) / 40 } - // 0.05 units for rates between 1-9.95 U/h - let rateGroup2 = (20...199).map { Double($0) / 20 } - // 0.1 units for rates between 10-35 U/h - let rateGroup3 = (100...350).map { Double($0) / 10 } - return rateGroup1 + rateGroup2 + rateGroup3 - case .custom: - return nil - } - } - - public var basalRateDescription: String? { - switch self { - case .omnipod: - // 0.05 units for rates between 0.05-30U/hr - return "0.05-30 by 0.05" - case .medtronicX22: - // 0.05 units for rates between 0.0-35U/hr - return "0-35 by 0.05" - case .medtronicX23: - // 0.025 units for rates between 0.0-0.975 U/h - // 0.05 units for rates between 1-9.95 U/h - // 0.1 units for rates between 10-35 U/h - return "0-1-10-35 by 0.025|0.05|0.1" - case .custom: - return nil - } - } - } - - public var deliverableIncrements: DeliverableIncrements { - didSet { - if let supportedBasalRates = deliverableIncrements.supportedBasalRates { - self.supportedBasalRates = supportedBasalRates - } else if let minBasalRates = supportedBasalRates.first, let maxBasalRates = supportedBasalRates.last, supportedBasalRates.indices.contains(1) { - let stepSize = supportedBasalRates[1]-minBasalRates - self.supportedBasalRates = (Int(minBasalRates/stepSize)...Int(maxBasalRates/stepSize)).map { Double($0) / (1 / stepSize) } - } - - if let supportedBolusVolumes = deliverableIncrements.supportedBolusVolumes { - self.supportedBolusVolumes = supportedBolusVolumes - } else if let minBolusVolumes = supportedBolusVolumes.first, let maxBolusVolumes = supportedBolusVolumes.last, supportedBolusVolumes.indices.contains(1) { - let stepSize = supportedBolusVolumes[1]-minBolusVolumes - self.supportedBolusVolumes = (Int(minBolusVolumes/stepSize)...Int(maxBolusVolumes/stepSize)).map { Double($0) / (1 / stepSize) } - } - } - } - - public var supportedBolusVolumes: [Double] - public var supportedBolusVolumesDescription: String { - guard let bolusVolumesDescription = deliverableIncrements.bolusVolumesDescription else { - guard let minBolusVolume = supportedBolusVolumes.first, let maxBolusVolume = supportedBolusVolumes.last, supportedBolusVolumes.indices.contains(1) else { - return "–" - } - return String(format: "\(minBolusVolume)-\(maxBolusVolume) by %.3f", (supportedBolusVolumes[1]-minBolusVolume)) - } - return bolusVolumesDescription - } - - public var supportedBasalRates: [Double] - public var supportedBasalRatesDescription: String { - guard let basalRatesDescription = deliverableIncrements.basalRateDescription else { - guard let minBasalRate = supportedBasalRates.first, let maxBasalRate = supportedBasalRates.last, supportedBasalRates.indices.contains(1) else { - return "–" - } - return String(format: "\(minBasalRate)-\(maxBasalRate) by %.3f", (supportedBasalRates[1]-minBasalRate)) - } - return basalRatesDescription - } - - public var basalRateSchedule: BasalRateSchedule? - public var reservoirUnitsRemaining: Double - public var tempBasalEnactmentShouldError: Bool - public var bolusEnactmentShouldError: Bool - public var bolusCancelShouldError: Bool - public var deliverySuspensionShouldError: Bool - public var deliveryResumptionShouldError: Bool - public var deliveryCommandsShouldTriggerUncertainDelivery: Bool - public var maximumBolus: Double - public var maximumBasalRatePerHour: Double - public var suspendState: SuspendState - public var pumpBatteryChargeRemaining: Double? - public var occlusionDetected: Bool = false - public var pumpErrorDetected: Bool = false - public var deliveryIsUncertain: Bool = false - - public var unfinalizedBolus: UnfinalizedDose? - public var unfinalizedTempBasal: UnfinalizedDose? - - var finalizedDoses: [UnfinalizedDose] - var additionalPumpEvents: [NewPumpEvent] - - public var progressPercentComplete: Double? - public var progressWarningThresholdPercentValue: Double? - public var progressCriticalThresholdPercentValue: Double? - - public var insulinType: InsulinType? - public var timeZone: TimeZone - - public var dosesToStore: [UnfinalizedDose] { - return finalizedDoses + [unfinalizedTempBasal, unfinalizedBolus].compactMap {$0} - } - - public var pumpEventsToStore: [NewPumpEvent] { - return dosesToStore.map { NewPumpEvent($0) } + additionalPumpEvents - } - - public init(deliverableIncrements: DeliverableIncrements = .medtronicX22, - reservoirUnitsRemaining: Double = 200.0, - tempBasalEnactmentShouldError: Bool = false, - bolusEnactmentShouldError: Bool = false, - bolusCancelShouldError: Bool = false, - deliverySuspensionShouldError: Bool = false, - deliveryResumptionShouldError: Bool = false, - deliveryCommandsShouldTriggerUncertainDelivery: Bool = false, - maximumBolus: Double = 25.0, - maximumBasalRatePerHour: Double = 5.0, - suspendState: SuspendState = .resumed(Date()), - pumpBatteryChargeRemaining: Double? = 1, - unfinalizedBolus: UnfinalizedDose? = nil, - unfinalizedTempBasal: UnfinalizedDose? = nil, - finalizedDoses: [UnfinalizedDose] = [], - additionalPumpEvents: [NewPumpEvent] = [], - progressWarningThresholdPercentValue: Double? = 0.75, - progressCriticalThresholdPercentValue: Double? = 0.9, - insulinType: InsulinType = .novolog) - { - self.deliverableIncrements = deliverableIncrements - self.supportedBolusVolumes = deliverableIncrements.supportedBolusVolumes ?? [] - self.supportedBasalRates = deliverableIncrements.supportedBasalRates ?? [] - self.reservoirUnitsRemaining = reservoirUnitsRemaining - self.tempBasalEnactmentShouldError = tempBasalEnactmentShouldError - self.bolusEnactmentShouldError = bolusEnactmentShouldError - self.bolusCancelShouldError = bolusCancelShouldError - self.deliverySuspensionShouldError = deliverySuspensionShouldError - self.deliveryResumptionShouldError = deliveryResumptionShouldError - self.deliveryCommandsShouldTriggerUncertainDelivery = deliveryCommandsShouldTriggerUncertainDelivery - self.maximumBolus = maximumBolus - self.maximumBasalRatePerHour = maximumBasalRatePerHour - self.suspendState = suspendState - self.pumpBatteryChargeRemaining = pumpBatteryChargeRemaining - self.finalizedDoses = finalizedDoses - self.additionalPumpEvents = additionalPumpEvents - self.progressWarningThresholdPercentValue = progressWarningThresholdPercentValue - self.progressCriticalThresholdPercentValue = progressCriticalThresholdPercentValue - self.insulinType = insulinType - self.timeZone = .currentFixed - } - - public mutating func finalizeFinishedDoses() { - if let bolus = unfinalizedBolus, bolus.finished { - finalizedDoses.append(bolus) - unfinalizedBolus = nil - } - - if let tempBasal = unfinalizedTempBasal, tempBasal.finished { - finalizedDoses.append(tempBasal) - unfinalizedTempBasal = nil - } - } -} - - -extension MockPumpManagerState: RawRepresentable { - public typealias RawValue = [String: Any] - - public init?(rawValue: RawValue) { - guard let reservoirUnitsRemaining = rawValue["reservoirUnitsRemaining"] as? Double else { - return nil - } - - let defaultDeliverableIncrements: DeliverableIncrements = .medtronicX22 - self.deliverableIncrements = (rawValue["deliverableIncrements"] as? DeliverableIncrements.RawValue).flatMap(DeliverableIncrements.init(rawValue:)) ?? defaultDeliverableIncrements - self.supportedBolusVolumes = rawValue["supportedBolusVolumes"] as? [Double] ?? defaultDeliverableIncrements.supportedBolusVolumes ?? [] - self.supportedBasalRates = rawValue["supportedBasalRates"] as? [Double] ?? defaultDeliverableIncrements.supportedBasalRates ?? [] - self.reservoirUnitsRemaining = reservoirUnitsRemaining - self.tempBasalEnactmentShouldError = rawValue["tempBasalEnactmentShouldError"] as? Bool ?? false - self.bolusEnactmentShouldError = rawValue["bolusEnactmentShouldError"] as? Bool ?? false - self.bolusCancelShouldError = rawValue["bolusCancelShouldError"] as? Bool ?? false - self.deliverySuspensionShouldError = rawValue["deliverySuspensionShouldError"] as? Bool ?? false - self.deliveryResumptionShouldError = rawValue["deliveryResumptionShouldError"] as? Bool ?? false - self.deliveryCommandsShouldTriggerUncertainDelivery = rawValue["deliveryCommandsShouldTriggerUncertainDelivery"] as? Bool ?? false - self.maximumBolus = rawValue["maximumBolus"] as? Double ?? 25.0 - self.maximumBasalRatePerHour = rawValue["maximumBasalRatePerHour"] as? Double ?? 5.0 - self.pumpBatteryChargeRemaining = rawValue["pumpBatteryChargeRemaining"] as? Double ?? nil - self.occlusionDetected = rawValue["occlusionDetected"] as? Bool ?? false - self.pumpErrorDetected = rawValue["pumpErrorDetected"] as? Bool ?? false - self.deliveryIsUncertain = rawValue["deliveryIsUncertain"] as? Bool ?? false - - self.progressPercentComplete = rawValue["progressPercentComplete"] as? Double - self.progressWarningThresholdPercentValue = rawValue["progressWarningThresholdPercentValue"] as? Double - self.progressCriticalThresholdPercentValue = rawValue["progressCriticalThresholdPercentValue"] as? Double - - if let rawBasalRateSchedule = rawValue["basalRateSchedule"] as? BasalRateSchedule.RawValue { - self.basalRateSchedule = BasalRateSchedule(rawValue: rawBasalRateSchedule) - } - - if let rawUnfinalizedBolus = rawValue["unfinalizedBolus"] as? UnfinalizedDose.RawValue { - self.unfinalizedBolus = UnfinalizedDose(rawValue: rawUnfinalizedBolus) - } - - if let rawUnfinalizedTempBasal = rawValue["unfinalizedTempBasal"] as? UnfinalizedDose.RawValue { - self.unfinalizedTempBasal = UnfinalizedDose(rawValue: rawUnfinalizedTempBasal) - } - - if let rawFinalizedDoses = rawValue["finalizedDoses"] as? [UnfinalizedDose.RawValue] { - self.finalizedDoses = rawFinalizedDoses.compactMap( { UnfinalizedDose(rawValue: $0) } ) - } else { - self.finalizedDoses = [] - } - - if let rawAdditionalPumpEvents = rawValue["additionalPumpEvents"] as? [NewPumpEvent.RawValue] { - self.additionalPumpEvents = rawAdditionalPumpEvents.compactMap( { NewPumpEvent(rawValue: $0) } ) - } else { - self.additionalPumpEvents = [] - } - - if let rawSuspendState = rawValue["suspendState"] as? SuspendState.RawValue, let suspendState = SuspendState(rawValue: rawSuspendState) { - self.suspendState = suspendState - } else { - self.suspendState = .resumed(Date()) - } - - if let rawInsulinType = rawValue["insulinType"] as? InsulinType.RawValue, let insulinType = InsulinType(rawValue: rawInsulinType) { - self.insulinType = insulinType - } else { - self.insulinType = .novolog - } - - if let timeZoneOffset = rawValue["timeZone"] as? Int { - self.timeZone = TimeZone(secondsFromGMT: timeZoneOffset) ?? .currentFixed - } else { - self.timeZone = .currentFixed - } - } - - public var rawValue: RawValue { - - var raw: RawValue = [ - "deliverableIncrements": deliverableIncrements.rawValue, - "supportedBolusVolumes": supportedBolusVolumes, - "supportedBasalRates": supportedBasalRates, - "reservoirUnitsRemaining": reservoirUnitsRemaining, - "timeZone": timeZone.secondsFromGMT() - ] - - raw["basalRateSchedule"] = basalRateSchedule?.rawValue - raw["suspendState"] = suspendState.rawValue - - if tempBasalEnactmentShouldError { - raw["tempBasalEnactmentShouldError"] = true - } - - if bolusEnactmentShouldError { - raw["bolusEnactmentShouldError"] = true - } - - if bolusCancelShouldError { - raw["bolusCancelShouldError"] = true - } - - if deliverySuspensionShouldError { - raw["deliverySuspensionShouldError"] = true - } - - if deliveryResumptionShouldError { - raw["deliveryResumptionShouldError"] = true - } - - if deliveryCommandsShouldTriggerUncertainDelivery { - raw["deliveryCommandsShouldTriggerUncertainDelivery"] = true - } - - if deliveryIsUncertain { - raw["deliveryIsUncertain"] = true - } - - raw["finalizedDoses"] = finalizedDoses.map({ $0.rawValue }) - raw["additionalPumpEvents"] = additionalPumpEvents.map({ $0.rawValue }) - - raw["maximumBolus"] = maximumBolus - raw["maximumBasalRatePerHour"] = maximumBasalRatePerHour - - raw["unfinalizedBolus"] = unfinalizedBolus?.rawValue - raw["unfinalizedTempBasal"] = unfinalizedTempBasal?.rawValue - - raw["pumpBatteryChargeRemaining"] = pumpBatteryChargeRemaining - - raw["occlusionDetected"] = occlusionDetected - raw["pumpErrorDetected"] = pumpErrorDetected - - raw["progressPercentComplete"] = progressPercentComplete - raw["progressWarningThresholdPercentValue"] = progressWarningThresholdPercentValue - raw["progressCriticalThresholdPercentValue"] = progressCriticalThresholdPercentValue - - raw["insulinType"] = insulinType?.rawValue - - return raw - } -} - -extension MockPumpManagerState: CustomDebugStringConvertible { - public var debugDescription: String { - return """ - ## MockPumpManagerState - * deliverableIncrements: \(deliverableIncrements) - * reservoirUnitsRemaining: \(reservoirUnitsRemaining) - * basalRateSchedule: \(basalRateSchedule as Any) - * tempBasalEnactmentShouldError: \(tempBasalEnactmentShouldError) - * bolusEnactmentShouldError: \(bolusEnactmentShouldError) - * bolusCancelShouldError: \(bolusCancelShouldError) - * deliverySuspensionShouldError: \(deliverySuspensionShouldError) - * deliveryResumptionShouldError: \(deliveryResumptionShouldError) - * maximumBolus: \(maximumBolus) - * maximumBasalRatePerHour: \(maximumBasalRatePerHour) - * pumpBatteryChargeRemaining: \(String(describing: pumpBatteryChargeRemaining)) - * suspendState: \(suspendState) - * unfinalizedBolus: \(String(describing: unfinalizedBolus)) - * unfinalizedTempBasal: \(String(describing: unfinalizedTempBasal)) - * finalizedDoses: \(finalizedDoses) - * additionalPumpEvents: \(additionalPumpEvents) - * occlusionDetected: \(occlusionDetected) - * pumpErrorDetected: \(pumpErrorDetected) - * progressPercentComplete: \(progressPercentComplete as Any) - * progressWarningThresholdPercentValue: \(progressWarningThresholdPercentValue as Any) - * progressCriticalThresholdPercentValue: \(progressCriticalThresholdPercentValue as Any) - * insulinType: \(insulinType as Any) - """ - } -} - -public enum SuspendState: Equatable, RawRepresentable { - public typealias RawValue = [String: Any] - - private enum SuspendStateType: Int { - case suspend, resume - } - - case suspended(Date) - case resumed(Date) - - public init?(rawValue: RawValue) { - guard let suspendStateType = rawValue["suspendStateType"] as? SuspendStateType.RawValue, - let date = rawValue["date"] as? Date else { - return nil - } - switch SuspendStateType(rawValue: suspendStateType) { - case .suspend?: - self = .suspended(date) - case .resume?: - self = .resumed(date) - default: - return nil - } - } - - public var rawValue: RawValue { - switch self { - case .suspended(let date): - return [ - "suspendStateType": SuspendStateType.suspend.rawValue, - "date": date - ] - case .resumed(let date): - return [ - "suspendStateType": SuspendStateType.resume.rawValue, - "date": date - ] - } - } -} diff --git a/Dependencies/LoopKit/MockKit/MockService.swift b/Dependencies/LoopKit/MockKit/MockService.swift deleted file mode 100644 index 28df76678..000000000 --- a/Dependencies/LoopKit/MockKit/MockService.swift +++ /dev/null @@ -1,175 +0,0 @@ -// -// MockService.swift -// MockKit -// -// Created by Darin Krauss on 5/17/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import os.log -import Foundation -import LoopKit - -public final class MockService: Service { - - public static let serviceIdentifier = "MockService" - - public static let localizedTitle = "Simulator" - - public weak var serviceDelegate: ServiceDelegate? - - public var remoteData: Bool - - public var logging: Bool - - public var analytics: Bool - - public let maxHistoryItems = 1000 - - private var lockedHistory = Locked<[String]>([]) - - public var history: [String] { - lockedHistory.value - } - - private var dateFormatter = ISO8601DateFormatter() - - public init() { - self.remoteData = true - self.logging = true - self.analytics = true - } - - public init?(rawState: RawStateValue) { - self.remoteData = rawState["remoteData"] as? Bool ?? false - self.logging = rawState["logging"] as? Bool ?? false - self.analytics = rawState["analytics"] as? Bool ?? false - } - - public var rawState: RawStateValue { - var rawValue: RawStateValue = [:] - rawValue["remoteData"] = remoteData - rawValue["logging"] = logging - rawValue["analytics"] = analytics - return rawValue - } - - public let isOnboarded = true // No distinction between created and onboarded - - public func completeCreate() {} - - public func completeUpdate() { - serviceDelegate?.serviceDidUpdateState(self) - } - - public func completeDelete() { - serviceDelegate?.serviceWantsDeletion(self) - } - - public func clearHistory() { - lockedHistory.value = [] - } - - private func record(_ message: String) { - let timestamp = self.dateFormatter.string(from: Date()) - lockedHistory.mutate { history in - history.append("\(timestamp): \(message)") - if history.count > self.maxHistoryItems { - history.removeFirst(history.count - self.maxHistoryItems) - } - } - } - -} - -extension MockService: AnalyticsService { - public func recordAnalyticsEvent(_ name: String, withProperties properties: [AnyHashable: Any]?, outOfSession: Bool) { - if analytics { - record("[AnalyticsService] \(name) \(String(describing: properties)) \(outOfSession)") - } - } - - public func recordIdentify(_ property: String, value: String) { - record("[AnalyticsService] Identify: \(property) \(value)") - } -} - -extension MockService: LoggingService { - - public func log(_ message: StaticString, subsystem: String, category: String, type: OSLogType, _ args: [CVarArg]) { - if logging { - // Since this is only stored in memory, do not worry about public/private qualifiers - let messageWithoutQualifiers = message.description.replacingOccurrences(of: "%{public}", with: "%").replacingOccurrences(of: "%{private}", with: "%") - let messageWithArguments = String(format: messageWithoutQualifiers, arguments: args) - - record("[LoggingService] \(messageWithArguments)") - } - } - -} - -extension MockService: RemoteDataService { - - public func uploadTemporaryOverrideData(updated: [TemporaryScheduleOverride], deleted: [TemporaryScheduleOverride], completion: @escaping (Result) -> Void) { - if remoteData { - record("[RemoteDataService] Upload temporary override data (updated: \(updated.count), deleted: \(deleted.count))") - } - completion(.success(false)) - } - - public func uploadAlertData(_ stored: [SyncAlertObject], completion: @escaping (Result) -> Void) { - if remoteData { - record("[RemoteDataService] Upload alert data (stored: \(stored.count))") - } - completion(.success(false)) - } - - public func uploadCarbData(created: [SyncCarbObject], updated: [SyncCarbObject], deleted: [SyncCarbObject], completion: @escaping (Result) -> Void) { - if remoteData { - record("[RemoteDataService] Upload carb data (created: \(created.count), updated: \(updated.count), deleted: \(deleted.count))") - } - completion(.success(false)) - } - - public func uploadDoseData(created: [DoseEntry], deleted: [DoseEntry], completion: @escaping (_ result: Result) -> Void) { - if remoteData { - record("[RemoteDataService] Upload dose data (created: \(created.count), deleted: \(deleted.count))") - } - completion(.success(false)) - } - - public func uploadDosingDecisionData(_ stored: [StoredDosingDecision], completion: @escaping (Result) -> Void) { - if remoteData { - let warned = stored.filter { !$0.warnings.isEmpty } - let errored = stored.filter { !$0.errors.isEmpty } - record("[RemoteDataService] Upload dosing decision data (stored: \(stored.count), warned: \(warned.count), errored: \(errored.count))") - } - completion(.success(false)) - } - - public func uploadGlucoseData(_ stored: [StoredGlucoseSample], completion: @escaping (Result) -> Void) { - if remoteData { - record("[RemoteDataService] Upload glucose data (stored: \(stored.count))") - } - completion(.success(false)) - } - - public func uploadPumpEventData(_ stored: [PersistedPumpEvent], completion: @escaping (Result) -> Void) { - if remoteData { - record("[RemoteDataService] Upload pump event data (stored: \(stored.count))") - } - completion(.success(false)) - } - - public func uploadSettingsData(_ stored: [StoredSettings], completion: @escaping (Result) -> Void) { - if remoteData { - record("[RemoteDataService] Upload settings data (stored: \(stored.count))") - } - completion(.success(false)) - } - - public func validatePushNotificationSource(_ notification: [String : AnyObject]) -> Result { - return .success(Void()) - } - -} diff --git a/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/Contents.json b/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/Contents.json b/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/battery.circle.fill.symbolset/Contents.json b/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/battery.circle.fill.symbolset/Contents.json deleted file mode 100644 index c3c4f288b..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/battery.circle.fill.symbolset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "symbols" : [ - { - "filename" : "battery.circle.fill.svg", - "idiom" : "universal" - } - ] -} diff --git a/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/battery.circle.fill.symbolset/battery.circle.fill.svg b/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/battery.circle.fill.symbolset/battery.circle.fill.svg deleted file mode 100644 index dc3d77684..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/battery.circle.fill.symbolset/battery.circle.fill.svg +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/drop.circle.fill.symbolset/Contents.json b/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/drop.circle.fill.symbolset/Contents.json deleted file mode 100644 index 47da447df..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/drop.circle.fill.symbolset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "symbols" : [ - { - "filename" : "drop.circle.fill.svg", - "idiom" : "universal" - } - ] -} diff --git a/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/drop.circle.fill.symbolset/drop.circle.fill.svg b/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/drop.circle.fill.symbolset/drop.circle.fill.svg deleted file mode 100644 index c244db665..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/Assets.xcassets/status.badge/drop.circle.fill.symbolset/drop.circle.fill.svg +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/LoopKit/MockKit/Resources/Sounds/critical.caf b/Dependencies/LoopKit/MockKit/Resources/Sounds/critical.caf deleted file mode 100644 index b0a3e0bc3..000000000 Binary files a/Dependencies/LoopKit/MockKit/Resources/Sounds/critical.caf and /dev/null differ diff --git a/Dependencies/LoopKit/MockKit/Resources/Sounds/sub.caf b/Dependencies/LoopKit/MockKit/Resources/Sounds/sub.caf deleted file mode 100644 index 4e03d9267..000000000 Binary files a/Dependencies/LoopKit/MockKit/Resources/Sounds/sub.caf and /dev/null differ diff --git a/Dependencies/LoopKit/MockKit/Resources/ar.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/ar.lproj/Localizable.strings deleted file mode 100644 index a13542ddc..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/ar.lproj/Localizable.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/cs.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/cs.lproj/Localizable.strings deleted file mode 100644 index c61ce558a..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/cs.lproj/Localizable.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Žádný inzulín"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/da.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/da.lproj/Localizable.strings deleted file mode 100644 index e50d1579f..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/da.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Kommunikationsproblem"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin suspenderet"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Ingen insulin"; - -/* Status highlight that pump has a dead battery. */ -"Pump Battery Dead" = "Pumpebatteri dødt"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Pumpefejl"; - -/* Status highlight that an occlusion was detected. */ -"Pump Occlusion" = "Pumpen er blokeret"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Genoptag"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspender"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Midlertidig basal"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/de.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/de.lproj/Localizable.strings deleted file mode 100644 index 653f0b6b9..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/de.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Problem"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulinabgabe unterbrochen"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Kein Insulin"; - -/* Status highlight that pump has a dead battery. */ -"Pump Battery Dead" = "Pumpenbatterie tot"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Pumpenfehler"; - -/* Status highlight that an occlusion was detected. */ -"Pump Occlusion" = "Pumpenverschluss"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Fortsetzen"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Unterbrechen"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temporäre Basalrate"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/en.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/en.lproj/Localizable.strings deleted file mode 100644 index 9099ee8b0..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/en.lproj/Localizable.strings +++ /dev/null @@ -1,8 +0,0 @@ -/* - Localizable.strings - LoopKit - - Created by Pete Schwamb on 3/19/23. - Copyright © 2023 LoopKit Authors. All rights reserved. -*/ - diff --git a/Dependencies/LoopKit/MockKit/Resources/es.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/es.lproj/Localizable.strings deleted file mode 100644 index c31c9ff1d..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/es.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolo"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problema de comunicaciones"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulina Suspendida"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No hay insulina"; - -/* Status highlight that pump has a dead battery. */ -"Pump Battery Dead" = "Batería de la bomba agotada"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Error de la bomba"; - -/* Status highlight that an occlusion was detected. */ -"Pump Occlusion" = "Oclusión de la bomba"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Reanudar"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspender"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Insulina basal temporal"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/fi.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/fi.lproj/Localizable.strings deleted file mode 100644 index 433bca0bf..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/fi.lproj/Localizable.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Yhteysongelma"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insuliini pysäytetty"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Ei insuliinia"; - -/* Status highlight that pump has a dead battery. */ -"Pump Battery Dead" = "Pumpun paristo ei toimi"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Pumpun virhe"; - -/* Status highlight that an occlusion was detected. */ -"Pump Occlusion" = "Tukkeutunut pumppu"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Tilapäinen basaali"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/fr.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/fr.lproj/Localizable.strings deleted file mode 100644 index 8c3e5d619..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/fr.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problème de com."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insuline suspendue"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Pas d'insuline"; - -/* Status highlight that pump has a dead battery. */ -"Pump Battery Dead" = "Batterie HS"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Erreur détectée"; - -/* Status highlight that an occlusion was detected. */ -"Pump Occlusion" = "Occlusion détectée"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Reprendre"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspendre"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Débit basal temporaire"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/he.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/he.lproj/Localizable.strings deleted file mode 100644 index 40420079f..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/he.lproj/Localizable.strings +++ /dev/null @@ -1,6 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Pump Error"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/it.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/it.lproj/Localizable.strings deleted file mode 100644 index c7d5df96f..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/it.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolo"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problema di Comunicazione"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Erogazione Insulina sospesa"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Insulina Terminata"; - -/* Status highlight that pump has a dead battery. */ -"Pump Battery Dead" = "Batteria Microinfusore esaurita"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Errore Mincroinfusore"; - -/* Status highlight that an occlusion was detected. */ -"Pump Occlusion" = "Occlusione microinfusore"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Riprendi"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Blocco Erogazione"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Basale Temporanea"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/ja.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/ja.lproj/Localizable.strings deleted file mode 100644 index ca2331019..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/ja.lproj/Localizable.strings +++ /dev/null @@ -1,6 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "ボーラス"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "ポンプエラー"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/nb.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/nb.lproj/Localizable.strings deleted file mode 100644 index 96176c37e..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/nb.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Kommunikasjonsutgave"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulintilførsel utsatt"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Ingen insulin"; - -/* Status highlight that pump has a dead battery. */ -"Pump Battery Dead" = "Pumpebatteri er dødt"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Pumpefeil"; - -/* Status highlight that an occlusion was detected. */ -"Pump Occlusion" = "Pumpen er blokkert"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Gjenoppta"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Utsette"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Midlertidig basal"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/nl.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/nl.lproj/Localizable.strings deleted file mode 100644 index 27296b6e4..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/nl.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Communicatieprobleem"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insuline Onderbroken"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Geen Insuline"; - -/* Status highlight that pump has a dead battery. */ -"Pump Battery Dead" = "Pompbatterij Leeg"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Pomp Foutmelding"; - -/* Status highlight that an occlusion was detected. */ -"Pump Occlusion" = "Pompverstopping"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Hervatten"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Onderbreek"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Tijdelijk Basaal"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/pl.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/pl.lproj/Localizable.strings deleted file mode 100644 index 98f8d0f5e..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/pl.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problem z komunikacją"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Podawanie insuliny zawieszone"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Brak insuliny"; - -/* Status highlight that pump has a dead battery. */ -"Pump Battery Dead" = "Rozładowana bateria pompy"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Błąd pompy"; - -/* Status highlight that an occlusion was detected. */ -"Pump Occlusion" = "Niedrożność pompy"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Wznów"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Wstrzymaj"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Tymczasowa dawka podstawowa"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/pt-BR.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/pt-BR.lproj/Localizable.strings deleted file mode 100644 index dd1a533db..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,6 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Erro na Bomba"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/ro.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/ro.lproj/Localizable.strings deleted file mode 100644 index cc7ecbc1f..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/ro.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problemă de comunicații"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Administrarea insulinei suspendată"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Fără insulină"; - -/* Status highlight that pump has a dead battery. */ -"Pump Battery Dead" = "Baterie epuizata pompa"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Eroare pompă"; - -/* Status highlight that an occlusion was detected. */ -"Pump Occlusion" = "Ocluzie pompă"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Reluați"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspendați"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Bazală temporară"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/ru.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/ru.lproj/Localizable.strings deleted file mode 100644 index 8c623e967..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/ru.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Болюс"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Проблемы со связью"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Подача инсулина приостановлена"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Нет инсулина"; - -/* Status highlight that pump has a dead battery. */ -"Pump Battery Dead" = "Батарея помпы неисправна"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Ошибка помпы"; - -/* Status highlight that an occlusion was detected. */ -"Pump Occlusion" = "Закупорка помпы"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Возобновление"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Приостановка"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "ВБС"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/sk.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/sk.lproj/Localizable.strings deleted file mode 100644 index 0e196405b..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/sk.lproj/Localizable.strings +++ /dev/null @@ -1,12 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Žiadny inzulín"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Pozastavenie"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Dočasný bazál"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/sv.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/sv.lproj/Localizable.strings deleted file mode 100644 index f8b8da152..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/sv.lproj/Localizable.strings +++ /dev/null @@ -1,24 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Kommandoproblem"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulintillförsel pausad"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Inget insulin"; - -/* Status highlight that pump has a dead battery. */ -"Pump Battery Dead" = "Pumpbatteri urladdat"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Pumpfel"; - -/* Status highlight that an occlusion was detected. */ -"Pump Occlusion" = "Pumpocklusion"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temporär basal"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/tr.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/tr.lproj/Localizable.strings deleted file mode 100644 index 6329f20f9..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/tr.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "İletişim Sorunu"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "İnsülin Askıya Alındı"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "İnsülin yok"; - -/* Status highlight that pump has a dead battery. */ -"Pump Battery Dead" = "Pompa Pili Bitti"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Pompa Hatası"; - -/* Status highlight that an occlusion was detected. */ -"Pump Occlusion" = "Pompa Tıkanıklığı"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Devam et"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Askıya al"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Geçici Bazal"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/vi.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/vi.lproj/Localizable.strings deleted file mode 100644 index 217ffde81..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/vi.lproj/Localizable.strings +++ /dev/null @@ -1,6 +0,0 @@ -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Status highlight that a pump error occurred. */ -"Pump Error" = "Bơm lỗi"; - diff --git a/Dependencies/LoopKit/MockKit/Resources/zh-Hans.lproj/Localizable.strings b/Dependencies/LoopKit/MockKit/Resources/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index ab3ccffac..000000000 --- a/Dependencies/LoopKit/MockKit/Resources/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Status highlight that a pump error occurred. */ -"Pump Error" = "胰岛素泵错误"; - diff --git a/Dependencies/LoopKit/MockKit/UnfinalizedDose.swift b/Dependencies/LoopKit/MockKit/UnfinalizedDose.swift deleted file mode 100644 index 4007fb857..000000000 --- a/Dependencies/LoopKit/MockKit/UnfinalizedDose.swift +++ /dev/null @@ -1,285 +0,0 @@ -// -// UnfinalizedDose.swift -// MockKit -// -// Created by Pete Schwamb on 7/30/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -public struct UnfinalizedDose: RawRepresentable, Equatable, CustomStringConvertible { - public typealias RawValue = [String: Any] - - enum DoseType: Int { - case bolus = 0 - case tempBasal - case suspend - case resume - } - - private let dateFormatter = ISO8601DateFormatter() - - private let insulinFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.maximumFractionDigits = 3 - return formatter - }() - - fileprivate var uniqueKey: Data { - return "\(doseType) \(scheduledUnits ?? units) \(dateFormatter.string(from: startTime))".data(using: .utf8)! - } - - let doseType: DoseType - public var units: Double - var scheduledUnits: Double? // Tracks the scheduled units, as boluses may be canceled before finishing, at which point units would reflect actual delivered volume. - var scheduledTempRate: Double? // Tracks the original temp rate, as during finalization the units are discretized to pump pulses, changing the actual rate - let startTime: Date - var duration: TimeInterval - let insulinType: InsulinType? - let automatic: Bool? - - var finishTime: Date { - get { - return startTime.addingTimeInterval(duration) - } - set { - duration = newValue.timeIntervalSince(startTime) - } - } - - public var progress: Double { - let elapsed = -startTime.timeIntervalSinceNow - return min(elapsed / duration, 1) - } - - public var finished: Bool { - return progress >= 1 - } - - // Units per hour - public var rate: Double { - guard duration.hours > 0 else { - return 0 - } - return units / duration.hours - } - - public var finalizedUnits: Double? { - guard finished else { - return nil - } - return units - } - - init(bolusAmount: Double, startTime: Date, duration: TimeInterval, insulinType: InsulinType? = nil, automatic: Bool = false) { - self.doseType = .bolus - self.units = bolusAmount - self.startTime = startTime - self.duration = duration - self.scheduledUnits = nil - self.insulinType = insulinType - self.automatic = automatic - } - - init(tempBasalRate: Double, startTime: Date, duration: TimeInterval, insulinType: InsulinType? = nil) { - self.doseType = .tempBasal - self.units = tempBasalRate * duration.hours - self.startTime = startTime - self.duration = duration - self.scheduledUnits = nil - self.insulinType = insulinType - self.automatic = true - } - - init(suspendStartTime: Date, automatic: Bool? = nil) { - self.doseType = .suspend - self.units = 0 - self.startTime = suspendStartTime - self.duration = 0 - self.insulinType = nil - self.automatic = automatic - } - - init(resumeStartTime: Date, insulinType: InsulinType? = nil, automatic: Bool? = nil) { - self.doseType = .resume - self.units = 0 - self.startTime = resumeStartTime - self.duration = 0 - self.insulinType = insulinType - self.automatic = automatic - } - - public mutating func cancel(at date: Date) { - guard date < finishTime else { - return - } - - scheduledUnits = units - let newDuration = date.timeIntervalSince(startTime) - - switch doseType { - case .bolus: - units = rate * newDuration.hours - case .tempBasal: - scheduledTempRate = rate - units = floor(rate * newDuration.hours * 20) / 20 - default: - break - } - duration = newDuration - } - - public var isMutable: Bool { - switch doseType { - case .bolus, .tempBasal: - return !finished - default: - return false - } - } - - public var description: String { - let unitsStr = insulinFormatter.string(from: NSNumber(value:units)) ?? "?" - switch doseType { - case .bolus: - if let scheduledUnits = scheduledUnits, - let scheduledUnitsStr = insulinFormatter.string(from: NSNumber(value:scheduledUnits)) - { - return "Interrupted Bolus units:\(unitsStr) (\(scheduledUnitsStr) scheduled) startTime:\(startTime) duration:\(String(describing: duration))" - } else { - return "Bolus units:\(unitsStr) startTime:\(startTime) duration:\(String(describing: duration))" - } - case .tempBasal: - return "Temp Basal rate:\(scheduledTempRate ?? rate) units:\(unitsStr) startTime:\(startTime) duration:\(String(describing: duration))" - case .suspend, .resume: - return "\(doseType) startTime:\(startTime)" - } - } - - public var eventTitle: String { - switch doseType { - case .bolus: - return LocalizedString("Bolus", comment: "Pump Event title for UnfinalizedDose with doseType of .bolus") - case .resume: - return LocalizedString("Resume", comment: "Pump Event title for UnfinalizedDose with doseType of .resume") - case .suspend: - return LocalizedString("Suspend", comment: "Pump Event title for UnfinalizedDose with doseType of .suspend") - case .tempBasal: - return LocalizedString("Temp Basal", comment: "Pump Event title for UnfinalizedDose with doseType of .tempBasal") - } - } - - // RawRepresentable - public init?(rawValue: RawValue) { - guard - let rawDoseType = rawValue["doseType"] as? Int, - let doseType = DoseType(rawValue: rawDoseType), - let units = rawValue["units"] as? Double, - let startTime = rawValue["startTime"] as? Date, - let duration = rawValue["duration"] as? Double - else { - return nil - } - - self.doseType = doseType - self.units = units - self.startTime = startTime - self.duration = duration - - if let scheduledUnits = rawValue["scheduledUnits"] as? Double { - self.scheduledUnits = scheduledUnits - } - - if let scheduledTempRate = rawValue["scheduledTempRate"] as? Double { - self.scheduledTempRate = scheduledTempRate - } - - if let rawInsulinType = rawValue["insulinType"] as? InsulinType.RawValue, let insulinType = InsulinType(rawValue: rawInsulinType) { - self.insulinType = insulinType - } else { - self.insulinType = nil - } - - self.automatic = rawValue["automatic"] as? Bool - } - - public var rawValue: RawValue { - var rawValue: RawValue = [ - "doseType": doseType.rawValue, - "units": units, - "startTime": startTime, - "duration": duration, - ] - - if let scheduledUnits = scheduledUnits { - rawValue["scheduledUnits"] = scheduledUnits - } - - if let scheduledTempRate = scheduledTempRate { - rawValue["scheduledTempRate"] = scheduledTempRate - } - - if let insulinType = insulinType { - rawValue["insulinType"] = insulinType.rawValue - } - - if let automatic = automatic { - rawValue["automatic"] = automatic - } - - return rawValue - } -} - -extension NewPumpEvent { - init(_ dose: UnfinalizedDose) { - let entry = DoseEntry(dose) - self.init(date: dose.startTime, dose: entry, raw: dose.uniqueKey, title: dose.eventTitle) - } - - // Used for TestingScenarios, injecting doses into PumpManager - public var unfinalizedDose: UnfinalizedDose? { - - let defaultInsulinType = InsulinType.novolog - - if let dose = dose { - let duration = dose.endDate.timeIntervalSince(dose.startDate) - switch dose.type { - case .basal: - return nil - case .bolus: - var newDose = UnfinalizedDose(bolusAmount: dose.programmedUnits, startTime: dose.startDate, duration: duration, insulinType: dose.insulinType ?? defaultInsulinType, automatic: dose.automatic ?? false) - if let delivered = dose.deliveredUnits { - newDose.scheduledUnits = dose.programmedUnits - newDose.units = delivered - } - return newDose - case .resume: - return UnfinalizedDose(resumeStartTime: dose.startDate, insulinType: dose.insulinType ?? defaultInsulinType, automatic: dose.automatic) - case .suspend: - return UnfinalizedDose(suspendStartTime: dose.startDate, automatic: dose.automatic) - case .tempBasal: - return UnfinalizedDose(tempBasalRate: dose.unitsPerHour, startTime: dose.startDate, duration: duration, insulinType: dose.insulinType ?? defaultInsulinType) - } - } - return nil - } -} - -extension DoseEntry { - init (_ dose: UnfinalizedDose) { - switch dose.doseType { - case .bolus: - self = DoseEntry(type: .bolus, startDate: dose.startTime, endDate: dose.finishTime, value: dose.scheduledUnits ?? dose.units, unit: .units, deliveredUnits: dose.finalizedUnits, insulinType: dose.insulinType, automatic: dose.automatic, isMutable: dose.isMutable) - case .tempBasal: - self = DoseEntry(type: .tempBasal, startDate: dose.startTime, endDate: dose.finishTime, value: dose.scheduledTempRate ?? dose.rate, unit: .unitsPerHour, deliveredUnits: dose.finalizedUnits, insulinType: dose.insulinType, isMutable: dose.isMutable) - case .suspend: - self = DoseEntry(suspendDate: dose.startTime, automatic: dose.automatic) - case .resume: - self = DoseEntry(resumeDate: dose.startTime, insulinType: dose.insulinType, automatic: dose.automatic) - } - } -} diff --git a/Dependencies/LoopKit/MockKitTests/Info.plist b/Dependencies/LoopKit/MockKitTests/Info.plist deleted file mode 100644 index 64d65ca49..000000000 --- a/Dependencies/LoopKit/MockKitTests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - 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/Dependencies/LoopKit/MockKitTests/UnfinalizedDoseTests.swift b/Dependencies/LoopKit/MockKitTests/UnfinalizedDoseTests.swift deleted file mode 100644 index 598a67dc1..000000000 --- a/Dependencies/LoopKit/MockKitTests/UnfinalizedDoseTests.swift +++ /dev/null @@ -1,300 +0,0 @@ -// -// MockKitTests.swift -// MockKitTests -// -// Created by Nathaniel Hamming on 2020-11-27. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import LoopKit -@testable import MockKit - -class UnfinalizedDoseTests: XCTestCase { - - func testInitializationBolus() { - let amount = 3.5 - let startTime = Date() - let duration = TimeInterval(5) - let unfinalizedBolus = UnfinalizedDose(bolusAmount: amount, - startTime: startTime, - duration: duration, - insulinType: nil, - automatic: false) - XCTAssertEqual(unfinalizedBolus.doseType, .bolus) - XCTAssertEqual(unfinalizedBolus.units, amount) - XCTAssertNil(unfinalizedBolus.scheduledUnits) - XCTAssertNil(unfinalizedBolus.scheduledTempRate) - XCTAssertEqual(unfinalizedBolus.startTime, startTime) - XCTAssertEqual(unfinalizedBolus.duration, duration) - XCTAssertEqual(unfinalizedBolus.finishTime, startTime.addingTimeInterval(duration)) - XCTAssertEqual(unfinalizedBolus.rate, amount/duration.hours) - XCTAssertNil(unfinalizedBolus.insulinType) - XCTAssertEqual(unfinalizedBolus.automatic, false) - } - - func testInitializationTBR() { - let amount = 0.5 - let startTime = Date() - let duration = TimeInterval.minutes(30) - let unfinalizedTBR = UnfinalizedDose(tempBasalRate: amount, - startTime: startTime, - duration: duration) - XCTAssertEqual(unfinalizedTBR.doseType, .tempBasal) - XCTAssertEqual(unfinalizedTBR.units, amount*duration.hours) - XCTAssertNil(unfinalizedTBR.scheduledUnits) - XCTAssertNil(unfinalizedTBR.scheduledTempRate) - XCTAssertEqual(unfinalizedTBR.startTime, startTime) - XCTAssertEqual(unfinalizedTBR.duration, duration) - XCTAssertEqual(unfinalizedTBR.finishTime, startTime.addingTimeInterval(duration)) - XCTAssertEqual(unfinalizedTBR.rate, amount) - } - - func testInitializatinSuspend() { - let startTime = Date() - let unfinalizedSuspend = UnfinalizedDose(suspendStartTime: startTime) - XCTAssertEqual(unfinalizedSuspend.doseType, .suspend) - XCTAssertEqual(unfinalizedSuspend.units, 0) - XCTAssertNil(unfinalizedSuspend.scheduledUnits) - XCTAssertNil(unfinalizedSuspend.scheduledTempRate) - XCTAssertEqual(unfinalizedSuspend.startTime, startTime) - XCTAssertEqual(unfinalizedSuspend.rate, 0) - } - - func testInitializationResume() { - let startTime = Date() - let unfinalizedResume = UnfinalizedDose(resumeStartTime: startTime) - XCTAssertEqual(unfinalizedResume.doseType, .resume) - XCTAssertEqual(unfinalizedResume.units, 0) - XCTAssertNil(unfinalizedResume.scheduledUnits) - XCTAssertNil(unfinalizedResume.scheduledTempRate) - XCTAssertEqual(unfinalizedResume.startTime, startTime) - XCTAssertEqual(unfinalizedResume.rate, 0) - } - - func testIsFinished() { - let amount = 0.5 - let now = Date() - let duration = TimeInterval.minutes(30) - var unfinalizedTBR = UnfinalizedDose(tempBasalRate: amount, - startTime: now, - duration: duration) - XCTAssertFalse(unfinalizedTBR.finished) - - unfinalizedTBR = UnfinalizedDose(tempBasalRate: amount, - startTime: now-duration, - duration: duration) - XCTAssertTrue(unfinalizedTBR.finished) - } - - func testFinalizedUnits() { - let amount = 3.5 - let now = Date() - let duration = TimeInterval.minutes(1) - var unfinalizedBolus = UnfinalizedDose(bolusAmount: amount, - startTime: now, - duration: duration) - XCTAssertNil(unfinalizedBolus.finalizedUnits) - - unfinalizedBolus = UnfinalizedDose(bolusAmount: amount, - startTime: now-duration, - duration: duration) - XCTAssertEqual(unfinalizedBolus.finalizedUnits, amount) - } - - func testCancel() { - let now = Date() - let rate = 3.0 - let duration = TimeInterval.hours(1) - var dose = UnfinalizedDose(tempBasalRate: rate, - startTime: now, - duration: duration) - dose.cancel(at: now + duration/2) - - XCTAssertEqual(dose.units, rate/2) - XCTAssertEqual(dose.scheduledUnits, rate) - XCTAssertEqual(dose.scheduledTempRate, rate) - XCTAssertEqual(dose.duration, duration/2) - } - - func testRawValue() { - let amount = 3.5 - let startTime = Date() - let duration = TimeInterval.minutes(1) - let unfinalizedBolus = UnfinalizedDose(bolusAmount: amount, - startTime: startTime, - duration: duration) - let rawValue = unfinalizedBolus.rawValue - XCTAssertEqual(UnfinalizedDose.DoseType(rawValue: rawValue["doseType"] as! UnfinalizedDose.DoseType.RawValue), .bolus) - XCTAssertEqual(rawValue["units"] as! Double, amount) - XCTAssertEqual(rawValue["startTime"] as! Date, startTime) - XCTAssertNil(rawValue["scheduledUnits"]) - XCTAssertNil(rawValue["scheduledTempRate"]) - XCTAssertEqual(rawValue["duration"] as! Double, duration) - } - - func testRawValueBolusWithScheduledUnits() { - let amount = 3.5 - let startTime = Date() - let duration = TimeInterval.minutes(1) - var unfinalizedBolus = UnfinalizedDose(bolusAmount: amount, - startTime: startTime, - duration: duration) - unfinalizedBolus.scheduledUnits = amount - let rawValue = unfinalizedBolus.rawValue - XCTAssertEqual(UnfinalizedDose.DoseType(rawValue: rawValue["doseType"] as! UnfinalizedDose.DoseType.RawValue), .bolus) - XCTAssertEqual(rawValue["units"] as! Double, amount) - XCTAssertEqual(rawValue["startTime"] as! Date, startTime) - XCTAssertEqual(rawValue["scheduledUnits"] as! Double, amount) - XCTAssertNil(rawValue["scheduleTempRate"]) - XCTAssertEqual(rawValue["duration"] as! Double, duration) - - let restoredUnfinalizedBolus = UnfinalizedDose(rawValue: rawValue)! - XCTAssertEqual(restoredUnfinalizedBolus.doseType, unfinalizedBolus.doseType) - XCTAssertEqual(restoredUnfinalizedBolus.units, unfinalizedBolus.units) - XCTAssertEqual(restoredUnfinalizedBolus.scheduledUnits, unfinalizedBolus.scheduledUnits) - XCTAssertEqual(restoredUnfinalizedBolus.scheduledTempRate, unfinalizedBolus.scheduledTempRate) - XCTAssertEqual(restoredUnfinalizedBolus.startTime, unfinalizedBolus.startTime) - XCTAssertEqual(restoredUnfinalizedBolus.duration, unfinalizedBolus.duration) - XCTAssertEqual(restoredUnfinalizedBolus.finishTime, unfinalizedBolus.finishTime) - XCTAssertEqual(restoredUnfinalizedBolus.rate, unfinalizedBolus.rate) - } - - func testRawValueTBRWithScheduledTempRate() { - let rate = 0.5 - let startTime = Date() - let duration = TimeInterval.minutes(30) - var unfinalizedTBR = UnfinalizedDose(tempBasalRate: rate, - startTime: startTime, - duration: duration) - unfinalizedTBR.scheduledTempRate = rate - let rawValue = unfinalizedTBR.rawValue - XCTAssertEqual(UnfinalizedDose.DoseType(rawValue: rawValue["doseType"] as! UnfinalizedDose.DoseType.RawValue), .tempBasal) - XCTAssertEqual(rawValue["units"] as! Double, rate*duration.hours) - XCTAssertEqual(rawValue["startTime"] as! Date, startTime) - XCTAssertNil(rawValue["scheduledUnits"]) - XCTAssertEqual(rawValue["scheduledTempRate"] as! Double, rate) - XCTAssertEqual(rawValue["duration"] as! Double, duration) - - let restoredUnfinalizedTBR = UnfinalizedDose(rawValue: rawValue)! - XCTAssertEqual(restoredUnfinalizedTBR.doseType, unfinalizedTBR.doseType) - XCTAssertEqual(restoredUnfinalizedTBR.units, unfinalizedTBR.units) - XCTAssertEqual(restoredUnfinalizedTBR.scheduledUnits, unfinalizedTBR.scheduledUnits) - XCTAssertEqual(restoredUnfinalizedTBR.scheduledTempRate, unfinalizedTBR.scheduledTempRate) - XCTAssertEqual(restoredUnfinalizedTBR.startTime, unfinalizedTBR.startTime) - XCTAssertEqual(restoredUnfinalizedTBR.duration, unfinalizedTBR.duration) - XCTAssertEqual(restoredUnfinalizedTBR.finishTime, unfinalizedTBR.finishTime) - XCTAssertEqual(restoredUnfinalizedTBR.rate, unfinalizedTBR.rate) - } - - func testRestoreFromRawValue() { - let rate = 0.5 - let startTime = Date() - let duration = TimeInterval.minutes(30) - let expectedUnfinalizedTBR = UnfinalizedDose(tempBasalRate: rate, - startTime: startTime, - duration: duration) - let rawValue = expectedUnfinalizedTBR.rawValue - let unfinalizedTBR = UnfinalizedDose(rawValue: rawValue)! - XCTAssertEqual(unfinalizedTBR.doseType, .tempBasal) - XCTAssertEqual(unfinalizedTBR.units, rate*duration.hours) - XCTAssertNil(unfinalizedTBR.scheduledUnits) - XCTAssertNil(unfinalizedTBR.scheduledTempRate) - XCTAssertEqual(unfinalizedTBR.startTime, startTime) - XCTAssertEqual(unfinalizedTBR.duration, duration) - XCTAssertEqual(unfinalizedTBR.finishTime, startTime.addingTimeInterval(duration)) - XCTAssertEqual(unfinalizedTBR.rate, rate) - } - - func testDoseEntryInitFromUnfinalizedBolus() { - let amount = 3.5 - let now = Date() - let duration = TimeInterval.minutes(1) - let unfinalizedBolus = UnfinalizedDose(bolusAmount: amount, - startTime: now, - duration: duration) - let doseEntry = DoseEntry(unfinalizedBolus) - XCTAssertEqual(doseEntry.type, .bolus) - XCTAssertEqual(doseEntry.startDate, now) - XCTAssertEqual(doseEntry.endDate, now.addingTimeInterval(duration)) - XCTAssertEqual(doseEntry.programmedUnits, amount) - XCTAssertEqual(doseEntry.unit, .units) - XCTAssertNil(doseEntry.deliveredUnits) - } - - func testDoseEntryInitFromUnfinalizedTBR() { - let amount = 0.5 - let now = Date() - let duration = TimeInterval.minutes(30) - let rate = amount*duration.hours - let unfinalizedTBR = UnfinalizedDose(tempBasalRate: amount, - startTime: now, - duration: duration) - let doseEntry = DoseEntry(unfinalizedTBR) - XCTAssertEqual(doseEntry.type, .tempBasal) - XCTAssertEqual(doseEntry.startDate, now) - XCTAssertEqual(doseEntry.endDate, now.addingTimeInterval(duration)) - XCTAssertEqual(doseEntry.programmedUnits, rate) - XCTAssertEqual(doseEntry.unit, .unitsPerHour) - XCTAssertNil(doseEntry.deliveredUnits) - } - - func testDoseEntryInitFromUnfinalizedSuspend() { - let now = Date() - let unfinalizedSuspend = UnfinalizedDose(suspendStartTime: now) - let doseEntry = DoseEntry(unfinalizedSuspend) - XCTAssertEqual(doseEntry.type, .suspend) - XCTAssertEqual(doseEntry.startDate, now) - XCTAssertEqual(doseEntry.endDate, now) - XCTAssertEqual(doseEntry.programmedUnits, 0) - XCTAssertEqual(doseEntry.unit, .units) - XCTAssertNil(doseEntry.deliveredUnits) - } - - func testDoseEntryInitFromUnfinalizedResume() { - let now = Date() - let unfinalizedResume = UnfinalizedDose(resumeStartTime: now) - let doseEntry = DoseEntry(unfinalizedResume) - XCTAssertEqual(doseEntry.type, .resume) - XCTAssertEqual(doseEntry.startDate, now) - XCTAssertEqual(doseEntry.endDate, now) - XCTAssertEqual(doseEntry.programmedUnits, 0) - XCTAssertEqual(doseEntry.unit, .units) - XCTAssertNil(doseEntry.deliveredUnits) - } - - func testBolusCancelLongAfterFinishTime() { - let end = Date() - let duration = TimeInterval(1) - var dose = UnfinalizedDose(bolusAmount: 1, startTime: end-duration, duration: duration) - dose.cancel(at: end + .hours(1)) - - XCTAssertEqual(1.0, dose.units) - XCTAssertTrue(dose.finished) - } - - func testInterruptedBolus() { - let end = Date() - let duration = TimeInterval.minutes(1) - var dose = UnfinalizedDose(bolusAmount: 5, - startTime: end - duration/2, - duration: duration) - dose.cancel(at: end) - - XCTAssertEqual(dose.units, 2.5) - XCTAssertEqual(dose.scheduledUnits, 5) - XCTAssertEqual(dose.duration, TimeInterval.minutes(0.5)) - XCTAssertEqual(dose.finishTime, end) - XCTAssertTrue(dose.finished) - XCTAssertEqual(dose.progress, 1) - XCTAssertEqual(dose.finalizedUnits!, 2.5) - XCTAssertTrue(dose.description.contains("Interrupted Bolus")) - - let doseEntry = DoseEntry(dose) - XCTAssertEqual(doseEntry.deliveredUnits, 2.5) - XCTAssertEqual(doseEntry.programmedUnits, 5) - XCTAssertEqual(doseEntry.startDate, end - duration/2) - XCTAssertEqual(doseEntry.endDate, end) - XCTAssertEqual(doseEntry.type, .bolus) - } -} diff --git a/Dependencies/LoopKit/MockKitUI/Extensions/Comparable.swift b/Dependencies/LoopKit/MockKitUI/Extensions/Comparable.swift deleted file mode 100644 index 8ffc4dcaa..000000000 --- a/Dependencies/LoopKit/MockKitUI/Extensions/Comparable.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// Comparable.swift -// LoopKit -// -// Created by Michael Pangburn on 11/20/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -extension Comparable { - func clamped(to range: ClosedRange) -> Self { - if self < range.lowerBound { - return range.lowerBound - } else if self > range.upperBound { - return range.upperBound - } else { - return self - } - } - - mutating func clamp(to range: ClosedRange) { - self = clamped(to: range) - } -} diff --git a/Dependencies/LoopKit/MockKitUI/Extensions/IdentifiableClass.swift b/Dependencies/LoopKit/MockKitUI/Extensions/IdentifiableClass.swift deleted file mode 100644 index d0bf7f297..000000000 --- a/Dependencies/LoopKit/MockKitUI/Extensions/IdentifiableClass.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// IdentifiableClass.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -protocol IdentifiableClass: AnyObject { - static var className: String { get } -} - - -extension IdentifiableClass { - static var className: String { - return NSStringFromClass(self).components(separatedBy: ".").last! - } -} diff --git a/Dependencies/LoopKit/MockKitUI/Extensions/NibLoadable.swift b/Dependencies/LoopKit/MockKitUI/Extensions/NibLoadable.swift deleted file mode 100644 index 475c0f988..000000000 --- a/Dependencies/LoopKit/MockKitUI/Extensions/NibLoadable.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// NibLoadable.swift -// LoopKit -// -// Created by Nate Racklyeft on 7/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -protocol NibLoadable: IdentifiableClass { - static func nib() -> UINib -} - - -extension NibLoadable { - static func nib() -> UINib { - return UINib(nibName: className, bundle: Bundle(for: self)) - } -} diff --git a/Dependencies/LoopKit/MockKitUI/Extensions/NumberFormatter.swift b/Dependencies/LoopKit/MockKitUI/Extensions/NumberFormatter.swift deleted file mode 100644 index 6d9d3ab78..000000000 --- a/Dependencies/LoopKit/MockKitUI/Extensions/NumberFormatter.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// NSNumberFormatter.swift -// Loop -// -// Created by Nate Racklyeft on 9/5/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit - - -extension NumberFormatter { - func string(from number: Double) -> String? { - return string(from: NSNumber(value: number)) - } - - func string(from number: Double, unit: String, style: Formatter.UnitStyle = .medium, avoidLineBreaking: Bool = true) -> String? { - guard let stringValue = string(from: number) else { - return nil - } - - let separator: String - switch style { - case .long: - separator = " " - case .medium: - separator = avoidLineBreaking ? .nonBreakingSpace : " " - case .short: - fallthrough - @unknown default: - separator = avoidLineBreaking ? .wordJoiner : "" - } - - let unit = avoidLineBreaking ? unit.replacingOccurrences(of: "/", with: "\(String.wordJoiner)/\(String.wordJoiner)") : unit - - return String( - format: LocalizedString("%1$@%2$@%3$@", comment: "String format for value with units (1: value, 2: separator, 3: units)"), - stringValue, - separator, - unit - ) - } -} - -public extension String { - static let nonBreakingSpace = "\u{00a0}" - static let wordJoiner = "\u{2060}" -} diff --git a/Dependencies/LoopKit/MockKitUI/Extensions/TimeInterval.swift b/Dependencies/LoopKit/MockKitUI/Extensions/TimeInterval.swift deleted file mode 100644 index a568b77b8..000000000 --- a/Dependencies/LoopKit/MockKitUI/Extensions/TimeInterval.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// NSTimeInterval.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension TimeInterval { - static func minutes(_ minutes: Double) -> TimeInterval { - return self.init(minutes: minutes) - } - - static func hours(_ hours: Double) -> TimeInterval { - return self.init(hours: hours) - } - - init(minutes: Double) { - self.init(minutes * 60) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - var minutes: Double { - return self / 60.0 - } - - var hours: Double { - return minutes / 60.0 - } -} diff --git a/Dependencies/LoopKit/MockKitUI/Extensions/UIColor.swift b/Dependencies/LoopKit/MockKitUI/Extensions/UIColor.swift deleted file mode 100644 index f8b88c4af..000000000 --- a/Dependencies/LoopKit/MockKitUI/Extensions/UIColor.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// UIColor.swift -// LoopKitUI -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// -import UIKit - - -extension UIColor { - static let delete = UIColor.higRed() -} - - -// MARK: - HIG colors -// See: https://developer.apple.com/ios/human-interface-guidelines/visual-design/color/ -extension UIColor { - private static func higRed() -> UIColor { - return UIColor(red: 1, green: 59 / 255, blue: 48 / 255, alpha: 1) - } -} diff --git a/Dependencies/LoopKit/MockKitUI/Extensions/UIImage.swift b/Dependencies/LoopKit/MockKitUI/Extensions/UIImage.swift deleted file mode 100644 index e518caf6c..000000000 --- a/Dependencies/LoopKit/MockKitUI/Extensions/UIImage.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// UIImage.swift -// MockKitUI -// -// Created by Pete Schwamb on 5/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import UIKit - -private class FrameworkBundle { - static let main = Bundle(for: FrameworkBundle.self) -} - -extension UIImage { - convenience init?(frameworkImage name: String) { - self.init(named: name, in: FrameworkBundle.main, with: nil) - } -} diff --git a/Dependencies/LoopKit/MockKitUI/Extensions/UITableViewCell.swift b/Dependencies/LoopKit/MockKitUI/Extensions/UITableViewCell.swift deleted file mode 100644 index dd26055d0..000000000 --- a/Dependencies/LoopKit/MockKitUI/Extensions/UITableViewCell.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// UITableViewCell.swift -// CarbKit -// -// Created by Nathan Racklyeft on 1/15/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -extension UITableViewCell: IdentifiableClass, NibLoadable { -} diff --git a/Dependencies/LoopKit/MockKitUI/Info.plist b/Dependencies/LoopKit/MockKitUI/Info.plist deleted file mode 100644 index adc94e95f..000000000 --- a/Dependencies/LoopKit/MockKitUI/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - - diff --git a/Dependencies/LoopKit/MockKitUI/LocalizedString.swift b/Dependencies/LoopKit/MockKitUI/LocalizedString.swift deleted file mode 100644 index c092c97ed..000000000 --- a/Dependencies/LoopKit/MockKitUI/LocalizedString.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// LocalizedString.swift -// LoopKit -// -// Created by Retina15 on 8/6/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -private class LocalBundle { - /// Returns the resource bundle associated with the current Swift module. - static var main: Bundle = { - if let mainResourceURL = Bundle.main.resourceURL, - let bundle = Bundle(url: mainResourceURL.appendingPathComponent("LoopKit_LoopKit.bundle")) - { - return bundle - } - return Bundle(for: LocalBundle.self) - }() -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, comment: comment) - } -} diff --git a/Dependencies/LoopKit/MockKitUI/MockCGMManager+UI.swift b/Dependencies/LoopKit/MockKitUI/MockCGMManager+UI.swift deleted file mode 100644 index b0be8a164..000000000 --- a/Dependencies/LoopKit/MockKitUI/MockCGMManager+UI.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// MockCGMManager+UI.swift -// LoopKitUI -// -// Created by Michael Pangburn on 11/23/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import SwiftUI -import HealthKit -import LoopKit -import LoopKitUI -import MockKit - - -extension MockCGMManager: CGMManagerUI { - - public static var onboardingImage: UIImage? { return UIImage(named: "CGM Simulator", in: Bundle(for: MockCGMManagerSettingsViewController.self), compatibleWith: nil) } - - public var smallImage: UIImage? { return UIImage(named: "CGM Simulator", in: Bundle(for: MockCGMManagerSettingsViewController.self), compatibleWith: nil) } - - public static func setupViewController(bluetoothProvider: BluetoothProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) -> SetupUIResult { - return .createdAndOnboarded(MockCGMManager()) - } - - public func settingsViewController(bluetoothProvider: BluetoothProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) -> CGMManagerViewController { - let settings = MockCGMManagerSettingsViewController(cgmManager: self, displayGlucoseUnitObservable: displayGlucoseUnitObservable) - let nav = CGMManagerSettingsNavigationViewController(rootViewController: settings) - return nav - } - - public var cgmStatusBadge: DeviceStatusBadge? { - return self.mockSensorState.cgmStatusBadge - } - - public var cgmStatusHighlight: DeviceStatusHighlight? { - return self.mockSensorState.cgmStatusHighlight - } - - public var cgmLifecycleProgress: DeviceLifecycleProgress? { - return self.mockSensorState.cgmLifecycleProgress - } -} diff --git a/Dependencies/LoopKit/MockKitUI/MockHUDProvider.swift b/Dependencies/LoopKit/MockKitUI/MockHUDProvider.swift deleted file mode 100644 index 051843e76..000000000 --- a/Dependencies/LoopKit/MockKitUI/MockHUDProvider.swift +++ /dev/null @@ -1,98 +0,0 @@ -// -// MockHUDProvider.swift -// MockKitUI -// -// Created by Michael Pangburn on 3/5/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import LoopKit -import LoopKitUI -import MockKit -import Foundation - -final class MockHUDProvider: NSObject, HUDProvider { - - var managerIdentifier: String { - return MockPumpManager.managerIdentifier - } - - private var pumpManager: MockPumpManager - - private var lastPumpManagerStatus: PumpManagerStatus - - private weak var reservoirView: ReservoirVolumeHUDView? - - private weak var batteryView: BatteryLevelHUDView? - - init(pumpManager: MockPumpManager, allowedInsulinTypes: [InsulinType]) { - self.pumpManager = pumpManager - self.lastPumpManagerStatus = pumpManager.status - super.init() - pumpManager.addStateObserver(self, queue: .main) - } - - var visible: Bool = false - - var hudViewRawState: HUDViewRawState { - var rawValue: HUDViewRawState = [ - "pumpReservoirCapacity": pumpManager.pumpReservoirCapacity - ] - - if let pumpBatteryChargeRemaining = lastPumpManagerStatus.pumpBatteryChargeRemaining { - rawValue["pumpBatteryChargeRemaining"] = pumpBatteryChargeRemaining - } - - rawValue["reservoirUnitsRemaining"] = pumpManager.state.reservoirUnitsRemaining - - return rawValue - } - - func createHUDView() -> BaseHUDView? { - reservoirView = ReservoirVolumeHUDView.instantiate() - updateReservoirView() - - return reservoirView - } - - static func createHUDView(rawValue: HUDViewRawState) -> BaseHUDView? { - guard let pumpReservoirCapacity = rawValue["pumpReservoirCapacity"] as? Double else { - return nil - } - - let reservoirVolumeHUDView = ReservoirVolumeHUDView.instantiate() - if let reservoirUnitsRemaining = rawValue["reservoirUnitsRemaining"] as? Double { - let reservoirLevel = (reservoirUnitsRemaining / pumpReservoirCapacity).clamped(to: 0...1) - reservoirVolumeHUDView.level = reservoirLevel - reservoirVolumeHUDView.setReservoirVolume(volume: reservoirUnitsRemaining, at: Date()) - } - - return reservoirVolumeHUDView - } - - func didTapOnHUDView(_ view: BaseHUDView, allowDebugFeatures: Bool) -> HUDTapAction? { - return nil - } - - private func updateReservoirView() { - let reservoirVolume = pumpManager.state.reservoirUnitsRemaining - let reservoirLevel = (reservoirVolume / pumpManager.pumpReservoirCapacity).clamped(to: 0...1) - reservoirView?.level = reservoirLevel - reservoirView?.setReservoirVolume(volume: reservoirVolume, at: Date()) - } - - private func updateBatteryView() { - batteryView?.batteryLevel = lastPumpManagerStatus.pumpBatteryChargeRemaining - } -} - -extension MockHUDProvider: MockPumpManagerStateObserver { - func mockPumpManager(_ manager: MockPumpManager, didUpdate state: MockPumpManagerState) { - updateReservoirView() - } - - func mockPumpManager(_ manager: MockPumpManager, didUpdate status: PumpManagerStatus, oldStatus: PumpManagerStatus) { - lastPumpManagerStatus = status - updateBatteryView() - } -} diff --git a/Dependencies/LoopKit/MockKitUI/MockKitUI.h b/Dependencies/LoopKit/MockKitUI/MockKitUI.h deleted file mode 100644 index 212fdcf67..000000000 --- a/Dependencies/LoopKit/MockKitUI/MockKitUI.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// MockKitUI.h -// MockKitUI -// -// Created by Michael Pangburn on 12/20/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -#import - -//! Project version number for MockKitUI. -FOUNDATION_EXPORT double MockKitUIVersionNumber; - -//! Project version string for MockKitUI. -FOUNDATION_EXPORT const unsigned char MockKitUIVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/LoopKit/MockKitUI/MockPumpManager+UI.swift b/Dependencies/LoopKit/MockKitUI/MockPumpManager+UI.swift deleted file mode 100644 index 144fd3ec8..000000000 --- a/Dependencies/LoopKit/MockKitUI/MockPumpManager+UI.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// MockPumpManager+UI.swift -// LoopKitUI -// -// Created by Michael Pangburn on 11/20/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import SwiftUI -import LoopKit -import LoopKitUI -import MockKit - - -extension MockPumpManager: PumpManagerUI { - - private var appName: String { - return Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as! String - } - - public static var onboardingImage: UIImage? { return UIImage(named: "Pump Simulator", in: Bundle(for: MockPumpManagerSettingsViewController.self), compatibleWith: nil) } - - public var smallImage: UIImage? { return UIImage(named: "Pump Simulator", in: Bundle(for: MockPumpManagerSettingsViewController.self), compatibleWith: nil) } - - public static func setupViewController(initialSettings settings: PumpManagerSetupSettings, bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool, allowedInsulinTypes: [InsulinType]) -> SetupUIResult { - let mockPumpManager = MockPumpManager() - mockPumpManager.setMaximumTempBasalRate(settings.maxBasalRateUnitsPerHour) - mockPumpManager.syncBasalRateSchedule(items: settings.basalSchedule.items, completion: { _ in }) - return .createdAndOnboarded(mockPumpManager) - } - - public func settingsViewController(bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool, allowedInsulinTypes: [InsulinType]) -> PumpManagerViewController { - let settings = MockPumpManagerSettingsViewController(pumpManager: self, supportedInsulinTypes: allowedInsulinTypes) - let nav = PumpManagerSettingsNavigationViewController(rootViewController: settings) - return nav - } - - public func deliveryUncertaintyRecoveryViewController(colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) -> (UIViewController & CompletionNotifying) { - return DeliveryUncertaintyRecoveryViewController(appName: appName, uncertaintyStartedAt: Date()) { - self.state.deliveryCommandsShouldTriggerUncertainDelivery = false - self.state.deliveryIsUncertain = false - } - } - - public func hudProvider(bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowedInsulinTypes: [InsulinType]) -> HUDProvider? { - return MockHUDProvider(pumpManager: self, allowedInsulinTypes: allowedInsulinTypes) - } - - public static func createHUDView(rawValue: HUDProvider.HUDViewRawState) -> BaseHUDView? { - return MockHUDProvider.createHUDView(rawValue: rawValue) - } - - -} - -public enum MockPumpStatusBadge: DeviceStatusBadge { - case timeSyncNeeded - - public var image: UIImage? { - switch self { - case .timeSyncNeeded: - return UIImage(systemName: "clock.fill") - } - } - - public var state: DeviceStatusBadgeState { - switch self { - case .timeSyncNeeded: - return .warning - } - } -} - - -// MARK: - PumpStatusIndicator -extension MockPumpManager { - public var pumpStatusHighlight: DeviceStatusHighlight? { - return buildPumpStatusHighlight(for: state) - } - - public var pumpLifecycleProgress: DeviceLifecycleProgress? { - return buildPumpLifecycleProgress(for: state) - } - - public var pumpStatusBadge: DeviceStatusBadge? { - return isClockOffset ? MockPumpStatusBadge.timeSyncNeeded : nil - } -} diff --git a/Dependencies/LoopKit/MockKitUI/MockService+UI.swift b/Dependencies/LoopKit/MockKitUI/MockService+UI.swift deleted file mode 100644 index e3ff7495e..000000000 --- a/Dependencies/LoopKit/MockKitUI/MockService+UI.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// MockService+UI.swift -// MockKitUI -// -// Created by Darin Krauss on 5/17/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import MockKit -import HealthKit - -extension MockService: ServiceUI { - public static var image: UIImage? { - return UIImage(systemName: "icloud.and.arrow.up") - } - - public static func setupViewController(colorPalette: LoopUIColorPalette, pluginHost: PluginHost) -> SetupUIResult { - return .userInteractionRequired(ServiceNavigationController(rootViewController: MockServiceTableViewController(service: MockService(), for: .create))) - } - - public func settingsViewController(colorPalette: LoopUIColorPalette) -> ServiceViewController { - return ServiceNavigationController(rootViewController: MockServiceTableViewController(service: self, for: .update)) - } - -} - diff --git a/Dependencies/LoopKit/MockKitUI/MockSupport.swift b/Dependencies/LoopKit/MockKitUI/MockSupport.swift deleted file mode 100644 index e7ce5b942..000000000 --- a/Dependencies/LoopKit/MockKitUI/MockSupport.swift +++ /dev/null @@ -1,158 +0,0 @@ -// -// MockSupport.swift -// MockKitUI -// -// Created by Rick Pasetto on 10/13/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit -import LoopKitUI -import SwiftUI - -public class MockSupport: SupportUI { - - public static let supportIdentifier = "MockSupport" - - var versionUpdate: VersionUpdate? - var alertIssuer: AlertIssuer? { - return self.delegate - } - var lastVersionCheckAlertDate: Date? - - public init() { } - - public required init?(rawState: RawStateValue) { - lastVersionCheckAlertDate = rawState["lastVersionCheckAlertDate"] as? Date - } - - public var rawState: RawStateValue { - var rawValue: RawStateValue = [:] - rawValue["lastVersionCheckAlertDate"] = lastVersionCheckAlertDate - return rawValue - } - - public func checkVersion(bundleIdentifier: String, currentVersion: String, completion: @escaping (Result) -> Void) { - maybeIssueAlert(versionUpdate ?? .none) - completion(.success(versionUpdate)) - } - - public weak var delegate: SupportUIDelegate? - - public func configurationMenuItems() -> [AnyView] { - return [] - } - - public func supportMenuItem(supportInfoProvider: SupportInfoProvider, urlHandler: @escaping (URL) -> Void) -> AnyView? { - return AnyView(SupportMenuItem(mockSupport: self)) - } - - public func softwareUpdateView(bundleIdentifier: String, currentVersion: String, guidanceColors: GuidanceColors, openAppStore: (() -> Void)?) -> AnyView? { - return AnyView( - Button("versionUpdate: \(versionUpdate!.localizedDescription)\n\nbundleIdentifier: \(bundleIdentifier)\n\ncurrentVersion: \(currentVersion)") { - openAppStore?() - } - ) - } -} - -extension MockSupport { - - var alertCadence: TimeInterval { - return TimeInterval.minutes(1) - } - - private var appName: String { - return Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as! String - } - - private func maybeIssueAlert(_ versionUpdate: VersionUpdate) { - guard versionUpdate >= .recommended else { - noAlertNecessary() - return - } - - let alertIdentifier = Alert.Identifier(managerIdentifier: MockSupport.supportIdentifier, alertIdentifier: versionUpdate.rawValue) - let alertContent: LoopKit.Alert.Content - if firstAlert { - alertContent = Alert.Content(title: versionUpdate.localizedDescription, - body: String(format: LocalizedString(""" - Your %1$@ app is out of date. It will continue to work, but we recommend updating to the latest version. - - Go to %2$@ Settings > Software Update to complete. - """, comment: "Alert content body for first software update alert (1: app name)(2: app name)"), appName, appName), - acknowledgeActionButtonLabel: LocalizedString("OK", comment: "Default acknowledgement")) - } else if let lastVersionCheckAlertDate = lastVersionCheckAlertDate, - abs(lastVersionCheckAlertDate.timeIntervalSinceNow) > alertCadence { - alertContent = Alert.Content(title: LocalizedString("Update Reminder", comment: "Recurring software update alert title"), - body: String(format: LocalizedString(""" - A software update is recommended to continue using the %1$@ app. - - Go to %2$@ Settings > Software Update to install the latest version. - """, comment: "Alert content body for recurring software update alert"), appName, appName), - acknowledgeActionButtonLabel: LocalizedString("OK", comment: "Default acknowledgement")) - } else { - return - } - let interruptionLevel: LoopKit.Alert.InterruptionLevel = versionUpdate == .required ? .critical : .active - alertIssuer?.issueAlert(Alert(identifier: alertIdentifier, foregroundContent: alertContent, backgroundContent: alertContent, trigger: .immediate, interruptionLevel: interruptionLevel)) - recordLastAlertDate() - } - - private func noAlertNecessary() { - lastVersionCheckAlertDate = nil - } - - private var firstAlert: Bool { - return lastVersionCheckAlertDate == nil - } - - private func recordLastAlertDate() { - lastVersionCheckAlertDate = Date() - } - -} - -struct SupportMenuItem : View { - - let mockSupport: MockSupport - - @State var showActionSheet: Bool = false - - private var buttons: [ActionSheet.Button] { - VersionUpdate.allCases.map { versionUpdate in - let setter = { mockSupport.versionUpdate = versionUpdate } - switch versionUpdate { - case .required: - return ActionSheet.Button.destructive(Text(versionUpdate.localizedDescription), action: setter) - default: - return ActionSheet.Button.default(Text(versionUpdate.localizedDescription), action: setter) - } - } + - [.cancel(Text("Cancel"))] - } - - private var actionSheet: ActionSheet { - ActionSheet(title: Text("Version Check Response"), message: Text("How should the simulator respond to a version check?"), buttons: buttons) - } - - var body: some View { - Button(action: { - self.showActionSheet.toggle() - }) { - Text("Mock Version Check \(currentVersionUpdate)") - } - .actionSheet(isPresented: $showActionSheet, content: { - self.actionSheet - }) - - Button(action: { mockSupport.lastVersionCheckAlertDate = nil } ) { - Text("Clear Last Version Check Alert Date") - } - } - - var currentVersionUpdate: String { - return mockSupport.versionUpdate.map { "(\($0.rawValue))" } ?? "" - } -} diff --git a/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/CGM Simulator.imageset/CGM Simulator.pdf b/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/CGM Simulator.imageset/CGM Simulator.pdf deleted file mode 100644 index 5665b083a..000000000 Binary files a/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/CGM Simulator.imageset/CGM Simulator.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/CGM Simulator.imageset/Contents.json b/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/CGM Simulator.imageset/Contents.json deleted file mode 100644 index f1250762c..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/CGM Simulator.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "CGM Simulator.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/Contents.json b/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/Pump Simulator.imageset/Contents.json b/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/Pump Simulator.imageset/Contents.json deleted file mode 100644 index 858a62442..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/Pump Simulator.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "Pump Simulator.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/Pump Simulator.imageset/Pump Simulator.pdf b/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/Pump Simulator.imageset/Pump Simulator.pdf deleted file mode 100644 index 839b4cbef..000000000 Binary files a/Dependencies/LoopKit/MockKitUI/Resources/Assets.xcassets/Pump Simulator.imageset/Pump Simulator.pdf and /dev/null differ diff --git a/Dependencies/LoopKit/MockKitUI/Resources/ar.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/ar.lproj/Localizable.strings deleted file mode 100644 index a4bd1d844..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/ar.lproj/Localizable.strings +++ /dev/null @@ -1,13 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "إلغاء"; - -/* The alert title for a resume error */ -"Error Resuming" = "خطأ في الاستئناف"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "موافق"; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/cs.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/cs.lproj/Localizable.strings deleted file mode 100644 index 961bc6a02..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/cs.lproj/Localizable.strings +++ /dev/null @@ -1,25 +0,0 @@ -/* Alert content body for recurring software update alert */ -"A software update is recommended to continue using the %1$@ app.\n\nGo to %2$@ Settings > Software Update to install the latest version." = "Chcete-li nadále používat aplikaci %1$@, doporučujeme její aktualizaci. \n\nPřejděte do %2$@ Nastavení > Aktualizace softwaru pro nainstalování nejnovější verze."; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Opravdu chcete tuto službu smazat?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Zpět"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Zrušit"; - -/* Button title to delete a service */ -"Delete Service" = "Smazat službu"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "Typ inzulínu"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Alert content body for first software update alert (1: app name)(2: app name) */ -"Your %1$@ app is out of date. It will continue to work, but we recommend updating to the latest version.\n\nGo to %2$@ Settings > Software Update to complete." = "Vaše aplikace %1$@ je zastaralá. Bude fungovat i nadále, ale doporučujeme aktualizaci na nejnovější verzi. \n\nPro dokončení přejděte do %2$@ Nastavení > Aktualizace softwaru."; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/da.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/da.lproj/Localizable.strings deleted file mode 100644 index 6ca1fc18e..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/da.lproj/Localizable.strings +++ /dev/null @@ -1,68 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Alert content body for recurring software update alert */ -"A software update is recommended to continue using the %1$@ app.\n\nGo to %2$@ Settings > Software Update to install the latest version." = "Det anbefales at foretage en softwareopdatering for at fortsætte med at bruge %1$@ appen.\n\nGå til Indstillinger for %2$@ > Softwareopdatering for at installere den nyeste version."; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Er du sikker på, du vil slette denne service?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Tilbage"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuller"; - -/* Title for CGM simulator settings */ -"CGM Settings" = "CGM-indstillinger"; - -/* No comment provided by engineer. */ -"Clear Last Version Check Alert Date" = "Ryd advarselsdato for sidste versionskontrol"; - -/* No comment provided by engineer. */ -"Comms Recovery" = "Kommunikation-genoprettelse"; - -/* Button title to delete a service */ -"Delete Service" = "Slet service"; - -/* The alert title for a resume error */ -"Error Resuming" = "Fejl ved genoptagelse"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Fejl ved suspendering"; - -/* Caption for History - History Caption */ -"History" = "Historik"; - -/* No comment provided by engineer. */ -"How should the simulator respond to a version check?" = "Hvordan skal simulatoren reagere på en versionskontrol?"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "Insulintype"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Pumpeindstillinger"; - -/* Button title recovering comms */ -"Recover Simulator" = "Gendan simulator"; - -/* Caption for Source */ -"Source" = "Kilde"; - -/* Recurring software update alert title */ -"Update Reminder" = "Påmindelse om opdatering"; - -/* No comment provided by engineer. */ -"Version Check Response" = "Svar på versionskontrol"; - -/* Alert content body for first software update alert (1: app name)(2: app name) */ -"Your %1$@ app is out of date. It will continue to work, but we recommend updating to the latest version.\n\nGo to %2$@ Settings > Software Update to complete." = "Din %1$@ app er forældet. Det vil fortsætte med at fungere, men vi anbefaler at opdatere til den nyeste version.\n\nGå til Indstillinger for %2$@ > Softwareopdatering for at fuldføre."; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/de.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/de.lproj/Localizable.strings deleted file mode 100644 index 36c5cbd4b..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/de.lproj/Localizable.strings +++ /dev/null @@ -1,68 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Alert content body for recurring software update alert */ -"A software update is recommended to continue using the %1$@ app.\n\nGo to %2$@ Settings > Software Update to install the latest version." = "Eine Softwareaktualisierung wird empfohlen, um die %1$@-App weiterhin zu verwenden.\n\nGehe zu %2$@ Einstellungen > Softwareaktualisierung, um die neueste Version zu installieren."; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Bist Du sicher, dass Du diesen Dienst löschen möchtest?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Zurück"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Abbrechen"; - -/* Title for CGM simulator settings */ -"CGM Settings" = "CGM-Einstellungen"; - -/* No comment provided by engineer. */ -"Clear Last Version Check Alert Date" = "Löschen Sie das Datum der letzten Versionsprüfungswarnung"; - -/* No comment provided by engineer. */ -"Comms Recovery" = "Comms Wiederherstellung"; - -/* Button title to delete a service */ -"Delete Service" = "Dienst löschen"; - -/* The alert title for a resume error */ -"Error Resuming" = "Fehler beim Fortfahren"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Fehler beim Unterbrechen"; - -/* Caption for History - History Caption */ -"History" = "Historie"; - -/* No comment provided by engineer. */ -"How should the simulator respond to a version check?" = "Wie soll der Simulator auf eine Versionsprüfung reagieren?"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "Insulintyp"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Pumpeneinstellungen"; - -/* Button title recovering comms */ -"Recover Simulator" = "Simulator wiederherstellen"; - -/* Caption for Source */ -"Source" = "Quelle"; - -/* Recurring software update alert title */ -"Update Reminder" = "Update-Erinnerung"; - -/* No comment provided by engineer. */ -"Version Check Response" = "Antwort der Versionsprüfung"; - -/* Alert content body for first software update alert (1: app name)(2: app name) */ -"Your %1$@ app is out of date. It will continue to work, but we recommend updating to the latest version.\n\nGo to %2$@ Settings > Software Update to complete." = "Deine %1$@-App ist nicht mehr aktuell. Sie funktioniert weiterhin, aber wir empfehlen Dir, auf die neueste Version zu aktualisieren.\n\nGehen zu %2$@ Einstellungen > Softwareaktualisierung, um die Aktualisierung abzuschließen."; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/en.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/en.lproj/Localizable.strings deleted file mode 100644 index 2b2e4675a..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/en.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - LoopKit - - Created by Pete Schwamb on 3/19/23. - Copyright © 2023 LoopKit Authors. All rights reserved. -*/ diff --git a/Dependencies/LoopKit/MockKitUI/Resources/es.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/es.lproj/Localizable.strings deleted file mode 100644 index ecb119770..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/es.lproj/Localizable.strings +++ /dev/null @@ -1,68 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Alert content body for recurring software update alert */ -"A software update is recommended to continue using the %1$@ app.\n\nGo to %2$@ Settings > Software Update to install the latest version." = "Se recomienda una actualización de software para continuar usando la aplicación %1$@. \n\n Vaya a Configuración %2$@ > Actualización de Software para instalar la última versión."; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "¿Está seguro de que desea eliminar este servicio?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Atrás"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancelar"; - -/* Title for CGM simulator settings */ -"CGM Settings" = "Configuración del MCG"; - -/* No comment provided by engineer. */ -"Clear Last Version Check Alert Date" = "Borrar última versión y comprobar fecha de alerta"; - -/* No comment provided by engineer. */ -"Comms Recovery" = "Recuperación de comunicaciones"; - -/* Button title to delete a service */ -"Delete Service" = "Eliminar servicio"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Reanudando"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspendiendo"; - -/* Caption for History - History Caption */ -"History" = "Historial"; - -/* No comment provided by engineer. */ -"How should the simulator respond to a version check?" = "¿Cómo debe responder el simulador a una verificación de versión?"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "Tipo de Insulina"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Configuración de la bomba"; - -/* Button title recovering comms */ -"Recover Simulator" = "Recuperar Simulador"; - -/* Caption for Source */ -"Source" = "Fuente"; - -/* Recurring software update alert title */ -"Update Reminder" = "Recordatorio de actualización"; - -/* No comment provided by engineer. */ -"Version Check Response" = "Respuesta de verificación de versión"; - -/* Alert content body for first software update alert (1: app name)(2: app name) */ -"Your %1$@ app is out of date. It will continue to work, but we recommend updating to the latest version.\n\nGo to %2$@ Settings > Software Update to complete." = "Tu aplicación %1$@ no está actualizada. Seguirá funcionando, pero recomendamos actualizar a la última versión. \n\n Vaya a %2$@ Configuración > Actualización de Software para completar."; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/fi.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/fi.lproj/Localizable.strings deleted file mode 100644 index db227c370..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/fi.lproj/Localizable.strings +++ /dev/null @@ -1,47 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Haluatko varmasti poistaa tämän palvelun?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Takaisin"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Kumoa"; - -/* Title for CGM simulator settings */ -"CGM Settings" = "CGM-asetukset"; - -/* No comment provided by engineer. */ -"Comms Recovery" = "Yhteyksien palautus"; - -/* Button title to delete a service */ -"Delete Service" = "Poista palvelu"; - -/* The alert title for a resume error */ -"Error Resuming" = "Virhe jatkamisessa"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Virhe pysäytyksessä"; - -/* Caption for History - History Caption */ -"History" = "Historia"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "Insuliinityyppi"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Pumpun asetukset"; - -/* Button title recovering comms */ -"Recover Simulator" = "Palauta simulaattori"; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/fr.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/fr.lproj/Localizable.strings deleted file mode 100644 index 56a369926..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/fr.lproj/Localizable.strings +++ /dev/null @@ -1,62 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Voulez-vous vraiment supprimer ce service?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Retour"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuler"; - -/* Title for CGM simulator settings */ -"CGM Settings" = "Paramètres CGM"; - -/* No comment provided by engineer. */ -"Clear Last Version Check Alert Date" = "Effacer la date d'alerte de la dernière vérification de version"; - -/* No comment provided by engineer. */ -"Comms Recovery" = "Récupération des communications"; - -/* Button title to delete a service */ -"Delete Service" = "Supprimer le service"; - -/* The alert title for a resume error */ -"Error Resuming" = "Erreur lors de la reprise"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Erreur lors de la suspension"; - -/* Caption for History - History Caption */ -"History" = "Historique"; - -/* No comment provided by engineer. */ -"How should the simulator respond to a version check?" = "Comment le simulateur devrait-il répondre à une vérification de version?"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "Type d'insuline"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Paramètres de la pompe"; - -/* Button title recovering comms */ -"Recover Simulator" = "Rétablissement du simulateur"; - -/* Caption for Source */ -"Source" = "Source"; - -/* Recurring software update alert title */ -"Update Reminder" = "Rappel de mise à jour"; - -/* No comment provided by engineer. */ -"Version Check Response" = "Réponse à la vérification de version"; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/he.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/he.lproj/Localizable.strings deleted file mode 100644 index 929f694b3..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/he.lproj/Localizable.strings +++ /dev/null @@ -1,28 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Are you sure you want to delete this service?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancel"; - -/* Button title to delete a service */ -"Delete Service" = "Delete Service"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Resuming"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspending"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Pump Settings"; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/hi.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/hi.lproj/Localizable.strings deleted file mode 100644 index c197275b7..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/hi.lproj/Localizable.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the cancel action in an action sheet */ -"Cancel" = "निरस्त"; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/it.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/it.lproj/Localizable.strings deleted file mode 100644 index 01af32014..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/it.lproj/Localizable.strings +++ /dev/null @@ -1,62 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Sei sicuro di voler eliminare questo servizio?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Indietro"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annulla"; - -/* Title for CGM simulator settings */ -"CGM Settings" = "Impostazioni CGM"; - -/* No comment provided by engineer. */ -"Clear Last Version Check Alert Date" = "Cancella l'ultima versione Controlla la data dell'avviso"; - -/* No comment provided by engineer. */ -"Comms Recovery" = "recovero delle comunicazioni"; - -/* Button title to delete a service */ -"Delete Service" = "Elimina Servizio"; - -/* The alert title for a resume error */ -"Error Resuming" = "Errore durante la Ripresa"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Errore durante l’interruzione"; - -/* Caption for History - History Caption */ -"History" = "Storia"; - -/* No comment provided by engineer. */ -"How should the simulator respond to a version check?" = "Come dovrebbe rispondere il simulatore a un controllo della versione?"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "Tipo d'insulina"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "impostazione del microinfusore"; - -/* Button title recovering comms */ -"Recover Simulator" = "Simulatore di recupero"; - -/* Caption for Source */ -"Source" = "Fonte"; - -/* Recurring software update alert title */ -"Update Reminder" = "Promemoria di aggiornamento"; - -/* No comment provided by engineer. */ -"Version Check Response" = "Responso del controllo versione"; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/ja.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/ja.lproj/Localizable.strings deleted file mode 100644 index 2c0867bca..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/ja.lproj/Localizable.strings +++ /dev/null @@ -1,25 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "キャンセル"; - -/* Button title to delete a service */ -"Delete Service" = "Delete Service"; - -/* The alert title for a resume error */ -"Error Resuming" = "再開エラー"; - -/* The alert title for a suspend error */ -"Error Suspending" = "一時中止エラー"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "ポンプ設定"; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/nb.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/nb.lproj/Localizable.strings deleted file mode 100644 index 9b5043f7c..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/nb.lproj/Localizable.strings +++ /dev/null @@ -1,68 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@ ."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* Alert content body for recurring software update alert */ -"A software update is recommended to continue using the %1$@ app.\n\nGo to %2$@ Settings > Software Update to install the latest version." = "En programvareoppdatering anbefales for å fortsette å bruke %1$@-appen.\n\nGå til %2$@ Innstillinger > Programvareoppdatering for å installere den nyeste versjonen."; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Er du sikker på at du vil slette denne tjenesten?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Tilbake"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Avbryt"; - -/* Title for CGM simulator settings */ -"CGM Settings" = "CGM-innstillinger"; - -/* No comment provided by engineer. */ -"Clear Last Version Check Alert Date" = "Fjern varseldato for siste versjonskontroll"; - -/* No comment provided by engineer. */ -"Comms Recovery" = "Kommunikasjon gjennopprettet"; - -/* Button title to delete a service */ -"Delete Service" = "Slett tjeneste"; - -/* The alert title for a resume error */ -"Error Resuming" = "Feil ved gjenopptagelse"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Kunne ikke stoppe"; - -/* Caption for History - History Caption */ -"History" = "Historie"; - -/* No comment provided by engineer. */ -"How should the simulator respond to a version check?" = "Hvordan skal simulatoren svare på en versjonskontroll?"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "Insulintype"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "Ok"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Pumpeinnstillinger"; - -/* Button title recovering comms */ -"Recover Simulator" = "Gjenopprett simulator"; - -/* Caption for Source */ -"Source" = "Kilde"; - -/* Recurring software update alert title */ -"Update Reminder" = "Oppdater påminnelse"; - -/* No comment provided by engineer. */ -"Version Check Response" = "Svar på versjonskontroll"; - -/* Alert content body for first software update alert (1: app name)(2: app name) */ -"Your %1$@ app is out of date. It will continue to work, but we recommend updating to the latest version.\n\nGo to %2$@ Settings > Software Update to complete." = "Din %1$@ app er utdatert. Den vil fortsette å fungere, men vi anbefaler å oppdatere til siste versjon. \n\nGå til %2$@ Innstillinger > Programvareoppdatering for å fullføre."; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/nl.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/nl.lproj/Localizable.strings deleted file mode 100644 index ff4f936d2..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/nl.lproj/Localizable.strings +++ /dev/null @@ -1,74 +0,0 @@ -/* No comment provided by engineer. */ -"%@ has been unable to communicate with the Simulator Pump since %@.\n\nWithout communication, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered." = "%1$@ kan niet communiceren met de Pompsimulator sinds %2$@.\n\nZonder communicatie kan de app geen opdrachten meer versturen voor insulinetoediening of nauwkeurige recente informatie weergeven over jouw actieve insuline of de insuline die is toegediend."; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Alert content body for recurring software update alert */ -"A software update is recommended to continue using the %1$@ app.\n\nGo to %2$@ Settings > Software Update to install the latest version." = "Een software-update wordt aanbevolen om de %1$@ app te blijven gebruiken. \n\nGa naar %2$@ Instellingen > Software Update om de nieuwste versie te installeren."; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Weet je zeker dat je deze service wil verwijderen?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Terug"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuleer"; - -/* Title for CGM simulator settings */ -"CGM Settings" = "CGM Instellingen"; - -/* No comment provided by engineer. */ -"Clear Last Version Check Alert Date" = "Wis laatste versie Controleer Waarschuwingsdatum"; - -/* No comment provided by engineer. */ -"Comms Recovery" = "Comms Herstel"; - -/* Button title to delete a service */ -"Delete Service" = "Service Verwijderen"; - -/* The alert title for a resume error */ -"Error Resuming" = "Fout Bij Hervatten"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Fout Bij Onderbreken"; - -/* Caption for History - History Caption */ -"History" = "Geschiedenis"; - -/* No comment provided by engineer. */ -"How should the simulator respond to a version check?" = "Hoe moet de simulator reageren op een versiecontrole?"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "Insulinetype"; - -/* No comment provided by engineer. */ -"Mock Version Check %@" = "Mock Versie Check %@"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "Ok"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Pompinstellingen"; - -/* Button title recovering comms */ -"Recover Simulator" = "Simulator Herstellen"; - -/* Caption for Source */ -"Source" = "Bron"; - -/* Recurring software update alert title */ -"Update Reminder" = "Update Herinnering"; - -/* No comment provided by engineer. */ -"Version Check Response" = "Reactie op versiecontrole"; - -/* Alert content body for first software update alert (1: app name)(2: app name) */ -"Your %1$@ app is out of date. It will continue to work, but we recommend updating to the latest version.\n\nGo to %2$@ Settings > Software Update to complete." = "Je %1$@ app is verouderd. De app blijft werken, maar we raden je aan om de app bij te werken naar de nieuwste versie. \n\nGa naar %2$@ Instellingen > Software Update om de update te voltooien."; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/pl.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/pl.lproj/Localizable.strings deleted file mode 100644 index eabe68bf1..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/pl.lproj/Localizable.strings +++ /dev/null @@ -1,74 +0,0 @@ -/* No comment provided by engineer. */ -"%@ has been unable to communicate with the Simulator Pump since %@.\n\nWithout communication, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered." = "%1$@ nie może komunikować się z symulatorem pompy od %2$@ . \n\nBez komunikacji aplikacja nie może wysyłać poleceń podawania insuliny ani wyświetlać aktualnych informacji o aktywnej lub podawanej insulinie."; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Alert content body for recurring software update alert */ -"A software update is recommended to continue using the %1$@ app.\n\nGo to %2$@ Settings > Software Update to install the latest version." = "Aby nadal korzystać z aplikacji %1$@ , zalecamy aktualizację oprogramowania. \n\n Przejdź do %2$@ Ustawienia > Aktualizacja oprogramowania, aby zainstalować najnowszą wersję."; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Czy na pewno chcesz usunąć tę usługę?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Powrót"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Anuluj"; - -/* Title for CGM simulator settings */ -"CGM Settings" = "Ustawienia CGM"; - -/* No comment provided by engineer. */ -"Clear Last Version Check Alert Date" = "Wyczyść ostatni odczytany alarm"; - -/* No comment provided by engineer. */ -"Comms Recovery" = "Odzyskiwanie komunikacji"; - -/* Button title to delete a service */ -"Delete Service" = "Usuń usługę"; - -/* The alert title for a resume error */ -"Error Resuming" = "Błąd wznawiania"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Błąd wstrzymywania"; - -/* Caption for History - History Caption */ -"History" = "Historia"; - -/* No comment provided by engineer. */ -"How should the simulator respond to a version check?" = "Jak symulator powinien zareagować na sprawdzenie wersji?"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "Rodzaj insuliny"; - -/* No comment provided by engineer. */ -"Mock Version Check %@" = "Pozorowana kontrola wersji %@"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Ustawienia pompy"; - -/* Button title recovering comms */ -"Recover Simulator" = "Odzyskaj komunikat"; - -/* Caption for Source */ -"Source" = "Źródło"; - -/* Recurring software update alert title */ -"Update Reminder" = "Przypomnienie o aktualizacji"; - -/* No comment provided by engineer. */ -"Version Check Response" = "Odpowiedź na sprawdzenie wersji"; - -/* Alert content body for first software update alert (1: app name)(2: app name) */ -"Your %1$@ app is out of date. It will continue to work, but we recommend updating to the latest version.\n\nGo to %2$@ Settings > Software Update to complete." = "Twoja aplikacja %1$@ jest nieaktualna. Będzie nadal działać, ale zalecamy aktualizację do najnowszej wersji. \n\n Przejdź do %2$@ Ustawienia > Aktualizacja oprogramowania, aby dokonać aktualizacji."; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/pt-BR.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/pt-BR.lproj/Localizable.strings deleted file mode 100644 index 7670cb73d..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,25 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancelar"; - -/* Button title to delete a service */ -"Delete Service" = "Delete Service"; - -/* The alert title for a resume error */ -"Error Resuming" = "Erro ao Retomar"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Erro ao Suspender"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Configurações da Bomba"; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/ro.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/ro.lproj/Localizable.strings deleted file mode 100644 index 0ef4b794e..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/ro.lproj/Localizable.strings +++ /dev/null @@ -1,74 +0,0 @@ -/* No comment provided by engineer. */ -"%@ has been unable to communicate with the Simulator Pump since %@.\n\nWithout communication, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered." = "%1$@ nu a putut comunica cu pompa simulată din %2$@.\n\nFără comunicare, aplicația nu poate continua să trimită comenzi pentru administrarea de insulină sau să afișeze informații exacte și recente despre insulina dumneavoastră activă sau insulina care vi se administrează."; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Alert content body for recurring software update alert */ -"A software update is recommended to continue using the %1$@ app.\n\nGo to %2$@ Settings > Software Update to install the latest version." = "Se recomandă o actualizare a software-ului pentru a continua să utilizați aplicația %1$@.\n\nAccesați %2$@ Setări > Actualizare software pentru a instala cea mai recentă versiune."; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Ești sigur că vrei să ștergi acest serviciu?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Înapoi"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Renunță"; - -/* Title for CGM simulator settings */ -"CGM Settings" = "Setări CGM"; - -/* No comment provided by engineer. */ -"Clear Last Version Check Alert Date" = "Ștergeți data ultimei alerte de verificare a versiunii"; - -/* No comment provided by engineer. */ -"Comms Recovery" = "Recuperare comenzi"; - -/* Button title to delete a service */ -"Delete Service" = "Șterge serviciul"; - -/* The alert title for a resume error */ -"Error Resuming" = "Eroare în timpul reluării"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Eroare în timpul suspendării"; - -/* Caption for History - History Caption */ -"History" = "Istoric"; - -/* No comment provided by engineer. */ -"How should the simulator respond to a version check?" = "Cum ar trebui să răspundă simulatorul la o verificare a versiunii?"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "Tipul de insulină"; - -/* No comment provided by engineer. */ -"Mock Version Check %@" = "Verificare versiune simulată %@"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Setări pompă"; - -/* Button title recovering comms */ -"Recover Simulator" = "Simulator de recuperare"; - -/* Caption for Source */ -"Source" = "Sursă"; - -/* Recurring software update alert title */ -"Update Reminder" = "Memento actualizare"; - -/* No comment provided by engineer. */ -"Version Check Response" = "Răspuns de verificare a versiunii"; - -/* Alert content body for first software update alert (1: app name)(2: app name) */ -"Your %1$@ app is out of date. It will continue to work, but we recommend updating to the latest version.\n\nGo to %2$@ Settings > Software Update to complete." = "Aplicația dvs. %1$@ nu este actualizată. Aceasta va continua să funcționeze, dar vă recomandăm să o actualizați la cea mai recentă versiune.\n\nAccesați %2$@ Setări > Actualizare software pentru a finaliza."; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/ru.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/ru.lproj/Localizable.strings deleted file mode 100644 index 3055c3a65..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/ru.lproj/Localizable.strings +++ /dev/null @@ -1,68 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Alert content body for recurring software update alert */ -"A software update is recommended to continue using the %1$@ app.\n\nGo to %2$@ Settings > Software Update to install the latest version." = "Для продолжения использования приложения %1$@ рекомендуется обновить программное обеспечение.\n\nПерейдите в %2$@ Настройки > Обновление ПО, чтобы установить последнюю версию."; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Вы уверены, что хотите удалить этот сервис?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Назад"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Отмена"; - -/* Title for CGM simulator settings */ -"CGM Settings" = "Настройки CGM"; - -/* No comment provided by engineer. */ -"Clear Last Version Check Alert Date" = "Очистить последнюю дату проверки версии"; - -/* No comment provided by engineer. */ -"Comms Recovery" = "Восстановление связи"; - -/* Button title to delete a service */ -"Delete Service" = "Удалить сервис"; - -/* The alert title for a resume error */ -"Error Resuming" = "Ошибка возобновления"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Ошибка приостановки"; - -/* Caption for History - History Caption */ -"History" = "История"; - -/* No comment provided by engineer. */ -"How should the simulator respond to a version check?" = "Как симулятор должен реагировать на проверку версии?"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "Тип инсулина"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Настройки помпы"; - -/* Button title recovering comms */ -"Recover Simulator" = "Восстановить симулятор"; - -/* Caption for Source */ -"Source" = "Источник"; - -/* Recurring software update alert title */ -"Update Reminder" = "Напоминание об обновлении"; - -/* No comment provided by engineer. */ -"Version Check Response" = "Ответ на проверку версии"; - -/* Alert content body for first software update alert (1: app name)(2: app name) */ -"Your %1$@ app is out of date. It will continue to work, but we recommend updating to the latest version.\n\nGo to %2$@ Settings > Software Update to complete." = "Ваше приложение %1$@ устарело. Оно будет продолжать работать, но мы рекомендуем обновить его до последней версии.\n\nДля завершения обновления перейдите в %2$@ Настройки > Обновление ПО."; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/sk.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/sk.lproj/Localizable.strings deleted file mode 100644 index 781977159..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/sk.lproj/Localizable.strings +++ /dev/null @@ -1,31 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@ ."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Naozaj chcete odstrániť túto službu?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Späť"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Zrušiť"; - -/* Button title to delete a service */ -"Delete Service" = "Odstrániť službu"; - -/* The alert title for a resume error */ -"Error Resuming" = "Chyba pri obnovení"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Chyba pri pozastavení"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "Typ inzulínu"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/sv.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/sv.lproj/Localizable.strings deleted file mode 100644 index d6e254b0a..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/sv.lproj/Localizable.strings +++ /dev/null @@ -1,47 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Vill du ta bort den här tjänsten?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Tillbaka"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Avbryt"; - -/* Title for CGM simulator settings */ -"CGM Settings" = "CGM-inställningar"; - -/* No comment provided by engineer. */ -"Comms Recovery" = "Återställning av kommandon"; - -/* Button title to delete a service */ -"Delete Service" = "Ta bort tjänst"; - -/* The alert title for a resume error */ -"Error Resuming" = "Fel vid återupptagande"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Fel vid försök till paus"; - -/* Caption for History - History Caption */ -"History" = "Historik"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "Insulintyp"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Pumpinställningar"; - -/* Button title recovering comms */ -"Recover Simulator" = "Återställ simulator"; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/tr.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/tr.lproj/Localizable.strings deleted file mode 100644 index d9a35369d..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/tr.lproj/Localizable.strings +++ /dev/null @@ -1,62 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Confirmation message for deleting a service */ -"Are you sure you want to delete this service?" = "Bu servisi silmek istediğinizden emin misiniz?"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Geri"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "İptal"; - -/* Title for CGM simulator settings */ -"CGM Settings" = "CGM Ayarları"; - -/* No comment provided by engineer. */ -"Clear Last Version Check Alert Date" = "Son Sürüm Kontrolü Uyarı Tarihini Temizle"; - -/* No comment provided by engineer. */ -"Comms Recovery" = "İletişim Kurtarma"; - -/* Button title to delete a service */ -"Delete Service" = "Servisi Sil"; - -/* The alert title for a resume error */ -"Error Resuming" = "Sürdürme Hatası"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Askıya Alma Hatası"; - -/* Caption for History - History Caption */ -"History" = "Geçmiş"; - -/* No comment provided by engineer. */ -"How should the simulator respond to a version check?" = "Simülatör bir sürüm kontrolüne nasıl yanıt vermelidir?"; - -/* Controller title for insulin type selection screen */ -"Insulin Type" = "İnsülin Tipi"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "Tamam"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Pompa Ayarları"; - -/* Button title recovering comms */ -"Recover Simulator" = "Simülatörü kurtar"; - -/* Caption for Source */ -"Source" = "Kaynak"; - -/* Recurring software update alert title */ -"Update Reminder" = "Güncelleme Hatırlatıcısı"; - -/* No comment provided by engineer. */ -"Version Check Response" = "Sürüm Kontrolü Yanıtı"; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/vi.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/vi.lproj/Localizable.strings deleted file mode 100644 index c6ac8ef3d..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/vi.lproj/Localizable.strings +++ /dev/null @@ -1,25 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Hủy bỏ"; - -/* Button title to delete a service */ -"Delete Service" = "Delete Service"; - -/* The alert title for a resume error */ -"Error Resuming" = "Lỗi khi đang tái thực hiện"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Lỗi khi đang tạm ngưng"; - -/* Button title to acknowledge error - Default acknowledgement */ -"OK" = "OK"; - -/* Title for Pump simulator settings */ -"Pump Settings" = "Cấu hình của bơm"; - diff --git a/Dependencies/LoopKit/MockKitUI/Resources/zh-Hans.lproj/Localizable.strings b/Dependencies/LoopKit/MockKitUI/Resources/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 989e94b57..000000000 --- a/Dependencies/LoopKit/MockKitUI/Resources/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,15 +0,0 @@ -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "取消"; - -/* The alert title for a resume error */ -"Error Resuming" = "恢复输注错误"; - -/* The alert title for a suspend error */ -"Error Suspending" = "无法暂停"; - diff --git a/Dependencies/LoopKit/MockKitUI/View Controllers/GlucoseTrendTableViewController.swift b/Dependencies/LoopKit/MockKitUI/View Controllers/GlucoseTrendTableViewController.swift deleted file mode 100644 index ab0334d6e..000000000 --- a/Dependencies/LoopKit/MockKitUI/View Controllers/GlucoseTrendTableViewController.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// GlucoseTrendTableViewController.swift -// LoopKitUI -// -// Created by Michael Pangburn on 12/17/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit -import LoopKitUI - - -protocol GlucoseTrendTableViewControllerDelegate: AnyObject { - func glucoseTrendTableViewControllerDidChangeTrend(_ controller: GlucoseTrendTableViewController) -} - -final class GlucoseTrendTableViewController: RadioSelectionTableViewController { - - var glucoseTrend: GlucoseTrend? { - get { - if let selectedIndex = selectedIndex { - return GlucoseTrend.allCases[selectedIndex] - } else { - return nil - } - } - set { - if let newValue = newValue { - selectedIndex = GlucoseTrend.allCases.firstIndex(of: newValue) - } else { - selectedIndex = nil - } - } - } - - weak var glucoseTrendDelegate: GlucoseTrendTableViewControllerDelegate? - - convenience init() { - self.init(style: .grouped) - options = GlucoseTrend.allCases.map { trend in - "\(trend.symbol) \(trend.localizedDescription)" - } - delegate = self - } -} - -extension GlucoseTrendTableViewController: RadioSelectionTableViewControllerDelegate { - func radioSelectionTableViewControllerDidChangeSelectedIndex(_ controller: RadioSelectionTableViewController) { - glucoseTrendDelegate?.glucoseTrendTableViewControllerDidChangeTrend(self) - } -} diff --git a/Dependencies/LoopKit/MockKitUI/View Controllers/IssueAlertTableViewController.swift b/Dependencies/LoopKit/MockKitUI/View Controllers/IssueAlertTableViewController.swift deleted file mode 100644 index 1fff4da34..000000000 --- a/Dependencies/LoopKit/MockKitUI/View Controllers/IssueAlertTableViewController.swift +++ /dev/null @@ -1,150 +0,0 @@ -// -// IssueAlertTableViewController.swift -// MockKitUI -// -// Created by Rick Pasetto on 4/24/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit -import LoopKitUI -import MockKit - -final class IssueAlertTableViewController: UITableViewController { - - let cgmManager: MockCGMManager - - static let delay = TimeInterval(60) - - private enum AlertRow: Int, CaseIterable, CustomStringConvertible { - case immediate = 0 - case delayed - case repeating - case issueLater - case buzz - case critical - case criticalDelayed - case retract // should be kept at the bottom of the list - - var description: String { - switch self { - case .immediate: return "Issue an immediate alert" - case .delayed: return "Issue a \"delayed \(delay) seconds\" alert" - case .repeating: return "Issue a \"repeating every \(delay) seconds\" alert" - case .issueLater: return "Issue an immediate alert \(delay) seconds from now" - case .retract: return "Retract any alert above" - case .buzz: return "Issue an immediate vibrate alert" - case .critical: return "Issue a critical immediate alert" - case .criticalDelayed: return "Issue a \"delayed \(delay) seconds\" critical alert" - } - } - - var trigger: Alert.Trigger { - switch self { - case .immediate: return .immediate - case .retract: return .immediate - case .critical: return .immediate - case .delayed: return .delayed(interval: delay) - case .criticalDelayed: return .delayed(interval: delay) - case .repeating: return .repeating(repeatInterval: delay) - case .issueLater: return .immediate - case .buzz: return .immediate - } - } - - var delayBeforeIssue: TimeInterval? { - switch self { - case .issueLater: return delay - default: return nil - } - } - - var identifier: Alert.AlertIdentifier { - switch self { - case .buzz: return MockCGMManager.buzz.identifier - case .critical, .criticalDelayed: return MockCGMManager.critical.identifier - default: return MockCGMManager.submarine.identifier - } - } - - var metadata: Alert.Metadata? { - switch self { - case .buzz: - return Alert.Metadata(dict: [ - "string": Alert.MetadataValue("Buzz"), - "int": Alert.MetadataValue(1), - "double": Alert.MetadataValue(2.34), - "bool": Alert.MetadataValue(true), - ]) - default: - return nil - } - } - } - - init(cgmManager: MockCGMManager) { - self.cgmManager = cgmManager - super.init(style: .plain) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - title = "Issue Alerts" - - tableView.rowHeight = UITableView.automaticDimension - tableView.estimatedRowHeight = 44 - - tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className) - - let button = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped(_:))) - navigationItem.setRightBarButton(button, animated: false) - } - - @objc func doneTapped(_ sender: Any) { - done() - } - - private func done() { - if let nav = navigationController as? SettingsNavigationViewController { - nav.notifyComplete() - } - } - - // MARK: - UITableViewDataSource - - override func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return AlertRow.allCases.count - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell - cell.textLabel?.text = String(describing: AlertRow(rawValue: indexPath.row)!) - cell.textLabel?.textAlignment = .center - cell.isEnabled = AlertRow(rawValue: indexPath.row)! == .retract && !cgmManager.hasRetractableAlert ? false : true - return cell - } - - // MARK: - UITableViewDelegate - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let row = AlertRow(rawValue: indexPath.row)! - switch row { - case .retract: - cgmManager.retractCurrentAlert() - default: - cgmManager.issueAlert(identifier: row.identifier, trigger: row.trigger, delay: row.delayBeforeIssue, metadata: row.metadata) - } - tableView.deselectRow(at: indexPath, animated: true) - tableView.reloadRows(at: [IndexPath(row: AlertRow.retract.rawValue, section: indexPath.section)], with: .automatic) - } -} diff --git a/Dependencies/LoopKit/MockKitUI/View Controllers/MeasurementFrequencyTableViewController.swift b/Dependencies/LoopKit/MockKitUI/View Controllers/MeasurementFrequencyTableViewController.swift deleted file mode 100644 index 0455c9c96..000000000 --- a/Dependencies/LoopKit/MockKitUI/View Controllers/MeasurementFrequencyTableViewController.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// MeasurementFrequencyTableViewController.swift -// MockKitUI -// -// Created by Nathaniel Hamming on 2020-06-22. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit -import LoopKitUI -import MockKit - -protocol MeasurementFrequencyTableViewControllerDelegate: AnyObject { - func measurementFrequencyTableViewControllerDidChangeFrequency(_ controller: MeasurementFrequencyTableViewController) -} - -final class MeasurementFrequencyTableViewController: RadioSelectionTableViewController { - - var measurementFrequency: MeasurementFrequency? { - get { - if let selectedIndex = selectedIndex { - return MeasurementFrequency.allCases[selectedIndex] - } else { - return nil - } - } - set { - if let newValue = newValue { - selectedIndex = MeasurementFrequency.allCases.firstIndex(of: newValue) - } else { - selectedIndex = nil - } - } - } - - weak var measurementFrequencyDelegate: MeasurementFrequencyTableViewControllerDelegate? - - convenience init() { - self.init(style: .grouped) - options = MeasurementFrequency.allCases.map { frequency in - "\(frequency.localizedDescription)" - } - delegate = self - } -} - -extension MeasurementFrequencyTableViewController: RadioSelectionTableViewControllerDelegate { - func radioSelectionTableViewControllerDidChangeSelectedIndex(_ controller: RadioSelectionTableViewController) { - measurementFrequencyDelegate?.measurementFrequencyTableViewControllerDidChangeFrequency(self) - } -} diff --git a/Dependencies/LoopKit/MockKitUI/View Controllers/MockCGMManagerSettingsViewController.swift b/Dependencies/LoopKit/MockKitUI/View Controllers/MockCGMManagerSettingsViewController.swift deleted file mode 100644 index a52ffedee..000000000 --- a/Dependencies/LoopKit/MockKitUI/View Controllers/MockCGMManagerSettingsViewController.swift +++ /dev/null @@ -1,801 +0,0 @@ -// -// MockCGMManagerSettingsViewController.swift -// LoopKitUI -// -// Created by Michael Pangburn on 11/23/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import Combine -import HealthKit -import LoopKit -import LoopKitUI -import MockKit - -final class MockCGMManagerSettingsViewController: UITableViewController { - let cgmManager: MockCGMManager - - private let displayGlucoseUnitObservable: DisplayGlucoseUnitObservable - - private lazy var cancellables = Set() - - private var glucoseUnit: HKUnit { - displayGlucoseUnitObservable.displayGlucoseUnit - } - - init(cgmManager: MockCGMManager, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable) { - self.cgmManager = cgmManager - self.displayGlucoseUnitObservable = displayGlucoseUnitObservable - - super.init(style: .grouped) - title = LocalizedString("CGM Settings", comment: "Title for CGM simulator settings") - - displayGlucoseUnitObservable.$displayGlucoseUnit - .sink { [weak self] _ in self?.tableView.reloadData() } - .store(in: &cancellables) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - tableView.rowHeight = UITableView.automaticDimension - tableView.estimatedRowHeight = 44 - - tableView.register(SettingsTableViewCell.self, forCellReuseIdentifier: SettingsTableViewCell.className) - tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className) - tableView.register(BoundSwitchTableViewCell.self, forCellReuseIdentifier: BoundSwitchTableViewCell.className) - - let button = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped(_:))) - self.navigationItem.setRightBarButton(button, animated: false) - } - - @objc func doneTapped(_ sender: Any) { - done() - } - - private func done() { - if let nav = navigationController as? SettingsNavigationViewController { - nav.notifyComplete() - } - } - - // MARK: - Data Source - - private enum Section: Int, CaseIterable { - case model = 0 - case glucoseThresholds - case effects - case cgmStatus - case history - case alerts - case lifecycleProgress - case healthKit - case uploading - case deleteCGM - } - - private enum ModelRow: Int, CaseIterable { - case constant = 0 - case sineCurve - case noData - case signalLoss - case unreliableData - case frequency - } - - private enum GlucoseThresholds: Int, CaseIterable { - case enableAlerting - case cgmLowerLimit - case urgentLowGlucoseThreshold - case lowGlucoseThreshold - case highGlucoseThreshold - case cgmUpperLimit - } - - private enum EffectsRow: Int, CaseIterable { - case noise = 0 - case lowOutlier - case highOutlier - case error - } - - private enum CGMStatusRow: Int, CaseIterable { - case batteryRemaining = 0 - case requestCalibration - } - - private enum HistoryRow: Int, CaseIterable { - case trend = 0 - case backfill - } - - private enum AlertsRow: Int, CaseIterable { - case issueAlert = 0 - } - - private enum LifecycleProgressRow: Int, CaseIterable { - case percentComplete - case warningThreshold - case criticalThreshold - } - - private enum HealthKitRow: Int, CaseIterable { - case healthKitStorageDelayEnabled = 0 - } - - private enum UploadingRow: Int, CaseIterable { - case uploadEnabled = 0 - } - - // MARK: - UITableViewDataSource - - override func numberOfSections(in tableView: UITableView) -> Int { - return Section.allCases.count - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch Section(rawValue: section)! { - case .model: - return ModelRow.allCases.count - case .glucoseThresholds: - return GlucoseThresholds.allCases.count - case .effects: - return EffectsRow.allCases.count - case .cgmStatus: - return CGMStatusRow.allCases.count - case .history: - return HistoryRow.allCases.count - case .alerts: - return AlertsRow.allCases.count - case .lifecycleProgress: - return LifecycleProgressRow.allCases.count - case .healthKit: - return HealthKitRow.allCases.count - case .uploading: - return UploadingRow.allCases.count - case .deleteCGM: - return 1 - } - } - - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - switch Section(rawValue: section)! { - case .model: - return "Model" - case .glucoseThresholds: - return "Glucose Thresholds" - case .effects: - return "Effects" - case .cgmStatus: - return "CGM Status" - case .history: - return "History" - case .alerts: - return "Alerts" - case .lifecycleProgress: - return "Lifecycle Progress" - case .healthKit: - return "HealthKit" - case .uploading: - return "Uploading" - case .deleteCGM: - return " " // Use an empty string for more dramatic spacing - } - } - - override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - switch Section(rawValue: section) { - case .healthKit: - return "Amount of time to wait before storing CGM samples to HealthKit. If enabled, the delay is \(cgmManager.fixedHealthKitStorageDelay.minutes) minutes. NOTE: after changing this, you will need to delete and re-add the CGM simulator!" - default: - return nil - } - } - - private lazy var quantityFormatter = QuantityFormatter() - - private lazy var percentageFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.minimumIntegerDigits = 1 - formatter.maximumFractionDigits = 1 - return formatter - }() - - private lazy var durationFormatter: DateComponentsFormatter = { - let durationFormatter = DateComponentsFormatter() - durationFormatter.allowedUnits = [.hour, .minute] - durationFormatter.unitsStyle = .full - return durationFormatter - }() - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch Section(rawValue: indexPath.section)! { - case .model: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - switch ModelRow(rawValue: indexPath.row)! { - case .constant: - cell.textLabel?.text = "Constant" - if case .constant(let glucose) = cgmManager.dataSource.model { - cell.detailTextLabel?.text = quantityFormatter.string(from: glucose, for: glucoseUnit) - cell.accessoryType = .checkmark - } else { - cell.accessoryType = .disclosureIndicator - } - case .sineCurve: - cell.textLabel?.text = "Sine Curve" - if case .sineCurve(parameters: (baseGlucose: let baseGlucose, amplitude: let amplitude, period: _, referenceDate: _)) = cgmManager.dataSource.model { - if let baseGlucoseText = quantityFormatter.numberFormatter.string(from: baseGlucose.doubleValue(for: glucoseUnit)), - let amplitudeText = quantityFormatter.string(from: amplitude, for: glucoseUnit) { - cell.detailTextLabel?.text = "\(baseGlucoseText) ± \(amplitudeText)" - } - cell.accessoryType = .checkmark - } else { - cell.accessoryType = .disclosureIndicator - } - case .noData: - cell.textLabel?.text = "No Data" - if case .noData = cgmManager.dataSource.model { - cell.accessoryType = .checkmark - } - case .signalLoss: - cell.textLabel?.text = "Signal Loss" - if case .signalLoss = cgmManager.dataSource.model { - cell.accessoryType = .checkmark - } - case .unreliableData: - cell.textLabel?.text = "Unreliable Data" - if case .unreliableData = cgmManager.dataSource.model { - cell.accessoryType = .checkmark - } - case .frequency: - cell.textLabel?.text = "Measurement Frequency" - cell.detailTextLabel?.text = cgmManager.dataSource.dataPointFrequency.localizedDescription - cell.accessoryType = .disclosureIndicator - } - return cell - case .glucoseThresholds: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - switch GlucoseThresholds(rawValue: indexPath.row)! { - case .enableAlerting: - let cell = tableView.dequeueReusableCell(withIdentifier: BoundSwitchTableViewCell.className, for: indexPath) as! BoundSwitchTableViewCell - cell.textLabel?.text = "Glucose Value Alerting" - cell.switch?.isOn = cgmManager.mockSensorState.glucoseAlertingEnabled - cell.onToggle = { [weak self] isOn in - self?.cgmManager.mockSensorState.glucoseAlertingEnabled = isOn - } - cell.selectionStyle = .none - return cell - case .cgmLowerLimit: - cell.textLabel?.text = "CGM Lower Limit" - cell.detailTextLabel?.text = quantityFormatter.string(from: cgmManager.mockSensorState.cgmLowerLimit, for: glucoseUnit) - case .urgentLowGlucoseThreshold: - cell.textLabel?.text = "Urgent Low Glucose Threshold" - cell.detailTextLabel?.text = quantityFormatter.string(from: cgmManager.mockSensorState.urgentLowGlucoseThreshold, for: glucoseUnit) - case .lowGlucoseThreshold: - cell.textLabel?.text = "Low Glucose Threshold" - cell.detailTextLabel?.text = quantityFormatter.string(from: cgmManager.mockSensorState.lowGlucoseThreshold, for: glucoseUnit) - case .highGlucoseThreshold: - cell.textLabel?.text = "High Glucose Threshold" - cell.detailTextLabel?.text = quantityFormatter.string(from: cgmManager.mockSensorState.highGlucoseThreshold, for: glucoseUnit) - case .cgmUpperLimit: - cell.textLabel?.text = "CGM Upper Limit" - cell.detailTextLabel?.text = quantityFormatter.string(from: cgmManager.mockSensorState.cgmUpperLimit, for: glucoseUnit) - } - cell.accessoryType = .disclosureIndicator - return cell - case .effects: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - switch EffectsRow(rawValue: indexPath.row)! { - case .noise: - cell.textLabel?.text = "Glucose Noise" - if let maximumDeltaMagnitude = cgmManager.dataSource.effects.glucoseNoise { - cell.detailTextLabel?.text = quantityFormatter.string(from: maximumDeltaMagnitude, for: glucoseUnit) - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - case .lowOutlier: - cell.textLabel?.text = "Random Low Outlier" - if let chance = cgmManager.dataSource.effects.randomLowOutlier?.chance, - let percentageString = percentageFormatter.string(from: chance * 100) - { - cell.detailTextLabel?.text = "\(percentageString)% chance" - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - case .highOutlier: - cell.textLabel?.text = "Random High Outlier" - if let chance = cgmManager.dataSource.effects.randomHighOutlier?.chance, - let percentageString = percentageFormatter.string(from: chance * 100) - { - cell.detailTextLabel?.text = "\(percentageString)% chance" - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - case .error: - cell.textLabel?.text = "Random Error" - if let chance = cgmManager.dataSource.effects.randomErrorChance, - let percentageString = percentageFormatter.string(from: chance * 100) - { - cell.detailTextLabel?.text = "\(percentageString)% chance" - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - } - - cell.accessoryType = .disclosureIndicator - return cell - case .cgmStatus: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - switch CGMStatusRow(rawValue: indexPath.row)! { - case .batteryRemaining: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - cell.textLabel?.text = "Battery Remaining" - if let remainingCharge = cgmManager.cgmBatteryChargeRemaining { - cell.detailTextLabel?.text = "\(Int(round(remainingCharge * 100)))%" - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - cell.accessoryType = .disclosureIndicator - return cell - case .requestCalibration: - cell.textLabel?.text = "Request Calibration" - if cgmManager.isCalibrationRequested { - cell.accessoryType = .checkmark - } - } - return cell - case .history: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - switch HistoryRow(rawValue: indexPath.row)! { - case .trend: - cell.textLabel?.text = "Trend" - cell.detailTextLabel?.text = cgmManager.mockSensorState.trendType?.symbol - case .backfill: - cell.textLabel?.text = "Backfill Glucose" - } - cell.accessoryType = .disclosureIndicator - return cell - case .alerts: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - switch AlertsRow(rawValue: indexPath.row)! { - case .issueAlert: - cell.textLabel?.text = "Issue Alerts" - cell.accessoryType = .disclosureIndicator - } - return cell - case .lifecycleProgress: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - switch LifecycleProgressRow(rawValue: indexPath.row)! { - case .percentComplete: - cell.textLabel?.text = "Percent Completed" - if let percentCompleted = cgmManager.mockSensorState.cgmLifecycleProgress?.percentComplete { - cell.detailTextLabel?.text = "\(Int(round(percentCompleted * 100)))%" - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - case .warningThreshold: - cell.textLabel?.text = "Warning Threshold" - if let warningThreshold = cgmManager.mockSensorState.progressWarningThresholdPercentValue { - cell.detailTextLabel?.text = "\(Int(round(warningThreshold * 100)))%" - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - case .criticalThreshold: - cell.textLabel?.text = "Critical Threshold" - if let criticalThreshold = cgmManager.mockSensorState.progressCriticalThresholdPercentValue { - cell.detailTextLabel?.text = "\(Int(round(criticalThreshold * 100)))%" - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - } - cell.accessoryType = .disclosureIndicator - return cell - case .healthKit: - switch HealthKitRow(rawValue: indexPath.row)! { - case .healthKitStorageDelayEnabled: - let cell = tableView.dequeueReusableCell(withIdentifier: BoundSwitchTableViewCell.className, for: indexPath) as! BoundSwitchTableViewCell - cell.textLabel?.text = "Storage Delay" - cell.switch?.isOn = cgmManager.healthKitStorageDelayEnabled - cell.onToggle = { [weak self] isOn in - let confirmVC = UIAlertController(cgmDeletionHandler: { - self?.cgmManager.healthKitStorageDelayEnabled = isOn - self?.cgmManager.notifyDelegateOfDeletion { - DispatchQueue.main.async { - self?.done() - } - } - }, cancelHandler: { cell.switch?.isOn = self?.cgmManager.healthKitStorageDelayEnabled ?? false }) - - self?.present(confirmVC, animated: true) { - tableView.deselectRow(at: indexPath, animated: true) - } - } - cell.selectionStyle = .none - return cell - } - case .uploading: - switch UploadingRow(rawValue: indexPath.row)! { - case .uploadEnabled: - let cell = tableView.dequeueReusableCell(withIdentifier: BoundSwitchTableViewCell.className, for: indexPath) as! BoundSwitchTableViewCell - cell.textLabel?.text = "Upload CGM Samples" - cell.switch?.isOn = cgmManager.mockSensorState.samplesShouldBeUploaded - cell.onToggle = { [weak self] isOn in - self?.cgmManager.mockSensorState.samplesShouldBeUploaded = isOn - } - cell.selectionStyle = .none - return cell - } - case .deleteCGM: - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell - cell.textLabel?.text = "Delete CGM" - cell.textLabel?.textAlignment = .center - cell.tintColor = .delete - cell.isEnabled = true - return cell - } - } - - // MARK: - UITableViewDelegate - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let sender = tableView.cellForRow(at: indexPath) - - switch Section(rawValue: indexPath.section)! { - case .model: - switch ModelRow(rawValue: indexPath.row)! { - case .constant: - let vc = GlucoseEntryTableViewController(glucoseUnit: glucoseUnit) - vc.title = "Constant" - vc.indexPath = indexPath - vc.contextHelp = "A constant glucose model returns a fixed glucose value regardless of context." - vc.glucoseEntryDelegate = self - show(vc, sender: sender) - case .sineCurve: - let vc = SineCurveParametersTableViewController(glucoseUnit: glucoseUnit) - if case .sineCurve(parameters: let parameters) = cgmManager.dataSource.model { - vc.parameters = parameters - } else { - vc.parameters = nil - } - vc.contextHelp = "The sine curve parameters describe a mathematical model for glucose value production." - vc.delegate = self - show(vc, sender: sender) - case .noData: - cgmManager.dataSource.model = .noData - cgmManager.retractSignalLossAlert() - tableView.reloadRows(at: indexPaths(forSection: .model, rows: ModelRow.self), with: .automatic) - case .signalLoss: - cgmManager.dataSource.model = .signalLoss - cgmManager.issueSignalLossAlert() - tableView.reloadRows(at: indexPaths(forSection: .model, rows: ModelRow.self), with: .automatic) - case .unreliableData: - cgmManager.dataSource.model = .unreliableData - tableView.reloadRows(at: indexPaths(forSection: .model, rows: ModelRow.self), with: .automatic) - case .frequency: - let vc = MeasurementFrequencyTableViewController() - vc.measurementFrequency = cgmManager.dataSource.dataPointFrequency - vc.title = "Measurement Frequency" - vc.measurementFrequencyDelegate = self - show(vc, sender: sender) - } - case .glucoseThresholds: - let vc = GlucoseEntryTableViewController(glucoseUnit: glucoseUnit) - vc.indexPath = indexPath - vc.glucoseEntryDelegate = self - switch GlucoseThresholds(rawValue: indexPath.row)! { - case .enableAlerting: - return - case .cgmLowerLimit: - vc.title = "CGM Lower Limit" - vc.contextHelp = "The glucose value that marks the lower limit of the CGM. Any value at or below this value is presented at `LOW`. This value must be lower than the urgent low threshold. If not, it will be set to 1 below the urgent low glucose threshold." - case .urgentLowGlucoseThreshold: - vc.title = "Urgent Low Glucose Threshold" - vc.contextHelp = "The glucose value that marks the urgent low glucose threshold. Any value at or below this value is considered urgent low. This value must be above the cgm lower limit and lower than the low threshold. If not, it will be set to a value above the lower limit and below the low glucose threshold." - case .lowGlucoseThreshold: - vc.title = "Low Glucose Threshold" - vc.contextHelp = "The glucose value that marks the low glucose threshold. Any value at or below this value is considered low. This value must be above the urgent low threshold and lower than the high threshold. If not, it will be set to a value above the urgent lower limit and below the high glucose threshold." - case .highGlucoseThreshold: - vc.title = "High Glucose Threshold" - vc.contextHelp = "The glucose value that marks the high glucose threshold. Any value at or above this value is considered high. This value must be above the low threshold and lower than the cgm upper limit. If not, it will be set to a value above the low glucose threshold and below the upper limit." - case .cgmUpperLimit: - vc.title = "CGM Upper Limit" - vc.contextHelp = "The glucose value that marks the upper limit of the CGM. Any value at or above this value is presented at `HIGH`. This value must be above the high threshold. If not, it will be set to 1 above the high glucose threshold." - } - show(vc, sender: sender) - case .effects: - switch EffectsRow(rawValue: indexPath.row)! { - case .noise: - let vc = GlucoseEntryTableViewController(glucoseUnit: glucoseUnit) - if let maximumDeltaMagnitude = cgmManager.dataSource.effects.glucoseNoise { - vc.glucose = maximumDeltaMagnitude - } - vc.title = "Glucose Noise" - vc.contextHelp = "The magnitude of glucose noise applied to CGM values determines the maximum random amount of variation applied to each glucose value." - vc.indexPath = indexPath - vc.glucoseEntryDelegate = self - show(vc, sender: sender) - case .lowOutlier: - let vc = RandomOutlierTableViewController(glucoseUnit: glucoseUnit) - vc.title = "Low Outlier" - vc.randomOutlier = cgmManager.dataSource.effects.randomLowOutlier - vc.contextHelp = "Produced glucose values will have a chance of being decreased by the delta quantity." - vc.indexPath = indexPath - vc.delegate = self - show(vc, sender: sender) - case .highOutlier: - let vc = RandomOutlierTableViewController(glucoseUnit: glucoseUnit) - vc.title = "High Outlier" - vc.randomOutlier = cgmManager.dataSource.effects.randomHighOutlier - vc.contextHelp = "Produced glucose values will have a chance of being increased by the delta quantity." - vc.indexPath = indexPath - vc.delegate = self - show(vc, sender: sender) - case .error: - let vc = PercentageTextFieldTableViewController() - if let chance = cgmManager.dataSource.effects.randomErrorChance { - vc.percentage = chance - } - vc.title = "Random Error" - vc.contextHelp = "The percentage determines the chance with which the CGM will error when a glucose value is requested." - vc.indexPath = indexPath - vc.percentageDelegate = self - show(vc, sender: sender) - } - case .cgmStatus: - switch CGMStatusRow(rawValue: indexPath.row)! { - case .batteryRemaining: - let vc = PercentageTextFieldTableViewController() - vc.percentage = cgmManager.cgmBatteryChargeRemaining - vc.indexPath = indexPath - vc.percentageDelegate = self - show(vc, sender: sender) - case .requestCalibration: - cgmManager.requestCalibration(!cgmManager.isCalibrationRequested) - tableView.reloadRows(at: [indexPath], with: .automatic) - } - case .history: - switch HistoryRow(rawValue: indexPath.row)! { - case .trend: - let vc = GlucoseTrendTableViewController() - vc.glucoseTrend = cgmManager.mockSensorState.trendType - vc.title = "Glucose Trend" - vc.glucoseTrendDelegate = self - show(vc, sender: sender) - case .backfill: - let vc = DateAndDurationTableViewController() - vc.inputMode = .duration(.hours(3)) - vc.title = "Backfill" - vc.contextHelp = "Performing a backfill will not delete existing prior glucose values." - vc.indexPath = indexPath - vc.onSave { inputMode in - guard case .duration(let duration) = inputMode else { - assertionFailure() - return - } - self.cgmManager.backfillData(datingBack: duration) - } - show(vc, sender: sender) - } - case .alerts: - switch AlertsRow(rawValue: indexPath.row)! { - case .issueAlert: - let vc = IssueAlertTableViewController(cgmManager: cgmManager) - show(vc, sender: sender) - } - case .lifecycleProgress: - let vc = PercentageTextFieldTableViewController() - vc.indexPath = indexPath - vc.percentageDelegate = self - switch LifecycleProgressRow(rawValue: indexPath.row)! { - case .percentComplete: - vc.percentage = cgmManager.mockSensorState.cgmLifecycleProgress?.percentComplete - case .warningThreshold: - vc.percentage = cgmManager.mockSensorState.progressWarningThresholdPercentValue - case .criticalThreshold: - vc.percentage = cgmManager.mockSensorState.progressCriticalThresholdPercentValue - } - show(vc, sender: sender) - case .healthKit: - return - case .uploading: - return - case .deleteCGM: - let confirmVC = UIAlertController(cgmDeletionHandler: { - self.cgmManager.notifyDelegateOfDeletion { - DispatchQueue.main.async { - self.done() - } - } - }) - - present(confirmVC, animated: true) { - tableView.deselectRow(at: indexPath, animated: true) - } - } - } - - private func indexPaths( - forSection section: Section, - rows _: Row.Type - ) -> [IndexPath] where Row.RawValue == Int { - let rows = Row.allCases - return zip(rows, repeatElement(section, count: rows.count)).map { row, section in - return IndexPath(row: row.rawValue, section: section.rawValue) - } - } -} - -extension MockCGMManagerSettingsViewController: GlucoseEntryTableViewControllerDelegate { - func glucoseEntryTableViewControllerDidChangeGlucose(_ controller: GlucoseEntryTableViewController) { - guard let indexPath = controller.indexPath else { - assertionFailure() - return - } - - tableView.deselectRow(at: indexPath, animated: true) - - switch Section(rawValue: indexPath.section)! { - case .model: - switch ModelRow(rawValue: indexPath.row)! { - case .constant: - if let glucose = controller.glucose { - cgmManager.dataSource.model = .constant(glucose) - cgmManager.retractSignalLossAlert() - tableView.reloadRows(at: indexPaths(forSection: .model, rows: ModelRow.self), with: .automatic) - } - default: - assertionFailure() - } - case .effects: - switch EffectsRow(rawValue: indexPath.row) { - case .noise: - if let glucose = controller.glucose { - cgmManager.dataSource.effects.glucoseNoise = glucose - } - default: - assertionFailure() - } - case .glucoseThresholds: - if let glucose = controller.glucose { - switch GlucoseThresholds(rawValue: indexPath.row)! { - case .cgmLowerLimit: - cgmManager.mockSensorState.cgmLowerLimit = glucose - case .urgentLowGlucoseThreshold: - cgmManager.mockSensorState.urgentLowGlucoseThreshold = glucose - case .lowGlucoseThreshold: - cgmManager.mockSensorState.lowGlucoseThreshold = glucose - case .highGlucoseThreshold: - cgmManager.mockSensorState.highGlucoseThreshold = glucose - case .cgmUpperLimit: - cgmManager.mockSensorState.cgmUpperLimit = glucose - default: - assertionFailure() - } - } - default: - assertionFailure() - } - tableView.reloadRows(at: [indexPath], with: .automatic) - } -} - -extension MockCGMManagerSettingsViewController: SineCurveParametersTableViewControllerDelegate { - func sineCurveParametersTableViewControllerDidUpdateParameters(_ controller: SineCurveParametersTableViewController) { - if let parameters = controller.parameters { - cgmManager.dataSource.model = .sineCurve(parameters: parameters) - cgmManager.retractSignalLossAlert() - tableView.reloadRows(at: indexPaths(forSection: .model, rows: ModelRow.self), with: .automatic) - } - } -} - -extension MockCGMManagerSettingsViewController: RandomOutlierTableViewControllerDelegate { - func randomOutlierTableViewControllerDidChangeOutlier(_ controller: RandomOutlierTableViewController) { - guard let indexPath = controller.indexPath else { - assertionFailure() - return - } - - switch Section(rawValue: indexPath.section)! { - case .effects: - switch EffectsRow(rawValue: indexPath.row)! { - case .lowOutlier: - cgmManager.dataSource.effects.randomLowOutlier = controller.randomOutlier - case .highOutlier: - cgmManager.dataSource.effects.randomHighOutlier = controller.randomOutlier - default: - assertionFailure() - } - default: - assertionFailure() - } - tableView.reloadRows(at: [indexPath], with: .automatic) - } -} - -extension MockCGMManagerSettingsViewController: PercentageTextFieldTableViewControllerDelegate { - func percentageTextFieldTableViewControllerDidChangePercentage(_ controller: PercentageTextFieldTableViewController) { - guard let indexPath = controller.indexPath else { - assertionFailure() - return - } - - switch Section(rawValue: indexPath.section)! { - case .effects: - switch EffectsRow(rawValue: indexPath.row)! { - case .error: - cgmManager.dataSource.effects.randomErrorChance = controller.percentage?.clamped(to: 0...1) - default: - assertionFailure() - } - case .cgmStatus: - switch CGMStatusRow(rawValue: indexPath.row)! { - case .batteryRemaining: - if let batteryRemaining = controller.percentage.map({ $0.clamped(to: 0...1) }) { - cgmManager.cgmBatteryChargeRemaining = batteryRemaining - } - default: - assertionFailure() - } - case .lifecycleProgress: - switch LifecycleProgressRow(rawValue: indexPath.row)! { - case .percentComplete: - if let percentComplete = controller.percentage.map({ $0.clamped(to: 0...1) }) { - cgmManager.mockSensorState.cgmLifecycleProgress = MockCGMLifecycleProgress(percentComplete: percentComplete) - } else { - cgmManager.mockSensorState.cgmLifecycleProgress = nil - } - case .warningThreshold: - cgmManager.mockSensorState.progressWarningThresholdPercentValue = controller.percentage.map { $0.clamped(to: 0...1) } - case .criticalThreshold: - cgmManager.mockSensorState.progressCriticalThresholdPercentValue = controller.percentage.map { $0.clamped(to: 0...1) } - } - default: - assertionFailure() - } - tableView.reloadRows(at: [indexPath], with: .automatic) - } -} - -extension MockCGMManagerSettingsViewController: GlucoseTrendTableViewControllerDelegate { - func glucoseTrendTableViewControllerDidChangeTrend(_ controller: GlucoseTrendTableViewController) { - cgmManager.mockSensorState.trendType = controller.glucoseTrend - tableView.reloadRows(at: [[Section.history.rawValue, HistoryRow.trend.rawValue]], with: .automatic) - } -} - -extension MockCGMManagerSettingsViewController: MeasurementFrequencyTableViewControllerDelegate { - func measurementFrequencyTableViewControllerDidChangeFrequency(_ controller: MeasurementFrequencyTableViewController) { - if let measurementFrequency = controller.measurementFrequency { - cgmManager.dataSource.dataPointFrequency = measurementFrequency - cgmManager.updateGlucoseUpdateTimer() - tableView.reloadRows(at: [[Section.model.rawValue, ModelRow.frequency.rawValue]], with: .automatic) - } - } -} - -private extension UIAlertController { - convenience init(cgmDeletionHandler confirmHandler: @escaping () -> Void, cancelHandler: (() -> Void)? = nil) { - self.init( - title: nil, - message: "Are you sure you want to delete this CGM?", - preferredStyle: .actionSheet - ) - - addAction(UIAlertAction( - title: "Delete CGM", - style: .destructive, - handler: { _ in - confirmHandler() - } - )) - - let cancel = "Cancel" - addAction(UIAlertAction(title: cancel, style: .cancel, handler: { _ in cancelHandler?() })) - } -} diff --git a/Dependencies/LoopKit/MockKitUI/View Controllers/MockPumpManagerSettingsViewController.swift b/Dependencies/LoopKit/MockKitUI/View Controllers/MockPumpManagerSettingsViewController.swift deleted file mode 100644 index 9f99cc869..000000000 --- a/Dependencies/LoopKit/MockKitUI/View Controllers/MockPumpManagerSettingsViewController.swift +++ /dev/null @@ -1,626 +0,0 @@ -// -// MockPumpManagerSettingsViewController.swift -// LoopKitUI -// -// Created by Michael Pangburn on 11/20/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import HealthKit -import LoopKit -import LoopKitUI -import MockKit -import SwiftUI - - -final class MockPumpManagerSettingsViewController: UITableViewController { - - let pumpManager: MockPumpManager - let supportedInsulinTypes: [InsulinType] - - init(pumpManager: MockPumpManager, supportedInsulinTypes: [InsulinType]) { - self.pumpManager = pumpManager - self.supportedInsulinTypes = supportedInsulinTypes - super.init(style: .grouped) - title = LocalizedString("Pump Settings", comment: "Title for Pump simulator settings") - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private let quantityFormatter = QuantityFormatter() - - override func viewDidLoad() { - super.viewDidLoad() - - tableView.rowHeight = UITableView.automaticDimension - tableView.estimatedRowHeight = 44 - - tableView.sectionHeaderHeight = UITableView.automaticDimension - tableView.estimatedSectionHeaderHeight = 55 - - tableView.register(DateAndDurationTableViewCell.nib(), forCellReuseIdentifier: DateAndDurationTableViewCell.className) - tableView.register(SegmentedControlTableViewCell.self, forCellReuseIdentifier: SegmentedControlTableViewCell.className) - tableView.register(SettingsTableViewCell.self, forCellReuseIdentifier: SettingsTableViewCell.className) - tableView.register(BoundSwitchTableViewCell.self, forCellReuseIdentifier: BoundSwitchTableViewCell.className) - tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className) - tableView.register(SuspendResumeTableViewCell.self, forCellReuseIdentifier: SuspendResumeTableViewCell.className) - - pumpManager.addStatusObserver(self, queue: .main) - - let button = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped(_:))) - self.navigationItem.setRightBarButton(button, animated: false) - } - - @objc func doneTapped(_ sender: Any) { - done() - } - - private func done() { - if let nav = navigationController as? SettingsNavigationViewController { - nav.notifyComplete() - } - } - - // MARK: - Data Source - - private enum Section: Int, CaseIterable { - case basalRate = 0 - case actions - case settings - case statusProgress - case deletePump - } - - private enum ActionRow: Int, CaseIterable { - case suspendResume = 0 - case occlusion - case pumpError - } - - private enum SettingsRow: Int, CaseIterable { - case deliverableIncrements = 0 - case supportedBasalRates - case supportedBolusVolumes - case insulinType - case reservoirRemaining - case batteryRemaining - case tempBasalErrorToggle - case bolusErrorToggle - case bolusCancelErrorToggle - case suspendErrorToggle - case resumeErrorToggle - case uncertainDeliveryErrorToggle - case lastReconciliationDate - } - - private enum StatusProgressRow: Int, CaseIterable { - case percentComplete - case warningThreshold - case criticalThreshold - } - - // MARK: UITableViewDataSource - - override func numberOfSections(in tableView: UITableView) -> Int { - return Section.allCases.count - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch Section(rawValue: section)! { - case .basalRate: - return 1 - case .actions: - return ActionRow.allCases.count - case .settings: - return SettingsRow.allCases.count - case .statusProgress: - return StatusProgressRow.allCases.count - case .deletePump: - return 1 - } - } - - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - switch Section(rawValue: section)! { - case .basalRate: - return nil - case .actions: - return nil - case .settings: - return "Configuration" - case .statusProgress: - return "Status Progress" - case .deletePump: - return " " // Use an empty string for more dramatic spacing - } - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch Section(rawValue: indexPath.section)! { - case .basalRate: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - cell.textLabel?.text = "Current Basal Rate" - if let currentBasalRate = pumpManager.currentBasalRate { - cell.detailTextLabel?.text = quantityFormatter.string(from: currentBasalRate, for: HKUnit.internationalUnit().unitDivided(by: .hour())) - } else { - cell.detailTextLabel?.text = "—" - } - cell.isUserInteractionEnabled = false - return cell - case .actions: - switch ActionRow(rawValue: indexPath.row)! { - case .suspendResume: - let cell = tableView.dequeueReusableCell(withIdentifier: SuspendResumeTableViewCell.className, for: indexPath) as! SuspendResumeTableViewCell - cell.basalDeliveryState = pumpManager.status.basalDeliveryState - return cell - case .occlusion: - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell - if pumpManager.state.occlusionDetected { - cell.textLabel?.text = "Resolve Occlusion" - } else { - cell.textLabel?.text = "Detect Occlusion" - } - return cell - case .pumpError: - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell - if pumpManager.state.pumpErrorDetected { - cell.textLabel?.text = "Resolve Pump Error" - } else { - cell.textLabel?.text = "Cause Pump Error" - } - return cell - } - case .settings: - switch SettingsRow(rawValue: indexPath.row)! { - case .deliverableIncrements: - let cell = tableView.dequeueReusableCell(withIdentifier: SegmentedControlTableViewCell.className, for: indexPath) as! SegmentedControlTableViewCell - let possibleDeliverableIncrements = MockPumpManagerState.DeliverableIncrements.allCases - cell.textLabel?.text = "Increments" - cell.options = possibleDeliverableIncrements.map { increments in - switch increments { - case .omnipod: - return "Pod" - case .medtronicX22: - return "x22" - case .medtronicX23: - return "x23" - case .custom: - return "Custom" - } - } - cell.segmentedControl.selectedSegmentIndex = possibleDeliverableIncrements.firstIndex(of: pumpManager.state.deliverableIncrements)! - cell.onSelection { [pumpManager] index in - pumpManager.state.deliverableIncrements = possibleDeliverableIncrements[index] - tableView.reloadRows(at: [IndexPath(row: SettingsRow.supportedBasalRates.rawValue, section: Section.settings.rawValue), IndexPath(row: SettingsRow.supportedBolusVolumes.rawValue, section: Section.settings.rawValue)], with: .automatic) - } - return cell - case .supportedBasalRates: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - cell.textLabel?.text = "Basal Rates" - cell.detailTextLabel?.text = pumpManager.state.supportedBasalRatesDescription - if pumpManager.state.deliverableIncrements == .custom { - cell.accessoryType = .disclosureIndicator - } - return cell - case .supportedBolusVolumes: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - cell.textLabel?.text = "Bolus Volumes" - cell.detailTextLabel?.text = pumpManager.state.supportedBolusVolumesDescription - if pumpManager.state.deliverableIncrements == .custom { - cell.accessoryType = .disclosureIndicator - } - return cell - case .insulinType: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - cell.prepareForReuse() - cell.textLabel?.text = "Insulin Type" - cell.detailTextLabel?.text = pumpManager.state.insulinType?.brandName ?? "Unset" - cell.accessoryType = .disclosureIndicator - return cell - case .reservoirRemaining: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - cell.textLabel?.text = "Reservoir Remaining" - cell.detailTextLabel?.text = quantityFormatter.string(from: HKQuantity(unit: .internationalUnit(), doubleValue: pumpManager.state.reservoirUnitsRemaining), for: .internationalUnit()) - cell.accessoryType = .disclosureIndicator - return cell - case .batteryRemaining: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - cell.textLabel?.text = "Battery Remaining" - if let remainingCharge = pumpManager.status.pumpBatteryChargeRemaining { - cell.detailTextLabel?.text = "\(Int(round(remainingCharge * 100)))%" - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - cell.accessoryType = .disclosureIndicator - return cell - case .tempBasalErrorToggle: - return switchTableViewCell(for: indexPath, titled: "Error on Temp Basal", boundTo: \.tempBasalEnactmentShouldError) - case .bolusErrorToggle: - return switchTableViewCell(for: indexPath, titled: "Error on Bolus", boundTo: \.bolusEnactmentShouldError) - case .bolusCancelErrorToggle: - return switchTableViewCell(for: indexPath, titled: "Error on Cancel Bolus", boundTo: \.bolusCancelShouldError) - case .suspendErrorToggle: - return switchTableViewCell(for: indexPath, titled: "Error on Suspend", boundTo: \.deliverySuspensionShouldError) - case .resumeErrorToggle: - return switchTableViewCell(for: indexPath, titled: "Error on Resume", boundTo: \.deliveryResumptionShouldError) - case .uncertainDeliveryErrorToggle: - return switchTableViewCell(for: indexPath, titled: "Next Delivery Command Uncertain", boundTo: \.deliveryCommandsShouldTriggerUncertainDelivery) - case .lastReconciliationDate: - let cell = tableView.dequeueReusableCell(withIdentifier: DateAndDurationTableViewCell.className, for: indexPath) as! DateAndDurationTableViewCell - cell.titleLabel.text = "Last Reconciliation Date" - cell.date = pumpManager.lastSync ?? Date() - cell.datePicker.maximumDate = Date() - cell.datePicker.minimumDate = Date() - .hours(48) - cell.datePicker.datePickerMode = .dateAndTime - #if swift(>=5.2) - if #available(iOS 14.0, *) { - cell.datePicker.preferredDatePickerStyle = .wheels - } - #endif - cell.datePicker.isEnabled = true - cell.delegate = self - return cell - } - case .statusProgress: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) - switch StatusProgressRow(rawValue: indexPath.row)! { - case .percentComplete: - cell.textLabel?.text = "Percent Completed" - if let percentCompleted = pumpManager.state.progressPercentComplete { - cell.detailTextLabel?.text = "\(Int(round(percentCompleted * 100)))%" - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - case .warningThreshold: - cell.textLabel?.text = "Warning Threshold" - if let warningThreshold = pumpManager.state.progressWarningThresholdPercentValue { - cell.detailTextLabel?.text = "\(Int(round(warningThreshold * 100)))%" - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - case .criticalThreshold: - cell.textLabel?.text = "Critical Threshold" - if let criticalThreshold = pumpManager.state.progressCriticalThresholdPercentValue { - cell.detailTextLabel?.text = "\(Int(round(criticalThreshold * 100)))%" - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - } - cell.accessoryType = .disclosureIndicator - return cell - case .deletePump: - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell - cell.textLabel?.text = "Delete Pump" - cell.textLabel?.textAlignment = .center - cell.tintColor = .delete - cell.isEnabled = true - return cell - } - } - - private func switchTableViewCell(for indexPath: IndexPath, titled title: String, boundTo keyPath: WritableKeyPath) -> SwitchTableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: BoundSwitchTableViewCell.className, for: indexPath) as! BoundSwitchTableViewCell - cell.textLabel?.text = title - cell.switch?.isOn = pumpManager.state[keyPath: keyPath] - cell.onToggle = { [unowned pumpManager] isOn in - pumpManager.state[keyPath: keyPath] = isOn - } - return cell - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let sender = tableView.cellForRow(at: indexPath) - - switch Section(rawValue: indexPath.section)! { - case .actions: - switch ActionRow(rawValue: indexPath.row)! { - case .suspendResume: - if let suspendResumeCell = sender as? SuspendResumeTableViewCell { - suspendResumeCellTapped(suspendResumeCell) - } - tableView.deselectRow(at: indexPath, animated: true) - case .occlusion: - pumpManager.injectPumpEvents(pumpManager.state.occlusionDetected ? [NewPumpEvent(alarmClearAt: Date())] : [NewPumpEvent(alarmAt: Date(), alarmType: .occlusion)]) - pumpManager.state.occlusionDetected = !pumpManager.state.occlusionDetected - tableView.deselectRow(at: indexPath, animated: true) - tableView.reloadRows(at: [indexPath], with: .automatic) - case .pumpError: - pumpManager.injectPumpEvents(pumpManager.state.pumpErrorDetected ? [NewPumpEvent(alarmClearAt: Date())] : [NewPumpEvent(alarmAt: Date(), alarmType: .other("Mock Pump Error"))]) - pumpManager.state.pumpErrorDetected = !pumpManager.state.pumpErrorDetected - tableView.deselectRow(at: indexPath, animated: true) - tableView.reloadRows(at: [indexPath], with: .automatic) - } - case .settings: - tableView.deselectRow(at: indexPath, animated: true) - switch SettingsRow(rawValue: indexPath.row)! { - case .deliverableIncrements: - break - case .supportedBasalRates: - if pumpManager.state.deliverableIncrements == .custom, pumpManager.state.supportedBasalRates.indices.contains(1) { - let basalRates = pumpManager.state.supportedBasalRates - let vc = SupportedRangeTableViewController(minValue: basalRates.first!, maxValue: basalRates.last!, stepSize: basalRates[1] - basalRates.first!) - vc.title = "Supported Basal Rates" - vc.indexPath = indexPath - vc.delegate = self - show(vc, sender: sender) - } - break - case .supportedBolusVolumes: - if pumpManager.state.deliverableIncrements == .custom, pumpManager.state.supportedBolusVolumes.indices.contains(1) { - let bolusVolumes = pumpManager.state.supportedBolusVolumes - let vc = SupportedRangeTableViewController(minValue: bolusVolumes.first!, maxValue: bolusVolumes.last!, stepSize: bolusVolumes[1] - bolusVolumes.first!) - vc.title = "Supported Bolus Volumes" - vc.indexPath = indexPath - vc.delegate = self - show(vc, sender: sender) - } - break - case .insulinType: - let view = InsulinTypeSetting(initialValue: pumpManager.state.insulinType, supportedInsulinTypes: InsulinType.allCases, allowUnsetInsulinType: true) { (newType) in - self.pumpManager.state.insulinType = newType - } - let vc = DismissibleHostingController(rootView: view) { - tableView.reloadRows(at: [indexPath], with: .automatic) - } - vc.title = LocalizedString("Insulin Type", comment: "Controller title for insulin type selection screen") - show(vc, sender: sender) - case .reservoirRemaining: - let vc = TextFieldTableViewController() - vc.value = String(format: "%.1f", pumpManager.state.reservoirUnitsRemaining) - vc.unit = "U" - vc.keyboardType = .decimalPad - vc.indexPath = indexPath - vc.delegate = self - show(vc, sender: sender) - case .batteryRemaining: - let vc = PercentageTextFieldTableViewController() - vc.percentage = pumpManager.status.pumpBatteryChargeRemaining - vc.indexPath = indexPath - vc.percentageDelegate = self - show(vc, sender: sender) - case .tempBasalErrorToggle, .bolusErrorToggle, .bolusCancelErrorToggle, .suspendErrorToggle, .resumeErrorToggle, .uncertainDeliveryErrorToggle: - break - case .lastReconciliationDate: - tableView.deselectRow(at: indexPath, animated: true) - tableView.beginUpdates() - tableView.endUpdates() - } - case .statusProgress: - let vc = PercentageTextFieldTableViewController() - vc.indexPath = indexPath - vc.percentageDelegate = self - switch StatusProgressRow(rawValue: indexPath.row)! { - case .percentComplete: - vc.percentage = pumpManager.state.progressPercentComplete - case .warningThreshold: - vc.percentage = pumpManager.state.progressWarningThresholdPercentValue - case .criticalThreshold: - vc.percentage = pumpManager.state.progressCriticalThresholdPercentValue - } - show(vc, sender: sender) - case .deletePump: - let confirmVC = UIAlertController(pumpDeletionHandler: { - self.pumpManager.notifyDelegateOfDeactivation { - DispatchQueue.main.async { - self.done() - } - } - }) - - present(confirmVC, animated: true) { - tableView.deselectRow(at: indexPath, animated: true) - } - default: - tableView.deselectRow(at: indexPath, animated: true) - } - } - - private func suspendResumeCellTapped(_ cell: SuspendResumeTableViewCell) { - switch cell.shownAction { - case .resume: - pumpManager.resumeDelivery { (error) in - if let error = error { - DispatchQueue.main.async { - let title = LocalizedString("Error Resuming", comment: "The alert title for a resume error") - self.present(UIAlertController(with: error, title: title), animated: true) - } - } - } - case .suspend: - pumpManager.suspendDelivery { (error) in - if let error = error { - DispatchQueue.main.async { - let title = LocalizedString("Error Suspending", comment: "The alert title for a suspend error") - self.present(UIAlertController(with: error, title: title), animated: true) - } - } - } - default: - break - } - } - - override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { - switch Section(rawValue: indexPath.section)! { - case .settings: - switch SettingsRow(rawValue: indexPath.row)! { - case .lastReconciliationDate: - - let resetAction = UIContextualAction(style: .normal, title: "Reset") {[weak self] _,_,_ in - self?.pumpManager.testLastReconciliation = nil - tableView.reloadRows(at: [indexPath], with: .automatic) - } - resetAction.backgroundColor = .systemRed - return UISwipeActionsConfiguration(actions: [resetAction]) - default: - break - } - default: - break - } - return nil - } - -} - -extension MockPumpManagerSettingsViewController: DatePickerTableViewCellDelegate { - func datePickerTableViewCellDidUpdateDate(_ cell: DatePickerTableViewCell) { - guard let row = tableView.indexPath(for: cell)?.row else { return } - - switch SettingsRow(rawValue: row) { - case .lastReconciliationDate?: - pumpManager.testLastReconciliation = cell.date - default: - break - } - } -} - -extension MockPumpManagerSettingsViewController: PumpManagerStatusObserver { - public func pumpManager(_ pumpManager: PumpManager, didUpdate status: PumpManagerStatus, oldStatus: PumpManagerStatus) { - dispatchPrecondition(condition: .onQueue(.main)) - - if let suspendResumeTableViewCell = self.tableView?.cellForRow(at: IndexPath(row: ActionRow.suspendResume.rawValue, section: Section.actions.rawValue)) as? SuspendResumeTableViewCell - { - suspendResumeTableViewCell.basalDeliveryState = status.basalDeliveryState - } - - tableView.reloadSections([Section.basalRate.rawValue], with: .automatic) - } -} - -extension MockPumpManagerSettingsViewController: TextFieldTableViewControllerDelegate { - func textFieldTableViewControllerDidReturn(_ controller: TextFieldTableViewController) { - update(from: controller) - } - - func textFieldTableViewControllerDidEndEditing(_ controller: TextFieldTableViewController) { - update(from: controller) - } - - private func update(from controller: TextFieldTableViewController) { - guard let indexPath = controller.indexPath else { assertionFailure(); return } - assert(indexPath == [Section.settings.rawValue, SettingsRow.reservoirRemaining.rawValue]) - if let value = controller.value.flatMap(Double.init) { - pumpManager.state.reservoirUnitsRemaining = max(value, 0) - } - tableView.reloadRows(at: [indexPath], with: .automatic) - } -} - -extension MockPumpManagerSettingsViewController: PercentageTextFieldTableViewControllerDelegate { - func percentageTextFieldTableViewControllerDidChangePercentage(_ controller: PercentageTextFieldTableViewController) { - guard let indexPath = controller.indexPath else { - assertionFailure() - return - } - - switch indexPath { - case [Section.settings.rawValue, SettingsRow.batteryRemaining.rawValue]: - pumpManager.pumpBatteryChargeRemaining = controller.percentage.map { $0.clamped(to: 0...1) } - tableView.reloadRows(at: [indexPath], with: .automatic) - case [Section.statusProgress.rawValue, StatusProgressRow.percentComplete.rawValue]: - pumpManager.state.progressPercentComplete = controller.percentage.map { $0.clamped(to: 0...1) } - tableView.reloadRows(at: [indexPath], with: .automatic) - case [Section.statusProgress.rawValue, StatusProgressRow.warningThreshold.rawValue]: - pumpManager.state.progressWarningThresholdPercentValue = controller.percentage.map { $0.clamped(to: 0...1) } - tableView.reloadRows(at: [indexPath], with: .automatic) - case [Section.statusProgress.rawValue, StatusProgressRow.criticalThreshold.rawValue]: - pumpManager.state.progressCriticalThresholdPercentValue = controller.percentage.map { $0.clamped(to: 0...1) } - tableView.reloadRows(at: [indexPath], with: .automatic) - default: - assertionFailure() - } - } -} - -private extension UIAlertController { - convenience init(pumpDeletionHandler handler: @escaping () -> Void) { - self.init( - title: nil, - message: "Are you sure you want to delete this pump?", - preferredStyle: .actionSheet - ) - - addAction(UIAlertAction( - title: "Delete Pump", - style: .destructive, - handler: { _ in handler() } - )) - - addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) - } - - convenience init(title: String, error: Error) { - - let message: String - - if let localizedError = error as? LocalizedError { - let sentenceFormat = LocalizedString("%@.", comment: "Appends a full-stop to a statement") - message = [localizedError.failureReason, localizedError.recoverySuggestion].compactMap({ $0 }).map({ - String(format: sentenceFormat, $0) - }).joined(separator: "\n") - } else { - message = String(describing: error) - } - - self.init( - title: title, - message: message, - preferredStyle: .alert - ) - - addAction(UIAlertAction( - title: LocalizedString("OK", comment: "Button title to acknowledge error"), - style: .default, - handler: nil - )) - } -} - -extension MockPumpManagerSettingsViewController: SupportedRangeTableViewControllerDelegate { - func supportedRangeDidUpdate(_ controller: SupportedRangeTableViewController) { - guard let indexPath = controller.indexPath else { - assertionFailure() - return - } - - let rangeMin = Int(controller.minValue/controller.stepSize) - let rangeMax = Int(controller.maxValue/controller.stepSize) - let rangeStep = 1/controller.stepSize - let values: [Double] = (rangeMin...rangeMax).map { Double($0) / rangeStep } - - switch indexPath { - case [Section.settings.rawValue, SettingsRow.supportedBasalRates.rawValue]: - pumpManager.state.supportedBasalRates = values - tableView.reloadRows(at: [indexPath], with: .automatic) - case [Section.settings.rawValue, SettingsRow.supportedBolusVolumes.rawValue]: - pumpManager.state.supportedBolusVolumes = values - tableView.reloadRows(at: [indexPath], with: .automatic) - default: - assertionFailure() - } - } -} - -fileprivate extension NewPumpEvent { - init(alarmAt date: Date, alarmType: PumpAlarmType? = nil) { - self.init(date: date, - dose: nil, - raw: Data(UUID().uuidString.utf8), - title: "alarm[\(alarmType?.rawValue ?? "")]", - type: .alarm, - alarmType: alarmType) - } - - init(alarmClearAt date: Date) { - self.init(date: date, - dose: nil, - raw: Data(UUID().uuidString.utf8), - title: "alarmClear", - type: .alarmClear) - } -} diff --git a/Dependencies/LoopKit/MockKitUI/View Controllers/MockServiceTableViewController.swift b/Dependencies/LoopKit/MockKitUI/View Controllers/MockServiceTableViewController.swift deleted file mode 100644 index 7bc12bc4e..000000000 --- a/Dependencies/LoopKit/MockKitUI/View Controllers/MockServiceTableViewController.swift +++ /dev/null @@ -1,347 +0,0 @@ -// -// MockServiceSettingsViewController.swift -// MockKitUI -// -// Created by Darin Krauss on 5/17/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit -import LoopKitUI -import MockKit - -final class MockServiceTableViewController: UITableViewController { - - public enum Operation { - case create - case update - } - - private let service: MockService - - private let operation: Operation - - init(service: MockService, for operation: Operation) { - self.service = service - self.operation = operation - - super.init(style: .grouped) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - tableView.register(SettingsTableViewCell.self, forCellReuseIdentifier: SettingsTableViewCell.className) - tableView.register(SwitchTableViewCell.self, forCellReuseIdentifier: SwitchTableViewCell.className) - tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className) - - title = service.localizedTitle - - if operation == .create { - navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancel)) - } - navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(done)) - } - - @objc private func cancel() { - notifyComplete() - } - - @objc private func done() { - switch operation { - case .create: - service.completeCreate() - if let serviceNavigationController = navigationController as? ServiceNavigationController { - serviceNavigationController.notifyServiceCreatedAndOnboarded(service) - } - case .update: - service.completeUpdate() - } - - notifyComplete() - } - - private func confirmDeletion(completion: (() -> Void)? = nil) { - let alert = UIAlertController(serviceDeletionHandler: { - self.service.completeDelete() - self.notifyComplete() - }) - - present(alert, animated: true, completion: completion) - } - - private func notifyComplete() { - if let serviceNavigationController = navigationController as? ServiceNavigationController { - serviceNavigationController.notifyComplete() - } - } - - // MARK: - Data Source - - private enum Section: Int, CaseIterable { - case source - case history - case deleteService - } - - private enum Source: Int, CaseIterable { - case remoteData - case logging - case analytics - } - - private enum History: Int, CaseIterable { - case viewHistory - case clearHistory - } - - // MARK: - UITableViewDataSource - - override func numberOfSections(in tableView: UITableView) -> Int { - switch operation { - case .create: - return Section.allCases.count - 2 // No history or deleteService - case .update: - return Section.allCases.count - } - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch Section(rawValue: section)! { - case .source: - return Source.allCases.count - case .history: - return History.allCases.count - case .deleteService: - return 1 - } - } - - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - switch Section(rawValue: section)! { - case .source: - return LocalizedString("Source", comment: "Caption for Source") - case .history: - return LocalizedString("History", comment: "Caption for History") - case .deleteService: - return " " // Use an empty string for more dramatic spacing - } - } - - override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { - switch Section(rawValue: indexPath.section)! { - case .source: - return false - default: - return true - } - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch Section(rawValue: indexPath.section)! { - case .source: - let cell = tableView.dequeueReusableCell(withIdentifier: SwitchTableViewCell.className, for: indexPath) as! SwitchTableViewCell - switch Source(rawValue: indexPath.row)! { - case .remoteData: - cell.textLabel?.text = "Remote Data" - cell.switch?.isOn = service.remoteData - cell.switch?.addTarget(self, action: #selector(remoteDataChanged(_:)), for: .valueChanged) - case .logging: - cell.textLabel?.text = "Logging" - cell.switch?.isOn = service.logging - cell.switch?.addTarget(self, action: #selector(loggingChanged(_:)), for: .valueChanged) - case .analytics: - cell.textLabel?.text = "Analytics" - cell.switch?.isOn = service.analytics - cell.switch?.addTarget(self, action: #selector(analyticsChanged(_:)), for: .valueChanged) - } - return cell - case .history: - switch History(rawValue: indexPath.row)! { - case .viewHistory: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) as! SettingsTableViewCell - cell.textLabel?.text = "View History" - cell.accessoryType = .disclosureIndicator - return cell - case .clearHistory: - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell - cell.textLabel?.text = "Clear History" - cell.tintColor = .delete - return cell - } - case .deleteService: - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell - cell.textLabel?.text = "Delete Service" - cell.textLabel?.textAlignment = .center - cell.tintColor = .delete - return cell - } - } - - @objc private func remoteDataChanged(_ sender: UISwitch) { - service.remoteData = sender.isOn - } - - @objc private func loggingChanged(_ sender: UISwitch) { - service.logging = sender.isOn - } - - @objc private func analyticsChanged(_ sender: UISwitch) { - service.analytics = sender.isOn - } - - // MARK: - UITableViewDelegate - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - switch Section(rawValue: indexPath.section)! { - case .source: - break - case .history: - switch History(rawValue: indexPath.row)! { - case .viewHistory: - show(MockServiceHistoryViewController.init(mockService: service), sender: tableView.cellForRow(at: indexPath)) - case .clearHistory: - let alert = UIAlertController(clearHistoryHandler: { - self.service.clearHistory() - }) - present(alert, animated: true) { - tableView.deselectRow(at: indexPath, animated: true) - } - } - case .deleteService: - confirmDeletion { - tableView.deselectRow(at: indexPath, animated: true) - } - } - } - -} - -fileprivate class MockServiceHistoryViewController: UIViewController { - - private let mockService: MockService - - private lazy var textView = UITextView() - - init(mockService: MockService) { - self.mockService = mockService - - super.init(nibName: nil, bundle: nil) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func loadView() { - view = textView - } - - override func viewDidLoad() { - super.viewDidLoad() - - title = LocalizedString("History", comment: "History Caption") - - textView.contentInsetAdjustmentBehavior = .always - textView.isEditable = false - if let font = UIFont(name: "Menlo-Regular", size: 12) { - textView.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: font) - } - - textView.text = mockService.history.joined(separator: "\n") - - navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(share)) - } - - @objc func share() { - let timestamp = ISO8601DateFormatter.string(from: Date(), timeZone: .current, formatOptions: [.withInternetDateTime]) - let title = "\(mockService.localizedTitle)_History_\(timestamp).txt" - - let item = SharedResponse(text: textView.text, title: title) - - do { - try item.write() - } catch let error { - present(UIAlertController(with: error), animated: true) - return - } - - present(UIActivityViewController(activityItems: [item], applicationActivities: nil), animated: true) - } - -} - -fileprivate class SharedResponse: NSObject, UIActivityItemSource { - - private let text: String - - private let title: String - - private let url: URL - - init(text: String, title: String) { - var url = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true) - url.appendPathComponent(title, isDirectory: false) - - self.text = text - self.title = title - self.url = url - - super.init() - } - - func write() throws { - try text.write(to: url, atomically: true, encoding: .utf8) - } - - // MARK: - UIActivityItemSource - - func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any { - return url - } - - func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? { - return url - } - - func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivity.ActivityType?) -> String { - return title - } - - func activityViewController(_ activityViewController: UIActivityViewController, dataTypeIdentifierForActivityType activityType: UIActivity.ActivityType?) -> String { - return "public.utf8-plain-text" - } - -} - -fileprivate extension UIAlertController { - - convenience init(clearHistoryHandler handler: @escaping () -> Void) { - self.init(title: nil, message: "Are you sure you want to clear the history?", preferredStyle: .actionSheet) - addAction(UIAlertAction(title: "Clear History", style: .destructive, handler: { _ in handler() })) - addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) - } - - convenience init(serviceDeletionHandler handler: @escaping () -> Void) { - self.init( - title: nil, - message: LocalizedString("Are you sure you want to delete this service?", comment: "Confirmation message for deleting a service"), - preferredStyle: .actionSheet - ) - - addAction(UIAlertAction( - title: LocalizedString("Delete Service", comment: "Button title to delete a service"), - style: .destructive, - handler: { _ in - handler() - })) - - let cancel = LocalizedString("Cancel", comment: "The title of the cancel action in an action sheet") - addAction(UIAlertAction(title: cancel, style: .cancel, handler: nil)) - } -} diff --git a/Dependencies/LoopKit/MockKitUI/View Controllers/RandomOutlierTableViewController.swift b/Dependencies/LoopKit/MockKitUI/View Controllers/RandomOutlierTableViewController.swift deleted file mode 100644 index b7ead5e5c..000000000 --- a/Dependencies/LoopKit/MockKitUI/View Controllers/RandomOutlierTableViewController.swift +++ /dev/null @@ -1,160 +0,0 @@ -// -// RandomOutlierTableViewController.swift -// LoopKitUI -// -// Created by Michael Pangburn on 11/25/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import HealthKit -import LoopKit -import LoopKitUI -import MockKit - - -protocol RandomOutlierTableViewControllerDelegate: AnyObject { - func randomOutlierTableViewControllerDidChangeOutlier(_ controller: RandomOutlierTableViewController) -} - -final class RandomOutlierTableViewController: UITableViewController { - - let glucoseUnit: HKUnit - - var randomOutlier: MockCGMDataSource.Effects.RandomOutlier? { - get { - guard let chance = chance, let delta = delta else { - return nil - } - return (chance: chance, delta: delta) - } - set { - chance = newValue?.chance - delta = newValue?.delta - } - } - - var contextHelp: String? - - var indexPath: IndexPath? - - weak var delegate: RandomOutlierTableViewControllerDelegate? - - private var chance: Double? { - didSet { - delegate?.randomOutlierTableViewControllerDidChangeOutlier(self) - } - } - - private var delta: HKQuantity? { - didSet { - delegate?.randomOutlierTableViewControllerDidChangeOutlier(self) - } - } - - private lazy var percentageFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.minimumIntegerDigits = 1 - formatter.maximumFractionDigits = 1 - return formatter - }() - - private lazy var glucoseFormatter = QuantityFormatter() - - init(glucoseUnit: HKUnit) { - self.glucoseUnit = glucoseUnit - super.init(style: .grouped) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - tableView.register(SettingsTableViewCell.self, forCellReuseIdentifier: SettingsTableViewCell.className) - } - - // MARK: - Data Source - - private enum Row: Int, CaseIterable { - case chance = 0 - case delta - } - - override func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return Row.allCases.count - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) as! SettingsTableViewCell - - switch Row(rawValue: indexPath.row)! { - case .chance: - cell.textLabel?.text = "Chance" - if let chance = chance, - let percentageText = percentageFormatter.string(from: chance * 100) { - cell.detailTextLabel?.text = "\(percentageText)%" - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - case .delta: - cell.textLabel?.text = "Delta" - if let delta = delta { - cell.detailTextLabel?.text = glucoseFormatter.string(from: delta, for: glucoseUnit) - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - } - - cell.accessoryType = .disclosureIndicator - return cell - } - - // MARK: - UITableViewDelegate - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let sender = tableView.cellForRow(at: indexPath) - - switch Row(rawValue: indexPath.row)! { - case .chance: - let vc = PercentageTextFieldTableViewController() - vc.percentage = chance - vc.title = "Chance" - vc.contextHelp = "The percentage determines the chance with which the CGM will produce an outlier when a glucose value is requested." - vc.percentageDelegate = self - show(vc, sender: sender) - case .delta: - let vc = GlucoseEntryTableViewController(glucoseUnit: glucoseUnit) - vc.glucose = delta - vc.title = "Delta" - vc.contextHelp = "The delta determines the offset from the expected glucose value when the CGM produces an outlier." - vc.glucoseEntryDelegate = self - show(vc, sender: sender) - } - } - - override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - return contextHelp - } -} - -extension RandomOutlierTableViewController: PercentageTextFieldTableViewControllerDelegate { - func percentageTextFieldTableViewControllerDidChangePercentage(_ controller: PercentageTextFieldTableViewController) { - chance = controller.percentage?.clamped(to: 0...1) - tableView.reloadRows(at: [[0, Row.chance.rawValue]], with: .automatic) - } -} - -extension RandomOutlierTableViewController: GlucoseEntryTableViewControllerDelegate { - func glucoseEntryTableViewControllerDidChangeGlucose(_ controller: GlucoseEntryTableViewController) { - delta = controller.glucose - tableView.reloadRows(at: [[0, Row.delta.rawValue]], with: .automatic) - } -} - diff --git a/Dependencies/LoopKit/MockKitUI/View Controllers/SineCurveParametersTableViewController.swift b/Dependencies/LoopKit/MockKitUI/View Controllers/SineCurveParametersTableViewController.swift deleted file mode 100644 index 3d874b951..000000000 --- a/Dependencies/LoopKit/MockKitUI/View Controllers/SineCurveParametersTableViewController.swift +++ /dev/null @@ -1,237 +0,0 @@ -// -// SineCurveParametersTableViewController.swift -// LoopKitUI -// -// Created by Michael Pangburn on 11/24/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import HealthKit -import LoopKit -import LoopKitUI -import MockKit - - -protocol SineCurveParametersTableViewControllerDelegate: AnyObject { - func sineCurveParametersTableViewControllerDidUpdateParameters(_ controller: SineCurveParametersTableViewController) -} - -final class SineCurveParametersTableViewController: UITableViewController { - - let glucoseUnit: HKUnit - - var parameters: MockCGMDataSource.Model.SineCurveParameters? { - get { - if let baseGlucose = baseGlucose, - let amplitude = amplitude, - let period = period, - let referenceDate = referenceDate - { - return (baseGlucose: baseGlucose, amplitude: amplitude, period: period, referenceDate: referenceDate) - } else { - return nil - } - } - set { - baseGlucose = newValue?.baseGlucose - amplitude = newValue?.amplitude - period = newValue?.period ?? defaultPeriod - referenceDate = newValue?.referenceDate ?? defaultReferenceDate - } - } - - var defaultPeriod: TimeInterval = .hours(6) - var defaultReferenceDate = Date() - - private var baseGlucose: HKQuantity? { - didSet { - delegate?.sineCurveParametersTableViewControllerDidUpdateParameters(self) - } - } - - private var amplitude: HKQuantity? { - didSet { - delegate?.sineCurveParametersTableViewControllerDidUpdateParameters(self) - } - } - - private var period: TimeInterval? { - didSet { - delegate?.sineCurveParametersTableViewControllerDidUpdateParameters(self) - } - } - - private var referenceDate: Date? { - didSet { - delegate?.sineCurveParametersTableViewControllerDidUpdateParameters(self) - } - } - - var contextHelp: String? - - weak var delegate: SineCurveParametersTableViewControllerDelegate? - - private lazy var glucoseFormatter = QuantityFormatter() - - private lazy var durationFormatter: DateComponentsFormatter = { - let formatter = DateComponentsFormatter() - formatter.allowedUnits = [.hour, .minute] - formatter.unitsStyle = .short - return formatter - }() - - private lazy var dateFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .short - formatter.timeStyle = .short - return formatter - }() - - init(glucoseUnit: HKUnit) { - self.glucoseUnit = glucoseUnit - super.init(style: .grouped) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - title = "Sine Curve" - - tableView.register(SettingsTableViewCell.self, forCellReuseIdentifier: SettingsTableViewCell.className) - } - - // MARK: - Data Source - - private enum Row: Int, CaseIterable { - case baseGlucose = 0 - case amplitude - case period - case referenceDate - } - - override func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return Row.allCases.count - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) as! SettingsTableViewCell - let formatGlucose = { self.glucoseFormatter.string(from: $0, for: self.glucoseUnit) } - - switch Row(rawValue: indexPath.row)! { - case .baseGlucose: - cell.textLabel?.text = "Base Glucose" - cell.detailTextLabel?.text = baseGlucose.map(formatGlucose) ?? SettingsTableViewCell.NoValueString - case .amplitude: - cell.textLabel?.text = "Amplitude" - cell.detailTextLabel?.text = amplitude.map(formatGlucose) ?? SettingsTableViewCell.NoValueString - case .period: - cell.textLabel?.text = "Period" - cell.detailTextLabel?.text = period.flatMap(durationFormatter.string(from:)) ?? SettingsTableViewCell.NoValueString - case .referenceDate: - cell.textLabel?.text = "Reference Date" - cell.detailTextLabel?.text = referenceDate.map(dateFormatter.string(from:)) ?? SettingsTableViewCell.NoValueString - } - - cell.accessoryType = .disclosureIndicator - return cell - } - - // MARK: - UITableViewDelegate - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let sender = tableView.cellForRow(at: indexPath) - let title = sender?.textLabel?.text - - func presentGlucoseEntryViewController(for glucose: HKQuantity?, contextHelp: String?) { - let vc = GlucoseEntryTableViewController(glucoseUnit: glucoseUnit) - vc.glucose = glucose - vc.title = title - vc.contextHelp = contextHelp - vc.indexPath = indexPath - vc.glucoseEntryDelegate = self - show(vc, sender: sender) - } - - func presentDateAndDurationViewController(for inputMode: DateAndDurationTableViewController.InputMode, contextHelp: String?) { - let vc = DateAndDurationTableViewController() - vc.inputMode = inputMode - vc.title = title - vc.contextHelp = contextHelp - vc.indexPath = indexPath - vc.delegate = self - show(vc, sender: sender) - } - - switch Row(rawValue: indexPath.row)! { - case .baseGlucose: - presentGlucoseEntryViewController(for: baseGlucose, contextHelp: "The base glucose represents the zero about which the sine curve oscillates.") - case .amplitude: - presentGlucoseEntryViewController(for: amplitude, contextHelp: "The amplitude represents the magnitude of the oscillation of the glucose curve.") - case .period: - presentDateAndDurationViewController(for: .duration(period ?? defaultPeriod), contextHelp: "The period describes the duration of one complete glucose cycle.") - case .referenceDate: - presentDateAndDurationViewController(for: .date(referenceDate ?? defaultReferenceDate, mode: .dateAndTime), contextHelp: "The reference date describes the origin of the sine curve with respect to time. Changing the reference date applies a phase shift to the curve.") - } - } - - override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - return contextHelp - } -} - -extension SineCurveParametersTableViewController: GlucoseEntryTableViewControllerDelegate { - func glucoseEntryTableViewControllerDidChangeGlucose(_ controller: GlucoseEntryTableViewController) { - guard let indexPath = controller.indexPath else { - assertionFailure() - return - } - - switch Row(rawValue: indexPath.row)! { - case .baseGlucose: - baseGlucose = controller.glucose - case .amplitude: - amplitude = controller.glucose - default: - assertionFailure() - } - - tableView.reloadRows(at: [indexPath], with: .automatic) - } -} - -extension SineCurveParametersTableViewController: DateAndDurationTableViewControllerDelegate { - func dateAndDurationTableViewControllerDidChangeDate(_ controller: DateAndDurationTableViewController) { - guard let indexPath = controller.indexPath else { - assertionFailure() - return - } - - switch Row(rawValue: indexPath.row)! { - case .period: - guard case .duration(let duration) = controller.inputMode else { - assertionFailure() - return - } - period = duration - case .referenceDate: - guard case .date(let date, mode: _) = controller.inputMode else { - assertionFailure() - return - } - referenceDate = date - default: - assertionFailure() - } - - tableView.reloadRows(at: [indexPath], with: .automatic) - } -} diff --git a/Dependencies/LoopKit/MockKitUI/View Controllers/SupportedRangeTableViewController.swift b/Dependencies/LoopKit/MockKitUI/View Controllers/SupportedRangeTableViewController.swift deleted file mode 100644 index 93bf3f0fa..000000000 --- a/Dependencies/LoopKit/MockKitUI/View Controllers/SupportedRangeTableViewController.swift +++ /dev/null @@ -1,151 +0,0 @@ -// -// SupportedRangeTableViewController.swift -// MockKitUI -// -// Created by Nathaniel Hamming on 2020-11-16. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import Foundation - - -import UIKit -import HealthKit -import LoopKit -import LoopKitUI -import MockKit - - -protocol SupportedRangeTableViewControllerDelegate: AnyObject { - func supportedRangeDidUpdate(_ controller: SupportedRangeTableViewController) -} - -final class SupportedRangeTableViewController: UITableViewController { - - weak var delegate: SupportedRangeTableViewControllerDelegate? - - var minValue: Double - - var maxValue: Double - - var stepSize: Double - - var indexPath: IndexPath? - - private let numberFormatter: NumberFormatter = { - let formatter = NumberFormatter() - - formatter.numberStyle = .decimal - formatter.minimumFractionDigits = 0 - formatter.maximumFractionDigits = 3 - - return formatter - }() - - init(minValue: Double, - maxValue: Double, - stepSize: Double) - { - self.minValue = minValue - self.maxValue = maxValue - self.stepSize = stepSize - super.init(style: .grouped) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - tableView.register(SettingsTableViewCell.self, forCellReuseIdentifier: SettingsTableViewCell.className) - } - - // MARK: - Data Source - - private enum Row: Int, CaseIterable { - case minValue = 0 - case maxValue - case stepSize - } - - override func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return Row.allCases.count - } - - override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - return "Changing the supported values of the pump may cause the app to crash. Ensure you are changing them such that the set therapy values are still valid (e.g., basal rate, max bolus, etc.)" - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) as! SettingsTableViewCell - - switch Row(rawValue: indexPath.row)! { - case .minValue: - cell.textLabel?.text = "Minimum Value" - cell.detailTextLabel?.text = numberFormatter.string(from: minValue) - case .maxValue: - cell.textLabel?.text = "Maximum Value" - cell.detailTextLabel?.text = numberFormatter.string(from: maxValue) - case .stepSize: - cell.textLabel?.text = "Step Size" - cell.detailTextLabel?.text = numberFormatter.string(from: stepSize) - } - - cell.accessoryType = .disclosureIndicator - return cell - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let sender = tableView.cellForRow(at: indexPath) - - let value: Double - switch Row(rawValue: indexPath.row)! { - case .minValue: - value = minValue - case .maxValue: - value = maxValue - case .stepSize: - value = stepSize - } - - let vc = TextFieldTableViewController() - vc.value = numberFormatter.string(from: value) - vc.keyboardType = .decimalPad - vc.indexPath = indexPath - vc.delegate = self - show(vc, sender: sender) - tableView.deselectRow(at: indexPath, animated: true) - } -} - -extension SupportedRangeTableViewController: TextFieldTableViewControllerDelegate { - func textFieldTableViewControllerDidReturn(_ controller: TextFieldTableViewController) { - update(from: controller) - } - - func textFieldTableViewControllerDidEndEditing(_ controller: TextFieldTableViewController) { - update(from: controller) - } - - private func update(from controller: TextFieldTableViewController) { - guard let indexPath = controller.indexPath, - let value = controller.value.flatMap(Double.init) else { assertionFailure(); return } - - switch Row(rawValue: indexPath.row)! { - case .minValue: - minValue = max(value, 0.0) - case .maxValue: - maxValue = max(value, 0.0) - case .stepSize: - stepSize = max(value, 0.0) - } - - delegate?.supportedRangeDidUpdate(self) - tableView.reloadRows(at: [indexPath], with: .automatic) - } -} diff --git a/Dependencies/LoopKit/MockKitUI/Views/BoundSwitchTableViewCell.swift b/Dependencies/LoopKit/MockKitUI/Views/BoundSwitchTableViewCell.swift deleted file mode 100644 index f17bbe19a..000000000 --- a/Dependencies/LoopKit/MockKitUI/Views/BoundSwitchTableViewCell.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// BoundSwitchTableViewCell.swift -// MockKitUI -// -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import LoopKitUI -import UIKit - -class BoundSwitchTableViewCell: SwitchTableViewCell { - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - - selectionStyle = .none - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - var onToggle: ((_ isOn: Bool) -> Void)? { - didSet { - if onToggle == nil { - self.switch?.removeTarget(nil, action: nil, for: .valueChanged) - } else { - `switch`?.addTarget(self, action: #selector(respondToToggle), for: .valueChanged) - } - } - } - - override func prepareForReuse() { - super.prepareForReuse() - - onToggle = nil - `switch`?.addTarget(self, action: #selector(respondToToggle), for: .valueChanged) - } - - @objc private func respondToToggle() { - if let `switch` = `switch`, let onToggle = onToggle { - onToggle(`switch`.isOn) - } - } -} diff --git a/Dependencies/LoopKit/MockKitUI/Views/DeliveryUncertaintyRecoveryView.swift b/Dependencies/LoopKit/MockKitUI/Views/DeliveryUncertaintyRecoveryView.swift deleted file mode 100644 index 00eac8ab7..000000000 --- a/Dependencies/LoopKit/MockKitUI/Views/DeliveryUncertaintyRecoveryView.swift +++ /dev/null @@ -1,88 +0,0 @@ -// -// DeliveryUncertaintyRecoveryView.swift -// MockKitUI -// -// Created by Pete Schwamb on 8/17/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct DeliveryUncertaintyRecoveryView: View, HorizontalSizeClassOverride { - @Environment(\.dismissAction) private var dismiss - - let appName: String - let uncertaintyStartedAt: Date - let recoverCommsTapped: () -> Void - - var body: some View { - NavigationView { - GuidePage(content: { - Text("\(self.appName) has been unable to communicate with the Simulator Pump since \(self.uncertaintyDateLocalizedString).\n\nWithout communication, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered.") - }) { - Button(action: { - self.recoverCommsTapped() - self.dismiss() - }) { - Text(LocalizedString("Recover Simulator", comment: "Button title recovering comms")) - .actionButtonStyle() - .padding() - } - } - .environment(\.horizontalSizeClass, horizontalOverride) - .navigationBarTitle(Text("Comms Recovery"), displayMode: .large) - .toolbar { - ToolbarItem(placement: .navigationBarLeading) { - backButton - } - } - } - } - - private var uncertaintyDateLocalizedString: String { - DateFormatter.localizedString(from: uncertaintyStartedAt, dateStyle: .none, timeStyle: .short) - } - - private var backButton: some View { - Button(LocalizedString("Back", comment: "Back button text on DeliveryUncertaintyRecoveryView"), action: { - self.dismiss() - }) - } -} - -struct DeliveryUncertaintyRecoveryView_Previews: PreviewProvider { - static var previews: some View { - DeliveryUncertaintyRecoveryView(appName: "Test App", uncertaintyStartedAt: Date()) { - print("Recover Comms") - } - } -} - - -// Wrapper to provide a CompletionNotifying ViewController -class DeliveryUncertaintyRecoveryViewController: UIHostingController, CompletionNotifying { - - public weak var completionDelegate: CompletionDelegate? - - init(appName: String, uncertaintyStartedAt: Date, recoverCommsTapped: @escaping () -> Void) { - - var dismiss = {} - - let view = DeliveryUncertaintyRecoveryView(appName: appName, uncertaintyStartedAt: uncertaintyStartedAt) { - recoverCommsTapped() - dismiss() - } - .environment(\.dismissAction, { dismiss() }) - - super.init(rootView: AnyView(view)) - - dismiss = { - self.completionDelegate?.completionNotifyingDidComplete(self) - } - } - - @objc required dynamic init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} diff --git a/Dependencies/LoopKit/Package.resolved b/Dependencies/LoopKit/Package.resolved deleted file mode 100644 index 627418b87..000000000 --- a/Dependencies/LoopKit/Package.resolved +++ /dev/null @@ -1,14 +0,0 @@ -{ - "pins" : [ - { - "identity" : "swiftcharts", - "kind" : "remoteSourceControl", - "location" : "https://github.com/ivanschuetz/SwiftCharts", - "state" : { - "branch" : "master", - "revision" : "c354c1945bb35a1f01b665b22474f6db28cba4a2" - } - } - ], - "version" : 2 -} diff --git a/Dependencies/LoopKit/Package.swift b/Dependencies/LoopKit/Package.swift deleted file mode 100644 index 3ff4a8c97..000000000 --- a/Dependencies/LoopKit/Package.swift +++ /dev/null @@ -1,63 +0,0 @@ -// swift-tools-version: 5.7 -// The swift tools-version declares the minimum version of Swift required to build this package. - -// *************** Not complete yet, do not expect this to work! *********************** -// There are issues with how test fixtures are copied into the bundle, and then referenced, -// and other issues, largely around accessing bundle resources, and probably others not yet -// discovered, as this is not being used as a swift package from any actual project yet. - -import PackageDescription - -let package = Package( - name: "LoopKit", - defaultLocalization: "en", - platforms: [.iOS("15.0")], - products: [ - // Products define the executables and libraries a package produces, and make them visible to other packages. - .library( - name: "LoopKit", - targets: ["LoopKit"]), - .library( - name: "LoopKitUI", - targets: ["LoopKitUI"]), - ], - dependencies: [ - .package( - url: "https://github.com/ivanschuetz/SwiftCharts", - branch: "master" - ) - // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), - ], - targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages this package depends on. - .target( - name: "LoopKit", - dependencies: [], - path: "LoopKit"), - .testTarget( - name: "LoopKitTests", - dependencies: ["LoopKit"], - path: "LoopKitTests", - resources: [ - .copy("Fixtures") - ]), - .target( - name: "LoopKitUI", - dependencies: ["LoopKit", "SwiftCharts"], - path: "LoopKitUI"), - .target( - name: "LoopTestingKit", - dependencies: ["LoopKit"], - path: "LoopTestingKit"), - .target( - name: "MockKit", - dependencies: ["LoopKit", "LoopKitUI", "LoopTestingKit"], - path: "MockKit"), - .target( - name: "MockKitUI", - dependencies: ["MockKit", "LoopKit", "LoopKitUI"], - path: "MockKitUI"), - ] -) diff --git a/Dependencies/LoopKit/README.md b/Dependencies/LoopKit/README.md deleted file mode 100644 index 463b54dc2..000000000 --- a/Dependencies/LoopKit/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# LoopKit - -[![Build Status](https://travis-ci.org/LoopKit/LoopKit.svg?branch=master)](https://travis-ci.org/LoopKit/LoopKit) -[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) -[![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://loop.zulipchat.com) - -LoopKit is a set of tools to speed up development of your own closed-loop insulin delivery app. It is agnostic to treatment decisions and input sources. - -## Loop - -[Loop](https://github.com/LoopKit/Loop) is a full-featured app built on top of LoopKit. - -## LoopKit provides - -* Data storage and retrieval, using HealthKit and Core Data as appropriate -* Protocol types for representing data models in a flexible way -* Common calculation algorithms like Insulin On Board -* Boilerplate user interfaces like editing basal rate schedules and carb entry - -## LoopKit does not provide - -* Treatment decisions: Your Diabetes May Vary. -* Device communications: Device-specific libraries are maintained separately. - -# License - -LoopKit is available under the MIT license. See the LICENSE file for more info. - -# Code of Conduct - -Please note that this project is released with a [Contributor Code of Conduct](https://github.com/LoopKit/LoopKit/blob/master/CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. diff --git a/Dependencies/MKRingProgressView/.gitignore b/Dependencies/MKRingProgressView/.gitignore deleted file mode 100644 index 8615121b2..000000000 --- a/Dependencies/MKRingProgressView/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -# Xcode -# -build/ -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata -*.xccheckout -*.moved-aside -DerivedData -*.hmap -*.ipa -*.xcuserstate - -# CocoaPods -# -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control -# -# Pods/ - -# Carthage -# -# Add this line if you want to avoid checking in source code from Carthage dependencies. -# Carthage/Checkouts - -Carthage/Build diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/AppDelegate.swift b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/AppDelegate.swift deleted file mode 100644 index 1941d679f..000000000 --- a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/AppDelegate.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// AppDelegate.swift -// MKRingProgressViewExample -// -// Created by Max Konovalov on 20/10/15. -// Copyright © 2015 Max Konovalov. All rights reserved. -// - -import UIKit - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { - //let icon = generateAppIcon(scale: 2) - return true - } - - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - -} - diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Contents.json b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 98ae57ec1..000000000 --- a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom": "iphone", - "filename" : "Icon-20@2x.png", - "scale": "2x" - }, - { - "size" : "20x20", - "idiom": "iphone", - "filename" : "Icon-20@3x.png", - "scale": "3x" - }, - { - "size" : "20x20", - "idiom": "ipad", - "filename" : "Icon-20.png", - "scale": "1x" - }, - { - "size" : "20x20", - "idiom": "ipad", - "filename" : "Icon-20@2x.png", - "scale": "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-60@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-29.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-40.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-76.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-1024.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-1024.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-1024.png deleted file mode 100644 index 28d0cf02d..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-1024.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-20.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-20.png deleted file mode 100644 index 8c20aaacd..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-20.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png deleted file mode 100644 index 8c16f9486..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png deleted file mode 100644 index fe5bf9678..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-29.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-29.png deleted file mode 100644 index 596371365..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-29.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png deleted file mode 100644 index f968f3f83..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png deleted file mode 100644 index 0daf3e9b2..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-40.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-40.png deleted file mode 100644 index 8c16f9486..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-40.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png deleted file mode 100644 index d1bdfb4f1..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png deleted file mode 100644 index b8a3fc233..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png deleted file mode 100644 index b8a3fc233..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png deleted file mode 100644 index c8a7b52b5..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-76.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-76.png deleted file mode 100644 index 90fc67e15..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-76.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png deleted file mode 100644 index 8042ed2e0..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png deleted file mode 100644 index 37ce86b3b..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/Contents.json b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/Contents.json deleted file mode 100644 index da4a164c9..000000000 --- a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon1.imageset/Contents.json b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon1.imageset/Contents.json deleted file mode 100644 index 5218a68fe..000000000 --- a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon1.imageset/Contents.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "icon1@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "icon1@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon1.imageset/icon1@2x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon1.imageset/icon1@2x.png deleted file mode 100644 index 0f4597782..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon1.imageset/icon1@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon1.imageset/icon1@3x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon1.imageset/icon1@3x.png deleted file mode 100644 index b6b21bdeb..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon1.imageset/icon1@3x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon2.imageset/Contents.json b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon2.imageset/Contents.json deleted file mode 100644 index 7ca1f6be4..000000000 --- a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon2.imageset/Contents.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "icon2@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "icon2@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon2.imageset/icon2@2x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon2.imageset/icon2@2x.png deleted file mode 100644 index 5ff228518..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon2.imageset/icon2@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon2.imageset/icon2@3x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon2.imageset/icon2@3x.png deleted file mode 100644 index f71d2f73b..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon2.imageset/icon2@3x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon3.imageset/Contents.json b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon3.imageset/Contents.json deleted file mode 100644 index 013b4c5f5..000000000 --- a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon3.imageset/Contents.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "icon3@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "icon3@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon3.imageset/icon3@2x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon3.imageset/icon3@2x.png deleted file mode 100644 index 2d34e3480..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon3.imageset/icon3@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon3.imageset/icon3@3x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon3.imageset/icon3@3x.png deleted file mode 100644 index 0f71933b5..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/icon3.imageset/icon3@3x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/tab.imageset/Contents.json b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/tab.imageset/Contents.json deleted file mode 100644 index 9434bcf40..000000000 --- a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/tab.imageset/Contents.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "tab@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "tab@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/tab.imageset/tab@2x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/tab.imageset/tab@2x.png deleted file mode 100644 index d023a4f4a..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/tab.imageset/tab@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/tab.imageset/tab@3x.png b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/tab.imageset/tab@3x.png deleted file mode 100644 index b8f001b75..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Assets.xcassets/tab.imageset/tab@3x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Base.lproj/LaunchScreen.storyboard b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index a8f8faf38..000000000 --- a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Base.lproj/Main.storyboard b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Base.lproj/Main.storyboard deleted file mode 100644 index 965949127..000000000 --- a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Base.lproj/Main.storyboard +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Icon.swift b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Icon.swift deleted file mode 100644 index fcf2b51bc..000000000 --- a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Icon.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// Icon.swift -// MKRingProgressViewExample -// -// Created by Max Konovalov on 25/05/2018. -// Copyright © 2018 Max Konovalov. All rights reserved. -// - -import UIKit - -func generateAppIcon(scale: CGFloat = 1.0) -> UIImage { - let size = CGSize(width: 512, height: 512) - let rect = CGRect(origin: .zero, size: size) - - let icon = UIView(frame: rect) - icon.backgroundColor = #colorLiteral(red: 0.1176470588, green: 0.1176470588, blue: 0.1254901961, alpha: 1) - - let group = RingProgressGroupView(frame: icon.bounds.insetBy(dx: 33, dy: 33)) - group.ringWidth = 50 - group.ringSpacing = 10 - group.ring1StartColor = #colorLiteral(red: 0.8823529412, green: 0, blue: 0.07843137255, alpha: 1) - group.ring1EndColor = #colorLiteral(red: 1, green: 0.1960784314, blue: 0.5294117647, alpha: 1) - group.ring2StartColor = #colorLiteral(red: 0.2156862745, green: 0.862745098, blue: 0, alpha: 1) - group.ring2EndColor = #colorLiteral(red: 0.7176470588, green: 1, blue: 0, alpha: 1) - group.ring3StartColor = #colorLiteral(red: 0, green: 0.7294117647, blue: 0.8823529412, alpha: 1) - group.ring3EndColor = #colorLiteral(red: 0, green: 0.9803921569, blue: 0.8156862745, alpha: 1) - group.ring1.progress = 1.0 - group.ring2.progress = 1.0 - group.ring3.progress = 1.0 - icon.addSubview(group) - - UIGraphicsBeginImageContextWithOptions(size, true, scale) - icon.drawHierarchy(in: rect, afterScreenUpdates: true) - let image = UIGraphicsGetImageFromCurrentImageContext()! - UIGraphicsEndImageContext() - - return image -} diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Info.plist b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Info.plist deleted file mode 100644 index a905c2b55..000000000 --- a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/Info.plist +++ /dev/null @@ -1,49 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - Rings - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UIStatusBarStyle - UIStatusBarStyleLightContent - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/MKRingProgressGroupButton.swift b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/MKRingProgressGroupButton.swift deleted file mode 100644 index 1a42e07aa..000000000 --- a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/MKRingProgressGroupButton.swift +++ /dev/null @@ -1,83 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2015 Max Konovalov - -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. -*/ - -import UIKit - -class RingProgressGroupButton: UIButton { - - let contentView = RingProgressGroupView() - - let selectionIndicatorView = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: 20)) - - var contentMargin: CGFloat = 2 { - didSet { - setNeedsLayout() - } - } - - override init(frame: CGRect) { - super.init(frame: frame) - setup() - } - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - setup() - } - - private func setup() { - selectionIndicatorView.isUserInteractionEnabled = false - selectionIndicatorView.backgroundColor = .clear - selectionIndicatorView.layer.masksToBounds = false - selectionIndicatorView.layer.shadowColor = UIColor.white.cgColor - selectionIndicatorView.layer.shadowOpacity = 1.0 - selectionIndicatorView.layer.shadowRadius = 1.0 - selectionIndicatorView.layer.shadowOffset = CGSize(width: 0, height: 0) - addSubview(selectionIndicatorView) - selectionIndicatorView.isHidden = true - - contentView.isUserInteractionEnabled = false - addSubview(contentView) - } - - override func layoutSubviews() { - super.layoutSubviews() - let size = min(bounds.width, bounds.height) - contentMargin * 2 - contentView.frame = CGRect(x: (bounds.width - size)/2, y: (bounds.height - size)/2, width: size, height: size) - selectionIndicatorView.frame = contentView.frame - selectionIndicatorView.layer.shadowPath = CGPath(__byStroking: UIBezierPath(ovalIn: selectionIndicatorView.bounds.insetBy(dx: -1, dy: -1)).cgPath, transform: nil, lineWidth: 1.0, lineCap: .round, lineJoin: .round, miterLimit: 0) - } - - override var isHighlighted: Bool { - didSet { - contentView.alpha = isHighlighted ? 0.3 : 1.0 - } - } - - override var isSelected: Bool { - didSet { - selectionIndicatorView.isHidden = !isSelected - } - } -} diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/MKRingProgressGroupView.swift b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/MKRingProgressGroupView.swift deleted file mode 100644 index 88494ab3c..000000000 --- a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/MKRingProgressGroupView.swift +++ /dev/null @@ -1,108 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2015 Max Konovalov - -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. -*/ - -import UIKit -import MKRingProgressView - -@IBDesignable -class RingProgressGroupView: UIView { - - let ring1 = RingProgressView() - let ring2 = RingProgressView() - let ring3 = RingProgressView() - - @IBInspectable var ring1StartColor: UIColor = .red { - didSet { - ring1.startColor = ring1StartColor - } - } - - @IBInspectable var ring1EndColor: UIColor = .blue { - didSet { - ring1.endColor = ring1EndColor - } - } - - @IBInspectable var ring2StartColor: UIColor = .red { - didSet { - ring2.startColor = ring2StartColor - } - } - - @IBInspectable var ring2EndColor: UIColor = .blue { - didSet { - ring2.endColor = ring2EndColor - } - } - - @IBInspectable var ring3StartColor: UIColor = .red { - didSet { - ring3.startColor = ring3StartColor - } - } - - @IBInspectable var ring3EndColor: UIColor = .blue { - didSet { - ring3.endColor = ring3EndColor - } - } - - @IBInspectable var ringWidth: CGFloat = 20 { - didSet { - ring1.ringWidth = ringWidth - ring2.ringWidth = ringWidth - ring3.ringWidth = ringWidth - setNeedsLayout() - } - } - - @IBInspectable var ringSpacing: CGFloat = 2 { - didSet { - setNeedsLayout() - } - } - - override init(frame: CGRect) { - super.init(frame: frame) - setup() - } - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - setup() - } - - private func setup() { - addSubview(ring1) - addSubview(ring2) - addSubview(ring3) - } - - override func layoutSubviews() { - super.layoutSubviews() - ring1.frame = bounds - ring2.frame = bounds.insetBy(dx: ringWidth + ringSpacing, dy: ringWidth + ringSpacing) - ring3.frame = bounds.insetBy(dx: 2 * ringWidth + 2 * ringSpacing, dy: 2 * ringWidth + 2 * ringSpacing) - } -} diff --git a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/ViewController.swift b/Dependencies/MKRingProgressView/Example/ActivityRingsExample/ViewController.swift deleted file mode 100644 index 5d86a5ec2..000000000 --- a/Dependencies/MKRingProgressView/Example/ActivityRingsExample/ViewController.swift +++ /dev/null @@ -1,117 +0,0 @@ -// -// ViewController.swift -// MKRingProgressViewExample -// -// Created by Max Konovalov on 20/10/15. -// Copyright © 2015 Max Konovalov. All rights reserved. -// - -import UIKit - -class ViewController: UIViewController { - - @IBOutlet weak var groupContainerView: UIView! - @IBOutlet weak var progressGroup: RingProgressGroupView! - - @IBOutlet weak var iconsHeightConstraint: NSLayoutConstraint! - - var buttons = [RingProgressGroupButton]() - var selectedIndex = 0 - - override func viewDidLoad() { - super.viewDidLoad() - - let containerView = UIView(frame: navigationController!.navigationBar.bounds) - navigationController!.navigationBar.addSubview(containerView) - - // These are optional and only serve to improve accessibility - progressGroup.ring1.accessibilityLabel = NSLocalizedString("Move", comment: "") - progressGroup.ring2.accessibilityLabel = NSLocalizedString("Exercise", comment: "") - progressGroup.ring3.accessibilityLabel = NSLocalizedString("Stand", comment: "") - - let n = 7 - for i in 0.. selectedIndex) ? -self.view.frame.width : self.view.frame.width - - buttons[selectedIndex].isSelected = false - sender.isSelected = true - selectedIndex = newIndex - - UIView.animate(withDuration: 0.2, delay: 0.0, usingSpringWithDamping: 0.9, initialSpringVelocity: 0.0, options: [], animations: { () -> Void in - self.groupContainerView.transform = CGAffineTransform(translationX: dx, y: 0) - }) { (_) -> Void in - self.groupContainerView.transform = CGAffineTransform(translationX: -dx, y: 0) - self.progressGroup.ring1.progress = 0.0 - self.progressGroup.ring2.progress = 0.0 - self.progressGroup.ring3.progress = 0.0 - UIView.animate(withDuration: 0.3, delay: 0.0, usingSpringWithDamping: 0.9, initialSpringVelocity: 0.0, options: [], animations: { () -> Void in - self.groupContainerView.transform = CGAffineTransform.identity - }, completion: { (_) -> Void in - self.updateMainGroupProgress() - }) - } - } - - private func updateButtonsProgress() { - UIView.animate(withDuration: 0.5) { - for button in self.buttons { - button.contentView.ring1.progress = Double(arc4random() % 200) / 100.0 - button.contentView.ring2.progress = Double(arc4random() % 200) / 100.0 - button.contentView.ring3.progress = Double(arc4random() % 200) / 100.0 - } - } - } - - private func updateMainGroupProgress(delay: TimeInterval = 0.0) { - let selectedGroup = buttons[selectedIndex] - UIView.animate(withDuration: 1.0, delay: delay, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.0, options: [], animations: { - self.progressGroup.ring1.progress = selectedGroup.contentView.ring1.progress - self.progressGroup.ring2.progress = selectedGroup.contentView.ring2.progress - self.progressGroup.ring3.progress = selectedGroup.contentView.ring3.progress - }, completion: nil) - } - - @IBAction func randomize(_ sender: AnyObject? = nil) { - updateButtonsProgress() - updateMainGroupProgress() - } - -} diff --git a/Dependencies/MKRingProgressView/Example/MKRingProgressViewExample.xcodeproj/project.pbxproj b/Dependencies/MKRingProgressView/Example/MKRingProgressViewExample.xcodeproj/project.pbxproj deleted file mode 100644 index 36ba58d42..000000000 --- a/Dependencies/MKRingProgressView/Example/MKRingProgressViewExample.xcodeproj/project.pbxproj +++ /dev/null @@ -1,587 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 5022C19720B803AB0068B650 /* Icon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5022C19620B803AB0068B650 /* Icon.swift */; }; - 50246419217CCA2B00454379 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50246418217CCA2B00454379 /* AppDelegate.swift */; }; - 5024641B217CCA2B00454379 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5024641A217CCA2B00454379 /* ViewController.swift */; }; - 5024641E217CCA2B00454379 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5024641C217CCA2B00454379 /* Main.storyboard */; }; - 50246420217CCA2B00454379 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5024641F217CCA2B00454379 /* Assets.xcassets */; }; - 50246423217CCA2B00454379 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 50246421217CCA2B00454379 /* LaunchScreen.storyboard */; }; - 50246428217CCB1000454379 /* MKRingProgressView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5025B8911E52FF5D0018FA7D /* MKRingProgressView.framework */; }; - 50246429217CCB1000454379 /* MKRingProgressView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5025B8911E52FF5D0018FA7D /* MKRingProgressView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 5025B8921E52FF6F0018FA7D /* MKRingProgressView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5025B8911E52FF5D0018FA7D /* MKRingProgressView.framework */; }; - 5025B8941E52FFC90018FA7D /* MKRingProgressView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5025B8911E52FF5D0018FA7D /* MKRingProgressView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 507AB38C217E231800D87320 /* ParametersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507AB38B217E231800D87320 /* ParametersViewController.swift */; }; - 507AB38F217E2A2600D87320 /* Icon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507AB38E217E2A2600D87320 /* Icon.swift */; }; - 508CBF7B1BD6C2C7008A3B4E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508CBF7A1BD6C2C7008A3B4E /* AppDelegate.swift */; }; - 508CBF7D1BD6C2C7008A3B4E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508CBF7C1BD6C2C7008A3B4E /* ViewController.swift */; }; - 508CBF801BD6C2C7008A3B4E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 508CBF7E1BD6C2C7008A3B4E /* Main.storyboard */; }; - 508CBF821BD6C2C7008A3B4E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 508CBF811BD6C2C7008A3B4E /* Assets.xcassets */; }; - 508CBF851BD6C2C7008A3B4E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 508CBF831BD6C2C7008A3B4E /* LaunchScreen.storyboard */; }; - 508CBF921BD6CA0C008A3B4E /* MKRingProgressGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508CBF911BD6CA0C008A3B4E /* MKRingProgressGroupView.swift */; }; - 508CBF951BD6DBC2008A3B4E /* MKRingProgressGroupButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508CBF941BD6DBC2008A3B4E /* MKRingProgressGroupButton.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 5025B8901E52FF5D0018FA7D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 5025B88C1E52FF5D0018FA7D /* MKRingProgressView.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 5085266E1E52FDC000D611F4; - remoteInfo = MKRingProgressView; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 5024642C217CCB1000454379 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 50246429217CCB1000454379 /* MKRingProgressView.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; - 5025B8971E52FFC90018FA7D /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 5025B8941E52FFC90018FA7D /* MKRingProgressView.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 5022C19620B803AB0068B650 /* Icon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icon.swift; sourceTree = ""; }; - 50246416217CCA2A00454379 /* ProgressRingExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ProgressRingExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 50246418217CCA2B00454379 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 5024641A217CCA2B00454379 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - 5024641D217CCA2B00454379 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 5024641F217CCA2B00454379 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 50246422217CCA2B00454379 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 50246424217CCA2B00454379 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 5025B88C1E52FF5D0018FA7D /* MKRingProgressView.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = MKRingProgressView.xcodeproj; path = ../MKRingProgressView.xcodeproj; sourceTree = ""; }; - 507AB38B217E231800D87320 /* ParametersViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParametersViewController.swift; sourceTree = ""; }; - 507AB38E217E2A2600D87320 /* Icon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icon.swift; sourceTree = ""; }; - 508CBF771BD6C2C7008A3B4E /* ActivityRingsExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ActivityRingsExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 508CBF7A1BD6C2C7008A3B4E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 508CBF7C1BD6C2C7008A3B4E /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - 508CBF7F1BD6C2C7008A3B4E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 508CBF811BD6C2C7008A3B4E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 508CBF841BD6C2C7008A3B4E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 508CBF861BD6C2C7008A3B4E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 508CBF911BD6CA0C008A3B4E /* MKRingProgressGroupView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MKRingProgressGroupView.swift; sourceTree = ""; }; - 508CBF941BD6DBC2008A3B4E /* MKRingProgressGroupButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MKRingProgressGroupButton.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 50246413217CCA2A00454379 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 50246428217CCB1000454379 /* MKRingProgressView.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 508CBF741BD6C2C7008A3B4E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 5025B8921E52FF6F0018FA7D /* MKRingProgressView.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 50246417217CCA2B00454379 /* ProgressRingExample */ = { - isa = PBXGroup; - children = ( - 50246418217CCA2B00454379 /* AppDelegate.swift */, - 507AB38E217E2A2600D87320 /* Icon.swift */, - 5024641A217CCA2B00454379 /* ViewController.swift */, - 507AB38B217E231800D87320 /* ParametersViewController.swift */, - 5024641C217CCA2B00454379 /* Main.storyboard */, - 50246421217CCA2B00454379 /* LaunchScreen.storyboard */, - 5024641F217CCA2B00454379 /* Assets.xcassets */, - 50246424217CCA2B00454379 /* Info.plist */, - ); - path = ProgressRingExample; - sourceTree = ""; - }; - 5025B88D1E52FF5D0018FA7D /* Products */ = { - isa = PBXGroup; - children = ( - 5025B8911E52FF5D0018FA7D /* MKRingProgressView.framework */, - ); - name = Products; - sourceTree = ""; - }; - 508CBF6E1BD6C2C7008A3B4E = { - isa = PBXGroup; - children = ( - 5025B88C1E52FF5D0018FA7D /* MKRingProgressView.xcodeproj */, - 508CBF791BD6C2C7008A3B4E /* ActivityRingsExample */, - 50246417217CCA2B00454379 /* ProgressRingExample */, - 508CBF781BD6C2C7008A3B4E /* Products */, - ); - sourceTree = ""; - }; - 508CBF781BD6C2C7008A3B4E /* Products */ = { - isa = PBXGroup; - children = ( - 508CBF771BD6C2C7008A3B4E /* ActivityRingsExample.app */, - 50246416217CCA2A00454379 /* ProgressRingExample.app */, - ); - name = Products; - sourceTree = ""; - }; - 508CBF791BD6C2C7008A3B4E /* ActivityRingsExample */ = { - isa = PBXGroup; - children = ( - 50DEDC431BD7811E009C3882 /* MKRingProgressGroup */, - 508CBF7A1BD6C2C7008A3B4E /* AppDelegate.swift */, - 5022C19620B803AB0068B650 /* Icon.swift */, - 508CBF7C1BD6C2C7008A3B4E /* ViewController.swift */, - 508CBF7E1BD6C2C7008A3B4E /* Main.storyboard */, - 508CBF831BD6C2C7008A3B4E /* LaunchScreen.storyboard */, - 508CBF811BD6C2C7008A3B4E /* Assets.xcassets */, - 508CBF861BD6C2C7008A3B4E /* Info.plist */, - ); - path = ActivityRingsExample; - sourceTree = ""; - }; - 50DEDC431BD7811E009C3882 /* MKRingProgressGroup */ = { - isa = PBXGroup; - children = ( - 508CBF911BD6CA0C008A3B4E /* MKRingProgressGroupView.swift */, - 508CBF941BD6DBC2008A3B4E /* MKRingProgressGroupButton.swift */, - ); - name = MKRingProgressGroup; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 50246415217CCA2A00454379 /* ProgressRingExample */ = { - isa = PBXNativeTarget; - buildConfigurationList = 50246425217CCA2B00454379 /* Build configuration list for PBXNativeTarget "ProgressRingExample" */; - buildPhases = ( - 50246412217CCA2A00454379 /* Sources */, - 50246413217CCA2A00454379 /* Frameworks */, - 50246414217CCA2A00454379 /* Resources */, - 5024642C217CCB1000454379 /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ProgressRingExample; - productName = RingProgressExample; - productReference = 50246416217CCA2A00454379 /* ProgressRingExample.app */; - productType = "com.apple.product-type.application"; - }; - 508CBF761BD6C2C7008A3B4E /* ActivityRingsExample */ = { - isa = PBXNativeTarget; - buildConfigurationList = 508CBF891BD6C2C7008A3B4E /* Build configuration list for PBXNativeTarget "ActivityRingsExample" */; - buildPhases = ( - 508CBF731BD6C2C7008A3B4E /* Sources */, - 508CBF741BD6C2C7008A3B4E /* Frameworks */, - 508CBF751BD6C2C7008A3B4E /* Resources */, - 5025B8971E52FFC90018FA7D /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ActivityRingsExample; - productName = MKRingProgressViewExample; - productReference = 508CBF771BD6C2C7008A3B4E /* ActivityRingsExample.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 508CBF6F1BD6C2C7008A3B4E /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 1000; - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "Max Konovalov"; - TargetAttributes = { - 50246415217CCA2A00454379 = { - CreatedOnToolsVersion = 10.0; - ProvisioningStyle = Manual; - }; - 508CBF761BD6C2C7008A3B4E = { - CreatedOnToolsVersion = 7.0.1; - LastSwiftMigration = 0930; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 508CBF721BD6C2C7008A3B4E /* Build configuration list for PBXProject "MKRingProgressViewExample" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 508CBF6E1BD6C2C7008A3B4E; - productRefGroup = 508CBF781BD6C2C7008A3B4E /* Products */; - projectDirPath = ""; - projectReferences = ( - { - ProductGroup = 5025B88D1E52FF5D0018FA7D /* Products */; - ProjectRef = 5025B88C1E52FF5D0018FA7D /* MKRingProgressView.xcodeproj */; - }, - ); - projectRoot = ""; - targets = ( - 508CBF761BD6C2C7008A3B4E /* ActivityRingsExample */, - 50246415217CCA2A00454379 /* ProgressRingExample */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXReferenceProxy section */ - 5025B8911E52FF5D0018FA7D /* MKRingProgressView.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = MKRingProgressView.framework; - remoteRef = 5025B8901E52FF5D0018FA7D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - -/* Begin PBXResourcesBuildPhase section */ - 50246414217CCA2A00454379 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 50246423217CCA2B00454379 /* LaunchScreen.storyboard in Resources */, - 50246420217CCA2B00454379 /* Assets.xcassets in Resources */, - 5024641E217CCA2B00454379 /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 508CBF751BD6C2C7008A3B4E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 508CBF851BD6C2C7008A3B4E /* LaunchScreen.storyboard in Resources */, - 508CBF821BD6C2C7008A3B4E /* Assets.xcassets in Resources */, - 508CBF801BD6C2C7008A3B4E /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 50246412217CCA2A00454379 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 5024641B217CCA2B00454379 /* ViewController.swift in Sources */, - 507AB38C217E231800D87320 /* ParametersViewController.swift in Sources */, - 507AB38F217E2A2600D87320 /* Icon.swift in Sources */, - 50246419217CCA2B00454379 /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 508CBF731BD6C2C7008A3B4E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 508CBF7D1BD6C2C7008A3B4E /* ViewController.swift in Sources */, - 508CBF7B1BD6C2C7008A3B4E /* AppDelegate.swift in Sources */, - 508CBF951BD6DBC2008A3B4E /* MKRingProgressGroupButton.swift in Sources */, - 5022C19720B803AB0068B650 /* Icon.swift in Sources */, - 508CBF921BD6CA0C008A3B4E /* MKRingProgressGroupView.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 5024641C217CCA2B00454379 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 5024641D217CCA2B00454379 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 50246421217CCA2B00454379 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 50246422217CCA2B00454379 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; - 508CBF7E1BD6C2C7008A3B4E /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 508CBF7F1BD6C2C7008A3B4E /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 508CBF831BD6C2C7008A3B4E /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 508CBF841BD6C2C7008A3B4E /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 50246426217CCA2B00454379 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = ""; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = "$(SRCROOT)/ProgressRingExample/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.maxkonovalov.ProgressRingExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 50246427217CCA2B00454379 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = ""; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = "$(SRCROOT)/ProgressRingExample/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.maxkonovalov.ProgressRingExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 508CBF871BD6C2C7008A3B4E /* 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; - 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 = 8.2; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 508CBF881BD6C2C7008A3B4E /* 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; - 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 = 8.2; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 508CBF8A1BD6C2C7008A3B4E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = "$(SRCROOT)/ActivityRingsExample/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.maxkonovalov.ActivityRingsExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_COMPILATION_MODE = singlefile; - }; - name = Debug; - }; - 508CBF8B1BD6C2C7008A3B4E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = "$(SRCROOT)/ActivityRingsExample/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.maxkonovalov.ActivityRingsExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 50246425217CCA2B00454379 /* Build configuration list for PBXNativeTarget "ProgressRingExample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 50246426217CCA2B00454379 /* Debug */, - 50246427217CCA2B00454379 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 508CBF721BD6C2C7008A3B4E /* Build configuration list for PBXProject "MKRingProgressViewExample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 508CBF871BD6C2C7008A3B4E /* Debug */, - 508CBF881BD6C2C7008A3B4E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 508CBF891BD6C2C7008A3B4E /* Build configuration list for PBXNativeTarget "ActivityRingsExample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 508CBF8A1BD6C2C7008A3B4E /* Debug */, - 508CBF8B1BD6C2C7008A3B4E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 508CBF6F1BD6C2C7008A3B4E /* Project object */; -} diff --git a/Dependencies/MKRingProgressView/Example/MKRingProgressViewExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Dependencies/MKRingProgressView/Example/MKRingProgressViewExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 371651bf2..000000000 --- a/Dependencies/MKRingProgressView/Example/MKRingProgressViewExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Dependencies/MKRingProgressView/Example/MKRingProgressViewExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dependencies/MKRingProgressView/Example/MKRingProgressViewExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Dependencies/MKRingProgressView/Example/MKRingProgressViewExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/AppDelegate.swift b/Dependencies/MKRingProgressView/Example/ProgressRingExample/AppDelegate.swift deleted file mode 100644 index 9e2280185..000000000 --- a/Dependencies/MKRingProgressView/Example/ProgressRingExample/AppDelegate.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// AppDelegate.swift -// RingProgressExample -// -// Created by Max Konovalov on 21/10/2018. -// Copyright © 2018 Max Konovalov. All rights reserved. -// - -import UIKit - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? - - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - //let icon = generateAppIcon(scale: 2) - return true - } - - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - -} - diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Contents.json b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 98ae57ec1..000000000 --- a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom": "iphone", - "filename" : "Icon-20@2x.png", - "scale": "2x" - }, - { - "size" : "20x20", - "idiom": "iphone", - "filename" : "Icon-20@3x.png", - "scale": "3x" - }, - { - "size" : "20x20", - "idiom": "ipad", - "filename" : "Icon-20.png", - "scale": "1x" - }, - { - "size" : "20x20", - "idiom": "ipad", - "filename" : "Icon-20@2x.png", - "scale": "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-60@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-29.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-40.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-76.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-1024.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-1024.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-1024.png deleted file mode 100644 index 374a3f02e..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-1024.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-20.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-20.png deleted file mode 100644 index e5cef17a2..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-20.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png deleted file mode 100644 index 92715c43f..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png deleted file mode 100644 index c09c10e5d..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-29.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-29.png deleted file mode 100644 index e1cac0beb..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-29.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png deleted file mode 100644 index fe8e04698..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png deleted file mode 100644 index c7c20c935..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-40.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-40.png deleted file mode 100644 index 92715c43f..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-40.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png deleted file mode 100644 index 8d9faf15f..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png deleted file mode 100644 index 4887a8bef..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png deleted file mode 100644 index 4887a8bef..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png deleted file mode 100644 index ce988aefc..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-76.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-76.png deleted file mode 100644 index 819156f1d..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-76.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png deleted file mode 100644 index ff069a262..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png deleted file mode 100644 index 4b9ca75b1..000000000 Binary files a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/Contents.json b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/Contents.json deleted file mode 100644 index da4a164c9..000000000 --- a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Base.lproj/LaunchScreen.storyboard b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 9362cb623..000000000 --- a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Base.lproj/Main.storyboard b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Base.lproj/Main.storyboard deleted file mode 100644 index 3cbbc0fc7..000000000 --- a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Base.lproj/Main.storyboard +++ /dev/null @@ -1,257 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Icon.swift b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Icon.swift deleted file mode 100644 index 0ee6a784f..000000000 --- a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Icon.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// Icon.swift -// ProgressRingExample -// -// Created by Max Konovalov on 22/10/2018. -// Copyright © 2018 Max Konovalov. All rights reserved. -// - -import UIKit -import MKRingProgressView - -func generateAppIcon(scale: CGFloat = 1.0) -> UIImage { - let size = CGSize(width: 512, height: 512) - let rect = CGRect(origin: .zero, size: size) - - let icon = UIView(frame: rect) - icon.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) - - let ring = RingProgressView(frame: icon.bounds.insetBy(dx: 66, dy: 66)) - ring.ringWidth = 93 - ring.startColor = #colorLiteral(red: 1, green: 0.07450980392, blue: 0.3254901961, alpha: 1) - ring.endColor = #colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1) - ring.progress = 1.0 - icon.addSubview(ring) - - UIGraphicsBeginImageContextWithOptions(size, true, scale) - icon.drawHierarchy(in: rect, afterScreenUpdates: true) - let image = UIGraphicsGetImageFromCurrentImageContext()! - UIGraphicsEndImageContext() - - return image -} diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Info.plist b/Dependencies/MKRingProgressView/Example/ProgressRingExample/Info.plist deleted file mode 100644 index cc1fdac00..000000000 --- a/Dependencies/MKRingProgressView/Example/ProgressRingExample/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Ring - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/ParametersViewController.swift b/Dependencies/MKRingProgressView/Example/ProgressRingExample/ParametersViewController.swift deleted file mode 100644 index 4f78aee35..000000000 --- a/Dependencies/MKRingProgressView/Example/ProgressRingExample/ParametersViewController.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// ParametersViewController.swift -// ProgressRingExample -// -// Created by Max Konovalov on 22/10/2018. -// Copyright © 2018 Max Konovalov. All rights reserved. -// - -import MKRingProgressView -import UIKit - -protocol ParametersViewControllerDelegate: class { - func parametersViewControllerDidChangeProgress(_ progress: Double) - func parametersViewControllerDidChangeStyle(_ style: RingProgressViewStyle) - func parametersViewControllerDidChangeShadowOpacity(_ shadowOpacity: CGFloat) - func parametersViewControllerDidChangeHidesRingForZeroProgressValue(_ hidesRingForZeroProgress: Bool) -} - -class ParametersViewController: UITableViewController { - weak var delegate: ParametersViewControllerDelegate? - - override func viewDidLoad() { - super.viewDidLoad() - tableView.tableFooterView = UIView() - } - - @IBAction func progressChanged(_ sender: UISlider) { - let progress = Double(sender.value) - delegate?.parametersViewControllerDidChangeProgress(progress) - } - - @IBAction func styleChanged(_ sender: UISegmentedControl) { - guard let style = RingProgressViewStyle(rawValue: sender.selectedSegmentIndex) else { - return - } - delegate?.parametersViewControllerDidChangeStyle(style) - } - - @IBAction func shadowChanged(_ sender: UISwitch) { - let shadowOpacity: CGFloat = sender.isOn ? 1.0 : 0.0 - delegate?.parametersViewControllerDidChangeShadowOpacity(shadowOpacity) - } - - @IBAction func hidesRingForZeroProgressChanged(_ sender: UISwitch) { - let hidesRingForZeroProgress = sender.isOn - delegate?.parametersViewControllerDidChangeHidesRingForZeroProgressValue(hidesRingForZeroProgress) - } -} diff --git a/Dependencies/MKRingProgressView/Example/ProgressRingExample/ViewController.swift b/Dependencies/MKRingProgressView/Example/ProgressRingExample/ViewController.swift deleted file mode 100644 index 45a0e7ff0..000000000 --- a/Dependencies/MKRingProgressView/Example/ProgressRingExample/ViewController.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// ViewController.swift -// RingProgressExample -// -// Created by Max Konovalov on 21/10/2018. -// Copyright © 2018 Max Konovalov. All rights reserved. -// - -import MKRingProgressView -import UIKit - -class ViewController: UIViewController { - @IBOutlet var ringProgressView: RingProgressView! - @IBOutlet var valueLabel: UILabel! - - override func viewDidLayoutSubviews() { - super.viewDidLayoutSubviews() - ringProgressView.ringWidth = ringProgressView.bounds.width * 0.2 - } - - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - if case let parametersViewController as ParametersViewController = segue.destination { - parametersViewController.delegate = self - } - } -} - -extension ViewController: ParametersViewControllerDelegate { - func parametersViewControllerDidChangeProgress(_ progress: Double) { - ringProgressView.progress = progress - valueLabel.text = String(format: "%.2f", progress) - } - - func parametersViewControllerDidChangeStyle(_ style: RingProgressViewStyle) { - ringProgressView.style = style - } - - func parametersViewControllerDidChangeShadowOpacity(_ shadowOpacity: CGFloat) { - ringProgressView.shadowOpacity = shadowOpacity - } - - func parametersViewControllerDidChangeHidesRingForZeroProgressValue(_ hidesRingForZeroProgress: Bool) { - ringProgressView.hidesRingForZeroProgress = hidesRingForZeroProgress - } -} diff --git a/Dependencies/MKRingProgressView/LICENSE b/Dependencies/MKRingProgressView/LICENSE deleted file mode 100644 index 8f030dd59..000000000 --- a/Dependencies/MKRingProgressView/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Max Konovalov - -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/Dependencies/MKRingProgressView/MKRingProgressView.png b/Dependencies/MKRingProgressView/MKRingProgressView.png deleted file mode 100644 index 859fef0d5..000000000 Binary files a/Dependencies/MKRingProgressView/MKRingProgressView.png and /dev/null differ diff --git a/Dependencies/MKRingProgressView/MKRingProgressView.podspec b/Dependencies/MKRingProgressView/MKRingProgressView.podspec deleted file mode 100644 index 013a61438..000000000 --- a/Dependencies/MKRingProgressView/MKRingProgressView.podspec +++ /dev/null @@ -1,19 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'MKRingProgressView' - s.version = '2.2.2' - s.summary = 'Ring progress view similar to Activity app on Apple Watch' - s.homepage = 'https://github.com/maxkonovalov/MKRingProgressView' - s.license = 'MIT' - s.author = 'Max Konovalov' - s.source = { git: 'https://github.com/maxkonovalov/MKRingProgressView.git', tag: s.version.to_s } - - s.source_files = 'MKRingProgressView/**/*.swift' - - s.ios.deployment_target = '8.2' - s.tvos.deployment_target = '9.0' - - s.swift_version = '5.0' - s.swift_versions = ['4.0', '4.2', '5.0'] - - s.frameworks = 'UIKit' -end diff --git a/Dependencies/MKRingProgressView/MKRingProgressView.xcodeproj/project.pbxproj b/Dependencies/MKRingProgressView/MKRingProgressView.xcodeproj/project.pbxproj deleted file mode 100644 index 1127013ad..000000000 --- a/Dependencies/MKRingProgressView/MKRingProgressView.xcodeproj/project.pbxproj +++ /dev/null @@ -1,342 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 5022C19A20B872EA0068B650 /* MKRingProgressLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5022C19920B872EA0068B650 /* MKRingProgressLayer.swift */; }; - 508526731E52FDC000D611F4 /* MKRingProgressView.h in Headers */ = {isa = PBXBuildFile; fileRef = 508526711E52FDC000D611F4 /* MKRingProgressView.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5085267B1E52FE7800D611F4 /* MKGradientGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508526791E52FE7800D611F4 /* MKGradientGenerator.swift */; }; - 5085267C1E52FE7800D611F4 /* MKRingProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5085267A1E52FE7800D611F4 /* MKRingProgressView.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 5022C19920B872EA0068B650 /* MKRingProgressLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MKRingProgressLayer.swift; sourceTree = ""; }; - 5085266E1E52FDC000D611F4 /* MKRingProgressView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MKRingProgressView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 508526711E52FDC000D611F4 /* MKRingProgressView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MKRingProgressView.h; sourceTree = ""; }; - 508526721E52FDC000D611F4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 508526791E52FE7800D611F4 /* MKGradientGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MKGradientGenerator.swift; sourceTree = ""; }; - 5085267A1E52FE7800D611F4 /* MKRingProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MKRingProgressView.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 5085266A1E52FDC000D611F4 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 508526641E52FDC000D611F4 = { - isa = PBXGroup; - children = ( - 508526701E52FDC000D611F4 /* MKRingProgressView */, - 5085266F1E52FDC000D611F4 /* Products */, - ); - sourceTree = ""; - }; - 5085266F1E52FDC000D611F4 /* Products */ = { - isa = PBXGroup; - children = ( - 5085266E1E52FDC000D611F4 /* MKRingProgressView.framework */, - ); - name = Products; - sourceTree = ""; - }; - 508526701E52FDC000D611F4 /* MKRingProgressView */ = { - isa = PBXGroup; - children = ( - 508526711E52FDC000D611F4 /* MKRingProgressView.h */, - 508526791E52FE7800D611F4 /* MKGradientGenerator.swift */, - 5022C19920B872EA0068B650 /* MKRingProgressLayer.swift */, - 5085267A1E52FE7800D611F4 /* MKRingProgressView.swift */, - 508526721E52FDC000D611F4 /* Info.plist */, - ); - path = MKRingProgressView; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 5085266B1E52FDC000D611F4 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 508526731E52FDC000D611F4 /* MKRingProgressView.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 5085266D1E52FDC000D611F4 /* MKRingProgressView */ = { - isa = PBXNativeTarget; - buildConfigurationList = 508526761E52FDC000D611F4 /* Build configuration list for PBXNativeTarget "MKRingProgressView" */; - buildPhases = ( - 5085266B1E52FDC000D611F4 /* Headers */, - 508526691E52FDC000D611F4 /* Sources */, - 5085266A1E52FDC000D611F4 /* Frameworks */, - 5085266C1E52FDC000D611F4 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = MKRingProgressView; - productName = MKRingProgressView; - productReference = 5085266E1E52FDC000D611F4 /* MKRingProgressView.framework */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 508526651E52FDC000D611F4 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1230; - ORGANIZATIONNAME = "Max Konovalov"; - TargetAttributes = { - 5085266D1E52FDC000D611F4 = { - CreatedOnToolsVersion = 8.2.1; - LastSwiftMigration = 1020; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 508526681E52FDC000D611F4 /* Build configuration list for PBXProject "MKRingProgressView" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 508526641E52FDC000D611F4; - productRefGroup = 5085266F1E52FDC000D611F4 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 5085266D1E52FDC000D611F4 /* MKRingProgressView */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 5085266C1E52FDC000D611F4 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 508526691E52FDC000D611F4 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 5085267B1E52FE7800D611F4 /* MKGradientGenerator.swift in Sources */, - 5022C19A20B872EA0068B650 /* MKRingProgressLayer.swift in Sources */, - 5085267C1E52FE7800D611F4 /* MKRingProgressView.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 508526741E52FDC000D611F4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = 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_DOCUMENTATION_COMMENTS = YES; - 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - 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; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - 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.6; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TVOS_DEPLOYMENT_TARGET = 12.0; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 508526751E52FDC000D611F4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = 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_DOCUMENTATION_COMMENTS = YES; - 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - 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; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - 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.6; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TVOS_DEPLOYMENT_TARGET = 12.0; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 508526771E52FDC000D611F4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = MKRingProgressView/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.maxkonovalov.MKRingProgressView; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 508526781E52FDC000D611F4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = MKRingProgressView/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.maxkonovalov.MKRingProgressView; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 508526681E52FDC000D611F4 /* Build configuration list for PBXProject "MKRingProgressView" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 508526741E52FDC000D611F4 /* Debug */, - 508526751E52FDC000D611F4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 508526761E52FDC000D611F4 /* Build configuration list for PBXNativeTarget "MKRingProgressView" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 508526771E52FDC000D611F4 /* Debug */, - 508526781E52FDC000D611F4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 508526651E52FDC000D611F4 /* Project object */; -} diff --git a/Dependencies/MKRingProgressView/MKRingProgressView.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Dependencies/MKRingProgressView/MKRingProgressView.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 24780a9c2..000000000 --- a/Dependencies/MKRingProgressView/MKRingProgressView.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Dependencies/MKRingProgressView/MKRingProgressView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dependencies/MKRingProgressView/MKRingProgressView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Dependencies/MKRingProgressView/MKRingProgressView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Dependencies/MKRingProgressView/MKRingProgressView/Info.plist b/Dependencies/MKRingProgressView/MKRingProgressView/Info.plist deleted file mode 100644 index fbe1e6b31..000000000 --- a/Dependencies/MKRingProgressView/MKRingProgressView/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Dependencies/MKRingProgressView/MKRingProgressView/MKGradientGenerator.swift b/Dependencies/MKRingProgressView/MKRingProgressView/MKGradientGenerator.swift deleted file mode 100644 index 21e90c993..000000000 --- a/Dependencies/MKRingProgressView/MKRingProgressView/MKGradientGenerator.swift +++ /dev/null @@ -1,223 +0,0 @@ -/* - The MIT License (MIT) - - Copyright (c) 2015 Max Konovalov - - 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. - */ - -import UIKit - -internal final class GradientGenerator { - - var scale: CGFloat = UIScreen.main.scale { - didSet { - if scale != oldValue { - reset() - } - } - } - - var size: CGSize = .zero { - didSet { - if size != oldValue { - reset() - } - } - } - - var colors: [CGColor] = [] { - didSet { - if colors != oldValue { - reset() - } - } - } - - var locations: [Float] = [] { - didSet { - if locations != oldValue { - reset() - } - } - } - - var startPoint: CGPoint = CGPoint(x: 0.5, y: 0.5) { - didSet { - if startPoint != oldValue { - reset() - } - } - } - - var endPoint: CGPoint = CGPoint(x: 1.0, y: 0.5) { - didSet { - if endPoint != oldValue { - reset() - } - } - } - - private var generatedImage: CGImage? - - func reset() { - generatedImage = nil - } - - func image() -> CGImage { - if let image = generatedImage { - return image - } - - let w = Int(size.width * scale) - let h = Int(size.height * scale) - let bitsPerComponent: Int = MemoryLayout.size * 8 - let bytesPerPixel: Int = bitsPerComponent * 4 / 8 - - var data = [ARGB]() - - for y in 0.. ARGB { - let t = conicalGradientStop(point, size, startPoint, endPoint) - return interpolatedColor(t, colors, locations) - } - - private func conicalGradientStop(_ point: CGPoint, _ size: CGSize, _ g0: CGPoint, _ g1: CGPoint) -> Float { - let c = CGPoint(x: size.width * g0.x, y: size.height * g0.y) - let s = CGPoint(x: size.width * (g1.x - g0.x), y: size.height * (g1.y - g0.y)) - let q = atan2(s.y, s.x) - let p = CGPoint(x: point.x - c.x, y: point.y - c.y) - var a = atan2(p.y, p.x) - q - if a < 0 { - a += 2 * .pi - } - let t = a / (2 * .pi) - return Float(t) - } - - private func interpolatedColor(_ t: Float, _ colors: [CGColor], _ locations: [Float]) -> ARGB { - assert(!colors.isEmpty) - assert(colors.count == locations.count) - - var p0: Float = 0 - var p1: Float = 1 - - var c0 = colors.first! - var c1 = colors.last! - - for (i, v) in locations.enumerated() { - if v > p0 && t >= v { - p0 = v - c0 = colors[i] - } - if v < p1 && t <= v { - p1 = v - c1 = colors[i] - } - } - - let p: Float - if p0 == p1 { - p = 0 - } else { - p = lerp(t, inRange: p0...p1, outRange: 0...1) - } - - let color0 = ARGB(c0) - let color1 = ARGB(c1) - - return color0.interpolateTo(color1, p) - } - -} - -// MARK: - Color Data - -fileprivate struct ARGB { - let a: UInt8 = 0xff - var r: UInt8 - var g: UInt8 - var b: UInt8 -} - -extension ARGB: Equatable { - static func ==(lhs: ARGB, rhs: ARGB) -> Bool { - return (lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b) - } -} - -extension ARGB { - - init(_ color: CGColor) { - let c = color.components?.map { min(max($0, 0.0), 1.0) } - switch color.numberOfComponents { - case 2: - self.init(r: UInt8((c?[0])! * 0xff), g: UInt8((c?[0])! * 0xff), b: UInt8((c?[0])! * 0xff)) - case 4: - self.init(r: UInt8((c?[0])! * 0xff), g: UInt8((c?[1])! * 0xff), b: UInt8((c?[2])! * 0xff)) - default: - self.init(r: 0, g: 0, b: 0) - } - } - - func interpolateTo(_ color: ARGB, _ t: Float) -> ARGB { - let r = lerp(t, self.r, color.r) - let g = lerp(t, self.g, color.g) - let b = lerp(t, self.b, color.b) - return ARGB(r: r, g: g, b: b) - } - -} - -// MARK: - Utility - -fileprivate func lerp(_ t: Float, _ a: UInt8, _ b: UInt8) -> UInt8 { - return UInt8(Float(a) + min(max(t, 0), 1) * (Float(b) - Float(a))) -} - -fileprivate func lerp(_ value: Float, inRange: ClosedRange, outRange: ClosedRange) -> Float { - return (value - inRange.lowerBound) * (outRange.upperBound - outRange.lowerBound) / (inRange.upperBound - inRange.lowerBound) + outRange.lowerBound -} diff --git a/Dependencies/MKRingProgressView/MKRingProgressView/MKRingProgressLayer.swift b/Dependencies/MKRingProgressView/MKRingProgressView/MKRingProgressLayer.swift deleted file mode 100644 index f379a95fa..000000000 --- a/Dependencies/MKRingProgressView/MKRingProgressView/MKRingProgressLayer.swift +++ /dev/null @@ -1,327 +0,0 @@ -/* - The MIT License (MIT) - - Copyright (c) 2015 Max Konovalov - - 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. - */ - -import UIKit - -@objc(MKRingProgressLayer) -open class RingProgressLayer: CALayer { - /// The progress ring start color. - @objc open var startColor: CGColor = UIColor.red.cgColor { - didSet { - setNeedsDisplay() - } - } - - /// The progress ring end color. - @objc open var endColor: CGColor = UIColor.blue.cgColor { - didSet { - setNeedsDisplay() - } - } - - /// The color of the background ring. - @objc open var backgroundRingColor: CGColor? { - didSet { - setNeedsDisplay() - } - } - - /// The width of the progress ring. - @objc open var ringWidth: CGFloat = 20 { - didSet { - setNeedsDisplay() - } - } - - /// The style of the progress line end (rounded or straight). - @objc open var progressStyle: RingProgressViewStyle = .round { - didSet { - setNeedsDisplay() - } - } - - /// The opacity of the shadow under the progress end. - @objc open var endShadowOpacity: CGFloat = 1.0 { - didSet { - endShadowOpacity = min(max(endShadowOpacity, 0.0), 1.0) - setNeedsDisplay() - } - } - - /// Whether or not to hide the progress ring when progress is zero. - @objc open var hidesRingForZeroProgress: Bool = false { - didSet { - setNeedsDisplay() - } - } - - /// Whether or not to allow anti-aliasing for the generated image. - @objc open var allowsAntialiasing: Bool = true { - didSet { - setNeedsDisplay() - } - } - - /// The scale of the generated gradient image. - /// Use lower values for better performance and higher values for more precise gradients. - @objc open var gradientImageScale: CGFloat = 1.0 { - didSet { - setNeedsDisplay() - } - } - - /// The current progress shown by the view. - /// Values less than 0.0 are clamped. Values greater than 1.0 present multiple revolutions of the progress ring. - @NSManaged public var progress: CGFloat - - /// Disable actions for `progress` property. - internal var disableProgressAnimation: Bool = false - - private let gradientGenerator = GradientGenerator() - - open override class func needsDisplay(forKey key: String) -> Bool { - if key == "progress" { - return true - } - return super.needsDisplay(forKey: key) - } - - open override func action(forKey event: String) -> CAAction? { - if !disableProgressAnimation, event == "progress" { - if let action = super.action(forKey: "opacity") as? CABasicAnimation { - let animation = action.copy() as! CABasicAnimation - animation.keyPath = event - animation.fromValue = presentation()?.value(forKey: event) - animation.toValue = nil - return animation - } else { - let animation = CABasicAnimation(keyPath: event) - animation.duration = 0.001 - return animation - } - } - return super.action(forKey: event) - } - - open override func display() { - contents = contentImage() - } - - func contentImage() -> CGImage? { - let size = bounds.size - if #available(iOS 10.0, tvOS 10.0, *) { - let format = UIGraphicsImageRendererFormat.default() - let image = UIGraphicsImageRenderer(size: size, format: format).image { ctx in - drawContent(in: ctx.cgContext) - } - return image.cgImage - } else { - UIGraphicsBeginImageContextWithOptions(size, false, 0) - guard let ctx = UIGraphicsGetCurrentContext() else { - return nil - } - drawContent(in: ctx) - let image = UIGraphicsGetImageFromCurrentImageContext()?.cgImage - UIGraphicsEndImageContext() - return image - } - } - - private func drawContent(in context: CGContext) { - context.setShouldAntialias(allowsAntialiasing) - context.setAllowsAntialiasing(allowsAntialiasing) - - let useGradient = startColor != endColor - - let squareSize = min(bounds.width, bounds.height) - let squareRect = CGRect(x: (bounds.width - squareSize) / 2, y: (bounds.height - squareSize) / 2, - width: squareSize, height: squareSize) - let gradientRect = squareRect.integral - - let w = min(ringWidth, squareSize / 2) - let r = min(bounds.width, bounds.height) / 2 - w / 2 - let c = CGPoint(x: bounds.width / 2, y: bounds.height / 2) - let p = max(0.0, disableProgressAnimation ? progress : presentation()?.progress ?? 0.0) - let angleOffset = CGFloat.pi / 2 - let angle = 2 * .pi * p - angleOffset - let minAngle = 1.1 * atan(0.5 * w / r) - let maxAngle = 2 * .pi - 3 * minAngle - angleOffset - - let circleRect = squareRect.insetBy(dx: w / 2, dy: w / 2) - let circlePath = UIBezierPath(ovalIn: circleRect) - - let angle1 = angle > maxAngle ? maxAngle : angle - - context.setLineWidth(w) - context.setLineCap(progressStyle.lineCap) - - // Draw backdrop circle - - context.addPath(circlePath.cgPath) - let bgColor = backgroundRingColor ?? startColor.copy(alpha: 0.15)! - context.setStrokeColor(bgColor) - context.strokePath() - - // Draw solid arc - - if angle > maxAngle { - let offset = angle - maxAngle - - let arc2Path = UIBezierPath(arcCenter: c, - radius: r, - startAngle: -angleOffset, - endAngle: offset, - clockwise: true) - context.addPath(arc2Path.cgPath) - context.setStrokeColor(startColor) - context.strokePath() - - context.translateBy(x: circleRect.midX, y: circleRect.midY) - context.rotate(by: offset) - context.translateBy(x: -circleRect.midX, y: -circleRect.midY) - } - - // Draw shadow and progress end - - if p > 0.0 || !hidesRingForZeroProgress { - context.saveGState() - - if endShadowOpacity > 0.0 { - context.addPath(CGPath(__byStroking: circlePath.cgPath, - transform: nil, - lineWidth: w, - lineCap: .round, - lineJoin: .round, - miterLimit: 0)!) - context.clip() - - let shadowOffset = CGSize(width: w / 10 * cos(angle + angleOffset), - height: w / 10 * sin(angle + angleOffset)) - context.setShadow(offset: shadowOffset, - blur: w / 3, - color: UIColor(white: 0.0, alpha: endShadowOpacity).cgColor) - } - - let arcEnd = CGPoint(x: c.x + r * cos(angle1), y: c.y + r * sin(angle1)) - - let shadowPath: UIBezierPath = { - switch progressStyle { - case .round: - return UIBezierPath(ovalIn: CGRect(x: arcEnd.x - w / 2, - y: arcEnd.y - w / 2, - width: w, - height: w)) - case .square: - let path = UIBezierPath(rect: CGRect(x: arcEnd.x - w / 2, - y: arcEnd.y - 2, - width: w, - height: 2)) - path.apply(CGAffineTransform(translationX: -arcEnd.x, y: -arcEnd.y)) - path.apply(CGAffineTransform(rotationAngle: angle1)) - path.apply(CGAffineTransform(translationX: arcEnd.x, y: arcEnd.y)) - return path - } - }() - - let shadowFillColor: CGColor = { - let fadeStartProgress: CGFloat = 0.02 - if !hidesRingForZeroProgress || p > fadeStartProgress { - return startColor - } - // gradually decrease shadow opacity - return startColor.copy(alpha: p / fadeStartProgress)! - }() - context.addPath(shadowPath.cgPath) - context.setFillColor(shadowFillColor) - context.fillPath() - - context.restoreGState() - } - - // Draw gradient arc - - let gradient: CGImage? = { - guard useGradient else { - return nil - } - let s = Float(1.5 * w / (2 * .pi * r)) - gradientGenerator.scale = gradientImageScale - gradientGenerator.size = gradientRect.size - gradientGenerator.colors = [endColor, endColor, startColor, startColor] - gradientGenerator.locations = [0.0, s, 1.0 - s, 1.0] - gradientGenerator.endPoint = CGPoint(x: 0.5 - CGFloat(2 * s), y: 1.0) - return gradientGenerator.image() - }() - - if p > 0.0 { - let arc1Path = UIBezierPath(arcCenter: c, - radius: r, - startAngle: -angleOffset, - endAngle: angle1, - clockwise: true) - if let gradient = gradient { - context.saveGState() - - context.addPath(CGPath(__byStroking: arc1Path.cgPath, - transform: nil, - lineWidth: w, - lineCap: progressStyle.lineCap, - lineJoin: progressStyle.lineJoin, - miterLimit: 0)!) - context.clip() - - context.interpolationQuality = .none - context.draw(gradient, in: gradientRect) - - context.restoreGState() - } else { - context.setStrokeColor(startColor) - context.setLineWidth(w) - context.setLineCap(progressStyle.lineCap) - context.addPath(arc1Path.cgPath) - context.strokePath() - } - } - } -} - -private extension RingProgressViewStyle { - var lineCap: CGLineCap { - switch self { - case .round: - return .round - case .square: - return .butt - } - } - - var lineJoin: CGLineJoin { - switch self { - case .round: - return .round - case .square: - return .miter - } - } -} diff --git a/Dependencies/MKRingProgressView/MKRingProgressView/MKRingProgressView.h b/Dependencies/MKRingProgressView/MKRingProgressView/MKRingProgressView.h deleted file mode 100644 index f6e45c13f..000000000 --- a/Dependencies/MKRingProgressView/MKRingProgressView/MKRingProgressView.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// MKRingProgressView.h -// MKRingProgressView -// -// Created by Max Konovalov on 14/02/2017. -// Copyright © 2017 Max Konovalov. All rights reserved. -// - -#import - -//! Project version number for MKRingProgressView. -FOUNDATION_EXPORT double MKRingProgressViewVersionNumber; - -//! Project version string for MKRingProgressView. -FOUNDATION_EXPORT const unsigned char MKRingProgressViewVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/MKRingProgressView/MKRingProgressView/MKRingProgressView.swift b/Dependencies/MKRingProgressView/MKRingProgressView/MKRingProgressView.swift deleted file mode 100644 index 9d70c4bbf..000000000 --- a/Dependencies/MKRingProgressView/MKRingProgressView/MKRingProgressView.swift +++ /dev/null @@ -1,197 +0,0 @@ -/* - The MIT License (MIT) - - Copyright (c) 2015 Max Konovalov - - 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. - */ - -import UIKit - -@objc(MKRingProgressViewStyle) -public enum RingProgressViewStyle: Int { - case round - case square -} - -@IBDesignable -@objc(MKRingProgressView) -open class RingProgressView: UIView { - /// The start color of the progress ring. - @IBInspectable open var startColor: UIColor { - get { - return UIColor(cgColor: ringProgressLayer.startColor) - } - set { - ringProgressLayer.startColor = newValue.cgColor - } - } - - /// The end color of the progress ring. - @IBInspectable open var endColor: UIColor { - get { - return UIColor(cgColor: ringProgressLayer.endColor) - } - set { - ringProgressLayer.endColor = newValue.cgColor - } - } - - /// The color of backdrop circle, visible at progress values between 0.0 and 1.0. - /// If not specified, `startColor` with 15% opacity will be used. - @IBInspectable open var backgroundRingColor: UIColor? { - get { - if let color = ringProgressLayer.backgroundRingColor { - return UIColor(cgColor: color) - } - return nil - } - set { - ringProgressLayer.backgroundRingColor = newValue?.cgColor - } - } - - /// The width of the progress ring. Defaults to `20`. - @IBInspectable open var ringWidth: CGFloat { - get { - return ringProgressLayer.ringWidth - } - set { - ringProgressLayer.ringWidth = newValue - } - } - - /// The style of the progress line end. Defaults to `round`. - @objc open var style: RingProgressViewStyle { - get { - return ringProgressLayer.progressStyle - } - set { - ringProgressLayer.progressStyle = newValue - } - } - - /// The opacity of the shadow below progress line end. Defaults to `1.0`. - /// Values outside the [0,1] range will be clamped. - @IBInspectable open var shadowOpacity: CGFloat { - get { - return ringProgressLayer.endShadowOpacity - } - set { - ringProgressLayer.endShadowOpacity = newValue - } - } - - /// Whether or not to hide the progress ring when progress is zero. Defaults to `false`. - @IBInspectable open var hidesRingForZeroProgress: Bool { - get { - return ringProgressLayer.hidesRingForZeroProgress - } - set { - ringProgressLayer.hidesRingForZeroProgress = newValue - } - } - - /// The Antialiasing switch. Defaults to `true`. - @IBInspectable open var allowsAntialiasing: Bool { - get { - return ringProgressLayer.allowsAntialiasing - } - set { - ringProgressLayer.allowsAntialiasing = newValue - } - } - - /// The scale of the generated gradient image. - /// Use lower values for better performance and higher values for more precise gradients. - @IBInspectable open var gradientImageScale: CGFloat { - get { - return ringProgressLayer.gradientImageScale - } - set { - ringProgressLayer.gradientImageScale = newValue - } - } - - /// The progress. Can be any nonnegative number, every whole number corresponding to one full revolution, i.e. 1.0 -> 360°, 2.0 -> 720°, etc. Defaults to `0.0`. Animatable. - @IBInspectable open var progress: Double { - get { - return Double(ringProgressLayer.progress) - } - set { - ringProgressLayer.progress = CGFloat(newValue) - } - } - - open override class var layerClass: AnyClass { - return RingProgressLayer.self - } - - private var ringProgressLayer: RingProgressLayer { - return layer as! RingProgressLayer - } - - public override init(frame: CGRect) { - super.init(frame: frame) - setup() - } - - public required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - setup() - } - - init() { - super.init(frame: .zero) - setup() - } - - private func setup() { - layer.drawsAsynchronously = true - layer.contentsScale = UIScreen.main.scale - isAccessibilityElement = true - #if swift(>=4.2) - accessibilityTraits = UIAccessibilityTraits.updatesFrequently - #else - accessibilityTraits = UIAccessibilityTraitUpdatesFrequently - #endif - accessibilityLabel = "Ring progress" - } - - open override func prepareForInterfaceBuilder() { - super.prepareForInterfaceBuilder() - ringProgressLayer.disableProgressAnimation = true - } - - // MARK: Accessibility - - private var overriddenAccessibilityValue: String? - - open override var accessibilityValue: String? { - get { - if let override = overriddenAccessibilityValue { - return override - } - return String(format: "%.f%%", progress * 100) - } - set { - overriddenAccessibilityValue = newValue - } - } -} diff --git a/Dependencies/MKRingProgressView/README.md b/Dependencies/MKRingProgressView/README.md deleted file mode 100644 index 116c3c8fe..000000000 --- a/Dependencies/MKRingProgressView/README.md +++ /dev/null @@ -1,87 +0,0 @@ -# MKRingProgressView - -[![Language](http://img.shields.io/badge/language-swift-brightgreen.svg?style=flat)](https://developer.apple.com/swift) -[![Platform](https://img.shields.io/cocoapods/p/MKRingProgressView.svg?style=flat)](http://cocoapods.org/pods/MKRingProgressView) -[![License](https://img.shields.io/cocoapods/l/MKRingProgressView.svg?style=flat)](http://cocoapods.org/pods/MKRingProgressView) -[![Version](https://img.shields.io/cocoapods/v/MKRingProgressView.svg?style=flat)](http://cocoapods.org/pods/MKRingProgressView) -[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) - - -Ring progress view similar to Activity app on Apple Watch - -MKRingProgressView - -## Features - -- Progress animation -- Customizable start/end and backdrop ring colors -- Customizable ring width -- Customizable progress line end style -- Customizable shadow under progress line end -- Progress values above 100% (or 360°) can also be displayed - -## Installation - -### CocoaPods - -To install `MKRingProgressView` via [CocoaPods](http://cocoapods.org), add the following line to your Podfile: - -``` -pod 'MKRingProgressView' -``` - -### Carthage - -To install `MKRingProgressView` via [Carthage](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos), add the following line to your Cartfile: - -``` -github "maxkonovalov/MKRingProgressView" -``` - -## Usage - -See the example Xcode project. It contains 2 targets: -- **ProgressRingExample** - a simple example containing a single progress ring with adjustable parameters. -- **ActivityRingsExample** - an advanced usage example replicating Activity app by Apple. It also contains additional classes for convenient grouping of 3 ring progress views together. - -### Interface Builder - -`MKRingProgressView` can be set up in Interface Builder. To use it, set the custom view class to `MKRingProgressView`. Most of the control's parameters can be customized in Interface Builder. - -### Code - -```swift -let ringProgressView = RingProgressView(frame: CGRect(x: 0, y: 100, width: 100, height: 100)) -ringProgressView.startColor = .red -ringProgressView.endColor = .magenta -ringProgressView.ringWidth = 25 -ringProgressView.progress = 0.0 -view.addSubview(ringProgressView) -``` - -The `progress` value can be animated the same way you would normally animate any property using `UIView`'s block-based animations: - -```swift -UIView.animate(withDuration: 0.5) { - ringProgressView.progress = 1.0 -} -``` - -## Performance - -To achieve better performance the following options are possible: - -- Set `gradientImageScale` to lower values like `0.5` (defaults to `1.0`) -- Set `startColor` and `endColor` to the same value -- Set `shadowOpacity` to `0.0` -- Set `allowsAntialiasing` to `false` - -## Requirements - -- iOS 8.2 -- tvOS 9.0 -- Xcode 10, Swift 4+ - -## License - -`MKRingProgressView` is available under the MIT license. See the LICENSE file for more info. diff --git a/Dependencies/MinimedKit/.gitignore b/Dependencies/MinimedKit/.gitignore deleted file mode 100644 index 72baa4591..000000000 --- a/Dependencies/MinimedKit/.gitignore +++ /dev/null @@ -1,91 +0,0 @@ -# Xcode -# -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore -.DS_Store - -## User settings -xcuserdata/ - -## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) -*.xcscmblueprint -*.xccheckout - -## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) -build/ -DerivedData/ -*.moved-aside -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 - -## Obj-C/Swift specific -*.hmap - -## App packaging -*.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 -# *.xcodeproj -# -# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata -# hence it is not needed unless you have added a package configuration file to your project -# .swiftpm - -.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/Dependencies/MinimedKit/MinimedKit.xcodeproj/project.pbxproj b/Dependencies/MinimedKit/MinimedKit.xcodeproj/project.pbxproj deleted file mode 100644 index 3b548eea5..000000000 --- a/Dependencies/MinimedKit/MinimedKit.xcodeproj/project.pbxproj +++ /dev/null @@ -1,2375 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 56; - objects = { - -/* Begin PBXBuildFile section */ - C1229C2229C7ECA70066A89C /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1229C2129C7ECA70066A89C /* TimeInterval.swift */; }; - C1229C2429C7ECEB0066A89C /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1229C2329C7ECEB0066A89C /* Data.swift */; }; - C13CC33529C7B6A9007F25DE /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1E34B6729C7AD62009A50A5 /* LoopKit.framework */; }; - C13CC33829C7B6BC007F25DE /* MinimedKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1E3491129C7A866009A50A5 /* MinimedKit.framework */; }; - C13CC34529C7B73A007F25DE /* MinimedKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1E3491129C7A866009A50A5 /* MinimedKit.framework */; }; - C13CC38829C7B757007F25DE /* ResumePumpEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC34C29C7B755007F25DE /* ResumePumpEventTests.swift */; }; - C13CC38929C7B757007F25DE /* BolusNormalPumpEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC34D29C7B755007F25DE /* BolusNormalPumpEventTests.swift */; }; - C13CC38A29C7B757007F25DE /* ReadCurrentGlucosePageMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC34F29C7B755007F25DE /* ReadCurrentGlucosePageMessageBodyTests.swift */; }; - C13CC38B29C7B757007F25DE /* ChangeTimeCarelinMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35029C7B755007F25DE /* ChangeTimeCarelinMessageBodyTests.swift */; }; - C13CC38C29C7B757007F25DE /* MeterMessageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35129C7B755007F25DE /* MeterMessageTests.swift */; }; - C13CC38D29C7B757007F25DE /* ChangeTempBasalCarelinkMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35229C7B755007F25DE /* ChangeTempBasalCarelinkMessageBodyTests.swift */; }; - C13CC38E29C7B757007F25DE /* ReadOtherDevicesIDsMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35329C7B755007F25DE /* ReadOtherDevicesIDsMessageBodyTests.swift */; }; - C13CC38F29C7B757007F25DE /* BolusCarelinkMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35429C7B755007F25DE /* BolusCarelinkMessageBodyTests.swift */; }; - C13CC39029C7B757007F25DE /* FindDeviceMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35529C7B755007F25DE /* FindDeviceMessageBodyTests.swift */; }; - C13CC39129C7B757007F25DE /* ReadRemoteControlIDsMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35629C7B755007F25DE /* ReadRemoteControlIDsMessageBodyTests.swift */; }; - C13CC39229C7B757007F25DE /* ReadTempBasalCarelinkMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35729C7B755007F25DE /* ReadTempBasalCarelinkMessageBodyTests.swift */; }; - C13CC39329C7B757007F25DE /* DeviceLinkMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35829C7B755007F25DE /* DeviceLinkMessageBodyTests.swift */; }; - C13CC39429C7B757007F25DE /* ChangeMaxBasalRateMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35929C7B755007F25DE /* ChangeMaxBasalRateMessageBodyTests.swift */; }; - C13CC39529C7B757007F25DE /* ChangeRemoteControlIDMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35A29C7B755007F25DE /* ChangeRemoteControlIDMessageBodyTests.swift */; }; - C13CC39629C7B757007F25DE /* GetBatteryCarelinkMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35B29C7B755007F25DE /* GetBatteryCarelinkMessageBodyTests.swift */; }; - C13CC39729C7B757007F25DE /* ReadRemainingInsulinMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35C29C7B755007F25DE /* ReadRemainingInsulinMessageBodyTests.swift */; }; - C13CC39829C7B757007F25DE /* ChangeMaxBolusMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35D29C7B755007F25DE /* ChangeMaxBolusMessageBodyTests.swift */; }; - C13CC39929C7B757007F25DE /* GetPumpModelCarelinkMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35E29C7B755007F25DE /* GetPumpModelCarelinkMessageBodyTests.swift */; }; - C13CC39A29C7B757007F25DE /* GetGlucosePageMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC35F29C7B755007F25DE /* GetGlucosePageMessageBodyTests.swift */; }; - C13CC39B29C7B757007F25DE /* MinimedPacketTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36029C7B755007F25DE /* MinimedPacketTests.swift */; }; - C13CC39C29C7B757007F25DE /* MinimedPumpManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36129C7B755007F25DE /* MinimedPumpManagerTests.swift */; }; - C13CC39D29C7B757007F25DE /* NSDateComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36229C7B755007F25DE /* NSDateComponents.swift */; }; - C13CC39E29C7B757007F25DE /* PumpOpsSynchronousTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36329C7B755007F25DE /* PumpOpsSynchronousTests.swift */; }; - C13CC39F29C7B757007F25DE /* NSDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36429C7B755007F25DE /* NSDataTests.swift */; }; - C13CC3A029C7B757007F25DE /* TimestampedHistoryEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36529C7B755007F25DE /* TimestampedHistoryEventTests.swift */; }; - C13CC3A129C7B757007F25DE /* CRC8Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36629C7B755007F25DE /* CRC8Tests.swift */; }; - C13CC3A229C7B757007F25DE /* SensorDataHighGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36829C7B756007F25DE /* SensorDataHighGlucoseEventTests.swift */; }; - C13CC3A329C7B757007F25DE /* SensorTimestampGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36929C7B756007F25DE /* SensorTimestampGlucoseEventTests.swift */; }; - C13CC3A429C7B757007F25DE /* BatteryChangeGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36A29C7B756007F25DE /* BatteryChangeGlucoseEventTests.swift */; }; - C13CC3A529C7B757007F25DE /* SensorErrorGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36B29C7B756007F25DE /* SensorErrorGlucoseEventTests.swift */; }; - C13CC3A629C7B757007F25DE /* SensorCalFactorGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36C29C7B756007F25DE /* SensorCalFactorGlucoseEventTests.swift */; }; - C13CC3A729C7B757007F25DE /* SensorCalGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36D29C7B756007F25DE /* SensorCalGlucoseEventTests.swift */; }; - C13CC3A829C7B757007F25DE /* CalBGForGHGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36E29C7B756007F25DE /* CalBGForGHGlucoseEventTests.swift */; }; - C13CC3A929C7B757007F25DE /* SensorStatusGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC36F29C7B756007F25DE /* SensorStatusGlucoseEventTests.swift */; }; - C13CC3AA29C7B757007F25DE /* SensorDataLowGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37029C7B756007F25DE /* SensorDataLowGlucoseEventTests.swift */; }; - C13CC3AB29C7B757007F25DE /* GlucoseSensorDataGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37129C7B756007F25DE /* GlucoseSensorDataGlucoseEventTests.swift */; }; - C13CC3AC29C7B757007F25DE /* SensorSyncGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37229C7B756007F25DE /* SensorSyncGlucoseEventTests.swift */; }; - C13CC3AD29C7B757007F25DE /* DateTimeChangeGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37329C7B756007F25DE /* DateTimeChangeGlucoseEventTests.swift */; }; - C13CC3AE29C7B757007F25DE /* SensorPacketGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37429C7B756007F25DE /* SensorPacketGlucoseEventTests.swift */; }; - C13CC3AF29C7B757007F25DE /* TenSomethingGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37529C7B756007F25DE /* TenSomethingGlucoseEventTests.swift */; }; - C13CC3B029C7B757007F25DE /* BasalScheduleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37629C7B756007F25DE /* BasalScheduleTests.swift */; }; - C13CC3B129C7B757007F25DE /* MockRileyLinkProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37829C7B756007F25DE /* MockRileyLinkProvider.swift */; }; - C13CC3B229C7B757007F25DE /* MockPumpManagerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37929C7B756007F25DE /* MockPumpManagerDelegate.swift */; }; - C13CC3B329C7B757007F25DE /* MockPumpOps.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37A29C7B756007F25DE /* MockPumpOps.swift */; }; - C13CC3B429C7B757007F25DE /* MockPumpMessageSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37B29C7B756007F25DE /* MockPumpMessageSender.swift */; }; - C13CC3B529C7B757007F25DE /* MockRileyLinkDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37C29C7B756007F25DE /* MockRileyLinkDevice.swift */; }; - C13CC3B629C7B757007F25DE /* GlucosePageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37D29C7B756007F25DE /* GlucosePageTests.swift */; }; - C13CC3B729C7B757007F25DE /* NSStringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37E29C7B756007F25DE /* NSStringExtensions.swift */; }; - C13CC3B829C7B757007F25DE /* ReadSettingsCarelinkMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC37F29C7B756007F25DE /* ReadSettingsCarelinkMessageBodyTests.swift */; }; - C13CC3B929C7B757007F25DE /* PumpModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC38029C7B756007F25DE /* PumpModelTests.swift */; }; - C13CC3BB29C7B757007F25DE /* HistoryPageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC38229C7B756007F25DE /* HistoryPageTests.swift */; }; - C13CC3BC29C7B757007F25DE /* CRC16Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC38329C7B757007F25DE /* CRC16Tests.swift */; }; - C13CC3BD29C7B757007F25DE /* MySentryPumpStatusMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC38429C7B757007F25DE /* MySentryPumpStatusMessageBodyTests.swift */; }; - C13CC3BE29C7B757007F25DE /* NSDateComponentsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC38529C7B757007F25DE /* NSDateComponentsTests.swift */; }; - C13CC3BF29C7B757007F25DE /* PumpOpsSynchronousBuildFromFramesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC38629C7B757007F25DE /* PumpOpsSynchronousBuildFromFramesTests.swift */; }; - C13CC3C029C7B757007F25DE /* ReconciliationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC38729C7B757007F25DE /* ReconciliationTests.swift */; }; - C13CC3C329C7B8BC007F25DE /* MinimedPumpManager.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C13CC3C129C7B8BC007F25DE /* MinimedPumpManager.storyboard */; }; - C13CC3DD29C7BA48007F25DE /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13CC3DC29C7BA48007F25DE /* OSLog.swift */; }; - C1E3491529C7A866009A50A5 /* MinimedKit.h in Headers */ = {isa = PBXBuildFile; fileRef = C1E3491429C7A866009A50A5 /* MinimedKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C1E34A1E29C7A98F009A50A5 /* CalBGForGHGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3492529C7A98B009A50A5 /* CalBGForGHGlucoseEvent.swift */; }; - C1E34A1F29C7A98F009A50A5 /* RelativeTimestampedGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3492629C7A98B009A50A5 /* RelativeTimestampedGlucoseEvent.swift */; }; - C1E34A2029C7A98F009A50A5 /* SensorCalGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3492729C7A98B009A50A5 /* SensorCalGlucoseEvent.swift */; }; - C1E34A2129C7A98F009A50A5 /* SensorErrorGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3492829C7A98B009A50A5 /* SensorErrorGlucoseEvent.swift */; }; - C1E34A2229C7A98F009A50A5 /* TenSomethingGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3492929C7A98B009A50A5 /* TenSomethingGlucoseEvent.swift */; }; - C1E34A2329C7A98F009A50A5 /* SensorStatusGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3492A29C7A98B009A50A5 /* SensorStatusGlucoseEvent.swift */; }; - C1E34A2429C7A98F009A50A5 /* SensorValueGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3492B29C7A98B009A50A5 /* SensorValueGlucoseEvent.swift */; }; - C1E34A2529C7A98F009A50A5 /* SensorSyncGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3492C29C7A98B009A50A5 /* SensorSyncGlucoseEvent.swift */; }; - C1E34A2629C7A98F009A50A5 /* SensorTimestampGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3492D29C7A98B009A50A5 /* SensorTimestampGlucoseEvent.swift */; }; - C1E34A2729C7A98F009A50A5 /* SensorDataLowGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3492E29C7A98B009A50A5 /* SensorDataLowGlucoseEvent.swift */; }; - C1E34A2829C7A98F009A50A5 /* SensorPacketGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3492F29C7A98B009A50A5 /* SensorPacketGlucoseEvent.swift */; }; - C1E34A2929C7A98F009A50A5 /* DateTimeChangeGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3493029C7A98B009A50A5 /* DateTimeChangeGlucoseEvent.swift */; }; - C1E34A2A29C7A98F009A50A5 /* UnknownGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3493129C7A98B009A50A5 /* UnknownGlucoseEvent.swift */; }; - C1E34A2B29C7A98F009A50A5 /* DataEndGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3493229C7A98B009A50A5 /* DataEndGlucoseEvent.swift */; }; - C1E34A2C29C7A98F009A50A5 /* NineteenSomethingGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3493329C7A98B009A50A5 /* NineteenSomethingGlucoseEvent.swift */; }; - C1E34A2D29C7A98F009A50A5 /* GlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3493429C7A98B009A50A5 /* GlucoseEvent.swift */; }; - C1E34A2E29C7A98F009A50A5 /* GlucoseSensorDataGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3493529C7A98B009A50A5 /* GlucoseSensorDataGlucoseEvent.swift */; }; - C1E34A2F29C7A98F009A50A5 /* SensorDataHighGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3493629C7A98B009A50A5 /* SensorDataHighGlucoseEvent.swift */; }; - C1E34A3029C7A98F009A50A5 /* BatteryChangeGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3493729C7A98B009A50A5 /* BatteryChangeGlucoseEvent.swift */; }; - C1E34A3129C7A98F009A50A5 /* SensorCalFactorGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3493829C7A98B009A50A5 /* SensorCalFactorGlucoseEvent.swift */; }; - C1E34A3229C7A98F009A50A5 /* SensorWeakSignalGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3493929C7A98B009A50A5 /* SensorWeakSignalGlucoseEvent.swift */; }; - C1E34A3329C7A98F009A50A5 /* SensorValueGlucoseEvent+CGMManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3493B29C7A98B009A50A5 /* SensorValueGlucoseEvent+CGMManager.swift */; }; - C1E34A3429C7A98F009A50A5 /* MySentryPumpStatusMessageBody+CGMManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3493C29C7A98B009A50A5 /* MySentryPumpStatusMessageBody+CGMManager.swift */; }; - C1E34A3829C7A98F009A50A5 /* MinimedPumpManagerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3494529C7A98C009A50A5 /* MinimedPumpManagerState.swift */; }; - C1E34A3929C7A98F009A50A5 /* MinimedPumpManagerRecents.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3494629C7A98C009A50A5 /* MinimedPumpManagerRecents.swift */; }; - C1E34A3A29C7A98F009A50A5 /* EnliteSensorDisplayable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3494729C7A98C009A50A5 /* EnliteSensorDisplayable.swift */; }; - C1E34A3B29C7A98F009A50A5 /* PumpOpsSession+LoopKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3494829C7A98C009A50A5 /* PumpOpsSession+LoopKit.swift */; }; - C1E34A3C29C7A98F009A50A5 /* BasalProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3494929C7A98C009A50A5 /* BasalProfile.swift */; }; - C1E34A3D29C7A98F009A50A5 /* HistoryPage+PumpOpsSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3494A29C7A98C009A50A5 /* HistoryPage+PumpOpsSession.swift */; }; - C1E34A3E29C7A98F009A50A5 /* ReservoirReading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3494B29C7A98C009A50A5 /* ReservoirReading.swift */; }; - C1E34A3F29C7A98F009A50A5 /* PumpMessageSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3494C29C7A98C009A50A5 /* PumpMessageSender.swift */; }; - C1E34A4029C7A98F009A50A5 /* MinimedPumpManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3494D29C7A98C009A50A5 /* MinimedPumpManagerError.swift */; }; - C1E34A4129C7A98F009A50A5 /* DoseStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3494E29C7A98C009A50A5 /* DoseStore.swift */; }; - C1E34A4229C7A98F009A50A5 /* PumpSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3494F29C7A98C009A50A5 /* PumpSettings.swift */; }; - C1E34A4329C7A98F009A50A5 /* PumpOps.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3495029C7A98C009A50A5 /* PumpOps.swift */; }; - C1E34A4429C7A98F009A50A5 /* PumpMessage+PumpOpsSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3495129C7A98C009A50A5 /* PumpMessage+PumpOpsSession.swift */; }; - C1E34A4529C7A98F009A50A5 /* InsulinDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3495229C7A98C009A50A5 /* InsulinDataSource.swift */; }; - C1E34A4629C7A98F009A50A5 /* MinimedDoseProgressEstimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3495329C7A98C009A50A5 /* MinimedDoseProgressEstimator.swift */; }; - C1E34A4729C7A98F009A50A5 /* MinimedPumpMessageSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3495429C7A98C009A50A5 /* MinimedPumpMessageSender.swift */; }; - C1E34A4829C7A98F009A50A5 /* MinimedPumpManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3495529C7A98C009A50A5 /* MinimedPumpManager.swift */; }; - C1E34A4929C7A98F009A50A5 /* UnfinalizedDose.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3495629C7A98C009A50A5 /* UnfinalizedDose.swift */; }; - C1E34A4A29C7A98F009A50A5 /* RileyLinkDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3495729C7A98C009A50A5 /* RileyLinkDevice.swift */; }; - C1E34A4B29C7A98F009A50A5 /* PumpOpsError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3495829C7A98C009A50A5 /* PumpOpsError.swift */; }; - C1E34A4C29C7A98F009A50A5 /* PumpState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3495929C7A98C009A50A5 /* PumpState.swift */; }; - C1E34A5029C7A98F009A50A5 /* ChangeWatchdogEnablePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3496429C7A98C009A50A5 /* ChangeWatchdogEnablePumpEvent.swift */; }; - C1E34A5129C7A98F009A50A5 /* PumpAlarmPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3496529C7A98C009A50A5 /* PumpAlarmPumpEvent.swift */; }; - C1E34A5229C7A98F009A50A5 /* ChangeCaptureEventEnablePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3496629C7A98C009A50A5 /* ChangeCaptureEventEnablePumpEvent.swift */; }; - C1E34A5329C7A98F009A50A5 /* TempBasalDurationPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3496729C7A98C009A50A5 /* TempBasalDurationPumpEvent.swift */; }; - C1E34A5429C7A98F009A50A5 /* ChangeBolusScrollStepSizePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3496829C7A98C009A50A5 /* ChangeBolusScrollStepSizePumpEvent.swift */; }; - C1E34A5529C7A98F009A50A5 /* ChangeSensorSetup2PumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3496929C7A98C009A50A5 /* ChangeSensorSetup2PumpEvent.swift */; }; - C1E34A5629C7A98F009A50A5 /* JournalEntryInsulinMarkerPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3496A29C7A98C009A50A5 /* JournalEntryInsulinMarkerPumpEvent.swift */; }; - C1E34A5729C7A98F009A50A5 /* ChangeMaxBolusPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3496B29C7A98C009A50A5 /* ChangeMaxBolusPumpEvent.swift */; }; - C1E34A5829C7A98F009A50A5 /* ChangeVariableBolusPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3496C29C7A98C009A50A5 /* ChangeVariableBolusPumpEvent.swift */; }; - C1E34A5929C7A98F009A50A5 /* ChangeBolusReminderEnablePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3496D29C7A98C009A50A5 /* ChangeBolusReminderEnablePumpEvent.swift */; }; - C1E34A5A29C7A98F009A50A5 /* ChangeCarbUnitsPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3496E29C7A98C009A50A5 /* ChangeCarbUnitsPumpEvent.swift */; }; - C1E34A5B29C7A98F009A50A5 /* BolusWizardEstimatePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3496F29C7A98C009A50A5 /* BolusWizardEstimatePumpEvent.swift */; }; - C1E34A5C29C7A98F009A50A5 /* ClearAlarmPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497029C7A98C009A50A5 /* ClearAlarmPumpEvent.swift */; }; - C1E34A5D29C7A98F009A50A5 /* ChangeAlarmNotifyModePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497129C7A98C009A50A5 /* ChangeAlarmNotifyModePumpEvent.swift */; }; - C1E34A5E29C7A98F009A50A5 /* ChangeAlarmClockEnablePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497229C7A98C009A50A5 /* ChangeAlarmClockEnablePumpEvent.swift */; }; - C1E34A5F29C7A98F009A50A5 /* JournalEntryPumpLowReservoirPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497329C7A98C009A50A5 /* JournalEntryPumpLowReservoirPumpEvent.swift */; }; - C1E34A6029C7A98F009A50A5 /* ChangeTimeFormatPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497429C7A98C009A50A5 /* ChangeTimeFormatPumpEvent.swift */; }; - C1E34A6129C7A98F009A50A5 /* SelectBasalProfilePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497529C7A98C009A50A5 /* SelectBasalProfilePumpEvent.swift */; }; - C1E34A6229C7A98F009A50A5 /* DailyTotal522PumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497629C7A98C009A50A5 /* DailyTotal522PumpEvent.swift */; }; - C1E34A6329C7A98F009A50A5 /* BGReceivedPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497729C7A98C009A50A5 /* BGReceivedPumpEvent.swift */; }; - C1E34A6429C7A98F009A50A5 /* TimestampedPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497829C7A98C009A50A5 /* TimestampedPumpEvent.swift */; }; - C1E34A6529C7A98F009A50A5 /* SuspendPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497929C7A98C009A50A5 /* SuspendPumpEvent.swift */; }; - C1E34A6629C7A98F009A50A5 /* EnableBolusWizardPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497A29C7A98C009A50A5 /* EnableBolusWizardPumpEvent.swift */; }; - C1E34A6729C7A98F009A50A5 /* UnabsorbedInsulinPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497B29C7A98C009A50A5 /* UnabsorbedInsulinPumpEvent.swift */; }; - C1E34A6829C7A98F009A50A5 /* DeleteOtherDeviceIDPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497C29C7A98C009A50A5 /* DeleteOtherDeviceIDPumpEvent.swift */; }; - C1E34A6929C7A98F009A50A5 /* AlarmClockReminderPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497D29C7A98C009A50A5 /* AlarmClockReminderPumpEvent.swift */; }; - C1E34A6A29C7A98F009A50A5 /* ChangeBGReminderEnablePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497E29C7A98C009A50A5 /* ChangeBGReminderEnablePumpEvent.swift */; }; - C1E34A6B29C7A98F009A50A5 /* JournalEntryPumpLowBatteryPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3497F29C7A98C009A50A5 /* JournalEntryPumpLowBatteryPumpEvent.swift */; }; - C1E34A6C29C7A98F009A50A5 /* NewTimePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498029C7A98C009A50A5 /* NewTimePumpEvent.swift */; }; - C1E34A6D29C7A98F009A50A5 /* ChangeMaxBasalPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498129C7A98C009A50A5 /* ChangeMaxBasalPumpEvent.swift */; }; - C1E34A6E29C7A98F009A50A5 /* ChangeTempBasalTypePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498229C7A98C009A50A5 /* ChangeTempBasalTypePumpEvent.swift */; }; - C1E34A6F29C7A98F009A50A5 /* ChangeSensorAlarmSilenceConfigPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498329C7A98C009A50A5 /* ChangeSensorAlarmSilenceConfigPumpEvent.swift */; }; - C1E34A7029C7A98F009A50A5 /* ChangeOtherDeviceIDPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498429C7A98C009A50A5 /* ChangeOtherDeviceIDPumpEvent.swift */; }; - C1E34A7129C7A98F009A50A5 /* PrimePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498529C7A98C009A50A5 /* PrimePumpEvent.swift */; }; - C1E34A7229C7A98F009A50A5 /* DailyTotal523PumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498629C7A98C009A50A5 /* DailyTotal523PumpEvent.swift */; }; - C1E34A7329C7A98F009A50A5 /* BatteryPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498729C7A98C009A50A5 /* BatteryPumpEvent.swift */; }; - C1E34A7429C7A98F009A50A5 /* EnableDisableRemotePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498829C7A98C009A50A5 /* EnableDisableRemotePumpEvent.swift */; }; - C1E34A7529C7A98F009A50A5 /* TempBasalPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498929C7A98C009A50A5 /* TempBasalPumpEvent.swift */; }; - C1E34A7629C7A98F009A50A5 /* ChangeSensorRateOfChangeAlertSetupPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498A29C7A98C009A50A5 /* ChangeSensorRateOfChangeAlertSetupPumpEvent.swift */; }; - C1E34A7729C7A98F009A50A5 /* RestoreMystery55PumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498B29C7A98C009A50A5 /* RestoreMystery55PumpEvent.swift */; }; - C1E34A7829C7A98F009A50A5 /* BolusWizardSetupPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498C29C7A98C009A50A5 /* BolusWizardSetupPumpEvent.swift */; }; - C1E34A7929C7A98F009A50A5 /* ChangeTimePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498D29C7A98C009A50A5 /* ChangeTimePumpEvent.swift */; }; - C1E34A7A29C7A98F009A50A5 /* ChangeBolusReminderTimePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498E29C7A98C009A50A5 /* ChangeBolusReminderTimePumpEvent.swift */; }; - C1E34A7B29C7A98F009A50A5 /* ChangeBolusWizardSetupPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3498F29C7A98C009A50A5 /* ChangeBolusWizardSetupPumpEvent.swift */; }; - C1E34A7C29C7A98F009A50A5 /* PlaceholderPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499029C7A98C009A50A5 /* PlaceholderPumpEvent.swift */; }; - C1E34A7D29C7A98F009A50A5 /* PumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499129C7A98C009A50A5 /* PumpEvent.swift */; }; - C1E34A7E29C7A98F009A50A5 /* ChangeBasalProfilePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499229C7A98C009A50A5 /* ChangeBasalProfilePumpEvent.swift */; }; - C1E34A7F29C7A98F009A50A5 /* ResumePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499329C7A98C009A50A5 /* ResumePumpEvent.swift */; }; - C1E34A8029C7A98F009A50A5 /* ChangeBGReminderOffsetPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499429C7A98C009A50A5 /* ChangeBGReminderOffsetPumpEvent.swift */; }; - C1E34A8129C7A98F009A50A5 /* ChangeWatchdogMarriageProfilePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499529C7A98C009A50A5 /* ChangeWatchdogMarriageProfilePumpEvent.swift */; }; - C1E34A8229C7A98F009A50A5 /* BasalProfileStartPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499629C7A98C009A50A5 /* BasalProfileStartPumpEvent.swift */; }; - C1E34A8329C7A98F009A50A5 /* ResultDailyTotalPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499729C7A98C009A50A5 /* ResultDailyTotalPumpEvent.swift */; }; - C1E34A8429C7A98F009A50A5 /* UnknownPumpEvent57.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499829C7A98C009A50A5 /* UnknownPumpEvent57.swift */; }; - C1E34A8529C7A98F009A50A5 /* RestoreMystery54PumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499929C7A98C009A50A5 /* RestoreMystery54PumpEvent.swift */; }; - C1E34A8629C7A98F009A50A5 /* CalBGForPHPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499A29C7A98C009A50A5 /* CalBGForPHPumpEvent.swift */; }; - C1E34A8729C7A98F009A50A5 /* ChangeParadigmLinkIDPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499B29C7A98C009A50A5 /* ChangeParadigmLinkIDPumpEvent.swift */; }; - C1E34A8829C7A98F009A50A5 /* ChangeChildBlockEnablePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499C29C7A98C009A50A5 /* ChangeChildBlockEnablePumpEvent.swift */; }; - C1E34A8929C7A98F009A50A5 /* ChangeBasalProfilePatternPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499D29C7A98C009A50A5 /* ChangeBasalProfilePatternPumpEvent.swift */; }; - C1E34A8A29C7A98F009A50A5 /* RewindPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499E29C7A98C009A50A5 /* RewindPumpEvent.swift */; }; - C1E34A8B29C7A98F009A50A5 /* BolusReminderPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E3499F29C7A98C009A50A5 /* BolusReminderPumpEvent.swift */; }; - C1E34A8C29C7A98F009A50A5 /* ChangeMeterIDPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349A029C7A98C009A50A5 /* ChangeMeterIDPumpEvent.swift */; }; - C1E34A8D29C7A98F009A50A5 /* ChangeAudioBolusPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349A129C7A98C009A50A5 /* ChangeAudioBolusPumpEvent.swift */; }; - C1E34A8E29C7A98F009A50A5 /* DeleteBolusReminderTimePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349A229C7A98C009A50A5 /* DeleteBolusReminderTimePumpEvent.swift */; }; - C1E34A8F29C7A98F009A50A5 /* ChangeReservoirWarningTimePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349A329C7A98C009A50A5 /* ChangeReservoirWarningTimePumpEvent.swift */; }; - C1E34A9029C7A98F009A50A5 /* JournalEntryExerciseMarkerPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349A429C7A98C009A50A5 /* JournalEntryExerciseMarkerPumpEvent.swift */; }; - C1E34A9129C7A98F009A50A5 /* BolusNormalPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349A529C7A98C009A50A5 /* BolusNormalPumpEvent.swift */; }; - C1E34A9229C7A98F009A50A5 /* AlarmSensorPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349A629C7A98C009A50A5 /* AlarmSensorPumpEvent.swift */; }; - C1E34A9329C7A98F009A50A5 /* DailyTotal515PumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349A729C7A98C009A50A5 /* DailyTotal515PumpEvent.swift */; }; - C1E34A9429C7A98F009A50A5 /* JournalEntryMealMarkerPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349A829C7A98C009A50A5 /* JournalEntryMealMarkerPumpEvent.swift */; }; - C1E34A9629C7A98F009A50A5 /* MessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349AD29C7A98C009A50A5 /* MessageBody.swift */; }; - C1E34A9729C7A98F009A50A5 /* ReadCurrentPageNumberMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349AE29C7A98C009A50A5 /* ReadCurrentPageNumberMessageBody.swift */; }; - C1E34A9829C7A98F009A50A5 /* PowerOnCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349AF29C7A98C009A50A5 /* PowerOnCarelinkMessageBody.swift */; }; - C1E34A9929C7A98F009A50A5 /* GetBatteryCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349B029C7A98C009A50A5 /* GetBatteryCarelinkMessageBody.swift */; }; - C1E34A9A29C7A98F009A50A5 /* SetRemoteControlEnabledMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349B129C7A98C009A50A5 /* SetRemoteControlEnabledMessageBody.swift */; }; - C1E34A9B29C7A98F009A50A5 /* GetHistoryPageCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349B229C7A98C009A50A5 /* GetHistoryPageCarelinkMessageBody.swift */; }; - C1E34A9C29C7A98F009A50A5 /* PumpAckMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349B329C7A98C009A50A5 /* PumpAckMessageBody.swift */; }; - C1E34A9D29C7A98F009A50A5 /* MySentryAckMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349B429C7A98C009A50A5 /* MySentryAckMessageBody.swift */; }; - C1E34A9E29C7A98F009A50A5 /* MySentryAlertMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349B529C7A98C009A50A5 /* MySentryAlertMessageBody.swift */; }; - C1E34A9F29C7A98F009A50A5 /* PumpErrorMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349B629C7A98C009A50A5 /* PumpErrorMessageBody.swift */; }; - C1E34AA029C7A98F009A50A5 /* UnknownMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349B729C7A98C009A50A5 /* UnknownMessageBody.swift */; }; - C1E34AA129C7A98F009A50A5 /* DeviceLinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349B829C7A98C009A50A5 /* DeviceLinkMessageBody.swift */; }; - C1E34AA229C7A98F009A50A5 /* ReadTempBasalCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349B929C7A98C009A50A5 /* ReadTempBasalCarelinkMessageBody.swift */; }; - C1E34AA329C7A98F009A50A5 /* ReadCurrentGlucosePageMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349BA29C7A98C009A50A5 /* ReadCurrentGlucosePageMessageBody.swift */; }; - C1E34AA429C7A98F009A50A5 /* GlucosePage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349BC29C7A98C009A50A5 /* GlucosePage.swift */; }; - C1E34AA529C7A98F009A50A5 /* HistoryPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349BD29C7A98C009A50A5 /* HistoryPage.swift */; }; - C1E34AA629C7A98F009A50A5 /* GlucoseEventType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349BE29C7A98C009A50A5 /* GlucoseEventType.swift */; }; - C1E34AA729C7A98F009A50A5 /* TimestampedGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349BF29C7A98C009A50A5 /* TimestampedGlucoseEvent.swift */; }; - C1E34AA829C7A98F009A50A5 /* PartialDecode.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349C029C7A98C009A50A5 /* PartialDecode.swift */; }; - C1E34AA929C7A98F009A50A5 /* MySentryAlertType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349C129C7A98C009A50A5 /* MySentryAlertType.swift */; }; - C1E34AAA29C7A98F009A50A5 /* CRC16.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349C229C7A98C009A50A5 /* CRC16.swift */; }; - C1E34AAB29C7A98F009A50A5 /* BasalSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349C329C7A98C009A50A5 /* BasalSchedule.swift */; }; - C1E34AAC29C7A98F009A50A5 /* PumpEventType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349C429C7A98C009A50A5 /* PumpEventType.swift */; }; - C1E34AAD29C7A98F009A50A5 /* TimestampedHistoryEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349C529C7A98C009A50A5 /* TimestampedHistoryEvent.swift */; }; - C1E34AAE29C7A98F009A50A5 /* GetGlucosePageMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349C629C7A98C009A50A5 /* GetGlucosePageMessageBody.swift */; }; - C1E34AAF29C7A98F009A50A5 /* MySentryPumpStatusMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349C729C7A98C009A50A5 /* MySentryPumpStatusMessageBody.swift */; }; - C1E34AB029C7A98F009A50A5 /* GetPumpModelCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349C829C7A98C009A50A5 /* GetPumpModelCarelinkMessageBody.swift */; }; - C1E34AB129C7A98F009A50A5 /* MySentryAlertClearedMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349C929C7A98C009A50A5 /* MySentryAlertClearedMessageBody.swift */; }; - C1E34AB229C7A98F009A50A5 /* ChangeTempBasalCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349CA29C7A98C009A50A5 /* ChangeTempBasalCarelinkMessageBody.swift */; }; - C1E34AB329C7A98F009A50A5 /* ReadOtherDevicesIDsMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349CB29C7A98C009A50A5 /* ReadOtherDevicesIDsMessageBody.swift */; }; - C1E34AB429C7A98F009A50A5 /* ReadTimeCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349CC29C7A98C009A50A5 /* ReadTimeCarelinkMessageBody.swift */; }; - C1E34AB529C7A98F009A50A5 /* ReadSettingsCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349CD29C7A98C009A50A5 /* ReadSettingsCarelinkMessageBody.swift */; }; - C1E34AB629C7A98F009A50A5 /* GetPumpFirmwareVersionMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349CE29C7A98C009A50A5 /* GetPumpFirmwareVersionMessageBody.swift */; }; - C1E34AB729C7A98F009A50A5 /* MessageType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349CF29C7A98C009A50A5 /* MessageType.swift */; }; - C1E34AB829C7A98F009A50A5 /* ReadRemoteControlIDsMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349D029C7A98C009A50A5 /* ReadRemoteControlIDsMessageBody.swift */; }; - C1E34AB929C7A98F009A50A5 /* PumpMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349D129C7A98C009A50A5 /* PumpMessage.swift */; }; - C1E34ABA29C7A98F009A50A5 /* SuspendResumeMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349D229C7A98C009A50A5 /* SuspendResumeMessageBody.swift */; }; - C1E34ABB29C7A98F009A50A5 /* ReadOtherDevicesStatusMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349D329C7A98C009A50A5 /* ReadOtherDevicesStatusMessageBody.swift */; }; - C1E34ABC29C7A98F009A50A5 /* ChangeMaxBolusMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349D429C7A98C009A50A5 /* ChangeMaxBolusMessageBody.swift */; }; - C1E34ABD29C7A98F009A50A5 /* ChangeMaxBasalRateMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349D529C7A98C009A50A5 /* ChangeMaxBasalRateMessageBody.swift */; }; - C1E34ABE29C7A98F009A50A5 /* FindDeviceMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349D629C7A98C009A50A5 /* FindDeviceMessageBody.swift */; }; - C1E34ABF29C7A98F009A50A5 /* ReadRemainingInsulinMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349D729C7A98C009A50A5 /* ReadRemainingInsulinMessageBody.swift */; }; - C1E34AC029C7A98F009A50A5 /* PacketType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349D829C7A98C009A50A5 /* PacketType.swift */; }; - C1E34AC129C7A98F009A50A5 /* MeterMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349D929C7A98C009A50A5 /* MeterMessage.swift */; }; - C1E34AC229C7A98F009A50A5 /* BolusCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349DA29C7A98C009A50A5 /* BolusCarelinkMessageBody.swift */; }; - C1E34AC329C7A98F009A50A5 /* DataFrameMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349DB29C7A98C009A50A5 /* DataFrameMessageBody.swift */; }; - C1E34AC429C7A98F009A50A5 /* ChangeRemoteControlIDMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349DC29C7A98C009A50A5 /* ChangeRemoteControlIDMessageBody.swift */; }; - C1E34AC529C7A98F009A50A5 /* ReadPumpStatusMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349DD29C7A98C009A50A5 /* ReadPumpStatusMessageBody.swift */; }; - C1E34AC629C7A98F009A50A5 /* ChangeTimeCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349DE29C7A98C009A50A5 /* ChangeTimeCarelinkMessageBody.swift */; }; - C1E34AC729C7A98F009A50A5 /* SelectBasalProfileMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349DF29C7A98C009A50A5 /* SelectBasalProfileMessageBody.swift */; }; - C1E34AC829C7A98F009A50A5 /* ButtonPressCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349E029C7A98D009A50A5 /* ButtonPressCarelinkMessageBody.swift */; }; - C1E34AC929C7A98F009A50A5 /* CarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349E129C7A98D009A50A5 /* CarelinkMessageBody.swift */; }; - C1E34ACC29C7A98F009A50A5 /* BatteryChemistryType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349E929C7A98D009A50A5 /* BatteryChemistryType.swift */; }; - C1E34ACD29C7A98F009A50A5 /* PumpColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349EA29C7A98D009A50A5 /* PumpColor.swift */; }; - C1E34ACE29C7A98F009A50A5 /* PumpModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349EB29C7A98D009A50A5 /* PumpModel.swift */; }; - C1E34ACF29C7A98F009A50A5 /* PumpRegion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349EC29C7A98D009A50A5 /* PumpRegion.swift */; }; - C1E34AD029C7A98F009A50A5 /* MinimedPacket.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349EE29C7A98D009A50A5 /* MinimedPacket.swift */; }; - C1E34AD129C7A98F009A50A5 /* CRC8.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349EF29C7A98D009A50A5 /* CRC8.swift */; }; - C1E34AD229C7A98F009A50A5 /* FourByteSixByteEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E349F029C7A98D009A50A5 /* FourByteSixByteEncoding.swift */; }; - C1E34ADC29C7A98F009A50A5 /* ISO8601DateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34A0D29C7A98E009A50A5 /* ISO8601DateFormatter.swift */; }; - C1E34ADD29C7A98F009A50A5 /* Int.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34A0E29C7A98E009A50A5 /* Int.swift */; }; - C1E34ADE29C7A98F009A50A5 /* NSDateComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34A0F29C7A98E009A50A5 /* NSDateComponents.swift */; }; - C1E34AFB29C7A9BD009A50A5 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C1E34AE429C7A9BC009A50A5 /* Localizable.strings */; }; - C1E34B0429C7ABCB009A50A5 /* MinimedKitUI.h in Headers */ = {isa = PBXBuildFile; fileRef = C1E34B0329C7ABCB009A50A5 /* MinimedKitUI.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C1E34B2329C7ABF3009A50A5 /* MinimedKitUI.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C1E34B0829C7ABF2009A50A5 /* MinimedKitUI.xcassets */; }; - C1E34B2429C7ABF3009A50A5 /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B0A29C7ABF2009A50A5 /* Image.swift */; }; - C1E34B2529C7ABF3009A50A5 /* MinimedPumpIDSetupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B0C29C7ABF2009A50A5 /* MinimedPumpIDSetupViewController.swift */; }; - C1E34B2629C7ABF3009A50A5 /* MinimedPumpManagerSetupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B0D29C7ABF2009A50A5 /* MinimedPumpManagerSetupViewController.swift */; }; - C1E34B2729C7ABF3009A50A5 /* MinimedPumpClockSetupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B0E29C7ABF2009A50A5 /* MinimedPumpClockSetupViewController.swift */; }; - C1E34B2829C7ABF3009A50A5 /* MinimedPumpSetupCompleteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B0F29C7ABF2009A50A5 /* MinimedPumpSetupCompleteViewController.swift */; }; - C1E34B2929C7ABF3009A50A5 /* MinimedPumpSentrySetupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B1029C7ABF2009A50A5 /* MinimedPumpSentrySetupViewController.swift */; }; - C1E34B2A29C7ABF3009A50A5 /* MinimedPumpManager+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B1129C7ABF2009A50A5 /* MinimedPumpManager+UI.swift */; }; - C1E34B2B29C7ABF3009A50A5 /* PumpModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B1229C7ABF2009A50A5 /* PumpModel.swift */; }; - C1E34B2C29C7ABF3009A50A5 /* RadioSelectionTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B1329C7ABF2009A50A5 /* RadioSelectionTableViewController.swift */; }; - C1E34B2E29C7ABF3009A50A5 /* MinimedPumpUICoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B1529C7ABF2009A50A5 /* MinimedPumpUICoordinator.swift */; }; - C1E34B2F29C7ABF3009A50A5 /* CommandResponseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B1629C7ABF2009A50A5 /* CommandResponseViewController.swift */; }; - C1E34B3029C7ABF3009A50A5 /* MinimedHUDProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B1729C7ABF2009A50A5 /* MinimedHUDProvider.swift */; }; - C1E34B3129C7ABF3009A50A5 /* UseMySentrySelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B1929C7ABF3009A50A5 /* UseMySentrySelectionView.swift */; }; - C1E34B3229C7ABF3009A50A5 /* DataSourceSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B1A29C7ABF3009A50A5 /* DataSourceSelectionView.swift */; }; - C1E34B3329C7ABF3009A50A5 /* BatteryTypeSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B1B29C7ABF3009A50A5 /* BatteryTypeSelectionView.swift */; }; - C1E34B3429C7ABF3009A50A5 /* ReservoirHUDView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C1E34B1C29C7ABF3009A50A5 /* ReservoirHUDView.xib */; }; - C1E34B3529C7ABF3009A50A5 /* MinimedPumpSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B1D29C7ABF3009A50A5 /* MinimedPumpSettingsView.swift */; }; - C1E34B3629C7ABF3009A50A5 /* ReservoirHUDView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B1E29C7ABF3009A50A5 /* ReservoirHUDView.swift */; }; - C1E34B3729C7ABF3009A50A5 /* MinimedPumpSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B1F29C7ABF3009A50A5 /* MinimedPumpSettingsViewModel.swift */; }; - C1E34B3829C7ABF3009A50A5 /* InsulinTypeConfirmation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B2029C7ABF3009A50A5 /* InsulinTypeConfirmation.swift */; }; - C1E34B3929C7ABF3009A50A5 /* MinimedReservoirView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B2129C7ABF3009A50A5 /* MinimedReservoirView.swift */; }; - C1E34B3A29C7ABF3009A50A5 /* TimeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B2229C7ABF3009A50A5 /* TimeView.swift */; }; - C1E34B3E29C7AC0A009A50A5 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C1E34B4029C7AC0A009A50A5 /* Localizable.strings */; }; - C1E34B6429C7AD31009A50A5 /* MinimedKitPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B6229C7AD31009A50A5 /* MinimedKitPlugin.swift */; }; - C1E34B6829C7AD62009A50A5 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1E34B6729C7AD62009A50A5 /* LoopKit.framework */; }; - C1E34B6B29C7AD9C009A50A5 /* MinimedKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1E3491129C7A866009A50A5 /* MinimedKit.framework */; }; - C1E34B6C29C7AD9C009A50A5 /* MinimedKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C1E3491129C7A866009A50A5 /* MinimedKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - C1E34B6F29C7AD9C009A50A5 /* MinimedKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1E34B0129C7ABCB009A50A5 /* MinimedKitUI.framework */; }; - C1E34B7029C7AD9C009A50A5 /* MinimedKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C1E34B0129C7ABCB009A50A5 /* MinimedKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - C1E34B7529C7AF61009A50A5 /* LocalisedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B7429C7AF61009A50A5 /* LocalisedString.swift */; }; - C1E34B7729C7AFCF009A50A5 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B7629C7AFCF009A50A5 /* Data.swift */; }; - C1E34B7929C7AFF7009A50A5 /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B7829C7AFF7009A50A5 /* TimeInterval.swift */; }; - C1E34B7B29C7B044009A50A5 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B7A29C7B044009A50A5 /* OSLog.swift */; }; - C1E34B7D29C7B075009A50A5 /* RileyLinkKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1E34B7C29C7B075009A50A5 /* RileyLinkKit.framework */; }; - C1E34B8129C7B155009A50A5 /* PumpOpsSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B8029C7B155009A50A5 /* PumpOpsSession.swift */; }; - C1E34B8329C7B1AB009A50A5 /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B8229C7B1AB009A50A5 /* TimeZone.swift */; }; - C1E34B8529C7B1D4009A50A5 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B8429C7B1D4009A50A5 /* HKUnit.swift */; }; - C1E34B8829C7B292009A50A5 /* Comparable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B8729C7B292009A50A5 /* Comparable.swift */; }; - C1E34B8A29C7B2FC009A50A5 /* LocalisedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B8929C7B2FC009A50A5 /* LocalisedString.swift */; }; - C1E34B8C29C7B334009A50A5 /* IdentifiableClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B8B29C7B334009A50A5 /* IdentifiableClass.swift */; }; - C1E34B8E29C7B34F009A50A5 /* NibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B8D29C7B34F009A50A5 /* NibLoadable.swift */; }; - C1E34B9029C7B38A009A50A5 /* NumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B8F29C7B38A009A50A5 /* NumberFormatter.swift */; }; - C1E34B9229C7B46C009A50A5 /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E34B9129C7B46C009A50A5 /* TimeZone.swift */; }; - C1E34B9829C7B5A3009A50A5 /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1E34B9729C7B5A3009A50A5 /* LoopKitUI.framework */; }; - C1E34B9A29C7B5E9009A50A5 /* RileyLinkKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1E34B9329C7B59B009A50A5 /* RileyLinkKitUI.framework */; }; - C1E34B9D29C7B623009A50A5 /* RileyLinkKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1E34B9329C7B59B009A50A5 /* RileyLinkKitUI.framework */; }; - C1E34B9E29C7B623009A50A5 /* RileyLinkKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C1E34B9329C7B59B009A50A5 /* RileyLinkKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - C1E34B9F29C7B649009A50A5 /* RileyLinkKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1E34B7C29C7B075009A50A5 /* RileyLinkKit.framework */; }; - C1E34BA029C7B649009A50A5 /* RileyLinkKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C1E34B7C29C7B075009A50A5 /* RileyLinkKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - C1E34BA229C7B652009A50A5 /* RileyLinkBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1E34BA129C7B652009A50A5 /* RileyLinkBLEKit.framework */; }; - C1E34BA329C7B652009A50A5 /* RileyLinkBLEKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C1E34BA129C7B652009A50A5 /* RileyLinkBLEKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - C13CC33A29C7B6BC007F25DE /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C1E3490829C7A866009A50A5 /* Project object */; - proxyType = 1; - remoteGlobalIDString = C1E3491029C7A866009A50A5; - remoteInfo = MinimedKit; - }; - C13CC34629C7B73A007F25DE /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C1E3490829C7A866009A50A5 /* Project object */; - proxyType = 1; - remoteGlobalIDString = C1E3491029C7A866009A50A5; - remoteInfo = MinimedKit; - }; - C1E34B6D29C7AD9C009A50A5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C1E3490829C7A866009A50A5 /* Project object */; - proxyType = 1; - remoteGlobalIDString = C1E3491029C7A866009A50A5; - remoteInfo = MinimedKit; - }; - C1E34B7129C7AD9C009A50A5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C1E3490829C7A866009A50A5 /* Project object */; - proxyType = 1; - remoteGlobalIDString = C1E34B0029C7ABCB009A50A5; - remoteInfo = MinimedKitUI; - }; - CEC751C729D88240006E9D24 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CEC751BF29D88240006E9D24 /* OmniKit.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = C124016C29C7D87A00B32844; - remoteInfo = OmniKit; - }; - CEC751C929D88240006E9D24 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CEC751BF29D88240006E9D24 /* OmniKit.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = C124020B29C7D92700B32844; - remoteInfo = OmniKitUI; - }; - CEC751CB29D88240006E9D24 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CEC751BF29D88240006E9D24 /* OmniKit.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = C124021729C7D93D00B32844; - remoteInfo = OmniKitPlugin; - }; - CEC751CD29D88240006E9D24 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CEC751BF29D88240006E9D24 /* OmniKit.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = C12ED9CA29C7DBA900435701; - remoteInfo = OmniKitTests; - }; - CEC751CF29D88240006E9D24 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CEC751BF29D88240006E9D24 /* OmniKit.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = C1229C6B29C7F0840066A89C; - remoteInfo = OmniKitPacketParser; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - C1E34B7329C7AD9C009A50A5 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - C1E34BA329C7B652009A50A5 /* RileyLinkBLEKit.framework in Embed Frameworks */, - C1E34B9E29C7B623009A50A5 /* RileyLinkKitUI.framework in Embed Frameworks */, - C1E34BA029C7B649009A50A5 /* RileyLinkKit.framework in Embed Frameworks */, - C1E34B6C29C7AD9C009A50A5 /* MinimedKit.framework in Embed Frameworks */, - C1E34B7029C7AD9C009A50A5 /* MinimedKitUI.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 193F1E522B44C22A00525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - 193F1E532B44C22A00525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; - 193F1E542B44C22A00525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; - C1229C2129C7ECA70066A89C /* TimeInterval.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeInterval.swift; sourceTree = ""; }; - C1229C2329C7ECEB0066A89C /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; }; - C13CC34129C7B73A007F25DE /* MinimedKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MinimedKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - C13CC34C29C7B755007F25DE /* ResumePumpEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResumePumpEventTests.swift; sourceTree = ""; }; - C13CC34D29C7B755007F25DE /* BolusNormalPumpEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusNormalPumpEventTests.swift; sourceTree = ""; }; - C13CC34F29C7B755007F25DE /* ReadCurrentGlucosePageMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadCurrentGlucosePageMessageBodyTests.swift; sourceTree = ""; }; - C13CC35029C7B755007F25DE /* ChangeTimeCarelinMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTimeCarelinMessageBodyTests.swift; sourceTree = ""; }; - C13CC35129C7B755007F25DE /* MeterMessageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeterMessageTests.swift; sourceTree = ""; }; - C13CC35229C7B755007F25DE /* ChangeTempBasalCarelinkMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTempBasalCarelinkMessageBodyTests.swift; sourceTree = ""; }; - C13CC35329C7B755007F25DE /* ReadOtherDevicesIDsMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadOtherDevicesIDsMessageBodyTests.swift; sourceTree = ""; }; - C13CC35429C7B755007F25DE /* BolusCarelinkMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusCarelinkMessageBodyTests.swift; sourceTree = ""; }; - C13CC35529C7B755007F25DE /* FindDeviceMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FindDeviceMessageBodyTests.swift; sourceTree = ""; }; - C13CC35629C7B755007F25DE /* ReadRemoteControlIDsMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadRemoteControlIDsMessageBodyTests.swift; sourceTree = ""; }; - C13CC35729C7B755007F25DE /* ReadTempBasalCarelinkMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadTempBasalCarelinkMessageBodyTests.swift; sourceTree = ""; }; - C13CC35829C7B755007F25DE /* DeviceLinkMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceLinkMessageBodyTests.swift; sourceTree = ""; }; - C13CC35929C7B755007F25DE /* ChangeMaxBasalRateMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeMaxBasalRateMessageBodyTests.swift; sourceTree = ""; }; - C13CC35A29C7B755007F25DE /* ChangeRemoteControlIDMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeRemoteControlIDMessageBodyTests.swift; sourceTree = ""; }; - C13CC35B29C7B755007F25DE /* GetBatteryCarelinkMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetBatteryCarelinkMessageBodyTests.swift; sourceTree = ""; }; - C13CC35C29C7B755007F25DE /* ReadRemainingInsulinMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadRemainingInsulinMessageBodyTests.swift; sourceTree = ""; }; - C13CC35D29C7B755007F25DE /* ChangeMaxBolusMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeMaxBolusMessageBodyTests.swift; sourceTree = ""; }; - C13CC35E29C7B755007F25DE /* GetPumpModelCarelinkMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetPumpModelCarelinkMessageBodyTests.swift; sourceTree = ""; }; - C13CC35F29C7B755007F25DE /* GetGlucosePageMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetGlucosePageMessageBodyTests.swift; sourceTree = ""; }; - C13CC36029C7B755007F25DE /* MinimedPacketTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPacketTests.swift; sourceTree = ""; }; - C13CC36129C7B755007F25DE /* MinimedPumpManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPumpManagerTests.swift; sourceTree = ""; }; - C13CC36229C7B755007F25DE /* NSDateComponents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDateComponents.swift; sourceTree = ""; }; - C13CC36329C7B755007F25DE /* PumpOpsSynchronousTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpOpsSynchronousTests.swift; sourceTree = ""; }; - C13CC36429C7B755007F25DE /* NSDataTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDataTests.swift; sourceTree = ""; }; - C13CC36529C7B755007F25DE /* TimestampedHistoryEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimestampedHistoryEventTests.swift; sourceTree = ""; }; - C13CC36629C7B755007F25DE /* CRC8Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CRC8Tests.swift; sourceTree = ""; }; - C13CC36829C7B756007F25DE /* SensorDataHighGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorDataHighGlucoseEventTests.swift; sourceTree = ""; }; - C13CC36929C7B756007F25DE /* SensorTimestampGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorTimestampGlucoseEventTests.swift; sourceTree = ""; }; - C13CC36A29C7B756007F25DE /* BatteryChangeGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatteryChangeGlucoseEventTests.swift; sourceTree = ""; }; - C13CC36B29C7B756007F25DE /* SensorErrorGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorErrorGlucoseEventTests.swift; sourceTree = ""; }; - C13CC36C29C7B756007F25DE /* SensorCalFactorGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorCalFactorGlucoseEventTests.swift; sourceTree = ""; }; - C13CC36D29C7B756007F25DE /* SensorCalGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorCalGlucoseEventTests.swift; sourceTree = ""; }; - C13CC36E29C7B756007F25DE /* CalBGForGHGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalBGForGHGlucoseEventTests.swift; sourceTree = ""; }; - C13CC36F29C7B756007F25DE /* SensorStatusGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorStatusGlucoseEventTests.swift; sourceTree = ""; }; - C13CC37029C7B756007F25DE /* SensorDataLowGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorDataLowGlucoseEventTests.swift; sourceTree = ""; }; - C13CC37129C7B756007F25DE /* GlucoseSensorDataGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseSensorDataGlucoseEventTests.swift; sourceTree = ""; }; - C13CC37229C7B756007F25DE /* SensorSyncGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorSyncGlucoseEventTests.swift; sourceTree = ""; }; - C13CC37329C7B756007F25DE /* DateTimeChangeGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateTimeChangeGlucoseEventTests.swift; sourceTree = ""; }; - C13CC37429C7B756007F25DE /* SensorPacketGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorPacketGlucoseEventTests.swift; sourceTree = ""; }; - C13CC37529C7B756007F25DE /* TenSomethingGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TenSomethingGlucoseEventTests.swift; sourceTree = ""; }; - C13CC37629C7B756007F25DE /* BasalScheduleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasalScheduleTests.swift; sourceTree = ""; }; - C13CC37829C7B756007F25DE /* MockRileyLinkProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockRileyLinkProvider.swift; sourceTree = ""; }; - C13CC37929C7B756007F25DE /* MockPumpManagerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockPumpManagerDelegate.swift; sourceTree = ""; }; - C13CC37A29C7B756007F25DE /* MockPumpOps.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockPumpOps.swift; sourceTree = ""; }; - C13CC37B29C7B756007F25DE /* MockPumpMessageSender.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockPumpMessageSender.swift; sourceTree = ""; }; - C13CC37C29C7B756007F25DE /* MockRileyLinkDevice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockRileyLinkDevice.swift; sourceTree = ""; }; - C13CC37D29C7B756007F25DE /* GlucosePageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucosePageTests.swift; sourceTree = ""; }; - C13CC37E29C7B756007F25DE /* NSStringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSStringExtensions.swift; sourceTree = ""; }; - C13CC37F29C7B756007F25DE /* ReadSettingsCarelinkMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadSettingsCarelinkMessageBodyTests.swift; sourceTree = ""; }; - C13CC38029C7B756007F25DE /* PumpModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpModelTests.swift; sourceTree = ""; }; - C13CC38129C7B756007F25DE /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C13CC38229C7B756007F25DE /* HistoryPageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryPageTests.swift; sourceTree = ""; }; - C13CC38329C7B757007F25DE /* CRC16Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CRC16Tests.swift; sourceTree = ""; }; - C13CC38429C7B757007F25DE /* MySentryPumpStatusMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MySentryPumpStatusMessageBodyTests.swift; sourceTree = ""; }; - C13CC38529C7B757007F25DE /* NSDateComponentsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDateComponentsTests.swift; sourceTree = ""; }; - C13CC38629C7B757007F25DE /* PumpOpsSynchronousBuildFromFramesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpOpsSynchronousBuildFromFramesTests.swift; sourceTree = ""; }; - C13CC38729C7B757007F25DE /* ReconciliationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReconciliationTests.swift; sourceTree = ""; }; - C13CC3C229C7B8BC007F25DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MinimedPumpManager.storyboard; sourceTree = ""; }; - C13CC3C529C7B8D0007F25DE /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3C629C7B8D4007F25DE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3C729C7B8D8007F25DE /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/MinimedPumpManager.strings"; sourceTree = ""; }; - C13CC3C829C7B8DA007F25DE /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3C929C7B8DB007F25DE /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3CA29C7B8DC007F25DE /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3CB29C7B8DD007F25DE /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3CC29C7B8DE007F25DE /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3CD29C7B8DF007F25DE /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3CE29C7B8E0007F25DE /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3CF29C7B8E0007F25DE /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3D029C7B8E1007F25DE /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3D129C7B8E2007F25DE /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3D229C7B8E3007F25DE /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3D329C7B8E4007F25DE /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/MinimedPumpManager.strings"; sourceTree = ""; }; - C13CC3D429C7B8E5007F25DE /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3D529C7B8E5007F25DE /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3D629C7B8E6007F25DE /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3D729C7B8E7007F25DE /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3D829C7B8E9007F25DE /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3D929C7B8E9007F25DE /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3DA29C7B8EB007F25DE /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/MinimedPumpManager.strings; sourceTree = ""; }; - C13CC3DC29C7BA48007F25DE /* OSLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; - C1BF2DB929C8007300EB8987 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - C1E3491129C7A866009A50A5 /* MinimedKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MinimedKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C1E3491429C7A866009A50A5 /* MinimedKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MinimedKit.h; sourceTree = ""; }; - C1E3492529C7A98B009A50A5 /* CalBGForGHGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalBGForGHGlucoseEvent.swift; sourceTree = ""; }; - C1E3492629C7A98B009A50A5 /* RelativeTimestampedGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RelativeTimestampedGlucoseEvent.swift; sourceTree = ""; }; - C1E3492729C7A98B009A50A5 /* SensorCalGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorCalGlucoseEvent.swift; sourceTree = ""; }; - C1E3492829C7A98B009A50A5 /* SensorErrorGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorErrorGlucoseEvent.swift; sourceTree = ""; }; - C1E3492929C7A98B009A50A5 /* TenSomethingGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TenSomethingGlucoseEvent.swift; sourceTree = ""; }; - C1E3492A29C7A98B009A50A5 /* SensorStatusGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorStatusGlucoseEvent.swift; sourceTree = ""; }; - C1E3492B29C7A98B009A50A5 /* SensorValueGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorValueGlucoseEvent.swift; sourceTree = ""; }; - C1E3492C29C7A98B009A50A5 /* SensorSyncGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorSyncGlucoseEvent.swift; sourceTree = ""; }; - C1E3492D29C7A98B009A50A5 /* SensorTimestampGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorTimestampGlucoseEvent.swift; sourceTree = ""; }; - C1E3492E29C7A98B009A50A5 /* SensorDataLowGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorDataLowGlucoseEvent.swift; sourceTree = ""; }; - C1E3492F29C7A98B009A50A5 /* SensorPacketGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorPacketGlucoseEvent.swift; sourceTree = ""; }; - C1E3493029C7A98B009A50A5 /* DateTimeChangeGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateTimeChangeGlucoseEvent.swift; sourceTree = ""; }; - C1E3493129C7A98B009A50A5 /* UnknownGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnknownGlucoseEvent.swift; sourceTree = ""; }; - C1E3493229C7A98B009A50A5 /* DataEndGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataEndGlucoseEvent.swift; sourceTree = ""; }; - C1E3493329C7A98B009A50A5 /* NineteenSomethingGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NineteenSomethingGlucoseEvent.swift; sourceTree = ""; }; - C1E3493429C7A98B009A50A5 /* GlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseEvent.swift; sourceTree = ""; }; - C1E3493529C7A98B009A50A5 /* GlucoseSensorDataGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseSensorDataGlucoseEvent.swift; sourceTree = ""; }; - C1E3493629C7A98B009A50A5 /* SensorDataHighGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorDataHighGlucoseEvent.swift; sourceTree = ""; }; - C1E3493729C7A98B009A50A5 /* BatteryChangeGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatteryChangeGlucoseEvent.swift; sourceTree = ""; }; - C1E3493829C7A98B009A50A5 /* SensorCalFactorGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorCalFactorGlucoseEvent.swift; sourceTree = ""; }; - C1E3493929C7A98B009A50A5 /* SensorWeakSignalGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorWeakSignalGlucoseEvent.swift; sourceTree = ""; }; - C1E3493B29C7A98B009A50A5 /* SensorValueGlucoseEvent+CGMManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SensorValueGlucoseEvent+CGMManager.swift"; sourceTree = ""; }; - C1E3493C29C7A98B009A50A5 /* MySentryPumpStatusMessageBody+CGMManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MySentryPumpStatusMessageBody+CGMManager.swift"; sourceTree = ""; }; - C1E3494029C7A98C009A50A5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C1E3494529C7A98C009A50A5 /* MinimedPumpManagerState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPumpManagerState.swift; sourceTree = ""; }; - C1E3494629C7A98C009A50A5 /* MinimedPumpManagerRecents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPumpManagerRecents.swift; sourceTree = ""; }; - C1E3494729C7A98C009A50A5 /* EnliteSensorDisplayable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnliteSensorDisplayable.swift; sourceTree = ""; }; - C1E3494829C7A98C009A50A5 /* PumpOpsSession+LoopKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PumpOpsSession+LoopKit.swift"; sourceTree = ""; }; - C1E3494929C7A98C009A50A5 /* BasalProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasalProfile.swift; sourceTree = ""; }; - C1E3494A29C7A98C009A50A5 /* HistoryPage+PumpOpsSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HistoryPage+PumpOpsSession.swift"; sourceTree = ""; }; - C1E3494B29C7A98C009A50A5 /* ReservoirReading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReservoirReading.swift; sourceTree = ""; }; - C1E3494C29C7A98C009A50A5 /* PumpMessageSender.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpMessageSender.swift; sourceTree = ""; }; - C1E3494D29C7A98C009A50A5 /* MinimedPumpManagerError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPumpManagerError.swift; sourceTree = ""; }; - C1E3494E29C7A98C009A50A5 /* DoseStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoseStore.swift; sourceTree = ""; }; - C1E3494F29C7A98C009A50A5 /* PumpSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpSettings.swift; sourceTree = ""; }; - C1E3495029C7A98C009A50A5 /* PumpOps.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpOps.swift; sourceTree = ""; }; - C1E3495129C7A98C009A50A5 /* PumpMessage+PumpOpsSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PumpMessage+PumpOpsSession.swift"; sourceTree = ""; }; - C1E3495229C7A98C009A50A5 /* InsulinDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsulinDataSource.swift; sourceTree = ""; }; - C1E3495329C7A98C009A50A5 /* MinimedDoseProgressEstimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedDoseProgressEstimator.swift; sourceTree = ""; }; - C1E3495429C7A98C009A50A5 /* MinimedPumpMessageSender.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPumpMessageSender.swift; sourceTree = ""; }; - C1E3495529C7A98C009A50A5 /* MinimedPumpManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPumpManager.swift; sourceTree = ""; }; - C1E3495629C7A98C009A50A5 /* UnfinalizedDose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnfinalizedDose.swift; sourceTree = ""; }; - C1E3495729C7A98C009A50A5 /* RileyLinkDevice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RileyLinkDevice.swift; sourceTree = ""; }; - C1E3495829C7A98C009A50A5 /* PumpOpsError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpOpsError.swift; sourceTree = ""; }; - C1E3495929C7A98C009A50A5 /* PumpState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpState.swift; sourceTree = ""; }; - C1E3496429C7A98C009A50A5 /* ChangeWatchdogEnablePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeWatchdogEnablePumpEvent.swift; sourceTree = ""; }; - C1E3496529C7A98C009A50A5 /* PumpAlarmPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpAlarmPumpEvent.swift; sourceTree = ""; }; - C1E3496629C7A98C009A50A5 /* ChangeCaptureEventEnablePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeCaptureEventEnablePumpEvent.swift; sourceTree = ""; }; - C1E3496729C7A98C009A50A5 /* TempBasalDurationPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TempBasalDurationPumpEvent.swift; sourceTree = ""; }; - C1E3496829C7A98C009A50A5 /* ChangeBolusScrollStepSizePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBolusScrollStepSizePumpEvent.swift; sourceTree = ""; }; - C1E3496929C7A98C009A50A5 /* ChangeSensorSetup2PumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeSensorSetup2PumpEvent.swift; sourceTree = ""; }; - C1E3496A29C7A98C009A50A5 /* JournalEntryInsulinMarkerPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JournalEntryInsulinMarkerPumpEvent.swift; sourceTree = ""; }; - C1E3496B29C7A98C009A50A5 /* ChangeMaxBolusPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeMaxBolusPumpEvent.swift; sourceTree = ""; }; - C1E3496C29C7A98C009A50A5 /* ChangeVariableBolusPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeVariableBolusPumpEvent.swift; sourceTree = ""; }; - C1E3496D29C7A98C009A50A5 /* ChangeBolusReminderEnablePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBolusReminderEnablePumpEvent.swift; sourceTree = ""; }; - C1E3496E29C7A98C009A50A5 /* ChangeCarbUnitsPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeCarbUnitsPumpEvent.swift; sourceTree = ""; }; - C1E3496F29C7A98C009A50A5 /* BolusWizardEstimatePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusWizardEstimatePumpEvent.swift; sourceTree = ""; }; - C1E3497029C7A98C009A50A5 /* ClearAlarmPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClearAlarmPumpEvent.swift; sourceTree = ""; }; - C1E3497129C7A98C009A50A5 /* ChangeAlarmNotifyModePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeAlarmNotifyModePumpEvent.swift; sourceTree = ""; }; - C1E3497229C7A98C009A50A5 /* ChangeAlarmClockEnablePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeAlarmClockEnablePumpEvent.swift; sourceTree = ""; }; - C1E3497329C7A98C009A50A5 /* JournalEntryPumpLowReservoirPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JournalEntryPumpLowReservoirPumpEvent.swift; sourceTree = ""; }; - C1E3497429C7A98C009A50A5 /* ChangeTimeFormatPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTimeFormatPumpEvent.swift; sourceTree = ""; }; - C1E3497529C7A98C009A50A5 /* SelectBasalProfilePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectBasalProfilePumpEvent.swift; sourceTree = ""; }; - C1E3497629C7A98C009A50A5 /* DailyTotal522PumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DailyTotal522PumpEvent.swift; sourceTree = ""; }; - C1E3497729C7A98C009A50A5 /* BGReceivedPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BGReceivedPumpEvent.swift; sourceTree = ""; }; - C1E3497829C7A98C009A50A5 /* TimestampedPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimestampedPumpEvent.swift; sourceTree = ""; }; - C1E3497929C7A98C009A50A5 /* SuspendPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SuspendPumpEvent.swift; sourceTree = ""; }; - C1E3497A29C7A98C009A50A5 /* EnableBolusWizardPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnableBolusWizardPumpEvent.swift; sourceTree = ""; }; - C1E3497B29C7A98C009A50A5 /* UnabsorbedInsulinPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnabsorbedInsulinPumpEvent.swift; sourceTree = ""; }; - C1E3497C29C7A98C009A50A5 /* DeleteOtherDeviceIDPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeleteOtherDeviceIDPumpEvent.swift; sourceTree = ""; }; - C1E3497D29C7A98C009A50A5 /* AlarmClockReminderPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlarmClockReminderPumpEvent.swift; sourceTree = ""; }; - C1E3497E29C7A98C009A50A5 /* ChangeBGReminderEnablePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBGReminderEnablePumpEvent.swift; sourceTree = ""; }; - C1E3497F29C7A98C009A50A5 /* JournalEntryPumpLowBatteryPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JournalEntryPumpLowBatteryPumpEvent.swift; sourceTree = ""; }; - C1E3498029C7A98C009A50A5 /* NewTimePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewTimePumpEvent.swift; sourceTree = ""; }; - C1E3498129C7A98C009A50A5 /* ChangeMaxBasalPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeMaxBasalPumpEvent.swift; sourceTree = ""; }; - C1E3498229C7A98C009A50A5 /* ChangeTempBasalTypePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTempBasalTypePumpEvent.swift; sourceTree = ""; }; - C1E3498329C7A98C009A50A5 /* ChangeSensorAlarmSilenceConfigPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeSensorAlarmSilenceConfigPumpEvent.swift; sourceTree = ""; }; - C1E3498429C7A98C009A50A5 /* ChangeOtherDeviceIDPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeOtherDeviceIDPumpEvent.swift; sourceTree = ""; }; - C1E3498529C7A98C009A50A5 /* PrimePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrimePumpEvent.swift; sourceTree = ""; }; - C1E3498629C7A98C009A50A5 /* DailyTotal523PumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DailyTotal523PumpEvent.swift; sourceTree = ""; }; - C1E3498729C7A98C009A50A5 /* BatteryPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatteryPumpEvent.swift; sourceTree = ""; }; - C1E3498829C7A98C009A50A5 /* EnableDisableRemotePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnableDisableRemotePumpEvent.swift; sourceTree = ""; }; - C1E3498929C7A98C009A50A5 /* TempBasalPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TempBasalPumpEvent.swift; sourceTree = ""; }; - C1E3498A29C7A98C009A50A5 /* ChangeSensorRateOfChangeAlertSetupPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeSensorRateOfChangeAlertSetupPumpEvent.swift; sourceTree = ""; }; - C1E3498B29C7A98C009A50A5 /* RestoreMystery55PumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestoreMystery55PumpEvent.swift; sourceTree = ""; }; - C1E3498C29C7A98C009A50A5 /* BolusWizardSetupPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusWizardSetupPumpEvent.swift; sourceTree = ""; }; - C1E3498D29C7A98C009A50A5 /* ChangeTimePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTimePumpEvent.swift; sourceTree = ""; }; - C1E3498E29C7A98C009A50A5 /* ChangeBolusReminderTimePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBolusReminderTimePumpEvent.swift; sourceTree = ""; }; - C1E3498F29C7A98C009A50A5 /* ChangeBolusWizardSetupPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBolusWizardSetupPumpEvent.swift; sourceTree = ""; }; - C1E3499029C7A98C009A50A5 /* PlaceholderPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlaceholderPumpEvent.swift; sourceTree = ""; }; - C1E3499129C7A98C009A50A5 /* PumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpEvent.swift; sourceTree = ""; }; - C1E3499229C7A98C009A50A5 /* ChangeBasalProfilePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBasalProfilePumpEvent.swift; sourceTree = ""; }; - C1E3499329C7A98C009A50A5 /* ResumePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResumePumpEvent.swift; sourceTree = ""; }; - C1E3499429C7A98C009A50A5 /* ChangeBGReminderOffsetPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBGReminderOffsetPumpEvent.swift; sourceTree = ""; }; - C1E3499529C7A98C009A50A5 /* ChangeWatchdogMarriageProfilePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeWatchdogMarriageProfilePumpEvent.swift; sourceTree = ""; }; - C1E3499629C7A98C009A50A5 /* BasalProfileStartPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasalProfileStartPumpEvent.swift; sourceTree = ""; }; - C1E3499729C7A98C009A50A5 /* ResultDailyTotalPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultDailyTotalPumpEvent.swift; sourceTree = ""; }; - C1E3499829C7A98C009A50A5 /* UnknownPumpEvent57.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnknownPumpEvent57.swift; sourceTree = ""; }; - C1E3499929C7A98C009A50A5 /* RestoreMystery54PumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestoreMystery54PumpEvent.swift; sourceTree = ""; }; - C1E3499A29C7A98C009A50A5 /* CalBGForPHPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalBGForPHPumpEvent.swift; sourceTree = ""; }; - C1E3499B29C7A98C009A50A5 /* ChangeParadigmLinkIDPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeParadigmLinkIDPumpEvent.swift; sourceTree = ""; }; - C1E3499C29C7A98C009A50A5 /* ChangeChildBlockEnablePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeChildBlockEnablePumpEvent.swift; sourceTree = ""; }; - C1E3499D29C7A98C009A50A5 /* ChangeBasalProfilePatternPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBasalProfilePatternPumpEvent.swift; sourceTree = ""; }; - C1E3499E29C7A98C009A50A5 /* RewindPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RewindPumpEvent.swift; sourceTree = ""; }; - C1E3499F29C7A98C009A50A5 /* BolusReminderPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusReminderPumpEvent.swift; sourceTree = ""; }; - C1E349A029C7A98C009A50A5 /* ChangeMeterIDPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeMeterIDPumpEvent.swift; sourceTree = ""; }; - C1E349A129C7A98C009A50A5 /* ChangeAudioBolusPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeAudioBolusPumpEvent.swift; sourceTree = ""; }; - C1E349A229C7A98C009A50A5 /* DeleteBolusReminderTimePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeleteBolusReminderTimePumpEvent.swift; sourceTree = ""; }; - C1E349A329C7A98C009A50A5 /* ChangeReservoirWarningTimePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeReservoirWarningTimePumpEvent.swift; sourceTree = ""; }; - C1E349A429C7A98C009A50A5 /* JournalEntryExerciseMarkerPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JournalEntryExerciseMarkerPumpEvent.swift; sourceTree = ""; }; - C1E349A529C7A98C009A50A5 /* BolusNormalPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusNormalPumpEvent.swift; sourceTree = ""; }; - C1E349A629C7A98C009A50A5 /* AlarmSensorPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlarmSensorPumpEvent.swift; sourceTree = ""; }; - C1E349A729C7A98C009A50A5 /* DailyTotal515PumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DailyTotal515PumpEvent.swift; sourceTree = ""; }; - C1E349A829C7A98C009A50A5 /* JournalEntryMealMarkerPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JournalEntryMealMarkerPumpEvent.swift; sourceTree = ""; }; - C1E349AD29C7A98C009A50A5 /* MessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageBody.swift; sourceTree = ""; }; - C1E349AE29C7A98C009A50A5 /* ReadCurrentPageNumberMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadCurrentPageNumberMessageBody.swift; sourceTree = ""; }; - C1E349AF29C7A98C009A50A5 /* PowerOnCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PowerOnCarelinkMessageBody.swift; sourceTree = ""; }; - C1E349B029C7A98C009A50A5 /* GetBatteryCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetBatteryCarelinkMessageBody.swift; sourceTree = ""; }; - C1E349B129C7A98C009A50A5 /* SetRemoteControlEnabledMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetRemoteControlEnabledMessageBody.swift; sourceTree = ""; }; - C1E349B229C7A98C009A50A5 /* GetHistoryPageCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetHistoryPageCarelinkMessageBody.swift; sourceTree = ""; }; - C1E349B329C7A98C009A50A5 /* PumpAckMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpAckMessageBody.swift; sourceTree = ""; }; - C1E349B429C7A98C009A50A5 /* MySentryAckMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MySentryAckMessageBody.swift; sourceTree = ""; }; - C1E349B529C7A98C009A50A5 /* MySentryAlertMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MySentryAlertMessageBody.swift; sourceTree = ""; }; - C1E349B629C7A98C009A50A5 /* PumpErrorMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpErrorMessageBody.swift; sourceTree = ""; }; - C1E349B729C7A98C009A50A5 /* UnknownMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnknownMessageBody.swift; sourceTree = ""; }; - C1E349B829C7A98C009A50A5 /* DeviceLinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceLinkMessageBody.swift; sourceTree = ""; }; - C1E349B929C7A98C009A50A5 /* ReadTempBasalCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadTempBasalCarelinkMessageBody.swift; sourceTree = ""; }; - C1E349BA29C7A98C009A50A5 /* ReadCurrentGlucosePageMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadCurrentGlucosePageMessageBody.swift; sourceTree = ""; }; - C1E349BC29C7A98C009A50A5 /* GlucosePage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucosePage.swift; sourceTree = ""; }; - C1E349BD29C7A98C009A50A5 /* HistoryPage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryPage.swift; sourceTree = ""; }; - C1E349BE29C7A98C009A50A5 /* GlucoseEventType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseEventType.swift; sourceTree = ""; }; - C1E349BF29C7A98C009A50A5 /* TimestampedGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimestampedGlucoseEvent.swift; sourceTree = ""; }; - C1E349C029C7A98C009A50A5 /* PartialDecode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PartialDecode.swift; sourceTree = ""; }; - C1E349C129C7A98C009A50A5 /* MySentryAlertType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MySentryAlertType.swift; sourceTree = ""; }; - C1E349C229C7A98C009A50A5 /* CRC16.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CRC16.swift; sourceTree = ""; }; - C1E349C329C7A98C009A50A5 /* BasalSchedule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasalSchedule.swift; sourceTree = ""; }; - C1E349C429C7A98C009A50A5 /* PumpEventType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpEventType.swift; sourceTree = ""; }; - C1E349C529C7A98C009A50A5 /* TimestampedHistoryEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimestampedHistoryEvent.swift; sourceTree = ""; }; - C1E349C629C7A98C009A50A5 /* GetGlucosePageMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetGlucosePageMessageBody.swift; sourceTree = ""; }; - C1E349C729C7A98C009A50A5 /* MySentryPumpStatusMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MySentryPumpStatusMessageBody.swift; sourceTree = ""; }; - C1E349C829C7A98C009A50A5 /* GetPumpModelCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetPumpModelCarelinkMessageBody.swift; sourceTree = ""; }; - C1E349C929C7A98C009A50A5 /* MySentryAlertClearedMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MySentryAlertClearedMessageBody.swift; sourceTree = ""; }; - C1E349CA29C7A98C009A50A5 /* ChangeTempBasalCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTempBasalCarelinkMessageBody.swift; sourceTree = ""; }; - C1E349CB29C7A98C009A50A5 /* ReadOtherDevicesIDsMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadOtherDevicesIDsMessageBody.swift; sourceTree = ""; }; - C1E349CC29C7A98C009A50A5 /* ReadTimeCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadTimeCarelinkMessageBody.swift; sourceTree = ""; }; - C1E349CD29C7A98C009A50A5 /* ReadSettingsCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadSettingsCarelinkMessageBody.swift; sourceTree = ""; }; - C1E349CE29C7A98C009A50A5 /* GetPumpFirmwareVersionMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetPumpFirmwareVersionMessageBody.swift; sourceTree = ""; }; - C1E349CF29C7A98C009A50A5 /* MessageType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageType.swift; sourceTree = ""; }; - C1E349D029C7A98C009A50A5 /* ReadRemoteControlIDsMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadRemoteControlIDsMessageBody.swift; sourceTree = ""; }; - C1E349D129C7A98C009A50A5 /* PumpMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpMessage.swift; sourceTree = ""; }; - C1E349D229C7A98C009A50A5 /* SuspendResumeMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SuspendResumeMessageBody.swift; sourceTree = ""; }; - C1E349D329C7A98C009A50A5 /* ReadOtherDevicesStatusMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadOtherDevicesStatusMessageBody.swift; sourceTree = ""; }; - C1E349D429C7A98C009A50A5 /* ChangeMaxBolusMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeMaxBolusMessageBody.swift; sourceTree = ""; }; - C1E349D529C7A98C009A50A5 /* ChangeMaxBasalRateMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeMaxBasalRateMessageBody.swift; sourceTree = ""; }; - C1E349D629C7A98C009A50A5 /* FindDeviceMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FindDeviceMessageBody.swift; sourceTree = ""; }; - C1E349D729C7A98C009A50A5 /* ReadRemainingInsulinMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadRemainingInsulinMessageBody.swift; sourceTree = ""; }; - C1E349D829C7A98C009A50A5 /* PacketType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PacketType.swift; sourceTree = ""; }; - C1E349D929C7A98C009A50A5 /* MeterMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeterMessage.swift; sourceTree = ""; }; - C1E349DA29C7A98C009A50A5 /* BolusCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusCarelinkMessageBody.swift; sourceTree = ""; }; - C1E349DB29C7A98C009A50A5 /* DataFrameMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataFrameMessageBody.swift; sourceTree = ""; }; - C1E349DC29C7A98C009A50A5 /* ChangeRemoteControlIDMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeRemoteControlIDMessageBody.swift; sourceTree = ""; }; - C1E349DD29C7A98C009A50A5 /* ReadPumpStatusMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadPumpStatusMessageBody.swift; sourceTree = ""; }; - C1E349DE29C7A98C009A50A5 /* ChangeTimeCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTimeCarelinkMessageBody.swift; sourceTree = ""; }; - C1E349DF29C7A98C009A50A5 /* SelectBasalProfileMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectBasalProfileMessageBody.swift; sourceTree = ""; }; - C1E349E029C7A98D009A50A5 /* ButtonPressCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonPressCarelinkMessageBody.swift; sourceTree = ""; }; - C1E349E129C7A98D009A50A5 /* CarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarelinkMessageBody.swift; sourceTree = ""; }; - C1E349E929C7A98D009A50A5 /* BatteryChemistryType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatteryChemistryType.swift; sourceTree = ""; }; - C1E349EA29C7A98D009A50A5 /* PumpColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpColor.swift; sourceTree = ""; }; - C1E349EB29C7A98D009A50A5 /* PumpModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpModel.swift; sourceTree = ""; }; - C1E349EC29C7A98D009A50A5 /* PumpRegion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpRegion.swift; sourceTree = ""; }; - C1E349EE29C7A98D009A50A5 /* MinimedPacket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPacket.swift; sourceTree = ""; }; - C1E349EF29C7A98D009A50A5 /* CRC8.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CRC8.swift; sourceTree = ""; }; - C1E349F029C7A98D009A50A5 /* FourByteSixByteEncoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FourByteSixByteEncoding.swift; sourceTree = ""; }; - C1E34A0D29C7A98E009A50A5 /* ISO8601DateFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ISO8601DateFormatter.swift; sourceTree = ""; }; - C1E34A0E29C7A98E009A50A5 /* Int.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Int.swift; sourceTree = ""; }; - C1E34A0F29C7A98E009A50A5 /* NSDateComponents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDateComponents.swift; sourceTree = ""; }; - C1E34AE529C7A9BC009A50A5 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AE629C7A9BC009A50A5 /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AE729C7A9BC009A50A5 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AE829C7A9BC009A50A5 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - C1E34AE929C7A9BC009A50A5 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AEA29C7A9BC009A50A5 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AEB29C7A9BC009A50A5 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AEC29C7A9BC009A50A5 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AED29C7A9BC009A50A5 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AEE29C7A9BC009A50A5 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AEF29C7A9BC009A50A5 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AF029C7A9BC009A50A5 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AF129C7A9BC009A50A5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AF229C7A9BC009A50A5 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AF329C7A9BC009A50A5 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AF429C7A9BC009A50A5 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - C1E34AF529C7A9BC009A50A5 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AF629C7A9BC009A50A5 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AF729C7A9BC009A50A5 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AF829C7A9BC009A50A5 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AF929C7A9BC009A50A5 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - C1E34AFA29C7A9BC009A50A5 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B0129C7ABCB009A50A5 /* MinimedKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MinimedKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C1E34B0329C7ABCB009A50A5 /* MinimedKitUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MinimedKitUI.h; sourceTree = ""; }; - C1E34B0829C7ABF2009A50A5 /* MinimedKitUI.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = MinimedKitUI.xcassets; sourceTree = ""; }; - C1E34B0A29C7ABF2009A50A5 /* Image.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Image.swift; sourceTree = ""; }; - C1E34B0C29C7ABF2009A50A5 /* MinimedPumpIDSetupViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPumpIDSetupViewController.swift; sourceTree = ""; }; - C1E34B0D29C7ABF2009A50A5 /* MinimedPumpManagerSetupViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPumpManagerSetupViewController.swift; sourceTree = ""; }; - C1E34B0E29C7ABF2009A50A5 /* MinimedPumpClockSetupViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPumpClockSetupViewController.swift; sourceTree = ""; }; - C1E34B0F29C7ABF2009A50A5 /* MinimedPumpSetupCompleteViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPumpSetupCompleteViewController.swift; sourceTree = ""; }; - C1E34B1029C7ABF2009A50A5 /* MinimedPumpSentrySetupViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPumpSentrySetupViewController.swift; sourceTree = ""; }; - C1E34B1129C7ABF2009A50A5 /* MinimedPumpManager+UI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MinimedPumpManager+UI.swift"; sourceTree = ""; }; - C1E34B1229C7ABF2009A50A5 /* PumpModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpModel.swift; sourceTree = ""; }; - C1E34B1329C7ABF2009A50A5 /* RadioSelectionTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioSelectionTableViewController.swift; sourceTree = ""; }; - C1E34B1429C7ABF2009A50A5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C1E34B1529C7ABF2009A50A5 /* MinimedPumpUICoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPumpUICoordinator.swift; sourceTree = ""; }; - C1E34B1629C7ABF2009A50A5 /* CommandResponseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommandResponseViewController.swift; sourceTree = ""; }; - C1E34B1729C7ABF2009A50A5 /* MinimedHUDProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedHUDProvider.swift; sourceTree = ""; }; - C1E34B1929C7ABF3009A50A5 /* UseMySentrySelectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UseMySentrySelectionView.swift; sourceTree = ""; }; - C1E34B1A29C7ABF3009A50A5 /* DataSourceSelectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataSourceSelectionView.swift; sourceTree = ""; }; - C1E34B1B29C7ABF3009A50A5 /* BatteryTypeSelectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatteryTypeSelectionView.swift; sourceTree = ""; }; - C1E34B1C29C7ABF3009A50A5 /* ReservoirHUDView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ReservoirHUDView.xib; sourceTree = ""; }; - C1E34B1D29C7ABF3009A50A5 /* MinimedPumpSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPumpSettingsView.swift; sourceTree = ""; }; - C1E34B1E29C7ABF3009A50A5 /* ReservoirHUDView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReservoirHUDView.swift; sourceTree = ""; }; - C1E34B1F29C7ABF3009A50A5 /* MinimedPumpSettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedPumpSettingsViewModel.swift; sourceTree = ""; }; - C1E34B2029C7ABF3009A50A5 /* InsulinTypeConfirmation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsulinTypeConfirmation.swift; sourceTree = ""; }; - C1E34B2129C7ABF3009A50A5 /* MinimedReservoirView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedReservoirView.swift; sourceTree = ""; }; - C1E34B2229C7ABF3009A50A5 /* TimeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeView.swift; sourceTree = ""; }; - C1E34B4129C7AC4C009A50A5 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B4229C7AC4F009A50A5 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - C1E34B4329C7AC51009A50A5 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B4429C7AC54009A50A5 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B4529C7AC56009A50A5 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B4629C7AC58009A50A5 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B4729C7AC5B009A50A5 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B4829C7AC5D009A50A5 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B4929C7AC5F009A50A5 /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B4A29C7AC61009A50A5 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B4B29C7AC64009A50A5 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B4C29C7AC66009A50A5 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B4D29C7AC68009A50A5 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B4E29C7AC69009A50A5 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - C1E34B4F29C7AC6A009A50A5 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B5029C7AC6B009A50A5 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B5129C7AC6C009A50A5 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B5229C7AC6D009A50A5 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B5329C7AC6E009A50A5 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B5429C7AC6F009A50A5 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B5529C7AC70009A50A5 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - C1E34B5B29C7AD01009A50A5 /* MinimedKitPlugin.loopplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MinimedKitPlugin.loopplugin; sourceTree = BUILT_PRODUCTS_DIR; }; - C1E34B6229C7AD31009A50A5 /* MinimedKitPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedKitPlugin.swift; sourceTree = ""; }; - C1E34B6329C7AD31009A50A5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C1E34B6729C7AD62009A50A5 /* LoopKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LoopKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C1E34B7429C7AF61009A50A5 /* LocalisedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalisedString.swift; sourceTree = ""; }; - C1E34B7629C7AFCF009A50A5 /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; }; - C1E34B7829C7AFF7009A50A5 /* TimeInterval.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeInterval.swift; sourceTree = ""; }; - C1E34B7A29C7B044009A50A5 /* OSLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; - C1E34B7C29C7B075009A50A5 /* RileyLinkKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RileyLinkKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C1E34B8029C7B155009A50A5 /* PumpOpsSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpOpsSession.swift; sourceTree = ""; }; - C1E34B8229C7B1AB009A50A5 /* TimeZone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeZone.swift; sourceTree = ""; }; - C1E34B8429C7B1D4009A50A5 /* HKUnit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HKUnit.swift; sourceTree = ""; }; - C1E34B8729C7B292009A50A5 /* Comparable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Comparable.swift; sourceTree = ""; }; - C1E34B8929C7B2FC009A50A5 /* LocalisedString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalisedString.swift; sourceTree = ""; }; - C1E34B8B29C7B334009A50A5 /* IdentifiableClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentifiableClass.swift; sourceTree = ""; }; - C1E34B8D29C7B34F009A50A5 /* NibLoadable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NibLoadable.swift; sourceTree = ""; }; - C1E34B8F29C7B38A009A50A5 /* NumberFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberFormatter.swift; sourceTree = ""; }; - C1E34B9129C7B46C009A50A5 /* TimeZone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeZone.swift; sourceTree = ""; }; - C1E34B9329C7B59B009A50A5 /* RileyLinkKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RileyLinkKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C1E34B9729C7B5A3009A50A5 /* LoopKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LoopKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C1E34BA129C7B652009A50A5 /* RileyLinkBLEKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RileyLinkBLEKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - CEC751BF29D88240006E9D24 /* OmniKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OmniKit.xcodeproj; path = ../OmniKit/OmniKit.xcodeproj; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - C13CC33E29C7B73A007F25DE /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C13CC34529C7B73A007F25DE /* MinimedKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C1E3490E29C7A866009A50A5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C1E34B6829C7AD62009A50A5 /* LoopKit.framework in Frameworks */, - C1E34B7D29C7B075009A50A5 /* RileyLinkKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C1E34AFE29C7ABCB009A50A5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C1E34B9829C7B5A3009A50A5 /* LoopKitUI.framework in Frameworks */, - C13CC33529C7B6A9007F25DE /* LoopKit.framework in Frameworks */, - C1E34B9A29C7B5E9009A50A5 /* RileyLinkKitUI.framework in Frameworks */, - C13CC33829C7B6BC007F25DE /* MinimedKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C1E34B5829C7AD01009A50A5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C1E34BA229C7B652009A50A5 /* RileyLinkBLEKit.framework in Frameworks */, - C1E34B9D29C7B623009A50A5 /* RileyLinkKitUI.framework in Frameworks */, - C1E34B9F29C7B649009A50A5 /* RileyLinkKit.framework in Frameworks */, - C1E34B6B29C7AD9C009A50A5 /* MinimedKit.framework in Frameworks */, - C1E34B6F29C7AD9C009A50A5 /* MinimedKitUI.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - C1229C2029C7EC9B0066A89C /* Extensions */ = { - isa = PBXGroup; - children = ( - C1229C2129C7ECA70066A89C /* TimeInterval.swift */, - C1229C2329C7ECEB0066A89C /* Data.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - C13CC34229C7B73A007F25DE /* MinimedKitTests */ = { - isa = PBXGroup; - children = ( - C1229C2029C7EC9B0066A89C /* Extensions */, - C13CC37629C7B756007F25DE /* BasalScheduleTests.swift */, - C13CC36629C7B755007F25DE /* CRC8Tests.swift */, - C13CC38329C7B757007F25DE /* CRC16Tests.swift */, - C13CC36729C7B756007F25DE /* GlucoseEvents */, - C13CC37D29C7B756007F25DE /* GlucosePageTests.swift */, - C13CC38229C7B756007F25DE /* HistoryPageTests.swift */, - C13CC38129C7B756007F25DE /* Info.plist */, - C13CC34E29C7B755007F25DE /* Messages */, - C13CC36029C7B755007F25DE /* MinimedPacketTests.swift */, - C13CC36129C7B755007F25DE /* MinimedPumpManagerTests.swift */, - C13CC37729C7B756007F25DE /* Mocks */, - C13CC38429C7B757007F25DE /* MySentryPumpStatusMessageBodyTests.swift */, - C13CC36429C7B755007F25DE /* NSDataTests.swift */, - C13CC36229C7B755007F25DE /* NSDateComponents.swift */, - C13CC38529C7B757007F25DE /* NSDateComponentsTests.swift */, - C13CC37E29C7B756007F25DE /* NSStringExtensions.swift */, - C13CC34B29C7B755007F25DE /* PumpEvents */, - C13CC38029C7B756007F25DE /* PumpModelTests.swift */, - C13CC38629C7B757007F25DE /* PumpOpsSynchronousBuildFromFramesTests.swift */, - C13CC36329C7B755007F25DE /* PumpOpsSynchronousTests.swift */, - C13CC37F29C7B756007F25DE /* ReadSettingsCarelinkMessageBodyTests.swift */, - C13CC38729C7B757007F25DE /* ReconciliationTests.swift */, - C13CC36529C7B755007F25DE /* TimestampedHistoryEventTests.swift */, - ); - path = MinimedKitTests; - sourceTree = ""; - }; - C13CC34B29C7B755007F25DE /* PumpEvents */ = { - isa = PBXGroup; - children = ( - C13CC34C29C7B755007F25DE /* ResumePumpEventTests.swift */, - C13CC34D29C7B755007F25DE /* BolusNormalPumpEventTests.swift */, - ); - path = PumpEvents; - sourceTree = ""; - }; - C13CC34E29C7B755007F25DE /* Messages */ = { - isa = PBXGroup; - children = ( - C13CC34F29C7B755007F25DE /* ReadCurrentGlucosePageMessageBodyTests.swift */, - C13CC35029C7B755007F25DE /* ChangeTimeCarelinMessageBodyTests.swift */, - C13CC35129C7B755007F25DE /* MeterMessageTests.swift */, - C13CC35229C7B755007F25DE /* ChangeTempBasalCarelinkMessageBodyTests.swift */, - C13CC35329C7B755007F25DE /* ReadOtherDevicesIDsMessageBodyTests.swift */, - C13CC35429C7B755007F25DE /* BolusCarelinkMessageBodyTests.swift */, - C13CC35529C7B755007F25DE /* FindDeviceMessageBodyTests.swift */, - C13CC35629C7B755007F25DE /* ReadRemoteControlIDsMessageBodyTests.swift */, - C13CC35729C7B755007F25DE /* ReadTempBasalCarelinkMessageBodyTests.swift */, - C13CC35829C7B755007F25DE /* DeviceLinkMessageBodyTests.swift */, - C13CC35929C7B755007F25DE /* ChangeMaxBasalRateMessageBodyTests.swift */, - C13CC35A29C7B755007F25DE /* ChangeRemoteControlIDMessageBodyTests.swift */, - C13CC35B29C7B755007F25DE /* GetBatteryCarelinkMessageBodyTests.swift */, - C13CC35C29C7B755007F25DE /* ReadRemainingInsulinMessageBodyTests.swift */, - C13CC35D29C7B755007F25DE /* ChangeMaxBolusMessageBodyTests.swift */, - C13CC35E29C7B755007F25DE /* GetPumpModelCarelinkMessageBodyTests.swift */, - C13CC35F29C7B755007F25DE /* GetGlucosePageMessageBodyTests.swift */, - ); - path = Messages; - sourceTree = ""; - }; - C13CC36729C7B756007F25DE /* GlucoseEvents */ = { - isa = PBXGroup; - children = ( - C13CC36829C7B756007F25DE /* SensorDataHighGlucoseEventTests.swift */, - C13CC36929C7B756007F25DE /* SensorTimestampGlucoseEventTests.swift */, - C13CC36A29C7B756007F25DE /* BatteryChangeGlucoseEventTests.swift */, - C13CC36B29C7B756007F25DE /* SensorErrorGlucoseEventTests.swift */, - C13CC36C29C7B756007F25DE /* SensorCalFactorGlucoseEventTests.swift */, - C13CC36D29C7B756007F25DE /* SensorCalGlucoseEventTests.swift */, - C13CC36E29C7B756007F25DE /* CalBGForGHGlucoseEventTests.swift */, - C13CC36F29C7B756007F25DE /* SensorStatusGlucoseEventTests.swift */, - C13CC37029C7B756007F25DE /* SensorDataLowGlucoseEventTests.swift */, - C13CC37129C7B756007F25DE /* GlucoseSensorDataGlucoseEventTests.swift */, - C13CC37229C7B756007F25DE /* SensorSyncGlucoseEventTests.swift */, - C13CC37329C7B756007F25DE /* DateTimeChangeGlucoseEventTests.swift */, - C13CC37429C7B756007F25DE /* SensorPacketGlucoseEventTests.swift */, - C13CC37529C7B756007F25DE /* TenSomethingGlucoseEventTests.swift */, - ); - path = GlucoseEvents; - sourceTree = ""; - }; - C13CC37729C7B756007F25DE /* Mocks */ = { - isa = PBXGroup; - children = ( - C13CC37829C7B756007F25DE /* MockRileyLinkProvider.swift */, - C13CC37929C7B756007F25DE /* MockPumpManagerDelegate.swift */, - C13CC37A29C7B756007F25DE /* MockPumpOps.swift */, - C13CC37B29C7B756007F25DE /* MockPumpMessageSender.swift */, - C13CC37C29C7B756007F25DE /* MockRileyLinkDevice.swift */, - ); - path = Mocks; - sourceTree = ""; - }; - C13CC3DB29C7BA37007F25DE /* Extensions */ = { - isa = PBXGroup; - children = ( - C13CC3DC29C7BA48007F25DE /* OSLog.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - C1E3490729C7A866009A50A5 = { - isa = PBXGroup; - children = ( - CEC751BF29D88240006E9D24 /* OmniKit.xcodeproj */, - C1E3491329C7A866009A50A5 /* MinimedKit */, - C1E34B0229C7ABCB009A50A5 /* MinimedKitUI */, - C1E34B5C29C7AD01009A50A5 /* MinimedKitPlugin */, - C13CC34229C7B73A007F25DE /* MinimedKitTests */, - C1E3491229C7A866009A50A5 /* Products */, - C1E34B6629C7AD62009A50A5 /* Frameworks */, - ); - sourceTree = ""; - }; - C1E3491229C7A866009A50A5 /* Products */ = { - isa = PBXGroup; - children = ( - C1E3491129C7A866009A50A5 /* MinimedKit.framework */, - C1E34B0129C7ABCB009A50A5 /* MinimedKitUI.framework */, - C1E34B5B29C7AD01009A50A5 /* MinimedKitPlugin.loopplugin */, - C13CC34129C7B73A007F25DE /* MinimedKitTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - C1E3491329C7A866009A50A5 /* MinimedKit */ = { - isa = PBXGroup; - children = ( - C1E34AE329C7A9BC009A50A5 /* Resources */, - C1E3493A29C7A98B009A50A5 /* CGMManager */, - C1E34A0C29C7A98E009A50A5 /* Extensions */, - C1E3492429C7A98B009A50A5 /* GlucoseEvents */, - C1E3494029C7A98C009A50A5 /* Info.plist */, - C1E349AC29C7A98C009A50A5 /* Messages */, - C1E349E829C7A98D009A50A5 /* Models */, - C1E3496329C7A98C009A50A5 /* PumpEvents */, - C1E3494429C7A98C009A50A5 /* PumpManager */, - C1E349ED29C7A98D009A50A5 /* Radio */, - C1E3491429C7A866009A50A5 /* MinimedKit.h */, - C1E34B7429C7AF61009A50A5 /* LocalisedString.swift */, - ); - path = MinimedKit; - sourceTree = ""; - }; - C1E3492429C7A98B009A50A5 /* GlucoseEvents */ = { - isa = PBXGroup; - children = ( - C1E3492529C7A98B009A50A5 /* CalBGForGHGlucoseEvent.swift */, - C1E3492629C7A98B009A50A5 /* RelativeTimestampedGlucoseEvent.swift */, - C1E3492729C7A98B009A50A5 /* SensorCalGlucoseEvent.swift */, - C1E3492829C7A98B009A50A5 /* SensorErrorGlucoseEvent.swift */, - C1E3492929C7A98B009A50A5 /* TenSomethingGlucoseEvent.swift */, - C1E3492A29C7A98B009A50A5 /* SensorStatusGlucoseEvent.swift */, - C1E3492B29C7A98B009A50A5 /* SensorValueGlucoseEvent.swift */, - C1E3492C29C7A98B009A50A5 /* SensorSyncGlucoseEvent.swift */, - C1E3492D29C7A98B009A50A5 /* SensorTimestampGlucoseEvent.swift */, - C1E3492E29C7A98B009A50A5 /* SensorDataLowGlucoseEvent.swift */, - C1E3492F29C7A98B009A50A5 /* SensorPacketGlucoseEvent.swift */, - C1E3493029C7A98B009A50A5 /* DateTimeChangeGlucoseEvent.swift */, - C1E3493129C7A98B009A50A5 /* UnknownGlucoseEvent.swift */, - C1E3493229C7A98B009A50A5 /* DataEndGlucoseEvent.swift */, - C1E3493329C7A98B009A50A5 /* NineteenSomethingGlucoseEvent.swift */, - C1E3493429C7A98B009A50A5 /* GlucoseEvent.swift */, - C1E3493529C7A98B009A50A5 /* GlucoseSensorDataGlucoseEvent.swift */, - C1E3493629C7A98B009A50A5 /* SensorDataHighGlucoseEvent.swift */, - C1E3493729C7A98B009A50A5 /* BatteryChangeGlucoseEvent.swift */, - C1E3493829C7A98B009A50A5 /* SensorCalFactorGlucoseEvent.swift */, - C1E3493929C7A98B009A50A5 /* SensorWeakSignalGlucoseEvent.swift */, - ); - path = GlucoseEvents; - sourceTree = ""; - }; - C1E3493A29C7A98B009A50A5 /* CGMManager */ = { - isa = PBXGroup; - children = ( - C1E3493B29C7A98B009A50A5 /* SensorValueGlucoseEvent+CGMManager.swift */, - C1E3493C29C7A98B009A50A5 /* MySentryPumpStatusMessageBody+CGMManager.swift */, - ); - path = CGMManager; - sourceTree = ""; - }; - C1E3494429C7A98C009A50A5 /* PumpManager */ = { - isa = PBXGroup; - children = ( - C1E3494529C7A98C009A50A5 /* MinimedPumpManagerState.swift */, - C1E3494629C7A98C009A50A5 /* MinimedPumpManagerRecents.swift */, - C1E3494729C7A98C009A50A5 /* EnliteSensorDisplayable.swift */, - C1E3494829C7A98C009A50A5 /* PumpOpsSession+LoopKit.swift */, - C1E3494929C7A98C009A50A5 /* BasalProfile.swift */, - C1E3494A29C7A98C009A50A5 /* HistoryPage+PumpOpsSession.swift */, - C1E3494B29C7A98C009A50A5 /* ReservoirReading.swift */, - C1E3494C29C7A98C009A50A5 /* PumpMessageSender.swift */, - C1E3494D29C7A98C009A50A5 /* MinimedPumpManagerError.swift */, - C1E3494E29C7A98C009A50A5 /* DoseStore.swift */, - C1E3494F29C7A98C009A50A5 /* PumpSettings.swift */, - C1E3495029C7A98C009A50A5 /* PumpOps.swift */, - C1E34B8029C7B155009A50A5 /* PumpOpsSession.swift */, - C1E3495129C7A98C009A50A5 /* PumpMessage+PumpOpsSession.swift */, - C1E3495229C7A98C009A50A5 /* InsulinDataSource.swift */, - C1E3495329C7A98C009A50A5 /* MinimedDoseProgressEstimator.swift */, - C1E3495429C7A98C009A50A5 /* MinimedPumpMessageSender.swift */, - C1E3495529C7A98C009A50A5 /* MinimedPumpManager.swift */, - C1E3495629C7A98C009A50A5 /* UnfinalizedDose.swift */, - C1E3495729C7A98C009A50A5 /* RileyLinkDevice.swift */, - C1E3495829C7A98C009A50A5 /* PumpOpsError.swift */, - C1E3495929C7A98C009A50A5 /* PumpState.swift */, - ); - path = PumpManager; - sourceTree = ""; - }; - C1E3496329C7A98C009A50A5 /* PumpEvents */ = { - isa = PBXGroup; - children = ( - C1E3496429C7A98C009A50A5 /* ChangeWatchdogEnablePumpEvent.swift */, - C1E3496529C7A98C009A50A5 /* PumpAlarmPumpEvent.swift */, - C1E3496629C7A98C009A50A5 /* ChangeCaptureEventEnablePumpEvent.swift */, - C1E3496729C7A98C009A50A5 /* TempBasalDurationPumpEvent.swift */, - C1E3496829C7A98C009A50A5 /* ChangeBolusScrollStepSizePumpEvent.swift */, - C1E3496929C7A98C009A50A5 /* ChangeSensorSetup2PumpEvent.swift */, - C1E3496A29C7A98C009A50A5 /* JournalEntryInsulinMarkerPumpEvent.swift */, - C1E3496B29C7A98C009A50A5 /* ChangeMaxBolusPumpEvent.swift */, - C1E3496C29C7A98C009A50A5 /* ChangeVariableBolusPumpEvent.swift */, - C1E3496D29C7A98C009A50A5 /* ChangeBolusReminderEnablePumpEvent.swift */, - C1E3496E29C7A98C009A50A5 /* ChangeCarbUnitsPumpEvent.swift */, - C1E3496F29C7A98C009A50A5 /* BolusWizardEstimatePumpEvent.swift */, - C1E3497029C7A98C009A50A5 /* ClearAlarmPumpEvent.swift */, - C1E3497129C7A98C009A50A5 /* ChangeAlarmNotifyModePumpEvent.swift */, - C1E3497229C7A98C009A50A5 /* ChangeAlarmClockEnablePumpEvent.swift */, - C1E3497329C7A98C009A50A5 /* JournalEntryPumpLowReservoirPumpEvent.swift */, - C1E3497429C7A98C009A50A5 /* ChangeTimeFormatPumpEvent.swift */, - C1E3497529C7A98C009A50A5 /* SelectBasalProfilePumpEvent.swift */, - C1E3497629C7A98C009A50A5 /* DailyTotal522PumpEvent.swift */, - C1E3497729C7A98C009A50A5 /* BGReceivedPumpEvent.swift */, - C1E3497829C7A98C009A50A5 /* TimestampedPumpEvent.swift */, - C1E3497929C7A98C009A50A5 /* SuspendPumpEvent.swift */, - C1E3497A29C7A98C009A50A5 /* EnableBolusWizardPumpEvent.swift */, - C1E3497B29C7A98C009A50A5 /* UnabsorbedInsulinPumpEvent.swift */, - C1E3497C29C7A98C009A50A5 /* DeleteOtherDeviceIDPumpEvent.swift */, - C1E3497D29C7A98C009A50A5 /* AlarmClockReminderPumpEvent.swift */, - C1E3497E29C7A98C009A50A5 /* ChangeBGReminderEnablePumpEvent.swift */, - C1E3497F29C7A98C009A50A5 /* JournalEntryPumpLowBatteryPumpEvent.swift */, - C1E3498029C7A98C009A50A5 /* NewTimePumpEvent.swift */, - C1E3498129C7A98C009A50A5 /* ChangeMaxBasalPumpEvent.swift */, - C1E3498229C7A98C009A50A5 /* ChangeTempBasalTypePumpEvent.swift */, - C1E3498329C7A98C009A50A5 /* ChangeSensorAlarmSilenceConfigPumpEvent.swift */, - C1E3498429C7A98C009A50A5 /* ChangeOtherDeviceIDPumpEvent.swift */, - C1E3498529C7A98C009A50A5 /* PrimePumpEvent.swift */, - C1E3498629C7A98C009A50A5 /* DailyTotal523PumpEvent.swift */, - C1E3498729C7A98C009A50A5 /* BatteryPumpEvent.swift */, - C1E3498829C7A98C009A50A5 /* EnableDisableRemotePumpEvent.swift */, - C1E3498929C7A98C009A50A5 /* TempBasalPumpEvent.swift */, - C1E3498A29C7A98C009A50A5 /* ChangeSensorRateOfChangeAlertSetupPumpEvent.swift */, - C1E3498B29C7A98C009A50A5 /* RestoreMystery55PumpEvent.swift */, - C1E3498C29C7A98C009A50A5 /* BolusWizardSetupPumpEvent.swift */, - C1E3498D29C7A98C009A50A5 /* ChangeTimePumpEvent.swift */, - C1E3498E29C7A98C009A50A5 /* ChangeBolusReminderTimePumpEvent.swift */, - C1E3498F29C7A98C009A50A5 /* ChangeBolusWizardSetupPumpEvent.swift */, - C1E3499029C7A98C009A50A5 /* PlaceholderPumpEvent.swift */, - C1E3499129C7A98C009A50A5 /* PumpEvent.swift */, - C1E3499229C7A98C009A50A5 /* ChangeBasalProfilePumpEvent.swift */, - C1E3499329C7A98C009A50A5 /* ResumePumpEvent.swift */, - C1E3499429C7A98C009A50A5 /* ChangeBGReminderOffsetPumpEvent.swift */, - C1E3499529C7A98C009A50A5 /* ChangeWatchdogMarriageProfilePumpEvent.swift */, - C1E3499629C7A98C009A50A5 /* BasalProfileStartPumpEvent.swift */, - C1E3499729C7A98C009A50A5 /* ResultDailyTotalPumpEvent.swift */, - C1E3499829C7A98C009A50A5 /* UnknownPumpEvent57.swift */, - C1E3499929C7A98C009A50A5 /* RestoreMystery54PumpEvent.swift */, - C1E3499A29C7A98C009A50A5 /* CalBGForPHPumpEvent.swift */, - C1E3499B29C7A98C009A50A5 /* ChangeParadigmLinkIDPumpEvent.swift */, - C1E3499C29C7A98C009A50A5 /* ChangeChildBlockEnablePumpEvent.swift */, - C1E3499D29C7A98C009A50A5 /* ChangeBasalProfilePatternPumpEvent.swift */, - C1E3499E29C7A98C009A50A5 /* RewindPumpEvent.swift */, - C1E3499F29C7A98C009A50A5 /* BolusReminderPumpEvent.swift */, - C1E349A029C7A98C009A50A5 /* ChangeMeterIDPumpEvent.swift */, - C1E349A129C7A98C009A50A5 /* ChangeAudioBolusPumpEvent.swift */, - C1E349A229C7A98C009A50A5 /* DeleteBolusReminderTimePumpEvent.swift */, - C1E349A329C7A98C009A50A5 /* ChangeReservoirWarningTimePumpEvent.swift */, - C1E349A429C7A98C009A50A5 /* JournalEntryExerciseMarkerPumpEvent.swift */, - C1E349A529C7A98C009A50A5 /* BolusNormalPumpEvent.swift */, - C1E349A629C7A98C009A50A5 /* AlarmSensorPumpEvent.swift */, - C1E349A729C7A98C009A50A5 /* DailyTotal515PumpEvent.swift */, - C1E349A829C7A98C009A50A5 /* JournalEntryMealMarkerPumpEvent.swift */, - ); - path = PumpEvents; - sourceTree = ""; - }; - C1E349AC29C7A98C009A50A5 /* Messages */ = { - isa = PBXGroup; - children = ( - C1E349AD29C7A98C009A50A5 /* MessageBody.swift */, - C1E349AE29C7A98C009A50A5 /* ReadCurrentPageNumberMessageBody.swift */, - C1E349AF29C7A98C009A50A5 /* PowerOnCarelinkMessageBody.swift */, - C1E349B029C7A98C009A50A5 /* GetBatteryCarelinkMessageBody.swift */, - C1E349B129C7A98C009A50A5 /* SetRemoteControlEnabledMessageBody.swift */, - C1E349B229C7A98C009A50A5 /* GetHistoryPageCarelinkMessageBody.swift */, - C1E349B329C7A98C009A50A5 /* PumpAckMessageBody.swift */, - C1E349B429C7A98C009A50A5 /* MySentryAckMessageBody.swift */, - C1E349B529C7A98C009A50A5 /* MySentryAlertMessageBody.swift */, - C1E349B629C7A98C009A50A5 /* PumpErrorMessageBody.swift */, - C1E349B729C7A98C009A50A5 /* UnknownMessageBody.swift */, - C1E349B829C7A98C009A50A5 /* DeviceLinkMessageBody.swift */, - C1E349B929C7A98C009A50A5 /* ReadTempBasalCarelinkMessageBody.swift */, - C1E349BA29C7A98C009A50A5 /* ReadCurrentGlucosePageMessageBody.swift */, - C1E349BB29C7A98C009A50A5 /* Models */, - C1E349C629C7A98C009A50A5 /* GetGlucosePageMessageBody.swift */, - C1E349C729C7A98C009A50A5 /* MySentryPumpStatusMessageBody.swift */, - C1E349C829C7A98C009A50A5 /* GetPumpModelCarelinkMessageBody.swift */, - C1E349C929C7A98C009A50A5 /* MySentryAlertClearedMessageBody.swift */, - C1E349CA29C7A98C009A50A5 /* ChangeTempBasalCarelinkMessageBody.swift */, - C1E349CB29C7A98C009A50A5 /* ReadOtherDevicesIDsMessageBody.swift */, - C1E349CC29C7A98C009A50A5 /* ReadTimeCarelinkMessageBody.swift */, - C1E349CD29C7A98C009A50A5 /* ReadSettingsCarelinkMessageBody.swift */, - C1E349CE29C7A98C009A50A5 /* GetPumpFirmwareVersionMessageBody.swift */, - C1E349CF29C7A98C009A50A5 /* MessageType.swift */, - C1E349D029C7A98C009A50A5 /* ReadRemoteControlIDsMessageBody.swift */, - C1E349D129C7A98C009A50A5 /* PumpMessage.swift */, - C1E349D229C7A98C009A50A5 /* SuspendResumeMessageBody.swift */, - C1E349D329C7A98C009A50A5 /* ReadOtherDevicesStatusMessageBody.swift */, - C1E349D429C7A98C009A50A5 /* ChangeMaxBolusMessageBody.swift */, - C1E349D529C7A98C009A50A5 /* ChangeMaxBasalRateMessageBody.swift */, - C1E349D629C7A98C009A50A5 /* FindDeviceMessageBody.swift */, - C1E349D729C7A98C009A50A5 /* ReadRemainingInsulinMessageBody.swift */, - C1E349D829C7A98C009A50A5 /* PacketType.swift */, - C1E349D929C7A98C009A50A5 /* MeterMessage.swift */, - C1E349DA29C7A98C009A50A5 /* BolusCarelinkMessageBody.swift */, - C1E349DB29C7A98C009A50A5 /* DataFrameMessageBody.swift */, - C1E349DC29C7A98C009A50A5 /* ChangeRemoteControlIDMessageBody.swift */, - C1E349DD29C7A98C009A50A5 /* ReadPumpStatusMessageBody.swift */, - C1E349DE29C7A98C009A50A5 /* ChangeTimeCarelinkMessageBody.swift */, - C1E349DF29C7A98C009A50A5 /* SelectBasalProfileMessageBody.swift */, - C1E349E029C7A98D009A50A5 /* ButtonPressCarelinkMessageBody.swift */, - C1E349E129C7A98D009A50A5 /* CarelinkMessageBody.swift */, - ); - path = Messages; - sourceTree = ""; - }; - C1E349BB29C7A98C009A50A5 /* Models */ = { - isa = PBXGroup; - children = ( - C1E349BC29C7A98C009A50A5 /* GlucosePage.swift */, - C1E349BD29C7A98C009A50A5 /* HistoryPage.swift */, - C1E349BE29C7A98C009A50A5 /* GlucoseEventType.swift */, - C1E349BF29C7A98C009A50A5 /* TimestampedGlucoseEvent.swift */, - C1E349C029C7A98C009A50A5 /* PartialDecode.swift */, - C1E349C129C7A98C009A50A5 /* MySentryAlertType.swift */, - C1E349C229C7A98C009A50A5 /* CRC16.swift */, - C1E349C329C7A98C009A50A5 /* BasalSchedule.swift */, - C1E349C429C7A98C009A50A5 /* PumpEventType.swift */, - C1E349C529C7A98C009A50A5 /* TimestampedHistoryEvent.swift */, - ); - path = Models; - sourceTree = ""; - }; - C1E349E829C7A98D009A50A5 /* Models */ = { - isa = PBXGroup; - children = ( - C1E349E929C7A98D009A50A5 /* BatteryChemistryType.swift */, - C1E349EA29C7A98D009A50A5 /* PumpColor.swift */, - C1E349EB29C7A98D009A50A5 /* PumpModel.swift */, - C1E349EC29C7A98D009A50A5 /* PumpRegion.swift */, - ); - path = Models; - sourceTree = ""; - }; - C1E349ED29C7A98D009A50A5 /* Radio */ = { - isa = PBXGroup; - children = ( - C1E349EE29C7A98D009A50A5 /* MinimedPacket.swift */, - C1E349EF29C7A98D009A50A5 /* CRC8.swift */, - C1E349F029C7A98D009A50A5 /* FourByteSixByteEncoding.swift */, - ); - path = Radio; - sourceTree = ""; - }; - C1E34A0C29C7A98E009A50A5 /* Extensions */ = { - isa = PBXGroup; - children = ( - C1E34A0D29C7A98E009A50A5 /* ISO8601DateFormatter.swift */, - C1E34A0E29C7A98E009A50A5 /* Int.swift */, - C1E34A0F29C7A98E009A50A5 /* NSDateComponents.swift */, - C1E34B7629C7AFCF009A50A5 /* Data.swift */, - C1E34B7829C7AFF7009A50A5 /* TimeInterval.swift */, - C1E34B7A29C7B044009A50A5 /* OSLog.swift */, - C1E34B8229C7B1AB009A50A5 /* TimeZone.swift */, - C1E34B8429C7B1D4009A50A5 /* HKUnit.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - C1E34AE329C7A9BC009A50A5 /* Resources */ = { - isa = PBXGroup; - children = ( - C1E34AE429C7A9BC009A50A5 /* Localizable.strings */, - ); - path = Resources; - sourceTree = ""; - }; - C1E34B0229C7ABCB009A50A5 /* MinimedKitUI */ = { - isa = PBXGroup; - children = ( - C1E34B8929C7B2FC009A50A5 /* LocalisedString.swift */, - C1E34B3B29C7ABF7009A50A5 /* Resources */, - C1E34B1629C7ABF2009A50A5 /* CommandResponseViewController.swift */, - C1E34B0929C7ABF2009A50A5 /* Extensions */, - C1E34B1429C7ABF2009A50A5 /* Info.plist */, - C1E34B1729C7ABF2009A50A5 /* MinimedHUDProvider.swift */, - C1E34B1129C7ABF2009A50A5 /* MinimedPumpManager+UI.swift */, - C1E34B1529C7ABF2009A50A5 /* MinimedPumpUICoordinator.swift */, - C1E34B1229C7ABF2009A50A5 /* PumpModel.swift */, - C1E34B1329C7ABF2009A50A5 /* RadioSelectionTableViewController.swift */, - C1E34B0B29C7ABF2009A50A5 /* Setup */, - C1E34B1829C7ABF3009A50A5 /* Views */, - C1E34B0329C7ABCB009A50A5 /* MinimedKitUI.h */, - ); - path = MinimedKitUI; - sourceTree = ""; - }; - C1E34B0929C7ABF2009A50A5 /* Extensions */ = { - isa = PBXGroup; - children = ( - C1E34B0A29C7ABF2009A50A5 /* Image.swift */, - C1E34B8729C7B292009A50A5 /* Comparable.swift */, - C1E34B8B29C7B334009A50A5 /* IdentifiableClass.swift */, - C1E34B8D29C7B34F009A50A5 /* NibLoadable.swift */, - C1E34B8F29C7B38A009A50A5 /* NumberFormatter.swift */, - C1E34B9129C7B46C009A50A5 /* TimeZone.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - C1E34B0B29C7ABF2009A50A5 /* Setup */ = { - isa = PBXGroup; - children = ( - C1E34B0C29C7ABF2009A50A5 /* MinimedPumpIDSetupViewController.swift */, - C1E34B0D29C7ABF2009A50A5 /* MinimedPumpManagerSetupViewController.swift */, - C1E34B0E29C7ABF2009A50A5 /* MinimedPumpClockSetupViewController.swift */, - C1E34B0F29C7ABF2009A50A5 /* MinimedPumpSetupCompleteViewController.swift */, - C1E34B1029C7ABF2009A50A5 /* MinimedPumpSentrySetupViewController.swift */, - ); - path = Setup; - sourceTree = ""; - }; - C1E34B1829C7ABF3009A50A5 /* Views */ = { - isa = PBXGroup; - children = ( - C1E34B1929C7ABF3009A50A5 /* UseMySentrySelectionView.swift */, - C1E34B1A29C7ABF3009A50A5 /* DataSourceSelectionView.swift */, - C1E34B1B29C7ABF3009A50A5 /* BatteryTypeSelectionView.swift */, - C1E34B1C29C7ABF3009A50A5 /* ReservoirHUDView.xib */, - C1E34B1D29C7ABF3009A50A5 /* MinimedPumpSettingsView.swift */, - C1E34B1E29C7ABF3009A50A5 /* ReservoirHUDView.swift */, - C1E34B1F29C7ABF3009A50A5 /* MinimedPumpSettingsViewModel.swift */, - C1E34B2029C7ABF3009A50A5 /* InsulinTypeConfirmation.swift */, - C1E34B2129C7ABF3009A50A5 /* MinimedReservoirView.swift */, - C1E34B2229C7ABF3009A50A5 /* TimeView.swift */, - ); - path = Views; - sourceTree = ""; - }; - C1E34B3B29C7ABF7009A50A5 /* Resources */ = { - isa = PBXGroup; - children = ( - C13CC3C129C7B8BC007F25DE /* MinimedPumpManager.storyboard */, - C1E34B0829C7ABF2009A50A5 /* MinimedKitUI.xcassets */, - C1E34B4029C7AC0A009A50A5 /* Localizable.strings */, - ); - path = Resources; - sourceTree = ""; - }; - C1E34B5C29C7AD01009A50A5 /* MinimedKitPlugin */ = { - isa = PBXGroup; - children = ( - C13CC3DB29C7BA37007F25DE /* Extensions */, - C1E34B6329C7AD31009A50A5 /* Info.plist */, - C1E34B6229C7AD31009A50A5 /* MinimedKitPlugin.swift */, - ); - path = MinimedKitPlugin; - sourceTree = ""; - }; - C1E34B6629C7AD62009A50A5 /* Frameworks */ = { - isa = PBXGroup; - children = ( - C1E34BA129C7B652009A50A5 /* RileyLinkBLEKit.framework */, - C1E34B9729C7B5A3009A50A5 /* LoopKitUI.framework */, - C1E34B9329C7B59B009A50A5 /* RileyLinkKitUI.framework */, - C1E34B7C29C7B075009A50A5 /* RileyLinkKit.framework */, - C1E34B6729C7AD62009A50A5 /* LoopKit.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - CEC751C029D88240006E9D24 /* Products */ = { - isa = PBXGroup; - children = ( - CEC751C829D88240006E9D24 /* OmniKit.framework */, - CEC751CA29D88240006E9D24 /* OmniKitUI.framework */, - CEC751CC29D88240006E9D24 /* OmniKitPlugin.loopplugin */, - CEC751CE29D88240006E9D24 /* OmniKitTests.xctest */, - CEC751D029D88240006E9D24 /* OmniKitPacketParser */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - C1E3490C29C7A866009A50A5 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - C1E3491529C7A866009A50A5 /* MinimedKit.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C1E34AFC29C7ABCB009A50A5 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - C1E34B0429C7ABCB009A50A5 /* MinimedKitUI.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C1E34B5629C7AD01009A50A5 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - C13CC34029C7B73A007F25DE /* MinimedKitTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = C13CC34829C7B73A007F25DE /* Build configuration list for PBXNativeTarget "MinimedKitTests" */; - buildPhases = ( - C13CC33D29C7B73A007F25DE /* Sources */, - C13CC33E29C7B73A007F25DE /* Frameworks */, - C13CC33F29C7B73A007F25DE /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - C13CC34729C7B73A007F25DE /* PBXTargetDependency */, - ); - name = MinimedKitTests; - productName = MinimedKitTests; - productReference = C13CC34129C7B73A007F25DE /* MinimedKitTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - C1E3491029C7A866009A50A5 /* MinimedKit */ = { - isa = PBXNativeTarget; - buildConfigurationList = C1E3491829C7A866009A50A5 /* Build configuration list for PBXNativeTarget "MinimedKit" */; - buildPhases = ( - C1E3490C29C7A866009A50A5 /* Headers */, - C1E3490D29C7A866009A50A5 /* Sources */, - C1E3490E29C7A866009A50A5 /* Frameworks */, - C1E3490F29C7A866009A50A5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = MinimedKit; - productName = MinimedKit; - productReference = C1E3491129C7A866009A50A5 /* MinimedKit.framework */; - productType = "com.apple.product-type.framework"; - }; - C1E34B0029C7ABCB009A50A5 /* MinimedKitUI */ = { - isa = PBXNativeTarget; - buildConfigurationList = C1E34B0529C7ABCB009A50A5 /* Build configuration list for PBXNativeTarget "MinimedKitUI" */; - buildPhases = ( - C1E34AFC29C7ABCB009A50A5 /* Headers */, - C1E34AFD29C7ABCB009A50A5 /* Sources */, - C1E34AFE29C7ABCB009A50A5 /* Frameworks */, - C1E34AFF29C7ABCB009A50A5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - C13CC33B29C7B6BC007F25DE /* PBXTargetDependency */, - ); - name = MinimedKitUI; - productName = MinimedKitUI; - productReference = C1E34B0129C7ABCB009A50A5 /* MinimedKitUI.framework */; - productType = "com.apple.product-type.framework"; - }; - C1E34B5A29C7AD01009A50A5 /* MinimedKitPlugin */ = { - isa = PBXNativeTarget; - buildConfigurationList = C1E34B5F29C7AD01009A50A5 /* Build configuration list for PBXNativeTarget "MinimedKitPlugin" */; - buildPhases = ( - C1E34B5629C7AD01009A50A5 /* Headers */, - C1E34B5729C7AD01009A50A5 /* Sources */, - C1E34B5829C7AD01009A50A5 /* Frameworks */, - C1E34B5929C7AD01009A50A5 /* Resources */, - C1E34B7329C7AD9C009A50A5 /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - C1E34B6E29C7AD9C009A50A5 /* PBXTargetDependency */, - C1E34B7229C7AD9C009A50A5 /* PBXTargetDependency */, - ); - name = MinimedKitPlugin; - productName = MinimedKitPlugin; - productReference = C1E34B5B29C7AD01009A50A5 /* MinimedKitPlugin.loopplugin */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - C1E3490829C7A866009A50A5 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1420; - LastUpgradeCheck = 1420; - ORGANIZATIONNAME = "LoopKit Authors"; - TargetAttributes = { - C13CC34029C7B73A007F25DE = { - CreatedOnToolsVersion = 14.2; - }; - C1E3491029C7A866009A50A5 = { - CreatedOnToolsVersion = 14.2; - }; - C1E34B0029C7ABCB009A50A5 = { - CreatedOnToolsVersion = 14.2; - LastSwiftMigration = 1420; - }; - C1E34B5A29C7AD01009A50A5 = { - CreatedOnToolsVersion = 14.2; - LastSwiftMigration = 1420; - }; - }; - }; - buildConfigurationList = C1E3490B29C7A866009A50A5 /* Build configuration list for PBXProject "MinimedKit" */; - compatibilityVersion = "Xcode 14.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - da, - it, - sv, - tr, - ru, - es, - nl, - he, - cs, - fi, - de, - ar, - nb, - "pt-BR", - sk, - vi, - ro, - ja, - "zh-Hans", - fr, - pl, - hu, - ); - mainGroup = C1E3490729C7A866009A50A5; - productRefGroup = C1E3491229C7A866009A50A5 /* Products */; - projectDirPath = ""; - projectReferences = ( - { - ProductGroup = CEC751C029D88240006E9D24 /* Products */; - ProjectRef = CEC751BF29D88240006E9D24 /* OmniKit.xcodeproj */; - }, - ); - projectRoot = ""; - targets = ( - C1E3491029C7A866009A50A5 /* MinimedKit */, - C1E34B0029C7ABCB009A50A5 /* MinimedKitUI */, - C1E34B5A29C7AD01009A50A5 /* MinimedKitPlugin */, - C13CC34029C7B73A007F25DE /* MinimedKitTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXReferenceProxy section */ - CEC751C829D88240006E9D24 /* OmniKit.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = OmniKit.framework; - remoteRef = CEC751C729D88240006E9D24 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - CEC751CA29D88240006E9D24 /* OmniKitUI.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = OmniKitUI.framework; - remoteRef = CEC751C929D88240006E9D24 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - CEC751CC29D88240006E9D24 /* OmniKitPlugin.loopplugin */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = OmniKitPlugin.loopplugin; - remoteRef = CEC751CB29D88240006E9D24 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - CEC751CE29D88240006E9D24 /* OmniKitTests.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = OmniKitTests.xctest; - remoteRef = CEC751CD29D88240006E9D24 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - CEC751D029D88240006E9D24 /* OmniKitPacketParser */ = { - isa = PBXReferenceProxy; - fileType = "compiled.mach-o.executable"; - path = OmniKitPacketParser; - remoteRef = CEC751CF29D88240006E9D24 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - -/* Begin PBXResourcesBuildPhase section */ - C13CC33F29C7B73A007F25DE /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C1E3490F29C7A866009A50A5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C1E34AFB29C7A9BD009A50A5 /* Localizable.strings in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C1E34AFF29C7ABCB009A50A5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C13CC3C329C7B8BC007F25DE /* MinimedPumpManager.storyboard in Resources */, - C1E34B3E29C7AC0A009A50A5 /* Localizable.strings in Resources */, - C1E34B3429C7ABF3009A50A5 /* ReservoirHUDView.xib in Resources */, - C1E34B2329C7ABF3009A50A5 /* MinimedKitUI.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C1E34B5929C7AD01009A50A5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - C13CC33D29C7B73A007F25DE /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C13CC3B729C7B757007F25DE /* NSStringExtensions.swift in Sources */, - C1229C2229C7ECA70066A89C /* TimeInterval.swift in Sources */, - C13CC38F29C7B757007F25DE /* BolusCarelinkMessageBodyTests.swift in Sources */, - C13CC39529C7B757007F25DE /* ChangeRemoteControlIDMessageBodyTests.swift in Sources */, - C13CC39E29C7B757007F25DE /* PumpOpsSynchronousTests.swift in Sources */, - C13CC3BC29C7B757007F25DE /* CRC16Tests.swift in Sources */, - C13CC3B929C7B757007F25DE /* PumpModelTests.swift in Sources */, - C13CC3A329C7B757007F25DE /* SensorTimestampGlucoseEventTests.swift in Sources */, - C13CC3AD29C7B757007F25DE /* DateTimeChangeGlucoseEventTests.swift in Sources */, - C13CC3B429C7B757007F25DE /* MockPumpMessageSender.swift in Sources */, - C13CC39D29C7B757007F25DE /* NSDateComponents.swift in Sources */, - C13CC3BF29C7B757007F25DE /* PumpOpsSynchronousBuildFromFramesTests.swift in Sources */, - C13CC3A029C7B757007F25DE /* TimestampedHistoryEventTests.swift in Sources */, - C13CC3AB29C7B757007F25DE /* GlucoseSensorDataGlucoseEventTests.swift in Sources */, - C13CC39229C7B757007F25DE /* ReadTempBasalCarelinkMessageBodyTests.swift in Sources */, - C13CC3A229C7B757007F25DE /* SensorDataHighGlucoseEventTests.swift in Sources */, - C13CC38829C7B757007F25DE /* ResumePumpEventTests.swift in Sources */, - C13CC3BD29C7B757007F25DE /* MySentryPumpStatusMessageBodyTests.swift in Sources */, - C13CC39C29C7B757007F25DE /* MinimedPumpManagerTests.swift in Sources */, - C13CC3A429C7B757007F25DE /* BatteryChangeGlucoseEventTests.swift in Sources */, - C13CC3C029C7B757007F25DE /* ReconciliationTests.swift in Sources */, - C13CC3AA29C7B757007F25DE /* SensorDataLowGlucoseEventTests.swift in Sources */, - C13CC38929C7B757007F25DE /* BolusNormalPumpEventTests.swift in Sources */, - C13CC39B29C7B757007F25DE /* MinimedPacketTests.swift in Sources */, - C13CC39829C7B757007F25DE /* ChangeMaxBolusMessageBodyTests.swift in Sources */, - C13CC3B229C7B757007F25DE /* MockPumpManagerDelegate.swift in Sources */, - C13CC39F29C7B757007F25DE /* NSDataTests.swift in Sources */, - C13CC3B529C7B757007F25DE /* MockRileyLinkDevice.swift in Sources */, - C13CC3A529C7B757007F25DE /* SensorErrorGlucoseEventTests.swift in Sources */, - C13CC3A629C7B757007F25DE /* SensorCalFactorGlucoseEventTests.swift in Sources */, - C13CC39129C7B757007F25DE /* ReadRemoteControlIDsMessageBodyTests.swift in Sources */, - C13CC3B029C7B757007F25DE /* BasalScheduleTests.swift in Sources */, - C13CC3AF29C7B757007F25DE /* TenSomethingGlucoseEventTests.swift in Sources */, - C13CC39929C7B757007F25DE /* GetPumpModelCarelinkMessageBodyTests.swift in Sources */, - C13CC3AC29C7B757007F25DE /* SensorSyncGlucoseEventTests.swift in Sources */, - C13CC3A729C7B757007F25DE /* SensorCalGlucoseEventTests.swift in Sources */, - C13CC38E29C7B757007F25DE /* ReadOtherDevicesIDsMessageBodyTests.swift in Sources */, - C13CC38D29C7B757007F25DE /* ChangeTempBasalCarelinkMessageBodyTests.swift in Sources */, - C13CC3B829C7B757007F25DE /* ReadSettingsCarelinkMessageBodyTests.swift in Sources */, - C13CC39429C7B757007F25DE /* ChangeMaxBasalRateMessageBodyTests.swift in Sources */, - C13CC3B129C7B757007F25DE /* MockRileyLinkProvider.swift in Sources */, - C13CC39A29C7B757007F25DE /* GetGlucosePageMessageBodyTests.swift in Sources */, - C13CC3B629C7B757007F25DE /* GlucosePageTests.swift in Sources */, - C13CC3A929C7B757007F25DE /* SensorStatusGlucoseEventTests.swift in Sources */, - C13CC39329C7B757007F25DE /* DeviceLinkMessageBodyTests.swift in Sources */, - C13CC38C29C7B757007F25DE /* MeterMessageTests.swift in Sources */, - C13CC38B29C7B757007F25DE /* ChangeTimeCarelinMessageBodyTests.swift in Sources */, - C1229C2429C7ECEB0066A89C /* Data.swift in Sources */, - C13CC3B329C7B757007F25DE /* MockPumpOps.swift in Sources */, - C13CC3A829C7B757007F25DE /* CalBGForGHGlucoseEventTests.swift in Sources */, - C13CC39729C7B757007F25DE /* ReadRemainingInsulinMessageBodyTests.swift in Sources */, - C13CC3BE29C7B757007F25DE /* NSDateComponentsTests.swift in Sources */, - C13CC39629C7B757007F25DE /* GetBatteryCarelinkMessageBodyTests.swift in Sources */, - C13CC3A129C7B757007F25DE /* CRC8Tests.swift in Sources */, - C13CC39029C7B757007F25DE /* FindDeviceMessageBodyTests.swift in Sources */, - C13CC38A29C7B757007F25DE /* ReadCurrentGlucosePageMessageBodyTests.swift in Sources */, - C13CC3AE29C7B757007F25DE /* SensorPacketGlucoseEventTests.swift in Sources */, - C13CC3BB29C7B757007F25DE /* HistoryPageTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C1E3490D29C7A866009A50A5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C1E34AD129C7A98F009A50A5 /* CRC8.swift in Sources */, - C1E34A6129C7A98F009A50A5 /* SelectBasalProfilePumpEvent.swift in Sources */, - C1E34A6229C7A98F009A50A5 /* DailyTotal522PumpEvent.swift in Sources */, - C1E34ADD29C7A98F009A50A5 /* Int.swift in Sources */, - C1E34A2F29C7A98F009A50A5 /* SensorDataHighGlucoseEvent.swift in Sources */, - C1E34A4C29C7A98F009A50A5 /* PumpState.swift in Sources */, - C1E34A7529C7A98F009A50A5 /* TempBasalPumpEvent.swift in Sources */, - C1E34AA629C7A98F009A50A5 /* GlucoseEventType.swift in Sources */, - C1E34A4A29C7A98F009A50A5 /* RileyLinkDevice.swift in Sources */, - C1E34A8B29C7A98F009A50A5 /* BolusReminderPumpEvent.swift in Sources */, - C1E34ADE29C7A98F009A50A5 /* NSDateComponents.swift in Sources */, - C1E34A5629C7A98F009A50A5 /* JournalEntryInsulinMarkerPumpEvent.swift in Sources */, - C1E34A5D29C7A98F009A50A5 /* ChangeAlarmNotifyModePumpEvent.swift in Sources */, - C1E34A6529C7A98F009A50A5 /* SuspendPumpEvent.swift in Sources */, - C1E34A7B29C7A98F009A50A5 /* ChangeBolusWizardSetupPumpEvent.swift in Sources */, - C1E34A5529C7A98F009A50A5 /* ChangeSensorSetup2PumpEvent.swift in Sources */, - C1E34A6329C7A98F009A50A5 /* BGReceivedPumpEvent.swift in Sources */, - C1E34A3829C7A98F009A50A5 /* MinimedPumpManagerState.swift in Sources */, - C1E34A7C29C7A98F009A50A5 /* PlaceholderPumpEvent.swift in Sources */, - C1E34AC229C7A98F009A50A5 /* BolusCarelinkMessageBody.swift in Sources */, - C1E34A9229C7A98F009A50A5 /* AlarmSensorPumpEvent.swift in Sources */, - C1E34A4029C7A98F009A50A5 /* MinimedPumpManagerError.swift in Sources */, - C1E34A6A29C7A98F009A50A5 /* ChangeBGReminderEnablePumpEvent.swift in Sources */, - C1E34ACD29C7A98F009A50A5 /* PumpColor.swift in Sources */, - C1E34A6729C7A98F009A50A5 /* UnabsorbedInsulinPumpEvent.swift in Sources */, - C1E34A6F29C7A98F009A50A5 /* ChangeSensorAlarmSilenceConfigPumpEvent.swift in Sources */, - C1E34A6929C7A98F009A50A5 /* AlarmClockReminderPumpEvent.swift in Sources */, - C1E34A4829C7A98F009A50A5 /* MinimedPumpManager.swift in Sources */, - C1E34A9829C7A98F009A50A5 /* PowerOnCarelinkMessageBody.swift in Sources */, - C1E34A8329C7A98F009A50A5 /* ResultDailyTotalPumpEvent.swift in Sources */, - C1E34A9B29C7A98F009A50A5 /* GetHistoryPageCarelinkMessageBody.swift in Sources */, - C1E34AAD29C7A98F009A50A5 /* TimestampedHistoryEvent.swift in Sources */, - C1E34ABD29C7A98F009A50A5 /* ChangeMaxBasalRateMessageBody.swift in Sources */, - C1E34A6C29C7A98F009A50A5 /* NewTimePumpEvent.swift in Sources */, - C1E34A2129C7A98F009A50A5 /* SensorErrorGlucoseEvent.swift in Sources */, - C1E34A2D29C7A98F009A50A5 /* GlucoseEvent.swift in Sources */, - C1E34A7129C7A98F009A50A5 /* PrimePumpEvent.swift in Sources */, - C1E34AC929C7A98F009A50A5 /* CarelinkMessageBody.swift in Sources */, - C1E34A9729C7A98F009A50A5 /* ReadCurrentPageNumberMessageBody.swift in Sources */, - C1E34A9629C7A98F009A50A5 /* MessageBody.swift in Sources */, - C1E34A3E29C7A98F009A50A5 /* ReservoirReading.swift in Sources */, - C1E34A5429C7A98F009A50A5 /* ChangeBolusScrollStepSizePumpEvent.swift in Sources */, - C1E34AB029C7A98F009A50A5 /* GetPumpModelCarelinkMessageBody.swift in Sources */, - C1E34AC329C7A98F009A50A5 /* DataFrameMessageBody.swift in Sources */, - C1E34A7629C7A98F009A50A5 /* ChangeSensorRateOfChangeAlertSetupPumpEvent.swift in Sources */, - C1E34AA929C7A98F009A50A5 /* MySentryAlertType.swift in Sources */, - C1E34B8529C7B1D4009A50A5 /* HKUnit.swift in Sources */, - C1E34ABC29C7A98F009A50A5 /* ChangeMaxBolusMessageBody.swift in Sources */, - C1E34A4229C7A98F009A50A5 /* PumpSettings.swift in Sources */, - C1E34AA129C7A98F009A50A5 /* DeviceLinkMessageBody.swift in Sources */, - C1E34AAB29C7A98F009A50A5 /* BasalSchedule.swift in Sources */, - C1E34A6629C7A98F009A50A5 /* EnableBolusWizardPumpEvent.swift in Sources */, - C1E34A3129C7A98F009A50A5 /* SensorCalFactorGlucoseEvent.swift in Sources */, - C1E34A6829C7A98F009A50A5 /* DeleteOtherDeviceIDPumpEvent.swift in Sources */, - C1E34A4929C7A98F009A50A5 /* UnfinalizedDose.swift in Sources */, - C1E34A1E29C7A98F009A50A5 /* CalBGForGHGlucoseEvent.swift in Sources */, - C1E34AB229C7A98F009A50A5 /* ChangeTempBasalCarelinkMessageBody.swift in Sources */, - C1E34A7F29C7A98F009A50A5 /* ResumePumpEvent.swift in Sources */, - C1E34AA229C7A98F009A50A5 /* ReadTempBasalCarelinkMessageBody.swift in Sources */, - C1E34A2629C7A98F009A50A5 /* SensorTimestampGlucoseEvent.swift in Sources */, - C1E34A7829C7A98F009A50A5 /* BolusWizardSetupPumpEvent.swift in Sources */, - C1E34A8229C7A98F009A50A5 /* BasalProfileStartPumpEvent.swift in Sources */, - C1E34A5129C7A98F009A50A5 /* PumpAlarmPumpEvent.swift in Sources */, - C1E34A3929C7A98F009A50A5 /* MinimedPumpManagerRecents.swift in Sources */, - C1E34ACF29C7A98F009A50A5 /* PumpRegion.swift in Sources */, - C1E34A2E29C7A98F009A50A5 /* GlucoseSensorDataGlucoseEvent.swift in Sources */, - C1E34ACE29C7A98F009A50A5 /* PumpModel.swift in Sources */, - C1E34A3A29C7A98F009A50A5 /* EnliteSensorDisplayable.swift in Sources */, - C1E34A8029C7A98F009A50A5 /* ChangeBGReminderOffsetPumpEvent.swift in Sources */, - C1E34AB529C7A98F009A50A5 /* ReadSettingsCarelinkMessageBody.swift in Sources */, - C1E34A9329C7A98F009A50A5 /* DailyTotal515PumpEvent.swift in Sources */, - C1E34A8129C7A98F009A50A5 /* ChangeWatchdogMarriageProfilePumpEvent.swift in Sources */, - C1E34A8E29C7A98F009A50A5 /* DeleteBolusReminderTimePumpEvent.swift in Sources */, - C1E34A5229C7A98F009A50A5 /* ChangeCaptureEventEnablePumpEvent.swift in Sources */, - C1E34B7B29C7B044009A50A5 /* OSLog.swift in Sources */, - C1E34A7729C7A98F009A50A5 /* RestoreMystery55PumpEvent.swift in Sources */, - C1E34AA029C7A98F009A50A5 /* UnknownMessageBody.swift in Sources */, - C1E34AB629C7A98F009A50A5 /* GetPumpFirmwareVersionMessageBody.swift in Sources */, - C1E34A8A29C7A98F009A50A5 /* RewindPumpEvent.swift in Sources */, - C1E34A3029C7A98F009A50A5 /* BatteryChangeGlucoseEvent.swift in Sources */, - C1E34B8329C7B1AB009A50A5 /* TimeZone.swift in Sources */, - C1E34AA429C7A98F009A50A5 /* GlucosePage.swift in Sources */, - C1E34A3B29C7A98F009A50A5 /* PumpOpsSession+LoopKit.swift in Sources */, - C1E34A7229C7A98F009A50A5 /* DailyTotal523PumpEvent.swift in Sources */, - C1E34A2529C7A98F009A50A5 /* SensorSyncGlucoseEvent.swift in Sources */, - C1E34A5929C7A98F009A50A5 /* ChangeBolusReminderEnablePumpEvent.swift in Sources */, - C1E34B7929C7AFF7009A50A5 /* TimeInterval.swift in Sources */, - C1E34A5729C7A98F009A50A5 /* ChangeMaxBolusPumpEvent.swift in Sources */, - C1E34A6E29C7A98F009A50A5 /* ChangeTempBasalTypePumpEvent.swift in Sources */, - C1E34AB929C7A98F009A50A5 /* PumpMessage.swift in Sources */, - C1E34AB329C7A98F009A50A5 /* ReadOtherDevicesIDsMessageBody.swift in Sources */, - C1E34AB429C7A98F009A50A5 /* ReadTimeCarelinkMessageBody.swift in Sources */, - C1E34AA829C7A98F009A50A5 /* PartialDecode.swift in Sources */, - C1E34A4629C7A98F009A50A5 /* MinimedDoseProgressEstimator.swift in Sources */, - C1E34A9E29C7A98F009A50A5 /* MySentryAlertMessageBody.swift in Sources */, - C1E34A2929C7A98F009A50A5 /* DateTimeChangeGlucoseEvent.swift in Sources */, - C1E34AB829C7A98F009A50A5 /* ReadRemoteControlIDsMessageBody.swift in Sources */, - C1E34A2829C7A98F009A50A5 /* SensorPacketGlucoseEvent.swift in Sources */, - C1E34A5C29C7A98F009A50A5 /* ClearAlarmPumpEvent.swift in Sources */, - C1E34A3429C7A98F009A50A5 /* MySentryPumpStatusMessageBody+CGMManager.swift in Sources */, - C1E34AAC29C7A98F009A50A5 /* PumpEventType.swift in Sources */, - C1E34A3D29C7A98F009A50A5 /* HistoryPage+PumpOpsSession.swift in Sources */, - C1E34AC029C7A98F009A50A5 /* PacketType.swift in Sources */, - C1E34A3329C7A98F009A50A5 /* SensorValueGlucoseEvent+CGMManager.swift in Sources */, - C1E34A9129C7A98F009A50A5 /* BolusNormalPumpEvent.swift in Sources */, - C1E34ABF29C7A98F009A50A5 /* ReadRemainingInsulinMessageBody.swift in Sources */, - C1E34ACC29C7A98F009A50A5 /* BatteryChemistryType.swift in Sources */, - C1E34AC629C7A98F009A50A5 /* ChangeTimeCarelinkMessageBody.swift in Sources */, - C1E34A8629C7A98F009A50A5 /* CalBGForPHPumpEvent.swift in Sources */, - C1E34A5329C7A98F009A50A5 /* TempBasalDurationPumpEvent.swift in Sources */, - C1E34A2729C7A98F009A50A5 /* SensorDataLowGlucoseEvent.swift in Sources */, - C1E34A4429C7A98F009A50A5 /* PumpMessage+PumpOpsSession.swift in Sources */, - C1E34ABA29C7A98F009A50A5 /* SuspendResumeMessageBody.swift in Sources */, - C1E34A2A29C7A98F009A50A5 /* UnknownGlucoseEvent.swift in Sources */, - C1E34AAA29C7A98F009A50A5 /* CRC16.swift in Sources */, - C1E34ABB29C7A98F009A50A5 /* ReadOtherDevicesStatusMessageBody.swift in Sources */, - C1E34A8929C7A98F009A50A5 /* ChangeBasalProfilePatternPumpEvent.swift in Sources */, - C1E34A9029C7A98F009A50A5 /* JournalEntryExerciseMarkerPumpEvent.swift in Sources */, - C1E34A3F29C7A98F009A50A5 /* PumpMessageSender.swift in Sources */, - C1E34AC729C7A98F009A50A5 /* SelectBasalProfileMessageBody.swift in Sources */, - C1E34AC129C7A98F009A50A5 /* MeterMessage.swift in Sources */, - C1E34AAE29C7A98F009A50A5 /* GetGlucosePageMessageBody.swift in Sources */, - C1E34A2229C7A98F009A50A5 /* TenSomethingGlucoseEvent.swift in Sources */, - C1E34B7529C7AF61009A50A5 /* LocalisedString.swift in Sources */, - C1E34AA729C7A98F009A50A5 /* TimestampedGlucoseEvent.swift in Sources */, - C1E34AC829C7A98F009A50A5 /* ButtonPressCarelinkMessageBody.swift in Sources */, - C1E34A9A29C7A98F009A50A5 /* SetRemoteControlEnabledMessageBody.swift in Sources */, - C1E34A7929C7A98F009A50A5 /* ChangeTimePumpEvent.swift in Sources */, - C1E34A8F29C7A98F009A50A5 /* ChangeReservoirWarningTimePumpEvent.swift in Sources */, - C1E34AD029C7A98F009A50A5 /* MinimedPacket.swift in Sources */, - C1E34A4129C7A98F009A50A5 /* DoseStore.swift in Sources */, - C1E34A8C29C7A98F009A50A5 /* ChangeMeterIDPumpEvent.swift in Sources */, - C1E34A9F29C7A98F009A50A5 /* PumpErrorMessageBody.swift in Sources */, - C1E34A4329C7A98F009A50A5 /* PumpOps.swift in Sources */, - C1E34A7029C7A98F009A50A5 /* ChangeOtherDeviceIDPumpEvent.swift in Sources */, - C1E34A2329C7A98F009A50A5 /* SensorStatusGlucoseEvent.swift in Sources */, - C1E34A9C29C7A98F009A50A5 /* PumpAckMessageBody.swift in Sources */, - C1E34AA329C7A98F009A50A5 /* ReadCurrentGlucosePageMessageBody.swift in Sources */, - C1E34A5A29C7A98F009A50A5 /* ChangeCarbUnitsPumpEvent.swift in Sources */, - C1E34AAF29C7A98F009A50A5 /* MySentryPumpStatusMessageBody.swift in Sources */, - C1E34ABE29C7A98F009A50A5 /* FindDeviceMessageBody.swift in Sources */, - C1E34AB129C7A98F009A50A5 /* MySentryAlertClearedMessageBody.swift in Sources */, - C1E34AD229C7A98F009A50A5 /* FourByteSixByteEncoding.swift in Sources */, - C1E34A5829C7A98F009A50A5 /* ChangeVariableBolusPumpEvent.swift in Sources */, - C1E34A4729C7A98F009A50A5 /* MinimedPumpMessageSender.swift in Sources */, - C1E34B8129C7B155009A50A5 /* PumpOpsSession.swift in Sources */, - C1E34A8D29C7A98F009A50A5 /* ChangeAudioBolusPumpEvent.swift in Sources */, - C1E34A5029C7A98F009A50A5 /* ChangeWatchdogEnablePumpEvent.swift in Sources */, - C1E34ADC29C7A98F009A50A5 /* ISO8601DateFormatter.swift in Sources */, - C1E34A3C29C7A98F009A50A5 /* BasalProfile.swift in Sources */, - C1E34A7329C7A98F009A50A5 /* BatteryPumpEvent.swift in Sources */, - C1E34A8829C7A98F009A50A5 /* ChangeChildBlockEnablePumpEvent.swift in Sources */, - C1E34A7429C7A98F009A50A5 /* EnableDisableRemotePumpEvent.swift in Sources */, - C1E34A5B29C7A98F009A50A5 /* BolusWizardEstimatePumpEvent.swift in Sources */, - C1E34A7D29C7A98F009A50A5 /* PumpEvent.swift in Sources */, - C1E34A8529C7A98F009A50A5 /* RestoreMystery54PumpEvent.swift in Sources */, - C1E34A4529C7A98F009A50A5 /* InsulinDataSource.swift in Sources */, - C1E34A6B29C7A98F009A50A5 /* JournalEntryPumpLowBatteryPumpEvent.swift in Sources */, - C1E34AB729C7A98F009A50A5 /* MessageType.swift in Sources */, - C1E34A2029C7A98F009A50A5 /* SensorCalGlucoseEvent.swift in Sources */, - C1E34A5E29C7A98F009A50A5 /* ChangeAlarmClockEnablePumpEvent.swift in Sources */, - C1E34A1F29C7A98F009A50A5 /* RelativeTimestampedGlucoseEvent.swift in Sources */, - C1E34A9D29C7A98F009A50A5 /* MySentryAckMessageBody.swift in Sources */, - C1E34A4B29C7A98F009A50A5 /* PumpOpsError.swift in Sources */, - C1E34A7E29C7A98F009A50A5 /* ChangeBasalProfilePumpEvent.swift in Sources */, - C1E34A8429C7A98F009A50A5 /* UnknownPumpEvent57.swift in Sources */, - C1E34A2429C7A98F009A50A5 /* SensorValueGlucoseEvent.swift in Sources */, - C1E34A6429C7A98F009A50A5 /* TimestampedPumpEvent.swift in Sources */, - C1E34AC429C7A98F009A50A5 /* ChangeRemoteControlIDMessageBody.swift in Sources */, - C1E34AC529C7A98F009A50A5 /* ReadPumpStatusMessageBody.swift in Sources */, - C1E34A8729C7A98F009A50A5 /* ChangeParadigmLinkIDPumpEvent.swift in Sources */, - C1E34B7729C7AFCF009A50A5 /* Data.swift in Sources */, - C1E34A7A29C7A98F009A50A5 /* ChangeBolusReminderTimePumpEvent.swift in Sources */, - C1E34A5F29C7A98F009A50A5 /* JournalEntryPumpLowReservoirPumpEvent.swift in Sources */, - C1E34A6029C7A98F009A50A5 /* ChangeTimeFormatPumpEvent.swift in Sources */, - C1E34A9929C7A98F009A50A5 /* GetBatteryCarelinkMessageBody.swift in Sources */, - C1E34AA529C7A98F009A50A5 /* HistoryPage.swift in Sources */, - C1E34A2B29C7A98F009A50A5 /* DataEndGlucoseEvent.swift in Sources */, - C1E34A6D29C7A98F009A50A5 /* ChangeMaxBasalPumpEvent.swift in Sources */, - C1E34A2C29C7A98F009A50A5 /* NineteenSomethingGlucoseEvent.swift in Sources */, - C1E34A9429C7A98F009A50A5 /* JournalEntryMealMarkerPumpEvent.swift in Sources */, - C1E34A3229C7A98F009A50A5 /* SensorWeakSignalGlucoseEvent.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C1E34AFD29C7ABCB009A50A5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C1E34B2829C7ABF3009A50A5 /* MinimedPumpSetupCompleteViewController.swift in Sources */, - C1E34B8829C7B292009A50A5 /* Comparable.swift in Sources */, - C1E34B8A29C7B2FC009A50A5 /* LocalisedString.swift in Sources */, - C1E34B2429C7ABF3009A50A5 /* Image.swift in Sources */, - C1E34B3029C7ABF3009A50A5 /* MinimedHUDProvider.swift in Sources */, - C1E34B3729C7ABF3009A50A5 /* MinimedPumpSettingsViewModel.swift in Sources */, - C1E34B2E29C7ABF3009A50A5 /* MinimedPumpUICoordinator.swift in Sources */, - C1E34B3129C7ABF3009A50A5 /* UseMySentrySelectionView.swift in Sources */, - C1E34B8C29C7B334009A50A5 /* IdentifiableClass.swift in Sources */, - C1E34B2729C7ABF3009A50A5 /* MinimedPumpClockSetupViewController.swift in Sources */, - C1E34B3229C7ABF3009A50A5 /* DataSourceSelectionView.swift in Sources */, - C1E34B3A29C7ABF3009A50A5 /* TimeView.swift in Sources */, - C1E34B3929C7ABF3009A50A5 /* MinimedReservoirView.swift in Sources */, - C1E34B2A29C7ABF3009A50A5 /* MinimedPumpManager+UI.swift in Sources */, - C1E34B2F29C7ABF3009A50A5 /* CommandResponseViewController.swift in Sources */, - C1E34B3529C7ABF3009A50A5 /* MinimedPumpSettingsView.swift in Sources */, - C1E34B3329C7ABF3009A50A5 /* BatteryTypeSelectionView.swift in Sources */, - C1E34B2929C7ABF3009A50A5 /* MinimedPumpSentrySetupViewController.swift in Sources */, - C1E34B9229C7B46C009A50A5 /* TimeZone.swift in Sources */, - C1E34B8E29C7B34F009A50A5 /* NibLoadable.swift in Sources */, - C1E34B3629C7ABF3009A50A5 /* ReservoirHUDView.swift in Sources */, - C1E34B3829C7ABF3009A50A5 /* InsulinTypeConfirmation.swift in Sources */, - C1E34B2B29C7ABF3009A50A5 /* PumpModel.swift in Sources */, - C1E34B2529C7ABF3009A50A5 /* MinimedPumpIDSetupViewController.swift in Sources */, - C1E34B9029C7B38A009A50A5 /* NumberFormatter.swift in Sources */, - C1E34B2629C7ABF3009A50A5 /* MinimedPumpManagerSetupViewController.swift in Sources */, - C1E34B2C29C7ABF3009A50A5 /* RadioSelectionTableViewController.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C1E34B5729C7AD01009A50A5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C13CC3DD29C7BA48007F25DE /* OSLog.swift in Sources */, - C1E34B6429C7AD31009A50A5 /* MinimedKitPlugin.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - C13CC33B29C7B6BC007F25DE /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = C1E3491029C7A866009A50A5 /* MinimedKit */; - targetProxy = C13CC33A29C7B6BC007F25DE /* PBXContainerItemProxy */; - }; - C13CC34729C7B73A007F25DE /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = C1E3491029C7A866009A50A5 /* MinimedKit */; - targetProxy = C13CC34629C7B73A007F25DE /* PBXContainerItemProxy */; - }; - C1E34B6E29C7AD9C009A50A5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = C1E3491029C7A866009A50A5 /* MinimedKit */; - targetProxy = C1E34B6D29C7AD9C009A50A5 /* PBXContainerItemProxy */; - }; - C1E34B7229C7AD9C009A50A5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = C1E34B0029C7ABCB009A50A5 /* MinimedKitUI */; - targetProxy = C1E34B7129C7AD9C009A50A5 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - C13CC3C129C7B8BC007F25DE /* MinimedPumpManager.storyboard */ = { - isa = PBXVariantGroup; - children = ( - C13CC3C229C7B8BC007F25DE /* Base */, - C13CC3C529C7B8D0007F25DE /* ar */, - C13CC3C629C7B8D4007F25DE /* en */, - C13CC3C729C7B8D8007F25DE /* zh-Hans */, - C13CC3C829C7B8DA007F25DE /* cs */, - C13CC3C929C7B8DB007F25DE /* da */, - C13CC3CA29C7B8DC007F25DE /* nl */, - C13CC3CB29C7B8DD007F25DE /* fi */, - C13CC3CC29C7B8DE007F25DE /* fr */, - C13CC3CD29C7B8DF007F25DE /* de */, - C13CC3CE29C7B8E0007F25DE /* he */, - C13CC3CF29C7B8E0007F25DE /* it */, - C13CC3D029C7B8E1007F25DE /* ja */, - C13CC3D129C7B8E2007F25DE /* nb */, - C13CC3D229C7B8E3007F25DE /* pl */, - C13CC3D329C7B8E4007F25DE /* pt-BR */, - C13CC3D429C7B8E5007F25DE /* ro */, - C13CC3D529C7B8E5007F25DE /* ru */, - C13CC3D629C7B8E6007F25DE /* sk */, - C13CC3D729C7B8E7007F25DE /* es */, - C13CC3D829C7B8E9007F25DE /* sv */, - C13CC3D929C7B8E9007F25DE /* tr */, - C13CC3DA29C7B8EB007F25DE /* vi */, - 193F1E522B44C22A00525770 /* hu */, - ); - name = MinimedPumpManager.storyboard; - sourceTree = ""; - }; - C1E34AE429C7A9BC009A50A5 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - C1E34AE529C7A9BC009A50A5 /* de */, - C1E34AE629C7A9BC009A50A5 /* he */, - C1E34AE729C7A9BC009A50A5 /* ar */, - C1E34AE829C7A9BC009A50A5 /* zh-Hans */, - C1E34AE929C7A9BC009A50A5 /* ja */, - C1E34AEA29C7A9BC009A50A5 /* nb */, - C1E34AEB29C7A9BC009A50A5 /* es */, - C1E34AEC29C7A9BC009A50A5 /* da */, - C1E34AED29C7A9BC009A50A5 /* it */, - C1E34AEE29C7A9BC009A50A5 /* sk */, - C1E34AEF29C7A9BC009A50A5 /* sv */, - C1E34AF029C7A9BC009A50A5 /* cs */, - C1E34AF129C7A9BC009A50A5 /* Base */, - C1E34AF229C7A9BC009A50A5 /* tr */, - C1E34AF329C7A9BC009A50A5 /* pl */, - C1E34AF429C7A9BC009A50A5 /* pt-BR */, - C1E34AF529C7A9BC009A50A5 /* vi */, - C1E34AF629C7A9BC009A50A5 /* ru */, - C1E34AF729C7A9BC009A50A5 /* fr */, - C1E34AF829C7A9BC009A50A5 /* fi */, - C1E34AF929C7A9BC009A50A5 /* nl */, - C1E34AFA29C7A9BC009A50A5 /* ro */, - 193F1E532B44C22A00525770 /* hu */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - C1E34B4029C7AC0A009A50A5 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - C1E34B4129C7AC4C009A50A5 /* ar */, - C1E34B4229C7AC4F009A50A5 /* zh-Hans */, - C1E34B4329C7AC51009A50A5 /* cs */, - C1E34B4429C7AC54009A50A5 /* da */, - C1E34B4529C7AC56009A50A5 /* nl */, - C1E34B4629C7AC58009A50A5 /* fi */, - C1E34B4729C7AC5B009A50A5 /* fr */, - C1E34B4829C7AC5D009A50A5 /* de */, - C1E34B4929C7AC5F009A50A5 /* he */, - C1E34B4A29C7AC61009A50A5 /* it */, - C1E34B4B29C7AC64009A50A5 /* ja */, - C1E34B4C29C7AC66009A50A5 /* nb */, - C1E34B4D29C7AC68009A50A5 /* pl */, - C1E34B4E29C7AC69009A50A5 /* pt-BR */, - C1E34B4F29C7AC6A009A50A5 /* ro */, - C1E34B5029C7AC6B009A50A5 /* ru */, - C1E34B5129C7AC6C009A50A5 /* sk */, - C1E34B5229C7AC6D009A50A5 /* es */, - C1E34B5329C7AC6E009A50A5 /* sv */, - C1E34B5429C7AC6F009A50A5 /* tr */, - C1E34B5529C7AC70009A50A5 /* vi */, - C1BF2DB929C8007300EB8987 /* en */, - 193F1E542B44C22A00525770 /* hu */, - ); - name = Localizable.strings; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - C13CC34929C7B73A007F25DE /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = UY678SP37Q; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.MinimedKitTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - C13CC34A29C7B73A007F25DE /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = UY678SP37Q; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.MinimedKitTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - C1E3491629C7A866009A50A5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = 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_DOCUMENTATION_COMMENTS = YES; - 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - 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 = 15.2; - LOCALIZED_STRING_MACRO_NAMES = ( - NSLocalizedString, - CFCopyLocalizedString, - LocalizedString, - ); - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - C1E3491729C7A866009A50A5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = 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_DOCUMENTATION_COMMENTS = YES; - 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - 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 = 15.2; - LOCALIZED_STRING_MACRO_NAMES = ( - NSLocalizedString, - CFCopyLocalizedString, - LocalizedString, - ); - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - C1E3491929C7A866009A50A5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.MinimedKit; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - C1E3491A29C7A866009A50A5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.MinimedKit; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - C1E34B0629C7ABCB009A50A5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.MinimedKitUI; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - C1E34B0729C7ABCB009A50A5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.MinimedKitUI; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - C1E34B6029C7AD01009A50A5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = MinimedKitPlugin/Info.plist; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.MinimedKitPlugin; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - WRAPPER_EXTENSION = loopplugin; - }; - name = Debug; - }; - C1E34B6129C7AD01009A50A5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = MinimedKitPlugin/Info.plist; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = org.loopkit.MinimedKitPlugin; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - WRAPPER_EXTENSION = loopplugin; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - C13CC34829C7B73A007F25DE /* Build configuration list for PBXNativeTarget "MinimedKitTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C13CC34929C7B73A007F25DE /* Debug */, - C13CC34A29C7B73A007F25DE /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C1E3490B29C7A866009A50A5 /* Build configuration list for PBXProject "MinimedKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C1E3491629C7A866009A50A5 /* Debug */, - C1E3491729C7A866009A50A5 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C1E3491829C7A866009A50A5 /* Build configuration list for PBXNativeTarget "MinimedKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C1E3491929C7A866009A50A5 /* Debug */, - C1E3491A29C7A866009A50A5 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C1E34B0529C7ABCB009A50A5 /* Build configuration list for PBXNativeTarget "MinimedKitUI" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C1E34B0629C7ABCB009A50A5 /* Debug */, - C1E34B0729C7ABCB009A50A5 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C1E34B5F29C7AD01009A50A5 /* Build configuration list for PBXNativeTarget "MinimedKitPlugin" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C1E34B6029C7AD01009A50A5 /* Debug */, - C1E34B6129C7AD01009A50A5 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = C1E3490829C7A866009A50A5 /* Project object */; -} diff --git a/Dependencies/MinimedKit/MinimedKit/CGMManager/MySentryPumpStatusMessageBody+CGMManager.swift b/Dependencies/MinimedKit/MinimedKit/CGMManager/MySentryPumpStatusMessageBody+CGMManager.swift deleted file mode 100644 index 35f7c9e15..000000000 --- a/Dependencies/MinimedKit/MinimedKit/CGMManager/MySentryPumpStatusMessageBody+CGMManager.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// MySentryPumpStatusMessageBody.swift -// Loop -// -// Created by Nate Racklyeft on 7/28/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit -import LoopKit - - -extension MySentryPumpStatusMessageBody: GlucoseDisplayable { - public var isStateValid: Bool { - switch glucose { - case .active: - return true - default: - return false - } - } - - public var trendType: LoopKit.GlucoseTrend? { - guard case .active = glucose else { - return nil - } - - switch glucoseTrend { - case .down: - return .down - case .downDown: - return .downDown - case .up: - return .up - case .upUp: - return .upUp - case .flat: - return .flat - } - } - - public var trendRate: HKQuantity? { - return nil - } - - public var isLocal: Bool { - return true - } - - // TODO Placeholder. This functionality will come with LOOP-1311 - public var glucoseRangeCategory: GlucoseRangeCategory? { - return nil - } - - var batteryPercentage: Int { - return batteryRemainingPercent - } - - var glucoseSyncIdentifier: String? { - guard let date = glucoseDateComponents, - let year = date.year, - let month = date.month, - let day = date.day, - let hour = date.hour, - let minute = date.minute, - let second = date.second - else { - return nil - } - - return "\(year)-\(month)-\(day) \(hour)-\(minute)-\(second)" - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/CGMManager/SensorValueGlucoseEvent+CGMManager.swift b/Dependencies/MinimedKit/MinimedKit/CGMManager/SensorValueGlucoseEvent+CGMManager.swift deleted file mode 100644 index ab76e32b6..000000000 --- a/Dependencies/MinimedKit/MinimedKit/CGMManager/SensorValueGlucoseEvent+CGMManager.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// SensorValueGlucoseEvent.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - - -extension SensorValueGlucoseEvent { - var glucoseSyncIdentifier: String? { - let date = timestamp - - guard - let year = date.year, - let month = date.month, - let day = date.day, - let hour = date.hour, - let minute = date.minute, - let second = date.second - else { - return nil - } - - return "\(year)-\(month)-\(day) \(hour)-\(minute)-\(second)" - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Extensions/Data.swift b/Dependencies/MinimedKit/MinimedKit/Extensions/Data.swift deleted file mode 100644 index 805fd406d..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Extensions/Data.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// Data.swift -// MinimedKit -// -// Created by Pete Schwamb on 3/19/23. -// - -import Foundation - -extension Data { - private func toDefaultEndian(_: T.Type) -> T { - return self.withUnsafeBytes({ (rawBufferPointer: UnsafeRawBufferPointer) -> T in - let bufferPointer = rawBufferPointer.bindMemory(to: T.self) - guard let pointer = bufferPointer.baseAddress else { - return 0 - } - return T(pointer.pointee) - }) - } - - func to(_ type: T.Type) -> T { - return T(littleEndian: toDefaultEndian(type)) - } - - func toBigEndian(_ type: T.Type) -> T { - return T(bigEndian: toDefaultEndian(type)) - } - - mutating func append(_ newElement: T) { - var element = newElement.littleEndian - append(Data(bytes: &element, count: element.bitWidth / 8)) - } - - mutating func appendBigEndian(_ newElement: T) { - var element = newElement.bigEndian - append(Data(bytes: &element, count: element.bitWidth / 8)) - } - - init(_ value: T) { - var value = value.littleEndian - self.init(bytes: &value, count: value.bitWidth / 8) - } - - init(bigEndian value: T) { - var value = value.bigEndian - self.init(bytes: &value, count: value.bitWidth / 8) - } -} - - -// String conversion methods, adapted from https://stackoverflow.com/questions/40276322/hex-binary-string-conversion-in-swift/40278391#40278391 -extension Data { - init?(hexadecimalString: String) { - self.init(capacity: hexadecimalString.utf16.count / 2) - - // Convert 0 ... 9, a ... f, A ...F to their decimal value, - // return nil for all other input characters - func decodeNibble(u: UInt16) -> UInt8? { - switch u { - case 0x30 ... 0x39: // '0'-'9' - return UInt8(u - 0x30) - case 0x41 ... 0x46: // 'A'-'F' - return UInt8(u - 0x41 + 10) // 10 since 'A' is 10, not 0 - case 0x61 ... 0x66: // 'a'-'f' - return UInt8(u - 0x61 + 10) // 10 since 'a' is 10, not 0 - default: - return nil - } - } - - var even = true - var byte: UInt8 = 0 - for c in hexadecimalString.utf16 { - guard let val = decodeNibble(u: c) else { return nil } - if even { - byte = val << 4 - } else { - byte += val - self.append(byte) - } - even = !even - } - guard even else { return nil } - } - - var hexadecimalString: String { - return map { String(format: "%02hhx", $0) }.joined() - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Extensions/HKUnit.swift b/Dependencies/MinimedKit/MinimedKit/Extensions/HKUnit.swift deleted file mode 100644 index 33ebde25a..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Extensions/HKUnit.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// HKUnit.swift -// MinimedKit -// -// Created by Pete Schwamb on 3/19/23. -// - -import HealthKit - -extension HKUnit { - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: .literUnit(with: .deci)) - }() - - static let millimolesPerLiter: HKUnit = { - return HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: .liter()) - }() - - static let internationalUnitsPerHour: HKUnit = { - return HKUnit.internationalUnit().unitDivided(by: .hour()) - }() - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Extensions/ISO8601DateFormatter.swift b/Dependencies/MinimedKit/MinimedKit/Extensions/ISO8601DateFormatter.swift deleted file mode 100644 index 6bcac6500..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Extensions/ISO8601DateFormatter.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// ISO8601DateFormatter.swift -// RileyLink -// -// Created by Nate Racklyeft on 6/15/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - - -extension ISO8601DateFormatter { - - class func defaultFormatter() -> Self { - let formatter = self.init() - formatter.formatOptions = .withInternetDateTime //Ex: 2023-01-09T20:44:28Z - - return formatter - } - - class func fractionalSecondsFormatter() -> Self { - let formatter = self.init() - formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] //Ex: 2023-01-09T20:44:28.253Z - - return formatter - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Extensions/Int.swift b/Dependencies/MinimedKit/MinimedKit/Extensions/Int.swift deleted file mode 100644 index 6d91d309a..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Extensions/Int.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// Int.swift -// Naterade -// -// Created by Nathan Racklyeft on 12/26/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension Int { - init(bigEndianBytes bytes: T) where T.Element == UInt8 { - assert(bytes.count <= 4) - var result: UInt = 0 - - for (index, byte) in bytes.enumerated() { - let shiftAmount = UInt((bytes.count) - index - 1) * 8 - result += UInt(byte) << shiftAmount - } - - self.init(result) - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Extensions/NSDateComponents.swift b/Dependencies/MinimedKit/MinimedKit/Extensions/NSDateComponents.swift deleted file mode 100644 index 405575ab4..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Extensions/NSDateComponents.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// NSDateComponents.swift -// Naterade -// -// Created by Nathan Racklyeft on 9/13/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension DateComponents { - init(mySentryBytes: Data) { - self.init() - - hour = Int(mySentryBytes[0] & 0b00011111) - minute = Int(mySentryBytes[1] & 0b00111111) - second = Int(mySentryBytes[2] & 0b00111111) - year = Int(mySentryBytes[3]) + 2000 - month = Int(mySentryBytes[4] & 0b00001111) - day = Int(mySentryBytes[5] & 0b00011111) - - calendar = Calendar(identifier: .gregorian) - } - - init(pumpEventData: Data, offset: Int, length: Int = 5) { - self.init(pumpEventBytes: pumpEventData.subdata(in: offset..> 4) + - Int((pumpEventBytes[1] & 0b11000000) >> 6) - year = Int(pumpEventBytes[4] & 0b01111111) + 2000 - } else { - day = Int(pumpEventBytes[0] & 0b00011111) - month = Int((pumpEventBytes[0] & 0b11100000) >> 4) + - Int((pumpEventBytes[1] & 0b10000000) >> 7) - year = Int(pumpEventBytes[1] & 0b01111111) + 2000 - } - - calendar = Calendar(identifier: .gregorian) - } - - init(glucoseEventBytes: Data) { - self.init() - - year = Int(glucoseEventBytes[3] & 0b01111111) + 2000 - month = Int((glucoseEventBytes[0] & 0b11000000) >> 4) + - Int((glucoseEventBytes[1] & 0b11000000) >> 6) - day = Int(glucoseEventBytes[2] & 0b00011111) - hour = Int(glucoseEventBytes[0] & 0b00011111) - minute = Int(glucoseEventBytes[1] & 0b00111111) - - calendar = Calendar(identifier: .gregorian) - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Extensions/OSLog.swift b/Dependencies/MinimedKit/MinimedKit/Extensions/OSLog.swift deleted file mode 100644 index 9b2a593d4..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Extensions/OSLog.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// OSLog.swift -// MinimedKit -// -// Created by Pete Schwamb on 3/19/23. -// - -import os.log - - -extension OSLog { - convenience init(category: String) { - self.init(subsystem: "com.randallknutson.OmniBLE", category: category) - } - - func debug(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .debug, args) - } - - func info(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .info, args) - } - - func `default`(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .default, args) - } - - func error(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .error, args) - } - - private func log(_ message: StaticString, type: OSLogType, _ args: [CVarArg]) { - switch args.count { - case 0: - os_log(message, log: self, type: type) - case 1: - os_log(message, log: self, type: type, args[0]) - case 2: - os_log(message, log: self, type: type, args[0], args[1]) - case 3: - os_log(message, log: self, type: type, args[0], args[1], args[2]) - case 4: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3]) - case 5: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4]) - default: - os_log(message, log: self, type: type, args) - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Extensions/TimeInterval.swift b/Dependencies/MinimedKit/MinimedKit/Extensions/TimeInterval.swift deleted file mode 100644 index 70b3b2cbf..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Extensions/TimeInterval.swift +++ /dev/null @@ -1,80 +0,0 @@ -// -// TimeInterval.swift -// MinimedKit -// -// Created by Pete Schwamb on 3/19/23. -// - -import Foundation - -extension TimeInterval { - - static func days(_ days: Double) -> TimeInterval { - return self.init(days: days) - } - - static func hours(_ hours: Double) -> TimeInterval { - return self.init(hours: hours) - } - - static func minutes(_ minutes: Int) -> TimeInterval { - return self.init(minutes: Double(minutes)) - } - - static func minutes(_ minutes: Double) -> TimeInterval { - return self.init(minutes: minutes) - } - - static func seconds(_ seconds: Double) -> TimeInterval { - return self.init(seconds) - } - - static func milliseconds(_ milliseconds: Double) -> TimeInterval { - return self.init(milliseconds / 1000) - } - - init(days: Double) { - self.init(hours: days * 24) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - init(minutes: Double) { - self.init(minutes * 60) - } - - init(seconds: Double) { - self.init(seconds) - } - - init(milliseconds: Double) { - self.init(milliseconds / 1000) - } - - var milliseconds: Double { - return self * 1000 - } - - init(hundredthsOfMilliseconds: Double) { - self.init(hundredthsOfMilliseconds / 100000) - } - - var hundredthsOfMilliseconds: Double { - return self * 100000 - } - - var minutes: Double { - return self / 60.0 - } - - var hours: Double { - return minutes / 60.0 - } - - var days: Double { - return hours / 24.0 - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Extensions/TimeZone.swift b/Dependencies/MinimedKit/MinimedKit/Extensions/TimeZone.swift deleted file mode 100644 index f7de7c605..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Extensions/TimeZone.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// TimeZone.swift -// MinimedKit -// -// Created by Pete Schwamb on 3/19/23. -// - -import Foundation - -extension TimeZone { - static var currentFixed: TimeZone { - return TimeZone(secondsFromGMT: TimeZone.current.secondsFromGMT())! - } - - var fixed: TimeZone { - return TimeZone(secondsFromGMT: secondsFromGMT())! - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/BatteryChangeGlucoseEvent.swift b/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/BatteryChangeGlucoseEvent.swift deleted file mode 100644 index 00ed6237a..000000000 --- a/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/BatteryChangeGlucoseEvent.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// BatteryChangeGlucoseEvent.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/16/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct BatteryChangeGlucoseEvent : GlucoseEvent { - public let length: Int - public let rawData: Data - public let timestamp: DateComponents - - public init?(availableData: Data, relativeTimestamp: DateComponents) { - length = 5 - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - rawData = availableData.subdata(in: 0..> 5 & 0b00000011) { - case 0x00: - originType = "rf" - default: - originType = "unknown" - } - } - - public var dictionaryRepresentation: [String: Any] { - return [ - "name": "CalBGForGH", - "amount": amount, - "originType": originType - ] - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/DataEndGlucoseEvent.swift b/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/DataEndGlucoseEvent.swift deleted file mode 100644 index 8fb3bcc81..000000000 --- a/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/DataEndGlucoseEvent.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// DataEndGlucoseEvent.swift -// RileyLink -// -// Created by Timothy Mecklem on 12/9/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct DataEndGlucoseEvent: GlucoseEvent { - public let length: Int - public let rawData: Data - public let timestamp: DateComponents - - public init?(availableData: Data, relativeTimestamp: DateComponents) { - length = 1 - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - rawData = availableData.subdata(in: 0..> 5 & 0b00000011) { - case 0x00: - statusType = "off" - case 0x01: - statusType = "on" - case 0x02: - statusType = "lost" - default: - statusType = "unknown" - } - } - - public var dictionaryRepresentation: [String: Any] { - return [ - "name": "SensorStatus", - "statusType": statusType - ] - } -} - diff --git a/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/SensorSyncGlucoseEvent.swift b/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/SensorSyncGlucoseEvent.swift deleted file mode 100644 index 0256ee475..000000000 --- a/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/SensorSyncGlucoseEvent.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// SensorSyncGlucoseEvent.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/16/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct SensorSyncGlucoseEvent: GlucoseEvent { - public let length: Int - public let rawData: Data - public let timestamp: DateComponents - private let syncType: String - - public init?(availableData: Data, relativeTimestamp: DateComponents) { - length = 5 - - guard length <= availableData.count else { - return nil - } - - func d(_ idx: Int) -> Int { - return Int(availableData[idx]) - } - - rawData = availableData.subdata(in: 0..> 5 & 0b00000011) { - case 0x01: - syncType = "new" - case 0x02: - syncType = "old" - default: - syncType = "find" - } - } - - public var dictionaryRepresentation: [String: Any] { - return [ - "name": "SensorSync", - "syncType": syncType - ] - } -} - diff --git a/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/SensorTimestampGlucoseEvent.swift b/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/SensorTimestampGlucoseEvent.swift deleted file mode 100644 index 1df4ad9dd..000000000 --- a/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/SensorTimestampGlucoseEvent.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// SensorTimestampGlucoseEvent.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/16/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum SensorTimestampType: String { - case lastRf - case pageEnd - case gap - case unknown - - init(code: UInt8) { - switch code { - case 0x00: - self = .lastRf - case 0x01: - self = .pageEnd - case 0x02: - self = .gap - default: - self = .unknown - } - } - -} - -public struct SensorTimestampGlucoseEvent: GlucoseEvent { - public let length: Int - public let rawData: Data - public let timestamp: DateComponents - public let timestampType: SensorTimestampType - - public init?(availableData: Data, relativeTimestamp: DateComponents) { - length = 5 - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0..> 5 & 0b00000011) - } - - public func isForwardOffsetReference() -> Bool { - return timestampType == .lastRf || timestampType == .pageEnd - } - - public var dictionaryRepresentation: [String: Any] { - return [ - "name": "SensorTimestamp", - "timestampType": timestampType - ] - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/SensorValueGlucoseEvent.swift b/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/SensorValueGlucoseEvent.swift deleted file mode 100644 index 12d8362bd..000000000 --- a/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/SensorValueGlucoseEvent.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// SensorValueGlucoseEvent.swift -// RileyLink -// -// Created by Timothy Mecklem on 12/11/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -/// An event that contains an sgv -public protocol SensorValueGlucoseEvent: RelativeTimestampedGlucoseEvent { - - var sgv: Int { - get - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/SensorWeakSignalGlucoseEvent.swift b/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/SensorWeakSignalGlucoseEvent.swift deleted file mode 100644 index 33ed544d4..000000000 --- a/Dependencies/MinimedKit/MinimedKit/GlucoseEvents/SensorWeakSignalGlucoseEvent.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// SensorWeakSignalGlucoseEvent.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/16/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct SensorWeakSignalGlucoseEvent: RelativeTimestampedGlucoseEvent { - public let length: Int - public let rawData: Data - public let timestamp: DateComponents - - public init?(availableData: Data, relativeTimestamp: DateComponents) { - length = 1 - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.0 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Dependencies/MinimedKit/MinimedKit/LocalisedString.swift b/Dependencies/MinimedKit/MinimedKit/LocalisedString.swift deleted file mode 100644 index 314681428..000000000 --- a/Dependencies/MinimedKit/MinimedKit/LocalisedString.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// LocalisedString.swift -// MinimedKit -// -// Created by Pete Schwamb on 3/19/23. -// - -import Foundation - -private class LocalBundle { - /// Returns the resource bundle associated with the current Swift module. - static var main: Bundle = { - if let mainResourceURL = Bundle.main.resourceURL, - let bundle = Bundle(url: mainResourceURL.appendingPathComponent("MinimedKit_MinimedKit.bundle")) - { - return bundle - } - return Bundle(for: LocalBundle.self) - }() -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, comment: comment) - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/BolusCarelinkMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/BolusCarelinkMessageBody.swift deleted file mode 100644 index c43eda9b3..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/BolusCarelinkMessageBody.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// BolusCarelinkMessageBody.swift -// Naterade -// -// Created by Nathan Racklyeft on 3/5/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public class BolusCarelinkMessageBody: CarelinkLongMessageBody { - - public convenience init(units: Double, insulinBitPackingScale: Int = 10) { - - let length: Int - let scrollRate: Int - - if insulinBitPackingScale >= 40 { - length = 2 - - // 40-stroke pumps scroll faster for higher unit values - switch units { - case let u where u > 10: - scrollRate = 4 - case let u where u > 1: - scrollRate = 2 - default: - scrollRate = 1 - } - } else { - length = 1 - scrollRate = 1 - } - - let strokes = Int(units * Double(insulinBitPackingScale / scrollRate)) * scrollRate - - let data = Data(hexadecimalString: String(format: "%02x%0\(2 * length)x", length, strokes))! - - self.init(rxData: data)! - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/ButtonPressCarelinkMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/ButtonPressCarelinkMessageBody.swift deleted file mode 100644 index fefddd012..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/ButtonPressCarelinkMessageBody.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// ButtonPressCarelinkMessageBody.swift -// RileyLink -// -// Created by Pete Schwamb on 3/12/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public class ButtonPressCarelinkMessageBody: CarelinkLongMessageBody { - - public enum ButtonType: UInt8 { - case act = 0x02 - case esc = 0x01 - case down = 0x04 - case up = 0x03 - case easy = 0x00 - } - - public convenience init(buttonType: ButtonType) { - let numArgs = 1 - let data = Data(hexadecimalString: String(format: "%02x%02x", numArgs, buttonType.rawValue))! - - self.init(rxData: data)! - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/CarelinkMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/CarelinkMessageBody.swift deleted file mode 100644 index 74d25ca6d..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/CarelinkMessageBody.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// CarelinkMessageBody.swift -// Naterade -// -// Created by Nathan Racklyeft on 12/26/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - -extension Data { - func paddedTo(length: Int) -> Data { - var data = self - data.append(contentsOf: [UInt8](repeating: 0, count: length - data.count)) - return data - } -} - -public class CarelinkLongMessageBody: DecodableMessageBody { - public static var length: Int = 65 - - let rxData: Data - - public required init?(rxData: Data) { - self.rxData = rxData.paddedTo(length: type(of: self).length) - } - - public var txData: Data { - return rxData - } - - public var description: String { - return "CarelinkLongMessage(\(rxData.hexadecimalString))" - } - -} - - -public class CarelinkShortMessageBody: MessageBody { - public static var length: Int = 1 - - let data: Data - - public convenience init() { - self.init(rxData: Data(repeating: 0, count: 1))! - } - - public required init?(rxData: Data) { - self.data = rxData - - if rxData.count != type(of: self).length { - return nil - } - } - - public var txData: Data { - return data - } - - public var description: String { - return "CarelinkShortMessage(\(data.hexadecimalString))" - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/ChangeMaxBasalRateMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/ChangeMaxBasalRateMessageBody.swift deleted file mode 100644 index df3c44415..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/ChangeMaxBasalRateMessageBody.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// ChangeMaxBasalRateMessageBody.swift -// MinimedKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - - -public class ChangeMaxBasalRateMessageBody: CarelinkLongMessageBody { - - static let multiplier: Double = 40 - - public convenience init?(maxBasalUnitsPerHour: Double) { - guard maxBasalUnitsPerHour >= 0 && maxBasalUnitsPerHour <= 35 else { - return nil - } - - let ticks = UInt16(maxBasalUnitsPerHour * type(of: self).multiplier) - let length = UInt8(clamping: ticks.bitWidth / 8) - var data = Data([length]) - - data.appendBigEndian(ticks) - - self.init(rxData: data) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/ChangeMaxBolusMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/ChangeMaxBolusMessageBody.swift deleted file mode 100644 index 33d05ba4c..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/ChangeMaxBolusMessageBody.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// ChangeMaxBolusMessageBody.swift -// MinimedKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - - -public class ChangeMaxBolusMessageBody: CarelinkLongMessageBody { - - static let multiplier: Double = 10 - - public convenience init?(pumpModel: PumpModel, maxBolusUnits: Double) { - guard maxBolusUnits >= 0 && maxBolusUnits <= 25 else { - return nil - } - - var data = Data() - - if pumpModel.usesTwoBytesForMaxBolus { - let ticks = UInt16(maxBolusUnits * type(of: self).multiplier) - data.appendBigEndian(ticks) - } else { - let ticks = UInt8(maxBolusUnits * type(of: self).multiplier) - data.appendBigEndian(ticks) - } - - let length = UInt8(clamping: data.count) - data.insert(length, at: 0) - - self.init(rxData: data) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/ChangeRemoteControlIDMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/ChangeRemoteControlIDMessageBody.swift deleted file mode 100644 index 72eee01e1..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/ChangeRemoteControlIDMessageBody.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// ChangeRemoteControlIDMessageBody.swift -// MinimedKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - - -public class ChangeRemoteControlIDMessageBody: CarelinkLongMessageBody { - public convenience init?(id: Data? = nil, index: Int) { - guard index < 3 else { - return nil - } - - var rxData = Data(repeating: 0x2d, count: 8) // 2d signifies a deletion - rxData[0] = 0x07 // length - rxData[1] = UInt8(clamping: index) - - if let id = id { - for (index, byte) in id.enumerated() { - rxData[2 + index] = 0b00110000 + byte - } - } - - self.init(rxData: rxData) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/ChangeTempBasalCarelinkMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/ChangeTempBasalCarelinkMessageBody.swift deleted file mode 100644 index 9a4ee066b..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/ChangeTempBasalCarelinkMessageBody.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// ChangeTempBasalCarelinkMessageBody.swift -// Naterade -// -// Created by Nathan Racklyeft on 3/6/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public class ChangeTempBasalCarelinkMessageBody: MessageBody { - public static var length: Int = 65 - - public var txData: Data - - let unitsPerHour: Double - let duration: TimeInterval - - public init(unitsPerHour: Double, duration: TimeInterval) { - - self.unitsPerHour = unitsPerHour - self.duration = duration - - let length = 3 - let strokesPerUnit: Double = 40 - let strokes = Int(unitsPerHour * strokesPerUnit) - let timeSegments = Int(duration / TimeInterval(30 * 60)) - - let data = Data(hexadecimalString: String(format: "%02x%04x%02x", length, strokes, timeSegments))! - - self.txData = data.paddedTo(length: type(of: self).length) - } - - public var description: String { - return "ChangeTempBasal(rate:\(unitsPerHour) U/hr duration:\(duration)" - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/ChangeTimeCarelinkMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/ChangeTimeCarelinkMessageBody.swift deleted file mode 100644 index f5b522ca9..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/ChangeTimeCarelinkMessageBody.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// ChangeTimeCarelinkMessageBody.swift -// Naterade -// -// Created by Nathan Racklyeft on 3/17/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public class ChangeTimeCarelinkMessageBody: CarelinkLongMessageBody { - - public convenience init?(dateComponents: DateComponents) { - - var calendar = Calendar(identifier: .gregorian) - if let timeZone = dateComponents.timeZone { - calendar.timeZone = timeZone - } - - guard dateComponents.isValidDate(in: calendar) else { - return nil - } - - let length = 7 - let data = Data(hexadecimalString: String(format: "%02x%02x%02x%02x%04x%02x%02x", length, dateComponents.hour!, dateComponents.minute!, dateComponents.second!, dateComponents.year!, dateComponents.month!, dateComponents.day!))! - - self.init(rxData: data) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/DataFrameMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/DataFrameMessageBody.swift deleted file mode 100644 index 722c66519..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/DataFrameMessageBody.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// DataFrameMessageBody.swift -// RileyLink -// -// Created by Pete Schwamb on 5/6/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation - -public class DataFrameMessageBody: CarelinkLongMessageBody { - public let isLastFrame: Bool - public let frameNumber: Int - public let contents: Data - - public required init?(rxData: Data) { - guard rxData.count == type(of: self).length else { - return nil - } - - self.isLastFrame = rxData[0] & 0b1000_0000 != 0 - self.frameNumber = Int(rxData[0] & 0b0111_1111) - self.contents = rxData.subdata(in: (1.. [DataFrameMessageBody] { - var frames = [DataFrameMessageBody]() - let frameContentsSize = DataFrameMessageBody.length - 1 - - for frameNumber in sequence(first: 0, next: { $0 + 1 }) { - let startIndex = frameNumber * frameContentsSize - var endIndex = startIndex + frameContentsSize - var isLastFrame = false - - if endIndex >= contents.count { - isLastFrame = true - endIndex = contents.count - } - - frames.append(DataFrameMessageBody( - frameNumber: frameNumber + 1, - isLastFrame: isLastFrame, - contents: contents[startIndex..> 8 & 0xff) - txData[3] = UInt8(voltsInt & 0xff) - } - - public var description: String { - return "GetBattery(status:\(status), volts:\(volts))" - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/GetGlucosePageMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/GetGlucosePageMessageBody.swift deleted file mode 100644 index 064a59112..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/GetGlucosePageMessageBody.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// GetGlucosePageMessageBody.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/19/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public class GetGlucosePageMessageBody: CarelinkLongMessageBody { - public let lastFrame: Bool - public let frameNumber: Int - public let frame: Data - - public required init?(rxData: Data) { - guard rxData.count == type(of: self).length else { - return nil - } - frameNumber = Int(rxData[0]) & 0b1111111 - lastFrame = (rxData[0]) & 0b10000000 > 0 - frame = rxData.subdata(in: 1..<65) - super.init(rxData: rxData) - } - - public required init(pageNum: UInt32) { - let numArgs = 4 - lastFrame = false - frame = Data() - frameNumber = 0 - let data = Data(hexadecimalString: String(format: "%02x%08x", numArgs, pageNum))! - super.init(rxData: data)! - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/GetHistoryPageCarelinkMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/GetHistoryPageCarelinkMessageBody.swift deleted file mode 100644 index 4a80f9ca1..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/GetHistoryPageCarelinkMessageBody.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// GetHistoryPageCarelinkMessageBody.swift -// RileyLink -// -// Created by Pete Schwamb on 3/14/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public class GetHistoryPageCarelinkMessageBody: CarelinkLongMessageBody { - public let lastFrame: Bool - public let frameNumber: Int - public let frame: Data - - public required init?(rxData: Data) { - guard rxData.count == type(of: self).length else { - return nil - } - frameNumber = Int(rxData[0]) & 0b1111111 - lastFrame = (rxData[0]) & 0b10000000 > 0 - frame = rxData.subdata(in: 1..<65) - super.init(rxData: rxData) - } - - public required init(pageNum: Int) { - let numArgs = 1 - lastFrame = false - frame = Data() - frameNumber = 0 - let data = Data(hexadecimalString: String(format: "%02x%02x", numArgs, UInt8(pageNum)))! - super.init(rxData: data)! - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/GetPumpFirmwareVersionMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/GetPumpFirmwareVersionMessageBody.swift deleted file mode 100644 index 35de7951e..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/GetPumpFirmwareVersionMessageBody.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// GetPumpFirmwareVersionMessageBody.swift -// MinimedKit -// -// Created by Pete Schwamb on 10/10/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -public class GetPumpFirmwareVersionMessageBody: CarelinkLongMessageBody { - public let version: String - - public required init?(rxData: Data) { - let stringEnd = rxData.firstIndex(of: 0) ?? rxData.count - guard rxData.count == type(of: self).length, - let vsn = String(data: rxData.subdata(in: 1..> 1 - ackFlag = flags == 0x03 - glucose = Int((rxData[4]) & 0b1) << 8 + Int(rxData[4]) - } else { - ackFlag = false - glucose = 0 - return nil - } - } - - public var txData: Data { - return rxData - } - - public var dictionaryRepresentation: [String: Any] { - return [ - "glucose": glucose, - "ackFlag": ackFlag, - ] - } - - public var description: String { - return "Meter(\(glucose), \(ackFlag))" - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/Models/BasalSchedule.swift b/Dependencies/MinimedKit/MinimedKit/Messages/Models/BasalSchedule.swift deleted file mode 100644 index fac4ee3ff..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/Models/BasalSchedule.swift +++ /dev/null @@ -1,148 +0,0 @@ -// -// BasalSchedule.swift -// RileyLink -// -// Created by Pete Schwamb on 5/6/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct BasalScheduleEntry: Equatable { - public let index: Int - public let timeOffset: TimeInterval - public let rate: Double // U/hour - - public init(index: Int, timeOffset: TimeInterval, rate: Double) { - self.index = index - self.timeOffset = timeOffset - self.rate = rate - } -} - - -public struct BasalSchedule: Equatable { - public let entries: [BasalScheduleEntry] - - public init(entries: [BasalScheduleEntry]) { - self.entries = entries - } - - public func rateAt(offset: TimeInterval) -> Double { - let (_, entry, _) = lookup(offset: offset) - return entry.rate - } - - // Only valid for fixed offset timezones - public func currentRate(using calendar: Calendar, at date: Date = Date()) -> Double { - let midnight = calendar.startOfDay(for: date) - return rateAt(offset: date.timeIntervalSince(midnight)) - } - - // Returns index, entry, and time remaining - func lookup(offset: TimeInterval) -> (Int, BasalScheduleEntry, TimeInterval) { - guard offset >= 0 && offset < .hours(24) else { - fatalError("Schedule offset out of bounds") - } - - var last: TimeInterval = .hours(24) - for (index, entry) in entries.reversed().enumerated() { - if entry.timeOffset <= offset { - return (entries.count - (index + 1), entry, last - entry.timeOffset) - } - last = entry.timeOffset - } - fatalError("Schedule incomplete") - } -} - -extension BasalSchedule { - static let rawValueLength = 192 - public typealias RawValue = Data - - public init?(rawValue: RawValue) { - var entries = [BasalScheduleEntry]() - - for tuple in sequence(first: (index: 0, offset: 0), next: { (index: $0.index + 1, $0.offset + 3) }) { - let beginOfRange = tuple.offset - let endOfRange = beginOfRange + 3 - - guard endOfRange < rawValue.count else { - break - } - - if let entry = BasalScheduleEntry( - index: tuple.index, - rawValue: rawValue[beginOfRange..= entry.timeOffset { - // Stop if the new timeOffset isn't greater than the last one - break - } - - entries.append(entry) - } else { - // Stop if we can't decode the entry - break - } - } - - guard entries.count > 0 else { - return nil - } - - self.init(entries: entries) - } - - public var rawValue: RawValue { - var buffer = Data(count: BasalSchedule.rawValueLength) - var byteIndex = 0 - - for rawEntry in entries.map({ $0.rawValue }) { - buffer.replaceSubrange(byteIndex..<(byteIndex + rawEntry.count), with: rawEntry) - byteIndex += rawEntry.count - } - - // Send the special "empty" code to clear a schedule - if entries.count == 0 { - buffer[2] = 0x3f - } - - return buffer - } -} - - -private extension BasalScheduleEntry { - static let rawValueLength = 3 - typealias RawValue = Data - - init?(index: Int, rawValue: RawValue) { - guard rawValue.count == BasalScheduleEntry.rawValueLength else { - return nil - } - - let rawRate = rawValue[rawValue.startIndex.. UInt16 { - - var crc: UInt16 = 0xffff - var pdata = (data as NSData).bytes.bindMemory(to: UInt8.self, capacity: data.count) - var nbytes = data.count - /* loop over the buffer data */ - while nbytes > 0 { - let idx = ((crc >> 8) ^ UInt16(pdata.pointee)) & 0xff - crc = ((crc << 8) ^ crcTable[Int(idx)]) & 0xffff - pdata = pdata.successor() - nbytes -= 1 - } - return crc -} - -func checkCRC16(_ data: Data) -> Bool { - if data.count > 2 { - let lowByte: UInt8 = data[data.count - 1] - let hiByte: UInt8 = data[data.count - 2] - let packetCRC: UInt16 = (UInt16(hiByte) << 8) + UInt16(lowByte) - return packetCRC == computeCRC16(data.subdata(in: 0.. GlucoseEvent { - let remainingData = pageData.subdata(in: offset..= 20 { - return GlucoseSensorDataGlucoseEvent(availableData: remainingData, relativeTimestamp: relativeTimestamp)! - } - - return UnknownGlucoseEvent(availableData: remainingData, relativeTimestamp: relativeTimestamp)! - } - - - while offset < length { - // ignore null bytes - if pageData[offset] == 0 { - offset += 1 - continue - } else { - break - } - } - - func initialTimestamp() -> DateComponents? { - var tempOffset = offset - var relativeEventCount: Double = 0 - while tempOffset < length { - let event = matchEvent(tempOffset, relativeTimestamp: DateComponents()) - if event is RelativeTimestampedGlucoseEvent { - relativeEventCount += 1 - } else if let sensorTimestampEvent = event as? SensorTimestampGlucoseEvent, - relativeEventCount == 0 || sensorTimestampEvent.isForwardOffsetReference() { - - let offsetDate = sensorTimestampEvent.timestamp.date!.addingTimeInterval(TimeInterval(minutes: relativeEventCount * 5)) - return calendar.dateComponents([.year, .month, .day, .hour, .minute, .calendar], from: offsetDate) - } else if !(event is NineteenSomethingGlucoseEvent /* seems to be a filler byte */ || event is DataEndGlucoseEvent) { - return nil - } - tempOffset += event.length - } - return nil - } - - - guard var relativeTimestamp = initialTimestamp() else { - self.needsTimestamp = true - self.events = events - return - } - - while offset < length { - // ignore null bytes - if pageData[offset] == 0 { - offset += 1 - continue - } - - let event = matchEvent(offset, relativeTimestamp: relativeTimestamp) - if let event = event as? SensorTimestampGlucoseEvent { - relativeTimestamp = event.timestamp - } else if event is RelativeTimestampedGlucoseEvent { - let offsetDate = relativeTimestamp.date!.addingTimeInterval(TimeInterval(minutes: -5)) - relativeTimestamp = calendar.dateComponents([.year, .month, .day, .hour, .minute, .calendar], from: offsetDate) - } - - events.insert(event, at: 0) - - offset += event.length - } - self.needsTimestamp = false - self.events = events - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/Models/HistoryPage.swift b/Dependencies/MinimedKit/MinimedKit/Messages/Models/HistoryPage.swift deleted file mode 100644 index 657f17f14..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/Models/HistoryPage.swift +++ /dev/null @@ -1,86 +0,0 @@ -// -// HistoryPage.swift -// RileyLink -// -// Created by Pete Schwamb on 3/3/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - - -public enum HistoryPageError: Error { - case invalidCRC - case unknownEventType(eventType: UInt8) -} - -extension HistoryPageError: LocalizedError { - public var errorDescription: String? { - switch self { - case .invalidCRC: - return LocalizedString("History page failed crc check", comment: "Error description for history page failing crc check") - case .unknownEventType(let eventType): - return String(format: LocalizedString("Unknown history record type: %$1@", comment: "Format string for error description for an unknown record type in a history page. (1: event type number)"), eventType) - } - } -} - -public struct HistoryPage { - - public let events: [PumpEvent] - - // Useful interface for testing - init(events: [PumpEvent]) { - self.events = events - } - - public init(pageData: Data, pumpModel: PumpModel) throws { - - guard checkCRC16(pageData) else { - events = [PumpEvent]() - throw HistoryPageError.invalidCRC - } - - let pageData = pageData.subdata(in: 0..<1022) - - func matchEvent(_ offset: Int) -> PumpEvent? { - if let eventType = PumpEventType(rawValue: pageData[offset]) { - let remainingData = pageData.subdata(in: offset.. { - case known(T1) - case unknown(T2) -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/Models/PumpEventType.swift b/Dependencies/MinimedKit/MinimedKit/Messages/Models/PumpEventType.swift deleted file mode 100644 index 6a8ab4e8b..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/Models/PumpEventType.swift +++ /dev/null @@ -1,228 +0,0 @@ -// -// PumpEventType.swift -// RileyLink -// -// Created by Pete Schwamb on 3/7/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - - -public enum PumpEventType: UInt8 { - case bolusNormal = 0x01 - case prime = 0x03 - case alarmPump = 0x06 - case resultDailyTotal = 0x07 - case changeBasalProfilePattern = 0x08 - case changeBasalProfile = 0x09 - case calBGForPH = 0x0a - case alarmSensor = 0x0b - case clearAlarm = 0x0c - case selectBasalProfile = 0x14 - case tempBasalDuration = 0x16 - case changeTime = 0x17 - case newTime = 0x18 - case journalEntryPumpLowBattery = 0x19 - case battery = 0x1a - case setAutoOff = 0x1b - case suspend = 0x1e - case resume = 0x1f - case selftest = 0x20 - case rewind = 0x21 - case clearSettings = 0x22 - case changeChildBlockEnable = 0x23 - case changeMaxBolus = 0x24 - case enableDisableRemote = 0x26 - case changeMaxBasal = 0x2c - case enableBolusWizard = 0x2d - case changeBGReminderOffset = 0x31 - case changeAlarmClockTime = 0x32 - case tempBasal = 0x33 - case journalEntryPumpLowReservoir = 0x34 - case alarmClockReminder = 0x35 - case changeMeterId = 0x36 - case meterBGx15 = 0x39 - case questionable3b = 0x3b - case changeParadigmLinkID = 0x3c - case bgReceived = 0x3f - case journalEntryMealMarker = 0x40 - case journalEntryExerciseMarker = 0x41 - case journalEntryInsulinMarker = 0x42 - case journalEntryOtherMarker = 0x43 - case changeSensorAutoCalEnable = 0x44 - case changeBolusWizardSetup = 0x4f - case changeSensorSetup2 = 0x50 - case restoreMystery51 = 0x51 - case restoreMystery52 = 0x52 - case changeSensorAlarmSilenceConfig = 0x53 - case restoreMystery54 = 0x54 - case restoreMystery55 = 0x55 - case changeSensorRateOfChangeAlertSetup = 0x56 - case changeBolusScrollStepSize = 0x57 - case bolusWizardSetup = 0x5a - case bolusWizardBolusEstimate = 0x5b - case unabsorbedInsulin = 0x5c - case saveSettings = 0x5d - case changeVariableBolus = 0x5e - case changeAudioBolus = 0x5f - case changeBGReminderEnable = 0x60 - case changeAlarmClockEnable = 0x61 - case changeTempBasalType = 0x62 - case changeAlarmNotifyMode = 0x63 - case changeTimeFormat = 0x64 - case changeReservoirWarningTime = 0x65 - case changeBolusReminderEnable = 0x66 - case changeBolusReminderTime = 0x67 - case deleteBolusReminderTime = 0x68 - case bolusReminder = 0x69 - case deleteAlarmClockTime = 0x6a - case dailyTotal515 = 0x6c - case dailyTotal522 = 0x6d - case dailyTotal523 = 0x6e - case changeCarbUnits = 0x6f - case basalProfileStart = 0x7b - case changeWatchdogEnable = 0x7c - case changeOtherDeviceID = 0x7d - case changeWatchdogMarriageProfile = 0x81 - case deleteOtherDeviceID = 0x82 - case changeCaptureEventEnable = 0x83 - - public var eventType: PumpEvent.Type { - switch self { - case .bolusNormal: - return BolusNormalPumpEvent.self - case .prime: - return PrimePumpEvent.self - case .alarmPump: - return PumpAlarmPumpEvent.self - case .resultDailyTotal: - return ResultDailyTotalPumpEvent.self - case .changeBasalProfilePattern: - return ChangeBasalProfilePatternPumpEvent.self - case .changeBasalProfile: - return ChangeBasalProfilePumpEvent.self - case .changeBolusWizardSetup: - return ChangeBolusWizardSetupPumpEvent.self - case .calBGForPH: - return CalBGForPHPumpEvent.self - case .alarmSensor: - return AlarmSensorPumpEvent.self - case .clearAlarm: - return ClearAlarmPumpEvent.self - case .tempBasalDuration: - return TempBasalDurationPumpEvent.self - case .changeTime: - return ChangeTimePumpEvent.self - case .newTime: - return NewTimePumpEvent.self - case .journalEntryPumpLowBattery: - return JournalEntryPumpLowBatteryPumpEvent.self - case .battery: - return BatteryPumpEvent.self - case .suspend: - return SuspendPumpEvent.self - case .resume: - return ResumePumpEvent.self - case .rewind: - return RewindPumpEvent.self - case .changeChildBlockEnable: - return ChangeChildBlockEnablePumpEvent.self - case .changeMaxBolus: - return ChangeMaxBolusPumpEvent.self - case .enableDisableRemote: - return EnableDisableRemotePumpEvent.self - case .changeMaxBasal: - return ChangeMaxBasalPumpEvent.self - case .enableBolusWizard: - return EnableBolusWizardPumpEvent.self - case .changeBGReminderOffset: - return ChangeBGReminderOffsetPumpEvent.self - case .tempBasal: - return TempBasalPumpEvent.self - case .journalEntryPumpLowReservoir: - return JournalEntryPumpLowReservoirPumpEvent.self - case .alarmClockReminder: - return AlarmClockReminderPumpEvent.self - case .changeParadigmLinkID: - return ChangeParadigmLinkIDPumpEvent.self - case .bgReceived: - return BGReceivedPumpEvent.self - case .journalEntryExerciseMarker: - return JournalEntryExerciseMarkerPumpEvent.self - case .journalEntryInsulinMarker: - return JournalEntryInsulinMarkerPumpEvent.self - case .journalEntryMealMarker: - return JournalEntryMealMarkerPumpEvent.self - case .changeSensorSetup2: - return ChangeSensorSetup2PumpEvent.self - case .changeSensorRateOfChangeAlertSetup: - return ChangeSensorRateOfChangeAlertSetupPumpEvent.self - case .changeBolusScrollStepSize: - return ChangeBolusScrollStepSizePumpEvent.self - case .bolusWizardSetup: - return BolusWizardSetupPumpEvent.self - case .bolusWizardBolusEstimate: - return BolusWizardEstimatePumpEvent.self - case .unabsorbedInsulin: - return UnabsorbedInsulinPumpEvent.self - case .changeVariableBolus: - return ChangeVariableBolusPumpEvent.self - case .changeAudioBolus: - return ChangeAudioBolusPumpEvent.self - case .changeBGReminderEnable: - return ChangeBGReminderEnablePumpEvent.self - case .changeAlarmClockEnable: - return ChangeAlarmClockEnablePumpEvent.self - case .changeTempBasalType: - return ChangeTempBasalTypePumpEvent.self - case .changeAlarmNotifyMode: - return ChangeAlarmNotifyModePumpEvent.self - case .changeTimeFormat: - return ChangeTimeFormatPumpEvent.self - case .changeReservoirWarningTime: - return ChangeReservoirWarningTimePumpEvent.self - case .changeBolusReminderEnable: - return ChangeBolusReminderEnablePumpEvent.self - case .changeBolusReminderTime: - return ChangeBolusReminderTimePumpEvent.self - case .deleteBolusReminderTime: - return DeleteBolusReminderTimePumpEvent.self - case .dailyTotal515: - return DailyTotal515PumpEvent.self - case .dailyTotal522: - return DailyTotal522PumpEvent.self - case .dailyTotal523: - return DailyTotal523PumpEvent.self - case .changeCarbUnits: - return ChangeCarbUnitsPumpEvent.self - case .basalProfileStart: - return BasalProfileStartPumpEvent.self - case .changeWatchdogEnable: - return ChangeWatchdogEnablePumpEvent.self - case .changeOtherDeviceID: - return ChangeOtherDeviceIDPumpEvent.self - case .changeWatchdogMarriageProfile: - return ChangeWatchdogMarriageProfilePumpEvent.self - case .deleteOtherDeviceID: - return DeleteOtherDeviceIDPumpEvent.self - case .changeCaptureEventEnable: - return ChangeCaptureEventEnablePumpEvent.self - case .selectBasalProfile: - return SelectBasalProfilePumpEvent.self - case .changeSensorAlarmSilenceConfig: - return ChangeSensorAlarmSilenceConfigPumpEvent.self - case .restoreMystery54: - return RestoreMystery54PumpEvent.self - case .restoreMystery55: - return RestoreMystery55PumpEvent.self - case .changeMeterId: - return ChangeMeterIDPumpEvent.self - case .bolusReminder: - return BolusReminderPumpEvent.self - case .meterBGx15: - return BGReceivedPumpEvent.self - default: - return PlaceholderPumpEvent.self - } - } -} - diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/Models/TimestampedGlucoseEvent.swift b/Dependencies/MinimedKit/MinimedKit/Messages/Models/TimestampedGlucoseEvent.swift deleted file mode 100644 index c9a8dc5f1..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/Models/TimestampedGlucoseEvent.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// TimestampedGlucoseEvent.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/19/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct TimestampedGlucoseEvent { - public let glucoseEvent: GlucoseEvent - public let date: Date - - public init(glucoseEvent: GlucoseEvent, date: Date) { - self.glucoseEvent = glucoseEvent - self.date = date - } -} - - -extension TimestampedGlucoseEvent: DictionaryRepresentable { - public var dictionaryRepresentation: [String: Any] { - var dict = glucoseEvent.dictionaryRepresentation - - dict["timestamp"] = ISO8601DateFormatter.defaultFormatter().string(from: date) - - return dict - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/Models/TimestampedHistoryEvent.swift b/Dependencies/MinimedKit/MinimedKit/Messages/Models/TimestampedHistoryEvent.swift deleted file mode 100644 index 98e2b42ec..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/Models/TimestampedHistoryEvent.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// TimestampedPumpEvent.swift -// RileyLink -// -// Created by Nate Racklyeft on 6/15/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - - -// Boxes a TimestampedPumpEvent, storing its reconciled date components -public struct TimestampedHistoryEvent { - public let pumpEvent: PumpEvent - public let date: Date - - public init(pumpEvent: PumpEvent, date: Date) { - self.pumpEvent = pumpEvent - self.date = date - } -} - - -extension TimestampedHistoryEvent: DictionaryRepresentable { - public var dictionaryRepresentation: [String : Any] { - var dict = pumpEvent.dictionaryRepresentation - - dict["timestamp"] = ISO8601DateFormatter.defaultFormatter().string(from: date) - - return dict - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/MySentryAckMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/MySentryAckMessageBody.swift deleted file mode 100644 index 2625d6577..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/MySentryAckMessageBody.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// MySentryAckMessageBody.swift -// Naterade -// -// Created by Nathan Racklyeft on 9/4/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -/// Describes an ACK message sent by a MySentry device in response to pump status messages. -/// a2 350535 06 59 000695 00 04 00 00 00 e2 -public struct MySentryAckMessageBody: MessageBody { - public static let length = 9 - - let sequence: UInt8 - let mySentryID: Data - let responseMessageTypes: [MessageType] - - public init?(sequence: UInt8, watchdogID: Data, responseMessageTypes: [MessageType]) { - guard responseMessageTypes.count <= 4 && watchdogID.count == 3 else { - return nil - } - - self.sequence = sequence - self.mySentryID = watchdogID - self.responseMessageTypes = responseMessageTypes - } - - public init?(rxData: Data) { - guard rxData.count == type(of: self).length else { - return nil - } - - sequence = rxData[0] - mySentryID = rxData.subdata(in: 1..<4) - responseMessageTypes = rxData[5..<9].compactMap({ MessageType(rawValue: $0) }) - } - - public var txData: Data { - var buffer = [UInt8](repeating: 0, count: type(of: self).length) - - buffer[0] = sequence - buffer.replaceSubrange(1..<4, with: mySentryID[0..<3]) - - buffer.replaceSubrange(5..<5 + responseMessageTypes.count, with: responseMessageTypes.map({ $0.rawValue })) - - return Data(buffer) - } - - public var description: String { - return "MySentryAck(\(sequence), \(mySentryID.hexadecimalString), \(responseMessageTypes))" - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/MySentryAlertClearedMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/MySentryAlertClearedMessageBody.swift deleted file mode 100644 index 9fe116545..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/MySentryAlertClearedMessageBody.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// MySentryAlertClearedMessageBody.swift -// Naterade -// -// Created by Nathan Racklyeft on 9/6/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -/** -Describes message sent immediately from the pump to any paired MySentry devices after a user clears an alert - -See: [MinimedRF Class](https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/messages/alert_cleared.rb) - -``` -a2 594040 02 80 52 14 -``` -*/ -public struct MySentryAlertClearedMessageBody: DecodableMessageBody, DictionaryRepresentable { - public static let length = 2 - - public let alertType: MySentryAlertType? - - private let rxData: Data - - public init?(rxData: Data) { - guard rxData.count == type(of: self).length else { - return nil - } - - self.rxData = rxData - - alertType = MySentryAlertType(rawValue: rxData[1]) - } - - public var txData: Data { - return rxData - } - - public var dictionaryRepresentation: [String: Any] { - return [ - "alertType": (alertType != nil ? String(describing: alertType!) : rxData.subdata(in: 1..<2).hexadecimalString), - "cleared": true - ] - } - - public var description: String { - return "MySentryAlertCleared(\(String(describing: alertType)))" - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/MySentryAlertMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/MySentryAlertMessageBody.swift deleted file mode 100644 index 7d5072180..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/MySentryAlertMessageBody.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// MySentryAlertMessageBody.swift -// Naterade -// -// Created by Nathan Racklyeft on 9/6/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -/** -Describes an alert message sent immediately from the pump to any paired MySentry devices - -See: [MinimedRF Class](https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/messages/alert.rb) - -``` -a2 594040 01 7c 65 0727070f0906 0175 4c -``` -*/ -public struct MySentryAlertMessageBody: DecodableMessageBody, DictionaryRepresentable { - public static let length = 10 - - public let alertType: MySentryAlertType? - public let alertDate: Date - - private let rxData: Data - - public init?(rxData: Data) { - guard rxData.count == type(of: self).length, let - alertDate = DateComponents(mySentryBytes: rxData.subdata(in: 2..<8)).date - else { - return nil - } - - self.rxData = rxData - - alertType = MySentryAlertType(rawValue: rxData[1]) - self.alertDate = alertDate - } - - public var txData: Data { - return rxData - } - - public var dictionaryRepresentation: [String: Any] { - let dateFormatter = DateFormatter() - - dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" - dateFormatter.locale = Locale(identifier: "en_US_POSIX") - - return [ - "alertDate": dateFormatter.string(from: alertDate), - "alertType": (alertType != nil ? String(describing: alertType!) : rxData.subdata(in: 1..<2).hexadecimalString), - "byte89": rxData.subdata(in: 8..<10).hexadecimalString - ] - } - - public var description: String { - return "MySentryAlert(\(String(describing: alertType)), \(alertDate))" - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/MySentryPumpStatusMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/MySentryPumpStatusMessageBody.swift deleted file mode 100644 index 9a1456a6d..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/MySentryPumpStatusMessageBody.swift +++ /dev/null @@ -1,277 +0,0 @@ -// -// MySentryPumpStatusMessageBody.swift -// Naterade -// -// Created by Nathan Racklyeft on 9/5/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public enum GlucoseTrend { - case flat - case up - case upUp - case down - case downDown - - init?(byte: UInt8) { - switch byte & 0b1110 { - case 0b0000: - self = .flat - case 0b0010: - self = .up - case 0b0100: - self = .upUp - case 0b0110: - self = .down - case 0b1000: - self = .downDown - default: - return nil - } - } -} - - -public enum SensorReading { - case off - case missing - case meterBGNow - case weakSignal - case calError - case warmup - case ended - case highBG // Above 400 mg/dL - case lost - case unknown - case active(glucose: Int) - - init(glucose: Int) { - switch glucose { - case 0: - self = .off - case 1: - self = .missing - case 2: - self = .meterBGNow - case 4: - self = .weakSignal - case 6: - self = .calError - case 8: - self = .warmup - case 10: - self = .ended - case 14: - self = .highBG - case 20: - self = .lost - case 0...20: - self = .unknown - default: - self = .active(glucose: glucose) - } - } -} - -public enum ClockType { - case twentyFourHour - case twelveHour -} - - -/** - Describes a status message sent periodically from the pump to any paired MySentry devices - - See: [MinimedRF Class](https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/messages/pump_status.rb) - ``` - -- ------ -- 00 01 020304050607 08 09 10 11 1213 14 15 16 17 18 19 20 21 2223 24 25 26 27 282930313233 3435 -- - se tr pump date 01 bh ph resv bt st sr nxcal iob bl sens date 0000 - a2 594040 04 c9 51 092c1e0f0904 01 32 33 00 037a 02 02 05 b0 18 30 13 2b 00d1 00 00 00 70 092b000f0904 0000 33 - a2 594040 04 fb 51 1205000f0906 01 05 05 02 0000 04 00 00 00 ff 00 ff ff 0040 00 00 00 71 1205000f0906 0000 2b - a2 594040 04 ff 50 1219000f0906 01 00 00 00 0000 04 00 00 00 00 00 00 00 005e 00 00 00 72 000000000000 0000 8b - a2 594040 04 01 50 1223000f0906 01 00 00 00 0000 04 00 00 00 00 00 00 00 0059 00 00 00 72 000000000000 0000 9f - a2 594040 04 2f 51 1727070f0905 01 84 85 00 00cd 01 01 05 b0 3e 0a 0a 1a 009d 03 00 00 71 1726000f0905 0000 d0 - a2 594040 04 9c 51 0003310f0905 01 39 37 00 025b 01 01 06 8d 26 22 08 15 0034 00 00 00 70 0003000f0905 0000 67 - a2 594040 04 87 51 0f18150f0907 01 03 71 00 045e 04 02 07 2c 04 44 ff ff 005e 02 00 00 73 0f16000f0907 0000 35 - ``` - */ -public struct MySentryPumpStatusMessageBody: DecodableMessageBody, MessageBody, DictionaryRepresentable { - private static let reservoirMultiplier: Double = 10 - private static let iobMultiplier: Double = 40 - public static let length = 36 - - public let sequence: UInt8 - - public let pumpDateComponents: DateComponents - public let batteryRemainingPercent: Int - public let iob: Double - public let reservoirRemainingUnits: Double - public let reservoirRemainingPercent: Int - public let reservoirRemainingMinutes: Int - - public let glucoseTrend: GlucoseTrend - public let glucoseDateComponents: DateComponents? - public let glucose: SensorReading - public let previousGlucose: SensorReading - public let sensorAgeHours: Int - public let sensorRemainingHours: Int - public let clockType: ClockType - - public let nextSensorCalibrationDateComponents: DateComponents? - - private let rxData: Data - - public init?(rxData: Data) { - guard rxData.count == type(of: self).length, let trend = GlucoseTrend(byte: rxData[1]) else { - return nil - } - - self.rxData = rxData - - sequence = rxData[0] - - let pumpDateComponents = DateComponents(mySentryBytes: rxData.subdata(in: 2..<8)) - - let hourByte: UInt8 = rxData[2] - clockType = ((hourByte & 0b10000000) > 0) ? .twentyFourHour : .twelveHour - - guard let calendar = pumpDateComponents.calendar, pumpDateComponents.isValidDate(in: calendar) else { - return nil - } - - self.pumpDateComponents = pumpDateComponents - - self.glucoseTrend = trend - - reservoirRemainingUnits = Double(Int(bigEndianBytes: rxData.subdata(in: 12..<14))) / type(of: self).reservoirMultiplier - - let reservoirRemainingPercent: UInt8 = rxData[15] - self.reservoirRemainingPercent = Int(round(Double(reservoirRemainingPercent) / 4.0 * 100)) - - reservoirRemainingMinutes = Int(bigEndianBytes: rxData.subdata(in: 16..<18)) - - iob = Double(Int(bigEndianBytes: rxData.subdata(in: 22..<24))) / type(of: self).iobMultiplier - - let batteryRemainingPercent: UInt8 = rxData[14] - self.batteryRemainingPercent = Int(round(Double(batteryRemainingPercent) / 4.0 * 100)) - - let glucoseValue = Int(bigEndianBytes: Data([rxData[9], rxData[24] << 7])) >> 7 - let previousGlucoseValue = Int(bigEndianBytes: Data([rxData[10], rxData[24] << 6])) >> 7 - - glucose = SensorReading(glucose: glucoseValue) - previousGlucose = SensorReading(glucose: previousGlucoseValue) - - switch glucose { - case .off: - glucoseDateComponents = nil - default: - let glucoseDateComponents = DateComponents(mySentryBytes: rxData.subdata(in: 28..<34)) - - if glucoseDateComponents.isValidDate(in: calendar) { - self.glucoseDateComponents = glucoseDateComponents - } else { - self.glucoseDateComponents = nil - } - } - - let sensorAgeHours: UInt8 = rxData[18] - self.sensorAgeHours = Int(sensorAgeHours) - - let sensorRemainingHours: UInt8 = rxData[19] - self.sensorRemainingHours = Int(sensorRemainingHours) - - let matchingHour: UInt8 = rxData[20] - var nextSensorCalibrationDateComponents = DateComponents() - nextSensorCalibrationDateComponents.hour = Int(matchingHour) - nextSensorCalibrationDateComponents.minute = Int(rxData[21]) - nextSensorCalibrationDateComponents.calendar = calendar - self.nextSensorCalibrationDateComponents = nextSensorCalibrationDateComponents - } - - public var dictionaryRepresentation: [String: Any] { - let dateComponentsString = { (components: DateComponents) -> String in - String( - format: "%04d-%02d-%02dT%02d:%02d:%02d", - components.year!, - components.month!, - components.day!, - components.hour!, - components.minute!, - components.second! - ) - } - - var dict: [String: Any] = [ - "glucoseTrend": String(describing: glucoseTrend), - "pumpDate": dateComponentsString(pumpDateComponents), - "reservoirRemaining": reservoirRemainingUnits, - "reservoirRemainingPercent": reservoirRemainingPercent, - "reservoirRemainingMinutes": reservoirRemainingMinutes, - "iob": iob - ] - - switch glucose { - case .active(glucose: let glucose): - dict["glucose"] = glucose - default: - break - } - - if let glucoseDateComponents = glucoseDateComponents { - dict["glucoseDate"] = dateComponentsString(glucoseDateComponents) - } - dict["sensorStatus"] = String(describing: glucose) - - switch previousGlucose { - case .active(glucose: let glucose): - dict["lastGlucose"] = glucose - default: - break - } - dict["lastSensorStatus"] = String(describing: previousGlucose) - - dict["sensorAgeHours"] = sensorAgeHours - dict["sensorRemainingHours"] = sensorRemainingHours - if let components = nextSensorCalibrationDateComponents { - dict["nextSensorCalibration"] = String(format: "%02d:%02d", components.hour!, components.minute!) - } - - dict["batteryRemainingPercent"] = batteryRemainingPercent - - dict["byte1"] = rxData.subdata(in: 1..<2).hexadecimalString - // {50} - let byte1: UInt8 = rxData[1] - dict["byte1High"] = String(format: "%02x", byte1 & 0b11110000) - // {1} - dict["byte1Low"] = Int(byte1 & 0b00000001) - // Observed values: 00, 01, 02, 03 - // These seem to correspond with carb/bolus activity - dict["byte11"] = rxData.subdata(in: 11..<12).hexadecimalString - // Current alarms? - // 25: {00,52,65} 4:49 AM - 4:59 AM - // 26: 00 - dict["byte2526"] = rxData.subdata(in: 25..<27).hexadecimalString - // 27: {73} - dict["byte27"] = rxData.subdata(in: 27..<28).hexadecimalString - - return dict - } - - public var txData: Data { - return rxData - } - - public var description: String { - return "MySentryPumpStatus(seq:\(sequence), pumpDate:\(pumpDateComponents), batt:\(batteryRemainingPercent), iob:\(iob), reservoir:\(reservoirRemainingUnits), reservoir_percent:\(reservoirRemainingPercent), reservoir_minutes:\(reservoirRemainingMinutes), glucose_trend:\(glucoseTrend), glucose_date:\(glucoseDateComponents), glucose:\(glucose), previous_glucose:\(previousGlucose), sensor_age:\(sensorAgeHours), sensor_remaining:\(sensorRemainingHours), clock_type:\(clockType), next_cal:\(nextSensorCalibrationDateComponents))" - } -} - -extension MySentryPumpStatusMessageBody: Equatable { -} - -public func ==(lhs: MySentryPumpStatusMessageBody, rhs: MySentryPumpStatusMessageBody) -> Bool { - return lhs.pumpDateComponents == rhs.pumpDateComponents && lhs.glucoseDateComponents == rhs.glucoseDateComponents -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/PacketType.swift b/Dependencies/MinimedKit/MinimedKit/Messages/PacketType.swift deleted file mode 100644 index ac17b90c9..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/PacketType.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// PacketType.swift -// Naterade -// -// Created by Nathan Racklyeft on 9/2/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -public enum PacketType: UInt8 { - case mySentry = 0xA2 - case meter = 0xA5 - case carelink = 0xA7 - case sensor = 0xA8 -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/PowerOnCarelinkMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/PowerOnCarelinkMessageBody.swift deleted file mode 100644 index 6e6948984..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/PowerOnCarelinkMessageBody.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// PowerOnCarelinkMessageBody.swift -// Naterade -// -// Created by Nathan Racklyeft on 12/26/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public struct PowerOnCarelinkMessageBody: MessageBody { - public static var length: Int = 65 - - public var txData: Data - let duration: TimeInterval - - public init(duration: TimeInterval) { - self.duration = duration - let numArgs = 2 - let on = 1 - let durationMinutes: Int = Int(ceil(duration / 60.0)) - self.txData = Data(hexadecimalString: String(format: "%02x%02x%02x", numArgs, on, durationMinutes))!.paddedTo(length: PowerOnCarelinkMessageBody.length) - } - - public var description: String { - return "PowerOn(duration:\(duration))" - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/PumpAckMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/PumpAckMessageBody.swift deleted file mode 100644 index 29f82c4a0..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/PumpAckMessageBody.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// PumpAckMessageBody.swift -// RileyLink -// -// Created by Pete Schwamb on 3/14/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public class PumpAckMessageBody: DecodableMessageBody { - public static let length = 1 - - let rxData: Data - - public required init?(rxData: Data) { - self.rxData = rxData - } - - public var txData: Data { - return rxData - } - - public var description: String { - return "PumpAck(\(rxData.hexadecimalString))" - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/PumpErrorMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/PumpErrorMessageBody.swift deleted file mode 100644 index dffdff261..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/PumpErrorMessageBody.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// PumpErrorMessageBody.swift -// RileyLink -// -// Created by Pete Schwamb on 5/10/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum PumpErrorCode: UInt8, CustomStringConvertible { - // commandRefused can happen when temp basal type is set incorrectly, during suspended pump, or unfinished prime. - case commandRefused = 0x08 - case maxSettingExceeded = 0x09 - case bolusInProgress = 0x0c - case pageDoesNotExist = 0x0d - - public var description: String { - switch self { - case .commandRefused: - return LocalizedString("Command refused", comment: "Pump error code returned when command refused") - case .maxSettingExceeded: - return LocalizedString("Max setting exceeded", comment: "Pump error code describing max setting exceeded") - case .bolusInProgress: - return LocalizedString("Bolus in progress", comment: "Pump error code when bolus is in progress") - case .pageDoesNotExist: - return LocalizedString("History page does not exist", comment: "Pump error code when invalid history page is requested") - } - } - - public var recoverySuggestion: String? { - switch self { - case .commandRefused: - return LocalizedString("Check that the pump is not suspended or priming, or has a percent temp basal type", comment: "Suggestions for diagnosing a command refused pump error") - default: - return nil - } - } -} - -public class PumpErrorMessageBody: DecodableMessageBody { - public static let length = 1 - - let rxData: Data - public let errorCode: PartialDecode - - public required init?(rxData: Data) { - self.rxData = rxData - let rawErrorCode = rxData[0] - if let errorCode = PumpErrorCode(rawValue: rawErrorCode) { - self.errorCode = .known(errorCode) - } else { - self.errorCode = .unknown(rawErrorCode) - } - } - - public var txData: Data { - return rxData - } - - public var description: String { - return "PumpError(\(errorCode))" - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/PumpMessage.swift b/Dependencies/MinimedKit/MinimedKit/Messages/PumpMessage.swift deleted file mode 100644 index 10253fe5a..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/PumpMessage.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// PumpMessage.swift -// Naterade -// -// Created by Nathan Racklyeft on 9/2/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - -public struct PumpMessage : CustomStringConvertible { - public let packetType: PacketType - public let address: Data - public let messageType: MessageType - public let messageBody: MessageBody - - public init(packetType: PacketType, address: String, messageType: MessageType, messageBody: MessageBody) { - self.packetType = packetType - self.address = Data(hexadecimalString: address)! - self.messageType = messageType - self.messageBody = messageBody - } - - public init?(rxData: Data) { - guard rxData.count >= 6, - let packetType = PacketType(rawValue: rxData[0]), packetType != .meter, - let messageType = MessageType(rawValue: rxData[4]), - let messageBody = messageType.decodeType.init(rxData: rxData.subdata(in: 5.. 1 { - page = Int(rxData[0]) - } - - if page < 0 || page > 36 { - page = 36 - } - - pageNum = page - super.init(rxData: rxData) - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/ReadOtherDevicesIDsMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/ReadOtherDevicesIDsMessageBody.swift deleted file mode 100644 index b0d7b88e9..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/ReadOtherDevicesIDsMessageBody.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// ReadOtherDevicesIDsMessageBody.swift -// MinimedKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - - -public class ReadOtherDevicesIDsMessageBody: CarelinkLongMessageBody { - - public let ids: [Data] - - public required init?(rxData: Data) { - guard rxData.count == type(of: self).length else { - return nil - } - - let count = Int(rxData[1]) - - var ids: [Data] = [] - - for index in stride(from: 0, to: count, by: 1) { - let start = (index * 5 + 3) - let end = start + 4 - - ids.append(rxData.subdata(in: start.. 0 - suspended = rxData[3] > 0 - self.txData = rxData - } - - public init(bolusing: Bool, suspended: Bool) { - self.bolusing = bolusing - self.suspended = suspended - self.txData = Data(hexadecimalString: "0303\(bolusing ? "01" : "00")\(suspended ? "01" : "00")")!.paddedTo(length: 65) - } - - public var description: String { - return "ReadPumpStatus(bolusing:\(bolusing), suspended:\(suspended))" - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/ReadRemainingInsulinMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/ReadRemainingInsulinMessageBody.swift deleted file mode 100644 index 4ecf1c574..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/ReadRemainingInsulinMessageBody.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// ReadRemainingInsulinMessageBody.swift -// RileyLink -// -// Created by Nathan Racklyeft on 5/25/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public class ReadRemainingInsulinMessageBody: DecodableMessageBody { - public var txData: Data { return rxData } - - public var rxData: Data - - public static var length: Int = 65 - - public func getUnitsRemaining(insulinBitPackingScale: Int) -> Double { - - let strokes: Data - - switch insulinBitPackingScale { - case let x where x > 10: - strokes = rxData.subdata(in: 3..<5) - default: - strokes = rxData.subdata(in: 1..<3) - } - - return Double(Int(bigEndianBytes: strokes)) / Double(insulinBitPackingScale) - } - - public required init?(rxData: Data) { - guard rxData.count == type(of: self).length else { - return nil - } - self.rxData = rxData - } - - init(reservoirVolume: Double, insulinBitPackingScale: Int) { - rxData = Data().paddedTo(length: Self.length) - let scaledAmount = Int(reservoirVolume * Double(insulinBitPackingScale)) - let strokesData = Data(bigEndian: scaledAmount) - let offset = insulinBitPackingScale > 10 ? 3 : 1 - rxData[offset] = strokesData[6] - rxData[offset+1] = strokesData[7] - } - - public var description: String { - return "ReadRemainingInsulin(x23:\(getUnitsRemaining(insulinBitPackingScale: PumpModel.model523.insulinBitPackingScale)), x22:\(getUnitsRemaining(insulinBitPackingScale: PumpModel.model522.insulinBitPackingScale)))" - } - -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/ReadRemoteControlIDsMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/ReadRemoteControlIDsMessageBody.swift deleted file mode 100644 index 529adb6fa..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/ReadRemoteControlIDsMessageBody.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// ReadRemoteControlIDsMessageBody.swift -// MinimedKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -private let idSize = 6 - -public class ReadRemoteControlIDsMessageBody: CarelinkLongMessageBody { - public let ids: [Data] - - public required init?(rxData: Data) { - guard rxData.count == type(of: self).length else { - return nil - } - - var ids: [Data] = [] - - remotes: for index in stride(from: 0, to: 3, by: 1) { - let start = (index * idSize + 1) - let end = start + idSize - - var remoteID = Data(capacity: idSize) - - for byte in rxData[start..> 8 & 0xff) - txData[5] = UInt8(dateComponents.year! & 0xff) - txData[6] = UInt8(dateComponents.month!) - txData[7] = UInt8(dateComponents.day!) - } - - public var description: String { - return "ReadTime(\(dateComponents))" - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/SelectBasalProfileMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/SelectBasalProfileMessageBody.swift deleted file mode 100644 index 5523185b4..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/SelectBasalProfileMessageBody.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// SelectBasalProfileMessageBody.swift -// MinimedKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation - -public class SelectBasalProfileMessageBody: CarelinkLongMessageBody { - public convenience init(newProfile: BasalProfile) { - self.init(rxData: Data([1, newProfile.rawValue]))! - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/SetRemoteControlEnabledMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/SetRemoteControlEnabledMessageBody.swift deleted file mode 100644 index b312e8c9b..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/SetRemoteControlEnabledMessageBody.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// SetRemoteControlEnabledMessageBody.swift -// MinimedKit -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - - -public class SetRemoteControlEnabledMessageBody: CarelinkLongMessageBody { - public convenience init(enabled: Bool) { - self.init(rxData: Data([1, enabled ? 1 : 0]))! - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/SuspendResumeMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/SuspendResumeMessageBody.swift deleted file mode 100644 index dd8ef3f42..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/SuspendResumeMessageBody.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// SuspendResumeMessageBody.swift -// MinimedKit -// -// Created by Pete Schwamb on 10/1/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -public class SuspendResumeMessageBody: MessageBody { - public static var length: Int = 65 - - public var txData: Data - - public enum SuspendResumeState: UInt8 { - case suspend = 0x01 - case resume = 0x00 - } - - let state: SuspendResumeState - - public init(state: SuspendResumeState) { - self.state = state - let numArgs = 1 - let data = Data(hexadecimalString: String(format: "%02x%02x", numArgs, state.rawValue))! - self.txData = data.paddedTo(length: type(of: self).length) - } - - public var description: String { - return "SuspendResume(type:\(state)" - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Messages/UnknownMessageBody.swift b/Dependencies/MinimedKit/MinimedKit/Messages/UnknownMessageBody.swift deleted file mode 100644 index c381615f9..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Messages/UnknownMessageBody.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// UnknownMessageBody.swift -// Naterade -// -// Created by Nathan Racklyeft on 9/16/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public struct UnknownMessageBody: DecodableMessageBody, DictionaryRepresentable { - public static var length = 0 - - let rxData: Data - - public init?(rxData: Data) { - self.rxData = rxData - } - - public var txData: Data { - return rxData - } - - public var dictionaryRepresentation: [String: Any] { - return ["rawData": rxData] - } - - public var description: String { - return "UnknownMessage(\(rxData.hexadecimalString))" - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/MinimedKit.h b/Dependencies/MinimedKit/MinimedKit/MinimedKit.h deleted file mode 100644 index 37afdb5b1..000000000 --- a/Dependencies/MinimedKit/MinimedKit/MinimedKit.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// MinimedKit.h -// MinimedKit -// -// Created by Pete Schwamb on 2/27/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -#import - -//! Project version number for MinimedKit. -FOUNDATION_EXPORT double MinimedKitVersionNumber; - -//! Project version string for MinimedKit. -FOUNDATION_EXPORT const unsigned char MinimedKitVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/MinimedKit/MinimedKit/Models/BatteryChemistryType.swift b/Dependencies/MinimedKit/MinimedKit/Models/BatteryChemistryType.swift deleted file mode 100644 index 77754d27e..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Models/BatteryChemistryType.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// BatteryChemistryType.swift -// RileyLink -// -// Created by Jeremy Lucas on 11/15/16 -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum BatteryChemistryType: Int, CustomStringConvertible, Identifiable, CaseIterable { - - public var id: Int { - return rawValue - } - - case alkaline = 0 - case lithium - - public var description: String { - switch self { - case .alkaline: - return LocalizedString("Alkaline", comment: "Describing the battery chemistry as Alkaline") - case .lithium: - return LocalizedString("Lithium", comment: "Describing the battery chemistry as Lithium") - } - } - - public var maxVoltage: Double { - switch self { - case .alkaline: - return 1.47 - case .lithium: - return 1.58 - } - } - - public var minVoltage: Double { - switch self { - case .alkaline: - return 1.18 - case .lithium: - return 1.32 - } - } - - public func chargeRemaining(at voltage: Measurement) -> Double { - let computed = (voltage.converted(to: .volts).value - self.minVoltage)/(self.maxVoltage - self.minVoltage) - return max(min(computed, 1), 0) - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Models/PumpColor.swift b/Dependencies/MinimedKit/MinimedKit/Models/PumpColor.swift deleted file mode 100644 index 032561685..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Models/PumpColor.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// PumpColor.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - - -public enum PumpColor: String { - case blue = "B" - case clear = "L" - case purple = "P" - case smoke = "S" - case pink = "H" -} diff --git a/Dependencies/MinimedKit/MinimedKit/Models/PumpModel.swift b/Dependencies/MinimedKit/MinimedKit/Models/PumpModel.swift deleted file mode 100644 index d3ab6f811..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Models/PumpModel.swift +++ /dev/null @@ -1,213 +0,0 @@ -// -// PumpModel.swift -// RileyLink -// -// Created by Pete Schwamb on 3/7/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - - -/// Represents a pump model and its defining characteristics. -/// This class implements the `RawRepresentable` protocol -public enum PumpModel: String { - case model508 = "508" - case model511 = "511" - case model711 = "711" - case model512 = "512" - case model712 = "712" - case model515 = "515" - case model715 = "715" - case model522 = "522" - case model722 = "722" - case model523 = "523" - case model723 = "723" - case model530 = "530" - case model730 = "730" - case model540 = "540" - case model740 = "740" - case model551 = "551" - case model751 = "751" - case model554 = "554" - case model754 = "754" - - private var size: Int { - return Int(rawValue)! / 100 - } - - private var generation: Int { - return Int(rawValue)! % 100 - } - - /// Identifies pumps that support a major-generation shift in record format, starting with the x23. - /// Mirrors the "larger" flag as defined by decoding-carelink - public var larger: Bool { - return generation >= 23 - } - - // On newer pumps, square wave boluses are added to history on start of delivery, and updated in place - // when delivery is finished - public var appendsSquareWaveToHistoryOnStartOfDelivery: Bool { - return generation >= 23 - } - - public var hasMySentry: Bool { - return generation >= 23 - } - - var hasLowSuspend: Bool { - return generation >= 51 - } - - public var recordsBasalProfileStartEvents: Bool { - return generation >= 23 - } - - /// Newer models allow higher precision delivery, and have bit packing to accomodate this. - public var insulinBitPackingScale: Int { - return (generation >= 23) ? 40 : 10 - } - - /// Pulses per unit is the inverse of the minimum volume of delivery. - public var pulsesPerUnit: Int { - return (generation >= 23) ? 40 : 20 - } - - public var reservoirCapacity: Int { - switch size { - case 5: - return 176 - case 7: - return 300 - default: - fatalError("Unknown reservoir capacity for PumpModel.\(self)") - } - } - - /// Even though this is capped by the system at 250 / 10 U, the message takes a UInt16. - var usesTwoBytesForMaxBolus: Bool { - return generation >= 23 - } - - public var supportedBasalRates: [Double] { - if generation >= 23 { - // 0.025 units (for rates between 0.0-0.975 U/h) - let rateGroup1 = ((0...39).map { Double($0) / Double(pulsesPerUnit) }) - // 0.05 units (for rates between 1-9.95 U/h) - let rateGroup2 = ((20...199).map { Double($0) / Double(pulsesPerUnit/2) }) - // 0.1 units (for rates between 10-35 U/h) - let rateGroup3 = ((100...350).map { Double($0) / Double(pulsesPerUnit/4) }) - return rateGroup1 + rateGroup2 + rateGroup3 - } else { - // 0.05 units for rates between 0.0-35U/hr - return (0...700).map { Double($0) / Double(pulsesPerUnit) } - } - } - - public var maximumBolusVolume: Int { - return 25 - } - - public var maximumBasalRate: Double { - return 35 - } - - public var supportedBolusVolumes: [Double] { - if generation >= 23 { - let breakpoints: [Int] = [0,1,10,maximumBolusVolume] - let scales: [Int] = [40,20,10] - let scalingGroups = zip(scales, (zip(breakpoints, breakpoints[1...]).map {($0.0)...$0.1})) - let segments = scalingGroups.map { (scale, range) -> [Double] in - let scaledRanges = ((range.lowerBound*scale+1)...(range.upperBound*scale)) - return scaledRanges.map { Double($0) / Double(scale) } - } - return segments.flatMap { $0 } - } else { - return (1...(maximumBolusVolume*10)).map { Double($0) / 10.0 } - } - } - - public var maximumBasalScheduleEntryCount: Int { - return 48 - } - - public var minimumBasalScheduleEntryDuration: TimeInterval { - return .minutes(30) - } - - public var isDeliveryRateVariable: Bool { - return generation >= 23 - } - - public func bolusDeliveryTime(units: Double) -> TimeInterval { - let unitsPerMinute: Double - if isDeliveryRateVariable { - switch units { - case let u where u < 1.0: - unitsPerMinute = 0.75 - case let u where u > 7.5: - unitsPerMinute = units / 5 - default: - unitsPerMinute = 1.5 - } - } else { - unitsPerMinute = 1.5 - } - return TimeInterval(minutes: units / unitsPerMinute) - } - - public func estimateTempBasalProgress(unitsPerHour: Double, duration: TimeInterval, elapsed: TimeInterval) -> (deliveredUnits: Double, progress: Double) { - let roundedVolume = round(unitsPerHour * elapsed.hours * Double(pulsesPerUnit)) / Double(pulsesPerUnit) - return (deliveredUnits: roundedVolume, progress: min(elapsed / duration, 1)) - } - - public func estimateBolusProgress(elapsed: TimeInterval, programmedUnits: Double) -> (deliveredUnits: Double, progress: Double) { - let duration = bolusDeliveryTime(units: programmedUnits) - let timeProgress = min(elapsed / duration, 1) - - let updateResolution: Double - let unroundedVolume: Double - - if isDeliveryRateVariable { - if programmedUnits < 1 { - updateResolution = 40 // Resolution = 0.025 - unroundedVolume = timeProgress * programmedUnits - } else { - var remainingUnits = programmedUnits - var baseDuration: TimeInterval = 0 - var overlay1Duration: TimeInterval = 0 - var overlay2Duration: TimeInterval = 0 - let baseDeliveryRate = 1.5 / TimeInterval(minutes: 1) - - baseDuration = min(duration, remainingUnits / baseDeliveryRate) - remainingUnits -= baseDuration * baseDeliveryRate - - overlay1Duration = min(duration, remainingUnits / baseDeliveryRate) - remainingUnits -= overlay1Duration * baseDeliveryRate - - overlay2Duration = min(duration, remainingUnits / baseDeliveryRate) - remainingUnits -= overlay2Duration * baseDeliveryRate - - unroundedVolume = (min(elapsed, baseDuration) + min(elapsed, overlay1Duration) + min(elapsed, overlay2Duration)) * baseDeliveryRate - - if overlay1Duration > elapsed { - updateResolution = 10 // Resolution = 0.1 - } else { - updateResolution = 20 // Resolution = 0.05 - } - } - - } else { - updateResolution = 20 // Resolution = 0.05 - unroundedVolume = timeProgress * programmedUnits - } - let roundedVolume = round(unroundedVolume * updateResolution) / updateResolution - return (deliveredUnits: roundedVolume, progress: roundedVolume / programmedUnits) - } -} - - -extension PumpModel: CustomStringConvertible { - public var description: String { - return rawValue - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Models/PumpRegion.swift b/Dependencies/MinimedKit/MinimedKit/Models/PumpRegion.swift deleted file mode 100644 index c90baa38c..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Models/PumpRegion.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// PumpRegion.swift -// RileyLink -// -// Created by Pete Schwamb on 9/8/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum PumpRegion: Int, CustomStringConvertible { - case northAmerica = 0 - case worldWide - case canada - - public var description: String { - switch self { - case .worldWide: - return LocalizedString("World-Wide", comment: "Describing the worldwide pump region") - case .northAmerica: - return LocalizedString("North America", comment: "Describing the North America pump region") - case .canada: - return LocalizedString("Canada", comment: "Describing the Canada pump region ") - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpEvents/AlarmClockReminderPumpEvent.swift b/Dependencies/MinimedKit/MinimedKit/PumpEvents/AlarmClockReminderPumpEvent.swift deleted file mode 100644 index d09c9cb44..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpEvents/AlarmClockReminderPumpEvent.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// AlarmClockReminderPumpEvent.swift -// RileyLink -// -// Created by Pete Schwamb on 3/8/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct AlarmClockReminderPumpEvent: TimestampedPumpEvent { - public let length: Int - public let rawData: Data - public let timestamp: DateComponents - - public init?(availableData: Data, pumpModel: PumpModel) { - length = 7 - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - timestamp = DateComponents(pumpEventData: availableData, offset: 2) - amount = (d(1) << 3) + (d(4) >> 5) - meter = availableData.subdata(in: 7..<10).hexadecimalString - } - - public var dictionaryRepresentation: [String: Any] { - return [ - "_type": "BGReceivedPumpEvent", - "amount": amount, - "meter": meter, - ] - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpEvents/BasalProfileStartPumpEvent.swift b/Dependencies/MinimedKit/MinimedKit/PumpEvents/BasalProfileStartPumpEvent.swift deleted file mode 100644 index b815ee64e..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpEvents/BasalProfileStartPumpEvent.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// BasalProfileStartPumpEvent.swift -// RileyLink -// -// Created by Pete Schwamb on 3/8/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct BasalProfileStartPumpEvent: TimestampedPumpEvent { - public let length: Int - public let rawData: Data - public let timestamp: DateComponents - - public let scheduleEntry: BasalScheduleEntry - - public init?(availableData: Data, pumpModel: PumpModel) { - length = 10 - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. 0 { - return duration - } else { - return TimeInterval(minutes: programmed / deliveryUnitsPerMinute) - } - } - - public init?(availableData: Data, pumpModel: PumpModel) { - - func doubleValueFromData(at index: Int) -> Double { - return Double(availableData[index]) - } - - func decodeInsulin(from bytes: Data) -> Double { - return Double(Int(bigEndianBytes: bytes)) / Double(pumpModel.insulinBitPackingScale) - } - - length = BolusNormalPumpEvent.calculateLength(pumpModel.larger) - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. 0 ? .square : .normal - } - - func isMutable(atDate date: Date = Date(), forPump model: PumpModel) -> Bool { - let deliveryFinishDate = date.addingTimeInterval(deliveryTime) - return model.appendsSquareWaveToHistoryOnStartOfDelivery && type == .square && deliveryFinishDate > date - } - - public var dictionaryRepresentation: [String: Any] { - var dictionary: [String: Any] = [ - "_type": "BolusNormal", - "amount": amount, - "programmed": programmed, - "type": type.rawValue, - "wasRemotelyTriggered": wasRemotelyTriggered, - ] - - if let unabsorbedInsulinRecord = unabsorbedInsulinRecord { - dictionary["appended"] = unabsorbedInsulinRecord.dictionaryRepresentation - } - - if unabsorbedInsulinTotal > 0 { - dictionary["unabsorbed"] = unabsorbedInsulinTotal - } - - if duration > 0 { - dictionary["duration"] = duration - } - - return dictionary - } - - public static func calculateLength(_ isLarger:Bool) -> Int { - if isLarger { - return 13 - } else { - return 9 - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpEvents/BolusReminderPumpEvent.swift b/Dependencies/MinimedKit/MinimedKit/PumpEvents/BolusReminderPumpEvent.swift deleted file mode 100644 index c4cda2217..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpEvents/BolusReminderPumpEvent.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// Mystery69PumpEvent.swift -// RileyLink -// -// Created by Pete Schwamb on 9/23/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct BolusReminderPumpEvent: TimestampedPumpEvent { - public let length: Int - public let rawData: Data - public let timestamp: DateComponents - - public init?(availableData: Data, pumpModel: PumpModel) { - let length: Int - if pumpModel.larger { - length = 9 - } else { - length = 7 // This may not actually occur, as I don't think x22 and earlier pumps have missed bolus reminders. - } - - guard length <= availableData.count else { - return nil - } - - let rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - func insulinDecode(_ a: Int, b: Int) -> Double { - return Double((a << 8) + b) / 40.0 - } - - if pumpModel.larger { - length = 22 - } else { - length = 20 - } - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - timestamp = DateComponents(pumpEventData: availableData, offset: 2) - amount = ((d(4) & 0b10000000) << 2) + ((d(6) & 0b10000000) << 1) + d(1) - } - - public var dictionaryRepresentation: [String: Any] { - return [ - "_type": "CalBGForPH", - "amount": amount, - ] - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpEvents/ChangeAlarmClockEnablePumpEvent.swift b/Dependencies/MinimedKit/MinimedKit/PumpEvents/ChangeAlarmClockEnablePumpEvent.swift deleted file mode 100644 index bfde97ec6..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpEvents/ChangeAlarmClockEnablePumpEvent.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// ChangeAlarmClockEnablePumpEvent.swift -// RileyLink -// -// Created by Pete Schwamb on 3/8/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct ChangeAlarmClockEnablePumpEvent: TimestampedPumpEvent { - public let length: Int - public let rawData: Data - public let timestamp: DateComponents - - public init?(availableData: Data, pumpModel: PumpModel) { - length = 7 - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - timeFormat = d(1) == 1 ? "24hr" : "am_pm" - } - - public var dictionaryRepresentation: [String: Any] { - return [ - "_type": "ChangeTimeFormat", - "timeFormat": timeFormat, - ] - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpEvents/ChangeTimePumpEvent.swift b/Dependencies/MinimedKit/MinimedKit/PumpEvents/ChangeTimePumpEvent.swift deleted file mode 100644 index 55f5ebbe1..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpEvents/ChangeTimePumpEvent.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// ChangeTimePumpEvent.swift -// RileyLink -// -// Created by Pete Schwamb on 3/8/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct ChangeTimePumpEvent: TimestampedPumpEvent { - public let length: Int - public let rawData: Data - public let timestamp: DateComponents - - public init?(availableData: Data, pumpModel: PumpModel) { - length = 7 - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0..> 1) & 0b1 - carbUnits = (useExchangesBit != 0) ? .Exchanges : .Grams - - let carbHighBit = (availableData[1]) & 0b1 - let carbLowBits = availableData[7] - - if carbUnits == .Exchanges { - carbohydrates = Double(carbLowBits) / 10.0 - } else { - carbohydrates = Double(Int(carbHighBit) << 8 + Int(carbLowBits)) - } - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - timestamp = DateComponents(pumpEventData: availableData, offset: 5) - amount = Double(d(4) << 2) / 40.0 - programmedAmount = Double(d(2) << 2) / 40.0 - primeType = programmedAmount == 0 ? "manual" : "fixed" - } - - public var dictionaryRepresentation: [String: Any] { - return [ - "_type": "Prime", - "amount": amount, - "programmedAmount": programmedAmount, - "primeType": primeType, - ] - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift b/Dependencies/MinimedKit/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift deleted file mode 100644 index 0e6761ef5..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift +++ /dev/null @@ -1,103 +0,0 @@ -// -// PumpAlarmPumpEvent.swift -// RileyLink -// -// Created by Pete Schwamb on 3/8/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum PumpAlarmType { - case batteryOutLimitExceeded - case noDelivery - case batteryDepleted - case autoOff - case deviceReset - case deviceResetBatteryIssue17 - case deviceResetBatteryIssue21 - case reprogramError - case emptyReservoir - case unknownType(rawType: UInt8) - - init(rawType: UInt8) { - switch rawType { - case 3: - self = .batteryOutLimitExceeded - case 4: - self = .noDelivery - case 5: - self = .batteryDepleted - case 6: - self = .autoOff - case 16: - self = .deviceReset - case 17: - self = .deviceResetBatteryIssue17 - case 21: - self = .deviceResetBatteryIssue21 - case 61: - self = .reprogramError - case 62: - self = .emptyReservoir - default: - self = .unknownType(rawType: rawType) - } - } -} - -extension PumpAlarmType { - var localizedString: String { - switch self { - case .autoOff: - return LocalizedString("Auto-Off Alarm", comment: "Title for PumpAlarmType.autoOff") - case .batteryOutLimitExceeded: - return LocalizedString("Battery Out Limit", comment: "Title for PumpAlarmType.batteryOutLimitExceeded") - case .noDelivery: - return LocalizedString("No Delivery Alarm", comment: "Title for PumpAlarmType.noDelivery") - case .batteryDepleted: - return LocalizedString("Battery Depleted", comment: "Title for PumpAlarmType.batteryDepleted") - case .deviceReset: - return LocalizedString("Device Reset", comment: "Title for deviceReset") - case .deviceResetBatteryIssue17: - return LocalizedString("BatteryIssue17", comment: "Title for PumpAlarmType.deviceResetBatteryIssue17") - case .deviceResetBatteryIssue21: - return LocalizedString("BatteryIssue21", comment: "Title for PumpAlarmType.deviceResetBatteryIssue21") - case .reprogramError: - return LocalizedString("Reprogram Error", comment: "Title for PumpAlarmType.reprogramError") - case .emptyReservoir: - return LocalizedString("Empty Reservoir", comment: "Title for PumpAlarmType.emptyReservoir") - case .unknownType: - return LocalizedString("Unknown Alarm", comment: "Title for PumpAlarmType.unknownType") - } - } -} - -public struct PumpAlarmPumpEvent: TimestampedPumpEvent { - public let length: Int - public let rawData: Data - public let timestamp: DateComponents - public let alarmType: PumpAlarmType - - public init?(availableData: Data, pumpModel: PumpModel) { - length = 9 - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. Bool { - // Delays only occur for bolus events - guard let bolus = self as? BolusNormalPumpEvent else { - return false - } - - // All normal bolus events are delayed - guard bolus.type == .square else { - return true - } - - // Square-wave bolus events are delayed for certain pump models - return !pumpModel.appendsSquareWaveToHistoryOnStartOfDelivery - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpEvents/RestoreMystery54PumpEvent.swift b/Dependencies/MinimedKit/MinimedKit/PumpEvents/RestoreMystery54PumpEvent.swift deleted file mode 100644 index 4c698addc..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpEvents/RestoreMystery54PumpEvent.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// RestoreMystery54PumpEvent.swift -// RileyLink -// -// Created by Pete Schwamb on 8/29/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct RestoreMystery54PumpEvent: TimestampedPumpEvent { - public let length: Int - public let rawData: Data - public let timestamp: DateComponents - - public init?(availableData: Data, pumpModel: PumpModel) { - length = 64 - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0..> 3) == 0 ? .Absolute : .Percent - if rateType == .Absolute { - rate = Double(((d(7) & 0b111) << 8) + d(1)) / 40.0 - } else { - rate = Double(d(1)) - } - - timestamp = DateComponents(pumpEventData: availableData, offset: 2) - - wasRemotelyTriggered = availableData[5] & 0b01000000 != 0 - } - - public var dictionaryRepresentation: [String: Any] { - return [ - "_type": "TempBasal", - "rate": rate, - "temp": rateType.rawValue, - "wasRemotelyTriggered": wasRemotelyTriggered, - ] - } - - public var description: String { - switch rateType { - case .Absolute: - return String(format: LocalizedString("Temporary Basal: %1$.3f U/hour", comment: "The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes)"), rate) - case .Percent: - return String(format: LocalizedString("Temporary Basal: %1$d%%", comment: "The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent)"), Int(rate)) - } - } -} - diff --git a/Dependencies/MinimedKit/MinimedKit/PumpEvents/TimestampedPumpEvent.swift b/Dependencies/MinimedKit/MinimedKit/PumpEvents/TimestampedPumpEvent.swift deleted file mode 100644 index 5a711053a..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpEvents/TimestampedPumpEvent.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// TimestampedPumpEvent.swift -// RileyLink -// -// Created by Pete Schwamb on 3/8/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public protocol TimestampedPumpEvent: PumpEvent { - - var timestamp: DateComponents { - get - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpEvents/UnabsorbedInsulinPumpEvent.swift b/Dependencies/MinimedKit/MinimedKit/PumpEvents/UnabsorbedInsulinPumpEvent.swift deleted file mode 100644 index ed96c8749..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpEvents/UnabsorbedInsulinPumpEvent.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// UnabsorbedInsulinPumpEvent.swift -// RileyLink -// -// Created by Pete Schwamb on 3/7/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct UnabsorbedInsulinPumpEvent: PumpEvent { - - public struct Record : DictionaryRepresentable { - var amount: Double - var age: Int - - init(amount: Double, age: Int) { - self.amount = amount - self.age = age - } - - public var dictionaryRepresentation: [String: Any] { - return [ - "amount": amount, - "age": age, - ] - } - } - - public let length: Int - public let rawData: Data - - public let records: [Record] - - public init?(availableData: Data, pumpModel: PumpModel) { - length = Int(max(availableData[1], 2)) - var records = [Record]() - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. Int { - return Int(availableData[idx]) - } - - let numRecords = (d(1) - 2) / 3 - - for idx in 0.. [String: Any] in - return r.dictionaryRepresentation - }), - ] - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpEvents/UnknownPumpEvent57.swift b/Dependencies/MinimedKit/MinimedKit/PumpEvents/UnknownPumpEvent57.swift deleted file mode 100644 index 08e65a89a..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpEvents/UnknownPumpEvent57.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// UnknownPumpEvent57.swift -// MinimedKit -// -// Created by Pete Schwamb on 8/11/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct UnknownPumpEvent57: TimestampedPumpEvent { - public let length: Int - public let rawData: Data - public let timestamp: DateComponents - - public init?(availableData: Data, pumpModel: PumpModel) { - length = 10 - - guard length <= availableData.count else { - return nil - } - - rawData = availableData.subdata(in: 0.. [NewPumpEvent] { - var events: [NewPumpEvent] = [] - var lastTempBasal: DoseEntry? - var lastSuspend: DoseEntry? - // Always assume the sequence may have started rewound. LoopKit will ignore unmatched resume events. - var isRewound = true - var title: String - let now = Date() - - for event in self { - var dose: DoseEntry? - var eventType: LoopKit.PumpEventType? - - title = String(describing: type(of: event.pumpEvent)) - - switch event.pumpEvent { - case let bolus as BolusNormalPumpEvent: - title = LocalizedString("Bolus", comment: "Event title for bolus") - let bolusEndDate: Date - if let lastSuspend = lastSuspend, bolus.programmed != bolus.amount, lastSuspend.startDate > event.date { - bolusEndDate = lastSuspend.startDate - } else if bolus.duration > 0 { - bolusEndDate = event.date.addingTimeInterval(bolus.duration) - } else { - bolusEndDate = event.date.addingTimeInterval(model.bolusDeliveryTime(units: bolus.amount)) - } - var automatic: Bool? - if !bolus.wasRemotelyTriggered { - automatic = false - } - dose = DoseEntry(type: .bolus, startDate: event.date, endDate: bolusEndDate, value: bolus.programmed, unit: .units, deliveredUnits: bolus.amount, automatic: automatic, isMutable: bolus.isMutable(atDate: now, forPump: model), wasProgrammedByPumpUI: !bolus.wasRemotelyTriggered) - case let suspendEvent as SuspendPumpEvent: - title = LocalizedString("Suspend", comment: "Event title for suspend") - dose = DoseEntry(suspendDate: event.date, wasProgrammedByPumpUI: !suspendEvent.wasRemotelyTriggered) - lastSuspend = dose - case let resumeEvent as ResumePumpEvent: - title = LocalizedString("Resume", comment: "Event title for resume") - dose = DoseEntry(resumeDate: event.date, wasProgrammedByPumpUI: !resumeEvent.wasRemotelyTriggered) - case let temp as TempBasalPumpEvent: - if case .Absolute = temp.rateType { - lastTempBasal = DoseEntry(type: .tempBasal, startDate: event.date, value: temp.rate, unit: .unitsPerHour, isMutable: false, wasProgrammedByPumpUI: !temp.wasRemotelyTriggered) - continue - } else { - title = LocalizedString("Percent Temp Basal", comment: "Event title for percent based temp basal") - } - case let tempDuration as TempBasalDurationPumpEvent: - if let lastTemp = lastTempBasal, lastTemp.startDate == event.date { - if tempDuration.duration == 0 { - title = LocalizedString("Cancel Temp Basal", comment: "Event title for temp basal cancel") - } else { - title = LocalizedString("Temp Basal", comment: "Event title for temporary basal rate start") - } - - // Temp basal events in mdt pump history are not mutable, but we report mutability to Loop as - // indicating whether we will be mutating this DoseEntry in the future, and until this TempBasal - // Is finished or canceled it is still mutable. - - let endDate = event.date.addingTimeInterval(TimeInterval(minutes: Double(tempDuration.duration))) - let isMutable = endDate < now - - dose = DoseEntry( - type: .tempBasal, - startDate: event.date, - endDate: endDate, - value: lastTemp.unitsPerHour, - unit: .unitsPerHour, - automatic: false, // If this was automatic dose, it should be set as such during reconciliation - isMutable: isMutable, - wasProgrammedByPumpUI: lastTemp.wasProgrammedByPumpUI - ) - } - case let basal as BasalProfileStartPumpEvent: - title = LocalizedString("Scheduled Basal", comment: "Event title for starting scheduled basal") - dose = DoseEntry( - type: .basal, - startDate: event.date, - // Use the maximum-possible duration for a basal entry; its true duration will be reconciled against other entries. - endDate: event.date.addingTimeInterval(.hours(24)), - value: basal.scheduleEntry.rate, - unit: .unitsPerHour, - isMutable: false - ) - case is RewindPumpEvent: - title = LocalizedString("Rewind", comment: "Event title for rewind") - eventType = .rewind - - /* - No insulin is delivered between the beginning of a rewind until the suggested fixed prime is delivered or cancelled. - - If the fixed prime is cancelled, it is never recorded in history. It is possible to cancel a fixed prime and perform one manually some time later, but basal delivery will have resumed during that period. - - We take the conservative approach and assume delivery is paused only between the Rewind and the first Prime event. - */ - dose = DoseEntry(suspendDate: event.date) - isRewound = true - case is PrimePumpEvent: - title = LocalizedString("Prime", comment: "Event title for prime pump event") - eventType = .prime - - if isRewound { - isRewound = false - dose = DoseEntry(resumeDate: event.date) - } - case let alarm as PumpAlarmPumpEvent: - title = alarm.alarmType.localizedString - eventType = .alarm - - if case .noDelivery = alarm.alarmType { - dose = DoseEntry(suspendDate: event.date) - } - break - case let alarm as ClearAlarmPumpEvent: - title = LocalizedString("Clear Alarm", comment: "Event title for clear alarm pump event") - eventType = .alarmClear - - if case .noDelivery = alarm.alarmType { - dose = DoseEntry(resumeDate: event.date) - } - break - case is JournalEntryMealMarkerPumpEvent: - title = LocalizedString("Meal", comment: "Event title for JournalEntryMealMarkerPumpEvent") - break - case is JournalEntryPumpLowBatteryPumpEvent: - title = LocalizedString("Low Battery", comment: "Event title for JournalEntryPumpLowBatteryPumpEvent") - break - case is JournalEntryPumpLowReservoirPumpEvent: - title = LocalizedString("Low Reservoir", comment: "Event title for JournalEntryPumpLowReservoirPumpEvent") - break - case is ChangeBasalProfilePumpEvent: - title = LocalizedString("Change Basal Schedule", comment: "Event title for ChangeBasalProfilePumpEvent") - break - case is ChangeBasalProfilePatternPumpEvent: - title = LocalizedString("Change Basal Profile Schedule", comment: "Event title for ChangeBasalProfilePatternPumpEvent") - break - case is SelectBasalProfilePumpEvent: - title = LocalizedString("Select Profile", comment: "Event title for SelectBasalProfilePumpEvent") - break - case is ChangeTimePumpEvent: - title = LocalizedString("Change Time", comment: "Event title for ChangeTimePumpEvent") - break - case is NewTimePumpEvent: - title = LocalizedString("New Time", comment: "Event title for NewTimePumpEvent") - break - default: - break - } - - events.append(NewPumpEvent(date: event.date, dose: dose, raw: event.pumpEvent.rawData, title: title, type: eventType)) - } - - return events - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/EnliteSensorDisplayable.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/EnliteSensorDisplayable.swift deleted file mode 100644 index c567b1143..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/EnliteSensorDisplayable.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// EnliteSensorDisplayable.swift -// Loop -// -// Created by Timothy Mecklem on 12/28/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation -import HealthKit -import LoopKit - - -struct EnliteSensorDisplayable: Equatable, GlucoseDisplayable { - public let isStateValid: Bool - public let trendType: LoopKit.GlucoseTrend? - public let trendRate: HKQuantity? - public let isLocal: Bool - - // TODO Placeholder. This functionality will come with LOOP-1311 - var glucoseRangeCategory: GlucoseRangeCategory? { - return nil - } - - var glucoseCondition: GlucoseCondition? { - return nil - } - - public init(_ event: MinimedKit.RelativeTimestampedGlucoseEvent) { - isStateValid = event.isStateValid - trendType = event.trendType - trendRate = event.trendRate - isLocal = event.isLocal - } - - public init(_ status: MySentryPumpStatusMessageBody) { - isStateValid = status.isStateValid - trendType = status.trendType - trendRate = nil - isLocal = status.isLocal - } -} - -extension MinimedKit.RelativeTimestampedGlucoseEvent { - var isStateValid: Bool { - return self is SensorValueGlucoseEvent - } - - var trendType: LoopKit.GlucoseTrend? { - return nil - } - - var trendRate: HKQuantity? { - return nil - } - - var isLocal: Bool { - return true - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/HistoryPage+PumpOpsSession.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/HistoryPage+PumpOpsSession.swift deleted file mode 100644 index 69fbc934f..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/HistoryPage+PumpOpsSession.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// HistoryPage+PumpOpsSession.swift -// RileyLinkKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - - -extension HistoryPage { - /// Returns TimestampedHistoryEvents from this page occuring after a given date - /// - /// - Parameters: - /// - start: The date to filter events occuring on or after - /// - timeZone: The current time zone offset of the pump - /// - model: The pump model - /// - Returns: A tuple containing: - /// - events: The matching events - /// - hasMoreEvents: Whether the next page likely contains events after the specified start date - /// - cancelledEarly: - func timestampedEvents(after start: Date, timeZone: TimeZone, model: PumpModel) -> (events: [TimestampedHistoryEvent], hasMoreEvents: Bool, cancelledEarly: Bool) { - // Start with some time in the future, to account for the condition when the pump's clock is ahead - // of ours by a small amount. - var timeCursor = Date(timeIntervalSinceNow: TimeInterval(minutes: 60)) - var events = [TimestampedHistoryEvent]() - var timeAdjustmentInterval: TimeInterval = 0 - var seenEventData = Set() - var lastEvent: PumpEvent? - - for event in self.events.reversed() { - if let event = event as? TimestampedPumpEvent, !seenEventData.contains(event.rawData) { - seenEventData.insert(event.rawData) - - var timestamp = event.timestamp - timestamp.timeZone = timeZone - - if let changeTimeEvent = event as? ChangeTimePumpEvent, let newTimeEvent = lastEvent as? NewTimePumpEvent { - timeAdjustmentInterval += (newTimeEvent.timestamp.date?.timeIntervalSince(changeTimeEvent.timestamp.date!))! - } - - if let alarm = event as? PumpAlarmPumpEvent, alarm.alarmType.indicatesUnrecoverableClockIssue { - NSLog("Found device reset battery issue in history (%@). Ending history fetch.", String(describing: event)) - return (events: events, hasMoreEvents: false, cancelledEarly: true) - } - - if let date = timestamp.date?.addingTimeInterval(timeAdjustmentInterval) { - - let shouldCheckDateForCompletion = !event.isDelayedAppend(with: model) - - if shouldCheckDateForCompletion { - if date <= start { - // Success, we have all the events we need - //NSLog("Found event at or before startDate(%@)", date as NSDate, String(describing: eventTimestampDeltaAllowance), startDate as NSDate) - return (events: events, hasMoreEvents: false, cancelledEarly: false) - } else if date.timeIntervalSince(timeCursor) > TimeInterval(minutes: 60) { - // Appears that pump lost time; we can't build up a valid timeline from this point back. - // TODO: Convert logging - NSLog("Found event (%@) out of order in history. Ending history fetch.", date as NSDate) - return (events: events, hasMoreEvents: false, cancelledEarly: true) - } - - timeCursor = date - } - - events.insert(TimestampedHistoryEvent(pumpEvent: event, date: date), at: 0) - } - } - - lastEvent = event - } - - return (events: events, hasMoreEvents: true, cancelledEarly: false) - } -} - -extension PumpAlarmType { - var indicatesUnrecoverableClockIssue: Bool { - switch self { - case .deviceResetBatteryIssue17, .deviceResetBatteryIssue21: - return true - default: - return false - } - - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/InsulinDataSource.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/InsulinDataSource.swift deleted file mode 100644 index 68122c3cf..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/InsulinDataSource.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// InsulinDataSource.swift -// Loop -// -// Created by Nathan Racklyeft on 6/10/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -public enum InsulinDataSource: Int, CustomStringConvertible, CaseIterable { - case pumpHistory = 0 - case reservoir - - public var description: String { - switch self { - case .pumpHistory: - return LocalizedString("Event History", comment: "Describing the pump history insulin data source") - case .reservoir: - return LocalizedString("Reservoir", comment: "Describing the reservoir insulin data source") - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedDoseProgressEstimator.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedDoseProgressEstimator.swift deleted file mode 100644 index 1eb756582..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedDoseProgressEstimator.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// MinimedDoseProgressEstimator.swift -// MinimedKit -// -// Created by Pete Schwamb on 3/14/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -class MinimedDoseProgressEstimator: DoseProgressTimerEstimator { - - let dose: DoseEntry - - public let pumpModel: PumpModel - - override var progress: DoseProgress { - let elapsed = -dose.startDate.timeIntervalSinceNow - - let (deliveredUnits, progress) = pumpModel.estimateBolusProgress(elapsed: elapsed, programmedUnits: dose.programmedUnits) - - return DoseProgress(deliveredUnits: deliveredUnits, percentComplete: progress) - } - - init(dose: DoseEntry, pumpModel: PumpModel, reportingQueue: DispatchQueue) { - self.dose = dose - self.pumpModel = pumpModel - super.init(reportingQueue: reportingQueue) - } - - override func timerParameters() -> (delay: TimeInterval, repeating: TimeInterval) { - let timeSinceStart = -dose.startDate.timeIntervalSinceNow - let duration = dose.endDate.timeIntervalSince(dose.startDate) - let timeBetweenPulses = duration / (Double(pumpModel.pulsesPerUnit) * dose.programmedUnits) - - let delayUntilNextPulse = timeBetweenPulses - timeSinceStart.remainder(dividingBy: timeBetweenPulses) - - return (delay: delayUntilNextPulse, repeating: timeBetweenPulses) - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpManager.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpManager.swift deleted file mode 100644 index c0eccb8fb..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpManager.swift +++ /dev/null @@ -1,1606 +0,0 @@ -// -// MinimedPumpManager.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import HealthKit -import LoopKit -import RileyLinkKit -import RileyLinkBLEKit -import os.log - -public protocol MinimedPumpManagerStateObserver: AnyObject { - func didUpdatePumpManagerState(_ state: MinimedPumpManagerState) -} - -public class MinimedPumpManager: RileyLinkPumpManager { - - public static let managerIdentifier = "Minimed500" - - // Primarily used for testing - public let dateGenerator: () -> Date - - public var managerIdentifier: String { - return MinimedPumpManager.managerIdentifier - } - - public init(state: MinimedPumpManagerState, rileyLinkDeviceProvider: RileyLinkDeviceProvider, pumpOps: PumpOps? = nil, dateGenerator: @escaping () -> Date = Date.init) { - self.lockedState = Locked(state) - - self.dateGenerator = dateGenerator - - self.hkDevice = HKDevice( - name: MinimedPumpManager.managerIdentifier, - manufacturer: "Medtronic", - model: state.pumpModel.rawValue, - hardwareVersion: nil, - firmwareVersion: state.pumpFirmwareVersion, - softwareVersion: String(MinimedKitVersionNumber), - localIdentifier: state.pumpID, - udiDeviceIdentifier: nil - ) - - super.init(rileyLinkDeviceProvider: rileyLinkDeviceProvider) - - // Pump communication - let idleListeningEnabled = state.pumpModel.hasMySentry && state.useMySentry - - self.pumpOps = pumpOps ?? MinimedPumpOps(pumpSettings: state.pumpSettings, pumpState: state.pumpState, delegate: self) - - self.rileyLinkDeviceProvider.idleListeningState = idleListeningEnabled ? MinimedPumpManagerState.idleListeningEnabledDefaults : .disabled - } - - public required convenience init?(rawState: PumpManager.RawStateValue) { - guard let state = MinimedPumpManagerState(rawValue: rawState), - let connectionManagerState = state.rileyLinkConnectionState else - { - return nil - } - - let deviceProvider = RileyLinkBluetoothDeviceProvider(autoConnectIDs: connectionManagerState.autoConnectIDs) - - self.init(state: state, rileyLinkDeviceProvider: deviceProvider) - - deviceProvider.delegate = self - } - - public private(set) var pumpOps: PumpOps! - - // We issue notifications at 30, 20, and 10. Indicators turn warning color at 30. - public let lowReservoirWarningLevel = 30.0 - - // MARK: - PumpManager - - public let stateObservers = WeakSynchronizedSet() - - public var state: MinimedPumpManagerState { - return lockedState.value - } - private let lockedState: Locked - - private func setState(_ changes: (_ state: inout MinimedPumpManagerState) -> Void) -> Void { - return setStateWithResult(changes) - } - - private func mutateState(_ changes: (_ state: inout MinimedPumpManagerState) -> Void) -> MinimedPumpManagerState { - return setStateWithResult({ (state) -> MinimedPumpManagerState in - changes(&state) - return state - }) - } - - private func setStateWithResult(_ changes: (_ state: inout MinimedPumpManagerState) -> ReturnType) -> ReturnType { - var oldValue: MinimedPumpManagerState! - var returnValue: ReturnType! - let newValue = lockedState.mutate { (state) in - oldValue = state - returnValue = changes(&state) - } - - guard oldValue != newValue else { - return returnValue - } - - let recents = self.recents - let oldStatus = status(for: oldValue, recents: recents) - let newStatus = status(for: newValue, recents: recents) - - // PumpManagerStatus may have changed - if oldStatus != newStatus - { - notifyStatusObservers(oldStatus: oldStatus) - } - - pumpDelegate.notify { (delegate) in - delegate?.pumpManagerDidUpdateState(self) - } - stateObservers.forEach { (observer) in - observer.didUpdatePumpManagerState(newValue) - } - return returnValue - } - - - /// Temporal state of the manager - public var recents: MinimedPumpManagerRecents { - get { - return lockedRecents.value - } - set { - let oldValue = recents - let oldStatus = status - lockedRecents.value = newValue - - // Battery percentage may have changed - if oldValue.latestPumpStatusFromMySentry != newValue.latestPumpStatusFromMySentry || - oldValue.latestPumpStatus != newValue.latestPumpStatus - { - let oldBatteryPercentage = state.batteryPercentage - let newBatteryPercentage: Double? - - // Persist the updated battery level - if let status = newValue.latestPumpStatusFromMySentry { - newBatteryPercentage = Double(status.batteryRemainingPercent) / 100 - } else if let status = newValue.latestPumpStatus { - newBatteryPercentage = batteryChemistry.chargeRemaining(at: status.batteryVolts) - } else { - newBatteryPercentage = nil - } - - self.setState({ (state) in - if oldBatteryPercentage != newBatteryPercentage { - state.batteryPercentage = newBatteryPercentage - checkPumpBattery(oldBatteryPercentage: oldBatteryPercentage, newBatteryPercentage: newBatteryPercentage) - } - - if let status = newValue.latestPumpStatus { - if case .resumed = state.suspendState, status.suspended { - state.suspendState = .suspended(dateGenerator()) - } - if case .suspended = state.suspendState, !status.suspended { - state.suspendState = .resumed(dateGenerator()) - } - } - }) - } - if oldStatus != status { - notifyStatusObservers(oldStatus: oldStatus) - } - } - } - private let lockedRecents = Locked(MinimedPumpManagerRecents()) - - private let statusObservers = WeakSynchronizedSet() - - private func notifyStatusObservers(oldStatus: PumpManagerStatus) { - let status = self.status - pumpDelegate.notify { (delegate) in - delegate?.pumpManager(self, didUpdate: status, oldStatus: oldStatus) - } - statusObservers.forEach { (observer) in - observer.pumpManager(self, didUpdate: status, oldStatus: oldStatus) - } - } - - private func logDeviceCommunication(_ message: String, type: DeviceLogEntryType = .send) { - // Not dispatching here; if delegate queue is blocked, timestamps will be delayed - self.pumpDelegate.delegate?.deviceManager(self, logEventForDeviceIdentifier: state.pumpID, type: type, message: message, completion: nil) - } - - private let cgmDelegate = WeakSynchronizedDelegate() - private let pumpDelegate = WeakSynchronizedDelegate() - - public let log = OSLog(category: "MinimedPumpManager") - - // MARK: - CGMManager - - private let hkDevice: HKDevice - - // MARK: - RileyLink Updates - - override public var rileyLinkConnectionManagerState: RileyLinkConnectionState? { - get { - return state.rileyLinkConnectionState - } - set { - setState { (state) in - state.rileyLinkConnectionState = newValue - } - } - } - - override public func device(_ device: RileyLinkDevice, didReceivePacket packet: RFPacket) { - device.assertOnSessionQueue() - - guard let data = MinimedPacket(encodedData: packet.data)?.data, - let message = PumpMessage(rxData: data), - message.address.hexadecimalString == state.pumpID, - case .mySentry = message.packetType - else { - return - } - - logDeviceCommunication("MySentry \(String(describing: message))", type: .receive) - - switch message.messageBody { - case let body as MySentryPumpStatusMessageBody: - self.updatePumpStatus(body, from: device) - case let body as MySentryAlertMessageBody: - self.log.default("MySentry Alert: %{public}@", String(describing: body)) - case let body as MySentryAlertClearedMessageBody: - self.log.default("MySentry Alert Cleared: %{public}@", String(describing: body)) - break - default: - self.log.error("Unknown MySentry Message: %d: %{public}@", message.messageType.rawValue, message.txData.hexadecimalString) - } - } - - override public func deviceTimerDidTick(_ device: RileyLinkDevice) { - pumpDelegate.notify { (delegate) in - delegate?.pumpManagerBLEHeartbeatDidFire(self) - } - } - - public var rileyLinkBatteryAlertLevel: Int? { - get { - return state.rileyLinkBatteryAlertLevel - } - set { - setState { state in - state.rileyLinkBatteryAlertLevel = newValue - } - } - } - - public override func device(_ device: RileyLinkDevice, didUpdateBattery level: Int) { - let repeatInterval: TimeInterval = .hours(1) - - if let alertLevel = state.rileyLinkBatteryAlertLevel, - level <= alertLevel, - state.lastRileyLinkBatteryAlertDate.addingTimeInterval(repeatInterval) < dateGenerator() - { - self.setState { state in - state.lastRileyLinkBatteryAlertDate = dateGenerator() - } - self.pumpDelegate.notify { delegate in - let identifier = Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: "lowRLBattery") - let alertBody = String(format: LocalizedString("\"%1$@\" has a low battery", comment: "Format string for low battery alert body for RileyLink. (1: device name)"), device.name ?? "unnamed") - let content = Alert.Content(title: LocalizedString("Low RileyLink Battery", comment: "Title for RileyLink low battery alert"), body: alertBody, acknowledgeActionButtonLabel: LocalizedString("OK", comment: "Acknowledge button label for RileyLink low battery alert")) - delegate?.issueAlert(Alert(identifier: identifier, foregroundContent: content, backgroundContent: content, trigger: .immediate)) - } - } - } - - // MARK: - CustomDebugStringConvertible - - override public var debugDescription: String { - return [ - "## MinimedPumpManager", - "isPumpDataStale: \(isPumpDataStale)", - "pumpOps: \(String(reflecting: pumpOps))", - "recents: \(String(reflecting: recents))", - "state: \(String(reflecting: state))", - "status: \(String(describing: status))", - "stateObservers.count: \(stateObservers.cleanupDeallocatedElements().count)", - "statusObservers.count: \(statusObservers.cleanupDeallocatedElements().count)", - super.debugDescription, - ].joined(separator: "\n") - } -} - -extension MinimedPumpManager { - /** - Attempts to fix an extended communication failure between a RileyLink device and the pump - - - parameter device: The RileyLink device - */ - private func troubleshootPumpComms(using device: RileyLinkDevice) { - device.assertOnSessionQueue() - - // Ensuring timer tick is enabled will allow more tries to bring the pump data up-to-date. - updateBLEHeartbeatPreference() - - // How long we should wait before we re-tune the RileyLink - let tuneTolerance = TimeInterval(minutes: 14) - - let lastTuned = state.lastTuned ?? .distantPast - - if lastTuned.timeIntervalSinceNow <= -tuneTolerance { - pumpOps.runSession(withName: "Tune pump", using: device) { (session) in - do { - let scanResult = try session.tuneRadio(attempts: 1) - self.log.default("Device %{public}@ auto-tuned to %{public}@ MHz", device.name ?? "", String(describing: scanResult.bestFrequency)) - } catch let error { - self.log.error("Device %{public}@ auto-tune failed with error: %{public}@", device.name ?? "", String(describing: error)) - self.rileyLinkDeviceProvider.deprioritize(device, completion: nil) - if let error = error as? LocalizedError { - self.pumpDelegate.notify { (delegate) in - delegate?.pumpManager(self, didError: PumpManagerError.communication(MinimedPumpManagerError.tuneFailed(error))) - } - } - } - } - } else { - rileyLinkDeviceProvider.deprioritize(device, completion: nil) - } - } - - /// - Throws: `PumpCommandError` specifying the failure sequence - private func runSuspendResumeOnSession(suspendResumeState: SuspendResumeMessageBody.SuspendResumeState, session: PumpOpsSession, insulinType: InsulinType) throws { - - defer { self.recents.suspendEngageState = .stable } - self.recents.suspendEngageState = suspendResumeState == .suspend ? .engaging : .disengaging - - try session.setSuspendResumeState(suspendResumeState) - - setState { (state) in - let date = dateGenerator() - switch suspendResumeState { - case .suspend: - state.suspendState = .suspended(date) - case .resume: - state.suspendState = .resumed(date) - } - - if suspendResumeState == .suspend { - let pumpModel = state.pumpModel - state.unfinalizedBolus?.cancel(at: dateGenerator(), pumpModel: pumpModel) - if let bolus = state.unfinalizedBolus { - state.pendingDoses.append(bolus) - } - state.unfinalizedBolus = nil - - state.pendingDoses.append(UnfinalizedDose(suspendStartTime: dateGenerator())) - } else { - state.pendingDoses.append(UnfinalizedDose(resumeStartTime: dateGenerator(), insulinType: insulinType)) - } - } - } - - private func setSuspendResumeState(state: SuspendResumeMessageBody.SuspendResumeState, insulinType: InsulinType, completion: @escaping (MinimedPumpManagerError?) -> Void) { - rileyLinkDeviceProvider.getDevices { (devices) in - guard let device = devices.firstConnected else { - completion(MinimedPumpManagerError.noRileyLink) - return - } - - let sessionName: String = { - switch state { - case .suspend: - return "Suspend Delivery" - case .resume: - return "Resume Delivery" - } - }() - - self.pumpOps.runSession(withName: sessionName, using: device) { (session) in - do { - try self.runSuspendResumeOnSession(suspendResumeState: state, session: session, insulinType: insulinType) - self.storePendingPumpEvents({ (error) in - completion(error) - }) - } catch let error { - self.troubleshootPumpComms(using: device) - completion(MinimedPumpManagerError.commsError(error as! PumpCommandError)) - } - } - } - } - - /** - Handles receiving a MySentry status message, which are only posted by MM x23 pumps. - - This message has two important pieces of info about the pump: reservoir volume and battery. - - Because the RileyLink must actively listen for these packets, they are not a reliable heartbeat. However, we can still use them to assert glucose data is current. - - - parameter status: The status message body - - parameter device: The RileyLink that received the message - */ - private func updatePumpStatus(_ status: MySentryPumpStatusMessageBody, from device: RileyLinkDevice) { - device.assertOnSessionQueue() - - log.default("MySentry message received") - - var pumpDateComponents = status.pumpDateComponents - var glucoseDateComponents = status.glucoseDateComponents - - let timeZone = state.timeZone - pumpDateComponents.timeZone = timeZone - glucoseDateComponents?.timeZone = timeZone - - checkRileyLinkBattery() - - // The pump sends the same message 3x, so ignore it if we've already seen it. - guard status != recents.latestPumpStatusFromMySentry, let pumpDate = pumpDateComponents.date else { - return - } - - // Ignore status messages without some semblance of recency. - guard abs(pumpDate.timeIntervalSinceNow) < .minutes(5) else { - log.error("Ignored MySentry status due to date mismatch: %{public}@ in %{public}", String(describing: pumpDate), String(describing: timeZone)) - return - } - - recents.latestPumpStatusFromMySentry = status - - switch status.glucose { - case .active(glucose: let glucose): - // Enlite data is included - if let date = glucoseDateComponents?.date { - let sample = NewGlucoseSample( - date: date, - quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: Double(glucose)), - condition: nil, - trend: status.glucoseTrend.loopKitGlucoseTrend, - trendRate: nil, - isDisplayOnly: false, - wasUserEntered: false, - syncIdentifier: status.glucoseSyncIdentifier ?? UUID().uuidString, - device: self.device - ) - - cgmDelegate.notify { (delegate) in - delegate?.cgmManager(self, hasNew: .newData([sample])) - } - } - case .off: - // Enlite is disabled, so assert glucose from another source - pumpDelegate.notify { (delegate) in - delegate?.pumpManagerBLEHeartbeatDidFire(self) - } - default: - // Anything else is an Enlite error - // TODO: Provide info about status.glucose - cgmDelegate.notify { (delegate) in - delegate?.cgmManager(self, hasNew: .error(PumpManagerError.deviceState(nil))) - } - } - - // Sentry packets are sent in groups of 3, 5s apart. Wait 11s before allowing the loop data to continue to avoid conflicting comms. - device.sessionQueueAsyncAfter(deadline: .now() + .seconds(11)) { [weak self] in - self?.refreshPumpData { _ in } - } - } - - public func buildPumpStatusHighlight(for state: MinimedPumpManagerState, recents: MinimedPumpManagerRecents, andDate date: Date) -> PumpStatusHighlight? { - - if case .suspended = state.suspendState { - return PumpStatusHighlight( - localizedMessage: LocalizedString("Insulin Suspended", comment: "Status highlight that insulin delivery was suspended."), - imageName: "pause.circle.fill", - state: .warning) - } - - if date.timeIntervalSince(lastSync(for: state, recents: recents) ?? .distantPast) > .minutes(12) { - return PumpStatusHighlight( - localizedMessage: LocalizedString("Signal Loss", comment: "Status highlight when communications with the pod haven't happened recently."), - imageName: "exclamationmark.circle.fill", - state: .critical) - } - return nil - } - - - private func checkRileyLinkBattery() { - rileyLinkDeviceProvider.getDevices { devices in - for device in devices { - device.updateBatteryLevel() - } - } - } - - private static var pumpBatteryLowAlertIdentifier: Alert.Identifier { - return Alert.Identifier(managerIdentifier: managerIdentifier, alertIdentifier: "PumpBatteryLow") - } - - private var pumpBatteryLowAlert: Alert { - let title = LocalizedString("Pump Battery Low", comment: "The notification title for a low pump battery") - let body = LocalizedString("Change the pump battery immediately", comment: "The notification alert describing a low pump battery") - let content = Alert.Content(title: title, body: body, acknowledgeActionButtonLabel: LocalizedString("Dismiss", comment: "Default alert dismissal")) - return Alert(identifier: Self.pumpBatteryLowAlertIdentifier, foregroundContent: content, backgroundContent: content, trigger: .immediate) - } - - private var batteryReplacementDetectionThreshold: Double { 0.5 } - - private func checkPumpBattery(oldBatteryPercentage: Double?, newBatteryPercentage: Double?) { - guard let newBatteryPercentage = newBatteryPercentage else { - return - } - if oldBatteryPercentage != newBatteryPercentage, newBatteryPercentage == 0 { - pumpDelegate.notify { (delegate) in - delegate?.issueAlert(self.pumpBatteryLowAlert) - } - } - - if let oldBatteryPercentage = oldBatteryPercentage, newBatteryPercentage - oldBatteryPercentage >= batteryReplacementDetectionThreshold { - pumpDelegate.notify { (delegate) in - delegate?.retractAlert(identifier: Self.pumpBatteryLowAlertIdentifier) - } - } - } - - /** - Store a new reservoir volume and notify observers of new pump data. - - - parameter units: The number of units remaining - - parameter date: The date the reservoir was read - - parameter completion: completion handler - */ - private func updateReservoirVolume(_ units: Double, at date: Date, completion: @escaping (Result) -> Void) { - // Must be called from the sessionQueue - - setState { (state) in - state.lastReservoirReading = ReservoirReading(units: units, validAt: date) - } - - pumpDelegate.notify { (delegate) in - delegate?.pumpManager(self, didReadReservoirValue: units, at: date) { (result) in - switch result { - case .failure(let error): - completion(.failure(error)) - break - case .success(let (newValue, lastValue, areStoredValuesContinuous)): - self.evaluateReservoirAlerts(lastValue: lastValue, newValue: newValue, areStoredValuesContinuous: areStoredValuesContinuous) - - if areStoredValuesContinuous { - self.recents.lastContinuousReservoir = date - } - completion(.success(areStoredValuesContinuous)) - } - } - } - - // New reservoir data means we may want to adjust our timer tick requirements - updateBLEHeartbeatPreference() - } - - private static var pumpReservoirEmptyAlertIdentifier: Alert.Identifier { - return Alert.Identifier(managerIdentifier: managerIdentifier, alertIdentifier: "PumpReservoirEmpty") - } - - private var pumpReservoirEmptyAlert: Alert { - let title = LocalizedString("Pump Reservoir Empty", comment: "The notification title for an empty pump reservoir") - let body = LocalizedString("Change the pump reservoir now", comment: "The notification alert describing an empty pump reservoir") - let content = Alert.Content(title: title, body: body, acknowledgeActionButtonLabel: LocalizedString("Ok", comment: "Default alert dismissal")) - return Alert(identifier: Self.pumpReservoirEmptyAlertIdentifier, foregroundContent: content, backgroundContent: content, trigger: .immediate) - } - - private static var pumpReservoirLowAlertIdentifier: Alert.Identifier { - return Alert.Identifier(managerIdentifier: managerIdentifier, alertIdentifier: "PumpReservoirLow") - } - - private func pumpReservoirLowAlertForAmount(_ units: Double, andTimeRemaining remaining: TimeInterval?) -> Alert { - let title = LocalizedString("Pump Reservoir Low", comment: "The notification title for a low pump reservoir") - - let unitsString = NumberFormatter.localizedString(from: NSNumber(value: units), number: .decimal) - - let intervalFormatter = DateComponentsFormatter() - intervalFormatter.allowedUnits = [.hour, .minute] - intervalFormatter.maximumUnitCount = 1 - intervalFormatter.unitsStyle = .full - intervalFormatter.includesApproximationPhrase = true - intervalFormatter.includesTimeRemainingPhrase = true - - let body: String - - if let remaining = remaining, let timeString = intervalFormatter.string(from: remaining) { - body = String(format: LocalizedString("%1$@ U left: %2$@", comment: "Low reservoir alert with time remaining format string. (1: Number of units remaining)(2: approximate time remaining)"), unitsString, timeString) - } else { - body = String(format: LocalizedString("%1$@ U left", comment: "Low reservoir alert format string. (1: Number of units remaining)"), unitsString) - } - - let content = Alert.Content(title: title, body: body, acknowledgeActionButtonLabel: LocalizedString("Ok", comment: "Default alert dismissal")) - return Alert(identifier: Self.pumpReservoirLowAlertIdentifier, foregroundContent: content, backgroundContent: content, trigger: .immediate) - } - - private func evaluateReservoirAlerts(lastValue: ReservoirValue?, newValue: ReservoirValue, areStoredValuesContinuous: Bool) { - // Send notifications for low reservoir if necessary - if let previousVolume = lastValue?.unitVolume { - guard newValue.unitVolume > 0 else { - pumpDelegate.notify { (delegate) in - delegate?.issueAlert(self.pumpReservoirEmptyAlert) - } - return - } - - let warningThresholds: [Double] = [10, 20, lowReservoirWarningLevel] - - for threshold in warningThresholds { - if newValue.unitVolume <= threshold && previousVolume > threshold { - pumpDelegate.notify { (delegate) in - delegate?.issueAlert(self.pumpReservoirLowAlertForAmount(newValue.unitVolume, andTimeRemaining: nil)) - } - break - } - } - - if newValue.unitVolume > previousVolume + 1 { - // TODO: report this as a pump event, or? //self.analyticsServicesManager.reservoirWasRewound() - - pumpDelegate.notify { (delegate) in - delegate?.retractAlert(identifier: Self.pumpReservoirLowAlertIdentifier) - } - } - } - } - - - static func reconcilePendingDosesWith(_ events: [NewPumpEvent], reconciliationMappings: [Data:ReconciledDoseMapping], pendingDoses: [UnfinalizedDose]) -> - (remainingEvents: [NewPumpEvent], reconciliationMappings: [Data:ReconciledDoseMapping], pendingDoses: [UnfinalizedDose]) { - - var newReconciliationMapping = reconciliationMappings - - var reconcilableEvents = events.filter { !newReconciliationMapping.keys.contains($0.raw) } - - // Pending doses can be matched to history events if start time difference is smaller than this - let matchingTimeWindow = TimeInterval(minutes: 1) - - func addReconciliationMapping(startTime: Date, uuid: UUID, eventRaw: Data, index: Int) -> Void { - let mapping = ReconciledDoseMapping(startTime: startTime, uuid: uuid, eventRaw: eventRaw) - newReconciliationMapping[eventRaw] = mapping - } - - // Reconcile any pending doses - let allPending = pendingDoses.map { (dose) -> UnfinalizedDose in - if let index = reconcilableEvents.firstMatchingIndex(for: dose, within: matchingTimeWindow) { - let historyEvent = reconcilableEvents[index] - addReconciliationMapping(startTime: dose.startTime, uuid: dose.uuid, eventRaw: historyEvent.raw, index: index) - var reconciledDose = dose - reconciledDose.reconcile(with: historyEvent) - reconcilableEvents.remove(at: index) - return reconciledDose - } - return dose - } - - // Remove reconciled events - let remainingPumpEvents = events.filter { (event) -> Bool in - return newReconciliationMapping[event.raw] == nil - } - - return (remainingEvents: remainingPumpEvents, reconciliationMappings: newReconciliationMapping, pendingDoses: allPending) - } - - private func reconcilePendingDosesWith(_ events: [NewPumpEvent], fetchedAt: Date) -> [NewPumpEvent] { - // Must be called from the sessionQueue - return setStateWithResult { (state) -> [NewPumpEvent] in - let allPending = (state.pendingDoses + [state.unfinalizedTempBasal, state.unfinalizedBolus]).compactMap({ $0 }) - let result = MinimedPumpManager.reconcilePendingDosesWith(events, reconciliationMappings: state.reconciliationMappings, pendingDoses: allPending) - state.lastReconciliation = dateGenerator() - - // Pending doses and reconciliation mappings will not be kept past this threshold - let expirationCutoff = dateGenerator().addingTimeInterval(.hours(-12)) - - state.reconciliationMappings = result.reconciliationMappings.filter { (key, value) -> Bool in - return value.startTime >= expirationCutoff - } - - state.unfinalizedBolus = nil - state.unfinalizedTempBasal = nil - state.pendingDoses = result.pendingDoses.filter { (dose) -> Bool in - if !dose.isFinished { - switch dose.doseType { - case .bolus: - state.unfinalizedBolus = dose - return false - case .tempBasal: - state.unfinalizedTempBasal = dose - return false - default: - break - } - } - - // If bolus should have ended more than a minute ago, and is not showing in pump history, remove it - if dose.doseType == .bolus, dose.finishTime < fetchedAt.addingTimeInterval(.minutes(-1)), !dose.isReconciledWithHistory { - log.default("Removing bolus that did not reconcile with history: %{public}@", String(describing: dose)) - return false - } - - return dose.startTime >= expirationCutoff - } - - if var runningTempBasal = state.unfinalizedTempBasal { - // Look for following temp basal cancel event in pump history - if let tempBasalCancellation = result.remainingEvents.first(where: { (event) -> Bool in - if let dose = event.dose, - dose.type == .tempBasal, - dose.startDate > runningTempBasal.startTime, - dose.startDate < runningTempBasal.finishTime, - dose.startDate.timeIntervalSince(dose.endDate) == 0 - { - return true - } - return false - }) { - runningTempBasal.cancel(at: tempBasalCancellation.date, pumpModel: state.pumpModel) - state.unfinalizedTempBasal = runningTempBasal - state.suspendState = .resumed(tempBasalCancellation.date) - } - } - return result.remainingEvents - } - } - - /// Polls the pump for new history events and passes them to the loop manager - /// - /// - Parameters: - /// - completion: A closure called once upon completion - /// - error: An error describing why the fetch and/or store failed - private func fetchPumpHistory(_ completion: @escaping (_ error: Error?) -> Void) { - guard let insulinType = insulinType else { - completion(PumpManagerError.configuration(MinimedPumpManagerError.insulinTypeNotConfigured)) - return - } - - rileyLinkDeviceProvider.getDevices { (devices) in - guard let device = devices.firstConnected else { - completion(PumpManagerError.connection(MinimedPumpManagerError.noRileyLink)) - return - } - - self.pumpOps.runSession(withName: "Fetch Pump History", using: device) { (session) in - do { - guard let startDate = self.pumpDelegate.call({ (delegate) in - return delegate?.startDateToFilterNewPumpEvents(for: self) - }) else { - preconditionFailure("pumpManagerDelegate cannot be nil") - } - - // Include events up to a minute before startDate, since pump event time and pending event time might be off - self.log.default("Fetching history since %{public}@", String(describing: startDate.addingTimeInterval(.minutes(-1)))) - let (historyEvents, model) = try session.getHistoryEvents(since: startDate.addingTimeInterval(.minutes(-1))) - - // Reconcile history with pending doses - let newPumpEvents = historyEvents.pumpEvents(from: model) - - // During reconciliation, some pump events may be reconciled as pending doses and removed. Remaining events should be annotated with current insulinType - let remainingHistoryEvents = self.reconcilePendingDosesWith(newPumpEvents, fetchedAt: self.dateGenerator()).map { (event) -> NewPumpEvent in - return NewPumpEvent( - date: event.date, - dose: event.dose?.annotated(with: insulinType), - raw: event.raw, - title: event.title, - type: event.type) - } - - self.pumpDelegate.notify({ (delegate) in - guard let delegate = delegate else { - preconditionFailure("pumpManagerDelegate cannot be nil") - } - - let pendingEvents = (self.state.pendingDoses + [self.state.unfinalizedBolus, self.state.unfinalizedTempBasal]).compactMap({ $0?.newPumpEvent() }) - - self.log.default("Reporting new pump events: %{public}@", String(describing: remainingHistoryEvents + pendingEvents)) - - delegate.pumpManager(self, hasNewPumpEvents: remainingHistoryEvents + pendingEvents, lastReconciliation: self.state.lastReconciliation, completion: { (error) in - // Called on an unknown queue by the delegate - if error == nil { - self.recents.lastAddedPumpEvents = self.dateGenerator() - self.setState({ (state) in - // Remove any pending doses that have been reconciled and are finished - if let bolus = state.unfinalizedBolus, bolus.isReconciledWithHistory, bolus.isFinished { - state.unfinalizedBolus = nil - } - if let tempBasal = state.unfinalizedTempBasal, tempBasal.isReconciledWithHistory, tempBasal.isFinished { - state.unfinalizedTempBasal = nil - } - state.pendingDoses.removeAll(where: { (dose) -> Bool in - if dose.isReconciledWithHistory && dose.isFinished { - print("Removing stored, finished, reconciled dose: \(dose)") - } - return dose.isReconciledWithHistory && dose.isFinished - }) - }) - } - completion(error) - }) - }) - } catch let error { - self.troubleshootPumpComms(using: device) - - completion(PumpManagerError.communication(error as? LocalizedError)) - } - } - } - } - - private func storePendingPumpEvents(forceFinalization: Bool = false, _ completion: @escaping (_ error: MinimedPumpManagerError?) -> Void) { - // Must be called from the sessionQueue - let events = (self.state.pendingDoses + [self.state.unfinalizedBolus, self.state.unfinalizedTempBasal]).compactMap({ $0?.newPumpEvent(forceFinalization: forceFinalization) }) - - log.debug("Storing pending pump events: %{public}@", String(describing: events)) - - self.pumpDelegate.notify({ (delegate) in - guard let delegate = delegate else { - preconditionFailure("pumpManagerDelegate cannot be nil") - } - - delegate.pumpManager(self, hasNewPumpEvents: events, lastReconciliation: self.state.lastReconciliation, completion: { (error) in - // Called on an unknown queue by the delegate - if let error = error { - self.log.error("Pump event storage failed: %{public}@", String(describing: error)) - completion(MinimedPumpManagerError.storageFailure) - } else { - completion(nil) - } - }) - }) - } - - // Safe to call from any thread - private var isPumpDataStale: Bool { - // How long should we wait before we poll for new pump data? - let pumpStatusAgeTolerance = rileyLinkDeviceProvider.idleListeningEnabled ? TimeInterval(minutes: 6) : TimeInterval(minutes: 4) - - return isReservoirDataOlderThan(timeIntervalSinceNow: -pumpStatusAgeTolerance) - } - - // Safe to call from any thread - private func isReservoirDataOlderThan(timeIntervalSinceNow: TimeInterval) -> Bool { - let state = self.state - var lastReservoirDate = state.lastReservoirReading?.validAt ?? .distantPast - - // Look for reservoir data from MySentry that hasn't yet been written (due to 11-second imposed delay) - if let sentryStatus = recents.latestPumpStatusFromMySentry { - var components = sentryStatus.pumpDateComponents - components.timeZone = state.timeZone - - lastReservoirDate = max(components.date ?? .distantPast, lastReservoirDate) - } - - return lastReservoirDate.timeIntervalSinceNow <= timeIntervalSinceNow - } - - private func updateBLEHeartbeatPreference() { - // Must not be called on the delegate's queue - rileyLinkDeviceProvider.timerTickEnabled = isPumpDataStale || pumpDelegate.call({ (delegate) -> Bool in - return delegate?.pumpManagerMustProvideBLEHeartbeat(self) == true - }) - } - - // MARK: - Configuration - - // MARK: Pump - - /// The user's preferred method of fetching insulin data from the pump - public var preferredInsulinDataSource: InsulinDataSource { - get { - return state.preferredInsulinDataSource - } - set { - setState { (state) in - state.preferredInsulinDataSource = newValue - } - } - } - - /// The pump battery chemistry, for voltage -> percentage calculation - public var batteryChemistry: BatteryChemistryType { - get { - return state.batteryChemistry - } - set { - setState { (state) in - state.batteryChemistry = newValue - } - } - } - - /// Whether to use MySentry packets on capable pumps: - public var useMySentry: Bool { - get { - return state.useMySentry - } - set { - let oldValue = state.useMySentry - setState { (state) in - state.useMySentry = newValue - } - if oldValue != newValue { - let useIdleListening = state.pumpModel.hasMySentry && state.useMySentry - self.rileyLinkDeviceProvider.idleListeningState = useIdleListening ? MinimedPumpManagerState.idleListeningEnabledDefaults : .disabled - } - } - } - -} - - -// MARK: - PumpManager -extension MinimedPumpManager: PumpManager { - - public static let localizedTitle = LocalizedString("Minimed 500/700 Series", comment: "Generic title of the minimed pump manager") - - public var localizedTitle: String { - return String(format: LocalizedString("Minimed %@", comment: "Pump title (1: model number)"), state.pumpModel.rawValue) - } - - public static var onboardingMaximumBasalScheduleEntryCount: Int { - return PumpModel.model522.maximumBasalScheduleEntryCount - } - - public static var onboardingSupportedBasalRates: [Double] { - return PumpModel.model522.supportedBasalRates - } - - public static var onboardingSupportedBolusVolumes: [Double] { - return PumpModel.model522.supportedBolusVolumes - } - - public static var onboardingSupportedMaximumBolusVolumes: [Double] { - return onboardingSupportedBolusVolumes - } - - /* - It takes a MM pump about 40s to deliver 1 Unit while bolusing - See: http://www.healthline.com/diabetesmine/ask-dmine-speed-insulin-pumps#3 - */ - private static let deliveryUnitsPerMinute = 1.5 - - public var supportedBasalRates: [Double] { - return state.pumpModel.supportedBasalRates - } - - public var supportedBolusVolumes: [Double] { - return state.pumpModel.supportedBolusVolumes - } - - public var supportedMaximumBolusVolumes: [Double] { - return state.pumpModel.supportedBolusVolumes - } - - public var maximumBasalScheduleEntryCount: Int { - return state.pumpModel.maximumBasalScheduleEntryCount - } - - public var minimumBasalScheduleEntryDuration: TimeInterval { - return state.pumpModel.minimumBasalScheduleEntryDuration - } - - public var pumpRecordsBasalProfileStartEvents: Bool { - return state.pumpModel.recordsBasalProfileStartEvents - } - - public var pumpReservoirCapacity: Double { - return Double(state.pumpModel.reservoirCapacity) - } - - public var isOnboarded: Bool { state.isOnboarded } - - private func lastSync(for state: MinimedPumpManagerState, recents: MinimedPumpManagerRecents) -> Date? { - return [state.lastReconciliation, recents.lastContinuousReservoir].compactMap { $0 }.max() - } - - public var lastSync: Date? { - return lastSync(for: state, recents: recents) - } - - public var insulinType: InsulinType? { - get { - return state.insulinType - } - set { - setState { (state) in - state.insulinType = newValue - } - } - } - - private func status(for state: MinimedPumpManagerState, recents: MinimedPumpManagerRecents) -> PumpManagerStatus { - let basalDeliveryState: PumpManagerStatus.BasalDeliveryState - - switch recents.suspendEngageState { - case .engaging: - basalDeliveryState = .suspending - case .disengaging: - basalDeliveryState = .resuming - case .stable: - switch recents.tempBasalEngageState { - case .engaging: - basalDeliveryState = .initiatingTempBasal - case .disengaging: - basalDeliveryState = .cancelingTempBasal - case .stable: - switch self.state.suspendState { - case .suspended(let date): - basalDeliveryState = .suspended(date) - case .resumed(let date): - if let tempBasal = state.unfinalizedTempBasal { - basalDeliveryState = .tempBasal(DoseEntry(tempBasal)) - } else { - basalDeliveryState = .active(date) - } - } - } - } - - let bolusState: PumpManagerStatus.BolusState - - switch recents.bolusEngageState { - case .engaging: - bolusState = .initiating - case .disengaging: - bolusState = .canceling - case .stable: - if let bolus = state.unfinalizedBolus, !bolus.isFinished { - bolusState = .inProgress(DoseEntry(bolus)) - } else { - bolusState = .noBolus - } - } - - return PumpManagerStatus( - timeZone: state.timeZone, - device: hkDevice, - pumpBatteryChargeRemaining: state.batteryPercentage, - basalDeliveryState: basalDeliveryState, - bolusState: bolusState, - insulinType: state.insulinType - ) - } - - public var status: PumpManagerStatus { - // Acquire the locks just once - let state = self.state - let recents = self.recents - - return status(for: state, recents: recents) - } - - public var rawState: PumpManager.RawStateValue { - return state.rawValue - } - - public var pumpManagerDelegate: PumpManagerDelegate? { - get { - return pumpDelegate.delegate - } - set { - pumpDelegate.delegate = newValue - } - } - - public var delegateQueue: DispatchQueue! { - get { - return pumpDelegate.queue - } - set { - pumpDelegate.queue = newValue - cgmDelegate.queue = newValue - } - } - - // MARK: Methods - - public func completeOnboard() { - setState({ (state) in - state.isOnboarded = true - }) - } - - public func suspendDelivery(completion: @escaping (Error?) -> Void) { - guard let insulinType = insulinType else { - completion(PumpManagerError.configuration(MinimedPumpManagerError.insulinTypeNotConfigured)) - return - } - - setSuspendResumeState(state: .suspend, insulinType: insulinType, completion: completion) - } - - public func resumeDelivery(completion: @escaping (Error?) -> Void) { - guard let insulinType = insulinType else { - completion(PumpManagerError.configuration(MinimedPumpManagerError.insulinTypeNotConfigured)) - return - } - - setSuspendResumeState(state: .resume, insulinType: insulinType, completion: completion) - } - - public func addStatusObserver(_ observer: PumpManagerStatusObserver, queue: DispatchQueue) { - statusObservers.insert(observer, queue: queue) - } - - public func removeStatusObserver(_ observer: PumpManagerStatusObserver) { - statusObservers.removeElement(observer) - } - - public func setMustProvideBLEHeartbeat(_ mustProvideBLEHeartbeat: Bool) { - rileyLinkDeviceProvider.timerTickEnabled = isPumpDataStale || mustProvideBLEHeartbeat - } - - /** - Ensures pump data is current by either waking and polling, or ensuring we're listening to sentry packets. - */ - public func ensureCurrentPumpData(completion: ((Date?) -> Void)?) { - rileyLinkDeviceProvider.assertIdleListening(forcingRestart: true) - - guard isPumpDataStale else { - log.default("Pump data is not stale: lastSync = %{public}@", String(describing: self.lastSync)) - completion?(self.lastSync) - return - } - - log.default("Pump data is stale, fetching.") - refreshPumpData(completion) - } - - private func refreshPumpData(_ completion: ((Date?) -> Void)?) { - rileyLinkDeviceProvider.getDevices { (devices) in - guard let device = devices.firstConnected else { - let error = PumpManagerError.connection(MinimedPumpManagerError.noRileyLink) - self.log.error("No devices found while fetching pump data") - self.pumpDelegate.notify({ (delegate) in - delegate?.pumpManager(self, didError: error) - completion?(self.lastSync) - }) - return - } - - self.pumpOps.runSession(withName: "Get Pump Status", using: device) { (session) in - do { - - let status = try session.getCurrentPumpStatus() - guard var date = status.clock.date else { - assertionFailure("Could not interpret a valid date from \(status.clock) in the system calendar") - throw PumpManagerError.configuration(MinimedPumpManagerError.noDate) - } - - // Initialize basal schedule, if unset - if self.state.basalSchedule.entries.count == 0, let basalSchedule = try? session.getBasalSchedule() { - self.setState { state in - state.basalSchedule = basalSchedule - } - } - - // Check if the clock should be reset - if abs(date.timeIntervalSince(self.dateGenerator())) > .seconds(20) { - self.log.error("Pump clock is more than 20 seconds off. Resetting.") - self.pumpDelegate.notify({ (delegate) in - delegate?.pumpManager(self, didAdjustPumpClockBy: date.timeIntervalSinceNow) - }) - try session.setTimeToNow() - - guard let newDate = try session.getTime().date else { - throw PumpManagerError.configuration(MinimedPumpManagerError.noDate) - } - - date = newDate - } - self.recents.latestPumpStatus = status - - self.updateReservoirVolume(status.reservoir, at: date) { result in - switch result { - case .failure: - completion?(self.lastSync) - case .success(let areStoredValuesContinuous): - if self.state.preferredInsulinDataSource == .pumpHistory || !areStoredValuesContinuous { - self.fetchPumpHistory { (error) in - if let error = error { - self.log.error("fetchPumpHistory failed: %{public}@", String(describing: error)) - } - completion?(self.lastSync) - } - } - } - } - } catch let error { - self.log.error("Failed to fetch pump status: %{public}@", String(describing: error)) - self.pumpDelegate.notify({ (delegate) in - delegate?.pumpManager(self, didError: PumpManagerError.communication(error as? LocalizedError)) - }) - self.troubleshootPumpComms(using: device) - completion?(self.lastSync) - } - } - } - } - - public func estimatedDuration(toBolus units: Double) -> TimeInterval { - self.state.pumpModel.bolusDeliveryTime(units: units) - } - - public func enactBolus(units: Double, activationType: BolusActivationType, completion: @escaping (PumpManagerError?) -> Void) { - let enactUnits = roundToSupportedBolusVolume(units: units) - - guard enactUnits > 0 else { - assertionFailure("Invalid zero unit bolus") - return - } - - guard let insulinType = insulinType else { - completion(.configuration(MinimedPumpManagerError.insulinTypeNotConfigured)) - return - } - - - pumpOps.runSession(withName: "Bolus", usingSelector: rileyLinkDeviceProvider.firstConnectedDevice) { (session) in - - guard let session = session else { - completion(.connection(MinimedPumpManagerError.noRileyLink)) - return - } - - if let unfinalizedBolus = self.state.unfinalizedBolus { - guard unfinalizedBolus.isFinished else { - completion(.deviceState(MinimedPumpManagerError.bolusInProgress)) - return - } - - self.setState({ (state) in - state.pendingDoses.append(unfinalizedBolus) - state.unfinalizedBolus = nil - }) - } - - self.recents.bolusEngageState = .engaging - - if case .suspended = self.state.suspendState { - guard activationType.isAutomatic == false else { - self.log.error("Not executing automatic bolus because pump is suspended") - self.recents.bolusEngageState = .stable - completion(.deviceState(MinimedPumpManagerError.pumpSuspended)) - return - } - do { - try self.runSuspendResumeOnSession(suspendResumeState: .resume, session: session, insulinType: insulinType) - } catch let error { - self.recents.bolusEngageState = .stable - self.log.error("Failed to resume pump for bolus: %{public}@", String(describing: error)) - completion(.communication(error as? LocalizedError)) - return - } - } - - let deliveryTime = self.estimatedDuration(toBolus: enactUnits) - - var uncertainBolusError: PumpManagerError? = nil - - if let error = session.setNormalBolus(units: enactUnits) { - switch error { - case .certain(let certainError): - self.log.error("Bolus failure: %{public}@", String(describing: certainError)) - if case PumpOpsError.pumpSuspended = certainError { - self.setState { state in - state.suspendState = .suspended(self.dateGenerator()) - } - } - self.recents.bolusEngageState = .stable - completion(.communication(certainError)) - return - case .uncertain(let uncertainError): - uncertainBolusError = .communication(error) - self.log.error("Bolus uncertain failure: %{public}@", String(describing: uncertainError)) - } - } - - // Between bluetooth and the radio and firmware, about 2s on average passes before we start tracking - let commsOffset = TimeInterval(seconds: -2) - let doseStart = self.dateGenerator().addingTimeInterval(commsOffset) - - let dose = UnfinalizedDose(bolusAmount: enactUnits, startTime: doseStart, duration: deliveryTime, insulinType: insulinType, automatic: activationType.isAutomatic) - self.setState({ (state) in - state.unfinalizedBolus = dose - }) - self.recents.bolusEngageState = .stable - - self.storePendingPumpEvents({ (error) in - completion(uncertainBolusError) - }) - } - } - - public func cancelBolus(completion: @escaping (PumpManagerResult) -> Void) { - - guard let insulinType = insulinType else { - completion(.failure(.configuration(MinimedPumpManagerError.insulinTypeNotConfigured))) - return - } - - self.recents.bolusEngageState = .disengaging - setSuspendResumeState(state: .suspend, insulinType: insulinType) { (error) in - self.recents.bolusEngageState = .stable - if let error = error { - completion(.failure(PumpManagerError.communication(error))) - } else { - completion(.success(nil)) - } - } - } - - public func enactTempBasal(unitsPerHour: Double, for duration: TimeInterval, completion: @escaping (PumpManagerError?) -> Void) { - guard let insulinType = insulinType else { - completion(.configuration(MinimedPumpManagerError.insulinTypeNotConfigured)) - return - } - - pumpOps.runSession(withName: "Set Temp Basal", usingSelector: rileyLinkDeviceProvider.firstConnectedDevice) { (session) in - guard let session = session else { - completion(.connection(MinimedPumpManagerError.noRileyLink)) - return - } - - self.recents.tempBasalEngageState = .engaging - - let result = session.setTempBasal(unitsPerHour, duration: duration) - - switch result { - case .success: - let now = self.dateGenerator() - - let dose = UnfinalizedDose(tempBasalRate: unitsPerHour, startTime: now, duration: duration, insulinType: insulinType, automatic: true) - - self.recents.tempBasalEngageState = .stable - - let isResumingScheduledBasal = duration < .ulpOfOne - - // If we were successful, then we know we aren't suspended - self.setState({ (state) in - if case .suspended = state.suspendState { - state.suspendState = .resumed(now) - } else if isResumingScheduledBasal { - state.suspendState = .resumed(now) - } - - let pumpModel = state.pumpModel - - state.unfinalizedTempBasal?.cancel(at: now, pumpModel: pumpModel) - if let previousTempBasal = state.unfinalizedTempBasal { - state.pendingDoses.append(previousTempBasal) - } - - if isResumingScheduledBasal { - state.unfinalizedTempBasal = nil - } else { - state.unfinalizedTempBasal = dose - } - }) - - self.storePendingPumpEvents({ (error) in - completion(nil) - }) - - // Continue below - case .failure(let error): - completion(.communication(error)) - - self.logDeviceCommunication("Set temp basal failed: \(error.localizedDescription)", type: .error) - - // If we got a command-refused error, we might be suspended or bolusing, so update the state accordingly - if case .arguments(.pumpError(.commandRefused)) = error { - do { - let status = try session.getCurrentPumpStatus() - self.setState({ (state) in - if case .resumed = state.suspendState, status.suspended { - state.suspendState = .suspended(self.dateGenerator()) - } - }) - self.recents.latestPumpStatus = status - } catch { - self.log.error("Post-basal suspend state fetch failed: %{public}@", String(describing: error)) - } - } - self.recents.tempBasalEngageState = .stable - return - } - } - } - - public func createBolusProgressReporter(reportingOn dispatchQueue: DispatchQueue) -> DoseProgressReporter? { - if let bolus = self.state.unfinalizedBolus, !bolus.isFinished { - return MinimedDoseProgressEstimator(dose: DoseEntry(bolus), pumpModel: state.pumpModel, reportingQueue: dispatchQueue) - } - return nil - } - - public func setMaximumTempBasalRate(_ rate: Double) { } - - public func syncBasalRateSchedule(items scheduleItems: [RepeatingScheduleValue], completion: @escaping (Result) -> Void) { - pumpOps.runSession(withName: "Save Basal Profile", usingSelector: rileyLinkDeviceProvider.firstConnectedDevice) { (session) in - guard let session = session else { - completion(.failure(PumpManagerError.connection(MinimedPumpManagerError.noRileyLink))) - return - } - - do { - let newSchedule = BasalSchedule(repeatingScheduleValues: scheduleItems) - try session.setBasalSchedule(newSchedule, for: .standard) - - - completion(.success(BasalRateSchedule(dailyItems: scheduleItems, timeZone: session.pump.timeZone)!)) - } catch let error { - self.log.error("Save basal profile failed: %{public}@", String(describing: error)) - completion(.failure(error)) - } - } - } - - public func syncDeliveryLimits(limits deliveryLimits: DeliveryLimits, completion: @escaping (Result) -> Void) { - pumpOps.runSession(withName: "Save Settings", usingSelector: rileyLinkDeviceProvider.firstConnectedDevice) { (session) in - guard let session = session else { - completion(.failure(PumpManagerError.connection(MinimedPumpManagerError.noRileyLink))) - return - } - - do { - if let maxBasalRate = deliveryLimits.maximumBasalRate?.doubleValue(for: .internationalUnitsPerHour) { - try session.setMaxBasalRate(unitsPerHour: maxBasalRate) - } - - if let maxBolus = deliveryLimits.maximumBolus?.doubleValue(for: .internationalUnit()) { - try session.setMaxBolus(units: maxBolus) - } - - let settings = try session.getSettings() - let storedDeliveryLimits = DeliveryLimits(maximumBasalRate: HKQuantity(unit: .internationalUnitsPerHour, doubleValue: settings.maxBasal), - maximumBolus: HKQuantity(unit: .internationalUnit(), doubleValue: settings.maxBolus)) - completion(.success(storedDeliveryLimits)) - } catch let error { - self.log.error("Save delivery limit settings failed: %{public}@", String(describing: error)) - completion(.failure(error)) - } - } - } - - public var isClockOffset: Bool { - let now = dateGenerator() - return TimeZone.current.secondsFromGMT(for: now) != state.timeZone.secondsFromGMT(for: now) - } - - public func setTime(completion: @escaping (PumpManagerError?) -> Void) { - pumpOps.runSession(withName: "Set time", usingSelector: rileyLinkDeviceProvider.firstConnectedDevice) { (session) in - do { - guard let session = session else { - throw PumpManagerError.connection(MinimedPumpManagerError.noRileyLink) - } - try session.setTimeToNow(in: .current) - completion(nil) - } catch let error { - completion(.communication(error as? LocalizedError)) - } - } - } - - public func deletePump(completion: @escaping () -> Void) { - storePendingPumpEvents(forceFinalization: true) { error in - self.notifyDelegateOfDeactivation { - completion() - } - } - } -} - -extension MinimedPumpManager: PumpOpsDelegate { - public func willSend(_ message: String) { - logDeviceCommunication(message, type: .send) - } - - public func didReceive(_ message: String) { - logDeviceCommunication(message, type: .receive) - } - - public func didError(_ message: String) { - logDeviceCommunication(message, type: .error) - } - - public func pumpOps(_ pumpOps: PumpOps, didChange state: PumpState) { - setState { (pumpManagerState) in - pumpManagerState.pumpState = state - } - } -} - -extension MinimedPumpManager: CGMManager { - public var device: HKDevice? { - return hkDevice - } - - public var cgmManagerDelegate: CGMManagerDelegate? { - get { - return cgmDelegate.delegate - } - set { - cgmDelegate.delegate = newValue - } - } - - public var shouldSyncToRemoteService: Bool { - return true - } - - public var providesBLEHeartbeat: Bool { - return false - } - - public var managedDataInterval: TimeInterval? { - return nil - } - - public var glucoseDisplay: GlucoseDisplayable? { - return recents.sensorState - } - - public var cgmManagerStatus: CGMManagerStatus { - return CGMManagerStatus(hasValidSensorSession: hasValidSensorSession, device: device) - } - - public var hasValidSensorSession: Bool { - // No tracking of session available - return true - } - - public func fetchNewDataIfNeeded(_ completion: @escaping (CGMReadingResult) -> Void) { - rileyLinkDeviceProvider.getDevices { (devices) in - guard let device = devices.firstConnected else { - completion(.error(PumpManagerError.connection(MinimedPumpManagerError.noRileyLink))) - return - } - - let latestGlucoseDate = self.cgmDelegate.call({ (delegate) -> Date in - return delegate?.startDateToFilterNewData(for: self) ?? Date(timeIntervalSinceNow: TimeInterval(hours: -24)) - }) - - guard latestGlucoseDate.timeIntervalSinceNow <= TimeInterval(minutes: -4.5) else { - completion(.noData) - return - } - - self.pumpOps.runSession(withName: "Fetch Enlite History", using: device) { (session) in - do { - let events = try session.getGlucoseHistoryEvents(since: latestGlucoseDate.addingTimeInterval(.minutes(1))) - - if let latestSensorEvent = events.compactMap({ $0.glucoseEvent as? RelativeTimestampedGlucoseEvent }).last { - self.recents.sensorState = EnliteSensorDisplayable(latestSensorEvent) - } - - let unit = HKUnit.milligramsPerDeciliter - let glucoseValues: [NewGlucoseSample] = events - // TODO: Is the { $0.date > latestGlucoseDate } filter duplicative? - .filter({ $0.glucoseEvent is SensorValueGlucoseEvent && $0.date > latestGlucoseDate }) - .map { - let glucoseEvent = $0.glucoseEvent as! SensorValueGlucoseEvent - let quantity = HKQuantity(unit: unit, doubleValue: Double(glucoseEvent.sgv)) - return NewGlucoseSample(date: $0.date, quantity: quantity, condition: nil, trend: glucoseEvent.trendType, trendRate: glucoseEvent.trendRate, isDisplayOnly: false, wasUserEntered: false, syncIdentifier: glucoseEvent.glucoseSyncIdentifier ?? UUID().uuidString, device: self.device) - } - - completion(.newData(glucoseValues)) - } catch let error { - completion(.error(error)) - } - } - } - } -} - -// MARK: - AlertResponder implementation -extension MinimedPumpManager { - public func acknowledgeAlert(alertIdentifier: Alert.AlertIdentifier, completion: @escaping (Error?) -> Void) { - completion(nil) - } -} - -// MARK: - AlertSoundVendor implementation -extension MinimedPumpManager { - public func getSoundBaseURL() -> URL? { return nil } - public func getSounds() -> [Alert.Sound] { return [] } -} - -extension GlucoseTrend { - var loopKitGlucoseTrend: LoopKit.GlucoseTrend { - switch self { - case .flat: - return .flat - case .up: - return .up - case .upUp: - return .upUp - case .down: - return .down - case .downDown: - return .downDown - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpManagerError.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpManagerError.swift deleted file mode 100644 index 5b466689e..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpManagerError.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// MinimedPumpManagerError.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum MinimedPumpManagerError: Error { - case noRileyLink - case bolusInProgress - case pumpSuspended - case insulinTypeNotConfigured - case noDate // TODO: This is less of an error and more of a precondition/assertion state - case tuneFailed(LocalizedError) - case commsError(LocalizedError) - case storageFailure -} - - -extension MinimedPumpManagerError: LocalizedError { - public var errorDescription: String? { - switch self { - case .noRileyLink: - return LocalizedString("No RileyLink Connected", comment: "Error description when no rileylink connected") - case .bolusInProgress: - return LocalizedString("Bolus in Progress", comment: "Error description when failure due to bolus in progress") - case .pumpSuspended: - return LocalizedString("Pump is Suspended", comment: "Error description when failure due to pump suspended") - case .insulinTypeNotConfigured: - return LocalizedString("Insulin Type is not configured", comment: "Error description for MinimedPumpManagerError.insulinTypeNotConfigured") - case .noDate: - return nil - case .tuneFailed(let error): - return [LocalizedString("RileyLink radio tune failed", comment: "Error description for tune failure"), error.errorDescription].compactMap({ $0 }).joined(separator: ": ") - case .commsError(let error): - return error.errorDescription - case .storageFailure: - return LocalizedString("Unable to store pump data", comment: "Error description when storage fails") - } - } - - public var failureReason: String? { - switch self { - case .tuneFailed(let error): - return error.failureReason - default: - return nil - } - } - - public var recoverySuggestion: String? { - switch self { - case .noRileyLink: - return LocalizedString("Make sure your RileyLink is nearby and powered on", comment: "Recovery suggestion") - case .insulinTypeNotConfigured: - return LocalizedString("Go to pump settings and select insulin type", comment: "Recovery suggestion for MinimedPumpManagerError.insulinTypeNotConfigured") - case .tuneFailed(let error): - return error.recoverySuggestion - default: - return nil - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpManagerRecents.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpManagerRecents.swift deleted file mode 100644 index 26d32cd8c..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpManagerRecents.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// MinimedPumpManagerRecents.swift -// MinimedKit -// -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -public struct MinimedPumpManagerRecents: Equatable { - - internal enum EngageablePumpState: Equatable { - case engaging - case disengaging - case stable - } - - internal var suspendEngageState: EngageablePumpState = .stable - - internal var bolusEngageState: EngageablePumpState = .stable - - internal var tempBasalEngageState: EngageablePumpState = .stable - - var lastAddedPumpEvents: Date = .distantPast - - var lastContinuousReservoir: Date = .distantPast - - var latestPumpStatus: PumpStatus? = nil - - var latestPumpStatusFromMySentry: MySentryPumpStatusMessageBody? = nil { - didSet { - if let sensorState = latestPumpStatusFromMySentry { - self.sensorState = EnliteSensorDisplayable(sensorState) - } - } - } - - var sensorState: EnliteSensorDisplayable? = nil -} - -extension MinimedPumpManagerRecents: CustomDebugStringConvertible { - public var debugDescription: String { - return """ - ### MinimedPumpManagerRecents - suspendEngageState: \(suspendEngageState) - bolusEngageState: \(bolusEngageState) - tempBasalEngageState: \(tempBasalEngageState) - lastAddedPumpEvents: \(lastAddedPumpEvents) - latestPumpStatus: \(String(describing: latestPumpStatus)) - lastContinuousReservoir: \(lastContinuousReservoir) - latestPumpStatusFromMySentry: \(String(describing: latestPumpStatusFromMySentry)) - sensorState: \(String(describing: sensorState)) - """ - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpManagerState.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpManagerState.swift deleted file mode 100644 index 7b4260f2d..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpManagerState.swift +++ /dev/null @@ -1,381 +0,0 @@ -// -// MinimedPumpManagerState.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import LoopKit -import RileyLinkKit -import RileyLinkBLEKit - -public struct ReconciledDoseMapping: Equatable { - let startTime: Date - let uuid: UUID - let eventRaw: Data -} - -extension ReconciledDoseMapping: RawRepresentable { - public typealias RawValue = [String:Any] - - public init?(rawValue: [String : Any]) { - guard - let startTime = rawValue["startTime"] as? Date, - let uuidString = rawValue["uuid"] as? String, - let uuid = UUID(uuidString: uuidString), - let eventRawString = rawValue["eventRaw"] as? String, - let eventRaw = Data(hexadecimalString: eventRawString) else - { - return nil - } - self.startTime = startTime - self.uuid = uuid - self.eventRaw = eventRaw - } - - public var rawValue: [String : Any] { - return [ - "startTime": startTime, - "uuid": uuid.uuidString, - "eventRaw": eventRaw.hexadecimalString, - ] - } -} - -public struct MinimedPumpManagerState: RawRepresentable, Equatable { - public typealias RawValue = PumpManager.RawStateValue - - public static let version = 2 - - public var isOnboarded: Bool - - public var batteryChemistry: BatteryChemistryType = .alkaline - - public var batteryPercentage: Double? - - public var suspendState: SuspendState - - public var lastReservoirReading: ReservoirReading? - - public var lastTuned: Date? // In-memory only - - public var lastValidFrequency: Measurement? - - public var preferredInsulinDataSource: InsulinDataSource = .pumpHistory - - public var useMySentry: Bool - - public let pumpColor: PumpColor - - public let pumpModel: PumpModel - - public let pumpFirmwareVersion: String - - public let pumpID: String - - public let pumpRegion: PumpRegion - - public var pumpSettings: PumpSettings { - get { - return PumpSettings(pumpID: pumpID, pumpRegion: pumpRegion) - } - } - - public var pumpState: PumpState { - get { - var state = PumpState() - state.pumpModel = pumpModel - state.timeZone = timeZone - state.lastValidFrequency = lastValidFrequency - state.lastTuned = lastTuned - state.useMySentry = useMySentry - return state - } - set { - lastValidFrequency = newValue.lastValidFrequency - lastTuned = newValue.lastTuned - timeZone = newValue.timeZone - } - } - - public var rileyLinkConnectionState: RileyLinkConnectionState? - - public var timeZone: TimeZone - - public var unfinalizedBolus: UnfinalizedDose? - - public var unfinalizedTempBasal: UnfinalizedDose? - - // Doses we're tracking that haven't shown up in history yet - public var pendingDoses: [UnfinalizedDose] = [] - - // Maps - public var reconciliationMappings: [Data:ReconciledDoseMapping] = [:] - - public var lastReconciliation: Date? - - public var insulinType: InsulinType? - - public var rileyLinkBatteryAlertLevel: Int? - - public var lastRileyLinkBatteryAlertDate: Date = .distantPast - - public var basalSchedule: BasalSchedule - - public init(isOnboarded: Bool, useMySentry: Bool, pumpColor: PumpColor, pumpID: String, pumpModel: PumpModel, pumpFirmwareVersion: String, pumpRegion: PumpRegion, rileyLinkConnectionState: RileyLinkConnectionState?, timeZone: TimeZone, suspendState: SuspendState, insulinType: InsulinType, lastTuned: Date?, lastValidFrequency: Measurement?, basalSchedule: BasalSchedule) - { - self.isOnboarded = isOnboarded - self.useMySentry = useMySentry - self.pumpColor = pumpColor - self.pumpID = pumpID - self.pumpModel = pumpModel - self.pumpFirmwareVersion = pumpFirmwareVersion - self.pumpRegion = pumpRegion - self.rileyLinkConnectionState = rileyLinkConnectionState - self.timeZone = timeZone - self.suspendState = suspendState - self.insulinType = insulinType - self.lastTuned = lastTuned - self.lastValidFrequency = lastValidFrequency - self.basalSchedule = basalSchedule - } - - public init?(rawValue: RawValue) { - guard - let version = rawValue["version"] as? Int, - let useMySentry = rawValue["useMySentry"] as? Bool, - let pumpID = rawValue["pumpID"] as? String, - - let batteryChemistryRaw = rawValue["batteryChemistry"] as? BatteryChemistryType.RawValue, - let batteryChemistry = BatteryChemistryType(rawValue: batteryChemistryRaw), - - let insulinDataSourceRaw = rawValue["insulinDataSource"] as? InsulinDataSource.RawValue, - let insulinDataSource = InsulinDataSource(rawValue: insulinDataSourceRaw), - - let pumpColorRaw = rawValue["pumpColor"] as? PumpColor.RawValue, - let pumpColor = PumpColor(rawValue: pumpColorRaw), - - let pumpModelNumber = rawValue["pumpModel"] as? PumpModel.RawValue, - let pumpModel = PumpModel(rawValue: pumpModelNumber), - - let pumpRegionRaw = rawValue["pumpRegion"] as? PumpRegion.RawValue, - let pumpRegion = PumpRegion(rawValue: pumpRegionRaw), - - let timeZoneSeconds = rawValue["timeZone"] as? Int, - let timeZone = TimeZone(secondsFromGMT: timeZoneSeconds) - else { - return nil - } - - // Migrate - if version == 1 - { - if let oldRileyLinkPumpManagerStateRaw = rawValue["rileyLinkPumpManagerState"] as? [String : Any], - let connectedPeripheralIDs = oldRileyLinkPumpManagerStateRaw["connectedPeripheralIDs"] as? [String] - { - self.rileyLinkConnectionState = RileyLinkConnectionState(autoConnectIDs: Set(connectedPeripheralIDs)) - } - } else { - if let rawState = rawValue["rileyLinkConnectionManagerState"] as? RileyLinkConnectionState.RawValue { - self.rileyLinkConnectionState = RileyLinkConnectionState(rawValue: rawState) - } - } - - - self.useMySentry = useMySentry - self.pumpID = pumpID - self.batteryChemistry = batteryChemistry - self.preferredInsulinDataSource = insulinDataSource - self.pumpColor = pumpColor - self.pumpModel = pumpModel - self.pumpRegion = pumpRegion - self.timeZone = timeZone - - isOnboarded = rawValue["isOnboarded"] as? Bool ?? true // Backward compatibility - - if let isPumpSuspended = rawValue["isPumpSuspended"] as? Bool { - // migrate - if isPumpSuspended { - suspendState = .suspended(Date()) - } else { - suspendState = .resumed(Date()) - } - } else if let rawSuspendState = rawValue["suspendState"] as? SuspendState.RawValue, let storedSuspendState = SuspendState(rawValue: rawSuspendState) { - suspendState = storedSuspendState - } else { - return nil - } - - if let frequencyRaw = rawValue["lastValidFrequency"] as? Double { - lastValidFrequency = Measurement(value: frequencyRaw, unit: .megahertz) - } else { - lastValidFrequency = nil - } - - pumpFirmwareVersion = (rawValue["pumpFirmwareVersion"] as? String) ?? "" - batteryPercentage = rawValue["batteryPercentage"] as? Double - - if let rawLastReservoirReading = rawValue["lastReservoirReading"] as? ReservoirReading.RawValue { - lastReservoirReading = ReservoirReading(rawValue: rawLastReservoirReading) - } - - if let rawUnfinalizedBolus = rawValue["unfinalizedBolus"] as? UnfinalizedDose.RawValue { - unfinalizedBolus = UnfinalizedDose(rawValue: rawUnfinalizedBolus) - } - - if let rawUnfinalizedTempBasal = rawValue["unfinalizedTempBasal"] as? UnfinalizedDose.RawValue { - unfinalizedTempBasal = UnfinalizedDose(rawValue: rawUnfinalizedTempBasal) - } - - if let rawPendingDoses = rawValue["pendingDoses"] as? [UnfinalizedDose.RawValue] { - pendingDoses = rawPendingDoses.compactMap( { UnfinalizedDose(rawValue: $0) } ) - } else { - pendingDoses = [] - } - - let recentlyReconciledEvents: [Data:ReconciledDoseMapping] - if let rawRecentlyReconciledEvents = rawValue["recentlyReconciledEvents"] as? [ReconciledDoseMapping.RawValue] { - let mappings = rawRecentlyReconciledEvents.compactMap { ReconciledDoseMapping(rawValue: $0) } - recentlyReconciledEvents = Dictionary(mappings.map{ ($0.eventRaw, $0) }, uniquingKeysWith: { (old, new) in new } ) - } else { - recentlyReconciledEvents = [:] - } - reconciliationMappings = recentlyReconciledEvents - - lastReconciliation = rawValue["lastReconciliation"] as? Date - - if let rawInsulinType = rawValue["insulinType"] as? InsulinType.RawValue { - insulinType = InsulinType(rawValue: rawInsulinType) - } - - rileyLinkBatteryAlertLevel = rawValue["rileyLinkBatteryAlertLevel"] as? Int - lastRileyLinkBatteryAlertDate = rawValue["lastRileyLinkBatteryAlertDate"] as? Date ?? Date.distantPast - - if let rawBasalSchedule = rawValue["basalSchedule"] as? BasalSchedule.RawValue, let basalSchedule = BasalSchedule(rawValue: rawBasalSchedule) { - self.basalSchedule = basalSchedule - } else { - self.basalSchedule = BasalSchedule(entries: []) - } - } - - public var rawValue: RawValue { - var value: [String : Any] = [ - "isOnboarded": isOnboarded, - "batteryChemistry": batteryChemistry.rawValue, - "insulinDataSource": preferredInsulinDataSource.rawValue, - "pumpColor": pumpColor.rawValue, - "pumpID": pumpID, - "pumpModel": pumpModel.rawValue, - "pumpFirmwareVersion": pumpFirmwareVersion, - "pumpRegion": pumpRegion.rawValue, - "timeZone": timeZone.secondsFromGMT(), - "suspendState": suspendState.rawValue, - "version": MinimedPumpManagerState.version, - "pendingDoses": pendingDoses.map { $0.rawValue }, - "recentlyReconciledEvents": reconciliationMappings.values.map { $0.rawValue }, - ] - - value["useMySentry"] = useMySentry - value["batteryPercentage"] = batteryPercentage - value["lastReservoirReading"] = lastReservoirReading?.rawValue - value["lastValidFrequency"] = lastValidFrequency?.converted(to: .megahertz).value - value["rileyLinkConnectionManagerState"] = rileyLinkConnectionState?.rawValue - value["unfinalizedBolus"] = unfinalizedBolus?.rawValue - value["unfinalizedTempBasal"] = unfinalizedTempBasal?.rawValue - value["lastReconciliation"] = lastReconciliation - value["insulinType"] = insulinType?.rawValue - value["rileyLinkBatteryAlertLevel"] = rileyLinkBatteryAlertLevel - value["lastRileyLinkBatteryAlertDate"] = lastRileyLinkBatteryAlertDate - value["basalSchedule"] = basalSchedule.rawValue - - return value - } -} - - -extension MinimedPumpManagerState { - static let idleListeningEnabledDefaults: RileyLinkBluetoothDevice.IdleListeningState = .enabled(timeout: .minutes(4), channel: 0) -} - - -extension MinimedPumpManagerState: CustomDebugStringConvertible { - public var debugDescription: String { - return [ - "## MinimedPumpManagerState", - "isOnboarded: \(isOnboarded)", - "batteryChemistry: \(batteryChemistry)", - "batteryPercentage: \(String(describing: batteryPercentage))", - "suspendState: \(suspendState)", - "lastValidFrequency: \(String(describing: lastValidFrequency))", - "preferredInsulinDataSource: \(preferredInsulinDataSource)", - "useMySentry: \(useMySentry)", - "pumpColor: \(pumpColor)", - "pumpID: ✔︎", - "pumpModel: \(pumpModel.rawValue)", - "pumpFirmwareVersion: \(pumpFirmwareVersion)", - "pumpRegion: \(pumpRegion)", - "reservoirUnits: \(String(describing: lastReservoirReading?.units))", - "reservoirValidAt: \(String(describing: lastReservoirReading?.validAt))", - "unfinalizedBolus: \(String(describing: unfinalizedBolus))", - "unfinalizedTempBasal: \(String(describing: unfinalizedTempBasal))", - "pendingDoses: \(pendingDoses)", - "timeZone: \(timeZone)", - "recentlyReconciledEvents: \(reconciliationMappings.values.map { "\($0.eventRaw.hexadecimalString) -> \($0.uuid)" })", - "lastReconciliation: \(String(describing: lastReconciliation))", - "insulinType: \(String(describing: insulinType))", - "rileyLinkBatteryAlertLevel: \(String(describing: rileyLinkBatteryAlertLevel))", - "lastRileyLinkBatteryAlertDate \(String(describing: lastRileyLinkBatteryAlertDate))", - String(reflecting: rileyLinkConnectionState), - ].joined(separator: "\n") - } -} - -public enum SuspendState: Equatable, RawRepresentable { - public typealias RawValue = [String: Any] - - private enum SuspendStateType: Int { - case suspend, resume - } - - case suspended(Date) - case resumed(Date) - - private var identifier: Int { - switch self { - case .suspended: - return 1 - case .resumed: - return 2 - } - } - - public init?(rawValue: RawValue) { - guard let suspendStateType = rawValue["case"] as? SuspendStateType.RawValue, - let date = rawValue["date"] as? Date else { - return nil - } - switch SuspendStateType(rawValue: suspendStateType) { - case .suspend?: - self = .suspended(date) - case .resume?: - self = .resumed(date) - default: - return nil - } - } - - public var rawValue: RawValue { - switch self { - case .suspended(let date): - return [ - "case": SuspendStateType.suspend.rawValue, - "date": date - ] - case .resumed(let date): - return [ - "case": SuspendStateType.resume.rawValue, - "date": date - ] - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpMessageSender.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpMessageSender.swift deleted file mode 100644 index 04070c931..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/MinimedPumpMessageSender.swift +++ /dev/null @@ -1,166 +0,0 @@ -// -// MinimedPumpMessageSender.swift -// MinimedKit -// -// Created by Pete Schwamb on 9/3/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import RileyLinkBLEKit -import os.log - - -public protocol CommsLogger: AnyObject { - // Comms logging - func willSend(_ message: String) - func didReceive(_ message: String) - func didError(_ message: String) -} - -private let log = OSLog(category: "MinimedPumpMessageSender") - -struct MinimedPumpMessageSender: PumpMessageSender { - - static let standardPumpResponseWindow: TimeInterval = .milliseconds(200) - - var commandSession: CommandSession - weak var commsLogger: CommsLogger? - - func resetRadioConfig() throws { - try commandSession.resetRadioConfig() - } - - func updateRegister(_ address: RileyLinkBLEKit.CC111XRegister, value: UInt8) throws { - try commandSession.updateRegister(address, value: value) - } - - func setBaseFrequency(_ frequency: Measurement) throws { - try commandSession.setBaseFrequency(frequency) - } - - func listen(onChannel channel: Int, timeout: TimeInterval) throws -> RileyLinkBLEKit.RFPacket? { - return try commandSession.listen(onChannel: channel, timeout: timeout) - } - - func getRileyLinkStatistics() throws -> RileyLinkBLEKit.RileyLinkStatistics { - return try commandSession.getRileyLinkStatistics() - } - - /// - Throws: PumpOpsError.deviceError - func send(_ msg: PumpMessage) throws { - do { - try commandSession.send(MinimedPacket(outgoingData: msg.txData).encodedData(), onChannel: 0, timeout: 0) - } catch let error as LocalizedError { - throw PumpOpsError.deviceError(error) - } - } - - /// Sends a message to the pump, expecting a PumpMessage with specific response body type - /// - /// - Parameters: - /// - message: The message to send - /// - responseType: The expected response message type - /// - repeatCount: The number of times to repeat the message before listening begins - /// - timeout: The length of time to listen for a pump response - /// - retryCount: The number of times to repeat the send & listen sequence - /// - Returns: The expected response message body - /// - Throws: - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.pumpError - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - func getResponse(to message: PumpMessage, responseType: MessageType, repeatCount: Int, timeout: TimeInterval, retryCount: Int) throws -> T { - - commsLogger?.willSend(String(describing: message)) - - do { - let response = try sendAndListen(message, repeatCount: repeatCount, timeout: timeout, retryCount: retryCount) - - guard response.messageType == responseType, let body = response.messageBody as? T else { - if let body = response.messageBody as? PumpErrorMessageBody { - commsLogger?.didReceive(String(describing: response)) - switch body.errorCode { - case .known(let code): - throw PumpOpsError.pumpError(code) - case .unknown(let code): - throw PumpOpsError.unknownPumpErrorCode(code) - } - } else { - throw PumpOpsError.unexpectedResponse(response, from: message) - } - } - commsLogger?.didReceive(String(describing: response)) - usleep(200000) // 0.2s - return body - } catch { - commsLogger?.didError(error.localizedDescription) - throw error - } - } - - /// Sends a message to the pump, listening for a any known PumpMessage in reply - /// - /// - Parameters: - /// - message: The message to send - /// - repeatCount: The number of times to repeat the message before listening begins - /// - timeout: The length of time to listen for a pump response - /// - retryCount: The number of times to repeat the send & listen sequence - /// - Returns: The message reply - /// - Throws: An error describing a failure in the sending or receiving of a message: - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unknownResponse - func sendAndListen(_ message: PumpMessage, repeatCount: Int, timeout: TimeInterval, retryCount: Int) throws -> PumpMessage { - let rfPacket = try sendAndListenForPacket(message, repeatCount: repeatCount, timeout: timeout, retryCount: retryCount) - - guard let packet = MinimedPacket(encodedData: rfPacket.data) else { - throw PumpOpsError.couldNotDecode(rx: rfPacket.data, during: message) - } - - guard let response = PumpMessage(rxData: packet.data) else { - // Unknown packet type or message type - throw PumpOpsError.unknownResponse(rx: packet.data, during: message) - } - - guard response.address == message.address else { - throw PumpOpsError.crosstalk(response, during: message) - } - - return response - } - - // Send a PumpMessage, and listens for a packet; used by callers who need to see RSSI - /// - Throws: - /// - PumpOpsError.noResponse - /// - PumpOpsError.deviceError - func sendAndListenForPacket(_ message: PumpMessage, repeatCount: Int, timeout: TimeInterval, retryCount: Int) throws -> RFPacket { - let packet: RFPacket? - - do { - packet = try commandSession.sendAndListen(MinimedPacket(outgoingData: message.txData).encodedData(), repeatCount: repeatCount, timeout: timeout, retryCount: retryCount) - } catch let error as LocalizedError { - throw PumpOpsError.deviceError(error) - } - - guard let rfPacket = packet else { - throw PumpOpsError.noResponse(during: message) - } - - return rfPacket - } - - /// - Throws: PumpOpsError.deviceError - func listenForPacket(onChannel channel: Int, timeout: TimeInterval) throws -> RFPacket? { - do { - return try listen(onChannel: channel, timeout: timeout) - } catch let error as LocalizedError { - throw PumpOpsError.deviceError(error) - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpMessage+PumpOpsSession.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpMessage+PumpOpsSession.swift deleted file mode 100644 index 5b9d02e59..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpMessage+PumpOpsSession.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// PumpMessage.swift -// RileyLinkKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - - -public extension PumpMessage { - /// Initializes a Carelink message using settings and a default body - /// - /// - Parameters: - /// - settings: Pump settings used for determining address - /// - type: The message type - /// - body: The message body, defaulting to a 1-byte empty body - init(pumpID: String, type: MessageType, body: MessageBody = CarelinkShortMessageBody()) { - self.init(packetType: .carelink, address: pumpID, messageType: type, messageBody: body) - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpMessageSender.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpMessageSender.swift deleted file mode 100644 index 60b58ad34..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpMessageSender.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// PumpMessageSender.swift -// RileyLink -// -// Created by Jaim Zuber on 3/2/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation -import RileyLinkBLEKit - -public protocol PumpMessageSender { - /// - Throws: LocalizedError - func resetRadioConfig() throws - - /// - Throws: LocalizedError - func updateRegister(_ address: CC111XRegister, value: UInt8) throws - - /// - Throws: LocalizedError - func setBaseFrequency(_ frequency: Measurement) throws - - /// - Throws: LocalizedError - func listen(onChannel channel: Int, timeout: TimeInterval) throws -> RFPacket? - - /// - Throws: LocalizedError - func send(_ msg: PumpMessage) throws - - /// - Throws: LocalizedError - func getRileyLinkStatistics() throws -> RileyLinkStatistics - - /// Sends a message to the pump, expecting a PumpMessage with specific response body type - /// - /// - Parameters: - /// - message: The message to send - /// - responseType: The expected response message type - /// - repeatCount: The number of times to repeat the message before listening begins - /// - timeout: The length of time to listen for a pump response - /// - retryCount: The number of times to repeat the send & listen sequence - /// - Returns: The expected response message body - /// - Throws: - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.pumpError - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - func getResponse(to message: PumpMessage, responseType: MessageType, repeatCount: Int, timeout: TimeInterval, retryCount: Int) throws -> T - - /// Sends a message to the pump, listening for a any known PumpMessage in reply - /// - /// - Parameters: - /// - message: The message to send - /// - repeatCount: The number of times to repeat the message before listening begins - /// - timeout: The length of time to listen for a pump response - /// - retryCount: The number of times to repeat the send & listen sequence - /// - Returns: The message reply - /// - Throws: An error describing a failure in the sending or receiving of a message: - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unknownResponse - func sendAndListen(_ message: PumpMessage, repeatCount: Int, timeout: TimeInterval, retryCount: Int) throws -> PumpMessage - - // Send a PumpMessage, and listens for a packet; used by callers who need to see RSSI - /// - Throws: - /// - PumpOpsError.noResponse - /// - PumpOpsError.deviceError - func sendAndListenForPacket(_ message: PumpMessage, repeatCount: Int, timeout: TimeInterval, retryCount: Int) throws -> RFPacket - - /// - Throws: PumpOpsError.deviceError - func listenForPacket(onChannel channel: Int, timeout: TimeInterval) throws -> RFPacket? -} - diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpOps.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpOps.swift deleted file mode 100644 index 6dfd0c7f0..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpOps.swift +++ /dev/null @@ -1,158 +0,0 @@ -// -// PumpOps.swift -// RileyLink -// -// Created by Pete Schwamb on 3/14/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation -import RileyLinkKit -import RileyLinkBLEKit -import os.log -import LoopKit - - -public protocol PumpOpsDelegate: AnyObject, CommsLogger { - func pumpOps(_ pumpOps: PumpOps, didChange state: PumpState) -} - -public protocol PumpOps { - func runSession(withName name: String, using device: RileyLinkDevice, _ block: @escaping (_ session: PumpOpsSession) -> Void) -} - -extension PumpOps { - public func runSession(withName name: String, usingSelector deviceSelector: @escaping (_ completion: @escaping (_ device: RileyLinkDevice?) -> Void) -> Void, _ block: @escaping (_ session: PumpOpsSession?) -> Void) { - deviceSelector { (device) in - guard let device = device else { - block(nil) - return - } - - self.runSession(withName: name, using: device, block) - } - } -} - -public class MinimedPumpOps: PumpOps { - private let log = OSLog(category: "PumpOps") - - private let pumpSettings: PumpSettings - - private let pumpState: Locked - - private let configuredDevices: Locked> = Locked(Set()) - - // Isolated to RileyLinkDeviceManager.sessionQueue - private var sessionDevice: RileyLinkDevice? - - private weak var delegate: PumpOpsDelegate? - - public init(pumpSettings: PumpSettings, pumpState: PumpState?, delegate: PumpOpsDelegate?) { - self.pumpSettings = pumpSettings - self.delegate = delegate - - if let pumpState = pumpState { - self.pumpState = Locked(pumpState) - } else { - let pumpState = PumpState() - self.pumpState = Locked(pumpState) - self.delegate?.pumpOps(self, didChange: pumpState) - } - } - - public func runSession(withName name: String, using device: RileyLinkDevice, _ block: @escaping (_ session: PumpOpsSession) -> Void) { - device.runSession(withName: name) { (commandSession) in - let minimedPumpMessageSender = MinimedPumpMessageSender(commandSession: commandSession, commsLogger: self.delegate) - let session = PumpOpsSession(settings: self.pumpSettings, pumpState: self.pumpState.value, messageSender: minimedPumpMessageSender, delegate: self) - self.sessionDevice = device - if !commandSession.firmwareVersion.isUnknown { - self.configureDevice(device, with: session) - } else { - self.log.error("Skipping device configuration due to unknown firmware version") - } - - block(session) - self.sessionDevice = nil - } - } - - // Must be called from within the RileyLinkDevice sessionQueue - private func configureDevice(_ device: RileyLinkDevice, with session: PumpOpsSession) { - guard !self.configuredDevices.value.contains(device.peripheralIdentifier) else { - return - } - - log.default("Configuring RileyLinkDevice: %{public}@", String(describing: device.deviceURI)) - - do { - _ = try session.configureRadio(for: pumpSettings.pumpRegion, frequency: pumpState.value.lastValidFrequency) - } catch let error { - // Ignore the error and let the block run anyway - log.error("Error configuring device: %{public}@", String(describing: error)) - return - } - - NotificationCenter.default.post(name: .DeviceRadioConfigDidChange, object: device) - NotificationCenter.default.addObserver(self, selector: #selector(deviceRadioConfigDidChange(_:)), name: .DeviceRadioConfigDidChange, object: device) - NotificationCenter.default.addObserver(self, selector: #selector(deviceRadioConfigDidChange(_:)), name: .DeviceConnectionStateDidChange, object: device) - _ = configuredDevices.mutate { (value) in - value.insert(device.peripheralIdentifier) - } - } - - @objc private func deviceRadioConfigDidChange(_ note: Notification) { - guard let device = note.object as? RileyLinkDevice else { - return - } - - NotificationCenter.default.removeObserver(self, name: .DeviceRadioConfigDidChange, object: device) - NotificationCenter.default.removeObserver(self, name: .DeviceConnectionStateDidChange, object: device) - - _ = configuredDevices.mutate { (value) in - value.remove(device.peripheralIdentifier) - } - } -} - -// Delivered on RileyLinkDeviceManager.sessionQueue -extension MinimedPumpOps: PumpOpsSessionDelegate { - public func pumpOpsSessionDidChangeRadioConfig(_ session: PumpOpsSession) { - if let sessionDevice = self.sessionDevice { - self.configuredDevices.value = [sessionDevice.peripheralIdentifier] - } - } - - public func pumpOpsSession(_ session: PumpOpsSession, didChange state: PumpState) { - self.pumpState.value = state - delegate?.pumpOps(self, didChange: state) - NotificationCenter.default.post( - name: .PumpOpsStateDidChange, - object: self, - userInfo: [MinimedPumpOps.notificationPumpStateKey: pumpState] - ) - } -} - - -extension MinimedPumpOps: CustomDebugStringConvertible { - public var debugDescription: String { - return [ - "### PumpOps", - "pumpSettings: \(String(reflecting: pumpSettings))", - "pumpState: \(String(reflecting: pumpState.value))", - "configuredDevices: \(configuredDevices.value.map({ $0.uuidString }))", - ].joined(separator: "\n") - } -} - - -/// Provide a notification contract that clients can use to inform RileyLink UI of changes to PumpOps.PumpState -extension MinimedPumpOps { - public static let notificationPumpStateKey = "com.rileylink.RileyLinkKit.PumpOps.PumpState" -} - - -extension Notification.Name { - public static let PumpOpsStateDidChange = Notification.Name(rawValue: "com.rileylink.RileyLinkKit.PumpOpsStateDidChange") -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpOpsError.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpOpsError.swift deleted file mode 100644 index f879b9db5..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpOpsError.swift +++ /dev/null @@ -1,125 +0,0 @@ -// -// PumpOpsError.swift -// RileyLink -// -// Created by Pete Schwamb on 5/9/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation -import RileyLinkBLEKit - - -/// An error that occurs during a command run -/// -/// - command: The error took place during the command sequence -/// - arguments: The error took place during the argument sequence -public enum PumpCommandError: Error { - case command(PumpOpsError) - case arguments(PumpOpsError) -} - -public enum PumpOpsError: Error { - case bolusInProgress - case couldNotDecode(rx: Data, during: CustomStringConvertible) - case crosstalk(PumpMessage, during: CustomStringConvertible) - case deviceError(LocalizedError) - case noResponse(during: CustomStringConvertible) - case pumpError(PumpErrorCode) - case pumpSuspended - case rfCommsFailure(String) - case unexpectedResponse(PumpMessage, from: PumpMessage) - case unknownPumpErrorCode(UInt8) - case unknownPumpModel(String) - case unknownResponse(rx: Data, during: CustomStringConvertible) -} - -extension PumpOpsError: LocalizedError { - public var errorDescription: String? { - switch self { - case .bolusInProgress: - return LocalizedString("A bolus is already in progress", comment: "Communications error for a bolus currently running") - case .couldNotDecode(rx: let data, during: let during): - return String(format: LocalizedString("Invalid response during %1$@: %2$@", comment: "Format string for failure reason. (1: The operation being performed) (2: The response data)"), String(describing: during), data.hexadecimalString) - case .crosstalk: - return LocalizedString("Comms with another pump detected", comment: "Description for PumpOpsError.crosstalk") - case .noResponse: - return LocalizedString("Pump did not respond", comment: "Description for PumpOpsError.noResponse") - case .pumpSuspended: - return LocalizedString("Pump is suspended", comment: "Description for PumpOpsError.pumpSuspended") - case .rfCommsFailure(let msg): - return msg - case .unexpectedResponse(let response, _): - return String(format: LocalizedString("Unexpected response %1$@", comment: "Format string for an unexpectedResponse. (2: The response)"), String(describing: response)) - case .unknownPumpErrorCode(let code): - return String(format: LocalizedString("Unknown pump error code: %1$@", comment: "The format string description of an unknown pump error code. (1: The specific error code raw value)"), String(describing: code)) - case .unknownPumpModel(let model): - return String(format: LocalizedString("Unknown pump model: %@", comment: ""), model) - case .unknownResponse(rx: let data, during: let during): - return String(format: LocalizedString("Unknown response during %1$@: %2$@", comment: "Format string for an unknown response. (1: The operation being performed) (2: The response data)"), String(describing: during), data.hexadecimalString) - case .pumpError(let errorCode): - return String(describing: errorCode) - case .deviceError(let error): - return [error.errorDescription, error.failureReason].compactMap({ $0 }).joined(separator: ": ") - } - } - - public var recoverySuggestion: String? { - switch self { - case .pumpError(let errorCode): - return errorCode.recoverySuggestion - case .deviceError(let error): - return error.recoverySuggestion - default: - return nil - } - } - - public var helpAnchor: String? { - switch self { - case .deviceError(let error): - return error.helpAnchor - default: - return nil - } - } -} - - -extension PumpCommandError: LocalizedError { - public var errorDescription: String? { - switch self { - case .arguments(let error): - return error.errorDescription - case .command(let error): - return error.errorDescription - } - } - - public var failureReason: String? { - switch self { - case .arguments(let error): - return error.failureReason - case .command(let error): - return error.failureReason - } - } - - public var recoverySuggestion: String? { - switch self { - case .arguments(let error): - return error.recoverySuggestion - case .command(let error): - return error.recoverySuggestion - } - } - - public var helpAnchor: String? { - switch self { - case .arguments(let error): - return error.helpAnchor - case .command(let error): - return error.helpAnchor - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpOpsSession+LoopKit.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpOpsSession+LoopKit.swift deleted file mode 100644 index 6dfad9807..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpOpsSession+LoopKit.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// PumpOpsSession.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - - -extension PumpOpsSession { - public func getBasalRateSchedule(for profile: BasalProfile) throws -> BasalRateSchedule? { - let basalSchedule = try getBasalSchedule(for: profile) - - return BasalRateSchedule(dailyItems: basalSchedule?.entries.map { $0.repeatingScheduleValue } ?? [], timeZone: pump.timeZone) - } -} - - -extension BasalSchedule { - public init(repeatingScheduleValues: [LoopKit.RepeatingScheduleValue]) { - self.init(entries: repeatingScheduleValues.enumerated().map({ (index, value) -> BasalScheduleEntry in - return BasalScheduleEntry(index: index, repeatingScheduleValue: value) - })) - } -} - - -extension MinimedKit.BasalScheduleEntry { - init(index: Int, repeatingScheduleValue: LoopKit.RepeatingScheduleValue) { - self.init(index: index, timeOffset: repeatingScheduleValue.startTime, rate: repeatingScheduleValue.value) - } - - var repeatingScheduleValue: LoopKit.RepeatingScheduleValue { - return RepeatingScheduleValue(startTime: timeOffset, value: rate) - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpOpsSession.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpOpsSession.swift deleted file mode 100644 index ab4cc8341..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpOpsSession.swift +++ /dev/null @@ -1,1160 +0,0 @@ -// -// PumpOpsSynchronous.swift -// RileyLink -// -// Created by Pete Schwamb on 3/12/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit -import RileyLinkBLEKit - - -public protocol PumpOpsSessionDelegate: AnyObject { - func pumpOpsSession(_ session: PumpOpsSession, didChange state: PumpState) - func pumpOpsSessionDidChangeRadioConfig(_ session: PumpOpsSession) -} - -public enum SetBolusError: Error { - case certain(PumpOpsError) - case uncertain(PumpOpsError) -} - -extension SetBolusError: LocalizedError { - public var errorDescription: String? { - switch self { - case .certain(let error): - return error.errorDescription - case .uncertain(let error): - return String(format: LocalizedString("Bolus may have failed: %1$@", comment: "Format string for uncertain bolus. (1: the reported error during bolusing)"), error.localizedDescription) - } - } - - public var recoverySuggestion: String? { - - switch self { - case .certain(let error): - return error.recoverySuggestion - case .uncertain: - return LocalizedString("Please check your pump bolus history to determine if the bolus was delivered.", comment: "recoverySuggestion for uncertain bolus") - } - } - - public var helpAnchor: String? { - switch self { - case .certain(let error): - return error.errorDescription - case .uncertain: - return LocalizedString("Loop sent a bolus command to the pump, but was unable to confirm that the pump received the command. For safety, Loop will assume the bolus was delivered. When Loop eventually fetches history from the pump, and the estimated bolus finish time is passed, Loop will update its records of delivery to match what the pump reports.", comment: "Help anchor for uncertain bolus") - } - } -} - - -public class PumpOpsSession { - - private(set) public var pump: PumpState { - didSet { - delegate.pumpOpsSession(self, didChange: pump) - } - } - public let settings: PumpSettings - private let messageSender: PumpMessageSender - - private unowned let delegate: PumpOpsSessionDelegate - - public init(settings: PumpSettings, pumpState: PumpState, messageSender: PumpMessageSender, delegate: PumpOpsSessionDelegate) { - self.settings = settings - self.pump = pumpState - self.messageSender = messageSender - self.delegate = delegate - } -} - - -// MARK: - Wakeup and power -extension PumpOpsSession { - private static let minimumTimeBetweenWakeAttempts = TimeInterval(minutes: 1) - - /// Attempts to send initial short wakeup message that kicks off the wakeup process. - /// - /// If successful, still does not fully wake up the pump - only alerts it such that the longer wakeup message can be sent next. - /// - /// - Throws: - /// - PumpCommandError.command containing: - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - private func sendWakeUpBurst() throws { - // Skip waking up if we recently tried - guard pump.lastWakeAttempt == nil || pump.lastWakeAttempt!.timeIntervalSinceNow <= -PumpOpsSession.minimumTimeBetweenWakeAttempts - else { - return - } - - pump.lastWakeAttempt = Date() - - let shortPowerMessage = PumpMessage(pumpID: settings.pumpID, type: .powerOn) - - if pump.pumpModel == nil || !pump.pumpModel!.hasMySentry { - // Older pumps have a longer sleep cycle between wakeups, so send an initial burst - do { - let _: PumpAckMessageBody = try messageSender.getResponse(to: shortPowerMessage, responseType: .pumpAck, repeatCount: 255, timeout: .milliseconds(1), retryCount: 0) - } - catch { } - } - - do { - let _: PumpAckMessageBody = try messageSender.getResponse(to: shortPowerMessage, responseType: .pumpAck, repeatCount: 255, timeout: .seconds(12), retryCount: 0) - } catch let error as PumpOpsError { - throw PumpCommandError.command(error) - } - } - - private func isPumpResponding() -> Bool { - do { - let _: GetPumpModelCarelinkMessageBody = try messageSender.getResponse(to: PumpMessage(pumpID: settings.pumpID, type: .getPumpModel), responseType: .getPumpModel, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 1) - return true - } catch { - return false - } - } - - /// - Throws: - /// - PumpCommandError.command - /// - PumpCommandError.arguments - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - private func wakeup(_ duration: TimeInterval = TimeInterval(minutes: 1)) throws { - guard !pump.isAwake else { - return - } - - // Send a short message to the pump to see if its radio is still powered on - if isPumpResponding() { - // TODO: Convert logging - NSLog("Pump responding despite our wake timer having expired. Extending timer") - // By my observations, the pump stays awake > 1 minute past last comms. Usually - // About 1.5 minutes, but we'll make it a minute to be safe. - pump.awakeUntil = Date(timeIntervalSinceNow: TimeInterval(minutes: 1)) - return - } - - // Command - try sendWakeUpBurst() - - // Arguments - do { - let longPowerMessage = PumpMessage(pumpID: settings.pumpID, type: .powerOn, body: PowerOnCarelinkMessageBody(duration: duration)) - let _: PumpAckMessageBody = try messageSender.getResponse(to: longPowerMessage, responseType: .pumpAck, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - } catch let error as PumpOpsError { - throw PumpCommandError.arguments(error) - } catch { - assertionFailure() - } - - // TODO: Convert logging - NSLog("Power on for %.0f minutes", duration.minutes) - pump.awakeUntil = Date(timeIntervalSinceNow: duration) - } -} - -// MARK: - Single reads -extension PumpOpsSession { - /// Retrieves the pump model from either the state or from the cache - /// - /// - Parameter usingCache: Whether the pump state should be checked first for a known pump model - /// - Returns: The pump model - /// - Throws: - /// - PumpCommandError.command - /// - PumpCommandError.arguments - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - public func getPumpModel(usingCache: Bool = true) throws -> PumpModel { - if usingCache, let pumpModel = pump.pumpModel { - return pumpModel - } - - try wakeup() - let body: GetPumpModelCarelinkMessageBody = try messageSender.getResponse(to: PumpMessage(pumpID: settings.pumpID, type: .getPumpModel), responseType: .getPumpModel, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - - guard let pumpModel = PumpModel(rawValue: body.model) else { - throw PumpOpsError.unknownPumpModel(body.model) - } - - pump.pumpModel = pumpModel - - return pumpModel - } - - /// Retrieves the pump firmware version - /// - /// - Returns: The pump firmware version as string - /// - Throws: - /// - PumpCommandError.command - /// - PumpCommandError.arguments - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - public func getPumpFirmwareVersion() throws -> String { - - try wakeup() - let body: GetPumpFirmwareVersionMessageBody = try messageSender.getResponse(to: PumpMessage(pumpID: settings.pumpID, type: .readFirmwareVersion), responseType: .readFirmwareVersion, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - - return body.version - } - - /// - Throws: - /// - PumpCommandError.command - /// - PumpCommandError.arguments - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - public func getBatteryStatus() throws -> GetBatteryCarelinkMessageBody { - try wakeup() - return try messageSender.getResponse(to: PumpMessage(pumpID: settings.pumpID, type: .getBattery), responseType: .getBattery, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - } - - /// - Throws: - /// - PumpCommandError.command - /// - PumpCommandError.arguments - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - internal func getPumpStatus() throws -> ReadPumpStatusMessageBody { - try wakeup() - return try messageSender.getResponse(to: PumpMessage(pumpID: settings.pumpID, type: .readPumpStatus), responseType: .readPumpStatus, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - } - - /// - Throws: - /// - PumpCommandError.command - /// - PumpCommandError.arguments - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - public func getSettings() throws -> ReadSettingsCarelinkMessageBody { - try wakeup() - return try messageSender.getResponse(to: PumpMessage(pumpID: settings.pumpID, type: .readSettings), responseType: .readSettings, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - } - - /// Reads the pump's time, returning a set of DateComponents in the pump's presumed time zone. - /// - /// - Returns: The pump's time components including timeZone - /// - Throws: - /// - PumpCommandError.command - /// - PumpCommandError.arguments - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - public func getTime() throws -> DateComponents { - try wakeup() - let response: ReadTimeCarelinkMessageBody = try messageSender.getResponse(to: PumpMessage(pumpID: settings.pumpID, type: .readTime), responseType: .readTime, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - var components = response.dateComponents - components.timeZone = pump.timeZone - return components - } - - /// Reads Basal Schedule from the pump - /// - /// - Returns: The pump's standard basal schedule - /// - Throws: - /// - PumpCommandError.command - /// - PumpCommandError.arguments - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - public func getBasalSchedule(for profile: BasalProfile = .standard) throws -> BasalSchedule? { - try wakeup() - - var isFinished = false - var message = PumpMessage(pumpID: settings.pumpID, type: profile.readMessageType) - var scheduleData = Data() - while (!isFinished) { - let body: DataFrameMessageBody = try messageSender.getResponse(to: message, responseType: profile.readMessageType, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - - scheduleData.append(body.contents) - isFinished = body.isLastFrame - message = PumpMessage(pumpID: settings.pumpID, type: .pumpAck) - } - - return BasalSchedule(rawValue: scheduleData) - } - - /// - Throws: - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - public func getOtherDevicesIDs() throws -> ReadOtherDevicesIDsMessageBody { - try wakeup() - - return try messageSender.getResponse(to: PumpMessage(pumpID: settings.pumpID, type: .readOtherDevicesIDs), responseType: .readOtherDevicesIDs, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - } - - /// - Throws: - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - public func getOtherDevicesEnabled() throws -> Bool { - try wakeup() - - let response: ReadOtherDevicesStatusMessageBody = try messageSender.getResponse(to: PumpMessage(pumpID: settings.pumpID, type: .readOtherDevicesStatus), responseType: .readOtherDevicesStatus, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - return response.isEnabled - } - - /// - Throws: - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - public func getRemoteControlIDs() throws -> ReadRemoteControlIDsMessageBody { - try wakeup() - - return try messageSender.getResponse(to: PumpMessage(pumpID: settings.pumpID, type: .readRemoteControlIDs), responseType: .readRemoteControlIDs, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - } -} - - -// MARK: - Aggregate reads -public struct PumpStatus: Equatable { - // Date components read from the pump, along with PumpState.timeZone - public let clock: DateComponents - public let batteryVolts: Measurement - public let batteryStatus: BatteryStatus - public let suspended: Bool - public let bolusing: Bool - public let reservoir: Double - public let model: PumpModel - public let pumpID: String -} - - -extension PumpOpsSession { - /// Reads the current insulin reservoir volume and the pump's date - /// - /// - Returns: - /// - The reservoir volume, in units of insulin - /// - DateCompoments representing the pump's clock - /// - Throws: - /// - PumpCommandError.command - /// - PumpCommandError.arguments - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unknownResponse - public func getRemainingInsulin() throws -> (units: Double, clock: DateComponents) { - - let pumpModel = try getPumpModel() - let pumpClock = try getTime() - - let reservoir: ReadRemainingInsulinMessageBody = try messageSender.getResponse(to: PumpMessage(pumpID: settings.pumpID, type: .readRemainingInsulin), responseType: .readRemainingInsulin, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - - return ( - units: reservoir.getUnitsRemaining(insulinBitPackingScale: pumpModel.insulinBitPackingScale), - clock: pumpClock - ) - } - - /// Reads clock, reservoir, battery, bolusing, and suspended state from pump - /// - /// - Returns: The pump status - /// - Throws: - /// - PumpCommandError - /// - PumpOpsError - public func getCurrentPumpStatus() throws -> PumpStatus { - let pumpModel = try getPumpModel() - - let battResp = try getBatteryStatus() - - let status = try getPumpStatus() - - let (reservoir, clock) = try getRemainingInsulin() - - return PumpStatus( - clock: clock, - batteryVolts: Measurement(value: battResp.volts, unit: UnitElectricPotentialDifference.volts), - batteryStatus: battResp.status, - suspended: status.suspended, - bolusing: status.bolusing, - reservoir: reservoir, - model: pumpModel, - pumpID: settings.pumpID - ) - } -} - - -// MARK: - Command messages -extension PumpOpsSession { - - enum CommandTestingFailureMode { - case argumentFailureDoSendArguments - case argumentFailureDoNotSendArguments - } - - /// - Throws: `PumpCommandError` specifying the failure sequence - private func runCommandWithArguments(_ message: PumpMessage, responseType: MessageType = .pumpAck, retryCount: Int = 3, testingFailureMode: CommandTestingFailureMode? = nil) throws -> T { - do { - try wakeup() - - let shortMessage = PumpMessage(packetType: message.packetType, address: message.address.hexadecimalString, messageType: message.messageType, messageBody: CarelinkShortMessageBody()) - let _: PumpAckMessageBody = try messageSender.getResponse(to: shortMessage, responseType: .pumpAck, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - } catch let error as PumpOpsError { - throw PumpCommandError.command(error) - } - - do { - if testingFailureMode == .argumentFailureDoNotSendArguments { - throw PumpOpsError.noResponse(during: "argumentFailureDoNotSendArguments") - } - let response: T = try messageSender.getResponse(to: message, responseType: responseType, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: retryCount) - if testingFailureMode == .argumentFailureDoSendArguments { - throw PumpOpsError.noResponse(during: "argumentFailureDoSendArguments") - } - return response - - } catch let error as PumpOpsError { - throw PumpCommandError.arguments(error) - } - } - - /// - Throws: `PumpCommandError` specifying the failure sequence - public func pressButton(_ type: ButtonPressCarelinkMessageBody.ButtonType) throws { - let message = PumpMessage(pumpID: settings.pumpID, type: .buttonPress, body: ButtonPressCarelinkMessageBody(buttonType: type)) - - let _: PumpAckMessageBody = try runCommandWithArguments(message) - } - - /// - Throws: `PumpCommandError` specifying the failure sequence - public func setSuspendResumeState(_ state: SuspendResumeMessageBody.SuspendResumeState) throws { - let message = PumpMessage(pumpID: settings.pumpID, type: .suspendResume, body: SuspendResumeMessageBody(state: state)) - - let _: PumpAckMessageBody = try runCommandWithArguments(message) - } - - /// - Throws: PumpCommandError - public func selectBasalProfile(_ profile: BasalProfile) throws { - let message = PumpMessage(pumpID: settings.pumpID, type: .selectBasalProfile, body: SelectBasalProfileMessageBody(newProfile: profile)) - - let _: PumpAckMessageBody = try runCommandWithArguments(message) - } - - /// - Throws: PumpCommandError - public func setMaxBasalRate(unitsPerHour: Double) throws { - guard let body = ChangeMaxBasalRateMessageBody(maxBasalUnitsPerHour: unitsPerHour) else { - throw PumpCommandError.command(PumpOpsError.pumpError(PumpErrorCode.maxSettingExceeded)) - } - - let message = PumpMessage(pumpID: settings.pumpID, type: .setMaxBasalRate, body: body) - - let _: PumpAckMessageBody = try runCommandWithArguments(message) - } - - /// - Throws: PumpCommandError - public func setMaxBolus(units: Double) throws { - guard let body = ChangeMaxBolusMessageBody(pumpModel: try getPumpModel(), maxBolusUnits: units) else { - throw PumpCommandError.command(PumpOpsError.pumpError(PumpErrorCode.maxSettingExceeded)) - } - - let message = PumpMessage(pumpID: settings.pumpID, type: .setMaxBolus, body: body) - - let _: PumpAckMessageBody = try runCommandWithArguments(message) - } - - /// Changes the current temporary basal rate - /// - /// - Parameters: - /// - unitsPerHour: The new basal rate, in Units per hour - /// - duration: The duration of the rate - /// - Returns: - /// - .success: A bool that indicates if the dose was confirmed successful - /// - .failure: An error describing why the command failed - public func setTempBasal(_ unitsPerHour: Double, duration: TimeInterval) -> Result { - - let message = PumpMessage(pumpID: settings.pumpID, type: .changeTempBasal, body: ChangeTempBasalCarelinkMessageBody(unitsPerHour: unitsPerHour, duration: duration)) - - do { - try wakeup() - } catch { - // Certain failure, as we haven't sent actual command yet; wakeup failed - return .failure(.command(error as? PumpOpsError ?? PumpOpsError.rfCommsFailure(String(describing: error)))) - } - - do { - let shortMessage = PumpMessage(packetType: message.packetType, address: message.address.hexadecimalString, messageType: message.messageType, messageBody: CarelinkShortMessageBody()) - let _: PumpAckMessageBody = try messageSender.getResponse(to: shortMessage, responseType: .pumpAck, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - } catch { - // Certain failure, as we haven't sent actual command yet; just preflight short command - return .failure(.command(error as? PumpOpsError ?? PumpOpsError.rfCommsFailure(String(describing: error)))) - } - - var uncertainFailureError: PumpCommandError? - - do { - let _: PumpAckMessageBody = try messageSender.getResponse(to: message, responseType: .pumpAck, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 1) - // Even in success case, we try to verify, below - } catch PumpOpsError.pumpError(let errorCode) { - return .failure(.arguments(.pumpError(errorCode))) - } catch PumpOpsError.unknownPumpErrorCode(let errorCode) { - return .failure(.arguments(.unknownPumpErrorCode(errorCode))) - } catch { - // Some pumps do not ACK a successful temp basal. Check manually to see if it was successful. - uncertainFailureError = .command(error as? PumpOpsError ?? PumpOpsError.rfCommsFailure(String(describing: error))) - } - - do { - let response: ReadTempBasalCarelinkMessageBody = try messageSender.getResponse(to: PumpMessage(pumpID: settings.pumpID, type: .readTempBasal), responseType: .readTempBasal, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - // Duration is always whole minute values - if response.timeRemaining == duration && response.rateType == .absolute { - return .success(true) - } else { - // readTempBasal does not match what we attempted to command - if let failureError = uncertainFailureError { - return .failure(failureError) - } - // successful readTempBasal shows no temp basal running, so we failed - return .failure(PumpCommandError.arguments(PumpOpsError.rfCommsFailure("Confirmed that temp basal failed, and "))) - } - } catch { - // unsuccessful readTempBasal; assume command reached pump, but we're uncertain - return .success(false) - } - } - - /// Changes the pump's clock to the specified date components in the system time zone - /// - /// - Parameter generator: A closure which returns the desired date components. An exeception is raised if the date components are not valid. - /// - Throws: PumpCommandError - public func setTime(_ generator: () -> DateComponents) throws { - try wakeup() - - do { - let shortMessage = PumpMessage(pumpID: settings.pumpID, type: .changeTime) - let _: PumpAckMessageBody = try messageSender.getResponse(to: shortMessage, responseType: .pumpAck, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - } catch let error as PumpOpsError { - throw PumpCommandError.command(error) - } - - do { - let components = generator() - let message = PumpMessage(pumpID: settings.pumpID, type: .changeTime, body: ChangeTimeCarelinkMessageBody(dateComponents: components)!) - let _: PumpAckMessageBody = try messageSender.getResponse(to: message, responseType: .pumpAck, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - self.pump.timeZone = components.timeZone?.fixed ?? .currentFixed - } catch let error as PumpOpsError { - throw PumpCommandError.arguments(error) - } - } - - public func setTimeToNow(in timeZone: TimeZone? = nil) throws { - let timeZone = timeZone ?? pump.timeZone - - try setTime { () -> DateComponents in - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = timeZone - var components = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: Date()) - components.timeZone = timeZone - return components - } - } - - /// Sets a bolus - /// - /// *Note: Use at your own risk!* - /// - /// - Parameters: - /// - units: The number of units to deliver - /// - cancelExistingTemp: If true, additional pump commands will be issued to clear any running temp basal. Defaults to false. - /// - Returns: SetBolusError if the command failed - public func setNormalBolus(units: Double) -> SetBolusError? { - let pumpModel: PumpModel - - do { - try wakeup() - pumpModel = try getPumpModel() - - let status = try getPumpStatus() - - if status.bolusing { - throw PumpOpsError.bolusInProgress - } - - if status.suspended { - throw PumpOpsError.pumpSuspended - } - - } catch let error as PumpOpsError { - return SetBolusError.certain(error) - } catch let error as PumpCommandError { - switch error { - case .command(let error): - return SetBolusError.certain(error) - case .arguments(let error): - return SetBolusError.certain(error) - } - } catch { - return SetBolusError.certain(PumpOpsError.rfCommsFailure(String(describing: error))) - } - - do { - let message = PumpMessage(pumpID: settings.pumpID, type: .bolus, body: BolusCarelinkMessageBody(units: units, insulinBitPackingScale: pumpModel.insulinBitPackingScale)) - - let testMode: CommandTestingFailureMode? = nil - - // Uncomment for manual testing of uncertain delivery states -// if units == 9.05 { -// testMode = .argumentFailureDoNotSendArguments -// } else if units == 8.05 { -// testMode = .argumentFailureDoSendArguments -// } else { -// testMode = nil -// } - - let _: PumpAckMessageBody = try runCommandWithArguments(message, testingFailureMode: testMode) - } catch let error as PumpOpsError { - return SetBolusError.certain(error) - } catch let error as PumpCommandError { - switch error { - case .command(let error): - return SetBolusError.certain(error) - case .arguments(let error): - return SetBolusError.uncertain(error) - } - } catch { - assertionFailure() - } - return nil - } - - /// - Throws: PumpCommandError - public func setRemoteControlEnabled(_ enabled: Bool) throws { - let message = PumpMessage(pumpID: settings.pumpID, type: .setRemoteControlEnabled, body: SetRemoteControlEnabledMessageBody(enabled: enabled)) - - let _: PumpAckMessageBody = try runCommandWithArguments(message) - } - - /// - Throws: PumpCommandError - public func setRemoteControlID(_ id: Data, atIndex index: Int) throws { - guard let body = ChangeRemoteControlIDMessageBody(id: id, index: index) else { - throw PumpCommandError.command(PumpOpsError.pumpError(PumpErrorCode.maxSettingExceeded)) - } - - let message = PumpMessage(pumpID: settings.pumpID, type: .setRemoteControlID, body: body) - - let _: PumpAckMessageBody = try runCommandWithArguments(message) - } - - /// - Throws: PumpCommandError - public func removeRemoteControlID(atIndex index: Int) throws { - guard let body = ChangeRemoteControlIDMessageBody(id: nil, index: index) else { - throw PumpCommandError.command(PumpOpsError.pumpError(PumpErrorCode.maxSettingExceeded)) - } - - let message = PumpMessage(pumpID: settings.pumpID, type: .setRemoteControlID, body: body) - - let _: PumpAckMessageBody = try runCommandWithArguments(message) - } - - /// - Throws: `PumpCommandError` specifying the failure sequence - public func setBasalSchedule(_ basalSchedule: BasalSchedule, for profile: BasalProfile) throws { - - let frames = DataFrameMessageBody.dataFramesFromContents(basalSchedule.rawValue) - - guard let firstFrame = frames.first else { - return - } - - let type: MessageType - switch profile { - case .standard: - type = .setBasalProfileStandard - case .profileA: - type = .setBasalProfileA - case .profileB: - type = .setBasalProfileB - } - - let message = PumpMessage(pumpID: settings.pumpID, type: type, body: firstFrame) - let _: PumpAckMessageBody = try runCommandWithArguments(message) - - for nextFrame in frames.dropFirst() { - let message = PumpMessage(pumpID: settings.pumpID, type: type, body: nextFrame) - do { - let _: PumpAckMessageBody = try messageSender.getResponse(to: message, responseType: .pumpAck, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - } catch let error as PumpOpsError { - throw PumpCommandError.arguments(error) - } - } - } - - public func getStatistics() throws -> RileyLinkStatistics { - return try messageSender.getRileyLinkStatistics() - } -} - - -// MARK: - MySentry (Watchdog) pairing -extension PumpOpsSession { - /// Pairs the pump with a virtual "watchdog" device to enable it to broadcast periodic status packets. Only pump models x23 and up are supported. - /// - /// - Parameter watchdogID: A 3-byte address for the watchdog device. - /// - Throws: - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unexpectedResponse - /// - PumpOpsError.unknownResponse - public func changeWatchdogMarriageProfile(_ watchdogID: Data) throws { - let commandTimeout = TimeInterval(seconds: 30) - - // Wait for the pump to start polling - guard let encodedData = try messageSender.listenForPacket(onChannel: 0, timeout: commandTimeout)?.data else { - throw PumpOpsError.noResponse(during: "Watchdog listening") - } - - guard let packet = MinimedPacket(encodedData: encodedData) else { - throw PumpOpsError.couldNotDecode(rx: encodedData, during: "Watchdog listening") - } - - guard let findMessage = PumpMessage(rxData: packet.data) else { - // Unknown packet type or message type - throw PumpOpsError.unknownResponse(rx: packet.data, during: "Watchdog listening") - } - - guard findMessage.address.hexadecimalString == settings.pumpID && findMessage.packetType == .mySentry, - let findMessageBody = findMessage.messageBody as? FindDeviceMessageBody, let findMessageResponseBody = MySentryAckMessageBody(sequence: findMessageBody.sequence, watchdogID: watchdogID, responseMessageTypes: [findMessage.messageType]) - else { - throw PumpOpsError.unknownResponse(rx: packet.data, during: "Watchdog listening") - } - - // Identify as a MySentry device - let findMessageResponse = PumpMessage(packetType: .mySentry, address: settings.pumpID, messageType: .pumpAck, messageBody: findMessageResponseBody) - - let linkMessage = try messageSender.sendAndListen(findMessageResponse, repeatCount: 0, timeout: commandTimeout, retryCount: 3) - - guard let - linkMessageBody = linkMessage.messageBody as? DeviceLinkMessageBody, - let linkMessageResponseBody = MySentryAckMessageBody(sequence: linkMessageBody.sequence, watchdogID: watchdogID, responseMessageTypes: [linkMessage.messageType]) - else { - throw PumpOpsError.unexpectedResponse(linkMessage, from: findMessageResponse) - } - - // Acknowledge the pump linked with us - let linkMessageResponse = PumpMessage(packetType: .mySentry, address: settings.pumpID, messageType: .pumpAck, messageBody: linkMessageResponseBody) - - try messageSender.send(linkMessageResponse) - } -} - - -// MARK: - Tuning -private extension PumpRegion { - var scanFrequencies: [Measurement] { - let scanFrequencies: [Double] - - switch self { - case .worldWide: - scanFrequencies = [868.25, 868.30, 868.35, 868.40, 868.45, 868.50, 868.55, 868.60, 868.65] - case .northAmerica, .canada: - scanFrequencies = [916.45, 916.50, 916.55, 916.60, 916.65, 916.70, 916.75, 916.80] - } - - return scanFrequencies.map { - return Measurement(value: $0, unit: .megahertz) - } - } -} - -enum RXFilterMode: UInt8 { - case wide = 0x50 // 300KHz - case narrow = 0x90 // 150KHz -} - -public struct FrequencyTrial { - public var tries: Int = 0 - public var successes: Int = 0 - public var avgRSSI: Double = -99 - public var frequency: Measurement - - init(frequency: Measurement) { - self.frequency = frequency - } -} - -public struct FrequencyScanResults { - public var trials: [FrequencyTrial] - public var bestFrequency: Measurement -} - -extension PumpOpsSession { - /// - Throws: - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.rfCommsFailure - public func tuneRadio(attempts: Int = 3) throws -> FrequencyScanResults { - let region = self.settings.pumpRegion - - do { - let results = try scanForPump(in: region.scanFrequencies, fallback: pump.lastValidFrequency, tries: attempts) - - pump.lastValidFrequency = results.bestFrequency - pump.lastTuned = Date() - - delegate.pumpOpsSessionDidChangeRadioConfig(self) - - return results - } catch let error as PumpOpsError { - throw error - } catch let error as LocalizedError { - throw PumpOpsError.deviceError(error) - } - } - - /// - Throws: PumpOpsError.deviceError - private func setRXFilterMode(_ mode: RXFilterMode) throws { - let drate_e = UInt8(0x9) // exponent of symbol rate (16kbps) - let chanbw = mode.rawValue - do { - try messageSender.updateRegister(.mdmcfg4, value: chanbw | drate_e) - } catch let error as LocalizedError { - throw PumpOpsError.deviceError(error) - } - } - - /// - Throws: - /// - PumpOpsError.deviceError - /// - RileyLinkDeviceError - func configureRadio(for region: PumpRegion, frequency: Measurement?) throws { - try messageSender.resetRadioConfig() - - switch region { - case .worldWide: - //try session.updateRegister(.mdmcfg4, value: 0x59) - try setRXFilterMode(.wide) - //try session.updateRegister(.mdmcfg3, value: 0x66) - //try session.updateRegister(.mdmcfg2, value: 0x33) - try messageSender.updateRegister(.mdmcfg1, value: 0x62) - try messageSender.updateRegister(.mdmcfg0, value: 0x1A) - try messageSender.updateRegister(.deviatn, value: 0x13) - case .northAmerica, .canada: - //try session.updateRegister(.mdmcfg4, value: 0x99) - try setRXFilterMode(.narrow) - //try session.updateRegister(.mdmcfg3, value: 0x66) - //try session.updateRegister(.mdmcfg2, value: 0x33) - try messageSender.updateRegister(.mdmcfg1, value: 0x61) - try messageSender.updateRegister(.mdmcfg0, value: 0x7E) - try messageSender.updateRegister(.deviatn, value: 0x15) - } - - if let frequency = frequency { - try messageSender.setBaseFrequency(frequency) - } - } - - /// - Throws: - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.rfCommsFailure - /// - LocalizedError - private func scanForPump(in frequencies: [Measurement], fallback: Measurement?, tries: Int = 3) throws -> FrequencyScanResults { - - var trials = [FrequencyTrial]() - - let middleFreq = frequencies[frequencies.count / 2] - - do { - // Needed to put the pump in listen mode - try messageSender.setBaseFrequency(middleFreq) - try wakeup() - } catch { - // Continue anyway; the pump likely heard us, even if we didn't hear it. - } - - for freq in frequencies { - var trial = FrequencyTrial(frequency: freq) - - try messageSender.setBaseFrequency(freq) - var sumRSSI = 0 - for _ in 1...tries { - // Ignore failures here - let rfPacket = try? messageSender.sendAndListenForPacket(PumpMessage(pumpID: settings.pumpID, type: .getPumpModel), repeatCount: 0, timeout: .milliseconds(130), retryCount: 3) - if let rfPacket = rfPacket, - let pkt = MinimedPacket(encodedData: rfPacket.data), - let response = PumpMessage(rxData: pkt.data), response.messageType == .getPumpModel - { - sumRSSI += rfPacket.rssi - trial.successes += 1 - } - trial.tries += 1 - } - // Mark each failure as a -99 rssi, so we can use highest rssi as best freq - sumRSSI += -99 * (trial.tries - trial.successes) - trial.avgRSSI = Double(sumRSSI) / Double(trial.tries) - trials.append(trial) - } - let sortedTrials = trials.sorted(by: { (a, b) -> Bool in - return a.avgRSSI > b.avgRSSI - }) - - guard sortedTrials.first!.successes > 0 else { - try messageSender.setBaseFrequency(fallback ?? middleFreq) - throw PumpOpsError.rfCommsFailure("No pump responses during scan") - } - - let results = FrequencyScanResults( - trials: trials, - bestFrequency: sortedTrials.first!.frequency - ) - - try messageSender.setBaseFrequency(results.bestFrequency) - - return results - } -} - - -// MARK: - Pump history -extension PumpOpsSession { - /// Fetches history entries which occurred on or after the specified date. - /// - /// It is possible for Minimed Pumps to non-atomically append multiple history entries with the same timestamp, for example, `BolusWizardEstimatePumpEvent` may appear and be read before `BolusNormalPumpEvent` is written. Therefore, the `startDate` parameter is used as part of an inclusive range, leaving the client to manage the possibility of duplicates. - /// - /// History timestamps are reconciled with UTC based on the `timeZone` property of PumpState, as well as recorded clock change events. - /// - /// - Parameter startDate: The earliest date of events to retrieve - /// - Returns: - /// - An array of fetched history entries, in ascending order of insertion - /// - The pump model - /// - Throws: - /// - PumpCommandError.command - /// - PumpCommandError.arguments - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unknownResponse - /// - HistoryPageError.invalidCRC - /// - HistoryPageError.unknownEventType - public func getHistoryEvents(since startDate: Date) throws -> ([TimestampedHistoryEvent], PumpModel) { - try wakeup() - - let pumpModel = try getPumpModel() - - var events = [TimestampedHistoryEvent]() - - pages: for pageNum in 0..<16 { - // TODO: Convert logging - NSLog("Fetching page %d", pageNum) - let pageData: Data - - do { - pageData = try getHistoryPage(pageNum) - } catch PumpCommandError.arguments(let error) { - if case PumpOpsError.pumpError(.pageDoesNotExist) = error { - return (events, pumpModel) - } - throw PumpCommandError.arguments(error) - } - - var idx = 0 - let chunkSize = 256 - while idx < pageData.count { - let top = min(idx + chunkSize, pageData.count) - let range = Range(uncheckedBounds: (lower: idx, upper: top)) - // TODO: Convert logging - NSLog(String(format: "HistoryPage %02d - (bytes %03d-%03d): ", pageNum, idx, top-1) + pageData.subdata(in: range).hexadecimalString) - idx = top - } - - let page = try HistoryPage(pageData: pageData, pumpModel: pumpModel) - - let (timestampedEvents, hasMoreEvents, _) = page.timestampedEvents(after: startDate, timeZone: pump.timeZone, model: pumpModel) - - events = timestampedEvents + events - - if !hasMoreEvents { - break - } - } - return (events, pumpModel) - } - - private func getHistoryPage(_ pageNum: Int) throws -> Data { - var frameData = Data() - - let msg = PumpMessage(pumpID: settings.pumpID, type: .getHistoryPage, body: GetHistoryPageCarelinkMessageBody(pageNum: pageNum)) - - var curResp: GetHistoryPageCarelinkMessageBody = try runCommandWithArguments(msg, responseType: .getHistoryPage) - - var expectedFrameNum = 1 - - while(expectedFrameNum == curResp.frameNumber) { - frameData.append(curResp.frame) - expectedFrameNum += 1 - let msg = PumpMessage(pumpID: settings.pumpID, type: .pumpAck) - if !curResp.lastFrame { - curResp = try messageSender.getResponse(to: msg, responseType: .getHistoryPage, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - } else { - try messageSender.send(msg) - break - } - } - - guard frameData.count == 1024 else { - throw PumpOpsError.rfCommsFailure("Short history page: \(frameData.count) bytes. Expected 1024") - } - return frameData - } -} - - -// MARK: - Glucose history -extension PumpOpsSession { - private func logGlucoseHistory(pageData: Data, pageNum: Int) { - var idx = 0 - let chunkSize = 256 - while idx < pageData.count { - let top = min(idx + chunkSize, pageData.count) - let range = Range(uncheckedBounds: (lower: idx, upper: top)) - // TODO: Convert logging - NSLog(String(format: "GlucosePage %02d - (bytes %03d-%03d): ", pageNum, idx, top-1) + pageData.subdata(in: range).hexadecimalString) - idx = top - } - } - - /// Fetches glucose history entries which occurred on or after the specified date. - /// - /// History timestamps are reconciled with UTC based on the `timeZone` property of PumpState, as well as recorded clock change events. - /// - /// - Parameter startDate: The earliest date of events to retrieve - /// - Returns: An array of fetched history entries, in ascending order of insertion - /// - Throws: - public func getGlucoseHistoryEvents(since startDate: Date) throws -> [TimestampedGlucoseEvent] { - try wakeup() - - var events = [TimestampedGlucoseEvent]() - - let currentGlucosePage: ReadCurrentGlucosePageMessageBody = try messageSender.getResponse(to: PumpMessage(pumpID: settings.pumpID, type: .readCurrentGlucosePage), responseType: .readCurrentGlucosePage, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - let startPage = Int(currentGlucosePage.pageNum) - //max lookback of 15 pages or when page is 0 - let endPage = max(startPage - 15, 0) - - pages: for pageNum in stride(from: startPage, to: endPage - 1, by: -1) { - // TODO: Convert logging - NSLog("Fetching page %d", pageNum) - var pageData: Data - var page: GlucosePage - - do { - pageData = try getGlucosePage(UInt32(pageNum)) - // logGlucoseHistory(pageData: pageData, pageNum: pageNum) - page = try GlucosePage(pageData: pageData) - - if page.needsTimestamp && pageNum == startPage { - // TODO: Convert logging - NSLog(String(format: "GlucosePage %02d needs a new sensor timestamp, writing...", pageNum)) - let _ = try writeGlucoseHistoryTimestamp() - - //fetch page again with new sensor timestamp - pageData = try getGlucosePage(UInt32(pageNum)) - logGlucoseHistory(pageData: pageData, pageNum: pageNum) - page = try GlucosePage(pageData: pageData) - } - } catch PumpOpsError.pumpError { - break pages - } - - for event in page.events.reversed() { - var timestamp = event.timestamp - timestamp.timeZone = pump.timeZone - - if event is UnknownGlucoseEvent { - continue pages - } - - if let date = timestamp.date { - if date < startDate && event is SensorTimestampGlucoseEvent { - // TODO: Convert logging - NSLog("Found reference event at (%@) to be before startDate(%@)", date as NSDate, startDate as NSDate) - break pages - } else { - events.insert(TimestampedGlucoseEvent(glucoseEvent: event, date: date), at: 0) - } - } - } - } - return events - } - - private func getGlucosePage(_ pageNum: UInt32) throws -> Data { - var frameData = Data() - - let msg = PumpMessage(pumpID: settings.pumpID, type: .getGlucosePage, body: GetGlucosePageMessageBody(pageNum: pageNum)) - - var curResp: GetGlucosePageMessageBody = try runCommandWithArguments(msg, responseType: .getGlucosePage) - - var expectedFrameNum = 1 - - while(expectedFrameNum == curResp.frameNumber) { - frameData.append(curResp.frame) - expectedFrameNum += 1 - let msg = PumpMessage(pumpID: settings.pumpID, type: .pumpAck) - if !curResp.lastFrame { - curResp = try messageSender.getResponse(to: msg, responseType: .getGlucosePage, repeatCount: 0, timeout: MinimedPumpMessageSender.standardPumpResponseWindow, retryCount: 3) - } else { - try messageSender.send(msg) - break - } - } - - guard frameData.count == 1024 else { - throw PumpOpsError.rfCommsFailure("Short glucose history page: \(frameData.count) bytes. Expected 1024") - } - return frameData - } - - public func writeGlucoseHistoryTimestamp() throws -> Void { - try wakeup() - - let shortWriteTimestamp = PumpMessage(pumpID: settings.pumpID, type: .writeGlucoseHistoryTimestamp) - let _: PumpAckMessageBody = try messageSender.getResponse(to: shortWriteTimestamp, responseType: .pumpAck, repeatCount: 0, timeout: .seconds(12), retryCount: 3) - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpSettings.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpSettings.swift deleted file mode 100644 index 4a964ff3c..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpSettings.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// PumpSettings.swift -// RileyLinkKit -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - - -public struct PumpSettings: RawRepresentable { - public typealias RawValue = [String: Any] - - public var pumpID: String - - public var pumpRegion: PumpRegion = .northAmerica - - public init?(rawValue: RawValue) { - guard let pumpID = rawValue["pumpID"] as? String else { - return nil - } - - self.pumpID = pumpID - - if let pumpRegionRaw = rawValue["pumpRegion"] as? PumpRegion.RawValue, - let pumpRegion = PumpRegion(rawValue: pumpRegionRaw) { - self.pumpRegion = pumpRegion - } - } - - public init(pumpID: String, pumpRegion: PumpRegion? = nil) { - self.pumpID = pumpID - - if let pumpRegion = pumpRegion { - self.pumpRegion = pumpRegion - } - } - - public var rawValue: RawValue { - return [ - "pumpID": pumpID, - "pumpRegion": pumpRegion.rawValue - ] - } -} - - -extension PumpSettings: CustomDebugStringConvertible { - public var debugDescription: String { - return [ - "## PumpSettings", - "pumpID: ✔︎", - "pumpRegion: \(pumpRegion)", - ].joined(separator: "\n") - } -} - -extension PumpSettings: Equatable { - public static func ==(lhs: PumpSettings, rhs: PumpSettings) -> Bool { - return lhs.pumpID == rhs.pumpID && lhs.pumpRegion == rhs.pumpRegion - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpState.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpState.swift deleted file mode 100644 index d61082c79..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/PumpState.swift +++ /dev/null @@ -1,101 +0,0 @@ -// -// PumpState.swift -// RileyLink -// -// Created by Nathan Racklyeft on 4/9/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - - -public struct PumpState: RawRepresentable, Equatable { - public typealias RawValue = [String: Any] - - public var timeZone: TimeZone - - public var pumpModel: PumpModel? - - public var useMySentry: Bool - - public var awakeUntil: Date? - - public var lastValidFrequency: Measurement? - - public var lastTuned: Date? - - var isAwake: Bool { - if let awakeUntil = awakeUntil { - return awakeUntil.timeIntervalSinceNow > 0 - } - - return false - } - - var lastWakeAttempt: Date? - - public init() { - self.timeZone = .currentFixed - self.useMySentry = true - } - - public init(timeZone: TimeZone, pumpModel: PumpModel, useMySentry: Bool) { - self.timeZone = timeZone - self.pumpModel = pumpModel - self.useMySentry = useMySentry - } - - public init?(rawValue: RawValue) { - guard - let timeZoneSeconds = rawValue["timeZone"] as? Int, - let timeZone = TimeZone(secondsFromGMT: timeZoneSeconds) - else { - return nil - } - - self.timeZone = timeZone - self.useMySentry = rawValue["useMySentry"] as? Bool ?? true - - if let pumpModelNumber = rawValue["pumpModel"] as? PumpModel.RawValue { - pumpModel = PumpModel(rawValue: pumpModelNumber) - } - - if let frequencyRaw = rawValue["lastValidFrequency"] as? Double { - lastValidFrequency = Measurement(value: frequencyRaw, unit: .megahertz) - } - } - - public var rawValue: RawValue { - var rawValue: RawValue = [ - "timeZone": timeZone.secondsFromGMT(), - "useMySentry": useMySentry, - ] - - if let pumpModel = pumpModel { - rawValue["pumpModel"] = pumpModel.rawValue - } - - if let frequency = lastValidFrequency?.converted(to: .megahertz) { - rawValue["lastValidFrequency"] = frequency.value - } - - return rawValue - } -} - - -extension PumpState: CustomDebugStringConvertible { - public var debugDescription: String { - - return [ - "## PumpState", - "timeZone: \(timeZone)", - "pumpModel: \(pumpModel?.rawValue ?? "")", - "useMySentry: \(useMySentry)", - "awakeUntil: \(awakeUntil ?? .distantPast)", - "lastValidFrequency: \(String(describing: lastValidFrequency))", - "lastTuned: \(awakeUntil ?? .distantPast))", - "lastWakeAttempt: \(String(describing: lastWakeAttempt))" - ].joined(separator: "\n") - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/ReservoirReading.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/ReservoirReading.swift deleted file mode 100644 index 51752e0ce..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/ReservoirReading.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// ReservoirReading.swift -// MinimedKit -// -// Created by Pete Schwamb on 2/4/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -public struct ReservoirReading: RawRepresentable, Equatable { - - public typealias RawValue = [String: Any] - - public let units: Double - public let validAt: Date - - public init(units: Double, validAt: Date) { - self.units = units - self.validAt = validAt - } - - public init?(rawValue: RawValue) { - guard - let units = rawValue["units"] as? Double, - let validAt = rawValue["validAt"] as? Date - else { - return nil - } - - self.units = units - self.validAt = validAt - } - - public var rawValue: RawValue { - return [ - "units": units, - "validAt": validAt - ] - } -} - -extension ReservoirReading: ReservoirValue { - public var startDate: Date { - return validAt - } - - public var unitVolume: Double { - return units - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/RileyLinkDevice.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/RileyLinkDevice.swift deleted file mode 100644 index f217b6f2c..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/RileyLinkDevice.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// RileyLinkDevice.swift -// Loop -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import HealthKit -import RileyLinkBLEKit - - -extension RileyLinkDeviceStatus { - func device(pumpID: String, pumpModel: PumpModel) -> HKDevice { - return HKDevice( - name: name, - manufacturer: "Medtronic", - model: pumpModel.rawValue, - hardwareVersion: nil, - firmwareVersion: version, - softwareVersion: String(MinimedKitVersionNumber), - localIdentifier: pumpID, - udiDeviceIdentifier: nil - ) - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/PumpManager/UnfinalizedDose.swift b/Dependencies/MinimedKit/MinimedKit/PumpManager/UnfinalizedDose.swift deleted file mode 100644 index 6298588e1..000000000 --- a/Dependencies/MinimedKit/MinimedKit/PumpManager/UnfinalizedDose.swift +++ /dev/null @@ -1,324 +0,0 @@ -// -// UnfinalizedDose.swift -// MinimedKit -// -// Created by Pete Schwamb on 7/31/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -public struct UnfinalizedDose: RawRepresentable, Equatable, CustomStringConvertible { - public typealias RawValue = [String: Any] - - enum DoseType: Int { - case bolus = 0 - case tempBasal - case suspend - case resume - } - - let doseType: DoseType - public var units: Double - var programmedUnits: Double? // Set when finalized; tracks programmed units - var programmedTempRate: Double? // Set when finalized; tracks programmed temp rate - let startTime: Date - var duration: TimeInterval - var isReconciledWithHistory: Bool - var uuid: UUID - let insulinType: InsulinType? - let automatic: Bool? - - var finishTime: Date { - get { - return startTime.addingTimeInterval(duration) - } - set { - duration = newValue.timeIntervalSince(startTime) - } - } - - public var progress: Double { - let elapsed = -startTime.timeIntervalSinceNow - return min(elapsed / duration, 1) - } - - public var isFinished: Bool { - return progress >= 1 - } - - // Units per hour - public var rate: Double { - guard duration.hours > 0 else { - return 0 - } - - return units / duration.hours - } - - public var finalizedUnits: Double? { - guard isFinished else { - return nil - } - return units - } - - init(bolusAmount: Double, startTime: Date, duration: TimeInterval, insulinType: InsulinType?, automatic: Bool, isReconciledWithHistory: Bool = false) { - self.doseType = .bolus - self.units = bolusAmount - self.startTime = startTime - self.duration = duration - self.programmedUnits = nil - self.insulinType = insulinType - self.uuid = UUID() - self.isReconciledWithHistory = isReconciledWithHistory - self.automatic = automatic - } - - init(tempBasalRate: Double, startTime: Date, duration: TimeInterval, insulinType: InsulinType?, automatic: Bool = true, isReconciledWithHistory: Bool = false) { - self.doseType = .tempBasal - self.units = tempBasalRate * duration.hours - self.startTime = startTime - self.duration = duration - self.programmedUnits = nil - self.insulinType = insulinType - self.automatic = automatic - self.isReconciledWithHistory = isReconciledWithHistory - self.uuid = UUID() - } - - init(suspendStartTime: Date, isReconciledWithHistory: Bool = false) { - self.doseType = .suspend - self.units = 0 - self.startTime = suspendStartTime - self.duration = 0 - self.isReconciledWithHistory = isReconciledWithHistory - self.insulinType = nil - self.automatic = false - self.uuid = UUID() - } - - init(resumeStartTime: Date, insulinType: InsulinType, isReconciledWithHistory: Bool = false) { - self.doseType = .resume - self.units = 0 - self.startTime = resumeStartTime - self.duration = 0 - self.insulinType = insulinType - self.isReconciledWithHistory = isReconciledWithHistory - self.automatic = false - self.uuid = UUID() - } - - public mutating func cancel(at date: Date, pumpModel: PumpModel) { - guard date < finishTime else { - return - } - - let programmedUnits = units - self.programmedUnits = programmedUnits - let newDuration = date.timeIntervalSince(startTime) - - switch doseType { - case .bolus: - (units,_) = pumpModel.estimateBolusProgress(elapsed: newDuration, programmedUnits: programmedUnits) - case .tempBasal: - programmedTempRate = rate - (units,_) = pumpModel.estimateTempBasalProgress(unitsPerHour: rate, duration: duration, elapsed: newDuration) - default: - break - } - duration = newDuration - } - - public var description: String { - switch doseType { - case .bolus: - return "Bolus units:\(programmedUnits ?? units) \(startTime)" - case .tempBasal: - return "TempBasal rate:\(programmedTempRate ?? rate) \(startTime) duration:\(String(describing: duration))" - default: - return "\(String(describing: doseType).capitalized) \(startTime)" - } - } - - public var eventTitle: String { - switch doseType { - case .bolus: - return LocalizedString("Bolus", comment: "Pump Event title for UnfinalizedDose with doseType of .bolus") - case .resume: - return LocalizedString("Resume", comment: "Pump Event title for UnfinalizedDose with doseType of .resume") - case .suspend: - return LocalizedString("Suspend", comment: "Pump Event title for UnfinalizedDose with doseType of .suspend") - case .tempBasal: - return LocalizedString("Temp Basal", comment: "Pump Event title for UnfinalizedDose with doseType of .tempBasal") - } - } - - public mutating func reconcile(with event: NewPumpEvent) { - isReconciledWithHistory = true - if let dose = event.dose { - switch dose.type { - case .bolus: - if programmedUnits == nil { - programmedUnits = units - } - let doseDuration = dose.endDate.timeIntervalSince(dose.startDate) - - if doseDuration > 0 && doseDuration < duration { - duration = doseDuration - } - if let deliveredUnits = dose.deliveredUnits { - units = deliveredUnits - } - default: - break - } - } - } - - // MARK: - RawRepresentable - public init?(rawValue: RawValue) { - guard - let rawDoseType = rawValue["doseType"] as? Int, - let doseType = DoseType(rawValue: rawDoseType), - let units = rawValue["units"] as? Double, - let startTime = rawValue["startTime"] as? Date, - let duration = rawValue["duration"] as? Double - else { - return nil - } - - self.doseType = doseType - self.units = units - self.startTime = startTime - self.duration = duration - - if let scheduledUnits = rawValue["scheduledUnits"] as? Double { - self.programmedUnits = scheduledUnits - } - - if let scheduledTempRate = rawValue["scheduledTempRate"] as? Double { - self.programmedTempRate = scheduledTempRate - } - - if let uuidString = rawValue["uuid"] as? String { - if let uuid = UUID(uuidString: uuidString) { - self.uuid = uuid - } else { - return nil - } - } else { - self.uuid = UUID() - } - - if let rawInsulinType = rawValue["insulinType"] as? InsulinType.RawValue, let insulinType = InsulinType(rawValue: rawInsulinType) { - self.insulinType = insulinType - } else { - self.insulinType = nil - } - - self.isReconciledWithHistory = rawValue["isReconciledWithHistory"] as? Bool ?? false - - let defaultAutomaticState = doseType == .tempBasal - - self.automatic = rawValue["automatic"] as? Bool ?? defaultAutomaticState - } - - public var rawValue: RawValue { - var rawValue: RawValue = [ - "doseType": doseType.rawValue, - "units": units, - "startTime": startTime, - "duration": duration, - "isReconciledWithHistory": isReconciledWithHistory, - "uuid": uuid.uuidString, - ] - - if let scheduledUnits = programmedUnits { - rawValue["scheduledUnits"] = scheduledUnits - } - - if let scheduledTempRate = programmedTempRate { - rawValue["scheduledTempRate"] = scheduledTempRate - } - - if let insulinType = insulinType { - rawValue["insulinType"] = insulinType.rawValue - } - - if let automatic = automatic { - rawValue["automatic"] = automatic - } - - return rawValue - } -} - -// MARK: - UnfinalizedDose - -extension UnfinalizedDose { - func newPumpEvent(forceFinalization: Bool = false) -> NewPumpEvent { - return NewPumpEvent(self, forceFinalization: forceFinalization) - } -} - -// MARK: - NewPumpEvent - - - -extension NewPumpEvent { - init(_ dose: UnfinalizedDose, forceFinalization: Bool = false) { - let entry = DoseEntry(dose, forceFinalization: forceFinalization) - let raw = dose.uuid.asRaw - self.init(date: dose.startTime, dose: entry, raw: raw, title: dose.eventTitle) - } -} - -// MARK: - DoseEntry - -extension DoseEntry { - init (_ dose: UnfinalizedDose, forceFinalization: Bool = false) { - switch dose.doseType { - case .bolus: - self = DoseEntry(type: .bolus, startDate: dose.startTime, endDate: dose.finishTime, value: dose.programmedUnits ?? dose.units, unit: .units, deliveredUnits: dose.finalizedUnits, insulinType: dose.insulinType, automatic: dose.automatic, isMutable: !dose.isReconciledWithHistory && !forceFinalization) - case .tempBasal: - let isMutable = !forceFinalization && (!dose.isReconciledWithHistory || !dose.isFinished) - self = DoseEntry(type: .tempBasal, startDate: dose.startTime, endDate: dose.finishTime, value: dose.programmedTempRate ?? dose.rate, unit: .unitsPerHour, deliveredUnits: dose.finalizedUnits, insulinType: dose.insulinType, automatic: dose.automatic, isMutable: isMutable) - case .suspend: - self = DoseEntry(suspendDate: dose.startTime, isMutable: !dose.isReconciledWithHistory) - case .resume: - self = DoseEntry(resumeDate: dose.startTime, insulinType: dose.insulinType, isMutable: !dose.isReconciledWithHistory) - } - } -} - -extension Collection where Element == NewPumpEvent { - /// find matching entry - func firstMatchingIndex(for dose: UnfinalizedDose, within: TimeInterval) -> Self.Index? { - return firstIndex(where: { (event) -> Bool in - guard let type = event.type, let eventDose = event.dose, abs(eventDose.startDate.timeIntervalSince(dose.startTime)) < within else { - return false - } - - switch dose.doseType { - case .bolus: - return type == .bolus && eventDose.programmedUnits == dose.programmedUnits ?? dose.units - case .tempBasal: - return type == .tempBasal && eventDose.unitsPerHour == dose.programmedTempRate ?? dose.rate - case .suspend: - return type == .suspend - case .resume: - return type == .resume - } - }) - } -} - -extension UUID { - var asRaw: Data { - return withUnsafePointer(to: self) { - Data(bytes: $0, count: MemoryLayout.size(ofValue: self)) - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Radio/CRC8.swift b/Dependencies/MinimedKit/MinimedKit/Radio/CRC8.swift deleted file mode 100644 index 18307f5d9..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Radio/CRC8.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// CRC8.swift -// RileyLink -// -// Created by Pete Schwamb on 2/27/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -fileprivate let crcTable: [UInt8] = [0x0, 0x9B, 0xAD, 0x36, 0xC1, 0x5A, 0x6C, 0xF7, 0x19, 0x82, 0xB4, 0x2F, 0xD8, 0x43, 0x75, 0xEE, 0x32, 0xA9, 0x9F, 0x4, 0xF3, 0x68, 0x5E, 0xC5, 0x2B, 0xB0, 0x86, 0x1D, 0xEA, 0x71, 0x47, 0xDC, 0x64, 0xFF, 0xC9, 0x52, 0xA5, 0x3E, 0x8, 0x93, 0x7D, 0xE6, 0xD0, 0x4B, 0xBC, 0x27, 0x11, 0x8A, 0x56, 0xCD, 0xFB, 0x60, 0x97, 0xC, 0x3A, 0xA1, 0x4F, 0xD4, 0xE2, 0x79, 0x8E, 0x15, 0x23, 0xB8, 0xC8, 0x53, 0x65, 0xFE, 0x9, 0x92, 0xA4, 0x3F, 0xD1, 0x4A, 0x7C, 0xE7, 0x10, 0x8B, 0xBD, 0x26, 0xFA, 0x61, 0x57, 0xCC, 0x3B, 0xA0, 0x96, 0xD, 0xE3, 0x78, 0x4E, 0xD5, 0x22, 0xB9, 0x8F, 0x14, 0xAC, 0x37, 0x1, 0x9A, 0x6D, 0xF6, 0xC0, 0x5B, 0xB5, 0x2E, 0x18, 0x83, 0x74, 0xEF, 0xD9, 0x42, 0x9E, 0x5, 0x33, 0xA8, 0x5F, 0xC4, 0xF2, 0x69, 0x87, 0x1C, 0x2A, 0xB1, 0x46, 0xDD, 0xEB, 0x70, 0xB, 0x90, 0xA6, 0x3D, 0xCA, 0x51, 0x67, 0xFC, 0x12, 0x89, 0xBF, 0x24, 0xD3, 0x48, 0x7E, 0xE5, 0x39, 0xA2, 0x94, 0xF, 0xF8, 0x63, 0x55, 0xCE, 0x20, 0xBB, 0x8D, 0x16, 0xE1, 0x7A, 0x4C, 0xD7, 0x6F, 0xF4, 0xC2, 0x59, 0xAE, 0x35, 0x3, 0x98, 0x76, 0xED, 0xDB, 0x40, 0xB7, 0x2C, 0x1A, 0x81, 0x5D, 0xC6, 0xF0, 0x6B, 0x9C, 0x7, 0x31, 0xAA, 0x44, 0xDF, 0xE9, 0x72, 0x85, 0x1E, 0x28, 0xB3, 0xC3, 0x58, 0x6E, 0xF5, 0x2, 0x99, 0xAF, 0x34, 0xDA, 0x41, 0x77, 0xEC, 0x1B, 0x80, 0xB6, 0x2D, 0xF1, 0x6A, 0x5C, 0xC7, 0x30, 0xAB, 0x9D, 0x6, 0xE8, 0x73, 0x45, 0xDE, 0x29, 0xB2, 0x84, 0x1F, 0xA7, 0x3C, 0xA, 0x91, 0x66, 0xFD, 0xCB, 0x50, 0xBE, 0x25, 0x13, 0x88, 0x7F, 0xE4, 0xD2, 0x49, 0x95, 0xE, 0x38, 0xA3, 0x54, 0xCF, 0xF9, 0x62, 0x8C, 0x17, 0x21, 0xBA, 0x4D, 0xD6, 0xE0, 0x7B] - -public extension Sequence where Element == UInt8 { - - func crc8() -> UInt8 { - - var crc: UInt8 = 0 - for byte in self { - crc = crcTable[Int((crc ^ byte) & 0xff)] - } - return crc - } -} diff --git a/Dependencies/MinimedKit/MinimedKit/Radio/FourByteSixByteEncoding.swift b/Dependencies/MinimedKit/MinimedKit/Radio/FourByteSixByteEncoding.swift deleted file mode 100644 index 5ce41efde..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Radio/FourByteSixByteEncoding.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// FourByteSixByteEncoding.swift -// RileyLink -// -// Created by Pete Schwamb on 2/27/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -fileprivate let codes = [21, 49, 50, 35, 52, 37, 38, 22, 26, 25, 42, 11, 44, 13, 14, 28] - -fileprivate let codesRev = Dictionary(uniqueKeysWithValues: codes.enumerated().map({ ($1, UInt8($0)) })) - -public extension Sequence where Element == UInt8 { - - func decode4b6b() -> [UInt8]? { - var buffer = [UInt8]() - var availBits = 0 - var bitAccumulator = 0 - for byte in self { - if byte == 0 { - break - } - - bitAccumulator = (bitAccumulator << 8) + Int(byte) - availBits += 8 - if availBits >= 12 { - guard let hiNibble = codesRev[bitAccumulator >> (availBits - 6)], - let loNibble = codesRev[(bitAccumulator >> (availBits - 12)) & 0b111111] - else { - return nil - } - let decoded = UInt8((hiNibble << 4) + loNibble) - buffer.append(decoded) - availBits -= 12 - bitAccumulator = bitAccumulator & (0xffff >> (16-availBits)) - } - } - return buffer - } - - func encode4b6b() -> [UInt8] { - var buffer = [UInt8]() - var bitAccumulator = 0x0 - var bitcount = 0 - for byte in self { - bitAccumulator <<= 6 - bitAccumulator |= codes[Int(byte >> 4)] - bitcount += 6 - - bitAccumulator <<= 6 - bitAccumulator |= codes[Int(byte & 0x0f)] - bitcount += 6 - - while bitcount >= 8 { - buffer.append(UInt8(bitAccumulator >> (bitcount-8)) & 0xff) - bitcount -= 8 - bitAccumulator &= (0xffff >> (16-bitcount)) - } - } - if bitcount > 0 { - bitAccumulator <<= (8-bitcount) - buffer.append(UInt8(bitAccumulator) & 0xff) - } - return buffer - } -} - diff --git a/Dependencies/MinimedKit/MinimedKit/Radio/MinimedPacket.swift b/Dependencies/MinimedKit/MinimedKit/Radio/MinimedPacket.swift deleted file mode 100644 index c66483b56..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Radio/MinimedPacket.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// MinimedPacket.swift -// RileyLinkBLEKit -// -// Created by Pete Schwamb on 10/7/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct MinimedPacket { - public let data: Data - - public init(outgoingData: Data) { - self.data = outgoingData - } - - public init?(encodedData: Data) { - - if let decoded = encodedData.decode4b6b() { - if decoded.count == 0 { - return nil - } - let msg = decoded.prefix(upTo: (decoded.count - 1)) - if decoded.last != msg.crc8() { - // CRC invalid - return nil - } - self.data = Data(msg) - } else { - // Could not decode message - return nil - } - } - - public func encodedData() -> Data { - var dataWithCRC = self.data - dataWithCRC.append(data.crc8()) - var encodedData = dataWithCRC.encode4b6b() - encodedData.append(0) - return Data(encodedData) - } -} - diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/Base.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/Base.lproj/Localizable.strings deleted file mode 100644 index afe05abcf..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/Base.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "A bolus is already in progress"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmClockReminder"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkaline"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Basal Profile %1$@: %2$@ U/hour"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Check that the pump is not suspended or priming, or has a percent temp basal type"; - -/* Pump error code returned when command refused */ -"Command refused" = "Command refused"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Comms with another pump detected."; - -/* Error description */ -"Decoding Error" = "Decoding Error"; - -/* Error description */ -"Device Error" = "Device Error"; - -/* Describing the pump history insulin data source */ -"Event History" = "Event History"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Invalid response during %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Lithium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Max setting exceeded"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 Series"; - -/* Describing the North America pump region */ -"North America" = "North America"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pump did not respond"; - -/* Error description */ -"Pump Error" = "Pump Error"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pump is suspended"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pump responded unexpectedly"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "PumpMessage(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Reservoir"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink radio tune failed"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Temporary Basal: %1$.3f U/hour"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Temporary Basal: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Temporary Basal: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Unknown pump error code: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Unknown pump model: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Unknown response during %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "World-Wide"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/ar.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/ar.lproj/Localizable.strings deleted file mode 100644 index 8a1f932e4..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/ar.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "A bolus is already in progress"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmClockReminder"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkaline"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Basal Profile %1$@: %2$@ U/hour"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Check that the pump is not suspended or priming, or has a percent temp basal type"; - -/* Pump error code returned when command refused */ -"Command refused" = "Command refused"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Comms with another pump detected."; - -/* Error description */ -"Decoding Error" = "Decoding Error"; - -/* Error description */ -"Device Error" = "Device Error"; - -/* Describing the pump history insulin data source */ -"Event History" = "Event History"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Invalid response during %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Lithium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Max setting exceeded"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 Series"; - -/* Describing the North America pump region */ -"North America" = "North America"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pump did not respond"; - -/* Error description */ -"Pump Error" = "Pump Error"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pump is suspended"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pump responded unexpectedly"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "PumpMessage(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "الخزان"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink radio tune failed"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Temporary Basal: %1$.3f U/hour"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Temporary Basal: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Temporary Basal: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Unknown pump error code: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Unknown pump model: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Unknown response during %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "World-Wide"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/ca.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/ca.lproj/Localizable.strings deleted file mode 100644 index afe05abcf..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/ca.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "A bolus is already in progress"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmClockReminder"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkaline"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Basal Profile %1$@: %2$@ U/hour"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Check that the pump is not suspended or priming, or has a percent temp basal type"; - -/* Pump error code returned when command refused */ -"Command refused" = "Command refused"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Comms with another pump detected."; - -/* Error description */ -"Decoding Error" = "Decoding Error"; - -/* Error description */ -"Device Error" = "Device Error"; - -/* Describing the pump history insulin data source */ -"Event History" = "Event History"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Invalid response during %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Lithium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Max setting exceeded"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 Series"; - -/* Describing the North America pump region */ -"North America" = "North America"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pump did not respond"; - -/* Error description */ -"Pump Error" = "Pump Error"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pump is suspended"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pump responded unexpectedly"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "PumpMessage(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Reservoir"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink radio tune failed"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Temporary Basal: %1$.3f U/hour"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Temporary Basal: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Temporary Basal: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Unknown pump error code: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Unknown pump model: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Unknown response during %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "World-Wide"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/cs.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/cs.lproj/Localizable.strings deleted file mode 100644 index e17c34d72..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/cs.lproj/Localizable.strings +++ /dev/null @@ -1,39 +0,0 @@ -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Probíhající bolus"; - -/* Event title for ChangeBasalProfilePatternPumpEvent */ -"Change Basal Profile Schedule" = "Změnit profil bazálního rozvrhu"; - -/* Event title for ChangeBasalProfilePumpEvent */ -"Change Basal Schedule" = "Změnit bazální rozvrh"; - -/* Event title for ChangeTimePumpEvent */ -"Change Time" = "Změnit čas"; - -/* Event title for clear alarm pump event */ -"Clear Alarm" = "Vymazat alarm"; - -/* Event title for JournalEntryPumpLowBatteryPumpEvent */ -"Low Battery" = "Vybitá baterie"; - -/* Event title for JournalEntryPumpLowReservoirPumpEvent */ -"Low Reservoir" = "Poloprázdný zásobník"; - -/* Event title for JournalEntryMealMarkerPumpEvent */ -"Meal" = "Jídlo"; - -/* Event title for NewTimePumpEvent */ -"New Time" = "Nový čas"; - -/* Acknowledge button label for RileyLink low battery alert */ -"OK" = "OK"; - -/* Event title for starting scheduled basal */ -"Scheduled Basal" = "Plánovaný bazál"; - -/* Event title for SelectBasalProfilePumpEvent */ -"Select Profile" = "Vybrat profil"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Ztráta signálu"; - diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/da.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/da.lproj/Localizable.strings deleted file mode 100644 index 90c331c35..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/da.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "En bolus er allerede i gang"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmUrPåmindelse"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "Alarm Sensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkaline"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Basal Profil %1$@: %2$@ E/time"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus i gang"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Tjek, at pumpen ikke er suspenderet eller under klargøring, eller har en procent midlertidig basaltype"; - -/* Pump error code returned when command refused */ -"Command refused" = "Kommando nægtet"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Kommunikation med en anden pumpe opdaget."; - -/* Error description */ -"Decoding Error" = "Undersøger fejl"; - -/* Error description */ -"Device Error" = "Enhedsfejl"; - -/* Describing the pump history insulin data source */ -"Event History" = "Hændelseshistorik"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Fejlagtigt svar ved %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Litium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Sørg for, at din RileyLink er i nærheden og tændt"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Max indstilling overskredet"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 Serier"; - -/* Describing the North America pump region */ -"North America" = "Nordamerika"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pumpe svarede ikke"; - -/* Error description */ -"Pump Error" = "Pumpefejl"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pumpe er afbrudt"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pumpe reagerede uventet"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "Pumpebesked(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Reservoir"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink radioindstilling fejlede"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Midlertidig Basal: %1$.3f E/time"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Midlertidig Basal: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Midlertidig basal: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Ukendt pumpe-fejlkode: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Ukendt pumpemodel %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Ukendt svar under %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "Verdensomspændende"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/de.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/de.lproj/Localizable.strings deleted file mode 100644 index 756c71fa4..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/de.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "Ein Bolus wird bereits abgegeben"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "Alarm Erinnerung"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkalisch"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Basalprofil %1$@: %2$@ E/Stunde"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolusabgabe läuft "; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Überprüfen Sie, ob die Pumpe nicht unterbrochen wurde oder sich im Füllmodus befindet, oder prozentual temporären Basalraten aktiviert sind"; - -/* Pump error code returned when command refused */ -"Command refused" = "Befehl verweigert"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Kommunikation mit einer anderen Pumpe festgestellt"; - -/* Error description */ -"Decoding Error" = "Dekodierungsfehler"; - -/* Error description */ -"Device Error" = "Gerätefehler"; - -/* Describing the pump history insulin data source */ -"Event History" = "Ereignisverlauf"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Ungültige Antwort während %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Lithium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Stellen Sie sicher, dass sich Ihr RileyLink in der Nähe befindet und eingeschaltet ist"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Max Einstellung überschritten"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 Serie"; - -/* Describing the North America pump region */ -"North America" = "Nordamerika"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pumpe hat nicht geantwortet"; - -/* Error description */ -"Pump Error" = "Pumpenfehler"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pumpe ist gesperrt"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pumpe hat unerwartet geantwortet"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "Pumpennachricht(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Reservoir"; - -/* Error description */ -"RileyLink radio tune failed" = "Einstellen des RileyLink Funksignals fehlgeschlagen"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Temporäre Basalrate: %1$.3f E/St"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Temporäre Basalrate: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Temporäre Basalrate: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Unbekannter Fehlercode der Pumpe: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Unbekanntes Pumpenmodell: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Unbekannte Antwort oder %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "Weltweit"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/en.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/en.lproj/Localizable.strings deleted file mode 100644 index afe05abcf..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/en.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "A bolus is already in progress"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmClockReminder"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkaline"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Basal Profile %1$@: %2$@ U/hour"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Check that the pump is not suspended or priming, or has a percent temp basal type"; - -/* Pump error code returned when command refused */ -"Command refused" = "Command refused"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Comms with another pump detected."; - -/* Error description */ -"Decoding Error" = "Decoding Error"; - -/* Error description */ -"Device Error" = "Device Error"; - -/* Describing the pump history insulin data source */ -"Event History" = "Event History"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Invalid response during %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Lithium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Max setting exceeded"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 Series"; - -/* Describing the North America pump region */ -"North America" = "North America"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pump did not respond"; - -/* Error description */ -"Pump Error" = "Pump Error"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pump is suspended"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pump responded unexpectedly"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "PumpMessage(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Reservoir"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink radio tune failed"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Temporary Basal: %1$.3f U/hour"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Temporary Basal: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Temporary Basal: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Unknown pump error code: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Unknown pump model: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Unknown response during %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "World-Wide"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/es.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/es.lproj/Localizable.strings deleted file mode 100644 index eeb712c01..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/es.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "Un bolo ya está en progreso"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmClockReminder"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alcalina"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Perfil Basal %1$@: %2$@ U/hora"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolo en progreso"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Revisa que la microinfusora no esté suspendida o en cebado, o que tenga una basal de tipo temporal"; - -/* Pump error code returned when command refused */ -"Command refused" = "Comando rechazado"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Comunicación con otra microinfusadora detectado."; - -/* Error description */ -"Decoding Error" = "Error de decodificación"; - -/* Error description */ -"Device Error" = "Error de Dispositivo"; - -/* Describing the pump history insulin data source */ -"Event History" = "Historial de Eventos"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Respuesta inválida durante %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Litio"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Asegúrese de que su RileyLink está cerca y encendido"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Ajuste máximo excedido"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed Serie 500/700"; - -/* Describing the North America pump region */ -"North America" = "Norte America"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "La microinfusora no respondió"; - -/* Error description */ -"Pump Error" = "Error de la bomba"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "La microinfusora está suspendida"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "La microinfusora respondió de forma inesperada"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "MensageMicroinfusadora(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Reservorio"; - -/* Error description */ -"RileyLink radio tune failed" = "Sintonización de señal de radio de RileyLink falló"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Basal Temporal: %1$.3f U/hora"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Basal Temporal: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Basal Temporal: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Error desconocido de código de microinfusora: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Modelo desconocido de microinfusora: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Respuesta desconocida durante %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "Mundial"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/fi.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/fi.lproj/Localizable.strings deleted file mode 100644 index c21570d30..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/fi.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "Bolus on jo käynnissä"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "HerätysKelloMuistutus"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "HälytysSensori"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkaliini"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Basaaliprofiili %1$@: %2$@ U/h"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus vireillä"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Tarkista, että pumppu ei ole pysäytetty, vakiotäytöllä tai basaalityypiksi ei ole valittu prosentteja"; - -/* Pump error code returned when command refused */ -"Command refused" = "Komento hylättiin"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Toisen pumpun viestintää havaittu."; - -/* Error description */ -"Decoding Error" = "Dekoodausvirhe"; - -/* Error description */ -"Device Error" = "Laitevirhe"; - -/* Describing the pump history insulin data source */ -"Event History" = "Tapahtumahistoria"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Virheellinen vastaus %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Litium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Varmista, että RileyLink on riittävän lähellä ja kytketty päälle"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Maksimiasetus ylitetty"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 -sarja"; - -/* Describing the North America pump region */ -"North America" = "Pohjois-Amerikka"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pumppu ei vastannut"; - -/* Error description */ -"Pump Error" = "Pumpun virhe"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pumppu on pysäytetty"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pumppu vastasi epätavallisesti"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "PumppuViesti(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Säiliö"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink-radion viritys epäonnistui"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Tilapäinen basaali: %1$.3f U/h"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Tilapäinen basaali: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Tilapäinen basaali: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Tuntematon pumpun virhekoodi: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Tuntematon pumppumalli: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Tuntematon vastaus %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "Maailmanlaajuinen"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/fr.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/fr.lproj/Localizable.strings deleted file mode 100644 index bf1582bb9..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/fr.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "Un bolus est déjà en cours"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "Alarme de rappel"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alcaline"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Profil basal %1$@: %2$@ U/heure"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus en cours"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Vérifiez que la pompe n’est pas suspendue ou en amorçage, ou a un basal temporaire en pourcentage"; - -/* Pump error code returned when command refused */ -"Command refused" = "Commande refusée"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Communications avec une autre pompe détectée"; - -/* Error description */ -"Decoding Error" = "Erreur de décodage"; - -/* Error description */ -"Device Error" = "Erreur de périphérique"; - -/* Describing the pump history insulin data source */ -"Event History" = "Historique des événements"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Réponse invalide pendant %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Lithium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Assurez-vous que votre RileyLink est à proximité et allumé"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Réglage maximum dépassé"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Serié Minimed 500/700"; - -/* Describing the North America pump region */ -"North America" = "Amérique du Nord"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "La pompe n’a pas répondu"; - -/* Error description */ -"Pump Error" = "Erreur détectée"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "La pompe est suspendue"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "La pompe a réagi de manière inattendue"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "Message de pompe(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Réservoir"; - -/* Error description */ -"RileyLink radio tune failed" = "La synthèse radio RileyLink a échoué"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Basal temporaire: %1$.3f U/heure"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Basal temporaire: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Basal temporaire: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Code d’erreur de pompe inconnu: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Modèle de pompe inconnu: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Réponse inconnue pendant %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "Monde Entier"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/he.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/he.lproj/Localizable.strings deleted file mode 100644 index 5b5e90d16..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/he.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "A bolus is already in progress"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmClockReminder"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkaline"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Basal Profile %1$@: %2$@ U/hour"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Check that the pump is not suspended or priming, or has a percent temp basal type"; - -/* Pump error code returned when command refused */ -"Command refused" = "Command refused"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Comms with another pump detected."; - -/* Error description */ -"Decoding Error" = "Decoding Error"; - -/* Error description */ -"Device Error" = "Device Error"; - -/* Describing the pump history insulin data source */ -"Event History" = "Event History"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Invalid response during %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Lithium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Max setting exceeded"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 Series"; - -/* Describing the North America pump region */ -"North America" = "North America"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pump did not respond"; - -/* Error description */ -"Pump Error" = "Pump Error"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pump is suspended"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pump responded unexpectedly"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "PumpMessage(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Reservoir"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink radio tune failed"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Temporary Basal: %1$.3f U/hour"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "בזאלי זמני: %1$d דקות"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Temporary Basal: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Unknown pump error code: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Unknown pump model: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Unknown response during %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "World-Wide"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/hu.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/hu.lproj/Localizable.strings deleted file mode 100644 index afe05abcf..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/hu.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "A bolus is already in progress"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmClockReminder"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkaline"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Basal Profile %1$@: %2$@ U/hour"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Check that the pump is not suspended or priming, or has a percent temp basal type"; - -/* Pump error code returned when command refused */ -"Command refused" = "Command refused"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Comms with another pump detected."; - -/* Error description */ -"Decoding Error" = "Decoding Error"; - -/* Error description */ -"Device Error" = "Device Error"; - -/* Describing the pump history insulin data source */ -"Event History" = "Event History"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Invalid response during %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Lithium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Max setting exceeded"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 Series"; - -/* Describing the North America pump region */ -"North America" = "North America"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pump did not respond"; - -/* Error description */ -"Pump Error" = "Pump Error"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pump is suspended"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pump responded unexpectedly"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "PumpMessage(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Reservoir"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink radio tune failed"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Temporary Basal: %1$.3f U/hour"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Temporary Basal: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Temporary Basal: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Unknown pump error code: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Unknown pump model: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Unknown response during %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "World-Wide"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/it.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/it.lproj/Localizable.strings deleted file mode 100644 index 6146a2847..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/it.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "Un bolo è già in esecuzione"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "Promemoria sveglia"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "Allarme Sensori"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alcalina"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Profilo basale %1$@: %2$@ U/ora"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolo in corso"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Verificare che il microinfusore non sia sospeso o che sia in caricamento o che abbia impostata una basale in percentuale"; - -/* Pump error code returned when command refused */ -"Command refused" = "Comando negato"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Comunicazione con un altro microinfusore rilevata"; - -/* Error description */ -"Decoding Error" = "Errore di decodifica"; - -/* Error description */ -"Device Error" = "Errore del dispositivo"; - -/* Describing the pump history insulin data source */ -"Event History" = "Storico degli eventi"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Risposta non valida per %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Litio"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Assicurati che RileyLink si trovi nelle vicinanze e sia acceso"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Impostazione massima superata"; - -/* Pump title (1: model number) */ -"Minimed %@" = "MiniMed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "MiniMed serie 500/700"; - -/* Describing the North America pump region */ -"North America" = "Nord America"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Il microinfusore non risponde"; - -/* Error description */ -"Pump Error" = "Errore microinfusore"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Il microinfusore è sospeso"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Il microinfusore ha risposto in modo inaspettato"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "Informazioni pompa(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Serbatoio"; - -/* Error description */ -"RileyLink radio tune failed" = "Sintonizzazione radio RileyLink fallita"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Basale temporanea: %1$.3f U/ora"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Basale temporanea: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Basale temporanea: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Codice errore microinfusore sconosciuto: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Modello di microinfusore sconosciuto: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Risposta sconosciuta per %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "Internazionale"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/ja.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/ja.lproj/Localizable.strings deleted file mode 100644 index 8e7c9b70b..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/ja.lproj/Localizable.strings +++ /dev/null @@ -1,139 +0,0 @@ -/* Low reservoir alert format string. (1: Number of units remaining) */ -"%1$@ U left" = "残 %1$@単位"; - -/* Low reservoir alert with time remaining format string. (1: Number of units remaining)(2: approximate time remaining) */ -"%1$@ U left: %2$@" = "残 %1$@単位: %2$@"; - -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "ボーラス注入中"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "アラームリマインダー"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "アラームセンサー"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "アルカリ"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "ベーサルプロファイル %1$@: %2$@ U/時"; - -/* Event title for bolus - Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "ボーラス"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "ボーラスが進行中"; - -/* The notification alert describing a low pump battery */ -"Change the pump battery immediately" = "すぐにポンプの電池を替えてください"; - -/* The notification alert describing an empty pump reservoir */ -"Change the pump reservoir now" = "ポンプのレザーバを替えてください"; - -/* Event title for ChangeTimePumpEvent */ -"Change Time" = "時刻を変更"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "ポンプが停止、プライミング中、または基礎レートが一時的に変更になっていないことを確認してください"; - -/* Pump error code returned when command refused */ -"Command refused" = "コマンド拒否"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "他のポンプが検出"; - -/* Error description */ -"Decoding Error" = "デコーディングエラー"; - -/* Error description */ -"Device Error" = "デバイスエラー"; - -/* Default alert dismissal */ -"Dismiss" = "閉じる"; - -/* Describing the pump history insulin data source */ -"Event History" = "Event History"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "%1$@ で反応が無効: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "リチウム"; - -/* Event title for JournalEntryPumpLowBatteryPumpEvent */ -"Low Battery" = "電池残量低下"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "RileyLink が近くにあり電源が入っているか確認"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "設定の制限を超えています"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 シリーズ"; - -/* Describing the North America pump region */ -"North America" = "North America"; - -/* Acknowledge button label for RileyLink low battery alert */ -"OK" = "OK"; - -/* The notification title for a low pump battery */ -"Pump Battery Low" = "ポンプの電池が不足"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "ポンプが反応しません"; - -/* Error description */ -"Pump Error" = "ポンプエラー"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "ポンプが停止しています"; - -/* The notification title for an empty pump reservoir */ -"Pump Reservoir Empty" = "ポンプのリザーバが空です"; - -/* The notification title for a low pump reservoir */ -"Pump Reservoir Low" = "ポンプのリザーバが低です"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "ポンプが不意に反応しました"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "ポンプメッセージ(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Reservoir"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink 通信に失敗しました"; - -/* Event title for starting scheduled basal */ -"Scheduled Basal" = "定期基礎"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "一時基礎レート: %1$.3f U/hour"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "一時基礎レート: %1$d 分"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "一時基礎レート: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "ポンプエラーコード 不明: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "ポンプモデル 不明: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "反応が不明 %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "World-Wide"; - diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/nb.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/nb.lproj/Localizable.strings deleted file mode 100644 index ed5c91daf..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/nb.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "En bolus pågår allerede"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "PåminnelseAlarmklokke"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkalisk"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Basalprofil %1$@: %2$@ E/timen"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus pågår"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Sjekk at pumpa ikke har stoppet tilførsel av insulin, at priming ikke foregår, eller har en midlertidig prosentbasaltype pågående."; - -/* Pump error code returned when command refused */ -"Command refused" = "Kommando avvist"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Oppdaget kommunikasjon med en annen pumpe"; - -/* Error description */ -"Decoding Error" = "Dekodingsfeil"; - -/* Error description */ -"Device Error" = "Enhetsfeil"; - -/* Describing the pump history insulin data source */ -"Event History" = "Hendelseshistorie"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Ugyldig respons ved %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Litium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Pass på at din RileyLink er slått på og er i nærheten"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Maksinnstilling overskredet"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 series"; - -/* Describing the North America pump region */ -"North America" = "Nord Amerika"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pumpa svarte ikke"; - -/* Error description */ -"Pump Error" = "Pumpefeil"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pumpe er pauset"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pumpen svarte uventet"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "Pumpemelding(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Reservoar"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink radiotuning feilet"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Midlertidig basaldose: %1$.3f E/timen"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Midlertidig basaldose: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Midlertidig basaldose: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Ukjent feilkode fra pumpe: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Ukjent pumpemodell: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Ukjent respons ved %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "Verdensomspennende"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/nl.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/nl.lproj/Localizable.strings deleted file mode 100644 index 9b62fb251..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/nl.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "Er is al een bolus actief"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "Wekker herinnering"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "Alarm sensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkaline"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Basaal profiel %1$@: %2$@ E/uur"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus in uitvoering"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Controleer of de pomp niet is onderbroken of aan het voorbereiden is, of dat er een percentage tijdelijke basaal staat ingesteld"; - -/* Pump error code returned when command refused */ -"Command refused" = "Commando geweigerd"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Communicatie met een andere pomp gedetecteerd"; - -/* Error description */ -"Decoding Error" = "Decodingsfout"; - -/* Error description */ -"Device Error" = "Apparaatfout"; - -/* Describing the pump history insulin data source */ -"Event History" = "Logboek"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Foutief antwoord gedurende %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Lithium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Zorg ervoor dat je RileyLink dicht bij is en aan staat"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Max instelling overschreden"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 series"; - -/* Describing the North America pump region */ -"North America" = "Noord-Amerika"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pomp reageert niet"; - -/* Error description */ -"Pump Error" = "Pomp foutmelding"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pomp is onderbroken"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pomp reageerde onverwacht"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "Bericht pomp (%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Reservoir"; - -/* Error description */ -"RileyLink radio tune failed" = "Afstemmen van de RileyLink frequentie mislukt"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Tijdelijk basaal: %1$.3f E/uur"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Tijdelijk basaal: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Tijdelijk basaal: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Onbekende foutmelding pomp: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Onbekend model pomp: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Onbekend antwoord gedurende %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "Wereldwijd"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/pl.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/pl.lproj/Localizable.strings deleted file mode 100644 index c692f82d9..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/pl.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "Podawanie bolusa jest już w toku"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmClockReminder"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkaliczna"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Profil bazy %1$@: %2$@ J/godzinę"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus w toku"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Sprawdź, czy pompa nie jest zawieszona, nie trwa wypełnianie lub nie ma ustawionej procentowej dawki tymczasowej w ustawieniach."; - -/* Pump error code returned when command refused */ -"Command refused" = "Odmowa wykonania polecenia"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Wykryto połączenie z inną pompą."; - -/* Error description */ -"Decoding Error" = "Błąd dekodowania"; - -/* Error description */ -"Device Error" = "Błąd urządzenia"; - -/* Describing the pump history insulin data source */ -"Event History" = "Historia zdarzeń"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Nieprawidłowa odpowiedź podczas %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Litowa"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Upewnij się, że RileyLink jest w pobliżu i jest włączony"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Maksymalne ustawienie przekroczone"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed serii 500/700"; - -/* Describing the North America pump region */ -"North America" = "Ameryka Północna"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pompa nie odpowiada"; - -/* Error description */ -"Pump Error" = "Błąd pompy"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pompa jest zawieszona"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pompa odpowiedziała w nieoczekiwany sposób"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "Wiadomość od pompy(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Zbiorniczek"; - -/* Error description */ -"RileyLink radio tune failed" = "Dostrajanie radia RileyLink zakończone niepowodzeniem"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Baza tymczasowa: %1$.3f J/godz"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Baza tymczasowa: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Baza tymczasowa: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Nieznany kod błędu pompy: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Nieznany model pompy: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Nieoczekiwana odpowiedź podczas %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "Ogólnoświatowa"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/pt-BR.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/pt-BR.lproj/Localizable.strings deleted file mode 100644 index 47f27a728..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "Um bolus está em andamento"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "LembreteDeAlarme"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmeDeSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alcalina"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Perfil Basal %1$@: %2$@ U/hora"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus em andamento"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Verifique se a bomba não está suspensa ou em preparação ou tem uma basal temporária percentual"; - -/* Pump error code returned when command refused */ -"Command refused" = "Comando recusado"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Comunicação com outra bomba detectada."; - -/* Error description */ -"Decoding Error" = "Erro de Decodificação"; - -/* Error description */ -"Device Error" = "Erro no Dispositivo"; - -/* Describing the pump history insulin data source */ -"Event History" = "Event History"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Resposta inválida durante %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Lítio"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Verifique se o seu RileyLink está próximo e ligado"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Configuração máxima excedida"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 Series"; - -/* Describing the North America pump region */ -"North America" = "América do Norte"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "A bomba não respondeu"; - -/* Error description */ -"Pump Error" = "Erro na Bomba"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Bomba suspensa"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = " Bomba respondeu inesperadamente"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "MensagemDaBomba(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Reservoir"; - -/* Error description */ -"RileyLink radio tune failed" = "A sintonia do rádio RileyLink falhou"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Basal Temporária: %1$.3f U/hora"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Basal Temporária: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Basal Temporária: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Código de erro da bomba desconhecido: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Modelo de bomba desconhecido: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Resposta desconhecida durante %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "Mundial"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/pt-PT.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/pt-PT.lproj/Localizable.strings deleted file mode 100644 index afe05abcf..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/pt-PT.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "A bolus is already in progress"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmClockReminder"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkaline"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Basal Profile %1$@: %2$@ U/hour"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Check that the pump is not suspended or priming, or has a percent temp basal type"; - -/* Pump error code returned when command refused */ -"Command refused" = "Command refused"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Comms with another pump detected."; - -/* Error description */ -"Decoding Error" = "Decoding Error"; - -/* Error description */ -"Device Error" = "Device Error"; - -/* Describing the pump history insulin data source */ -"Event History" = "Event History"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Invalid response during %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Lithium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Max setting exceeded"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 Series"; - -/* Describing the North America pump region */ -"North America" = "North America"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pump did not respond"; - -/* Error description */ -"Pump Error" = "Pump Error"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pump is suspended"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pump responded unexpectedly"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "PumpMessage(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Reservoir"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink radio tune failed"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Temporary Basal: %1$.3f U/hour"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Temporary Basal: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Temporary Basal: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Unknown pump error code: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Unknown pump model: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Unknown response during %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "World-Wide"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/ro.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/ro.lproj/Localizable.strings deleted file mode 100644 index 04bd34255..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/ro.lproj/Localizable.strings +++ /dev/null @@ -1,277 +0,0 @@ -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" are o baterie scăzută"; - -/* Low reservoir alert format string. (1: Number of units remaining) */ -"%1$@ U left" = "%1$@ U rămase"; - -/* Low reservoir alert with time remaining format string. (1: Number of units remaining)(2: approximate time remaining) */ -"%1$@ U left: %2$@" = "%1$@ U rămase: %2$@"; - -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "Există deja un bolus în curs de administrare"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmClockReminder"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alcalină"; - -/* Title for PumpAlarmType.autoOff */ -"Auto-Off Alarm" = "Alarma de oprire automată"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Profil bazal %1$@: %2$@ U/oră"; - -/* Title for PumpAlarmType.batteryDepleted */ -"Battery Depleted" = "Bateria descărcată"; - -/* Title for PumpAlarmType.batteryOutLimitExceeded */ -"Battery Out Limit" = "Limită de descărcare a bateriei"; - -/* Title for PumpAlarmType.deviceResetBatteryIssue17 */ -"BatteryIssue17" = "ProblemaBaterie17"; - -/* Title for PumpAlarmType.deviceResetBatteryIssue21 */ -"BatteryIssue21" = "ProblemaBaterie21"; - -/* Event title for bolus - Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus în derulare"; - -/* Error description when failure due to bolus in progress */ -"Bolus in Progress" = "Bolus în curs de administrare"; - -/* Format string for uncertain bolus. (1: the reported error during bolusing) */ -"Bolus may have failed: %1$@" = "Este posibil ca bolusul să fi eșuat: %1$@"; - -/* Describing the Canada pump region */ -"Canada" = "Canada"; - -/* Event title for temp basal cancel */ -"Cancel Temp Basal" = "Anulați bazala temporară"; - -/* Event title for ChangeBasalProfilePatternPumpEvent */ -"Change Basal Profile Schedule" = "Modificarea profilului programului de insulină bazală"; - -/* Event title for ChangeBasalProfilePumpEvent */ -"Change Basal Schedule" = "Modificarea programului de insulină bazală"; - -/* The notification alert describing a low pump battery */ -"Change the pump battery immediately" = "Schimbați imediat bateria pompei"; - -/* The notification alert describing an empty pump reservoir */ -"Change the pump reservoir now" = "Schimbați rezervorul pompei acum"; - -/* Event title for ChangeTimePumpEvent */ -"Change Time" = "Schimbare oră"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Verificați că pompa nu este suspendată sau în curs de inițiere sau ca nu folosește un tip procentual de bazală temporară"; - -/* Event title for clear alarm pump event */ -"Clear Alarm" = "Ștergeți alarma"; - -/* Pump error code returned when command refused */ -"Command refused" = "Comandă refuzată"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "S-a detectat o comunicare cu altă pompă."; - -/* Error description */ -"Decoding Error" = "Eroare la decodare"; - -/* Error description */ -"Device Error" = "Eroare dispozitiv"; - -/* Title for deviceReset */ -"Device Reset" = "Resetare dispozitiv"; - -/* Default alert dismissal */ -"Dismiss" = "Renunță"; - -/* Title for PumpAlarmType.emptyReservoir */ -"Empty Reservoir" = "Rezervor gol"; - -/* Describing the pump history insulin data source */ -"Event History" = "Istoric evenimente"; - -/* Error description for glucose page failing crc check */ -"Glucose page failed crc check" = "Pagina de glicemie nu a reușit verificarea crc"; - -/* Recovery suggestion for MinimedPumpManagerError.insulinTypeNotConfigured */ -"Go to pump settings and select insulin type" = "Accesați setările pompei și selectați tipul de insulină"; - -/* Pump error code when invalid history page is requested */ -"History page does not exist" = "Pagina de istoric nu există"; - -/* Error description for history page failing crc check */ -"History page failed crc check" = "Pagina pentru istoric nu a reușit verificarea crc"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Administrarea insulinei suspendată"; - -/* Error description for MinimedPumpManagerError.insulinTypeNotConfigured */ -"Insulin Type is not configured" = "Tipul de insulină nu este configurat"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Răspuns invalid în timpul %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Litiu"; - -/* Help anchor for uncertain bolus */ -"Loop sent a bolus command to the pump, but was unable to confirm that the pump received the command. For safety, Loop will assume the bolus was delivered. When Loop eventually fetches history from the pump, and the estimated bolus finish time is passed, Loop will update its records of delivery to match what the pump reports." = "Loop a trimis o comandă de bolus pompei, dar nu a putut confirma că pompa a primit comanda. Pentru siguranță, Loop va presupune că bolusul a fost administrat. Când Loop preia istoricul de la pompă și timpul estimat de terminare a bolusului este trecut, Loop își va actualiza înregistrările de livrare pentru a se potrivi cu ceea ce raportează pompa."; - -/* Event title for JournalEntryPumpLowBatteryPumpEvent */ -"Low Battery" = "Baterie descărcată"; - -/* Event title for JournalEntryPumpLowReservoirPumpEvent */ -"Low Reservoir" = "Rezervor scăzut"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Baterie RileyLink scăzută"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Asigurați-vă că RileyLink este pornit și situat în apropriere"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Setare maximă depășită"; - -/* Event title for JournalEntryMealMarkerPumpEvent */ -"Meal" = "Masă"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 Series"; - -/* Event title for NewTimePumpEvent */ -"New Time" = "Timp nou"; - -/* Title for PumpAlarmType.noDelivery */ -"No Delivery Alarm" = "Fără alarmă de administrare"; - -/* Error description when no rileylink connected */ -"No RileyLink Connected" = "Niciun RileyLink conectat"; - -/* Describing the North America pump region */ -"North America" = "America de Nord"; - -/* Default alert dismissal */ -"Ok" = "Ok"; - -/* Acknowledge button label for RileyLink low battery alert */ -"OK" = "OK"; - -/* Event title for percent based temp basal */ -"Percent Temp Basal" = "Procentul de bazală temporară"; - -/* recoverySuggestion for uncertain bolus */ -"Please check your pump bolus history to determine if the bolus was delivered." = "Vă rugăm să verificați istoricul bolusurilor de pe pompă pentru a determina dacă bolusul a fost administrat."; - -/* Event title for prime pump event */ -"Prime" = "Inițiere"; - -/* The notification title for a low pump battery */ -"Pump Battery Low" = "Nivel scăzut baterie pompă"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pumpa nu a răspuns"; - -/* Error description */ -"Pump Error" = "Eroare pompă"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pompa este suspendată"; - -/* Error description when failure due to pump suspended */ -"Pump is Suspended" = "Pompa este suspendată"; - -/* The notification title for an empty pump reservoir */ -"Pump Reservoir Empty" = "Rezervorul pompei este gol"; - -/* The notification title for a low pump reservoir */ -"Pump Reservoir Low" = "Rezervor de pompare scăzut"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pompa a răspuns în mod neașteptat"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "PumpMessage(%1$@, %2$@, %3$@, %4$@)"; - -/* Title for PumpAlarmType.reprogramError */ -"Reprogram Error" = "Eroare de reprogramare"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Rezervor"; - -/* Event title for resume - Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Reluați"; - -/* Event title for rewind */ -"Rewind" = "Derulare"; - -/* Error description */ -"RileyLink radio tune failed" = "Eșec RileyLink la reglarea radio"; - -/* Event title for starting scheduled basal */ -"Scheduled Basal" = "Bazală programată"; - -/* Event title for SelectBasalProfilePumpEvent */ -"Select Profile" = "Alegeți profilul"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Pierdere de semnal"; - -/* Event title for suspend - Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspendați"; - -/* Event title for temporary basal rate start - Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Bazală temporară"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Bazală temporară: %1$.3f U/oră"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Bazală temporară: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Bazală temporară: %1$d%%"; - -/* Error description when storage fails */ -"Unable to store pump data" = "Imposibil de salvat datele pompei"; - -/* Format string for an unexpectedResponse. (2: The response) */ -"Unexpected response %1$@" = "Răspuns neașteptat %1$@"; - -/* Title for PumpAlarmType.unknownType */ -"Unknown Alarm" = "Alarmă necunoscută"; - -/* Format string for error description for an unknown record type in a glucose page. (1: event type number) */ -"Unknown glucose record type: %$1@" = "Tip necunoscut de înregistrare glicemie: %$1@"; - -/* Format string for error description for an unknown record type in a history page. (1: event type number) */ -"Unknown history record type: %$1@" = "Tip necunoscut de înregistrare istoric: %$1@"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Cod de eroare pompă necunoscut: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Model de pompă necunoscut: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Răspuns nerecunoscut în timpul %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "Global"; - diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/ru.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/ru.lproj/Localizable.strings deleted file mode 100644 index edb38cb9f..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/ru.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "Болюс уже подается"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "Напоминание будильника"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "Предупреждение от сенсора"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Щелочная"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Профиль базала %1$@: %2$@ ед/ч"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Подача болюса"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Убедитесь, что помпа не остановлена или не находится в режиме заправки, а так же что ВБС в помпе установлен в Ед/ч, а не в процентах"; - -/* Pump error code returned when command refused */ -"Command refused" = "Отказ в выполнении команды"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Обнаружена коммуникация с другой помпой"; - -/* Error description */ -"Decoding Error" = "Ошибка декодирования"; - -/* Error description */ -"Device Error" = "Ошибка устройства"; - -/* Describing the pump history insulin data source */ -"Event History" = "История событий"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Неверный отклик %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Литиевая"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Убедитесь, что RileyLink находится поблизости и включен"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Максимальное значение превышено"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 серий"; - -/* Describing the North America pump region */ -"North America" = "Сев Америка"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Помпа не отвечает"; - -/* Error description */ -"Pump Error" = "Ошибка помпы"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Помпа остановлена"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Неожиданный отклик помпы"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "Сообщение помпы(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Резервуар"; - -/* Error description */ -"RileyLink radio tune failed" = "Настройка радиосвязи с RileyLink не удалась"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Временный базал: %1$.3f ед/ч"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Временный базал: %1$d мин"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Временный базал: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Неизвестный код ошибки помпы: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Неизвестная модель помпы: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Неизвестный отклик %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "Глобальный"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/sk.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/sk.lproj/Localizable.strings deleted file mode 100644 index 809615110..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/sk.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "Podanie bolusu už prebieha"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "Pripomienka budíka"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "Senzor alarmu"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkalické"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Bazálny Profil %1$@: %2$@ J/hod"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Prebieha bolus"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Skontrolujte že pumpa nie je pozastavená alebo sa nastavuje, alebo má percentuálny dočasný typ bazálu"; - -/* Pump error code returned when command refused */ -"Command refused" = "Príkaz zamietnutý"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Zaznamenané komunikácie s inou pumpou."; - -/* Error description */ -"Decoding Error" = "Chyba dekódovania"; - -/* Error description */ -"Device Error" = "Chyba zariadenia"; - -/* Describing the pump history insulin data source */ -"Event History" = "História Udalostí"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Neplatná odpoveď počas %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Líthiové"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Uistite sa, že je váš RileyLink v blízkosti a je zapnutý"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Prekročené max nastavenie"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = ""; - -/* Describing the North America pump region */ -"North America" = "Severná Amerika"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pumpa neodpovedá"; - -/* Error description */ -"Pump Error" = "Chyba pumpy"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pumpa je pozastavená"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pumpa odpovedala neočakávane"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "Správa o pumpe(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Rezervoár"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink radio ladenie zlyhalo"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Dočasný Bazál: %1$.3f J/hod"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Dočasný Bazál: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Dočasný Bazál: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Neznáma chyba pumpy kód: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Neznámy model pumpy: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Neznáma odpoveď počas %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "Celo-Svetovo"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/sv.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/sv.lproj/Localizable.strings deleted file mode 100644 index 141233347..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/sv.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "En bolusdos pågår redan"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmClockReminder"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkaliskt"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Basalprofil %1$@: %2$@ E/h"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus pågår"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Kontrollera att pumpen inte är pausad eller håller på att fyllas, eller har en temporär basal inställd med procentuellt värde."; - -/* Pump error code returned when command refused */ -"Command refused" = "Kommandot avvisades"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Kommunikation med en annan pump upptäcktes."; - -/* Error description */ -"Decoding Error" = "Avkodingsfel"; - -/* Error description */ -"Device Error" = "Enhetsfel"; - -/* Describing the pump history insulin data source */ -"Event History" = "Händelsehistorik"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Ogiltigt svar under %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Litium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Säkerställ att din RileyLink är nära och påslagen"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Inställt maxvärde överskridet"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700-serien"; - -/* Describing the North America pump region */ -"North America" = "Nordamerika"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pumpen svarade inte"; - -/* Error description */ -"Pump Error" = "Pumpfel"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pumpen är pausad"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pump svarade oväntat"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "Pumpmeddelande(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Reservoar"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLinks radiojustering misslyckades"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Temporär basal: %1$.3f E/timme"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Temporär basal: %1$d min"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Temporär basal: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Okänt pumpfel: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Okänd pumpmodell: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Okänt svar under %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "Global"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/tr.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/tr.lproj/Localizable.strings deleted file mode 100644 index d3050249d..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/tr.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "Bir bolus zaten devam ediyor"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmSaatiHatırlatma"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "Alarm Sensörü"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkalin"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Bazal Profili %1$@: %2$@ Ü/saat"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Bolus devam ediyor"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Pompanın askıya alınmadığını, dolum aşamasında olmadığını veya yüzde geçici bazal tipine sahip olmadığını kontrol edin."; - -/* Pump error code returned when command refused */ -"Command refused" = "Komut reddedildi"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Başka bir pompa algılandı."; - -/* Error description */ -"Decoding Error" = "Kod Çözme Hatası"; - -/* Error description */ -"Device Error" = "Cihaz Hatası"; - -/* Describing the pump history insulin data source */ -"Event History" = "Etkinlik Geçmişi"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "%1$@: %2$@ sırasında geçersiz yanıt"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Lityum"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "RileyLink'inizin yakında olduğundan ve açık olduğundan emin olun"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Maksimum ayar aşıldı"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 Series"; - -/* Describing the North America pump region */ -"North America" = "North America"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Pompa yanıt vermedi"; - -/* Error description */ -"Pump Error" = "Pompa Hatası"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Pompa askıya alındı"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Pompa beklenmedik bir şekilde yanıt verdi"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "PompaMesajı(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Rezervuar"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink ayarı başarısız oldu"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Geçici Bazal: %1$.3f Ü/saat"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Geçici Bazal: %1$d dk"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Geçici Bazal: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Bilinmeyen pompa hata kodu:%1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Bilinmeyen pompa modeli: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "%1$@: %2$@ sırasında bilinmeyen yanıt"; - -/* Describing the worldwide pump region */ -"World-Wide" = "World-Wide"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/uk.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/uk.lproj/Localizable.strings deleted file mode 100644 index d0fa90269..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/uk.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "Болюс вже подається"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "Нагадування будильника"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "Попередження від сенсора"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkaline"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Профіль базалу %1$@: %2$@ U/год"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Подання болюса"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Переконайтеся, що помпа не зупинена або не перебуває в режимі заправки, а так само, що ВБШ в помпі встановлено в U/год, а не у відсотках"; - -/* Pump error code returned when command refused */ -"Command refused" = "Команду відхилено"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Виявлено комунікацію з іншою помпою"; - -/* Error description */ -"Decoding Error" = "Помилка декодування"; - -/* Error description */ -"Device Error" = "Помилка пристрою"; - -/* Describing the pump history insulin data source */ -"Event History" = "Журнал подій"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Неправильний відгук %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Lithium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Впевніться, що RileyLink увімкнений та знаходиться поруч"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Максимальне значення перевищено"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 Series"; - -/* Describing the North America pump region */ -"North America" = "Північна Америка"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Помпа не відповідає"; - -/* Error description */ -"Pump Error" = "Помилка помпи"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Помпу призупинено"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Несподіваний відгук помпи"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "Повідомлення помпи(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Резервуар"; - -/* Error description */ -"RileyLink radio tune failed" = "Налаштування радіозв'язку з RileyLink не вдалося"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Тимчасовий базал: %1$.3f U/год"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Тимчасовий базал: %1$d хв"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Тимчасовий базал: %1$d хв%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Невідомий код помилки помпи: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Невідома модель помпи: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Невідомий відгук %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "World-Wide"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/vi.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/vi.lproj/Localizable.strings deleted file mode 100644 index 397c86b20..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/vi.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "Liều bolus đang được thực hiện"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmClockReminder"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "Alkaline"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "Hồ sơ Basal %1$@: %2$@ U/giờ"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "Liều Bolus đang được thực hiện"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "Kiểm tra và đảm bảo bơm không tạm ngưng hoặc đang bơm hoặc đang thực hiện liều basal tạm thời"; - -/* Pump error code returned when command refused */ -"Command refused" = "Lệnh bị từ chối"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "Comms cho bơm khác được phát hiện."; - -/* Error description */ -"Decoding Error" = "Đang giải mã bị lỗi"; - -/* Error description */ -"Device Error" = "Thiết bị lỗi"; - -/* Describing the pump history insulin data source */ -"Event History" = "Lược sử tác vụ trước đó"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "Phản ứng không phù hợp trong khoảng %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "Lithium"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "Đảm bảo RileyLink bên cạnh và đã được bật"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "Cài đặt tối đa vượt giới hạn"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700 Series"; - -/* Describing the North America pump region */ -"North America" = "North America"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "Bơm không phản hồi"; - -/* Error description */ -"Pump Error" = "Bơm lỗi"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "Bơm đang được tạm ngưng"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "Bơm phản ứng bất ngờ"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "PumpMessage(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "Ngăn chứa insulin"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink radio thất bại"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "Liều Basal tạm thời: %1$.3f U/giờ"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "Liều Basal tạm thời: %1$d phút"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "Liều Basal tạm thời: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "Không xác định lỗi của bơm: %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "Không xác định mẫu bơm: %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "Phản hồi không xác định trong %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "World-Wide"; diff --git a/Dependencies/MinimedKit/MinimedKit/Resources/zh-Hans.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKit/Resources/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 6299b5365..000000000 --- a/Dependencies/MinimedKit/MinimedKit/Resources/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,98 +0,0 @@ -/* Communications error for a bolus currently running */ -"A bolus is already in progress" = "正在输注大剂量"; - -/* The description of AlarmClockReminderPumpEvent */ -"AlarmClockReminder" = "AlarmClockReminder"; - -/* The description of AlarmSensorPumpEvent */ -"AlarmSensor" = "AlarmSensor"; - -/* Describing the battery chemistry as Alkaline */ -"Alkaline" = "碱性电池"; - -/* The format string description of a BasalProfileStartPumpEvent. (1: The index of the profile)(2: The basal rate) */ -"Basal Profile %1$@: %2$@ U/hour" = "基础率配置 %1$@: %2$@ U/小时"; - -/* Pump error code when bolus is in progress */ -"Bolus in progress" = "大剂量输注中"; - -/* Suggestions for diagnosing a command refused pump error */ -"Check that the pump is not suspended or priming, or has a percent temp basal type" = "确认胰岛素泵是否处于暂停或者充盈状态,或者正在执行百分比模式临时基础率。"; - -/* Pump error code returned when command refused */ -"Command refused" = "当前无法执行命令"; - -/* No comment provided by engineer. */ -"Comms with another pump detected" = "发现其他胰岛素泵"; - -/* Error description */ -"Decoding Error" = "解码错误"; - -/* Error description */ -"Device Error" = "设备错误"; - -/* Describing the pump history insulin data source */ -"Event History" = "历史事件"; - -/* Format string for failure reason. (1: The operation being performed) (2: The response data) */ -"Invalid response during %1$@: %2$@" = "无效响应 %1$@: %2$@"; - -/* Describing the battery chemistry as Lithium */ -"Lithium" = "锂铁电池"; - -/* Recovery suggestion */ -"Make sure your RileyLink is nearby and powered on" = "请确认Rileylink靠近手机并且已打开"; - -/* Pump error code describing max setting exceeded */ -"Max setting exceeded" = "超过最大限制"; - -/* Pump title (1: model number) */ -"Minimed %@" = "Minimed %@"; - -/* Generic title of the minimed pump manager */ -"Minimed 500/700 Series" = "Minimed 500/700系列"; - -/* Describing the North America pump region */ -"North America" = "北美"; - -/* No comment provided by engineer. */ -"Pump did not respond" = "胰岛素泵无响应"; - -/* Error description */ -"Pump Error" = "胰岛素泵错误"; - -/* No comment provided by engineer. */ -"Pump is suspended" = "胰岛素泵暂停输注"; - -/* No comment provided by engineer. */ -"Pump responded unexpectedly" = "胰岛素泵通信异常"; - -/* The format string describing a pump message. (1: The packet type)(2: The message type)(3: The message address)(4: The message data */ -"PumpMessage(%1$@, %2$@, %3$@, %4$@)" = "泵的信息(%1$@, %2$@, %3$@, %4$@)"; - -/* Describing the reservoir insulin data source */ -"Reservoir" = "储药器"; - -/* Error description */ -"RileyLink radio tune failed" = "RileyLink调频失败"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in minutes) */ -"Temporary Basal: %1$.3f U/hour" = "临时基础率: %1$.3f U/小时"; - -/* The format string description of a TempBasalDurationPumpEvent. (1: The duration of the temp basal in minutes) */ -"Temporary Basal: %1$d min" = "临时基础率: %1$d 分钟"; - -/* The format string description of a TempBasalPumpEvent. (1: The rate of the temp basal in percent) */ -"Temporary Basal: %1$d%%" = "临时基础率: %1$d%%"; - -/* The format string description of an unknown pump error code. (1: The specific error code raw value) */ -"Unknown pump error code: %1$@" = "未知的泵错误代码 %1$@"; - -/* No comment provided by engineer. */ -"Unknown pump model: %@" = "未知的泵型号 %@"; - -/* Format string for an unknown response. (1: The operation being performed) (2: The response data) */ -"Unknown response during %1$@: %2$@" = "未知的响应错误 %1$@: %2$@"; - -/* Describing the worldwide pump region */ -"World-Wide" = "全球"; diff --git a/Dependencies/MinimedKit/MinimedKitPlugin/Extensions/OSLog.swift b/Dependencies/MinimedKit/MinimedKitPlugin/Extensions/OSLog.swift deleted file mode 100644 index 0bf2196f0..000000000 --- a/Dependencies/MinimedKit/MinimedKitPlugin/Extensions/OSLog.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// OSLog.swift -// MinimedKitPlugin -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import os.log - - -extension OSLog { - convenience init(category: String) { - self.init(subsystem: "com.loopkit.MinimedKit", category: category) - } - - func debug(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .debug, args) - } - - func info(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .info, args) - } - - func `default`(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .default, args) - } - - func error(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .error, args) - } - - private func log(_ message: StaticString, type: OSLogType, _ args: [CVarArg]) { - switch args.count { - case 0: - os_log(message, log: self, type: type) - case 1: - os_log(message, log: self, type: type, args[0]) - case 2: - os_log(message, log: self, type: type, args[0], args[1]) - case 3: - os_log(message, log: self, type: type, args[0], args[1], args[2]) - case 4: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3]) - case 5: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4]) - default: - os_log(message, log: self, type: type, args) - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKitPlugin/Info.plist b/Dependencies/MinimedKit/MinimedKitPlugin/Info.plist deleted file mode 100644 index 2cce66c09..000000000 --- a/Dependencies/MinimedKit/MinimedKitPlugin/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - com.loopkit.Loop.PumpManagerDisplayName - Minimed 500/700 Series - com.loopkit.Loop.PumpManagerIdentifier - Minimed500 - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - - diff --git a/Dependencies/MinimedKit/MinimedKitPlugin/MinimedKitPlugin.swift b/Dependencies/MinimedKit/MinimedKitPlugin/MinimedKitPlugin.swift deleted file mode 100644 index b3996441a..000000000 --- a/Dependencies/MinimedKit/MinimedKitPlugin/MinimedKitPlugin.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// MinimedKitPlugin.swift -// MinimedKitPlugin -// -// Created by Pete Schwamb on 8/24/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import os.log -import LoopKitUI -import MinimedKit -import MinimedKitUI - -class MinimedKitPlugin: NSObject, PumpManagerUIPlugin { - private let log = OSLog(category: "MinimedKitPlugin") - - public var pumpManagerType: PumpManagerUI.Type? { - return MinimedPumpManager.self - } - - override init() { - super.init() - log.default("Instantiated") - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/BasalScheduleTests.swift b/Dependencies/MinimedKit/MinimedKitTests/BasalScheduleTests.swift deleted file mode 100644 index 27e2128bb..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/BasalScheduleTests.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// BasalScheduleTests.swift -// RileyLink -// -// Created by Jaim Zuber on 5/2/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class BasalScheduleTests: XCTestCase { - - var sampleData: Data { - let sampleDataString = "06000052000178050202000304000402000504000602000704000802000904000a02000b04000c02000d02000e02000f040010020011040012020013040014020015040016020017040018020019000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - - return Data(hexadecimalString: sampleDataString)! - } - - func testBasicConversion() { - let profile = BasalSchedule(rawValue: sampleData)! - - XCTAssertEqual(profile.entries.count, 26) - - let basalSchedule = profile.entries - - // Test each element - XCTAssertEqual(basalSchedule[0].index, 0) - XCTAssertEqual(basalSchedule[0].timeOffset, TimeInterval(minutes: 0)) - XCTAssertEqual(basalSchedule[0].rate, 0.15, accuracy: .ulpOfOne) - - XCTAssertEqual(basalSchedule[1].index, 1) - XCTAssertEqual(basalSchedule[1].timeOffset, TimeInterval(minutes: 30)) - XCTAssertEqual(basalSchedule[1].rate, 2.05, accuracy: .ulpOfOne) - - // Tests parsing rates that take two bytes to encode - XCTAssertEqual(basalSchedule[2].index, 2) - XCTAssertEqual(basalSchedule[2].timeOffset, TimeInterval(minutes: 60)) - XCTAssertEqual(basalSchedule[2].rate, 35.00, accuracy: .ulpOfOne) - - // Tests parsing entry on the second page - XCTAssertEqual(basalSchedule[25].index, 25) - XCTAssertEqual(basalSchedule[25].timeOffset, TimeInterval(minutes: 750)) - XCTAssertEqual(basalSchedule[25].rate, 0.05, accuracy: .ulpOfOne) - - XCTAssertEqual(sampleData.hexadecimalString, profile.rawValue.hexadecimalString) - } - - func testTxData() { - let profile = BasalSchedule(entries: [ - BasalScheduleEntry(index: 0, timeOffset: .hours(0), rate: 1.0), - BasalScheduleEntry(index: 1, timeOffset: .hours(4), rate: 2.0), - ]) - - XCTAssertEqual("280000500008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", profile.rawValue.hexadecimalString) - } - - func testDataFrameParsing() { - let frames = DataFrameMessageBody.dataFramesFromContents(sampleData) - - XCTAssertEqual("0106000052000178050202000304000402000504000602000704000802000904000a02000b04000c02000d02000e02000f04001002001104001202001304001402", frames[0].txData.hexadecimalString) - XCTAssertEqual("0200150400160200170400180200190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", frames[1].txData.hexadecimalString) - XCTAssertEqual("8300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", frames[2].txData.hexadecimalString) - - XCTAssertEqual(3, frames.count) - } - - func testEmptySchedule() { - let emptyData = Data(hexadecimalString: "00003f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")! - - let profile = BasalSchedule(rawValue: emptyData) - XCTAssertNil(profile) - - XCTAssertEqual(emptyData, BasalSchedule(entries: []).rawValue) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/CRC16Tests.swift b/Dependencies/MinimedKit/MinimedKitTests/CRC16Tests.swift deleted file mode 100644 index 9c335be89..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/CRC16Tests.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// CRC16Tests.swift -// RileyLink -// -// Created by Pete Schwamb on 2/27/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - - -class CRC16Tests: XCTestCase { - - func testComputeCRC16() { - let input = Data(hexadecimalString: "5be409a20a1510325000784b502800a400002400a8965c0b404fc038cbd008d5d0010080008000240009a24a15107b0500800c1510180a000ade19a32c15105bde2ba30c1510325000b44b5024006c0000200070965c0b4c78c03482c040c8c001007000700020002ba34c15100a0c22932d75903f2122938d7510c527ad5b0006900f15101a5000b44b500000380000000038965c0e70a1c04c19d03423d04069d00100380038000c0006904f15107b060080101510200e005b0034ab1015100d5000784b500000280000000028965c113858c070f8c04c70d0347ad040c0d00100280028001c0034ab5015100ab005863175903f360586117510c527ad5bb01486111510005100784b50940000000038005c965c14281fc0386fc0700fd04c87d03491d040d7d001005c005c00380014865115105b002291121510285000784b500000840000000084965c145c48c02866c038b6c07056d04cced034d8d0010084008400480022915215107b0700801315102610002100038414151003000000360785341510064a097e009e54b5100c4a03a11415107b0704a11415102610007b0704a11415102610007b0710a1141510261000030003000306a11415100ae937a23475103f1d37a2347510c527ad5be91ea3141510165000784b502c00480000140060965c0e848cc05cd2c028f0c03840d001006000600014001ea35415107b0800801515102a13000a5621ba3515905b5623ba151510005100b455505800000000340024965c116053c084dfc05c25d02843d03893d0010024002400340023ba5515105b00188c161510005000b455500000000000000000965c142411c06061c084edc05c33d02851d038a1d00100180018004c00188c56151000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")! - XCTAssertTrue(0x803a == computeCRC16(input)) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/CRC8Tests.swift b/Dependencies/MinimedKit/MinimedKitTests/CRC8Tests.swift deleted file mode 100644 index 2d60fe88e..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/CRC8Tests.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// CRC8Tests.swift -// RileyLink -// -// Created by Pete Schwamb on 2/27/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class CRC8Tests: XCTestCase { - - func testComputeCRC8() { - let input = Data(hexadecimalString: "a259705504a24117043a0e080b003d3d00015b030105d817790a0f00000300008b1702000e080b0000")! - XCTAssertEqual(0x71, input.crc8()) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Extensions/Data.swift b/Dependencies/MinimedKit/MinimedKitTests/Extensions/Data.swift deleted file mode 100644 index 8ac359fa2..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Extensions/Data.swift +++ /dev/null @@ -1,90 +0,0 @@ -// -// Data.swift -// MinimedKitTests -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension Data { - private func toDefaultEndian(_: T.Type) -> T { - return self.withUnsafeBytes({ (rawBufferPointer: UnsafeRawBufferPointer) -> T in - let bufferPointer = rawBufferPointer.bindMemory(to: T.self) - guard let pointer = bufferPointer.baseAddress else { - return 0 - } - return T(pointer.pointee) - }) - } - - func to(_ type: T.Type) -> T { - return T(littleEndian: toDefaultEndian(type)) - } - - func toBigEndian(_ type: T.Type) -> T { - return T(bigEndian: toDefaultEndian(type)) - } - - mutating func append(_ newElement: T) { - var element = newElement.littleEndian - append(Data(bytes: &element, count: element.bitWidth / 8)) - } - - mutating func appendBigEndian(_ newElement: T) { - var element = newElement.bigEndian - append(Data(bytes: &element, count: element.bitWidth / 8)) - } - - init(_ value: T) { - var value = value.littleEndian - self.init(bytes: &value, count: value.bitWidth / 8) - } - - init(bigEndian value: T) { - var value = value.bigEndian - self.init(bytes: &value, count: value.bitWidth / 8) - } -} - - -// String conversion methods, adapted from https://stackoverflow.com/questions/40276322/hex-binary-string-conversion-in-swift/40278391#40278391 -extension Data { - init?(hexadecimalString: String) { - self.init(capacity: hexadecimalString.utf16.count / 2) - - // Convert 0 ... 9, a ... f, A ...F to their decimal value, - // return nil for all other input characters - func decodeNibble(u: UInt16) -> UInt8? { - switch u { - case 0x30 ... 0x39: // '0'-'9' - return UInt8(u - 0x30) - case 0x41 ... 0x46: // 'A'-'F' - return UInt8(u - 0x41 + 10) // 10 since 'A' is 10, not 0 - case 0x61 ... 0x66: // 'a'-'f' - return UInt8(u - 0x61 + 10) // 10 since 'a' is 10, not 0 - default: - return nil - } - } - - var even = true - var byte: UInt8 = 0 - for c in hexadecimalString.utf16 { - guard let val = decodeNibble(u: c) else { return nil } - if even { - byte = val << 4 - } else { - byte += val - self.append(byte) - } - even = !even - } - guard even else { return nil } - } - - var hexadecimalString: String { - return map { String(format: "%02hhx", $0) }.joined() - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Extensions/TimeInterval.swift b/Dependencies/MinimedKit/MinimedKitTests/Extensions/TimeInterval.swift deleted file mode 100644 index e2e99b7a5..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Extensions/TimeInterval.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// TimeInterval.swift -// MinimedKitTests -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension TimeInterval { - - static func days(_ days: Double) -> TimeInterval { - return self.init(days: days) - } - - static func hours(_ hours: Double) -> TimeInterval { - return self.init(hours: hours) - } - - static func minutes(_ minutes: Int) -> TimeInterval { - return self.init(minutes: Double(minutes)) - } - - static func minutes(_ minutes: Double) -> TimeInterval { - return self.init(minutes: minutes) - } - - static func seconds(_ seconds: Double) -> TimeInterval { - return self.init(seconds) - } - - static func milliseconds(_ milliseconds: Double) -> TimeInterval { - return self.init(milliseconds / 1000) - } - - init(days: Double) { - self.init(hours: days * 24) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - init(minutes: Double) { - self.init(minutes * 60) - } - - init(seconds: Double) { - self.init(seconds) - } - - init(milliseconds: Double) { - self.init(milliseconds / 1000) - } - - var milliseconds: Double { - return self * 1000 - } - - init(hundredthsOfMilliseconds: Double) { - self.init(hundredthsOfMilliseconds / 100000) - } - - var hundredthsOfMilliseconds: Double { - return self * 100000 - } - - var minutes: Double { - return self / 60.0 - } - - var hours: Double { - return minutes / 60.0 - } - - var days: Double { - return hours / 24.0 - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/BatteryChangeGlucoseEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/BatteryChangeGlucoseEventTests.swift deleted file mode 100644 index 196068d9a..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/BatteryChangeGlucoseEventTests.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// BatteryChangeGlucoseEventTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/18/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class BatteryChangeGlucoseEventTests: XCTestCase { - - func testDecoding() { - let rawData = Data(hexadecimalString: "0a0bae0a0e")! - let subject = BatteryChangeGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - let expectedTimestamp = DateComponents(calendar: Calendar(identifier: .gregorian), - year: 2014, month: 2, day: 10, hour: 11, minute: 46) - XCTAssertEqual(subject.timestamp, expectedTimestamp) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/CalBGForGHGlucoseEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/CalBGForGHGlucoseEventTests.swift deleted file mode 100644 index a2341078b..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/CalBGForGHGlucoseEventTests.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// CalBGForGHGlucoseEventTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/18/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class CalBGForGHGlucoseEventTests: XCTestCase { - - func testDecoding() { - let rawData = Data(hexadecimalString: "0e4f5b138fa0")! - let subject = CalBGForGHGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - let expectedTimestamp = DateComponents(calendar: Calendar(identifier: .gregorian), - year: 2015, month: 5, day: 19, hour: 15, minute: 27) - XCTAssertEqual(subject.timestamp, expectedTimestamp) - XCTAssertEqual(subject.amount, 160) - XCTAssertEqual(subject.dictionaryRepresentation["originType"] as! String, "rf") - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/DateTimeChangeGlucoseEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/DateTimeChangeGlucoseEventTests.swift deleted file mode 100644 index 3f99d1dcd..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/DateTimeChangeGlucoseEventTests.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// DateTimeChangeGlucoseEventTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/18/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class DateTimeChangeGlucoseEventTests: XCTestCase { - - func testDecoding() { - let rawData = Data(hexadecimalString: "0c0ad23e0e")! - let subject = DateTimeChangeGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - let expectedTimestamp = DateComponents(calendar: Calendar(identifier: .gregorian), - year: 2014, month: 3, day: 30, hour: 10, minute: 18) - XCTAssertEqual(subject.timestamp, expectedTimestamp) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/GlucoseSensorDataGlucoseEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/GlucoseSensorDataGlucoseEventTests.swift deleted file mode 100644 index 9f5d3c95d..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/GlucoseSensorDataGlucoseEventTests.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// GlucoseSensorDataGlucoseEventTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/18/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class GlucoseSensorDataGlucoseEventTests: XCTestCase { - - func testDecoding() { - let rawData = Data(hexadecimalString: "35")! - let subject = GlucoseSensorDataGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - XCTAssertEqual(subject.sgv, 106) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorCalFactorGlucoseEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorCalFactorGlucoseEventTests.swift deleted file mode 100644 index b0c84fe6a..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorCalFactorGlucoseEventTests.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// SensorCalFactorGlucoseEventTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/18/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class SensorCalFactorGlucoseEventTests: XCTestCase { - - func testDecoding() { - let rawData = Data(hexadecimalString: "0f4f67130f128c")! - let subject = SensorCalFactorGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - let expectedTimestamp = DateComponents(calendar: Calendar(identifier: .gregorian), - year: 2015, month: 5, day: 19, hour: 15, minute: 39) - XCTAssertEqual(subject.timestamp, expectedTimestamp) - XCTAssertEqual(subject.factor, 4.748) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorCalGlucoseEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorCalGlucoseEventTests.swift deleted file mode 100644 index 2c0b7b60c..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorCalGlucoseEventTests.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// SensorCalGlucoseEventTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/18/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class SensorCalGlucoseEventTests: XCTestCase { - - func testDecodingMeterBgNow() { - let rawData = Data(hexadecimalString: "0300")! - let subject = SensorCalGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - XCTAssertEqual(subject.dictionaryRepresentation["calibrationType"] as! String, "meter_bg_now") - } - - func testDecodingWaiting() { - let rawData = Data(hexadecimalString: "0301")! - let subject = SensorCalGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - XCTAssertEqual(subject.dictionaryRepresentation["calibrationType"] as! String, "waiting") - } - - func testDecodingCalError() { - let rawData = Data(hexadecimalString: "0302")! - let subject = SensorCalGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - XCTAssertEqual(subject.dictionaryRepresentation["calibrationType"] as! String, "cal_error") - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorDataHighGlucoseEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorDataHighGlucoseEventTests.swift deleted file mode 100644 index 8f3f5d031..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorDataHighGlucoseEventTests.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// SensorDataHighGlucoseEventTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 12/6/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class SensorDataHighGlucoseEventTests: XCTestCase { - - func testDecoding() { - let rawData = Data(hexadecimalString: "07FF")! - let subject = SensorDataHighGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - XCTAssertEqual(subject.sgv, 400) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorDataLowGlucoseEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorDataLowGlucoseEventTests.swift deleted file mode 100644 index b78264c7b..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorDataLowGlucoseEventTests.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// SensorDataLowEventTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 12/5/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class SensorDataLowGlucoseEventTests: XCTestCase { - - func testDecoding() { - let rawData = Data(hexadecimalString: "06")! - let subject = SensorDataLowGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - XCTAssertEqual(subject.sgv, 40) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorErrorGlucoseEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorErrorGlucoseEventTests.swift deleted file mode 100644 index cc1487b24..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorErrorGlucoseEventTests.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// SensorErrorGlucoseEventTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 12/6/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class SensorErrorGlucoseEventTests: XCTestCase { - - func testDecoding() { - let rawData = Data(hexadecimalString: "0501")! - let subject = SensorErrorGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - XCTAssertEqual(subject.dictionaryRepresentation["errorType"] as! String, "end") - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorPacketGlucoseEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorPacketGlucoseEventTests.swift deleted file mode 100644 index 1817d2ba6..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorPacketGlucoseEventTests.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// SensorPacketGlucoseEventTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 12/6/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class SensorPacketGlucoseEventTests: XCTestCase { - - func testDecoding() { - let rawData = Data(hexadecimalString: "0402")! - let subject = SensorPacketGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - XCTAssertEqual(subject.dictionaryRepresentation["packetType"] as! String, "init") - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorStatusGlucoseEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorStatusGlucoseEventTests.swift deleted file mode 100644 index da371494b..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorStatusGlucoseEventTests.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// SensorStatusGlucoseEventTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/18/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class SensorStatusGlucoseEventTests: XCTestCase { - - func testDecodingStatusTypeOff() { - let rawData = Data(hexadecimalString: "0b0baf0a0e")! - let subject = SensorStatusGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - let expectedTimestamp = DateComponents(calendar: Calendar(identifier: .gregorian), - year: 2014, month: 2, day: 10, hour: 11, minute: 47) - XCTAssertEqual(subject.timestamp, expectedTimestamp) - XCTAssertEqual(subject.dictionaryRepresentation["statusType"] as! String, "off") - } - - func testDecodingStatusTypeOn() { - let rawData = Data(hexadecimalString: "0b0baf2a0e")! - let subject = SensorStatusGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - let expectedTimestamp = DateComponents(calendar: Calendar(identifier: .gregorian), - year: 2014, month: 2, day: 10, hour: 11, minute: 47) - XCTAssertEqual(subject.timestamp, expectedTimestamp) - XCTAssertEqual(subject.dictionaryRepresentation["statusType"] as! String, "on") - } - - func testDecodingStatusTypeLost() { - let rawData = Data(hexadecimalString: "0b0baf4a0e")! - let subject = SensorStatusGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - let expectedTimestamp = DateComponents(calendar: Calendar(identifier: .gregorian), - year: 2014, month: 2, day: 10, hour: 11, minute: 47) - XCTAssertEqual(subject.timestamp, expectedTimestamp) - XCTAssertEqual(subject.dictionaryRepresentation["statusType"] as! String, "lost") - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorSyncGlucoseEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorSyncGlucoseEventTests.swift deleted file mode 100644 index 5f503147f..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorSyncGlucoseEventTests.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// SensorSyncGlucoseEventTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/18/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class SensorSyncGlucoseEventTests: XCTestCase { - - func testSyncTypeNew() { - let rawData = Data(hexadecimalString: "0d4d44330f")! - let subject = SensorSyncGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - let expectedTimestamp = DateComponents(calendar: Calendar(identifier: .gregorian), - year: 2015, month: 5, day: 19, hour: 13, minute: 04) - XCTAssertEqual(subject.timestamp, expectedTimestamp) - XCTAssertEqual(subject.dictionaryRepresentation["syncType"] as! String, "new") - } - - func testSyncTypeOld() { - let rawData = Data(hexadecimalString: "0d4d44530f")! - let subject = SensorSyncGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - let expectedTimestamp = DateComponents(calendar: Calendar(identifier: .gregorian), - year: 2015, month: 5, day: 19, hour: 13, minute: 04) - XCTAssertEqual(subject.timestamp, expectedTimestamp) - XCTAssertEqual(subject.dictionaryRepresentation["syncType"] as! String, "old") - } - - func testSyncTypeFind() { - let rawData = Data(hexadecimalString: "0d4d44730f")! - let subject = SensorSyncGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - let expectedTimestamp = DateComponents(calendar: Calendar(identifier: .gregorian), - year: 2015, month: 5, day: 19, hour: 13, minute: 04) - XCTAssertEqual(subject.timestamp, expectedTimestamp) - XCTAssertEqual(subject.dictionaryRepresentation["syncType"] as! String, "find") - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorTimestampGlucoseEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorTimestampGlucoseEventTests.swift deleted file mode 100644 index b778728f5..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/SensorTimestampGlucoseEventTests.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// SensorTimestampGlucoseEventTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/18/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class SensorTimestampGlucoseEventTests: XCTestCase { - - func testDecodingPageEnd() { - let rawData = Data(hexadecimalString: "0814B62810")! - let subject = SensorTimestampGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - XCTAssertEqual(subject.timestampType, .pageEnd) - - let expectedTimestamp = DateComponents(calendar: Calendar(identifier: .gregorian), - year: 2016, month: 02, day: 08, hour: 20, minute: 54) - XCTAssertEqual(subject.timestamp, expectedTimestamp) - } - - - func testTimestampTypeLastRf() { - let rawData = Data(hexadecimalString: "088d9b5d0c")! - let subject = SensorTimestampGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - XCTAssertEqual(subject.timestampType, .gap) - - let expectedTimestamp = DateComponents(calendar: Calendar(identifier: .gregorian), - year: 2012, month: 10, day: 29, hour: 13, minute: 27) - XCTAssertEqual(subject.timestamp, expectedTimestamp) - } - - func testTimestampTypeGap() { - let rawData = Data(hexadecimalString: "088d9b1d0c")! - let subject = SensorTimestampGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - XCTAssertEqual(subject.timestampType, .lastRf) - - let expectedTimestamp = DateComponents(calendar: Calendar(identifier: .gregorian), - year: 2012, month: 10, day: 29, hour: 13, minute: 27) - XCTAssertEqual(subject.timestamp, expectedTimestamp) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/TenSomethingGlucoseEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/TenSomethingGlucoseEventTests.swift deleted file mode 100644 index 1564c6579..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucoseEvents/TenSomethingGlucoseEventTests.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// TenSomethingGlucoseEventTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/18/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class TenSomethingGlucoseEventTests: XCTestCase { - - func testDecoding() { - let rawData = Data(hexadecimalString: "100bb40a0e010000")! - let subject = TenSomethingGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - - let expectedTimestamp = DateComponents(calendar: Calendar(identifier: .gregorian), - year: 2014, month: 2, day: 10, hour: 11, minute: 52) - XCTAssertEqual(subject.timestamp, expectedTimestamp) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/GlucosePageTests.swift b/Dependencies/MinimedKit/MinimedKitTests/GlucosePageTests.swift deleted file mode 100644 index 152ab5891..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/GlucosePageTests.swift +++ /dev/null @@ -1,108 +0,0 @@ -// -// GlucosePageTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/16/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class GlucosePageTests: XCTestCase { - - func testGlucosePageCRC() { - do { - let _ = try GlucosePage(pageData: Data(hexadecimalString: "201E1D1C1A1817161718191B1D1B1C1F212527282A2E3235383C3FCD9086850E0E0000011006850E1043484857EB181006940E0F595E00000110069F0E106670757374767A7D7F8181817D7813726D6663605E5B554F4C4E4F4B484946423E3B38353234332D2B2B2B2C2E302F2F312F2D2D2E2D2C2D2D2A2B292700000110069F1310242323272B2C3235383C00000110069514103E3E3F404141444A4945413E3D3D3A35302C2823201D1B1C1D1A1A1B1C1E2123272B2F3231323235383B3F43484949474542779007A0000E41423D6C171007AD000F3C3D3D3B3C3E3F41474F545A626A6E700000011007860210717271727476797A7A7B7C7D7C7B777472706E6D6C6B6A6763605C5A6064636160605F5D5C5C5B5956545250555A585656555554565654504D4C4A484E515455555452504F4D4D504E4D4E505050504F4E4D4C4C4F50510000011007980910539290079C090E54554BC4141007A8090F4A4A49494C4C4D50515253524F53524F4D4C7590078E0B0E7590878E0B0E4A4947433BD0121007A30B0F373333312F2B26242423252526292A2A2A0000011007810D102A2A2828282B3337383A3F44474746484B4F52504B4846434343413D393500000110079F0F10312F2D2B27211E1D3F90078E100E1C1A191214100798100F181817181F20242A2E33383E41464B4B4F56595E000001100788121065686667660000011007A3121066686B6D6F727375777774707273706C6764615F5A575553453D39322C251F1A1C191614171D2124282C2E31353A3F4144484A4B4C4D50555B000001100790171061656A6665656768C99007B9170E0000011007B917106869659413100889000F625F5D5D5F5D5A56524B4E4E4C4B4847494B494A4D5051514F4E4C4E4E4D4B4A494A4B4B4B4B47474D4E4E4E4E4E4C4B4A46434B4D4C4B49490000011008B804104B4B4B4D515456565655545455595A5800000110088F0610595A5A595A595755555858575655545453525152534E4A474445484B4E4F13505251135113515051525154AF9088A6090E0000011008A6091052505594141008B3090F55565B5A58534F4B49134037132F28132320131A13181514151615171919191A1A1B1A1B1C1D202325242221225890088B0D0E00000110088C0D1023252AEC151008990D0F2B2B2E31393F3A3C41484E555D00000110089F0E1063696E73767A7C7D7F7E7F8085878689E59008B50F0E0000011008B50F10878979CD13100885100F76737272706D0000011008A71010696461605D5A57555352520000011008A11110504C4947484743434278900893120E0000011008941210423F3A3837D6131008A9120F33322F2E2F31322F2C2C2B2828292A2827243A90088E140E211C19181809141008A4140F191A19191028B6140813131313133C95")!) - } catch GlucosePageError.invalidCRC { - XCTFail("page decoding threw invalid crc") - } catch GlucosePageError.unknownEventType(let eventType) { - XCTFail("unknown event type" + String(eventType)) - } catch { - XCTFail("Unexpected exception...") - } - } - - func testGlucosePageInvalidCRC() { - do { - let _ = try GlucosePage(pageData: Data(hexadecimalString: "201E1D1C1A1817161718191B1D1B1C1F212527282A2E3235383C3FCD9086850E0E0000011006850E1043484857EB181006940E0F595E00000110069F0E106670757374767A7D7F8181817D7813726D6663605E5B554F4C4E4F4B484946423E3B38353234332D2B2B2B2C2E302F2F312F2D2D2E2D2C2D2D2A2B292700000110069F1310242323272B2C3235383C00000110069514103E3E3F404141444A4945413E3D3D3A35302C2823201D1B1C1D1A1A1B1C1E2123272B2F3231323235383B3F43484949474542779007A0000E41423D6C171007AD000F3C3D3D3B3C3E3F41474F545A626A6E700000011007860210717271727476797A7A7B7C7D7C7B777472706E6D6C6B6A6763605C5A6064636160605F5D5C5C5B5956545250555A585656555554565654504D4C4A484E515455555452504F4D4D504E4D4E505050504F4E4D4C4C4F50510000011007980910539290079C090E54554BC4141007A8090F4A4A49494C4C4D50515253524F53524F4D4C7590078E0B0E7590878E0B0E4A4947433BD0121007A30B0F373333312F2B26242423252526292A2A2A0000011007810D102A2A2828282B3337383A3F44474746484B4F52504B4846434343413D393500000110079F0F10312F2D2B27211E1D3F90078E100E1C1A191214100798100F181817181F20242A2E33383E41464B4B4F56595E000001100788121065686667660000011007A3121066686B6D6F727375777774707273706C6764615F5A575553453D39322C251F1A1C191614171D2124282C2E31353A3F4144484A4B4C4D50555B000001100790171061656A6665656768C99007B9170E0000011007B917106869659413100889000F625F5D5D5F5D5A56524B4E4E4C4B4847494B494A4D5051514F4E4C4E4E4D4B4A494A4B4B4B4B47474D4E4E4E4E4E4C4B4A46434B4D4C4B49490000011008B804104B4B4B4D515456565655545455595A5800000110088F0610595A5A595A595755555858575655545453525152534E4A474445484B4E4F13505251135113515051525154AF9088A6090E0000011008A6091052505594141008B3090F55565B5A58534F4B49134037132F28132320131A13181514151615171919191A1A1B1A1B1C1D202325242221225890088B0D0E00000110088C0D1023252AEC151008990D0F2B2B2E31393F3A3C41484E555D00000110089F0E1063696E73767A7C7D7F7E7F8085878689E59008B50F0E0000011008B50F10878979CD13100885100F76737272706D0000011008A71010696461605D5A57555352520000011008A11110504C4947484743434278900893120E0000011008941210423F3A3837D6131008A9120F33322F2E2F31322F2C2C2B2828292A2827243A90088E140E211C19181809141008A4140F191A19191028B6140813131313133C94")!) - XCTFail("Should have thrown InvalidCRC") - } catch GlucosePageError.invalidCRC { - // Happy path - } catch GlucosePageError.unknownEventType(let eventType) { - XCTFail("unknown event type" + String(eventType)) - } catch { - XCTFail("Unexpected exception...") - } - } - - func testUnknownRecords() { - do { - //11 is a currently unknown opcode - let pageData = Data(hexadecimalString: "111028B6140813E2E2".leftPadding(toLength: 2048, withPad: "0"))! - let page = try GlucosePage(pageData: pageData) - let events = page.events - - XCTAssertEqual((events.first as! UnknownGlucoseEvent).dictionaryRepresentation["op"] as! String, "11") - XCTAssertEqual(events.count, 3) - - } catch GlucosePageError.invalidCRC { - XCTFail("page decoding threw invalid crc") - } catch GlucosePageError.unknownEventType(let eventType) { - XCTFail("unknown event type" + String(eventType)) - } catch { - XCTFail("Unexpected exception...") - } - } - - func testNeedsTimestamp() { - do { - //11 is a currently unknown opcode - let pageData = Data(hexadecimalString: "01011053b3940810531111AE".leftPadding(toLength: 2048, withPad: "0"))! - let page = try GlucosePage(pageData: pageData) - - XCTAssertTrue(page.needsTimestamp) - - } catch GlucosePageError.invalidCRC { - XCTFail("page decoding threw invalid crc") - } catch GlucosePageError.unknownEventType(let eventType) { - XCTFail("unknown event type" + String(eventType)) - } catch { - XCTFail("Unexpected exception...") - } - } - - func testDoesNotNeedTimestamp() { - do { - //sensor timestamp with timestampType of .lastRf - let pageData = Data(hexadecimalString: "1013b39408534232".leftPadding(toLength: 2048, withPad: "0"))! - let page = try GlucosePage(pageData: pageData) - - XCTAssertFalse(page.needsTimestamp) - - } catch GlucosePageError.invalidCRC { - XCTFail("page decoding threw invalid crc") - } catch GlucosePageError.unknownEventType(let eventType) { - XCTFail("unknown event type" + String(eventType)) - } catch { - XCTFail("Unexpected exception...") - } - } - - func testLastSensorTimestampTypeGapNeedsTimestamp() { - do { - //sensor timestamp with timestampType of .gap - let pageData = Data(hexadecimalString: "1053b3940853535A".leftPadding(toLength: 2048, withPad: "0"))! - let page = try GlucosePage(pageData: pageData) - - XCTAssertTrue(page.needsTimestamp) - - } catch GlucosePageError.invalidCRC { - XCTFail("page decoding threw invalid crc") - } catch GlucosePageError.unknownEventType(let eventType) { - XCTFail("unknown event type" + String(eventType)) - } catch { - XCTFail("Unexpected exception...") - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/HistoryPageTests.swift b/Dependencies/MinimedKit/MinimedKitTests/HistoryPageTests.swift deleted file mode 100644 index f9ecef73f..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/HistoryPageTests.swift +++ /dev/null @@ -1,496 +0,0 @@ -// -// HistoryPageTests.swift -// RileyLink -// -// Created by Pete Schwamb on 3/7/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class HistoryPageTests: XCTestCase { - - func testHistoryPageCRC() { - let pumpModel = PumpModel.model551 - do { - let _ = try HistoryPage(pageData: Data(hexadecimalString: "6e2190050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0802101122007b0200c01602102c1c007b0000c000031000160007000002be22900000006e2290050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de08031011220034640edc120310810123ef12031000101111117d0223ef12031000a2ce8aa0001011111100000000000000000000000000000000000000007b0200c01603102c1c0021001cce16031003000000100fd03603107b021edb1603102c1c0003000100011cdb160310820106dc16031000a2ce8aa0820108dc16031000101111117b0000c000041000160007000002b823900000006e2390050000000000000002b802b8640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0804101122007b0200c01604102c1c007b0000c000051000160007000002be24900000006e2490050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0805101122007b0200c01605102c1c007b0000c000061000160007000002be25900000006e2590050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0806101122007b0200c01606102c1c007b0000c000071000160007000002be26900000006e2690050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de08071011220081010bec0a071000a2ce8aa07d010bec0a071000a2ce8aa000000000000000000000000000000000000000000000000000820108c40b071000a2ce8aa081010cc40b071000a2ce8aa07d010cc40b071000a2ce8aa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004475")!, pumpModel: pumpModel) - } catch HistoryPageError.invalidCRC { - XCTFail("page decoding threw invalid crc") - } catch HistoryPageError.unknownEventType(let eventType) { - XCTFail("unknown event type" + String(eventType)) - } catch { - XCTFail("Unexpected exception...") - } - } - - func testHistoryParsingShouldNotContinuePastAlarmsIndicatingUnrecoverableClock() { - do { - let page = try HistoryPage(pageData: Data(hexadecimalString: - "6dbb94050c00e80000000001c600ca2c00fc38000000fc3800000000000000fc6402000000020c00e80000002601a6e2005c1427000000000000280f423f0000001400aae2005c141700abe2005c141800abe2005c140106060097d84b5c1401232300b0e44b5c141700a8c70c5c141800a8c70c5c1401141400afd94d5c1401323200a3d24e5c141e00abd90e1c141f00a2eb0e1c14011e1e00a2d84f5c14011e1e00afe7501c140615050d0040600105061104e9004040a1050c15124000010564000a4000010517001e40000105180000400001052100034000010503000000001640200105170009420041051800b6ee115c14070000000201856d0185050c00e8000000000002000264000000000000000000000000000000000000000000000c00e80000001700b6ee115c141800b6ee115c143300b8f0115c14001601b8f0115c14000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008559")!, pumpModel: .model522) - XCTAssertEqual(31, page.events.count) - - let startDate = ISO8601DateFormatter().date(from: "2020-11-20T00:00:00Z")! - let timeZone = TimeZone(secondsFromGMT: -21600)! - - let (timestampedEvents, _, _) = page.timestampedEvents(after: startDate, timeZone: timeZone, model: .model522) - - XCTAssertEqual(11, timestampedEvents.count) - - } catch { - XCTFail("Unexpected exception...") - } - } - - func testDroppedBolus() { - let pumpModel = PumpModel.model523 - do { - let events = try HistoryPage(pageData: Data(hexadecimalString: "09010265144717002a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b000265144717002a00140007651447177b000765144717002a00170008651447171800376414471733540266144717001601026614471733581b691447170016011b6914471701006a006a0000000c6d5447173300027014471700160002701447177b000270140717002a003300077014471700160007701447177b000770140717002a0033000a701447170016000a701447177b000a70140717002a0001000b000b006a00117354471701000400040074001c4155471700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c2c6")!, pumpModel: pumpModel) - print("events = \(events.events.count)") - } catch { - XCTFail("Unexpected exception...") - } - } - - - func testHistoryPageInvalidCRC() { - let pumpModel = PumpModel.model551 - do { - let _ = try HistoryPage(pageData: Data(hexadecimalString: "6e2190050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0802101122007b0200c01602102c1c007b0000c000031000160007000002be22900000006e2290050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de08031011220034640edc120310810123ef12031000101111117d0223ef12031000a2ce8aa0001011111100000000000000000000000000000000000000007b0200c01603102c1c0021001cce16031003000000100fd03603107b021edb1603102c1c0003000100011cdb160310820106dc16031000a2ce8aa0820108dc16031000101111117b0000c000041000160007000002b823900000006e2390050000000000000002b802b8640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0804101122007b0200c01604102c1c007b0000c000051000160007000002be24900000006e2490050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0805101122007b0200c01605102c1c007b0000c000061000160007000002be25900000006e2590050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0806101122007b0200c01606102c1c007b0000c000071000160007000002be26900000006e2690050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de08071011220081010bec0a071000a2ce8aa07d010bec0a071000a2ce8aa000000000000000000000000000000000000000000000000000820108c40b071000a2ce8aa081010cc40b071000a2ce8aa07d010cc40b071000a2ce8aa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004455")!, pumpModel: pumpModel) - XCTFail("Should have thrown InvalidCRC") - } catch HistoryPageError.invalidCRC { - // Happy path - } catch HistoryPageError.unknownEventType(let eventType) { - XCTFail("unknown event type" + String(eventType)) - } catch { - XCTFail("Unexpected exception...") - } - } - - - func testTempBasalDecoding() { - let pumpModel = PumpModel.model551 - do { - let page = try HistoryPage(pageData: Data(hexadecimalString: "160179230c121033104a2a0c12100016014a2a0c1210330854000d121000160154000d12107b05541e0d1210180a007b064000101210200e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004876")!, pumpModel: pumpModel) - - let events = page.events - XCTAssertEqual(events.count, 7) - - let duration = events[0] as! TempBasalDurationPumpEvent - XCTAssertEqual(duration.duration, 30) - XCTAssertEqual(duration.timestamp, DateComponents(gregorianYear: 2016, month: 4, day: 18, hour: 12, minute: 35, second: 57)) - - let tempBasal = events[1] as! TempBasalPumpEvent - XCTAssertEqual(tempBasal.rateType, TempBasalPumpEvent.RateType.Absolute) - XCTAssertEqual(tempBasal.rate, 0.4) - XCTAssertEqual(tempBasal.wasRemotelyTriggered, false) - XCTAssertEqual(tempBasal.timestamp, DateComponents(gregorianYear: 2016, month: 4, day: 18, hour: 12, minute: 42, second: 10)) - - let duration2 = events[2] as! TempBasalDurationPumpEvent - XCTAssertEqual(duration2.duration, 30) - XCTAssertEqual(duration2.timestamp, DateComponents(gregorianYear: 2016, month: 4, day: 18, hour: 12, minute: 42, second: 10)) - - let tempBasal2 = events[3] as! TempBasalPumpEvent - XCTAssertEqual(tempBasal2.rateType, TempBasalPumpEvent.RateType.Absolute) - XCTAssertEqual(tempBasal2.rate, 0.2) - XCTAssertEqual(tempBasal2.wasRemotelyTriggered, false) - XCTAssertEqual(tempBasal2.timestamp, DateComponents(gregorianYear: 2016, month: 4, day: 18, hour: 13, minute: 0, second: 20)) - - } catch HistoryPageError.invalidCRC { - XCTFail("page decoding threw invalid crc") - } catch HistoryPageError.unknownEventType(_) { - XCTFail("unknown event type") - } catch { - XCTFail("Unexpected exception...") - } - } - - func testHistoryDecoding() { - let pumpModel = PumpModel.model551 - do { - let page = try HistoryPage(pageData: Data(hexadecimalString: "5be409a20a1510325000784b502800a400002400a8965c0b404fc038cbd008d5d0010080008000240009a24a15107b0500800c1510180a000ade19a32c15105bde2ba30c1510325000b44b5024006c0000200070965c0b4c78c03482c040c8c001007000700020002ba34c15100a0c22932d75903f2122938d7510c527ad5b0006900f15101a5000b44b500000380000000038965c0e70a1c04c19d03423d04069d00100380038000c0006904f15107b060080101510200e005b0034ab1015100d5000784b500000280000000028965c113858c070f8c04c70d0347ad040c0d00100280028001c0034ab5015100ab005863175903f360586117510c527ad5bb01486111510005100784b50940000000038005c965c14281fc0386fc0700fd04c87d03491d040d7d001005c005c00380014865115105b002291121510285000784b500000840000000084965c145c48c02866c038b6c07056d04cced034d8d0010084008400480022915215107b0700801315102610002100038414151003000000360785341510064a097e009e54b5100c4a03a11415107b0704a11415102610007b0704a11415102610007b0710a1141510261000030003000306a11415100ae937a23475103f1d37a2347510c527ad5be91ea3141510165000784b502c00480000140060965c0e848cc05cd2c028f0c03840d001006000600014001ea35415107b0800801515102a13000a5621ba3515905b5623ba151510005100b455505800000000340024965c116053c084dfc05c25d02843d03893d0010024002400340023ba5515105b00188c161510005000b455500000000000000000965c142411c06061c084edc05c33d02851d038a1d00100180018004c00188c5615100a7339ac3615905b7305ad161510005100b455506800000000480020965c171828c02432c06082c0840ed05c54d02872d038c2d0010034003400440005ad5615100a55158c3775903f2a158cb77510c527ad5b55278c171510005100b455505800000000600000965c1a341bc01843c0244dc0609dc08429d05c6fd0288dd038ddd00100180018006000278c5715100a1930b73715905b1901b8171510005100b455503c00000000440000965c1a1833c03447c0186fc02479c060c9c08455d05c9bd028b9d0010018001800440001b85715107b000080001610000e0007000004f035100000006e351005112ce9b00a000004f001401903b04b00dd01a4013c00d0000005070200040000000000000000de730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fc5e")!, pumpModel: pumpModel) - - let events = page.events - XCTAssertGreaterThan(events.count, 20) - - let bolusWizard = events[0] as! BolusWizardEstimatePumpEvent - XCTAssertEqual(bolusWizard.bgTargetHigh, 150) - XCTAssertEqual(bolusWizard.bgTargetLow, 80) - XCTAssertEqual(bolusWizard.bloodGlucose, 228) - XCTAssertEqual(bolusWizard.bolusEstimate, 4.2) - XCTAssertEqual(bolusWizard.carbohydrates, 50) - XCTAssertEqual(bolusWizard.carbRatio, 12.0) - XCTAssertEqual(bolusWizard.correctionEstimate, 1.0) - XCTAssertEqual(bolusWizard.foodEstimate, 4.1) - XCTAssertEqual(bolusWizard.insulinSensitivity, 75) - XCTAssertEqual(bolusWizard.unabsorbedInsulinTotal, 0.9) - XCTAssertEqual(bolusWizard.timestamp, DateComponents(gregorianYear: 2016, month: 2, day: 21, hour: 10, minute: 34, second: 9)) - - let bolus = events[1] as! BolusNormalPumpEvent - XCTAssertEqual(bolus.amount, 3.2) - - XCTAssertEqual(bolus.type, BolusNormalPumpEvent.BolusType.normal) - XCTAssertEqual(bolus.duration, 0) - XCTAssertEqual(bolus.programmed, 3.2) - XCTAssertEqual(bolus.unabsorbedInsulinTotal, 0.9) - XCTAssertEqual(bolus.timestamp, DateComponents(gregorianYear: 2016, month: 2, day: 21, hour: 10, minute: 34, second: 9)) - XCTAssertEqual(bolus.wasRemotelyTriggered, false) - - let unabsorbedInsulinRecords = bolus.unabsorbedInsulinRecord!.records - XCTAssertEqual(unabsorbedInsulinRecords.count, 3) - XCTAssertEqual(unabsorbedInsulinRecords[0].amount, 1.6) - XCTAssertEqual(unabsorbedInsulinRecords[0].age, 79) - XCTAssertEqual(unabsorbedInsulinRecords[1].amount, 1.4) - XCTAssertEqual(unabsorbedInsulinRecords[1].age, 459) - XCTAssertEqual(unabsorbedInsulinRecords[2].amount, 0.2) - XCTAssertEqual(unabsorbedInsulinRecords[2].age, 469) - - let basalProfileStart = events[2] as! BasalProfileStartPumpEvent - XCTAssertEqual(basalProfileStart.dictionaryRepresentation["offset"] as! Int, 43200000) - XCTAssertEqual(basalProfileStart.scheduleEntry.timeOffset, 43200) - XCTAssertEqual(basalProfileStart.scheduleEntry.rate, 0.25) - XCTAssertEqual(basalProfileStart.scheduleEntry.index, 5) - XCTAssertEqual(basalProfileStart.timestamp, DateComponents(gregorianYear: 2016, month: 2, day: 21, hour: 12, minute: 0, second: 0)) - - let calBGForPH = events[3] as! CalBGForPHPumpEvent - XCTAssertEqual(calBGForPH.amount, 222) - XCTAssertEqual(calBGForPH.timestamp, DateComponents(gregorianYear: 2016, month: 2, day: 21, hour: 12, minute: 35, second: 25)) - - let bgReceived = events[7] as! BGReceivedPumpEvent - XCTAssertEqual(bgReceived.amount, 268) - XCTAssertEqual(bgReceived.meter, "c527ad") - XCTAssertEqual(bgReceived.timestamp, DateComponents(gregorianYear: 2016, month: 2, day: 21, hour: 13, minute: 19, second: 34)) - - let rewind = events[20] as! RewindPumpEvent - XCTAssertEqual(rewind.timestamp, DateComponents(gregorianYear: 2016, month: 2, day: 21, hour: 20, minute: 4, second: 3)) - - let prime = events[21] as! PrimePumpEvent - XCTAssertEqual(prime.amount, 5.4) - XCTAssertEqual(prime.primeType, "manual") - XCTAssertEqual(prime.programmedAmount, 0.0) - XCTAssertEqual(prime.timestamp, DateComponents(gregorianYear: 2016, month: 2, day: 21, hour: 20, minute: 5, second: 7)) - - let resultTotals = events[50] as! DailyTotal523PumpEvent - // 2016-02-22T00:00:00 - var resultTotalsDate = DateComponents() - resultTotalsDate.calendar = Calendar(identifier: Calendar.Identifier.gregorian) - resultTotalsDate.year = 2016 - resultTotalsDate.month = 2 - resultTotalsDate.day = 21 - - XCTAssertEqual(resultTotals.timestamp, resultTotalsDate) - - var timestamp = resultTotals.timestamp - timestamp.timeZone = TimeZone(secondsFromGMT: -5 * 60 * 60) - - XCTAssertEqual(resultTotals.dictionaryRepresentation["validDate"] as? String, "2016-02-21") - - } catch HistoryPageError.invalidCRC { - XCTFail("page decoding threw invalid crc") - } catch HistoryPageError.unknownEventType(_) { - XCTFail("unknown event type") - } catch { - XCTFail("Unexpected exception...") - } - } - - func testHistoryDecoding523() { - let pumpModel = PumpModel.model523 - do { - let page = try HistoryPage(pageData: Data(hexadecimalString: "010052005200000042225465105b00443b1465100e5000784b5000002e000000002e785c0e1a18c03822c01658d002dad001002e002e004c00443b5465100a3361023605905b337202166510005100b455505800000000420016785c0e2e43c01a57c03861c01697d0010016001600420072025665107b00400000061000100007000002cb45100000006e45100500e7000002000002cb01512f017a35007b00d60016008e0000040101000400000000000000009b3300000000000000007b014000010610020c000aca48092106105bca4b09010610005000c850502800000000000028785c0e16c2c02efec01a12d0381cd001002800280000004c094106107b024000040610080d007b0340000606100c10005b006a130966101450006e4b5000004800000000487801004800480000006a134966107b0440000a0610140b000afa41362b06105bfa67360b6610475000b44b5044009c00000800d8785c05489fc001006800680008045d38ab6610010070007000080067368b66107b0540000c0610180a007b064000100610200e005b0043191266103c5000784b500000c800000000c8785c2c020ed00818d00822d00a2cd00836d00840d00a4ad00854d0085ed00a68d00872d0087cd06286d01690d0010064001c0000066b1ab26610010064006400000043199266107b0740001306102610001e0165121306107b076e121306102610001f206e12130610210074121306101a0062141306101a01771413061003000000436a153306107b07661b13061026100003000300035c1b1306107b08401e1406102915000a825b103506905b826010150610005100b455507c000000000c0070785c200279c00483c0068dc00697c006a1c068abc002b9d008c3d008cdd00ad7d05b826210150610005100b455507c000000000c0070785c200279c00483c0068dc00697c006a1c068abc002b9d008c3d008cdd00ad7d00100700070000c0062105506100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c4d")!, pumpModel: pumpModel) - - let events = page.events - XCTAssertGreaterThan(events.count, 20) - - let bolus = events[0] as! BolusNormalPumpEvent - XCTAssertEqual(bolus.amount, 2.05) - XCTAssertEqual(bolus.type, BolusNormalPumpEvent.BolusType.normal) - XCTAssertEqual(bolus.duration, 0) - XCTAssertEqual(bolus.programmed, 2.05) - XCTAssertEqual(bolus.unabsorbedInsulinTotal, 0.0) - - let timestamp = DateComponents(gregorianYear: 2016, month: 4, day: 5, hour: 20, minute: 34, second: 02) - - XCTAssertEqual(bolus.timestamp, timestamp) - - } catch HistoryPageError.invalidCRC { - XCTFail("page decoding threw invalid crc") - } catch HistoryPageError.unknownEventType(_) { - XCTFail("unknown event type") - } catch { - XCTFail("Unexpected exception...") - } - - } - - func testHistoryDecodingBolusWizardSettings522() { - let pumpModel = PumpModel.model522 - do { - let page = try HistoryPage(pageData: Data(hexadecimalString: "5a0f7050141d10151300080000000000000000000000000000001e1414211e00000000000000000000005f69000000000000000000000000000000000000000000151300080000000000000000000000000000001e14142d1e00000000000000000000005f6900000000000000000000000000000000000000000044338c4055145d100016014055145d10333e445a145d10001601445a145d10335a4464145d100016014464145d10335e4069145d100016014069145d10010a0a004a6b341d10010f0f007979341d10010a0a00484b351d103383445a155d10001601445a155d10333c4369155d100016014369155d10011919006f7a351d10333c4b41165d100016014b41165d10333c4e55165d100016014e55165d10333c486e165d10001601486e165d10331b4c73165d100016014c73165d10333c5f4b175d100016015f4b175d1001080800554d371d10010808006a5d371d10333c6564175d100016016564175d1001050500766a371d10333c4878175d100016014878175d100700000a6a5d906d5d90050c00e8000000000a6a056234050830000005083000000000000005086413000000130c00e800000033394a50005e100016014a50005e1033394864005e100016014864005e1033004969005e100016014969005e1033004878005e100016014878005e1033004155015e100016014155015e103348495f015e10001601495f015e1033394564015e100016014564015e1033484a69015e100016014a69015e1033104c73015e100016014c73015e1033394578015e100016014578015e1033394550025e100016014550025e103314465a025e10001601465a025e1033004a5f025e100016014a5f025e103300456e025e10001601456e025e1033004241035e100016014241035e1033004550035e100016014550035e103300495f035e10001601495f035e103300456e035e10001601456e035e1033394678035e100016014678035e10338c4d46045e100016014d46045e10338c4664045e100016014664045e1033444a41055e100016014a41055e10010404007561281e1033447968085e100016017968085e10334a7972085e100016017972085e1033444478085e100016014478085e1033444250095e100016014250095e1033147954095e100016017954095e103344415a095e10001601415a095e10338c7968095e100016017968095e10011414006e6c291e1033447972095e100016017972095e10335841460a5e1000160141460a5e10010a0a0047492a1e10336841500a5e1000160141500a5e10010a0a006b512a1e103344415a0a5e10001601415a0a5e10330041500b5e1000160141500b5e103300455f0b5e10001601455f0b5e103346416e0b5e10001601416e0b5e10334641460c5e100000000000005a49")!, pumpModel: pumpModel) - - let events = page.events - - let bwsettings = events[0] as! BolusWizardSetupPumpEvent - var timestamp = DateComponents(gregorianYear: 2016, month: 5, day: 29, hour: 20, minute: 16, second: 48) - XCTAssertEqual(bwsettings.timestamp, timestamp) - - - let tempBasal = events[1] as! TempBasalPumpEvent - timestamp = DateComponents(gregorianYear: 2016, month: 5, day: 29, hour: 20, minute: 21, second: 0) - - XCTAssertEqual(tempBasal.timestamp, timestamp) - - } catch HistoryPageError.invalidCRC { - XCTFail("page decoding threw invalid crc") - } catch HistoryPageError.unknownEventType(_) { - XCTFail("unknown event type") - } catch { - XCTFail("Unexpected exception...") - } - - } - - func testHistoryQuestionable3b() throws { - let pumpModel = PumpModel.model723 - - let page = try HistoryPage(pageData: Data(hexadecimalString: "0615036800406001070636036f0040600107062f1dfc004020c107062f0e77004020c107062f0e88004020c107062f0e99004020c107062f0eaa004020c107062f0ebb004020c107062f0ee1004020c107062f0ef4004020c107062f0f05004020c10706110f12004020c10706150411004040a1070c151e400001076401164000010717001f4000010718000040000107190033410001071a003a500401071a010159040107063706753a5044a1071a0030590401070c3730590401071a01135a04010706560692305944a1073b84145a0401070c56275a040107070000000001870000006e0187050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a0002570102070603036802576102070c030c4000010764010f400001071700134000010718000040000107070000000002870000006e0287050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002100054000010703000000000a402001077b001b4000010700000017001f420041071800758e0d5410070000000001870000006e01870500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064004c8f0d14100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001305")!, pumpModel: pumpModel) - let events = page.events - - XCTAssertEqual(45, events.count) - } - - func testMealMarkerFor754() throws { - let pumpModel = PumpModel.model754 - - let page = try HistoryPage(pageData: Data(hexadecimalString: "0b664d61d542aa100b665040e142aa100b720061c143aa100b65ab6adb43aa107b0140c0040a100828007b0240de060a100d32000b730068d048aa100b73006fd149aa100b664d7ad649aa100a5472d7296a103f0a72d7896a10ce26920b73006adb49aa105b004af7090a10289000be3c3200005400000000543201005400540000004af7490a100b700072cb4aaa100b700072d54aaa100b700041e14aaa100b710041f04aaa100abe70da2d6a103f1770dacd6a10ce26925b694cdb0d0a10329000be3c322400680000080084325c0554d4040100a000a00008004cdb4d0a107b0340c00f0a101e32000a7b5ec12f6a103f0f5ec16f6a10ce26920b680057d64faa100a7574df2f6a103f0e74dfaf6a10ce2692140077f22f0a107b0077f22f0a100009000b73005cf44faa100b730057c250aa100b730055cb50aa100b664d4ed050aa100b664f57db50aa100b72006bc151aa1014017af3110a107b037bf3110a101e3200010078007800000051f4510a105b0058c3120a10469000be3c320000900000000090325c08781204a016140100a000a000780058c3520a100b730068ea52aa100b73004ef852aa100a3f70f8326a103f0770f8f26a10ce26920b730057c753aa105b0042e9130a10289000be3c320000540000000054325c0e4260045e6a04787404a07814010054005400980042e9530a100aa35ae5346a103f145ae5746a10ce26925b5a6be5140a10009000be3c371400000000880000375c11543e044298045ea20478ac04a0b0147c014bfb140a1081016dc3150a1000a2148cc87d016dc3150a1000a2148cc8000000000000000000000000000000000000000000000000000b730052ee56aa100b73005ef856aa107b0440c0170a102e32000b664f57c757aa100b73005ccc57aa107b0040c0000b10002800070000067c6a900000006e6a9006007a3fbe070000067c041c3f02602500c800a800000140007802000201007a07510bd620020d00000d01000000000000640043c4000b100b730052c640ab1064017bc6000b100b73004ed040ab10335660d4000b1008163060d4000b100b73005ce040ab100b665657ea40ab100b664e55f340ab100b664d6bc141ab100b66525ccc41ab100b730056ea44ab100b665856c745ab1040005dc9050b100c010b690040c746ab10330073e1070b1008160073e1070b107b0273e1070b100d32000a7a72f0276b103f0f72f0476b10ce24cd5b4452f1070b10009000be3c320c0000000000000c3201000c000c00000052f1470b105b0066c7080b104c9000be3c320000a000000000a0325c050c16040100a000a0000c0066c7480b100b720051ee48ab100b65b25bcc49ab100b72005bf44bab100abe4ffa2b6b103f174ffacb6b10ce24cd33735cfa0b0b100816305cfa0b0b1073da")!, pumpModel: pumpModel) - let events = page.events - - XCTAssertEqual(93, events.count) - - let mealMarker = events[75] as! JournalEntryMealMarkerPumpEvent - - XCTAssertEqual(JournalEntryMealMarkerPumpEvent.CarbUnits.Grams, mealMarker.carbUnits) - XCTAssertEqual(12, mealMarker.carbohydrates) - - - XCTAssertEqual(DateComponents(gregorianYear: 2016, month: 7, day: 11, hour: 5, minute: 9, second: 29), mealMarker.timestamp) - - } - - func testInsulinMarker551() throws { - let pumpModel = PumpModel.model551 - - let page = try HistoryPage(pageData: Data(hexadecimalString: "7b0640c0100b10200e007b0740c0130b102610007b0840de140b102915007b0040c0000c1000100007000001576b900000006e6b90050000000000000001570157640000000000000000000000000000000000000000000000000000000000000000000000007b0140c0010c10020c007b0240c0040c10080d007b0340c0060c100c10007b0440c00a0c10140b007b0540c00c0c10180a007b0640c0100c10200e007b0740c0130c102610007b0840de140c102915007b0040c0000d1000100007000001576c900000006e6c90050000000000000001570157640000000000000000000000000000000000000000000000000000000000000000000000007b0140c0010d10020c007b0240c0040d10080d007b0340c0060d100c10007b0440c00a0d10140b007b0540c00c0d10180a007b0640c0100d10200e007b0740c0130d102610007b0840de140d102915007b0040c0000e1000100007000001576d900000006e6d90050000000000000001570157640000000000000000000000000000000000000000000000000000000000000000000000007b0140c0010e10020c007b0240c0040e10080d007b0340c0060e100c10007b0440c00a0e10140b007b0540c00c0e10180a007b0640c0100e10200e007b0740c0130e102610007b0840de140e102915000ad271c7376e103f1a71c7576e10c527ad7b0040c0000f1000100007000001576e900000006e6e900500d2d2d201000001570157640000000000000000000000000000000000000000000000000000000000000000000000007b0140c0010f10020c007b0240c0040f10080d007b0340c0060f100c10007b0440c00a0f10140b007b0540c00c0f10180a007b0640c0100f10200e007b0740c0130f102610007b0840de140f102915000a9a45c7366f103f1345c7566f10c527ad7b0040c000101000100007000001576f900000006e6f9005009a9a9a01000001570157640000000000000000000000000000000000000000000000000000000000000000000000007b0140c0011010020c007b0240c0041010080d007b0340c00610100c10007b0440c00a1010140b007b0540c00c1010180a0083014dd20d101040016fd20d10102c016f1266f20d10100a5077f22d101040004ef60d1010c8020a5878d5af10107b0640c0101010200e000a5857ca301010430073f010101042de66ed711010000a6559c032101042015cdc121010007b0740c01310102610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dae8")!, pumpModel: pumpModel) - let events = page.events - - XCTAssertEqual(72, events.count) - - let insulin1 = events[68] as! JournalEntryInsulinMarkerPumpEvent - XCTAssertEqual(99.0, insulin1.amount) - XCTAssertEqual(DateComponents(gregorianYear: 2016, month: 7, day: 16, hour: 17, minute: 45, second: 38), insulin1.timestamp) - - let insulin2 = events[70] as! JournalEntryInsulinMarkerPumpEvent - XCTAssertEqual(0.1, insulin2.amount) - XCTAssertEqual(DateComponents(gregorianYear: 2016, month: 7, day: 16, hour: 18, minute: 28, second: 28), insulin2.timestamp) - } - - func testCalBGForPHWithHighBG() throws { - let pumpModel = PumpModel.model754 - - let page = try HistoryPage(pageData: Data(hexadecimalString: "7b0640c0100b10200e007b0740c0130b102610007b0840de140b102915007b0040c0000c1000100007000001576b900000006e6b90050000000000000001570157640000000000000000000000000000000000000000000000000000000000000000000000007b0140c0010c10020c007b0240c0040c10080d007b0340c0060c100c10007b0440c00a0c10140b007b0540c00c0c10180a007b0640c0100c10200e007b0740c0130c102610007b0840de140c102915007b0040c0000d1000100007000001576c900000006e6c90050000000000000001570157640000000000000000000000000000000000000000000000000000000000000000000000007b0140c0010d10020c007b0240c0040d10080d007b0340c0060d100c10007b0440c00a0d10140b007b0540c00c0d10180a007b0640c0100d10200e007b0740c0130d102610007b0840de140d102915007b0040c0000e1000100007000001576d900000006e6d90050000000000000001570157640000000000000000000000000000000000000000000000000000000000000000000000007b0140c0010e10020c007b0240c0040e10080d007b0340c0060e100c10007b0440c00a0e10140b007b0540c00c0e10180a007b0640c0100e10200e007b0740c0130e102610007b0840de140e102915000ad271c7376e103f1a71c7576e10c527ad7b0040c0000f1000100007000001576e900000006e6e900500d2d2d201000001570157640000000000000000000000000000000000000000000000000000000000000000000000007b0140c0010f10020c007b0240c0040f10080d007b0340c0060f100c10007b0440c00a0f10140b007b0540c00c0f10180a007b0640c0100f10200e007b0740c0130f102610007b0840de140f102915000a9a45c7366f103f1345c7566f10c527ad7b0040c000101000100007000001576f900000006e6f9005009a9a9a01000001570157640000000000000000000000000000000000000000000000000000000000000000000000007b0140c0011010020c007b0240c0041010080d007b0340c00610100c10007b0440c00a1010140b007b0540c00c1010180a0083014dd20d101040016fd20d10102c016f1266f20d10100a5077f22d101040004ef60d1010c8020a5878d5af10107b0640c0101010200e000a5857ca301010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a3af")!, pumpModel: pumpModel) - let events = page.events - - XCTAssertEqual(67, events.count) - - let cal = events[64] as! CalBGForPHPumpEvent - XCTAssertEqual(DateComponents(gregorianYear: 2016, month: 7, day: 16, hour: 15, minute: 21, second: 56), cal.timestamp) - XCTAssertEqual(600, cal.amount) - - let cal2 = events[66] as! CalBGForPHPumpEvent - XCTAssertEqual(DateComponents(gregorianYear: 2016, month: 7, day: 16, hour: 16, minute: 10, second: 23), cal2.timestamp) - XCTAssertEqual(88, cal2.amount) - - } - - func testAlarmSensorDate() throws { - let pumpModel = PumpModel.model754 - - let page = try HistoryPage(pageData: Data(hexadecimalString: "5c118c1f04345b043c830478f104b4c314010040004000c00073e4530f100b730054c254af100b730068d554af100b730059e054af106f125deb140f10400040ec140f1005026f2148ec140f105b0066e7150f10239000be3c370000480000000048375c11407c048c9a0434d6043cfe04786c14010064006400480066e7550f100b720052cb56af100b65b44bd056af107b0440c0170f102e32000ae752c8376f103f1c52c8f76f10ce26925b8074c8170f10009000be3c373000000000480000375c14645d0440d5048cf304342f143c571478c5145b8041c9170f10009000be3c373000000000480000375c14645e0440d6048cf4043430143c581478c61401000c000c00480041c9570f105b804ed3170f102f9000be3c3730006000004c0060375c170c0e0464680440e0048cfe04343a143c621478d01434204ed3170f900100600060004c004ed3570f107b0040c000101000280007000008726f900000006e6f900600d199f30300000872046e3404043001430208001800f000f40602020300b63b270216330507000004090100000000000b65d74bd040b0100b65094bd042b09021004ad9021010030000003451da2210107b0067db021010002800030008000849db0210100a0759dc2270903f2059dce27010ce26925b9263dc021010009000c83c373c0000000010002c375c1160c1040ccb04642514409d148cbb1401003c003c00100063dc42101033736dd60310100816306dd60310100b730052df45b0100b730068c147b0100b664a54c747b010330062c707101008160062c70710107b0262c70710100d32000b664964d147b01040005de20710100c010b66454be447b0100b664154ef47b0100a4673f72770103f0873f7c77010ce2692400042f907101008010b664464f947b0100b730064d149b0105b006cf6091010379000be3c320000700000000070325c053cc11401007000700000006cf64910100b720052cb4ab0100b65b754ea4ab010337470c60b101008163070c60b1010010028002800540078c64b10100b73004ad04eb0100b730053db4eb0100b730063e54eb0100b73004eee4eb0100b6b004fda4fb0100b68004ae44fb0100a9e77e42f70103f1377e4cf7010ce24cd0b730053c252b0100b730051cb52b0100b730067d552b0100b730058e052b010330070e412101008160070e41210107b0370e41210101e32000b664d63e552b0100b664a4eee52b0100b66454af852b01001005000500000005dfa5310100b72004ec654b0100b65ca72d554b0100b65e767d556b0107b0440c01710102e32006f1265da17101040006ada17101005020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b15f")!, pumpModel: pumpModel) - let events = page.events - - XCTAssertEqual(82, events.count) - - let alarm = events[1] as! AlarmSensorPumpEvent - XCTAssertEqual(DateComponents(gregorianYear: 2016, month: 7, day: 15, hour: 20, minute: 2, second: 20), alarm.timestamp) - } - - func testPumpAlarms() throws { - let pumpModel = PumpModel.model723 - - let page = try HistoryPage(pageData: Data(hexadecimalString: "5c0800b8c11ce0c101013c013c00000059eb567a1033004bf5165a100016014bf5165a10330079cc175a1000160179cc175a10330079e0175a1000160179e0175a10330b70ef175a1000160170ef175a10061503680040600107060a2084004060010706110411114040a1070c150a4600010706050309004040a1071a0005410001070c0505410001071a0119410001076400304100010764001e4200010717003542000107180040c0001b10070000000001870000006e01870500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021004fc0001b10030000000056c1201b107b0079c1001b1000440033006cc7005b100016016cc7005b10330068dc005b1000160168dc005b10338568e1005b1000160168e1005b1033c56aeb005b100016016aeb005b1033b168f0005b1000160168f0005b1033b968f5005b1000160168f5005b1033be68fa005b1000160168fa005b1033bc69c3015b1000160169c3015b1033c169c8015b1000160169c8015b1033b868cd015b1000160168cd015b1033ae69d2015b1000160169d2015b1033ad69d7015b1000160169d7015b1033c368dc015b1000160168dc015b1033c868e1015b1000160168e1015b1033c169e6015b1000160169e6015b1033b668eb015b1000160168eb015b1033be68f0015b1000160168f0015b1033a468f5015b1000160168f5015b1033ab68fa015b1000160168fa015b1033a869c3025b1000160169c3025b10338968c8025b1000160168c8025b10336c68cd025b1000160168cd025b10336469d2025b1000160169d2025b10336d68d7025b1000160168d7025b10337a68dc025b1000160168dc025b10338968e1025b1000160168e1025b10339968e6025b1000160168e6025b10339268eb025b1000160168eb025b10338168f0025b1000160168f0025b10338369f5025b1000160169f5025b10337768fa025b1000160168fa025b10337668c3035b1000160168c3035b10338068c8035b1000160168c8035b10336768cd035b1000160168cd035b10330069d2035b1000160069d2035b107b0069d2031b10004400336968d7035b1000160168d7035b10338668dc035b1000160168dc035b10337b6ae1035b100016016ae1035b10338668e6035b1000160168e6035b10339668eb035b1000160168eb035b1033c069f0035b1000160169f0035b1033b769f5035b1000160169f5035b10339c69fa035b1000160169fa035b10330068c3045b1000160068c3045b107b0068c3041b10004400338368d2045b1000160168d2045b1033ac68d7045b1000160168d7045b10338769dc045b1000160169dc045b10335f68e1045b1000160168e1045b10330069e6045b1000160069e6045b100000000000bf1d")!, pumpModel: pumpModel) - let events = page.events - - XCTAssertEqual(126, events.count) - - let alarm = events[9] as! PumpAlarmPumpEvent - XCTAssertEqual("deviceResetBatteryIssue21", "\(alarm.alarmType)") - XCTAssertEqual(DateComponents(gregorianYear: 2007, month: 1, day: 1, hour: 0, minute: 0, second: 0), alarm.timestamp) - - let batteryDepletedAlarm = events[13] as! PumpAlarmPumpEvent - XCTAssertEqual("batteryDepleted", "\(batteryDepletedAlarm.alarmType)") - XCTAssertEqual(DateComponents(gregorianYear: 2007, month: 1, day: 1, hour: 0, minute: 0, second: 0), batteryDepletedAlarm.timestamp) - - } - - func testPageWithDuplicates() throws { - let pumpModel = PumpModel.model754 - - let page = try HistoryPage(pageData: Data(hexadecimalString: "1601874b15561033c0a250155610001601a25015561033bb9055155610001601905515561033b6b75a155610001601b75a15561033a9ad60155610001601ad6015561033a3a265155610001601a26515561033a0a76a155610001601a76a15561033a18b6f1556100016018b6f1556100b7200a17255b61033a38673155610001601867315561033a5957b155610001601957b1556100b65bc9d4056b61033a28441165610001601844116561033a4ab46165610001601ab461656103394964c165610001601964c16561033879b511656100016019b511656103378a756165610001601a75616561033688c5b1656100016018c5b1656103342846516561000160184651656103322b269165610001601b2691656103313af6e165610001601af6e165610332087741656100016018774165610331a8d791656100016018d791656103300a142175610001601a1421756103300a75a175610001601a75a17561033028760175610001601876017561033098c651756100016018c651756103307a16a175610001601a16a1756103305876f175610001601876f1756103314907317561000160190731756103300807917561000160080791756107b0380791716101c30007b008040001710002e0007000007f396900000006e969006007e679502000007f3061a4d01d917000000000000000001d90000000500900d5700141f030b000000020100000000003348b640005710001601b6400057103349a446005710001601a4460057103343834c005710001601834c005710331d8951005710001601895100571033469e560057100016019e56005710335b835b005710001601835b0057103351ba5e005710001601ba5e0057103358816400571000160181640057103360b768005710001601b768005710334aa56e005710001601a56e0057103343837400571000160183740057103344887900571000160188790057103337a042015710001601a04201571033388d4b0157100016018d4b015710333e8f500157100016018f500157103344b754015710001601b7540157103342a55a015710001601a55a0157103334836001571000160183600157103339896501571000160189650157103336a06a015710001601a06a0157103331836f015710001601836f0157103335ba72015710001601ba7201571033348e780157100016018e780157103300b740025710001600b7400257107b00b740021710002e003330a546025710001601a546025710332f844c025710001601844c025710332b8a510257100016018a51025710332b8a510257100016018a510257107b008b6f021710002e000b7300b64143b7103317824703571000160182470357107b008365031710002e000b6900804344b7107b0180400517100a3000000000000000ff92")!, pumpModel: pumpModel) - let events = page.events - - XCTAssertEqual(events[116].rawData, events[118].rawData) - XCTAssertEqual(events[117].rawData, events[119].rawData) - } - - func testSaveSettings() throws { - let pumpModel = PumpModel.model723 - - let page = try HistoryPage(pageData: Data(hexadecimalString: "7b01a91a061510042a0033adb62e065510001601b62e0655103360b633065510001601b6330655103300a838065510001600a8380655107b01a838061510042a00335fa80b085510001601a80b0855103300a422085510001600a4220855107b02a422081510113000336eab33085510001601ab330855103383a838085510001601a838085510337baa38085510001601aa38085510337aa801095510001601a801095510337ca806095510001601a8060955103382a80b095510001601a80b095510337ca810095510001601a810095510337caa10095510001601aa100955103378a815095510001601a8150955103380a81a095510001601a81a095510336caa24095510001601aa240955103300ac29095510001600ac290955107b02ac290915101130003366a833095510001601a8330955103300a938095510001600a9380955107b02a93809151011300033679f2e0a55100016019f2e0a55103373aa330a5510001601aa330a5510338bab380a5510001601ab380a55103383a40b0b5510001601a40b0b55103300a3100b5510001600a3100b55107b02a3100b15101130000100f000f0000000b0214b55103377ab290b5510001601ab290b551033b8a12e0b5510001601a12e0b551033baac330b5510001601ac330b55103376a8380b5510001601a8380b55103300a6010c5510001600a6010c55107b02a6010c1510113000010056005600df00ba094c5510339ba10b0c5510001601a10b0c55103300ae100c5510001600ae100c55107b02ae100c15101130003300ab2e0c5510001601ab2e0c55103300ab060d5510001600ab060d55107b02ab060d15101130002601a62f0d151027000000000000280000000000002601ae2f0d15102701b207000000280000000000005d009f300d1510140084312d15107b0084312d1510003200140197310d15107b0297310d1510113000338caa060e5510001601aa060e5510338da5180e5510001601a5180e55103384b82e0e5510001601b82e0e55103384ba2e0e5510001601ba2e0e551001003c003c003400942f4e55103300ab340e5510001600ab340e55107b03ab340e15101d3400337cab1f0f5510001601ab1f0f5510339aac240f5510001601ac240f551033b1ab290f5510001601ab290f551033b7ac2e0f5510001601ac2e0f551033bbab330f5510001601ab330f55103394ae380f5510001601ae380f5510337bac01105510001601ac011055103300ac0b105510001600ac0b1055107b03ac0b1015101d34003300ad1f105510001601ad1f1055103300ad24105510001600ad241055107b03ad241015101d34000100e600e6001b00a82e5055103379ad33105510001601ad331055103392ad38105510001601ad3810551033a5aa01115510001601aa01115510000004dd")!, pumpModel: pumpModel) - let events = page.events - - XCTAssertEqual(125, events.count) - - let saveSettings = events[79] as! PlaceholderPumpEvent - let json = saveSettings.dictionaryRepresentation - let displayedType = json["_type"] as! String - XCTAssertEqual("saveSettings", displayedType) - } - - func testBolusReminder() throws { - let pumpModel = PumpModel.model723 - - let page = try HistoryPage(pageData: Data(hexadecimalString: "6e8d900500000000000000074e07266200280200000000000000000028000000010000000000000000000000000000000000000034c88048030e101a009046060e10060303689046660e100c0317400001076400184000010764002040000107170025400001071800004000010707000001708e900000006e8e90050000000000000001700170640000000000000000000000000000000000000000000000000000000000000000000000007b000040000107003c003464006803010721000c6d030107030000001a386d2301077b002270030107003c00690700400b01072b00690c00400e01072e006911004014010734001a00185e15010706030368185e7501070c030e4000010764001b4000010717001c40000107180000400001077b000040000107003c006400034100010717001d4100010718008055011710070000050a01870000006e01870500000000000000050a050a64000000000000000000000000000000000000000000000000000000000000000000000000630197560117100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000863e")!, pumpModel: pumpModel) - let events = page.events - - XCTAssertEqual(32, events.count) - - let event1 = events[16] as! BolusReminderPumpEvent - XCTAssertEqual(DateComponents(gregorianYear: 2007, month: 1, day: 1, hour: 11, minute: 0, second: 0), event1.timestamp) - - let event2 = events[17] as! BolusReminderPumpEvent - XCTAssertEqual(DateComponents(gregorianYear: 2007, month: 1, day: 1, hour: 14, minute: 0, second: 0), event2.timestamp) - - let event3 = events[18] as! BolusReminderPumpEvent - XCTAssertEqual(DateComponents(gregorianYear: 2007, month: 1, day: 1, hour: 20, minute: 0, second: 0), event3.timestamp) - } - - func testHighBitsOfTempBasalRate() throws { - let pumpModel = PumpModel.model522 - - let page = try HistoryPage(pageData: Data(hexadecimalString: "0615050d0040600105062f1873004020c105062f0c5b004020c105062f0c6c004020c105062f0c7d004020c105062f0c8e004020c105062f0c9f004020c105062f0cc3004020c105062f0cd4004020c10506110ce3004020c105061504e9004040a1050c1516400001056400194300010517001d430001051800004300010521000343000105030000001208432001052c501852a0010524e530530001051a000d570201050603050d0d576201050c030c4000010564000d40000105170022400001051800804a021710070000003601856d0185050c00e8000000000036003664000000000000000000000000000000000000000000000c00e8000000070000025097906d9790050c00e8000000000250025064000000000000000000000000000000000000000000000c00e800000060019d600018106001a0600018106001a2610018103102b6570118105b00b6570118100150082178000100000000017801010100b657211810010a0a00ba5c2118105e01ab5d0118103102865e01181035008040021810010a0a0f865e6118103375a5650c1810081601a5650c18103300b4650c1810081600b4650c18106200b8650c1810333485660c181000160185660c18105b00b36e0e1810025008217800020000000002785c1402671402851402991402ad1402c11402df143200907a0e18106101907a0e18106a00b07a0e18106100b07a0e1810324f8c400f181061018c400f1810350080422f18101e00af450f181001030104b36e6e18101f00ba450f18103102936d1418105b00936d141810065008217800070000000007785c0502661401070700936d541810010d0d008d495518103500804f151810011b1b0098435618103300827b165810001601827b1658106a4fb8611718106100b861171810334a856317181005160185631718103300b36a171810001600b36a1718103390986b171810011601986b1718103300a66d171810001600a66d17181033c8b76d171810001601b76d1718103300b173171810001600b17317181033908174171810011601817417181033008974171810001600897417181033209a741718100316019a741718103300a674171810001600a6741718103350ae74171810051601ae74171810000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1f7")!, pumpModel: pumpModel) - let events = page.events - - XCTAssertEqual(90, events.count) - - let event1 = events[88] as! TempBasalPumpEvent - XCTAssertEqual(34.0, event1.rate) - - let event2 = events[84] as! TempBasalPumpEvent - XCTAssertEqual(20.0, event2.rate) - - let event3 = events[80] as! TempBasalPumpEvent - XCTAssertEqual(10.0, event3.rate) - - let event4 = events[76] as! TempBasalPumpEvent - XCTAssertEqual(5, event4.rate) - } - - func testChangeSensorAlarmSilenceConfig() throws { - let pumpModel = PumpModel.model723 - - let page = try HistoryPage(pageData: Data(hexadecimalString: "3350919f155610001601919f1556100b65de82a835b6100ae195aa3516105be199aa151610005000501e63a800000000240084635c08a0bf0464c90401008c008c0024009aaa5516103300a8ae155610001601a8ae1556107b06a890161610242a000b65d184a936b6100adf82ad3676103f1b82adf67610aa8c035bdf8cad161610005000501963c400000000700054635c0b8c4004a0fe0464081433509ead1656100016019ead1656100100640064007000a1ad56561033008eb41656100016018eb416561033009d821756100016009d821756107b069d82171610242a005301ae86171610f0334ab587175610001601b58717561033009b8a1756100016019b8a1756103314bb8e175610001601bb8e1756103348b495175610001601b495175610334f9f991756100016019f991756103300979e175610001600979e1756107b06979e171610242a000b65d182a837b6100b580083a837b610331ab5ae175610001601b5ae17561033009ab21756100016009ab21756107b069ab2171610242a00334abbb6175610001601bbb617561007000008f6b6100000006eb61005009230df09000008f6047e320478320037007c008c00c802a801010104008f105301f2280103e1e101040000000000003350ae81005710001601ae810057103350b69a005710001601b69a0057100b65c884a920b710335092b200571000160192b20057103350948a015710001601948a015710334f9a990157100016019a990157103350929e015710001601929e015710335094b201571000160194b2015710334b998502571000160199850257103350918a025710001601918a025710334faf9b025710001601af9b0257103340949e025710001601949e0257103345b5a2025710001601b5a2025710333baea9025710001601aea9025710331a9aad0257100016019aad025710331792b202571000160192b2025710330096b802571000160096b80257107b0196b8021710022c00330cab80035710001601ab8003571033009c860357100016019c86035710330ab394035710001601b39403571033009a990357100016009a990357107b019a99031710022c00333eaea8035710001601aea8035710334899ae03571000160199ae035710335094b203571000160194b203571033469a850457100016019a850457103300938a045710001600938a0457107b02938a041710083200334497900457100016019790045710334b9f940457100016019f940457103342939f045710001601939f0457103300b5a2045710001600b5a20457107b02b5a204171008320033009bad0457100016019bad045710330396b804571000160196b8045710330bac80055710001601ac800557103312938705571000160193870557103300948a05571000000000000000ff37")!, pumpModel: pumpModel) - let events = page.events - - XCTAssertEqual(118, events.count) - - XCTAssert(events[21] is ChangeSensorAlarmSilenceConfigPumpEvent) - } - - func testUnknownEventType68() throws { - // Veo 754 2.6a - // Thanks to @Mandelkern73 for discovering! - let pumpModel = PumpModel.model754 - let hexadecimalString = "090079614a98123f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b0a79610a1812141c00610079610a9812321279610a9812660079610a9812670079610a9812001e3c0179610a98123dc225450000003e000000000000260179610a98122705b7a100000028000000000000600079610a5812230079610a98125e0179610a98122d0179610a98125a0a79610a9812050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089180000640400530c004b10005c1600781a008c20006422004b0000001f041a0c17101c16241a2a201f221700323e0000000000000000000000000000000000000000003f620079610a98125f2979610a9812520079610a9812510279610a9812551179610a9812000f0f00ffff00ffff00ffff00ffff00ffff00ffff00ffff00001400ffff00ffff00ffff00ffff00ffff00ffff00ffff560079614a9812dcdc002828500079610a981220011e003c14001e3cffffffb44600003c41011e00781e001e3c23efa7642780801f54fc79614a9812fffcff00f05000ffff00ffff00ffff00ffff00ffff00ffff00fffffcfffcff00642c00ffff00ffff00ffff00ffff00ffff00ffff00ffff44017c0179610a9812260172620a18122705b7a10000002800000000000044007b650a181244015d660a181250005f660a181241011e00781e001e3cffffff642780801f41011e00781e001e3c23efa7642780801f5d005e670a18120b68006c6a4ab8120a464a6b4a18127b0b40400b1812161c0017004a4e0b581218005d4e0b5812810141530b181200a21c85687d0141530b181200a21c8568000000000000000000000000000000000000000000000000007b0c40400c1812181800170042630c5812180041630c58127d015b630c181200a21c8568000000000000000000000000000000000000000000000000007b0d40400d18121a18000b70004b614db8120b71004a6f4db8127b0e40400e18121c18007b0f40400f18121e20000b70005c664fb8127b104040101812202c007b1140401118122230000b70005d7951b8127b1240401218122430007b1340401318122630001e01624e1358121f2058541358127b1358541318122630007b144040141812282c000b7000595754b8123300516014181200160151601418123300546714181200160054671418120000004b1c" - let data = Data(hexadecimalString: hexadecimalString) - - let page = try HistoryPage(pageData: data!, pumpModel: pumpModel) - let events = page.events - - for event in events { - if let event = event as? TimestampedPumpEvent { - print(event.timestamp, event.dictionaryRepresentation) - } else { - print(event.dictionaryRepresentation) - } - } - - XCTAssertEqual(58, events.count) - XCTAssert(events[23] is PlaceholderPumpEvent) - XCTAssert(events[23].rawData[0] == PumpEventType.changeSensorAutoCalEnable.rawValue) - } - - func testMeterBGx15() throws { - let pumpModel = PumpModel.model515 - - let page = try HistoryPage(pageData: Data(hexadecimalString: "1601971f174a12333b9621174a120016019621174a1233429925174a120016019925174a1233479f2a174a120016019f2a174a123343a12f174a12001601a12f174a1233419c35174a120016019c35174a123337ab39174a12001601ab39174a1207000004fc8a126c8a12090c00e80000000004fc031e3f01de25000001de2500000000000001de6408000000083334b802004b12001601b802004b123330b507004b12001601b507004b123337b90c004b12001601b90c004b1233348312004b120016018312004b1233308717004b120016018717004b12332f8b1c004b120016018b1c004b121700b32f004b121800b32f004b121e00b635000b121f008036000b1233008c36000b120016008c36000b122600a706010b12270f1206000000280000000000002601aa06010b12270f1206000000280000000000002601af06010b1227000000000000280000000000002601b806010b12270f423f000000280000000000001a01a40b010b121700b921014b121800ba21014b12010101009923414b121700a217024b121800a117024b12010101008219424b1217009a1e034b1218009a1e034b12010303008520434b12333c9425034b120016019425034b12333c9725034b120016019725034b12333c9925034b120016019925034b12333c9d25034b120016019d25034b12333ca025034b12001601a025034b1201010100841b474b123300af1b074b12001601af1b074b123300b42f074b12001601b42f074b12390bb134876b128436633300a401084b12001600a401084b1236008613080b12370be5940cdf8f3800000000000017008723084b1218008823084b121700b531094b121800b531094b1217008f38094b1218008f38094b123601ad38090b12370be5940cdf8f380000000000002000bb3a090b12011e1e00ac114a0b12010f0f0097234a4b121700a0250b4b121800a0250b4b120114130091244b0b120114140091244b0b1262008f2f0b0b126401a62f0b0b12260196300b0b12270f423f0000002800000000000026019b300b0b1227000000000000280000000000001700b9330b4b121800ba330b4b12010a0a0090194c0b12012828008d184d0b121700a5220d4b121800a5220d4b126401b82b0d0b126400822c0d0b1217008c2c0d0b121800802d0d0c12070000039a8b126c8b1209005c5c5c010000039a01b63001e434000001e43400000000000001e46409000000096201a32f0d0c126200a62f0d0c12170084310d4c12180091300d4b1207000000048c126c8c12090c00e80000000000040004640000000000000000000000000000000000000000000064018e060e0b1236009a060e0b12370be5940cdf8f380000000000002601b3060e0b12270f1206000000280000000000001a0093150e0b120000007689")!, pumpModel: pumpModel) - - let events = page.events - - XCTAssertEqual(106, events.count) - - XCTAssert(events[62] is BGReceivedPumpEvent) - - let bgMeter = events[62] as! BGReceivedPumpEvent - - XCTAssertEqual(bgMeter.amount, 92) - XCTAssertEqual(bgMeter.meter, "843663") - XCTAssertEqual(bgMeter.timestamp, DateComponents(gregorianYear: 2018, month: 8, day: 11, hour: 7, minute: 52, second: 49)) - - } - - func testHistoryTimeShift() throws { - let model = PumpModel.model523 - - let pages = [ - "16004ee2124d127b044fe2120d121d240033004ee7124d120016014ee7124d1233004eec124d120016004eec124d127b044eec120d121d240033004ef1124d120016014ef1124d1233004ec9134d120016014ec9134d1233004ece134d120016004ece134d127b044ece130d121d2400338d4edd134d120016014edd134d1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fc9d", - "7b014fec040d12062800334c5ff1054d120016015ff1054d1233004ff6054d120016004ff6054d127b014ff6050d1206280001008a008a00000055d1264d1233004fe2064d120016014fe2064d1233004ff6064d120016004ff6064d127b014ff6060d1206280033514ffb064d120016014ffb064d1233004fc4074d120016004fc4074d127b024fc4070d120e240001004a004a006f0077cd274d12336e5ed3074d120016015ed3074d12334e5dd8074d120016015dd8074d1233004fdd074d120016004fdd074d127b024fdd070d120e2400330050fb074d1200160150fb074d1233004fd3084d120016014fd3084d1233004fd8084d120016004fd8084d127b024fd8080d120e240033ba4eec084d120016014eec084d1233ba4fc4094d120016014fc4094d1201007800780030004cd6294d1233004fdd094d120016004fdd094d127b024fdd090d120e240033004ff1094d120016014ff1094d1233004fc90a4d120016014fc90a4d1233004fdd0a4d120016014fdd0a4d1233005bf10a4d120016015bf10a4d1233004fc90b4d120016014fc90b4d1233004fdd0b4d120016014fdd0b4d1233004fec0b4d120016004fec0b4d127b034fec0b0d121720000100660066001d0060c12c4d12336151c90c4d1200160151c90c4d12335c4ece0c4d120016014ece0c4d12334f4fd30c4d120016014fd30c4d1233554ed80c4d120016014ed80c4d12335b4edd0c4d120016014edd0c4d1233004ee20c4d120016004ee20c4d127b034fe20c0d1217200033004ffb0d4d120016014ffb0d4d1233004fd30e4d120016014fd30e4d1233004fd80e4d120016004fd80e4d127b034fd80e0d121720007b0440de0e0d121d240033004fe20e4d120016014fe20e4d12330050e70e4d1200160050e70e4d127b0450e70e0d121d240033594edd0f4d120016014edd0f4d1233464fe20f4d120016014fe20f4d12336c4fe70f4d120016014fe70f4d1233804eec0f4d120016014eec0f4d1233764ff10f4d120016014ff10f4d1233644ff60f4d120016014ff60f4d1233575ffb0f4d120016015ffb0f4d12334b65c4104d1200160165c4104d1233004fc9104d120016004fc9104d127b044fc9100d121d240033004fce104d120016014fce104d1233004fe2104d120016014fe2104d1233004fec104d120016004fec104d127b044fec100d121d240033004ffb104d120016014ffb104d12330050d3114d1200160150d3114d1233004fe2114d120016004fe2114d127b044fe2110d121d240033634ec9124d120016014ec9124d12010078007800000060c9324d1233ba4ece124d120016014ece124d1233b24ed3124d120016014ed3124d1233914ed8124d120016014ed8124d1233774edd124d120016014edd124d1233004ee2124d120000000000362c", - "16014ee2144c1233644fe7144c120016014fe7144c1233634fec144c120016014fec144c12335a4ff1144c120016014ff1144c1233004ef6144c120016004ef6144c127b044ef6140c121d24007b0540c0150c122a300033684ece154c120016014ece154c12336f4ed3154c120016014ed3154c1233605fd8154c120016015fd8154c1233004fdd154c120016004fdd154c127b054fdd150c122a3000334a4fe2154c120016014fe2154c12334b4fe7154c120016014fe7154c12330044f2154c1200160144f2154c12334a4ec4164c120016014ec4164c1233555fc9164c120016015fc9164c121e0171d0160c127b0574ee160c122a30001f2074ee160c12336d4ef1164c120016014ef1164c1233004ef6164c120016004ef6164c127b054ff6160c122a3000334a4ec9174c120016014ec9174c1233564fce174c120016014fce174c1233674fd8174c120016014fd8174c12334d4edd174c120016014edd174c1233554fe2174c120016014fe2174c1233004ee7174c120016004ee7174c127b054fe7170c122a3000334a4ef6174c120016014ef6174c1233474efb174c120016014efb174c1207000007a26c920000006e6c92050000000000000007a204d63f02cc25000000000000000002cc0000000700000000000000000000000000000000000000334c4ec4004d120016014ec4004d1233774ec9004d120016014ec9004d1233894ece004d120016014ece004d12338a4ed3004d120016014ed3004d1233a54ed8004d120016014ed8004d1233ba4edd004d120016014edd004d1233b84eec004d120016014eec004d1233ba4ef1004d120016014ef1004d1233914ef6004d120016014ef6004d1233714efb004d120016014efb004d1233654fc4014d120016014fc4014d12335c4ec9014d120016014ec9014d1233624ece014d120016014ece014d1233664ed3014d120016014ed3014d1233584ed8014d120016014ed8014d1233474edd014d120016014edd014d1233004ee2014d120016004ee2014d127b004fe2010d1200300033074ef6014d120016014ef6014d1233004efb014d120016014efb014d1233004ed3024d120016014ed3024d1233007aea024d120016017aea024d1233004efb024d120016004efb024d127b004efb020d120030007b0140c0030d1206280033584ed8034d120016014ed8034d12336e4edd034d120016014edd034d12337e4fe2034d120016014fe2034d1233604ee7034d120016014ee7034d1233004eec034d120016004eec034d127b014fec030d1206280033534efb034d120016014efb034d1233004fc4044d120016004fc4044d127b014fc4040d1206280033004ed3044d120016014ed3044d1233005ee7044d120016015ee7044d1233004eec044d120016004eec044d1200000000ec9a", - "335762fb0b4c1200160162fb0b4c12336460c40c4c1200160160c40c4c12336960c90c4c1200160160c90c4c12335663ce0c4c1200160163ce0c4c12334661d30c4c1200160161d30c4c12334960d80c4c1200160160d80c4c12335561e20c4c1200160161e20c4c1233005ee70c4c120016005ee70c4c127b035ee70c0c1217200001006c006c00000061f82c4c12330079dd0d4c1200160179dd0d4c1233005df10d4c120016015df10d4c1233005dc90e4c120016015dc90e4c1233005fd80e4c120016005fd80e4c127b035fd80e0c121720007b0440de0e0c121d240033676dec0e4c120016016dec0e4c1233006ef10e4c120016006ef10e4c127b046ef10e0c121d2400335f4ff60e4c120016014ff60e4c1233564efb0e4c120016014efb0e4c1233524fc40f4c120016014fc40f4c12010068006800290064c42f4c12334b4fce0f4c120016014fce0f4c1233005ed30f4c120016005ed30f4c127b045fd30f0c121d2400333e50f60f4c1200160150f60f4c1233005ffb0f4c120016005ffb0f4c127b045ffb0f0c121d2400333660cb104c1200160160cb104c1233374fce104c120016014fce104c1233004fd3104c120016004fd3104c127b044fd3100c121d2400333a4fd8104c120016014fd8104c1233484fdd104c120016014fdd104c1233004ee2104c120016004ee2104c127b044fe2100c121d2400333c4efb104c120016014efb104c12333a4fc4114c120016014fc4114c1233004ec9114c120016004ec9114c127b044ec9110c121d240033374ed3114c120016014ed3114c12333b4ed8114c120016014ed8114c12333e50dd114c1200160150dd114c1233004fe2114c120016004fe2114c127b044fe2110c121d240033054fe7114c120016014fe7114c12330e4fec114c120016014fec114c1233074ff1114c120016014ff1114c12010020002000160063f2314c1233a24ff6114c120016014ff6114c1233994ffb114c120016014ffb114c12338e4ec4124c120016014ec4124c12337c49d4124c1200160149d4124c1201004a004a002a0069d6324c1233874ed8124c120016014ed8124c12337a50e2124c1200160150e2124c12335050e7124c1200160150e7124c1233384fec124c120016014fec124c1233004ef1124c120016014ef1124c1233004ece134c120016014ece134c1233004ed9134c120016014ed9134c12330060d9134c1200160160d9134c1233004ee7134c120016004ee7134c127b044fe7130c121d240001008c008c0041004eee334c1233ba4ff1134c120016014ff1134c1233b54ec9144c120016014ec9144c12339b4ece144c120016014ece144c1233954ed3144c120016014ed3144c1201006e006e00a9005dd6344c1233ba4fdd144c120016014fdd144c1233894ee2144c12000049f0", - "07000007456b920000006e6b920500000000000000074504d943026c210000000000000000026c000000070000000000000000000000000000000000000033496aec004c120016016aec004c12334a5cf1004c120016015cf1004c12334e5cf6004c120016015cf6004c1233535cfb004c120016015cfb004c1233565cc4014c120016015cc4014c1233555cc9014c120016015cc9014c12334d5dce014c120016015dce014c1233005dd3014c120016005dd3014c127b005dd3010c1200300033005ce7014c120016015ce7014c1233005dfb014c120016015dfb014c1233005cc4024c120016005cc4024c127b005cc4020c120030007b0140c0030c1206280033694fd8034c120016014fd8034c1233614edd034c120016014edd034c12334e4ee2034c120016014ee2034c1233004fe7034c120016004fe7034c127b014fe7030c1206280033004ef1034c120016014ef1034c1233004ef6034c120016004ef6034c127b014ff6030c1206280033004ec4044c120016014ec4044c1233004ed8044c120016014ed8044c1233004fdd044c120016004fdd044c127b014fdd040c1206280033004ee7044c120016014ee7044c1233004ef1044c120016004ef1044c127b014ef1040c1206280033004ec4054c120016014ec4054c1233004ed8054c120016004ed8054c127b014ed8050c12062800010094009400000058c9264c12339b4fec064c120016014fec064c12338d4ff1064c120016014ff1064c12337d4ff6064c120016014ff6064c1233744ffb064c120016014ffb064c1233634ec4074c120016014ec4074c1233524fc9074c120016014fc9074c1233004fce074c120016004fce074c127b024fce070c120e240033574ed8074c120016014ed8074c1233004fdd074c120016004fdd074c127b024fdd070c120e240033494ee2074c120016014ee2074c1233004fe7074c120016004fe7074c127b024fe7070c120e2400330050ce084c1200160150ce084c1233004fd8084c120016004fd8084c127b0250d8080c120e2400337960e7094c1200160160e7094c12337171ec094c1200160171ec094c12336c6ef1094c120016016ef1094c12336f6df6094c120016016df6094c1233656efb094c120016016efb094c12335d5ec40a4c120016015ec40a4c12336e6dc90a4c120016016dc90a4c12336f73ce0a4c1200160173ce0a4c12336761d80a4c1200160161d80a4c12334c5ddd0a4c120016015ddd0a4c1233005ce20a4c120016005ce20a4c127b025de20a0c120e240033005dec0a4c120016015dec0a4c12330062c40b4c1200160162c40b4c1233005dd30b4c120016005dd30b4c127b025dd30b0c120e24007b0340de0b0c1217200033635ff10b4c120016015ff10b4c1233625ff60b4c120016015ff60b4c120000b78f", - "330b4fd2114b120016014fd2114b1233004fd7114b120016014fd7114b12331250e1114b1200160150e1114b12330050e6114b1200160050e6114b127b0450e6110b121d240033374ff5114b120016014ff5114b1233004efa114b120016004efa114b127b044ffa110b121d2400333f4fc8124b120016014fc8124b1233004fcd124b120016004fcd124b127b044fcd120b121d2400010052005200000076cf324b12333b4fd2124b120016014fd2124b12336d49d9124b1200160149d9124b12335e4edc124b120016014edc124b12010038003800500046dd324b12335a4fe1124b120016014fe1124b1233554ee6124b120016014ee6124b1233004feb124b120016014feb124b12190040c2130b1233004fc3134b120016014fc3134b1233004fc8134b120016014fc8134b1233004fcd134b120016014fcd134b121a005bd9130b121a0176d9130b12346776d9130b12330051dd134b1200160151dd134b1233005ce7134b120016005ce7134b127b045de7130b121d240033594ef1134b120016014ef1134b12346468f4130b12210050f5130b12030000004540f6330b12030014001464f7130b12334a5cfb134b120016015cfb134b1233505cc4144b120016015cc4144b1233005cc9144b120016005cc9144b127b045cc9140b121d2400335a5cce144b120016015cce144b1233005dd3144b120016005dd3144b127b045dd3140b121d240033555cd8144b120016015cd8144b1201007c007c00330065de344b1233565de2144b120016015de2144b1233005de7144b120016005de7144b127b045de7140b121d2400330c5cec144b120016015cec144b1233005df1144b120016015df1144b1233015dc4154b120016015dc4154b1233005cc9154b120016015cc9154b1233005cdd154b120016015cdd154b1233005ce2154b120016005ce2154b127b055de2150b122a3000334b54ed154b1200160154ed154b12334d5df1154b120016015df1154b1233005df6154b120016015df6154b1233005cc4164b120016005cc4164b127b055cc4160b122a30001e0176c8160b127b054fe6160b122a30001f204fe6160b1201003c003c00330067e6364b1233765df1164b120016015df1164b12337d5df6164b120016015df6164b12337c61fb164b1200160161fb164b1233735ec4174b120016015ec4174b1233825dc9174b120016015dc9174b12337e5dce174b120016015dce174b12336b5fd3174b120016015fd3174b1233555fd8174b120016015fd8174b1233655ddd174b120016015ddd174b12336d5de2174b120016015de2174b1233585fe7174b120016015fe7174b1233505dec174b120016015dec174b1233005df1174b120016005df1174b127b055df1170b122a30007b0040c0000c120030000000000000000000004251", - "337364c2084b1200160164c2084b1233535fc7084b120016015fc7084b1233005ecc084b120016005ecc084b127b025ecc080b120e240033525ec2094b120016015ec2094b12336a5ec7094b120016015ec7094b1233a74fcc094b120016014fcc094b1233ba4fd1094b120016014fd1094b12010078007800140068d4294b1233004fdb094b120016014fdb094b1233004fef094b120016014fef094b12330050c70a4b1200160150c70a4b12330060db0a4b1200160160db0a4b1233004fef0a4b120016014fef0a4b12330060c70b4b1200160160c70b4b12330062d60b4b1200160062d60b4b127b0262d60b0b120e24007b0340de0b0b12172000334a5fe00b4b120016015fe00b4b12335a5fea0b4b120016015fea0b4b1233004fef0b4b120016004fef0b4b127b034fef0b0b1217200033525df90b4b120016015df90b4b12335b5dc20c4b120016015dc20c4b12335d5fc70c4b120016015fc70c4b1233614fcc0c4b120016014fcc0c4b1233974fd10c4b120016014fd10c4b1201002600260015005bd32c4b1233b760d60c4b1200160160d60c4b12339562db0c4b1200160162db0c4b1233704fe00c4b120016014fe00c4b12334c4fe50c4b120016014fe50c4b1233004fea0c4b120016004fea0c4b127b034fea0c0b12172000334a4fef0c4b120016014fef0c4b1233004ff40c4b120016004ff40c4b127b034ff40c0b12172000335d50f90d4b1200160150f90d4b1233855dc20e4b120016015dc20e4b12339f62c70e4b1200160162c70e4b1233944fcc0e4b120016014fcc0e4b12338e4ed10e4b120016014ed10e4b1233944fd60e4b120016014fd60e4b1234c876d90e0b1233974fdc0e4b120016014fdc0e4b1233884fe10e4b120016014fe10e4b12335950e60e4b1200160150e60e4b12334b4feb0e4b120016014feb0e4b1233004ff00e4b120016004ff00e4b127b044ff00e0b121d240033004fc80f4b120016014fc80f4b1233004fdc0f4b120016004fdc0f4b127b044fdc0f0b121d240033434fe60f4b120016014fe60f4b12334f4feb0f4b120016014feb0f4b12335c4ff00f4b120016014ff00f4b1233004ff50f4b120016004ff50f4b127b044ff50f0b121d240033494fc8104b120016014fc8104b12334e4fcd104b120016014fcd104b1233704ed2104b120016014ed2104b12337d4fd7104b120016014fd7104b1233794fdc104b120016014fdc104b1233614fe1104b120016014fe1104b12335f4fe6104b120016014fe6104b12335d4feb104b120016014feb104b1233614ef0104b120016014ef0104b1233524ff5104b120016014ff5104b1233474efa104b120016014efa104b1233004fc3114b120016004fc3114b127b044fc3110b121d2400330e4fcd114b120016014fcd114b120000000029b4", - "33004eef174a120016004eef174a127b054eef170a122a3000335b4ef9174a120016014ef9174a12070000084c6a920000006e6a920500000000000000084c055a4102f223000000000000000002f2000000090000000000000000000000000000000000000033524fc2004b120016014fc2004b1233584ec7004b120016014ec7004b1233004ecc004b120016004ecc004b127b004ecc000b12003000335a4ed6004b120016014ed6004b12337e4edb004b120016014edb004b1233606ff5004b120016016ff5004b1233004ef9004b120016004ef9004b127b004ef9000b1200300033004ace014b120016014ace014b1233634ed6014b120016014ed6014b1233004edb014b120016004edb014b127b004fdb010b1200300033004ee0014b120016014ee0014b1233004ef4014b120016014ef4014b1233004ec2024b120016004ec2024b127b004ec2020b1200300033624ed6024b120016014ed6024b1233824edb024b120016014edb024b1233874ee0024b120016014ee0024b127b014ec2030b1206280033045cd1034b120016015cd1034b1233005cd6034b120016015cd6034b1233005ce5034b120016005ce5034b127b015ce5030b1206280033005cef034b120016015cef034b1233015cc7044b120016015cc7044b1233005ccc044b120016005ccc044b127b015dcc040b12062800334c5cd1044b120016015cd1044b1233695cd6044b120016015cd6044b1233955cdb044b120016015cdb044b12339b5ce0044b120016015ce0044b12337c5ce5044b120016015ce5044b1233585cea044b120016015cea044b12334e5cef044b120016015cef044b12334e5eef044b120016015eef044b1233005cf4044b120016005cf4044b127b015cf4040b1206280033005cd1054b120016015cd1054b1233065bd9054b120016015bd9054b1233005cdb054b120016005cdb054b127b015ddb050b1206280033005ce0054b120016015ce0054b1233006be5054b120016016be5054b1233005cf9054b120016015cf9054b1233545cc7064b120016015cc7064b12335b5dcc064b120016015dcc064b1201008c008c00000043d1264b1233ba5dd6064b120016015dd6064b12640053df060b1217005bdf060b12180040df090b1217005fe2094b12180078e2064b12337a65e3064b1200160165e3064b12337a79e3064b1200160179e3064b1233005fe5064b120016005fe5064b127b015fe5060b12062800330061f4064b1200160161f4064b1233005ec7074b120016005ec7074b127b025ec7070b120e2400334a5dcc074b120016015dcc074b1233495dd1074b120016015dd1074b1233005dd6074b120016005dd6074b127b025dd6070b120e240033475df4074b120016015df4074b12336060f9074b1200160160f9074b120000ada4", - "08066ed8124a120030000628000e24001720001d24002830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009066ed8124a120030000628000e24001720001d24002a3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b046ed8124a121d240033004fe0124a120016014fe0124a1233004fe5124a120016004fe5124a127b044fe5120a121d2400010058005800130076e6324a12339e4ff4124a120016014ff4124a12338c4ff9124a120016014ff9124a1233794fc2134a120016014fc2134a1233604fc7134a120016014fc7134a12334c4ecc134a120016014ecc134a1233004fd1134a120016004fd1134a127b044fd1130a121d24000100740074004d0056d5334a1233a04fdb134a120016014fdb134a1233a350e0134a1200160150e0134a1233a14de8134a120016014de8134a1233994fea134a120016014fea134a1233684fef134a120016014fef134a12336950f4134a1200160150f4134a1233004ec0144a120016014ec0144a1233004fc7144a120016004fc7144a127b044fc7140a121d240033544fe0144a120016014fe0144a12335f4fe5144a120016014fe5144a12334f4fea144a120016014fea144a1233484fef144a120016014fef144a1233004ff4144a120016004ff4144a127b044ff4140a121d24007b0540c0150a122a3000331b4fc7154a120016014fc7154a1233004fcc154a120016004fcc154a127b054fcc150a122a30001e0177df150a127b054ec1160a122a30001f204ec1160a1233004fc2164a120016014fc2164a1233004ecc164a120016004ecc164a127b054ecc160a122a3000336d4ed1164a120016014ed1164a1201003c003c001b0072d3364a12331d4fd6164a120016014fd6164a12334f4fdb164a120016014fdb164a120100200020004d0063df364a1233424ee5164a120016014ee5164a12335d4bed164a120016014bed164a1233154dc5174a120016014dc5174a1233115dc7174a120016015dc7174a1233104fcc174a120016014fcc174a12330a4ed1174a120016014ed1174a1233144ed6174a120016014ed6174a12330d5adf174a120016015adf174a1233154ee5174a120016014ee5174a120000000000000018a8", - "33ba4fea0c4a120016014fea0c4a1233ba4fc20d4a120016014fc20d4a12010040004000000069c62d4a1233004fcc0d4a120016014fcc0d4a1233004fd10d4a120016004fd10d4a127b034fd10d0a1217200033004fd60d4a120016014fd60d4a1233004fea0d4a120016014fea0d4a1233004ec20e4a120016014ec20e4a1233004ed60e4a120016014ed60e4a1233004fea0e4a120016014fea0e4a1233004fef0e4a120016004fef0e4a127b044fef0e0a121d2800339d4ff40e4a120016014ff40e4a12339f4ff90e4a120016014ff90e4a1233a84fc20f4a120016014fc20f4a1233844fc70f4a120016014fc70f4a12336d4fcc0f4a120016014fcc0f4a1233754fd10f4a120016014fd10f4a12010066006600170061d12f4a120100420042007c006ad32f4a12335f4fd60f4a120016014fd60f4a1233004edb0f4a120016004edb0f4a127b044fdb0f0a121d2800333b4fe50f4a120016014fe50f4a1233004eea0f4a120016004eea0f4a127b044fea0f0a121d2800334a4ec7104a120016014ec7104a1233454fcc104a120016014fcc104a12334b4fd1104a120016014fd1104a1233414dd9104a120016014dd9104a12333d4fdb104a120016014fdb104a1233004ee0104a120016004ee0104a127b044fe0100a121d2800333c4ee5104a120016014ee5104a12333a4fea104a120016014fea104a1233414fef104a120016014fef104a1233454ef4104a120016014ef4104a12333f4ff9104a120016014ff9104a1233004ec2114a120016004ec2114a127b044ec2110a121d2800333c4fcc114a120016014fcc114a1233004fd1114a120016004fd1114a127b044fd1110a121d280033164fdb114a120016014fdb114a1233004fe0114a120016014fe0114a1233004fef114a120016004fef114a127b044fef110a121d280033004ff4114a120016014ff4114a1233004ecc124a120016014ecc124a12080661d8124a120030000628000e28001720001d280028300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090661d8124a120030000628000e24001720001d2400283000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b0461d8124a121d240000000000eeca", - - ].compactMap({ - return Data(hexadecimalString: $0) - }).map({ - return try! HistoryPage(pageData: $0, pumpModel: model) - }) - - // Assert that all events are in chronological order, even though there is a +3 and -3 hour time change in pages[7] - var nextDate = Date.distantFuture - - for page in pages { - let (timestampedEvents, _, cancelledEarly) = page.timestampedEvents(after: .distantPast, timeZone: TimeZone(secondsFromGMT: 0)!, model: model) - - XCTAssertFalse(cancelledEarly) - - for event in timestampedEvents.reversed() { - XCTAssertLessThanOrEqual(event.date, nextDate) - nextDate = event.date - } - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Info.plist b/Dependencies/MinimedKit/MinimedKitTests/Info.plist deleted file mode 100644 index fccbfa25b..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 3.0 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - - diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/BolusCarelinkMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/BolusCarelinkMessageBodyTests.swift deleted file mode 100644 index b501fe286..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/BolusCarelinkMessageBodyTests.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// BolusCarelinkMessageBodyTests.swift -// Naterade -// -// Created by Nathan Racklyeft on 3/5/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import XCTest -@testable import MinimedKit - - -class BolusCarelinkMessageBodyTests: XCTestCase { - - func testBolusMessageBody() { - let message = PumpMessage(packetType: .carelink, address: "123456", messageType: .bolus, messageBody: BolusCarelinkMessageBody(units: 1.1, insulinBitPackingScale: 40)) - - XCTAssertEqual( - Data(hexadecimalString: "a71234564202002C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - message.txData - ) - } - - func testBolusMessageBody522() { - let message = PumpMessage(packetType: .carelink, address: "123456", messageType: .bolus, messageBody: BolusCarelinkMessageBody(units: 1.1, insulinBitPackingScale: 10)) - - XCTAssertEqual( - Data(hexadecimalString: "a712345642010B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - message.txData - ) - } - - func testBolusMessageBodyRounding() { - let message = PumpMessage(packetType: .carelink, address: "123456", messageType: .bolus, messageBody: BolusCarelinkMessageBody(units: 1.475, insulinBitPackingScale: 40)) - - XCTAssertEqual( - Data(hexadecimalString: "a71234564202003A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - message.txData - ) - } - - func testBolusMessageBodyTwoByte() { - let message = PumpMessage(packetType: .carelink, address: "123456", messageType: .bolus, messageBody: BolusCarelinkMessageBody(units: 7.9, insulinBitPackingScale: 40)) - - XCTAssertEqual( - Data(hexadecimalString: "a71234564202013C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - message.txData - ) - } - - func testBolusMessageBodyGreaterThanTenUnits() { - let message = PumpMessage(packetType: .carelink, address: "123456", messageType: .bolus, messageBody: BolusCarelinkMessageBody(units: 10.25, insulinBitPackingScale: 40)) - - XCTAssertEqual( - Data(hexadecimalString: "a7123456420201980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - message.txData - ) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeMaxBasalRateMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeMaxBasalRateMessageBodyTests.swift deleted file mode 100644 index 18ed70adb..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeMaxBasalRateMessageBodyTests.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// ChangeMaxBasalRateMessageBodyTests.swift -// MinimedKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class ChangeMaxBasalRateMessageBodyTests: XCTestCase { - - func testMaxBasalRate() { - var body = ChangeMaxBasalRateMessageBody(maxBasalUnitsPerHour: 6.4)! - - XCTAssertEqual(Data(hexadecimalString: "0201000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!, body.txData, body.txData.hexadecimalString) - - body = ChangeMaxBasalRateMessageBody(maxBasalUnitsPerHour: 4.0)! - - XCTAssertEqual(Data(hexadecimalString: "0200A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!, body.txData, body.txData.hexadecimalString) - } - - func testMaxBasalRateRounded() { - let body = ChangeMaxBasalRateMessageBody(maxBasalUnitsPerHour: 9.115)! - - XCTAssertEqual(Data(hexadecimalString: "02016c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!, body.txData, body.txData.hexadecimalString) - - - } - - func testMaxBasalRateOutOfRange() { - XCTAssertNil(ChangeMaxBasalRateMessageBody(maxBasalUnitsPerHour: -1)) - XCTAssertNil(ChangeMaxBasalRateMessageBody(maxBasalUnitsPerHour: 36)) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeMaxBolusMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeMaxBolusMessageBodyTests.swift deleted file mode 100644 index d92f6e836..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeMaxBolusMessageBodyTests.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// ChangeMaxBolusMessageBodyTests.swift -// MinimedKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class ChangeMaxBolusMessageBodyTests: XCTestCase { - - func testMaxBolus522() { - let body = ChangeMaxBolusMessageBody(pumpModel: .model522, maxBolusUnits: 6.4)! - - XCTAssertEqual(Data(hexadecimalString: "0140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!, body.txData, body.txData.hexadecimalString) - } - - func testMaxBolus523() { - let body = ChangeMaxBolusMessageBody(pumpModel: .model523, maxBolusUnits: 6.4)! - - XCTAssertEqual(Data(hexadecimalString: "0200400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!, body.txData, body.txData.hexadecimalString) - } - - func testMaxBolusRounded522() { - let body = ChangeMaxBolusMessageBody(pumpModel: .model522, maxBolusUnits: 2.25)! - - XCTAssertEqual(Data(hexadecimalString: "0116000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!, body.txData, body.txData.hexadecimalString) - } - - - func testMaxBolusRounded523() { - let body = ChangeMaxBolusMessageBody(pumpModel: .model523, maxBolusUnits: 2.25)! - - XCTAssertEqual(Data(hexadecimalString: "0200160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!, body.txData, body.txData.hexadecimalString) - } - - func testMaxBolusOutOfRange() { - XCTAssertNil(ChangeMaxBolusMessageBody(pumpModel: .model522, maxBolusUnits: -1)) - XCTAssertNil(ChangeMaxBolusMessageBody(pumpModel: .model523, maxBolusUnits: 26)) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeRemoteControlIDMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeRemoteControlIDMessageBodyTests.swift deleted file mode 100644 index ee10e511b..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeRemoteControlIDMessageBodyTests.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// ChangeRemoteControlIDMessageBodyTests.swift -// MinimedKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class ChangeRemoteControlIDMessageBodyTests: XCTestCase { - - func testEncodeOneRemote() { - let expected = Data(hexadecimalString: "0700313233343536000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")! - let body = ChangeRemoteControlIDMessageBody(id: Data([1, 2, 3, 4, 5, 6]), index: 0)! - - XCTAssertEqual(expected, body.txData, body.txData.hexadecimalString) - } - - - func testEncodeZeroRemotes() { - let expected = Data(hexadecimalString: "07022d2d2d2d2d2d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")! - let body = ChangeRemoteControlIDMessageBody(id: nil, index: 2)! - - XCTAssertEqual(expected, body.txData) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeTempBasalCarelinkMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeTempBasalCarelinkMessageBodyTests.swift deleted file mode 100644 index f95a0e221..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeTempBasalCarelinkMessageBodyTests.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// ChangeTempBasalCarelinkMessageBodyTests.swift -// Naterade -// -// Created by Nathan Racklyeft on 3/6/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import MinimedKit - - -class ChangeTempBasalCarelinkMessageBodyTests: XCTestCase { - - func testTempBasalMessageBody() { - let message = PumpMessage(packetType: .carelink, address: "123456", messageType: .changeTempBasal, messageBody: ChangeTempBasalCarelinkMessageBody(unitsPerHour: 1.1, duration: TimeInterval(30 * 60))) - - XCTAssertEqual( - Data(hexadecimalString: "a71234564C03002C0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - message.txData - ) - } - - func testTempBasalMessageBodyLarge() { - let message = PumpMessage(packetType: .carelink, address: "123456", messageType: .changeTempBasal, messageBody: ChangeTempBasalCarelinkMessageBody(unitsPerHour: 6.5, duration: TimeInterval(150 * 60))) - - XCTAssertEqual( - Data(hexadecimalString: "a71234564C0301040500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - message.txData - ) - } - - func testTempBasalMessageBodyRounding() { - let message = PumpMessage(packetType: .carelink, address: "123456", messageType: .changeTempBasal, messageBody: ChangeTempBasalCarelinkMessageBody(unitsPerHour: 1.442, duration: TimeInterval(65.5 * 60))) - - XCTAssertEqual( - Data(hexadecimalString: "a71234564C0300390200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - message.txData - ) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeTimeCarelinMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeTimeCarelinMessageBodyTests.swift deleted file mode 100644 index d65963996..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/ChangeTimeCarelinMessageBodyTests.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// ChangeTimeCarelinMessageBodyTests.swift -// Naterade -// -// Created by Nathan Racklyeft on 3/17/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import MinimedKit - - -class ChangeTimeCarelinMessageBodyTests: XCTestCase { - - func testChangeTime() { - var components = DateComponents() - components.calendar = Calendar(identifier: Calendar.Identifier.gregorian) - - components.year = 2017 - components.month = 12 - components.day = 29 - components.hour = 9 - components.minute = 22 - components.second = 59 - - let message = PumpMessage(packetType: .carelink, address: "123456", messageType: .changeTime, messageBody: ChangeTimeCarelinkMessageBody(dateComponents: components)!) - - XCTAssertEqual(Data(hexadecimalString: "a7123456400709163B07E10C1D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), message.txData) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/DeviceLinkMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/DeviceLinkMessageBodyTests.swift deleted file mode 100644 index 3c35b62fb..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/DeviceLinkMessageBodyTests.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// DeviceLinkMessageBodyTests.swift -// RileyLink -// -// Created by Pete Schwamb on 3/7/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class DeviceLinkMessageBodyTests: XCTestCase { - - func testValidDeviceLinkMessage() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a23505350a93ce8aa000")!) - - if let message = message { - XCTAssertTrue(message.messageBody is DeviceLinkMessageBody) - } else { - XCTFail("\(String(describing: message)) is nil") - } - } - - func testMidnightSensor() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a23505350a93ce8aa000")!)! - - let body = message.messageBody as! DeviceLinkMessageBody - - XCTAssertEqual(body.sequence, 19) - XCTAssertEqual(body.deviceAddress.hexadecimalString, "ce8aa0") - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/FindDeviceMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/FindDeviceMessageBodyTests.swift deleted file mode 100644 index f1bf8d9b7..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/FindDeviceMessageBodyTests.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// FindDeviceMessageBodyTests.swift -// RileyLink -// -// Created by Pete Schwamb on 3/7/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class FindDeviceMessageBodyTests: XCTestCase { - - func testValidFindDeviceMessage() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a235053509cf99999900")!) - - if let message = message { - XCTAssertTrue(message.messageBody is FindDeviceMessageBody) - } else { - XCTFail("\(String(describing: message)) is nil") - } - } - - func testMidnightSensor() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a235053509cf99999900")!)! - - let body = message.messageBody as! FindDeviceMessageBody - - XCTAssertEqual(body.sequence, 79) - XCTAssertEqual(body.deviceAddress.hexadecimalString, "999999") - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/GetBatteryCarelinkMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/GetBatteryCarelinkMessageBodyTests.swift deleted file mode 100644 index 272ce53f8..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/GetBatteryCarelinkMessageBodyTests.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// GetBatteryCarelinkMessageBodyTests.swift -// RileyLink -// -// Created by Pete Schwamb on 3/16/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class GetBatteryCarelinkMessageBodyTests: XCTestCase { - - func testValidGetBatteryResponse() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a7350535720300008c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!) - - if let message = message { - XCTAssertTrue(message.messageBody is GetBatteryCarelinkMessageBody) - let body = message.messageBody as! GetBatteryCarelinkMessageBody - XCTAssertEqual(body.volts, 1.4) - - if case .normal = body.status { - // OK - } else { - XCTFail() - } - } else { - XCTFail("\(String(describing: message)) is nil") - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/GetGlucosePageMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/GetGlucosePageMessageBodyTests.swift deleted file mode 100644 index ea24d24c1..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/GetGlucosePageMessageBodyTests.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// GetGlucosePageMessageBodyTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/19/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class GetGlucosePageMessageBodyTests: XCTestCase { - - func testTxDataEncoding() { - let messageBody = GetGlucosePageMessageBody(pageNum: 13) - - XCTAssertEqual(messageBody.txData.subdata(in: 0..<5).hexadecimalString, "040000000d") - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/GetPumpModelCarelinkMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/GetPumpModelCarelinkMessageBodyTests.swift deleted file mode 100644 index c8c3ddae2..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/GetPumpModelCarelinkMessageBodyTests.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// GetPumpModelCarelinkMessageBodyTests.swift -// RileyLink -// -// Created by Pete Schwamb on 3/14/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class GetPumpModelCarelinkMessageBodyTests: XCTestCase { - - func testValidGetModelResponse() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a73505358d0903353233000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!) - - if let message = message { - XCTAssertTrue(message.messageBody is GetPumpModelCarelinkMessageBody) - let body = message.messageBody as! GetPumpModelCarelinkMessageBody - XCTAssertEqual(body.model, "523") - } else { - XCTFail("\(String(describing: message)) is nil") - } - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/MeterMessageTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/MeterMessageTests.swift deleted file mode 100644 index 462095177..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/MeterMessageTests.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// MeterMessageTests.swift -// RileyLink -// -// Created by Pete Schwamb on 3/10/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class MeterMessageTests: XCTestCase { - - func testValidMeterMessage() { - let message = MeterMessage(rxData: Data(hexadecimalString: "a5c527ad018e77")!) - - if let message = message { - XCTAssertEqual(message.glucose, 257) - XCTAssertEqual(message.ackFlag, false) - } else { - XCTFail("\(String(describing: message)) is nil") - } - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadCurrentGlucosePageMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadCurrentGlucosePageMessageBodyTests.swift deleted file mode 100644 index cc9e05d09..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadCurrentGlucosePageMessageBodyTests.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// ReadCurrentGlucosePageMessageBodyTests.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/19/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class ReadCurrentGlucosePageMessageBodyTests: XCTestCase { - - func testResponseInitializer() { - var responseData = Data(hexadecimalString: "0000000D6100100020")! - responseData.append(contentsOf: [UInt8](repeating: 0, count: 65 - responseData.count)) - - let messageBody = ReadCurrentGlucosePageMessageBody(rxData: responseData)! - - XCTAssertEqual(messageBody.pageNum, 3425) - XCTAssertEqual(messageBody.glucose, 16) - XCTAssertEqual(messageBody.isig, 32) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadOtherDevicesIDsMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadOtherDevicesIDsMessageBodyTests.swift deleted file mode 100644 index df0de3fd9..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadOtherDevicesIDsMessageBodyTests.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// ReadOtherDevicesIDsMessageBodyTests.swift -// MinimedKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class ReadOtherDevicesIDsMessageBodyTests: XCTestCase { - - func test0IDs() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a7594040f01f0015036800406001070636036f0040600107062f1dfc004020c107062f0e77000000000000000000000000000000000000000000000000000000000000000000")!) - let body = message?.messageBody as! ReadOtherDevicesIDsMessageBody - - XCTAssertEqual(0, body.ids.count) - } - - func test1IDs() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a7594040f01f0101a21057280000000636036f0040600107062f1dfc004020c107062f0e77000000000000000000000000000000000000000000000000000000000000000000")!) - let body = message?.messageBody as! ReadOtherDevicesIDsMessageBody - - XCTAssertEqual(1, body.ids.count) - XCTAssertEqual("a2105728", body.ids[0].hexadecimalString) - } - - func test2IDs() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a7594040f01f0201a210572800a2016016036f0040600107062f1dfc004020c107062f0e77000000000000000000000000000000000000000000000000000000000000000000")!) - let body = message?.messageBody as! ReadOtherDevicesIDsMessageBody - - XCTAssertEqual(2, body.ids.count) - XCTAssertEqual("a2105728", body.ids[0].hexadecimalString) - XCTAssertEqual("a2016016", body.ids[1].hexadecimalString) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadRemainingInsulinMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadRemainingInsulinMessageBodyTests.swift deleted file mode 100644 index 8ad101eab..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadRemainingInsulinMessageBodyTests.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// ReadRemainingInsulinMessageBodyTests.swift -// RileyLink -// -// Created by Nathan Racklyeft on 5/25/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class ReadRemainingInsulinMessageBodyTests: XCTestCase { - - func testReservoir723() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a7594040730400000ca3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!) - - let body = message?.messageBody as! ReadRemainingInsulinMessageBody - - XCTAssertEqual(80.875, body.getUnitsRemaining(insulinBitPackingScale: PumpModel.model723.insulinBitPackingScale)) - } - - func testReservoir522() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a7578398730205460000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!) - - let body = message?.messageBody as! ReadRemainingInsulinMessageBody - - XCTAssertEqual(135.0, body.getUnitsRemaining(insulinBitPackingScale: PumpModel.model522.insulinBitPackingScale)) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadRemoteControlIDsMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadRemoteControlIDsMessageBodyTests.swift deleted file mode 100644 index 06114cadc..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadRemoteControlIDsMessageBodyTests.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// ReadRemoteControlIDsMessageBodyTests.swift -// MinimedKitTests -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class ReadRemoteControlIDsMessageBodyTests: XCTestCase { - - func testDecodeOneRemote() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a759404076123132333435362d2d2d2d2d2d2d2d2d2d2d2d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!)! - - let body = message.messageBody as! ReadRemoteControlIDsMessageBody - - XCTAssertEqual(1, body.ids.count) - XCTAssertEqual(Data([1, 2, 3, 4, 5, 6]), body.ids[0]) - } - - - func testDecodeZeroRemotes() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a759404076122d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!)! - - let body = message.messageBody as! ReadRemoteControlIDsMessageBody - - XCTAssertEqual(0, body.ids.count) - } - - func testDecodeThreeRemotes() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a7594040761230303030303031303031303039393939393900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!)! - - let body = message.messageBody as! ReadRemoteControlIDsMessageBody - - XCTAssertEqual(3, body.ids.count) - XCTAssertEqual(Data([0, 0, 0, 0, 0, 0]), body.ids[0]) - XCTAssertEqual(Data([1, 0, 0, 1, 0, 0]), body.ids[1]) - XCTAssertEqual(Data([9, 9, 9, 9, 9, 9]), body.ids[2]) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadTempBasalCarelinkMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadTempBasalCarelinkMessageBodyTests.swift deleted file mode 100644 index cb5c62a98..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Messages/ReadTempBasalCarelinkMessageBodyTests.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// ReadTempBasalCarelinkMessageBodyTests.swift -// Naterade -// -// Created by Nathan Racklyeft on 3/7/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import MinimedKit - - -class ReadTempBasalCarelinkMessageBodyTests: XCTestCase { - - func testReadTempBasal() { - // 06 00 00 00 37 00 17 -> 1.375 U @ 23 min remaining - let message = PumpMessage(rxData: Data(hexadecimalString: "a7123456980600000037001700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!)! - - let body = message.messageBody as! ReadTempBasalCarelinkMessageBody - - XCTAssertEqual(TimeInterval(23 * 60), body.timeRemaining) - XCTAssertEqual(1.375, body.rate) - XCTAssertEqual(ReadTempBasalCarelinkMessageBody.RateType.absolute, body.rateType) - } - - func testReadTempBasalZero() { - // 06 00 00 00 00 00 1d -> 0 U @ 29 min remaining - let message = PumpMessage(rxData: Data(hexadecimalString: "a7123456980600000000001d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!)! - - let body = message.messageBody as! ReadTempBasalCarelinkMessageBody - - XCTAssertEqual(TimeInterval(29 * 60), body.timeRemaining) - XCTAssertEqual(0, body.rate) - XCTAssertEqual(ReadTempBasalCarelinkMessageBody.RateType.absolute, body.rateType) - } - - func testReadHighTempBasalRate() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a7754838980600000550001e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!)! - - let body = message.messageBody as! ReadTempBasalCarelinkMessageBody - - XCTAssertEqual(TimeInterval(30 * 60), body.timeRemaining) - XCTAssertEqual(34, body.rate) - XCTAssertEqual(ReadTempBasalCarelinkMessageBody.RateType.absolute, body.rateType) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/MinimedPacketTests.swift b/Dependencies/MinimedKit/MinimedKitTests/MinimedPacketTests.swift deleted file mode 100644 index bc1cf9cf8..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/MinimedPacketTests.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// MinimedPacketTests.swift -// RileyLink -// -// Created by Pete Schwamb on 2/27/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class MinimedPacketTests: XCTestCase { - - func testDecode4b6b() { - let input = Data(hexadecimalString: "ab2959595965574ab2d31c565748ea54e55a54b5558cd8cd55557194b56357156535ac5659956a55c55555556355555568bc5657255554e55a54b5555555b100")! - let packet = MinimedPacket(encodedData: input) - if let result = packet?.data { - let expectedOutput = Data(hexadecimalString: "a259705504a24117043a0e080b003d3d00015b030105d817790a0f00000300008b1702000e080b0000") - XCTAssertEqual(result, expectedOutput) - } else { - XCTFail("Unable to decode packet data") - } - } - - func testDecode4b6bWithBadData() { - let packet = MinimedPacket(encodedData: Data(hexadecimalString: "0102030405")!) - XCTAssertNil(packet) - } - - func testInvalidCRC() { - let inputWithoutCRC = Data(hexadecimalString: "a259705504a24117043a0e080b003d3d00015b030105d817790a0f00000300008b1702000e080b0000")! - let packet = MinimedPacket(encodedData: Data(inputWithoutCRC.encode4b6b())) - XCTAssertNil(packet) - } - - func testEncode4b6b() { - let input = Data(hexadecimalString: "a259705504a24117043a0e080b003d3d00015b030105d817790a0f00000300008b1702000e080b000071")! - let packet = MinimedPacket(outgoingData: input) - let expectedOutput = Data(hexadecimalString: "ab2959595965574ab2d31c565748ea54e55a54b5558cd8cd55557194b56357156535ac5659956a55c55555556355555568bc5657255554e55a54b5555555b1555000") - XCTAssertEqual(packet.encodedData(), expectedOutput) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/MinimedPumpManagerTests.swift b/Dependencies/MinimedKit/MinimedKitTests/MinimedPumpManagerTests.swift deleted file mode 100644 index 58a555544..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/MinimedPumpManagerTests.swift +++ /dev/null @@ -1,178 +0,0 @@ -// -// MinimedPumpManagerTests.swift -// MinimedKitTests -// -// Created by Pete Schwamb on 5/3/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import XCTest -import RileyLinkBLEKit -@testable import MinimedKit -import LoopKit - -class MinimedPumpManagerTests: XCTestCase { - - var rlProvider: MockRileyLinkProvider! - var mockPumpManagerDelegate: MockPumpManagerDelegate! - var pumpManager: MinimedPumpManager! - - var mockMessageSender: MockPumpMessageSender! - - // Date simulation - private var dateFormatter = ISO8601DateFormatter() - private var simulatedDate: Date = ISO8601DateFormatter().date(from: "2023-01-06T23:45:57Z")! - private var dateSimulationOffset: TimeInterval = 0 - - private func setSimulatedDate(from dateString: String) { - simulatedDate = dateFormatter.date(from: dateString)! - dateSimulationOffset = 0 - } - - private func timeTravel(_ time: TimeInterval) { - dateSimulationOffset += time - } - - private func dateGenerator() -> Date { - return self.simulatedDate + dateSimulationOffset - } - - - override func setUpWithError() throws { - let device = MockRileyLinkDevice() - - rlProvider = MockRileyLinkProvider(devices: [device]) - let rlManagerState = RileyLinkConnectionState(autoConnectIDs: []) - mockMessageSender = MockPumpMessageSender() - let pumpID = "636781" - mockMessageSender.pumpID = pumpID - let state = MinimedPumpManagerState( - isOnboarded: true, - useMySentry: true, - pumpColor: .blue, - pumpID: pumpID, - pumpModel: .model522, - pumpFirmwareVersion: "VER 2.4A1.1", - pumpRegion: .northAmerica, - rileyLinkConnectionState: rlManagerState, - timeZone: .currentFixed, - suspendState: .resumed(Date()), - insulinType: .novolog, - lastTuned: simulatedDate, - lastValidFrequency: nil, - basalSchedule: BasalSchedule(entries: [BasalScheduleEntry(index: 0, timeOffset: 0, rate: 1.0)])) - - var pumpState = state.pumpState - pumpState.awakeUntil = .distantFuture - let pumpOps = MockPumpOps(pumpState: pumpState, pumpSettings: state.pumpSettings, messageSender: mockMessageSender) - - pumpManager = MinimedPumpManager(state: state, rileyLinkDeviceProvider: rlProvider, pumpOps: pumpOps, dateGenerator: dateGenerator) - mockPumpManagerDelegate = MockPumpManagerDelegate() - pumpManager.pumpManagerDelegate = mockPumpManagerDelegate - } - - func testBolusWithInvalidResponse() { - let exp = expectation(description: "enactBolus callback") - pumpManager.enactBolus(units: 2.3, activationType: .manualNoRecommendation) { error in - XCTAssertNotNil(error) - exp.fulfill() - } - waitForExpectations(timeout: 2) - } - - func testBolusWithUncertainResponseIsReported() { - mockMessageSender.responses = [ - .readPumpStatus: [mockMessageSender.makeMockResponse(.readPumpStatus, ReadPumpStatusMessageBody(bolusing: false, suspended: false))], - .bolus: [mockMessageSender.ack], // Second ack missing will cause PumpOpsError.noReponse during second exchange - ] - - let exp = expectation(description: "enactBolus callback") - pumpManager.enactBolus(units: 2.3, activationType: .manualNoRecommendation) { error in - XCTAssertNotNil(error) - exp.fulfill() - } - waitForExpectations(timeout: 2) - - XCTAssertEqual(mockPumpManagerDelegate.reportedPumpEvents.count, 1) - let report = mockPumpManagerDelegate.reportedPumpEvents.first! - XCTAssertEqual(report.events.count, 1) - let event = report.events.first! - XCTAssertEqual(event.type, .bolus) - XCTAssertEqual(event.dose!.deliveredUnits, 2.3) - } - - func testPendingBolusRemovedIfMissingFromHistory() { - - mockMessageSender.responses = [ - .readPumpStatus: [mockMessageSender.makeMockResponse(.readPumpStatus, ReadPumpStatusMessageBody(bolusing: false, suspended: false))], - .bolus: [mockMessageSender.ack, mockMessageSender.ack], - ] - - var exp = expectation(description: "enactBolus callback") - pumpManager.enactBolus(units: 3.2, activationType: .manualNoRecommendation) { error in - XCTAssertNil(error) - exp.fulfill() - } - waitForExpectations(timeout: 2) - - XCTAssertEqual(mockPumpManagerDelegate.reportedPumpEvents.count, 1) - - timeTravel(.minutes(2)) - timeTravel(.seconds(8)) - - // Setup responses for successful history fetch - - mockPumpManagerDelegate.historyFetchStartDate = simulatedDate - - var dateComponents = DateComponents() - dateComponents.calendar = Calendar(identifier: Calendar.Identifier.gregorian) - dateComponents.year = 2023 - dateComponents.month = 1 - dateComponents.day = 6 - dateComponents.hour = 17 - dateComponents.minute = 48 - dateComponents.second = 05 - - - let pumpStatusResponse = mockMessageSender.makeMockResponse(.readPumpStatus, ReadPumpStatusMessageBody(bolusing: false, suspended: false)) - - let historyPageResponsesHex = [ - "0116012f6f094617331a306f094617001601306f09461701010100336f29461733002b740946170016012b740946173300304c0a4617001601304c0a461733002b", - "02600a46170016012b600a4617330a2b650a46170016012b650a4617331c2d6a0a46170016012d6a0a461701010100316a2a4617010101002c6f2a461701010100", - "0334742a4617010404001f772a461733002d790a46170016002d790a46170101010031792a4617010101002c422b4617331c30470b461700160130470b46170101", - "04010033472b461733142b4c0b46170016012b4c0b461733002b510b46170016012b510b4617330e29560b461700160129560b4617331c2c5b0b46170016012c5b", - "050b461733102b650b46170016012b650b4617330e2b6a0b46170016012b6a0b461733122f6f0b46170016012f6f0b461733102b740b46170016012b740b461733", - "060c2b790b46170016012b790b4617330e2b420c46170016012b420c4617330030470c461700160130470c461733182d4c0c46170016012d4c0c4617010707000d", - "07502c4617330022510c461700160022510c4617331a295b0c4617001601295b0c4617010101002e652c4617010101002c6a2c461733162d6f0c46170016012d6f", - "080c461733082c740c46170016012c740c461733002b790c46170016012b790c4617330a30420d461700160130420d4617331a2a470d46170016012a470d461701", - "092525000a482d4617331a2d5b0d46170016012d5b0d461701010100315b2d461733142d650d46170016012d650d4617331a2b6a0d46170016012b6a0d46170101", - "0a01002c6f2d461733182b740d46170016012b740d461733002e790d46170016012e790d461733002d510e46170016012d510e461733042d600e46170016012d60", - "0b0e461733002b650e46170016012b650e461733042d6f0e46170016012d6f0e4617330e2d740e46170016012d740e461733022d790e46170016012d790e461733", - "0c002b420f46170016012b420f461733022e470f46170016012e470f461733040e480f46170016010e480f461733082c4c0f46170016012c4c0f4617330c2b510f", - "0d46170016012b510f46173300295b0f4617001601295b0f461733062d600f46170016012d600f4617330a1f650f46170016011f650f461733002c6a0f46170016", - "0e002c6a0f4617010101002c6f2f4617010202002c742f4617010101002c792f461733082e421046170016012e4210461733022b471046170016012b4710461733", - "0f00204c104617001601204c10461733002a601046170016012a6010461733002074104617001601207410461733002b4c1146170016012b4c11461733002b6011", - "9046170016012b6011461700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000656b" - ] - - let mockHistoryPageResponses = historyPageResponsesHex.map { hex in - mockMessageSender.makeMockResponse(.getHistoryPage, CarelinkLongMessageBody(rxData: Data(hexadecimalString: hex)!)!) - } - - mockMessageSender.responses = [ - .getBattery: [mockMessageSender.makeMockResponse(.getBattery, GetBatteryCarelinkMessageBody(status: .normal, volts: 1.44))], - .readPumpStatus: [pumpStatusResponse, pumpStatusResponse], - .readTime: [mockMessageSender.makeMockResponse(.readTime, ReadTimeCarelinkMessageBody(dateComponents: dateComponents))], - .readRemainingInsulin: [mockMessageSender.makeMockResponse(.readRemainingInsulin, ReadRemainingInsulinMessageBody(reservoirVolume: 115.7, insulinBitPackingScale: PumpModel.model522.insulinBitPackingScale))], - .getHistoryPage: [mockMessageSender.ack, mockHistoryPageResponses.first!], - .pumpAck: Array(mockHistoryPageResponses.dropFirst()) - ] - - exp = expectation(description: "ensureCurrentPumpData callback") - pumpManager.ensureCurrentPumpData { date in - exp.fulfill() - } - - waitForExpectations(timeout: 3) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockPumpManagerDelegate.swift b/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockPumpManagerDelegate.swift deleted file mode 100644 index 9e1813b56..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockPumpManagerDelegate.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// MockPumpManagerDelegate.swift -// MinimedKitTests -// -// Created by Pete Schwamb on 9/5/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -class MockPumpManagerDelegate: PumpManagerDelegate { - - var historyFetchStartDate = Date() - - func pumpManagerBLEHeartbeatDidFire(_ pumpManager: PumpManager) {} - - func pumpManagerMustProvideBLEHeartbeat(_ pumpManager: PumpManager) -> Bool { - return false - } - - func pumpManagerWillDeactivate(_ pumpManager: PumpManager) {} - - func pumpManagerPumpWasReplaced(_ pumpManager: PumpManager) {} - - func pumpManager(_ pumpManager: PumpManager, didUpdatePumpRecordsBasalProfileStartEvents pumpRecordsBasalProfileStartEvents: Bool) {} - - func pumpManager(_ pumpManager: PumpManager, didError error: PumpManagerError) {} - - var reportedPumpEvents: [(events: [NewPumpEvent], lastReconciliation: Date?)] = [] - - func pumpManager(_ pumpManager: PumpManager, hasNewPumpEvents events: [NewPumpEvent], lastReconciliation: Date?, completion: @escaping (Error?) -> Void) { - reportedPumpEvents.append((events: events, lastReconciliation: lastReconciliation)) - completion(nil) - } - - struct MockReservoirValue: ReservoirValue { - let startDate: Date - let unitVolume: Double - } - - func pumpManager(_ pumpManager: PumpManager, didReadReservoirValue units: Double, at date: Date, completion: @escaping (Result<(newValue: ReservoirValue, lastValue: ReservoirValue?, areStoredValuesContinuous: Bool), Error>) -> Void) - { - let reservoirValue = MockReservoirValue(startDate: date, unitVolume: units) - DispatchQueue.main.async { - completion(.success((newValue: reservoirValue, lastValue: nil, areStoredValuesContinuous: true))) - } - } - - func pumpManager(_ pumpManager: PumpManager, didAdjustPumpClockBy adjustment: TimeInterval) {} - - func pumpManagerDidUpdateState(_ pumpManager: PumpManager) {} - - func startDateToFilterNewPumpEvents(for manager: PumpManager) -> Date { - return historyFetchStartDate - } - - var detectedSystemTimeOffset: TimeInterval = 0 - - func deviceManager(_ manager: DeviceManager, logEventForDeviceIdentifier deviceIdentifier: String?, type: DeviceLogEntryType, message: String, completion: ((Error?) -> Void)?) {} - - func pumpManager(_ pumpManager: PumpManager, didUpdate status: PumpManagerStatus, oldStatus: PumpManagerStatus) {} - - func issueAlert(_ alert: Alert) {} - - func retractAlert(identifier: Alert.Identifier) {} - - func doesIssuedAlertExist(identifier: Alert.Identifier, completion: @escaping (Result) -> Void) {} - - func lookupAllUnretracted(managerIdentifier: String, completion: @escaping (Result<[PersistedAlert], Error>) -> Void) {} - - func lookupAllUnacknowledgedUnretracted(managerIdentifier: String, completion: @escaping (Result<[PersistedAlert], Error>) -> Void) {} - - func recordRetractedAlert(_ alert: Alert, at date: Date) {} - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockPumpMessageSender.swift b/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockPumpMessageSender.swift deleted file mode 100644 index 195654715..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockPumpMessageSender.swift +++ /dev/null @@ -1,183 +0,0 @@ -// -// MockPumpMessageSender.swift -// MinimedKitTests -// -// Created by Pete Schwamb on 1/7/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import MinimedKit -import RileyLinkBLEKit - - -class MockPumpMessageSender: PumpMessageSender { - - var pumpID = "636781" - - func listenForPacket(onChannel channel: Int, timeout: TimeInterval) throws -> RileyLinkBLEKit.RFPacket? { - // do nothing - return nil - } - - func getRileyLinkStatistics() throws -> RileyLinkStatistics { - throw PumpOpsError.noResponse(during: "Tests") - } - - func makeMockResponse(_ messageType: MessageType, _ messageBody: MessageBody) -> PumpMessage { - return PumpMessage(packetType: .carelink, address: pumpID, messageType: messageType, messageBody: messageBody) - } - - var ack: PumpMessage { - return PumpMessage(pumpID: pumpID, type: .pumpAck) - } - - func sendAndListen(_ data: Data, repeatCount: Int, timeout: TimeInterval, retryCount: Int) throws -> RFPacket { - guard let decoded = MinimedPacket(encodedData: data), - let messageType = MessageType(rawValue: decoded.data[4]) - else { - throw PumpOpsError.noResponse(during: "Tests") - } - - let response: PumpMessage - - if let responseArray = responses[messageType] { - let numberOfResponsesReceived: Int - - if let someValue = responsesHaveOccured[messageType] { - numberOfResponsesReceived = someValue - } else { - numberOfResponsesReceived = 0 - } - - let nextNumberOfResponsesReceived = numberOfResponsesReceived + 1 - responsesHaveOccured[messageType] = nextNumberOfResponsesReceived - - if responseArray.count <= numberOfResponsesReceived { - throw PumpOpsError.noResponse(during: data) - } - - response = responseArray[numberOfResponsesReceived] - } else { - // .pumpAck from 636781 ? - let packet = MinimedPacket(encodedData: Data(hexadecimalString: "a969a39966b1566555b235")!)! - response = PumpMessage(rxData: packet.data)! - } - - var encoded = MinimedPacket(outgoingData: response.txData).encodedData() - encoded.insert(contentsOf: [0, 0], at: 0) - - guard let rfPacket = RFPacket(rfspyResponse: encoded) else { - throw PumpOpsError.noResponse(during: data) - } - - return rfPacket - } - - func getResponse(to message: PumpMessage, responseType: MessageType, repeatCount: Int, timeout: TimeInterval, retryCount: Int) throws -> T { - - let response = try sendAndListen(message, repeatCount: repeatCount, timeout: timeout, retryCount: retryCount) - - guard response.messageType == responseType, let body = response.messageBody as? T else { - if let body = response.messageBody as? PumpErrorMessageBody { - switch body.errorCode { - case .known(let code): - throw PumpOpsError.pumpError(code) - case .unknown(let code): - throw PumpOpsError.unknownPumpErrorCode(code) - } - } else { - throw PumpOpsError.unexpectedResponse(response, from: message) - } - } - return body - } - - /// Sends a message to the pump, listening for a any known PumpMessage in reply - /// - /// - Parameters: - /// - message: The message to send - /// - repeatCount: The number of times to repeat the message before listening begins - /// - timeout: The length of time to listen for a pump response - /// - retryCount: The number of times to repeat the send & listen sequence - /// - Returns: The message reply - /// - Throws: An error describing a failure in the sending or receiving of a message: - /// - PumpOpsError.couldNotDecode - /// - PumpOpsError.crosstalk - /// - PumpOpsError.deviceError - /// - PumpOpsError.noResponse - /// - PumpOpsError.unknownResponse - func sendAndListen(_ message: PumpMessage, repeatCount: Int, timeout: TimeInterval, retryCount: Int) throws -> PumpMessage { - let rfPacket = try sendAndListenForPacket(message, repeatCount: repeatCount, timeout: timeout, retryCount: retryCount) - - guard let packet = MinimedPacket(encodedData: rfPacket.data) else { - throw PumpOpsError.couldNotDecode(rx: rfPacket.data, during: message) - } - - guard let response = PumpMessage(rxData: packet.data) else { - // Unknown packet type or message type - throw PumpOpsError.unknownResponse(rx: packet.data, during: message) - } - - guard response.address == message.address else { - throw PumpOpsError.crosstalk(response, during: message) - } - - return response - } - - // Send a PumpMessage, and listens for a packet; used by callers who need to see RSSI - /// - Throws: - /// - PumpOpsError.noResponse - /// - PumpOpsError.deviceError - func sendAndListenForPacket(_ message: PumpMessage, repeatCount: Int, timeout: TimeInterval, retryCount: Int) throws -> RFPacket { - let packet: RFPacket? - - do { - packet = try sendAndListen(MinimedPacket(outgoingData: message.txData).encodedData(), repeatCount: repeatCount, timeout: timeout, retryCount: retryCount) - } catch let error as LocalizedError { - throw error - } - - guard let rfPacket = packet else { - throw PumpOpsError.noResponse(during: message) - } - - return rfPacket - } - - func listen(onChannel channel: Int, timeout: TimeInterval) throws -> RFPacket? { - throw PumpOpsError.noResponse(during: "Tests") - } - - func send(_ msg: MinimedKit.PumpMessage) throws { - // Do nothing - } - - func updateRegister(_ address: CC111XRegister, value: UInt8) throws { - throw PumpOpsError.noResponse(during: "Tests") - } - - func resetRadioConfig() throws { - throw PumpOpsError.noResponse(during: "Tests") - } - - func setBaseFrequency(_ frequency: Measurement) throws { - throw PumpOpsError.noResponse(during: "Tests") - } - - var responses = [MessageType: [PumpMessage]]() - - // internal tracking of how many times a response type has been received - private var responsesHaveOccured = [MessageType: Int]() -} - -extension MockPumpMessageSender: PumpOpsSessionDelegate { - func pumpOpsSession(_ session: PumpOpsSession, didChange state: PumpState) { - - } - - func pumpOpsSessionDidChangeRadioConfig(_ session: PumpOpsSession) { - - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockPumpOps.swift b/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockPumpOps.swift deleted file mode 100644 index f6e5c99bd..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockPumpOps.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// MockPumpOps.swift -// MinimedKitTests -// -// Created by Pete Schwamb on 9/5/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import MinimedKit -import RileyLinkBLEKit - -class MockPumpOps: PumpOps, PumpOpsSessionDelegate { - - let queue = DispatchQueue(label: "MockPumpOps") - - var pumpState: PumpState - - var pumpSettings: PumpSettings - - var messageSender: MockPumpMessageSender - - func pumpOpsSession(_ session: MinimedKit.PumpOpsSession, didChange state: MinimedKit.PumpState) { - pumpState = state - } - - func pumpOpsSessionDidChangeRadioConfig(_ session: MinimedKit.PumpOpsSession) { } - - public func runSession(withName name: String, using device: RileyLinkDevice, _ block: @escaping (_ session: PumpOpsSession) -> Void) { - let session = PumpOpsSession(settings: self.pumpSettings, pumpState: self.pumpState, messageSender: messageSender, delegate: self) - queue.async { - block(session) - } - } - - init(pumpState: PumpState, pumpSettings: PumpSettings, messageSender: MockPumpMessageSender = MockPumpMessageSender()) { - self.pumpState = pumpState - self.pumpSettings = pumpSettings - self.messageSender = messageSender - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockRileyLinkDevice.swift b/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockRileyLinkDevice.swift deleted file mode 100644 index 642d4cd6c..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockRileyLinkDevice.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// MockRileyLinkDevice.swift -// MinimedKitTests -// -// Created by Pete Schwamb on 9/5/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import RileyLinkBLEKit -import CoreBluetooth - -class MockRileyLinkDevice: RileyLinkDevice { - var isConnected: Bool = true - - var rlFirmwareDescription: String = "Mock" - - var hasOrangeLinkService: Bool = false - - var hardwareType: RileyLinkHardwareType? = .riley - - var rssi: Int? = nil - - var name: String? = "Mock" - - var deviceURI: String = "rileylink://Mock" - - var peripheralIdentifier: UUID = UUID() - - var peripheralState: CBPeripheralState = .connected - - func readRSSI() {} - - func setCustomName(_ name: String) {} - - func updateBatteryLevel() {} - - func orangeAction(_ command: OrangeLinkCommand) {} - - func setOrangeConfig(_ config: OrangeLinkConfigurationSetting, isOn: Bool) {} - - func orangeWritePwd() {} - - func orangeClose() {} - - func orangeReadSet() {} - - func orangeReadVDC() {} - - func findDevice() {} - - func setDiagnosticeLEDModeForBLEChip(_ mode: RileyLinkLEDMode) {} - - func readDiagnosticLEDModeForBLEChip(completion: @escaping (RileyLinkLEDMode?) -> Void) {} - - func assertOnSessionQueue() {} - - func sessionQueueAsyncAfter(deadline: DispatchTime, execute: @escaping () -> Void) {} - - func runSession(withName name: String, _ block: @escaping (CommandSession) -> Void) { - assertionFailure("MockRileyLinkDevice.runSession should not be called during testing. Use MockPumpOps for communication stubs.") - } - - func getStatus(_ completion: @escaping (RileyLinkDeviceStatus) -> Void) { - completion(RileyLinkDeviceStatus( - lastIdle: Date(), - name: name, - version: rlFirmwareDescription, - ledOn: false, - vibrationOn: false, - voltage: 3.0, - battery: nil, - hasPiezo: false)) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockRileyLinkProvider.swift b/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockRileyLinkProvider.swift deleted file mode 100644 index ca842f2a6..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/Mocks/MockRileyLinkProvider.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// MockRileyLinkProvider.swift -// MinimedKitTests -// -// Created by Pete Schwamb on 9/5/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import RileyLinkBLEKit - -class MockRileyLinkProvider: RileyLinkDeviceProvider { - - init(devices: [RileyLinkDevice]) { - self.devices = devices - } - - var devices: [RileyLinkDevice] - - var delegate: RileyLinkDeviceProviderDelegate? - - var idleListeningState: RileyLinkBluetoothDevice.IdleListeningState = .disabled - - var idleListeningEnabled: Bool = false - - var timerTickEnabled: Bool = false - - var connectingCount: Int = 0 - - func deprioritize(_ device: RileyLinkDevice, completion: (() -> Void)?) { - } - - func assertIdleListening(forcingRestart: Bool) { - } - - func getDevices(_ completion: @escaping ([RileyLinkDevice]) -> Void) { - completion(devices) - } - - func connect(_ device: RileyLinkDevice) { - } - - func disconnect(_ device: RileyLinkDevice) { - } - - func setScanningEnabled(_ enabled: Bool) { - } - - func shouldConnect(to deviceID: String) -> Bool { - return false - } - - var debugDescription: String = "MockRileyLinkProvider" - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/MySentryPumpStatusMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/MySentryPumpStatusMessageBodyTests.swift deleted file mode 100644 index e0b37eed9..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/MySentryPumpStatusMessageBodyTests.swift +++ /dev/null @@ -1,239 +0,0 @@ -// -// MySentryPumpStatusMessageBodyTests.swift -// Naterade -// -// Created by Nathan Racklyeft on 9/6/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class MySentryPumpStatusMessageBodyTests: XCTestCase { - - func testValidPumpStatusMessage() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a2594040042f511727070f09050184850000cd010105b03e0a0a1a009d030000711726000f09050000")!) - - if let message = message { - XCTAssertTrue(message.messageBody is MySentryPumpStatusMessageBody) - } else { - XCTFail("\(String(describing: message)) is nil") - } - } - - func testGlucoseTrendFlat() { - XCTAssertEqual(GlucoseTrend.flat, GlucoseTrend(byte: 0b00000000)) - XCTAssertEqual(GlucoseTrend.flat, GlucoseTrend(byte: 0b11110001)) - XCTAssertEqual(GlucoseTrend.flat, GlucoseTrend(byte: 0b11110001)) - XCTAssertEqual(GlucoseTrend.flat, GlucoseTrend(byte: 0b000)) - XCTAssertEqual(GlucoseTrend.flat, GlucoseTrend(byte: 0x51)) - } - - func testMidnightSensor() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a2594040049c510003310f090501393700025b0101068d262208150034000000700003000f09050000")!)! - - let body = message.messageBody as! MySentryPumpStatusMessageBody - - switch body.glucose { - case .active(glucose: let glucose): - XCTAssertEqual(114, glucose) - default: - XCTFail("\(body.glucose) is not .Active") - } - - switch body.previousGlucose { - case .active(glucose: let glucose): - XCTAssertEqual(110, glucose) - default: - XCTFail("\(body.previousGlucose) is not .Active") - } - - var dateComponents = DateComponents() - dateComponents.calendar = Calendar(identifier: Calendar.Identifier.gregorian) - dateComponents.year = 2015 - dateComponents.month = 9 - dateComponents.day = 5 - dateComponents.hour = 0 - dateComponents.minute = 3 - dateComponents.second = 49 - - XCTAssertEqual(dateComponents, body.pumpDateComponents) - - dateComponents.second = 0 - - XCTAssertEqual(dateComponents, body.glucoseDateComponents) - - XCTAssertEqual(GlucoseTrend.flat, body.glucoseTrend) - } - - func testActiveSensor() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a2594040042f511727070f09050184850000cd010105b03e0a0a1a009d030000711726000f09050000")!)! - - let body = message.messageBody as! MySentryPumpStatusMessageBody - - switch body.glucose { - case .active(glucose: let glucose): - XCTAssertEqual(265, glucose) - default: - XCTFail("\(body.glucose) is not .Active") - } - - switch body.previousGlucose { - case .active(glucose: let glucose): - XCTAssertEqual(267, glucose) - default: - XCTFail("\(body.previousGlucose) is not .Active") - } - - var dateComponents = DateComponents() - dateComponents.calendar = Calendar(identifier: Calendar.Identifier.gregorian) - dateComponents.year = 2015 - dateComponents.month = 9 - dateComponents.day = 5 - dateComponents.hour = 23 - dateComponents.minute = 39 - dateComponents.second = 7 - - XCTAssertEqual(dateComponents, body.pumpDateComponents) - - dateComponents.minute = 38 - dateComponents.second = 0 - - XCTAssertEqual(dateComponents, body.glucoseDateComponents) - - XCTAssertEqual(GlucoseTrend.flat, body.glucoseTrend) - } - - func testSensorEndEmptyReservoir() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a259404004fb511205000f090601050502000004000000ff00ffff0040000000711205000f09060000")!)! - - let body = message.messageBody as! MySentryPumpStatusMessageBody - - switch body.glucose { - case .ended: - break - default: - XCTFail("\(body.glucose) is not .Ended") - } - - switch body.previousGlucose { - case .ended: - break - default: - XCTFail("\(body.previousGlucose) is not .Ended") - } - - var dateComponents = DateComponents() - dateComponents.calendar = Calendar(identifier: Calendar.Identifier.gregorian) - dateComponents.year = 2015 - dateComponents.month = 9 - dateComponents.day = 6 - dateComponents.hour = 18 - dateComponents.minute = 5 - dateComponents.second = 0 - - XCTAssertEqual(dateComponents, body.pumpDateComponents) - XCTAssertEqual(dateComponents, body.glucoseDateComponents) - - XCTAssertEqual(GlucoseTrend.flat, body.glucoseTrend) - } - - func testSensorOffEmptyReservoir() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a259404004ff501219000f09060100000000000400000000000000005e000000720000000000000000")!)! - - let body = message.messageBody as! MySentryPumpStatusMessageBody - - switch body.glucose { - case .off: - break - default: - XCTFail("\(body.glucose) is not .Off") - } - - switch body.previousGlucose { - case .off: - break - default: - XCTFail("\(body.previousGlucose) is not .Off") - } - - var dateComponents = DateComponents() - dateComponents.calendar = Calendar(identifier: Calendar.Identifier.gregorian) - dateComponents.year = 2015 - dateComponents.month = 9 - dateComponents.day = 6 - dateComponents.hour = 18 - dateComponents.minute = 25 - dateComponents.second = 0 - - XCTAssertEqual(dateComponents, body.pumpDateComponents) - XCTAssertNil(body.glucoseDateComponents) - - XCTAssertEqual(GlucoseTrend.flat, body.glucoseTrend) - } - - func testSensorOffEmptyReservoirSuspended() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a25940400401501223000f090601000000000004000000000000000059000000720000000000000000")!)! - - let body = message.messageBody as! MySentryPumpStatusMessageBody - - switch body.glucose { - case .off: - break - default: - XCTFail("\(body.glucose) is not .Off") - } - - switch body.previousGlucose { - case .off: - break - default: - XCTFail("\(body.previousGlucose) is not .Off") - } - - var dateComponents = DateComponents() - dateComponents.calendar = Calendar(identifier: Calendar.Identifier.gregorian) - dateComponents.year = 2015 - dateComponents.month = 9 - dateComponents.day = 6 - dateComponents.hour = 18 - dateComponents.minute = 35 - dateComponents.second = 0 - - XCTAssertEqual(dateComponents, body.pumpDateComponents) - XCTAssertNil(body.glucoseDateComponents) - - XCTAssertEqual(GlucoseTrend.flat, body.glucoseTrend) - } - - func testClockType24Hour() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a295099004b6d5971f1510070a013f3a0002dd020105bd08880825000502000755171e0010070a0000")!)! - - let body = message.messageBody as! MySentryPumpStatusMessageBody - - var dateComponents = DateComponents() - dateComponents.calendar = Calendar(identifier: Calendar.Identifier.gregorian) - dateComponents.year = 2016 - dateComponents.month = 7 - dateComponents.day = 10 - dateComponents.hour = 23 - dateComponents.minute = 31 - dateComponents.second = 21 - - XCTAssertEqual(dateComponents, body.pumpDateComponents) - - var glucoseDateComponents = DateComponents() - glucoseDateComponents.calendar = Calendar(identifier: Calendar.Identifier.gregorian) - glucoseDateComponents.year = 2016 - glucoseDateComponents.month = 7 - glucoseDateComponents.day = 10 - glucoseDateComponents.hour = 23 - glucoseDateComponents.minute = 30 - glucoseDateComponents.second = 0 - - XCTAssertEqual(glucoseDateComponents, body.glucoseDateComponents) - - XCTAssertEqual(ClockType.twentyFourHour, body.clockType) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/NSDataTests.swift b/Dependencies/MinimedKit/MinimedKitTests/NSDataTests.swift deleted file mode 100644 index 3d90dc9e8..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/NSDataTests.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// NSDataTests.swift -// Naterade -// -// Created by Nathan Racklyeft on 9/5/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class NSDataTests: XCTestCase { - - func testInitWithHexadecimalStringEmpty() { - let data = Data(hexadecimalString: "") - XCTAssertEqual(0, data!.count) - } - - func testInitWithHexadecimalStringOdd() { - let data = Data(hexadecimalString: "a") - XCTAssertNil(data) - } - - func testInitWithHexadecimalStringZeros() { - let data = Data(hexadecimalString: "00") - XCTAssertEqual(1, data!.count) - - var bytes = [UInt8](repeating: 1, count: 1) - data?.copyBytes(to: &bytes, count: 1) - XCTAssertEqual(0, bytes[0]) - } - - func testInitWithHexadecimalStringShortData() { - let data = Data(hexadecimalString: "a2594040") - - XCTAssertEqual(4, data!.count) - - var bytes = [UInt8](repeating: 0, count: 4) - data?.copyBytes(to: &bytes, count: 4) - XCTAssertEqual([0xa2, 0x59, 0x40, 0x40], bytes) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/NSDateComponents.swift b/Dependencies/MinimedKit/MinimedKitTests/NSDateComponents.swift deleted file mode 100644 index 78a55ce20..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/NSDateComponents.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// NSDateComponents.swift -// RileyLink -// -// Created by Nathan Racklyeft on 4/9/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - - -extension DateComponents { - - init(gregorianYear year: Int, month: Int, day: Int, hour: Int, minute: Int, second: Int) { - self.init() - - self.calendar = Calendar(identifier: Calendar.Identifier.gregorian) - - self.year = year - self.month = month - self.day = day - self.hour = hour - self.minute = minute - self.second = second - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/NSDateComponentsTests.swift b/Dependencies/MinimedKit/MinimedKitTests/NSDateComponentsTests.swift deleted file mode 100644 index 25276c057..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/NSDateComponentsTests.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// NSDateComponentsTests.swift -// RileyLink -// -// Created by Nate Racklyeft on 6/13/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class NSDateComponentsTests: XCTestCase { - - func testInitWith5BytePumpEventData() { - let input = Data(hexadecimalString: "010018001800440001b8571510")! - let comps = DateComponents(pumpEventData: input, offset: 8) - XCTAssertEqual(2016, comps.year) - XCTAssertEqual(21, comps.day) - XCTAssertEqual(2, comps.month) - XCTAssertEqual(23, comps.hour) - XCTAssertEqual(56, comps.minute) - XCTAssertEqual(1, comps.second) - } - - func testInitWith2BytePumpEventData() { - let input = Data(hexadecimalString: "6e351005112ce9b00a000004f001401903b04b00dd01a4013c")! - let comps = DateComponents(pumpEventData: input, offset: 1, length: 2) - XCTAssertEqual(2016, comps.year) - XCTAssertEqual(21, comps.day) - XCTAssertEqual(2, comps.month) - } - - func testInitWithGlucoseData() { - let input = Data(hexadecimalString: "0bae0a0e")! - let comps = DateComponents(glucoseEventBytes: input) - XCTAssertEqual(2014, comps.year) - XCTAssertEqual(2, comps.month) - XCTAssertEqual(10, comps.day) - XCTAssertEqual(11, comps.hour) - XCTAssertEqual(46, comps.minute) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/NSStringExtensions.swift b/Dependencies/MinimedKit/MinimedKitTests/NSStringExtensions.swift deleted file mode 100644 index 9d75a7e11..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/NSStringExtensions.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// NSStringExtensions.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/18/16. -// Copyright © 2016 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension String { - func leftPadding(toLength: Int, withPad character: Character) -> String { - let newLength = self.count - if newLength < toLength { - return String(repeatElement(character, count: toLength - newLength)) + self - } else { - return String(self[index(startIndex, offsetBy: newLength - toLength)...]) - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/PumpEvents/BolusNormalPumpEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/PumpEvents/BolusNormalPumpEventTests.swift deleted file mode 100644 index 4007c7d5a..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/PumpEvents/BolusNormalPumpEventTests.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// BolusNormalPumpEventTests.swift -// RileyLink -// -// Created by Jaim Zuber on 3/8/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import XCTest - -@testable import MinimedKit - -class BolusNormalPumpEventTests: XCTestCase { - - let data523 = Data(hexadecimalString: "01009000900058008a344b1010")! - - var bolusPumpEvent523: BolusNormalPumpEvent! - - override func setUp() { - super.setUp() - bolusPumpEvent523 = BolusNormalPumpEvent(availableData: data523, pumpModel: PumpModel.model523)! - } - - func test523Year() { - XCTAssertEqual(bolusPumpEvent523.timestamp.year, 2016) - } - - func test523Month() { - XCTAssertEqual(bolusPumpEvent523.timestamp.month, 8) - } - - func test523RawData() { - XCTAssertEqual(bolusPumpEvent523.rawData, data523) - } - - func test523Duration() { - XCTAssertEqual(bolusPumpEvent523.duration, 0.0) - } - - func test523Length() { - XCTAssertEqual(bolusPumpEvent523.length, 13) - } - - func test523Type() { - XCTAssertEqual(bolusPumpEvent523.type, .normal) - } - - func test523UnabsorbedInsulinTotal() { - XCTAssertEqual(bolusPumpEvent523.unabsorbedInsulinTotal, 2.2) - } - - func test523Programmed() { - XCTAssertEqual(bolusPumpEvent523.programmed, 3.6) - } - - func test523Amount() { - XCTAssertEqual(bolusPumpEvent523.amount, 3.6) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/PumpEvents/ResumePumpEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/PumpEvents/ResumePumpEventTests.swift deleted file mode 100644 index 00197c727..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/PumpEvents/ResumePumpEventTests.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// ResumePumpEventTests.swift -// MinimedKitTests -// -// Created by Pete Schwamb on 11/10/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import XCTest - -@testable import MinimedKit - -class ResumePumpEventTests: XCTestCase { - - func testRemotelyTriggeredFlag() { - - let localResume = ResumePumpEvent(availableData: Data(hexadecimalString: "1f20a4e30e0a13")!, pumpModel: .model523)! - XCTAssert(!localResume.wasRemotelyTriggered) - - let remoteResume = ResumePumpEvent(availableData: Data(hexadecimalString: "1f209de40e4a13")!, pumpModel: .model523)! - XCTAssert(remoteResume.wasRemotelyTriggered) - } -} - diff --git a/Dependencies/MinimedKit/MinimedKitTests/PumpModelTests.swift b/Dependencies/MinimedKit/MinimedKitTests/PumpModelTests.swift deleted file mode 100644 index 650045337..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/PumpModelTests.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// PumpModelTests.swift -// RileyLink -// -// Created by Jaim Zuber on 2/24/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class PumpModelTests: XCTestCase { - - func test523AppendsSquareWaveToHistory() { - XCTAssertTrue(PumpModel.model523.appendsSquareWaveToHistoryOnStartOfDelivery) - } - - func test522DoesntAppendSquareWaveToHistory() { - XCTAssertFalse(PumpModel.model522.appendsSquareWaveToHistoryOnStartOfDelivery) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/PumpOpsSynchronousBuildFromFramesTests.swift b/Dependencies/MinimedKit/MinimedKitTests/PumpOpsSynchronousBuildFromFramesTests.swift deleted file mode 100644 index 0b7d42502..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/PumpOpsSynchronousBuildFromFramesTests.swift +++ /dev/null @@ -1,295 +0,0 @@ -// -// PumpOpsSynchronousBuildFromFramesTests.swift -// RileyLink -// -// Created by Jaim Zuber on 3/8/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import XCTest - -@testable import RileyLinkKit -@testable import MinimedKit -@testable import RileyLinkBLEKit - -class PumpOpsSynchronousBuildFromFramesTests: XCTestCase { - - var sut: PumpOpsSession! - var pumpSettings: PumpSettings! - var pumpState: PumpState! - var pumpID: String! - var pumpRegion: PumpRegion! - var pumpModel: PumpModel! - var mockPumpMessageSender: MockPumpMessageSender! - var timeZone: TimeZone! - - override func setUp() { - super.setUp() - - pumpID = "350535" - pumpRegion = .worldWide - pumpModel = PumpModel.model523 - - mockPumpMessageSender = MockPumpMessageSender() - timeZone = TimeZone(secondsFromGMT: 0) - - loadSUT() - } - - func loadSUT() { - pumpSettings = PumpSettings(pumpID: pumpID, pumpRegion: pumpRegion) - pumpState = PumpState() - pumpState.pumpModel = pumpModel - pumpState.awakeUntil = Date(timeIntervalSinceNow: 100) // pump is awake - - sut = PumpOpsSession(settings: pumpSettings, pumpState: pumpState, messageSender: mockPumpMessageSender, delegate: mockPumpMessageSender) - } - - func testErrorIsntThrown() { - mockPumpMessageSender.responses = buildResponsesDictionary() - - assertNoThrow(try _ = sut.getHistoryEvents(since: Date())) - } - - func testUnexpectedResponseThrowsError() { - var responseDictionary = buildResponsesDictionary() - var pumpAckArray = responseDictionary[.getHistoryPage]! - let message = PumpMessage(pumpID: pumpSettings.pumpID, type: .buttonPress) - pumpAckArray.insert(message, at: 0) - responseDictionary[.getHistoryPage]! = pumpAckArray - - mockPumpMessageSender.responses = responseDictionary - - // Didn't receive a .pumpAck short reponse so throw an error - assertThrows(try _ = sut.getHistoryEvents(since: Date())) - } - - func testUnexpectedPumpAckResponseThrowsError() { - var responseDictionary = buildResponsesDictionary() - var pumpAckArray = responseDictionary[.getHistoryPage]! - let message = PumpMessage(pumpID: pumpSettings.pumpID, type: .buttonPress) - pumpAckArray.insert(message, at: 1) - responseDictionary[.getHistoryPage]! = pumpAckArray - - mockPumpMessageSender.responses = responseDictionary - - // Didn't receive a .getHistoryPage as 2nd response so throw an error - assertThrows(try _ = sut.getHistoryEvents(since: Date())) - } - - func test332EventsReturnedUntilOutOrder() { - mockPumpMessageSender.responses = buildResponsesDictionary() - - let date = Date(timeIntervalSince1970: 0) - do { - let (historyEvents, _) = try sut.getHistoryEvents(since: date) - - XCTAssertEqual(historyEvents.count, 334) - } catch { - XCTFail() - } - } - - func testEventsReturnedAfterTime() { - mockPumpMessageSender.responses = buildResponsesDictionary() - timeZone = TimeZone.current - - loadSUT() - - - let date = DateComponents(calendar: Calendar.current, timeZone: pumpState.timeZone, year: 2017, month: 2, day: 11, hour: 0, minute: 0, second: 0).date! - do { - let (historyEvents, _) = try sut.getHistoryEvents(since: date) - - // Ends because we reached event before or at date - XCTAssertEqual(historyEvents.count, 290) - } catch { - XCTFail() - } - } - - func testGMTEventsAreTheSame() { - mockPumpMessageSender.responses = buildResponsesDictionary() - timeZone = TimeZone(secondsFromGMT:0) - - loadSUT() - - let date = DateComponents(calendar: Calendar.current, timeZone: pumpState.timeZone, year: 2017, month: 2, day: 11, hour: 0, minute: 0, second: 0).date! - do { - let (historyEvents, _) = try sut.getHistoryEvents(since: date) - - // Ends because we reached event before or at date - XCTAssertEqual(historyEvents.count, 290) - } catch { - XCTFail() - } - } - - func testEventsReturnedAreAscendingOrder() { - mockPumpMessageSender.responses = buildResponsesDictionary() - - //02/11/2017 @ 12:00am (UTC) - let date = DateComponents(calendar: Calendar.current, timeZone: pumpState.timeZone, year: 2017, month: 2, day: 11, hour: 0, minute: 0, second: 0).date! - do { - let (historyEvents, _) = try sut.getHistoryEvents(since: date) - - var dateCursor = historyEvents[0].date - - historyEvents.forEach { event in - - // Events can be slightly out of order - if ( dateCursor.timeIntervalSince(event.date) > TimeInterval(minutes: 0.2)) { - // But shouldn't be this much - XCTFail("Found out of order event") - } - - dateCursor = event.date - } - } catch { - XCTFail() - } - } - - func buildResponsesDictionary() -> [MessageType : [PumpMessage]] { - - var dictionary = [MessageType : [PumpMessage]]() - - // Build array of Messages for each frame - let frameZeroMessages = buildPumpMessagesFromFrameArray(fetchPageZeroFrames) - let frameOneMessages = buildPumpMessagesFromFrameArray(fetchPageOneFrames) - let frameTwoMessages = buildPumpMessagesFromFrameArray(fetchPageTwoFrames) - let frameThreeMessages = buildPumpMessagesFromFrameArray(fetchPageThreeFrames) - let frameFourMessages = buildPumpMessagesFromFrameArray(fetchPageFourFrames) - - let pumpAckMessage = PumpMessage(pumpID: pumpSettings.pumpID, type: .pumpAck, body: PumpAckMessageBody(rxData: Data(count: 1))!) - - let errorResponseMessage = PumpMessage(pumpID: pumpSettings.pumpID, type: .errorResponse, body: PumpErrorMessageBody(rxData: Data(count: 1))!) - - var getHistoryPageArray = [pumpAckMessage, frameZeroMessages[0]] - getHistoryPageArray.append(contentsOf: [pumpAckMessage, frameOneMessages[0]]) - getHistoryPageArray.append(contentsOf: [pumpAckMessage, frameTwoMessages[0]]) - getHistoryPageArray.append(contentsOf: [pumpAckMessage, frameThreeMessages[0]]) - getHistoryPageArray.append(contentsOf: [pumpAckMessage, frameFourMessages[0]]) - getHistoryPageArray.append(errorResponseMessage) - - // pump will be called twice, normal operation will receive a pumpAck and getHistoryPageMessage - dictionary[.getHistoryPage] = getHistoryPageArray - - var pumpAckArray = Array(frameZeroMessages.suffix(from: 1)) - pumpAckArray.append(contentsOf: Array(frameOneMessages.suffix(from: 1))) - pumpAckArray.append(contentsOf: Array(frameTwoMessages.suffix(from: 1))) - pumpAckArray.append(contentsOf: Array(frameThreeMessages.suffix(from: 1))) - pumpAckArray.append(contentsOf: Array(frameFourMessages.suffix(from: 1))) - // Pump sends more data after we send a .pumpAck - dictionary[.pumpAck] = pumpAckArray - - return dictionary - } - - - func buildPumpMessagesFromFrameArray(_ frameArray: [String]) -> [PumpMessage] { - return frameArray.map { self.buildPumpMessageFromFrame($0) } - } - - func buildPumpMessageFromFrame(_ frame: String) -> PumpMessage { - let frameData = Data(hexadecimalString: frame)! - let getHistoryPageMessageBody = GetHistoryPageCarelinkMessageBody(rxData: frameData)! - let getHistoryPageMessage = PumpMessage(packetType: PacketType.carelink, address: self.pumpID, messageType: .getHistoryPage, messageBody: getHistoryPageMessageBody) - return getHistoryPageMessage - } - - let fetchPageZeroFrames = [ - "01030000001822892c15117b050b8a0c1511180a000300030003018a0c1511330028990d551100160128990d551133001fa30d55110016001fa30d55117b051fa3", - "020d1511180a0033001fb20d55110016011fb20d55113300208a0e5511001601208a0e55117b0520a80e1511180a007b060080101511200e007b07008013151126", - "0310007b08009e1415112915007b000080001611001000070000014635110000006e351105005e00000100000146013c61000a030005000a000000000000010000", - "04000000000000000000005e5e00000000000000007b010080011611020c007b020080041611080d007b0300800616110c100033001e800656110016011e800656", - "05117b031e9e0616110c100033001e9e0856110016011e9e08561133001da80856110016001da80856117b031da80816110c100033001eb20856110016011eb208", - "06561133001d8a0956110016011d8a09561133001d990956110016001d990956117b031d990916110c100033001da30956110016011da309561133001ead095611", - "070016001ead0956117b031ead0916110c10007b0400800a1611140b007b0500800c1611180a007b060080101611200e007b0700801316112610007b08009e1416", - "08112915007b000080001711001000070000014136110000006e361105000000000000000141014164000000000000000000000000000000000000000000000000", - "090000000000000000000000007b010080011711020c007b020080041711080d007b0300800617110c10007b0400800a1711140b007b0500800c1711180a007b06", - "0a0080101711200e007b0700801317112610007b08009e1417112915007b000080001811001000070000015737110000006e371105000000000000000157015764", - "0b0000000000000000000000000000000000000000000000000000000000000000000000007b010080011811020c007b020080041811080d007b0300800618110c", - "0c100033001d9e0858110016011d9e08581133001dad0858110016001dad0858117b031dad0818110c10007b0400800a1811140b00000000000000000000000000", - "0d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cbf5" - ] - - let fetchPageOneFrames = [ - "016e3011050000000000000005c601821a04444a000000000000000004440000000b000000000000000000000000000000000000007b010080011111020c007b02", - "020080041111080d007b0300800611110c1000010050005000000025a12951117b0400800a1111140b007b0500800c1111180a000100780078000a0032bb2b5111", - "037b060080101111200e007b0700801311112610007b08009e1411112915007b000080001211001000070000021f31110000006e31110500000000000000021f01", - "04573f00c825000000000000000000c800000002000000000000000000000000000000000000007b010080011211020c007b020080041211080d007b0300800612", - "05110c10007b0400800a1211140b007b0500800c1211180a007b060080101211200e007b0700801312112610007b08009e1412112915007b000080001311001000", - "06070000015732110000006e3211050000000000000001570157640000000000000000000000000000000000000000000000000000000000000000000000007b01", - "070080011311020c007b020080041311080d007b0300800613110c10007b0400800a1311140b007b0500800c1311180a007b060080101311200e007b0700801313", - "08112610007b08009e1413112915007b000080001411001000070000015733110000006e3311050000000000000001570157640000000000000000000000000000", - "09000000000000000000000000000000000000000000007b010080011411020c007b020080041411080d00346417b70514117b0300800614110c10007b0400800a", - "0a1411140b007b0500800c1411180a007b060080101411200e0033002a931254110016012a931254117b062ab1121411200e007b0700801314112610007b08009e", - "0b1414112915003432198b1514117b000080001511001000070000015034110000006e341105000000000000000150015064000000000000000000000000000000", - "0c0000000000000000000000000000000000000000007b010080011511020c007b020080041511080d007b0300800615110c1000330021a206551100160121a206", - "0d5511330026a706551100160026a70655117b0326a70615110c1000330021bb06551100160121bb0655113300248407551100160024840755117b032584071511", - "0e0c1000330021a708551100160121a7085511330021b108551100160021b10855117b0321b10815110c1000330021bb08551100160121bb085511330020930955", - "0f110016012093095511330022a709551100160122a7095511330021ac09551100160021ac0955117b0322ac0915110c10007b0400800a1511140b000a5e06a32b", - "9015115b5e0ea30b7511055000b4555a00000a000000000a8c01000a000a0000000ea32b75117b0500800c1511180a00210030880c151100000000000000004e9d" - ] - - let fetchPageTwoFrames = [ - "016e2d110500000000000000016c016c640000000000000000000000000000000000000000000000000000000000000000000000007b010080010e11020c007b02", - "020080040e11080d007b030080060e110c10007b0400800a0e11140b0033531c840a4e110016011c840a4e1133001d890a4e110016001d890a4e117b041e890a0e", - "0311140b00334a1d930a4e110016011d930a4e1133001c980a4e110016001c980a4e117b041d980a0e11140b007b0500800c0e11180a007b060080100e11200e00", - "047b070080130e112610007b08009e140e112915007b000080000f1100100007000001632e110000006e2e11050000000000000001630163640000000000000000", - "05000000000000000000000000000000000000000000000000000000007b010080010f11020c007b020080040f11080d007b030080060f110c10007b0400800a0f", - "0611140b007b0500800c0f11180a00330017ae0c4f1100160117ae0c4f117b0518900d0f11180a007b060080100f11200e007b070080130f112610007b08009e14", - "070f112915007b00008000101100100007000001522f110000006e2f11050000000000000001520152640000000000000000000000000000000000000000000000", - "08000000000000000000000000007b010080011011020c007b020080041011080d007b0300800610110c100033473bb10950110016013bb109501133003bb60950", - "09110016003bb60950117b033bb60910110c10007b0400800a1011140b000100500050000000228a2a501101005000500050000c8d2a5011330000940a50110016", - "0a0100940a501133003b990a50110016013b990a501101005800580097000ea12a50117b043bb70a1011140b000100500050007d000ea92b5011330020ae0b5011", - "0b00160120ae0b50113338218d0c5011001601218d0c5011335934a60c501100160134a60c50117b0534880d1011180a00010050005000250007932d50110100d0", - "0c00d00071000e982d501101010001000130000ca22d5011330007a90d501100160107a90d501101005000500222000da92d5011330003b90d501100160103b90d", - "0d501133002c800e50110016012c800e501133003a8e0e50110016013a8e0e501133003a930e50110016003a930e50117b053a930e1011180a00330039990e5011", - "0e00160139990e50113300169e0e5011001600169e0e50117b05169e0e1011180a00330000b20e501100160100b20e5011330001b70e501100160001b70e50117b", - "0f0501b70e1011180a0001002800280085000aa12f50110100500050009d001aa62f5011010014001400ce0038b12f50117b060080101011200e007b0700801310", - "90112610007b08009e1410112915007b00008000111100100007000005c63011000000000000000000000000000000000000000000000000000000000000008e53" - ] - - let fetchPageThreeFrames = [ - "017b0700801309112610007b08009e1409112915007b000080000a11001000070000029429110000006e291105000000000000000294015634013e300000000000", - "02000000013e00000003000000000000000000000000000000000000007b010080010a11020c007b020080040a11080d007b030080060a110c10007b0400800a0a", - "0311140b000100c800c80000003abb294a11830106980a0a11010012001200ba00309a2a0a113310229c0a0a11001603229c0a0a117b0423ba0b0a11140b007b05", - "0400800c0a11180a007b060080100a11200e007b070080130a112610007b08009e140a112915007b000080000b1100100007000002392a110000006e2a11050000", - "0500000000000239015f3e00da26000000000000000000da00000002000000000000000000000000000000000000007b010080010b11020c007b020080040b1108", - "060d007b030080060b110c10007b0400800a0b11140b007b0500800c0b11180a00333b348e0d4b11001601348e0d4b1133001c930d4b110016001c930d4b117b05", - "071c930d0b11180a007b060080100b11200e007b070080130b112610007b08009e140b112915007b000080000c11001000070000015a2b110000006e2b11050000", - "080000000000015a015a640000000000000000000000000000000000000000000000000000000000000000000000007b010080010c11020c007b020080040c1108", - "090d007b030080060c110c10007b0400800a0c11140b00335b1dac0a4c110016011dac0a4c1133001db10a4c110016001db10a4c117b041db10a0c11140b003349", - "0a1db60a4c110016011db60a4c1133001ebb0a4c110016001ebb0a4c117b041ebb0a0c11140b007b0500800c0c11180a007b060080100c11200e007b070080130c", - "0b112610007b08009e140c112915007b000080000d1100100007000001632c110000006e2c11050000000000000001630163640000000000000000000000000000", - "0c000000000000000000000000000000000000000000007b010080010d11020c007b020080040d11080d007b030080060d110c100033551d9d084d110016011d9d", - "0d084d1133001ca2084d110016001ca2084d117b031da2080d110c100033531cb6084d110016011cb6084d1133001dbb084d110016001dbb084d117b031dbb080d", - "0e110c100033421d89094d110016011d89094d1133001c8e094d110016001c8e094d117b031c8e090d110c1000334b1d93094d110016011d93094d1133001e9809", - "0f4d110016001e98094d117b031e98090d110c10007b0400800a0d11140b007b0500800c0d11180a007b060080100d11200e007b070080130d112610007b08009e", - "90140d112915007b000080000e11001000070000016c2d110000000000000000000000000000000000000000000000000000000000000000000000000000000a4e" - ] - - let fetchPageFourFrames = [ - "010615036800406001070636036f0040600107062f1dfc004020c107062f0e77004020c107062f0e88004020c107062f0e99004020c107062f0eaa004020c10706", - "022f0ebb004020c107062f0ee1004020c107062f0ef4004020c107062f0f05004020c10706110f12004020c10706150411004040a1070c151f4300010764000f40", - "0300010764001e400001076400024100010717002241000107180000a20c0211070000000001870000006e01870500000000000000000000000000000000000000", - "04000000000000000000000000000000000000000000000000000000000021001a9e0d02112100219f0d0211210031a10d02111a0024b30d02111a0138b30d0211", - "05210028ba0d02112100018a0f0211064202742a8a4f42110c420a8b0f021121000e8b0f02110300000000338b2f02117b05088c0f0211180a007b051b8c0f0211", - "06180a000300030003118c0f021181010e8e0f021100a27b87767d020e8e0f021100a2ce8aa000a27b877600000000000000000000000000000000000000007b06", - "070080100211200e001a002a80100211060303682a807002110c03384000010764003b400001076400214100010717000942000107180000a50703110700000008", - "08221100220c6e2211050000000000000000080008640000000000000000000000000000000000200000000000000000000000000080000000607b0301a5070311", - "090c10000a63258d2903115b632a8d0963110050006e555a00000000000000008c7b0400800a0311140b007b0500800c0311180a007b060080100311200e001a00", - "0a38b21003110603036838b27003110c03174000010764011c4000010717001141000107180000ad0b0811070000007023110125076e2311150063000001000000", - "0b700070640000000000000000000000000000000000500000000000000000636300000080000000387b0400ad0b0811140b007d0208b70b081100a2ce8aa000a2", - "0c7b877600000000000000000000000000000000000000007b0500800c0811180a007b060080100811200e007d0224b710081100a2ce8aa000a27b877600000000", - "0d000000000000000000000000000000007b0700801308112610007b08009e1408112915007b00008000091100100007000000b52811002d0b6e28110500000000", - "0e00000000b500b5640000000000000000000000000000000000d00000000000000000000000000080000000587b010080010911020c007b020080040911080d00", - "0f7b0300800609110c10007b0400800a0911140b007b0500800c0911180a0001011801180000000a812f4911010006000601160030882f091133001d890f491100", - "9016011d890f491133002d8e0f49110016002d8e0f49117b052d8e0f0911180a007b060080100911200e000100200020002a0018963109110000000000000095fb" - ] -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/PumpOpsSynchronousTests.swift b/Dependencies/MinimedKit/MinimedKitTests/PumpOpsSynchronousTests.swift deleted file mode 100644 index 0aebe0549..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/PumpOpsSynchronousTests.swift +++ /dev/null @@ -1,428 +0,0 @@ -// -// PumpOpsSynchronousTests.swift -// RileyLink -// -// Created by Jaim Zuber on 2/21/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import XCTest - -@testable import RileyLinkKit -@testable import MinimedKit -@testable import RileyLinkBLEKit - -class PumpOpsSynchronousTests: XCTestCase { - - var sut: PumpOpsSession! - var pumpSettings: PumpSettings! - var pumpState: PumpState! - var pumpID: String! - var pumpRegion: PumpRegion! - var pumpModel: PumpModel! - var mockMessageSender: MockPumpMessageSender! - - let dateComponents2007 = DateComponents(calendar: Calendar.current, year: 2007, month: 1, day: 1) - let dateComponents2017 = DateComponents(calendar: Calendar.current, year: 2017, month: 1, day: 1) - - let squareBolusDataLength = 26 - - lazy var datePast2007: Date = { - return self.dateComponents2017.date!.addingTimeInterval(TimeInterval(minutes:60)) - }() - - lazy var datePast2017: Date = { - return self.dateComponents2017.date!.addingTimeInterval(TimeInterval(minutes:60)) - }() - - lazy var dateTimestamp2010: DateComponents = { - self.createSquareBolusEvent2010().timestamp - }() - - override func setUp() { - super.setUp() - - pumpID = "636781" - pumpRegion = .worldWide - pumpModel = PumpModel.model523 - - mockMessageSender = MockPumpMessageSender() - - setUpSUT() - } - - /// Creates the System Under Test. This is needed because our SUT has dependencies injected through the constructor - func setUpSUT() { - pumpSettings = PumpSettings(pumpID: pumpID, pumpRegion: pumpRegion) - pumpState = PumpState() - pumpState.pumpModel = pumpModel - pumpState.awakeUntil = Date(timeIntervalSinceNow: 100) // pump is awake - - sut = PumpOpsSession(settings: pumpSettings, pumpState: pumpState, messageSender: mockMessageSender, delegate: mockMessageSender) - } - - /// Duplicates logic in setUp with a new PumpModel - /// - /// - Parameter newPumpModel: model of the pump to test - func setUpTestWithPumpModel(_ newPumpModel: PumpModel) { - pumpModel = newPumpModel - setUpSUT() - } - - var ack: PumpMessage { - return PumpMessage(pumpID: pumpID, type: .pumpAck) - } - - func testSetNormalBolus() { - - mockMessageSender.responses = [ - .readPumpStatus: [mockMessageSender.makeMockResponse(.readPumpStatus, ReadPumpStatusMessageBody(bolusing: false, suspended: false))], - .bolus: [ack, ack], - ] - - let result = sut.setNormalBolus(units: 1) - - XCTAssertNil(result) - } - - func testSetNormalBolusWhileBolusing() { - - mockMessageSender.responses = [ - .readPumpStatus: [mockMessageSender.makeMockResponse(.readPumpStatus, ReadPumpStatusMessageBody(bolusing: true, suspended: false))], - .bolus: [ack, ack], - ] - - let result = sut.setNormalBolus(units: 1) - - XCTAssertNotNil(result) - - if case SetBolusError.certain(PumpOpsError.bolusInProgress) = result! { - // pass - } else { - XCTFail("Expected bolus in progress error, got: \(result!)") - } - } - - func testSetNormalBolusWhileSuspended() { - - mockMessageSender.responses = [ - .readPumpStatus: [mockMessageSender.makeMockResponse(.readPumpStatus, ReadPumpStatusMessageBody(bolusing: false, suspended: true))], - .bolus: [ack, ack], - ] - - let result = sut.setNormalBolus(units: 1) - - XCTAssertNotNil(result) - - if case SetBolusError.certain(PumpOpsError.pumpSuspended) = result! { - // pass - } else { - XCTFail("Expected pump suspended error, got: \(result!)") - } - } - - func testSetNormalBolusUncertain() { - mockMessageSender.responses = [ - .readPumpStatus: [mockMessageSender.makeMockResponse(.readPumpStatus, ReadPumpStatusMessageBody(bolusing: false, suspended: false))], - .bolus: [ack], // Second ack missing will cause PumpOpsError.noReponse during second exchange - ] - - let result = sut.setNormalBolus(units: 1) - - XCTAssertNotNil(result) - - switch result { - case .uncertain: - break - default: - XCTFail("Expected pump suspended error, got: \(result!)") - } - } - - func testShouldContinueIfTimestampBeforeStartDateNotEncountered() { - let page = HistoryPage(events: [createBatteryEvent()]) - - let (_, hasMoreEvents, _) = page.timestampedEvents(after: .distantPast, timeZone: pumpState.timeZone, model: pumpModel) - - XCTAssertTrue(hasMoreEvents) - } - - func testShouldFinishIfTimestampBeforeStartDateEncountered() { - let batteryEvent = createBatteryEvent() - let page = HistoryPage(events: [batteryEvent]) - - let afterBatteryEventDate = batteryEvent.timestamp.date!.addingTimeInterval(TimeInterval(hours: 10)) - - let (_, hasMoreEvents, _) = page.timestampedEvents(after: afterBatteryEventDate, timeZone: pumpState.timeZone, model: pumpModel) - - XCTAssertFalse(hasMoreEvents) - } - - func testEventsAfterStartDateAreReturned() { - let batteryEvent2007 = createBatteryEvent(withDateComponent: dateComponents2007) - let batteryEvent2017 = createBatteryEvent(withDateComponent: dateComponents2017) - let page = HistoryPage(events: [batteryEvent2007, batteryEvent2017]) - - let (events, _, _) = page.timestampedEvents(after: .distantPast, timeZone: pumpState.timeZone, model: pumpModel) - - XCTAssertEqual(events.count, 2) - } - - func testEventBeforeStartDateIsFiltered() { - let datePast2007 = dateComponents2007.date!.addingTimeInterval(TimeInterval(minutes: 60)) - - let batteryEvent2007 = createBatteryEvent(withDateComponent: dateComponents2007) - let batteryEvent2017 = createBatteryEvent(withDateComponent: dateComponents2017) - let page = HistoryPage(events: [batteryEvent2007, batteryEvent2017]) - - let (events, hasMoreEvents, cancelled) = page.timestampedEvents(after: datePast2007, timeZone: pumpState.timeZone, model: pumpModel) - - assertArray(events, doesntContainPumpEvent: batteryEvent2007) - XCTAssertEqual(events.count, 1) - XCTAssertFalse(hasMoreEvents) - XCTAssertFalse(cancelled) - } - - func testPumpLostTimeCancelsFetchEarly() { - let batteryEvent2007 = createBatteryEvent(withDateComponent: dateComponents2007) - let batteryEvent2017 = createBatteryEvent(withDateComponent: dateComponents2017) - let page = HistoryPage(events: [batteryEvent2017, batteryEvent2007]) - - let (events, hasMoreEvents, cancelledEarly) = page.timestampedEvents(after: Date.distantPast, timeZone: pumpState.timeZone, model: pumpModel) - - XCTAssertTrue(cancelledEarly) - XCTAssertFalse(hasMoreEvents) - XCTAssertEqual(events.count, 1) - assertArray(events, doesntContainPumpEvent: batteryEvent2017) - } - - func testEventsWithSameDataArentAddedTwice() { - let page = HistoryPage(events: [createBolusEvent2009(), createBolusEvent2009()]) - let (events, _, _) = page.timestampedEvents(after: Date.distantPast, timeZone: pumpState.timeZone, model: pumpModel) - XCTAssertEqual(events.count, 1) - } - - func testNonMutableSquareWaveBolusFor522IsReturned() { - // device that can have out of order events - setUpTestWithPumpModel(.model522) - // 2009-07-31 09:00:00 +0000 - // 120 minute duration - let squareWaveBolus = BolusNormalPumpEvent(availableData: Data(hexadecimalString: "010080048000240009a24a1510")!, pumpModel: pumpModel)! - - let page = HistoryPage(events: [squareWaveBolus]) - - let (timeStampedEvents, _, _) = page.timestampedEvents(after: .distantPast, timeZone: pumpState.timeZone, model: pumpModel) - - // It should be included - XCTAssertTrue(array(timeStampedEvents, containsPumpEvent: squareWaveBolus)) - } - - // This sets up a square wave bolus that has a timestamp four hours before a temp basal, but is appended to history - // "after" the temp basal. This is an important condition to test, because the temp basal could be filtered out erroneously - // if we were just filtering on startDate, and startDate was after the bolus timestamp, but before the temp basal. - // Previously, convertPumpEventToTimestampedEvents was being called with startDate: Date.distantPast - // Changing it to use a time in that important window to cover - func testDelayedAppendEventDoesNotCauseValidEventsToBeFilteredOut() { - setUpTestWithPumpModel(.model522) - - let tempEventBasal = createTempEventBasal2016() - let dateComponents = tempEventBasal.timestamp.addingTimeInterval(TimeInterval(hours:-4)) - let squareBolusEventFourHoursBefore = createSquareBolusEvent(dateComponents: dateComponents) - - let page = HistoryPage(events: [tempEventBasal, squareBolusEventFourHoursBefore]) - let (timeStampedEvents, hasMoreEvents, cancelled) = page.timestampedEvents(after: .distantPast, timeZone: pumpState.timeZone, model: pumpModel) - - // Debatable (undefined) whether this should be returned. It is tested to avoid inadvertantly changing behavior - assertArray(timeStampedEvents, containsPumpEvent: squareBolusEventFourHoursBefore) - XCTAssertTrue(hasMoreEvents) - XCTAssertFalse(cancelled) - } - - // MARK: Regular Bolus Event before starttime (offset 9 minutes) - func test522RegularBolusEventBeforeStartTimeShouldNotCancel() { - setUpTestWithPumpModel(.model522) - - let pumpEvent = createSquareBolusEvent2010() - let page = HistoryPage(events: [pumpEvent]) - - let startDate = pumpEvent.timestamp.date!.addingTimeInterval(TimeInterval(minutes:9)) - - let (timestampedEvents, hasMoreEvents, cancelled) = page.timestampedEvents(after: startDate, timeZone: pumpState.timeZone, model: pumpModel) - - assertArray(timestampedEvents, containsPumpEvent: pumpEvent) - //We found an event before the start time but we can't verify the timestamp from the Square Bolus so there could be more valid events - XCTAssertTrue(hasMoreEvents) - XCTAssertFalse(cancelled) - } - - // The test the border condition sof the pump lost time detection, the main behavior of which is covered - // in testPumpLostTimeCancelsFetchEarly. The precise point at which we decide pump time is lost (the one hour mark) is aribtrary. - - func testOutOfOrderEventUnderAnHourDoesntCancel() { - setUpTestWithPumpModel(.model523) - - let after2007Date = dateComponents2007.date!.addingTimeInterval(TimeInterval(minutes:59)) - - let batteryEvent = createBatteryEvent(withDateComponent: dateComponents2007) - let laterBatteryEvent = createBatteryEvent(atTime: after2007Date) - - let page = HistoryPage(events: [laterBatteryEvent, batteryEvent]) - - let (_, _, cancelled) = page.timestampedEvents(after: .distantPast, timeZone: pumpState.timeZone, model: pumpModel) - - XCTAssertFalse(cancelled) - } - - // MARK: Test Sanity Checks - func test2010EventSanityWith523() { - setUpTestWithPumpModel(.model523) - let bolusEvent = createSquareBolusEvent2010() - XCTAssertEqual(bolusEvent.timestamp.year!, 2010) - XCTAssertEqual(bolusEvent.timestamp.timeZone, pumpState.timeZone) - } - - func test2009EventSanityWith523() { - setUpTestWithPumpModel(.model523) - let bolusEvent = createBolusEvent2009() - XCTAssertEqual(bolusEvent.timestamp.year!, 2009) - XCTAssertEqual(bolusEvent.timestamp.timeZone, pumpState.timeZone) - } - - func test2009EventSavityWith522() { - setUpTestWithPumpModel(.model522) - XCTAssertEqual(createBolusEvent2009().timestamp.year!, 2009) - } - - func test2010EventSanityWith522() { - setUpTestWithPumpModel(.model522) - XCTAssertEqual(createSquareBolusEvent2010().timestamp.year!, 2010) - } - - func createBatteryEvent(withDateComponent dateComponents: DateComponents) -> BatteryPumpEvent { - return createBatteryEvent(atTime: dateComponents.date!) - } - - func createBatteryEvent(atTime date: Date = Date()) -> BatteryPumpEvent { - - let calendar = Calendar.current - - let year = calendar.component(.year, from: date) - 2000 - let month = calendar.component(.month, from: date) - let day = calendar.component(.day, from: date) - let hour = calendar.component(.hour, from: date) - let minute = calendar.component(.minute, from: date) - let second = calendar.component(.second, from: date) - - let secondByte = UInt8(second) & 0b00111111 - let minuteByte = UInt8(minute) & 0b00111111 - let hourByte = UInt8(hour) & 0b00011111 - let dayByte = UInt8(day) & 0b00011111 - let monthUpperComponent = (UInt8(month) & 0b00001100) << 4 - let monthLowerComponent = (UInt8(month) & 0b00000011) << 6 - let secondMonthByte = secondByte | monthUpperComponent - let minuteMonthByte = minuteByte | monthLowerComponent - let yearByte = UInt8(year) & 0b01111111 - - let batteryData = Data([0,0, secondMonthByte, minuteMonthByte, hourByte, dayByte, yearByte]) - let batteryPumpEvent = BatteryPumpEvent(availableData: batteryData, pumpModel: PumpModel.model523)! - return batteryPumpEvent - } - - func createSquareBolusEvent2010() -> BolusNormalPumpEvent { - //2010-08-01 05:00:16 +000 - let dateComponents = DateComponents(calendar: Calendar.current, timeZone: pumpState.timeZone, year: 2010, month: 8, day: 1, hour: 5, minute: 0, second: 16) - let data = Data(hexadecimalString: "01009000900058008a344b1010")! - return BolusNormalPumpEvent(length: BolusNormalPumpEvent.calculateLength(pumpModel.larger), rawData: data, timestamp: dateComponents, unabsorbedInsulinRecord: nil, amount: 0.0, programmed: 0.0, unabsorbedInsulinTotal: 0.0, type: .square, duration: TimeInterval(minutes: 120), wasRemotelyTriggered: false) - } - - func createSquareBolusEvent(dateComponents: DateComponents) -> BolusNormalPumpEvent { - let data = Data(hexadecimalString: randomDataString(length: squareBolusDataLength))! - return BolusNormalPumpEvent(length: BolusNormalPumpEvent.calculateLength(pumpModel.larger), rawData: data, timestamp: dateComponents, unabsorbedInsulinRecord: nil, amount: 0.0, programmed: 0.0, unabsorbedInsulinTotal: 0.0, type: .square, duration: TimeInterval(hours: 8), wasRemotelyTriggered: false) - } - - func createBolusEvent2011() -> BolusNormalPumpEvent { - //2010-08-01 05:00:11 +000 - let dateComponents = DateComponents(calendar: Calendar.current, timeZone: pumpState.timeZone, year: 2011, month: 8, day: 1, hour: 5, minute: 0, second: 16) - let data = Data(hexadecimalString: "01009000900058008a344b10FF")! - return BolusNormalPumpEvent(length: BolusNormalPumpEvent.calculateLength(pumpModel.larger), rawData: data, timestamp: dateComponents, unabsorbedInsulinRecord: nil, amount: 0.0, programmed: 0.0, unabsorbedInsulinTotal: 0.0, type: .normal, duration: TimeInterval(minutes: 120), wasRemotelyTriggered: false) - } - - func createTempEventBasal2016() -> TempBasalPumpEvent { - // 2016-05-30 01:21:00 +0000 - let tempEventBasal = TempBasalPumpEvent(availableData: Data(hexadecimalString:"338c4055145d1000")!, pumpModel: pumpModel)! - return tempEventBasal - } - - func createBolusEvent2009() -> BolusNormalPumpEvent { - - let dateComponents = DateComponents(calendar: Calendar.current, timeZone: pumpState.timeZone, year: 2009, month: 7, day: 31, hour: 9, minute: 0, second: 0) - let timeInterval: TimeInterval = TimeInterval(minutes: 2) - let data = Data(hexadecimalString:"338c4055145d2000")! - - return BolusNormalPumpEvent(length: 13, rawData: data, timestamp: dateComponents, unabsorbedInsulinRecord: nil, amount: 2.0, programmed: 1.0, unabsorbedInsulinTotal: 0.0, type: .normal, duration: timeInterval, wasRemotelyTriggered: false) - } - - func createNonDelayedEvent2009() -> BolusReminderPumpEvent { - let dateComponents = DateComponents(calendar: Calendar.current, timeZone: pumpState.timeZone, year: 2009, month: 7, day: 31, hour: 9, minute: 0, second: 0) - let data = Data(hexadecimalString:"338c48FFF45d2000")! - let length = 7 - - return BolusReminderPumpEvent(length: length, rawData: data, timestamp: dateComponents) - } -} - -// from comment at https://gist.github.com/szhernovoy/276e69eb90a0de84dd90 -func randomDataString(length:Int) -> String { - let charSet = "abcdef0123456789" - let c = charSet.map { String($0) } - var s:String = "" - for _ in 0.. Bool { - let event = timestampedEvents.first { $0.pumpEvent.rawData == pumpEvent.rawData } - - return event != nil -} - -func assertArray(_ timestampedEvents: [TimestampedHistoryEvent], containsPumpEvent pumpEvent: PumpEvent) { - XCTAssertNotNil(timestampedEvents.first { $0.pumpEvent.rawData == pumpEvent.rawData}) -} - -func assertArray(_ timestampedEvents: [TimestampedHistoryEvent], containsPumpEvents pumpEvents: [PumpEvent]) { - pumpEvents.forEach { assertArray(timestampedEvents, containsPumpEvent: $0) } -} - -func assertArray(_ timestampedEvents: [TimestampedHistoryEvent], doesntContainPumpEvent pumpEvent: PumpEvent) { - XCTAssertNil(timestampedEvents.first { $0.pumpEvent.rawData == pumpEvent.rawData }) -} - -// from http://jernejstrasner.com/2015/07/08/testing-throwable-methods-in-swift-2.html - transferred to Swift 3 -func assertThrows(_ expression: @autoclosure () throws -> T, _ message: String = "", file: StaticString = #file, line: UInt = #line) { - do { - let _ = try expression() - XCTFail("No error to catch! - \(message)", file: file, line: line) - } catch { - } -} - -func assertNoThrow(_ expression: @autoclosure () throws -> T, _ message: String = "", file: StaticString = #file, line: UInt = #line) { - do { - let _ = try expression() - } catch let error { - XCTFail("Caught error: \(error) - \(message)", file: file, line: line) - } -} - -extension DateComponents { - func addingTimeInterval(_ timeInterval: TimeInterval) -> DateComponents { - let newDate = self.date!.addingTimeInterval(timeInterval) - let newDateComponents = Calendar.current.dateComponents(in: TimeZone.currentFixed, from: newDate) - return newDateComponents - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/ReadSettingsCarelinkMessageBodyTests.swift b/Dependencies/MinimedKit/MinimedKitTests/ReadSettingsCarelinkMessageBodyTests.swift deleted file mode 100644 index 4c1934551..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/ReadSettingsCarelinkMessageBodyTests.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// ReadSettingsCarelinkMessageBodyTests.swift -// Naterade -// -// Created by Nathan Racklyeft on 12/26/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class ReadSettingsCarelinkMessageBodyTests: XCTestCase { - - func testValidSettings() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a7594040c01900010001010096008c00000000000064010400140019010101000000000000000000000000000000000000000000000000000000000000000000000000000000")!) - - if let message = message { - XCTAssertTrue(message.messageBody is ReadSettingsCarelinkMessageBody) - - if let body = message.messageBody as? ReadSettingsCarelinkMessageBody { - XCTAssertEqual(3.5, body.maxBasal) - XCTAssertEqual(15, body.maxBolus) - XCTAssertEqual(BasalProfile.standard, body.selectedBasalProfile) - XCTAssertEqual(4, body.insulinActionCurveHours) - } - - } else { - XCTFail("Message is nil") - } - } - - func testValidSettings523() { - let message = PumpMessage(rxData: Data(hexadecimalString: "a7754838c0150003010100e505500000000000000164000400140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!) - - if let message = message { - XCTAssertTrue(message.messageBody is ReadSettingsCarelinkMessageBody) - - if let body = message.messageBody as? ReadSettingsCarelinkMessageBody { - XCTAssertEqual(34, body.maxBasal) - XCTAssertEqual(22.9, body.maxBolus) - XCTAssertEqual(BasalProfile.standard, body.selectedBasalProfile) - XCTAssertEqual(4, body.insulinActionCurveHours) - } - - } else { - XCTFail("Message is nil") - } - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/ReconciliationTests.swift b/Dependencies/MinimedKit/MinimedKitTests/ReconciliationTests.swift deleted file mode 100644 index b5c9faa2d..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/ReconciliationTests.swift +++ /dev/null @@ -1,134 +0,0 @@ -// -// ReconciliationTests.swift -// MinimedKitTests -// -// Created by Pete Schwamb on 9/5/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import XCTest -import RileyLinkBLEKit -@testable import MinimedKit -import LoopKit - -extension DateFormatter { - static var descriptionFormatter: DateFormatter { - let formatter = self.init() - formatter.dateFormat = "yyyy-MM-dd HH:mm:ssZZZZZ" - - return formatter - } -} - - -final class ReconciliationTests: XCTestCase { - - let testingDateFormatter = DateFormatter.descriptionFormatter - - func testingDate(_ input: String) -> Date { - return testingDateFormatter.date(from: input)! - } - - func testPendingDoseUpdatesWithActualDeliveryFromHistoryDose() { - - let bolusTime = Date().addingTimeInterval(-TimeInterval(minutes: 5)); - - let bolusEventTime = bolusTime.addingTimeInterval(2) - - let cancelTime = bolusEventTime.addingTimeInterval(TimeInterval(minutes: 1)) - - let unfinalizedBolus = UnfinalizedDose(bolusAmount: 5.4, startTime: bolusTime, duration: TimeInterval(200), insulinType: .novolog, automatic: false, isReconciledWithHistory: false) - - // 5.4 bolus interrupted at 1.0 units - let eventDose = DoseEntry(type: .bolus, startDate: bolusEventTime, endDate: cancelTime, value: unfinalizedBolus.units, unit: .units, deliveredUnits: 1.0) - - let bolusEvent = NewPumpEvent( - date: bolusEventTime, - dose: eventDose, - raw: Data(hexadecimalString: "abcdef")!, - title: "Test Bolus", - type: .bolus) - - let result = MinimedPumpManager.reconcilePendingDosesWith([bolusEvent], reconciliationMappings: [:], pendingDoses: [unfinalizedBolus]) - - // Should mark pending bolus as reconciled - XCTAssertEqual(1, result.pendingDoses.count) - let pendingBolus = result.pendingDoses.first! - XCTAssertEqual(true, pendingBolus.isReconciledWithHistory) - - // Pending bolus should be updated with actual delivery amount - XCTAssertEqual(1.0, pendingBolus.units) - XCTAssertEqual(5.4, pendingBolus.programmedUnits) - XCTAssertEqual(TimeInterval(minutes: 1), pendingBolus.duration) - XCTAssertEqual(true, pendingBolus.isFinished) - } - - func testReconciledDosesShouldOnlyAppearInReturnedPendingDoses() { - - let bolusTime = Date().addingTimeInterval(-TimeInterval(minutes: 5)); - - // Shows up in history 2 seconds later - let bolusEventTime = bolusTime.addingTimeInterval(2) - - let bolusAmount = 1.5 - - let bolusDuration = PumpModel.model523.bolusDeliveryTime(units: bolusAmount) - - let unfinalizedBolus = UnfinalizedDose(bolusAmount: bolusAmount, startTime: bolusTime, duration: bolusDuration, insulinType: .novolog, automatic: false, isReconciledWithHistory: false) - - let eventDose = DoseEntry(type: .bolus, startDate: bolusEventTime, endDate: bolusEventTime.addingTimeInterval(bolusDuration), value: bolusAmount, unit: .units, deliveredUnits: bolusAmount) - - let bolusEvent = NewPumpEvent( - date: bolusEventTime, - dose: eventDose, - raw: Data(hexadecimalString: "abcdef")!, - title: "Test Bolus", - type: .bolus) - - let result = MinimedPumpManager.reconcilePendingDosesWith([bolusEvent], reconciliationMappings: [:], pendingDoses: [unfinalizedBolus]) - - // Should mark pending bolus as reconciled - XCTAssertEqual(1, result.pendingDoses.count) - let pendingBolus = result.pendingDoses.first! - XCTAssertEqual(true, pendingBolus.isReconciledWithHistory) - - XCTAssertEqual(1, result.reconciliationMappings.count) - XCTAssertEqual(unfinalizedBolus.uuid, result.reconciliationMappings[bolusEvent.raw]?.uuid) - XCTAssertEqual(unfinalizedBolus.startTime, result.reconciliationMappings[bolusEvent.raw]?.startTime) - - // Bolus should not be returned as history event - XCTAssert(result.remainingEvents.isEmpty) - } - - func testReconciledDosesShouldNotAppearInReturnedPumpEvents() { - - let bolusTime = Date().addingTimeInterval(-TimeInterval(minutes: 5)); - - // Shows up in history 2 seconds later - let bolusEventTime = bolusTime.addingTimeInterval(2) - - let bolusAmount = 1.5 - - let bolusDuration = PumpModel.model523.bolusDeliveryTime(units: bolusAmount) - - let eventDose = DoseEntry(type: .bolus, startDate: bolusEventTime, endDate: bolusEventTime.addingTimeInterval(bolusDuration), value: bolusAmount, unit: .units, deliveredUnits: bolusAmount) - - let bolusEvent = NewPumpEvent( - date: bolusEventTime, - dose: eventDose, - raw: Data(hexadecimalString: "abcdef")!, - title: "Test Bolus", - type: .bolus) - - - - let reconciliationMappings: [Data:ReconciledDoseMapping] = [ - bolusEvent.raw : ReconciledDoseMapping(startTime: bolusTime, uuid: UUID(), eventRaw: bolusEvent.raw) - ] - - let result = MinimedPumpManager.reconcilePendingDosesWith([bolusEvent], reconciliationMappings: reconciliationMappings, pendingDoses: []) - - // Bolus should not be returned as history event - XCTAssert(result.remainingEvents.isEmpty) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitTests/TimestampedHistoryEventTests.swift b/Dependencies/MinimedKit/MinimedKitTests/TimestampedHistoryEventTests.swift deleted file mode 100644 index 65e1ca911..000000000 --- a/Dependencies/MinimedKit/MinimedKitTests/TimestampedHistoryEventTests.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// TimestampedHistoryEventTests.swift -// RileyLink -// -// Created by Jaim Zuber on 2/24/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import MinimedKit - -class TimestampedHistoryEventTests: XCTestCase { - - - - - let hexData523 = Data(hexadecimalString: "5be409a20a1510325000784b502800a400002400a8965c0b404fc038cbd008d5d0010080008000240009a24a15107b0500800c1510180a000ade19a32c15105bde2ba30c1510325000b44b5024006c0000200070965c0b4c78c03482c040c8c001007000700020002ba34c15100a0c22932d75903f2122938d7510c527ad5b0006900f15101a5000b44b500000380000000038965c0e70a1c04c19d03423d04069d00100380038000c0006904f15107b060080101510200e005b0034ab1015100d5000784b500000280000000028965c113858c070f8c04c70d0347ad040c0d00100280028001c0034ab5015100ab005863175903f360586117510c527ad5bb01486111510005100784b50940000000038005c965c14281fc0386fc0700fd04c87d03491d040d7d001005c005c00380014865115105b002291121510285000784b500000840000000084965c145c48c02866c038b6c07056d04cced034d8d0010084008400480022915215107b0700801315102610002100038414151003000000360785341510064a097e009e54b5100c4a03a11415107b0704a11415102610007b0704a11415102610007b0710a1141510261000030003000306a11415100ae937a23475103f1d37a2347510c527ad5be91ea3141510165000784b502c00480000140060965c0e848cc05cd2c028f0c03840d001006000600014001ea35415107b0800801515102a13000a5621ba3515905b5623ba151510005100b455505800000000340024965c116053c084dfc05c25d02843d03893d0010024002400340023ba5515105b00188c161510005000b455500000000000000000965c142411c06061c084edc05c33d02851d038a1d00100180018004c00188c5615100a7339ac3615905b7305ad161510005100b455506800000000480020965c171828c02432c06082c0840ed05c54d02872d038c2d0010034003400440005ad5615100a55158c3775903f2a158cb77510c527ad5b55278c171510005100b455505800000000600000965c1a341bc01843c0244dc0609dc08429d05c6fd0288dd038ddd00100180018006000278c5715100a1930b73715905b1901b8171510005100b455503c00000000440000965c1a1833c03447c0186fc02479c060c9c08455d05c9bd028b9d0010018001800440001b85715107b000080001610000e0007000004f035100000006e351005112ce9b00a000004f001401903b04b00dd01a4013c00d0000005070200040000000000000000de730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fc5e")! - - - let hexData522 = Data(hexadecimalString: "5a0f7050141d10151300080000000000000000000000000000001e1414211e00000000000000000000005f69000000000000000000000000000000000000000000151300080000000000000000000000000000001e14142d1e00000000000000000000005f6900000000000000000000000000000000000000000044338c4055145d100016014055145d10333e445a145d10001601445a145d10335a4464145d100016014464145d10335e4069145d100016014069145d10010a0a004a6b341d10010f0f007979341d10010a0a00484b351d103383445a155d10001601445a155d10333c4369155d100016014369155d10011919006f7a351d10333c4b41165d100016014b41165d10333c4e55165d100016014e55165d10333c486e165d10001601486e165d10331b4c73165d100016014c73165d10333c5f4b175d100016015f4b175d1001080800554d371d10010808006a5d371d10333c6564175d100016016564175d1001050500766a371d10333c4878175d100016014878175d100700000a6a5d906d5d90050c00e8000000000a6a056234050830000005083000000000000005086413000000130c00e800000033394a50005e100016014a50005e1033394864005e100016014864005e1033004969005e100016014969005e1033004878005e100016014878005e1033004155015e100016014155015e103348495f015e10001601495f015e1033394564015e100016014564015e1033484a69015e100016014a69015e1033104c73015e100016014c73015e1033394578015e100016014578015e1033394550025e100016014550025e103314465a025e10001601465a025e1033004a5f025e100016014a5f025e103300456e025e10001601456e025e1033004241035e100016014241035e1033004550035e100016014550035e103300495f035e10001601495f035e103300456e035e10001601456e035e1033394678035e100016014678035e10338c4d46045e100016014d46045e10338c4664045e100016014664045e1033444a41055e100016014a41055e10010404007561281e1033447968085e100016017968085e10334a7972085e100016017972085e1033444478085e100016014478085e1033444250095e100016014250095e1033147954095e100016017954095e103344415a095e10001601415a095e10338c7968095e100016017968095e10011414006e6c291e1033447972095e100016017972095e10335841460a5e1000160141460a5e10010a0a0047492a1e10336841500a5e1000160141500a5e10010a0a006b512a1e103344415a0a5e10001601415a0a5e10330041500b5e1000160141500b5e103300455f0b5e10001601455f0b5e103346416e0b5e10001601416e0b5e10334641460c5e100000000000005a49")! - var historyPage523: HistoryPage! - var historyPage522: HistoryPage! - - - override func setUp() { - super.setUp() - - historyPage523 = try! HistoryPage(pageData: hexData523, pumpModel: PumpModel.model523) - historyPage522 = try! HistoryPage(pageData: hexData522, pumpModel: PumpModel.model522) - } - - func test523EventIsMutable() { - - let bolusEvent = getNormalBolusEvent() - let timeStampDate = bolusEvent.timestamp.date! - let dateToCheck = timeStampDate.addingTimeInterval(bolusEvent.deliveryTime/2) // within the delivery time - - let sut = TimestampedHistoryEvent(pumpEvent: bolusEvent, date: timeStampDate) - - // normal boluses on x23 are *not* mutable; they are just delayed append. Only square wave boluses are mutable - XCTAssertFalse(bolusEvent.isMutable(atDate: dateToCheck, forPump: .model523)) - - } - - func testBolusOnX22() { - let bolus = BolusNormalPumpEvent(availableData: Data(hexadecimalString: "567901e443494eda97dbfd38150216f3")!, pumpModel: .model522)! - XCTAssertEqual(bolus.wasRemotelyTriggered, true) - } - - func testSquareWaveIsMutableOnX23() { - let squareBolus = BolusNormalPumpEvent(availableData: Data(hexadecimalString: "010080008000240209a24a1510")!, pumpModel: .model523)! - let squareBolusTimestamp = squareBolus.timestamp.date! - let dateToCheckForSquareBolus = squareBolusTimestamp.addingTimeInterval(squareBolus.deliveryTime/2) // within the delivery time - XCTAssertTrue(squareBolus.isMutable(atDate: dateToCheckForSquareBolus, forPump: .model523)) - } - - func testSquareWaveIsNotMutableOnX23AfterDeliveryTime() { - let squareBolus = BolusNormalPumpEvent(availableData: Data(hexadecimalString: "010080008000240209a24a1510")!, pumpModel: .model523)! - let squareBolusTimestamp = squareBolus.timestamp.date! - let dateToCheckForSquareBolus = squareBolusTimestamp.addingTimeInterval(squareBolus.deliveryTime + 1) // 1s after delivery time - XCTAssertTrue(squareBolus.isMutable(atDate: dateToCheckForSquareBolus, forPump: .model523)) - } - - func getNormalBolusEvent() -> BolusNormalPumpEvent { - let events = historyPage523.events - let bolus = events[1] as! BolusNormalPumpEvent - print("Bolus hex = \(bolus.rawData.hexadecimalString)") - return bolus - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/CommandResponseViewController.swift b/Dependencies/MinimedKit/MinimedKitUI/CommandResponseViewController.swift deleted file mode 100644 index 43c7924a2..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/CommandResponseViewController.swift +++ /dev/null @@ -1,290 +0,0 @@ -// -// CommandResponseViewController.swift -// MinimedKitUI -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit -import LoopKitUI -import MinimedKit -import RileyLinkKit -import RileyLinkBLEKit - - -extension CommandResponseViewController { - typealias T = CommandResponseViewController - - private static let successText = LocalizedString("Succeeded", comment: "A message indicating a command succeeded") - - static func changeTime(ops: PumpOps?, device: RileyLinkDevice) -> T { - return T { (completionHandler) -> String in - ops?.runSession(withName: "Set time", using: device) { (session) in - let response: String - do { - try session.setTimeToNow(in: .current) - response = self.successText - } catch let error { - response = String(describing: error) - } - - DispatchQueue.main.async { - completionHandler(response) - } - } - - return LocalizedString("Changing time…", comment: "Progress message for changing pump time.") - } - } - - static func changeTime(ops: PumpOps?, rileyLinkDeviceProvider: RileyLinkDeviceProvider) -> T { - return T { (completionHandler) -> String in - ops?.runSession(withName: "Set time", usingSelector: rileyLinkDeviceProvider.firstConnectedDevice) { (session) in - let response: String - do { - guard let session = session else { - throw PumpManagerError.connection(MinimedPumpManagerError.noRileyLink) - } - - try session.setTimeToNow(in: .current) - response = self.successText - } catch let error { - response = String(describing: error) - } - - DispatchQueue.main.async { - completionHandler(response) - } - } - - return LocalizedString("Changing time…", comment: "Progress message for changing pump time.") - } - } - - static func dumpHistory(ops: PumpOps?, device: RileyLinkDevice) -> T { - return T { (completionHandler) -> String in - let calendar = Calendar(identifier: Calendar.Identifier.gregorian) - let oneDayAgo = calendar.date(byAdding: DateComponents(day: -1), to: Date()) - - ops?.runSession(withName: "Get history events", using: device) { (session) in - let response: String - do { - let (events, _) = try session.getHistoryEvents(since: oneDayAgo!) - var responseText = String(format: "Found %d events since %@", events.count, oneDayAgo! as NSDate) - for event in events { - responseText += String(format:"\nEvent: %@", event.dictionaryRepresentation) - } - - response = responseText - } catch let error { - response = String(describing: error) - } - - DispatchQueue.main.async { - completionHandler(response) - } - } - - return LocalizedString("Fetching history…", comment: "Progress message for fetching pump history.") - } - } - - static func fetchGlucose(ops: PumpOps?, device: RileyLinkDevice) -> T { - return T { (completionHandler) -> String in - let calendar = Calendar(identifier: Calendar.Identifier.gregorian) - let oneDayAgo = calendar.date(byAdding: DateComponents(day: -1), to: Date()) - - ops?.runSession(withName: "Get glucose history", using: device) { (session) in - let response: String - do { - let events = try session.getGlucoseHistoryEvents(since: oneDayAgo!) - var responseText = String(format: "Found %d events since %@", events.count, oneDayAgo! as NSDate) - for event in events { - responseText += String(format: "\nEvent: %@", event.dictionaryRepresentation) - } - - response = responseText - } catch let error { - response = String(describing: error) - } - - DispatchQueue.main.async { - completionHandler(response) - } - } - - return LocalizedString("Fetching glucose…", comment: "Progress message for fetching pump glucose.") - } - } - - static func getPumpModel(ops: PumpOps?, device: RileyLinkDevice) -> T { - return T { (completionHandler) -> String in - ops?.runSession(withName: "Get Pump Model", using: device) { (session) in - let response: String - do { - let model = try session.getPumpModel(usingCache: false) - response = "Pump Model: \(model)" - } catch let error { - response = String(describing: error) - } - - DispatchQueue.main.async { - completionHandler(response) - } - } - - return LocalizedString("Fetching pump model…", comment: "Progress message for fetching pump model.") - } - } - - static func mySentryPair(ops: PumpOps?, device: RileyLinkDevice) -> T { - return T { (completionHandler) -> String in - var byteArray = [UInt8](repeating: 0, count: 16) - (device.peripheralIdentifier as NSUUID).getBytes(&byteArray) - let watchdogID = Data(byteArray[0..<3]) - - ops?.runSession(withName: "Change watchdog marriage profile", using: device) { (session) in - let response: String - do { - try session.changeWatchdogMarriageProfile(watchdogID) - response = self.successText - } catch let error { - response = String(describing: error) - } - - DispatchQueue.main.async { - completionHandler(response) - } - } - - return LocalizedString( - "On your pump, go to the Find Device screen and select \"Find Device\"." + - "\n" + - "\nMain Menu >" + - "\nUtilities >" + - "\nConnect Devices >" + - "\nOther Devices >" + - "\nOn >" + - "\nFind Device", - comment: "Pump find device instruction" - ) - } - } - - static func pressDownButton(ops: PumpOps?, device: RileyLinkDevice) -> T { - return T { (completionHandler) -> String in - ops?.runSession(withName: "Press down button", using: device) { (session) in - let response: String - do { - try session.pressButton(.down) - response = self.successText - } catch let error { - response = String(describing: error) - } - - DispatchQueue.main.async { - completionHandler(response) - } - } - - return LocalizedString("Sending button press…", comment: "Progress message for sending button press to pump.") - } - } - - static func readBasalSchedule(ops: PumpOps?, device: RileyLinkDevice, integerFormatter: NumberFormatter) -> T { - return T { (completionHandler) -> String in - ops?.runSession(withName: "Get Basal Settings", using: device) { (session) in - let response: String - do { - let schedule = try session.getBasalSchedule(for: .profileB) - var str = String(format: LocalizedString("%1$@ basal schedule entries\n", comment: "The format string describing number of basal schedule entries: (1: number of entries)"), integerFormatter.string(from: NSNumber(value: schedule?.entries.count ?? 0))!) - for entry in schedule?.entries ?? [] { - str += "\(String(describing: entry))\n" - } - response = str - } catch let error { - response = String(describing: error) - } - - DispatchQueue.main.async { - completionHandler(response) - } - } - - return LocalizedString("Reading basal schedule…", comment: "Progress message for reading basal schedule") - } - } - - static func readPumpStatus(ops: PumpOps?, device: RileyLinkDevice, measurementFormatter: MeasurementFormatter) -> T { - return T { (completionHandler) -> String in - ops?.runSession(withName: "Read pump status", using: device) { (session) in - let response: String - do { - let status = try session.getCurrentPumpStatus() - - var str = String(format: LocalizedString("%1$@ Units of insulin remaining\n", comment: "The format string describing units of insulin remaining: (1: number of units)"), measurementFormatter.numberFormatter.string(from: NSNumber(value: status.reservoir))!) - str += String(format: LocalizedString("Battery: %1$@ volts\n", comment: "The format string describing pump battery voltage: (1: battery voltage)"), measurementFormatter.string(from: status.batteryVolts)) - str += String(format: LocalizedString("Suspended: %1$@\n", comment: "The format string describing pump suspended state: (1: suspended)"), String(describing: status.suspended)) - str += String(format: LocalizedString("Bolusing: %1$@\n", comment: "The format string describing pump bolusing state: (1: bolusing)"), String(describing: status.bolusing)) - - response = str - } catch let error { - response = String(describing: error) - } - - DispatchQueue.main.async { - completionHandler(response) - } - } - - return LocalizedString("Reading pump status…", comment: "Progress message for reading pump status") - } - } - - static func tuneRadio(ops: PumpOps?, device: RileyLinkDevice, measurementFormatter: MeasurementFormatter) -> T { - return T { (completionHandler) -> String in - ops?.runSession(withName: "Tune pump", using: device) { (session) in - let response: String - do { - let scanResult = try session.tuneRadio() - - var resultDict: [String: Any] = [:] - - let intFormatter = NumberFormatter() - let formatString = LocalizedString("%1$@ %2$@/%3$@ %4$@", comment: "The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI)") - - resultDict[LocalizedString("Best Frequency", comment: "The label indicating the best radio frequency")] = measurementFormatter.string(from: scanResult.bestFrequency) - resultDict[LocalizedString("Trials", comment: "The label indicating the results of each frequency trial")] = scanResult.trials.map({ (trial) -> String in - - return String( - format: formatString, - measurementFormatter.string(from: trial.frequency), - intFormatter.string(from: NSNumber(value: trial.successes))!, - intFormatter.string(from: NSNumber(value: trial.tries))!, - intFormatter.string(from: NSNumber(value: trial.avgRSSI))! - ) - }) - - var responseText: String - - if let data = try? JSONSerialization.data(withJSONObject: resultDict, options: .prettyPrinted), let string = String(data: data, encoding: .utf8) { - responseText = string - } else { - responseText = LocalizedString("No response", comment: "Message display when no response from tuning pump") - } - - response = responseText - } catch let error { - response = String(describing: error) - } - - DispatchQueue.main.async { - completionHandler(response) - } - } - - return LocalizedString("Tuning radio…", comment: "Progress message for tuning radio") - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Extensions/Comparable.swift b/Dependencies/MinimedKit/MinimedKitUI/Extensions/Comparable.swift deleted file mode 100644 index 61974d4fe..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Extensions/Comparable.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// Comparable.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 3/19/23. -// - -import Foundation - -extension Comparable { - func clamped(to range: ClosedRange) -> Self { - if self < range.lowerBound { - return range.lowerBound - } else if self > range.upperBound { - return range.upperBound - } else { - return self - } - } - - mutating func clamp(to range: ClosedRange) { - self = clamped(to: range) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Extensions/IdentifiableClass.swift b/Dependencies/MinimedKit/MinimedKitUI/Extensions/IdentifiableClass.swift deleted file mode 100644 index ad825fef7..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Extensions/IdentifiableClass.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// IdentifiableClass.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - - -protocol IdentifiableClass: AnyObject { - static var className: String { get } -} - - -extension IdentifiableClass { - static var className: String { - return NSStringFromClass(self).components(separatedBy: ".").last! - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Extensions/Image.swift b/Dependencies/MinimedKit/MinimedKitUI/Extensions/Image.swift deleted file mode 100644 index 3d7267f93..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Extensions/Image.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// Image.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 11/29/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -private class FrameworkBundle { - static let main = Bundle(for: FrameworkBundle.self) -} - -extension Image { - init(frameworkImage name: String, decorative: Bool = false) { - if decorative { - self.init(decorative: name, bundle: FrameworkBundle.main) - } else { - self.init(name, bundle: FrameworkBundle.main) - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Extensions/NibLoadable.swift b/Dependencies/MinimedKit/MinimedKitUI/Extensions/NibLoadable.swift deleted file mode 100644 index db5988bc5..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Extensions/NibLoadable.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// NibLoadable.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import UIKit - -protocol NibLoadable: IdentifiableClass { - static func nib() -> UINib -} - - -extension NibLoadable { - static func nib() -> UINib { - return UINib(nibName: className, bundle: Bundle(for: self)) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Extensions/NumberFormatter.swift b/Dependencies/MinimedKit/MinimedKitUI/Extensions/NumberFormatter.swift deleted file mode 100644 index 6a945f414..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Extensions/NumberFormatter.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// NumberFormatter.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension NumberFormatter { - - func decibleString(from decibles: Int?) -> String? { - if let decibles = decibles, let formatted = string(from: NSNumber(value: decibles)) { - return String(format: LocalizedString("%@ dB", comment: "Unit format string for an RSSI value in decibles"), formatted) - } else { - return nil - } - } - - func string(from number: Double) -> String? { - return string(from: NSNumber(value: number)) - } - - func string(from number: Double, unit: String, style: Formatter.UnitStyle = .medium, avoidLineBreaking: Bool = true) -> String? { - guard let stringValue = string(from: number) else { - return nil - } - - let separator: String - switch style { - case .long: - separator = " " - case .medium: - separator = avoidLineBreaking ? .nonBreakingSpace : " " - case .short: - fallthrough - @unknown default: - separator = avoidLineBreaking ? .wordJoiner : "" - } - - let unit = avoidLineBreaking ? unit.replacingOccurrences(of: "/", with: "\(String.wordJoiner)/\(String.wordJoiner)") : unit - - return String( - format: LocalizedString("%1$@%2$@%3$@", comment: "String format for value with units (1: value, 2: separator, 3: units)"), - stringValue, - separator, - unit - ) - } -} - -public extension String { - static let nonBreakingSpace = "\u{00a0}" - static let wordJoiner = "\u{2060}" -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Extensions/TimeZone.swift b/Dependencies/MinimedKit/MinimedKitUI/Extensions/TimeZone.swift deleted file mode 100644 index 969dfa8b7..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Extensions/TimeZone.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// TimeZone.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension TimeZone { - static var currentFixed: TimeZone { - return TimeZone(secondsFromGMT: TimeZone.current.secondsFromGMT())! - } - - var fixed: TimeZone { - return TimeZone(secondsFromGMT: secondsFromGMT())! - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Info.plist b/Dependencies/MinimedKit/MinimedKitUI/Info.plist deleted file mode 100644 index 7a3ea75eb..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Dependencies/MinimedKit/MinimedKitUI/LocalisedString.swift b/Dependencies/MinimedKit/MinimedKitUI/LocalisedString.swift deleted file mode 100644 index 9c70ad708..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/LocalisedString.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// LocalisedString.swift -// MinimedKit -// -// Created by Pete Schwamb on 3/19/23. -// - -import Foundation - -private class LocalBundle { - /// Returns the resource bundle associated with the current Swift module. - static var main: Bundle = { - if let mainResourceURL = Bundle.main.resourceURL, - let bundle = Bundle(url: mainResourceURL.appendingPathComponent("MinimedKitUI_MinimedKitUI.bundle")) - { - return bundle - } - return Bundle(for: LocalBundle.self) - }() -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, comment: comment) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/MinimedHUDProvider.swift b/Dependencies/MinimedKit/MinimedKitUI/MinimedHUDProvider.swift deleted file mode 100644 index b88f48182..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/MinimedHUDProvider.swift +++ /dev/null @@ -1,121 +0,0 @@ -// -// MinimedHUDProvider.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 2/4/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit -import LoopKitUI -import MinimedKit -import SwiftUI - -class MinimedHUDProvider: HUDProvider { - - var managerIdentifier: String { - return MinimedPumpManager.managerIdentifier - } - - private var state: MinimedPumpManagerState { - didSet { - guard visible else { - return - } - - if oldValue.lastReservoirReading != state.lastReservoirReading { - self.updateReservoirView() - } - } - } - - private let pumpManager: MinimedPumpManager - - private let bluetoothProvider: BluetoothProvider - - private let colorPalette: LoopUIColorPalette - - private let allowedInsulinTypes: [InsulinType] - - public init(pumpManager: MinimedPumpManager, bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowedInsulinTypes: [InsulinType]) { - self.pumpManager = pumpManager - self.bluetoothProvider = bluetoothProvider - self.state = pumpManager.state - self.colorPalette = colorPalette - self.allowedInsulinTypes = allowedInsulinTypes - pumpManager.stateObservers.insert(self, queue: .main) - } - - var visible: Bool = false { - didSet { - if oldValue != visible && visible { - self.updateReservoirView() - } - } - } - - private weak var reservoirView: ReservoirHUDView? - - private func updateReservoirView() { - if let lastReservoirVolume = state.lastReservoirReading, - let reservoirView = reservoirView - { - let reservoirLevel = (lastReservoirVolume.units / pumpManager.pumpReservoirCapacity).clamped(to: 0...1.0) - reservoirView.level = reservoirLevel - reservoirView.setReservoirVolume(volume: lastReservoirVolume.units, at: lastReservoirVolume.validAt) - } - } - - public func createHUDView() -> BaseHUDView? { - - reservoirView = ReservoirHUDView.instantiate() - - if visible { - updateReservoirView() - } - - return reservoirView - } - - public func didTapOnHUDView(_ view: BaseHUDView, allowDebugFeatures: Bool) -> HUDTapAction? { - let vc = pumpManager.settingsViewController(bluetoothProvider: bluetoothProvider, colorPalette: colorPalette, allowDebugFeatures: allowDebugFeatures, allowedInsulinTypes: allowedInsulinTypes) - return HUDTapAction.presentViewController(vc) - } - - public var hudViewRawState: HUDProvider.HUDViewRawState { - var rawValue: HUDProvider.HUDViewRawState = [ - "pumpReservoirCapacity": pumpManager.pumpReservoirCapacity - ] - - if let lastReservoirReading = state.lastReservoirReading { - rawValue["lastReservoirReading"] = lastReservoirReading.rawValue - } - - return rawValue - } - - public static func createHUDView(rawValue: HUDProvider.HUDViewRawState) -> BaseHUDView? { - guard let pumpReservoirCapacity = rawValue["pumpReservoirCapacity"] as? Double else { - return nil - } - - let reservoirHUDView = ReservoirHUDView.instantiate() - if let rawLastReservoirReading = rawValue["lastReservoirReading"] as? ReservoirReading.RawValue, - let lastReservoirReading = ReservoirReading(rawValue: rawLastReservoirReading) - { - let reservoirLevel = (lastReservoirReading.units / pumpReservoirCapacity).clamped(to: 0...1.0) - reservoirHUDView.level = reservoirLevel - reservoirHUDView.setReservoirVolume(volume: lastReservoirReading.units, at: lastReservoirReading.validAt) - } - - return reservoirHUDView - } -} - -extension MinimedHUDProvider: MinimedPumpManagerStateObserver { - func didUpdatePumpManagerState(_ state: MinimedPumpManagerState) { - dispatchPrecondition(condition: .onQueue(.main)) - self.state = state - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/MinimedKitUI.h b/Dependencies/MinimedKit/MinimedKitUI/MinimedKitUI.h deleted file mode 100644 index 2407773c5..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/MinimedKitUI.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// MinimedKitUI.h -// MinimedKitUI -// -// Created by Pete Schwamb on 3/19/23. -// - -#import -#import -#import - -//! Project version number for MinimedKitUI. -FOUNDATION_EXPORT double MinimedKitUIVersionNumber; - -//! Project version string for MinimedKitUI. -FOUNDATION_EXPORT const unsigned char MinimedKitUIVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/MinimedKit/MinimedKitUI/MinimedPumpManager+UI.swift b/Dependencies/MinimedKit/MinimedKitUI/MinimedPumpManager+UI.swift deleted file mode 100644 index 5cc6fa4d5..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/MinimedPumpManager+UI.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// MinimedPumpManager+UI.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import UIKit -import LoopKit -import LoopKitUI -import MinimedKit -import RileyLinkKitUI - - -extension MinimedPumpManager: PumpManagerUI { - - public static var onboardingImage: UIImage? { - return UIImage.pumpImage(in: nil, isLargerModel: false, isSmallImage: true) - } - - static public func setupViewController(initialSettings settings: PumpManagerSetupSettings, bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool, allowedInsulinTypes: [InsulinType]) -> SetupUIResult { - let navVC = MinimedPumpManagerSetupViewController.instantiateFromStoryboard() - navVC.supportedInsulinTypes = allowedInsulinTypes - let didConfirm: (InsulinType) -> Void = { [weak navVC] (confirmedType) in - if let navVC = navVC { - navVC.insulinType = confirmedType - let nextViewController = navVC.storyboard?.instantiateViewController(identifier: "RileyLinkSetup") as! RileyLinkSetupTableViewController - navVC.pushViewController(nextViewController, animated: true) - } - } - let didCancel: () -> Void = { [weak navVC] in - if let navVC = navVC { - navVC.didCancel() - } - } - let insulinSelectionView = InsulinTypeConfirmation(initialValue: .novolog, supportedInsulinTypes: allowedInsulinTypes, didConfirm: didConfirm, didCancel: didCancel) - let rootVC = UIHostingController(rootView: insulinSelectionView) - rootVC.title = "Insulin Type" - navVC.pushViewController(rootVC, animated: false) - navVC.navigationBar.backgroundColor = .secondarySystemBackground - navVC.maxBasalRateUnitsPerHour = settings.maxBasalRateUnitsPerHour - navVC.maxBolusUnits = settings.maxBolusUnits - navVC.basalSchedule = settings.basalSchedule - return .userInteractionRequired(navVC) - } - - public func settingsViewController(bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool, allowedInsulinTypes: [InsulinType]) -> PumpManagerViewController { - return MinimedUICoordinator(pumpManager: self, colorPalette: colorPalette, allowDebugFeatures: allowDebugFeatures, allowedInsulinTypes: allowedInsulinTypes) - } - - public func deliveryUncertaintyRecoveryViewController(colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) -> (UIViewController & CompletionNotifying) { - return MinimedUICoordinator(pumpManager: self, colorPalette: colorPalette, allowDebugFeatures: allowDebugFeatures, allowedInsulinTypes: []) - } - - public var smallImage: UIImage? { - return state.smallPumpImage - } - - public func hudProvider(bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowedInsulinTypes: [InsulinType]) -> HUDProvider? { - return MinimedHUDProvider(pumpManager: self, bluetoothProvider: bluetoothProvider, colorPalette: colorPalette, allowedInsulinTypes: allowedInsulinTypes) - } - - public static func createHUDView(rawValue: HUDProvider.HUDViewRawState) -> BaseHUDView? { - return MinimedHUDProvider.createHUDView(rawValue: rawValue) - } -} - -// MARK: - PumpStatusIndicator -extension MinimedPumpManager { - - public var pumpStatusHighlight: DeviceStatusHighlight? { - return buildPumpStatusHighlight(for: state, recents: recents, andDate: dateGenerator()) - } - - public var pumpLifecycleProgress: DeviceLifecycleProgress? { - return nil - } - - public var pumpStatusBadge: DeviceStatusBadge? { - return nil - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/MinimedPumpUICoordinator.swift b/Dependencies/MinimedKit/MinimedKitUI/MinimedPumpUICoordinator.swift deleted file mode 100644 index 06e3319ca..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/MinimedPumpUICoordinator.swift +++ /dev/null @@ -1,163 +0,0 @@ -// -// MinimedPumpUICoordinator.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 11/29/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit -import LoopKitUI -import MinimedKit -import RileyLinkBLEKit -import RileyLinkKit -import RileyLinkKitUI -import SwiftUI - -enum MinimedUIScreen { - case settings - - func next() -> MinimedUIScreen? { - switch self { - case .settings: - return nil - } - } -} - -class MinimedUICoordinator: UINavigationController, PumpManagerOnboarding, CompletionNotifying, UINavigationControllerDelegate { - - public weak var pumpManagerOnboardingDelegate: PumpManagerOnboardingDelegate? - - public weak var completionDelegate: CompletionDelegate? - - private let colorPalette: LoopUIColorPalette - - private var allowedInsulinTypes: [InsulinType] - - private var allowDebugFeatures: Bool - - var pumpManager: MinimedPumpManager - - var screenStack = [MinimedUIScreen]() - - var currentScreen: MinimedUIScreen { - return screenStack.last! - } - - init(pumpManager: MinimedPumpManager? = nil, colorPalette: LoopUIColorPalette, pumpManagerSettings: PumpManagerSetupSettings? = nil, allowDebugFeatures: Bool, allowedInsulinTypes: [InsulinType] = []) - { - if pumpManager == nil, let pumpManagerSettings = pumpManagerSettings { - let basalSchedule = pumpManagerSettings.basalSchedule - - let deviceProvider = RileyLinkBluetoothDeviceProvider(autoConnectIDs: []) - - let pumpManagerState = MinimedPumpManagerState( - isOnboarded: false, - useMySentry: true, // TODO - pumpColor: .blue, // TODO - pumpID: "111111", // TODO - pumpModel: .model508, // TODO - pumpFirmwareVersion: "1.11", // TODO - pumpRegion: .northAmerica, // TODO - rileyLinkConnectionState: nil, - timeZone: basalSchedule.timeZone, - suspendState: .resumed(Date()), // TODO - insulinType: .novolog, // TODO - lastTuned: nil, - lastValidFrequency: nil, - basalSchedule: BasalSchedule(repeatingScheduleValues: pumpManagerSettings.basalSchedule.items) - ) - - self.pumpManager = MinimedPumpManager(state: pumpManagerState, rileyLinkDeviceProvider: deviceProvider) - } else { - guard let pumpManager = pumpManager else { - fatalError("Unable to create Minimed PumpManager") - } - self.pumpManager = pumpManager - } - - self.colorPalette = colorPalette - - self.allowDebugFeatures = allowDebugFeatures - - self.allowedInsulinTypes = allowedInsulinTypes - - super.init(navigationBarClass: UINavigationBar.self, toolbarClass: UIToolbar.self) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - self.navigationBar.prefersLargeTitles = true - delegate = self - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - if screenStack.isEmpty { - screenStack = [determineInitialStep()] - let viewController = viewControllerForScreen(currentScreen) - viewController.isModalInPresentation = false - setViewControllers([viewController], animated: false) - } - } - - private func determineInitialStep() -> MinimedUIScreen { - return .settings - } - - private func viewControllerForScreen(_ screen: MinimedUIScreen) -> UIViewController { - switch screen { - case .settings: - let viewModel = MinimedPumpSettingsViewModel(pumpManager: pumpManager) - viewModel.didFinish = { [weak self] in - self?.stepFinished() - } - - let rileyLinkListDataSource = RileyLinkListDataSource(rileyLinkPumpManager: pumpManager) - - let handleRileyLinkSelection = { [weak self] (device: RileyLinkDevice) in - if let self = self { - let vc = RileyLinkDeviceTableViewController( - device: device, - batteryAlertLevel: self.pumpManager.rileyLinkBatteryAlertLevel, - batteryAlertLevelChanged: { [weak self] value in - self?.pumpManager.rileyLinkBatteryAlertLevel = value - } - ) - self.show(vc, sender: self) - } - } - - let view = MinimedPumpSettingsView(viewModel: viewModel, supportedInsulinTypes: allowedInsulinTypes, handleRileyLinkSelection: handleRileyLinkSelection, rileyLinkListDataSource: rileyLinkListDataSource) - return hostingController(rootView: view) - } - } - - private func hostingController(rootView: Content) -> DismissibleHostingController { - return DismissibleHostingController(rootView: rootView, colorPalette: colorPalette) - } - - private func stepFinished() { - if let nextStep = currentScreen.next() { - navigateTo(nextStep) - } else { - completionDelegate?.completionNotifyingDidComplete(self) - } - } - - func navigateTo(_ screen: MinimedUIScreen) { - screenStack.append(screen) - let viewController = viewControllerForScreen(screen) - viewController.isModalInPresentation = false - self.pushViewController(viewController, animated: true) - viewController.view.layoutSubviews() - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/PumpModel.swift b/Dependencies/MinimedKit/MinimedKitUI/PumpModel.swift deleted file mode 100644 index f927a7759..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/PumpModel.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// PumpModel.swift -// MinimedUI -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import MinimedKit - - -extension UIImage { - static func pumpImage(in color: PumpColor?, isLargerModel: Bool, isSmallImage: Bool) -> UIImage { - var nameComponents = [String]() - - nameComponents.append(isLargerModel ? "7xx" : "5xx") - - if isSmallImage { - nameComponents.append("Small") - } - - nameComponents.append({ () -> String in - switch color { - case .blue?: - return "Blue" - case .clear?: - return "Clear" - case .purple?: - return "Purple" - case .smoke?: - return "Smoke" - case .pink?: - return "Pink" - case .none: - return "Outline" - } - }()) - - let name = nameComponents.joined(separator: " ") - return UIImage(named: name, in: Bundle(for: MinimedPumpSettingsViewModel.self), compatibleWith: nil)! - } -} - - -extension PumpModel { - func largeImage(in color: PumpColor?) -> UIImage { - return UIImage.pumpImage(in: color, isLargerModel: reservoirCapacity > 200, isSmallImage: false) - } - - func smallImage(in color: PumpColor?) -> UIImage { - return UIImage.pumpImage(in: color, isLargerModel: reservoirCapacity > 200, isSmallImage: true) - } -} - - -extension MinimedPumpManagerState { - var largePumpImage: UIImage { - return UIImage.pumpImage(in: pumpColor, isLargerModel: pumpModel.reservoirCapacity > 200, isSmallImage: false) - } - - var smallPumpImage: UIImage { - return UIImage.pumpImage(in: pumpColor, isLargerModel: pumpModel.reservoirCapacity > 200, isSmallImage: true) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/RadioSelectionTableViewController.swift b/Dependencies/MinimedKit/MinimedKitUI/RadioSelectionTableViewController.swift deleted file mode 100644 index 28e033340..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/RadioSelectionTableViewController.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// RadioSelectionTableViewController.swift -// Loop -// -// Created by Nate Racklyeft on 8/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import LoopKitUI -import MinimedKit - - -extension RadioSelectionTableViewController: IdentifiableClass { - typealias T = RadioSelectionTableViewController - - static func insulinDataSource(_ value: InsulinDataSource) -> T { - let vc = T() - - vc.selectedIndex = value.rawValue - vc.options = (0..<2).compactMap({ InsulinDataSource(rawValue: $0) }).map { String(describing: $0) } - vc.contextHelp = LocalizedString("Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option.", comment: "Instructions on selecting an insulin data source") - - return vc - } - - static func batteryChemistryType(_ value: MinimedKit.BatteryChemistryType) -> T { - let vc = T() - - vc.selectedIndex = value.rawValue - vc.options = (0..<2).compactMap({ BatteryChemistryType(rawValue: $0) }).map { String(describing: $0) } - vc.contextHelp = LocalizedString("Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure.", comment: "Instructions on selecting battery chemistry type") - - return vc - } - - static func useMySentry(_ value: Bool) -> T { - let vc = T() - - vc.selectedIndex = value ? 0 : 1 - - vc.options = ["Use MySentry", "Do not use MySentry"] - vc.contextHelp = LocalizedString("Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models.", comment: "Instructions on selecting setting for MySentry") - - return vc - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/Base.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/Base.lproj/Localizable.strings deleted file mode 100644 index 8fced6f56..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/Base.lproj/Localizable.strings +++ /dev/null @@ -1,209 +0,0 @@ -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ basal schedule entries\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Units of insulin remaining\n"; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure."; - -/* Confirmation message for deleting a pump */ -"Are you sure you want to delete this pump?" = "Are you sure you want to delete this pump?"; - -/* The title of the cell describing an awake radio */ -"Awake Until" = "Awake Until"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basal Rates"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Battery: %1$@ volts\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Best Frequency"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Bolusing: %1$@\n"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancel"; - -/* The title of the command to change pump time */ -"Change Time" = "Change Time"; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Change Time Zone"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Changing time…"; - -/* The title of the section describing commands */ -"Commands" = "Commands"; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuration"; - -/* Button title to connect to pump during setup */ -"Connect" = "Connect"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Connection State"; - -/* Button title to delete pump - Title text for the button to remove a pump from Loop */ -"Delete Pump" = "Delete Pump"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Delivery Limits"; - -/* The title of the section describing the device */ -"Device" = "Device"; - -/* The title of the command to discover commands */ -"Discover Commands" = "Discover Commands"; - -/* Progress message for discovering commands. */ -"Discovering commands…" = "Discovering commands…"; - -/* The title of the command to enable diagnostic LEDs */ -"Enable Diagnostic LEDs" = "Enable Diagnostic LEDs"; - -/* Progress message for enabling diagnostic LEDs */ -"Enabled Diagnostic LEDs" = "Enabled Diagnostic LEDs"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Resuming"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspending"; - -/* The title of the command to fetch recent glucose */ -"Fetch Enlite Glucose" = "Fetch Enlite Glucose"; - -/* The title of the command to fetch recent history */ -"Fetch Recent History" = "Fetch Recent History"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Fetching glucose…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Fetching history…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Fetching pump model…"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Firmware Version"; - -/* The title of the command to get pump model */ -"Get Pump Model" = "Get Pump Model"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Get Statistics…"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option."; - -/* The title of the cell describing an awake radio */ -"Last Awake" = "Last Awake"; - -/* The title of the cell describing no radio awake data */ -"Listening Off" = "Listening Off"; - -/* The title of the command to pair with mysentry */ -"MySentry Pair" = "MySentry Pair"; - -/* The title of the cell showing device name */ -"Name" = "Name"; - -/* Message display when no response from tuning pump */ -"No response" = "No response"; - -/* The title of the cell showing the last idle */ -"On Idle" = "On Idle"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device"; - -/* The title text for the preferred insulin data source config */ -"Preferred Data Source" = "Preferred Data Source"; - -/* The title of the section describing the pump */ -"Pump" = "Pump"; - -/* The title text for the battery type value */ -"Pump Battery Type" = "Pump Battery Type"; - -/* The title of the cell showing pump ID - The title text for the pump ID config value */ -"Pump ID" = "Pump ID"; - -/* The title of the cell showing the pump model number */ -"Pump Model" = "Pump Model"; - -/* Title of the pump settings view controller */ -"Pump Settings" = "Pump Settings"; - -/* The title of the command to read basal schedule */ -"Read Basal Schedule" = "Read Basal Schedule"; - -/* The title of the command to read pump status */ -"Read Pump Status" = "Read Pump Status"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Reading basal schedule…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Reading pump status…"; - -/* The title of the cell showing the pump region */ -"Region" = "Region"; - -/* Button title to retry sentry setup */ -"Retry" = "Retry"; - -/* The title of the command to fetch RileyLink statistics */ -"RileyLink Statistics" = "RileyLink Statistics"; - -/* Title of button to save basal profile to pump - Title of button to save delivery limit settings to pump */ -"Save to Pump…" = "Save to Pump…"; - -/* The title of the command to send a button press */ -"Send Button Press" = "Send Button Press"; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Sending button press…"; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Signal Strength"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Succeeded"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Suspended: %1$@\n"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Trials"; - -/* The title of the command to re-tune the radio */ -"Tune Radio Frequency" = "Tune Radio Frequency"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Tuning radio…"; - -/* The detail text for an unknown pump model */ -"Unknown" = "Unknown"; - -/* The title of the cell showing uptime */ -"Uptime" = "Uptime"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/Base.lproj/MinimedPumpManager.storyboard b/Dependencies/MinimedKit/MinimedKitUI/Resources/Base.lproj/MinimedPumpManager.storyboard deleted file mode 100644 index d4515a39b..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/Base.lproj/MinimedPumpManager.storyboard +++ /dev/null @@ -1,583 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Blue.imageset/5xx Blue.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Blue.imageset/5xx Blue.pdf deleted file mode 100644 index e21ed93c2..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Blue.imageset/5xx Blue.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Blue.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Blue.imageset/Contents.json deleted file mode 100644 index bbde5d76f..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Blue.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "5xx Blue.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Clear.imageset/5xx Clear.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Clear.imageset/5xx Clear.pdf deleted file mode 100644 index 729e073d9..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Clear.imageset/5xx Clear.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Clear.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Clear.imageset/Contents.json deleted file mode 100644 index 38f640272..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Clear.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "5xx Clear.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Outline.imageset/5xx Outline.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Outline.imageset/5xx Outline.pdf deleted file mode 100644 index 98c745480..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Outline.imageset/5xx Outline.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Outline.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Outline.imageset/Contents.json deleted file mode 100644 index f8b744959..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Outline.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "5xx Outline.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Pink.imageset/5xx Pink.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Pink.imageset/5xx Pink.pdf deleted file mode 100644 index caf3807a2..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Pink.imageset/5xx Pink.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Pink.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Pink.imageset/Contents.json deleted file mode 100644 index 311a9a24b..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Pink.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "5xx Pink.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Purple.imageset/5xx Purple.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Purple.imageset/5xx Purple.pdf deleted file mode 100644 index 4e5d4dbda..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Purple.imageset/5xx Purple.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Purple.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Purple.imageset/Contents.json deleted file mode 100644 index f61c02d21..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Purple.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "5xx Purple.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Blue.imageset/5xx Small Blue.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Blue.imageset/5xx Small Blue.pdf deleted file mode 100644 index bf39cbf9a..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Blue.imageset/5xx Small Blue.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Blue.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Blue.imageset/Contents.json deleted file mode 100644 index 614bfff56..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Blue.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "5xx Small Blue.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Clear.imageset/5xx Small Clear.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Clear.imageset/5xx Small Clear.pdf deleted file mode 100644 index 3bc6bffa7..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Clear.imageset/5xx Small Clear.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Clear.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Clear.imageset/Contents.json deleted file mode 100644 index 5de7a81c1..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Clear.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "5xx Small Clear.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Outline.imageset/5xx Small Outline.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Outline.imageset/5xx Small Outline.pdf deleted file mode 100644 index c66a87458..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Outline.imageset/5xx Small Outline.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Outline.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Outline.imageset/Contents.json deleted file mode 100644 index 51fcb1b73..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Outline.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "5xx Small Outline.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Pink.imageset/5xx Small Pink.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Pink.imageset/5xx Small Pink.pdf deleted file mode 100644 index 497261c1c..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Pink.imageset/5xx Small Pink.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Pink.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Pink.imageset/Contents.json deleted file mode 100644 index 83aaa6c3a..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Pink.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "5xx Small Pink.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Purple.imageset/5xx Small Purple.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Purple.imageset/5xx Small Purple.pdf deleted file mode 100644 index d4d725fc4..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Purple.imageset/5xx Small Purple.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Purple.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Purple.imageset/Contents.json deleted file mode 100644 index 07ee82138..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Purple.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "5xx Small Purple.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Smoke.imageset/5xx Small Smoke.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Smoke.imageset/5xx Small Smoke.pdf deleted file mode 100644 index 23fff3411..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Smoke.imageset/5xx Small Smoke.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Smoke.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Smoke.imageset/Contents.json deleted file mode 100644 index 0b6fe5c06..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Small Smoke.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "5xx Small Smoke.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Smoke.imageset/5xx Smoke.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Smoke.imageset/5xx Smoke.pdf deleted file mode 100644 index 19819d2f7..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Smoke.imageset/5xx Smoke.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Smoke.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Smoke.imageset/Contents.json deleted file mode 100644 index 9f0dcfcfe..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/5xx Smoke.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "5xx Smoke.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Blue.imageset/7xx Blue.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Blue.imageset/7xx Blue.pdf deleted file mode 100644 index ec7130208..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Blue.imageset/7xx Blue.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Blue.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Blue.imageset/Contents.json deleted file mode 100644 index 58550d002..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Blue.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "7xx Blue.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Clear.imageset/7xx Clear.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Clear.imageset/7xx Clear.pdf deleted file mode 100644 index 8076474d4..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Clear.imageset/7xx Clear.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Clear.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Clear.imageset/Contents.json deleted file mode 100644 index a4c179442..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Clear.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "7xx Clear.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Outline.imageset/7xx Outline.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Outline.imageset/7xx Outline.pdf deleted file mode 100644 index 9733fc76f..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Outline.imageset/7xx Outline.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Outline.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Outline.imageset/Contents.json deleted file mode 100644 index 6d85bf062..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Outline.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "7xx Outline.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Pink.imageset/7xx Pink.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Pink.imageset/7xx Pink.pdf deleted file mode 100644 index 93feb7078..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Pink.imageset/7xx Pink.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Pink.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Pink.imageset/Contents.json deleted file mode 100644 index 43344768f..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Pink.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "7xx Pink.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Purple.imageset/7xx Purple.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Purple.imageset/7xx Purple.pdf deleted file mode 100644 index 0ce7433e9..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Purple.imageset/7xx Purple.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Purple.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Purple.imageset/Contents.json deleted file mode 100644 index 812786407..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Purple.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "7xx Purple.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Blue.imageset/7xx Small Blue.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Blue.imageset/7xx Small Blue.pdf deleted file mode 100644 index ea29cab18..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Blue.imageset/7xx Small Blue.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Blue.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Blue.imageset/Contents.json deleted file mode 100644 index cedc61779..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Blue.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "7xx Small Blue.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Clear.imageset/7xx Small Clear.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Clear.imageset/7xx Small Clear.pdf deleted file mode 100644 index 41cc88bd3..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Clear.imageset/7xx Small Clear.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Clear.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Clear.imageset/Contents.json deleted file mode 100644 index 15058ebca..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Clear.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "7xx Small Clear.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Outline.imageset/7xx Small Outline.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Outline.imageset/7xx Small Outline.pdf deleted file mode 100644 index a5439cd58..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Outline.imageset/7xx Small Outline.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Outline.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Outline.imageset/Contents.json deleted file mode 100644 index f72a3b339..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Outline.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "7xx Small Outline.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Pink.imageset/7xx Small Pink.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Pink.imageset/7xx Small Pink.pdf deleted file mode 100644 index 125f7affc..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Pink.imageset/7xx Small Pink.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Pink.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Pink.imageset/Contents.json deleted file mode 100644 index 69fa7bb14..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Pink.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "7xx Small Pink.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Purple.imageset/7xx Small Purple.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Purple.imageset/7xx Small Purple.pdf deleted file mode 100644 index 3357082d1..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Purple.imageset/7xx Small Purple.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Purple.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Purple.imageset/Contents.json deleted file mode 100644 index b1b91d440..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Purple.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "7xx Small Purple.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Smoke.imageset/7xx Small Smoke.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Smoke.imageset/7xx Small Smoke.pdf deleted file mode 100644 index cd6d4b563..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Smoke.imageset/7xx Small Smoke.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Smoke.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Smoke.imageset/Contents.json deleted file mode 100644 index af301d6d8..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Small Smoke.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "7xx Small Smoke.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Smoke.imageset/7xx Smoke.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Smoke.imageset/7xx Smoke.pdf deleted file mode 100644 index 4c22c8759..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Smoke.imageset/7xx Smoke.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Smoke.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Smoke.imageset/Contents.json deleted file mode 100644 index 38c272c21..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/7xx Smoke.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "7xx Smoke.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Pump ID Diagram.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Pump ID Diagram.imageset/Contents.json deleted file mode 100644 index 9f62caa6d..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Pump ID Diagram.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "Pump ID Diagram.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Pump ID Diagram.imageset/Pump ID Diagram.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Pump ID Diagram.imageset/Pump ID Diagram.pdf deleted file mode 100644 index 6273873e8..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Pump ID Diagram.imageset/Pump ID Diagram.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Pump Screen Background.colorset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Pump Screen Background.colorset/Contents.json deleted file mode 100644 index be8df5ebc..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Pump Screen Background.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - }, - "colors" : [ - { - "idiom" : "universal", - "color" : { - "color-space" : "srgb", - "components" : { - "red" : "0xAC", - "alpha" : "1.000", - "blue" : "0xB3", - "green" : "0xB7" - } - } - } - ] -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Pump Screen Text.colorset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Pump Screen Text.colorset/Contents.json deleted file mode 100644 index b95109e8f..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/Pump Screen Text.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - }, - "colors" : [ - { - "idiom" : "universal", - "color" : { - "color-space" : "srgb", - "components" : { - "red" : "48", - "alpha" : "1.000", - "blue" : "32", - "green" : "66" - } - } - } - ] -} \ No newline at end of file diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/reservoir.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/reservoir.imageset/Contents.json deleted file mode 100644 index 7a65fb9c2..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/reservoir.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "reservoir.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/reservoir.imageset/reservoir.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/reservoir.imageset/reservoir.pdf deleted file mode 100644 index 9f1765ba9..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/reservoir.imageset/reservoir.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/reservoir_mask.imageset/Contents.json b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/reservoir_mask.imageset/Contents.json deleted file mode 100644 index e19598694..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/reservoir_mask.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "reservoir_mask.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/reservoir_mask.imageset/reservoir_mask.pdf b/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/reservoir_mask.imageset/reservoir_mask.pdf deleted file mode 100644 index 3d5339917..000000000 Binary files a/Dependencies/MinimedKit/MinimedKitUI/Resources/MinimedKitUI.xcassets/reservoir_mask.imageset/reservoir_mask.pdf and /dev/null differ diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/ar.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/ar.lproj/Localizable.strings deleted file mode 100644 index 015607ef1..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/ar.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ basal schedule entries\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Units of insulin remaining\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Are you sure you want to delete this Pump?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Battery: %1$@ volts\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Best Frequency"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Bolusing: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "إلغاء"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Canceling Temp Basal"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Changing"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Changing time…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Choose the type of battery you are using in your pump for better alerting about low battery conditions."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "المعطيات"; - -/* Button title to connect to pump during setup */ -"Connect" = "Connect"; - -/* Text for continue button */ -"Continue" = "Continue"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Delete Pump"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Devices"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Do not use MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "خطأ في الاستئناف"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspending"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Error Syncing Time"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Fetching glucose…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Fetching history…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Fetching pump model…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Firmware Version"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "توصيل الأنسولين"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Insulintyp"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "No"; - -/* Message display when no response from tuning pump */ -"No response" = "No response"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Preferred Data Source"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Pump Battery Remaining"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Pump Battery Type"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pump ID"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Reading basal schedule…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Reading pump status…"; - -/* The title of the cell showing the pump region */ -"Region" = "Region"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Resume Delivery"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Resuming"; - -/* Button title to retry sentry setup */ -"Retry" = "أعد المحاولة"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Select the type of insulin that you will be using in this pump."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Sending button press…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starting Temp Basal"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Succeeded"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspend Delivery"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Suspended: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspending"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Time Change Detected"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Trials"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Tuning radio…"; - -/* Units for showing temp basal rate */ -"U/hr" = "وحدة لكل ساعة"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "unknown"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Unknown"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Use MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Yes"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/ar.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/ar.lproj/MinimedPumpManager.strings deleted file mode 100644 index 5bc404048..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/ar.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "RileyLink Setup"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Find Device"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Other Devices"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Do not change the time using your pumpʼs menu."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Utilities"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Connect Devices"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Pump Clock"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "Pump ID"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Your pump is ready for use."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Enter the 6-digit pump ID"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Region and Color"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Setup Complete"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Pump Broadcasts"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "On"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Pump Setup"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Enter the pump region"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Pump Setup"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Main Menu"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/ca.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/ca.lproj/Localizable.strings deleted file mode 100644 index ebe3f7138..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/ca.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ basal schedule entries\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Units of insulin remaining\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Are you sure you want to delete this Pump?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Battery: %1$@ volts\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Best Frequency"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Bolusing: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Cancel"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Canceling Temp Basal"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Changing"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Changing time…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Choose the type of battery you are using in your pump for better alerting about low battery conditions."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Configuration"; - -/* Button title to connect to pump during setup */ -"Connect" = "Connect"; - -/* Text for continue button */ -"Continue" = "Continue"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Delete Pump"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Devices"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Do not use MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Resuming"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspending"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Error Syncing Time"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Fetching glucose…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Fetching history…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Fetching pump model…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Firmware Version"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Insulintyp"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "No"; - -/* Message display when no response from tuning pump */ -"No response" = "No response"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Preferred Data Source"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Pump Battery Remaining"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Pump Battery Type"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pump ID"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Reading basal schedule…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Reading pump status…"; - -/* The title of the cell showing the pump region */ -"Region" = "Region"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Resume Delivery"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Resuming"; - -/* Button title to retry sentry setup */ -"Retry" = "Retry"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Select the type of insulin that you will be using in this pump."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Sending button press…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starting Temp Basal"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Succeeded"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspend Delivery"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Suspended: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspending"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Time Change Detected"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Trials"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Tuning radio…"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hr"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "unknown"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Unknown"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Use MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Yes"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/cs.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/cs.lproj/Localizable.strings deleted file mode 100644 index 9fc5664ea..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/cs.lproj/Localizable.strings +++ /dev/null @@ -1,33 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Cancel button title */ -"Cancel" = "Zrušit"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Měním čas…"; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Konfigurace"; - -/* Text for continue button */ -"Continue" = "Pokračovat"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Typ inzulínu"; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Ne"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID pumpy"; - -/* Button title to retry sentry setup */ -"Retry" = "Zkusit znovu"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Plánovaný bazál"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Úspěšně ukončeno"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/cs.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/cs.lproj/MinimedPumpManager.strings deleted file mode 100644 index 0f416c1c4..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/cs.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,15 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "Nastavení RileyLinku"; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "ID pumpy"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Zadejte 6místné ID pumpy"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Nastavení dokončeno"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "Zapnuto"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/da.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/da.lproj/Localizable.strings deleted file mode 100644 index 3b45b1f8c..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/da.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ planlagt basal \n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ enheder insulin tilbage\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ enheder tilbage på %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Justerer pumpetid..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkaline og Lithium batterier henfalder med forskellige hastigheder. Alkaline har tendens til at have et lineært fald over tid, hvor Lithium batteri celler typisk opretholder deres spænding indtil halvejen i deres levetid. Ved normalt brug i en ikke-MySentry kompatibel Minimed (x22/x15) insulinpumpe, som kører Loop, vil alkalinebatterier holde cirka 4 til 5 dage. Lithium batterier holder mellem 1 til 2 uger. Denne indstilling bruger forskellige batteri henfaldssatser for hver kemiske batteritype og alarmerer brugeren, når et batteri er cirka 8 til 10 timer fra at løbe tør."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Er du sikker på, at du vil fjerne denne pumpe?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Batteri: %1$@ volt\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Bedste frekvens"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Giver bolus: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Annuller"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Annuller midlertidig basal"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Ændrer"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Ændrer tid..."; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Vælg den batteritype, du bruger i din pumpe, for at få bedre advarsler om lavt batteri."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Konfiguration"; - -/* Button title to connect to pump during setup */ -"Connect" = "Forbind"; - -/* Text for continue button */ -"Continue" = "Fortsæt"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Fjern pumpe"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Enheder"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Brug ikke MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Fejl ved genoptagelse"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Fejl ved suspendering"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Fejl ved synkronisering af tid"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Henter glukose..."; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Henter historik..."; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Henter pumpemodel..."; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Firmware-version"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin \nsuspenderet"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulintilførsel"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Levering af insulin kan blive bestemt fra pumpen ved enten at tolke på begivenhedshistorikken eller ved at sammenligne volumen af reservoiret over tid. Aflæsning af begivenhedshistorik kan give mere præcise statusgrafer og uploading af up-to-date behandlings data til Nightscout, men betyder hurtigere dræning af pumpebatteriet, risiko for højere fejlrate i radiokommunikation i forhold til aflæsning af volumen af reservoiret. Hvis den valgte kilde ikke kan anvendes,så vil systemet falde tilbage på den anden mulighed."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin tilbage"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Insulintype"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Medtronic-pumpe-modellerne 523, 723, 554 og 754 har en funktion kaldet \"MySentry\", der regelmæssigt sender batteriniveauet for reservoiret og pumpen. Ved at lytte til disse udsendelser kan Loop kommunikere mindre hyppigt med pumpen, hvilket kan forlænge pumpens batterilevetid. Når denne funktion anvendes, forbliver RileyLink dog vågen i længere tid og bruger mere af sit eget batteri. Hvis du aktiverer denne funktion, kan pumpens batterilevetid forlænges, mens du deaktiverer den kan forlænge RileyLink-batteriets levetid. Denne indstilling ignoreres for andre pumpemodeller."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Nej"; - -/* Message display when no response from tuning pump */ -"No response" = "Intet svar"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nej, behold pumpen som den er"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "På din pumpe skal du gå til skærmbilledet Find enhed og vælge \"Find enhed\". \n\n Hovedmenu >\n Hjælpeprogrammer >\n Tilslut enheder >\n Andre enheder >\n På >\n Find enhed"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Foretruken data kilde"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Resterende Pumpe Batteri"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Pumpe batteritype"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pumpe ID"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pumpetid"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Læser basal-plan..."; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Læser pumpestatus..."; - -/* The title of the cell showing the pump region */ -"Region" = "Region"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Fortsæt indgivelse"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Fortsætter"; - -/* Button title to retry sentry setup */ -"Retry" = "Forsøg igen"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Planlagt basal"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Vælg den type insulin, du skal bruge i denne pumpe."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Sender knaptryk "; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starter midlertidig basal"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Gennemført"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Afbryd insulintilførsel"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Afbrudt: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Afbryder"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synkroniser til aktuel tid"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Tiden på din pumpe er forskellig fra den aktuelle tid. Vil du opdatere tiden på din pumpe til det aktuelle tidspunkt?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Tidsændring registreret"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Forsøg"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Indstiller radio..."; - -/* Units for showing temp basal rate */ -"U/hr" = "E/t"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "ukendt"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Ukendt"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Brug MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Ja"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, synkroniser til det aktuelle klokkeslæt"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/da.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/da.lproj/MinimedPumpManager.strings deleted file mode 100644 index 5518996fe..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/da.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "RileyLink indstilling"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Find enhed"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Andre enheder"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Juster ikke uret i pumpens menu."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Tilbehør"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Tilslut enheder"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Pumpeur"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "Pumpens ID er den 6-cifrede nummeriske del af serienummeret (mærket SN eller S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "Pumpe ID"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Pumpen er klar til brug."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Indtast det 6-cifrede pumpe ID"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "Hvis du rejser til en anden tidszone i længere tid, kan du ændre pumpens tidszone i Loop’s indstillinger."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop vil holde din pumpes ur synkroniseret med din telefon i den tidszone, du er i nu."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "Pumpe region og farve er angivet som de sidste 3 bogstaver i modelnummeret (mærket REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Region og Farve"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Opsætning fuldført"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Pumpe-udsendelser"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "Tændt"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Pumpeindstilling"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Angiv pumperegion"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Pumpeindstilling"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop vil lytte efter status beskeder fra pumpen. Følg nedenstående skridt på pumpen, for at aktivere disse beskeder:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Hovedmenu"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/de.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/de.lproj/Localizable.strings deleted file mode 100644 index 325872788..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/de.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ basale Zeitplaneinträge\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Insulineinheiten verbleiben\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ IE verbleibend bei %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pumpenzeit einstellen"; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkali- und Lithiumbatterien zerfallen unterschiedlich schnell. Alkaline neigen dazu, einen linearen Spannungsabfall im Laufe der Zeit zu haben, während Lithium-Zellen-Batterien neigen dazu, die Spannung bis zur Hälfte ihrer Lebensdauer beizubehalten. Bei normaler Verwendung in einer Nicht-MySentry-kompatiblen Minimed (x22 / x15) Insulinpumpe, die Loop läuft, halten Alkali-Batterien etwa 4 bis 5 Tage. Lithium-Batterien halten zwischen 1-2 Wochen. Diese Auswahl verwendet unterschiedliche Batteriespannungs-Abnahmeraten für jeden der Batteriechemietypen und warnt den Benutzer, wenn eine Batterie ungefähr 8 bis 10 Stunden nach einem Fehler liegt."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Sind Sie sicher, dass Sie diese Pumpe löschen wollen?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Batterie: %1$@ Volt\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Beste Frequenz"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Bolusabgabe: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Abbrechen"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Temporäre Basalrate abbrechen"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Wechselt"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Zeit ändern"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Wählen Sie den Batterietyp, den Sie in Ihrer Pumpe verwenden, um besser über einen niedrigen Batteriestand informiert zu werden."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Konfiguration"; - -/* Button title to connect to pump during setup */ -"Connect" = "Verbinden"; - -/* Text for continue button */ -"Continue" = "Weiter"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Pumpe löschen"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Geräte"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "MySentry nicht verwenden"; - -/* The alert title for a resume error */ -"Error Resuming" = "Fehler beim Fortfahren"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Fehler beim Unterbrechen"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Fehler beim Synchronisieren der Zeit"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Glukosewerte abrufen…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Verlauf abrufen…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Pumpenmodell abrufen…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Firmware-Version"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulinabgabe\nunterbrochen"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulinabgabe"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Die Insulinabgabe kann von der Pumpe bestimmt werden, indem entweder die Ereignishistorie interpretiert wird oder das Reservoirvolumen über die Zeit verglichen wird. Das Lesen der Ereignishistorie ermöglicht eine genauere Statusgrafik und das Hochladen aktueller Behandlungsdaten in Nightscout, auf Kosten einer schnelleren Pumpenbatterieentleerung und der Möglichkeit einer höheren Funkfehlerrate im Vergleich zum Lesen des Reservoirvolumens. Wenn das ausgewählte Gerät aus irgendeinem Grund nicht verwendet werden kann, versucht das System, auf die andere Option zurückzugreifen."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Verbleibendes Insulin"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Insulintyp"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Die Medtronic-Pumpenmodelle 523, 723, 554 und 754 verfügen über eine Funktion namens \"MySentry\", die in regelmäßigen Abständen den Füllstand des Reservoirs und der Pumpenbatterie meldet. Das Abhören dieser Übertragungen ermöglicht es Loop, weniger häufig mit der Pumpe zu kommunizieren, was die Lebensdauer der Pumpenbatterie verlängern kann. Bei Verwendung dieser Funktion bleibt Ihr RileyLink jedoch länger wach und verbraucht mehr von der eigenen Batterie. Die Aktivierung dieser Funktion kann die Lebensdauer der Pumpenbatterie verlängern, während die Deaktivierung der Funktion die Lebensdauer der RileyLink-Batterie verlängern kann. Diese Einstellung wird bei anderen Pumpenmodellen ignoriert."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Nein"; - -/* Message display when no response from tuning pump */ -"No response" = "Keine Antwort"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nein, Pumpe so lassen wie sie ist"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "Gehen Sie auf Ihrer Pumpe zum Menü \"Geräte anschließen\" und wählen Sie „Geräte finden\".\n\nHauptmenü Insulinpumpe >\nZusatzfunktionen >\nGeräte anschließen >\nAndere Geräte >\nEin >\nGerät finden"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Bevorzugte Datenquelle"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Verbleibende Pumpenbatterie"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Typ Pumpenbatterie"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pumpen-ID"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Uhrzeit der Pumpe"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Basalzeitplan lesen…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Pumpenstand lesen…"; - -/* The title of the cell showing the pump region */ -"Region" = "Region"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Abgabe fortsetzen"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Fortsetzen"; - -/* Button title to retry sentry setup */ -"Retry" = "Wiederholen"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Geplante Basalrate"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Wählen Sie die Art des Insulins aus, die Sie in dieser Pumpe verwenden möchten."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Sende Knopfdruck…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starten der temporären Basalrate"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Erfolgreich"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Abgabe unterbrechen"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Unterbrochen: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Unterbrechen"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Mit aktueller Uhrzeit synchronisieren."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Die Uhrzeit Ihrer Pumpe unterscheidet sich von Ihrer aktuellen Uhrzeit. Möchten Sie die Uhrzeit Ihrer Pumpe auf Ihre aktuelle Uhrzeit aktualisieren?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Änderung der Uhrzeit erkannt"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Versuche"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Frequenz abstimmen…"; - -/* Units for showing temp basal rate */ -"U/hr" = "IE/h"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "unbekannt"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Unbekannt"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "MySentry verwenden"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Ja"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, mit aktueller Zeit synchronisieren"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/de.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/de.lproj/MinimedPumpManager.strings deleted file mode 100644 index b9317e9b3..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/de.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "RileyLink Einrichten"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Gerät finden"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Andere Geräte"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Ändern Sie nicht die Zeit in Ihrem Pumpenmenü."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Dienstprogramme"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Geräte verbinden"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Uhrzeit der Pumpe"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "Die Pumpen-ID ist der 6-stellige numerische Teil der Seriennummer (gekennzeichnet als SN oder S / N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "Pumpen-ID"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Ihre Pumpe ist betriebsbereit."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Geben Sie die 6-stellige Pumpen-ID ein"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "Wenn Sie für längere Zeit in eine andere Zeitzone verreisen, kann die Zeitzone der Pumpe jederzeit über das Einstellungsmenü von Loop geändert werden."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop synchronisiert die Uhrzeit Ihrer Pumpe mit der Uhrzeit Ihres Smartphones in Ihrer aktuellen Zeitzone."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "Die Region und die Farbe der Pumpe sind mit den letzten 3 Buchstaben in der Modellnummer bezeichnet (REF-Nummer in der Kennzeichnung der Pumpe)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Region und Farbe"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Einrichtung abgeschlossen"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Datenübertragung der Pumpe"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "An"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Einstellungen der Pumpe"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Geben Sie die Region der Pumpe ein"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Einstellungen der Pumpe"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop wird die Statusberichte Ihrer Pumpe überwachen. Führen Sie die nachfolgenden Schritte in Ihrer Pumpe aus, um diese Statusberichte einzuschalten:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Hauptmenü"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/en.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/en.lproj/Localizable.strings deleted file mode 100644 index ebe3f7138..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/en.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ basal schedule entries\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Units of insulin remaining\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Are you sure you want to delete this Pump?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Battery: %1$@ volts\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Best Frequency"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Bolusing: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Cancel"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Canceling Temp Basal"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Changing"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Changing time…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Choose the type of battery you are using in your pump for better alerting about low battery conditions."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Configuration"; - -/* Button title to connect to pump during setup */ -"Connect" = "Connect"; - -/* Text for continue button */ -"Continue" = "Continue"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Delete Pump"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Devices"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Do not use MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Resuming"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspending"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Error Syncing Time"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Fetching glucose…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Fetching history…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Fetching pump model…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Firmware Version"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Insulintyp"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "No"; - -/* Message display when no response from tuning pump */ -"No response" = "No response"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Preferred Data Source"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Pump Battery Remaining"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Pump Battery Type"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pump ID"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Reading basal schedule…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Reading pump status…"; - -/* The title of the cell showing the pump region */ -"Region" = "Region"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Resume Delivery"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Resuming"; - -/* Button title to retry sentry setup */ -"Retry" = "Retry"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Select the type of insulin that you will be using in this pump."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Sending button press…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starting Temp Basal"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Succeeded"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspend Delivery"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Suspended: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspending"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Time Change Detected"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Trials"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Tuning radio…"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hr"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "unknown"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Unknown"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Use MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Yes"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/en.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/en.lproj/MinimedPumpManager.strings deleted file mode 100644 index e05f87473..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/en.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,74 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "RileyLink Setup"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Find Device"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Other Devices"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Do not change the time using your pumpʼs menu."; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Pump Clock"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Enter the 6-digit pump ID"; - -/* Class = "UILabel"; text = "Review your pump settings below. You can change these settings at any time in Loopʼs Settings screen."; ObjectID = "HfQ-fG-8vO"; */ -"HfQ-fG-8vO.text" = "Review your pump settings below. You can change these settings at any time in Loopʼs Settings screen."; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Setup Complete"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Pump Setup"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Pump Setup"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Main Menu"; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Utilities"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Connect Devices"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "Pump ID"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Your pump is ready for use."; - -/* Class = "UITableViewController"; title = "Pump Settings"; ObjectID = "iQZ-kT-QUm"; */ -"iQZ-kT-QUm.title" = "Pump Settings"; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Region and Color"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Pump Broadcasts"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "On"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Enter the pump region"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/es.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/es.lproj/Localizable.strings deleted file mode 100644 index 67b765f79..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/es.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ entradas de configuración basal\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Unidades de insulina restantes\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "quedan %1$@ unidades a las %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Ajustando la hora de la bomba..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Las baterías alcalinas y de litio se degradan en ritmos distintos. La alcalinas tienden a tener una baja de voltaje linear en el tiempo mientras que las de litio tienden a mantener un voltaje hasta que pasan la mitad de su tiempo de vida. Bajo condiciones normales en una micro-infusora no compatible con MySentry ( x22/x15) siendo utilizado con Loop, las baterías alcalinas durarán aproximadamente de 4 a 5 días. Las baterías de litio durarán de una a dos semanas. Esta selección utilizará diferentes rangos de decadencia para el voltaje de cada una de las bataerías y alertará al usuario cuando la batería tenga aproximadamente de 8 a 10 horas restantes de vida."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "¿Está seguro de que desea eliminar esta bomba?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Batería: %1$@ voltios\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Mejor frecuencia"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Bolo en progreso: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Cancelar"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Cancelación de basal temporal"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Cambiando"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Cambiando hora..."; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Elija el tipo de batería que está utilizando en su bomba para una mejor alerta sobre las condiciones de batería baja."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Configuración"; - -/* Button title to connect to pump during setup */ -"Connect" = "Conectar"; - -/* Text for continue button */ -"Continue" = "Continuar"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Eliminar Microinfusora"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Dispositivos"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "No utilice MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Reanudando"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspendiendo"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Error de sincronización de tiempo"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Obtener glucosa…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Obtener historial…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Obtener modelo de microinfusora…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Versión del programa"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulina Suspendida"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "La entrega de insulina puede ser determinada por la microinfusora interpretando los eventos históricos o comparando el volúmen del reservorio sobre el tiempo. Leer los eventos históricos permite una gráfica de status mas exacta y permite subir tratamientos actualizados a Nightscout, con el costo de una menor duración de la batería y la posiblidad de mayores errores de radio comparado con leer solamente el volúmen del reservorio. Si la fuente seleccionada no puede ser utilizada por cualquier motivo, el sistema intentará utilizar la otra opción."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulina restante"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Tipo de Insulina"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Los modelos de bomba Medtronic 523, 723, 554 y 754 tienen una función llamada 'MySentry' que transmite periódicamente los niveles de la batería y del del depósito de la bomba. Escuchar estas transmisiones permite que Loop se comunique con la bomba con menos frecuencia, lo que puede aumentar la duración de la batería de la bomba. Sin embargo, cuando se usa esta función, el RileyLink permanece despierto la mayor parte del tiempo y usa más de su propia batería. Habilitar esto puede prolongar la duración de la batería de la bomba, mientras que deshabilitarlo puede prolongar la duración de la batería de RileyLink. Este ajuste se ignora para otros modelos de bomba."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "No"; - -/* Message display when no response from tuning pump */ -"No response" = "No respuesta"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, mantenga la bomba como está"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Fuente de Datos Preferida"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Pump Battery Remaining"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Tipo de batería de microinfusora"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID de Bomba"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Hora de la bomba"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Obteniendo perfil basal…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Obteniendo estada de microinfusadora…"; - -/* The title of the cell showing the pump region */ -"Region" = "Región"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Resumir la infusión"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Resumiendo"; - -/* Button title to retry sentry setup */ -"Retry" = "Reintentar"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Insulina basal programada"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Seleccione el tipo de insulina que utilizará en esta bomba."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Enviando presion de botón…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Inicio de basal temporal"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Logrado"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspender la infusión"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Suspendido: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspendiendo"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sincronizar con la hora actual"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "La hora de la bomba es diferente de la hora actual. Desea actualizar la hora de su bomba a la hora actual?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Cambio de hora detectado"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Pruebas"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Sintonizando frecuencia de radio…"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hra"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "unknown"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Desconocido"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Usar MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Sí"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Sí, sincronizar con la hora actual"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/es.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/es.lproj/MinimedPumpManager.strings deleted file mode 100644 index 14e22ed04..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/es.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "Configuración de RileyLink"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Encontrar Dispositivo"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Otros Dispositivos"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "No cambies la hora utilizando el menú de tu microinfusora."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Utilidades"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Conectar Dispositivos"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Reloj de Microinfusora"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "El número de ID de la microinfusora es la porción de 6 dígitos del número serial (indicados como SN o S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "ID de Bomba"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Tu microinfusora está lista para usarse."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Ingrese ID de 6 dígitios de la microinfusora"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "En caso de viajar a una zona horaria distinta por un periodo extendido de tiempo, podrás cambiar la zona horaria de la microinfusora en cualquier momento a través de la pantalla de Configuración de Loop."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop mantendrá el reloj de tu microinfusora sincronizado con tu teléfono en la zona horaria en la que te encuentres ahora."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "La región de la microinfusora y el color están indicados en las tres últimas letras del número de modelo (indicados como REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Región y Color"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Instalación completada"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Pump Broadcasts"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "Encendido"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Configuración de Microinfusora"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Ingresa la región de la Microinfusora"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Configuración de Microinfusora"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop escuchará mensajes de estado enviados por tu microinfusora. Sigue los pasos enlistados a continuación en tu microinfusora para habilitar estos mensajes:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Menú Principal"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/fi.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/fi.lproj/Localizable.strings deleted file mode 100644 index 408f9ae6d..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/fi.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@ U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ basaaliohjelman kirjausta\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ insuliiniyksikköä jäljellä\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ yksikköä jäljellä klo %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkali- ja litiumparistot tyhjenevät eri nopeudella. Alkaliparistojen varaus vähenee yleensä lineaarisesti ajan kuluessa, kun taas litiumparistot ylläpitävät yleensä varaustaan korkeana kunnes käyttöaika on noin puolessa välissä. Normaalilla käytöllä Minimed (x22/x15) insuliinipumppu toimii Loop-käytössä alkaliparistolla noin 4–5 päivää. Litiumparistot kestävät 1–2 viikkoa. Tämä valinta näyttää pariston varauksen vähenemisnopeuden sen perusteella kumpi paristotyyppi on valittu ja varoittaa käyttäjää, kun pariston käyttöaika on loppumassa noin 8–10 tunnin kuluessa"; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Are you sure you want to delete this Pump?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Paristo: %1$@ volttia\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Paras taajuus"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Annostellaan bolus: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Kumoa"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Kumotaan tilapäinen basaali"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Changing"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Muutetaan aikaa…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Choose the type of battery you are using in your pump for better alerting about low battery conditions."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Määritykset"; - -/* Button title to connect to pump during setup */ -"Connect" = "Yhdistä"; - -/* Text for continue button */ -"Continue" = "Jatka"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Poista pumppu"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Laitteet"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Do not use MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Virhe jatkamisessa"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Virhe pysäytyksessä"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Error Syncing Time"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Haetaan glukoosiarvo…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Haetaan viimeaikaisia tapahtumia…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Haetaan pumpun mallia…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Laiteohjelmiston versio"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Pumpun annostelemat insuliinimäärät on mahdollista määrittää joko tulkitsemalla tapahtumahistoriaa tai arvioimalla pumppusäiliön insuliinimäärää ajan kuluessa. Tapahtumahistorian lukeminen antaa tarkemman kuvan tilanteesta ja mahdollistaa ajantasaisen tiedonsiirron Nightscoutiin, mutta toisaalta tämä kuluttaa pumpun paristoa nopeammin ja lisää radiovirheiden todennäköisyyttä siihen verrattuna, että luettaisiin ainoastaan pumppusäiliössä olevan insuliinin määrää. Jos valittua lähdettä ei voida mistä tahansa syystä käyttää, järjestelmä pyrkii käyttämään toista vaihtoehtoa."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Insuliinityyppi"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "No"; - -/* Message display when no response from tuning pump */ -"No response" = "Ei vastausta"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "Mene pumppusi Etsi laite -näytölle ja valitse \"Etsi laite\".\n\n Päävalikko >\nTyökalut >\nYhdistä laitteet >\nMuut laitteet >\nPäällä >\nEtsi laite"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Ensisijainen tietolähde"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Pump Battery Remaining"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Pumpun paristotyyppi"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pumpun tunniste"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Luetaan basaaliohjelmaa…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Luetaan pumpun tilaa…"; - -/* The title of the cell showing the pump region */ -"Region" = "Alue"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Jatka annostelua"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Jatketaan"; - -/* Button title to retry sentry setup */ -"Retry" = "Yritä uudelleen"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Ohjelmoitu basaali"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Valitse insuliinin tyyppi, jota käytät tässä pumpussa."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Lähetetään napin painallusta…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Aloitetaan tilapäinen basaali"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Onnistui"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Pysäytä annostelu"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Annostelu pysäytetty: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Pysäytetään"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Time Change Detected"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Yritykset"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Säädetään radiota…"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/h"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "unknown"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Tuntematon"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Use MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Yes"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/fi.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/fi.lproj/MinimedPumpManager.strings deleted file mode 100644 index 8c76bdacf..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/fi.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "RileyLink-asennus"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Etsi laite"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Muut laitteet"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Älä muuta kellonaikaa käyttämällä pumpun omaa valikkoa."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Apuohjelmat"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Yhdistä laitteet"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Pumpun kello"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "Pumpun tunniste on 6-numeroinen osa sarjanumeroa (alkaa SN tai S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "Pumpun tunniste"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Pumppu on käyttövalmis."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Syötä 6-numeroinen pumpun tunniste"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "Jos matkustat toiselle aikavyöhykkeelle pidemmäksi aikaa, voit muuttaa pumpun aikavyöhykkeen milloin tahansa Loopin Asetukset-näkymässä."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop synkronoi pumpun kellon puhelimesi kanssa samalle aikavyöhykkeelle sijaintisi perusteella."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "Pumpun alue ja väri on merkitty kolmella viimeisellä kirjaimella mallinumeron lopussa (nimetty REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Alue ja väri"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Asennus valmis"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Pumpun lähetykset"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "Päällä"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Pumpun asennus"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Syötä pumpun alue"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Pumpun asennus"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop kuuntelee pumpun lähettämiä tilaviestejä. Seuraa alla mainittuja ohjeita ottaaksesi nämä viestit käyttöön pumpussasi:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Päävalikko"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/fr.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/fr.lproj/Localizable.strings deleted file mode 100644 index c7a1b7abf..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/fr.lproj/Localizable.strings +++ /dev/null @@ -1,226 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ entrées du programme basal\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ unités d’insuline restantes\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unités restantes à %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Ajustement de l'horloge de la pompe..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Les piles Alkaline et Lithium se vident à des vitesses différentes. Les Alkalines tendent à avoir une tension qui décroit de façon linéaire alors que les piles Lithium maintiennent leur tension jusqu’à la moitiée de leur durée de vie. Lors d’un usage normale de Loop avec pompe compatible Non-MySentry Minimed (x22/x15), les piles Alkalines durent environ 4-5 jours. Les piles Lithium durent 1-2 semaines. Cette option utilisera différents modèles en fonction du type de pile et alertera l’utilisateur quand la pile sera à 8-10 heures de sa fin de vie. "; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Voulez-vous vraiment supprimer cette pompe?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Pile: %1$@ volts\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Meilleure Fréquence"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Bolus en cours: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Annuler"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Annulation du débit basal temporaire"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Changement en cours..."; - -/* Progress message for changing pump time. */ -"Changing time…" = "Changement de l’heure..."; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Choisissez le type de batterie que vous utilisez dans votre pompe pour une meilleure alerte en cas de batterie faible."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Configuration"; - -/* Button title to connect to pump during setup */ -"Connect" = "Relier"; - -/* Text for continue button */ -"Continue" = "Continuer"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Supprimer la pompe"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Dispositifs"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Ne pas utiliser MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Erreur lors de la reprise"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Erreur lors de la suspension"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Erreur de synchronisation de l'heure"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Obtention des glycémies …"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Obtention de l’historique …"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Obtention du modèle de pompe…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Version du micrologiciel"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insuline\nSuspendue"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Administration de l'insuline"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Les données d’administration de l’insuline sont obtenues de la pompe en regardant l’historique des événements ou en comparant le niveau du réservoir avant/après. Récupérer l’historique des événements permet d'obtenir un graphique des donnés plus fiable ainsi qu’un téléchargement plus à jour sur Nightscout, au prix d’une décharge plus rapide de la pile et d'un taux d'erreur radio plus élevé comparé à la lecture seule du niveau du réservoir. Si une de ces options ne marche pas, le système essayera de revenir à l’autre option par défaut."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insuline restante"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Type d'insuline"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Les modèles de pompe Medtronic 523, 723, 554 et 754 sont dotés d'une fonction appelée \"MySentry\" qui émet périodiquement les niveaux de batterie du réservoir et de la pompe. Capter ces émissions permet à Loop de communiquer moins fréquemment avec la pompe, ce qui peut augmenter la durée de vie de la batterie de la pompe. Cependant, lorsque cette fonction est utilisée, le RileyLink reste actif plus longtemps et utilise davantage sa propre batterie. L'activation de cette fonction peut prolonger la durée de vie de la batterie de la pompe, tandis que sa désactivation peut prolonger la durée de vie de la batterie du RileyLink. Ce paramètre est ignoré pour les autres modèles de pompe."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Non"; - -/* Message display when no response from tuning pump */ -"No response" = "Pas de réponse"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Non, garder la pompe telle quelle"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "User -vertaal naar Frans inclusief codes: Key: On your pump, go to the Find Device screen and select \\\"Find Device\\\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device -On your pump, go to the Find Device screen and select \\\"Find Device\\\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device -Pump find device instruction - -ChatGPT -Clé : Sur votre pompe, allez à l'écran Rechercher un appareil et sélectionnez\\ \"Rechercher un appareil\\\".\n\nMenu principal >\nUtilitaires >\nConnecter les appareils >\nAutres appareils >\nActivé >\nRechercher un appareil\n\nSur votre pompe, allez à l'écran Rechercher un appareil et sélectionnez \\ \"Rechercher un appareil\\\".\n\nMenu principal >\nUtilitaires >\nConnecter les appareils >\nAutres appareils >\nActivé >\nRechercher un appareil\n\nInstructions de recherche d'appareil de la pompe"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Source de données préférée"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Batterie Pompe restante"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Type de pile dans la pompe"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID de la pompe"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Heure de la pompe"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Lecture du programme basal…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Lecture de l’état de la pompe…"; - -/* The title of the cell showing the pump region */ -"Region" = "Région"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Reprendre l'administration"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Reprise en cours"; - -/* Button title to retry sentry setup */ -"Retry" = "Réessayer"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Basal programmé"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Sélectionnez le type d'insuline que vous utiliserez dans cette pompe."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Envoi d'une pression sur le bouton…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Démarrage basal temporaire"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Réussi"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspendre l'administration"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Suspendu: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspension en cours"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchroniser avec l'heure actuelle"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "L'heure de votre pompe est différente de l'heure actuelle. Voulez vous mettre à jour l'heure de votre pompe avec l'heure actuelle ?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Changement d'heure détecté"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Essais"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Regulation de la fréquence radio…"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/h"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "inconnu"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Inconnu"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Utiliser MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Oui"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Oui, synchroniser avec l'heure actuelle"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/fr.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/fr.lproj/MinimedPumpManager.strings deleted file mode 100644 index 522ad1eb1..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/fr.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "Configuration de RileyLink"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Découvrir dispositif"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Autres dispositifs"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Ne changez pas l’heure en utilisant le menu de votre pompe."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Utilitaires"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Connecter des dispositifs"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Horloge de la pompe"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "L’ID de la pompe correspond à la partie numérique à 6 chiffres du numéro de série (étiquetée SN ou S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "ID de la pompe"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Votre pompe est prête à l’emploi."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Entrée l’ID de pompe de 6 chiffres"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "Si vous voyagez dans un fuseau horaire différent pendant une période prolongée, vous pouvez modifier le fuseau horaire de la pompe à tout moment dans l’écran Paramètres de Loop."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop gardera l’horloge de votre pompe synchronisée avec votre téléphone dans le fuseau horaire où vous vous trouvez maintenant."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "La région et la couleur de la pompe sont désignées par les 3 dernières lettres du numéro de modèle (étiquetées REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Région et Couleur"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "L’installation est terminée"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Transmissions de la pompe"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "Activé"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Configuration de la Pompe"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Entrez la région de la pompe"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Configuration de la Pompe"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop écoutera les messages d’état envoyés par votre pompe. Suivez les étapes ci-dessous sur votre pompe pour activer ces messages:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Menu Principal"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/he.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/he.lproj/Localizable.strings deleted file mode 100644 index 88083e091..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/he.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ basal schedule entries\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Units of insulin remaining\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Are you sure you want to delete this Pump?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Battery: %1$@ volts\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Best Frequency"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Bolusing: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Cancel"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Canceling Temp Basal"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Changing"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Changing time…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Choose the type of battery you are using in your pump for better alerting about low battery conditions."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Configuration"; - -/* Button title to connect to pump during setup */ -"Connect" = "Connect"; - -/* Text for continue button */ -"Continue" = "Continue"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Delete Pump"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Devices"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Do not use MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Resuming"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspending"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Error Syncing Time"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Fetching glucose…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Fetching history…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Fetching pump model…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Firmware Version"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Insulintyp"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "No"; - -/* Message display when no response from tuning pump */ -"No response" = "No response"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Preferred Data Source"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Pump Battery Remaining"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Pump Battery Type"; - -/* The title text for the pump ID config value */ -"Pump ID" = "מספר זיהוי המשאבה"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Reading basal schedule…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Reading pump status…"; - -/* The title of the cell showing the pump region */ -"Region" = "Region"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Resume Delivery"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Resuming"; - -/* Button title to retry sentry setup */ -"Retry" = "Retry"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Select the type of insulin that you will be using in this pump."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Sending button press…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starting Temp Basal"; - -/* A message indicating a command succeeded */ -"Succeeded" = "בוצע בהצלחה"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspend Delivery"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Suspended: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspending"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "בצע עדכון לשעה הנוכחית"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "השעה במשאבה שלך שונה מהשעה הנוכחית. האם ברצונך לעדכן את השעה במשאבה לשעה הנוכחית?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "זוהה שינוי באיזור הזמן"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Trials"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Tuning radio…"; - -/* Units for showing temp basal rate */ -"U/hr" = "יח׳/שעה"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "unknown"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Unknown"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Use MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "כן"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/he.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/he.lproj/MinimedPumpManager.strings deleted file mode 100644 index a3e63442f..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/he.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "RileyLink Setup"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Find Device"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Other Devices"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Do not change the time using your pumpʼs menu."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Utilities"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Connect Devices"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Pump Clock"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "מספר זיהוי המשאבה הוא ששת הספרות של מספר הסידורי (רשום כ-SN או S/N)"; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "מספר זיהוי המשאבה"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Your pump is ready for use."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "הזן את מספר זיהוי המשאבה בן 6 הספרות"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Region and Color"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Setup Complete"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Pump Broadcasts"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "דולק"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Pump Setup"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Enter the pump region"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Pump Setup"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Main Menu"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/hi.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/hi.lproj/Localizable.strings deleted file mode 100644 index cee529e13..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/hi.lproj/Localizable.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* The title of the cancel action in an action sheet */ -"Cancel" = "निरस्त"; - -/* Text for continue button */ -"Continue" = "जारी"; - -/* The title of the cell showing device name */ -"Name" = "नाम"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/hu.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/hu.lproj/Localizable.strings deleted file mode 100644 index 945bb50d8..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/hu.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ basal schedule entries\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Units of insulin remaining\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Are you sure you want to delete this Pump?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Battery: %1$@ volts\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Best Frequency"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Bolusing: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Mégse"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Canceling Temp Basal"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Changing"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Changing time…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Choose the type of battery you are using in your pump for better alerting about low battery conditions."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Beállítások"; - -/* Button title to connect to pump during setup */ -"Connect" = "Csatlakozás"; - -/* Text for continue button */ -"Continue" = "Continue"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Delete Pump"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Eszközök"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Do not use MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Resuming"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspending"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Error Syncing Time"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Fetching glucose…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Fetching history…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Fetching pump model…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Firmware Version"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Insulintyp"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Nem"; - -/* Message display when no response from tuning pump */ -"No response" = "No response"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Preferred Data Source"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Pump Battery Remaining"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Pump Battery Type"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pump ID"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Reading basal schedule…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Reading pump status…"; - -/* The title of the cell showing the pump region */ -"Region" = "Region"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Resume Delivery"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Resuming"; - -/* Button title to retry sentry setup */ -"Retry" = "Retry"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Select the type of insulin that you will be using in this pump."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Sending button press…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starting Temp Basal"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Succeeded"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspend Delivery"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Suspended: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspending"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Time Change Detected"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Trials"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Tuning radio…"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/óra"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "unknown"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Ismeretlen"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Use MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Igen"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/hu.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/hu.lproj/MinimedPumpManager.strings deleted file mode 100644 index a44f54c69..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/hu.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ - -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "RileyLink Setup"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Find Device"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Other Devices"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Do not change the time using your pumpʼs menu."; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Pump Clock"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Enter the 6-digit pump ID"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Setup Complete"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Pump Setup"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Pump Setup"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Main Menu"; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Utilities"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Connect Devices"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "Pump ID"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Your pump is ready for use."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Region and Color"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Pump Broadcasts"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "On"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Enter the pump region"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/it.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/it.lproj/Localizable.strings deleted file mode 100644 index 0c1a79ae9..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/it.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ inserimento basale\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Unità insulina residua\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unità rimanenti alle ore %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Regolazione Orario Microinfusore..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Le batterie alcaline e al litio decadono a velocità diverse. Le batterie alcaline tendono ad avere una caduta di tensione lineare nel tempo mentre le batterie al litio tendono a mantenere la tensione fino a metà della loro durata. In condizioni di utilizzo normali con in esecuzione Loop, in un microinfusore d'insulina non compatibile con MySentry (x22/x15), le batterie alcaline durano dai 4 ai 5 giorni circa. Le batterie al litio durano tra 1-2 settimane. Questa selezione utilizzerà diverse velocità di decadimento della tensione della batteria per ciascuno dei tipi di chimica della batteria e avviserà l'utente quando una batteria si trova a circa 8-10 ore dall'esaurimento."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Sei sicuro di voler eliminare questo microinfusore?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Batteria: %1$@ volts\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "La migliore Frequenza"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Bolo in corso: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Annulla"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Annullamento Basale Temp"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Modifica"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Modifica ora in corso"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Seleziona il tipo di batteria che stai utilizzando nel microinfusore per ricevere più facilmente informazioni sulle condizioni della batteria."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Configurazione"; - -/* Button title to connect to pump during setup */ -"Connect" = "Collegarsi"; - -/* Text for continue button */ -"Continue" = "Continua"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Cancella Microinfusore"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Dispositivi"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Non utilizzare MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Errore durante la Ripresa"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Errore durante l’interruzione"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Errore durante la sincronizzazione"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Sincronizza glicemie…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Sincronizza storia…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Sincronizza modello micro…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Versione Firmware"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Erogazione Insulina sospesa"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulina Somministrata"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "L'insulina somministrata può essere determinata dalla pompa sia interpretando la cronologia eventi o confrontando il volume del serbatoio nel tempo. La lettura della cronologia degli eventi consente una statistica più accurata e trasmette dati sempre aggiornati a Nightscout, a discapito di un maggiore consumo di batteria e con la possibilità di incorrere in un maggior tasso di errore di comunicazione rispetto alla sola lettura del volume del serbatoio. Se la sorgente selezionata non può essere utilizzata per qualsiasi ragione, il sistema tenterà di ripiegare sull'altra opzione."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulina Rimanente"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Tipo d'insulina"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "I modelli di pompa Medtronic 523, 723, 554 e 754 dispongono di una funzione denominata \"MySentry\" che trasmette periodicamente i livelli della batteria del serbatoio e della pompa. L'ascolto di queste trasmissioni consente a Loop di comunicare meno frequentemente con il microinfusore, il che può aumentare la durata della batteria del microinfusore. Tuttavia, quando si utilizza questa funzione, RileyLink rimane sveglio per la maggior parte del tempo e utilizza più della propria batteria. Abilitare questa opzione può allungare la durata della batteria della pompa, mentre disabilitarla può allungare la durata della batteria di RileyLink. Questa impostazione viene ignorata per altri modelli di pompa."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "No"; - -/* Message display when no response from tuning pump */ -"No response" = "Nessuna risposta"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, mantienere la pompa così com'è"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "Sulla pompa, vai alla schermata Trova dispositivo e seleziona \"Trova dispositivo\".\n\nMenu principale >\nUtilities >\nConnetti Dispositivi >\nAltri Dispositivi >\nSu >\nTrova Dispositivi"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Fonte Dati"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Batteria Pompa Rimanente"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Tipo Batteria Microinfusore"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID microinfusore"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Orario Micro"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Lettura programma basale…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Lettura stato microinfusore…"; - -/* The title of the cell showing the pump region */ -"Region" = "Paese"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Riprendi erogazione"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Ripresa in corso"; - -/* Button title to retry sentry setup */ -"Retry" = "Riprova"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Basale Programmata"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Seleziona il tipo di insulina che utilizzerai in questo microinfusore."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Inviando prova pressione pulsante…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Attivazione velocità basale temporanea in corso"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Effettuato con successo"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Sospendi erogazione"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Sospeso: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Sospensione in corso"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sincronizza con l'ora corrente"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "l'orario del microinfusore e' diverso da quello del tempo attuale. Vuoi fare un controllo e cambiare l'orario del microinfusore con il tempo attuale?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Rilevato Cambio di orario "; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Prove"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Sintonizzazione radio…"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/ora"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "sconosciuto"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Sconosciuto"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Accoppia MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "sì"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Sì, sincronizza con l'ora corrente"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/it.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/it.lproj/MinimedPumpManager.strings deleted file mode 100644 index c502f06ae..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/it.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "Configurazione"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Trova Dispositivo"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Altri Device"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Non modificare l'ora utilizzando il menu del microinfusore."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Utilita'"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Connetti Device"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Orologio Microinfusore"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "L'ID del microinfusore e' il numero di 6 cifre del SN o S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "ID microinfusore"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Il microinfusore e' pronto per l'uso."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Inserire 6-cifre ID micro"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "Se stai viaggiando in un paese con un differente fuso orario, puoi cambiare il fuso orario del tuo microinfusore quando vuoi nel menu' impostazioni di Loop."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop sincronizzera' automaticamente l'orario impostato sul tuo microinfusore con quello del paese in cui ti trovi."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "La provenienza del microinfusore ed il colore sono descritti nelle ultime tre lettere del modello del tuo microinfusore (REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Provenienza e colore"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Impostazione completata"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Trasmissione Microinfusore"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "Acceso"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Impostazione Microinfusore"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Inserisci la provenienza del microinfusore"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Impostazione Microinfusore"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop sara' in attesa di messaggi di stato inviati dal microinfusore. Segui i successivi passaggi per abilitare questi messaggi:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Menu Principale"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/ja.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/ja.lproj/Localizable.strings deleted file mode 100644 index 135ce5dcd..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/ja.lproj/Localizable.strings +++ /dev/null @@ -1,147 +0,0 @@ -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "基礎パターン入力 %1$@回\n\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "インスリン 残り%1$@U\n\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%2$@の時点で %1$@ U 残っています"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "アルカリ電池とリチウム電池では消耗速度が異なります。アルカリは徐々に電力が落ちるのに対し、リチウムは電池生命の前半は電圧を保持します。MySentryに互換性のないMinimed (x22/x15)でループを使用する場合は、アルカリ電池は4~5日、リチウム電池は1~2週間使用できることが多いです。それぞれの電池の種類の電圧消耗速度を設定して、電池生命が約8~10時間になるとユーザに知らせます。"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "電池: %1$@ ボルト\n\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "最良周波数"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "ボーラス注入中: %1$@\n\n"; - -/* Cancel button title */ -"Cancel" = "キャンセル"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "一時基礎レートをキャンセルします"; - -/* Progress message for changing pump time. */ -"Changing time…" = "時間を変えています"; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "コンフィグレーション"; - -/* Button title to connect to pump during setup */ -"Connect" = "接続"; - -/* Text for continue button */ -"Continue" = "次へ"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "ポンプを削除"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "デバイス"; - -/* The alert title for a resume error */ -"Error Resuming" = "再開エラー"; - -/* The alert title for a suspend error */ -"Error Suspending" = "一時中止エラー"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "グルコースを取得しています..."; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "履歴を取得しています..."; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "ポンプモデルを取得しています ..."; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "ファームウェアバージョン"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "インスリン注入は、イベント履歴を解釈する、またはリザーバの残量を計ることにより決定されます。イベント履歴を読み取ることにより、ステータスグラフがより正確になり、Nightscoutに最新のトリートメントデータをアップロードできます。リザーバの残量のみを計るよりも、ポンプの電池寿命が短くなり、無線周波数のエラーが増える可能性があります。選択されているデータソースが何らかの事情により使えない場合は、システムはもう片方のソースを使用します。"; - -/* Message display when no response from tuning pump */ -"No response" = "反応なし"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "ポンプの Find Device 画面で「Find Device」を選択します。\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "推奨データソース"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "ポンプの電池の種類"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ポンプ ID"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "基礎パターンを読んでいます ..."; - -/* Progress message for reading pump status */ -"Reading pump status…" = "ポンプの状態を読んでいます ..."; - -/* The title of the cell showing the pump region */ -"Region" = "リージョン"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "注入を再開"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "再開中"; - -/* Button title to retry sentry setup */ -"Retry" = "やり直す"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "定期基礎"; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "ボタン押しを送信しています ..."; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "一時基礎を開始"; - -/* A message indicating a command succeeded */ -"Succeeded" = "成功"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "注入を一時停止"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "一時停止: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "一時停止中"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "トライ"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "無線を合わせています ..."; - -/* Units for showing temp basal rate */ -"U/hr" = "U/時"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "不明"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/ja.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/ja.lproj/MinimedPumpManager.strings deleted file mode 100644 index 74559859d..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/ja.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "RileyLink 設定"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "デバイスを探す"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "他のデバイス"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "ポンプのメニュー機能を使って日付時刻を変更しないでください。"; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "ユーティリティ"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "デバイスを接続"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "ポンプ時刻"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "ポンプIDはシリアル番号の 6桁の数字の部分です。(SNやS/Nで表示)"; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "ポンプ ID"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "ポンプを使えます"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "6桁のポンプ ID"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "時差がある海外へ旅行に行く時は、ループの設定画面からいつでもポンプの日付時刻を変更出来ます。."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "ループはiPhoneと同期して、あなたが今いる場所のタイムゾーンにポンプの日付時刻を同期し続けます。"; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "ポンプのリージョンと色は型番 (REFで表示)の最終の3文字で表されています。"; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "リージョンと色"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "設定完了"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "ポンプのブロードキャスト"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "オン"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "ポンプ設定"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "ポンプリージョンを入力"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "ポンプ設定"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "ループがポンプが発するステータスメッセージを聞き取ります。ポンプがメッセージを発せられるように次のステップにしたがって設定してください。"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "メインメニュー"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/nb.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/nb.lproj/Localizable.strings deleted file mode 100644 index 27d65bce3..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/nb.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ basalsprofilinnslag"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "Gjenstående %1$@ Enheter med insulin"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ enheter gjenstår ved %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Justerer pumpetid..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkaliske- og lithiumbatterier mister spenning med forskjellige kurver. Alkaliske har som regel en lineært minskende spenning, mens lithiumbatterier pleier å holde på spenningen gjennom omtrent halvparten av levetiden. Ved normalt bruk i en Non-MySentry kompatibel Minimed (x22/x15) insulinpumpe som kjører Loop, pleier alkaliske batterier å holde i 4 til 5 dager. Lithiumbatterier holder som regel 1-2 uker. Dette valget vil bruke forskjellige kurver for nedgang i batterispenning for hver av de forskjellige batteritypene, og varsle brukeren når batteriet er omtrent 8 til 10 timer fra å være tomt."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Er du sikker på at du vil slette denne pumpen?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Batteri: %1$@ volt\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Beste frekvens"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Gir bolus: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Avbryt"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Avbryter midlertidig basal"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Endrer"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Endrer tid..."; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Velg typen batteri du bruker i pumpen for bedre å varsle om lavt batteri."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Konfigurasjon"; - -/* Button title to connect to pump during setup */ -"Connect" = "Koble til"; - -/* Text for continue button */ -"Continue" = "Fortsett"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Slette pumpe"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Enheter"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Ikke bruk MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Feil ved gjenopptagelse"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Kunne ikke stoppe"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Feil ved synkroniseringstid"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Henter blodsukkerverdi…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Henter historikk…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Henter pumpemodell…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Firmware versjon"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulintilførsel utsatt"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulintilførsel"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Insulintilførsel kan hentes fra pumpa, enten ved å tolke hendelsehistorikken, eller ved å sammenligne reservoarvolumet over tid. Ved å lese hendelsehistorikken får man mer nøyaktig statuskurve og kan laste opp oppdaterte hendelser til Nightscout. Ulempen er høyere batteriforbruk i pumpa, og muligheten for større antall feil ved radiokommunikasjon - sammenlignet med å bare lese reservoarvolumet. Hvis den valgte kilden av noen grunn ikke kan brukes, vill systemet prøve den andre måten."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Gjenværende insulin"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Insulintype"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Medtronic-pumpemodellene 523, 723, 554 og 754 har en funksjon kalt 'MySentry' som med jevne mellomrom kringkaster reservoar- og pumpebatterinivåene. Når du lytter til disse sendingene, kan Loop kommunisere med pumpen sjeldnere, noe som kan øke pumpens batterilevetid. Men når du bruker denne funksjonen, holder RileyLink seg våken mer av tiden og bruker mer av sitt eget batteri. Aktivering av dette kan forlenge pumpens batterilevetid, mens deaktivering kan forlenge RileyLink-batteriets levetid. Denne innstillingen ignoreres for andre pumpemodeller."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Nei"; - -/* Message display when no response from tuning pump */ -"No response" = "Ingen svar"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nei, behold pumpen som den er"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "På pumpen, gå til \"Find Device\"-skjermen og velg \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Foretrukken datakilde"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Gjenværende pumpebatteri"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Type pumpebatteri"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pumpe ID"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pumpetid"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Leser basalplan…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Leser pumpestatus…"; - -/* The title of the cell showing the pump region */ -"Region" = "Region"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Gjenoppta leveranse"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Gjenopptar"; - -/* Button title to retry sentry setup */ -"Retry" = "Prøv på nytt"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Planlagt basal"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Velg hvilken type insulin du skal bruke i denne pumpen."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Sender tastetrykk…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starter temp-basal"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Suksess"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Pause leveranse"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Pauset: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Pauser"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synkroniser til gjeldende tid"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Klokken på pumpen er forskjellig fra gjeldende tid. Vil du oppdatere tiden på pumpen til gjeldende tid?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Tidsendring oppdaget"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Forsøk"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Stiller radiofrekvens…"; - -/* Units for showing temp basal rate */ -"U/hr" = "E/t"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "ukjent"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Ukjent"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Bruk MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Ja"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, Synkroniser til gjeldende tid"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/nb.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/nb.lproj/MinimedPumpManager.strings deleted file mode 100644 index 3cb300b13..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/nb.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "RileyLink-oppsett"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Finn enhet"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Andre enheter"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Ikke endre tiden via pumpemenyen."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Tilbehør"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Tilkoble enheter"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Pumpeklokke"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "Pumpe-ID er den 6-siffrede (tall) delen av serienummeret (merket som SN eller S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "Pumpe ID"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Din pumpe er klar for bruk."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Skriv 6-siffret pumpe-ID"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "Hvis du reiser til en annen tidssone for en lenger tid, kan du endre pumpens tidssone når som helst under innstillinger i Loop."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop holder din pumpes klokke synkronisert med din telefon til den tidssone du er i nå."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "Pumperegionen og farge er angitt som de 3 siste bokstavene i modellnummeret (merket som REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Region og farge"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Klargjøring ferdig"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Pumpe sender"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "På"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Pumpeinnstillinger"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Angi pumperegionen"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Pumpeinnstillinger"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop hører etter statusmeldinger sendt fra din pumpe. Følg trinnene nedenfor på din pumpe for å gjøre disse meldingene tilgjengelige:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Hovedmenu"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/nl.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/nl.lproj/Localizable.strings deleted file mode 100644 index 45da67350..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/nl.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ basaalschema-invoeren\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ eenheden insuline resterend\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ eenheden over om %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pomptijd aanpassen..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkaline en Lithium batterijen werken na verloop van tijd minder goed. Alkaline heeft de neiging om in de loop van de tijd een lineair spanningsverlies te hebben, terwijl lithium batterijen de neiging hebben om hun spanning te behouden tot halverwege hun levensduur. Bij normaal gebruik in een niet-MySentry-compatibele Minimed (x22/x15) insulinepomp met Loop, gaan Alkaline batterijen ongeveer 4 tot 5 dagen mee. Lithiumbatterijen gaan tussen de 1-2 weken mee. Deze selectie gebruikt verschillende leegloop snelheden voor batterijvoltage voor elk van de typen batterijen en waarschuwt de gebruiker wanneer een batterij ongeveer in 8 tot 10 uur leeg is."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Weet je zeker dat je deze pomp wilt verwijderen?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Batterij: %1$@ volt\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Beste frequentie"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Bolussen: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Annuleer"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Tijdelijk basaal annuleren"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Verandering"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Tijd aanpassen..."; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Kies het type batterij dat je gebruikt in je pomp om beter te kunnen waarschuwen voor een te laag batterij niveau."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Configuratie"; - -/* Button title to connect to pump during setup */ -"Connect" = "Verbinden"; - -/* Text for continue button */ -"Continue" = "Ga verder"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Verwijder de pomp"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Apparaten"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Gebruik MySentry niet"; - -/* The alert title for a resume error */ -"Error Resuming" = "Fout bij hervatten"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Fout bij onderbreken"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Fout bij synchroniseren tijd"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Glucosegegevens aan het ophalen…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Haal geschiedenis op…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Haal pompmodel op…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Firmwareversie"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insuline\nOnderbroken"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulinetoediening"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "De toediening van insuline kan worden vastgesteld met info van de pomp, ofwel door het logboek te bekijken ofwel door het reservoirvolume over een bepaalde tijd te vergelijken. Het lezen van het logboek zorgt voor een meer accurate statusgrafiek en het uploaden van up-to-date behandelingsgegevens naar Nightscout. Dit gaat ten koste van de batterij en er bestaat een grotere kans op fouten vanwege de draadloze verbinding vergeleken met het alleen lezen van het reservoirvolume. Als de geselecteerde bron om welke reden dan ook niet kan worden gebruikt, probeert het systeem terug te vallen op de andere optie."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Resterende insuline"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Insuline soort"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "De Medtronic-pompmodellen 523, 723, 554 en 754 hebben een functie genaamd 'MySentry' die periodiek het niveau van het reservoir en de pompbatterij uitzendt. Door deze signalen op te vangen, hoeft Loop minder vaak met de pomp te communiceren, waardoor de batterij van de pomp langer meegaat. Bij gebruik van deze functie blijft de RileyLink echter langer actief en gebruikt meer van zijn batterij. Als je dit inschakelt, gaat de batterij van de pomp langer mee en als je dit uitschakelt, gaat de batterij van de RileyLink langer mee. Deze instelling wordt genegeerd voor andere pompmodellen."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Nee"; - -/* Message display when no response from tuning pump */ -"No response" = "Geen reactie"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nee, laat de pomp ongewijzigd"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "Ga op je pomp naar het scherm 'Vind Apparaat' en selecteer \"Vind Apparaat\".\n\nHoofdmenu >\nHulpprogramma's >\nVerbind Apparaten >\nAndere Apparaten >\nAan >\nVind Apparaat"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Voorkeur gegevensbron"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Pompbatterij resterend"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Pompbatterijtype"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pompserienummer"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pomptijd"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Lees basaal schema…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Lees pomp gegevens…"; - -/* The title of the cell showing the pump region */ -"Region" = "Regio"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Hervat toediening"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Hervat"; - -/* Button title to retry sentry setup */ -"Retry" = "Opnieuw proberen"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Ingestelde basaal"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Selecteer het type insuline dat je in deze pomp gaat gebruiken."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Signaal 'Druk op knop' versturen"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Tijdelijk basaal starten"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Geslaagd"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Onderbreek toediening"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Onderbroken: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Onderbreken"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchroniseer met de huidige tijd"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "De tijd op je pomp is anders dan de huidige tijd. Wil je de tijd op je pomp bijwerken naar de huidige tijd?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Tijdsverschil ontdekt"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Pogingen"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Radio instellen…"; - -/* Units for showing temp basal rate */ -"U/hr" = "E/uur"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "onbekend"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Onbekend"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Gebruik MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Ja"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, synchroniseer met huidige tijd"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/nl.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/nl.lproj/MinimedPumpManager.strings deleted file mode 100644 index 354563cee..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/nl.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "RileyLink Installatie"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Zoek Apparaat"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Andere apparaten"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Verander de tijd niet via het menu van de pomp."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Hulpprogramma's"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Koppel apparaten"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Pomp klok"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "Het pompserienummer is het 6-cijferige gedeelte van het serienummer (aangegeven als SN of S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "Pompserienummer"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "De pomp is klaar voor gebruik."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Voer het 6-cijferige pompserienummer in"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "Als je voor een langere periode in een andere tijdzone verblijft, dan kun je altijd de tijdzone van de pomp veranderen in het instellingenscherm van Loop."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop zorgt ervoor dat de klok van je pomp gesynchroniseerd blijft met je telefoon in de tijdzone waarin je je nu bevindt."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "De regio en kleur van de pomp worden aangeduid in de laatste 3 letters van het modelnummer (gelabeld als REF)"; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Regio en kleur"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Configuratie Voltooid"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Pomp Signalen"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "Aan"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Pompconfiguratie"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Voer regio van de pomp in"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Pompconfiguratie"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop luistert naar statusberichten die door de pomp worden verzonden. Volg de stappen hieronder op de pomp om deze statusberichten in te schakelen:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Hoofdmenu"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/pl.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/pl.lproj/Localizable.strings deleted file mode 100644 index ff73fb8da..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/pl.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@J"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ wpisów dawki podstawowej\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ jednostek insuliny pozostało\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ jednostek pozostaje w %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Synchronizacja czasu pompy..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Baterie alkaliczne i litowe różnią się szybkością rozładowywania. Baterie alkaliczne mają tendencję do liniowego spadku napięcia w czasie, natomiast baterie litowe mają tendencję do utrzymywania napięcia do momentu osiągnięcia połowy żywotności. W trakcie normalnego korzystania z Loop w niekompatybilnej z MySentry pompie (x22/x15), czas życia baterii alkalicznych wynosi ok. 4-5 dni. Żywotność baterii litowych wynosi ok. 1-2 tygodni. Wybór odpowiedniego typu baterii pozwoli na wybranie lepszego algorytmu zużycia baterii, dzięki czemu Loop będzie mógł wysłać ostrzeżenie, gdy zostanie ok. 8-10 godzin do całkowitego rozładowania."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Czy na pewno chcesz usunąć tę pompę?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Bateria: %1$@ V\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Najlepsza częstotliwość"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Podawanie bolusa: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Anuluj"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Anulowanie tymczasowej dawki podstawowej"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Zmiana"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Zmiana czasu…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Wybierz typ baterii używanej w pompie, aby lepiej ostrzegać o niskim stanie baterii."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Konfiguracja"; - -/* Button title to connect to pump during setup */ -"Connect" = "Połącz"; - -/* Text for continue button */ -"Continue" = "Kontynuuj"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Usuń pompę"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Urządzenia"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Nie używaj MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Błąd wznawiania"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Błąd wstrzymywania"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Błąd synchronizacji czasu"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Pobieranie glukozy…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Pobieranie historii…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Pobieranie modelu pompy…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Wersja oprogramowania"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Podawanie insuliny zawieszone"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Podaż insuliny jest ustalana dzięki pobieraniu danych z pompy. Może się to odbywać na dwa sposoby: poprzez interpretację historii zdarzeń lub poprzez porównywanie objętości zbiornika na insulinę w czasie. Interpretacja historii zdarzeń pozwala na dokładniejsze odwzorowanie wykresu statusu i wysyłanie aktualnych danych dotyczących leczenia do Nightscouta. Odbywa się to kosztem szybszego zużycia baterii i większym ryzykiem błędu transmisji radiowej względem drugiego sposobu, czyli porównywania objętości zbiornika na insulinę w czasie. Jeśli wybrany sposób z jakiegoś powodu nie może być użyty, system podejmie próbę powrotu do drugiej opcji."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Pozostała ilość insuliny"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Rodzaj insuliny"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Modele pomp firmy Medtronic 523, 723, 554 i 754 są wyposażone w funkcję o nazwie „MySentry”, która okresowo wysyła informacje o stanie baterii i poziomie w zbiorniczku pompy. Odbiór tych informacji pozwala Loop na rzadszą komunikację z pompą, co może wydłużyć żywotność baterii pompy. Jednak podczas korzystania z tej funkcji RileyLink pracuje przez większą część czasu i zużywa więcej własnej baterii. Włączenie tej opcji może wydłużyć żywotność baterii pompy, a jej wyłączenie może wydłużyć żywotność baterii RileyLink. To ustawienie jest ignorowane w przypadku innych modeli pomp."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Nie"; - -/* Message display when no response from tuning pump */ -"No response" = "Brak odpowiedzi"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nie, pozostaw pompę bez zmian"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "W pompie przejdź do ekranu Znajdź urządzenie i wybierz opcję „Znajdź urządzenie”.\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Preferowane źródło danych"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Kondycja baterii"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Rodzaj baterii w pompie"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID pompy"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Czas pompy"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Sprawdzanie dawki podstawowej…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Sprawdzanie statusu pompy…"; - -/* The title of the cell showing the pump region */ -"Region" = "Region"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Wznów podawanie"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Wznawianie"; - -/* Button title to retry sentry setup */ -"Retry" = "Spróbuj ponownie"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Zaplanowana dawka podstawowa"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Wybierz rodzaj insuliny, której będziesz używać w pompie."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Wysyłanie polecenia wciśnięcia przycisku…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Rozpoczynanie tymczasowej dawki podstawowej"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Zakończone powodzeniem"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Wstrzymaj podawanie"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Zawieszona: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Wstrzymywanie"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchronizuj z bieżącym czasem"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Czas na pompie różni się od aktualnego czasu. Czy chcesz zaktualizować czas na pompie do aktualnego czasu?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Wykryto zmianę czasu"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Wyniki testu"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Dostrajanie radia…"; - -/* Units for showing temp basal rate */ -"U/hr" = "J/godz"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "nieznany"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Nieznany"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Użyj MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Tak"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Tak, zsynchronizuj z bieżącym czasem"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/pl.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/pl.lproj/MinimedPumpManager.strings deleted file mode 100644 index 8b60f48e0..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/pl.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "Konfiguracja RileyLink"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Znajdź urządzenie"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Inne urządzenia"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Nie zmieniaj godziny w menu swojej pompy."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Narzędzia"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Połącz urządzenia"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Zegar w pompie"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "ID pompy to 6-cyfrowy numer (oznaczony jako SN lub S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "ID pompy"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Twoja pompa jest gotowa do użycia."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Wprowadź 6-cyfrowy numer pompy"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "Jeśli podróżujesz do innej strefy czasowej, możesz ją zmienić w dowolnym momencie w zakładce Ustawienia."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop będzie synchronizował zegar w pompie z aktualną strefą czasową ustawioną w Twoim telefonie."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "Region i kolor pompy są oznaczone jako 3 ostatnie litery numeru modelu (który jest określony jako REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Region i kolor"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Konfiguracja zakończona"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Komunikaty pompy"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "Włącz"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Konfiguracja pompy"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Wprowadź region pompy"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Konfiguracja pompy"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop będzie nasłuchiwał komunikatów wysyłanych przez Twoją pompę. Postępuj zgodnie z poniższymi krokami (na Twojej pompie), aby umożliwić wysyłanie komunikatów:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Menu główne"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/pt-BR.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/pt-BR.lproj/Localizable.strings deleted file mode 100644 index 1d516ab7f..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ entradas de basal programadas\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Unidades de insulina restantes\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unidades restantes em %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Baterias alcalinas e de lítio descarregam de formas diferentes. Baterias alcalinas tendem a perder voltagem linearmente, enquanto baterias de célula de lítio tendem a manter a voltagem até metade de sua vida útil. Em condições normais de uso do Loop em uma bomba Minimed que não utiliza o MySentry (x22/x15), baterias alcalinas devem durar entre 4 e 5 dias. Baterias de lítio duram entre 1 e 2 semanas. Essa seleção vai utilizar diferentes taxas de descarregamento para cada tipo de bateria e alertar o usuário quando a bateria estiver entre 8 e 10 horas de falhar."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Are you sure you want to delete this Pump?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Bateria: %1$@ volts\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Melhor Frequência"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Injetando Bolus: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Cancelar"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Cancelar Basal Temporária"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Changing"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Alterando a hora..."; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Choose the type of battery you are using in your pump for better alerting about low battery conditions."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Configuração"; - -/* Button title to connect to pump during setup */ -"Connect" = "Conectar"; - -/* Text for continue button */ -"Continue" = "Continuar"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Deletar Bomba"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Dispositivos"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Do not use MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Erro ao Retomar"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Erro ao Suspender"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Error Syncing Time"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Buscando glicose…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "`Buscando histórico…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Buscando modelo da bomba..."; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Versão do Firmware"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "A quantidade de insulina utilizada pode ser determinada tanto interpretando o histórico de eventos quanto medindo a diferença no volume do reservatório. Ler a partir do histórico de eventos permite um gráfico de estado mais preciso e o envio de dados de tratamento mais atualizados para o Nightscout, mas com um maior gasto de bateria e com uma maior possibilidade de erros de transmissão, quando comparado com a leitura apenas do volume do reservatório. Se a fonte selecionada não puder ser utilizada por algum motivo, o sistema tentará a outra opção."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Insulintyp"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "No"; - -/* Message display when no response from tuning pump */ -"No response" = "Sem Resposta"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "Na sua Bomba, vá para a tela de encontrar dispositivos (Find Device) e selecione \"Encontrar Dispositivo\" (Find Device).\n\nMenu Principal >\nUtilitários (Utilities) >\nConectar Dispositivos (Connect Devices)\nOutros Dispositivos (Other Devices) >\nLigar (On) >\nEncontrar Dispositivo (Find Device)"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Fonte de Dados Preferido"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Pump Battery Remaining"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Tipo de Bateria da Bomba"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID da Bomba"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Lendo programação de basal…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Lendo estado da bomba…"; - -/* The title of the cell showing the pump region */ -"Region" = "Região"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Retomar Entrega"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Retomando"; - -/* Button title to retry sentry setup */ -"Retry" = "Tentar de Novo"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Basal Agendado"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Select the type of insulin that you will be using in this pump."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Enviando aperto do botão"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Iniciando Temp Basal"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Completo"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspender Entrega"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Suspenso: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspendendo"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Time Change Detected"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Tentativas"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Sintonizando frequência…"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hr"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "unknown"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Desconhecido"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Use MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Yes"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/pt-BR.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/pt-BR.lproj/MinimedPumpManager.strings deleted file mode 100644 index 2c231bd37..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/pt-BR.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "Configuração RileyLink"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Localizar Dispositivo"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Outro Dispositivo"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Não altere a hora utilizando o menu da sua bomba."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Utilidades"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Conectar Dispositivos"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Hora da Bomba"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "O ID da bomba é a parte numérica de 6 dígitos do número de série (etiquetado como SN ou S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "ID da Bomba"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Sua bomba está pronta para uso."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Digite o ID da bomba de 6 dígitos"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "Se você viajar para um fuso horário diferente por um longo período de tempo, poderá alterar o fuso horário da bomba a qualquer momento na tela Configurações do Loop."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop manterá o relógio da sua bomba sincronizado com o seu telefone no fuso horário em que você está agora."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "A região e a cor da bomba são indicadas como as três últimas letras do número do modelo (etiquetado como REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Região e Cor"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Instalação Concluída"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Transmissões da Bomba"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "Ligado"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Configuração da Bomba"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Entre com a região da bomba"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Configuração da Bomba"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop receberá as mensagens de status enviadas por sua bomba. Siga as etapas abaixo na sua bomba para ativar estas mensagens:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Título Principal"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/pt-PT.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/pt-PT.lproj/Localizable.strings deleted file mode 100644 index 82d828f7f..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/pt-PT.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ basal schedule entries\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Units of insulin remaining\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Are you sure you want to delete this Pump?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Battery: %1$@ volts\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Best Frequency"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Bolusing: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Cancelar"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Canceling Temp Basal"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Changing"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Changing time…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Choose the type of battery you are using in your pump for better alerting about low battery conditions."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Ajustes"; - -/* Button title to connect to pump during setup */ -"Connect" = "Conectar"; - -/* Text for continue button */ -"Continue" = "Continue"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Delete Pump"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Dispositivos"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Do not use MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Resuming"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspending"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Error Syncing Time"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Fetching glucose…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Fetching history…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Fetching pump model…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Firmware Version"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Insulintyp"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "No"; - -/* Message display when no response from tuning pump */ -"No response" = "No response"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Preferred Data Source"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Pump Battery Remaining"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Pump Battery Type"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pump ID"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Reading basal schedule…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Reading pump status…"; - -/* The title of the cell showing the pump region */ -"Region" = "Region"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Resume Delivery"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Resuming"; - -/* Button title to retry sentry setup */ -"Retry" = "Retry"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Select the type of insulin that you will be using in this pump."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Sending button press…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starting Temp Basal"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Succeeded"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspend Delivery"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Suspended: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspending"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Time Change Detected"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Trials"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Tuning radio…"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hr"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "unknown"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Unknown"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Use MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Yes"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/ro.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/ro.lproj/Localizable.strings deleted file mode 100644 index 8158e5029..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/ro.lproj/Localizable.strings +++ /dev/null @@ -1,227 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ intervale de insulină bazală\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Unități de insulină rămase\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unități rămase la %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Reglarea timpului pompei..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Baterii alcaline și cele cu litiu se descarcă diferit. La cele alcaline, tensiunea scade proporțional cu descărcare, pe când cele cu litiu mențin tensiunea normală pană aproape de descărcare completă. În condiții normale pe pompele Minimed care nu sunt compatibile cu MySentry (x22/x15), rulând Loop, bateriile alcaline durează 4-5 zile. Bateriile cu litiu durează aproximativ 1-2 săptămâni. Prin această opțiune se alege modul de calcul al descărcării bateriilor în funcție de tipul lor, astfel încât utilizatorul să fie anunțat cu 8-10 ore înainte de descărcare completă."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Sunteți sigur că doriți să ștergeți această pompă?"; - -/* No comment provided by engineer. */ -"Battery Chemistry" = "Chimia bateriei"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Baterie: %1$@ volți\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Frecvența optimă"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Se livrează: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Renunță"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Oprește bazala temporară"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Se modifică"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Se modifică ora…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Alegeți tipul de baterie pe care îl utilizați în pompă pentru o mai bună avertizare cu privire la condițiile scăzute ale bateriei."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Configurare"; - -/* Button title to connect to pump during setup */ -"Connect" = "Conectare"; - -/* Text for continue button */ -"Continue" = "Continuă"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Elimină pompa"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Dispozitive"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Nu utilizați MySentry"; - -/* No comment provided by engineer. */ -"Done" = "Realizat"; - -/* The alert title for a resume error */ -"Error Resuming" = "Eroare în timpul reluării"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Eroare în timpul suspendării"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Eroare la sincronizarea timpului"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Obținerea glicemiei…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Obținerea istoricului…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Obținerea modelului pompei…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Versiunea Firmware"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Administrarea insulinei suspendată"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Livrarea insulinei poate fi determinată din interpretarea istoricului citit din pompă sau analizând nivelul rezervorului în timp. Citirea istoricului de evenimente permite o construcție mai exacta a graficului și uploadarea datelor actualizate în Nightscout cu prețul descărcării mai rapide a bateriei pompei si a probabilității mai mari de erori de transmisie radio, comparând cu citire numai a nivelului rezervorului. Dacă dintr-o cauză sau alta sistemul nu va reuși să folosească opțiunea aleasă, se va încerca revenirea la cealaltă posibilitate."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulină rămasă"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Tipul de insulină"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Modelele de pompe Medtronic 523, 723, 554 și 754 au o funcție numită \"MySentry\" care transmite periodic nivelul rezervorului și al bateriei pompei. Ascultarea acestor transmisiuni permite ca Loop să comunice mai rar cu pompa, ceea ce poate crește durata de viață a bateriei pompei. Cu toate acestea, atunci când se utilizează această funcție, RileyLink rămâne treaz mai mult timp și utilizează mai mult din propria baterie. Activarea acestei funcții poate prelungi durata de viață a bateriei pompei, în timp ce dezactivarea acesteia poate prelungi durata de viață a bateriei RileyLink. Această setare este ignorată pentru alte modele de pompe."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Nu"; - -/* Message display when no response from tuning pump */ -"No response" = "Niciun răspuns"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nu, păstrați pompa așa cum este"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "Pe pompa, mergeți la ecranul \"Find Device\" și selectați \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Sursa de date preferată"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Nivel baterie pompă"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Tipul bateriei pompei"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID pompă"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Ora pompei"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Se citește programul bazalelor…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Se citește starea pompei…"; - -/* The title of the cell showing the pump region */ -"Region" = "Regiune"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Reia administrarea"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Se reia"; - -/* Button title to retry sentry setup */ -"Retry" = "Reîncearcă"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Bazală programată"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Selectaţi tipul de insulină pe care o veţi utiliza în această pompă."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Se trimite apăsarea butonului…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Pornire bazală temporară"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Succes"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Suspendă administrarea"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Suspendat: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Se suspendă"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sincronizați cu ora curentă"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Ora de pe pompă este diferită de ora curentă. Puteți revizui ora pompei și să o sincronizați cu ora curentă în meniul setări."; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "S-a detectat schimbarea orei"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Încercări"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Se ajustează frecvența…"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/oră"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "necunoscut"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Necunoscut"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Utilizați MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Da"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Da, sincronizați cu ora curentă"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/ro.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/ro.lproj/MinimedPumpManager.strings deleted file mode 100644 index 4a6a34a43..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/ro.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "Configurarea RileyLink-ului"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Caută dispozitivul"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Alte dispozitive"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Nu modificați timpul folosind meniul pompei."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Utilitare"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Dispozitive conectate"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Ceas pompă"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "ID-ul de pompă este porțiunea de 6 cifre din numărul serial (afișat ca SN sau S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "ID pompă"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Pompa este gata de utilizare."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Introduceți ID-ul de pompă din 6 cifre"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "În cazul în care călătoriți într-un alt fus orar pentru o perioadă extinsă, puteți modifica fusul orar al pompei din ecranul de setări Loop."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop va menține sincronizat ceasul pompei cu cel al telefonului, în fusul orar în care vă aflați acum."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "Regiunea pompei și culoarea sunt indicate prin ultimele 3 litere ale numărului de model (afișat ca REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Regiune și culoare"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Configurare finalizată"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Transmisii pompă"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "Pornit"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Setare pompă"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Introduceți regiunea pompei"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Setare pompă"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop va recepționa mesajele de status transmise de pompă. Urmații pașii de mai jos pentru a activa aceste mesaje:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Meniu principal"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/ru.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/ru.lproj/Localizable.strings deleted file mode 100644 index b4b57cc3e..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/ru.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ дБ"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@Ед"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ записи базального расписания\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Осталось единиц инсулина\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ ед остается в %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Настройка времени помпы..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Щелочные и литиевые батарейки садятся с различной скоростью. У щелочных падение линейное, в то время как литиевые сохраняют напряжение в течение половины срока службы. При нормальном пользовании в помпе Minimed без Mysentry (x22/x15) с применением алгоритма ИПЖ щелочные батарейки служат примерно от 4 до 5 дней. Литиевые служат от 1 до 2 недель. Эта настройка будет использовать разную скорость падения напряжения батареек в зависимости от их химического типа и предупреждать пользователя за 8-10 часов до отказа "; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Вы уверены, что хотите удалить эту помпу?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Батарея: %1$@ вольт\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Лучшая частота"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Болюс: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Отмена"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Отмена врем базала"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Изменение"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Выполняется изменение времени"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Выберите тип батарейки, используемой в помпе, для лучшего оповещения о низком заряде батареи."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Конфигурация"; - -/* Button title to connect to pump during setup */ -"Connect" = "Соединение с помпой"; - -/* Text for continue button */ -"Continue" = "Продолжить"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Удалить помпу"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Устройства"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Не использовать MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Ошибка возобновления"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Ошибка приостановки"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Ошибка синхронизации времени"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Получаю гликемию…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Получаю логи…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Получаю модель помпы…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Версия прошивки"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Подача\nприостановлена"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Подача инсулина"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Подача инсулина может определяться с помпы путем интерпретации истории событий или сравнением изменения объемов резервуара за прошедшее время. Чтение истории событий позволяет вычертить более точный график состояния и загрузить в Nightscout актуальные данные лечения/назначений (за счет более быстрого истощения батареи помпы и более высокого процента ошибок радиосвязи) по сравнению со считыванием данных только об объеме резервуара."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Остаток инсулина"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Тип инсулина"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Модели помпы Medtronic 523, 723, 554 и 754 имеют функцию MySentry, которая периодически передает данные об уровне заряда батареи в резервуаре и помпе. Прослушивание этих передач позволяет Loop реже связываться с помпой, что может увеличить срок службы батареи помпы. Однако при использовании этой функции RileyLink дольше не спит и использует больше собственной батареи. Включение этого параметра может увеличить срок службы батареи помпы, а его отключение может продлить срок службы батареи RileyLink. Этот параметр игнорируется для других моделей помп."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Нет"; - -/* Message display when no response from tuning pump */ -"No response" = "Нет ответа"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Нет, оставить время в помпе как есть"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "На помпе перейдите к экрану «Найти устройство» и выберите «Найти устройство». \n\n Главное меню >\n Утилиты >\n Подключить устройства >\n Другие устройства >\n Вкл >\n Найти устройство"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Предпочтительный источник данных"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Оставшийся заряд батареи помпы"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Тип батарейки в помпе"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Идентификатор ID помпы"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Время в помпе"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Чтение графика базала…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Чтение статуса помпы…"; - -/* The title of the cell showing the pump region */ -"Region" = "Регион"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Возобновить подачу"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Возобновляется"; - -/* Button title to retry sentry setup */ -"Retry" = "Повторить"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Запланированная база"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Выберите тип инсулина, который вы будете использовать в этой помпе."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Отправляется команда нажать кнопку…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Время начала временного базала"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Успешно"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Остановить подачу"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Приостановлено: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Выполняется остановка"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Синхронизация с текущим временем"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Время на вашей помпе отличается от текущего времени. Вы хотите обновить время на вашей помпе на текущее?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Обнаружено изменение времени"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Попытки"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Настраивается радиочастота…"; - -/* Units for showing temp basal rate */ -"U/hr" = "Ед/ч"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "Неизвестно"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Неизвестно"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Использование MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Да"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Да, синхронизировать с текущим временем"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/ru.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/ru.lproj/MinimedPumpManager.strings deleted file mode 100644 index 8794e5412..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/ru.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "Настройка RilryLink"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Найти устройство"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Другие устройства"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Не меняйте настройки времени через меню помпы."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Утилиты"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Соединить устройства"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Часы помпы"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "ID помпы это 6-значная цифровая часть серийного номера (обозначаемого SN or S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "Идентификатор ID помпы"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Помпа готова к работе."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Ввести 6-значный ID помпы"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "Если вы перемещаетесь в другой часовой пояс на длительное время, вы можете изменить часовой пояс в любое время через экран общих настроек Loop."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop будет синхронизировать часы помпы с часами телефона в том часовом поясе, в котором вы сейчас находитесь."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "Регион помпы и ее цвет обозначаются тремя последними буквами номера модели (маркируется как REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Регион и цвет"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Настройка завершена"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Помпа передает"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "Включено"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Настройки помпы"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Введите регион помпы"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Настройки помпы"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop будет отслеживать сообщения о состоянии с помпы. Выполните следующие шаги на помпе чтобы активировать такие сообщения"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Главное меню"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/sk.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/sk.lproj/Localizable.strings deleted file mode 100644 index 23c3613c4..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/sk.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@ j"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ vstupy do základného plánu\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Jednotiek zostávajúci inzulín\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ jednotiek zostávajúcich na %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Nastavenie času čerpadla..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkalické a lítiové batérie sa rozkladajú rôznou rýchlosťou. Alkalické majú tendenciu lineárne klesať v priebehu času, zatiaľ čo lítiové batérie majú tendenciu udržiavať napätie až do polovice svojej životnosti. Pri bežnom používaní v inzulínovej pumpe Minimed (x22/x15), ktorá nie je kompatibilná so systémom MySentry a beží v slučke, vydržia alkalické batérie približne 4 až 5 dní. Lítiové batérie vydržia 1 až 2 týždne. Pri tomto výbere sa pre každý typ chemického zloženia batérie použije iná rýchlosť úbytku napätia a používateľ bude upozornený, keď batériu delí približne 8 až 10 hodín od zlyhania."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Ste si istí, že chcete toto čerpadlo vymazať?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Batéria: %1$@ volt\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Najlepšia Frekvencia"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Podáva sa bolus: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Zrušiť"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Ruší sa Dočasný Bazál"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Zmena"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Mení sa čas…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Vyberte typ batérie, ktorú používate v pumpe, aby ste mohli byť lepšie upozornení na stav vybitia batérie."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Konfigurácia"; - -/* Button title to connect to pump during setup */ -"Connect" = "Pripojiť"; - -/* Text for continue button */ -"Continue" = "Pokračovať"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Vymazať Pumpu"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Zariadenia"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Nepoužívajte službu MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Chyba pri obnovení"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Chyba pri pozastavení"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Čas synchronizácie chyby"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Získavanie glukózy…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Získavanie histórie…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Získavanie modelu čerpadla…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Verzia firmvéru"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Inzulín\nSuspendovaný"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Podávanie inzulínu"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Podávanie inzulínu možno určiť z pumpy buď interpretáciou histórie udalostí alebo porovnaním objemu zásobníka v priebehu času. Čítanie histórie udalostí umožňuje presnejší stavový graf a nahrávanie aktuálnych údajov o liečbe do Nightscoutu za cenu rýchlejšieho vybíjania batérie pumpy a možnosti vyššej chybovosti rádia v porovnaní so samotným čítaním objemu zásobníka. Ak zvolený zdroj nemožno z akéhokoľvek dôvodu použiť, systém sa pokúsi vrátiť späť k inej možnosti."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Zostávajúci inzulín"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Typ inzulínu"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Modely pumpy Medtronic 523, 723, 554 a 754 majú funkciu s názvom „MySentry“, ktorá pravidelne vysiela úroveň nabitia batérie zásobníka a pumpy. Počúvanie týchto vysielaní umožňuje Loopu komunikovať s pumpou menej často, čo môže predĺžiť výdrž batérie pumpy. Pri používaní tejto funkcie však RileyLink zostáva viac času v bdelom stave a využíva viac vlastnej batérie. Povolenie môže predĺžiť životnosť batérie pumpy, zatiaľ čo jej vypnutie môže predĺžiť životnosť batérie RileyLink. Toto nastavenie sa pri iných modeloch čerpadiel ignoruje."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Nie"; - -/* Message display when no response from tuning pump */ -"No response" = "Žiadna odpoveď"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nie, nechajte čerpadlo tak, ako je"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "Na pumpe prejdite na obrazovku Nájsť zariadenie a vyberte možnosť „Nájsť zariadenie“. \n\n Hlavné menu >\n Pomôcky >\n Pripojiť zariadenia >\n Iné zariadenia >\n Zapnuté >\n Nájsť zariadenie"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Uprednostňovaný zdroj údajov"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Zostávajúca batéria čerpadla"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Top batérie pumpy"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID pumpy"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Čas čerpadla"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Načítava sa rozvrh bazálu…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Načítavam stav pumpy…"; - -/* The title of the cell showing the pump region */ -"Region" = "Región"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Obnoviť podávanie inzulínu"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Obnovuje sa"; - -/* Button title to retry sentry setup */ -"Retry" = "Skúsiť znova"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Naplánovaný bazál"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Vyberte typ inzulínu, ktorý budete v tejto pumpe používať."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Posiela stlačenie tlačidla…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Spustiť Dočasný Bazál"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Úspešné"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Pozastavenie dodávky"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Pozastavené: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Pozastavenie"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchronizácia s aktuálnym časom"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Čas na vašej pumpe sa líši od skutočného času. Chcete aktualizovať čas na čerpadle na aktuálny čas?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Zistila sa zmena času"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Testovanie"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Naladenie rádia…"; - -/* Units for showing temp basal rate */ -"U/hr" = "J/hod"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "neznámy"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Neznáme"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Používajte službu MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Áno"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Áno, synchronizujte s aktuálnym časom"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/sk.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/sk.lproj/MinimedPumpManager.strings deleted file mode 100644 index c4eb7212f..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/sk.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,39 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "Nastavenie RileyLinku"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Nájsť zariadenie"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Nemeňte čas pomocou ponuky pumpy."; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "ID pumpy je 6-ciferná číselná časť sériového čísla (označené ako SN alebo S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "ID pumpy"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Vaša pumpa je pripravená na použitie."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Zadajte 6-miestne ID pumpy"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "Ak cestujete do iného časového pásma na dlhší čas, časové pásmo pumpy môžete kedykoľvek zmeniť na obrazovke Nastavenia Loop."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop bude udržiavať hodiny pumpy synchronizované s telefónom v časovom pásme, v ktorom sa práve nachádzate."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "Oblasť pumpy a farba sú označené ako posledné 3 písmená modelového čísla (označené ako REF)."; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Nastavenie je dokončené"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "Zapnuté"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop bude počúvať stavové správy odoslané vašou pumpou. Ak chcete povoliť tieto správy, postupujte na pumpe podľa nasledujúcich krokov:"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/sv.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/sv.lproj/Localizable.strings deleted file mode 100644 index 94adce1e3..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/sv.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ basalscheman\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Enheter insulin återstår\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ enheter återstår kl. %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Justerar pumptid..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkaliska och litiumbatterier tappar spänning med olika hastighet. Alkaliska tenderar att ha ett linjärt spänningsfall över tiden, medan litiumcellsbatterier tenderar att behålla spänning fram till halva deras livslängd. Under normal användning, i en icke-MySentry-kompatibel Minimed (x22/x15) insulinpump som loopas, varar alkaliska batterier cirka 4 till 5 dagar. Litiumbatterier håller mellan 1–2 veckor. Detta val kommer att använda olika spänningsfall beroende på batterityp och varna användaren när ett batteri har cirka 8–10 timmar kvar av sin livslängd."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Är du säker på att du vill radera denna pump?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Batteri: %1$@ volt\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Bästa frekvensen"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Ger bolus: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Avbryt"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Avbryt temporär basal"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Byter"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Ändrar tid…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Välj vilken typ av batteri du använder i din pump."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Konfiguration"; - -/* Button title to connect to pump during setup */ -"Connect" = "Anslut"; - -/* Text for continue button */ -"Continue" = "Fortsätt"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Radera pump"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Enheter"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Använd inte MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Fel vid återupptagande"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Fel vid försök till paus"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Fel vid synkronisering av tid"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Hämtar glukos…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Hämtar historik…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Hämtar pumpmodell…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Firmware"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulintillförsel\npausad"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulintillförsel"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Mängd doserat insulin kan bestämmas antingen genom att tolka händelsehistoriken från pumpen eller genom att jämföra reservoarvolymen över tid. Att läsa av händelsehistoriken tillåter ett mer korrekt statusdiagram och mer aktuella behandlingsdata för uppladdning till Nightscout, men laddar ur batteriet snabbare och ökar risken för andel eventuella radiofel jämfört med avläsning av endast reservoarvolym. Om det ena alternativet av någon anledning inte kan användas, försöker systemet med det andra alternativet."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin som återstår"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Insulintyp"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Modellerna 523, 723, 554 och 754 från Medtronic har en funktion som kallas MySentry, som regelbundet övervakar reservoar- och pumpbatterinivåer. Genom att lyssna efter dessa sändningar kan iAPS kommunicera med pumpen mindre ofta, vilket kan öka pumpens batteritid. Men när du använder den här funktionen kommer RileyLink att vara vaken oftare vilket använder mer av sitt eget batteri. Aktivering av detta kan förlänga pumpens batteritid, medan inaktivera det kan förlänga RileyLink-batteriets livslängd. Denna inställning ignoreras för andra pumpmodeller."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Nej"; - -/* Message display when no response from tuning pump */ -"No response" = "Inget svar"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nej, behåll pumptid"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "På din pump, gå till skärmen 'Hitta enhet' och välj 'Hitta enhet'.\n\nHuvudmeny >\nTillbehör >\nAnslut enheter >\nAndra enheter >\nPå >\nHitta enhet"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Föredragen datakälla"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Pumpbatteri kvar"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Typ av pumpbatteri"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pump-ID"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pumptid"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Läser basalscheman…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Läser pumpstatus…"; - -/* The title of the cell showing the pump region */ -"Region" = "Region"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Återuppta insulindosering"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Återupptar"; - -/* Button title to retry sentry setup */ -"Retry" = "Försök igen"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Schemalagd basal"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Välj vilken typ av insulin du kommer att använda."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Skicka knapptryckning…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Börjar temporär basal"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Lyckades"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Pausa insulintillförsel"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Pausad: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Pausar"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synkronisera med aktuell tid"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Tiden på din pump skiljer sig från aktuell tid. Vill du uppdatera tiden på din pump till aktuell tid?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Tidsändring upptäckt"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Försök"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Justera radio…"; - -/* Units for showing temp basal rate */ -"U/hr" = "E/timme"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "okänd"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Okänd"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Använd MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Ja"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, synkronisera med aktuell tid"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/sv.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/sv.lproj/MinimedPumpManager.strings deleted file mode 100644 index 9a86238f2..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/sv.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "RileyLink inställning"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Hitta enhet"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Annan enhet"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Ädra inte tiden i din pumps menyer."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Tillbehör"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Anslut eheter"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Pumpklocka"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "Ditt pump-ID är den 6-siffriga nemeriska delen av serienumret (markerat med SN eller S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "Pump-ID"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Din pump är redo att användas."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Ange 6-siffrigt pump-ID"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "Om du reser till annan tidszon under en längre tid, kan du ändra tidszonen närsomhelst i Loops iställningar."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop kommer att synkronisera pumpens klocka med din telefon i tidszonen du befinner dig nu."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "Pumpregion och färg är märkta som de 3 sista siffrorna i modellnumret (markerad som REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Region och färg"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Inställning klar"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Pumpsändningar"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "På"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Pumpinställning"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Ange pumpregion"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Pumpinställning"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop kommer att lyssna på statusmeddelanden skickade av din pump. Följ de här stegen nedan på din pump för att aktivera dessa meddelanden:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Huvudmeny"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/tr.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/tr.lproj/Localizable.strings deleted file mode 100644 index 59aa23399..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/tr.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@Ü"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ bazal girişleri programla\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Ünite kalan insülin\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ ünite kaldı %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pompa Zamanı Ayarlanıyor..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Alkalin ve Lityum piller farklı oranlarda biterler. Alkali, zamanla doğrusal bir voltaj düşüşüne sahip olma eğilimindeyken, lityum hücreli piller, kullanım ömürlerinin yarısına kadar voltajı koruma eğilimindedir. MySentry uyumlu olmayan Minimed (x22/x15) insülin pompası ile çalışan Döngüde normal kullanım altında, Alkalin piller yaklaşık 4 ila 5 gün dayanırken, Lityum piller ise 1-2 hafta arasında dayanabilir. Bu seçim, pil kimyası türlerinin her biri için farklı pil voltajı oranlarını kullanır ve kullanıcıyı bir pilin bitmesine yaklaşık 8 ila 10 saat kaldığında uyarır."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Bu Pompayı silmek istediğinizden emin misiniz?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Pil: %1$@ volt\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "En İyi Frekans"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Bolus: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "İptal"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Geçici Bazalı İptal Et"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Değiştirme"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Saat değiştiriliyor…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Düşük pil koşulları hakkında daha iyi uyarı almak için pompanızda kullandığınız pil türünü seçin."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Konfigürasyon"; - -/* Button title to connect to pump during setup */ -"Connect" = "Bağla"; - -/* Text for continue button */ -"Continue" = "Devam et"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Pompayı Sil"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Cihazlar"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "MySentry'i kullanmayın"; - -/* The alert title for a resume error */ -"Error Resuming" = "Sürdürme Hatası"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Askıya Alma Hatası"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Zaman Senkronizasyon Hatası"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Glikoz alınıyor…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Geçmiş Alınıyor…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Pompa Modeli Alınıyor…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Donanım yazılımı sürümü"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "İnsülin\nAskıya alındı"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "İnsulin İletimi"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "İnsülin iletimi, olay geçmişi yorumlanarak veya zaman içindeki rezervuar hacmi karşılaştırılarak pompadan belirlenebilir. Olay geçmişinin okunması, daha doğru bir durum grafiğine ve Nightscout'a güncel tedavi verilerinin yüklenmesine izin verir, bu da sadece rezervuar hacmini okumaya kıyasla daha hızlı pompa pili tüketimi ve daha yüksek bir radyo hatası olasılığına sebep olur. Seçilen kaynak herhangi bir nedenle kullanılamıyorsa sistem diğer seçeneğe geri dönmeye çalışacaktır."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Kalan İnsülin"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "İnsülin Tipi"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Medtronic pompa modelleri 523, 723, 554 ve 754, rezervuar ve pompa pil seviyelerini periyodik olarak yayınlayan 'MySentry' adlı bir özelliğe sahiptir. Bu yayınların dinlenmesi, Loop'un pompayla daha az iletişim kurmasını sağlayarak pompanın pil ömrünü uzatabilir. Ancak, bu özelliği kullanırken, RileyLink daha çok uyanık kalır ve kendi pilinden daha fazla tüketir. Bunun etkinleştirilmesi pompa pil ömrünü uzatabilir, devre dışı bırakılması ise RileyLink pil ömrünü uzatabilir. Bu ayar, diğer pompa modelleri için dikkate alınmaz."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Hayır"; - -/* Message display when no response from tuning pump */ -"No response" = "Cevap yok"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Hayır, Pompayı Olduğu Gibi Tutun"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "Pompanızda Cihaz Bul ekranına gidin ve \"Cihaz Bul\" öğesini seçin.\n\nAna Menü >\nAraçlar>\nCihazları Bağlayın >\nDiğer cihazlar >\nAçık >\nCihaz Bul"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Tercih Edilen Veri Kaynağı"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Pump Battery Remaining"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Pompa Pil Tipi"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pompa Kimliği"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pompa Zamanı"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Bazal Programı Okunuyor…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Pompa Durumu Okunuyor…"; - -/* The title of the cell showing the pump region */ -"Region" = "Bölge"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "İletimi Devam Ettir"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Devam ediyor"; - -/* Button title to retry sentry setup */ -"Retry" = "Yeniden dene"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Programlanan Bazal"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Bu pompada kullanacağınız insülin tipini seçin."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Gönder butonuna basılıyor…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Geçici Bazal başlatılıyor"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Başarılı"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "İletimi Askıya Al"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Askıya alındı: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Askıya alınıyor"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Geçerli Saate Senkronize Et"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Pompanızdaki saat geçerli saatten farklı. Pompanızdaki saati geçerli saate güncellemek istiyor musunuz?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Zaman Değişikliği Algılandı"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Denemeler"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Radyo ayarlanıyor…"; - -/* Units for showing temp basal rate */ -"U/hr" = "Ü/sa"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "unknown"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Bilinmeyen"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "MySentry'yi kullanın"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Evet"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Evet, Geçerli Saatle Senkronize Et"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/tr.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/tr.lproj/MinimedPumpManager.strings deleted file mode 100644 index 3fe1c4c6e..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/tr.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "RileyLink Kurulumu"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Cihaz Bul"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Diğer cihazlar"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Pompanızın menüsünü kullanarak zamanı değiştirmeyin."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Araçlar"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Cihazları Bağlayın"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Pompa Saati"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "Pompa kimliği, seri numarasının (SN veya S/N olarak etiketlenmiş) 6 haneli sayısal kısmıdır."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "Pompa Kimliği"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Pompanız kullanıma hazır."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "6 haneli pompa kimliğini girin"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "Uzun süreli farklı bir saat dilimine seyahat ederseniz, pompanın saat dilimini istediğiniz zaman Loop'un Ayarlar ekranından değiştirebilirsiniz."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop, pompanızın saatini şu anda bulunduğunuz saat diliminde telefonunuzla senkronize halde tutacaktır."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "Pompa bölgesi ve rengi, model numarasının (REF olarak etiketlenmiştir) son 3 harfi olarak belirtilir."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Bölge ve Renk"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Kurulum tamamlandı"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Pompa Yayınları"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "Açık"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Pompa Kurulumu"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Pompa bölgesini girin"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Pompa Kurulumu"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop, pompanız tarafından gönderilen durum mesajlarını dinleyecektir. Bu mesajları etkinleştirmek için pompanızda aşağıdaki adımları izleyin:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Ana Menü"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/uk.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/uk.lproj/Localizable.strings deleted file mode 100644 index da56714aa..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/uk.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ запису базального розкладу\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Залишилося одиниць інсуліну\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ одиниць залишилося на %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Налаштування часу помпи..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Лужні та літієві батареї розкладаються з різною швидкістю. Лужні батареї, як правило, мають лінійне падіння напруги з часом, тоді як літієві батареї, як правило, зберігають напругу до середини свого терміну служби. За нормального використання інсулінової помпи Minimed (x22/x15), не сумісної з MySentry, працює Loop, лужних батарей вистачає приблизно на 4–5 днів. Літієві батареї працюють від 1 до 2 тижнів. Цей вибір використовуватиме різні швидкості спаду напруги батареї для кожного типу хімічного складу батареї та сповіщатиме користувача, коли до виходу з ладу батареї залишиться приблизно 8–10 годин."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Ви впевнені, що хочете видалити цю помпу?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Батарея: %1$@ вольт\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Найкраща частота"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Болюс: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Відмінити"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Скасування тимчасового базалу"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Зміна"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Зміна часу…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Виберіть тип акумулятора, який ви використовуєте у своїй помпі, щоб краще сповіщати про розряд акумулятора."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Налаштування"; - -/* Button title to connect to pump during setup */ -"Connect" = "Підключити"; - -/* Text for continue button */ -"Continue" = "Продовжити"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Видалити помпу"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Пристрої"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Не використовувати MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Помилка при відновленні"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Помилка призупинення"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Помилка при синхронізації часу"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Отримую глікемію."; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Отримую логи..."; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Отримую модель помпи…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Версія прошивки"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Інсулін\nПризупинено"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Доставка інсуліну"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Подача інсуліну може визначатися з помпи шляхом інтерпретації історії подій чи порівнянням зміни обсягів резервуара за час. Читання історії подій дозволяє викреслити більш точний графік стану та завантажити в Nightscout актуальні дані лікування/призначень (за рахунок швидшого виснаження батареї помпи та вищого відсотка помилок радіозв'язку) порівняно зі зчитуванням даних лише про обсяг резервуара."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Залишок інсуліну"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Тип інсуліну"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Моделі помпи Medtronic 523, 723, 554 та 754 мають функцію MySentry, яка періодично передає дані про рівень заряду батареї в резервуарі та помпі. Прослуховування цих передач дозволяє Loop рідше зв'язуватися з насосом, що може збільшити термін служби батареї насоса. Однак при використанні цієї функції RileyLink довше не спить та використовує більше власної батареї. Увімкнення цього параметра може збільшити термін служби батареї насоса, а його вимкнення може продовжити термін служби батареї RileyLink. Цей параметр ігнорується для інших моделей помп."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Ні"; - -/* Message display when no response from tuning pump */ -"No response" = "Немає відповіді"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Ні, залишити як є"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "На помпі перейдіть до екрана «Знайти пристрій» та виберіть «Знайти пристрій». \n\n Головне меню >\n Утиліти >\n Підключити пристрої >\n Інші пристрої >\n Увімкнути >\n Знайти пристрій"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Бажане джерело даних"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Заряд батареї помпи, що залишився"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Тип батареї помпи"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID помпи"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Час помпи"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Читання графіка базалу…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Читання статусу помпи..."; - -/* The title of the cell showing the pump region */ -"Region" = "Регіон"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Відновити подачу"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Відновлюється"; - -/* Button title to retry sentry setup */ -"Retry" = "Спробувати знову"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Запланований базал"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Виберіть тип інсуліну, який ви будете використовувати у цій поспі."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Відправляється команда нажать кнопку…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Час початку тимчасового базала"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Успішно"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Призупинити доставку"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Призупинено: %1$@ "; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Виконується зупинка"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Встановити поточний час"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Час на вашій помпіі відрізняється від поточного часу. Хочете оновити час на помпі до поточного?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Виявлено зміну часу"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Спроби"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Налаштовується радіочастота."; - -/* Units for showing temp basal rate */ -"U/hr" = "U/год"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "невідомий"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Невідомий"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Використання MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Так"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Так, синхронізувати з поточним часом"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/vi.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/vi.lproj/Localizable.strings deleted file mode 100644 index 602c6fee2..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/vi.lproj/Localizable.strings +++ /dev/null @@ -1,221 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ Lịch biểu liều nền\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "%1$@ Số unit insulin còn lại\n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units vẫn đang còn lúc %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Đang điều chỉnh thời gian bơm..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "Pin kềm và pin lithium phân rã ở các mức độ khác nhau. Pin kềm có xu hướng giảm điện áp tuyến tính theo thời gian trong khi pin lithium có xu hướng duy trì điện áp cho đến khi hết nửa vòng đời. Trong điều kiện sử dụng bình thường trên bơm Minimed (loại X22 hay X15) khi chạy Loop, pin kiềm có thể dùng được trong khoảng 4 đến 5 ngày trong khi pin lithium dùng dc 2 tuần. Việc lựa chọn này được sử dụng theo các mức phân rã điện áp khác nhau cho mỗi loại pin hóa học và sẽ có cảnh báo đối với người dùng khi pin hỏng đạt khoảng từ 8-10 giờ."; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Bạn có chắc muốn xóa bơm này không?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "Pin: %1$@ volts\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "Tần số tối ưu"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "Đang tiêm liều bolus: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "Hủy bỏ"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Đang hủy liều Basal tạm thời"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Đang thay đổi"; - -/* Progress message for changing pump time. */ -"Changing time…" = "Đang thay đổi giờ…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Chọn loại pin bạn đang sử dụng trong máy bơm để cảnh báo tốt hơn về tình trạng pin yếu."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "Cấu hình"; - -/* Button title to connect to pump during setup */ -"Connect" = "Kết nối"; - -/* Text for continue button */ -"Continue" = "Tiếp tục"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "Xóa bơm"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Thiết bị"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Không sử dụng MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "Lỗi khi đang tái thực hiện"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Lỗi khi đang tạm ngưng"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Lỗi đồng bộ thời gian"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "Đang lấy dữ liệu đường huyết…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "Đang lấy thông tin…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "Đang lấy model bơm…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Chương trình cơ sở"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\n Đã tạm ngưng"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Khối lượng tiêm insulin"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "Việc tiêm insulin có thể được quyết định từ bơm bằng cách kết hợp giải thuật dữ liệu của người sử dụng và so sánh với khối lượngngăn chứa insulin theo thời gian. Việc đọc các dữ liệu cũ sẽ đảm bảo biểu đồ đường huyết luôn được tính chính xác và tải dữ liệu điều trị cập nhật lên Nightscout, nhưng lại tăng việc tiêu hao pin cũng như lỗi giao tiếp tần số radio cao hơn việc chỉ đọc mỗi dữ liệu ngăn chứa insulin. Trong trường hợp nguồn dữ liệu không được lựa chọn vì bất kỳ lý do gì thì phần mềm sẽ quay sang lựa chọn khác."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin còn lại"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Loại Insulin"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Các mẫu máy bơm Medtronic 523, 723, 554 và 754 có một tính năng gọi là 'MySentry', phát sóng định kỳ mức pin của bình chứa và máy bơm. Việc lắng nghe các chương trình phát sóng này cho phép Loop liên lạc với máy bơm ít thường xuyên hơn, điều này có thể tăng tuổi thọ pin của máy bơm. Tuy nhiên, khi sử dụng tính năng này, RileyLink sẽ hoạt động lâu hơn và sử dụng nhiều pin hơn. Việc bật tính năng này có thể kéo dài tuổi thọ pin của máy bơm, trong khi việc tắt tính năng này có thể kéo dài tuổi thọ pin RileyLink. Cài đặt này bị bỏ qua đối với các kiểu máy bơm khác."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "Không"; - -/* Message display when no response from tuning pump */ -"No response" = "Không có phản hồi nào"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Không, Giữ nguyên máy bơm"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "Trên máy bơm của bạn, hãy đi tới \"Find Device\". Chọn Main Menu >\Utilities >\\Connect Devices >\\Other Devices >\\On >\\Find Device. -Bơm sẽ tìm thấy chỉ định"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "Nguồn dữ liệu được ưa thích"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Pin còn lại của Bơm"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "Loại pin của bơm"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Số ID của bơm"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Thời gian của Bơm"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "Đang đọc lịch biểu liều nền…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "Đang đọc tình trạng bơm…"; - -/* The title of the cell showing the pump region */ -"Region" = "Khu vực"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Tiếp tục lại việc tiêm insulin"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Đang tiếp tục lại"; - -/* Button title to retry sentry setup */ -"Retry" = "Thử lại"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Đã lên chương trình cho liều Basal"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Chọn loại insulin bạn sẽ sử dụng trong máy bơm này."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "Đang gửi nút bấm…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Đang bắt đầu liều Basal tạm thời"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Đã thành công"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "Tạm ngưng liều insulin"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "Đã tạm ngưng: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Đang tạm ngưng"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Đồng bộ thời gian hiện tại"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Thời gian trên máy bơm của bạn khác với thời gian hiện tại. Bạn có muốn cập nhật thời gian trên máy bơm của mình đến thời điểm hiện tại không?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "Đã phát hiện thay đổi thời gian"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "Các thử nghiệm"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "Chuyển tần số radio…"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/giờ"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "không xác định"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "Không nhận ra"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Sử dụng MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Có"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Có, đồng bộ với thời gian hiện tại"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/vi.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/vi.lproj/MinimedPumpManager.strings deleted file mode 100644 index 6fa6b0b65..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/vi.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "Cài đặt RileyLink"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "Tìm kiếm thiết bị"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "Các thiết bị khác"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "Không thay đổi thời gian sử dụng trên menu bơm của bạn."; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "Các tiện ích"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "Kết nối thiết bị"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "Đồng hồ của bơm"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "Số ID của bơm là phần số củ dãy số seri (được ký hiệu là SN hay S/N)."; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "Số ID của bơm"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "Bơm của bạn đã sẵn sàng."; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "Nhập 6 số ID của bơm"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "Trường hợp bạn du lịch đến vùng khác múi giờ trong thời gian dài, bạn có thể thay dổi múi giờ của bơm bất kỳ lúc nào trong phần cấu hình của bơm."; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop sẽ giữ đồng hồ của bơm đồng hóa với điện thoại trong múi giờ mà bạn đang hiện diện."; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "Khu vực và màu sắc của bơm được thể hiện qua 3 chữ cuối của chủng loại bơm (thể hiện là REF)."; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "Vùng và Màu sắc"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "Cấu hình hoàn thành"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "Pump Broadcasts"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "On"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "Cấu hình cho bơm"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "Nhập khu vực của bơm"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "Cấu hình cho bơm"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop sẽ lắng nghe các thông điệp được gửi từ bơm của bạn. Làm theo các bước dưới đây để thực hiện các thông điệp này:"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "Menu chính"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/zh-Hans.lproj/Localizable.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 6db74af69..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,220 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* The format string for displaying a frequency tune trial. Extra spaces added for emphesis: (1: frequency in MHz)(2: success count)(3: total count)(4: average RSSI) */ -"%1$@ %2$@/%3$@ %4$@" = "%1$@ %2$@/%3$@ %4$@"; - -/* The format string describing number of basal schedule entries: (1: number of entries) */ -"%1$@ basal schedule entries\n" = "%1$@ 基础率\n"; - -/* The format string describing units of insulin remaining: (1: number of units) */ -"%1$@ Units of insulin remaining\n" = "胰岛素剩余量 %1$@ U \n"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* String format for value with units (1: value, 2: separator, 3: units) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* Instructions on selecting battery chemistry type */ -"Alkaline and Lithium batteries decay at differing rates. Alkaline tend to have a linear voltage drop over time whereas lithium cell batteries tend to maintain voltage until halfway through their lifespan. Under normal usage in a Non-MySentry compatible Minimed (x22/x15) insulin pump running Loop, Alkaline batteries last approximately 4 to 5 days. Lithium batteries last between 1-2 weeks. This selection will use different battery voltage decay rates for each of the battery chemistry types and alert the user when a battery is approximately 8 to 10 hours from failure." = "碱性电池和锂电池以不同的速率衰减。随着时间的推移,碱性电池往往具有线性电压降,而锂电池电池则随时间呈线性下降的电压一直保持到其寿命的一半。在非MySentry兼容Minimed(x22 / x15)的胰岛素泵运行Loop时,正常使用情况下,碱性电池可持续大约4至5天,锂电池持续1-2周。此选择将针对每种电池化学类型使用不同的电池电压衰减速率,并在电池电量耗尽前8至10小时前提醒用户。"; - -/* Text to confirm delete this pump */ -"Are you sure you want to delete this Pump?" = "Are you sure you want to delete this Pump?"; - -/* The format string describing pump battery voltage: (1: battery voltage) */ -"Battery: %1$@ volts\n" = "电池:%1$@ V\n"; - -/* The label indicating the best radio frequency */ -"Best Frequency" = "最优频率"; - -/* The format string describing pump bolusing state: (1: bolusing) */ -"Bolusing: %1$@\n" = "大剂量: %1$@\n"; - -/* Cancel button title */ -"Cancel" = "取消"; - -/* Title text for suspend resume button when temp basal canceling */ -"Canceling Temp Basal" = "Canceling Temp Basal"; - -/* Text shown in basal rate space when basal is changing */ -"Changing" = "Changing"; - -/* Progress message for changing pump time. */ -"Changing time…" = "正在修改时间…"; - -/* Instructions on selecting battery chemistry type */ -"Choose the type of battery you are using in your pump for better alerting about low battery conditions." = "Choose the type of battery you are using in your pump for better alerting about low battery conditions."; - -/* The title of the configuration section in MinimedPumpManager settings */ -"Configuration" = "配置"; - -/* Button title to connect to pump during setup */ -"Connect" = "连接"; - -/* Text for continue button */ -"Continue" = "继续"; - -/* Button label for removing Pump - Text to delete pump */ -"Delete Pump" = "删除泵"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "设备"; - -/* Description for option to not use MySentry */ -"Do not use MySentry" = "Do not use MySentry"; - -/* The alert title for a resume error */ -"Error Resuming" = "无法恢复"; - -/* The alert title for a suspend error */ -"Error Suspending" = "无法暂停"; - -/* The alert title for an error while synching time */ -"Error Syncing Time" = "Error Syncing Time"; - -/* Progress message for fetching pump glucose. */ -"Fetching glucose…" = "正在获取葡萄糖信息…"; - -/* Progress message for fetching pump history. */ -"Fetching history…" = "正在获取历史数据…"; - -/* Progress message for fetching pump model. */ -"Fetching pump model…" = "正在获取胰岛素泵型号…"; - -/* The title of the cell showing the pump firmware version */ -"Firmware Version" = "Firmware Version"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "胰岛素输注"; - -/* Instructions on selecting an insulin data source */ -"Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option." = "可以通过解释事件历史记录或比较随时间推移的储存容量来确定胰岛素输注总量。阅读事件历史记录可以获得更精确的胰岛素输注量并将最新的数据上传到Nightscout,但该方式会造成更快的电池消耗以及可能造成Rileylink通信失败概率增大。如果选中的方式无法正常工作,系统将自动尝试运行另一个方案。"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "胰岛素余量"; - -/* Text for confidence reminders navigation link */ -"Insulin Type" = "Insulintyp"; - -/* Format string fof navigation bar title for MinimedPumpSettingsView (1: model number) */ -"Medtronic %1$@" = "Medtronic %1$@"; - -/* Instructions on selecting setting for MySentry */ -"Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models." = "Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models."; - -/* Value string for MySentry config when MySentry is not being used */ -"No" = "No"; - -/* Message display when no response from tuning pump */ -"No response" = "无响应"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Pump find device instruction */ -"On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device" = "On your pump, go to the Find Device screen and select \"Find Device\".\n\nMain Menu >\nUtilities >\nConnect Devices >\nOther Devices >\nOn >\nFind Device"; - -/* navigation title for pump battery type selection - Text for medtronic pump preferred data source */ -"Preferred Data Source" = "首选数据源"; - -/* Text for medtronic pump battery percent remaining */ -"Pump Battery Remaining" = "Pump Battery Remaining"; - -/* navigation title for pump battery type selection - Text for medtronic pump battery type */ -"Pump Battery Type" = "胰岛素泵电池类型"; - -/* The title text for the pump ID config value */ -"Pump ID" = "胰岛素泵序列号"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Progress message for reading basal schedule */ -"Reading basal schedule…" = "正在读取基础率配置文件…"; - -/* Progress message for reading pump status */ -"Reading pump status…" = "正在读取胰岛素泵状态…"; - -/* The title of the cell showing the pump region */ -"Region" = "Region"; - -/* Title text for button to resume insulin delivery */ -"Resume Delivery" = "Resume Delivery"; - -/* Title text for button when insulin delivery is in the process of being resumed */ -"Resuming" = "Resuming"; - -/* Button title to retry sentry setup */ -"Retry" = "重试"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "预设基础率"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pump." = "Select the type of insulin that you will be using in this pump."; - -/* Progress message for sending button press to pump. */ -"Sending button press…" = "正在发送亮屏指令…"; - -/* Title text for suspend resume button when temp basal starting */ -"Starting Temp Basal" = "Starting Temp Basal"; - -/* A message indicating a command succeeded */ -"Succeeded" = "成功"; - -/* Title text for button to suspend insulin delivery */ -"Suspend Delivery" = "暂停输注"; - -/* The format string describing pump suspended state: (1: suspended) */ -"Suspended: %1$@\n" = "暂停: %1$@\n"; - -/* Title text for button when insulin delivery is in the process of being stopped */ -"Suspending" = "Suspending"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Title for pod sync time action sheet. */ -"Time Change Detected" = "检测到时间变化"; - -/* The label indicating the results of each frequency trial */ -"Trials" = "尝试"; - -/* Progress message for tuning radio */ -"Tuning radio…" = "正在调频…"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/小时"; - -/* Text to indicate battery percentage is unknown */ -"unknown" = "unknown"; - -/* Text shown in basal rate space when delivery status is unknown */ -"Unknown" = "未知"; - -/* Description for option to use MySentry - navigation title for pump battery type selection - Text for medtronic pump to use MySentry */ -"Use MySentry" = "Use MySentry"; - -/* Value string for MySentry config when MySentry is being used */ -"Yes" = "Yes"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; diff --git a/Dependencies/MinimedKit/MinimedKitUI/Resources/zh-Hans.lproj/MinimedPumpManager.strings b/Dependencies/MinimedKit/MinimedKitUI/Resources/zh-Hans.lproj/MinimedPumpManager.strings deleted file mode 100644 index 4d2d021e4..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Resources/zh-Hans.lproj/MinimedPumpManager.strings +++ /dev/null @@ -1,69 +0,0 @@ -/* Class = "UITableViewController"; title = "RileyLink Setup"; ObjectID = "0MV-2k-Dty"; */ -"0MV-2k-Dty.title" = "RileyLink设置"; - -/* Class = "UILabel"; text = "Find Device"; ObjectID = "1fp-45-qWK"; */ -"1fp-45-qWK.text" = "发现设备"; - -/* Class = "UILabel"; text = "Other Devices"; ObjectID = "A6i-Cb-baR"; */ -"A6i-Cb-baR.text" = "其他设备"; - -/* Class = "UILabel"; text = "Do not change the time using your pumpʼs menu."; ObjectID = "Bdb-j4-WcR"; */ -"Bdb-j4-WcR.text" = "不要通过胰岛素泵来修改时间"; - -/* Class = "UILabel"; text = "Utilities"; ObjectID = "c7t-pZ-WqY"; */ -"c7t-pZ-WqY.text" = "功能"; - -/* Class = "UILabel"; text = "Connect Devices"; ObjectID = "erq-yb-anx"; */ -"erq-yb-anx.text" = "连接设备"; - -/* Class = "UITableViewController"; title = "Pump Clock"; ObjectID = "Fps-h3-V4K"; */ -"Fps-h3-V4K.title" = "泵时钟"; - -/* Class = "UITableViewSection"; footerTitle = "The pump ID is the 6-digit numerical portion of the serial number (labeled as SN or S/N)."; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.footerTitle" = "泵的ID是6位数字的序列号(标签为SN或S/N)"; - -/* Class = "UITableViewSection"; headerTitle = "Pump ID"; ObjectID = "fVG-pl-jT9"; */ -"fVG-pl-jT9.headerTitle" = "泵ID"; - -/* Class = "UILabel"; text = "Your pump is ready for use."; ObjectID = "g1m-3k-XI3"; */ -"g1m-3k-XI3.text" = "泵设置已完成"; - -/* Class = "UITextField"; placeholder = "Enter the 6-digit pump ID"; ObjectID = "HeG-VF-L5P"; */ -"HeG-VF-L5P.placeholder" = "输入六位数字的泵ID"; - -/* Class = "UILabel"; text = "If you travel to a different time zone for an extended period of time, you can change the pumpʼs time zone at any time in Loopʼs Settings screen."; ObjectID = "HuY-fE-vM8"; */ -"HuY-fE-vM8.text" = "如果你在不同的时区旅行,可以通过Loops直接设置泵的时区。"; - -/* Class = "UILabel"; text = "Loop will keep your pumpʼs clock synchronized with your phone in the time zone youʼre in now."; ObjectID = "IQ5-53-x9s"; */ -"IQ5-53-x9s.text" = "Loop将会对泵和手机所处的时区保持一致"; - -/* Class = "UITableViewSection"; footerTitle = "The pump region and color are denoted as the last 3 letters of the the model number (labeled as REF)."; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.footerTitle" = "泵的区域和颜色包含在设备型号的最后三个字母中(标记为REF)。"; - -/* Class = "UITableViewSection"; headerTitle = "Region and Color"; ObjectID = "lGI-LD-xR7"; */ -"lGI-LD-xR7.headerTitle" = "区域与颜色"; - -/* Class = "UITableViewController"; title = "Setup Complete"; ObjectID = "Nwf-TJ-KmJ"; */ -"Nwf-TJ-KmJ.title" = "设置完成"; - -/* Class = "UITableViewController"; title = "Pump Broadcasts"; ObjectID = "oBL-lh-SHI"; */ -"oBL-lh-SHI.title" = "泵广播"; - -/* Class = "UILabel"; text = "On"; ObjectID = "ojQ-ob-gBx"; */ -"ojQ-ob-gBx.text" = "开"; - -/* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "OZk-Db-KCs"; */ -"OZk-Db-KCs.title" = "泵设置"; - -/* Class = "UILabel"; text = "Enter the pump region"; ObjectID = "tGa-FP-JqD"; */ -"tGa-FP-JqD.text" = "输入泵区域"; - -/* Class = "UINavigationItem"; title = "Pump Setup"; ObjectID = "V47-Nq-7ew"; */ -"V47-Nq-7ew.title" = "泵设置"; - -/* Class = "UILabel"; text = "Loop will listen for status messages sent by your pump. Follow the steps below on your pump to enable these messages:"; ObjectID = "yLn-Ya-p1R"; */ -"yLn-Ya-p1R.text" = "Loop将监听泵的状态信息,并按照如下步骤操作胰岛素泵来开启此功能"; - -/* Class = "UITableViewSection"; headerTitle = "Main Menu"; ObjectID = "ZnF-zy-5gR"; */ -"ZnF-zy-5gR.headerTitle" = "主菜单"; - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpClockSetupViewController.swift b/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpClockSetupViewController.swift deleted file mode 100644 index 564aada38..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpClockSetupViewController.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// MinimedPumpClockSetupViewController.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKitUI - -class MinimedPumpClockSetupViewController: SetupTableViewController { - - override func viewDidLoad() { - super.viewDidLoad() - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpIDSetupViewController.swift b/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpIDSetupViewController.swift deleted file mode 100644 index ab7da9ac5..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpIDSetupViewController.swift +++ /dev/null @@ -1,475 +0,0 @@ -// -// MinimedPumpIDSetupViewController.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit -import LoopKitUI -import MinimedKit -import RileyLinkKit - - -class MinimedPumpIDSetupViewController: SetupTableViewController { - - var rileyLinkPumpManager: RileyLinkPumpManager! - - private enum RegionCode: String { - case northAmerica = "NA" - case canada = "CA/CM" - case worldWide = "WW" - - var region: PumpRegion { - switch self { - case .northAmerica: - return .northAmerica - case .canada: - return .canada - case .worldWide: - return .worldWide - } - } - } - - private var pumpRegionCode: RegionCode? { - didSet { - regionAndColorPickerCell.regionLabel.text = pumpRegionCode?.region.description - regionAndColorPickerCell.regionLabel.textColor = nil - - updateStateForSettings() - } - } - - private var pumpColor: PumpColor? { - didSet { - regionAndColorPickerCell.pumpImageView.image = .pumpImage(in: pumpColor, isLargerModel: true, isSmallImage: true) - - updateStateForSettings() - } - } - - private var pumpID: String? { - get { - return pumpIDTextField.text - } - set { - pumpIDTextField.text = newValue - } - } - - private var pumpOps: PumpOps? - - private var pumpState: PumpState? - - private var pumpFirmwareVersion: String? - - var maxBasalRateUnitsPerHour: Double! - - var maxBolusUnits: Double! - - var basalSchedule: BasalRateSchedule! - - private var isSentrySetUpNeeded: Bool = false - - var pumpManagerState: MinimedPumpManagerState? { - get { - guard - let navVC = navigationController as? MinimedPumpManagerSetupViewController, - let insulinType = navVC.insulinType, - let pumpColor = pumpColor, - let pumpID = pumpID, - let pumpModel = pumpState?.pumpModel, - let pumpRegion = pumpRegionCode?.region, - let timeZone = pumpState?.timeZone, - let pumpFirmwareVersion = pumpFirmwareVersion - else { - return nil - } - - return MinimedPumpManagerState( - isOnboarded: false, - useMySentry: pumpState?.useMySentry ?? true, - pumpColor: pumpColor, - pumpID: pumpID, - pumpModel: pumpModel, - pumpFirmwareVersion: pumpFirmwareVersion, - pumpRegion: pumpRegion, - rileyLinkConnectionState: rileyLinkPumpManager.rileyLinkConnectionManagerState, - timeZone: timeZone, - suspendState: .resumed(Date()), - insulinType: insulinType, - lastTuned: pumpState?.lastTuned, - lastValidFrequency: pumpState?.lastValidFrequency, - basalSchedule: BasalSchedule(repeatingScheduleValues: basalSchedule.items) - ) - } - } - - var pumpManager: MinimedPumpManager? { - guard let pumpManagerState = pumpManagerState else { - return nil - } - - return MinimedPumpManager( - state: pumpManagerState, - rileyLinkDeviceProvider: rileyLinkPumpManager.rileyLinkDeviceProvider) - } - - // MARK: - - - @IBOutlet weak var pumpIDTextField: UITextField! - - @IBOutlet fileprivate weak var regionAndColorPickerCell: RegionAndColorPickerTableViewCell! - - @IBOutlet weak var activityIndicator: SetupIndicatorView! - - @IBOutlet weak var loadingLabel: UILabel! - - override func viewDidLoad() { - super.viewDidLoad() - - regionAndColorPickerCell.pickerView.delegate = self - regionAndColorPickerCell.pickerView.dataSource = self - - continueState = .inputSettings - - NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidHide), name: UIResponder.keyboardDidHideNotification, object: nil) - } - - override func setEditing(_ editing: Bool, animated: Bool) { - super.setEditing(editing, animated: animated) - } - - // MARK: - UITableViewDelegate - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - guard continueState != .reading else { - return - } - - if let cell = tableView.cellForRow(at: indexPath) as? RegionAndColorPickerTableViewCell { - cell.becomeFirstResponder() - - // Apply initial values to match the picker - if pumpRegionCode == nil { - pumpRegionCode = MinimedPumpIDSetupViewController.regionRows[0] - } - if pumpColor == nil { - pumpColor = MinimedPumpIDSetupViewController.colorRows[0] - } - } - - tableView.deselectRow(at: indexPath, animated: true) - } - - // MARK: - Navigation - - private enum State { - case loadingView - case inputSettings - case readyToRead - case reading - case completed - } - - private var continueState: State = .loadingView { - didSet { - switch continueState { - case .loadingView: - updateStateForSettings() - case .inputSettings: - pumpIDTextField.isEnabled = true - activityIndicator.state = .hidden - footerView.primaryButton.isEnabled = false - footerView.primaryButton.setConnectTitle() - lastError = nil - case .readyToRead: - pumpIDTextField.isEnabled = true - activityIndicator.state = .hidden - footerView.primaryButton.isEnabled = true - footerView.primaryButton.setConnectTitle() - case .reading: - pumpIDTextField.isEnabled = false - activityIndicator.state = .indeterminantProgress - footerView.primaryButton.isEnabled = false - footerView.primaryButton.setConnectTitle() - lastError = nil - case .completed: - pumpIDTextField.isEnabled = true - activityIndicator.state = .completed - footerView.primaryButton.isEnabled = true - footerView.primaryButton.resetTitle() - lastError = nil - } - } - } - - private var lastError: Error? { - didSet { - guard oldValue != nil || lastError != nil else { - return - } - - var errorText = lastError?.localizedDescription - - if let error = lastError as? LocalizedError { - let localizedText = [error.errorDescription, error.failureReason, error.recoverySuggestion].compactMap({ $0 }).joined(separator: ". ") - - if !localizedText.isEmpty { - errorText = localizedText - } - } - - tableView.beginUpdates() - loadingLabel.text = errorText - - let isHidden = (errorText == nil) - loadingLabel.isHidden = isHidden - tableView.endUpdates() - // If we changed the error text, update the continue state - if !isHidden { - updateStateForSettings() - } - } - } - - private func updateStateForSettings() { - let isReadyToRead = pumpRegionCode != nil && pumpColor != nil && pumpID?.count == 6 - - if isReadyToRead { - continueState = .readyToRead - } else { - continueState = .inputSettings - } - } - - private func setupPump(with settings: PumpSettings) { - continueState = .reading - - let pumpOps = MinimedPumpOps(pumpSettings: settings, pumpState: pumpState, delegate: self) - self.pumpOps = pumpOps - pumpOps.runSession(withName: "Pump ID Setup", usingSelector: rileyLinkPumpManager.rileyLinkDeviceProvider.firstConnectedDevice, { (session) in - guard let session = session else { - DispatchQueue.main.async { - self.lastError = PumpManagerError.connection(MinimedPumpManagerError.noRileyLink) - } - return - } - - do { - _ = try session.tuneRadio() - let model = try session.getPumpModel() - var isSentrySetUpNeeded = false - - self.pumpFirmwareVersion = try session.getPumpFirmwareVersion() - - // Radio - if model.hasMySentry { - let isSentryEnabled = try session.getOtherDevicesEnabled() - - if isSentryEnabled { - let sentryIDCount = try session.getOtherDevicesIDs().ids.count - - isSentrySetUpNeeded = (sentryIDCount == 0) - } else { - isSentrySetUpNeeded = true - } - } else { - // Pre-sentry models need a remote ID to decrease the radio wake interval - let remoteIDCount = try session.getRemoteControlIDs().ids.count - - if remoteIDCount == 0 { - try session.setRemoteControlID(Data([9, 9, 9, 9, 9, 9]), atIndex: 2) - } - - try session.setRemoteControlEnabled(true) - } - - // Settings - let newSchedule = BasalSchedule(repeatingScheduleValues: self.basalSchedule.items) - try session.setBasalSchedule(newSchedule, for: .standard) - try session.setMaxBolus(units: self.maxBolusUnits) - try session.setMaxBasalRate(unitsPerHour: self.maxBasalRateUnitsPerHour) - try session.selectBasalProfile(.standard) - try session.setTimeToNow(in: .current) - - DispatchQueue.main.async { - self.isSentrySetUpNeeded = isSentrySetUpNeeded - - if self.pumpState != nil { - self.continueState = .completed - } else { - self.lastError = PumpManagerError.connection(MinimedPumpManagerError.noRileyLink) - } - } - } catch let error { - DispatchQueue.main.async { - self.lastError = error - } - } - }) - } - - override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { - return continueState == .completed - } - - override func continueButtonPressed(_ sender: Any) { - if case .completed = continueState { - if let setupViewController = navigationController as? MinimedPumpManagerSetupViewController, - let pumpManager = pumpManager // create mdt 1 - { - setupViewController.pumpManagerSetupComplete(pumpManager) - } - if isSentrySetUpNeeded { - performSegue(withIdentifier: "Sentry", sender: sender) - } else { - super.continueButtonPressed(sender) - } - } else if case .readyToRead = continueState, let pumpID = pumpID, let pumpRegion = pumpRegionCode?.region { -#if targetEnvironment(simulator) - self.continueState = .completed - self.pumpState = PumpState(timeZone: .currentFixed, pumpModel: PumpModel(rawValue: - "523")!, useMySentry: false) - self.pumpFirmwareVersion = "2.4Mock" -#else - setupPump(with: PumpSettings(pumpID: pumpID, pumpRegion: pumpRegion)) -#endif - } - } - - override func cancelButtonPressed(_ sender: Any) { - if regionAndColorPickerCell.isFirstResponder { - regionAndColorPickerCell.resignFirstResponder() - } else if pumpIDTextField.isFirstResponder { - pumpIDTextField.resignFirstResponder() - } else { - super.cancelButtonPressed(sender) - } - } - - @objc func keyboardDidHide() { - regionAndColorPickerCell.resignFirstResponder() - } -} - - -extension MinimedPumpIDSetupViewController: UIPickerViewDelegate, UIPickerViewDataSource { - private static let regionRows: [RegionCode] = [.northAmerica, .canada, .worldWide] - - private static let colorRows: [PumpColor] = [.blue, .clear, .purple, .smoke, .pink] - - private enum PickerViewComponent: Int { - case region - case color - - static let count = 2 - } - - func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { - switch PickerViewComponent(rawValue: component)! { - case .region: - return MinimedPumpIDSetupViewController.regionRows[row].rawValue - case .color: - return MinimedPumpIDSetupViewController.colorRows[row].rawValue - } - } - - func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { - switch PickerViewComponent(rawValue: component)! { - case .region: - pumpRegionCode = MinimedPumpIDSetupViewController.regionRows[row] - case .color: - pumpColor = MinimedPumpIDSetupViewController.colorRows[row] - } - } - - func numberOfComponents(in pickerView: UIPickerView) -> Int { - return PickerViewComponent.count - } - - func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { - switch PickerViewComponent(rawValue: component)! { - case .region: - return MinimedPumpIDSetupViewController.regionRows.count - case .color: - return MinimedPumpIDSetupViewController.colorRows.count - } - } -} - - -extension MinimedPumpIDSetupViewController: UITextFieldDelegate { - func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - guard let text = textField.text, let stringRange = Range(range, in: text) else { - updateStateForSettings() - return true - } - - let newText = text.replacingCharacters(in: stringRange, with: string) - - if newText.count >= 6 { - if newText.count == 6 { - textField.text = newText - textField.resignFirstResponder() - } - - updateStateForSettings() - return false - } - - textField.text = newText - updateStateForSettings() - return false - } - - func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { - return true - } - - func textFieldShouldReturn(_ textField: UITextField) -> Bool { - textField.resignFirstResponder() - return true - } -} - - -extension MinimedPumpIDSetupViewController: PumpOpsDelegate { - // TODO: create PumpManager and report it to Loop before pump setup - // No pumpManager available yet, so no device logs. - func willSend(_ message: String) {} - func didReceive(_ message: String) {} - func didError(_ message: String) {} - - func pumpOps(_ pumpOps: PumpOps, didChange state: PumpState) { - DispatchQueue.main.async { - self.pumpState = state - } - } -} - - -class RegionAndColorPickerTableViewCell: UITableViewCell { - override var canBecomeFirstResponder: Bool { - return true - } - - fileprivate private(set) lazy var pickerView = UIPickerView() - - override var inputView: UIView? { - return pickerView - } - - @IBOutlet weak var regionLabel: UILabel! - - @IBOutlet weak var pumpImageView: UIImageView! -} - - -private extension SetupButton { - func setConnectTitle() { - setTitle(LocalizedString("Connect", comment: "Button title to connect to pump during setup"), for: .normal) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpManagerSetupViewController.swift b/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpManagerSetupViewController.swift deleted file mode 100644 index f3b0fde7f..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpManagerSetupViewController.swift +++ /dev/null @@ -1,140 +0,0 @@ -// -// MinimedPumpSetupViewController.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit -import LoopKitUI -import MinimedKit -import RileyLinkBLEKit -import RileyLinkKit -import RileyLinkKitUI - - -public class MinimedPumpManagerSetupViewController: RileyLinkManagerSetupViewController { - - class func instantiateFromStoryboard() -> MinimedPumpManagerSetupViewController { - return UIStoryboard(name: "MinimedPumpManager", bundle: Bundle(for: MinimedPumpManagerSetupViewController.self)).instantiateInitialViewController() as! MinimedPumpManagerSetupViewController - } - - override public func viewDidLoad() { - super.viewDidLoad() - - if #available(iOSApplicationExtension 13.0, *) { - view.backgroundColor = .systemBackground - } else { - view.backgroundColor = .white - } - navigationBar.shadowImage = UIImage() - - if let pumpIDSetupVC = topViewController as? MinimedPumpIDSetupViewController, let rileyLinkPumpManager = rileyLinkPumpManager { - pumpIDSetupVC.rileyLinkPumpManager = rileyLinkPumpManager - } - - } - - private(set) var pumpManager: MinimedPumpManager? - - internal var insulinType: InsulinType? - - internal var supportedInsulinTypes: [InsulinType]? - - /* - 1. RileyLink - - RileyLinkPumpManagerState - - 2. Pump - - PumpSettings - - PumpColor - -- Submit -- - - PumpOps - - PumpState - - 3. (Optional) Connect Devices - - 4. Time - - 5. Basal Rates & Delivery Limits - - 6. Pump Setup Complete - - */ - - override public func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { - super.navigationController(navigationController, willShow: viewController, animated: animated) - - if let setupViewController = viewController as? SetupTableViewController { - setupViewController.delegate = self - } - - // Set state values - switch viewController { - case let vc as MinimedPumpIDSetupViewController: - vc.rileyLinkPumpManager = rileyLinkPumpManager - vc.maxBolusUnits = maxBolusUnits - vc.maxBasalRateUnitsPerHour = maxBasalRateUnitsPerHour - vc.basalSchedule = basalSchedule - case let vc as MinimedPumpSentrySetupViewController: - vc.pumpManager = pumpManager - case is MinimedPumpClockSetupViewController: - break - case let vc as MinimedPumpSetupCompleteViewController: - vc.pumpImage = pumpManager?.state.largePumpImage - default: - break - } - - // Adjust the appearance for the main setup view controllers only - if viewController is SetupTableViewController { - navigationBar.isTranslucent = false - navigationBar.shadowImage = UIImage() - } else { - navigationBar.isTranslucent = true - navigationBar.shadowImage = nil - viewController.navigationItem.largeTitleDisplayMode = .never - } - } - - public func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { - - // Adjust the appearance for the main setup view controllers only - if viewController is SetupTableViewController { - navigationBar.isTranslucent = false - navigationBar.shadowImage = UIImage() - } else { - navigationBar.isTranslucent = true - navigationBar.shadowImage = nil - } - } - - public func pumpManagerSetupComplete(_ pumpManager: MinimedPumpManager) { - self.pumpManager = pumpManager - pumpManagerOnboardingDelegate?.pumpManagerOnboarding(didCreatePumpManager: pumpManager) - } - - override open func finishedSetup() { - if let pumpManager = pumpManager { - pumpManager.completeOnboard() - - pumpManagerOnboardingDelegate?.pumpManagerOnboarding(didOnboardPumpManager: pumpManager) - completionDelegate?.completionNotifyingDidComplete(self) - } - } - - public func finishedSettingsDisplay() { - completionDelegate?.completionNotifyingDidComplete(self) - } - - public func didCancel() { - completionDelegate?.completionNotifyingDidComplete(self) - } -} - -extension MinimedPumpManagerSetupViewController: SetupTableViewControllerDelegate { - public func setupTableViewControllerCancelButtonPressed(_ viewController: SetupTableViewController) { - didCancel() - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpSentrySetupViewController.swift b/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpSentrySetupViewController.swift deleted file mode 100644 index 2a51fc73b..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpSentrySetupViewController.swift +++ /dev/null @@ -1,180 +0,0 @@ -// -// MinimedPumpSentrySetupViewController.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit -import LoopKitUI -import MinimedKit - - -class MinimedPumpSentrySetupViewController: SetupTableViewController { - - var pumpManager: MinimedPumpManager? - - @IBOutlet weak var activityIndicator: SetupIndicatorView! - - @IBOutlet weak var loadingLabel: UILabel! - - override func viewDidLoad() { - super.viewDidLoad() - - lastError = nil - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - if pumpManager == nil { - navigationController?.popViewController(animated: true) - } - - // Select the first row - tableView.selectRow(at: [1, 0], animated: true, scrollPosition: .none) - } - - override func continueButtonPressed(_ sender: Any) { - switch continueState { - case .notStarted: - listenForPairing() - case .listening: - break - case .completed: - if let setupViewController = navigationController as? MinimedPumpManagerSetupViewController, - let pumpManager = pumpManager - { - super.continueButtonPressed(sender) - setupViewController.pumpManagerSetupComplete(pumpManager) - } - } - } - - // MARK: - - - private enum State { - case notStarted - case listening - case completed - } - - private var continueState: State = .notStarted { - didSet { - switch continueState { - case .notStarted: - footerView.primaryButton.isEnabled = true - activityIndicator.state = .hidden - footerView.primaryButton.setTitle(LocalizedString("Retry", comment: "Button title to retry sentry setup"), for: .normal) - case .listening: - lastError = nil - activityIndicator.state = .indeterminantProgress - footerView.primaryButton.isEnabled = false - case .completed: - lastError = nil - activityIndicator.state = .completed - footerView.primaryButton.isEnabled = true - footerView.primaryButton.resetTitle() - } - } - } - - private func listenForPairing() { - guard let pumpManager = pumpManager else { - continueState = .notStarted - lastError = PumpManagerError.connection(MinimedPumpManagerError.noRileyLink) - return - } - - continueState = .listening - - pumpManager.pumpOps.runSession(withName: "MySentry Pairing", usingSelector: pumpManager.rileyLinkDeviceProvider.firstConnectedDevice) { (session) in - guard let session = session else { - DispatchQueue.main.async { - self.continueState = .notStarted - self.lastError = PumpManagerError.connection(MinimedPumpManagerError.noRileyLink) - } - return - } - - let watchdogID = Data([0xd0, 0x00, 0x07]) - do { - try session.changeWatchdogMarriageProfile(watchdogID) - DispatchQueue.main.async { - self.continueState = .completed - } - } catch let error { - DispatchQueue.main.async { - self.continueState = .notStarted - self.lastError = error - } - } - } - } - - private var lastError: Error? { - didSet { - guard oldValue != nil || lastError != nil else { - return - } - - var errorText = lastError?.localizedDescription - - if let error = lastError as? LocalizedError { - let localizedText = [error.errorDescription, error.failureReason, error.recoverySuggestion].compactMap({ $0 }).joined(separator: ". ") - - if !localizedText.isEmpty { - errorText = localizedText - } - } - - tableView.beginUpdates() - loadingLabel.text = errorText - - let isHidden = (errorText == nil) - loadingLabel.isHidden = isHidden - tableView.endUpdates() - } - } - -} - - -class PumpMenuItemTableViewCell: UITableViewCell { - override func awakeFromNib() { - super.awakeFromNib() - - updateLabel(selected: false) - } - - private func updateLabel(selected: Bool) { - let font = UIFont(name: "Menlo-Bold", size: 14) ?? UIFont.monospacedDigitSystemFont(ofSize: 14, weight: .medium) - let metrics = UIFontMetrics(forTextStyle: .body) - metrics.scaledFont(for: font) - - let paragraphStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle - paragraphStyle.firstLineHeadIndent = 15 - - let bundle = Bundle(for: type(of: self)) - let textColor = UIColor(named: "Pump Screen Text", in: bundle, compatibleWith: traitCollection)! - let backgroundColor = UIColor(named: "Pump Screen Background", in: bundle, compatibleWith: traitCollection)! - - textLabel?.backgroundColor = backgroundColor - textLabel?.attributedText = NSAttributedString( - string: textLabel?.text ?? "", - attributes: [ - .backgroundColor: selected ? textColor : backgroundColor, - .foregroundColor: selected ? backgroundColor : textColor, - .font: metrics.scaledFont(for: font), - .paragraphStyle: paragraphStyle, - ] - ) - } - - override func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - updateLabel(selected: selected) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpSetupCompleteViewController.swift b/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpSetupCompleteViewController.swift deleted file mode 100644 index 3131eeacb..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Setup/MinimedPumpSetupCompleteViewController.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// MinimedPumpSetupCompleteViewController.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKitUI - -class MinimedPumpSetupCompleteViewController: SetupTableViewController { - - @IBOutlet private var pumpImageView: UIImageView! - - var pumpImage: UIImage? { - didSet { - if isViewLoaded { - pumpImageView.image = pumpImage - } - } - } - - override func viewDidLoad() { - super.viewDidLoad() - - pumpImageView.image = pumpImage - - self.navigationItem.hidesBackButton = true - self.navigationItem.rightBarButtonItem = nil - } - - override func continueButtonPressed(_ sender: Any) { - if let setupViewController = navigationController as? MinimedPumpManagerSetupViewController { - setupViewController.finishedSetup() - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Views/BatteryTypeSelectionView.swift b/Dependencies/MinimedKit/MinimedKitUI/Views/BatteryTypeSelectionView.swift deleted file mode 100644 index 7bb0752e6..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Views/BatteryTypeSelectionView.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// BatteryTypeSelectionView.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 11/30/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import MinimedKit -import LoopKitUI - -struct BatteryTypeSelectionView: View { - - @Binding var batteryType: BatteryChemistryType - - var body: some View { - VStack { - List { - Section { - Text(LocalizedString("Choose the type of battery you are using in your pump for better alerting about low battery conditions.", comment: "Instructions on selecting battery chemistry type")) - .fixedSize(horizontal: false, vertical: true) - .padding(.vertical, 10) - } - Picker("Battery Chemistry", selection: $batteryType) { - ForEach(BatteryChemistryType.allCases, id: \.self) { batteryType in - Text(batteryType.description) - } - } - .pickerStyle(.inline) - } - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Pump Battery Type", comment: "navigation title for pump battery type selection")) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Views/DataSourceSelectionView.swift b/Dependencies/MinimedKit/MinimedKitUI/Views/DataSourceSelectionView.swift deleted file mode 100644 index 103c66aa2..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Views/DataSourceSelectionView.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// DataSourceSelectionView.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 11/30/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import MinimedKit -import LoopKitUI - -struct DataSourceSelectionView: View { - - @Binding var batteryType: InsulinDataSource - - var body: some View { - VStack { - List { - Picker("Preferred Data Source", selection: $batteryType) { - ForEach(InsulinDataSource.allCases, id: \.self) { dataSource in - Text(dataSource.description) - } - } - .pickerStyle(.inline) - Section(content: { - }, footer: { - Text(LocalizedString("Insulin delivery can be determined from the pump by either interpreting the event history or comparing the reservoir volume over time. Reading event history allows for a more accurate status graph and uploading up-to-date treatment data to Nightscout, at the cost of faster pump battery drain and the possibility of a higher radio error rate compared to reading only reservoir volume. If the selected source cannot be used for any reason, the system will attempt to fall back to the other option.", comment: "Instructions on selecting an insulin data source")) - }) - } - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Preferred Data Source", comment: "navigation title for pump battery type selection")) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Views/InsulinTypeConfirmation.swift b/Dependencies/MinimedKit/MinimedKitUI/Views/InsulinTypeConfirmation.swift deleted file mode 100644 index 8ccb644f7..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Views/InsulinTypeConfirmation.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// InsulinTypeConfirmation.swift -// MockKitUI -// -// Created by Pete Schwamb on 1/1/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI - -struct InsulinTypeConfirmation: View { - - @State private var insulinType: InsulinType? - private var supportedInsulinTypes: [InsulinType] - private var didConfirm: (InsulinType) -> Void - private var didCancel: () -> Void - - init(initialValue: InsulinType, supportedInsulinTypes: [InsulinType], didConfirm: @escaping (InsulinType) -> Void, didCancel: @escaping () -> Void) { - self._insulinType = State(initialValue: initialValue) - self.supportedInsulinTypes = supportedInsulinTypes - self.didConfirm = didConfirm - self.didCancel = didCancel - } - - func continueWithType(_ insulinType: InsulinType?) { - if let insulinType = insulinType { - didConfirm(insulinType) - } else { - assertionFailure() - } - } - - var body: some View { - VStack { - List { - Section { - Text(LocalizedString("Select the type of insulin that you will be using in this pump.", comment: "Title text for insulin type confirmation page")) - } - Section { - InsulinTypeChooser(insulinType: $insulinType, supportedInsulinTypes: supportedInsulinTypes) - } - .buttonStyle(PlainButtonStyle()) // Disable row highlighting on selection - } - .insetGroupedListStyle() - - Button(action: { self.continueWithType(insulinType) }) { - Text(LocalizedString("Continue", comment: "Text for continue button")) - .actionButtonStyle(.primary) - .padding() - } - } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(LocalizedString("Cancel", comment: "Cancel button title"), action: { - didCancel() - }) - } - } - } -} - -struct InsulinTypeConfirmation_Previews: PreviewProvider { - static var previews: some View { - InsulinTypeConfirmation(initialValue: .humalog, supportedInsulinTypes: InsulinType.allCases, didConfirm: { (newType) in }, didCancel: {}) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Views/MinimedPumpSettingsView.swift b/Dependencies/MinimedKit/MinimedKitUI/Views/MinimedPumpSettingsView.swift deleted file mode 100644 index 8ed8ce61a..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Views/MinimedPumpSettingsView.swift +++ /dev/null @@ -1,386 +0,0 @@ -// -// MinimedPumpSettingsView.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 11/29/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import SwiftUI -import LoopKitUI -import LoopKit -import RileyLinkKit -import RileyLinkBLEKit - -struct MinimedPumpSettingsView: View { - - @Environment(\.guidanceColors) private var guidanceColors - @Environment(\.insulinTintColor) var insulinTintColor - - @ObservedObject var viewModel: MinimedPumpSettingsViewModel - @ObservedObject var rileyLinkListDataSource: RileyLinkListDataSource - - var supportedInsulinTypes: [InsulinType] - - @State private var showingDeletionSheet = false - - @State private var showSyncTimeOptions = false; - - var handleRileyLinkSelection: (RileyLinkDevice) -> Void - - init(viewModel: MinimedPumpSettingsViewModel, supportedInsulinTypes: [InsulinType], handleRileyLinkSelection: @escaping (RileyLinkDevice) -> Void, rileyLinkListDataSource: RileyLinkListDataSource) { - self.viewModel = viewModel - self.supportedInsulinTypes = supportedInsulinTypes - self.handleRileyLinkSelection = handleRileyLinkSelection - self.rileyLinkListDataSource = rileyLinkListDataSource - } - - var body: some View { - List { - Section { - headerImage - .padding(.vertical) - HStack(alignment: .top) { - deliveryStatus - Spacer() - reservoirStatus - } - .padding(.bottom, 5) - - } - - if let basalDeliveryState = viewModel.basalDeliveryState { - Section { - HStack { - Button(basalDeliveryState.buttonLabelText) { - viewModel.suspendResumeButtonPressed(action: basalDeliveryState.shownAction) - }.disabled(viewModel.suspendResumeButtonEnabled) - if viewModel.suspendResumeButtonEnabled { - Spacer() - ProgressView() - } - } - } - } - - Section(header: SectionHeader(label: LocalizedString("Configuration", comment: "The title of the configuration section in MinimedPumpManager settings"))) - { - NavigationLink(destination: InsulinTypeSetting(initialValue: viewModel.pumpManager.state.insulinType, supportedInsulinTypes: supportedInsulinTypes, allowUnsetInsulinType: false, didChange: viewModel.didChangeInsulinType)) { - HStack { - Text(LocalizedString("Insulin Type", comment: "Text for confidence reminders navigation link")).foregroundColor(Color.primary) - if let currentTitle = viewModel.pumpManager.state.insulinType?.brandName { - Spacer() - Text(currentTitle) - .foregroundColor(.secondary) - } - } - } - NavigationLink(destination: BatteryTypeSelectionView(batteryType: $viewModel.batteryChemistryType)) { - HStack { - Text(LocalizedString("Pump Battery Type", comment: "Text for medtronic pump battery type")).foregroundColor(Color.primary) - Spacer() - Text(viewModel.batteryChemistryType.description) - .foregroundColor(.secondary) - } - } - - NavigationLink(destination: DataSourceSelectionView(batteryType: $viewModel.preferredDataSource)) { - HStack { - Text(LocalizedString("Preferred Data Source", comment: "Text for medtronic pump preferred data source")).foregroundColor(Color.primary) - Spacer() - Text(viewModel.preferredDataSource.description) - .foregroundColor(.secondary) - } - } - - if viewModel.pumpManager.state.pumpModel.hasMySentry { - NavigationLink(destination: UseMySentrySelectionView(mySentryConfig: $viewModel.mySentryConfig)) { - HStack { - Text(LocalizedString("Use MySentry", comment: "Text for medtronic pump to use MySentry")).foregroundColor(Color.primary) - Spacer() - Text((viewModel.mySentryConfig == .useMySentry ? - LocalizedString("Yes", comment: "Value string for MySentry config when MySentry is being used") : - LocalizedString("No", comment: "Value string for MySentry config when MySentry is not being used")) - ) - .foregroundColor(.secondary) - } - } - } - } - - Section(header: HStack { - Text(LocalizedString("Devices", comment: "Header for devices section of RileyLinkSetupView")) - Spacer() - ProgressView() - }) { - ForEach(rileyLinkListDataSource.devices, id: \.peripheralIdentifier) { device in - Toggle(isOn: rileyLinkListDataSource.autoconnectBinding(for: device)) { - HStack { - Text(device.name ?? "Unknown") - Spacer() - - if rileyLinkListDataSource.autoconnectBinding(for: device).wrappedValue { - if device.isConnected { - Text(formatRSSI(rssi:device.rssi)).foregroundColor(.secondary) - } else { - Image(systemName: "wifi.exclamationmark") - .imageScale(.large) - .foregroundColor(guidanceColors.warning) - } - } - } - .contentShape(Rectangle()) - .onTapGesture { - handleRileyLinkSelection(device) - } - } - } - } - .onAppear { - rileyLinkListDataSource.isScanningEnabled = true - } - .onDisappear { - rileyLinkListDataSource.isScanningEnabled = false - } - - - Section() { - HStack { - Text(LocalizedString("Pump Battery Remaining", comment: "Text for medtronic pump battery percent remaining")).foregroundColor(Color.primary) - Spacer() - if let chargeRemaining = viewModel.pumpManager.status.pumpBatteryChargeRemaining { - Text(String("\(Int(round(chargeRemaining * 100)))%")) - } else { - Text(String(LocalizedString("unknown", comment: "Text to indicate battery percentage is unknown"))) - } - } - HStack { - Text(LocalizedString("Pump Time", comment: "The title of the command to change pump time zone")) - Spacer() - if viewModel.isClockOffset { - Image(systemName: "clock.fill") - .foregroundColor(guidanceColors.warning) - } - TimeView(timeZone: viewModel.pumpManager.status.timeZone) - .foregroundColor( viewModel.isClockOffset ? guidanceColors.warning : nil) - } - if viewModel.synchronizingTime { - HStack { - Text(LocalizedString("Adjusting Pump Time...", comment: "Text indicating ongoing pump time synchronization")) - .foregroundColor(.secondary) - Spacer() - ActivityIndicator(isAnimating: .constant(true), style: .medium) - } - } else if self.viewModel.pumpManager.status.timeZone != TimeZone.currentFixed { - Button(action: { - showSyncTimeOptions = true - }) { - Text(LocalizedString("Sync to Current Time", comment: "The title of the command to change pump time zone")) - } - .actionSheet(isPresented: $showSyncTimeOptions) { - syncPumpTimeActionSheet - } - } - } - - - Section { - LabeledValueView(label: LocalizedString("Pump ID", comment: "The title text for the pump ID config value"), - value: viewModel.pumpManager.state.pumpID) - LabeledValueView(label: LocalizedString("Firmware Version", comment: "The title of the cell showing the pump firmware version"), - value: String(describing: viewModel.pumpManager.state.pumpFirmwareVersion)) - LabeledValueView(label: LocalizedString("Region", comment: "The title of the cell showing the pump region"), - value: String(describing: viewModel.pumpManager.state.pumpRegion)) - } - - - Section() { - deletePumpButton - } - - } - .alert(item: $viewModel.activeAlert, content: { alert in - switch alert { - case .suspendError(let error): - return Alert(title: Text(LocalizedString("Error Suspending", comment: "The alert title for a suspend error")), - message: Text(errorText(error))) - case .resumeError(let error): - return Alert(title: Text(LocalizedString("Error Resuming", comment: "The alert title for a resume error")), - message: Text(errorText(error))) - case .syncTimeError(let error): - return Alert(title: Text(LocalizedString("Error Syncing Time", comment: "The alert title for an error while synching time")), - message: Text(errorText(error))) - } - }) - - .insetGroupedListStyle() - .navigationBarItems(trailing: doneButton) - .navigationBarTitle(String(format: LocalizedString("Medtronic %1$@", comment: "Format string fof navigation bar title for MinimedPumpSettingsView (1: model number)"), viewModel.pumpManager.state.pumpModel.description)) - } - - var deliverySectionTitle: String { - if self.viewModel.isScheduledBasal { - return LocalizedString("Scheduled Basal", comment: "Title of insulin delivery section") - } else { - return LocalizedString("Insulin Delivery", comment: "Title of insulin delivery section") - } - } - - var deliveryStatus: some View { - VStack(alignment: .leading, spacing: 5) { - Text(deliverySectionTitle) - .foregroundColor(Color(UIColor.secondaryLabel)) - if viewModel.isSuspendedOrResuming { - HStack(alignment: .center) { - Image(systemName: "pause.circle.fill") - .font(.system(size: 34)) - .fixedSize() - .foregroundColor(viewModel.suspendResumeButtonColor(guidanceColors: guidanceColors)) - Text(LocalizedString("Insulin\nSuspended", comment: "Text shown in insulin delivery space when insulin suspended")) - .fontWeight(.bold) - .fixedSize() - } - } else if let basalRate = self.viewModel.basalDeliveryRate { - HStack(alignment: .center) { - HStack(alignment: .lastTextBaseline, spacing: 3) { - Text(viewModel.basalRateFormatter.string(from: basalRate) ?? "") - .font(.system(size: 28)) - .fontWeight(.heavy) - .fixedSize() - Text(LocalizedString("U/hr", comment: "Units for showing temp basal rate")) - .foregroundColor(.secondary) - } - } - } else if viewModel.basalDeliveryState?.isTransitioning == true { - HStack(alignment: .center) { - Image(systemName: "arrow.clockwise.circle.fill") - .font(.system(size: 34)) - .fixedSize() - .foregroundColor(.secondary) - Text(LocalizedString("Changing", comment: "Text shown in basal rate space when basal is changing")) - .fontWeight(.bold) - .fixedSize() - .foregroundColor(.secondary) - } - } else { - HStack(alignment: .center) { - Image(systemName: "x.circle.fill") - .font(.system(size: 34)) - .fixedSize() - .foregroundColor(guidanceColors.warning) - Text(LocalizedString("Unknown", comment: "Text shown in basal rate space when delivery status is unknown")) - .fontWeight(.bold) - .fixedSize() - } - } - } - } - - func reservoirColor(for reservoirLevelHighlightState: ReservoirLevelHighlightState) -> Color { - switch reservoirLevelHighlightState { - case .normal: - return insulinTintColor - case .warning: - return guidanceColors.warning - case .critical: - return guidanceColors.critical - } - } - - var reservoirStatus: some View { - VStack(alignment: .leading, spacing: 5) { - Text(LocalizedString("Insulin Remaining", comment: "Header for insulin remaining on pod settings screen")) - .foregroundColor(Color(UIColor.secondaryLabel)) - if let reservoirReading = viewModel.reservoirReading, - let reservoirLevelHighlightState = viewModel.reservoirLevelHighlightState, - let reservoirPercent = viewModel.reservoirPercentage - { - HStack { - MinimedReservoirView(filledPercent: reservoirPercent, fillColor: reservoirColor(for: reservoirLevelHighlightState)) - .frame(width: 23, height: 32) - Text(viewModel.reservoirText(for: reservoirReading.units)) - .font(.system(size: 28)) - .fontWeight(.heavy) - .fixedSize() - } - } - } - } - - var syncPumpTimeActionSheet: ActionSheet { - ActionSheet( - title: Text(LocalizedString("Time Change Detected", comment: "Title for pod sync time action sheet.")), - message: Text(LocalizedString("The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?", comment: "Message for pod sync time action sheet")), - buttons: [ - .default(Text(LocalizedString("Yes, Sync to Current Time", comment: "Button text to confirm pump time sync"))) { - self.viewModel.changeTimeZoneTapped() - }, - .cancel(Text(LocalizedString("No, Keep Pump As Is", comment: "Button text to cancel pump time sync"))) - ] - ) - } - - private func errorText(_ error: Error) -> String { - if let error = error as? LocalizedError { - return [error.localizedDescription, error.recoverySuggestion].compactMap{$0}.joined(separator: ". ") - } else { - return error.localizedDescription - } - } - - var decimalFormatter: NumberFormatter = { - let formatter = NumberFormatter() - - formatter.numberStyle = .decimal - formatter.minimumFractionDigits = 0 - formatter.maximumFractionDigits = 2 - - return formatter - }() - - private func formatRSSI(rssi: Int?) -> String { - if let rssi = rssi, let rssiStr = decimalFormatter.decibleString(from: rssi) { - return rssiStr - } else { - return "" - } - } - - private var deletePumpButton: some View { - Button(action: { - showingDeletionSheet = true - }, label: { - Text(LocalizedString("Delete Pump", comment: "Button label for removing Pump")) - .foregroundColor(.red) - }).actionSheet(isPresented: $showingDeletionSheet) { - ActionSheet( - title: Text(LocalizedString("Are you sure you want to delete this Pump?", comment: "Text to confirm delete this pump")), - buttons: [ - .destructive(Text(LocalizedString("Delete Pump", comment: "Text to delete pump"))) { - viewModel.deletePump() - }, - .cancel(), - ] - ) - } - } - - private var headerImage: some View { - VStack(alignment: .center) { - Image(uiImage: viewModel.pumpImage) - .resizable() - .aspectRatio(contentMode: ContentMode.fit) - .frame(height: 150) - .padding(.horizontal) - } - .frame(maxWidth: .infinity) - } - - private var doneButton: some View { - Button("Done", action: { - viewModel.doneButtonPressed() - }) - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Views/MinimedPumpSettingsViewModel.swift b/Dependencies/MinimedKit/MinimedKitUI/Views/MinimedPumpSettingsViewModel.swift deleted file mode 100644 index 523d8bb4f..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Views/MinimedPumpSettingsViewModel.swift +++ /dev/null @@ -1,309 +0,0 @@ -// -// MinimedPumpSettingsViewModel.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 11/29/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import MinimedKit -import LoopKit -import SwiftUI -import LoopKitUI -import HealthKit - - -enum MinimedSettingsViewAlert: Identifiable { - case suspendError(Error) - case resumeError(Error) - case syncTimeError(PumpManagerError) - - var id: String { - switch self { - case .suspendError: - return "suspendError" - case .resumeError: - return "resumeError" - case .syncTimeError: - return "syncTimeError" - } - } -} - -enum MySentryConfig: Int, Identifiable, CaseIterable { - var id: RawValue { - return self.rawValue - } - - case useMySentry = 0 - case doNotUseMySentry - - var localizedDescription: String { - switch self { - case .useMySentry: - return LocalizedString("Use MySentry", comment: "Description for option to use MySentry") - case .doNotUseMySentry: - return LocalizedString("Do not use MySentry", comment: "Description for option to not use MySentry") - } - } -} - -public enum ReservoirLevelHighlightState: String, Equatable { - case normal - case warning - case critical -} - -class MinimedPumpSettingsViewModel: ObservableObject { - - @Published var suspendResumeTransitioning: Bool = false - @Published var basalDeliveryState: PumpManagerStatus.BasalDeliveryState? - @Published var reservoirReading: ReservoirReading? - - @Published var batteryChemistryType: BatteryChemistryType { - didSet { - pumpManager.batteryChemistry = batteryChemistryType - } - } - - @Published var preferredDataSource: InsulinDataSource { - didSet { - pumpManager.preferredInsulinDataSource = preferredDataSource - } - } - - @Published var mySentryConfig: MySentryConfig { - didSet { - pumpManager.useMySentry = mySentryConfig == .useMySentry - } - } - - @Published var activeAlert: MinimedSettingsViewAlert? - @Published var suspendResumeButtonEnabled: Bool = false - @Published var synchronizingTime: Bool = false - - var pumpManager: MinimedPumpManager - - var didFinish: (() -> Void)? - - let basalRateFormatter: NumberFormatter = { - let numberFormatter = NumberFormatter() - numberFormatter.numberStyle = .decimal - numberFormatter.minimumFractionDigits = 1 - numberFormatter.minimumIntegerDigits = 1 - return numberFormatter - }() - - let reservoirVolumeFormatter = { - let formatter = QuantityFormatter(for: .internationalUnit()) - formatter.numberFormatter.maximumFractionDigits = 1 - return formatter - }() - - init(pumpManager: MinimedPumpManager) { - self.pumpManager = pumpManager - self.basalDeliveryState = pumpManager.status.basalDeliveryState - self.reservoirReading = pumpManager.state.lastReservoirReading - self.batteryChemistryType = pumpManager.batteryChemistry - self.preferredDataSource = pumpManager.preferredInsulinDataSource - self.mySentryConfig = pumpManager.useMySentry ? .useMySentry : .doNotUseMySentry - - self.pumpManager.addStatusObserver(self, queue: DispatchQueue.main) - pumpManager.stateObservers.insert(self, queue: .main) - } - - var pumpImage: UIImage { - return pumpManager.state.largePumpImage - } - - func deletePump() { - pumpManager.deletePump { - DispatchQueue.main.async { - self.didFinish?() - } - } - } - - func doneButtonPressed() { - self.didFinish?() - } - - func suspendResumeButtonPressed(action: SuspendResumeAction) { - suspendResumeButtonEnabled = true - switch action { - case .resume: - pumpManager.resumeDelivery { error in - DispatchQueue.main.async { - self.suspendResumeButtonEnabled = false - if let error = error { - self.activeAlert = .resumeError(error) - } - } - } - case .suspend: - pumpManager.suspendDelivery { error in - DispatchQueue.main.async { - self.suspendResumeButtonEnabled = false - if let error = error { - self.activeAlert = .suspendError(error) - } - } - } - } - } - - func didChangeInsulinType(_ newType: InsulinType?) { - self.pumpManager.insulinType = newType - } - - var isScheduledBasal: Bool { - switch basalDeliveryState { - case .active(_), .initiatingTempBasal: - return true - case .tempBasal(_), .cancelingTempBasal, .suspending, .suspended(_), .resuming, .none: - return false - } - } - - var isSuspendedOrResuming: Bool { - switch basalDeliveryState { - case .suspended, .resuming: - return true - default: - return false - } - } - - func suspendResumeButtonColor(guidanceColors: GuidanceColors) -> Color { - switch basalDeliveryState { - case .suspending, .resuming: - return Color.secondary - case .suspended: - return guidanceColors.warning - default: - return .accentColor - } - } - - var basalDeliveryRate: Double? { - switch basalDeliveryState { - case .suspending, .resuming, .suspended, .none, .initiatingTempBasal, .cancelingTempBasal: - return nil - case .active: - // return scheduled basal rate - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = pumpManager.state.timeZone - return pumpManager.state.basalSchedule.currentRate(using: calendar) - case .tempBasal(let dose): - return dose.unitsPerHour - } - } - - public var reservoirLevelHighlightState: ReservoirLevelHighlightState? { - guard let reservoirReading = reservoirReading else { - return nil - } - - let value = reservoirReading.units - - if value > pumpManager.lowReservoirWarningLevel { - return .normal - } else if value > 0 { - return .warning - } else { - return .critical - } - } - - public var reservoirPercentage: Double? { - guard let reservoirReading = reservoirReading else { - return nil - } - - return (reservoirReading.units / pumpManager.pumpReservoirCapacity).clamped(to: 0...1.0) - } - - func reservoirText(for units: Double) -> String { - let quantity = HKQuantity(unit: .internationalUnit(), doubleValue: units) - return reservoirVolumeFormatter.string(from: quantity, for: .internationalUnit()) ?? "" - } - - var isClockOffset: Bool { - return pumpManager.isClockOffset - } - - func changeTimeZoneTapped() { - synchronizingTime = true - pumpManager.setTime { (error) in - DispatchQueue.main.async { - self.synchronizingTime = false - if let error = error { - self.activeAlert = .syncTimeError(error) - } - } - } - } - -} - -extension MinimedPumpSettingsViewModel: PumpManagerStatusObserver { - public func pumpManager(_ pumpManager: PumpManager, didUpdate status: PumpManagerStatus, oldStatus: PumpManagerStatus) { - basalDeliveryState = status.basalDeliveryState - } -} - -extension MinimedPumpSettingsViewModel: MinimedPumpManagerStateObserver { - func didUpdatePumpManagerState(_ state: MinimedKit.MinimedPumpManagerState) { - reservoirReading = state.lastReservoirReading - batteryChemistryType = state.batteryChemistry - preferredDataSource = state.preferredInsulinDataSource - mySentryConfig = state.useMySentry ? .useMySentry : .doNotUseMySentry - } -} - - -enum SuspendResumeAction { - case suspend - case resume -} - -extension PumpManagerStatus.BasalDeliveryState { - - - var shownAction: SuspendResumeAction { - switch self { - case .active, .suspending, .tempBasal, .cancelingTempBasal, .initiatingTempBasal: - return .suspend - case .suspended, .resuming: - return .resume - } - } - - var buttonLabelText: String { - switch self { - case .active, .tempBasal: - return LocalizedString("Suspend Delivery", comment: "Title text for button to suspend insulin delivery") - case .suspending: - return LocalizedString("Suspending", comment: "Title text for button when insulin delivery is in the process of being stopped") - case .suspended: - return LocalizedString("Resume Delivery", comment: "Title text for button to resume insulin delivery") - case .resuming: - return LocalizedString("Resuming", comment: "Title text for button when insulin delivery is in the process of being resumed") - case .initiatingTempBasal: - return LocalizedString("Starting Temp Basal", comment: "Title text for suspend resume button when temp basal starting") - case .cancelingTempBasal: - return LocalizedString("Canceling Temp Basal", comment: "Title text for suspend resume button when temp basal canceling") - } - } - - var isTransitioning: Bool { - switch self { - case .suspending, .resuming, .initiatingTempBasal, .cancelingTempBasal: - return true - default: - return false - } - } - -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Views/MinimedReservoirView.swift b/Dependencies/MinimedKit/MinimedKitUI/Views/MinimedReservoirView.swift deleted file mode 100644 index 329edf9f2..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Views/MinimedReservoirView.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// MinimedReservoirView.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 11/30/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -struct MinimedReservoirView: View { - - let filledPercent: Double - let fillColor: Color - - // mask height to reservoir height ratio - let maskHeightRatio = 0.887 - - let reservoirAspectRatio = 28.0 / 44.0 - - func reservoirSize(in frame: CGSize) -> CGSize { - let frameAspectRatio = frame.width / frame.height - if frameAspectRatio > reservoirAspectRatio { - return CGSize( - width: frame.height * reservoirAspectRatio, - height: frame.height) - } else { - return CGSize( - width: frame.width, - height: frame.width / reservoirAspectRatio) - } - } - - var body: some View { - ZStack(alignment: Alignment(horizontal: .center, vertical: .center)) { - GeometryReader { geometry in - let reservoirSize = reservoirSize(in: geometry.size) - let frameCenterX = geometry.size.width / 2 - let frameCenterY = geometry.size.height / 2 - let maskHeight = reservoirSize.height * maskHeightRatio - let fillHeight = maskHeight * filledPercent - let maskOffset = (reservoirSize.height - maskHeight) / 2 - - Rectangle() - .fill(fillColor) - .mask( - Image("reservoir_mask") - .resizable() - .scaledToFit() - .frame(height: maskHeight) - .position(x:frameCenterX, y:frameCenterY+maskOffset) - ) - .mask( - Rectangle().path(in: CGRect(x:0, y: frameCenterY+maskHeight/2 - fillHeight + maskOffset, width: geometry.size.width, height: fillHeight)) - ) - } - Image("reservoir") - .resizable() - .scaledToFit() - } - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Views/ReservoirHUDView.swift b/Dependencies/MinimedKit/MinimedKitUI/Views/ReservoirHUDView.swift deleted file mode 100644 index 7a266c94a..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Views/ReservoirHUDView.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// ReservoirVolumeHUDView.swift -// Naterade -// -// Created by Nathan Racklyeft on 5/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import LoopKitUI - -public final class ReservoirHUDView: LevelHUDView, NibLoadable { - - override public var orderPriority: HUDViewOrderPriority { - return 4 - } - - @IBOutlet private weak var volumeLabel: UILabel! - - public class func instantiate() -> ReservoirHUDView { - return nib().instantiate(withOwner: nil, options: nil)[0] as! ReservoirHUDView - } - - override public func awakeFromNib() { - super.awakeFromNib() - - volumeLabel.isHidden = true - } - - override public func levelDidChange() { - super.levelDidChange() - - switch level { - case .none: - volumeLabel.isHidden = true - case let x? where x > 0.25: - volumeLabel.isHidden = true - case let x? where x > 0.10: - volumeLabel.textColor = tintColor - volumeLabel.isHidden = false - default: - volumeLabel.textColor = tintColor - volumeLabel.isHidden = false - } - } - - private lazy var timeFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .none - formatter.timeStyle = .short - - return formatter - }() - - private lazy var numberFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.maximumFractionDigits = 0 - - return formatter - }() - - public func setReservoirVolume(volume: Double, at date: Date) { - if let units = numberFormatter.string(from: volume) { - volumeLabel.text = String(format: LocalizedString("%@U", comment: "Format string for reservoir volume. (1: The localized volume)"), units) - let time = timeFormatter.string(from: date) - caption?.text = time - - accessibilityValue = String(format: LocalizedString("%1$@ units remaining at %2$@", comment: "Accessibility format string for (1: localized volume)(2: time)"), units, time) - } - } - - public override func tintColorDidChange() { - super.tintColorDidChange() - - volumeLabel.tintColor = tintColor - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Views/ReservoirHUDView.xib b/Dependencies/MinimedKit/MinimedKitUI/Views/ReservoirHUDView.xib deleted file mode 100644 index b210e9c77..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Views/ReservoirHUDView.xib +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/MinimedKit/MinimedKitUI/Views/TimeView.swift b/Dependencies/MinimedKit/MinimedKitUI/Views/TimeView.swift deleted file mode 100644 index 1ef7d65a8..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Views/TimeView.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// TimeView.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 11/30/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -struct TimeView: View { - - let timeZone: TimeZone - - private let shortTimeFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .none - formatter.timeStyle = .short - return formatter - }() - - @State var currentDate = Date() - let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() - - var timeZoneString: String { - shortTimeFormatter.timeZone = timeZone - return shortTimeFormatter.string(from: currentDate) - } - - var body: some View { - Text(timeZoneString).onReceive(timer) { input in - currentDate = input - } - } -} - -struct TimeView_Previews: PreviewProvider { - static var previews: some View { - TimeView(timeZone: .current) - } -} diff --git a/Dependencies/MinimedKit/MinimedKitUI/Views/UseMySentrySelectionView.swift b/Dependencies/MinimedKit/MinimedKitUI/Views/UseMySentrySelectionView.swift deleted file mode 100644 index e4b7d7e6b..000000000 --- a/Dependencies/MinimedKit/MinimedKitUI/Views/UseMySentrySelectionView.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// UseMySentrySelectionView.swift -// MinimedKitUI -// -// Created by Pete Schwamb on 11/30/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import MinimedKit -import LoopKitUI - -struct UseMySentrySelectionView: View { - - @Binding var mySentryConfig: MySentryConfig - - var body: some View { - VStack { - List { - Picker("Use MySentry", selection: $mySentryConfig) { - ForEach(MySentryConfig.allCases, id: \.self) { config in - Text(config.localizedDescription) - } - } - .pickerStyle(.inline) - Section(content: {}, footer: { - Text(LocalizedString("Medtronic pump models 523, 723, 554, and 754 have a feature called 'MySentry' that periodically broadcasts the reservoir and pump battery levels. Listening for these broadcasts allows Loop to communicate with the pump less frequently, which can increase pump battery life. However, when using this feature the RileyLink stays awake more of the time and uses more of its own battery. Enabling this may lengthen pump battery life, while disabling it may lengthen RileyLink battery life. This setting is ignored for other pump models.", comment: "Instructions on selecting setting for MySentry")) - }) - } - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Use MySentry", comment: "navigation title for pump battery type selection")) - } -} diff --git a/Dependencies/MinimedKit/README.md b/Dependencies/MinimedKit/README.md deleted file mode 100644 index f43207e3e..000000000 --- a/Dependencies/MinimedKit/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# MinimedKit -Medtronic PumpManager For Loop - -## Status -Supported, and included in Loop - -## For more information -Please join loop zulipchat at https://loop.zulipchat.com/ diff --git a/Dependencies/OmniBLE/.gitignore b/Dependencies/OmniBLE/.gitignore deleted file mode 100644 index 72baa4591..000000000 --- a/Dependencies/OmniBLE/.gitignore +++ /dev/null @@ -1,91 +0,0 @@ -# Xcode -# -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore -.DS_Store - -## User settings -xcuserdata/ - -## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) -*.xcscmblueprint -*.xccheckout - -## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) -build/ -DerivedData/ -*.moved-aside -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 - -## Obj-C/Swift specific -*.hmap - -## App packaging -*.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 -# *.xcodeproj -# -# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata -# hence it is not needed unless you have added a package configuration file to your project -# .swiftpm - -.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/Dependencies/OmniBLE/Common/Data.swift b/Dependencies/OmniBLE/Common/Data.swift deleted file mode 100644 index ed3c76835..000000000 --- a/Dependencies/OmniBLE/Common/Data.swift +++ /dev/null @@ -1,90 +0,0 @@ -// -// NSData.swift -// OmniBLE -// -// Created by Nathan Racklyeft on 9/2/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension Data { - private func toDefaultEndian(_: T.Type) -> T { - return self.withUnsafeBytes({ (rawBufferPointer: UnsafeRawBufferPointer) -> T in - let bufferPointer = rawBufferPointer.bindMemory(to: T.self) - guard let pointer = bufferPointer.baseAddress else { - return 0 - } - return T(pointer.pointee) - }) - } - - func to(_ type: T.Type) -> T { - return T(littleEndian: toDefaultEndian(type)) - } - - func toBigEndian(_ type: T.Type) -> T { - return T(bigEndian: toDefaultEndian(type)) - } - - mutating func append(_ newElement: T) { - var element = newElement.littleEndian - append(Data(bytes: &element, count: element.bitWidth / 8)) - } - - mutating func appendBigEndian(_ newElement: T) { - var element = newElement.bigEndian - append(Data(bytes: &element, count: element.bitWidth / 8)) - } - - init(_ value: T) { - var value = value.littleEndian - self.init(bytes: &value, count: value.bitWidth / 8) - } - - init(bigEndian value: T) { - var value = value.bigEndian - self.init(bytes: &value, count: value.bitWidth / 8) - } -} - -// String conversion methods, adapted from https://stackoverflow.com/questions/40276322/hex-binary-string-conversion-in-swift/40278391#40278391 -extension Data { - init?(hexadecimalString: String) { - self.init(capacity: hexadecimalString.utf16.count / 2) - - // Convert 0 ... 9, a ... f, A ...F to their decimal value, - // return nil for all other input characters - func decodeNibble(u: UInt16) -> UInt8? { - switch u { - case 0x30 ... 0x39: // '0'-'9' - return UInt8(u - 0x30) - case 0x41 ... 0x46: // 'A'-'F' - return UInt8(u - 0x41 + 10) // 10 since 'A' is 10, not 0 - case 0x61 ... 0x66: // 'a'-'f' - return UInt8(u - 0x61 + 10) // 10 since 'a' is 10, not 0 - default: - return nil - } - } - - var even = true - var byte: UInt8 = 0 - for c in hexadecimalString.utf16 { - guard let val = decodeNibble(u: c) else { return nil } - if even { - byte = val << 4 - } else { - byte += val - self.append(byte) - } - even = !even - } - guard even else { return nil } - } - - var hexadecimalString: String { - return map { String(format: "%02hhx", $0) }.joined() - } -} diff --git a/Dependencies/OmniBLE/Common/FrameworkLocalText.swift b/Dependencies/OmniBLE/Common/FrameworkLocalText.swift deleted file mode 100644 index 2b4215664..000000000 --- a/Dependencies/OmniBLE/Common/FrameworkLocalText.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// FrameworkLocalText.swift -// OmniBLE -// -// Created by Pete Schwamb on 7/21/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import SwiftUI - -private class FrameworkReferenceClass { - static let bundle = Bundle(for: FrameworkReferenceClass.self) -} - -func FrameworkLocalText(_ key: LocalizedStringKey, comment: StaticString) -> Text { - return Text(key, bundle: FrameworkReferenceClass.bundle, comment: comment) -} diff --git a/Dependencies/OmniBLE/Common/HKUnit.swift b/Dependencies/OmniBLE/Common/HKUnit.swift deleted file mode 100644 index 045599310..000000000 --- a/Dependencies/OmniBLE/Common/HKUnit.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// HKUnit.swift -// OmniBLE -// -// Created by Nathan Racklyeft on 1/17/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -extension HKUnit { - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: .literUnit(with: .deci)) - }() - - static let millimolesPerLiter: HKUnit = { - return HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: .liter()) - }() - - static let internationalUnitsPerHour: HKUnit = { - return HKUnit.internationalUnit().unitDivided(by: .hour()) - }() - -} diff --git a/Dependencies/OmniBLE/Common/IdentifiableClass.swift b/Dependencies/OmniBLE/Common/IdentifiableClass.swift deleted file mode 100644 index 226d69294..000000000 --- a/Dependencies/OmniBLE/Common/IdentifiableClass.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// IdentifiableClass.swift -// OmniBLE -// -// Created by Nathan Racklyeft on 2/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -protocol IdentifiableClass: AnyObject { - static var className: String { get } -} - - -extension IdentifiableClass { - static var className: String { - return NSStringFromClass(self).components(separatedBy: ".").last! - } -} diff --git a/Dependencies/OmniBLE/Common/Image.swift b/Dependencies/OmniBLE/Common/Image.swift deleted file mode 100644 index 6d3596142..000000000 --- a/Dependencies/OmniBLE/Common/Image.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// Image.swift -// OmniBLE -// -// Created by Pete Schwamb on 2/7/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -private class FrameworkBundle { - static let main = Bundle(for: FrameworkBundle.self) -} - -extension Image { - init(frameworkImage name: String, decorative: Bool = false) { - if decorative { - self.init(decorative: name, bundle: FrameworkBundle.main) - } else { - self.init(name, bundle: FrameworkBundle.main) - } - } -} diff --git a/Dependencies/OmniBLE/Common/LocalizedString.swift b/Dependencies/OmniBLE/Common/LocalizedString.swift deleted file mode 100644 index 1660d5516..000000000 --- a/Dependencies/OmniBLE/Common/LocalizedString.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// LocalizedString.swift -// OmniBLE -// -// Created by Kathryn DiSimone on 8/15/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -private class FrameworkBundle { - static let main = Bundle(for: FrameworkBundle.self) -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: FrameworkBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: FrameworkBundle.main, comment: comment) - } -} diff --git a/Dependencies/OmniBLE/Common/NibLoadable.swift b/Dependencies/OmniBLE/Common/NibLoadable.swift deleted file mode 100644 index 5b057ead2..000000000 --- a/Dependencies/OmniBLE/Common/NibLoadable.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// NibLoadable.swift -// OmniBLE -// -// Created by Nate Racklyeft on 7/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -protocol NibLoadable: IdentifiableClass { - static func nib() -> UINib -} - - -extension NibLoadable { - static func nib() -> UINib { - return UINib(nibName: className, bundle: Bundle(for: self)) - } -} diff --git a/Dependencies/OmniBLE/Common/NumberFormatter.swift b/Dependencies/OmniBLE/Common/NumberFormatter.swift deleted file mode 100644 index 488c57ba4..000000000 --- a/Dependencies/OmniBLE/Common/NumberFormatter.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// NumberFormatter.swift -// OmniBLE -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - -extension NumberFormatter { - func decibleString(from decibles: Int?) -> String? { - if let decibles = decibles, let formatted = string(from: NSNumber(value: decibles)) { - return String(format: LocalizedString("%@ dB", comment: "Unit format string for an RSSI value in decibles"), formatted) - } else { - return nil - } - } - - func string(from number: Double) -> String? { - return string(from: NSNumber(value: number)) - } -} diff --git a/Dependencies/OmniBLE/Common/OSLog.swift b/Dependencies/OmniBLE/Common/OSLog.swift deleted file mode 100644 index 2a53a50e0..000000000 --- a/Dependencies/OmniBLE/Common/OSLog.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// OSLog.swift -// OmniBLE -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import os.log - - -extension OSLog { - convenience init(category: String) { - self.init(subsystem: "com.randallknutson.OmniBLE", category: category) - } - - func debug(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .debug, args) - } - - func info(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .info, args) - } - - func `default`(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .default, args) - } - - func error(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .error, args) - } - - private func log(_ message: StaticString, type: OSLogType, _ args: [CVarArg]) { - switch args.count { - case 0: - os_log(message, log: self, type: type) - case 1: - os_log(message, log: self, type: type, args[0]) - case 2: - os_log(message, log: self, type: type, args[0], args[1]) - case 3: - os_log(message, log: self, type: type, args[0], args[1], args[2]) - case 4: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3]) - case 5: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4]) - default: - os_log(message, log: self, type: type, args) - } - } -} diff --git a/Dependencies/OmniBLE/Common/TimeInterval.swift b/Dependencies/OmniBLE/Common/TimeInterval.swift deleted file mode 100644 index 3f884ab3a..000000000 --- a/Dependencies/OmniBLE/Common/TimeInterval.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// NSTimeInterval.swift -// OmniBLE -// -// Created by Nathan Racklyeft on 1/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension TimeInterval { - - static func days(_ days: Double) -> TimeInterval { - return self.init(days: days) - } - - static func hours(_ hours: Double) -> TimeInterval { - return self.init(hours: hours) - } - - static func minutes(_ minutes: Int) -> TimeInterval { - return self.init(minutes: Double(minutes)) - } - - static func minutes(_ minutes: Double) -> TimeInterval { - return self.init(minutes: minutes) - } - - static func seconds(_ seconds: Double) -> TimeInterval { - return self.init(seconds) - } - - static func milliseconds(_ milliseconds: Double) -> TimeInterval { - return self.init(milliseconds / 1000) - } - - init(days: Double) { - self.init(hours: days * 24) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - init(minutes: Double) { - self.init(minutes * 60) - } - - init(seconds: Double) { - self.init(seconds) - } - - init(milliseconds: Double) { - self.init(milliseconds / 1000) - } - - var milliseconds: Double { - return self * 1000 - } - - init(hundredthsOfMilliseconds: Double) { - self.init(hundredthsOfMilliseconds / 100000) - } - - var hundredthsOfMilliseconds: Double { - return self * 100000 - } - - var minutes: Double { - return self / 60.0 - } - - var hours: Double { - return minutes / 60.0 - } - - var days: Double { - return hours / 24.0 - } - -} diff --git a/Dependencies/OmniBLE/Common/TimeZone.swift b/Dependencies/OmniBLE/Common/TimeZone.swift deleted file mode 100644 index 22992adf6..000000000 --- a/Dependencies/OmniBLE/Common/TimeZone.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// TimeZone.swift -// OmniBLE -// -// Created by Nate Racklyeft on 10/2/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -import Foundation - -extension TimeZone { - static var currentFixed: TimeZone { - return TimeZone(secondsFromGMT: TimeZone.current.secondsFromGMT())! - } - - var fixed: TimeZone { - return TimeZone(secondsFromGMT: secondsFromGMT())! - } - - /// This only works for fixed utc offset timezones - func scheduleOffset(forDate date: Date) -> TimeInterval { - var calendar = Calendar.current - calendar.timeZone = self - let components = calendar.dateComponents([.day , .month, .year], from: date) - guard let startOfSchedule = calendar.date(from: components) else { - fatalError("invalid date") - } - return date.timeIntervalSince(startOfSchedule) - } -} diff --git a/Dependencies/OmniBLE/Common/UIColor.swift b/Dependencies/OmniBLE/Common/UIColor.swift deleted file mode 100644 index f389ede36..000000000 --- a/Dependencies/OmniBLE/Common/UIColor.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// UIColor.swift -// OmniBLE -// -// Created by Nathan Racklyeft on 1/23/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -extension UIColor { - @nonobjc static var tintColor: UIColor? = nil - - @nonobjc static let secondaryLabelColor = UIColor(red: 142 / 255, green: 142 / 255, blue: 147 / 255, alpha: 1) - - @nonobjc static let gridColor = UIColor(white: 193 / 255, alpha: 1) - - @nonobjc static let glucoseTintColor = UIColor.HIGTealBlueColor() - - @nonobjc static let IOBTintColor = UIColor.HIGOrangeColor() - - @nonobjc static let COBTintColor = UIColor.HIGYellowColor() - - @nonobjc static let doseTintColor = UIColor.HIGGreenColor() - - @nonobjc static let freshColor = UIColor.HIGGreenColor() - - @nonobjc static let agingColor = UIColor.HIGYellowColor() - - @nonobjc static let staleColor = UIColor.HIGRedColor() - - @nonobjc static let unknownColor = UIColor.HIGGrayColor().withAlphaComponent(0.5) - - @nonobjc static let deleteColor = UIColor.HIGRedColor() - - // MARK: - HIG colors - // See: https://developer.apple.com/ios/human-interface-guidelines/visual-design/color/ - - private static func HIGTealBlueColor() -> UIColor { - return UIColor(red: 90 / 255, green: 200 / 255, blue: 250 / 255, alpha: 1) - } - - private static func HIGYellowColor() -> UIColor { - return UIColor(red: 1, green: 204 / 255, blue: 0 / 255, alpha: 1) - } - - private static func HIGOrangeColor() -> UIColor { - return UIColor(red: 1, green: 149 / 255, blue: 0 / 255, alpha: 1) - } - - private static func HIGPinkColor() -> UIColor { - return UIColor(red: 1, green: 45 / 255, blue: 85 / 255, alpha: 1) - } - - private static func HIGBlueColor() -> UIColor { - return UIColor(red: 0, green: 122 / 255, blue: 1, alpha: 1) - } - - private static func HIGGreenColor() -> UIColor { - return UIColor(red: 76 / 255, green: 217 / 255, blue: 100 / 255, alpha: 1) - } - - private static func HIGRedColor() -> UIColor { - return UIColor(red: 1, green: 59 / 255, blue: 48 / 255, alpha: 1) - } - - private static func HIGPurpleColor() -> UIColor { - return UIColor(red: 88 / 255, green: 86 / 255, blue: 214 / 255, alpha: 1) - } - - private static func HIGGrayColor() -> UIColor { - return UIColor(red: 142 / 255, green: 143 / 255, blue: 147 / 255, alpha: 1) - } - -} diff --git a/Dependencies/OmniBLE/LICENSE b/Dependencies/OmniBLE/LICENSE deleted file mode 100644 index 8fdc171b8..000000000 --- a/Dependencies/OmniBLE/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 Randall Knutson - -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/Dependencies/OmniBLE/Localizations/ar.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/ar.lproj/Localizable.strings deleted file mode 100644 index 579956322..000000000 --- a/Dependencies/OmniBLE/Localizations/ar.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Expiration Reminder"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Expired"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* */ -"Pod Expires" = "Pod Expires"; - -/* */ -"Pod Activated" = "Pod Activated"; - -/* */ -"Notification Settings" = "Notification Settings"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hours"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* title for device details page */ -"Device Details" = "Device Details"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Replace Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Expired"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "Insert Cannula"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Retry"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "Play Test Beeps"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "Read Pulse Log"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "Suspend"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "Resume"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulin Type"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Retry"; - -/* Action button description when deactivated */ -"Continue" = "Continue"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Listen for 2 beeps."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Paired"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Cancel"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Action button title for attach pod view */ -"Continue" = "Continue"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Check Cannula */ -"Check Cannula" = "Check Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Deactivating..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Label for expiration reminder row */ -"Time" = "Time"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* */ -"Setup Complete" = "Setup Complete"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheral Not Ready"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Incorrect Response"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; -/* navigation title for notification settings */ -"Notification Settings" = "Notification Settings"; - -/* Label for scheduled reminder value row */ -"Time" = "Time"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Enabled"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Rate"; - -/* Insulin unit per hour */ -"U/hr" = "U/hr"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Activated"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "Cancel"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Continue"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Low Reservoir"; - -/* */ -"Save" = "Save"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ ago"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Silence Pod mode suppresses all Pod alert and confirmation reminder beeping."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniBLE/Localizations/bn.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/bn.lproj/Localizable.strings deleted file mode 100644 index 77af0f085..000000000 --- a/Dependencies/OmniBLE/Localizations/bn.lproj/Localizable.strings +++ /dev/null @@ -1,784 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Expiration Reminder"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Expired"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* */ -"Pod Expires" = "Pod Expires"; - -/* */ -"Pod Activated" = "Pod Activated"; - -/* */ -"Notification Settings" = "Notification Settings"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hours"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* title for device details page */ -"Device Details" = "Device Details"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Replace Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Expired"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "Insert Cannula"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Retry"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "Play Test Beeps"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "Read Pulse Log"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "Suspend"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "Resume"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulin Type"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Retry"; - -/* Action button description when deactivated */ -"Continue" = "Continue"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Listen for 2 beeps."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Paired"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Cancel"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Remove blue Pod needle cap and check cannula. Then remove paper backing."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Action button title for attach pod view */ -"Continue" = "Continue"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Check Cannula */ -"Check Cannula" = "Check Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Deactivating..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Label for expiration reminder row */ -"Time" = "Time"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* */ -"Setup Complete" = "Setup Complete"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheral Not Ready"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Incorrect Response"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; -/* navigation title for notification settings */ -"Notification Settings" = "Notification Settings"; - -/* Label for scheduled reminder value row */ -"Time" = "Time"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Enabled"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Rate"; - -/* Insulin unit per hour */ -"U/hr" = "U/hr"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Activated"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "Cancel"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Continue"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Low Reservoir"; - -/* */ -"Save" = "Save"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; diff --git a/Dependencies/OmniBLE/Localizations/ca.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/ca.lproj/Localizable.strings deleted file mode 100644 index 77af0f085..000000000 --- a/Dependencies/OmniBLE/Localizations/ca.lproj/Localizable.strings +++ /dev/null @@ -1,784 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Expiration Reminder"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Expired"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* */ -"Pod Expires" = "Pod Expires"; - -/* */ -"Pod Activated" = "Pod Activated"; - -/* */ -"Notification Settings" = "Notification Settings"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hours"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* title for device details page */ -"Device Details" = "Device Details"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Replace Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Expired"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "Insert Cannula"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Retry"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "Play Test Beeps"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "Read Pulse Log"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "Suspend"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "Resume"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulin Type"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Retry"; - -/* Action button description when deactivated */ -"Continue" = "Continue"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Listen for 2 beeps."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Paired"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Cancel"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Remove blue Pod needle cap and check cannula. Then remove paper backing."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Action button title for attach pod view */ -"Continue" = "Continue"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Check Cannula */ -"Check Cannula" = "Check Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Deactivating..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Label for expiration reminder row */ -"Time" = "Time"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* */ -"Setup Complete" = "Setup Complete"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheral Not Ready"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Incorrect Response"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; -/* navigation title for notification settings */ -"Notification Settings" = "Notification Settings"; - -/* Label for scheduled reminder value row */ -"Time" = "Time"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Enabled"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Rate"; - -/* Insulin unit per hour */ -"U/hr" = "U/hr"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Activated"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "Cancel"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Continue"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Low Reservoir"; - -/* */ -"Save" = "Save"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; diff --git a/Dependencies/OmniBLE/Localizations/da.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/da.lproj/Localizable.strings deleted file mode 100644 index 427eb55bb..000000000 --- a/Dependencies/OmniBLE/Localizations/da.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Advarsel om flere kommandoer"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Påmindelse om udløb"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod udløbet"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Lavt Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Påmindelse om igangværende suspension"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Genoptag insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod-parring ufuldstændig"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Tidsændring registreret"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Advarsel om flere kommandoer"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod udløber om %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Skift Pod nu. Pod har været aktiv i 72 timer."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Skift Pod nu. Insulintilførsel stopper om 1 time."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin eller mindre tilbage i Pod. Skift Pod snart."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Påmindelse om igangværende suspension"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Perioden for suspension af insulin er afsluttet.\n\nDu kan genoptage afgivelsen fra den øverste del af startskærmen eller fra skærmen med pumpeindstillinger. Du vil blive mindet om dette igen om 15 minutter."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Færdiggør venligst parring af din pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Tiden på din pumpe er forskellig fra den aktuelle tid. Du kan gennemgå pumpetiden og synkronisere til den aktuelle tid i indstillinger."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspensionstiden er udløbet. Åbn appen, og genoptag."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Uafsluttet aktivering"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod udløber om"; - -/* */ -"Pod Expires" = "Pod Udløber"; - -/* */ -"Pod Activated" = "Pod Aktiveret"; - -/* */ -"Notification Settings" = "Notifikationsindstillinger"; - -/* */ -"Confidence Reminders" = "Tillidspåmindelser"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspenderer Insulinlevering"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod udløbet"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Uafsluttet deaktivering"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Ingen Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Par Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Par pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Parrer."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Klargør. Vent venligst."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod'en blev parret med succes. Fortsæt."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Afslut deaktivering"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Udskift Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "dag"; - -/* Unit for plural days in pod life remaining */ -"days" = "dage"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "time"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "timer"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minut"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutter"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulintilførsel"; - -/* */ -"Scheduled Basal" = "Planlagt Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Resterende Insulin"; - -/* Section header for activity section */ -"Activity" = "Aktivitet"; - -/* title for device details page */ -"Device Details" = "Enhedsdetaljer"; - -/* Section header for configuration section */ -"Configuration" = "Konfiguration"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Afslut deaktivering"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Udskift Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Udskift Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Uafsluttet aktivering"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod udløber om"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod udløbet"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Uafsluttet deaktivering"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Ingen Pod"; - -/* Pod life HUD view label */ -"Fault" = "Fejl"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Alder"; - -/* Label describing time remaining view */ -"Remaining" = "Tilbage"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Udskift Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Ingen Pod parret"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod allerede parret"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulintype ikke konfigureret"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod er ikke klar til kanyleindførsel."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ugyldig indstilling"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Venligst par med en ny Pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Kommunikationsproblem"; - -/* */ -"Finish Pairing" = "Afslut parring"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Afslut deaktivering"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Ingen Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "Ingen insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod udløbet"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod er blokeret"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod-fejl"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Ingen insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin suspenderet"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signaltab"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuel Basal"; - -/* */ -"Insert Cannula" = "Indfør kanyle"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Indsætter..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Prøv igen"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Kontrollerer..."; - -/* */ -"Check cannula insertion finished" = "Kontroller indsættelse af kanyle færdig"; - -/* */ -"Get pod status" = "Pod status"; - -/* */ -"Save Basal Profile" = "Indstil Basal Profil"; - -/* */ -"Save basal profile failed: %{public}@" = "Kunne ikke gemme basal profil: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Springer over Spil Test Bip på grund af at en bolus stadig er i gang."; - -/* */ -"Play Test Beeps" = "Afspil Test Bip"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Springer over Spil Test Bip på grund af at en bolus stadig er i gang."; - -/* */ -"Read Pulse Log" = "Læs Pulslog"; - -/* */ -"Set Confirmation Beeps to %s" = "Sæt bekræftelsesbip til %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Sæt Bekræftelse Bip Præference"; - -/* */ -"Suspend" = "Suspender"; - -/* */ -"Failed to suspend: %{public}@" = "Kunne ikke suspendere %{public}@"; - -/* */ -"Resume" = "Genoptag"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Annuller bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Tomt Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Blokering Opdaget"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritisk Pod-fejl"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulintilførslen er stoppet. Skift Pod nu."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Resterende Insulin"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Indstil Midlertidig Basalrate"; - -/* Section header for activity section */ -"Activity" = "Aktivitet"; - -/* Section header for configuration section */ -"Configuration" = "Konfiguration"; - -/* Title for previous pod page */ -"Previous Pod" = "Forrige Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pumpetid"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Justerer pumpetid..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synkroniser til aktuel tid"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Skift til en anden insulintilførselsenhed"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Tiden på din pumpe er forskellig fra den aktuelle tid. Vil du opdatere tiden på din pumpe til det aktuelle tidspunkt?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, synkroniser til aktuel tid"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nej, behold pumpen som den er"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Fjern pumpe"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Er du sikker på at du vil stoppe med at bruge Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Slet Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulintype"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synkroniser til aktuel tid"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Pause Indgivelse"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulintilførsel vil blive stoppet, indtil du genoptager manuelt. Hvornår vil du have iAPS til at minde dig om at genoptage leveringen?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutter"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 time"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 time 30 minutter"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 timer"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Kunne ikke suspendere insulintilførsel"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Kunne ikke genoptage insulintilførsel"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Kunne ikke indstille pumpetid"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Mislykkedes at annullere Manuel Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Deaktiver Poden. Når deaktiveringen er fuldført, kan du fjerne den og parre en ny Pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Deaktiver Poden. Når deaktiveringen er fuldført, kan du parre en ny Pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deaktiver Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktiverer."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deaktiveret med succes. Fortsæt."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Prøv igen"; - -/* Action button description when deactivated */ -"Continue" = "Fortsæt"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Kunne ikke kommunikere med Pod'en. Hvis problemet fortsætter, tryk Afbryd og kassér Pod'en. Du kan herefter aktivere en ny Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Kassér Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Fjern Pod fra kroppen"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Din Pod leverer muligvis stadig insulin.\nFjern den fra din krop og tryk derefter på \"Fortsæt\"."; - -/* Insulin Unit */ -"U" = "E"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Skift Pod nu. Insulintilførsel stopper 8 timer efter, at Pod'en er udløbet, eller når der ikke er mere insulin tilbage."; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Fyld et nyt bælg med U-100 Insulin (efterlad den blå nålehætte på)."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Lyt efter 2 bip."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Parret"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Annuller"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Er du sikker på, at du vil annullere Pod-opsætningen?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Hvis du annullerer Pod-opsætningen, deaktiveres den aktuelle Pod og den vil være ubrugelig."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, deaktiver Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nej, fortsæt med Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Forbered pumpested."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Tjek Pod, sæt på kroppen og bekræft derefter Pod er sat korrekt på."; - -/* Action button title for attach pod view */ -"Continue" = "Fortsæt"; - -/* */ -"Attach Pod" = "Påsæt Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bekræft fastgørelse af Pod"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Bekræft venligst, at Pod er sikkert fastgjort til din krop.\n\nKanyaen kan kun indsættes én gang med hver side. Tryk på “Bekræft”, når Pod er fastgjort."; - -/* Button title for confirm attachment option */ -"Confirm" = "Bekræft"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tryk nedenfor for at starte kanyleindsættelse."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Vent, indtil indsættelsen er afsluttet."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Indsat"; - -/* Check Cannula */ -"Check Cannula" = "Kontroller kanylen"; - -/* */ -"Is the cannula inserted properly?" = "Er kanylen indsat korrekt?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Vinduet på toppen af Pod'en skal være farvet pink, når kanylen er korrekt indsat i huden."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nej"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Parrer..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Klargør..."; - -/* */ -"Deactivating..." = "Deaktiverer..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktiveret"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Din pod er klar til brug.\n\n%1$@ minder dig om, at du skal skifte din pod, inden den udløber. Du kan ændre dette til et tidspunkt, der passer dig."; - -/* */ -"Scheduled Reminder" = "Planlagt Påmindelse"; - -/* Label for expiration reminder row */ -"Time" = "Tid"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Afslut opsætning"; - -/* */ -"Setup Complete" = "Opsætning fuldført"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Ingen Påmindelse"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Perifer Enhed Ikke Klar"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Ukorrekt Respons"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Tom Værdi"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Ukendt Karakteristik"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod-påmindelser"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Appen konfigurerer en påmindelse på Pod'en for at give dig besked inden Pod-udløb. Indstil antallet af timer i forvejen, du vil konfigurere, når du parrer en ny Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dette er en påmindelse om, at du planlagde, hvornår du parrede din nuværende Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Appen giver dig besked, når mængden af insulin i Pod'en når dette niveau."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Kritiske Advarsler"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Påmindelserne ovenfor vil ikke lyde, hvis din enhed er i lydløs tilstand eller Forstyr ikke.\n\nDer er andre kritiske Pod alarmer og alarmer, der vil lyde, selvom din enhed er indstillet til Lydløs eller Forstyr ikke."; -/* navigation title for notification settings */ -"Notification Settings" = "Notifikationsindstillinger"; - -/* Label for scheduled reminder value row */ -"Time" = "Tid"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Påmindelse om lavt reservoir"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Sørg for, at din telefon og Pod er tæt på hinanden. Hvis der fortsat er kommunikationsproblemer, skal du flytte til et nyt område."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Skift Pod nu. Insulintilførsel stopper om %1$@, eller når der ikke er mere insulin tilbage."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Deaktiveret"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Aktiveret"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Forlænget"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Der anvendes ingen tillidspåmindelser."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Værdi"; - -/* Insulin unit per hour */ -"U/hr" = "E/t"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ i %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "iAPS justerer ikke automatisk din insulindosering, før den midlertidige basalrate er afsluttet eller annulleret."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Sæt Midlertidig Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Midlertidig Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Midlertidig Basal Mislykkedes"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Kan ikke indstille en midlertidig basalrate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Kan ikke indstille en midlertidig basalrate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Manglende Konfiguration"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Denne PumpManager er ikke blevet konfigureret med maximal basal rate fordi det var tilføjet før manuel temp basal var en feature. Gå til Terapi Indstillinger -> Leveringsgrænser og set en ny maximal basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standard for udløbspåmindelse"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Forringe Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "Ingen\nlevering"; - -/* description label for active time pod details row */ -"Active Time" = "Aktiv Tid"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Levering"; - -/* description label for device name pod details row */ -"Device Name" = "Enhedsnavn"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot-nummer"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sekvensnummer"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware-version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Aktiveret"; - -/* description label for active time pod details row */ -"Active Time" = "Aktiv Tid"; - -/* description label for last status date pod details row */ -"Last Status" = "Sidste Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fejldetaljer"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pumpe Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Du skal nu begynde at konfigurere dine påmindelser, fylde din Pod med insulin, parre den med din enhed og placere den på din krop."; - -/* Cancel button title */ -"Cancel" = "Annuller"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Fortsæt"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Spring Omnipod Onboarding over?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Appen giver dig besked før Pod'en udløber.\n\nIndstil antallet af timer før udløb som påmindelse."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Næste"; - -/* */ -"Expiration Reminder" = "Udløbs Påmindelse"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Appen giver dig besked, når mængden af insulin i Pod'en når dette niveau (50-10 E)\n\nIndstil antallet enheder, du vil bruge som påmindelse."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Lavt Reservoir"; - -/* */ -"Save" = "Gem"; - -/* hr (short for hour) */ -"hr" = "t"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Annuller Manuel Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin \nSuspenderet"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Genoptag Insulintilførsel"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Sørg for, at din pod er tæt på, og prøv igen."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod ikke forbundet"; - -/* Label for suspended at time */ -"Suspended At" = "Suspenderet"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Genoptager insulintilførsel..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspenderer insulinlevering..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Ingen Pods fundet"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "For mange pods fundet"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Sørg for, at iPhone er i nærheden af den aktive pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Prøv igen"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Flyt til et nyt område væk fra andre Pods og prøv igen."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Sørg for, at din pod er fyldt og i nærheden."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Flyt iPhone længere væk fra podden"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Flyt iPhone nærmere podden"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Hav kun den originale pod tæt på eller deaktiver den original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Kommunikationsfejl. Flyt til et nyt område"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Sørg for, at din pod er tæt på, og prøv igen."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Vent, indtil eksisterende bolus er færdig, eller annuller bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Vent, indtil eksisterende bolus er færdig, eller annuller bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Vent, indtil den eksisterende midlertidige basal er færdig, eller suspender for at annullere"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ siden"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Silence Pod mode suppresses all Pod alert and confirmation reminder beeping."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniBLE/Localizations/de.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/de.lproj/Localizable.strings deleted file mode 100644 index 384770215..000000000 --- a/Dependencies/OmniBLE/Localizations/de.lproj/Localizable.strings +++ /dev/null @@ -1,826 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Mehrfache Befehlsbenachrichtigung"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Erinnerung an POD Ablaufdatum"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "POD abgelaufen"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Niedriger Reservoirstand"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Unterbrechung in Fortschrittserinnerung"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Insulin fortsetzen"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "POD Verbindung unvollständig"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Zeitänderung erkannt"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Mehrfache Befehlsbenachrichtigung"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod läuft ab in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Ersetze den POD jetzt. POD ist seit 72 Stunden aktiv."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Pod jetzt ersetzen. Insulinzufuhr endet in 1 Stunde."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ Insulin oder weniger verfügbar im Pod. Pod bald ersetzen."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Unterbrechung in Fortschrittserinnerung"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Die Insulinunterbrechung ist beendet.\n\nSie können die Zufuhr über das Banner auf dem Startbildschirm oder über die Pumpeneinstellungen fortsetzen. Sie werden in 15 Minuten noch einmal erinnert."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Bitte beenden Sie die Kopplung Ihres Pods."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Die Zeit auf Ihrer Pumpe unterscheidet sich von der aktuellen Zeit. Sie können die Pumpenzeit überprüfen und in den Einstellungen mit der aktuellen Zeit synchronisieren."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Unterbrechungszeit ist abgelaufen. Öffne die App zum Fortsetzen."; - -/* Action button default text for PodAlerts */ -"Ok" = "OK"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unvollendete Aktivierung"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "POD läuft ab in"; - -/* */ -"Pod Expires" = "POD läuft ab"; - -/* */ -"Pod Activated" = "Pod aktiviert"; - -/* */ -"Notification Settings" = "Benachrichtigungseinstellungen"; - -/* */ -"Confidence Reminders" = "Pumpe Bestätigungstöne"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Insulinabgabe unterbrechen"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "POD abgelaufen"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unvollendete Deaktivierung"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Kein POD"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "POD verbinden"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pod koppeln."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Kopplung läuft."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Vorbereitung läuft. Bitte warten."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod erfolgreich gekoppelt. Fortfahren."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Deaktivierung abschließen"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Pod ersetzen"; - -/* Unit for singular day in pod life remaining */ -"day" = "Tag"; - -/* Unit for plural days in pod life remaining */ -"days" = "Tage"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "Stunde"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "Stunden"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "Minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "Minuten"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulinabgabe"; - -/* */ -"Scheduled Basal" = "Geplante Basalrate"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Verbleibendes Insulin"; - -/* Section header for activity section */ -"Activity" = "Aktivität"; - -/* title for device details page */ -"Device Details" = "Gerätedetails"; - -/* Section header for configuration section */ -"Configuration" = "Konfiguration"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Deaktivierung abschließen"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Pod ersetzen"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Pod ersetzen"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unvollendete Aktivierung"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "POD läuft ab in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "POD abgelaufen"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unvollendete Deaktivierung"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Kein POD"; - -/* Pod life HUD view label */ -"Fault" = "Störung"; - -/* Label describing pod age view */ -"Pod Age" = "Pod-Alter"; - -/* Label describing time remaining view */ -"Remaining" = "Verbleibend"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Pod ersetzen"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Kein POD gekoppelt"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "POD bereits gekoppelt"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulintyp nicht konfiguriert"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Der Pod ist nicht bereit zum Einsetzen der Kanüle."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ungültige Einstellung"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Bitte einen neuen POD koppeln"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Kommunikationsfehler"; - -/* */ -"Finish Pairing" = "Kopplung beenden"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Deaktivierung abschließen"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Kein POD"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "Kein Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "POD abgelaufen"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pumpe verstopft"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Fehler"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Kein Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin ausgesetzt"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signalverlust"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuelle Temporäre Basalrate"; - -/* */ -"Insert Cannula" = "Kanüle einsetzen"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Kanüle einsetzen..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Wiederholen"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Wird geprüft..."; - -/* */ -"Check cannula insertion finished" = "Prüfe ob das Einfügen der Kanüle beendet ist"; - -/* */ -"Get pod status" = "Pod-Status abrufen"; - -/* */ -"Save Basal Profile" = "Basal-Profil speichern"; - -/* */ -"Save basal profile failed: %{public}@" = "Speichern des Basalprofils fehlgeschlagen: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Überspringe abspiel Testton wegen noch laufendem Bolus."; - -/* */ -"Play Test Beeps" = "Testtöne abspielen"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Überspringe Lese Pulse Protokoll wegen noch laufendem Bolus."; - -/* */ -"Read Pulse Log" = "Pulse-Log lesen"; - -/* */ -"Set Confirmation Beeps to %s" = "Bestätigungston auf %s setzen"; - -/* */ -"Set Confirmation Beeps Preference" = "Bestätigungstonleinstellungen festlegen"; - -/* */ -"Suspend" = "Unterbrechen"; - -/* */ -"Failed to suspend: %{public}@" = "Fehler beim Anhalten: %{public}@"; - -/* */ -"Resume" = "Fortsetzen"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Bolus abbrechen"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Reservoir leer"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Verstopfung erkannt"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Schwerwiegender POD Fehler"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulinabgabe gestoppt. Pod jetzt ersetzen."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Verbleibendes Insulin"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Temporäre Basalrate setzen"; - -/* Section header for activity section */ -"Activity" = "Aktivität"; - -/* Section header for configuration section */ -"Configuration" = "Konfiguration"; - -/* Title for previous pod page */ -"Previous Pod" = "Vorheriger Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pumpenzeit"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pumpenzeit anpassen..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Mit aktueller Zeit synchronisieren"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Zu einer anderen Insulinpumpe wechseln"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Die Zeit Ihrer Pumpe unterscheidet sich von der aktuellen Zeit. Möchten Sie die Pumpenzeit auf die aktuelle Zeit aktualisieren?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, mit aktueller Zeit synchronisieren"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nein, Pumpe unverändert behalten"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Pumpe entfernen"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Möchten Sie Omnipod DASH wirklich nicht mehr verwenden?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Omnipod DASH löschen"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulin Typ"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Mit aktueller Zeit synchronisieren"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Abgabe unterbrechen"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Die Insulinabgabe wird angehalten, bis sie manuell fortgesetzt wird. Wann soll Loop daran erinnern, die Insulinabgabe fortzusetzen?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 Minuten"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 Stunde"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 Stunde 30 Minuten"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 Stunden"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Unterbrechung Insulinagabe fehlgeschlagen"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Forsetzen der Insulinabgabe fehlgeschlagen"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Setzen der Pumpenzeit fehlgeschlagen"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Fehler beim Abbrechen der manuellen Basalrate"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Bitte deaktivieren Sie den Pod. Sobald der Pod vollständig deaktiviert ist, können Sie ihn vom Körper entfernen und einen neuen koppeln."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Bitte deaktivieren Sie den Pod. Sobald der Pod vollständig deaktiviert ist, können Sie ihn vom Körper entfernen und einen neuen koppeln."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Pod deaktivieren"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktivierung."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod erfolgreich deaktiviert. Fortfahren."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Wiederholen"; - -/* Action button description when deactivated */ -"Continue" = "Fortsetzen"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Es gab ein Problem bei der Kommunikation mit dem Pod. Wenn dieses Problem weiterhin besteht, tippe auf \"Pod verwerfen\". Du kannst dann einen neuen Pod aktivieren."; - -/* Text for discard pod button */ -"Discard Pod" = "Pod verwerfen"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Pod vom Körper entfernen"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Dein Pod kann noch Insulin abgeben.\nEntferne den Pod vom Körper und tippe dann auf \"Weiter\""; - -/* Insulin Unit */ -"U" = " IE"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Ersetze jetzt den Pod! Die Insulinabgabe wird in 8 Stunden unterbrochen, spätestens wenn die Gültigkeit abgelaufen ist oder kein Insulin mehr vorhanden ist."; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Füllen Sie einen neuen Pod mit U-100 Insulin (lassen Sie blaue Nadelabdeckung auf dem Pod)."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Entfernen Sie blaue Pod-Nadel Kappe und prüfen Sie die Kanüle. Danach die Klebefolien auf der Rückseite entfernen."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Auf 2 Signaltöne warten."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Gekoppelt"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Abbrechen"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Bist du sicher, dass du das Pod-Setup abbrechen möchtest?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Wenn Sie das Pod-Setup abbrechen, wird der aktuelle Pod deaktiviert und wird unbrauchbar."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, Pod deaktivieren"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nein, mit Pod fortfahren"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Setzstelle vorbereiten."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Prüfen Sie den Pod, auf der Setzstelle anbringen, dann Prodanbringung bestätigen."; - -/* Action button title for attach pod view */ -"Continue" = "Fortsetzen"; - -/* */ -"Attach Pod" = "Pod anlegen"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Pod-Anbringung bestätigen"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Bitte bestätige, dass der Pod sicher an deinen Körper angebrachtist.\n\nDie Kanüle kann nur einmal mit jedem Pod eingeführt werden. Tippe auf \"Bestätigen\", wenn der Pod angebracht ist."; - -/* Button title for confirm attachment option */ -"Confirm" = "Bestätigen"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tippe unten, um die Kanüleneinführung zu starten."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Warten Sie, bis die Einführung abgeschlossen ist."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Eingeführt"; - -/* Check Cannula */ -"Check Cannula" = "Kanüle prüfen"; - -/* */ -"Is the cannula inserted properly?" = "Ist die Kanüle korrekt eingeführt?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Das Fenster oben am Pod sollte rosa gefärbt sein, wenn die Kanüle richtig in die Haut eingeführt wurde."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nein"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Kopplung läuft..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Vorbereitung..."; - -/* */ -"Deactivating..." = "Deaktivierung..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktiviert"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Dein Pod ist einsatzbereit.\n\n%1$@ wird dich daran erinnern, deinen Pod zu ändern, bevor er abläuft. Sie können dies zu einer für Sie passenden Zeit ändern."; - -/* */ -"Scheduled Reminder" = "Erinnerungen festlegen"; - -/* Label for expiration reminder row */ -"Time" = "Uhrzeit"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Einrichtung abschließen"; - -/* */ -"Setup Complete" = "Setup vollständig"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Keine Erinnerung"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripherie nicht bereit"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Fehlerhafte Antwort"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Zeitüberschreitung"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Leerer Wert"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unbekannte Eigenschaft"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Fehler in Datenkommunikation"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Erinnerungen"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Die App erstellt eine Erinnerung, um dich vor dem Ablauf des Pods zu benachrichtigen. Wähle die Anzahl der Stunden, die du vor der Kopplung eines neuen Pods benachrichtigt werden möchtest."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dies ist eine Erinnerung, die du beim Koppeln deines aktuellen Pods erstellt hast."; - -/* */ -"Scheduled Reminder" = "Erinnerungen festlegen"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Die App benachrichtigt dich, wenn die Insulinmenge im Pod diesen Wert erreicht."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Kritische Warnungen"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Die obigen Hinweise ertönen nicht, wenn sich dein Gerät im Modus Lautlos oder Nicht stören befindet.\n\n Es gibt weitere kritische Pod-Warnungen und Alarme, die auch dann ertönen, wenn dein Gerät auf \"Lautlos\" oder \"Nicht stören\" eingestellt ist."; -/* navigation title for notification settings */ -"Notification Settings" = "Benachrichtigungseinstellungen"; - -/* Label for scheduled reminder value row */ -"Time" = "Uhrzeit"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Keine Erinnerung"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Erinnerung bei niedrigem Füllstand"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Vergewissere dich, dass sich dein iPhone und Pod in unmittelbarer Nähe zueinander befinden. Wenn die Kommunikationsprobleme fortbestehen, dann wechsle den Standort."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Wechsle jetzt den Pod! Die Insulinabgabe wird in %1$@ unterbrochen, spätestens wenn kein Insulin mehr vorhanden ist."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Deaktiviert"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Aktiviert"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Verlängert"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Keine Erinnerungseinstellungen in Verwendung."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Vertrauenserinnerungen ertönen für von Ihnen initiierte Befehle, wie Bolus, Bolus abbrechen, Unterbrechen, Fortsetzen, Benachrichtigungserinnerungen speichern usw. Wenn Loop die Abgabe automatisch anpasst, werden keine Vertrauenserinnerungen verwendet."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Vertrauenserinnerungen ertönen, wenn Loop die Lieferung automatisch anpasst, sowie für von Ihnen initiierte Befehle."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Vertrauenserinnerungen ertönen, wenn Loop die Lieferung automatisch anpasst, sowie für von Ihnen initiierte Befehle."; ->>>>>>> 420dc4ed (Crowdin (#362)) - -/* Label text for temporary basal rate summary */ -"Rate" = "BR"; - -/* Insulin unit per hour */ -"U/hr" = "IE/Std"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ für %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop passt deine Insulinabgabe nicht automatisch an, bis die temporäre Basalrate beendet oder abgebrochen wird."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Temporäre Basalrate festlegen"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporäre Basalrate"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporäre Basalrate fehlgeschlagen"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Konnte keine temporäre Basalrate festlegen: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Konnte keine temporäre Basalrate festlegen: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Fehlende Konfiguration"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Dieser PumpManager wurde nicht mit einer maximalen Basalrate konfiguriert, da er hinzugefügt wurde, bevor es die Funktion \"manuelle temporäre Basalrate\" gab. Bitte gehe zum Menü Therapieeinstellungen -> Verabreichungsgrenzen und lege eine neue maximale Basalrate fest."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standard Ablauf-Erinnerung"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informationen zum vorherigen Pod"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "keine\nAbgabe"; - -/* description label for active time pod details row */ -"Active Time" = "Laufzeit"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "gesamte Abgabe"; - -/* description label for device name pod details row */ -"Device Name" = "Gerätename"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot-Nummer"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequenznummer"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware-Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod aktiviert"; - -/* description label for active time pod details row */ -"Active Time" = "Laufzeit"; - -/* description label for last status date pod details row */ -"Last Status" = "Letzter Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fehlerdetails"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Im nächsten Schritt wirst du deine Erinnerungen konfigurieren, deinen Pod mit Insulin füllen, ihn mit deinem Gerät koppeln und an deinem Körper anbringen."; - -/* Cancel button title */ -"Cancel" = "Abbrechen"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Fortsetzen"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Das Omnipod Onboarding überspringen?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Die App benachrichtigt dich vor dem Ablauf des Pods.\n\nScrolle zur Einstellung der gewünschten Vorlaufzeit für die Erinnerung."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "weiter"; - -/* */ -"Expiration Reminder" = "Erinnerung an den Ablauf der Nutzungsdauer"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Die App benachrichtigt dich, wenn die Insulinmenge im Pod diesen Wert (50-10 U) erreicht.\n\nScrolle, um die Anzahl der Einheiten einzustellen, bei denen du erinnert werden möchtest."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Niedriger Reservoirstand"; - -/* */ -"Save" = "Speichern"; - -/* hr (short for hour) */ -"hr" = "h"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "manuelle Basalrate abbrechen"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulinabgabe\nunterbrochen"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Insulinabgabe fortsetzen"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Stelle sicher, dass dein Pod in der Nähe liegt und versuche es erneut."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod ist nicht verbunden"; - -/* Label for suspended at time */ -"Suspended At" = "Unterbrochen um"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Insulinabgabe fortsetzen..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Insulinabgabe unterbrechen..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Kein Pod gefunden"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Zu viele Pods gefunden"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Achte darauf, dass sich das iPhone in der Nähe des aktiven Pods befindet."; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Versuche es nochmals"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Begib dich an einen Ort außerhalb der Reichweite von anderen Pods und versuche es nochmals."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Vergewissere dich, dass dein Pod gefüllt und in der Nähe ist."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Bitte das iPhone weiter weg vom Pod positionieren"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Bitte verändere die Position des iPhones gegenüber dem Pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Bitte halte nur den ursprünglichen Pod in Reichweite oder deaktiviere ihn"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Störsignale möglich. Bitte Position ändern und dann erneut versuchen"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Stelle sicher, dass dein Pod in der Nähe liegt und versuche es erneut."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Warte, bis der aktuelle Bolus abgegeben wurde, oder brich den Bolus ab."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Warte, bis der aktuelle Bolus abgegeben wurde, oder brich den Bolus ab."; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Warte, bis die aktuelle temporäre Basalrate beendet wurde, oder brich sie ab."; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ vor"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Stille"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normaler Operationsmodus, in dem hörbare Pod Signale für alle Pod Alarme verwendet werden und wenn Vertrauenserinnerungen aktiviert sind."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Alle Pod Alarme verwenden keine Signale und Bestätigungssignale werden unterdrückt. Der Pod springt nur bei tödlichen Pod-Fehlern und beim Abspielen von Testsignalen.\n\nWarnung: Warnung - Wann immer der Pod zum Schweigen gebracht wird, muss er innerhalb des Bluetooth-Bereichs dieses Geräts gehalten werden, um Benachrichtigungen für Pod-Benachrichtigungen zu erhalten."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Stille Pod Modus unterdrückt alle Pod Warnungen und Bestätigungs-Erinnerung."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Stille Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod-Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Vorherige Pod-Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump-Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Pumpenmanager Details abrufen..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Pumpmanager Details aktualisieren"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnose-Infos"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Pod-Status ablesen"; diff --git a/Dependencies/OmniBLE/Localizations/en.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/en.lproj/Localizable.strings deleted file mode 100644 index 0082c6e7a..000000000 --- a/Dependencies/OmniBLE/Localizations/en.lproj/Localizable.strings +++ /dev/null @@ -1,828 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ - -/* Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Expiration Reminder"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Expired"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* */ -"Pod Expires" = "Pod Expires"; - -/* */ -"Pod Activated" = "Pod Activated"; - -/* */ -"Notification Settings" = "Notification Settings"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hours"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* title for device details page */ -"Device Details" = "Device Details"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Replace Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Expired"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "Insert Cannula"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Retry"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "Play Test Beeps"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "Read Pulse Log"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "Suspend"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "Resume"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulin Type"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; - - /* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Retry"; - -/* Action button description when deactivated */ -"Continue" = "Continue"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Listen for 2 beeps."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Paired"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Cancel"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Action button title for attach pod view */ -"Continue" = "Continue"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Check Cannula */ -"Check Cannula" = "Check Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Deactivating..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Label for expiration reminder row */ -"Time" = "Time"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* */ -"Setup Complete" = "Setup Complete"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheral Not Ready"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Incorrect Response"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; - -/* navigation title for notification settings */ -"Notification Settings" = "Notification Settings"; - -/* Label for scheduled reminder value row */ -"Time" = "Time"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Enabled"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Rate"; - -/* Insulin unit per hour */ -"U/hr" = "U/hr"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; - -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time"= "Active Time"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Activated"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "Cancel"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Continue"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Low Reservoir"; - -/* */ -"Save" = "Save"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ ago"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Silence Pod mode suppresses all Pod alert and confirmation reminder beeping."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; - -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniBLE/Localizations/es.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/es.lproj/Localizable.strings deleted file mode 100644 index 26cb7ea96..000000000 --- a/Dependencies/OmniBLE/Localizations/es.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Expiration Reminder"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Expired"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* */ -"Pod Expires" = "Pod Expires"; - -/* */ -"Pod Activated" = "Pod Activated"; - -/* */ -"Notification Settings" = "Notification Settings"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Cambie el Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "horas"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutos"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Section header for activity section */ -"Activity" = "Actividad"; - -/* title for device details page */ -"Device Details" = "Device Details"; - -/* Section header for configuration section */ -"Configuration" = "Configuracion"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Cambie el Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Cambie el Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Pod life HUD view label */ -"Fault" = "Fallo"; - -/* Label describing pod age view */ -"Pod Age" = "Edad del Pod"; - -/* Label describing time remaining view */ -"Remaining" = "Restante"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Cambie el Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Expired"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "Insertar Cánula"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Retry"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "Tocar Pitidos de Prueba"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "Read Pulse Log"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "Suspend"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "Resume"; - -/* */ -"Bolus" = "Bolo"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "Actividad"; - -/* Section header for configuration section */ -"Configuration" = "Configuracion"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulin Type"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspender la infusión"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Desactivar Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Retry"; - -/* Action button description when deactivated */ -"Continue" = "Continuar"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Listen for 2 beeps."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Paired"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Cancelar"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Action button title for attach pod view */ -"Continue" = "Continuar"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Check Cannula */ -"Check Cannula" = "Check Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Deactivating..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Label for expiration reminder row */ -"Time" = "Tiempo"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* */ -"Setup Complete" = "Setup Complete"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheral Not Ready"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Incorrect Response"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; -/* navigation title for notification settings */ -"Notification Settings" = "Notification Settings"; - -/* Label for scheduled reminder value row */ -"Time" = "Tiempo"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Habilitado"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Ratio"; - -/* Insulin unit per hour */ -"U/hr" = "U/h"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time" = "Tiempo Activo"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Activated"; - -/* description label for active time pod details row */ -"Active Time" = "Tiempo Activo"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "Cancelar"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Continuar"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Recordatorio de Caducidad"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Low Reservoir"; - -/* */ -"Save" = "Guardar"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "Hace %@"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Silence Pod mode suppresses all Pod alert and confirmation reminder beeping."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniBLE/Localizations/fi.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/fi.lproj/Localizable.strings deleted file mode 100644 index fc139222a..000000000 --- a/Dependencies/OmniBLE/Localizations/fi.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Expiration Reminder"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Expired"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* */ -"Pod Expires" = "Pod Expires"; - -/* */ -"Pod Activated" = "Pod Activated"; - -/* */ -"Notification Settings" = "Notification Settings"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Vaihda pumppu"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hours"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Section header for activity section */ -"Activity" = "Liikunta"; - -/* title for device details page */ -"Device Details" = "Device Details"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Vaihda pumppu"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Vaihda pumppu"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Pod life HUD view label */ -"Fault" = "Virhe"; - -/* Label describing pod age view */ -"Pod Age" = "Pumpun ikä"; - -/* Label describing time remaining view */ -"Remaining" = "Jäljellä"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Vaihda pumppu"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Expired"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "Aseta kanyyli"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Retry"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "Soita testiäänet"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "Lue pulssiloki"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "Suspend"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "Resume"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "Liikunta"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulin Type"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Pysäytä annostelu"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deaktivoi pumppu"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Retry"; - -/* Action button description when deactivated */ -"Continue" = "Jatka"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Listen for 2 beeps."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Paired"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Cancel"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Action button title for attach pod view */ -"Continue" = "Jatka"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Check Cannula */ -"Check Cannula" = "Check Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Deactivating..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Label for expiration reminder row */ -"Time" = "Time"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* */ -"Setup Complete" = "Setup Complete"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheral Not Ready"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Incorrect Response"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; -/* navigation title for notification settings */ -"Notification Settings" = "Notification Settings"; - -/* Label for scheduled reminder value row */ -"Time" = "Time"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Käytössä"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Rate"; - -/* Insulin unit per hour */ -"U/hr" = "U/hr"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time" = "Aktiivinen aika"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Activated"; - -/* description label for active time pod details row */ -"Active Time" = "Aktiivinen aika"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "Cancel"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Jatka"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Vanhenemismuistutus"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Low Reservoir"; - -/* */ -"Save" = "Save"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Silence Pod mode suppresses all Pod alert and confirmation reminder beeping."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniBLE/Localizations/fr.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/fr.lproj/Localizable.strings deleted file mode 100644 index cdc520cbd..000000000 --- a/Dependencies/OmniBLE/Localizations/fr.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Alerte de commande multiple"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Rappel d’expiration"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod expiré"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Réservoir bas"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspendre le rappel en cours"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Reprendre l'Insuline"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Appareillage pod incomplet"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Changement de temps détecté"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Alerte de commande multiple"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expire dans %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Changez de Pod maintenant. Le Pod est actif depuis 72h."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Changez de Pod maintenant. La fourniture d'Insuline s'arrêtera dans 1 heure."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insuline restante ou moins dans le pod. Changez bientôt le pod."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspendre le rappel en cours"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "La période de suspension de l'insuline est terminée. \n\nVous pouvez relancer l'administration à partir de la bannière sur l'écran d'accueil ou à partir de l'écran des paramètres de votre pompe. Vous recevrez un nouveau rappel dans 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Veuillez finir d'appairer votre Pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "L'heure de votre pompe est différente de l'heure actuelle. Vous pouvez vérifier l'heure de la pompe et la synchroniser avec l'heure actuelle dans les paramètres."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "La période de suspension est terminée. Ouvrez l'application et reprenez."; - -/* Action button default text for PodAlerts */ -"Ok" = "OK"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Activation inachevée"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Péremption du Pod dans"; - -/* */ -"Pod Expires" = "Péremption du Pod"; - -/* */ -"Pod Activated" = "Pod activé"; - -/* */ -"Notification Settings" = "Paramètres des notifications"; - -/* */ -"Confidence Reminders" = "Rappels de confiance"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspendre l'administration d'insuline"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expiré"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Désactivation inachevée"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Aucun Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Appairer le Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Appairer le Pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Appairage en cours."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Préparation. Veuillez patienter."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod appairé avec succès. Continuer."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Terminer la désactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Remplacer le pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "jour"; - -/* Unit for plural days in pod life remaining */ -"days" = "jours"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "heure"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "heures"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Administration de l'insuline"; - -/* */ -"Scheduled Basal" = "Basal programmé"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insuline restante"; - -/* Section header for activity section */ -"Activity" = "Activité"; - -/* title for device details page */ -"Device Details" = "Détails de l'appareil"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Terminer la désactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Remplacer le pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Remplacer le pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Activation inachevée"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Péremption du Pod dans"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expiré"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Désactivation inachevée"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Aucun Pod"; - -/* Pod life HUD view label */ -"Fault" = "Erreur"; - -/* Label describing pod age view */ -"Pod Age" = "Âge du pod"; - -/* Label describing time remaining view */ -"Remaining" = "Restant"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Remplacer le pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Aucun pod appairé"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod déjà appairé"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Type d'insuline non configuré"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Le Pod n’est pas dans un état prêt pour l’insertion de la canule."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Paramètre invalide"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Veuillez appairer un nouveau pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problème de com."; - -/* */ -"Finish Pairing" = "Finir l'appariement"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Terminer la désactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Aucun Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "Pas d'insuline"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod expiré"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Occlusion du Pod"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Erreur du Pod"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Pas d'insuline"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insuline suspendue"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Perte de signal"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Débit basal manuel"; - -/* */ -"Insert Cannula" = "Insérer la canule"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Insertion en cours"; - -/* Cannula insertion button text while showing error */ -"Retry" = "Réessayer"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Vérification en cours..."; - -/* */ -"Check cannula insertion finished" = "Vérification de l'insertion de canule terminée"; - -/* */ -"Get pod status" = "Obtenir l'état du Pod"; - -/* */ -"Save Basal Profile" = "Définir profil de basal"; - -/* */ -"Save basal profile failed: %{public}@" = "Échec de l'enregistrement du profil de basal : %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Ignorer les bips de test en raison du bolus en cours."; - -/* */ -"Play Test Beeps" = "Jouer des bips de test"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Ignorer les bips de test en raison du bolus en cours."; - -/* */ -"Read Pulse Log" = "Lecture journal d'impulsion"; - -/* */ -"Set Confirmation Beeps to %s" = "Définir les bips de confirmation à %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Définir la préférence des bips de confirmation"; - -/* */ -"Suspend" = "Suspendre"; - -/* */ -"Failed to suspend: %{public}@" = "Échec de la suspension : %{public}@"; - -/* */ -"Resume" = "Reprendre"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Annuler bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Réservoir vide"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion détectée"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Erreur critique du Pod"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "L'administration d'insuline s'est arrêtée. Changez de Pod maintenant."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insuline restante"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Régler basal temporaire"; - -/* Section header for activity section */ -"Activity" = "Activité"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Title for previous pod page */ -"Previous Pod" = "Pod précédent"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Heure de la pompe"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Ajustement de l'heure de la pompe..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Définir sur l'heure actuelle"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Basculer vers un autre dispositif de distribution d'insuline"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "L'heure de votre pompe est différente de l'heure actuelle. Voulez vous mettre à jour l'heure de votre pompe avec l'heure actuelle ?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Oui, synchroniser avec l'heure actuelle"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Non, garder la pompe telle quelle"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Retirer la pompe"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Voulez-vous vraiment arrêter d’utiliser Omnipod ?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Supprimer Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Type d'Insuline"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Définir sur l'heure actuelle"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspendre la distribution"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "L'administration d'insuline sera interrompue jusqu'à ce que vous la repreniez manuellement. Quand voulez-vous que Loop vous rappelle de reprendre l'administration ?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 heure"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 heure 30 minutes"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 heures"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Échec de la suspension de l'administration d'insuline"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Échec de la reprise de l’administration d’insuline"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Échec de réglage de l'heure de la pompe"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Échec d'annulation du basal manuel"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Veuillez désactiver le pod. Une fois la désactivation terminée, vous pouvez le retirer et appairer un nouveau pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Veuillez désactiver le pod. Une fois la désactivation terminée, vous pouvez appairer un nouveau Pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Désactiver le pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Désactivation."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod désactivé avec succès. Continuez."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Réessayer"; - -/* Action button description when deactivated */ -"Continue" = "Continuer"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Il y a eu un problème de communication avec le Pod. Si ce problème persiste, appuyez sur Jeter le pod. Vous pourrez ensuite activer un nouveau Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Jeter le Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Retirer le Pod du corps"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Votre Pod peut encore délivrer de l'insuline.\nRetirez-le de votre corps, puis appuyez sur \"Continuer\""; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Changez de Pod maintenant. La fourniture d'insuline s'arrêtera 8 heures après l'expiration du Pod ou quand il n'y aura plus d'insuline."; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Écoutez deux bips."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Appairé"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Annuler"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Es-tu sûr de vouloir annuler l'installation?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Si vous annulez la configuration du Pod, le Pod actuel sera désactivé et sera inutilisable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Oui, Désactiver"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Non, continuer avec le Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Préparez le site."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Vérifiez Pod, appliquez au site, puis confirmez l'attachement du pod."; - -/* Action button title for attach pod view */ -"Continue" = "Continuer"; - -/* */ -"Attach Pod" = "Collez le Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirmer l'attachement du Pod"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Veuillez confirmer que le Pod est solidement attaché à votre corps.\n\nLa canule ne peut être insérée qu'une seule fois à chaque Pod. Appuyez sur « Confirmer » lorsque le Pod est attaché."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirmer"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Appuyez ci-dessous pour démarrer l'insertion de la cannule."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Attendez que l'insertion soit terminée."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inséré"; - -/* Check Cannula */ -"Check Cannula" = "Vérifier la canule"; - -/* */ -"Is the cannula inserted properly?" = "La canule est-elle insérée correctement ?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "La zone sur le dessus du Pod devrait être colorée rose lorsque la canule est correctement insérée dans la peau."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Oui"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Non"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Appairage en cours..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Amorçage en cours..."; - -/* */ -"Deactivating..." = "Désactivation en cours"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Désactivé"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Votre pod est prêt à être utilisé.\n\n%1$@ vous rappellera de changer votre pod avant qu'il n'expire. Vous pouvez changer ce rappel à un moment qui vous convient."; - -/* */ -"Scheduled Reminder" = "Rappel programmé"; - -/* Label for expiration reminder row */ -"Time" = "Heure"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Terminer la configuration"; - -/* */ -"Setup Complete" = "Mise en place terminée"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Aucun rappel"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Périphérique non prêt"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Réponse incorrecte"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Temps écoulé"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Valeur Vide"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Caractéristique inconnu"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Rappels d'Omnipod"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "L'application configure un rappel sur le pod pour vous avertir avant l'expiration du Pod. Définissez le nombre d'heures d'avance que vous souhaitez configurer lors de l'appairage d'un nouveau Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Ceci est un rappel que vous avez planifié lorsque vous avez appairéé votre Pod actuel."; - -/* */ -"Scheduled Reminder" = "Rappel programmé"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "L'application vous avertit lorsque la quantité d'insuline dans le Pod atteint ce niveau."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Alertes critiques"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Les rappels ci-dessus ne sonneront pas si votre appareil est en mode silencieux ou Ne pas déranger.\n\nIl y a d'autres alertes et alarmes de Pod critiques qui sonneront même si votre appareil est réglé sur mode Silencieux ou Ne pas déranger."; -/* navigation title for notification settings */ -"Notification Settings" = "Paramètres des notifications"; - -/* Label for scheduled reminder value row */ -"Time" = "Heure"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Aucun rappel"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Rappel du réservoir bas"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Assurez-vous que votre téléphone et votre pod sont proches. Si des problèmes de communication persistent, déplacez vers une nouvelle zone."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Changez de Pod maintenant. La distribution d'insuline s'arrêtera dans %1$@ ou quand il n'y aura plus d'insuline."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Désactivé"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Activée"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Etendu"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Aucun rappel de confiance n'est utilisé."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Les rappels de confiance retentissent pour les commandes que vous initiez, comme le bolus, l'annulation du bolus, la suspension, la reprise, l'enregistrement des rappels de notification, etc. Lorsque l'application ajuste automatiquement l'administration, aucun rappel de confiance n'est utilisé."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Des rappels de confiance retentissent lorsque l'application ajuste automatiquement la livraison ainsi que pour les commandes que vous lancez."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Taux"; - -/* Insulin unit per hour */ -"U/hr" = "U/h"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ pour %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "La boucle n'ajuste pas automatiquement la distribution d'insuline tant que le débit de basal temporaire n'est pas terminé ou est annulé."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Définir le Basal Temporaire"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Basal Temporaire"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Échec du Basal Temporaire"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Impossible de définir un taux de basal temporaire : %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Impossible de définir un taux de basal temporaire : %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Configuration manquante"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Le Gestionnaire de Pompes n'a pas été configuré avec un débit de base maximum car il a été ajouté avant que le Basal temporaire manuel soit une fonctionnalité. Veuillez aller dans les paramètres de thérapie -> limites de délivrance et définir un nouveau taux de basal maximum."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Rappel d'expiration activé"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informations du Pod précédent"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "Plus \nd'injection"; - -/* description label for active time pod details row */ -"Active Time" = "Heure d’activation"; - -/* description label for total delivery pod details row */ -"Total Delivery" = " Total délivré"; - -/* description label for device name pod details row */ -"Device Name" = "Nom du dispositif"; - -/* description label for lot number pod details row */ -"Lot Number" = "Numéro de lot"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Numéro de séquence"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Version du firmware"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "Version Firmware BLE"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod activé"; - -/* description label for active time pod details row */ -"Active Time" = "Heure d’activation"; - -/* description label for last status date pod details row */ -"Last Status" = "Dernier état"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Détail du défaut Pod"; - -/* Title for PodSetupView */ -"Pod Setup" = "Mise en place de la pompe"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Vous allez maintenant commencer le processus de configuration de votre pod avec les rappels, en remplissant votre Pod d'insuline, en l'associant à votre appareil et en le plaçant sur votre corps."; - -/* Cancel button title */ -"Cancel" = "Annuler"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Continuer"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Ignorer l'intégration d'Omnipod ?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "L'application vous avertit avant l'expiration du Pod.\n\nFaites défiler pour définir le nombre d'heures d'avance que vous souhaitez avoir."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Continuer"; - -/* */ -"Expiration Reminder" = "Rappel d’expiration"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "L'application vous avertit lorsque la quantité d'insuline dans le Pod atteint ce niveau (50-10 U).\n\nFaites défiler pour définir le nombre d'unités a partir duquel vous souhaitez être rappelé."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Réservoir bas"; - -/* */ -"Save" = "Sauvegarder"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Annuler le basal manuel"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insuline\nSuspendue"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Reprendre l'injection d'insuline"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Assurez-vous que votre iPhone est à proximité et réessayez."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod non connecté"; - -/* Label for suspended at time */ -"Suspended At" = "Suspendu à"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Reprendre l'injection d'insuline..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspension de la distribution d'insuline..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Aucun Pod trouvé"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Trop de Pods trouvés"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Assurez-vous que l'iPhone est à proximité du pod actif"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Réessayer"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Déplacez-vous vers un nouvel endroit éloigné de tout autre Pod et réessayez."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Assurez-vous que votre pod est rempli et à proximité."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Veuillez repositionner l'iPhone plus loin que le pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Veuillez repositionner l'iPhone plus loin que le pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Veuillez rapprocher le Pod original ou désactiver le Pod d'origine"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Interférences possibles. Veuillez vous déplacer vers un nouvel emplacement"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Assurez-vous que votre iPhone est à proximité et réessayez."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Attendez que le bolus en cours se termine, ou annulez le bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Attendez que le bolus en cours se termine, ou annulez le bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Attendez que le débit basal temporaire se termine pour quitter, ou mettez en suspens pour annuler"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "Il y a %@"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Réduit au silence"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Mode de fonctionnement normal où les bips audio Pod sont utilisés pour toutes les alertes de Pod et quand les rappels de confiance sont activés."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Toutes les alertes de Pod n'utilisent aucun bip et les bips de rappel de confirmation sont supprimés. Le Pod ne sera disponible que pour les défauts fataux du Pod et lors de la lecture des bips de test.\n\n⚠️Attention - Chaque fois que le Pod est réduit au silence, il doit être maintenu à portée Bluetooth de cet appareil pour recevoir des notifications pour les alertes de Pod."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Le mode Pod silencieux supprime tous les bips d'alerte et de rappel de confirmation."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Pod silencieux"; - -/* title for pod details page */ -"Pod Details" = "Détails du Pod"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Détails du Pod précédent"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Détails du Gestionnaire de Pompes"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Récupération des détails du gestionnaire de pompe..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Actualiser les détails du Gestionnaire de Pompe"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostiques"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Lire l’état de la pompe"; diff --git a/Dependencies/OmniBLE/Localizations/he.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/he.lproj/Localizable.strings deleted file mode 100644 index 579956322..000000000 --- a/Dependencies/OmniBLE/Localizations/he.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Expiration Reminder"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Expired"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* */ -"Pod Expires" = "Pod Expires"; - -/* */ -"Pod Activated" = "Pod Activated"; - -/* */ -"Notification Settings" = "Notification Settings"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hours"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* title for device details page */ -"Device Details" = "Device Details"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Replace Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Expired"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "Insert Cannula"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Retry"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "Play Test Beeps"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "Read Pulse Log"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "Suspend"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "Resume"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulin Type"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Retry"; - -/* Action button description when deactivated */ -"Continue" = "Continue"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Listen for 2 beeps."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Paired"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Cancel"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Action button title for attach pod view */ -"Continue" = "Continue"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Check Cannula */ -"Check Cannula" = "Check Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Deactivating..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Label for expiration reminder row */ -"Time" = "Time"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* */ -"Setup Complete" = "Setup Complete"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheral Not Ready"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Incorrect Response"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; -/* navigation title for notification settings */ -"Notification Settings" = "Notification Settings"; - -/* Label for scheduled reminder value row */ -"Time" = "Time"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Enabled"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Rate"; - -/* Insulin unit per hour */ -"U/hr" = "U/hr"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Activated"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "Cancel"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Continue"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Low Reservoir"; - -/* */ -"Save" = "Save"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ ago"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Silence Pod mode suppresses all Pod alert and confirmation reminder beeping."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniBLE/Localizations/hu.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/hu.lproj/Localizable.strings deleted file mode 100644 index 90ac66acd..000000000 --- a/Dependencies/OmniBLE/Localizations/hu.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Expiration Reminder"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Expired"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* */ -"Pod Expires" = "Pod Expires"; - -/* */ -"Pod Activated" = "Pod Activated"; - -/* */ -"Notification Settings" = "Notification Settings"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "óra"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "perc"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* title for device details page */ -"Device Details" = "Device Details"; - -/* Section header for configuration section */ -"Configuration" = "Beállítások"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Replace Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Expired"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "Insert Cannula"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Retry"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "Play Test Beeps"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "Read Pulse Log"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "Felfüggesztés"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "Visszatérés"; - -/* */ -"Bolus" = "Bólus"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Section header for configuration section */ -"Configuration" = "Beállítások"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulin Type"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Retry"; - -/* Action button description when deactivated */ -"Continue" = "Continue"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Listen for 2 beeps."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Paired"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Mégse"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Action button title for attach pod view */ -"Continue" = "Continue"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Check Cannula */ -"Check Cannula" = "Check Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Igen"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nem"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Deactivating..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Label for expiration reminder row */ -"Time" = "Idő"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* */ -"Setup Complete" = "Setup Complete"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheral Not Ready"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Incorrect Response"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; -/* navigation title for notification settings */ -"Notification Settings" = "Notification Settings"; - -/* Label for scheduled reminder value row */ -"Time" = "Idő"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Enabled"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Rate"; - -/* Insulin unit per hour */ -"U/hr" = "U/óra"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Activated"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "Mégse"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Continue"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Low Reservoir"; - -/* */ -"Save" = "Save"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ ago"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Silence Pod mode suppresses all Pod alert and confirmation reminder beeping."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniBLE/Localizations/it.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/it.lproj/Localizable.strings deleted file mode 100644 index c088ad63b..000000000 --- a/Dependencies/OmniBLE/Localizations/it.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Avviso Comandi Multipli"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Promemoria di scadenza del Pod"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod scaduto"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Livello serbatoio basso"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Sospendi In Corso Promemoria"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Riprendi L'Insulina"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Accoppiamento del Pod incompleto"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Rilevato Cambio Di Tempo"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Avviso Comandi Multipli"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod scade in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Cambia Pod ora. Il Pod è attivo da 72 ore."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Cambia il Pod ora. Il dispensamento dell'insulina si fermerà tra 1 ora."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulina o meno rimanente nel Pod. Cambia il pod presto."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Sospendi In Corso Promemoria"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Il periodo di sospensione di insulina è terminato.\n\nPuoi riprendere la dispensamento dal banner sulla schermata iniziale o dalle impostazioni del microinfusore. Ti verrà ricordato di nuovo tra 15 minuti."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Per favore finisci di abbinare il pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Il tempo sul microinfusore è diverso dall'ora corrente. Puoi revisionare l'ora del microinfusore e sincronizzare l'ora corrente nelle impostazioni."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Il tempo di sospensione è scaduto. Apri l'app e ricomincia."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Attivazione Non Completata"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod scade in"; - -/* */ -"Pod Expires" = "Scadenza pod"; - -/* */ -"Pod Activated" = "Pod attivato"; - -/* */ -"Notification Settings" = "Impostazioni di Notifica"; - -/* */ -"Confidence Reminders" = "Promemoria Di Sicurezza"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Sospendi diffusione di Insulina"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod scaduto"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Deattivazione incompleta"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Nessun Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Connetti Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Connetti Pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Abbinamento in corso."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Attendere prego."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod associato con successo. Continuare."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Termina deattivazione"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Sostituisci Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "giorno"; - -/* Unit for plural days in pod life remaining */ -"days" = "giorni"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "ora"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "ore"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minuto"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minuti"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulina Somministrata"; - -/* */ -"Scheduled Basal" = "Basale programmata"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulina Rimanente"; - -/* Section header for activity section */ -"Activity" = "Attività"; - -/* title for device details page */ -"Device Details" = "Dettagli del Dispositivo"; - -/* Section header for configuration section */ -"Configuration" = "Impostazioni"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Termina deattivazione"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Sostituisci Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Sostituisci Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Attivazione Non Completata"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod scade in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod scaduto"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Deattivazione incompleta"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Nessun Pod"; - -/* Pod life HUD view label */ -"Fault" = "Guasto"; - -/* Label describing pod age view */ -"Pod Age" = "Età Pod"; - -/* Label describing time remaining view */ -"Remaining" = "Rimanente"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Sostituisci Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Nessun Pod abbinato"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod già abbinato"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Tipo di insulina non configurato"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod non è pronto per l’inserimento della cannula."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Impostazione non valida"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Abbina nuovo Pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problema Comms"; - -/* */ -"Finish Pairing" = "Finisci l'abbinamento"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Termina Deattivazione"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Nessun Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "Nessuna Insulina"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod scaduto"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Occlusione Del Pod"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Errore Pod"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Nessuna Insulina"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulina Sospesa"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Perdita Di Segnale"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Basale manuale temporanea"; - -/* */ -"Insert Cannula" = "Inserisci cannula"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserimento..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Riprova"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Controllo in corso..."; - -/* */ -"Check cannula insertion finished" = "Controlla che l'inserimento della cannula é finito"; - -/* */ -"Get pod status" = "Ottieni stato del pod"; - -/* */ -"Save Basal Profile" = "Salva impostazione di basale"; - -/* */ -"Save basal profile failed: %{public}@" = "Salvataggio di profilo basale non riuscito: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps a causa del bolo ancora in corso."; - -/* */ -"Play Test Beeps" = "Emetti bip di prova"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Omettendo Leggi il registro Pulse a causa del bolo ancora in corso."; - -/* */ -"Read Pulse Log" = "Leggi Registro Battiti"; - -/* */ -"Set Confirmation Beeps to %s" = "Imposta gli avvisi di conferma a %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Imposta Preferenze Di Conferma Beep"; - -/* */ -"Suspend" = "Sospendi"; - -/* */ -"Failed to suspend: %{public}@" = "Sospensione fallita: %{public}@"; - -/* */ -"Resume" = "Riprendi"; - -/* */ -"Bolus" = "Bolo"; - -/* */ -"Cancel Bolus" = "Cancella bolo"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Serbatoio vuoto"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusione rilevata"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Errore Critico del Pod"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Consegna di insulina interrotta. Cambia Pod ora."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulina Rimanente"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Imposta Basale Temporanea"; - -/* Section header for activity section */ -"Activity" = "Attività"; - -/* Section header for configuration section */ -"Configuration" = "Impostazioni"; - -/* Title for previous pod page */ -"Previous Pod" = "Pod Precedente"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Orario del microinfusore"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Regolando Tempo microinfusore..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sincronizza con l'ora corrente"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Cambia ad un altro dispositivo per la somministrazione di insulina"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "L'ora sul microinfusore è diversa dall'ora corrente. Vuoi aggiornare l'ora del microinfusore all'ora corrente?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Sì, sincronizza con l'ora corrente"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Tieni microinfusore Come È"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Rimuovi microinfusore"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Sei sicuro/a di voler interrompere l’uso di Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Elimina Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Tipo di Insulina"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sincronizza con l'ora corrente"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Sospendi erogazione"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "La somministrazione di insulina verrà interrotta fino a quando non riprendi manualmente. Quando vuoi che Loop ti ricordi di riprendere la diffusione?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minuti"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 ora"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 ora e 30 minuti"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 ore"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Sospensione della consegna dell'insulina non riuscita"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Ripresa della consegna dell'insulina non riuscita"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Impostazione dell'orario del microinfusore fallita"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Cancellazione dell basale manuale non riuscita"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Disattiva Pod. Quando deattivazione è riuscita, puoi rimuovere il pod e attivare uno nuovo."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Disattiva Pod. Quando deattivazione è riuscita, puoi attivare uno nuovo pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Disattiva Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deattivazione."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod disattivato con successo. Continuare."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Riprova"; - -/* Action button description when deactivated */ -"Continue" = "Continua"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Si è verificato un problema di comunicazione con il pod. Se questo problema persiste, premi Scarta pod. Poi puoi attivare un nuovo pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Scarta pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Rimuovi pod dal corpo"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Il tuo Pod può ancora consegnare Insulina.\nRimuovilo dal corpo, dopodiché premi “Continua.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Cambia il Pod ora. La somministrazione di insulina si fermerà 8 ore dopo la scadenza del Pod o quando non rimane più insulina."; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Riempi un nuovo pod con U-100 Insulina (lascia il cappuccio blu dell’ago sul pod)."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Ascolta per 2 bip."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Abbinato"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Cancella"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Sei sicuro di voler cancellare impostazioni del pod?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Se si annulla la configurazione del Pod, il Pod corrente verrà disattivato e sarà inutilizzabile."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Sì, disattiva Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, continua con il Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepara il sito."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Controlla il Pod, applica al sito e conferma che il pod è attaccato."; - -/* Action button title for attach pod view */ -"Continue" = "Continua"; - -/* */ -"Attach Pod" = "Applica pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Conferma che il pod è attaccato"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Assicurati che il Pod è fissato in modo sicuro al vostro corpo.\n\nLa cannula può essere inserita solo una volta per ogni pod. Premi “Conferma” quando il pod è collegato."; - -/* Button title for confirm attachment option */ -"Confirm" = "Conferma"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Premi qui sotto per cominciare l'inserimento della cannula."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Aspetta fino a che l'inserimento è completo."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserito"; - -/* Check Cannula */ -"Check Cannula" = "Controlla cannula"; - -/* */ -"Is the cannula inserted properly?" = "La cannula è inserita correttamente?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "La finestra nella parte superiore del Pod sara' di colore rosa quando la cannula è stata inserita correttamente nella pelle."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Sì"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Abbinamento in corso..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Caricamento in corso..."; - -/* */ -"Deactivating..." = "Sto disattivando..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Disattivato"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Il tuo Pod è pronto per l'uso. \n\n %1$@. Verrà ricordato di cambiare il tuo pod prima che scada. Questo orario può essere cambiato con un altro a te più conveniente."; - -/* */ -"Scheduled Reminder" = "Imposta promemoria"; - -/* Label for expiration reminder row */ -"Time" = "Tempo"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Termina configurazione"; - -/* */ -"Setup Complete" = "Configurazione terminata"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Nessun promemoria"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Periferica non pronta"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Risposta errata"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Tempo scaduto"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Valore vuoto"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Caratteristica sconosciuta"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Promemoria Omnipod"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "L'App puo' configurare un promemoria capace di avvisare in anticipo della scadenza del Pod. Puoi impostare il numero di ore preferito per il preavviso dalla voce Omnipod della schermata principale cliccando Configurazione>Impostazioni Notifiche>Notifica Scadenza e sceglire il numero di ore desiderato per l'avviso di scadenza."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Questo è un promemoria che hai programmato quando hai abbinato il tuo attuale Pod."; - -/* */ -"Scheduled Reminder" = "Imposta promemoria"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "L'App ti avvisa quando la quantità d'insulina nel Pod raggiunge un determinato livello."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Avvisi critici"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "I promemoria qui sopra non suoneranno se il dispositivo è in modalità silenzioso o non disturbare.\n\nCi sono altri avvisi e avvisi di pod critici che suoneranno anche se il dispositivo è impostato in modalità silenzioso o non disturbare."; -/* navigation title for notification settings */ -"Notification Settings" = "Impostazioni di Notifica"; - -/* Label for scheduled reminder value row */ -"Time" = "Tempo"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Nessun promemoria"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Notifica di serbatoio basso"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Assicurati che il tuo telefono e il Pod siano vicini l'uno all'altro. Se il problema di comunicazione persiste, spostati in un'altra zona."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Cambiare Pod adesso. L' erogazione d'insulina si interromperà tra %1$@ o quando non ci sarà più insulina nel serbatoio."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabilitato"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Abilitato"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Esteso"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Non vengono utilizzati promemoria di fiducia."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "I promemoria di fiducia suoneranno per i comandi inoltrati, come boli, cancellazione boli, sospensioni, ripristini erogazione, salvataggi di promemoria, etc. Quando iAPS invece regolerà in automatico l'erogazione allora non userà alcun promemoria di fiducia."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "I promemoria di fiducia suonano quando iAPS regola automaticamente l'erogazione e per i comandi avviati dall'utente."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Valore"; - -/* Insulin unit per hour */ -"U/hr" = "U/ora"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ per %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop non regolerà automaticamente l'erogazione d'insulina fino a quando l'impostazione della basale temporanea non sarà terminata o cancellata."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Imposta basale temporanea"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Basale temporanea"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Basale temporanea fallita"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Impossibile impostare una velocità basale temporanea: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Impossibile impostare una velocità basale temporanea: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Configurazione mancante"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Questo microinfusore non è stato configurato con una dose di basale massima perché questa è stata inserita prima che la basale temporanea manuale diventasse una funzione attiva. Andare su Impostazioni terapia - > Limiti erogazione e impostare un nuovo profilo basale massimo."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Promemoria scadenza predefinito"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informazioni Pod precedente"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\n erogata"; - -/* description label for active time pod details row */ -"Active Time" = "Tempo di attività"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Erogazione totale"; - -/* description label for device name pod details row */ -"Device Name" = "Nome dispositivo"; - -/* description label for lot number pod details row */ -"Lot Number" = "Numero lotto"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Numero di serie"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Versione firmware"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "Versione firmware BLE"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod attivato"; - -/* description label for active time pod details row */ -"Active Time" = "Tempo di attività"; - -/* description label for last status date pod details row */ -"Last Status" = "Ultimo stato"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Dettagli errore Pod"; - -/* Title for PodSetupView */ -"Pod Setup" = "Configurazione pod"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Ora inizierai il processo di configurazione dei tuoi promemoria, riempiendo il tuo Pod d'insulina, accoppiandolo al tuo dispositivo e posizionandolo sul tuo corpo."; - -/* Cancel button title */ -"Cancel" = "Cancella"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Continua"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Saltare la procedura di installazione di Omnipod?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "L'app ti informa in anticipo della scadenza del Pod.\n\nScorri per impostare il numero di ore di preavviso che vorresti avere."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Avanti"; - -/* */ -"Expiration Reminder" = "Promemoria di scadenza"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "L' app ti avvisa quando la quantità d'insulina nel Pod raggiunge questo livello (50-10 U).\n\nScorri per impostare il numero di unità da ricordare."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Livello serbatoio basso"; - -/* */ -"Save" = "Salva"; - -/* hr (short for hour) */ -"hr" = "h"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Annulla basale manuale"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulina\nSospesa"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Riprendi erogazione insulina"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Assicurati che il tuo pod sia vicino e riprova."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod non connesso"; - -/* Label for suspended at time */ -"Suspended At" = "Sospeso a"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Sto riprendendo l'erogazione di insulina..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Sospendo erogazione di insulina..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Nessun pod trovato"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Trovati troppi pod"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Assicurarsi che iPhone sia vicino al Pod attivo"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Riprovare"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Spostati in una nuova area lontana da qualsiasi altro Pod e riprova."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Assicurati che il Pod sia riempito e nelle vicinanze."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Si prega di riposizionare iPhone più lontano dal Pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Si prega di riposizionare l'iPhone rispetto al Pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Si prega di portare solo il pod originale nel raggio d'azione o disattivare il pod originale"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Possibile dialogo incrociato. Si prega di spostarsi in una nuova posizione"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Assicurati che il tuo pod sia vicino e riprova."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Attendere la fine del bolo o annulla il bolo"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Attendere la fine del bolo o annulla il bolo"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Attendi il termine della velocità basale temporanea esistente oppure sospendi per annullare"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ fa"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenziato"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Modalità di funzionamento normale in cui vengono utilizzati segnali acustici del Pod per tutti gli avvisi Pod e quando i promemoria di fiducia sono abilitati."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Tutti gli avvisi Pod non usano alcun segnale acustico e gli avvisi acustici di conferma vengono soppressi. Il Pod sarà solo beep per difetti di Pod fatali e durante la riproduzione di beep di prova.\n\n⚠️Attenzione - Ogni volta che il Pod viene silenziato, deve essere mantenuto entro la gamma Bluetooth di questo dispositivo per ricevere le notifiche per gli avvisi Pod."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "La modalità Pod Silenziato sopprime tutti gli avvisi e promemoria di conferma del Pod."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Pod Silenziato"; - -/* title for pod details page */ -"Pod Details" = "Dettagli Pod"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Dettagli Pod Precedente"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Dettagli Microinfusore"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Recupero Dettagli Microinfusore..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Recupero Dettagli Microinfusore"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostica"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Leggi stato microinfusore"; diff --git a/Dependencies/OmniBLE/Localizations/ja.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/ja.lproj/Localizable.strings deleted file mode 100644 index 6cdb095bd..000000000 --- a/Dependencies/OmniBLE/Localizations/ja.lproj/Localizable.strings +++ /dev/null @@ -1,789 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ - -/* Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Expiration Reminder"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Expired"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* */ -"Pod Expires" = "Pod Expires"; - -/* */ -"Pod Activated" = "Pod Activated"; - -/* */ -"Notification Settings" = "Notification Settings"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hours"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* title for device details page */ -"Device Details" = "Device Details"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Replace Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Expired"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "Insert Cannula"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Retry"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "Play Test Beeps"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "Read Pulse Log"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "Suspend"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "Resume"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulin Type"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; - - /* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Retry"; - -/* Action button description when deactivated */ -"Continue" = "Continue"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Listen for 2 beeps."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Paired"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Cancel"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Remove blue Pod needle cap and check cannula. Then remove paper backing."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Action button title for attach pod view */ -"Continue" = "Continue"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Check Cannula */ -"Check Cannula" = "Check Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Deactivating..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Label for expiration reminder row */ -"Time" = "Time"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* */ -"Setup Complete" = "Setup Complete"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheral Not Ready"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Incorrect Response"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; - -/* navigation title for notification settings */ -"Notification Settings" = "Notification Settings"; - -/* Label for scheduled reminder value row */ -"Time" = "Time"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Enabled"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Rate"; - -/* Insulin unit per hour */ -"U/hr" = "U/hr"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; - -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time"= "Active Time"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Activated"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "Cancel"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Continue"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Low Reservoir"; - -/* */ -"Save" = "Save"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; diff --git a/Dependencies/OmniBLE/Localizations/lt.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/lt.lproj/Localizable.strings deleted file mode 100644 index 77af0f085..000000000 --- a/Dependencies/OmniBLE/Localizations/lt.lproj/Localizable.strings +++ /dev/null @@ -1,784 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Expiration Reminder"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Expired"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* */ -"Pod Expires" = "Pod Expires"; - -/* */ -"Pod Activated" = "Pod Activated"; - -/* */ -"Notification Settings" = "Notification Settings"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hours"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* title for device details page */ -"Device Details" = "Device Details"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Replace Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Expired"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "Insert Cannula"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Retry"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "Play Test Beeps"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "Read Pulse Log"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "Suspend"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "Resume"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulin Type"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Retry"; - -/* Action button description when deactivated */ -"Continue" = "Continue"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Listen for 2 beeps."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Paired"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Cancel"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Remove blue Pod needle cap and check cannula. Then remove paper backing."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Action button title for attach pod view */ -"Continue" = "Continue"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Check Cannula */ -"Check Cannula" = "Check Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Deactivating..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Label for expiration reminder row */ -"Time" = "Time"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* */ -"Setup Complete" = "Setup Complete"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheral Not Ready"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Incorrect Response"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; -/* navigation title for notification settings */ -"Notification Settings" = "Notification Settings"; - -/* Label for scheduled reminder value row */ -"Time" = "Time"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Enabled"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Rate"; - -/* Insulin unit per hour */ -"U/hr" = "U/hr"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Activated"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "Cancel"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Continue"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Low Reservoir"; - -/* */ -"Save" = "Save"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; diff --git a/Dependencies/OmniBLE/Localizations/nb.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/nb.lproj/Localizable.strings deleted file mode 100644 index 57ba996a5..000000000 --- a/Dependencies/OmniBLE/Localizations/nb.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Varsel om samtidige kommandoer"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Utløpspåminnelse"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod utløpt"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Lite insulin i pod"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Påminnelse om pauset insulinleveranse"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Gjenoppta insulintilførsel"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Parkobling av pod var ufullstendig"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Tidsendring oppdaget"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Varsel om samtidige kommandoer"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod utløper om %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Bytt pod nå. Pod har vært aktiv i 72 timer."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Bytt Pod nå. Insulintilførselen stopper om 1 time."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin eller mindre igjen i pod. Bytt pod snart."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Påminnelse om pauset insulinleveranse"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Angitt tid for pause av insulintilførsel er utløpt.\n\nDu kan gjenoppta leveransen fra banneret på Hjem-skjermen, eller fra panelet på pumpen (gjelder kun Medtronic). Du vil bli påminnet igjen om 15 minutter."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Vennligst fullfør parkobling av pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Tiden på pumpen er forskjellig fra gjeldende tidspunkt. Du kan kontrollere pumpens tid og synkronisere til gjeldende tidspunkt i innstillinger."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Angitt tid for pause av insulintilførsel er utløpt. Åpne appen for å gjenoppta leveransen."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Ufullstendig aktivering"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod utløper om"; - -/* */ -"Pod Expires" = "Pod utløper"; - -/* */ -"Pod Activated" = "Pod aktivert"; - -/* */ -"Notification Settings" = "Varslingsinnstillinger"; - -/* */ -"Confidence Reminders" = "Bekreftelseslyder"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Sett insulintilførsel på pause"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Utløpt pod"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Ufullstendig deaktivering"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Ingen pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Parkoble pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Parkoble pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Kobler sammen."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Fyller. Vennligst vent."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Sammenkobling av pod var vellykket. Vennligst fortsett."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Fullfør deaktiveringen"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Bytt pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "dag"; - -/* Unit for plural days in pod life remaining */ -"days" = "dager"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "time"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "timer"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minutt"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutter"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulintilførsel"; - -/* */ -"Scheduled Basal" = "Planlagt basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin i pod"; - -/* Section header for activity section */ -"Activity" = "Aktivitet"; - -/* title for device details page */ -"Device Details" = "Enhetsdetaljer"; - -/* Section header for configuration section */ -"Configuration" = "Oppsett"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Fullfør deaktiveringen"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Bytt pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Bytt pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Ufullstendig aktivering"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod utløper om"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Utløpt pod"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Ufullstendig deaktivering"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Ingen pod"; - -/* Pod life HUD view label */ -"Fault" = "Feil"; - -/* Label describing pod age view */ -"Pod Age" = "Pod-alder"; - -/* Label describing time remaining view */ -"Remaining" = "Gjenstående"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Bytt pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Ingen sammenkoblet pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod er allerede sammenkoblet"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulintype ikke konfigurert"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod er ikke klar for å sette inn kanyle."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ugyldig innstilling"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Vennligst koble til ny pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Kommunikasjons-problem"; - -/* */ -"Finish Pairing" = "Fullfør parkobling"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Fullfør deaktiveringen"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Ingen pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "Tom for insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod utløpt"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pumpen er tilstoppet"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod-feil"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Tom for insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulintilførsel pauset"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signaltap"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuell basal"; - -/* */ -"Insert Cannula" = "Sett inn kanyle"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Setter inn..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Prøv igjen"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Kontrollerer..."; - -/* */ -"Check cannula insertion finished" = "Kontroller at kanyleinnsettingen er fullført"; - -/* */ -"Get pod status" = "Les pod-status"; - -/* */ -"Save Basal Profile" = "Lagre basalprofil"; - -/* */ -"Save basal profile failed: %{public}@" = "Lagring av basalprofil mislyktes: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Avbryter test av varsellyd fra pod siden bolus-leveranse fortsatt pågår."; - -/* */ -"Play Test Beeps" = "Spill test-toner"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Avbryter lesing av pulslogg siden bolus-leveranse fortsatt pågår."; - -/* */ -"Read Pulse Log" = "Les pulslogg"; - -/* */ -"Set Confirmation Beeps to %s" = "Angi bekreftelseslyder til %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Angi innstillinger for bekreftelseslyder"; - -/* */ -"Suspend" = "Pause leveranse"; - -/* */ -"Failed to suspend: %{public}@" = "Kunne ikke sette på pause: %{public}@"; - -/* */ -"Resume" = "Gjenoppta leveranse"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Avbryt bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "Ok"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Tomt reservoar"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Tilstoppelse oppdaget"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritisk feil ved pod"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulintilførselen har stanset. Bytt pod nå."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin i pod"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Angi manuell basal"; - -/* Section header for activity section */ -"Activity" = "Aktivitet"; - -/* Section header for configuration section */ -"Configuration" = "Oppsett"; - -/* Title for previous pod page */ -"Previous Pod" = "Forrige pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pumpe-tid"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Juster pumpe-tid..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synkroniser til gjeldende tid"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Bytt til en annen insulinpumpe"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Tiden det tar på pumpen er forskjellig fra nåværende tidspunkt. Ønsker du å oppdatere tidspunktet på pumpen til nåværende tidspunkt?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, synkroniser til gjeldende tid"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nei, behold pumpen som den er"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Fjern pumpe"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Er du sikker på at du vil slutte å bruke Omnipod Dash?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Slett Omnipod Dash"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulintype"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synkroniser til gjeldende tid"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Pause leveranse"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulintilførselen stanses inntil du gjenopptar manuelt. Vil du at appen skal minne minne deg på å gjenoppta tilførselen?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutter"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 time"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 time 30 minutter"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 timer"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Insulintilførselen kunne ikke settes på pause"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Insulinleveringen kunne ikke gjenopptas"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Kunne ikke angi pumpetid"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Kunne ikke avbryte manuell basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Vennligst deaktiver pod. Når den er deaktivert kan du fjerne den fra kroppen og parkoble en ny pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Vennligst deaktiver pod. Når den er deaktivert kan du parkoble en ny pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deaktiver Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktiverer."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Deaktivering av pod var vellykket. Vennligst fortsett."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Prøv igjen"; - -/* Action button description when deactivated */ -"Continue" = "Fortsett"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Det var kommunikasjonsproblemer med pod. Om problemet vedvarer, trykk Forkast pod. Du kan deretter aktivere en ny pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Forkast pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Fjern pod fra kroppen"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Det kan fortsatt bli levert insulin fra poden.\nFjern den fra kroppen, og trykk \"Fortsett\"."; - -/* Insulin Unit */ -"U" = "E"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Bytt pod nå. Insulintilførsel stopper 8 timer etter at den er utgått eller når det ikke er mer insulin igjen."; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Fyll en ny Pod med U-100 insulin (la den blå hetten være på)."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Lytt etter 2 pip."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Sammenkoblet"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Avbryt"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Er du sikker på at du vil avbryte parkobling av pod?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Hvis du avbryter oppsett av pod, vil poden bli deaktivert og kan ikke lenger brukes."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, deaktiver pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nei, fortsett med pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Gjør klart stedet hvor pod skal festes."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Kontroller pod, fest på kroppen, og bekreft at den sitter korrekt."; - -/* Action button title for attach pod view */ -"Continue" = "Fortsett"; - -/* */ -"Attach Pod" = "Fest pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bekreft at pod er festet"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Bekreft at pod er festet til kroppen.\n\nKanylen kan bare settes inn en gang. Trykk på \"Bekreft\" når pod er festet."; - -/* Button title for confirm attachment option */ -"Confirm" = "Bekreft"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Trykk under for å begynne innsetting av kanylen."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Vent til innsettingen er fullført."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Kanyle er satt inn"; - -/* Check Cannula */ -"Check Cannula" = "Kontroller kanyle"; - -/* */ -"Is the cannula inserted properly?" = "Er kanylen satt inn riktig?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Vinduet på oversiden av pod skal farges rosa når kanylen har blitt satt inn riktig."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nei"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Kobler sammen..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Fyller..."; - -/* */ -"Deactivating..." = "Deaktiverer..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktivert"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Pod er klar til bruk.\n\n%1$@ vil minne deg på å bytte pod før den utløper. Du kan sette påminnelsen til et passende tidspunkt."; - -/* */ -"Scheduled Reminder" = "Planlagt påminnelse"; - -/* Label for expiration reminder row */ -"Time" = "Tidspunkt"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Fullfør oppsett"; - -/* */ -"Setup Complete" = "Oppsett ferdig"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Ingen påminnelse"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Tilbehør er ikke klart"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Ugyldig respons"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Tidsavbrudd"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Tom verdi"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Ukjent karakteristikk"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod-påminnelser"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Appen stiller inn en påminnelse i poden for å varsle deg i forkant av at pod utløper. Angi hvor mange timer i forveien du ønsker varselet når du parkobler en ny pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dette er en påminnelse om at du planla da du parkoblet din nåværende pod."; - -/* */ -"Scheduled Reminder" = "Planlagt påminnelse"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Appen gir deg beskjed når insulinmengden i pod når dette nivået."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Kritiske varslinger"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Påminnelsene over vil ikke lyde hvis enheten er i stillemodus eller Ikke forstyrr-modus.\n\nDet finnes andre kritiske pod-varsler og -alarmer som vil lyde selv om enheten er satt til stillemodus eller Ikke forstyrr."; -/* navigation title for notification settings */ -"Notification Settings" = "Varslingsinnstillinger"; - -/* Label for scheduled reminder value row */ -"Time" = "Tidspunkt"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Ingen påminnelse"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Påminnelse om lite insulin i pod"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Sørg for at telefonen og poden er nær hverandre. Gå til et nytt område hvis kommunikasjonsproblemene vedvarer."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Bytt pod nå. Insulintilførselen stopper om %1$@, eller når det er tomt for insulin."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Deaktivert"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Aktivert"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Utvidet"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Det brukes ingen bekreftelseslyder."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Ratio"; - -/* Insulin unit per hour */ -"U/hr" = "E/t"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ i %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Appen vil ikke automatisk justere insulintilførselen før den manuelle basalraten er fullført eller kansellert."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Angi manuell basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Manuell basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Manuell basal mislyktes"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Kunne ikke angi en manuell basalrate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Kunne ikke angi en manuell basalrate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Manglende konfigurasjon"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Denne pumpedriveren har ikke blitt konfigurert med en maksimal basalrate fordi den ble lagt til før manuell midlertidig basal var en tilgjengelig funksjon. Gå til Pumpeinnstillinger -> leveringsgrenser og sett en ny maksimal basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Utløpspåminnelse"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informasjon om forrige pod"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "Ingen\nleveranse"; - -/* description label for active time pod details row */ -"Active Time" = "Aktiveringstidspunkt"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total leveranse"; - -/* description label for device name pod details row */ -"Device Name" = "Enhetsnavn"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot-nummer"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sekvensnummer"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Fastvareversjon"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE fastvareversjon"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod aktivert"; - -/* description label for active time pod details row */ -"Active Time" = "Aktiveringstidspunkt"; - -/* description label for last status date pod details row */ -"Last Status" = "Siste status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Detaljer om pod-feil"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pumpeoppsett"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Du vil nå starte prosessen med å konfigurere påminnelser, fylle pod med insulin, koble den til telefonen, og plassere den på kroppen."; - -/* Cancel button title */ -"Cancel" = "Avbryt"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Fortsett"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Hopp over Omnipod onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Appen varsler deg før pod utløper.\n\nAngi hvor mange timer i forkant du vil varsles."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Neste"; - -/* */ -"Expiration Reminder" = "Utløpspåminnelse"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Appen varsler deg når mengden insulin i pod kommer ned på dette nivået (50-10 E).\n\nAngi insulinnivå som skal utløse denne påminnelsen."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Lite insulin i pod"; - -/* */ -"Save" = "Lagre"; - -/* hr (short for hour) */ -"hr" = "t"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Avbryt manuell basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulintilførsel\npauset"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Gjenoppta insulintilførsel"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Pass på at poden er i nærheten, og prøv igjen."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod er ikke tilkoblet"; - -/* Label for suspended at time */ -"Suspended At" = "Pauset kl"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Gjenopptar insulintilførselen..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Stopper insulintilførsel..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Finner ikke pod"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Fant for mange poder"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Pass på at iPhone er i nærheten av den aktive poden"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Prøv på nytt"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Prøv på nytt et annet sted, utenfor rekkevidde av andre poder."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Pass på at poden er fylt, og i nærheten av telefonen."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Vennligst flytt iPhone lenger bort fra poden"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Vennligst flytt iPhone relativt til pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Vennligst ha bare den opprinnelige poden innenfor rekkevidde, eller deaktiver den opprinnelige poden"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Elektronisk støy i omgivelsene? Prøv på ny i et annet rom."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Pass på at poden er i nærheten, og prøv igjen."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Vent til eksisterende bolus er ferdig, eller avbryt bolus."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Vent til eksisterende bolus er ferdig, eller avbryt bolus."; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Vent til eksisterende midlertidig basal er ferdig, eller sett insulintilførsel på pause for å avbryte."; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ siden"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Silence Pod mode suppresses all Pod alert and confirmation reminder beeping."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniBLE/Localizations/nl.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/nl.lproj/Localizable.strings deleted file mode 100644 index 2e37adf37..000000000 --- a/Dependencies/OmniBLE/Localizations/nl.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Waarschuwing voor meerdere commando's"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Waarschuwing dat je Pod vervalt"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod verlopen"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Reservoir bijna leeg"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Onderbreek in voortgang herinnering"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Insuline hervatten"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod koppeling onvolledig"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Wijziging in tijd gedetecteerd"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Waarschuwing voor meerdere commando's"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod verloopt in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Vervang Pod nu. Pod is 72 uur in gebruik geweest."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Vervang Pod nu. Insulinetoediening stopt over 1 uur."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insuline of minder resterend in Pod. Vervang Pod binnenkort."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Onderbreek in voortgang herinnering"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "De insuline opschortingsperiode is afgelopen.\n\nJe kunt de toediening hervatten via de banner op het beginscherm of via de pompinstellingen. Je wordt na 15 minuten opnieuw herinnerd."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Voltooi het koppelen van je Pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "De pomptijd verschilt van de huidige tijd. Je kunt de pomptijd bekijken en synchroniseren met de huidige tijd in instellingen."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Opschortingstijd is voorbij. Open iAPS en hervat."; - -/* Action button default text for PodAlerts */ -"Ok" = "OK"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Onvoltooide activering"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod verloopt over"; - -/* */ -"Pod Expires" = "Pod verloopt"; - -/* */ -"Pod Activated" = "Pod geactiveerd"; - -/* */ -"Notification Settings" = "Instellingen voor meldingen"; - -/* */ -"Confidence Reminders" = "Bevestigingsmeldingen met piepjes vanuit de Pod"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Onderbreken van insulinetoediening"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod verlopen"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Onvoltooide activering"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Geen Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Koppel Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Koppel Pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Verbinden…."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Primen. Een ogenblik geduld."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod succesvol gekoppeld. Doorgaan."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Voltooi de deactivering"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Vervang Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "dag"; - -/* Unit for plural days in pod life remaining */ -"days" = "dagen"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "uur"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "uren"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minuut"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minuten"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulinetoediening"; - -/* */ -"Scheduled Basal" = "Gepland basaal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Resterende insuline"; - -/* Section header for activity section */ -"Activity" = "Activiteit"; - -/* title for device details page */ -"Device Details" = "Apparaatdetails"; - -/* Section header for configuration section */ -"Configuration" = "Instellingen"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Voltooi de deactivering"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Vervang Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Vervang Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Onvoltooide activering"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod verloopt over"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod verlopen"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Onvoltooide activering"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Geen Pod"; - -/* Pod life HUD view label */ -"Fault" = "Fout"; - -/* Label describing pod age view */ -"Pod Age" = "Podleeftijd"; - -/* Label describing time remaining view */ -"Remaining" = "Resterend"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Vervang Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Geen Pod verbonden"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod reeds verbonden"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulinetype niet geconfigureerd"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is niet gereed voor canuleplaatsing."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ongeldige instelling"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Verbind een nieuwe Pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Opdrachtenprobleem"; - -/* */ -"Finish Pairing" = "Koppeling voltooien"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Voltooi deactivering"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Geen Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "Geen insuline"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod verlopen"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod verstopping"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Geen insuline"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insuline tijdelijk uitgeschakeld"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signaalverlies"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Handmatige tijdelijke basaal"; - -/* */ -"Insert Cannula" = "Plaats canule"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inbrengen..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Opnieuw proberen"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Controleren..."; - -/* */ -"Check cannula insertion finished" = "Controleer of canuleplaatsing is voltooid"; - -/* */ -"Get pod status" = "Podstatus ophalen"; - -/* */ -"Save Basal Profile" = "Bewaar basaalprofiel"; - -/* */ -"Save basal profile failed: %{public}@" = "Opslaan basaalprofiel mislukt: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "De testgeluiden worden overgeslagen omdat de bolus nog bezig is."; - -/* */ -"Play Test Beeps" = "Speel testpiepjes af"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Overslaan 'Read Pulse Log' omdat bolus nog bezig is."; - -/* */ -"Read Pulse Log" = "Pulslog uitlezen"; - -/* */ -"Set Confirmation Beeps to %s" = "Stel bevestigingsgeluiden in op %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Stel voorkeuren bevestigingsgeluiden in"; - -/* */ -"Suspend" = "Onderbreek"; - -/* */ -"Failed to suspend: %{public}@" = "Opschorten mislukt: %{public}@"; - -/* */ -"Resume" = "Hervat"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Annuleer bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Reservoir leeg"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Afsluiting gedetecteerd"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritieke Pod fout"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulinetoediening gestopt. Vervang Pod nu."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Resterende insuline"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Stel tijdelijke basaal in"; - -/* Section header for activity section */ -"Activity" = "Activiteit"; - -/* Section header for configuration section */ -"Configuration" = "Instellingen"; - -/* Title for previous pod page */ -"Previous Pod" = "Vorige Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pomptijd"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pomptijd aanpassen..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchroniseer met de huidige tijd"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Schakel over op een ander insulinetoedieningsapparaat"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "De pomptijd is anders dan de huidige tijd. Wil je de tijd van je pomp updaten naar de huidige tijd?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, zet naar huidige tijd"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nee, pomp laten zoals hij is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Verwijder Pod"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Weet je zeker dat je wilt stoppen met deze Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Verwijder Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulinesoort"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchroniseer met de huidige tijd"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Onderbreek toediening"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "De insulinetoediening wordt gestopt totdat je de toediening handmatig hervat. Wanneer wil je dat iAPS je eraan herinnert om de toediening te hervatten?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minuten"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 uur"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 uur en 30 minuten"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 uur"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Onderbreken van insulinetoediening mislukt"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Hervatten insulinelevering mislukt"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Instellen pomptijd mislukt"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Annuleren van handmatige basaal mislukt"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Deactiveer de Pod. Wanneer de deactivering voltooid is, kun je de Pod verwijderen en een nieuwe koppelen."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Deactiveer de Pod. Wanneer de deactivering voltooid is, kun je hem verwijderen en een nieuwe Pod koppelen."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deactiveer Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactiveren."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod met succes gedeactiveerd. Doorgaan."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Opnieuw proberen"; - -/* Action button description when deactivated */ -"Continue" = "Vervolg"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Er was een communicatieprobleem met de Pod. Als dit probleem zich blijft voordoen, tik dan op 'Pod verwijderen'. Je kunt dan een nieuwe Pod activeren."; - -/* Text for discard pod button */ -"Discard Pod" = "Pod verwijderen"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Verwijder Pod van lichaam"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Mogelijk levert je Pod nog steeds insuline.\nVerwijder deze van je lichaam en tik op \"Doorgaan\""; - -/* Insulin Unit */ -"U" = "E"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Vervang Pod nu. De insulinetoediening stopt 8 uur nadat de Pod is verlopen of wanneer er geen insuline meer over is."; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Vul een nieuwe Pod met U-100 insuline. Verwijder de blauwe naalddop niet."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Luister naar 2 piepjes."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Verbonden"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Annuleer"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Weet je zeker dat je de Podinstallatie wilt annuleren?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Als je de Podinstallatie annuleert, wordt de huidige Pod gedeactiveerd en onbruikbaar."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, deactiveer deze Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nee, ga door met deze Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Bereid de infusieplaats voor."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Controleer de Pod, breng aan op de infusieplaats en bevestig de plaatsing."; - -/* Action button title for attach pod view */ -"Continue" = "Vervolg"; - -/* */ -"Attach Pod" = "Bevestig Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bevestig Podplaatsing"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Bevestig dat de Pod goed op je lichaam is bevestigd.\n\nDe canule kan slechts eenmaal per Pod worden ingebracht. Tik op \"Bevestigen\" wanneer de Pod goed is aangebracht op je lichaam."; - -/* Button title for confirm attachment option */ -"Confirm" = "Bevestig"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tik hieronder om het inbrengen van de canule te starten."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wacht tot het inbrengen is voltooid."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Ingebracht"; - -/* Check Cannula */ -"Check Cannula" = "Check canule"; - -/* */ -"Is the cannula inserted properly?" = "Is de canule correct ingebracht?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Het venster aan de bovenkant van de Pod moet roze gekleurd zijn wanneer de canule goed in de huid is ingebracht."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nee"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Verbinden..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Voorvullen..."; - -/* */ -"Deactivating..." = "Uitschakelen..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Uitgeschakeld"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Je Pod is klaar voor gebruik.\n\niAPS (%1$@) zal je eraan herinneren om je Pod te vervangen voordat deze verloopt. Je kunt dit veranderen in een tijdstip dat je beter uitkomt."; - -/* */ -"Scheduled Reminder" = "Geplande melding"; - -/* Label for expiration reminder row */ -"Time" = "Tijd"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Voltooi setup"; - -/* */ -"Setup Complete" = "Setup voltooid"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Geen herinnering"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Randapparaat niet gereed"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Onjuist antwoord"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Lege waarde"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Onbekend kenmerk"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod herinneringen"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "iAPS configureert melding op de Pod om je op de hoogte te stellen wanneer de Pod verloopt. Stel het aantal uren vooraf in dat je standaard wilt instellen als je een nieuwe Pod koppelt."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dit is een herinnering die je hebt gepland toen je je huidige Pod koppelde."; - -/* */ -"Scheduled Reminder" = "Geplande melding"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "iAPS geeft een melding als de hoeveelheid insuline in de Pod dit niveau bereikt."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Kritieke waarschuwingen"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Als je apparaat stil is of in de Niet storen-modus staat, hoor je de bovenstaande herinneringen niet in de app. Er zijn echter andere belangrijke waarschuwingen voor de Pod die nog steeds in de app verschijnen, zelfs als je apparaat stil is of in de Niet storen-modus staat. De Pod maakt ook geluid met piepjes voor alle herinneringen en waarschuwingen, behalve als de Pod is uitgeschakeld."; -/* navigation title for notification settings */ -"Notification Settings" = "Instellingen voor meldingen"; - -/* Label for scheduled reminder value row */ -"Time" = "Tijd"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Geen herinnering"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Herinnering 'Reservoir bijna leeg'"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Zorg ervoor dat je iPhone en Pod dicht bij elkaar liggen. Als communicatieproblemen aanhouden, ga dan naar een nieuw gebied."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Vervang Pod nu. De insulinetoediening stopt over %1$@ of wanneer er geen insuline meer over is."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Uitgeschakeld"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Ingeschakeld"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Uitgebreid"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Er worden geen bevestigingsmeldingen gebruikt."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Bevestigingsmeldingen zullen klinken voor opdrachten die je zelf geeft zoals bolus, annulering, geschorst, hervatten, opslaan van meldingen etc. Als iAPS de toediening automatisch wijzigt dan worden geen bevestigingsmeldingen gegeven."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Bevestigingsmeldingen zullen klinken als iAPS de levering automatisch aanpast en bij opdrachten die je zelf geeft."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Waarde"; - -/* Insulin unit per hour */ -"U/hr" = "E/uur"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ voor %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "iAPS zal niet automatisch jouw insulinetoediening aanpassen tot de tijdelijke basaalstand is beëindigd of is geannuleerd."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Tijdelijke basaal instellen"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Tijdelijke basaal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Tijdelijke basaalstanden mislukt"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Kan geen tijdelijke basaalstand instellen: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Kan geen tijdelijke basaalstand instellen: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Configuratie ontbreekt"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Deze pompmanager is niet geconfigureerd met een maximale basaalstand omdat het is toegevoegd voordat handmatig tijdelijke basaal een functie was. Ga naar therapie instellingen -> afleverlimieten en stel een nieuwe maximale basaalstand in."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standaard herinnering voor einde Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informatie vorige Pod"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "Geen \nlevering"; - -/* description label for active time pod details row */ -"Active Time" = "Actieve duur"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Totaal afgegeven"; - -/* description label for device name pod details row */ -"Device Name" = "Apparaatnaam"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lotnummer"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Volgnummer"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmwareversie"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmwareversie"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod geactiveerd"; - -/* description label for active time pod details row */ -"Active Time" = "Activatie tijd"; - -/* description label for last status date pod details row */ -"Last Status" = "Laatste status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod foutdetails"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Je gaat nu beginnen met het configureren van je herinneringen, het vullen van je Pod met insuline, het koppelen van je apparaat en het plaatsen van de Pod op je lichaam."; - -/* Cancel button title */ -"Cancel" = "Annuleer"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Vervolg"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Omnipod onboarding overslaan?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "iAPS geeft een melding voordat de Pod vervalt.\n\nScroll om in te stellen hoeveel uren, voordat de Pod verloopt, je een kennisgeving wilt hebben."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Volgende"; - -/* */ -"Expiration Reminder" = "Let op je Pod vervalt"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "iAPS geeft een melding als de hoeveelheid insuline in de Pod dit niveau bereikt (50-10 E).\n\nScroll om in te stellen bij welk aantal eenheden je wilt worden herinnerd."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Reservoir bijna leeg"; - -/* */ -"Save" = "Opslaan"; - -/* hr (short for hour) */ -"hr" = "uur"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Annuleer handmatige basaal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insuline\nOnderbroken"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Insulinetoediening hervatten"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Zorg dat je Pod in de buurt is en probeer opnieuw."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod is niet verbonden"; - -/* Label for suspended at time */ -"Suspended At" = "Onderbroken op"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Insulinetoediening hervatten..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Onderbreken van insulinetoediening..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Geen pods gevonden"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Te veel pods gevonden"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Zorg ervoor dat de iPhone dicht bij de actieve pod in de buurt is"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Probeer opnieuw"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Verplaats naar een nieuw gebied dat uit de buurt is van andere Pods en probeer opnieuw."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Zorg ervoor dat je pod is ingevuld en in de buurt is."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Verplaats de iPhone verder weg van de pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Verplaats de iPhone ten opzichte van de pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Breng alstublieft alleen de originele pod binnen bereik of deactiveer de originele pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Verstoring mogelijk. Ga naar een nieuwe locatie en probeer het opnieuw"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Zorg dat je Pod in de buurt is en probeer opnieuw."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wacht tot huidige bolus is voltooid, of annuleer bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wacht tot huidige bolus is voltooid, of annuleer bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wacht tot de huidige tijdelijke basaalsnelheid is voltooid, of onderbreek om te annuleren"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ geleden"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Gedempt"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normale modus waarbij hoorbare piepjes worden gebruikt voor alle Podwaarschuwingen en wanneer bevestigingsmeldingen zijn ingeschakeld."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Alle Podalarmen gebruiken geen piepjes en bevestigingsmeldingen worden gedempt. De Pod zal alleen piepen bij fatale Podfouten en bij testpiepjes.\n\n⚠️Waarschuwing - Als de Pod is gedempt, moet deze binnen het Bluetooth-bereik van dit apparaat zijn om meldingen voor Pod te ontvangen."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Stille Podmodus dempt alle Podalarmen en bevestigingsmeldingen."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Podgeluiden dempen"; - -/* title for pod details page */ -"Pod Details" = "Poddetails"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Details vorige Pod"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Details pompmanager"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Gegevens pompmanager ophalen..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Ververs details pompmanager"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostische gegevens"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Lees pompstatus"; diff --git a/Dependencies/OmniBLE/Localizations/pl.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/pl.lproj/Localizable.strings deleted file mode 100644 index 97b53eca7..000000000 --- a/Dependencies/OmniBLE/Localizations/pl.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Expiration Reminder"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Expired"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* */ -"Pod Expires" = "Pod Expires"; - -/* */ -"Pod Activated" = "Pod Activated"; - -/* */ -"Notification Settings" = "Notification Settings"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Wymień PODa"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hours"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minut"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Section header for activity section */ -"Activity" = "Aktywność"; - -/* title for device details page */ -"Device Details" = "Device Details"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Wymień PODa"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Wymień PODa"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Pod life HUD view label */ -"Fault" = "Usterka"; - -/* Label describing pod age view */ -"Pod Age" = "Wiek PODa"; - -/* Label describing time remaining view */ -"Remaining" = "Pozostało"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Wymień PODa"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Expired"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "Wprowadź kaniulę"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Retry"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "Odtwarzaj dźwięki testu"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "Read Pulse Log"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "Suspend"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "Resume"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "Aktywność"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulin Type"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Wstrzymaj podawanie"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Dezaktywuj PODa"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Retry"; - -/* Action button description when deactivated */ -"Continue" = "Kontynuuj"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Listen for 2 beeps."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Paired"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Anuluj"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Action button title for attach pod view */ -"Continue" = "Kontynuuj"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Check Cannula */ -"Check Cannula" = "Check Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Deactivating..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Label for expiration reminder row */ -"Time" = "Czas"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* */ -"Setup Complete" = "Setup Complete"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheral Not Ready"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Incorrect Response"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; -/* navigation title for notification settings */ -"Notification Settings" = "Notification Settings"; - -/* Label for scheduled reminder value row */ -"Time" = "Czas"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Włączony"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Rate"; - -/* Insulin unit per hour */ -"U/hr" = "U/hr"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time" = "Czas aktywny"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Activated"; - -/* description label for active time pod details row */ -"Active Time" = "Czas aktywny"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "Anuluj"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Kontynuuj"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Przypomnienie o terminie ważności"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Low Reservoir"; - -/* */ -"Save" = "Zapisz"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ temu"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Silence Pod mode suppresses all Pod alert and confirmation reminder beeping."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniBLE/Localizations/pt-BR.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/pt-BR.lproj/Localizable.strings deleted file mode 100644 index e3729d5a0..000000000 --- a/Dependencies/OmniBLE/Localizations/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Expiration Reminder"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Expired"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* */ -"Pod Expires" = "Pod Expires"; - -/* */ -"Pod Activated" = "Pod Activated"; - -/* */ -"Notification Settings" = "Notification Settings"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Substituir Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "horas"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutos"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Section header for activity section */ -"Activity" = "Atividade"; - -/* title for device details page */ -"Device Details" = "Device Details"; - -/* Section header for configuration section */ -"Configuration" = "Ajustes"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Substituir Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Substituir Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Pod life HUD view label */ -"Fault" = "Falha"; - -/* Label describing pod age view */ -"Pod Age" = "Idade do Pod"; - -/* Label describing time remaining view */ -"Remaining" = "Restante"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Substituir Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Expired"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "Inserir Cânula"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Retry"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "Tocar bipes de teste"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "Ler Log do Pulse"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "Suspend"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "Resume"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "Atividade"; - -/* Section header for configuration section */ -"Configuration" = "Ajustes"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Tipo de Insulina"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspender Entrega"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Desativar Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Retry"; - -/* Action button description when deactivated */ -"Continue" = "Continuar"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Listen for 2 beeps."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Paired"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Cancelar"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Action button title for attach pod view */ -"Continue" = "Continuar"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Check Cannula */ -"Check Cannula" = "Check Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Deactivating..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Label for expiration reminder row */ -"Time" = "Hora"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* */ -"Setup Complete" = "Setup Complete"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheral Not Ready"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Incorrect Response"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; -/* navigation title for notification settings */ -"Notification Settings" = "Notification Settings"; - -/* Label for scheduled reminder value row */ -"Time" = "Hora"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Ativado"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Taxa"; - -/* Insulin unit per hour */ -"U/hr" = "U/hr"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time" = "Tempo Ativo"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Activated"; - -/* description label for active time pod details row */ -"Active Time" = "Tempo Ativo"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "Cancelar"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Continuar"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Lembrete de Expiração"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Low Reservoir"; - -/* */ -"Save" = "Salvar"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ atrás"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Silence Pod mode suppresses all Pod alert and confirmation reminder beeping."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniBLE/Localizations/pt-PT.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/pt-PT.lproj/Localizable.strings deleted file mode 100644 index d749cfe1f..000000000 --- a/Dependencies/OmniBLE/Localizations/pt-PT.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Expiration Reminder"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Expired"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* */ -"Pod Expires" = "Pod Expires"; - -/* */ -"Pod Activated" = "Pod Activated"; - -/* */ -"Notification Settings" = "Notification Settings"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "horas"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutos"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* title for device details page */ -"Device Details" = "Device Details"; - -/* Section header for configuration section */ -"Configuration" = "Ajustes"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Replace Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Expired"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "Insert Cannula"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Retry"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "Play Test Beeps"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "Read Pulse Log"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "Suspend"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "Resume"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Section header for configuration section */ -"Configuration" = "Ajustes"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulin Type"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Retry"; - -/* Action button description when deactivated */ -"Continue" = "Continue"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Listen for 2 beeps."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Paired"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Cancelar"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Action button title for attach pod view */ -"Continue" = "Continue"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Check Cannula */ -"Check Cannula" = "Check Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Deactivating..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Label for expiration reminder row */ -"Time" = "Hora"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* */ -"Setup Complete" = "Setup Complete"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheral Not Ready"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Incorrect Response"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; -/* navigation title for notification settings */ -"Notification Settings" = "Notification Settings"; - -/* Label for scheduled reminder value row */ -"Time" = "Hora"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Enabled"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Taxa"; - -/* Insulin unit per hour */ -"U/hr" = "U/hr"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Activated"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "Cancelar"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Continue"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Low Reservoir"; - -/* */ -"Save" = "Salvar"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ ago"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Silence Pod mode suppresses all Pod alert and confirmation reminder beeping."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniBLE/Localizations/ro.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/ro.lproj/Localizable.strings deleted file mode 100644 index 6cdb095bd..000000000 --- a/Dependencies/OmniBLE/Localizations/ro.lproj/Localizable.strings +++ /dev/null @@ -1,789 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ - -/* Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Expiration Reminder"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Expired"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* */ -"Pod Expires" = "Pod Expires"; - -/* */ -"Pod Activated" = "Pod Activated"; - -/* */ -"Notification Settings" = "Notification Settings"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hours"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* title for device details page */ -"Device Details" = "Device Details"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "No Pod"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Replace Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Expired"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "Insert Cannula"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Retry"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "Play Test Beeps"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "Read Pulse Log"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "Suspend"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "Resume"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Insulin Type"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; - - /* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Retry"; - -/* Action button description when deactivated */ -"Continue" = "Continue"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Listen for 2 beeps."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Paired"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Cancel"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Remove blue Pod needle cap and check cannula. Then remove paper backing."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Action button title for attach pod view */ -"Continue" = "Continue"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Check Cannula */ -"Check Cannula" = "Check Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Deactivating..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Label for expiration reminder row */ -"Time" = "Time"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* */ -"Setup Complete" = "Setup Complete"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheral Not Ready"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Incorrect Response"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; - -/* navigation title for notification settings */ -"Notification Settings" = "Notification Settings"; - -/* Label for scheduled reminder value row */ -"Time" = "Time"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Enabled"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Rate"; - -/* Insulin unit per hour */ -"U/hr" = "U/hr"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; - -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time"= "Active Time"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Activated"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "Cancel"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Continue"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Low Reservoir"; - -/* */ -"Save" = "Save"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; diff --git a/Dependencies/OmniBLE/Localizations/ru.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/ru.lproj/Localizable.strings deleted file mode 100644 index 21a81cd02..000000000 --- a/Dependencies/OmniBLE/Localizations/ru.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Предупреждение о нескольких командах"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Напоминание об истечении срока"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Истёк срок действия пода"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "В резервуаре мало инсулина"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Напоминание о приостановке пода"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Возобновить подачу"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Сопряжение не завершено"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Обнаружено изменение времени"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Предупреждение о нескольких командах"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Под истекает через %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Замените под сейчас. Он был активен 72 часа."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Замените под сейчас. Подача инсулина прекратится через 1 час."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ или менее инсулина осталось в поде. Необходима скорая замена."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Напоминание о приостановке пода"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Срок приостановки истек.\n\nВы можете продолжить подачу с основного экрана или через настройки помпы. Повторное напоминание через 15 минут."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Пожалуйста, завершите сопряжение вашего пода."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Время на помпе отличается от текущего времени. Вы можете проверить время помпы и синхронизировать его с текущим временем в настройках."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Под приостановлен. Откройте приложение и возобновите подачу."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ок"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Незаконченная активация"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Под истекает через"; - -/* */ -"Pod Expires" = "Под действителен до"; - -/* */ -"Pod Activated" = "Под активирован"; - -/* */ -"Notification Settings" = "Настройки уведомлений"; - -/* */ -"Confidence Reminders" = "Напоминания о верификации"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Приостановить подачу инсулина"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Срок действия пода истек"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Деактивация не завершена"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Нет пода"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Сопряжение пода"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Сопряжение пода."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Сопряжение"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Заправка. Пожалуйста, подождите."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Под успешно сопряжен. Продолжить."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Завершить деактивацию"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Заменить Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "день"; - -/* Unit for plural days in pod life remaining */ -"days" = "дней"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "час"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "часов"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "минута"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "минут"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Подача инсулина"; - -/* */ -"Scheduled Basal" = "Запланированный Базал"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Осталось инсулина"; - -/* Section header for activity section */ -"Activity" = "Нагрузка"; - -/* title for device details page */ -"Device Details" = "Сведения об устройстве"; - -/* Section header for configuration section */ -"Configuration" = "Конфигурация"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Завершить деактивацию"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Заменить Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Заменить Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Незаконченная активация"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Под истекает через"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Срок действия пода истек"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Деактивация не завершена"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Нет пода"; - -/* Pod life HUD view label */ -"Fault" = "Сбой"; - -/* Label describing pod age view */ -"Pod Age" = "Pod проработал"; - -/* Label describing time remaining view */ -"Remaining" = "Заполняется"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Заменить Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Нет сопряженного пода"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Под уже сопряжен"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Тип инсулина не настроен"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Под не готов к установке катетера."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Недопустимые настройки"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Пожалуйста, подключите новый под"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Проблемы с сообщением"; - -/* */ -"Finish Pairing" = "Завершить сопряжение"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Завершить деактивацию"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Нет пода"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "Нет инсулина"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Истёк срок действия пода"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Окклюзия Пода"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Ошибка Пода"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Нет инсулина"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Подача приостановлена"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Сигнал потерян"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Ручная ВБС"; - -/* */ -"Insert Cannula" = "Вставьте катетер"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Введение..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Повторить"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Проверка..."; - -/* */ -"Check cannula insertion finished" = "Проверьте - завершилось ли введение канюли"; - -/* */ -"Get pod status" = "Получить статус Пода"; - -/* */ -"Save Basal Profile" = "Сохранить Базальный профиль"; - -/* */ -"Save basal profile failed: %{public}@" = "Базальный профиль не сохранен: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Пропуск звуковых тестовых сигналов, пока идет болюс."; - -/* */ -"Play Test Beeps" = "Включить проверку сигналов"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Пропуск чтения журнала пульса, пока идет болюс."; - -/* */ -"Read Pulse Log" = "Читать журнал сигналов"; - -/* */ -"Set Confirmation Beeps to %s" = "Задать подтверждающие сигналы на %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Настройка подтверждающих звуковых сигналов"; - -/* */ -"Suspend" = "Остановка"; - -/* */ -"Failed to suspend: %{public}@" = "Не удалось приостановить подачу: %{public}@"; - -/* */ -"Resume" = "Возобновление"; - -/* */ -"Bolus" = "Болюс"; - -/* */ -"Cancel Bolus" = "Отменить болюс"; - -/* Alert acknowledgment OK button */ -"OK" = "ОК"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Резервуар пуст"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Обнаружена закупорка"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Критическая ошибка Пода"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Подача инсулина остановлена. Замените Под."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Осталось инсулина"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Установить Временную Базальную Скорость"; - -/* Section header for activity section */ -"Activity" = "Нагрузка"; - -/* Section header for configuration section */ -"Configuration" = "Конфигурация"; - -/* Title for previous pod page */ -"Previous Pod" = "Предыдущий Под"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Время помпы"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Настройка времени помпы..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Синхронизировать с текущим временем"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Переключиться на другое устройство подачи инсулина"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Время на помпе отличается от текущего времени. Обновить время на помпе до текущего времени?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Да, синхронизировать с текущим временем"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Нет, оставить как есть"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Снимите Под"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Вы уверены, что хотите прекратить использование Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Удалить Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Тип инсулина"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Синхронизировать с текущим временем"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Остановить подачу"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Подача инсулина будет остановлена, пока Вы не возобновите ее вручную. Когда Вы хотели бы, чтобы Loop напомнил Вам возобновить подачу?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 минут"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 час"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 час и 30 минут"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 часа"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Не удалось приостановить подачу инсулина"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Не удалось возобновить подачу инсулина"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Не удалось настроить время на помпе"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Не удалось отменить ручной базал"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Пожалуйста, деактивируйте Под. Когда деактивация завершится, Вы можете снять Под и установить новый."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Пожалуйста, деактивируйте Под. Когда деактивация завершится, Вы можете установить новый Под."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Деактивировать Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Деактивировать."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Под успешно деактивирован. Продолжить."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Повторить"; - -/* Action button description when deactivated */ -"Continue" = "Продолжить"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Возникла проблема связи с Подом. Если эта проблема сохраняется, нажмите Отменить Под. Затем, Вы можете активировать новый."; - -/* Text for discard pod button */ -"Discard Pod" = "Отклонить под"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Удалить под из тела"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Ваш Под все еще может доставлять инсулин.\nСнимите его с тела, затем нажмите - \"Продолжить.\""; - -/* Insulin Unit */ -"U" = "Ед"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Замените Под. Подача инсулина будет остановлена спустя 8 часов после истечения срока действия Пода, либо когда резервуар будет пуст."; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Заполните новый Под U-100 инсулином (оставьте синюю защитную крышку Пода)."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Удалите синюю крышку иглы Пода и проверьте канюлю. Затем удалите защитные пленки."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Прослушайте 2 звуковых сигнала."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Сопряжен"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Отмена"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Вы уверены, что хотите отменить установку Пода?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Если отменить установку Пода, текущий Под будет деактивирован и его невозможно будет использовать."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Да, деактивировать Под"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Нет, продолжить с текущим Подом"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Подготовьте место."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Проверьте Под, установите его на теле, затем подтвердите установку Пода."; - -/* Action button title for attach pod view */ -"Continue" = "Продолжить"; - -/* */ -"Attach Pod" = "Прикрепите Под"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Подтвердите прикрепление Пода"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Пожалуйста, подтвердите, что Под надежно прикреплен к телу.\n\nКанюля может быть вставлена только один раз с каждым Подом. Нажмите \"Подтверждаю\", когда Под будет прикреплен."; - -/* Button title for confirm attachment option */ -"Confirm" = "Подтверждаю"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Нажмите ниже, чтобы начать установку канюли."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Дождитесь окончания введения канюли."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Введено"; - -/* Check Cannula */ -"Check Cannula" = "Проверьте канюлю"; - -/* */ -"Is the cannula inserted properly?" = "Правильно ли вставлена канюля?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Окно в верхней части Пода - должно окрасится в розовый цвет, когда канюля правильно установлена под кожу."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Да"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Нет"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Сопряжение..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Заправка..."; - -/* */ -"Deactivating..." = "Деактивация..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Деактивирован"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Ваш Под готов к использованию.\n\n%1$@ напомнит Вам поменять Под до истечения срока его использования. Можно изменить это время на удобное для Вас."; - -/* */ -"Scheduled Reminder" = "Запланировать напоминание"; - -/* Label for expiration reminder row */ -"Time" = "Время"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Завершить настройку"; - -/* */ -"Setup Complete" = "Настройка завершена"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Не напоминать"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Периферия не готова"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Неверный отклик"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Время ожидания истекло"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Отсутствует значение"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Неизвестная характеристика"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Напоминания Omnipod"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Настройте напоминание, чтобы заранее получить уведомление об истечении срока действия Пода. Укажите за сколько часов до истечения срока действия Пода получать уведомление, при сопряжении с новым Подом."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Это напоминание, которое Вы запланировали, когда установили сопряжение с текущим Подом."; - -/* */ -"Scheduled Reminder" = "Запланировать напоминание"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Приложение оповестит Вас, когда количество инсулина в Поде достигнет этого уровня."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Критические предупреждения"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Приведенные выше напоминания не будут звучать, если ваше устройство находится в режиме отключения звука или \"Не беспокоить\".\n\nСуществуют и другие важные оповещения Pod и сигналы тревоги, которые будут звучать, даже если ваше устройство настроено на беззвучный режим или режим \"Не беспокоить\"."; -/* navigation title for notification settings */ -"Notification Settings" = "Настройки уведомлений"; - -/* Label for scheduled reminder value row */ -"Time" = "Время"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Не напоминать"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Напоминание об уровне резервуара"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Убедитесь, что Ваш телефон и Под рядом друг с другом. Если проблемы сохранятся, переместитесь в другое помещение."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Замените Под сейчас. Подача инсулина будет остановлена спустя %1$@ или когда резервуар будет пуст."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Отключены"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Активировано"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Расширенные"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Доверенные звуковые сигналы не используются."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Доверенные звуковые сигналы сработают для операций, которые Вы инициируете - Болюс, Отмена Болюса, Приостановка подачи, Возобновление подачи, Сохранение напоминаний и т. д. Когда петля автоматически меняет подачу инсулина - звуковые сигналы не используются."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Доверенные звуковые сигналы сработают даже тогда, когда петля автоматически изменит подачу инсулина, а также для команд, которые Вы инициируете."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Скорость"; - -/* Insulin unit per hour */ -"U/hr" = "Ед/ч"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ на %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Петля не будет автоматически изменять подачу инсулина, пока Временная Базальная Скорость не завершится, либо не будет отменена пользователем."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Установить Временный Базал"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Временный базал"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Не удалось установить базал"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Не удалось установить ВБС: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Не удалось установить ВБС: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Отсутствует конфигурация"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Помощник настройки помпы не был сконфигурирован относительно максимального уровня базального инсулина. Пожалуйста, перейдите в \"Настройки помпы\" -> \"Предел подачи\" и установите новый максимальный уровень базального инсулина."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Напоминание об истечении срока"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Информация о предыдущем Поде"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "Нет\nПодачи"; - -/* description label for active time pod details row */ -"Active Time" = "Активирован в"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Всего доставлено"; - -/* description label for device name pod details row */ -"Device Name" = "Имя устройства"; - -/* description label for lot number pod details row */ -"Lot Number" = "Номер партии"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Порядковый номер"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Версия прошивки"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE версия прошивки"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Под активирован"; - -/* description label for active time pod details row */ -"Active Time" = "Активирован в"; - -/* description label for last status date pod details row */ -"Last Status" = "Последний статус"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Детали о сбое"; - -/* Title for PodSetupView */ -"Pod Setup" = "Настройка Пода"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Сейчас Вы начнете процесс конфигурации напоминаний, заполнения Пода инсулином, сопряжения с телефоном и установку его на тело."; - -/* Cancel button title */ -"Cancel" = "Отмена"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Продолжить"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Пропустить Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Приложение заранее оповестит Вас об истечении срока действия Пода.\n\nПрокрутите, чтобы установить количество часов до такого оповещения."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Далее"; - -/* */ -"Expiration Reminder" = "Напоминание об истечении срока"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Приложение оповестит Вас, когда количество инсулина в Поде достигнет этого уровеня (50-10 Ед.).\n\nПрокрутите, чтобы установить количество единиц для напоминания."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "В резервуаре мало инсулина"; - -/* */ -"Save" = "Сохранить"; - -/* hr (short for hour) */ -"hr" = "ч"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Отменить Ручной Базал"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Подача\nПриостановлена"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Возобновить подачу инсулина"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Убедитесь, что Ваш Под поблизости и попробуйте снова."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Под не подключен"; - -/* Label for suspended at time */ -"Suspended At" = "Приостановлено в"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Возобновление подачи инсулина..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Приостановка подачи инсулина..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Поды не найдены"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Найдено слишком много подов"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Убедитесь, что iPhone находится рядом с активным Подом"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Попробуйте снова"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Переместитесь в другое помещение подальше любых других Подов и попробуйте снова."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Убедитесь, что Под заполнен и поблизости."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Пожалуйста, переместите iPhone подальше от Пода"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Пожалуйста, переместите iPhone относительно Пода"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Пожалуйста, держите только исходный Под в зоне действия или деактивируйте оригинальный Под"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Возможна коммуникация с чужой помпой. Пожалуйста, переместитесь в новое место"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Убедитесь, что Ваш Под поблизости и попробуйте снова."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Дождитесь окончания болюса или отмените его"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Дождитесь окончания болюса или отмените его"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Дождитесь окончания текущего временного базала или отмените его"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ назад"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Беззвучно"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Обычный режим работы, при котором звуковые сигналы используются для всех оповещений Пода и при включенных доверенных напоминаниях."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Все уведомления Пода не издают звуковых сигналов и напоминания о подтверждении подавлены. Под будет издавать звуковые сигналы только при критических сбоях Пода и когда проигрываются тестовые звуки.\n\n⚠️Предупреждение — Когда Под заглушен, он должен находиться в пределах Bluetooth-диапазона этого устройства, для получения сигналов уведомлений."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Беззвучный режим Пода отключает все звуковые сигналы и напоминания о подтверждении Пода."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Беззвучный Под"; - -/* title for pod details page */ -"Pod Details" = "Сведения о Поде"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Сведения о предыдущем Поде"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Сведения о помпе"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Получение сведений о помпе..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Обновить сведения о помпе"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Диагностика"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Получить статус Пода"; diff --git a/Dependencies/OmniBLE/Localizations/sk.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/sk.lproj/Localizable.strings deleted file mode 100644 index 952e4ea76..000000000 --- a/Dependencies/OmniBLE/Localizations/sk.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Upozornenie na viacero príkazov"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pripomienka o expirácii"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod expiroval"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Nízka hladina v rezervoári"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Pripomienka prebiehajúceho pozastavenia"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Obnoviť podávanie inzulínu"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Párovanie podu nebolo dokončené"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Zistila sa zmena času"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Upozornenie na viacero príkazov"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod vyprší za %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Vymeniť pod teraz. Pod bol aktívny 72 hodín."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Treba vymeniť pod. Podávanie inzulínu sa zastaví o 1 hodinu."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "V podu zostáva %1$@ inzulínu alebo menej. Čoskoro vymeňte pod."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Pripomienka prebiehajúceho pozastavenia"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Obdobie pozastavenia podávania inzulínu sa skončilo.\n\nPodávanie môžete obnoviť z bannera na domovskej obrazovke alebo z obrazovky nastavení pumpy. Znovu sa vám to pripomenie za 15 minút."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Dokončite párovanie podu."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Čas na vašej pumpe sa líši od aktuálneho času. Čas na čerpadle si môžete skontrolovať a synchronizovať s aktuálnym časom v nastaveniach."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Čas pozastavenia vypršal. Otvorte aplikáciu a pokračujte."; - -/* Action button default text for PodAlerts */ -"Ok" = "OK"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Aktivácia neukončená"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expiruje o"; - -/* */ -"Pod Expires" = "Expirácia Podu"; - -/* */ -"Pod Activated" = "Pod aktivovaný"; - -/* */ -"Notification Settings" = "Nastavenia oznámení"; - -/* */ -"Confidence Reminders" = "Upozornenia s pípnutím zo zariadenia Pod"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Zastavte podávanie inzulínu"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod vypršal"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Deaktivácia neukončená"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Žiadny pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Párovať pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Párovať pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Párovanie."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Pripravuje sa. Prosím čakajte."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod sprárovaný úspešne. Pokračovať."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Dokončiť deaktiváciu"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Vymeňte pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "deň"; - -/* Unit for plural days in pod life remaining */ -"days" = "dni"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hodina"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hodiny"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minúta"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minút"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Podávanie inzulínu"; - -/* */ -"Scheduled Basal" = "Naplánovaný bazál"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Zostávajúci inzulín"; - -/* Section header for activity section */ -"Activity" = "Aktivita"; - -/* title for device details page */ -"Device Details" = "Podrobnosti o zariadení"; - -/* Section header for configuration section */ -"Configuration" = "Nastavenie"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Dokončiť deaktiváciu"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Vymeňte pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Vymeňte pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Aktivácia neukončená"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expiruje o"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod vypršal"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Deaktivácia neukončená"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Žiadny pod"; - -/* Pod life HUD view label */ -"Fault" = "Chyba"; - -/* Label describing pod age view */ -"Pod Age" = "Vek podu"; - -/* Label describing time remaining view */ -"Remaining" = "Zostávajúce"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Vymeňte pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Nie je spárovaný žiadny pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod je už spárovaný"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Typ inzulínu nie je nakonfigurovaný"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod nie je v stave pripravenom na zavedenie kanyly."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Neplatné nastavenie"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Spárujte nový pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problém s komunikáciou"; - -/* */ -"Finish Pairing" = "Dokončiť párovanie"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Dokončiť deaktiváciu"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Žiadny pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "Žiadny inzulín"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod expiroval"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Oklúzia podu"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Chyba podu"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Žiadny inzulín"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Inzulín Suspendovaný"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Strata signálu"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuálny bazál"; - -/* */ -"Insert Cannula" = "Zaviesť Kanylu"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Zavádza sa..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Skúsiť znova"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Kontroluje sa..."; - -/* */ -"Check cannula insertion finished" = "Skontrolujte, či je zavedenie kanyly dokončené"; - -/* */ -"Get pod status" = "Zistiť stav Podu"; - -/* */ -"Save Basal Profile" = "Nastavovanie bazálneho profilu"; - -/* */ -"Save basal profile failed: %{public}@" = "Uloženie základného profilu sa nepodarilo: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Vynechanie pípnutia testu prehrávania z dôvodu stále prebiehajúceho podávania bolusu."; - -/* */ -"Play Test Beeps" = "Prehrať skúšobné pípnutia"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Vynechanie pípnutia testu prehrávania z dôvodu stále prebiehajúceho podávania bolusu."; - -/* */ -"Read Pulse Log" = "Čítať protokol pulzov"; - -/* */ -"Set Confirmation Beeps to %s" = "Nastavenie potvrdzujúcich zvukových signálov na %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Nastavenie preferencie potvrdzujúcich zvukových signálov"; - -/* */ -"Suspend" = "Pozastavenie"; - -/* */ -"Failed to suspend: %{public}@" = "Nepodarilo sa pozastaviť: %{public}@"; - -/* */ -"Resume" = "Pokračovať"; - -/* */ -"Bolus" = "Dávka"; - -/* */ -"Cancel Bolus" = "Zrušiť bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Prázdny zásobník"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Zistená oklúzia"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritická chyba zariadenia Pod"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Podávanie inzulínu sa zastavilo. Vymeňte modul teraz."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Zostávajúci inzulín"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Nastavenie dočasnej bazálnej sadzby"; - -/* Section header for activity section */ -"Activity" = "Aktivita"; - -/* Section header for configuration section */ -"Configuration" = "Nastavenie"; - -/* Title for previous pod page */ -"Previous Pod" = "Predchádzajúci Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Čas čerpadla"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Nastavenie času čerpadla..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchronizácia s aktuálnym časom"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Prechod na iné zariadenie na podávanie inzulínu"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Čas na vašej pumpe sa líši od aktuálneho času. Chcete aktualizovať čas na vašej pumpe na aktuálny čas?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Áno, synchronizujte s aktuálnym časom"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nie, nechajte čerpadlo tak, ako je"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Odstrániť Pod"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Naozaj chcete prestať používať Ominpod Dash?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Vymazať Omnipod Dash"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Typ Inzulínu"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchronizácia s aktuálnym časom"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Pozastavenie dodávky"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Podávanie inzulínu bude zastavené, kým ho neobnovíte manuálne. Kedy chcete, aby vám slučka pripomenula obnovenie podávania?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minút"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hodina"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hodina 30 minút"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hodiny"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Pozastavenie podávania inzulínu zlyhalo"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Obnovenie podávania inzulínu zlyhalo"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Nastavenie času pumpy zlyhalo"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Zrušenie manuálneho bazálu zlyhalo"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Prosím, deaktivujte pod. Po dokončení deaktivácie, ho môžete odstrániť a spárovať nový pod."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Prosím, deaktivujte pod. Po dokončení deaktivácie, môžete spárovať nový pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Deaktivovať Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktivuje sa."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deaktivovaný úspešne. Pokračovať."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Skúsiť znova"; - -/* Action button description when deactivated */ -"Continue" = "Pokračovať"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Nastal problém s komunikáciou s modulom. Ak tento problém pretrváva, ťuknite na položku Discard Pod. Potom môžete aktivovať nový pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Zlikvidujte pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Odstránenie struku z tela"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Váš Pod môže stále podávať inzulín.\nOdstráňte ho z tela a potom klepnite na \"Pokračova.\""; - -/* Insulin Unit */ -"U" = "J"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Zmeniť Pod teraz. Podávanie inzulínu sa zastaví 8 hodín po uplynutí doby platnosti Podu alebo keď už nezostane žiadny inzulín."; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Naplňte nový pod s inzulínom U-100 (modrý uzáver ihly pod nechajte nasadený)."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Počúvajte 2 pípnutia."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Spárované"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Zrušiť"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Naozaj chcete zrušiť svoj hlas?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Ak zrušíte nastavenie podov, aktuálny pod bude deaktivovaný a nebude možné ho používať."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Áno, deaktivujte pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nie, pokračujte so zariadením Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Príprava miesta na telo."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Skontrolujte pod, aplikujte ho na telo, potom potvrďte prilepenie podu."; - -/* Action button title for attach pod view */ -"Continue" = "Pokračovať"; - -/* */ -"Attach Pod" = "Aplikujte pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Potvrdiť pripojenie zariadenia Pod"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Uistite sa, že je pod bezpečne pripevnený k vášmu telu.\n\nKanylu možno do každého podu zaviesť len raz. Keď je Pod pripojený, klepnite na \"Potvrdiť\"."; - -/* Button title for confirm attachment option */ -"Confirm" = "Potvrdiť"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Ťuknutím nižšie spustíte zavádzanie kanyly."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Počkajte kým nie je zavedenie ukončené."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Vložené do tela"; - -/* Check Cannula */ -"Check Cannula" = "Skontrolujte kanylu"; - -/* */ -"Is the cannula inserted properly?" = "Je kanyla správne zavedená?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Keď je kanyla správne zavedená do kože, okienko v hornej časti Podu by malo byť sfarbené do ružova."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Áno"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nie"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Páruje sa..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Príprava..."; - -/* */ -"Deactivating..." = "Deaktivuje sa..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktivované"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Váš pod je pripravený na použitie.\n\n%1$@ vám pripomenie, aby ste si vymenili pod pred uplynutím jeho platnosti. Môžete to zmeniť na čas, ktorý vám vyhovuje."; - -/* */ -"Scheduled Reminder" = "Naplánovaná pripomienka"; - -/* Label for expiration reminder row */ -"Time" = "Čas"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Dokončiť nastavenie"; - -/* */ -"Setup Complete" = "Nastavenie je dokončené"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Žiadna pripomienka"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Periférne zariadenie nie je pripravené"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Nesprávna odpoveď"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Časový limit vypršal"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Prázdna hodnota"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Neznáma charakteristika"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Pripomienky omnipodu"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Aplikácia nakonfiguruje pripomienku na pod, ktorá vás vopred upozorní na vypršanie platnosti pod. Nastavte počet hodín vopred, ktoré chcete nakonfigurovať pri párovaní nového zariadenia Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Toto je pripomienka, ktorú ste naplánovali pri spárovaní aktuálneho Podu."; - -/* */ -"Scheduled Reminder" = "Naplánovaná pripomienka"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Aplikácia vás upozorní, keď množstvo inzulínu v pode dosiahne túto úroveň."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Kritické výstrahy"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Vyššie uvedené upozornenia nezaznejú, ak je vaše zariadenie v tichom režime alebo v režime Nerušiť.\n\nExistujú ďalšie kritické upozornenia a alarmy Pod, ktoré zaznejú, aj keď je vaše zariadenie nastavené na tichý režim alebo režim Nerušiť."; -/* navigation title for notification settings */ -"Notification Settings" = "Nastavenia oznámení"; - -/* Label for scheduled reminder value row */ -"Time" = "Čas"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Žiadna pripomienka"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Pripomienka Nízka hladina v rezervoári"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Uistite sa, že iPhone a pod sú blízko seba. Ak problémy s komunikáciou pretrvávajú, presuňte sa do inej oblasti."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Ihneď vymeniť pod. Podávanie inzulínu sa zastaví o %1$@ alebo keď sa minie inzulín."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Vypnuté"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Zapnuté"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Rozšírený"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Nepoužívajú sa žiadne oznámenia."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Upozornenia budú znieť pri príkazoch, ktoré iniciujete, ako napríklad bolus, zrušenie bolusu, pozastavenie, obnovenie, uloženie pripomienok upozornení atď. Keď aplikácia automaticky upravuje podávanie, nepoužívajú sa žiadne pripomenutia dôvery."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Upozornenia zaznejú, keď aplikácia automaticky upraví doručenie a na príkazy, ktoré sami zadáte."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Dávka"; - -/* Insulin unit per hour */ -"U/hr" = "J/hod"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ pre %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop vám automaticky neupraví dávkovanie inzulínu, kým sa dočasná bazálna rýchlosť neskončí alebo nezruší."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Nastaviť dočasný bazál"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Dočasný bazál"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Dočasný bazál zlyhal"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Nie je možné nastaviť dočasnú dávku bazálu: %1$@ \n\n %2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Nie je možné nastaviť dočasnú dávku bazálu: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Chýba konfigurácia"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Tento manažér čerpadiel nebol nakonfigurovaný s maximálnou bazálnou rýchlosťou, pretože bol pridaný skôr, ako bola pridaná funkcia manuálneho bazálneho nastavenia. Prejdite do nastavení terapie -> limity dodávok a nastavte novú maximálnu bazálnu rýchlosť."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Predvolené pripomenutie o expirácii"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Predchádzajúce informácie o Pod"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "Žiadna\ndodávka"; - -/* description label for active time pod details row */ -"Active Time" = "Aktívny Čas"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Celková dávka"; - -/* description label for device name pod details row */ -"Device Name" = "Názov zariadenia"; - -/* description label for lot number pod details row */ -"Lot Number" = "Číslo šarže"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sekvenčné číslo"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Verzia firmvéru"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE verzia firmvéru"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod aktivovaný"; - -/* description label for active time pod details row */ -"Active Time" = "Aktívny Čas"; - -/* description label for last status date pod details row */ -"Last Status" = "Posledný stav"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Detaily chyby podu"; - -/* Title for PodSetupView */ -"Pod Setup" = "Nastavenie podu"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Teraz začnete s procesom konfigurácie pripomienok, naplnením podu inzulínom, jeho spárovaním s vašim zariadením a umiestnením podu na telo."; - -/* Cancel button title */ -"Cancel" = "Zrušiť"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Pokračovať"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Preskočiť Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Aplikácia vás vopred upozorní na expiráciu podu. \n\nRolovaním nastavte počet hodín vopred, kedy chcete upozornenie dostať."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Ďalej"; - -/* */ -"Expiration Reminder" = "Pripomienka Expirácie"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Aplikácia vás upozorní, keď množstvo inzulínu v pode dosiahne túto úroveň (50 – 10 U). \n\nRolovaním nastavte počet jednotiek, pri ktorých chcete byť upozornení."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Nízka hladina v rezervoári"; - -/* */ -"Save" = "Uložiť"; - -/* hr (short for hour) */ -"hr" = "h"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Zrušenie manuálneho bazálneho"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Inzulín\nSuspendovaný"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Obnoviť podávanie inzulínu"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Uistite sa, že je váš iPhone v dosahu a skúste znova."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Žiadny Pod nie je pripojený"; - -/* Label for suspended at time */ -"Suspended At" = "Pozastavené na"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Obnovuje sa podávanie inzulínu..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Pozastavenie podávania inzulínu..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Nenašiel sa žiadny pod"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Našlo sa príliš veľa podov"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Uistite sa, že iPhone je v dosahu aktívneho podu"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Skúste znova"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Presuňte sa ďalej od ostatných modulov a skúste znova."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Uistite sa, že je váš pod naplnený a v blízkosti."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Premiestnite RileyLink ďalej od podu"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Zmeňte polohu RileyLink vzhľadom k podu"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Prosím, majte iba pôvodný pod v dosahu alebo deaktivujte pôvodný pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Možné presluchy. Presuňte sa na iné miesto"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Uistite sa, že je váš iPhone v dosahu a skúste znova."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Počkajte na dokončenie bolusu alebo bolus zrušte"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Počkajte na dokončenie bolusu alebo bolus zrušte"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Počkajte, kým sa dokončí dočasný bazál, alebo ho zrušte"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "pred %@"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Umlčané"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normálny prevádzkový režim, v ktorom sa zvukové signály Pod používajú pre všetky upozornenia Pod a keď sú povolené pripomenutia dôvery."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Všetky upozornenia Pod nepoužívajú žiadne zvukové signály a zvukové signály pripomínajúce potvrdenie sú potlačené. Pod bude pípať len pri fatálnych poruchách Pod a pri prehrávaní testovacích pípnutí.\n\n⚠️Warning - Vždy, keď je Pod stlmený, musí byť v dosahu Bluetooth tohto zariadenia, aby prijímal upozornenia na upozornenia Pod."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Režim Silence Pod potlačí všetky upozornenia Pod a upozornenia na potvrdenie."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Umlčané"; - -/* title for pod details page */ -"Pod Details" = "Detaily Podu"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Predchádzajúci Pod Podrobnosti"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Podrobnosti o manažérovi čerpadla"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Získanie údajov o správcovi čerpadla..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Podrobnosti o manažérovi čerpadla"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostiky"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Zistiť stav Podu"; diff --git a/Dependencies/OmniBLE/Localizations/sv.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/sv.lproj/Localizable.strings deleted file mode 100644 index e71410d02..000000000 --- a/Dependencies/OmniBLE/Localizations/sv.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Multipla kommandoaviseringar"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Påminnelse om utgångsdatum"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod har utgått"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Låg reservoarvolym"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Påminnelse om pausad pump"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Återuppta insulintillförsel"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Parkoppling inte klar"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Tidsjustering upptäckt"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multipla kommandoaviseringar"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Podden går ut om %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Byt podd nu. Podden har använts i 72 timmar."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Byt podd nu. Insulintillförseln stoppas om 1 timme."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin eller mindre kvar i podd. Överväg att byta podd snart."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Påminnelse om pausad pump"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Planerad period av paus av pump är slut.\n\nDu kan återuppta insulintillförsel i pumpinställningar. Du kommer bli påmind igen om 15 minuter."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Du behöver göra färdigt parkopplingen av din podd."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Tiden på din pump skiljer sig från den aktuella tiden. Du kan granska pumpens tid och synkronisera till aktuell tid i pumpinställningar."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Planerad paus är över. Öppna app och återuppta insulintillförsel."; - -/* Action button default text for PodAlerts */ -"Ok" = "OK"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Har inte blivit färdigaktiverad"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Podd går ut om"; - -/* */ -"Pod Expires" = "Podd går ut"; - -/* */ -"Pod Activated" = "Podd aktiverades"; - -/* */ -"Notification Settings" = "Notisinställningar"; - -/* */ -"Confidence Reminders" = "Bekräftelseljud"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Pausa insulintillförsel"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Podden har gått ut"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Inaktivering inte färdigställd"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Ingen podd"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Parkoppla podd"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Parkoppla podd."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Parkopplar."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Fyller podden. Vänligen vänta."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Podden har parkopplats. Fortsätt."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Avsluta inaktivering"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Byt podd"; - -/* Unit for singular day in pod life remaining */ -"day" = "dag"; - -/* Unit for plural days in pod life remaining */ -"days" = "dagar"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "timme"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "timmar"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minut"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minuter"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulintillförsel"; - -/* */ -"Scheduled Basal" = "Schemalagd basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin kvar"; - -/* Section header for activity section */ -"Activity" = "Aktivitet"; - -/* title for device details page */ -"Device Details" = "Enhetsdetaljer"; - -/* Section header for configuration section */ -"Configuration" = "Konfiguration"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Avsluta inaktivering"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Byt podd"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Byt podd"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Har inte blivit färdigaktiverad"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Podd går ut om"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Podden har gått ut"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Inaktivering inte färdigställd"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Ingen podd"; - -/* Pod life HUD view label */ -"Fault" = "Fel"; - -/* Label describing pod age view */ -"Pod Age" = "Poddålder"; - -/* Label describing time remaining view */ -"Remaining" = "Återstår"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Byt podd"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Ingen podd har parkopplats"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Podd redan parkopplad"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Du måste välja typ av insulin"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Podd är inte redo att föra in kanyl."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ogiltig inställning"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Var god parkoppla ny podd"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Kommunikationsproblem"; - -/* */ -"Finish Pairing" = "Avsluta parkoppling"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Avsluta inaktivering"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Ingen podd"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "Inget insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod har utgått"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Ocklusion i podd"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Poddfel"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Inget insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Pump pausad"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signalförlust"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuell temporär basal"; - -/* */ -"Insert Cannula" = "För in kanyl"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Kanylen förs in..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Försök igen"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Kontrollerar..."; - -/* */ -"Check cannula insertion finished" = "Kontrollera att kanylen har förts in"; - -/* */ -"Get pod status" = "Hämta poddstatus"; - -/* */ -"Save Basal Profile" = "Spara basalprofil"; - -/* */ -"Save basal profile failed: %{public}@" = "Kunde inte spara basalprofil: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Hoppar över testpip på grund av en pågående bolus."; - -/* */ -"Play Test Beeps" = "Spela upp testljud"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Hoppar över pulsloggen på grund av en pågående bolus."; - -/* */ -"Read Pulse Log" = "Läs pulslogg"; - -/* */ -"Set Confirmation Beeps to %s" = "Ställ in bekräftelsepip till %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Inställning för bekräftelseepip"; - -/* */ -"Suspend" = "Pausa"; - -/* */ -"Failed to suspend: %{public}@" = "Kunde inte pausa: %{public}@"; - -/* */ -"Resume" = "Återuppta"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Avbryt bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Tom insulinreservoar"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Ocklusion upptäckt"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritiskt poddfel"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulintilförsel stoppad. Byt podd nu."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin kvar"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Ange temporär basaldos"; - -/* Section header for activity section */ -"Activity" = "Aktivitet"; - -/* Section header for configuration section */ -"Configuration" = "Konfiguration"; - -/* Title for previous pod page */ -"Previous Pod" = "Tidigare podd"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pumptid"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Justerar pumptid..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synkronisera med aktuell tid"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Byt till annan pump/insulinadministrering"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Tiden på din pump skiljer sig från aktuell tid. Vill du uppdatera tiden på din pump till aktuell tid?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, synkronisera med aktuell tid"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nej, behåll pumptid"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Ta bort podd"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Säkert att du vill sluta använda Omnipod Dash?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Ta bort Omnipod Dash"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Typ av insulin"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synkronisera med aktuell tid"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Pausa pump"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulintillförsel kommer att stoppas tills du återupptar dennamanuellt. När vill du att iAPS ska påminna dig om att återuppta insulintillförsel?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minuter"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 timme"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 timme 30 minuter"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 timmar"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Kunde inte pausa pump"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Misslyckades att återuppta insulintillförsel"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Det gick inte att ställa in pumptid"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Misslyckades att avbryta manuell basal"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Inaktivera din podd. Avlägsna sedan podden från kroppen och parkoppla en ny."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Inaktivera podden. När inaktiveringen är klar kan du parkoppla en ny podd."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Inaktivera podd"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Inaktiverar."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Podd avaktiverades. Fortsätt."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Försök igen"; - -/* Action button description when deactivated */ -"Continue" = "Fortsätt"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Det gick inte att kommunicera med podden. Om problemet kvarstår, tryck på 'Kasta Pod'. Du kan sedan aktivera en ny podd."; - -/* Text for discard pod button */ -"Discard Pod" = "Kasta podd"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Ta bort podd från kroppen"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Din podd kan eventuellt fortfarande ge Insulin.\nTa bort den från din kropp och tryck sedan på ”Fortsätt.”"; - -/* Insulin Unit */ -"U" = "IE"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Byt podd nu. Insulintillförsel kommer att upphöra 8 timmar efter att podd går ut eller tills att inget insulin återstår."; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Fyll en ny podd med insulin (låt det blå kanlyskyddet sitta kvar)."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Ta bort poddens blåa kanylskydd och kontrollera att kanylen inte redan sticker ut. Ta sedan bort skyddspappret."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Det ska höras 2 pip."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Parkopplad"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Avbryt"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Är du säker på att du vill avsluta din poddinställning?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Om du avbryter din podinställning, kommer din podd att avaktiveras och sluta fungera."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, inaktivera podden"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nej, fortsätt med denna podd"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Förbered hud."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Kontrollera din podd, sätt fast den och bekräfta sedan att den sitter bra."; - -/* Action button title for attach pod view */ -"Continue" = "Fortsätt"; - -/* */ -"Attach Pod" = "Fäst podden"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Kontrollera att podden sitter bra"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Kontrollera att podden sitter bra på din kropp.\n\nKanylen kan bara föras in en gång. Tryck på \"Bekräfta\" när podden sitter fast."; - -/* Button title for confirm attachment option */ -"Confirm" = "Bekräfta"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tryck nedan för att föra in kanyl."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Vänta tills kanyl förts in."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Kanyl har förts in"; - -/* Check Cannula */ -"Check Cannula" = "Kontrollera kanyl"; - -/* */ -"Is the cannula inserted properly?" = "Är kanylen införd korrekt?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Det lilla fönstret på podden färgas rosa när kanylen är ordentligt insatt i huden."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nej"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Parkopplar..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Fyller..."; - -/* */ -"Deactivating..." = "Inaktiverar..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Inaktiverad"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Din podd är klar att användas.\n\n%1$@ kommer att påminna dig att byta pod innan den utgår. Du kan ändra påminnelsetiden för detta."; - -/* */ -"Scheduled Reminder" = "Schemalagd påminnelse"; - -/* Label for expiration reminder row */ -"Time" = "Tid"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Gär färdigt inställning"; - -/* */ -"Setup Complete" = "Inställning färdig"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Ingen påminnelse"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Perifer enhet inte redo"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Felaktigt svar"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Tomt värde"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Okänd karaktäristik"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "NACK"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod-påminnelser"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Du kan ange när du vill att appen ska påminna dig om när du behöver byta podd. Ange det antal timmar i förväg du vil ha påminnelsen"; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Detta är en schemalagd påminnelse som du ställde in när du parkopplade nuvarande podd."; - -/* */ -"Scheduled Reminder" = "Schemalagd påminnelse"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Appen kommer att visa notis när mängden insulin går ner till denna nivå"; - -/* Description text for critical alerts */ -"Critical Alerts" = "Varningar"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Påminnelser kommer vara tysta ifall att du har tyst läge eller stör ej - läge på. \n\nDet finns andra varningar som kommer att ljuda även vid tyst läge leer stör ej - läge."; -/* navigation title for notification settings */ -"Notification Settings" = "Notisinställningar"; - -/* Label for scheduled reminder value row */ -"Time" = "Tid"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Ingen påminnelse"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Påminnelse om låg insulinnivå"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Säkerställ att din telefon och podd är nära varandra. Om problemet kvarstår, flytta till annan plats."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Byt podd nu. Insulintillförsel kommer att stoppas om %1$@ eller när insulinet är slut."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Av"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "På"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Utökad"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Inga ljud på."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Bekräftelseljud kommer att pipa för för ala pumpkommandon du ger, som bolus, avbryt bolus, pausa pump, återuppta insulintillförsel, spara påminnelser etc. När iAPS automatiskt justerar insulintillförsel kommer inga pip att ljuda."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Bekräftelsepip kommer att ljuda även vid automatiska pumpkommandon såväl som vid manuella."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Värde"; - -/* Insulin unit per hour */ -"U/hr" = "IE/h"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ i %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "iAPS kommer inte automatiskt att justera dina insulindoser förrän den temporära basalen är färdig eller har avbrytits."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Ställ in temporaär basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporär basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporär basal misslyckades"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Kunde inte ställa in en temporär basaldos: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Kunde inte ställa in en temporär basaldos: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Konfiguration saknas"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "En maximal basaldos har inte ställts in. Gå till inställningen 'Maxdoser' för att ställa in den maximala basaldosen"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standard påminnelsetid"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Info om tidigare podd"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "Inget\ninsulin"; - -/* description label for active time pod details row */ -"Active Time" = "Aktiv tid"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total mängd insulin given"; - -/* description label for device name pod details row */ -"Device Name" = "Enhetsnamn"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot-nummer"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sekvensnummer"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware-version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware - version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Podd aktiverades"; - -/* description label for active time pod details row */ -"Active Time" = "Aktiv tid"; - -/* description label for last status date pod details row */ -"Last Status" = "Senaste status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Poddfelsdetaljer "; - -/* Title for PodSetupView */ -"Pod Setup" = "Pumpinställning"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Du kommer nu att börja att konfigurera dina påminnelser, fylla din podd med insulin, parkoppla podden och fästa den på kroppen."; - -/* Cancel button title */ -"Cancel" = "Avbryt"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Fortsätt"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Hoppa över Omnipod-introduktionen?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Appen meddelar dig i förväg om när din podd går ut.\n\nSkrolla för att ställa in hur många timmar i förväg du vill bli påmind."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Nästa"; - -/* */ -"Expiration Reminder" = "Påminnelse om utgångsdatum"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Appen meddelar dig när mängden insulin i podden når denna nivå (50-10 U).\n\nSkrolla för att ange vid vilket antal enheter som du vill bli påmind."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Låg reservoarvolym"; - -/* */ -"Save" = "Spara"; - -/* hr (short for hour) */ -"hr" = "h"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Avbryt manuell basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Pump\npausad"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Återuppta pump"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Kontrollera att din podd är nära och försök igen"; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Podd inte ansluten"; - -/* Label for suspended at time */ -"Suspended At" = "Pausad kl."; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Återupptar pump..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Pausar pump..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Hittade ingen podd"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "För många poddar hittades"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Säkerställ att du ar din iPhone nära din podd"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Försök igen"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Pröva att gå till ett annat rum och försök igen."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Säkerställ att din podd är nära och fylld med insulin."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Pröva att flytta din iPhone längre ifrån podden"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Flytta din iPhone i förhållande till din podd"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Ha endast din ursprungliga podd nära dig eller inaktivera denna podd"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Möjlig överhörning. Pröva att flytta dig till ett annat rum/annan plats"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Kontrollera att din podd är nära och försök igen"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Vänta på att pågående bolus blir färdig eller avbryt bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Vänta på att pågående bolus blir färdig eller avbryt bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Vänta på pågående temp. basal är färdig, alternativt pausa eller avbryt"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ sedan"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Tystad"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normalt läge när ljud är på för både varningar och för bekräftelser."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "\"Varningar kommer inte längre använda ljud och även alla bekräftelseljud kommer att vara avstängda. Podden kommer bara att pipa om du väljer att spela upp testljud.\n\n⚠️Varning - när podden är tystad måste du vara inom räckhåll för dina enheter för att få några poddvarningar.\""; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Under tyst poddläge stängs alla poddens ljud av."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Tysta podden"; - -/* title for pod details page */ -"Pod Details" = "Poddetaljer"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Detaljer om tidigare podd"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Information om pumphanteraren"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Hämtar pumphanterarens detaljer..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Uppdatera pumphanterarens detaljer"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostik"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Läd poddstatus"; diff --git a/Dependencies/OmniBLE/Localizations/tr.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/tr.lproj/Localizable.strings deleted file mode 100644 index deae189e4..000000000 --- a/Dependencies/OmniBLE/Localizations/tr.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Çoklu Komut Uyarısı"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Süre Sonu Hatırlatıcısı"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod Süreci Doldu"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Düşük Rezervuar"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Devam Ediyor Hatırlatıcısını, Askıya Al"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "İnsüline Devam Et"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Eşleştirme Tamamlanmadı"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Zaman Değişikliği Tespit Edildi"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Çoklu Komut Uyarısı"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod %1$@ içinde sona eriyor."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Pod'u şimdi değiştirin. Pod 72 saattir etkin."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Pod'u şimdi değiştirin. İnsülin iletimi 1 saat içinde duracaktır."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "Pod'ta %1$@ veya daha az insülin kaldı. Pod'u en kısa sürede değiştirin."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Devam Ediyor Hatırlatıcısını, Askıya Al"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "İnsülin askıya alma süresi sona erdi.\n\nİletime ana ekrandaki başlıktan veya pompa ayarları ekranınızdan devam edebilirsiniz. 15 dakika sonra tekrar hatırlatılacaktır."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Lütfen pod eşleştirmeyi bitirin."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Pompanızdaki saat şu anki saatten farklı. Pompa zamanını gözden geçirebilir ve ayarlarda şimdiki zamana eşitleyebilirsiniz."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Askıya alma süresi doldu. Uygulamayı açın ve İnsülin iletimini devam ettirin."; - -/* Action button default text for PodAlerts */ -"Ok" = "Tamam"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Bitmemiş Etkinleştirme"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod şu sürede doluyor"; - -/* */ -"Pod Expires" = "Pod'un Süresi Sona Eriyor"; - -/* */ -"Pod Activated" = "Pod Etkinleştirildi"; - -/* */ -"Notification Settings" = "Bildirim ayarları"; - -/* */ -"Confidence Reminders" = "Onay sesi"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "İnsülin İletimini Askıya Al"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod süreci doldu"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Tamamlanmamış, devre dışı bırakma"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Pod Yok"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Pod Eşleştir"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pod Eşleştir."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Eşleştiriliyor."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Hazırlanıyor. Lütfen Bekleyin."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod başarıyla eşleştirildi. Devam edin."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Devre dışı bırakma işlemini tamamla"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Pod'u değiştir"; - -/* Unit for singular day in pod life remaining */ -"day" = "gün"; - -/* Unit for plural days in pod life remaining */ -"days" = "gün"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "saat"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "saat"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "dakika"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "dakika"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "İnsülin İletimi"; - -/* */ -"Scheduled Basal" = "Programlanmış Bazal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Kalan İnsülin"; - -/* Section header for activity section */ -"Activity" = "Aktivite"; - -/* title for device details page */ -"Device Details" = "Cihaz Detayları"; - -/* Section header for configuration section */ -"Configuration" = "Yapılandırma"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Devre dışı bırakma işlemini tamamla"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Pod'u değiştir"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Pod'u değiştir"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Bitmemiş Etkinleştirme"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod şu sürede doluyor"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod süreci doldu"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Tamamlanmamış, devre dışı bırakma"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Pod Yok"; - -/* Pod life HUD view label */ -"Fault" = "Hata"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Yaşı"; - -/* Label describing time remaining view */ -"Remaining" = "Geri Kalan"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Pod'u değiştir"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Eşleşmiş pod bulunmuyor"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod zaten eşleştirilmiş"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "İnsülin türü yapılandırılmadı"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod kanül yerleştirmeye hazır durumda değil."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Geçersiz Ayar"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Lütfen yeni bir pod eşleştirin"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "İletişim Sorunu"; - -/* */ -"Finish Pairing" = "Eşleştirmeyi Bitir"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Devre dışı bırakma işlemini tamamla"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Pod Yok"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "İnsülin Yok"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod Süreci Doldu"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Tıkanıklığı"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod hatası"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "İnsülin Yok"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "İnsülin Durduldu"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Sinyal Kaybı"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuel Bazal"; - -/* */ -"Insert Cannula" = "Kanül Yerleştir"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Yerleştiriliyor..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Tekrar Dene"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Denetleniyor..."; - -/* */ -"Check cannula insertion finished" = "Kanül yerleştirmenin bittiğini kontrol edin"; - -/* */ -"Get pod status" = "Pod durumu al"; - -/* */ -"Save Basal Profile" = "Bazal Profili Kaydet"; - -/* */ -"Save basal profile failed: %{public}@" = "Bazal profil kaydedilemedi: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Devam eden bolus nedeniyle Deneme Testi Bip Sesleri atlanıyor."; - -/* */ -"Play Test Beeps" = "Test Bip Sesi Çal"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Devam eden bolus nedeniyle Nabız Okuma Günlüğü atlanıyor."; - -/* */ -"Read Pulse Log" = "Nabız Kaydını Oku"; - -/* */ -"Set Confirmation Beeps to %s" = "Onay Biplerini %s olarak ayarla"; - -/* */ -"Set Confirmation Beeps Preference" = "Onay Bip Sesi Tercihini Ayarlayın"; - -/* */ -"Suspend" = "Askıya al"; - -/* */ -"Failed to suspend: %{public}@" = "İletim durdurulamadı: %{public}@"; - -/* */ -"Resume" = "Devam et"; - -/* */ -"Bolus" = "Bolus"; - -/* */ -"Cancel Bolus" = "Bolusu İptal Et"; - -/* Alert acknowledgment OK button */ -"OK" = "Tamam"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Rezervuar Boş"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Tıkanma Tespit Edildi"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Önemli Pod Hatası"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "İnsülin iletimi durduruldu. Pod'u şimdi değiştirin."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Kalan İnsülin"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Geçici Bazal Oranı Ayarla"; - -/* Section header for activity section */ -"Activity" = "Aktivite"; - -/* Section header for configuration section */ -"Configuration" = "Yapılandırma"; - -/* Title for previous pod page */ -"Previous Pod" = "Önceki Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pompa Zamanı"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pompa Zamanını Ayarlama..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Geçerli Saate Eşitle"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Diğer insülin iletim cihazına geçin"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Pompanızdaki saat, mevcut saatten farklı. Pompanızdaki saati şu anki saate güncellemek ister misiniz?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Evet güncelle"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Hayır güncelleme"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Pompayı Çıkart"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Omnipod DASH'ı kullanmayı bırakmak istediğinizden emin misiniz?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Omnipod DASH'ı Sil"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "İnsülin Tipi"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Geçerli Saate Eşitle"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "İletimi Askıya Al"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Siz manuel olarak devam edene kadar insülin iletimi durdurulacaktır. Loop'un teslimata devam etmenizi ne zaman hatırlatmasını istersiniz?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 dakika"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 saat"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 saat 30 dakika"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 saat"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "İnsülin İletimi Askıya Alınamadı"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "İnsülin İletimi Tekrar Başlatılamadı"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Pompa Zamanı Ayarlanamadı"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Manuel Bazal İptal Edilemedi"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Lütfen pod'u devre dışı bırakın. Devre dışı bırakma tamamlandığında, onu kaldırabilir ve yeni bir pod eşleştirebilirsiniz."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Lütfen pod'u devre dışı bırakın. Devre dışı bırakma tamamlandığında, yeni bir pod eşleştirebilirsiniz."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Pod'u devredışı bırak"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Devre dışı bırakılıyor."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod başarıyla devre dışı bırakıldı. Devam edin."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Tekrar Dene"; - -/* Action button description when deactivated */ -"Continue" = "Devam et"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Pod ile iletişimde bir sorun oluştu. Bu sorun devam ederse, Pod'u At'a tıklayın. Ardından yeni bir Pod etkinleştirebilirsiniz."; - -/* Text for discard pod button */ -"Discard Pod" = "Pod'u Çıkart"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Pod'u Vücudunuzdan Çıkarın"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Pod'unuz hâlâ İnsülin veriyor olabilir.\nVücudunuzdan çıkarın ve ardından “Devam Et.”e tıklayın"; - -/* Insulin Unit */ -"U" = "Ü"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Pod'u şimdi değiştirin. İnsülin iletimi, Pod'un süresi dolduktan 8 saat sonra veya daha fazla insülin kalmadığında duracaktır."; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "2 bip sesini dinleyin."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Eşleştirildi"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Vazgeç"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Pod kurulumunu iptal etmek istediğinizden emin misiniz?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Pod kurulumunu iptal ederseniz, mevcut Pod devre dışı bırakılır ve kullanılamaz hale gelir."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Evet, Pod'u Devre Dışı Bırak"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Hayır, Pod ile Devam Et"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "İnfüzyon bölgesini hazırlayın."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Pod'u kontrol edin, infüzyon bölgesine uygulayın, ardından pod ekini onaylayın."; - -/* Action button title for attach pod view */ -"Continue" = "Devam et"; - -/* */ -"Attach Pod" = "Pod'u Ekleyin"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Pod'un Yapıştırıldığını Onaylayın"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Lütfen Pod'un vücudunuza güvenli bir şekilde takıldığından emin olun.\n\nKanül her Pod ile yalnızca bir kez yerleştirilebilir. Pod takıldığında “Onayla”ya dokunun."; - -/* Button title for confirm attachment option */ -"Confirm" = "Onayla"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Kanül yerleştirmeyi başlatmak için aşağıya dokunun."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Ekleme tamamlanana kadar bekleyin."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Yerleştirildi"; - -/* Check Cannula */ -"Check Cannula" = "Kanülü Kontrol Edin"; - -/* */ -"Is the cannula inserted properly?" = "Kanül doğru şekilde yerleştirilmiş mi?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Kanül cilde düzgün bir şekilde yerleştirildiğinde Pod'un üstündeki pencere pembe renkte olmalıdır."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Evet"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Hayır"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Eşleştiriliyor..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Hazırlanıyor..."; - -/* */ -"Deactivating..." = "Devre dışı bırakılıyor..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Devre dışı"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Pod'unuz kullanıma hazır.\n\n%1$@ süresi dolmadan önce pod değiştirmeniz için hatırlatacak. Bunu sizin için uygun bir zamana değiştirebilirsiniz."; - -/* */ -"Scheduled Reminder" = "Programlanan Anımsatma"; - -/* Label for expiration reminder row */ -"Time" = "Saat"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Kurulumu Bitir"; - -/* */ -"Setup Complete" = "Kurulum tamamlandı"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Hatırlatıcı Yok"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Çevre birimi hazır değil"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Yanlış Yanıt"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Zaman Aşımı"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Boş Değer"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Bilinmeyen Özellik"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Hatırlatıcıları"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Uygulama, Pod'un sona ermesinden önce sizi bilgilendirmek için pod üzerinde bir hatırlatıcı yapılandırır. Yeni bir Pod'u eşleştirirken sizi pod sona ermeden kaç saat önce uyaracağını ayarlayın."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Bu mevcut Pod'unuzu eşleştirdiğinizde planladığınız bir hatırlatıcıdır."; - -/* */ -"Scheduled Reminder" = "Programlanan Anımsatma"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Uygulama, Pod'daki insülin miktarı bu seviyeye ulaştığında sizi bilgilendirir."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Kritik Uyarılar"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; -/* navigation title for notification settings */ -"Notification Settings" = "Bildirim ayarları"; - -/* Label for scheduled reminder value row */ -"Time" = "Saat"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Hatırlatıcı Yok"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Düşük Rezervuar Hatırlatıcısı"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Telefonunuzun ve pod'unuzun birbirine yakın olduğundan emin olun. İletişim sorunları devam ederse, yeni bir alana geçin."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Pod'u şimdi değiştirin. İnsülin iletimi %1$@ içinde veya daha fazla insülin kalmadığında duracaktır."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Devre dışı"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Etkin"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Yayma"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Onay sesi kullanılmaz."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Oran"; - -/* Insulin unit per hour */ -"U/hr" = "Ü/Sa"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%2$@ için %1$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Döngü, geçici bazal oran bitene veya iptal edilene kadar insülin iletiminizi otomatik olarak ayarlamaz."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Geçici Bazalı Ayarla"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Geçici Bazal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Geçici Bazal Başarısız"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Geçici bir bazal oran ayarlanamıyor: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Geçici bir bazal oran ayarlanamıyor: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Konfigurasyon Bulunamadı"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Pompa Yönetimi, daha önce manuel geçici bazal eklendiğinden, maksimum bazal oranı ile yapılandırılmadı. Lütfen terapi ayarları -> iletim limitlerine gidin ve yeni bir maksimum bazal oran ayarlayın."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Varsayılan Süre Sonu Hatırlatıcı"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Önceki Pod Bilgileri"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "İletim \nYok"; - -/* description label for active time pod details row */ -"Active Time" = "Aktif Süre"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Toplam İletim"; - -/* description label for device name pod details row */ -"Device Name" = "Cihaz adı"; - -/* description label for lot number pod details row */ -"Lot Number" = "Parti Numarası"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sıra Numarası"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Aygıt Yazılımı Sürümü"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Donanım Yazılımı Sürümü"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod Etkinleştirildi"; - -/* description label for active time pod details row */ -"Active Time" = "Aktif Süre"; - -/* description label for last status date pod details row */ -"Last Status" = "Son Durum"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Arıza Ayrıntıları"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Kurulumu"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Artık hatırlatıcılarınızı yapılandırma, Pod'unuzu insülin ile doldurma, cihazınızla eşleştirme ve vücudunuza yerleştirme işlemine başlayacaksınız."; - -/* Cancel button title */ -"Cancel" = "Vazgeç"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Devam et"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Omnipod Tanıtımı Atlansın mı?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Uygulama, Pod sona ermeden önce sizi bilgilendirir.\n\nKaç saat önce bildirim almak istediğinizi ayarlamak için kaydırın."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "İleri"; - -/* */ -"Expiration Reminder" = "Süre Sonu Hatırlatıcısı"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Uygulama, Pod içerisinde insülin miktarı (50-10 Ü) kaldığında sizi bilgilendirir.\n\nBildirim almak istediğiniz ünite miktarını ayarlamak için kaydırın."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Düşük Rezervuar"; - -/* */ -"Save" = "Kaydet"; - -/* hr (short for hour) */ -"hr" = "sa"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Manuel Bazalı İptal Et"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "İnsülin\nDurduldu"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "İnsülin İletimine Devam et"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Pod'unuzun yakında olduğundan emin olun ve tekrar deneyin."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod bağlı değil"; - -/* Label for suspended at time */ -"Suspended At" = "Askıya Alındı"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "İnsülin iletimi devam ediyor..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "İnsülin iletimi askıya alınıyor..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Pod bulunamadı"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Çok fazla pod bulundu"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "IPhone'un etkin pod'a yakın olduğundan emin olun"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Tekrar deneyin"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Diğer pod'lardan uzakta yeni bir alana gidin ve tekrar deneyin."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Pod'unuzun dolu ve yakında olduğundan emin olun."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Lütfen iPhone'u pod'tan daha uzağa konumlandırın"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Lütfen iPhone'u pod'a göre yeniden konumlandırın"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Lütfen kapsama alanına yalnızca orijinal pod'u getirin veya orijinal pod'u devre dışı bırakın"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Çakışma olasılığı mümkün. Lütfen yeni bir konuma geçin"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Pod'unuzun yakında olduğundan emin olun ve tekrar deneyin."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Mevcut bolusun bitmesini bekleyin veya bolusu iptal edin"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Mevcut bolusun bitmesini bekleyin veya bolusu iptal edin"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Mevcut geçici bazalın bitmesini bekleyin veya askıya almak için iptal edin"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ önce"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Silence Pod mode suppresses all Pod alert and confirmation reminder beeping."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniBLE/Localizations/uk.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/uk.lproj/Localizable.strings deleted file mode 100644 index 6f7c7cabc..000000000 --- a/Dependencies/OmniBLE/Localizations/uk.lproj/Localizable.strings +++ /dev/null @@ -1,826 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Попередження про Кілька Команд"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Нагадування про термін дії Podʼу"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Термін дії Podʼу минув"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Пустий Резервуар"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Нагадування про призупинення Podʼу"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Відновити подачу"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Створення Пари не завершено"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Виявлено Зміну Часу"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Попередження про Кілька Команд"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod спливає через %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Змінити Pod зараз. Pod був активним протягом 72 годин."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Замініть Pod зараз. Подача інсуліну припиниться через 1 годину."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ або менше інсуліну залишилося в Podʼі. Необхідна швидка заміна."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Нагадування про призупинення Podʼу"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Період призупинення інсуліну закінчився.\n\n Ви можете відновити введення з банера на головному екрані або з екрана налаштувань помпи. Вам буде нагадано знову через 15 хвилин."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Будь Ласка, завершіть підключення Podʼу."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Час на вашій помпі відрізняється від поточного часу. Ви можете переглянути час помпи та синхронізувати його з поточним часом у налаштуваннях."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Час призупинення вже вичерпано. Відкрийте додаток та продовжуйте роботу."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ок"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Незавершена Активація"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod закінчується через"; - -/* */ -"Pod Expires" = "Термін дії Podʼу минув"; - -/* */ -"Pod Activated" = "Pod активований"; - -/* */ -"Notification Settings" = "Параметри Сповіщень"; - -/* */ -"Confidence Reminders" = "Нагадування про Верифікацію"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Призупинити Введення Інсуліну"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Термін дії Podʼу минув"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Незавершена активація"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Немає Podʼу"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Парний Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Парний Pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Створення пари."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Заправлення. Будь ласка зачекайте."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Підключення успішно створено. Продовжити."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Завершення деактивації"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Замініть Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "день"; - -/* Unit for plural days in pod life remaining */ -"days" = "дні"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "годин"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "годин"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "хвилин"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "хвилин"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Подання Інсуліну"; - -/* */ -"Scheduled Basal" = "Запланований Базал"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Залишок Інсуліну"; - -/* Section header for activity section */ -"Activity" = "Активність"; - -/* title for device details page */ -"Device Details" = "Деталі Пристрою"; - -/* Section header for configuration section */ -"Configuration" = "Налаштування"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Завершення деактивації"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Замініть Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Замініть Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Незавершена Активація"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod закінчується через"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Термін дії Podʼу минув"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Незавершена активація"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Немає Podʼу"; - -/* Pod life HUD view label */ -"Fault" = "Збій"; - -/* Label describing pod age view */ -"Pod Age" = "Pod пропрацював"; - -/* Label describing time remaining view */ -"Remaining" = "Залишок"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Замініть Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Немає підключеного Podʼу"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod вже з'єднано"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Тип інсуліну не налаштований"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod не готовий для введення канюли."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Непридатні параметри"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Будь ласка, підключіть новий Pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Проблеми з повідомленням"; - -/* */ -"Finish Pairing" = "Завершити створення пари"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Завершення деактивації"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Немає Podʼу"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "Нема Інсуліну"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Термін дії Podʼу минув"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Помпа забита"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Помилка Podʼу"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Нема Інсуліну"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Подання Інсуліну Припинено"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Втрата сигналу"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Ручна Тимчасова Базальна Швидкість (ТБШ)"; - -/* */ -"Insert Cannula" = "Вставте Канюлю"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Введення..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Спробувати знову"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Перевірка..."; - -/* */ -"Check cannula insertion finished" = "Перевірте завершення введення канюлі"; - -/* */ -"Get pod status" = "Отримати статус Podʼу"; - -/* */ -"Save Basal Profile" = "Зберегти Базальний профіль"; - -/* */ -"Save basal profile failed: %{public}@" = "Не вдалося зберегти базальний профіль:%{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Пропуск звукових сигналів через те, що болюс ще триває."; - -/* */ -"Play Test Beeps" = "Програти тестовий звук"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Пропуск журналу пульсу через те, що болюс ще триває."; - -/* */ -"Read Pulse Log" = "Читати Журнал Подій"; - -/* */ -"Set Confirmation Beeps to %s" = "Установіть значення для звукових сигналів підтвердження %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Встановіть налаштування звукових сигналів підтвердження"; - -/* */ -"Suspend" = "Призупинити"; - -/* */ -"Failed to suspend: %{public}@" = "Не вдалося призупинити"; - -/* */ -"Resume" = "Відновити"; - -/* */ -"Bolus" = "Болюс"; - -/* */ -"Cancel Bolus" = "Скасувати Болюс"; - -/* Alert acknowledgment OK button */ -"OK" = "ОК"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Порожній резервуар"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Виявлено оклюзію"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Критична Помилка"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Введення інсуліну припинено. Змініть Pod зараз."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Залишок Інсуліну"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Встановіть Тимчасову Базальну Швидкість"; - -/* Section header for activity section */ -"Activity" = "Активність"; - -/* Section header for configuration section */ -"Configuration" = "Налаштування"; - -/* Title for previous pod page */ -"Previous Pod" = "Попередній Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Час помпи"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Налаштування Часу Помпи..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Встановити Поточний Час"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Перейдіть на інший пристрій для введення інсуліну"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Час на вашій помпі відрізняється від поточного часу. Хочете оновити час на помпі до поточного?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Так, синхронізувати з поточним часом"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Ні, залишити як є"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Зніміть Pod"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Ви впевнені, що хочете припинити використовувати Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Видалити Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Тип Інсуліну"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Встановити Поточний Час"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Призупинити Подачу"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Введення інсуліну буде припинено, доки ви не відновите його вручну. Коли ви хочете, щоб Loop нагадав вам відновити доставку?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 хвилин"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 година"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 година 30 хвилин"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 години"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Не вдалося Призупинити Подачу Інсуліну"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Не вдалося Відновити Подачу Інсуліну"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Не вдалося Встановити Час Помпи"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Не вдалося Скасувати Ручний Базал"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Будь ласка, деактивуйте Pod. Після завершення деактивації ви можете видалити його та створити пару з новим Podʼом."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Будь ласка, деактивуйте Pod. Після завершення деактивації ви можете підключити новий Pod."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Деактивувати Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Деактивувати."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod успішно деактивовано. Продовжити."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Спробувати знову"; - -/* Action button description when deactivated */ -"Continue" = "Продовжити"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Виникла проблема зв’язку з Podʼом. Якщо проблема не зникає, торкніться «Відхилити Pod». Потім ви можете активувати новий Pod."; - -/* Text for discard pod button */ -"Discard Pod" = "Відхилити Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Видалити Pod з тіла"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Ваш Pod може все ще подавати інсулін.\nВийміть його зі свого тіла, а потім натисніть «Продовжити»."; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Замініть Pod. Подача інсуліну буде зупинена через 8 годин після закінчення терміну дії Pod'a або коли резервуар буде порожній."; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Наповніть новий Pod інсуліном U-100 (залиште синю кришку капсули на голці)."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Видаліть синю кришку голки Podʼа та перевірте канюлю. Потім зніміть паперову підкладку."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Прослухайте 2 звукові сигнали."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Пов'язані"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Відмінити"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Ви впевнені, що бажаєте скасувати налаштування Pod'a? "; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Якщо ви скасуєте налаштування Pod'a, поточний Pod буде дезактивовано та стане непридатним для використання."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Так, відключити Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Ні, продовжити з Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Підготуйте місце."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Перевірте Pod, установіть його на тілі, а потім підтвердіть установку Pod."; - -/* Action button title for attach pod view */ -"Continue" = "Продовжити"; - -/* */ -"Attach Pod" = "Прикріпіть Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Підтвердіть прикріплення Pod"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Будь ласка, підтвердьте, що Pod надійно прикріплений до тіла.\n\nКанюля може бути вставлена лише один раз з кожним Podʼом. Натисніть \"Підтверджую\", коли Pod буде прикріплено."; - -/* Button title for confirm attachment option */ -"Confirm" = "Підтвердити"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Натисніть нижче, щоб розпочати введення канюлі."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Дочекайтеся завершення введення канюлі."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Введено"; - -/* Check Cannula */ -"Check Cannula" = "Перевірте Канюлю"; - -/* */ -"Is the cannula inserted properly?" = "Чи правильно вставлена канюля?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Віконце у верхній частині Pod повинно бути рожевим, коли канюля правильно вставлена в шкіру."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Так"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Ні"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Створення пари..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Присвоїти..."; - -/* */ -"Deactivating..." = "Деактивувати..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Деактивовано"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Ваш Pod готовий до використання.\n\n%1$@ нагадає вам змінити Pod до закінчення терміну його дії. Ви можете змінити це на зручний для вас час."; - -/* */ -"Scheduled Reminder" = "Заплановане Нагадування"; - -/* Label for expiration reminder row */ -"Time" = "Час"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Завершити налаштування"; - -/* */ -"Setup Complete" = "Налаштування завершено"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Немає Нагадувань"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Периферійний пристрій не готовий"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Неправильна відповідь"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Затримка"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Порожнє значення"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Невідома характеристика"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Нагадування Omnipod"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Програма налаштовує нагадування на Podʼі, щоб завчасно повідомити вас про закінчення терміну дії Pod. Встановіть кількість годин попереднього сповіщення, яке ви хочете налаштувати під час підключення нового Podʼу."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Це нагадування, яке ви запланували, коли сполучали свій поточний Pod."; - -/* */ -"Scheduled Reminder" = "Заплановане Нагадування"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Програма сповіщає вас, коли кількість інсуліну в Podʼі досягає цього рівня."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Критичні Сповіщення"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Нагадування вище не звучатимуть, якщо ваш пристрій перебуває в беззвучному режимі або режимі «Не турбувати».\n\nІснують інші важливі сповіщення та будильники Podʼу, які лунатимуть, навіть якщо на пристрої встановлено режим «Без звуку» або «Не турбувати»."; -/* navigation title for notification settings */ -"Notification Settings" = "Параметри сповіщень"; - -/* Label for scheduled reminder value row */ -"Time" = "Час"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Немає Нагадувань"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Нагадування про Низький Рівень Резервуару"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Переконайтеся, що ваш телефон і Pod знаходяться поруч один з одним. Якщо проблеми звʼязку не зникають, перейдіть у інше місце."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Змініть Pod зараз. Введення інсуліну припиниться через %1$@ або коли інсулін закінчиться."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Вимкнено"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Активовано"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Розширений"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Нагадування про довіру не використовуються."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Нагадування про достовірність лунатимуть для команд, які ви ініціюєте, як-от болюс, скасування болюсу, призупинення, відновлення, збереження сповіщень тощо. Коли Loop автоматично регулює доставку, нагадування про довіру не використовуються."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Нагадування про довіру лунатимуть, коли Loop автоматично регулює доставку, а також для команд, які ви ініціюєте."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Нагадування про довіру лунатимуть, коли Loop автоматично регулює доставку, а також для команд, які ви ініціюєте."; ->>>>>>> 7f4d47c8 (Crowdin (#334)) - -/* Label text for temporary basal rate summary */ -"Rate" = "Швидкість"; - -/* Insulin unit per hour */ -"U/hr" = "U/год"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ для %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Петля не регулюватиме подачу інсуліну автоматично, доки тимчасова базальна доза не закінчиться або не буде скасована."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Встановіть Тимчасову Базальну Швидкість"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Тимчасовий Базал"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Тимчасовий Базал не виконан"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Не вдалося встановити Тимчасову Базальну Швидкість: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Неможливо встановити Тимчасову Базальну Швидкість: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Відсутня конфігурація"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Помічник налаштування помпи не був налаштований щодо максимального рівня Базального інсуліну. Будь ласка, перейдіть в \"Параметри помпи\" -> \"Межа подачі\" і встановіть новий максимальний рівень Базального інсуліну."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Нагадування про закінчення терміну дії за умовчанням"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Попередня інформація про Pod"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "Без\nПодачи"; - -/* description label for active time pod details row */ -"Active Time" = "Активний Час"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Усього подано"; - -/* description label for device name pod details row */ -"Device Name" = "Ім'я пристрою"; - -/* description label for lot number pod details row */ -"Lot Number" = "Номер партії"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Порядковий номер"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Версія прошивки"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "Версія мікропрограми BLE"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod активований"; - -/* description label for active time pod details row */ -"Active Time" = "Активний Час"; - -/* description label for last status date pod details row */ -"Last Status" = "Останній статус"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Деталі несправності Podʼу"; - -/* Title for PodSetupView */ -"Pod Setup" = "Налаштування Podʼу"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Тепер ви почнете процес налаштування своїх нагадувань, заправляєте свій Pod інсуліном, з’єднуєте пристрій і розміщуєте його на своєму тілі."; - -/* Cancel button title */ -"Cancel" = "Відмінити"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Продовжити"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Пропустити онборт Omnipod?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Програма заздалегідь сповіщає вас про закінчення терміну дії Podʼу.\n\nПрокрутіть, щоб установити кількість годин попереднього сповіщення, яке ви хочете отримувати."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Далі"; - -/* */ -"Expiration Reminder" = "Нагадування про термін дії"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Додаток сповістить вас, коли кількість інсуліну в Podʼі досягне цього рівня (50-10 ОД).\n\nПрокрутіть, щоб установити кількість одиниць, про яку ви хочете отримати нагадування."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Пустий Резервуар"; - -/* */ -"Save" = "Зберегти"; - -/* hr (short for hour) */ -"hr" = "год"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Скасувати ручний Базал"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Інсулін\nПризупинено"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Відновити введення інсуліну"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Переконайтеся, що Pod поблизу, і повторіть спробу."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod не під'єднано"; - -/* Label for suspended at time */ -"Suspended At" = "Призупинено у"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Відновлення введення інсуліну..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Призупинення введення інсуліну..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Pod не знайдено"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Знайдено забагато Podʼів"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Переконайтеся, що iPhone знаходиться поруч з активним Podʼом"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Спробуйте знову"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Перейдіть у інше місце подалі від будь-яких інших Podʼів і спробуйте ще раз."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Переконайтеся, що Pod наповнений і знаходиться поруч."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Перемістіть iPhone далі від Podʼу"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Перемістіть iPhone далі від Podʼу"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Будь ласка, тримайте лише вихідний Pod у зоні дії або деактивуйте оригінальний Pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Перехресні перешкоди можливі. Будь ласка, перейдіть на нове місце"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Переконайтеся, що Pod поблизу, і повторіть спробу."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Зачекайте, поки поточний болюс закінчиться, або скасуйте болюс"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Зачекайте, поки поточний болюс закінчиться, або скасуйте болюс"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Дочекайтеся закінчення поточного Тимчасового Базалу або скасуйте його"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ тому"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Сповіщення вимкнено"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Звичайний режим роботи, коли звукові сигнали Pod використовуються для всіх сповіщень Pod і коли ввімкнено нагадування про конфіденційність."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Усі сповіщення Pod не використовують звукові сигнали, а звукові сигнали нагадування про підтвердження пригнічуються. Pod подає звукові сигнали лише у разі фатальних помилок Pod і під час відтворення тестових звукових сигналів.\n\n⚠️Попередження. Щоразу, коли Pod вимкнено, він має залишатися в зоні дії Bluetooth цього пристрою, щоб отримувати сповіщення про сповіщення Pod."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Режим Silence Pod пригнічує всі звукові сигнали сповіщень і нагадувань про підтвердження."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Деталі Pod"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Попередні подробиці Pod"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Деталі менеджера помпи"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Отримання деталей менеджера помп..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Оновити відомості про керування помпами"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Діагностика"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Отримати статус Pod'у"; diff --git a/Dependencies/OmniBLE/Localizations/vi.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/vi.lproj/Localizable.strings deleted file mode 100644 index c23795298..000000000 --- a/Dependencies/OmniBLE/Localizations/vi.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Lời Nhắc Pod Hết hạn"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod đã hết hạn"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Sắp hết thuốc"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Tiếp tục lại việc tiêm insulin"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod ghép nối không thành công"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Thay đổi thời gian được phát hiện"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod sẽ hết hạn trong: %1$@."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Thay pod ngay. Pod đã hoạt động 72 giờ qua."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Thay pod ngay. Insulin sẽ ngừng trong 1 giờ tới."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin hoặc ít hơn còn lại trong Pod. Thay Pod ngay."; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Thời gian tạm ngưng insulin đã kết thúc.\n\n Bạn có thể phục hồi việc tiêm thuốc từ màn hình chính hoặc từ màn hình cài đặt bơm. Sẽ có thông báo nhắc trong vòng 15 phút."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Đề nghị hoàn thành ghép đôi pod."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Thời gian trên bơm khác so với thời gian thực tế. Bạn có thể xem thời gian trên bơm và sync thời gian hiện hành trong cài đặt."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Thời gian tạm dừng hết. Mở ứng dụng và tiếp tục lại."; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Kích hoạt chưa hoàn thành"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod sẽ hết hạn trong"; - -/* */ -"Pod Expires" = "Pod hết hạn"; - -/* */ -"Pod Activated" = "Pod đã kích hoạt"; - -/* */ -"Notification Settings" = "Cài đặt thông báo"; - -/* */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Tạm dừng insulin"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod đã hết hạn"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Vô hiệu hóa chưa hoàn tất"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Không pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "Kết nối Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Kết nối Pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Đang ghép đôi."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Đang priming. Xin chờ."; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod ghép đôi thành công. Tiếp tục."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Hoàn tất việc ngưng kích hoạt"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Thay pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "ngày"; - -/* Unit for plural days in pod life remaining */ -"days" = "ngày"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "giờ"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "giờ"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "phút"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "phút"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Khối lượng tiêm insulin"; - -/* */ -"Scheduled Basal" = "Đã lên chương trình cho liều Basal"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin còn lại"; - -/* Section header for activity section */ -"Activity" = "Hoạt động"; - -/* title for device details page */ -"Device Details" = "Chi tiết thiết bị"; - -/* Section header for configuration section */ -"Configuration" = "Cấu hình"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Hoàn tất việc ngưng kích hoạt"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Thay pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Thay pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Kích hoạt chưa hoàn thành"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod sẽ hết hạn trong"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod đã hết hạn"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Vô hiệu hóa chưa hoàn tất"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "Không pod"; - -/* Pod life HUD view label */ -"Fault" = "Lỗi"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Label describing time remaining view */ -"Remaining" = "Đang còn lại"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "Thay pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Không có pod nào được kết nối"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod đã được ghép đôi"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Loại insulin chưa được khai báo"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod không sẵn sàng để gắn cannula."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Cài đặt không tồn tại"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Đề nghị ghép đôi pod mới"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Câu lệnh có vấn đề"; - -/* */ -"Finish Pairing" = "Hoàn tất ghép đôi"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Hoàn tất việc ngưng kích hoạt"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Không pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "Hết thuốc"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod đã hết hạn"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Lỗi Pod"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "Hết thuốc"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Đã tạm ngưng"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Mất tín hiệu"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Liều Basal thủ công"; - -/* */ -"Insert Cannula" = "Thay Cannula"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Đang gắn..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "Thử lại"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Đang kiểm tra..."; - -/* */ -"Check cannula insertion finished" = "Kiểm tra việc gắn cannula hoàn tất"; - -/* */ -"Get pod status" = "Lấy thông tin pod"; - -/* */ -"Save Basal Profile" = "Lưu profile basal"; - -/* */ -"Save basal profile failed: %{public}@" = "Lưu profile basal gặp lỗi: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Bỏ qua việc kiểm tra bíp do đang thực hiện liều bolus."; - -/* */ -"Play Test Beeps" = "Kiểm tra bíp"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Bỏ qua nhật ký đọc xung do liều bolus chưa hoàn thành."; - -/* */ -"Read Pulse Log" = "Đọc nhật ký do xung"; - -/* */ -"Set Confirmation Beeps to %s" = "Cài đặt tiếng Bíp mức %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Cài đặt tiếng Bíp"; - -/* */ -"Suspend" = "Đã tạm ngưng"; - -/* */ -"Failed to suspend: %{public}@" = "Tạm ngưng thất bại: %{public}@"; - -/* */ -"Resume" = "Tiếp tục"; - -/* */ -"Bolus" = "Liều bolus"; - -/* */ -"Cancel Bolus" = "Hủy bỏ liều bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Hết thuốc"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Phát hiện tắc nghẽn"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Pod lỗi nghiêm trọng"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin ngừng. Thay Pod ngay."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin còn lại"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Cài đặt liều nền tạm thời"; - -/* Section header for activity section */ -"Activity" = "Hoạt động"; - -/* Section header for configuration section */ -"Configuration" = "Cấu hình"; - -/* Title for previous pod page */ -"Previous Pod" = "Pod trước"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Thời gian của Bơm"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Đang điều chỉnh thời gian của bơm..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Đồng bộ thời gian hiện tại"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Chuyển đổi sang bơm khác"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Thời gian trên máy bơm của bạn khác với thời gian hiện tại. Bạn có muốn cập nhật thời gian trên máy bơm của mình đến thời điểm hiện tại không?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Có, đồng bộ với thời gian hiện tại"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Không, Giữ nguyên"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Thay bơm"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Bạn có chắc muốn dừng sử dụng Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Xóa Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "Loại Insulin"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Đồng bộ thời gian hiện tại"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Tạm ngưng liều insulin"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Việc tiêm insulin sẽ bị dừng cho đến khi bạn tiếp tục theo cách thủ công. Vậy khi nào bạn muốn Loop nhắc bạn tiếp tục tiêm?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 phút"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 giờ"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 giờ 30 phút"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 giờ"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Thất bại khi tạm dừng liều insulin"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Không thể tiêm insulin trở lại"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Không thể cài đặt thời gian cho bơm"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Không thể hủy liều basal thủ công"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Hủy kích hoạt pod. Khi việc hủy kích hoạt hoàn tất, gỡ bỏ pod ra khỏi cơ thể và ghép nối pod mới."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Hủy kích hoạt pod. Khi việc hủy kích hoạt hoàn tất, bạn có thể ghép nối pod mới."; - -/* Deactivate pod action button */ -"Deactivate Pod" = "Hủy kích hoạt Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Đang hủy kích hoạt."; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod hủy kích hoạt thành công. Tiếp tục."; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "Thử lại"; - -/* Action button description when deactivated */ -"Continue" = "Tiếp tục"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Đã xảy ra sự cố khi giao tiếp với Pod. Nếu sự cố này vẫn tiếp diễn, hãy nhấn vào Discard Pod. Sau đó, bạn có thể kích hoạt Pod mới."; - -/* Text for discard pod button */ -"Discard Pod" = "Loại bỏ pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Gỡ pod khỏi cơ thể"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Pod có thể đang tiêm insulin.\n Gỡ pod khỏi người sau đó nhấn \"Continue.\""; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Thay pod ngay. Insulin sẽ ngưng khi pod hết hạn 8 giờ tới hoặc khi không còn insulin."; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Dùng loại insulin U-100."; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Tháo nắp kim màu xanh của Pod và kiểm tra ống thông. Sau đó loại bỏ lớp lót giấy."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Nghe 2 tiếng bíp."; - -/* Label text indicating pairing finished.*/ -"Paired" = "Đã ghép đôi"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "Bỏ qua"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Bạn có chắc chắn muốn hủy cấu hình pod?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Nếu bạn hủy cấu hình pod, pod hiện tại sẽ bị hủy kích hoạt và sẽ không sử dụng được nữa."; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Có, hủy kích hoạt pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Không, tiếp tục"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Chuẩn bị vị trí."; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Kiểm tra pod, gắn vào vị trí sau đó xác nhận pod đã được gắn chặt."; - -/* Action button title for attach pod view */ -"Continue" = "Tiếp tục"; - -/* */ -"Attach Pod" = "Attach Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Xác nhận pod đã gắn chặt"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Xác nhận rằng Pod được gắn chặt vào cơ thể bạn.\n\nCannula chỉ có thể lắp một lần. Nhấn vào “Confirm” khi Pod đã gắn chặt."; - -/* Button title for confirm attachment option */ -"Confirm" = "Xác nhận"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Chạm phía dưới để bắt đầu gắn cannula."; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Đợi đến khi việc gắn hoàn tất."; - -/* Label text indicating insertion finished. */ -"Inserted" = "Đã gắn"; - -/* Check Cannula */ -"Check Cannula" = "Kiểm tra Cannula"; - -/* */ -"Is the cannula inserted properly?" = "Việc gắn cannual chuẩn chưa?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Ô vuông trên đầu của pod sẽ nháy đỏ khi cannual được gắn chuẩn vào trong cơ thể."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Có"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Không"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Đang ghép đôi..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* */ -"Deactivating..." = "Đang hủy kích hoạt..."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Đã hủy kích hoạt"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Pod đã sẵn sàng hoạt động.\n\n%1$@ sẽ nhắc nhở bạn thay đổi khi pod hết hạn. Bạn có thể thay khi nào tiện."; - -/* */ -"Scheduled Reminder" = "Lịch biểu lời nhắc"; - -/* Label for expiration reminder row */ -"Time" = "Thời gian"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Hoàn thành cài đặt"; - -/* */ -"Setup Complete" = "Cấu hình hoàn thành"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Không có lời nhắc"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Thiết bị ngoại vi chưa sẵn sàng"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Phản hồi không chuẩn"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Hết thời gian"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Giá trị trống"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Đặc điểm không xác định"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Không có gì"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Lời nhắc của Omnipod"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Ứng dụng cấu hình lời nhắc trên pod để thông báo trước cho bạn khi pod hết hạn. Đặt số giờ bạn muốn cấu hình khi ghép nối pod mới."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Đây là lời nhắc mà bạn đã lên lịch khi ghép nối Pod hiện tại của mình."; - -/* */ -"Scheduled Reminder" = "Lịch biểu lời nhắc"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Ứng dụng nhắc nhở bạn khi lượng insulin trong pod đạt đến mức này."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Cảnh báo nghiêm trọng"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Lời nhắc ở trên sẽ không phát ra âm thanh nếu thiết bị của bạn ở trạng thái Silent hoặc Do Not Disturb.\n\n Có nhiều cách cảnh báo khác nhau phát ra âm thanh ngay cả khi thiết bị của bạn ở trạng thái Silent hoặc Do Not Disturb."; -/* navigation title for notification settings */ -"Notification Settings" = "Cài đặt thông báo"; - -/* Label for scheduled reminder value row */ -"Time" = "Thời gian"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Không có lời nhắc"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Báo nhắc gần hết thuốc"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Đảm bảo điện thoại và pod được đặt gần nhau. Nếu kết nối vẫn gặp trở ngại, đặt lại chổ khác."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Thay pod ngay. Insulin sẽ ngưng tiêm trong %1$@ hoặc khi không còn insulin."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Vô hiệu hóa"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Cho phép"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Mở rộng"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Không có lời nhắc nào được sử dụng."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Các tác vụ sẽ có âm thanh như khi bạn bolus, hủy bỏ bolus, tạm dừng bơm, hoạt động lại hay lưu các lời nhắc thông báo... sẽ không có âm thanh khi ứng dụng chạy tự động."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Sẽ có âm thanh báo nhắc khi ứng dụng tự động điều chỉnh liều cũng như khi bạn khởi tạo ứng dụng."; - -/* Label text for temporary basal rate summary */ -"Rate" = "Tỷ lệ"; - -/* Insulin unit per hour */ -"U/hr" = "U/hr"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ cho %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop sẽ không tự động điều chỉnh liều insulin đến khi liều nền tạm thời thực hiện xong hoặc bị hủy bỏ."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Cài đặt liều nền tạm thời"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Liều nền tạm thời"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Liều nền tạm thời thất bại"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Không thể cài đặt liều nền tạm thời: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Không thể cài đặt liều nền tạm thời: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Thiếu cấu hình"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Liều nền tối đa chưa được cấu hình. Đề nghị vào Cài đặt-> Cấu hình bơm và cấu hình Liều nền tối đa mới."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Mặc định nhắc nhở hết hạn"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Thông tin Pod trước đó"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "Không\n Tiêm"; - -/* description label for active time pod details row */ -"Active Time" = "Thời gian Hoạt động"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Tổng liều"; - -/* description label for device name pod details row */ -"Device Name" = "Tên thiết bị"; - -/* description label for lot number pod details row */ -"Lot Number" = "Số Lô"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Số thứ tự"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod đã kích hoạt"; - -/* description label for active time pod details row */ -"Active Time" = "Thời gian Hoạt động"; - -/* description label for last status date pod details row */ -"Last Status" = "Trạng thái cuối"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Thông tin lỗi Pod"; - -/* Title for PodSetupView */ -"Pod Setup" = "Cấu hình Pod"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Bạn bắt đầu quá trình cài đặt các lời nhắc, đổ đầy thuốc vào pod, ghép đôi thiết bị và gắn pod lên người."; - -/* Cancel button title */ -"Cancel" = "Bỏ qua"; - -/* Text for continue button on PodSetupView */ -"Continue" = "Tiếp tục"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Ứng dụng sẽ thông báo trước cho bạn thời gian pod hết hạn.\n\n Kéo xuống để thiết lập số giờ để ứng dụng thông báo."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Kế tiếp"; - -/* */ -"Expiration Reminder" = "Nhắc nhở hết hạn"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Ứng dụng sẽ thông báo khi lượng insulin trong Pod đạt đến mức này (50-10 U).\n\n Kéo xuống để chọn số Unit mà bạn muốn để nhận thông báo."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "Sắp hết thuốc"; - -/* */ -"Save" = "Lưu"; - -/* hr (short for hour) */ -"hr" = "giờ"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Hủy bỏ liều basal thủ công"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\n Đã tạm ngưng"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Phục hồi liều insulin"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Đảm bảo rằng Pod của bạn đang ở gần và thử lại."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod chưa được kết nối"; - -/* Label for suspended at time */ -"Suspended At" = "Tạm ngưng tại"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Đang phục hồi liều insulin..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Đang tạm dừng liều insulin..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Không tìm thấy Pod"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Phát hiện quá nhiều pod"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Đảm bảo rằng iPhone gần với pod đang kích hoạt"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Thử lại"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Chuyển pod đến vị trí mới và thử lại."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Đảm bảo pod đã chứa đầy thuốc và gần bên."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Đặt iPhone xa khỏi pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Đặt iPhone lại gần pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Chỉ mang pod gốc trong phạm vi hoạt động hoặc hủy kích hoạt pod gốc"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Có nhiễu xuyên âm. Vui lòng di chuyển đến địa điểm mới"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Đảm bảo rằng Pod của bạn đang ở gần và thử lại."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Chờ đợi liều bolus hiện tại hoàn tất hoặc hủy liều bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Chờ đợi liều bolus hiện tại hoàn tất hoặc hủy liều bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Chờ đợi liều basal tạm thời hoàn tất hoặc chọn ngưng để hủy"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ trước đó"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Im lặng"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Chế độ hoạt động bình thường trong đó tiếng bíp của Pod được dùng cho mọi cảnh báo của Pod và khi lời nhắc được bật."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Tất cả các cảnh báo của Pod đều không sử dụng tiếng bíp và tiếng bíp nhắc nhở sẽ bị chặn. Pod sẽ chỉ phát ra tiếng bíp khi Pod gặp lỗi nghiêm trọng và khi thực hiện kiểm tra tiếng bíp.\n\n⚠️Cảnh báo - Bất cứ khi nào Pod ở chế độ im lặng, nó phải được đặt trong phạm vi hoạt động của Bluetooth để nhận thông báo về các cảnh báo của Pod."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Chế độ Silence Pod sẽ chặn tất cả tiếng bíp và lời nhắc nhở."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Pod im lặng"; - -/* title for pod details page */ -"Pod Details" = "Các thông tin của Pod"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Thông tin của Pod trước đó"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Chi tiết về Trình quản lý Máy bơm"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Đang truy xuất thông tin Trình quản lý máy bơm..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Làm mới Chi tiết về Trình quản lý Máy bơm"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Chẩn đoán"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Đọc tình trạng pod"; diff --git a/Dependencies/OmniBLE/Localizations/zh-Hans.lproj/Localizable.strings b/Dependencies/OmniBLE/Localizations/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 463eca07b..000000000 --- a/Dependencies/OmniBLE/Localizations/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,822 +0,0 @@ -/* - Localizable.strings - OmniBLE - Created by Jon Mårtensson on 2022-08-28. - Copyright © 2022 Randall Knutson. All rights reserved. -*/ -/* Alert content title for multiCommand pod alert */ - -"Multiple Command Alert" = "多个命令警报"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod到期提醒"; - -/* Alert content title for podExpiring pod alert */ -"Pod Expired" = "Pod已到期"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "低药量"; - -/* Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "泵暂停中 的提醒"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "恢复输注"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod 配对未完成"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "检测到时间变化"; - -/* Alert content body for multiCommand pod alert */ -"Multiple Command Alert" = "多个命令警报"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod 将于 %1$@到期"; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "立即更换 Pod ,Pod 已使用72小时"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "请立刻更改Pod ,胰岛素输注将在 1 小时后停止"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ 或更少胰岛素剩余,请即刻更换Pod"; - -/* Alert content body for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "泵暂停中 的提醒"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "胰岛素输注暂停期已经结束,\n\n您可以从屏幕上方的横幅或者从您的泵设置屏幕上恢复输注,您将在 15 分钟内再次被提醒"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "请完成配对您的pod"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "您泵上的时间不同于当前时间。您可以在设置里将泵时间并同步到当前时间。"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "输注暂停已经结束,打开应用程序并恢复输注"; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "未完成启用"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod将过期于 "; - -/* */ -"Pod Expires" = "Pod有效期限"; - -/* */ -"Pod Activated" = "Pod 已激活"; - -/* */ -"Notification Settings" = "通知设置"; - -/* */ -"Confidence Reminders" = "二次确认提醒"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "暂停胰岛素输注"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod已到期"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "尚未完成停用"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "无Pod"; - -/* Settings page link description when next lifecycle action is to pair new pod */ -"Pair Pod" = "配对Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "配对Pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "配对中."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "准备中,请稍候"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod配对成功,继续"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "完成停用"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "更换Pod"; - -/* Unit for singular day in pod life remaining */ -"day" = "天"; - -/* Unit for plural days in pod life remaining */ -"days" = "天"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "小时"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "小时"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "分钟"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "分钟"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "胰岛素输注"; - -/* */ -"Scheduled Basal" = "预设基础率"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "胰岛素余量"; - -/* Section header for activity section */ -"Activity" = "活动"; - -/* title for device details page */ -"Device Details" = "设备详情"; - -/* Section header for configuration section */ -"Configuration" = "配置"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "完成停用"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "更换Pod"; - -/* Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "更换Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "未完成启用"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod将过期于 "; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod已到期"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "尚未完成停用"; - -/* Label for pod life state when no pod paired */ -"No Pod" = "无Pod"; - -/* Pod life HUD view label */ -"Fault" = "错误"; - -/* Label describing pod age view */ -"Pod Age" = "Pod使用天数"; - -/* Label describing time remaining view */ -"Remaining" = "剩余"; - -/* Label indicating pod replacement necessary */ -"Replace Pod" = "更换Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "没有找到可配对的Pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod已经配对了"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Recovery suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* */ -"Finish Pairing" = "Finish Pairing"; - -/* Status highlight that when pod is deactivating */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "无Pod"; - -/* Status highlight message for emptyReservoir alarm. */ -"No Insulin" = "No Insulin"; - -/* Status highlight message for podExpired alarm. */ -"Pod Expired" = "Pod已到期"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* */ -"Insert Cannula" = "植入Pod"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Cannula insertion button text while showing error */ -"Retry" = "重试"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* */ -"Check cannula insertion finished" = "Check cannula insertion finished"; - -/* */ -"Get pod status" = "Get pod status"; - -/* */ -"Save Basal Profile" = "Save Basal Profile"; - -/* */ -"Save basal profile failed: %{public}@" = "Save basal profile failed: %{public}@"; - -/* */ -"Skipping Play Test Beeps due to bolus still in progress." = "Skipping Play Test Beeps due to bolus still in progress."; - -/* */ -"Play Test Beeps" = "测试提示音"; - -/* */ -"Skipping Read Pulse Log due to bolus still in progress." = "Skipping Read Pulse Log due to bolus still in progress."; - -/* */ -"Read Pulse Log" = "读取Pulse日志"; - -/* */ -"Set Confirmation Beeps to %s" = "Set Confirmation Beeps to %s"; - -/* */ -"Set Confirmation Beeps Preference" = "Set Confirmation Beeps Preference"; - -/* */ -"Suspend" = "暂停"; - -/* */ -"Failed to suspend: %{public}@" = "Failed to suspend: %{public}@"; - -/* */ -"Resume" = "恢复"; - -/* */ -"Bolus" = "大剂量"; - -/* */ -"Cancel Bolus" = "Cancel Bolus"; - -/* Alert acknowledgment OK button */ -"OK" = "Ok"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Empty Reservoir"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion Detected"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "胰岛素余量"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Section header for activity section */ -"Activity" = "活动"; - -/* Section header for configuration section */ -"Configuration" = "配置"; - -/* Title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* Title for pod sync time action sheet. */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Are you sure you want to stop using Omnipod DASH?"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Delete Omnipod DASH"; - -/* Text for confidence reminders navigation link" */ -"Insulin Type" = "胰岛素类型"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "暂停输注"; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Button text for 1 hour suspend duration" */ -"1 hour" = "1 hour"; -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; -/* Button text for 2 hour suspend duration */ -"2 hours" = "2小时"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "暂停胰岛素输注失败"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "恢复胰岛素输注失败"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "设置泵时间失败"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "取消手动基础率失败"; - -/* */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "请先停用Pod,停用完成后将Pod从身体上摘除并配对新的Pod"; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "请先停用Pod, 停用完成后您可以配对一个新的Pod"; - -/* Deactivate pod action button */ -"Deactivate Pod" = "解除Pod"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "停用中"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod已成功停用,继续"; - -/* Action button description for deactivate after failed attempt */ -"Retry" = "重试"; - -/* Action button description when deactivated */ -"Continue" = "继续"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "与Pod通讯时出现问题。如果这个问题无法解决,请弃用此Pod,并激活一个新Pod。"; - -/* Text for discard pod button */ -"Discard Pod" = "丢弃Pod"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "从身体上取下Pod"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "您的Pod 可能仍在输注胰岛素。\n将其从您的身体中取下,然后点击“继续”。"; - -/* Insulin Unit */ -"U" = "U"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "现在更换Pod 。Pod 过期后的8小时后胰岛素输注将完全停止。"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "用至少100个单位的胰岛素填充一个新的pod (不要取下Pod的针头盖)。"; - -/* Label text for step 1 of pair pod instructions */ -"Remove the Pod's blue needle cap and check cannula. Then remove paper backing." = "Remove the Pod's blue needle cap and check cannula. Then remove paper backing."; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "注意听两声哔声"; - -/* Label text indicating pairing finished.*/ -"Paired" = "已配对"; - -/* Cancel button text in navigation bar on pair pod UI */ -"Cancel" = "取消"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "您确定要取消Pod安装吗?"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "如果您现在取消Pod 设置,当前Pod将被停用并报废。"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "是的,解除Pod"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "否,继续设置 Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "将注射部位做好准备"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "检查Pod,贴在注射部位上,确保pod已经贴牢"; - -/* Action button title for attach pod view */ -"Continue" = "继续"; - -/* */ -"Attach Pod" = "粘贴Pod"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "确认Pod粘贴牢固"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "请确认Pod 已经安全地粘贴到到你的身体.\n\n每个Pod只能插入一次软管。当Pod被贴牢后,点击\"确认\""; - -/* Button title for confirm attachment option */ -"Confirm" = "确认"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "点击下面的按钮开始插入软管"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "等待,直到插入完成"; - -/* Label text indicating insertion finished. */ -"Inserted" = "插入完毕"; - -/* Check Cannula */ -"Check Cannula" = "检查出药口软管"; - -/* */ -"Is the cannula inserted properly?" = "软管是否成功插入?"; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "当软管被正确插入皮肤时,Pod顶部的透明窗口应该有粉红色"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "是"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "否"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "配对中..."; - -/* Pod pairing action button text while priming */ -"Priming..." = "充盈中..."; - -/* */ -"Deactivating..." = "停用中......"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "已停用"; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "您的Pod 已准备好。\n\n%1$@ 将会在Pod到期前发出提醒。 您也可以自行设定到期提醒时间"; - -/* */ -"Scheduled Reminder" = "预约提醒"; - -/* Label for expiration reminder row */ -"Time" = "时间"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "完成安装"; - -/* */ -"Setup Complete" = "安装已完成"; - -/* Value text for no expiration reminder */ -"No Reminder" = "无提醒"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "外围设备尚未准备好"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "错误的响应"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "超时"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Empty Value"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unknown Characteristic"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"Critical Alerts" = "Critical Alerts"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if you device is set to Silent or Do Not Disturb mode."; -/* navigation title for notification settings */ -"Notification Settings" = "通知设置"; - -/* Label for scheduled reminder value row */ -"Time" = "时间"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Label for low reservoir reminder row */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "已启用"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* Label text for temporary basal rate summary */ -"Rate" = "输注率"; - -/* Insulin unit per hour */ -"U/hr" = "U/小时"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; -/* Button text for setting manual temporary basal rate*/ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate."; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* Text shown in insulin remaining space when no pod is paired (Please keep the '\n' while translating!) */ -"No\nDelivery" = "No\nDelivery"; - -/* description label for active time pod details row */ -"Active Time" = "Pod启动时间"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* description label for device name pod details row */ -"Device Name" = "Device Name"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* description label for activated at timne pod details row */ -"Pod Activated" = "Pod 已激活"; - -/* description label for active time pod details row */ -"Active Time" = "Pod启动时间"; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Cancel button title */ -"Cancel" = "取消"; - -/* Text for continue button on PodSetupView */ -"Continue" = "继续"; - -/* Are you sure you want to skip Omnipod Onboarding? */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Text of continue button on ExpirationReminderSetupView" */ -"Next" = "Next"; - -/* */ -"Expiration Reminder" = "Pod到期提醒"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Label text for low reservoir value row */ -"Low Reservoir" = "低药量"; - -/* */ -"Save" = "保存​​"; - -/* hr (short for hour) */ -"hr" = "hr"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Error message shown when the pod is not connected */ -"Pod not connected" = "Pod not connected"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Make sure iPhone is nearby the active pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Make sure your pod is filled and nearby."; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Please reposition iPhone further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Please reposition iPhone relative to the pod"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Make sure your pod is nearby and try again."; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ ago"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping." = "Silence Pod mode suppresses all Pod alert and confirmation reminder beeping."; - -/* navigation title for Silnce Pod */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniBLE/OmniBLE.xcodeproj/project.pbxproj b/Dependencies/OmniBLE/OmniBLE.xcodeproj/project.pbxproj deleted file mode 100644 index 5e66cb0f0..000000000 --- a/Dependencies/OmniBLE/OmniBLE.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1694 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 55; - objects = { - -/* Begin PBXBuildFile section */ - 1016324D27137B1E007A3BC2 /* BluetoothManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1016324C27137B1E007A3BC2 /* BluetoothManager.swift */; }; - 1016325927185EE4007A3BC2 /* BeepType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1016325127185EE4007A3BC2 /* BeepType.swift */; }; - 1016325A27185EE5007A3BC2 /* FaultEventCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1016325227185EE4007A3BC2 /* FaultEventCode.swift */; }; - 1016325B27185EE5007A3BC2 /* Pod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1016325327185EE4007A3BC2 /* Pod.swift */; }; - 1016325C27185EE5007A3BC2 /* BasalDeliveryTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1016325427185EE4007A3BC2 /* BasalDeliveryTable.swift */; }; - 1016325D27185EE5007A3BC2 /* AlertSlot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1016325527185EE4007A3BC2 /* AlertSlot.swift */; }; - 1016325E27185EE5007A3BC2 /* PodProgressStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1016325627185EE4007A3BC2 /* PodProgressStatus.swift */; }; - 1016325F27185EE5007A3BC2 /* BasalSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1016325727185EE4007A3BC2 /* BasalSchedule.swift */; }; - 1016326027185EE5007A3BC2 /* UnfinalizedDose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1016325827185EE4007A3BC2 /* UnfinalizedDose.swift */; }; - 102111472709462300784F13 /* PodState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 102111402709462300784F13 /* PodState.swift */; }; - 102111482709462300784F13 /* PodInsulinMeasurements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 102111412709462300784F13 /* PodInsulinMeasurements.swift */; }; - 102111492709462300784F13 /* PodCommsSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 102111422709462300784F13 /* PodCommsSession.swift */; }; - 1021114A2709462300784F13 /* PodDoseProgressEstimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 102111432709462300784F13 /* PodDoseProgressEstimator.swift */; }; - 1021114B2709462300784F13 /* BasalSchedule+LoopKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 102111442709462300784F13 /* BasalSchedule+LoopKit.swift */; }; - 1021114D2709467400784F13 /* PodComms.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1021114C2709467400784F13 /* PodComms.swift */; }; - 1024E32B27446DB000DE01F2 /* MessagePacket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1024E32A27446DB000DE01F2 /* MessagePacket.swift */; }; - 1024E32D2746083800DE01F2 /* EapSqn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1024E32C2746083800DE01F2 /* EapSqn.swift */; }; - 10289E68271B2A08000339E6 /* NumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10289E67271B2A08000339E6 /* NumberFormatter.swift */; }; - 10289E6A271B2A3E000339E6 /* IdentifiableClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10289E69271B2A3E000339E6 /* IdentifiableClass.swift */; }; - 10289E6C27308746000339E6 /* BluetoothServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10289E6B27308746000339E6 /* BluetoothServices.swift */; }; - 10289E6E27309327000339E6 /* CBPeripheral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10289E6D27309327000339E6 /* CBPeripheral.swift */; }; - 10289E7627347C69000339E6 /* Nonce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10289E7527347C69000339E6 /* Nonce.swift */; }; - 10289E782734D10D000339E6 /* EnDecrypt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10289E772734D10C000339E6 /* EnDecrypt.swift */; }; - 10289E7B2739F886000339E6 /* EapMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10289E7A2739F886000339E6 /* EapMessage.swift */; }; - 10289E7D2739F893000339E6 /* Milenage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10289E7C2739F893000339E6 /* Milenage.swift */; }; - 10289E7F2739F8A1000339E6 /* EapAkaAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10289E7E2739F8A1000339E6 /* EapAkaAttribute.swift */; }; - 10289E812739F8E4000339E6 /* SessionKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10289E802739F8E4000339E6 /* SessionKeys.swift */; }; - 10289E832739F917000339E6 /* SessionEstablisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10289E822739F917000339E6 /* SessionEstablisher.swift */; }; - 1029AE4827094D0E00B7F5B6 /* OmniBLEPumpManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1029AE4627094D0E00B7F5B6 /* OmniBLEPumpManager.swift */; }; - 1029AE4927094D0E00B7F5B6 /* OmniBLEPumpManagerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1029AE4727094D0E00B7F5B6 /* OmniBLEPumpManagerState.swift */; }; - 1029AE4B27094DDC00B7F5B6 /* OmniBLEPumpManager+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1029AE4A27094DDC00B7F5B6 /* OmniBLEPumpManager+UI.swift */; }; - 1029AE4F27094E1900B7F5B6 /* OmniBLEUI.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1029AE4E27094E1900B7F5B6 /* OmniBLEUI.xcassets */; }; - 10389A2326FF7841002115E9 /* PodInfoPulseLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A0426FF7841002115E9 /* PodInfoPulseLog.swift */; }; - 10389A2426FF7841002115E9 /* VersionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A0526FF7841002115E9 /* VersionResponse.swift */; }; - 10389A2526FF7841002115E9 /* PodInfoActivationTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A0626FF7841002115E9 /* PodInfoActivationTime.swift */; }; - 10389A2626FF7841002115E9 /* TempBasalExtraCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A0726FF7841002115E9 /* TempBasalExtraCommand.swift */; }; - 10389A2726FF7841002115E9 /* DeactivatePodCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A0826FF7841002115E9 /* DeactivatePodCommand.swift */; }; - 10389A2826FF7841002115E9 /* AcknowledgeAlertCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A0926FF7841002115E9 /* AcknowledgeAlertCommand.swift */; }; - 10389A2926FF7841002115E9 /* PodInfoConfiguredAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A0A26FF7841002115E9 /* PodInfoConfiguredAlerts.swift */; }; - 10389A2A26FF7841002115E9 /* MessageBlock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A0B26FF7841002115E9 /* MessageBlock.swift */; }; - 10389A2B26FF7841002115E9 /* PlaceholderMessageBlock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A0C26FF7841002115E9 /* PlaceholderMessageBlock.swift */; }; - 10389A2C26FF7841002115E9 /* PodInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A0D26FF7841002115E9 /* PodInfo.swift */; }; - 10389A2D26FF7841002115E9 /* BolusExtraCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A0E26FF7841002115E9 /* BolusExtraCommand.swift */; }; - 10389A2E26FF7841002115E9 /* FaultConfigCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A0F26FF7841002115E9 /* FaultConfigCommand.swift */; }; - 10389A2F26FF7841002115E9 /* PodInfoPulseLogPlus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A1026FF7841002115E9 /* PodInfoPulseLogPlus.swift */; }; - 10389A3026FF7841002115E9 /* StatusResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A1126FF7841002115E9 /* StatusResponse.swift */; }; - 10389A3126FF7841002115E9 /* GetStatusCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A1226FF7841002115E9 /* GetStatusCommand.swift */; }; - 10389A3226FF7841002115E9 /* BasalScheduleExtraCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A1326FF7841002115E9 /* BasalScheduleExtraCommand.swift */; }; - 10389A3326FF7841002115E9 /* CancelDeliveryCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A1426FF7841002115E9 /* CancelDeliveryCommand.swift */; }; - 10389A3426FF7841002115E9 /* AssignAddressCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A1526FF7841002115E9 /* AssignAddressCommand.swift */; }; - 10389A3526FF7841002115E9 /* BeepConfigCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A1626FF7841002115E9 /* BeepConfigCommand.swift */; }; - 10389A3626FF7841002115E9 /* ErrorResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A1726FF7841002115E9 /* ErrorResponse.swift */; }; - 10389A3726FF7841002115E9 /* SetupPodCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A1826FF7841002115E9 /* SetupPodCommand.swift */; }; - 10389A3826FF7841002115E9 /* DetailedStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A1926FF7841002115E9 /* DetailedStatus.swift */; }; - 10389A3926FF7841002115E9 /* PodInfoResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A1A26FF7841002115E9 /* PodInfoResponse.swift */; }; - 10389A3A26FF7841002115E9 /* SetInsulinScheduleCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A1B26FF7841002115E9 /* SetInsulinScheduleCommand.swift */; }; - 10389A3B26FF7841002115E9 /* ConfigureAlertsCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A1C26FF7841002115E9 /* ConfigureAlertsCommand.swift */; }; - 10389A3C26FF7841002115E9 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A1D26FF7841002115E9 /* Message.swift */; }; - 10389A3F26FF7841002115E9 /* CRC16.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A2026FF7841002115E9 /* CRC16.swift */; }; - 10389A4126FF7841002115E9 /* MessageTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10389A2226FF7841002115E9 /* MessageTransport.swift */; }; - 191DB66D2A06F17800212AC9 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 191DB6522A06F17800212AC9 /* Localizable.strings */; }; - 196A6F232AFFFD1700E3C089 /* SilencePodPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 196A6F222AFFFD1200E3C089 /* SilencePodPreference.swift */; }; - 84752E9326ED0FFE009FD801 /* OmniBLE.h in Headers */ = {isa = PBXBuildFile; fileRef = 84752E8526ED0FFE009FD801 /* OmniBLE.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 84752ED626ED13F5009FD801 /* Id.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84752EBF26ED13F5009FD801 /* Id.swift */; }; - 84752ED726ED13F5009FD801 /* X25519KeyGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84752EC126ED13F5009FD801 /* X25519KeyGenerator.swift */; }; - 84752ED826ED13F5009FD801 /* OmniRandomByteGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84752EC226ED13F5009FD801 /* OmniRandomByteGenerator.swift */; }; - 84752EDD26ED13F5009FD801 /* Ids.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84752EC826ED13F5009FD801 /* Ids.swift */; }; - 84752EDE26ED13F5009FD801 /* PeripheralManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84752EC926ED13F5009FD801 /* PeripheralManagerError.swift */; }; - 84752EDF26ED13F5009FD801 /* PeripheralManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84752ECA26ED13F5009FD801 /* PeripheralManager.swift */; }; - 84752EE026ED13F5009FD801 /* PodProtocolError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84752ECB26ED13F5009FD801 /* PodProtocolError.swift */; }; - 84752EE126ED13F5009FD801 /* PayloadSplitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84752ECD26ED13F5009FD801 /* PayloadSplitter.swift */; }; - 84752EE226ED13F5009FD801 /* PayloadJoiner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84752ECE26ED13F5009FD801 /* PayloadJoiner.swift */; }; - 84752EE326ED13F5009FD801 /* BLEPacket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84752ECF26ED13F5009FD801 /* BLEPacket.swift */; }; - 84752EE526ED13F5009FD801 /* KeyExchange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84752ED226ED13F5009FD801 /* KeyExchange.swift */; }; - 84752EE626ED13F5009FD801 /* LTKExchanger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84752ED326ED13F5009FD801 /* LTKExchanger.swift */; }; - 84752EE726ED13F5009FD801 /* PairResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84752ED426ED13F5009FD801 /* PairResult.swift */; }; - 84752EE826ED13F5009FD801 /* PairMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84752ED526ED13F5009FD801 /* PairMessage.swift */; }; - 8475306E26ED15DE009FD801 /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 8475306D26ED15DE009FD801 /* CryptoSwift */; }; - 847530F626ED65DD009FD801 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 847530F426ED65DD009FD801 /* LoopKit.framework */; }; - 847530F826ED65DD009FD801 /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 847530F526ED65DD009FD801 /* LoopKitUI.framework */; }; - 8475313226ED838B009FD801 /* PodLifeHUDView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8475311F26ED838A009FD801 /* PodLifeHUDView.swift */; }; - 8475313726ED838B009FD801 /* PodLifeHUDView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8475312426ED838A009FD801 /* PodLifeHUDView.xib */; }; - 8475315326EDA193009FD801 /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8475314626EDA193009FD801 /* TimeInterval.swift */; }; - 8475315726EDA193009FD801 /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8475314A26EDA193009FD801 /* LocalizedString.swift */; }; - 8475315826EDA193009FD801 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8475314B26EDA193009FD801 /* OSLog.swift */; }; - 8475315926EDA193009FD801 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8475314C26EDA193009FD801 /* UIColor.swift */; }; - 8475315A26EDA193009FD801 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8475314D26EDA193009FD801 /* HKUnit.swift */; }; - 8475315B26EDA193009FD801 /* NibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8475314E26EDA193009FD801 /* NibLoadable.swift */; }; - 8475315C26EDA193009FD801 /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8475314F26EDA193009FD801 /* TimeZone.swift */; }; - 8475315D26EDA193009FD801 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8475315026EDA193009FD801 /* Data.swift */; }; - A91B2DEC276E1E5E001B0E95 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = A91B2DEB276E1E5E001B0E95 /* README.md */; }; - A9A5BCEF276C1E2D00B02C86 /* TestUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D054D427651D2400FAFEFB /* TestUtilities.swift */; }; - A9A5BCF0276C1E2D00B02C86 /* HexConversionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D054CA2764FC8200FAFEFB /* HexConversionTests.swift */; }; - A9A5BCF1276C1E5F00B02C86 /* EnDecryptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D3492F2764F5780037F77C /* EnDecryptTests.swift */; }; - A9A5BCF2276C1E6D00B02C86 /* PayloadSplitterTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D054D22765135900FAFEFB /* PayloadSplitterTest.swift */; }; - A9A5BCF3276C1E6D00B02C86 /* StringLengthPrefixEncodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D054D827651FDE00FAFEFB /* StringLengthPrefixEncodingTests.swift */; }; - A9A5BCF4276C1E6D00B02C86 /* PayloadJoinerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D349312764F5D30037F77C /* PayloadJoinerTest.swift */; }; - A9A5BCF5276C1E6D00B02C86 /* PayloadSplitJoinTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D054D627651D4F00FAFEFB /* PayloadSplitJoinTests.swift */; }; - A9A5BCF6276C1E6D00B02C86 /* MessagePacketTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D054CC2764FDB700FAFEFB /* MessagePacketTests.swift */; }; - A9A5BCF7276C1E7000B02C86 /* KeyExchangeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D054DB27655F9C00FAFEFB /* KeyExchangeTests.swift */; }; - C10D6D6C27A2393800F53D58 /* OmniBLETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C10D6D6B27A2393800F53D58 /* OmniBLETests.swift */; }; - C10D6D6E27A2395700F53D58 /* OmniBLEPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = C10D6D6D27A2395700F53D58 /* OmniBLEPlugin.swift */; }; - C187C191278FCEC9006E3557 /* InsulinTypeConfirmation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187C190278FCEC9006E3557 /* InsulinTypeConfirmation.swift */; }; - C187C19A279086A8006E3557 /* OmniBLEPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = C187C199279086A8006E3557 /* OmniBLEPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C187C1A3279087A4006E3557 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = C187C1A2279087A4006E3557 /* OSLog.swift */; }; - C1C001BF27A2337B00533D35 /* PeripheralManager+OmniBLE.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C001BE27A2337B00533D35 /* PeripheralManager+OmniBLE.swift */; }; - C1C001C127A2349D00533D35 /* OmniBLE.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C001C027A2349D00533D35 /* OmniBLE.swift */; }; - C1C001C427A2351D00533D35 /* OmniBLEReservoirView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C1C001C227A2351D00533D35 /* OmniBLEReservoirView.xib */; }; - C1C001C527A2351D00533D35 /* OmniBLEReservoirView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C001C327A2351D00533D35 /* OmniBLEReservoirView.swift */; }; - C1D27A1527908DC600C41EBA /* OmniBLE.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84752E8226ED0FFE009FD801 /* OmniBLE.framework */; }; - C1D27A1727908DE500C41EBA /* OmniBLE.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84752E8226ED0FFE009FD801 /* OmniBLE.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - C1D27A1B27911E9900C41EBA /* PodAdvertisement.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1D27A1A27911E9900C41EBA /* PodAdvertisement.swift */; }; - C1DBD513282FF79D009FCF74 /* ManualTempBasalEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1DBD512282FF79D009FCF74 /* ManualTempBasalEntryView.swift */; }; - C1ED1E7027BAE1A600FED71C /* BeepPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1ED1E6F27BAE1A600FED71C /* BeepPreference.swift */; }; - C1ED1E7227BAE44E00FED71C /* BeepPreferenceSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1ED1E7127BAE44E00FED71C /* BeepPreferenceSelectionView.swift */; }; - C1F67E8B27975B830017487F /* AttachPodView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E7327975B830017487F /* AttachPodView.swift */; }; - C1F67E8C27975B830017487F /* ScheduledExpirationReminderEditView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E7427975B830017487F /* ScheduledExpirationReminderEditView.swift */; }; - C1F67E8E27975B830017487F /* TimeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E7627975B830017487F /* TimeView.swift */; }; - C1F67E8F27975B830017487F /* OmniBLESettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E7727975B830017487F /* OmniBLESettingsView.swift */; }; - C1F67E9027975B830017487F /* ExpirationReminderSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E7827975B830017487F /* ExpirationReminderSetupView.swift */; }; - C1F67E9127975B830017487F /* DeactivatePodView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E7927975B830017487F /* DeactivatePodView.swift */; }; - C1F67E9227975B830017487F /* BasalStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E7A27975B830017487F /* BasalStateView.swift */; }; - C1F67E9327975B830017487F /* ExpirationReminderPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E7B27975B830017487F /* ExpirationReminderPickerView.swift */; }; - C1F67E9427975B830017487F /* LowReservoirReminderSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E7C27975B830017487F /* LowReservoirReminderSetupView.swift */; }; - C1F67E9527975B830017487F /* HUDAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C1F67E7D27975B830017487F /* HUDAssets.xcassets */; }; - C1F67E9727975B830017487F /* PairPodView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E7F27975B830017487F /* PairPodView.swift */; }; - C1F67E9827975B830017487F /* CheckInsertedCannulaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E8027975B830017487F /* CheckInsertedCannulaView.swift */; }; - C1F67E9927975B830017487F /* NotificationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E8127975B830017487F /* NotificationSettingsView.swift */; }; - C1F67E9A27975B830017487F /* DeliveryUncertaintyRecoveryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E8227975B830017487F /* DeliveryUncertaintyRecoveryView.swift */; }; - C1F67E9C27975B830017487F /* UncertaintyRecoveredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E8427975B830017487F /* UncertaintyRecoveredView.swift */; }; - C1F67E9D27975B830017487F /* InsertCannulaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E8527975B830017487F /* InsertCannulaView.swift */; }; - C1F67E9E27975B830017487F /* LowReservoirReminderEditView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E8627975B830017487F /* LowReservoirReminderEditView.swift */; }; - C1F67E9F27975B830017487F /* SetupCompleteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E8727975B830017487F /* SetupCompleteView.swift */; }; - C1F67EA027975B830017487F /* PodSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E8827975B830017487F /* PodSetupView.swift */; }; - C1F67EA227975B830017487F /* PodDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67E8A27975B830017487F /* PodDetailsView.swift */; }; - C1F67EA427975CCA0017487F /* DashUICoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EA327975CCA0017487F /* DashUICoordinator.swift */; }; - C1F67EB627975E710017487F /* RoundedCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EB327975E710017487F /* RoundedCard.swift */; }; - C1F67EB727975E710017487F /* LeadingImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EB427975E710017487F /* LeadingImage.swift */; }; - C1F67EB827975E710017487F /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EB527975E710017487F /* ErrorView.swift */; }; - C1F67EBA27975EB70017487F /* FrameworkLocalText.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EB927975EB70017487F /* FrameworkLocalText.swift */; }; - C1F67EC527975F360017487F /* InsertCannulaViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EBD27975F360017487F /* InsertCannulaViewModel.swift */; }; - C1F67EC627975F360017487F /* PairPodViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EBE27975F360017487F /* PairPodViewModel.swift */; }; - C1F67EC827975F360017487F /* DeactivatePodViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EC027975F360017487F /* DeactivatePodViewModel.swift */; }; - C1F67EC927975F360017487F /* DeliveryUncertaintyRecoveryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EC127975F360017487F /* DeliveryUncertaintyRecoveryViewModel.swift */; }; - C1F67ECA27975F360017487F /* OmniBLESettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EC227975F360017487F /* OmniBLESettingsViewModel.swift */; }; - C1F67ECB27975F360017487F /* PodLifeState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EC327975F360017487F /* PodLifeState.swift */; }; - C1F67EDA27979E400017487F /* PumpManagerAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67ED927979E400017487F /* PumpManagerAlert.swift */; }; - C1F67EDC2797A03A0017487F /* PendingCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EDB2797A03A0017487F /* PendingCommand.swift */; }; - C1F67EDE2797AFF10017487F /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EDD2797AFF10017487F /* Image.swift */; }; - C1F67EE02797B1EF0017487F /* OmniBLEHUDProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EDF2797B1EF0017487F /* OmniBLEHUDProvider.swift */; }; - C1F67EE227985F580017487F /* ReservoirLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F67EE127985F580017487F /* ReservoirLevel.swift */; }; - D800CF1927E682E90090EADB /* ZeroBasalScheduleTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D800CF1827E682E90090EADB /* ZeroBasalScheduleTest.swift */; }; - D802CCFC27DD97210072E3A1 /* AcknowledgeAlertsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D802CCFB27DD97210072E3A1 /* AcknowledgeAlertsTests.swift */; }; - D802CCFE27DD98AF0072E3A1 /* BolusTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D802CCFD27DD98AF0072E3A1 /* BolusTests.swift */; }; - D802CD0027DD98B80072E3A1 /* MessageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D802CCFF27DD98B80072E3A1 /* MessageTests.swift */; }; - D802CD0627DD98C10072E3A1 /* PodInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D802CD0127DD98C10072E3A1 /* PodInfoTests.swift */; }; - D802CD0727DD98C10072E3A1 /* PodStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D802CD0227DD98C10072E3A1 /* PodStateTests.swift */; }; - D802CD0827DD98C10072E3A1 /* StatusTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D802CD0327DD98C10072E3A1 /* StatusTests.swift */; }; - D802CD0927DD98C10072E3A1 /* PodCommsSessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D802CD0427DD98C10072E3A1 /* PodCommsSessionTests.swift */; }; - D802CD0A27DD98C10072E3A1 /* TempBasalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D802CD0527DD98C10072E3A1 /* TempBasalTests.swift */; }; - D802CD1027DD99AB0072E3A1 /* CRC16Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D802CD0F27DD99AB0072E3A1 /* CRC16Tests.swift */; }; - D802CD1227DD9AE10072E3A1 /* BasalScheduleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D802CD1127DD9AE10072E3A1 /* BasalScheduleTests.swift */; }; - D845A1372AF89F5500EA0853 /* ActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D845A1362AF89F5500EA0853 /* ActivityView.swift */; }; - D845A1392AF89F6300EA0853 /* FirstAppear.swift in Sources */ = {isa = PBXBuildFile; fileRef = D845A1382AF89F6300EA0853 /* FirstAppear.swift */; }; - D845A13B2AF89F7100EA0853 /* PlayTestBeepsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D845A13A2AF89F7100EA0853 /* PlayTestBeepsView.swift */; }; - D845A13F2AF89F8400EA0853 /* ReadPodStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D845A13C2AF89F8400EA0853 /* ReadPodStatusView.swift */; }; - D845A1402AF89F8400EA0853 /* ReadPulseLogView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D845A13D2AF89F8400EA0853 /* ReadPulseLogView.swift */; }; - D845A1412AF89F8400EA0853 /* PumpManagerDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D845A13E2AF89F8400EA0853 /* PumpManagerDetailsView.swift */; }; - D845A1432AF89F9200EA0853 /* SilencePodSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D845A1422AF89F9200EA0853 /* SilencePodSelectionView.swift */; }; - D8896C6227890E6B00E09A96 /* DetailedStatus+OmniBLE.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8896C6127890E6B00E09A96 /* DetailedStatus+OmniBLE.swift */; }; - D895BF5B275DE64000D51FC7 /* StringLengthPrefixEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = D895BF5A275DE64000D51FC7 /* StringLengthPrefixEncoding.swift */; }; - D897B06B29347ED500FDB009 /* BolusDeliveryTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D897B06A29347ED500FDB009 /* BolusDeliveryTable.swift */; }; - D897B06D29347EE500FDB009 /* InsulinTableEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = D897B06C29347EE500FDB009 /* InsulinTableEntry.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 84752E8D26ED0FFE009FD801 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 84752E7926ED0FFE009FD801 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 84752E8126ED0FFE009FD801; - remoteInfo = OmniBLE; - }; - C187C19F279086FF006E3557 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 84752E7926ED0FFE009FD801 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 84752E8126ED0FFE009FD801; - remoteInfo = OmniBLE; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - C1D27A1627908DCF00C41EBA /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - C1D27A1727908DE500C41EBA /* OmniBLE.framework in CopyFiles */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1016324C27137B1E007A3BC2 /* BluetoothManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothManager.swift; sourceTree = ""; }; - 1016325127185EE4007A3BC2 /* BeepType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeepType.swift; sourceTree = ""; }; - 1016325227185EE4007A3BC2 /* FaultEventCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaultEventCode.swift; sourceTree = ""; }; - 1016325327185EE4007A3BC2 /* Pod.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Pod.swift; sourceTree = ""; }; - 1016325427185EE4007A3BC2 /* BasalDeliveryTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasalDeliveryTable.swift; sourceTree = ""; }; - 1016325527185EE4007A3BC2 /* AlertSlot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertSlot.swift; sourceTree = ""; }; - 1016325627185EE4007A3BC2 /* PodProgressStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodProgressStatus.swift; sourceTree = ""; }; - 1016325727185EE4007A3BC2 /* BasalSchedule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasalSchedule.swift; sourceTree = ""; }; - 1016325827185EE4007A3BC2 /* UnfinalizedDose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnfinalizedDose.swift; sourceTree = ""; }; - 102111402709462300784F13 /* PodState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodState.swift; sourceTree = ""; }; - 102111412709462300784F13 /* PodInsulinMeasurements.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodInsulinMeasurements.swift; sourceTree = ""; }; - 102111422709462300784F13 /* PodCommsSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodCommsSession.swift; sourceTree = ""; }; - 102111432709462300784F13 /* PodDoseProgressEstimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodDoseProgressEstimator.swift; sourceTree = ""; }; - 102111442709462300784F13 /* BasalSchedule+LoopKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BasalSchedule+LoopKit.swift"; sourceTree = ""; }; - 1021114C2709467400784F13 /* PodComms.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodComms.swift; sourceTree = ""; }; - 1024E32A27446DB000DE01F2 /* MessagePacket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePacket.swift; sourceTree = ""; }; - 1024E32C2746083800DE01F2 /* EapSqn.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EapSqn.swift; sourceTree = ""; }; - 10289E67271B2A08000339E6 /* NumberFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberFormatter.swift; sourceTree = ""; }; - 10289E69271B2A3E000339E6 /* IdentifiableClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentifiableClass.swift; sourceTree = ""; }; - 10289E6B27308746000339E6 /* BluetoothServices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothServices.swift; sourceTree = ""; }; - 10289E6D27309327000339E6 /* CBPeripheral.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CBPeripheral.swift; sourceTree = ""; }; - 10289E7527347C69000339E6 /* Nonce.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Nonce.swift; sourceTree = ""; }; - 10289E772734D10C000339E6 /* EnDecrypt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnDecrypt.swift; sourceTree = ""; }; - 10289E7A2739F886000339E6 /* EapMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EapMessage.swift; sourceTree = ""; }; - 10289E7C2739F893000339E6 /* Milenage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Milenage.swift; sourceTree = ""; }; - 10289E7E2739F8A1000339E6 /* EapAkaAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EapAkaAttribute.swift; sourceTree = ""; }; - 10289E802739F8E4000339E6 /* SessionKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionKeys.swift; sourceTree = ""; }; - 10289E822739F917000339E6 /* SessionEstablisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionEstablisher.swift; sourceTree = ""; }; - 1029AE4627094D0E00B7F5B6 /* OmniBLEPumpManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OmniBLEPumpManager.swift; sourceTree = ""; }; - 1029AE4727094D0E00B7F5B6 /* OmniBLEPumpManagerState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OmniBLEPumpManagerState.swift; sourceTree = ""; }; - 1029AE4A27094DDC00B7F5B6 /* OmniBLEPumpManager+UI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OmniBLEPumpManager+UI.swift"; sourceTree = ""; }; - 1029AE4E27094E1900B7F5B6 /* OmniBLEUI.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = OmniBLEUI.xcassets; sourceTree = ""; }; - 10389A0426FF7841002115E9 /* PodInfoPulseLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodInfoPulseLog.swift; sourceTree = ""; }; - 10389A0526FF7841002115E9 /* VersionResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionResponse.swift; sourceTree = ""; }; - 10389A0626FF7841002115E9 /* PodInfoActivationTime.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodInfoActivationTime.swift; sourceTree = ""; }; - 10389A0726FF7841002115E9 /* TempBasalExtraCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TempBasalExtraCommand.swift; sourceTree = ""; }; - 10389A0826FF7841002115E9 /* DeactivatePodCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeactivatePodCommand.swift; sourceTree = ""; }; - 10389A0926FF7841002115E9 /* AcknowledgeAlertCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AcknowledgeAlertCommand.swift; sourceTree = ""; }; - 10389A0A26FF7841002115E9 /* PodInfoConfiguredAlerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodInfoConfiguredAlerts.swift; sourceTree = ""; }; - 10389A0B26FF7841002115E9 /* MessageBlock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageBlock.swift; sourceTree = ""; }; - 10389A0C26FF7841002115E9 /* PlaceholderMessageBlock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlaceholderMessageBlock.swift; sourceTree = ""; }; - 10389A0D26FF7841002115E9 /* PodInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodInfo.swift; sourceTree = ""; }; - 10389A0E26FF7841002115E9 /* BolusExtraCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusExtraCommand.swift; sourceTree = ""; }; - 10389A0F26FF7841002115E9 /* FaultConfigCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaultConfigCommand.swift; sourceTree = ""; }; - 10389A1026FF7841002115E9 /* PodInfoPulseLogPlus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodInfoPulseLogPlus.swift; sourceTree = ""; }; - 10389A1126FF7841002115E9 /* StatusResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusResponse.swift; sourceTree = ""; }; - 10389A1226FF7841002115E9 /* GetStatusCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetStatusCommand.swift; sourceTree = ""; }; - 10389A1326FF7841002115E9 /* BasalScheduleExtraCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasalScheduleExtraCommand.swift; sourceTree = ""; }; - 10389A1426FF7841002115E9 /* CancelDeliveryCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CancelDeliveryCommand.swift; sourceTree = ""; }; - 10389A1526FF7841002115E9 /* AssignAddressCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssignAddressCommand.swift; sourceTree = ""; }; - 10389A1626FF7841002115E9 /* BeepConfigCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeepConfigCommand.swift; sourceTree = ""; }; - 10389A1726FF7841002115E9 /* ErrorResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorResponse.swift; sourceTree = ""; }; - 10389A1826FF7841002115E9 /* SetupPodCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetupPodCommand.swift; sourceTree = ""; }; - 10389A1926FF7841002115E9 /* DetailedStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailedStatus.swift; sourceTree = ""; }; - 10389A1A26FF7841002115E9 /* PodInfoResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodInfoResponse.swift; sourceTree = ""; }; - 10389A1B26FF7841002115E9 /* SetInsulinScheduleCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetInsulinScheduleCommand.swift; sourceTree = ""; }; - 10389A1C26FF7841002115E9 /* ConfigureAlertsCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigureAlertsCommand.swift; sourceTree = ""; }; - 10389A1D26FF7841002115E9 /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = ""; }; - 10389A2026FF7841002115E9 /* CRC16.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CRC16.swift; sourceTree = ""; }; - 10389A2226FF7841002115E9 /* MessageTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageTransport.swift; sourceTree = ""; }; - 1909F73C2A127FEF00F145A2 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = ""; }; - 1909F73D2A127FF300F145A2 /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/Localizable.strings"; sourceTree = ""; }; - 1909F73E2A127FF800F145A2 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6532A06F17800212AC9 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6542A06F17800212AC9 /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6552A06F17800212AC9 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6562A06F17800212AC9 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - 191DB6572A06F17800212AC9 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6582A06F17800212AC9 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6592A06F17800212AC9 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = ""; }; - 191DB65A2A06F17800212AC9 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - 191DB65B2A06F17800212AC9 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - 191DB65C2A06F17800212AC9 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - 191DB65D2A06F17800212AC9 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - 191DB65E2A06F17800212AC9 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - 191DB65F2A06F17800212AC9 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6602A06F17800212AC9 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6612A06F17800212AC9 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6622A06F17800212AC9 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - 191DB6632A06F17800212AC9 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6642A06F17800212AC9 /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6652A06F17800212AC9 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6662A06F17800212AC9 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6672A06F17800212AC9 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6682A06F17800212AC9 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - 191DB6692A06F17800212AC9 /* bn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bn; path = bn.lproj/Localizable.strings; sourceTree = ""; }; - 191DB66A2A06F17800212AC9 /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/Localizable.strings"; sourceTree = ""; }; - 191DB66B2A06F17800212AC9 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - 191DB66C2A06F17800212AC9 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = ""; }; - 193F1E492B44C21100525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; - 193F1E4A2B44C21100525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; - 196A6F222AFFFD1200E3C089 /* SilencePodPreference.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SilencePodPreference.swift; sourceTree = ""; }; - 4B23AA6328D909E2009B453B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - 4B23AA6428D909E7009B453B /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - 4B23AA6528D909E9009B453B /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - 4B23AA6628D909EC009B453B /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - 4B23AA6728D909EE009B453B /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - 4B23AA6828D909F1009B453B /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - 4B23AA6A28D909F5009B453B /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - 4B23AA6B28D909F7009B453B /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - 4B23AA6C28D909FA009B453B /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - 4B23AA6D28D909FD009B453B /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - 4B23AA6E28D909FF009B453B /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - 4B23AA6F28D90A01009B453B /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - 4B23AA7028D90A03009B453B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - 4B23AA7128D90A06009B453B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - 4B23AA7228D90A08009B453B /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - 4B23AA7428D90A0D009B453B /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - 4B67E2D4289B4EDB002D92AF /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - 84752E8226ED0FFE009FD801 /* OmniBLE.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OmniBLE.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 84752E8526ED0FFE009FD801 /* OmniBLE.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OmniBLE.h; sourceTree = ""; }; - 84752E8626ED0FFE009FD801 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 84752E8B26ED0FFE009FD801 /* OmniBLETests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OmniBLETests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 84752E9226ED0FFE009FD801 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 84752EBF26ED13F5009FD801 /* Id.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Id.swift; sourceTree = ""; }; - 84752EC126ED13F5009FD801 /* X25519KeyGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = X25519KeyGenerator.swift; sourceTree = ""; }; - 84752EC226ED13F5009FD801 /* OmniRandomByteGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OmniRandomByteGenerator.swift; sourceTree = ""; }; - 84752EC826ED13F5009FD801 /* Ids.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Ids.swift; sourceTree = ""; }; - 84752EC926ED13F5009FD801 /* PeripheralManagerError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeripheralManagerError.swift; sourceTree = ""; }; - 84752ECA26ED13F5009FD801 /* PeripheralManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeripheralManager.swift; sourceTree = ""; }; - 84752ECB26ED13F5009FD801 /* PodProtocolError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodProtocolError.swift; sourceTree = ""; }; - 84752ECD26ED13F5009FD801 /* PayloadSplitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayloadSplitter.swift; sourceTree = ""; }; - 84752ECE26ED13F5009FD801 /* PayloadJoiner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayloadJoiner.swift; sourceTree = ""; }; - 84752ECF26ED13F5009FD801 /* BLEPacket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BLEPacket.swift; sourceTree = ""; }; - 84752ED226ED13F5009FD801 /* KeyExchange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyExchange.swift; sourceTree = ""; }; - 84752ED326ED13F5009FD801 /* LTKExchanger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTKExchanger.swift; sourceTree = ""; }; - 84752ED426ED13F5009FD801 /* PairResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PairResult.swift; sourceTree = ""; }; - 84752ED526ED13F5009FD801 /* PairMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PairMessage.swift; sourceTree = ""; }; - 847530F426ED65DD009FD801 /* LoopKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LoopKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 847530F526ED65DD009FD801 /* LoopKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LoopKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 8475311F26ED838A009FD801 /* PodLifeHUDView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodLifeHUDView.swift; sourceTree = ""; }; - 8475312426ED838A009FD801 /* PodLifeHUDView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PodLifeHUDView.xib; sourceTree = ""; }; - 8475314626EDA193009FD801 /* TimeInterval.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeInterval.swift; sourceTree = ""; }; - 8475314A26EDA193009FD801 /* LocalizedString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizedString.swift; sourceTree = ""; }; - 8475314B26EDA193009FD801 /* OSLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; - 8475314C26EDA193009FD801 /* UIColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; }; - 8475314D26EDA193009FD801 /* HKUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKUnit.swift; sourceTree = ""; }; - 8475314E26EDA193009FD801 /* NibLoadable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NibLoadable.swift; sourceTree = ""; }; - 8475314F26EDA193009FD801 /* TimeZone.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeZone.swift; sourceTree = ""; }; - 8475315026EDA193009FD801 /* Data.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; }; - A91B2DEB276E1E5E001B0E95 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - A9D054CA2764FC8200FAFEFB /* HexConversionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HexConversionTests.swift; sourceTree = ""; }; - A9D054CC2764FDB700FAFEFB /* MessagePacketTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePacketTests.swift; sourceTree = ""; }; - A9D054D22765135900FAFEFB /* PayloadSplitterTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayloadSplitterTest.swift; sourceTree = ""; }; - A9D054D427651D2400FAFEFB /* TestUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestUtilities.swift; sourceTree = ""; }; - A9D054D627651D4F00FAFEFB /* PayloadSplitJoinTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayloadSplitJoinTests.swift; sourceTree = ""; }; - A9D054D827651FDE00FAFEFB /* StringLengthPrefixEncodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringLengthPrefixEncodingTests.swift; sourceTree = ""; }; - A9D054DB27655F9C00FAFEFB /* KeyExchangeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyExchangeTests.swift; sourceTree = ""; }; - A9D3492F2764F5780037F77C /* EnDecryptTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnDecryptTests.swift; sourceTree = ""; }; - A9D349312764F5D30037F77C /* PayloadJoinerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayloadJoinerTest.swift; sourceTree = ""; }; - C10D6D6B27A2393800F53D58 /* OmniBLETests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OmniBLETests.swift; sourceTree = ""; }; - C10D6D6D27A2395700F53D58 /* OmniBLEPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OmniBLEPlugin.swift; sourceTree = ""; }; - C121D8D829C7866D00DA0520 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - C15A583029C7866600D3A5A1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; - C187C190278FCEC9006E3557 /* InsulinTypeConfirmation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinTypeConfirmation.swift; sourceTree = ""; }; - C187C197279086A8006E3557 /* OmniBLEPlugin.loopplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OmniBLEPlugin.loopplugin; sourceTree = BUILT_PRODUCTS_DIR; }; - C187C199279086A8006E3557 /* OmniBLEPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OmniBLEPlugin.h; sourceTree = ""; }; - C187C1A2279087A4006E3557 /* OSLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; - C187C1A427908B1C006E3557 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C19E3881298638CE00851444 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - C1C001BE27A2337B00533D35 /* PeripheralManager+OmniBLE.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PeripheralManager+OmniBLE.swift"; sourceTree = ""; }; - C1C001C027A2349D00533D35 /* OmniBLE.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OmniBLE.swift; sourceTree = ""; }; - C1C001C227A2351D00533D35 /* OmniBLEReservoirView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OmniBLEReservoirView.xib; sourceTree = ""; }; - C1C001C327A2351D00533D35 /* OmniBLEReservoirView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OmniBLEReservoirView.swift; sourceTree = ""; }; - C1D27A1A27911E9900C41EBA /* PodAdvertisement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PodAdvertisement.swift; sourceTree = ""; }; - C1DBD512282FF79D009FCF74 /* ManualTempBasalEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualTempBasalEntryView.swift; sourceTree = ""; }; - C1ED1E6F27BAE1A600FED71C /* BeepPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BeepPreference.swift; sourceTree = ""; }; - C1ED1E7127BAE44E00FED71C /* BeepPreferenceSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BeepPreferenceSelectionView.swift; sourceTree = ""; }; - C1F67E7327975B830017487F /* AttachPodView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttachPodView.swift; sourceTree = ""; }; - C1F67E7427975B830017487F /* ScheduledExpirationReminderEditView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScheduledExpirationReminderEditView.swift; sourceTree = ""; }; - C1F67E7627975B830017487F /* TimeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeView.swift; sourceTree = ""; }; - C1F67E7727975B830017487F /* OmniBLESettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OmniBLESettingsView.swift; sourceTree = ""; }; - C1F67E7827975B830017487F /* ExpirationReminderSetupView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExpirationReminderSetupView.swift; sourceTree = ""; }; - C1F67E7927975B830017487F /* DeactivatePodView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeactivatePodView.swift; sourceTree = ""; }; - C1F67E7A27975B830017487F /* BasalStateView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasalStateView.swift; sourceTree = ""; }; - C1F67E7B27975B830017487F /* ExpirationReminderPickerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExpirationReminderPickerView.swift; sourceTree = ""; }; - C1F67E7C27975B830017487F /* LowReservoirReminderSetupView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LowReservoirReminderSetupView.swift; sourceTree = ""; }; - C1F67E7D27975B830017487F /* HUDAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = HUDAssets.xcassets; sourceTree = ""; }; - C1F67E7F27975B830017487F /* PairPodView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PairPodView.swift; sourceTree = ""; }; - C1F67E8027975B830017487F /* CheckInsertedCannulaView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckInsertedCannulaView.swift; sourceTree = ""; }; - C1F67E8127975B830017487F /* NotificationSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationSettingsView.swift; sourceTree = ""; }; - C1F67E8227975B830017487F /* DeliveryUncertaintyRecoveryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeliveryUncertaintyRecoveryView.swift; sourceTree = ""; }; - C1F67E8427975B830017487F /* UncertaintyRecoveredView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UncertaintyRecoveredView.swift; sourceTree = ""; }; - C1F67E8527975B830017487F /* InsertCannulaView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsertCannulaView.swift; sourceTree = ""; }; - C1F67E8627975B830017487F /* LowReservoirReminderEditView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LowReservoirReminderEditView.swift; sourceTree = ""; }; - C1F67E8727975B830017487F /* SetupCompleteView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetupCompleteView.swift; sourceTree = ""; }; - C1F67E8827975B830017487F /* PodSetupView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodSetupView.swift; sourceTree = ""; }; - C1F67E8A27975B830017487F /* PodDetailsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodDetailsView.swift; sourceTree = ""; }; - C1F67EA327975CCA0017487F /* DashUICoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashUICoordinator.swift; sourceTree = ""; }; - C1F67EB327975E710017487F /* RoundedCard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoundedCard.swift; sourceTree = ""; }; - C1F67EB427975E710017487F /* LeadingImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeadingImage.swift; sourceTree = ""; }; - C1F67EB527975E710017487F /* ErrorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = ""; }; - C1F67EB927975EB70017487F /* FrameworkLocalText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrameworkLocalText.swift; sourceTree = ""; }; - C1F67EBD27975F360017487F /* InsertCannulaViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsertCannulaViewModel.swift; sourceTree = ""; }; - C1F67EBE27975F360017487F /* PairPodViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PairPodViewModel.swift; sourceTree = ""; }; - C1F67EC027975F360017487F /* DeactivatePodViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeactivatePodViewModel.swift; sourceTree = ""; }; - C1F67EC127975F360017487F /* DeliveryUncertaintyRecoveryViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeliveryUncertaintyRecoveryViewModel.swift; sourceTree = ""; }; - C1F67EC227975F360017487F /* OmniBLESettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OmniBLESettingsViewModel.swift; sourceTree = ""; }; - C1F67EC327975F360017487F /* PodLifeState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodLifeState.swift; sourceTree = ""; }; - C1F67ED927979E400017487F /* PumpManagerAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpManagerAlert.swift; sourceTree = ""; }; - C1F67EDB2797A03A0017487F /* PendingCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PendingCommand.swift; sourceTree = ""; }; - C1F67EDD2797AFF10017487F /* Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Image.swift; sourceTree = ""; }; - C1F67EDF2797B1EF0017487F /* OmniBLEHUDProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmniBLEHUDProvider.swift; sourceTree = ""; }; - C1F67EE127985F580017487F /* ReservoirLevel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReservoirLevel.swift; sourceTree = ""; }; - C1FAB5C729C786B000D25073 /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = ""; }; - C1FDCC1029C786F90056E652 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1FF3D5229C786A900BDC1EC /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; - D800CF1827E682E90090EADB /* ZeroBasalScheduleTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZeroBasalScheduleTest.swift; sourceTree = ""; }; - D802CCFB27DD97210072E3A1 /* AcknowledgeAlertsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AcknowledgeAlertsTests.swift; sourceTree = ""; }; - D802CCFD27DD98AF0072E3A1 /* BolusTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusTests.swift; sourceTree = ""; }; - D802CCFF27DD98B80072E3A1 /* MessageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageTests.swift; sourceTree = ""; }; - D802CD0127DD98C10072E3A1 /* PodInfoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodInfoTests.swift; sourceTree = ""; }; - D802CD0227DD98C10072E3A1 /* PodStateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodStateTests.swift; sourceTree = ""; }; - D802CD0327DD98C10072E3A1 /* StatusTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusTests.swift; sourceTree = ""; }; - D802CD0427DD98C10072E3A1 /* PodCommsSessionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PodCommsSessionTests.swift; sourceTree = ""; }; - D802CD0527DD98C10072E3A1 /* TempBasalTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TempBasalTests.swift; sourceTree = ""; }; - D802CD0F27DD99AB0072E3A1 /* CRC16Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CRC16Tests.swift; sourceTree = ""; }; - D802CD1127DD9AE10072E3A1 /* BasalScheduleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasalScheduleTests.swift; sourceTree = ""; }; - D845A1362AF89F5500EA0853 /* ActivityView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivityView.swift; sourceTree = ""; }; - D845A1382AF89F6300EA0853 /* FirstAppear.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirstAppear.swift; sourceTree = ""; }; - D845A13A2AF89F7100EA0853 /* PlayTestBeepsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayTestBeepsView.swift; sourceTree = ""; }; - D845A13C2AF89F8400EA0853 /* ReadPodStatusView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadPodStatusView.swift; sourceTree = ""; }; - D845A13D2AF89F8400EA0853 /* ReadPulseLogView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadPulseLogView.swift; sourceTree = ""; }; - D845A13E2AF89F8400EA0853 /* PumpManagerDetailsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpManagerDetailsView.swift; sourceTree = ""; }; - D845A1422AF89F9200EA0853 /* SilencePodSelectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SilencePodSelectionView.swift; sourceTree = ""; }; - D8896C6127890E6B00E09A96 /* DetailedStatus+OmniBLE.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DetailedStatus+OmniBLE.swift"; sourceTree = ""; }; - D895BF5A275DE64000D51FC7 /* StringLengthPrefixEncoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringLengthPrefixEncoding.swift; sourceTree = ""; }; - D897B06A29347ED500FDB009 /* BolusDeliveryTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusDeliveryTable.swift; sourceTree = ""; }; - D897B06C29347EE500FDB009 /* InsulinTableEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsulinTableEntry.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 84752E7F26ED0FFE009FD801 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 847530F626ED65DD009FD801 /* LoopKit.framework in Frameworks */, - 8475306E26ED15DE009FD801 /* CryptoSwift in Frameworks */, - 847530F826ED65DD009FD801 /* LoopKitUI.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 84752E8826ED0FFE009FD801 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C187C194279086A8006E3557 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C1D27A1527908DC600C41EBA /* OmniBLE.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 1016325027185EE4007A3BC2 /* OmnipodCommon */ = { - isa = PBXGroup; - children = ( - 1016325527185EE4007A3BC2 /* AlertSlot.swift */, - 1016325427185EE4007A3BC2 /* BasalDeliveryTable.swift */, - 102111442709462300784F13 /* BasalSchedule+LoopKit.swift */, - 1016325727185EE4007A3BC2 /* BasalSchedule.swift */, - C1ED1E6F27BAE1A600FED71C /* BeepPreference.swift */, - 1016325127185EE4007A3BC2 /* BeepType.swift */, - D897B06A29347ED500FDB009 /* BolusDeliveryTable.swift */, - 10389A2026FF7841002115E9 /* CRC16.swift */, - 1016325227185EE4007A3BC2 /* FaultEventCode.swift */, - D897B06C29347EE500FDB009 /* InsulinTableEntry.swift */, - 10389A1D26FF7841002115E9 /* Message.swift */, - 10389A0326FF7841002115E9 /* MessageBlocks */, - C1F67EDB2797A03A0017487F /* PendingCommand.swift */, - 1016325327185EE4007A3BC2 /* Pod.swift */, - 102111432709462300784F13 /* PodDoseProgressEstimator.swift */, - 102111412709462300784F13 /* PodInsulinMeasurements.swift */, - 1016325627185EE4007A3BC2 /* PodProgressStatus.swift */, - C1F67ED927979E400017487F /* PumpManagerAlert.swift */, - C1F67EE127985F580017487F /* ReservoirLevel.swift */, - 196A6F222AFFFD1200E3C089 /* SilencePodPreference.swift */, - 1016325827185EE4007A3BC2 /* UnfinalizedDose.swift */, - ); - path = OmnipodCommon; - sourceTree = ""; - }; - 10289E7427347C5B000339E6 /* EnDecrypt */ = { - isa = PBXGroup; - children = ( - 10289E7527347C69000339E6 /* Nonce.swift */, - 10289E772734D10C000339E6 /* EnDecrypt.swift */, - ); - path = EnDecrypt; - sourceTree = ""; - }; - 10289E792739F84C000339E6 /* Session */ = { - isa = PBXGroup; - children = ( - 10289E7E2739F8A1000339E6 /* EapAkaAttribute.swift */, - 10289E7A2739F886000339E6 /* EapMessage.swift */, - 1024E32C2746083800DE01F2 /* EapSqn.swift */, - 10289E7C2739F893000339E6 /* Milenage.swift */, - 10289E822739F917000339E6 /* SessionEstablisher.swift */, - 10289E802739F8E4000339E6 /* SessionKeys.swift */, - ); - path = Session; - sourceTree = ""; - }; - 10389A0326FF7841002115E9 /* MessageBlocks */ = { - isa = PBXGroup; - children = ( - 10389A0926FF7841002115E9 /* AcknowledgeAlertCommand.swift */, - 10389A1526FF7841002115E9 /* AssignAddressCommand.swift */, - 10389A1326FF7841002115E9 /* BasalScheduleExtraCommand.swift */, - 10389A1626FF7841002115E9 /* BeepConfigCommand.swift */, - 10389A0E26FF7841002115E9 /* BolusExtraCommand.swift */, - 10389A1426FF7841002115E9 /* CancelDeliveryCommand.swift */, - 10389A1C26FF7841002115E9 /* ConfigureAlertsCommand.swift */, - 10389A0826FF7841002115E9 /* DeactivatePodCommand.swift */, - 10389A1926FF7841002115E9 /* DetailedStatus.swift */, - 10389A1726FF7841002115E9 /* ErrorResponse.swift */, - 10389A0F26FF7841002115E9 /* FaultConfigCommand.swift */, - 10389A1226FF7841002115E9 /* GetStatusCommand.swift */, - 10389A0B26FF7841002115E9 /* MessageBlock.swift */, - 10389A0C26FF7841002115E9 /* PlaceholderMessageBlock.swift */, - 10389A0D26FF7841002115E9 /* PodInfo.swift */, - 10389A0626FF7841002115E9 /* PodInfoActivationTime.swift */, - 10389A0A26FF7841002115E9 /* PodInfoConfiguredAlerts.swift */, - 10389A0426FF7841002115E9 /* PodInfoPulseLog.swift */, - 10389A1026FF7841002115E9 /* PodInfoPulseLogPlus.swift */, - 10389A1A26FF7841002115E9 /* PodInfoResponse.swift */, - 10389A1B26FF7841002115E9 /* SetInsulinScheduleCommand.swift */, - 10389A1826FF7841002115E9 /* SetupPodCommand.swift */, - 10389A1126FF7841002115E9 /* StatusResponse.swift */, - 10389A0726FF7841002115E9 /* TempBasalExtraCommand.swift */, - 10389A0526FF7841002115E9 /* VersionResponse.swift */, - ); - path = MessageBlocks; - sourceTree = ""; - }; - 191DB6512A06F17800212AC9 /* Localizations */ = { - isa = PBXGroup; - children = ( - 191DB6522A06F17800212AC9 /* Localizable.strings */, - ); - path = Localizations; - sourceTree = ""; - }; - 84752E7826ED0FFE009FD801 = { - isa = PBXGroup; - children = ( - 191DB6512A06F17800212AC9 /* Localizations */, - A91B2DEB276E1E5E001B0E95 /* README.md */, - 84752EE926ED1402009FD801 /* Common */, - 84752E8426ED0FFE009FD801 /* OmniBLE */, - 84752E8F26ED0FFE009FD801 /* OmniBLETests */, - C187C198279086A8006E3557 /* OmniBLEPlugin */, - 84752E8326ED0FFE009FD801 /* Products */, - 84752E9C26ED10A0009FD801 /* Frameworks */, - ); - sourceTree = ""; - }; - 84752E8326ED0FFE009FD801 /* Products */ = { - isa = PBXGroup; - children = ( - 84752E8226ED0FFE009FD801 /* OmniBLE.framework */, - 84752E8B26ED0FFE009FD801 /* OmniBLETests.xctest */, - C187C197279086A8006E3557 /* OmniBLEPlugin.loopplugin */, - ); - name = Products; - sourceTree = ""; - }; - 84752E8426ED0FFE009FD801 /* OmniBLE */ = { - isa = PBXGroup; - children = ( - 84752EBE26ED13F5009FD801 /* Bluetooth */, - 1016325027185EE4007A3BC2 /* OmnipodCommon */, - 84752EAD26ED11A4009FD801 /* PumpManager */, - 8475311D26ED8246009FD801 /* PumpManagerUI */, - 84752E8526ED0FFE009FD801 /* OmniBLE.h */, - 84752E8626ED0FFE009FD801 /* Info.plist */, - 4B67E2D3289B4EDB002D92AF /* Localizable.strings */, - ); - path = OmniBLE; - sourceTree = ""; - }; - 84752E8F26ED0FFE009FD801 /* OmniBLETests */ = { - isa = PBXGroup; - children = ( - D802CCFB27DD97210072E3A1 /* AcknowledgeAlertsTests.swift */, - D802CD1127DD9AE10072E3A1 /* BasalScheduleTests.swift */, - D802CCFD27DD98AF0072E3A1 /* BolusTests.swift */, - D802CD0F27DD99AB0072E3A1 /* CRC16Tests.swift */, - A9D054CE2765131300FAFEFB /* Driver */, - A9D054CA2764FC8200FAFEFB /* HexConversionTests.swift */, - 84752E9226ED0FFE009FD801 /* Info.plist */, - D802CCFF27DD98B80072E3A1 /* MessageTests.swift */, - C10D6D6B27A2393800F53D58 /* OmniBLETests.swift */, - D802CD0427DD98C10072E3A1 /* PodCommsSessionTests.swift */, - D802CD0127DD98C10072E3A1 /* PodInfoTests.swift */, - D802CD0227DD98C10072E3A1 /* PodStateTests.swift */, - D802CD0327DD98C10072E3A1 /* StatusTests.swift */, - D802CD0527DD98C10072E3A1 /* TempBasalTests.swift */, - A9D054D427651D2400FAFEFB /* TestUtilities.swift */, - D800CF1827E682E90090EADB /* ZeroBasalScheduleTest.swift */, - ); - path = OmniBLETests; - sourceTree = ""; - }; - 84752E9C26ED10A0009FD801 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 847530F426ED65DD009FD801 /* LoopKit.framework */, - 847530F526ED65DD009FD801 /* LoopKitUI.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 84752EAD26ED11A4009FD801 /* PumpManager */ = { - isa = PBXGroup; - children = ( - D8896C6127890E6B00E09A96 /* DetailedStatus+OmniBLE.swift */, - 10389A2226FF7841002115E9 /* MessageTransport.swift */, - C1C001C027A2349D00533D35 /* OmniBLE.swift */, - 1029AE4627094D0E00B7F5B6 /* OmniBLEPumpManager.swift */, - 1029AE4727094D0E00B7F5B6 /* OmniBLEPumpManagerState.swift */, - C1D27A1A27911E9900C41EBA /* PodAdvertisement.swift */, - 1021114C2709467400784F13 /* PodComms.swift */, - 102111422709462300784F13 /* PodCommsSession.swift */, - 102111402709462300784F13 /* PodState.swift */, - ); - path = PumpManager; - sourceTree = ""; - }; - 84752EBE26ED13F5009FD801 /* Bluetooth */ = { - isa = PBXGroup; - children = ( - C1C001BE27A2337B00533D35 /* PeripheralManager+OmniBLE.swift */, - 84752ECB26ED13F5009FD801 /* PodProtocolError.swift */, - 1016324C27137B1E007A3BC2 /* BluetoothManager.swift */, - 10289E6B27308746000339E6 /* BluetoothServices.swift */, - 10289E6D27309327000339E6 /* CBPeripheral.swift */, - 10289E7427347C5B000339E6 /* EnDecrypt */, - 84752EBF26ED13F5009FD801 /* Id.swift */, - 84752EC826ED13F5009FD801 /* Ids.swift */, - 1024E32A27446DB000DE01F2 /* MessagePacket.swift */, - 84752ECA26ED13F5009FD801 /* PeripheralManager.swift */, - 84752EC926ED13F5009FD801 /* PeripheralManagerError.swift */, - D895BF5A275DE64000D51FC7 /* StringLengthPrefixEncoding.swift */, - 84752ECC26ED13F5009FD801 /* Packet */, - 84752ED126ED13F5009FD801 /* Pair */, - 10289E792739F84C000339E6 /* Session */, - 84752EC026ED13F5009FD801 /* Util */, - ); - path = Bluetooth; - sourceTree = ""; - }; - 84752EC026ED13F5009FD801 /* Util */ = { - isa = PBXGroup; - children = ( - 84752EC226ED13F5009FD801 /* OmniRandomByteGenerator.swift */, - 84752EC126ED13F5009FD801 /* X25519KeyGenerator.swift */, - ); - path = Util; - sourceTree = ""; - }; - 84752ECC26ED13F5009FD801 /* Packet */ = { - isa = PBXGroup; - children = ( - 84752ECF26ED13F5009FD801 /* BLEPacket.swift */, - 84752ECE26ED13F5009FD801 /* PayloadJoiner.swift */, - 84752ECD26ED13F5009FD801 /* PayloadSplitter.swift */, - ); - path = Packet; - sourceTree = ""; - }; - 84752ED126ED13F5009FD801 /* Pair */ = { - isa = PBXGroup; - children = ( - 84752ED226ED13F5009FD801 /* KeyExchange.swift */, - 84752ED326ED13F5009FD801 /* LTKExchanger.swift */, - 84752ED526ED13F5009FD801 /* PairMessage.swift */, - 84752ED426ED13F5009FD801 /* PairResult.swift */, - ); - path = Pair; - sourceTree = ""; - }; - 84752EE926ED1402009FD801 /* Common */ = { - isa = PBXGroup; - children = ( - 8475315026EDA193009FD801 /* Data.swift */, - 8475314D26EDA193009FD801 /* HKUnit.swift */, - 10289E69271B2A3E000339E6 /* IdentifiableClass.swift */, - 8475314A26EDA193009FD801 /* LocalizedString.swift */, - 8475314E26EDA193009FD801 /* NibLoadable.swift */, - 10289E67271B2A08000339E6 /* NumberFormatter.swift */, - 8475314B26EDA193009FD801 /* OSLog.swift */, - 8475314626EDA193009FD801 /* TimeInterval.swift */, - 8475314F26EDA193009FD801 /* TimeZone.swift */, - 8475314C26EDA193009FD801 /* UIColor.swift */, - C1F67EB927975EB70017487F /* FrameworkLocalText.swift */, - C1F67EDD2797AFF10017487F /* Image.swift */, - ); - path = Common; - sourceTree = ""; - }; - 8475311D26ED8246009FD801 /* PumpManagerUI */ = { - isa = PBXGroup; - children = ( - C1F67EDF2797B1EF0017487F /* OmniBLEHUDProvider.swift */, - 1029AE4A27094DDC00B7F5B6 /* OmniBLEPumpManager+UI.swift */, - 1029AE4E27094E1900B7F5B6 /* OmniBLEUI.xcassets */, - 8475312626ED838A009FD801 /* ViewControllers */, - C1F67EBB27975F060017487F /* ViewModels */, - 8475311E26ED838A009FD801 /* Views */, - ); - path = PumpManagerUI; - sourceTree = ""; - }; - 8475311E26ED838A009FD801 /* Views */ = { - isa = PBXGroup; - children = ( - D845A1362AF89F5500EA0853 /* ActivityView.swift */, - C1F67E7327975B830017487F /* AttachPodView.swift */, - C1F67E7A27975B830017487F /* BasalStateView.swift */, - C1ED1E7127BAE44E00FED71C /* BeepPreferenceSelectionView.swift */, - C1F67E8027975B830017487F /* CheckInsertedCannulaView.swift */, - C1F67E7927975B830017487F /* DeactivatePodView.swift */, - C1F67E8227975B830017487F /* DeliveryUncertaintyRecoveryView.swift */, - C1F67EB227975E710017487F /* DesignElements */, - C1F67E7B27975B830017487F /* ExpirationReminderPickerView.swift */, - C1F67E7827975B830017487F /* ExpirationReminderSetupView.swift */, - D845A1382AF89F6300EA0853 /* FirstAppear.swift */, - C1F67E7D27975B830017487F /* HUDAssets.xcassets */, - C1F67E8527975B830017487F /* InsertCannulaView.swift */, - C187C190278FCEC9006E3557 /* InsulinTypeConfirmation.swift */, - C1F67E8627975B830017487F /* LowReservoirReminderEditView.swift */, - C1F67E7C27975B830017487F /* LowReservoirReminderSetupView.swift */, - C1DBD512282FF79D009FCF74 /* ManualTempBasalEntryView.swift */, - C1F67E8127975B830017487F /* NotificationSettingsView.swift */, - C1C001C327A2351D00533D35 /* OmniBLEReservoirView.swift */, - C1C001C227A2351D00533D35 /* OmniBLEReservoirView.xib */, - C1F67E7727975B830017487F /* OmniBLESettingsView.swift */, - C1F67E7F27975B830017487F /* PairPodView.swift */, - D845A13A2AF89F7100EA0853 /* PlayTestBeepsView.swift */, - C1F67E8A27975B830017487F /* PodDetailsView.swift */, - 8475311F26ED838A009FD801 /* PodLifeHUDView.swift */, - 8475312426ED838A009FD801 /* PodLifeHUDView.xib */, - C1F67E8827975B830017487F /* PodSetupView.swift */, - D845A13E2AF89F8400EA0853 /* PumpManagerDetailsView.swift */, - D845A13C2AF89F8400EA0853 /* ReadPodStatusView.swift */, - D845A13D2AF89F8400EA0853 /* ReadPulseLogView.swift */, - C1F67E7427975B830017487F /* ScheduledExpirationReminderEditView.swift */, - C1F67E8727975B830017487F /* SetupCompleteView.swift */, - D845A1422AF89F9200EA0853 /* SilencePodSelectionView.swift */, - C1F67E7627975B830017487F /* TimeView.swift */, - C1F67E8427975B830017487F /* UncertaintyRecoveredView.swift */, - ); - path = Views; - sourceTree = ""; - }; - 8475312626ED838A009FD801 /* ViewControllers */ = { - isa = PBXGroup; - children = ( - C1F67EA327975CCA0017487F /* DashUICoordinator.swift */, - ); - path = ViewControllers; - sourceTree = ""; - }; - A9D054CE2765131300FAFEFB /* Driver */ = { - isa = PBXGroup; - children = ( - A9D054CF2765132000FAFEFB /* Comm */, - ); - path = Driver; - sourceTree = ""; - }; - A9D054CF2765132000FAFEFB /* Comm */ = { - isa = PBXGroup; - children = ( - A9D054D02765132800FAFEFB /* endecrypt */, - A9D054D12765133E00FAFEFB /* message */, - A9D054DA27655F8B00FAFEFB /* pair */, - ); - path = Comm; - sourceTree = ""; - }; - A9D054D02765132800FAFEFB /* endecrypt */ = { - isa = PBXGroup; - children = ( - A9D3492F2764F5780037F77C /* EnDecryptTests.swift */, - ); - path = endecrypt; - sourceTree = ""; - }; - A9D054D12765133E00FAFEFB /* message */ = { - isa = PBXGroup; - children = ( - A9D054CC2764FDB700FAFEFB /* MessagePacketTests.swift */, - A9D349312764F5D30037F77C /* PayloadJoinerTest.swift */, - A9D054D627651D4F00FAFEFB /* PayloadSplitJoinTests.swift */, - A9D054D22765135900FAFEFB /* PayloadSplitterTest.swift */, - A9D054D827651FDE00FAFEFB /* StringLengthPrefixEncodingTests.swift */, - ); - path = message; - sourceTree = ""; - }; - A9D054DA27655F8B00FAFEFB /* pair */ = { - isa = PBXGroup; - children = ( - A9D054DB27655F9C00FAFEFB /* KeyExchangeTests.swift */, - ); - path = pair; - sourceTree = ""; - }; - C187C198279086A8006E3557 /* OmniBLEPlugin */ = { - isa = PBXGroup; - children = ( - C10D6D6D27A2395700F53D58 /* OmniBLEPlugin.swift */, - C187C1A427908B1C006E3557 /* Info.plist */, - C187C1A127908795006E3557 /* Extensions */, - C187C199279086A8006E3557 /* OmniBLEPlugin.h */, - ); - path = OmniBLEPlugin; - sourceTree = ""; - }; - C187C1A127908795006E3557 /* Extensions */ = { - isa = PBXGroup; - children = ( - C187C1A2279087A4006E3557 /* OSLog.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - C1F67EB227975E710017487F /* DesignElements */ = { - isa = PBXGroup; - children = ( - C1F67EB327975E710017487F /* RoundedCard.swift */, - C1F67EB427975E710017487F /* LeadingImage.swift */, - C1F67EB527975E710017487F /* ErrorView.swift */, - ); - path = DesignElements; - sourceTree = ""; - }; - C1F67EBB27975F060017487F /* ViewModels */ = { - isa = PBXGroup; - children = ( - C1F67EC027975F360017487F /* DeactivatePodViewModel.swift */, - C1F67EC127975F360017487F /* DeliveryUncertaintyRecoveryViewModel.swift */, - C1F67EBD27975F360017487F /* InsertCannulaViewModel.swift */, - C1F67EC227975F360017487F /* OmniBLESettingsViewModel.swift */, - C1F67EBE27975F360017487F /* PairPodViewModel.swift */, - C1F67EC327975F360017487F /* PodLifeState.swift */, - ); - path = ViewModels; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 84752E7D26ED0FFE009FD801 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 84752E9326ED0FFE009FD801 /* OmniBLE.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C187C192279086A8006E3557 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - C187C19A279086A8006E3557 /* OmniBLEPlugin.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 84752E8126ED0FFE009FD801 /* OmniBLE */ = { - isa = PBXNativeTarget; - buildConfigurationList = 84752E9626ED0FFE009FD801 /* Build configuration list for PBXNativeTarget "OmniBLE" */; - buildPhases = ( - 84752E7D26ED0FFE009FD801 /* Headers */, - 84752E7E26ED0FFE009FD801 /* Sources */, - 84752E7F26ED0FFE009FD801 /* Frameworks */, - 84752E8026ED0FFE009FD801 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = OmniBLE; - packageProductDependencies = ( - 8475306D26ED15DE009FD801 /* CryptoSwift */, - ); - productName = OmniBLE; - productReference = 84752E8226ED0FFE009FD801 /* OmniBLE.framework */; - productType = "com.apple.product-type.framework"; - }; - 84752E8A26ED0FFE009FD801 /* OmniBLETests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 84752E9926ED0FFE009FD801 /* Build configuration list for PBXNativeTarget "OmniBLETests" */; - buildPhases = ( - 84752E8726ED0FFE009FD801 /* Sources */, - 84752E8826ED0FFE009FD801 /* Frameworks */, - 84752E8926ED0FFE009FD801 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 84752E8E26ED0FFE009FD801 /* PBXTargetDependency */, - ); - name = OmniBLETests; - productName = OmniBLETests; - productReference = 84752E8B26ED0FFE009FD801 /* OmniBLETests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - C187C196279086A8006E3557 /* OmniBLEPlugin */ = { - isa = PBXNativeTarget; - buildConfigurationList = C187C19B279086A8006E3557 /* Build configuration list for PBXNativeTarget "OmniBLEPlugin" */; - buildPhases = ( - C187C192279086A8006E3557 /* Headers */, - C187C193279086A8006E3557 /* Sources */, - C187C194279086A8006E3557 /* Frameworks */, - C187C195279086A8006E3557 /* Resources */, - C1D27A1627908DCF00C41EBA /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - C187C1A0279086FF006E3557 /* PBXTargetDependency */, - ); - name = OmniBLEPlugin; - productName = OmniBLEPlugin; - productReference = C187C197279086A8006E3557 /* OmniBLEPlugin.loopplugin */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 84752E7926ED0FFE009FD801 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 1250; - LastUpgradeCheck = 1330; - ORGANIZATIONNAME = "Randall Knutson"; - TargetAttributes = { - 84752E8126ED0FFE009FD801 = { - CreatedOnToolsVersion = 12.5.1; - }; - 84752E8A26ED0FFE009FD801 = { - CreatedOnToolsVersion = 12.5.1; - }; - C187C196279086A8006E3557 = { - CreatedOnToolsVersion = 13.2.1; - }; - }; - }; - buildConfigurationList = 84752E7C26ED0FFE009FD801 /* Build configuration list for PBXProject "OmniBLE" */; - compatibilityVersion = "Xcode 13.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - de, - "zh-Hans", - ja, - nb, - es, - da, - it, - sv, - pl, - "pt-BR", - vi, - ru, - fr, - fi, - nl, - ro, - he, - tr, - ar, - cs, - hi, - sk, - uk, - lt, - bn, - "pt-PT", - ca, - hu, - ); - mainGroup = 84752E7826ED0FFE009FD801; - packageReferences = ( - 8475306C26ED15DE009FD801 /* XCRemoteSwiftPackageReference "CryptoSwift" */, - ); - productRefGroup = 84752E8326ED0FFE009FD801 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 84752E8126ED0FFE009FD801 /* OmniBLE */, - 84752E8A26ED0FFE009FD801 /* OmniBLETests */, - C187C196279086A8006E3557 /* OmniBLEPlugin */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 84752E8026ED0FFE009FD801 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C1F67E9527975B830017487F /* HUDAssets.xcassets in Resources */, - 1029AE4F27094E1900B7F5B6 /* OmniBLEUI.xcassets in Resources */, - 191DB66D2A06F17800212AC9 /* Localizable.strings in Resources */, - 8475313726ED838B009FD801 /* PodLifeHUDView.xib in Resources */, - A91B2DEC276E1E5E001B0E95 /* README.md in Resources */, - C1C001C427A2351D00533D35 /* OmniBLEReservoirView.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 84752E8926ED0FFE009FD801 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C187C195279086A8006E3557 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 84752E7E26ED0FFE009FD801 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C1F67EDE2797AFF10017487F /* Image.swift in Sources */, - 1016325E27185EE5007A3BC2 /* PodProgressStatus.swift in Sources */, - D895BF5B275DE64000D51FC7 /* StringLengthPrefixEncoding.swift in Sources */, - 10389A3426FF7841002115E9 /* AssignAddressCommand.swift in Sources */, - 10289E812739F8E4000339E6 /* SessionKeys.swift in Sources */, - 84752EDD26ED13F5009FD801 /* Ids.swift in Sources */, - C1F67E8B27975B830017487F /* AttachPodView.swift in Sources */, - 84752ED826ED13F5009FD801 /* OmniRandomByteGenerator.swift in Sources */, - 1016324D27137B1E007A3BC2 /* BluetoothManager.swift in Sources */, - 84752EE026ED13F5009FD801 /* PodProtocolError.swift in Sources */, - C1D27A1B27911E9900C41EBA /* PodAdvertisement.swift in Sources */, - C1F67EE02797B1EF0017487F /* OmniBLEHUDProvider.swift in Sources */, - 10289E7F2739F8A1000339E6 /* EapAkaAttribute.swift in Sources */, - C1F67E9327975B830017487F /* ExpirationReminderPickerView.swift in Sources */, - 1016325B27185EE5007A3BC2 /* Pod.swift in Sources */, - C1F67E8C27975B830017487F /* ScheduledExpirationReminderEditView.swift in Sources */, - 10289E6C27308746000339E6 /* BluetoothServices.swift in Sources */, - 10389A3226FF7841002115E9 /* BasalScheduleExtraCommand.swift in Sources */, - 1016325A27185EE5007A3BC2 /* FaultEventCode.swift in Sources */, - 10289E6A271B2A3E000339E6 /* IdentifiableClass.swift in Sources */, - 84752EE526ED13F5009FD801 /* KeyExchange.swift in Sources */, - 10289E7627347C69000339E6 /* Nonce.swift in Sources */, - C1F67EB827975E710017487F /* ErrorView.swift in Sources */, - 1029AE4927094D0E00B7F5B6 /* OmniBLEPumpManagerState.swift in Sources */, - 10289E7D2739F893000339E6 /* Milenage.swift in Sources */, - 10389A3A26FF7841002115E9 /* SetInsulinScheduleCommand.swift in Sources */, - D845A13B2AF89F7100EA0853 /* PlayTestBeepsView.swift in Sources */, - 10389A3826FF7841002115E9 /* DetailedStatus.swift in Sources */, - C1F67E9927975B830017487F /* NotificationSettingsView.swift in Sources */, - 10389A2B26FF7841002115E9 /* PlaceholderMessageBlock.swift in Sources */, - 10389A3026FF7841002115E9 /* StatusResponse.swift in Sources */, - 1021114A2709462300784F13 /* PodDoseProgressEstimator.swift in Sources */, - 8475315A26EDA193009FD801 /* HKUnit.swift in Sources */, - 10389A2626FF7841002115E9 /* TempBasalExtraCommand.swift in Sources */, - 8475315C26EDA193009FD801 /* TimeZone.swift in Sources */, - 8475315726EDA193009FD801 /* LocalizedString.swift in Sources */, - C1F67E9727975B830017487F /* PairPodView.swift in Sources */, - D897B06B29347ED500FDB009 /* BolusDeliveryTable.swift in Sources */, - 10289E782734D10D000339E6 /* EnDecrypt.swift in Sources */, - C1F67EDA27979E400017487F /* PumpManagerAlert.swift in Sources */, - 10389A2D26FF7841002115E9 /* BolusExtraCommand.swift in Sources */, - 8475315926EDA193009FD801 /* UIColor.swift in Sources */, - 10389A2926FF7841002115E9 /* PodInfoConfiguredAlerts.swift in Sources */, - C1F67EB727975E710017487F /* LeadingImage.swift in Sources */, - C1F67ECB27975F360017487F /* PodLifeState.swift in Sources */, - 8475315B26EDA193009FD801 /* NibLoadable.swift in Sources */, - 10389A3126FF7841002115E9 /* GetStatusCommand.swift in Sources */, - 8475313226ED838B009FD801 /* PodLifeHUDView.swift in Sources */, - C1C001BF27A2337B00533D35 /* PeripheralManager+OmniBLE.swift in Sources */, - 10389A3F26FF7841002115E9 /* CRC16.swift in Sources */, - 10289E68271B2A08000339E6 /* NumberFormatter.swift in Sources */, - 1016325927185EE4007A3BC2 /* BeepType.swift in Sources */, - C1F67E9E27975B830017487F /* LowReservoirReminderEditView.swift in Sources */, - 8475315326EDA193009FD801 /* TimeInterval.swift in Sources */, - 10389A2326FF7841002115E9 /* PodInfoPulseLog.swift in Sources */, - C1F67E8E27975B830017487F /* TimeView.swift in Sources */, - 10389A2726FF7841002115E9 /* DeactivatePodCommand.swift in Sources */, - 10389A3626FF7841002115E9 /* ErrorResponse.swift in Sources */, - 10389A2C26FF7841002115E9 /* PodInfo.swift in Sources */, - C1F67E9827975B830017487F /* CheckInsertedCannulaView.swift in Sources */, - 10389A3C26FF7841002115E9 /* Message.swift in Sources */, - 8475315826EDA193009FD801 /* OSLog.swift in Sources */, - 84752ED726ED13F5009FD801 /* X25519KeyGenerator.swift in Sources */, - C1F67EC527975F360017487F /* InsertCannulaViewModel.swift in Sources */, - C1F67E9027975B830017487F /* ExpirationReminderSetupView.swift in Sources */, - 102111492709462300784F13 /* PodCommsSession.swift in Sources */, - 10289E832739F917000339E6 /* SessionEstablisher.swift in Sources */, - 84752EE126ED13F5009FD801 /* PayloadSplitter.swift in Sources */, - C1ED1E7227BAE44E00FED71C /* BeepPreferenceSelectionView.swift in Sources */, - 84752EDE26ED13F5009FD801 /* PeripheralManagerError.swift in Sources */, - 10389A2526FF7841002115E9 /* PodInfoActivationTime.swift in Sources */, - D845A1432AF89F9200EA0853 /* SilencePodSelectionView.swift in Sources */, - C1F67E9A27975B830017487F /* DeliveryUncertaintyRecoveryView.swift in Sources */, - 1021114D2709467400784F13 /* PodComms.swift in Sources */, - 10289E6E27309327000339E6 /* CBPeripheral.swift in Sources */, - C1F67EA427975CCA0017487F /* DashUICoordinator.swift in Sources */, - 1016325F27185EE5007A3BC2 /* BasalSchedule.swift in Sources */, - 10389A2F26FF7841002115E9 /* PodInfoPulseLogPlus.swift in Sources */, - 10389A2826FF7841002115E9 /* AcknowledgeAlertCommand.swift in Sources */, - C1C001C527A2351D00533D35 /* OmniBLEReservoirView.swift in Sources */, - D897B06D29347EE500FDB009 /* InsulinTableEntry.swift in Sources */, - 84752EDF26ED13F5009FD801 /* PeripheralManager.swift in Sources */, - C1F67EA227975B830017487F /* PodDetailsView.swift in Sources */, - 1029AE4B27094DDC00B7F5B6 /* OmniBLEPumpManager+UI.swift in Sources */, - 1016326027185EE5007A3BC2 /* UnfinalizedDose.swift in Sources */, - C1F67E9D27975B830017487F /* InsertCannulaView.swift in Sources */, - C1F67EC927975F360017487F /* DeliveryUncertaintyRecoveryViewModel.swift in Sources */, - 1016325C27185EE5007A3BC2 /* BasalDeliveryTable.swift in Sources */, - 84752EE326ED13F5009FD801 /* BLEPacket.swift in Sources */, - D845A1402AF89F8400EA0853 /* ReadPulseLogView.swift in Sources */, - 102111472709462300784F13 /* PodState.swift in Sources */, - 196A6F232AFFFD1700E3C089 /* SilencePodPreference.swift in Sources */, - 1021114B2709462300784F13 /* BasalSchedule+LoopKit.swift in Sources */, - 84752EE626ED13F5009FD801 /* LTKExchanger.swift in Sources */, - 10389A2A26FF7841002115E9 /* MessageBlock.swift in Sources */, - C1F67ECA27975F360017487F /* OmniBLESettingsViewModel.swift in Sources */, - C1F67EBA27975EB70017487F /* FrameworkLocalText.swift in Sources */, - C1F67E9227975B830017487F /* BasalStateView.swift in Sources */, - 1024E32B27446DB000DE01F2 /* MessagePacket.swift in Sources */, - 10289E7B2739F886000339E6 /* EapMessage.swift in Sources */, - D845A1392AF89F6300EA0853 /* FirstAppear.swift in Sources */, - C1C001C127A2349D00533D35 /* OmniBLE.swift in Sources */, - 10389A3326FF7841002115E9 /* CancelDeliveryCommand.swift in Sources */, - C1DBD513282FF79D009FCF74 /* ManualTempBasalEntryView.swift in Sources */, - 10389A2426FF7841002115E9 /* VersionResponse.swift in Sources */, - C1F67EA027975B830017487F /* PodSetupView.swift in Sources */, - C1ED1E7027BAE1A600FED71C /* BeepPreference.swift in Sources */, - 10389A3B26FF7841002115E9 /* ConfigureAlertsCommand.swift in Sources */, - D845A13F2AF89F8400EA0853 /* ReadPodStatusView.swift in Sources */, - D8896C6227890E6B00E09A96 /* DetailedStatus+OmniBLE.swift in Sources */, - 10389A3926FF7841002115E9 /* PodInfoResponse.swift in Sources */, - 84752EE226ED13F5009FD801 /* PayloadJoiner.swift in Sources */, - 1029AE4827094D0E00B7F5B6 /* OmniBLEPumpManager.swift in Sources */, - 10389A3526FF7841002115E9 /* BeepConfigCommand.swift in Sources */, - 1016325D27185EE5007A3BC2 /* AlertSlot.swift in Sources */, - C1F67EC827975F360017487F /* DeactivatePodViewModel.swift in Sources */, - C1F67E9127975B830017487F /* DeactivatePodView.swift in Sources */, - 84752EE726ED13F5009FD801 /* PairResult.swift in Sources */, - D845A1412AF89F8400EA0853 /* PumpManagerDetailsView.swift in Sources */, - 8475315D26EDA193009FD801 /* Data.swift in Sources */, - C1F67E9427975B830017487F /* LowReservoirReminderSetupView.swift in Sources */, - C1F67EB627975E710017487F /* RoundedCard.swift in Sources */, - C1F67EC627975F360017487F /* PairPodViewModel.swift in Sources */, - 84752ED626ED13F5009FD801 /* Id.swift in Sources */, - 84752EE826ED13F5009FD801 /* PairMessage.swift in Sources */, - C187C191278FCEC9006E3557 /* InsulinTypeConfirmation.swift in Sources */, - C1F67EDC2797A03A0017487F /* PendingCommand.swift in Sources */, - 10389A3726FF7841002115E9 /* SetupPodCommand.swift in Sources */, - 1024E32D2746083800DE01F2 /* EapSqn.swift in Sources */, - C1F67E9C27975B830017487F /* UncertaintyRecoveredView.swift in Sources */, - 102111482709462300784F13 /* PodInsulinMeasurements.swift in Sources */, - 10389A4126FF7841002115E9 /* MessageTransport.swift in Sources */, - C1F67E8F27975B830017487F /* OmniBLESettingsView.swift in Sources */, - 10389A2E26FF7841002115E9 /* FaultConfigCommand.swift in Sources */, - C1F67E9F27975B830017487F /* SetupCompleteView.swift in Sources */, - C1F67EE227985F580017487F /* ReservoirLevel.swift in Sources */, - D845A1372AF89F5500EA0853 /* ActivityView.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 84752E8726ED0FFE009FD801 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - A9A5BCF6276C1E6D00B02C86 /* MessagePacketTests.swift in Sources */, - D802CCFC27DD97210072E3A1 /* AcknowledgeAlertsTests.swift in Sources */, - A9A5BCF1276C1E5F00B02C86 /* EnDecryptTests.swift in Sources */, - D802CD0927DD98C10072E3A1 /* PodCommsSessionTests.swift in Sources */, - D802CD0827DD98C10072E3A1 /* StatusTests.swift in Sources */, - C10D6D6C27A2393800F53D58 /* OmniBLETests.swift in Sources */, - A9A5BCF2276C1E6D00B02C86 /* PayloadSplitterTest.swift in Sources */, - D802CD0A27DD98C10072E3A1 /* TempBasalTests.swift in Sources */, - A9A5BCEF276C1E2D00B02C86 /* TestUtilities.swift in Sources */, - A9A5BCF0276C1E2D00B02C86 /* HexConversionTests.swift in Sources */, - D802CD1227DD9AE10072E3A1 /* BasalScheduleTests.swift in Sources */, - D802CD0627DD98C10072E3A1 /* PodInfoTests.swift in Sources */, - D800CF1927E682E90090EADB /* ZeroBasalScheduleTest.swift in Sources */, - D802CD0727DD98C10072E3A1 /* PodStateTests.swift in Sources */, - A9A5BCF4276C1E6D00B02C86 /* PayloadJoinerTest.swift in Sources */, - A9A5BCF3276C1E6D00B02C86 /* StringLengthPrefixEncodingTests.swift in Sources */, - D802CD0027DD98B80072E3A1 /* MessageTests.swift in Sources */, - A9A5BCF7276C1E7000B02C86 /* KeyExchangeTests.swift in Sources */, - D802CD1027DD99AB0072E3A1 /* CRC16Tests.swift in Sources */, - A9A5BCF5276C1E6D00B02C86 /* PayloadSplitJoinTests.swift in Sources */, - D802CCFE27DD98AF0072E3A1 /* BolusTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C187C193279086A8006E3557 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C187C1A3279087A4006E3557 /* OSLog.swift in Sources */, - C10D6D6E27A2395700F53D58 /* OmniBLEPlugin.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 84752E8E26ED0FFE009FD801 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 84752E8126ED0FFE009FD801 /* OmniBLE */; - targetProxy = 84752E8D26ED0FFE009FD801 /* PBXContainerItemProxy */; - }; - C187C1A0279086FF006E3557 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 84752E8126ED0FFE009FD801 /* OmniBLE */; - targetProxy = C187C19F279086FF006E3557 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 191DB6522A06F17800212AC9 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 191DB6532A06F17800212AC9 /* de */, - 191DB6542A06F17800212AC9 /* he */, - 191DB6552A06F17800212AC9 /* ar */, - 191DB6562A06F17800212AC9 /* zh-Hans */, - 191DB6572A06F17800212AC9 /* ja */, - 191DB6582A06F17800212AC9 /* en */, - 191DB6592A06F17800212AC9 /* uk */, - 191DB65A2A06F17800212AC9 /* nb */, - 191DB65B2A06F17800212AC9 /* es */, - 191DB65C2A06F17800212AC9 /* da */, - 191DB65D2A06F17800212AC9 /* it */, - 191DB65E2A06F17800212AC9 /* sk */, - 191DB65F2A06F17800212AC9 /* sv */, - 191DB6602A06F17800212AC9 /* tr */, - 191DB6612A06F17800212AC9 /* pl */, - 191DB6622A06F17800212AC9 /* pt-BR */, - 191DB6632A06F17800212AC9 /* vi */, - 191DB6642A06F17800212AC9 /* lt */, - 191DB6652A06F17800212AC9 /* ru */, - 191DB6662A06F17800212AC9 /* fr */, - 191DB6672A06F17800212AC9 /* fi */, - 191DB6682A06F17800212AC9 /* nl */, - 191DB6692A06F17800212AC9 /* bn */, - 191DB66A2A06F17800212AC9 /* pt-PT */, - 191DB66B2A06F17800212AC9 /* ro */, - 191DB66C2A06F17800212AC9 /* ca */, - 193F1E492B44C21100525770 /* hu */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - 4B67E2D3289B4EDB002D92AF /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 4B67E2D4289B4EDB002D92AF /* de */, - 4B23AA6328D909E2009B453B /* en */, - 4B23AA6428D909E7009B453B /* zh-Hans */, - 4B23AA6528D909E9009B453B /* da */, - 4B23AA6628D909EC009B453B /* nl */, - 4B23AA6728D909EE009B453B /* fi */, - 4B23AA6828D909F1009B453B /* fr */, - 4B23AA6A28D909F5009B453B /* it */, - 4B23AA6B28D909F7009B453B /* ja */, - 4B23AA6C28D909FA009B453B /* nb */, - 4B23AA6D28D909FD009B453B /* pl */, - 4B23AA6E28D909FF009B453B /* pt-BR */, - 4B23AA6F28D90A01009B453B /* ro */, - 4B23AA7028D90A03009B453B /* ru */, - 4B23AA7128D90A06009B453B /* es */, - 4B23AA7228D90A08009B453B /* sv */, - 4B23AA7428D90A0D009B453B /* vi */, - C19E3881298638CE00851444 /* tr */, - C15A583029C7866600D3A5A1 /* ar */, - C121D8D829C7866D00DA0520 /* cs */, - C1FF3D5229C786A900BDC1EC /* he */, - C1FAB5C729C786B000D25073 /* hi */, - C1FDCC1029C786F90056E652 /* sk */, - 1909F73C2A127FEF00F145A2 /* uk */, - 1909F73D2A127FF300F145A2 /* pt-PT */, - 1909F73E2A127FF800F145A2 /* ca */, - 193F1E4A2B44C21100525770 /* hu */, - ); - name = Localizable.strings; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 84752E9426ED0FFE009FD801 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = 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_DOCUMENTATION_COMMENTS = YES; - 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - 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 = 15.1; - LOCALIZED_STRING_MACRO_NAMES = ( - NSLocalizedString, - CFCopyLocalizedString, - LocalizedString, - FrameworkLocalText, - ); - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 84752E9526ED0FFE009FD801 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = 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_DOCUMENTATION_COMMENTS = YES; - 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - 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 = 15.1; - LOCALIZED_STRING_MACRO_NAMES = ( - NSLocalizedString, - CFCopyLocalizedString, - LocalizedString, - FrameworkLocalText, - ); - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 84752E9726ED0FFE009FD801 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ""; - INFOPLIST_FILE = OmniBLE/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - LOCALIZED_STRING_MACRO_NAMES = ( - NSLocalizedString, - CFCopyLocalizedString, - LocalizedString, - FrameworkLocalText, - ); - PRODUCT_BUNDLE_IDENTIFIER = com.randallknutson.OmniBLE; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - WRAPPER_EXTENSION = framework; - }; - name = Debug; - }; - 84752E9826ED0FFE009FD801 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ""; - INFOPLIST_FILE = OmniBLE/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - LOCALIZED_STRING_MACRO_NAMES = ( - NSLocalizedString, - CFCopyLocalizedString, - LocalizedString, - FrameworkLocalText, - ); - PRODUCT_BUNDLE_IDENTIFIER = com.randallknutson.OmniBLE; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - WRAPPER_EXTENSION = framework; - }; - name = Release; - }; - 84752E9A26ED0FFE009FD801 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CODE_SIGN_STYLE = Automatic; - FRAMEWORK_SEARCH_PATHS = ""; - INFOPLIST_FILE = OmniBLETests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.randallknutson.OmniBLETests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 84752E9B26ED0FFE009FD801 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CODE_SIGN_STYLE = Automatic; - FRAMEWORK_SEARCH_PATHS = ""; - INFOPLIST_FILE = OmniBLETests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.randallknutson.OmniBLETests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - C187C19C279086A8006E3557 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = NO; - INFOPLIST_FILE = OmniBLEPlugin/Info.plist; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 LoopKit Authors. All rights reserved."; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.2; - LD_DYLIB_INSTALL_NAME = ""; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.randallknutson.OmniBLEPlugin; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - WRAPPER_EXTENSION = loopplugin; - }; - name = Debug; - }; - C187C19D279086A8006E3557 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = NO; - INFOPLIST_FILE = OmniBLEPlugin/Info.plist; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 LoopKit Authors. All rights reserved."; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.2; - LD_DYLIB_INSTALL_NAME = ""; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.randallknutson.OmniBLEPlugin; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - WRAPPER_EXTENSION = loopplugin; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 84752E7C26ED0FFE009FD801 /* Build configuration list for PBXProject "OmniBLE" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 84752E9426ED0FFE009FD801 /* Debug */, - 84752E9526ED0FFE009FD801 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 84752E9626ED0FFE009FD801 /* Build configuration list for PBXNativeTarget "OmniBLE" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 84752E9726ED0FFE009FD801 /* Debug */, - 84752E9826ED0FFE009FD801 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 84752E9926ED0FFE009FD801 /* Build configuration list for PBXNativeTarget "OmniBLETests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 84752E9A26ED0FFE009FD801 /* Debug */, - 84752E9B26ED0FFE009FD801 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C187C19B279086A8006E3557 /* Build configuration list for PBXNativeTarget "OmniBLEPlugin" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C187C19C279086A8006E3557 /* Debug */, - C187C19D279086A8006E3557 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 8475306C26ED15DE009FD801 /* XCRemoteSwiftPackageReference "CryptoSwift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/krzyzanowskim/CryptoSwift"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.4.1; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 8475306D26ED15DE009FD801 /* CryptoSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 8475306C26ED15DE009FD801 /* XCRemoteSwiftPackageReference "CryptoSwift" */; - productName = CryptoSwift; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 84752E7926ED0FFE009FD801 /* Project object */; -} diff --git a/Dependencies/OmniBLE/OmniBLE.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Dependencies/OmniBLE/OmniBLE.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/Dependencies/OmniBLE/OmniBLE.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/BluetoothManager.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/BluetoothManager.swift deleted file mode 100644 index e3b585d46..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/BluetoothManager.swift +++ /dev/null @@ -1,397 +0,0 @@ -// -// BluetoothManager.swift -// OmniBLE -// -// Created by Randall Knutson on 10/10/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import CoreBluetooth -import Foundation -import LoopKit -import os.log - -public enum BluetoothManagerError: Error { - case bluetoothNotAvailable(CBManagerState) -} - -extension BluetoothManagerError: LocalizedError { - public var errorDescription: String? { - switch self { - case .bluetoothNotAvailable(let state): - switch state { - case .poweredOff: - return LocalizedString("Bluetooth is powered off", comment: "Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff)") - case .resetting: - return LocalizedString("Bluetooth is resetting", comment: "Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting)") - case .unauthorized: - return LocalizedString("Bluetooth use is unauthorized", comment: "Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized)") - case .unsupported: - return LocalizedString("Bluetooth use unsupported on this device", comment: "Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported)") - case .unknown: - return LocalizedString("Bluetooth is unavailable for an unknown reason.", comment: "Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown)") - default: - return String(format: LocalizedString("Bluetooth is unavailable: %1$@", comment: "The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state)"), String(describing: state)) - } - } - } - - public var recoverySuggestion: String? { - switch self { - case .bluetoothNotAvailable(let state): - switch state { - case .poweredOff: - return LocalizedString("Turn bluetooth on", comment: "recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff)") - case .resetting: - return LocalizedString("Try again", comment: "recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting)") - case .unauthorized: - return LocalizedString("Please enable bluetooth permissions for this app in system settings", comment: "recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized)") - case .unsupported: - return LocalizedString("Please use a different device with bluetooth capabilities", comment: "recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported)") - default: - return nil - } - } - } -} - -protocol OmniBLEConnectionDelegate: AnyObject { - - /** - Tells the delegate that a peripheral has been connected to - - - parameter manager: The manager for the peripheral that was connected - */ - func omnipodPeripheralDidConnect(manager: PeripheralManager) - - /** - Tells the delegate that a connected peripheral has been restored from session restoration - - - parameter manager: The manager for the peripheral that was connected - */ - func omnipodPeripheralWasRestored(manager: PeripheralManager) - - - /** - Tells the delegate that a peripheral was disconnected - - - parameter peripheral: The peripheral that was disconnected - */ - func omnipodPeripheralDidDisconnect(peripheral: CBPeripheral, error: Error?) - - /** - Tells the delegate that a peripheral failed to connect - - - parameter peripheral: The peripheral that failed to connect - */ - func omnipodPeripheralDidFailToConnect(peripheral: CBPeripheral, error: Error?) - -} - - -class BluetoothManager: NSObject { - - weak var connectionDelegate: OmniBLEConnectionDelegate? - - private let log = OSLog(category: "BluetoothManager") - - /// Isolated to `managerQueue` - private var manager: CBCentralManager! = nil - - /// Isolated to `managerQueue` - private var devices: [OmniBLE] = [] - - /// Isolated to `managerQueue` - private var discoveryModeEnabled: Bool = false - - /// Isolated to `managerQueue` - private var autoConnectIDs: Set = [] { - didSet { - updateConnections() - } - } - - /// Isolated to `managerQueue` - private var hasDiscoveredAllAutoConnectDevices: Bool { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - return autoConnectIDs.isSubset(of: devices.map { $0.manager.peripheral.identifier.uuidString }) - } - - // MARK: - Synchronization - private let managerQueue = DispatchQueue(label: "com.OmniBLE.bluetoothManagerQueue", qos: .unspecified) - - override init() { - super.init() - - managerQueue.sync { - self.manager = CBCentralManager(delegate: self, queue: managerQueue, options: [CBCentralManagerOptionRestoreIdentifierKey: "com.OmniBLE"]) - } - } - - @discardableResult - private func addPeripheral(_ peripheral: CBPeripheral, podAdvertisement: PodAdvertisement?) -> OmniBLE { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - var device: OmniBLE! = devices.first(where: { $0.manager.peripheral.identifier == peripheral.identifier }) - - if let device = device { - log.default("Matched peripheral %{public}@ to existing device: %{public}@", peripheral, String(describing: device)) - device.manager.peripheral = peripheral - if let podAdvertisement = podAdvertisement { - device.advertisement = podAdvertisement - } - } else { - device = OmniBLE(peripheralManager: PeripheralManager(peripheral: peripheral, configuration: .omnipod, centralManager: manager), advertisement: podAdvertisement) - devices.append(device) - log.info("Created device") - } - return device - } - - // MARK: - Actions - - func discoverPods(completion: @escaping (BluetoothManagerError?) -> Void) { - dispatchPrecondition(condition: .notOnQueue(managerQueue)) - - managerQueue.sync { - self.discoverPods(completion) - } - } - - func endPodDiscovery() { - managerQueue.sync { - self.discoveryModeEnabled = false - self.manager.stopScan() - - // Disconnect from all devices not in our connection list - for device in devices { - let peripheral = device.manager.peripheral - if !autoConnectIDs.contains(peripheral.identifier.uuidString) && - (peripheral.state == .connected || peripheral.state == .connecting) - { - log.default("Disconnecting from peripheral: %{public}@", peripheral) - manager.cancelPeripheralConnection(peripheral) - } - } - } - } - - func connectToDevice(uuidString: String) { - managerQueue.async { - self.autoConnectIDs.insert(uuidString) - } - } - - func disconnectFromDevice(uuidString: String) { - managerQueue.async { - self.autoConnectIDs.remove(uuidString) - } - } - - private func updateConnections() { - guard manager.state == .poweredOn else { - log.debug("Skipping updateConnections until state is poweredOn") - return - } - - for device in devices { - let peripheral = device.manager.peripheral - if autoConnectIDs.contains(peripheral.identifier.uuidString) { - if peripheral.state == .disconnected || peripheral.state == .disconnecting { - log.info("updateConnections: Connecting to peripheral: %{public}@", peripheral) - manager.connect(peripheral, options: nil) - } - } else { - if peripheral.state == .connected || peripheral.state == .connecting { - log.info("updateConnections: Disconnecting from peripheral: %{public}@", peripheral) - manager.cancelPeripheralConnection(peripheral) - } - } - } - } - - private func discoverPods(_ completion: @escaping (BluetoothManagerError?) -> Void) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - log.default("discoverPods()") - - - guard manager.state == .poweredOn else { - completion(.bluetoothNotAvailable(manager.state)) - return - } - - // We will attempt to connect to all pairable devices when in discovery mode - discoveryModeEnabled = true - for device in devices { - let peripheral = device.manager.peripheral - if peripheral.state == .disconnected || peripheral.state == .disconnecting { - log.info("discoverPods: Connecting to peripheral: %{public}@", peripheral) - manager.connect(peripheral, options: nil) - } - } - startScanning() - - completion(nil) - } - - private func startScanning() { - log.default("Start scanning") - manager.scanForPeripherals(withServices: [OmnipodServiceUUID.advertisement.cbUUID], options: nil) - } - - private func stopScanning() { - log.default("Stop scanning") - manager.stopScan() - } - - // MARK: - Accessors - - public func getConnectedDevices() -> [OmniBLE] { - var connected: [OmniBLE] = [] - managerQueue.sync { - connected = self.devices.filter { $0.manager.peripheral.state == .connected } - } - return connected - } - - override var debugDescription: String { - - var report = [ - "## BluetoothManager", - "central: \(manager!)" - ] - - for device in devices { - report.append(String(reflecting: device)) - report.append("") - } - - return report.joined(separator: "\n\n") - } -} - - -extension BluetoothManager: CBCentralManagerDelegate { - func centralManagerDidUpdateState(_ central: CBCentralManager) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - log.default("%{public}@: %{public}@", #function, String(describing: central.state.rawValue)) - - if case .poweredOn = central.state { - // bluetooth may have reset; update peripheral references - for device in devices { - if let newPeripheral = central.retrievePeripherals(withIdentifiers: [device.manager.peripheral.identifier]).first { - log.debug("Re-connecting to known peripheral %{public}@", newPeripheral.identifier.uuidString) - device.manager.peripheral = newPeripheral - central.connect(newPeripheral) - } - } - - updateConnections() - - if (discoveryModeEnabled || !hasDiscoveredAllAutoConnectDevices) && !manager.isScanning { - startScanning() - } else if !discoveryModeEnabled && manager.isScanning { - stopScanning() - } - } - - for device in devices { - device.manager.assertConfiguration() - } - } - - func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - log.info("OmniBLE %{public}@: %{public}@", #function, dict) - - if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey] as? [CBPeripheral] { - for peripheral in peripherals { - let device = addPeripheral(peripheral, podAdvertisement: nil) - - if autoConnectIDs.contains(peripheral.identifier.uuidString) { - if peripheral.state == .connected { - connectionDelegate?.omnipodPeripheralWasRestored(manager: device.manager) - } - } else if peripheral.state == .connected || peripheral.state == .connecting { - // For some reason iOS is maintaining a connection to a device that isn't in our list. - manager.cancelPeripheralConnection(peripheral) - } - } - } - } - - func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - log.debug("%{public}@: %{public}@, %{public}@", #function, peripheral, advertisementData) - - if let podAdvertisement = PodAdvertisement(advertisementData) { - addPeripheral(peripheral, podAdvertisement: podAdvertisement) - - if discoveryModeEnabled && peripheral.state == .disconnected && podAdvertisement.pairable { - // Connect to any pairable device, during discovery - log.default("Connecting to pairable device %{public} in discovery mode", peripheral) - manager.connect(peripheral, options: nil) - } else if autoConnectIDs.contains(peripheral.identifier.uuidString) && peripheral.state == .disconnected { - log.debug("Reonnecting to autoconnect device") - manager.connect(peripheral, options: nil) - } else { - log.info("Ignoring paired or unconnectable peripheral: %{public}@", peripheral) - } - } else { - log.info("Ignoring peripheral with unexpected advertisement data: %{public}@", advertisementData) - } - - if !discoveryModeEnabled && central.isScanning && hasDiscoveredAllAutoConnectDevices { - log.debug("All peripherals discovered") - stopScanning() - } - } - - func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - log.debug("%{public}@: %{public}@", #function, peripheral) - - // Proxy connection events to peripheral manager - for device in devices where device.manager.peripheral.identifier == peripheral.identifier { - device.manager.centralManager(central, didConnect: peripheral) - connectionDelegate?.omnipodPeripheralDidConnect(manager: device.manager) - - // Get an RSSI reading for logging - peripheral.readRSSI() - } - } - - func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - log.debug("%{public}@: error=%{public}@ %{public}@", #function, error?.localizedDescription ?? "None", peripheral) - - // Proxy disconnection events to peripheral manager - for device in devices where device.manager.peripheral.identifier == peripheral.identifier { - device.manager.centralManager(central, didDisconnect: peripheral, error: error) - } - - connectionDelegate?.omnipodPeripheralDidDisconnect(peripheral: peripheral, error: error) - - if autoConnectIDs.contains(peripheral.identifier.uuidString) { - log.debug("Reconnecting disconnected autoconnect peripheral") - central.connect(peripheral, options: nil) - } - } - - func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { - dispatchPrecondition(condition: .onQueue(managerQueue)) - - log.error("%{public}@: %{public}@", #function, String(describing: error)) - - connectionDelegate?.omnipodPeripheralDidFailToConnect(peripheral: peripheral, error: error) - - if autoConnectIDs.contains(peripheral.identifier.uuidString) { - central.connect(peripheral, options: nil) - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/BluetoothServices.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/BluetoothServices.swift deleted file mode 100644 index 21d88c876..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/BluetoothServices.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// BluetoothServices.swift -// OmniBLE -// -// Created by Randall Knutson on 11/01/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import CoreBluetooth - -protocol CBUUIDRawValue: RawRepresentable {} -extension CBUUIDRawValue where RawValue == String { - var cbUUID: CBUUID { - return CBUUID(string: rawValue) - } -} - -enum PodCommand: UInt8 { - case RTS = 0x00 - case CTS = 0x01 - case NACK = 0x02 - case ABORT = 0x03 - case SUCCESS = 0x04 - case FAIL = 0x05 - case HELLO = 0x06 - case INCORRECT = 0x09 -} - -enum OmnipodServiceUUID: String, CBUUIDRawValue { - case advertisement = "00004024-0000-1000-8000-00805f9b34fb" - case service = "1A7E4024-E3ED-4464-8B7E-751E03D0DC5F" -} - -enum OmnipodCharacteristicUUID: String, CBUUIDRawValue { - case command = "1A7E2441-E3ED-4464-8B7E-751E03D0DC5F" - case data = "1A7E2442-E3ED-4464-8B7E-751E03D0DC5F" -} - -extension PeripheralManager.Configuration { - static var omnipod: PeripheralManager.Configuration { - return PeripheralManager.Configuration( - serviceCharacteristics: [ - OmnipodServiceUUID.service.cbUUID: [ - OmnipodCharacteristicUUID.command.cbUUID, - OmnipodCharacteristicUUID.data.cbUUID, - ] - ], - notifyingCharacteristics: [ - OmnipodServiceUUID.service.cbUUID: [ -// OmnipodCharacteristicUUID.command.cbUUID, -// OmnipodCharacteristicUUID.data.cbUUID, - ] - ], - valueUpdateMacros: [ - OmnipodCharacteristicUUID.command.cbUUID: { (manager: PeripheralManager) in - guard let characteristic = manager.peripheral.getCommandCharacteristic() else { return } - guard let value = characteristic.value else { return } - - manager.queueLock.lock() - manager.cmdQueue.append(value) - manager.queueLock.signal() - manager.queueLock.unlock() - }, - OmnipodCharacteristicUUID.data.cbUUID: { (manager: PeripheralManager) in - guard let characteristic = manager.peripheral.getDataCharacteristic() else { return } - guard let value = characteristic.value else { return } - - manager.queueLock.lock() - manager.dataQueue.append(value) - manager.queueLock.signal() - manager.queueLock.unlock() - } - ] - ) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/CBPeripheral.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/CBPeripheral.swift deleted file mode 100644 index 583a1032b..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/CBPeripheral.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// CBPeripheral.swift -// xDripG5 -// OmniBLE -// -// From CGMBLEKit/CGMBLEKit/CBPeripheral.swift -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import CoreBluetooth - - -// MARK: - Discovery helpers. -extension CBPeripheral { - func servicesToDiscover(from serviceUUIDs: [CBUUID]) -> [CBUUID] { - let knownServiceUUIDs = services?.compactMap({ $0.uuid }) ?? [] - return serviceUUIDs.filter({ !knownServiceUUIDs.contains($0) }) - } - - func characteristicsToDiscover(from characteristicUUIDs: [CBUUID], for service: CBService) -> [CBUUID] { - let knownCharacteristicUUIDs = service.characteristics?.compactMap({ $0.uuid }) ?? [] - return characteristicUUIDs.filter({ !knownCharacteristicUUIDs.contains($0) }) - } -} - - -extension Collection where Element: CBAttribute { - func itemWithUUID(_ uuid: CBUUID) -> Element? { - for attribute in self { - if attribute.uuid == uuid { - return attribute - } - } - - return nil - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/EnDecrypt/EnDecrypt.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/EnDecrypt/EnDecrypt.swift deleted file mode 100644 index 17dcaebf5..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/EnDecrypt/EnDecrypt.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// EnDecrypt.swift -// OmniBLE -// -// Created by Randall Knutson on 11/4/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import CryptoSwift -import os.log - -class EnDecrypt { - private let MAC_SIZE = 8 - private let log = OSLog(category: "EnDecrypt") - private let nonce: Nonce - private let ck: Data - - init(nonce: Nonce, ck: Data) { - self.nonce = nonce - self.ck = ck - } - - func decrypt(_ msg: MessagePacket, _ nonceSeq: Int) throws -> MessagePacket { - let payload = msg.payload - let header = msg.asData(forEncryption: false).subdata(in: 0..<16) - - let n = nonce.toData(sqn: nonceSeq, podReceiving: false) - let ccm = CCM(iv: n.bytes, tagLength: MAC_SIZE, messageLength: payload.count - MAC_SIZE, additionalAuthenticatedData: header.bytes) - let aes = try AES(key: ck.bytes, blockMode: ccm, padding: .noPadding) - let decryptedPayload = try aes.decrypt(payload.bytes) - - var msgCopy = msg - msgCopy.payload = Data(decryptedPayload) - return msgCopy - } - - func encrypt(_ headerMessage: MessagePacket, _ nonceSeq: Int) throws -> MessagePacket { - let payload = headerMessage.payload - let header = headerMessage.asData(forEncryption: true).subdata(in: 0..<16) - - let n = nonce.toData(sqn: nonceSeq, podReceiving: true) - let ccm = CCM(iv: n.bytes, tagLength: MAC_SIZE, messageLength: payload.count, additionalAuthenticatedData: header.bytes) - let aes = try AES(key: ck.bytes, blockMode: ccm, padding: .noPadding) - let encryptedPayload = try aes.encrypt(payload.bytes) - - var msgCopy = headerMessage - msgCopy.payload = Data(encryptedPayload) - return msgCopy - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/EnDecrypt/Nonce.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/EnDecrypt/Nonce.swift deleted file mode 100644 index 6ce3c2dd8..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/EnDecrypt/Nonce.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// Nonce.swift -// OmniBLE -// -// Created by Randall Knutson on 11/4/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -class Nonce { - let prefix: Data - - init (prefix: Data) { - guard prefix.count == 8 else { fatalError("Nonce prefix should be 8 bytes long") } - self.prefix = prefix - } - - func toData(sqn: Int, podReceiving: Bool) -> Data { - var ret = Data(bigEndian: sqn) - .subdata(in: 3..<8) - if (podReceiving) { - ret[0] = UInt8(ret[0] & 127) - } else { - ret[0] = UInt8(ret[0] | 128) - } - return prefix + ret - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Id.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/Id.swift deleted file mode 100644 index cf86fdf5c..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Id.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// Id.swift -// OmniBLE -// -// Created by Randall Knutson on 8/5/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -class Id: Equatable { - - static func fromInt(_ v: Int) -> Id { - return Id(Data(bigEndian: v).subdata(in: 4..<8)) - } - - static func fromUInt32(_ v: UInt32) -> Id { - return Id(Data(bigEndian: v)) - } - - let address: Data - - init(_ address: Data) { - guard address.count == 4 else { - // TODO: Should probably throw an error here. - // require(address.size == 4) - self.address = Data([0x00, 0x00, 0x00, 0x00]) - return - } - self.address = address - } - - func toInt64() -> Int64 { - return address.toBigEndian(Int64.self) - } - - func toUInt32() -> UInt32 { - return address.toBigEndian(UInt32.self) - } - - // MARK: Comparable - - static func == (lhs: Id, rhs: Id) -> Bool { - return lhs.address == rhs.address - } -} - -// The Dash PDM uses the PDM's SN << 2 for the bottom 5 nibbles and some -// unknown values for the top 3 nibbles of its fixed 32-bit controller ID. -func createControllerId() -> UInt32 { - // Use 0x17 for top byte to be similar to, but different from, Eros's 0x1F. - return 0x17000000 | ((arc4random() & 0x003FFFFF) << 2) -} - -// podId's cycle between 3 #'s of controllerId+1, +2, +3, +1, ... -func nextPodId(lastPodId: UInt32) -> UInt32 { - if (lastPodId & 0b11) == 0b11 { - // start over at controllerId + 1 - return (lastPodId & ~0b11) + 1 - } - // return the next sequential podId # - return lastPodId + 1 -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Ids.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/Ids.swift deleted file mode 100644 index 9a14fbc12..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Ids.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// Ids.swift -// OmniBLE -// -// Created by Randall Knutson on 8/5/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -let CONTROLLER_ID: UInt32 = 0x1092 // fixed AAPS controller Id # -let POD_ID_NOT_ACTIVATED = Data(hexadecimalString: "FFFFFFFE")! - -public class Ids { - - static func notActivated() -> Id { - return Id(POD_ID_NOT_ACTIVATED) - } - - private let controllerId: Id - private let currentPodId: Id - - var myId: Id { - return controllerId - } - - var podId: Id { - return currentPodId - } - - var myIdAddr: UInt32 { - return controllerId.toUInt32() - } - - var podIdAddr: UInt32 { - return currentPodId.toUInt32() - } - - init(myId: UInt32, podId: UInt32) { - controllerId = Id.fromUInt32(myId) - currentPodId = Id.fromUInt32(podId) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/MessagePacket.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/MessagePacket.swift deleted file mode 100644 index ff9f71ca3..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/MessagePacket.swift +++ /dev/null @@ -1,163 +0,0 @@ -// -// MessagePacket.swift -// OmniBLE -// -// Created by Randall Knutson on 8/4/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// -import Foundation - -enum MessageType: UInt8 { - case CLEAR = 0, ENCRYPTED, SESSION_ESTABLISHMENT, PAIRING -} - -struct MessagePacket { - private static let MAGIC_PATTERN = "TW" // all messages start with this string - private static let HEADER_SIZE = 16 - - static func parse(payload: Data) throws -> MessagePacket { - guard payload.count >= HEADER_SIZE else { - throw PodProtocolError.couldNotParseMessageException("Incorrect header size") - } - - guard (String(data: payload.subdata(in: 0..<2), encoding: .utf8) == MAGIC_PATTERN) else { - throw PodProtocolError.couldNotParseMessageException("Magic pattern mismatch") - } - let payloadData = payload - - let f1 = Flag(payloadData[2]) - let sas = f1.get(3) != 0 - let tfs = f1.get(4) != 0 - let version = Int16(((f1.get(0) << 2) | (f1.get(1) << 1) | (f1.get(2) << 0))) - let eqos = Int16((f1.get(7) | (f1.get(6) << 1) | (f1.get(5) << 2))) - - let f2 = Flag(payloadData[3]) - let ack = f2.get(0) != 0 - let priority = f2.get(1) != 0 - let lastMessage = f2.get(2) != 0 - let gateway = f2.get(3) != 0 - let type: MessageType = MessageType(rawValue: UInt8(f2.get(7) | (f2.get(6) << 1) | (f2.get(5) << 2) | (f2.get(4) << 3))) ?? .CLEAR - if (version != 0) { - throw PodProtocolError.couldNotParseMessageException("Wrong version") - } - let sequenceNumber = payloadData[4] - let ackNumber = payloadData[5] - let size = (UInt16(payloadData[6]) << 3) | (UInt16(payloadData[7]) >> 5) - guard payload.count >= (Int(size) + MessagePacket.HEADER_SIZE) else { - throw PodProtocolError.couldNotParseMessageException("Wrong payload size") - } - - let payloadEnd = Int(16 + size + (type == MessageType.ENCRYPTED ? 8 : 0)) - - return MessagePacket( - type: type, - source: Id(payload.subdata(in: 8..<12)).toUInt32(), - destination: Id(payload.subdata(in: 12..<16)).toUInt32(), - payload: payload.subdata(in: 16.. Data { - var bb = Data(capacity: 16 + payload.count) - bb.append(MessagePacket.MAGIC_PATTERN.data(using: .utf8)!) - - let f1 = Flag() - f1.set(0, self.version & 4 != 0) - f1.set(1, self.version & 2 != 0) - f1.set(2, self.version & 1 != 0) - f1.set(3, self.sas) - f1.set(4, self.tfs) - f1.set(5, self.eqos & 4 != 0) - f1.set(6, self.eqos & 2 != 0) - f1.set(7, self.eqos & 1 != 0) - - let f2 = Flag() - f2.set(0, self.ack) - f2.set(1, self.priority) - f2.set(2, self.lastMessage) - f2.set(3, self.gateway) - f2.set(4, self.type.rawValue & 8 != 0) - f2.set(5, self.type.rawValue & 4 != 0) - f2.set(6, self.type.rawValue & 2 != 0) - f2.set(7, self.type.rawValue & 1 != 0) - - bb.append(f1.value) - bb.append(f2.value) - bb.append(self.sequenceNumber) - bb.append(self.ackNumber) - let size = payload.count - ((type == MessageType.ENCRYPTED && !forEncryption) ? 8 : 0) - bb.append(UInt8(size >> 3)) - bb.append(UInt8((size << 5) & 0xff)) - bb.append(self.source.address) - bb.append(self.destination.address) - - bb.append(self.payload) - - return bb - } -} - -private class Flag { - var value: UInt8 - - init(_ value: UInt8 = 0) { - self.value = value - } - - func set(_ idx: UInt8, _ set: Bool) { - let mask: UInt8 = 1 << (7 - idx) - if (!set) { - return - } - value = value | mask - } - - func get(_ idx: UInt8) -> UInt8 { - let mask: UInt8 = 1 << (7 - idx) - if (value & mask == 0) { - return 0 - } - return 1 - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Packet/BLEPacket.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/Packet/BLEPacket.swift deleted file mode 100644 index 332fe1ad2..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Packet/BLEPacket.swift +++ /dev/null @@ -1,178 +0,0 @@ -// -// BLEPacket.swift -// OmniBLE -// -// Created by Randall Knutson on 8/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -let MAX_SIZE = 20 - -protocol BlePacket { - var payload: Data { get } - - func toData() -> Data -} - -struct FirstBlePacket: BlePacket { - private static let HEADER_SIZE_WITHOUT_MIDDLE_PACKETS = 7 // we are using all fields - private static let HEADER_SIZE_WITH_MIDDLE_PACKETS = 2 - - internal static let CAPACITY_WITHOUT_MIDDLE_PACKETS = - MAX_SIZE - HEADER_SIZE_WITHOUT_MIDDLE_PACKETS // we are using all fields - internal static let CAPACITY_WITH_MIDDLE_PACKETS = - MAX_SIZE - HEADER_SIZE_WITH_MIDDLE_PACKETS // we are not using crc32 or size - internal static let CAPACITY_WITH_THE_OPTIONAL_PLUS_ONE_PACKET = 18 - - private static let MAX_FRAGMENTS = 15 // 15*20=300 bytes - - let fullFragments: Int - let payload: Data - var size: UInt8? - var crc32: Data? - var oneExtraPacket: Bool = false - - func toData() -> Data { - var bb = Data(capacity: MAX_SIZE) - bb.append(UInt8(0)) // index - bb.append(UInt8(fullFragments)) // # of fragments except FirstBlePacket and LastOptionalPlusOneBlePacket - - if let crc32 = crc32 { - bb.append(crc32) - } - if let size = size { - bb.append(UInt8(size)) - } - bb.append(payload) - - return bb; - } - - static func parse(payload: Data) throws -> FirstBlePacket { - guard payload.count >= HEADER_SIZE_WITH_MIDDLE_PACKETS else { - throw PodProtocolError.messageIOException("Wrong packet size") - } - - if (Int(payload[0]) != 0) { - // most likely we lost the first packet. - throw PodProtocolError.incorrectPacketException(payload, 0) - } - - let fullFragments = Int(payload[1]) - guard (fullFragments < MAX_FRAGMENTS) else { - throw PodProtocolError.messageIOException(String(format: "Received more than %d fragments", MAX_FRAGMENTS)) - } - guard (fullFragments > 0) else { - throw PodProtocolError.messageIOException("Invalid message with 0 fragments") - } - - guard payload.count >= HEADER_SIZE_WITHOUT_MIDDLE_PACKETS else { - throw PodProtocolError.messageIOException("Wrong packet size") - } - - if (fullFragments == 0) { - let rest = payload[6] - let end = min(Int(rest) + HEADER_SIZE_WITHOUT_MIDDLE_PACKETS, payload.count) - guard payload.count >= end else { - throw PodProtocolError.messageIOException("Wrong packet size") - } - - return FirstBlePacket( - fullFragments: fullFragments, - payload: payload.subdata(in: HEADER_SIZE_WITHOUT_MIDDLE_PACKETS.. end - ) - } - else if (payload.count < MAX_SIZE) { - throw PodProtocolError.incorrectPacketException(payload, 0) - } - else { - return FirstBlePacket( - fullFragments: fullFragments, - payload: payload.subdata(in: HEADER_SIZE_WITH_MIDDLE_PACKETS.. Data { - return Data([index]) + payload - } - - static func parse(payload: Data) throws -> MiddleBlePacket { - guard payload.count >= MAX_SIZE else { throw PodProtocolError.messageIOException("Wrong packet size") } - return MiddleBlePacket( - index: payload[0], - payload: payload.subdata(in: 1.. Data { - var bb = Data(capacity: MAX_SIZE) - bb.append(index) - bb.append(size) - bb.append(crc32) - bb.append(payload) - bb.append(Data(count: MAX_SIZE - payload.count - LastBlePacket.HEADER_SIZE)) - return bb - } - - static func parse(payload: Data) throws -> LastBlePacket { - guard payload.count >= LastBlePacket.HEADER_SIZE else { throw PodProtocolError.messageIOException("Wrong packet size") } - - let rest = payload[1] - let end = min(Int(rest) + LastBlePacket.HEADER_SIZE, payload.count) - - guard payload.count >= end else { throw PodProtocolError.messageIOException("Wrong packet size") } - - return LastBlePacket( - index: payload[0], - size: rest, - payload: payload.subdata(in: LastBlePacket.HEADER_SIZE.. end - ) - } -} - -struct LastOptionalPlusOneBlePacket: BlePacket { - static let HEADER_SIZE = 2 - let index: UInt8 - let payload: Data - let size: UInt8 - - func toData() -> Data { - return Data([index, size]) + payload + Data(count: MAX_SIZE - payload.count - 2) - } - - static func parse(payload: Data) throws -> LastOptionalPlusOneBlePacket { - guard payload.count >= 2 else { throw PodProtocolError.messageIOException("Wrong packet size") } - let size = payload[1] - guard payload.count >= HEADER_SIZE + Int(size) else { throw PodProtocolError.messageIOException("Wrong packet size") } - - return LastOptionalPlusOneBlePacket( - index: payload[0], - payload: payload.subdata(in: HEADER_SIZE.. = Array() - - init(firstPacket: Data) throws { - let firstPacket = try FirstBlePacket.parse(payload: firstPacket) - fragments.append(firstPacket) - fullFragments = firstPacket.fullFragments - crc = firstPacket.crc32 - oneExtraPacket = firstPacket.oneExtraPacket - } - - func accumulate(packet: Data) throws { - if (packet.count < 3) { // idx, size, at least 1 byte of payload - throw PodProtocolError.incorrectPacketException(packet, (expectedIndex + 1)) - } - let idx = Int(packet[0]) - if (idx != expectedIndex + 1) { - throw PodProtocolError.incorrectPacketException(packet, (expectedIndex + 1)) - } - expectedIndex += 1 - switch idx{ - case let index where index < fullFragments: - fragments.append(try MiddleBlePacket.parse(payload: packet)) - case let index where index == fullFragments: - let lastPacket = try LastBlePacket.parse(payload: packet) - fragments.append(lastPacket) - crc = lastPacket.crc32 - oneExtraPacket = lastPacket.oneExtraPacket - case let index where index == fullFragments + 1 && oneExtraPacket: - fragments.append(try LastOptionalPlusOneBlePacket.parse(payload: packet)) - case let index where index > fullFragments: - throw PodProtocolError.incorrectPacketException(packet, idx) - default: - throw PodProtocolError.incorrectPacketException(packet, idx) - } - } - - func finalize() throws -> Data { - let payloads = fragments.map { x in x.payload } - let bb = payloads.reduce(Data(), { acc, elem in acc + elem }) - let computedCrc32 = bb.crc32() - if let crc32 = crc, crc32 != computedCrc32 { - throw PodProtocolError.invalidCrc(payloadCrc: crc32, computedCrc: computedCrc32) - } - return bb - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Packet/PayloadSplitter.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/Packet/PayloadSplitter.swift deleted file mode 100644 index ca0ea8399..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Packet/PayloadSplitter.swift +++ /dev/null @@ -1,88 +0,0 @@ -// -// PayloadSplitter.swift -// OmniBLE -// -// Created by Randall Knutson on 8/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import CryptoSwift - -class PayloadSplitter { - private let payload: Data - - init(payload: Data) { - self.payload = payload - } - - func splitInPackets() -> Array { - if (payload.count <= FirstBlePacket.CAPACITY_WITH_THE_OPTIONAL_PLUS_ONE_PACKET) { - return splitInOnePacket() - } - var ret = Array() - let crc32 = payload.crc32() - let middleFragments = (payload.count - FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS) / MiddleBlePacket.CAPACITY - let rest = UInt8((payload.count - middleFragments * MiddleBlePacket.CAPACITY) - FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS) - ret.append( - FirstBlePacket( - fullFragments: middleFragments + 1, - payload: payload.subdata(in: 0.. 0) { - for i in 1...middleFragments { - let p = payload.subdata(in: (FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + (i - 1) * MiddleBlePacket.CAPACITY)..<(FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + i * MiddleBlePacket.CAPACITY)) - ret.append( - MiddleBlePacket( - index: UInt8(i), - payload: p - ) - ) - } - } - let end = min(LastBlePacket.CAPACITY, Int(rest)) - ret.append( - LastBlePacket( - index: UInt8(middleFragments + 1), - size: rest, - payload: payload.subdata(in: middleFragments * MiddleBlePacket.CAPACITY + FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS.. LastBlePacket.CAPACITY) { - ret.append( - LastOptionalPlusOneBlePacket( - index: UInt8(middleFragments + 2), - payload: payload.subdata(in: middleFragments * MiddleBlePacket.CAPACITY + FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + LastBlePacket.CAPACITY.. Array { - var ret = Array() - let crc32 = payload.crc32() - let end = min(FirstBlePacket.CAPACITY_WITHOUT_MIDDLE_PACKETS, payload.count) - ret.append( - FirstBlePacket( - fullFragments: 0, - payload: payload.subdata(in: 0.. FirstBlePacket.CAPACITY_WITHOUT_MIDDLE_PACKETS) { - ret.append( - LastOptionalPlusOneBlePacket( - index: 1, - payload: payload.subdata(in: end.. Data { - let mac = try CMAC(key: key.bytes) - return try Data(mac.authenticate(data.bytes)) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Pair/LTKExchanger.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/Pair/LTKExchanger.swift deleted file mode 100644 index d7444d1df..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Pair/LTKExchanger.swift +++ /dev/null @@ -1,157 +0,0 @@ -// -// LTKExchanger.swift -// OmniBLE -// -// Created by Randall Knutson on 8/3/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// -import Foundation -import os.log - -class LTKExchanger { - static let GET_POD_STATUS_HEX_COMMAND: Data = Data(hex: "ffc32dbd08030e0100008a") - // This is the binary representation of "GetPodStatus command" - - static private let SP1 = "SP1=" - static private let SP2 = ",SP2=" - static private let SPS1 = "SPS1=" - static private let SPS2 = "SPS2=" - static private let SP0GP0 = "SP0,GP0" - static private let P0 = "P0=" - static private let UNKNOWN_P0_PAYLOAD = Data([0xa5]) - - private let manager: PeripheralManager - private let ids: Ids - private let podAddress = Ids.notActivated() - private let keyExchange = try! KeyExchange(X25519KeyGenerator(), OmniRandomByteGenerator()) - private var seq: UInt8 = 1 - - private let log = OSLog(category: "LTKExchanger") - - init(manager: PeripheralManager, ids: Ids) { - self.manager = manager - self.ids = ids - } - - func negotiateLTK() throws -> PairResult { - log.debug("Sending sp1sp2") - let sp1sp2 = PairMessage( - sequenceNumber: seq, - source: ids.myId, - destination: podAddress, - keys: [LTKExchanger.SP1, LTKExchanger.SP2], - payloads: [ids.podId.address, sp2()] - ) - try throwOnSendError(sp1sp2.message, LTKExchanger.SP1 + LTKExchanger.SP2) - - seq += 1 - log.debug("Sending sps1") - let sps1 = PairMessage( - sequenceNumber: seq, - source: ids.myId, - destination: podAddress, - keys: [LTKExchanger.SPS1], - payloads: [keyExchange.pdmPublic + keyExchange.pdmNonce] - ) - try throwOnSendError(sps1.message, LTKExchanger.SPS1) - - log.debug("Reading sps1") - let podSps1 = try manager.readMessagePacket() - guard let _ = podSps1 else { - throw PodProtocolError.pairingException("Could not read SPS1") - } - try processSps1FromPod(podSps1!) - // now we have all the data to generate: confPod, confPdm, ltk and noncePrefix - - log.debug("Sending sps2") - seq += 1 - let sps2 = PairMessage( - sequenceNumber: seq, - source: ids.myId, - destination: podAddress, - keys: [LTKExchanger.SPS2], - payloads: [keyExchange.pdmConf] - ) - try throwOnSendError(sps2.message, LTKExchanger.SPS2) - - let podSps2 = try manager.readMessagePacket() - guard let _ = podSps2 else { - throw PodProtocolError.pairingException("Could not read SPS2") - } - try validatePodSps2(podSps2!) - // No exception throwing after this point. It is possible that the pod saved the LTK - - seq += 1 - // send SP0GP0 - let sp0gp0 = PairMessage( - sequenceNumber: seq, - source: ids.myId, - destination: podAddress, - keys: [LTKExchanger.SP0GP0], - payloads: [Data()] - ) - let result = manager.sendMessagePacket(sp0gp0.message) - guard case .sentWithAcknowledgment = result else { - throw PodProtocolError.pairingException("Error sending SP0GP0: \(result)") - } - - let p0 = try manager.readMessagePacket() - guard let _ = p0 else { - throw PodProtocolError.pairingException("Could not read P0") - } - try validateP0(p0!) - - guard keyExchange.ltk.count == 16 else { - throw PodProtocolError.invalidLTKKey("Invalid Key, got \(String(data: keyExchange.ltk, encoding: .utf8) ?? "")") - } - - return PairResult( - ltk: keyExchange.ltk, - address: ids.podId.toUInt32(), - msgSeq: seq - ) - } - - private func throwOnSendError(_ msg: MessagePacket, _ msgType: String) throws { - let result = manager.sendMessagePacket(msg) - guard case .sentWithAcknowledgment = result else { - throw PodProtocolError.pairingException("Send failure: \(result)") - } - } - - private func processSps1FromPod(_ msg: MessagePacket) throws { - log.debug("Received SPS1 from pod: %@", msg.payload.hexadecimalString) - - let payload = try StringLengthPrefixEncoding.parseKeys([LTKExchanger.SPS1], msg.payload)[0] - log.debug("SPS1 payload from pod: %@", payload.hexadecimalString) - try keyExchange.updatePodPublicData(payload) - } - - private func validatePodSps2(_ msg: MessagePacket) throws { - log.debug("Received SPS2 from pod: %@", msg.payload.hexadecimalString) - - let payload = try StringLengthPrefixEncoding.parseKeys([LTKExchanger.SPS2], msg.payload)[0] - log.debug("SPS2 payload from pod: %@", payload.hexadecimalString) - - if (payload.count != KeyExchange.CMAC_SIZE) { - throw PodProtocolError.messageIOException("Invalid payload size") - } - try keyExchange.validatePodConf(payload) - } - - private func sp2() -> Data { - // This is GetPodStatus command, with page 0 parameter. - // We could replace that in the future with the serialized GetPodStatus() - return LTKExchanger.GET_POD_STATUS_HEX_COMMAND - } - - private func validateP0(_ msg: MessagePacket) throws { - log.debug("Received P0 from pod: %@", msg.payload.hexadecimalString) - - let payload = try StringLengthPrefixEncoding.parseKeys([LTKExchanger.P0], msg.payload)[0] - log.debug("P0 payload from pod: %@", payload.hexadecimalString) - if (payload != LTKExchanger.UNKNOWN_P0_PAYLOAD) { - throw PodProtocolError.pairingException("Reveived invalid P0 payload: \(payload)") - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Pair/PairMessage.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/Pair/PairMessage.swift deleted file mode 100644 index 5890b17a1..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Pair/PairMessage.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// PairMessage.swift -// OmniBLE -// -// Created by Randall Knutson on 8/4/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -struct PairMessage { - public let sequenceNumber: UInt8 - public let source: Id - public let destination: Id - private let keys: [String] - private let payloads: [Data] - public let message: MessagePacket - - init(sequenceNumber: UInt8, source: Id, destination: Id, keys: [String], payloads: [Data]) { - self.sequenceNumber = sequenceNumber - self.source = source - self.destination = destination - self.keys = keys - self.payloads = payloads - message = MessagePacket( - type: MessageType.PAIRING, - source: source.toUInt32(), - destination: destination.toUInt32(), - payload: StringLengthPrefixEncoding.formatKeys( - keys: keys, - payloads: payloads - ), - sequenceNumber :sequenceNumber, - sas: true - ) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Pair/PairResult.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/Pair/PairResult.swift deleted file mode 100644 index 15a4c27b1..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Pair/PairResult.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// PairResult.swift -// OmniBLE -// -// Created by Randall Knutson on 8/4/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -struct PairResult { - var ltk: Data - var address: UInt32 - var msgSeq: UInt8 -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/PeripheralManager+OmniBLE.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/PeripheralManager+OmniBLE.swift deleted file mode 100644 index 344f87555..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/PeripheralManager+OmniBLE.swift +++ /dev/null @@ -1,248 +0,0 @@ -// -// PeripheralManager+OmniBLE.swift -// OmniBLE -// -// Created by Randall Knutson on 11/2/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - - -enum SendMessageResult { - case sentWithAcknowledgment - case sentWithError(Error) - case unsentWithError(Error) -} - -extension PeripheralManager { - - /// - Throws: PeripheralManagerError - func sendHello(myId: UInt32) throws { - dispatchPrecondition(condition: .onQueue(queue)) - - let controllerId = Id.fromUInt32(myId).address - guard let characteristic = peripheral.getCommandCharacteristic() else { - throw PeripheralManagerError.notReady - } - - try writeValue(Data([PodCommand.HELLO.rawValue, 0x01, 0x04]) + controllerId, for: characteristic, type: .withResponse, timeout: 5) - } - - func enableNotifications() throws { - dispatchPrecondition(condition: .onQueue(queue)) - guard let cmdChar = peripheral.getCommandCharacteristic() else { - throw PeripheralManagerError.notReady - } - guard let dataChar = peripheral.getDataCharacteristic() else { - throw PeripheralManagerError.notReady - } - try setNotifyValue(true, for: cmdChar, timeout: .seconds(2)) - try setNotifyValue(true, for: dataChar, timeout: .seconds(2)) - } - - func sendMessagePacket(_ message: MessagePacket, _ forEncryption: Bool = false) -> SendMessageResult { - dispatchPrecondition(condition: .onQueue(queue)) - - var didSend = false - - do { - try requestToSend() - try waitForCommand(PodCommand.CTS, timeout: 5) - - let splitter = PayloadSplitter(payload: message.asData(forEncryption: forEncryption)) - let packets = splitter.splitInPackets() - - for (index, packet) in packets.enumerated() { - // Consider starting the last packet send as the point at which the message may be received by the pod. - // A failure after data is actually sent, but before the sendData() returns can still be received. - if index == packets.count - 1 { - didSend = true - } - try sendData(packet.toData(), timeout: 5) - try self.peekForNack() - } - - try waitForCommand(PodCommand.SUCCESS, timeout: 5) - } - catch { - if didSend { - return .sentWithError(error) - } else { - return .unsentWithError(error) - } - } - return .sentWithAcknowledgment - } - - /// - Throws: PeripheralManagerError - func readMessagePacket() throws -> MessagePacket? { - dispatchPrecondition(condition: .onQueue(queue)) - - var packet: MessagePacket? - - do { - try waitForCommand(PodCommand.RTS) - try sendCommandType(PodCommand.CTS) - - var expected: UInt8 = 0 - - let firstPacket = try waitForData(sequence: expected, timeout: 5) - - let joiner = try PayloadJoiner(firstPacket: firstPacket) - - for _ in 1...joiner.fullFragments { - expected += 1 - let packet = try waitForData(sequence: expected, timeout: 5) - try joiner.accumulate(packet: packet) - } - if (joiner.oneExtraPacket) { - expected += 1 - let packet = try waitForData(sequence: expected, timeout: 5) - try joiner.accumulate(packet: packet) - } - let fullPayload = try joiner.finalize() - try sendCommandType(PodCommand.SUCCESS) - packet = try MessagePacket.parse(payload: fullPayload) - } catch { - log.error("Error reading message: %{public}@", error.localizedDescription) - if let error = error as? PeripheralManagerError, error.isSymptomaticOfUnresponsivePod { - if peripheral.state == .connected { - log.error("Disconnecting due to error while reading pod response") - central?.cancelPeripheralConnection(peripheral) - } - } else { - try? sendCommandType(PodCommand.NACK) - } - throw PeripheralManagerError.incorrectResponse - } - - return packet - } - - /// - Throws: PeripheralManagerError - func peekForNack() throws -> Void { - dispatchPrecondition(condition: .onQueue(queue)) - - // Lock to protect cmdQueue - queueLock.lock() - defer { - queueLock.unlock() - } - - if cmdQueue.contains(where: { cmd in - return cmd[0] == PodCommand.NACK.rawValue - }) { - throw PeripheralManagerError.nack - } - } - - func requestToSend() throws { - clearCommsQueues() - try sendCommandType(.RTS, timeout: 5) - } - - /// - Throws: PeripheralManagerError - func sendCommandType(_ command: PodCommand, timeout: TimeInterval = 5) throws { - dispatchPrecondition(condition: .onQueue(queue)) - - guard let characteristic = peripheral.getCommandCharacteristic() else { - throw PeripheralManagerError.notReady - } - - try writeValue(Data([command.rawValue]), for: characteristic, type: .withResponse, timeout: timeout) - } - - /// - Throws: PeripheralManagerError - func waitForCommand(_ command: PodCommand, timeout: TimeInterval = 5) throws { - dispatchPrecondition(condition: .onQueue(queue)) - - // Wait for data to be read. - queueLock.lock() - if (cmdQueue.count == 0) { - queueLock.wait(until: Date().addingTimeInterval(timeout)) - } - queueLock.unlock() - - commandLock.lock() - defer { - commandLock.unlock() - } - - // Lock to protect dataQueue - queueLock.lock() - defer { - queueLock.unlock() - } - - if (cmdQueue.count > 0) { - let value = cmdQueue.remove(at: 0) - - if command.rawValue != value[0] { - log.error("waitForCommand failed. rawValue != value[0] (%d != %d); data=%@", command.rawValue, value[0], value.hexadecimalString) - throw PeripheralManagerError.incorrectResponse - } - - return - } - - throw PeripheralManagerError.emptyValue - } - - /// - Throws: PeripheralManagerError - func sendData(_ value: Data, timeout: TimeInterval) throws { - dispatchPrecondition(condition: .onQueue(queue)) - - guard let characteristic = peripheral.getDataCharacteristic() else { - throw PeripheralManagerError.notReady - } - - try writeValue(value, for: characteristic, type: .withResponse, timeout: timeout) - } - - /// - Throws: PeripheralManagerError - func waitForData(sequence: UInt8, timeout: TimeInterval) throws -> Data { - dispatchPrecondition(condition: .onQueue(queue)) - - // Wait for data to be read. - queueLock.lock() - if (dataQueue.count == 0) { - queueLock.wait(until: Date().addingTimeInterval(timeout)) - } - queueLock.unlock() - - commandLock.lock() - defer { - commandLock.unlock() - } - - // Lock to protect dataQueue - queueLock.lock() - defer { - queueLock.unlock() - } - - if (dataQueue.count > 0) { - let data = dataQueue.remove(at: 0) - - if (data[0] != sequence) { - log.error("waitForData failed data[0] != sequence (%d != %d).", data[0], sequence) - throw PeripheralManagerError.incorrectResponse - } - return data - } - - throw PeripheralManagerError.emptyValue - } -} - - -// Marks certain errors are the kinds we see from NXP pods that occasionally become unresponsive -extension PeripheralManagerError { - var isSymptomaticOfUnresponsivePod: Bool { - switch self { - case .emptyValue, .incorrectResponse: - return true - default: - return false - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/PeripheralManager.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/PeripheralManager.swift deleted file mode 100644 index a89a33890..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/PeripheralManager.swift +++ /dev/null @@ -1,549 +0,0 @@ -// -// PeripheralManager.swift -// xDripG5 -// OmniBLE -// -// Based on CGMBLEKit/CGMBLEKit/PeripheralManager.swift -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import CoreBluetooth -import Foundation -import os.log - -class PeripheralManager: NSObject { - - // TODO: Make private - let log = OSLog(category: "DashPeripheralManager") - - /// - /// This is mutable, because CBPeripheral instances can seemingly become invalid, and need to be periodically re-fetched from CBCentralManager - var peripheral: CBPeripheral { - didSet { - guard oldValue !== peripheral else { - return - } - - log.error("Replacing peripheral reference %{public}@ -> %{public}@", oldValue, peripheral) - - oldValue.delegate = nil - peripheral.delegate = self - - queue.sync { - self.needsConfiguration = true - } - } - } - - var dataQueue: [Data] = [] - var cmdQueue: [Data] = [] - let queueLock = NSCondition() - - var idleStart: Date? = nil - - var needsReconnection: Bool { - guard let start = idleStart else { return false } - - return Date().timeIntervalSince(start) > .minutes(2.9) - } - - - /// The dispatch queue used to serialize operations on the peripheral - let queue = DispatchQueue(label: "com.loopkit.PeripheralManager.queue", qos: .unspecified) - - private let sessionQueue: OperationQueue = { - let queue = OperationQueue() - queue.name = "com.OmniBLE.OmnipodDevice.sessionQueue" - queue.maxConcurrentOperationCount = 1 - - return queue - }() - - /// The condition used to signal command completion - let commandLock = NSCondition() - - /// The required conditions for the operation to complete - private var commandConditions = [CommandCondition]() - - /// Any error surfaced during the active operation - private var commandError: Error? - - private(set) weak var central: CBCentralManager? - - let configuration: Configuration - - // Confined to `queue` - private var needsConfiguration = true - - weak var delegate: PeripheralManagerDelegate? - - init(peripheral: CBPeripheral, configuration: Configuration, centralManager: CBCentralManager) { - self.peripheral = peripheral - self.central = centralManager - self.configuration = configuration - - super.init() - - peripheral.delegate = self - - assertConfiguration() - } -} - - -// MARK: - Nested types -extension PeripheralManager { - struct Configuration { - var serviceCharacteristics: [CBUUID: [CBUUID]] = [:] - var notifyingCharacteristics: [CBUUID: [CBUUID]] = [:] - var valueUpdateMacros: [CBUUID: (_ manager: PeripheralManager) -> Void] = [:] - } - - enum CommandCondition { - case notificationStateUpdate(characteristicUUID: CBUUID, enabled: Bool) - case valueUpdate(characteristic: CBCharacteristic, matching: ((Data?) -> Bool)?) - case write(characteristic: CBCharacteristic) - case discoverServices - case discoverCharacteristicsForService(serviceUUID: CBUUID) - case connect - } -} - -protocol PeripheralManagerDelegate: AnyObject { - // Called from the PeripheralManager's queue - func completeConfiguration(for manager: PeripheralManager) throws -} - - -// MARK: - Operation sequence management -extension PeripheralManager { - - - func configureAndRun(_ block: @escaping (_ manager: PeripheralManager) -> Void) -> (() -> Void) { - return { - if self.needsReconnection { - self.log.default("Triggering forceful reconnect") - do { - try self.reconnect(timeout: 5) - } catch let error { - self.log.error("Error while forcing reconnection: %{public}@", String(describing: error)) - } - } - - if !self.needsConfiguration && self.peripheral.services == nil { - self.log.error("Configured peripheral has no services. Reconfiguring %{public}@", self.peripheral) - } - - if self.needsConfiguration || self.peripheral.services == nil { - do { - self.log.default("Applying configuration") - try self.applyConfiguration() - self.needsConfiguration = false - - if let delegate = self.delegate { - try delegate.completeConfiguration(for: self) - - self.log.default("Delegate configuration notified") - } - - self.log.default("Peripheral configuration completed") - } catch let error { - self.log.error("Error applying peripheral configuration: %{public}@", String(describing: error)) - // Will retry - } - } - - block(self) - } - } - - func perform(_ block: @escaping (_ manager: PeripheralManager) -> Void) { - queue.async(execute: configureAndRun(block)) - } - - func assertConfiguration() { - if peripheral.state == .connected && central?.state == .poweredOn { - perform { (_) in - // Intentionally empty to trigger configuration if necessary - } - } - } - - private func applyConfiguration(discoveryTimeout: TimeInterval = 2) throws { - try discoverServices(configuration.serviceCharacteristics.keys.map { $0 }, timeout: discoveryTimeout) - - for service in peripheral.services ?? [] { - log.default("Discovered service: %{public}@", service) - guard let characteristics = configuration.serviceCharacteristics[service.uuid] else { - // Not all services may have characteristics - continue - } - try discoverCharacteristics(characteristics, for: service, timeout: discoveryTimeout) - } - - for (serviceUUID, characteristicUUIDs) in configuration.notifyingCharacteristics { - guard let service = peripheral.services?.itemWithUUID(serviceUUID) else { - throw PeripheralManagerError.unknownCharacteristic - } - - for characteristicUUID in characteristicUUIDs { - guard let characteristic = service.characteristics?.itemWithUUID(characteristicUUID) else { - throw PeripheralManagerError.unknownCharacteristic - } - - guard !characteristic.isNotifying else { - continue - } - - try setNotifyValue(true, for: characteristic, timeout: discoveryTimeout) - } - } - } -} - - -// MARK: - Synchronous Commands -extension PeripheralManager { - /// - Throws: PeripheralManagerError - func runCommand(timeout: TimeInterval, command: () -> Void) throws { - // Prelude - dispatchPrecondition(condition: .onQueue(queue)) - guard central?.state == .poweredOn && peripheral.state == .connected else { - self.log.info("runCommand guard failed - bluetooth not running or peripheral not connected: peripheral %@", peripheral) - throw PeripheralManagerError.notReady - } - - commandLock.lock() - - defer { - commandLock.unlock() - } - - guard commandConditions.isEmpty else { - throw PeripheralManagerError.emptyValue - } - - // Run - command() - - guard !commandConditions.isEmpty else { - // If the command didn't add any conditions, then finish immediately - return - } - - // Postlude - let signaled = commandLock.wait(until: Date(timeIntervalSinceNow: timeout)) - - defer { - commandError = nil - commandConditions = [] - } - - guard signaled else { - self.log.info("runCommand lock timeout reached - not signalled") - throw PeripheralManagerError.timeout(commandConditions) - } - - if let error = commandError { - throw PeripheralManagerError.cbPeripheralError(error) - } - } - - /// It's illegal to call this without first acquiring the commandLock - /// - /// - Parameter condition: The condition to add - func addCondition(_ condition: CommandCondition) { - dispatchPrecondition(condition: .onQueue(queue)) - commandConditions.append(condition) - } - - func discoverServices(_ serviceUUIDs: [CBUUID], timeout: TimeInterval) throws { - let servicesToDiscover = peripheral.servicesToDiscover(from: serviceUUIDs) - - guard servicesToDiscover.count > 0 else { - return - } - - try runCommand(timeout: timeout) { - addCondition(.discoverServices) - - peripheral.discoverServices(serviceUUIDs) - } - } - - func discoverCharacteristics(_ characteristicUUIDs: [CBUUID], for service: CBService, timeout: TimeInterval) throws { - let characteristicsToDiscover = peripheral.characteristicsToDiscover(from: characteristicUUIDs, for: service) - - guard characteristicsToDiscover.count > 0 else { - return - } - - try runCommand(timeout: timeout) { - addCondition(.discoverCharacteristicsForService(serviceUUID: service.uuid)) - - peripheral.discoverCharacteristics(characteristicsToDiscover, for: service) - } - } - - func reconnect(timeout: TimeInterval) throws { - try runCommand(timeout: timeout) { - addCondition(.connect) - central?.cancelPeripheralConnection(peripheral) - } - } - - /// - Throws: PeripheralManagerError - func setNotifyValue(_ enabled: Bool, for characteristic: CBCharacteristic, timeout: TimeInterval) throws { - try runCommand(timeout: timeout) { - addCondition(.notificationStateUpdate(characteristicUUID: characteristic.uuid, enabled: enabled)) - - peripheral.setNotifyValue(enabled, for: characteristic) - } - } - - /// - Throws: PeripheralManagerError - func readValue(for characteristic: CBCharacteristic, timeout: TimeInterval) throws -> Data? { - try runCommand(timeout: timeout) { - addCondition(.valueUpdate(characteristic: characteristic, matching: nil)) - - peripheral.readValue(for: characteristic) - } - - return characteristic.value - } - - /// - Throws: PeripheralManagerError - func writeValue(_ value: Data, for characteristic: CBCharacteristic, type: CBCharacteristicWriteType, timeout: TimeInterval) throws { - try runCommand(timeout: timeout) { - if case .withResponse = type { - addCondition(.write(characteristic: characteristic)) - } - - peripheral.writeValue(value, for: characteristic, type: type) - } - } -} - -extension PeripheralManager { - public override var debugDescription: String { - var items = [ - "## PeripheralManager", - "peripheral: \(peripheral)", - ] - queue.sync { - items.append("needsConfiguration: \(needsConfiguration)") - } - return items.joined(separator: "\n") - } -} - -// MARK: - Delegate methods executed on the central's queue -extension PeripheralManager: CBPeripheralDelegate { - - func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { - log.default("didDiscoverServices") - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .discoverServices = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .discoverCharacteristicsForService(serviceUUID: service.uuid) = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .notificationStateUpdate(characteristicUUID: characteristic.uuid, enabled: characteristic.isNotifying) = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .write(characteristic: characteristic) = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { - commandLock.lock() - - if let macro = configuration.valueUpdateMacros[characteristic.uuid] { - macro(self) - } - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .valueUpdate(characteristic: characteristic, matching: let matching) = condition { - return matching?(characteristic.value) ?? true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - - } - - func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) { - guard error == nil else { - self.log.error("Error reading rssi: %{public}@", String(describing: RSSI)) - return - } - self.log.default("didReadRSSI: %{public}@", String(describing: RSSI)) - } - -} - - -extension PeripheralManager { - - func clearCommsQueues() { - queueLock.lock() - if cmdQueue.count > 0 { - self.log.default("Removing %{public}d leftover elements from command queue", cmdQueue.count) - cmdQueue.removeAll() - } - if dataQueue.count > 0 { - self.log.default("Removing %{public}d leftover elements from data queue", dataQueue.count) - dataQueue.removeAll() - } - queueLock.unlock() - } - - func centralManager(_ central: CBCentralManager, didDisconnect peripheral: CBPeripheral, error: Error?) { - self.queue.async { - self.idleStart = nil - } - } - - func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { - self.log.debug("PeripheralManager - didConnect: %@", peripheral) - switch peripheral.state { - case .connected: - clearCommsQueues() - self.log.debug("PeripheralManager - didConnect - running assertConfiguration") - assertConfiguration() - - commandLock.lock() - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .connect = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - commandLock.unlock() - - default: - break - } - } -} - -extension CBPeripheral { - func getCommandCharacteristic() -> CBCharacteristic? { - guard let service = services?.itemWithUUID(OmnipodServiceUUID.service.cbUUID) else { - return nil - } - - return service.characteristics?.itemWithUUID(OmnipodCharacteristicUUID.command.cbUUID) - } - - func getDataCharacteristic() -> CBCharacteristic? { - guard let service = services?.itemWithUUID(OmnipodServiceUUID.service.cbUUID) else { - return nil - } - - return service.characteristics?.itemWithUUID(OmnipodCharacteristicUUID.data.cbUUID) - } -} - -// MARK: - Command session management -extension PeripheralManager { - public func runSession(withName name: String , _ block: @escaping () -> Void) { - self.log.default("Scheduling session %{public}@", name) - - sessionQueue.addOperation({ [weak self] in - self?.perform { (manager) in - manager.log.default("======================== %{public}@ ===========================", name) - block() - manager.log.default("------------------------ %{public}@ ---------------------------", name) - self?.idleStart = Date() - self?.log.default("Start of idle at %{public}@", String(describing: self?.idleStart)) - } - }) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/PeripheralManagerError.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/PeripheralManagerError.swift deleted file mode 100644 index 674bad40b..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/PeripheralManagerError.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// PeripheralManagerErrors.swift -// OmniBLE -// -// Created by Randall Knutson on 8/18/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -enum PeripheralManagerError: Error { - case cbPeripheralError(Error) - case notReady - case incorrectResponse - case timeout([PeripheralManager.CommandCondition]) - case emptyValue - case unknownCharacteristic - case nack -} - -extension PeripheralManagerError: LocalizedError { - public var errorDescription: String? { - switch self { - case .cbPeripheralError(let error): - return error.localizedDescription - case .notReady: - return LocalizedString("Peripheral Not Ready", comment: "Error message description for PeripheralManagerError.notReady") - case .incorrectResponse: - return LocalizedString("Incorrect Response", comment: "Error message description for PeripheralManagerError.incorrectResponse") - case .timeout: - return LocalizedString("Timeout", comment: "Error message description for PeripheralManagerError.timeout") - case .emptyValue: - return LocalizedString("Empty Value", comment: "Error message description for PeripheralManagerError.emptyValue") - case .unknownCharacteristic: - return LocalizedString("Unknown Characteristic", comment: "Error message description for PeripheralManagerError.unknownCharacteristic") - case .nack: - return LocalizedString("Nack", comment: "Error message description for PeripheralManagerError.nack") - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/PodProtocolError.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/PodProtocolError.swift deleted file mode 100644 index 07e836169..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/PodProtocolError.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// PodProtocolError.swift -// OmniBLE -// -// Created by Randall Knutson on 8/3/21. -// - -import Foundation -import CoreBluetooth - -enum PodProtocolError: Error { - case invalidLTKKey(_ message: String) - case pairingException(_ message: String) - case messageIOException(_ message: String) - case couldNotParseMessageException(_ message: String) - case incorrectPacketException(_ payload: Data, _ location: Int) - case invalidCrc(payloadCrc: Data, computedCrc: Data) -} - -extension PodProtocolError: LocalizedError { - public var errorDescription: String? { - switch self { - case .invalidLTKKey(let message): - return String(format: LocalizedString("Invalid LTK Key: %1$@", comment: "The format string for PodProtocolError.invalidLTKKey (1: message associated with error)"), message) - case .pairingException(let message): - return String(format: LocalizedString("Pairing Exception: %1$@", comment: "The format string for PodProtocolError.pairingException (1: message associated with error)"), message) - case .messageIOException(let message): - return String(format: LocalizedString("Message IO Exception: %1$@", comment: "The format string for PodProtocolError.messageIOException (1: message associated with error)"), message) - case .couldNotParseMessageException(let message): - return String(format: LocalizedString("Could not parse message: %1$@", comment: "The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error)"), message) - case .incorrectPacketException(let payload, let location): - let payloadStr = payload.hexadecimalString - return String(format: LocalizedString("Incorrect Packet Exception: %1$@ (location=%2$d)", comment: "The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location)"), payloadStr, location) - case .invalidCrc(let payloadCrc, let computedCrc): - return String(format: LocalizedString("Payload crc32 %1$@ does not match computed crc32 %2$@", comment: "The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc)"), payloadCrc.hexadecimalString, computedCrc.hexadecimalString) - } - } - - public var failureReason: String? { - return nil - } - - public var recoverySuggestion: String? { - return nil - } -} - - diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Session/EapAkaAttribute.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/Session/EapAkaAttribute.swift deleted file mode 100644 index e8936494b..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Session/EapAkaAttribute.swift +++ /dev/null @@ -1,198 +0,0 @@ -// -// EapAkaAttribute.swift -// OmniBLE -// -// Created by Randall Knutson on 11/8/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -enum EapAkaAttributeType: UInt8 { - case AT_RAND = 0x01 - case AT_AUTN = 0x02 - case AT_RES = 0x03 - case AT_AUTS = 0x04 - case AT_CLIENT_ERROR_CODE = 0x22 - case AT_CUSTOM_IV = 126; -} - -class EapAkaAttribute { - let SIZE_MULTIPLIER = 4 // The length for EAP-AKA attributes is a multiple of 4 - var payload: Data = Data() - - func toData() -> Data { - return Data() - } - - static func parseAttributes(payload: Data) throws -> Array{ - var tail = payload - var ret = Array() - while (tail.count > 0) { - if (tail.count < 2) { - throw MessageError.notEnoughData - } - let size = 4 * Int(tail[1]) - if (tail.count < size) { - throw MessageError.notEnoughData - } - let type = EapAkaAttributeType(rawValue: tail[0]) - switch (type) { - case .AT_RES: - ret.append(try EapAkaAttributeRes.parse(payload: tail.subdata(in: 2.. Data { - return Data([EapAkaAttributeType.AT_RAND.rawValue, UInt8(EapAkaAttributeRand.SIZE / SIZE_MULTIPLIER), 0x00, 0x00]) + payload - } - - static func parse(_ payload: Data) throws -> EapAkaAttribute { - if (payload.count < 2 + 16) { - throw MessageError.notEnoughData - } - return try EapAkaAttributeRand(payload: payload.subdata(in: 2..<2 + 16)) - } - - static let SIZE = 20 // type, size, 2 reserved bytes, payload=16 -} - -class EapAkaAttributeAutn : EapAkaAttribute { - init(payload: Data) throws { - super.init() - self.payload = payload - if payload.count != 16 { throw MessageError.notEnoughData } - } - - override func toData() -> Data { - return Data([EapAkaAttributeType.AT_AUTN.rawValue, UInt8(EapAkaAttributeAutn.SIZE / SIZE_MULTIPLIER), 0x00, 0x00]) + payload - } - - static func parse(_ payload: Data) throws -> EapAkaAttribute { - if (payload.count < 2 + 16) { - throw MessageError.notEnoughData - } - return try EapAkaAttributeAutn(payload: payload.subdata(in: 2..<2 + 16)) - } - - static let SIZE = 20 // type, size, 2 reserved bytes, payload=16 -} - -class EapAkaAttributeAuts : EapAkaAttribute { - - init(payload: Data) throws { - super.init() - self.payload = payload - if payload.count != 14 { throw MessageError.notEnoughData } - } - - override func toData() -> Data { - return Data([EapAkaAttributeType.AT_AUTS.rawValue, UInt8(EapAkaAttributeAuts.SIZE / SIZE_MULTIPLIER), 0x00, 0x00]) + payload - } - - - static func parse(payload: Data) throws -> EapAkaAttribute { - if (payload.count < SIZE - 2) { - throw MessageError.notEnoughData - } - return try EapAkaAttributeAuts(payload: payload) - } - - static let SIZE = 16 // type, size, 2 reserved bytes, payload=16 -} - -class EapAkaAttributeRes: EapAkaAttribute { - - init(payload: Data) throws { - super.init() - self.payload = payload - if payload.count != 8 { throw MessageError.notEnoughData } - } - - override func toData() -> Data { - return Data([ - EapAkaAttributeType.AT_RES.rawValue, - UInt8(EapAkaAttributeRes.SIZE / SIZE_MULTIPLIER), - 0x00, - UInt8(EapAkaAttributeRes.PAYLOAD_SIZE_BITS) - ]) + payload - } - - static func parse(payload: Data) throws -> EapAkaAttributeRes { - if (payload.count < 2 + 8) { - throw MessageError.notEnoughData - } - return try EapAkaAttributeRes(payload: payload.subdata(in: 2..<2 + 8)) - } - - static let SIZE = 12 // type, size, len in bits=2, payload=8 - static private let PAYLOAD_SIZE_BITS = 0x64 // type, size, 2 reserved bytes, payload -} - -class EapAkaAttributeCustomIV: EapAkaAttribute { - - init(payload: Data) throws { - super.init() - self.payload = payload - if payload.count != 4 { throw MessageError.notEnoughData } - } - - override func toData() -> Data { - return Data([EapAkaAttributeType.AT_CUSTOM_IV.rawValue, UInt8(EapAkaAttributeCustomIV.SIZE / SIZE_MULTIPLIER), 0x00, 0x00]) + payload - } - - static func parse(payload: Data) throws -> EapAkaAttributeCustomIV { - if (payload.count < 2 + 4) { - throw MessageError.notEnoughData - } - return try EapAkaAttributeCustomIV(payload: payload.subdata(in: 2..<2 + 4)) - } - - static let SIZE = 8 // type, size, 2 reserved bytes, payload=4 -} - -class EapAkaAttributeClientErrorCode: EapAkaAttribute { - - init(payload: Data) throws { - super.init() - self.payload = payload - if payload.count != 2 { throw MessageError.notEnoughData } - } - - override func toData() -> Data { - return Data([EapAkaAttributeType.AT_CLIENT_ERROR_CODE.rawValue, UInt8(EapAkaAttributeClientErrorCode.SIZE / SIZE_MULTIPLIER), 0x00, 0x00]) + payload - } - - static func parse(payload: Data) throws -> EapAkaAttributeClientErrorCode { - if (payload.count < 2 + 2) { - throw MessageError.notEnoughData - } - return try EapAkaAttributeClientErrorCode(payload: payload.subdata(in: 2..<4)) - } - - static let SIZE = 4 // type, size=1, payload:2 -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Session/EapMessage.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/Session/EapMessage.swift deleted file mode 100644 index 4fc8f32b0..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Session/EapMessage.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// EapMessage.swift -// OmniBLE -// -// Created by Randall Knutson on 11/8/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -enum EapCode: UInt8 { - case REQUEST = 0x01 - case RESPONSE = 0x02 - case SUCCESS = 0x03 - case FAILURE = 0x04 -} - -struct EapMessage { - var code: EapCode - var identifier: UInt8 - var subType: UInt8 = 0 - var attributes: [EapAkaAttribute] - - func toData() -> Data { - - var joinedAttributes = Data() - for attribute in attributes { - joinedAttributes.append(attribute.toData()) - } - - let attrSize = joinedAttributes.count - if (attrSize == 0) { - return Data([code.rawValue, identifier, 0x00, 0x04]) - } - let totalSize = EapMessage.HEADER_SIZE + attrSize - - var bb = Data() - bb.append(code.rawValue) - bb.append(identifier) - bb.append(UInt8((totalSize >> 8) & 0xFF)) - bb.append(UInt8(totalSize & 0xFF)) - bb.append(UInt8(EapMessage.AKA_PACKET_TYPE)) - bb.append(UInt8(EapMessage.SUBTYPE_AKA_CHALLENGE)) - bb.append(Data([0x00, 0x00])) - bb.append(joinedAttributes) - - return bb - } - - private static let HEADER_SIZE = 8 - private static let SUBTYPE_AKA_CHALLENGE = 0x01 - static let SUBTYPE_SYNCRONIZATION_FAILURE = 0x04 - - private static let AKA_PACKET_TYPE = 0x17 - - static func parse(payload: Data) throws -> EapMessage { - guard payload.count > 4 else { throw MessageError.notEnoughData } - - let totalSize = (Int(payload[2]) << 8) | Int(payload[3]) - guard payload.count == totalSize else { throw MessageError.notEnoughData } - - - if (payload.count == 4) { // SUCCESS/FAILURE - return EapMessage( - code: EapCode(rawValue: payload[0])!, - identifier: payload[1], - attributes: [] - ) - } - if (totalSize > 0 && payload[4] != AKA_PACKET_TYPE) { - throw MessageError.validationFailed(description: "Invalid eap payload.") - } - let attributesPayload = payload.subdata(in: 8.. Int { - return (Data([0x00, 0x00]) + data).withUnsafeBytes { - $0.load(as: Int.self).bigEndian - } - } - - func increment() -> EapSqn { - return EapSqn(int: toInt() + 1) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Session/Milenage.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/Session/Milenage.swift deleted file mode 100644 index 6b1f5e741..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Session/Milenage.swift +++ /dev/null @@ -1,134 +0,0 @@ -// -// Milenage.swift -// OmniBLE -// -// Created by Randall Knutson on 11/8/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import os.log -import CryptoSwift - -enum MilenageError: Error { - case Error(String) -} - -class Milenage { - static let RESYNC_AMF = Data(hex: "0000") - static let MILENAGE_OP = Data(hex: "cdc202d5123e20f62b6d676ac72cb318") - static let MILENAGE_AMF = Data(hex: "b9b9") - static let KEY_SIZE = 16 - static let AUTS_SIZE = 14 - static private let SQN = 6 - - private let log = OSLog(subsystem: "Milenage", category: "Milenage") - private let k: Data - let sqn: Data - let auts: Data - let amf: Data - var ck: Data - var autn: Data - var rand: Data - var synchronizationSqn: Data - var res: Data - var ak: Data - var macS: Data - var receivedMacS: Data - - init(k: Data, sqn: Data, randParam: Data? = nil, auts: Data = Data(repeating: 0x00, count: 14), amf: Data = Milenage.MILENAGE_AMF) throws { - guard (k.count == Milenage.KEY_SIZE) else { throw MilenageError.Error("Milenage key has to be \(Milenage.KEY_SIZE) bytes long. Received: \(k.hexadecimalString)") } - guard (sqn.count == Milenage.SQN) else { throw MilenageError.Error("Milenage SQN has to be \(Milenage.SQN) long. Received: \(sqn.hexadecimalString)") } - guard (auts.count == Milenage.AUTS_SIZE) else { throw MilenageError.Error("Milenage AUTS has to be \(Milenage.AUTS_SIZE) long. Received: \(auts.hexadecimalString)") } - guard (amf.count == Milenage.MILENAGE_AMF.count) else { - throw MilenageError.Error("Milenage AMF has to be ${MILENAGE_AMF.count} long." + - "Received: ${amf.toHex()}") - } - self.k = k - self.sqn = sqn - self.auts = auts - self.amf = amf - - let cipher = try AES(key: k.bytes, blockMode: ECB(), padding: .noPadding) - - let random = OmniRandomByteGenerator() - rand = randParam ?? random.nextBytes(length: Milenage.KEY_SIZE) - - let opc = Data(try cipher.encrypt(Milenage.MILENAGE_OP.bytes)) ^ Milenage.MILENAGE_OP - let randOpcEncrypted = Data(try cipher.encrypt((rand ^ opc).bytes)) - let randOpcEncryptedxorOpc = randOpcEncrypted ^ opc - var resAkInput = randOpcEncryptedxorOpc.subdata(in: 0..(repeating: 0x00, count: Milenage.KEY_SIZE) - - for i in 0...15 { - ckInput[(i + 12) % 16] = randOpcEncryptedxorOpc[i] - } - ckInput[15] = UInt8((Int(ckInput[15]) ^ 2)) - - ck = Data(try cipher.encrypt(ckInput)) ^ opc - - let sqnAmf = sqn + amf + sqn + amf - let sqnAmfxorOpc = sqnAmf ^ opc - var macAInput = Array(repeating: 0x00, count: Milenage.KEY_SIZE) - - for i in 0...15 { - macAInput[(i + 8) % 16] = sqnAmfxorOpc[i] - } - - let macAFull = Data(try cipher.encrypt((Data(macAInput) ^ randOpcEncrypted).bytes)) ^ opc - let macA = macAFull.subdata(in: 0..<8) - macS = macAFull.subdata(in: 8..<16) - - autn = (ak ^ sqn) + amf + macA - - // Used for re-synchronisation AUTS = SQN^AK || MAC-S - var akStarInput = Array(repeating: 0x00, count: Milenage.KEY_SIZE) - - for i in 0...15 { - akStarInput[(i + 4) % 16] = randOpcEncryptedxorOpc[i] - } - akStarInput[15] = UInt8((Int(akStarInput[15]) ^ 8)) - - let akStarFull = Data(try cipher.encrypt(akStarInput)) ^ opc - let akStar = akStarFull.subdata(in: 0..<6) - - let seqxorAkStar = auts.subdata(in: 0..<6) - synchronizationSqn = akStar ^ seqxorAkStar - receivedMacS = auts.subdata(in: 6..<14) - - // print("Milenage K: \(k.hexadecimalString)") - // print("Milenage RAND: \(rand.hexadecimalString)") - // print("Milenage SQN: \(sqn.hexadecimalString)") - // print("Milenage CK: \(ck.hexadecimalString)") - // print("Milenage AUTN: \(autn.hexadecimalString)") - // print("Milenage RES: \(res.hexadecimalString)") - // print("Milenage AK: \(ak.hexadecimalString)") - // print("Milenage AK STAR: \(akStar.hexadecimalString)") - // print("Milenage OPC: \(opc.hexadecimalString)") - // print("Milenage FullMAC: \(macAFull.hexadecimalString)") - // print("Milenage MacA: \(macA.hexadecimalString)") - // print("Milenage MacS: \(macS.hexadecimalString)") - // print("Milenage AUTS: \(auts.hexadecimalString)") - // print("Milenage synchronizationSqn: \(synchronizationSqn.hexadecimalString)") - // print("Milenage receivedMacS: \(receivedMacS.hexadecimalString)") - } - -} - -extension Data { - static func ^ (left: Data, right: Data) -> Data { - var out = Array(repeating: 0x00, count: left.count) - for i in 0.. SessionResult { - msgSeq += 1 - let challenge = try eapAkaChallenge() - let sendResult = manager.sendMessagePacket(challenge) - guard case .sentWithAcknowledgment = sendResult else { - throw SessionEstablishmentException.CommunicationError("Could not send the EAP AKA challenge: $sendResult") - } - guard let challengeResponse = try manager.readMessagePacket() else { - throw SessionEstablishmentException.CommunicationError("Could not establish session") - } - - let newSqn = try processChallengeResponse(challengeResponse: challengeResponse) - if (newSqn != nil) { - return .SessionNegotiationResynchronization(SessionNegotiationResynchronization( - synchronizedEapSqn: newSqn!, - msgSequenceNumber: UInt8(msgSeq) - )) - } - - msgSeq += 1 - let success = eapSuccess() - let _ = manager.sendMessagePacket(success) - - return .SessionKeys(SessionKeys( - ck: milenage.ck, - nonce: Nonce(prefix: controllerIV + nodeIV), - msgSequenceNumber: msgSeq - )) - } - - private func eapAkaChallenge() throws -> MessagePacket { - let attributes = [ - try EapAkaAttributeAutn(payload: milenage.autn), - try EapAkaAttributeRand(payload: milenage.rand), - try EapAkaAttributeCustomIV(payload: controllerIV) - ] - - let eapMsg = EapMessage( - code: EapCode.REQUEST, - identifier: identifier, - attributes: attributes - ) - return MessagePacket( - type: MessageType.SESSION_ESTABLISHMENT, - source: myId, - destination: podId, - payload: eapMsg.toData(), - sequenceNumber: UInt8(msgSeq) - ) - } - - private func assertIdentifier(msg: EapMessage) throws { - if (msg.identifier != identifier) { - log.debug("EAP-AKA: got incorrect identifier ${msg.identifier} expected: $identifier") - throw SessionEstablishmentException.CommunicationError("Received incorrect EAP identifier: ${msg.identifier}") - } - } - - private func processChallengeResponse(challengeResponse: MessagePacket) throws -> EapSqn? { - let eapMsg = try EapMessage.parse(payload: challengeResponse.payload) - - try assertIdentifier(msg: eapMsg) - - let eapSqn = try isResynchronization(eapMsg: eapMsg) - if (eapSqn != nil) { - return eapSqn - } - - try assertValidAkaMessage(eapMsg: eapMsg) - - for attr in eapMsg.attributes { - switch attr { - case is EapAkaAttributeRes: - if (milenage.res != attr.payload) { - throw SessionEstablishmentException.CommunicationError( - "RES mismatch." + - "Expected: ${milenage.res.toHex()}." + - "Actual: ${attr.payload.toHex()}." - ) - } - case is EapAkaAttributeCustomIV: - nodeIV = attr.payload.subdata(in: 0.. EapSqn? { - if (eapMsg.subType != EapMessage.SUBTYPE_SYNCRONIZATION_FAILURE || - eapMsg.attributes.count != 1 || - eapMsg.attributes[0] as? EapAkaAttributeAuts == nil - ) { - return nil - } - - let auts = eapMsg.attributes[0] as! EapAkaAttributeAuts - let autsMilenage = try Milenage( - k: ltk, - sqn: eapSqn, - randParam: milenage.rand, - auts: auts.payload - ) - - let newSqnMilenage = try Milenage( - k: ltk, - sqn: autsMilenage.synchronizationSqn, - randParam: milenage.rand, - auts: auts.payload, - amf: Milenage.RESYNC_AMF - ) - - if (newSqnMilenage.macS != newSqnMilenage.receivedMacS) { - throw SessionEstablishmentException.CommunicationError( - "MacS mismatch. " + - "Expected: ${newSqnMilenage.macS.toHex()}. " + - "Received: ${newSqnMilenage.receivedMacS.toHex()}" - ) - } - return try EapSqn(data: autsMilenage.synchronizationSqn) - } - - private func eapSuccess() -> MessagePacket { - let eapMsg = EapMessage( - code: EapCode.SUCCESS, - identifier: UInt8(identifier), - attributes: Array() - ) - - return MessagePacket( - type: MessageType.SESSION_ESTABLISHMENT, - source: myId, - destination: podId, - payload: eapMsg.toData(), - sequenceNumber: UInt8(msgSeq) - ) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Session/SessionKeys.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/Session/SessionKeys.swift deleted file mode 100644 index f0cef890f..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Session/SessionKeys.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// SessionKeys.swift -// OmniBLE -// -// Created by Randall Knutson on 11/8/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -struct SessionKeys { - var ck: Data - var nonce: Nonce - var msgSequenceNumber: Int -} - -struct SessionNegotiationResynchronization { - let synchronizedEapSqn: EapSqn - let msgSequenceNumber: UInt8 -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/StringLengthPrefixEncoding.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/StringLengthPrefixEncoding.swift deleted file mode 100644 index 8f5218195..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/StringLengthPrefixEncoding.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// StringLengthPrefixEncoding.swift -// OmniBLE -// -// Created by Randall Knutson on 8/5/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -final class StringLengthPrefixEncoding { - - static private let LENGTH_BYTES = 2 - - static func parseKeys(_ keys: Array, _ payload: Data) throws -> [Data] { - var ret = Array(repeating: Data(capacity: 0), count: keys.count) - var remaining = payload - for (index, key) in keys.enumerated() { - guard remaining.count >= key.count else { - throw PodProtocolError.messageIOException("Payload too short: \(payload)") - } - if (String(decoding: remaining.subdata(in: 0..= (key.count + LENGTH_BYTES) else { - throw PodProtocolError.messageIOException("Payload too short: \(payload)") - } - remaining = remaining.subdata(in: key.count..= length else { - throw PodProtocolError.messageIOException("Payload too short: \(payload)") - } - ret[index] = remaining.subdata(in: LENGTH_BYTES.., payloads: Array) -> Data { - let payloadTotalSize = payloads.reduce(0, { acc, i in acc + i.count }) - let keyTotalSize = keys.reduce(0, { acc, i in acc + i.count }) - let zeros = payloads.reduce(0, { acc, i in acc + (i.count == 0 ? 1 : 0) }) - - var bb = Data(capacity: 2 * (keys.count - zeros) + keyTotalSize + payloadTotalSize) - for (idx, key) in keys.enumerated() { - let payload = payloads[idx] - bb.append(key.data(using: .utf8)!) - if (payload.count != 0) { - bb.append(withUnsafeBytes(of: Int16(payload.count).bigEndian) { Data($0) }) - bb.append(payload) - } - } - - return bb - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Util/OmniRandomByteGenerator.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/Util/OmniRandomByteGenerator.swift deleted file mode 100644 index 3424b9596..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Util/OmniRandomByteGenerator.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// RandomByteGenerator.swift -// OmniBLE -// -// Created by Randall Knutson on 8/8/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -class OmniRandomByteGenerator: RandomByteGenerator { - func nextBytes(length: Int) -> Data { - var bytes = [Int8](repeating: 0, count: length) - let status = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes) - if status == errSecSuccess { // Always test the status. - return Data(bytes: bytes, count: bytes.count) - } - return Data() - } -} - -protocol RandomByteGenerator { - func nextBytes(length: Int) -> Data -} diff --git a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Util/X25519KeyGenerator.swift b/Dependencies/OmniBLE/OmniBLE/Bluetooth/Util/X25519KeyGenerator.swift deleted file mode 100644 index 36b2de051..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Bluetooth/Util/X25519KeyGenerator.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// X25519KeyGenerator.swift -// OmniBLE -// -// Created by Randall Knutson on 8/8/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// -import CryptoKit -import Foundation - -struct X25519KeyGenerator: PrivateKeyGenerator { - func generatePrivateKey() -> Data { - let key = Curve25519.KeyAgreement.PrivateKey() - return key.rawRepresentation - } - func publicFromPrivate(_ privateKey: Data) throws -> Data{ - let key = try Curve25519.KeyAgreement.PrivateKey(rawRepresentation: privateKey) - return key.publicKey.rawRepresentation - } - func computeSharedSecret(_ privateKey: Data, _ publicKey: Data) throws -> Data { - let priv = try Curve25519.KeyAgreement.PrivateKey(rawRepresentation: privateKey) - let pub = try Curve25519.KeyAgreement.PublicKey(rawRepresentation: publicKey) - let secret = try priv.sharedSecretFromKeyAgreement(with: pub) - return secret.withUnsafeBytes({ return Data($0)}) - } -} - -protocol PrivateKeyGenerator { - func generatePrivateKey() -> Data - func publicFromPrivate(_ privateKey: Data) throws -> Data - func computeSharedSecret(_ privateKey: Data, _ publicKey: Data) throws -> Data -} diff --git a/Dependencies/OmniBLE/OmniBLE/Info.plist b/Dependencies/OmniBLE/OmniBLE/Info.plist deleted file mode 100644 index 9bcb24442..000000000 --- a/Dependencies/OmniBLE/OmniBLE/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - 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 - $(CURRENT_PROJECT_VERSION) - - diff --git a/Dependencies/OmniBLE/OmniBLE/OmniBLE.h b/Dependencies/OmniBLE/OmniBLE/OmniBLE.h deleted file mode 100644 index edf827448..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmniBLE.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// OmniBLE.h -// OmniBLE -// -// Created by Randall Knutson on 9/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -#import - -//! Project version number for OmniBLE. -FOUNDATION_EXPORT double OmniBLEVersionNumber; - -//! Project version string for OmniBLE. -FOUNDATION_EXPORT const unsigned char OmniBLEVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/AlertSlot.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/AlertSlot.swift deleted file mode 100644 index d61dd190b..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/AlertSlot.swift +++ /dev/null @@ -1,719 +0,0 @@ -// -// Alert.swift -// OmniBLE -// -// From OmniKit/Model/Alert.swift -// Created by Pete Schwamb on 10/24/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -fileprivate let defaultShutdownImminentTime = Pod.serviceDuration - Pod.endOfServiceImminentWindow -fileprivate let defaultExpirationReminderTime = Pod.nominalPodLife - Pod.defaultExpirationReminderOffset -fileprivate let defaultExpiredTime = Pod.nominalPodLife - -// PDM and pre-SwiftUI use every1MinuteFor3MinutesAndRepeatEvery15Minutes, but with SwiftUI use every15Minutes -fileprivate let suspendTimeExpiredBeepRepeat = BeepRepeat.every15Minutes - -public enum AlertTrigger { - case unitsRemaining(Double) - case timeUntilAlert(TimeInterval) -} - -extension AlertTrigger: CustomDebugStringConvertible { - public var debugDescription: String { - switch self { - case .unitsRemaining(let units): - return "\(Int(units))U" - case .timeUntilAlert(let triggerTime): - return "triggerTime=\(triggerTime.timeIntervalStr)" - } - } -} - -public enum BeepRepeat: UInt8 { - case once = 0 - case every1MinuteFor3MinutesAndRepeatEvery60Minutes = 1 - case every1MinuteFor15Minutes = 2 - case every1MinuteFor3MinutesAndRepeatEvery15Minutes = 3 - case every3MinutesFor60minutesStartingAt2Minutes = 4 - case every60Minutes = 5 - case every15Minutes = 6 - case every15MinutesFor60minutesStartingAt14Minutes = 7 - case every5Minutes = 8 -} - - -public struct AlertConfiguration { - - let slot: AlertSlot - let active: Bool - let duration: TimeInterval - let trigger: AlertTrigger - let beepRepeat: BeepRepeat - let beepType: BeepType - let silent: Bool - let autoOffModifier: Bool - - static let length = 6 - - public init(alertType: AlertSlot, active: Bool = true, duration: TimeInterval = 0, trigger: AlertTrigger, beepRepeat: BeepRepeat, beepType: BeepType, silent: Bool = false, autoOffModifier: Bool = false) - { - self.slot = alertType - self.active = active - self.duration = duration - self.trigger = trigger - self.beepRepeat = beepRepeat - self.beepType = beepType - self.silent = silent - self.autoOffModifier = autoOffModifier - } -} - -extension AlertConfiguration: CustomDebugStringConvertible { - public var debugDescription: String { - var str = "slot:\(slot)" - if !active { - str += ", active:\(active)" - } - if duration != 0 { - str += ", duration:\(duration.timeIntervalStr)" - } - str += ", trigger:\(trigger), beepRepeat:\(beepRepeat)" - if beepType != .noBeepNonCancel { - str += ", beepType:\(beepType)" - } else { - str += ", silent:\(silent)" - } - if autoOffModifier { - str += ", autoOffModifier:\(autoOffModifier)" - } - return "\nAlertConfiguration(\(str))" - } -} - - - -public enum PodAlert: CustomStringConvertible, RawRepresentable, Equatable { - public typealias RawValue = [String: Any] - - // slot0AutoOff: auto-off timer; requires user input every x minutes -- NOT IMPLEMENTED - case autoOff(active: Bool, offset: TimeInterval, countdownDuration: TimeInterval, silent: Bool = false) - - // slot1NotUsed - case notUsed - - // slot2ShutdownImminent: 79 hour alarm (1 hour before shutdown) - // 2 sets of beeps every 15 minutes for 1 hour - case shutdownImminent(offset: TimeInterval, absAlertTime: TimeInterval, silent: Bool = false) - - // slot3ExpirationReminder: User configurable with PDM (1-24 hours before 72 hour expiration) - // 2 sets of beeps every minute for 3 minutes and repeat every 15 minutes - // The PDM doesn't use a duration for this alert (presumably because it is limited to 2^9-1 minutes or 8h31m) - case expirationReminder(offset: TimeInterval, absAlertTime: TimeInterval, duration: TimeInterval = 0, silent: Bool = false) - - // slot4LowReservoir: reservoir below configured value alert - case lowReservoir(units: Double, silent: Bool = false) - - // slot5SuspendedReminder: pod suspended reminder, before suspendTime; - // short beep every 15 minutes if > 30 min, else short beep every 5 minutes - case podSuspendedReminder(active: Bool, offset: TimeInterval, suspendTime: TimeInterval, timePassed: TimeInterval = 0, silent: Bool = false) - - // slot6SuspendTimeExpired: pod suspend time expired alarm, after suspendTime; - // 2 sets of beeps every minute for 3 minutes repeated every 15 minutes (PDM & pre-SwiftUI implementations) - // 2 sets of beeps every 15 minutes (for SwiftUI PumpManagerAlerts implementations) - case suspendTimeExpired(offset: TimeInterval, suspendTime: TimeInterval, silent: Bool = false) - - // slot7Expired: 2 hours long, time for user to start pairing process - case waitingForPairingReminder - - // slot7Expired: 1 hour long, time for user to finish priming, cannula insertion - case finishSetupReminder - - // slot7Expired: 72 hour alarm - case expired(offset: TimeInterval, absAlertTime: TimeInterval, duration: TimeInterval, silent: Bool = false) - - public var description: String { - var alertName: String - switch self { - // slot0AutoOff - case .autoOff: - alertName = LocalizedString("Auto-off", comment: "Description for auto-off alert") - // slot1NotUsed - case .notUsed: - alertName = LocalizedString("Not used", comment: "Description for not used slot alert") - // slot2ShutdownImminent - case .shutdownImminent: - alertName = LocalizedString("Shutdown imminent", comment: "Description for shutdown imminent alert") - // slot3ExpirationReminder - case .expirationReminder: - alertName = LocalizedString("Expiration reminder", comment: "Description for expiration reminder alert") - // slot4LowReservoir - case .lowReservoir: - alertName = LocalizedString("Low reservoir", comment: "Format string for description for low reservoir alert") - // slot5SuspendedReminder - case .podSuspendedReminder: - alertName = LocalizedString("Pod suspended reminder", comment: "Description for pod suspended reminder alert") - // slot6SuspendTimeExpired - case .suspendTimeExpired: - alertName = LocalizedString("Suspend time expired", comment: "Description for suspend time expired alert") - // slot7Expired - case .waitingForPairingReminder: - alertName = LocalizedString("Waiting for pairing reminder", comment: "Description waiting for pairing reminder alert") - case .finishSetupReminder: - alertName = LocalizedString("Finish setup reminder", comment: "Description for finish setup reminder alert") - case .expired: - alertName = LocalizedString("Pod expired", comment: "Description for pod expired alert") - } - if self.configuration.active == false { - alertName += LocalizedString(" (inactive)", comment: "Description for an inactive alert modifier") - } - return alertName - } - - public var configuration: AlertConfiguration { - switch self { - // slot0AutoOff - case .autoOff(let active, _, let countdownDuration, let silent): - return AlertConfiguration(alertType: .slot0AutoOff, active: active, duration: .minutes(15), trigger: .timeUntilAlert(countdownDuration), beepRepeat: .every1MinuteFor15Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep, silent: silent, autoOffModifier: true) - - // slot1NotUsed - case .notUsed: - return AlertConfiguration(alertType: .slot1NotUsed, duration: .minutes(55), trigger: .timeUntilAlert(.minutes(5)), beepRepeat: .every5Minutes, beepType: .noBeepNonCancel) - - // slot2ShutdownImminent - case .shutdownImminent(let offset, let absAlertTime, let silent): - let active = absAlertTime != 0 // disable if absAlertTime is 0 - let triggerTime: TimeInterval - if active { - triggerTime = absAlertTime - offset - } else { - triggerTime = 0 - } - return AlertConfiguration(alertType: .slot2ShutdownImminent, active: active, trigger: .timeUntilAlert(triggerTime), beepRepeat: .every15Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep, silent: silent) - - // slot3ExpirationReminder - case .expirationReminder(let offset, let absAlertTime, let duration, let silent): - let active = absAlertTime != 0 // disable if absAlertTime is 0 - let triggerTime: TimeInterval - if active { - triggerTime = absAlertTime - offset - } else { - triggerTime = 0 - } - return AlertConfiguration(alertType: .slot3ExpirationReminder, active: active, duration: duration, trigger: .timeUntilAlert(triggerTime), beepRepeat: .every1MinuteFor3MinutesAndRepeatEvery15Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep, silent: silent) - - // slot4LowReservoir - case .lowReservoir(let units, let silent): - let active = units != 0 // disable if units is 0 - return AlertConfiguration(alertType: .slot4LowReservoir, active: active, trigger: .unitsRemaining(units), beepRepeat: .every1MinuteFor3MinutesAndRepeatEvery60Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep, silent: silent) - - // slot5SuspendedReminder - // A suspendTime of 0 is an untimed suspend - // timePassed will be > 0 for an existing pod suspended reminder changing its silent state - case .podSuspendedReminder(let active, _, let suspendTime, let timePassed, let silent): - let reminderInterval, duration: TimeInterval - var beepRepeat: BeepRepeat - let beepType: BeepType - let trigger: AlertTrigger - var isActive: Bool = active - - if suspendTime == 0 || suspendTime >= TimeInterval(minutes: 30) { - // Use 15-minute pod suspended reminder beeps for untimed or longer scheduled suspend times. - reminderInterval = TimeInterval(minutes: 15) - beepRepeat = .every15Minutes - } else { - // Use 5-minute pod suspended reminder beeps for shorter scheduled suspend times. - reminderInterval = TimeInterval(minutes: 5) - beepRepeat = .every5Minutes - } - - // Make alert inactive if there isn't enough remaining in suspend time for a reminder beep. - let suspendTimeRemaining = suspendTime - timePassed - if suspendTime != 0 && suspendTimeRemaining <= reminderInterval { - isActive = false - } - - if isActive { - // Compute the alert trigger time as the interval until the next upcoming reminder interval - let triggerTime: TimeInterval = .seconds(reminderInterval - Double((Int(timePassed) % Int(reminderInterval)))) - - if suspendTime == 0 { - duration = 0 // Untimed suspend, no duration - } else { - // duration is from triggerTime to suspend time remaining - duration = suspendTimeRemaining - triggerTime - } - trigger = .timeUntilAlert(triggerTime) // time to next reminder interval with the suspend time - beepType = .beep - } else { - beepRepeat = .once - duration = 0 - trigger = .timeUntilAlert(.minutes(0)) - beepType = .noBeepCancel - } - return AlertConfiguration(alertType: .slot5SuspendedReminder, active: isActive, duration: duration, trigger: trigger, beepRepeat: beepRepeat, beepType: beepType, silent: silent) - - // slot6SuspendTimeExpired - case .suspendTimeExpired(_, let suspendTime, let silent): - let active = suspendTime != 0 // disable if suspendTime is 0 - let trigger: AlertTrigger - let beepRepeat: BeepRepeat - let beepType: BeepType - if active { - trigger = .timeUntilAlert(suspendTime) - beepRepeat = suspendTimeExpiredBeepRepeat - beepType = .bipBeepBipBeepBipBeepBipBeep - } else { - trigger = .timeUntilAlert(.minutes(0)) - beepRepeat = .once - beepType = .noBeepCancel - } - return AlertConfiguration(alertType: .slot6SuspendTimeExpired, active: active, trigger: trigger, beepRepeat: beepRepeat, beepType: beepType, silent: silent) - - // slot7Expired - case .waitingForPairingReminder: - // After pod is powered up, beep every 10 minutes for up to 2 hours before pairing before failing - let totalDuration: TimeInterval = .hours(2) - let startOffset: TimeInterval = .minutes(10) - return AlertConfiguration(alertType: .slot7Expired, duration: totalDuration - startOffset, trigger: .timeUntilAlert(startOffset), beepRepeat: .every5Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep) - case .finishSetupReminder: - // After pod is paired, beep every 5 minutes for up to 1 hour for pod setup to complete before failing - let totalDuration: TimeInterval = .hours(1) - let startOffset: TimeInterval = .minutes(5) - return AlertConfiguration(alertType: .slot7Expired, duration: totalDuration - startOffset, trigger: .timeUntilAlert(startOffset), beepRepeat: .every5Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep) - case .expired(let offset, let absAlertTime, let duration, let silent): - // Normally used to alert at Pod.nominalPodLife (72 hours) for Pod.expirationAdvisoryWindow (7 hours) - // 2 sets of beeps repeating every 60 minutes - let active = absAlertTime != 0 // disable if absAlertTime is 0 - let triggerTime: TimeInterval - if active { - triggerTime = absAlertTime - offset - } else { - triggerTime = .minutes(0) - } - return AlertConfiguration(alertType: .slot7Expired, active: active, duration: duration, trigger: .timeUntilAlert(triggerTime), beepRepeat: .every60Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep, silent: silent) - } - } - - - // MARK: - RawRepresentable - public init?(rawValue: RawValue) { - - guard let name = rawValue["name"] as? String else { - return nil - } - - switch name { - case "autoOff": - guard let active = rawValue["active"] as? Bool, - let countdownDuration = rawValue["countdownDuration"] as? TimeInterval else - { - return nil - } - let offset = rawValue["offset"] as? TimeInterval ?? 0 - let silent = rawValue["silent"] as? Bool ?? false - self = .autoOff(active: active, offset: offset, countdownDuration: countdownDuration, silent: silent) - case "shutdownImminent": - guard let alarmTime = rawValue["alarmTime"] as? TimeInterval else { - return nil - } - let offset = rawValue["offset"] as? TimeInterval ?? 0 - let offsetToUse, absAlertTime: TimeInterval - if offset == 0 { - // use default values as no offset value was found - absAlertTime = defaultShutdownImminentTime - offsetToUse = absAlertTime - alarmTime - } else { - absAlertTime = offset + alarmTime - offsetToUse = offset - } - let silent = rawValue["silent"] as? Bool ?? false - self = .shutdownImminent(offset: offsetToUse, absAlertTime: absAlertTime, silent: silent) - case "expirationReminder": - guard let alertTime = rawValue["alertTime"] as? TimeInterval else { - return nil - } - let offset = rawValue["offset"] as? TimeInterval ?? 0 - let offsetToUse, absAlertTime: TimeInterval - if offset == 0 { - // use default values as no offset value was found - absAlertTime = defaultExpirationReminderTime - offsetToUse = absAlertTime - alertTime - } else { - absAlertTime = offset + alertTime - offsetToUse = offset - } - let duration = rawValue["duration"] as? TimeInterval ?? 0 - let silent = rawValue["silent"] as? Bool ?? false - self = .expirationReminder(offset: offsetToUse, absAlertTime: absAlertTime, duration: duration, silent: silent) - case "lowReservoir": - guard let units = rawValue["units"] as? Double else { - return nil - } - let silent = rawValue["silent"] as? Bool ?? false - self = .lowReservoir(units: units, silent: silent) - case "podSuspendedReminder": - guard let active = rawValue["active"] as? Bool, - let suspendTime = rawValue["suspendTime"] as? TimeInterval else - { - return nil - } - let offset = rawValue["offset"] as? TimeInterval ?? 0 - let silent = rawValue["silent"] as? Bool ?? false - self = .podSuspendedReminder(active: active, offset: offset, suspendTime: suspendTime, silent: silent) - case "suspendTimeExpired": - guard let suspendTime = rawValue["suspendTime"] as? Double else { - return nil - } - let offset = rawValue["offset"] as? TimeInterval ?? 0 - let silent = rawValue["silent"] as? Bool ?? false - self = .suspendTimeExpired(offset: offset, suspendTime: suspendTime, silent: silent) - case "waitingForPairingReminder": - self = .waitingForPairingReminder - case "finishSetupReminder": - self = .finishSetupReminder - case "expired": - guard let alarmTime = rawValue["alarmTime"] as? TimeInterval, - let duration = rawValue["duration"] as? TimeInterval else - { - return nil - } - let offset = rawValue["offset"] as? TimeInterval ?? 0 - let offsetToUse, absAlertTime: TimeInterval - if offset == 0 { - // use default values as no offset value was found - absAlertTime = defaultExpiredTime - offsetToUse = absAlertTime - alarmTime - } else { - absAlertTime = offset + alarmTime - offsetToUse = offset - } - let silent = rawValue["silent"] as? Bool ?? false - self = .expired(offset: offsetToUse, absAlertTime: absAlertTime, duration: duration, silent: silent) - default: - return nil - } - } - - public var rawValue: RawValue { - - let name: String = { - switch self { - case .autoOff: - return "autoOff" - case .notUsed: - return "notUsed" - case .shutdownImminent: - return "shutdownImminent" - case .expirationReminder: - return "expirationReminder" - case .lowReservoir: - return "lowReservoir" - case .podSuspendedReminder: - return "podSuspendedReminder" - case .suspendTimeExpired: - return "suspendTimeExpired" - case .waitingForPairingReminder: - return "waitingForPairingReminder" - case .finishSetupReminder: - return "finishSetupReminder" - case .expired: - return "expired" - } - }() - - var rawValue: RawValue = [ - "name": name, - ] - - switch self { - case .autoOff(let active, let offset, let countdownDuration, let silent): - rawValue["active"] = active - rawValue["offset"] = offset - rawValue["countdownDuration"] = countdownDuration - rawValue["silent"] = silent - case .shutdownImminent(let offset, let absAlertTime, let silent): - rawValue["offset"] = offset - rawValue["alarmTime"] = absAlertTime - offset - rawValue["silent"] = silent - case .expirationReminder(let offset, let absAlertTime, let duration, let silent): - rawValue["offset"] = offset - rawValue["alertTime"] = absAlertTime - offset - rawValue["duration"] = duration - rawValue["silent"] = silent - case .lowReservoir(let units, let silent): - rawValue["units"] = units - rawValue["silent"] = silent - case .podSuspendedReminder(let active, let offset, let suspendTime, _, let silent): - rawValue["active"] = active - rawValue["offset"] = offset - rawValue["suspendTime"] = suspendTime - rawValue["silent"] = silent - case .suspendTimeExpired(let offset, let suspendTime, let silent): - rawValue["offset"] = offset - rawValue["suspendTime"] = suspendTime - rawValue["silent"] = silent - case .expired(let offset, let absAlertTime, let duration, let silent): - rawValue["offset"] = offset - rawValue["alarmTime"] = absAlertTime - offset - rawValue["duration"] = duration - rawValue["silent"] = silent - default: - break - } - - return rawValue - } -} - -public enum AlertSlot: UInt8 { - case slot0AutoOff = 0x00 - case slot1NotUsed = 0x01 - case slot2ShutdownImminent = 0x02 - case slot3ExpirationReminder = 0x03 - case slot4LowReservoir = 0x04 - case slot5SuspendedReminder = 0x05 - case slot6SuspendTimeExpired = 0x06 - case slot7Expired = 0x07 - - public var bitMaskValue: UInt8 { - return 1< AlertSlot { - return elements[index] - } - - public func index(after i: Int) -> Int { - return i+1 - } - - public var description: String { - if elements.count == 0 { - return LocalizedString("No alerts", comment: "Pod alert state when no alerts are active") - } else { - let alarmDescriptions = elements.map { String(describing: $0) } - return alarmDescriptions.joined(separator: ", ") - } - } - - public func compare(to other: AlertSet) -> (added: AlertSet, removed: AlertSet) { - let added = Set(other.elements).subtracting(Set(elements)) - let removed = Set(elements).subtracting(Set(other.elements)) - return (added: AlertSet(slots: Array(added)), removed: AlertSet(slots: Array(removed))) - } -} - -// Returns true if there are any active suspend related alerts -public func hasActiveSuspendAlert(configuredAlerts: [AlertSlot : PodAlert]) -> Bool { - if configuredAlerts.contains(where: { ($0.key == .slot5SuspendedReminder || $0.key == .slot6SuspendTimeExpired) && $0.value.configuration.active }) - { - return true - } - return false -} - -// Returns a descriptive string for all the alerts in alertSet -public func alertSetString(alertSet: AlertSet) -> String { - - if alertSet.isEmpty { - // Don't bother displaying any additional info for an inactive alert - return String(describing: alertSet) - } - - let alertDescription = alertSet.map { (slot) -> String in - switch slot { - case .slot0AutoOff: - return PodAlert.autoOff(active: true, offset: 0, countdownDuration: 0).description - case .slot1NotUsed: - return PodAlert.notUsed.description - case .slot2ShutdownImminent: - return PodAlert.shutdownImminent(offset: 0, absAlertTime: defaultShutdownImminentTime).description - case .slot3ExpirationReminder: - return PodAlert.expirationReminder(offset: 0, absAlertTime: defaultExpirationReminderTime).description - case .slot4LowReservoir: - return PodAlert.lowReservoir(units: Pod.maximumReservoirReading).description - case .slot5SuspendedReminder: - return PodAlert.podSuspendedReminder(active: true, offset: 0, suspendTime: .minutes(30)).description - case .slot6SuspendTimeExpired: - return PodAlert.suspendTimeExpired(offset: 0, suspendTime: .minutes(30)).description - case .slot7Expired: - return PodAlert.expired(offset: 0, absAlertTime: defaultExpiredTime, duration: Pod.expirationAdvisoryWindow).description - } - } - - return alertDescription.joined(separator: ", ") -} - -func configuredAlertsString(configuredAlerts: [AlertSlot : PodAlert]) -> String { - - if configuredAlerts.isEmpty { - return String(describing: configuredAlerts) - } - - let configuredAlertString = configuredAlerts.map { (configuredAlert) -> String in - - let podAlert = configuredAlert.value - let description = podAlert.description - guard podAlert.configuration.active else { - return description - } - - switch podAlert { - case .shutdownImminent(_, let absAlertTime, _): - return String(format: "%@ @ %@", description, absAlertTime.timeIntervalStr) - case .expirationReminder(_, let absAlertTime, _, _): - return String(format: "%@ @ %@", description, absAlertTime.timeIntervalStr) - case .lowReservoir(let unitTrigger, _): - return String(format: "%@ @ %dU", description, Int(unitTrigger)) - case .podSuspendedReminder(_, let offset, let suspendTime, _, _): - return String(format: "%@ ending @ %@ after %@", description, (offset + suspendTime).timeIntervalStr, suspendTime.timeIntervalStr) - case .suspendTimeExpired(let offset, let suspendTime, _): - return String(format: "%@ @ %@ after %@", description, (offset + suspendTime).timeIntervalStr, suspendTime.timeIntervalStr) - case .expired(_, let absAlertTime, _, _): - return String(format: "%@ @ %@", description, absAlertTime.timeIntervalStr) - default: - return "" - } - } - - return configuredAlertString.joined(separator: ", ") -} - -// Returns an array of appropriate PodAlerts with the specified silent value -// for all the configuredAlerts given all the current pod conditions. -func regeneratePodAlerts(silent: Bool, configuredAlerts: [AlertSlot: PodAlert], activeAlertSlots: AlertSet, currentPodTime: TimeInterval, currentReservoirLevel: Double) -> [PodAlert] { - var podAlerts: [PodAlert] = [] - - for alert in configuredAlerts { - // Just skip this alert if not previously active - guard alert.value.configuration.active else { - continue - } - - // Map alerts to corresponding appropriate new ones at the current pod time using the specified silent value. - switch alert.value { - - case .shutdownImminent(let offset, let alertTime, _): - // alertTime is absolute when offset is non-zero, otherwise use default value - var absAlertTime = offset != 0 ? alertTime : defaultShutdownImminentTime - if currentPodTime >= absAlertTime { - // alert trigger is not in the future, make inactive using a 0 value - absAlertTime = 0 - } - // create new shutdownImminent podAlert using the current timeActive and the original absolute alert time - podAlerts.append(PodAlert.shutdownImminent(offset: currentPodTime, absAlertTime: absAlertTime, silent: silent)) - - case .expirationReminder(let offset, let alertTime, let alertDuration, _): - let duration: TimeInterval - - // alertTime is absolute when offset is non-zero, otherwise use default value - var absAlertTime = offset != 0 ? alertTime : defaultExpirationReminderTime - if currentPodTime >= absAlertTime { - // alert trigger is not in the future, make inactive using a 0 value - absAlertTime = 0 - duration = 0 - } else { - duration = alertDuration - } - // create new expirationReminder podAlert using the current active time and the original absolute alert time and duration - podAlerts.append(PodAlert.expirationReminder(offset: currentPodTime, absAlertTime: absAlertTime, duration: duration, silent: silent)) - - case .lowReservoir(let unitTrigger, _): - let units: Double - if currentReservoirLevel > unitTrigger { - units = unitTrigger - } else { - // reservoir is no longer more than the unitTrigger, make inactive using a 0 value - units = 0 - } - podAlerts.append(PodAlert.lowReservoir(units: units, silent: silent)) - - case .podSuspendedReminder(let active, let offset, let suspendTime, _, _): - let timePassed: TimeInterval = min(currentPodTime - offset, .hours(2)) - // Pass along the computed time passed since alert was originally set so creation routine can - // do all the grunt work dealing with varying reminder intervals and time passing scenarios. - podAlerts.append(PodAlert.podSuspendedReminder(active: active, offset: offset, suspendTime: suspendTime, timePassed: timePassed, silent: silent)) - - case .suspendTimeExpired(let lastOffset, let lastSuspendTime, _): - let absAlertTime = lastOffset + lastSuspendTime - let suspendTime: TimeInterval - if currentPodTime >= absAlertTime { - // alert trigger is no longer in the future - if activeAlertSlots.contains(where: { $0 == .slot6SuspendTimeExpired } ) { - // The suspendTimeExpired alert has yet been acknowledged, - // set up a suspendTimeExpired alert for the next 15m interval. - // Compute a new suspendTime that is a multiple of 15 minutes - // from lastOffset which is at least one minute in the future. - let newOffsetSuspendTime = ceil((currentPodTime - lastOffset) / .minutes(15)) * .minutes(15) - let newAbsAlertTime = lastOffset + newOffsetSuspendTime - suspendTime = max(newAbsAlertTime - currentPodTime, .minutes(1)) - } else { - // The suspendTimeExpired alert was already been acknowledged, - // so now make this alert inactive by using a 0 suspendTime. - suspendTime = 0 - } - } else { - // recompute a new suspendTime based on the current pod time - suspendTime = absAlertTime - currentPodTime - print("setting new suspendTimeExpired suspendTime of \(suspendTime) with currentPodTime\(currentPodTime) and absAlertTime=\(absAlertTime)") - } - // create a new suspendTimeExpired PodAlert using the current active time and the computed suspendTime (if any) - podAlerts.append(PodAlert.suspendTimeExpired(offset: currentPodTime, suspendTime: suspendTime, silent: silent)) - - case .expired(let offset, let alertTime, let alertDuration, _): - let duration: TimeInterval - - // alertTime is absolute when offset is non-zero, otherwise use default value - var absAlertTime = offset != 0 ? alertTime : defaultExpiredTime - if currentPodTime >= absAlertTime { - // alert trigger is not in the future, make inactive using a 0 value - absAlertTime = 0 - duration = 0 - } else { - duration = alertDuration - } - // create new expired podAlert using the current active time and the original absolute alert time and duration - podAlerts.append(PodAlert.expired(offset: currentPodTime, absAlertTime: absAlertTime, duration: duration, silent: silent)) - - default: - break - } - } - return podAlerts -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BasalDeliveryTable.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BasalDeliveryTable.swift deleted file mode 100644 index e11b27346..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BasalDeliveryTable.swift +++ /dev/null @@ -1,238 +0,0 @@ -// -// BasalDeliveryTable.swift -// OmniBLE -// -// From OmniKit/Model/BasalDeliveryTable.swift -// Created by Pete Schwamb on 4/4/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -// Max time between pulses for scheduled basal and temp basal extra timing command -let maxTimeBetweenPulses = TimeInterval(hours: 5) - -// Near zero basal rate used for non-Eros pods for zero scheduled basal rates and temp basals -let nearZeroBasalRate = 0.01 - -// Special flag used for non-Eros pods for near zero basal rates pulse timing for $13 & $16 extra commands -let nearZeroBasalRateFlag: UInt32 = 0x80000000 - - -public struct BasalDeliveryTable { - static let segmentDuration: TimeInterval = .minutes(30) - - let entries: [InsulinTableEntry] - - public init(entries: [InsulinTableEntry]) { - self.entries = entries - } - - - public init(schedule: BasalSchedule) { - - struct TempSegment { - let pulses: Int - } - - let numSegments = 48 - let maxSegmentsPerEntry = 16 - - var halfPulseRemainder = false - - let expandedSegments = stride(from: 0, to: numSegments, by: 1).map { (index) -> TempSegment in - let rate = schedule.rateAt(offset: Double(index) * .minutes(30)) - let pulsesPerHour = Int(round(rate / Pod.pulseSize)) - let pulsesPerSegment = pulsesPerHour >> 1 - let halfPulse = pulsesPerHour & 0b1 != 0 - - let segment = TempSegment(pulses: pulsesPerSegment + ((halfPulseRemainder && halfPulse) ? 1 : 0)) - halfPulseRemainder = halfPulseRemainder != halfPulse - - return segment - } - - var tableEntries = [InsulinTableEntry]() - - let addEntry = { (segments: [TempSegment], alternateSegmentPulse: Bool) in - tableEntries.append(InsulinTableEntry( - segments: segments.count, - pulses: segments.first!.pulses, - alternateSegmentPulse: alternateSegmentPulse - )) - } - - var altSegmentPulse = false - var segmentsToMerge = [TempSegment]() - - for segment in expandedSegments { - guard let firstSegment = segmentsToMerge.first else { - segmentsToMerge.append(segment) - continue - } - - let delta = segment.pulses - firstSegment.pulses - - if segmentsToMerge.count == 1 { - altSegmentPulse = delta == 1 - } - - let expectedDelta: Int - - if !altSegmentPulse { - expectedDelta = 0 - } else { - expectedDelta = segmentsToMerge.count % 2 - } - - if expectedDelta != delta || segmentsToMerge.count == maxSegmentsPerEntry { - addEntry(segmentsToMerge, altSegmentPulse) - segmentsToMerge.removeAll() - } - - segmentsToMerge.append(segment) - } - addEntry(segmentsToMerge, altSegmentPulse) - - self.entries = tableEntries - } - - public init(tempBasalRate: Double, duration: TimeInterval) { - self.entries = BasalDeliveryTable.rateToTableEntries(rate: tempBasalRate, duration: duration) - } - - private static func rateToTableEntries(rate: Double, duration: TimeInterval) -> [InsulinTableEntry] { - var tableEntries = [InsulinTableEntry]() - - let pulsesPerHour = Int(round(rate / Pod.pulseSize)) - let pulsesPerSegment = pulsesPerHour >> 1 - let alternateSegmentPulse = pulsesPerHour & 0b1 != 0 - - var remaining = Int(round(duration / BasalDeliveryTable.segmentDuration)) - - while remaining > 0 { - let segments = min(remaining, 16) - let tableEntry = InsulinTableEntry(segments: segments, pulses: Int(pulsesPerSegment), alternateSegmentPulse: segments > 1 ? alternateSegmentPulse : false) - tableEntries.append(tableEntry) - remaining -= segments - } - return tableEntries - } - - public func numSegments() -> Int { - return entries.reduce(0) { $0 + $1.segments } - } -} - -extension BasalDeliveryTable: CustomDebugStringConvertible { - public var debugDescription: String { - return "BasalDeliveryTable(\(entries))" - } -} - -// Round basal rate by rounding down to pulse size boundary, -// but basal rates within a small delta will be rounded up. -// Rounds down to 0 for both non-Eros and Eros (temp basals). -func roundToSupportedBasalRate(rate: Double) -> Double -{ - let delta = 0.01 - let supportedBasalRates: [Double] = (0...600).map { Double($0) / Double(Pod.pulsesPerUnit) } - return supportedBasalRates.last(where: { $0 <= rate + delta }) ?? 0 -} - -// Return rounded basal rate for pulse timing purposes. -// For non-Eros, returns nearZeroBasalRate (0.01) for a zero basal rate. -func roundToSupportedBasalTimingRate(rate: Double) -> Double { - var rrate = roundToSupportedBasalRate(rate: rate) - if rrate == 0.0 { - rrate = Pod.zeroBasalRate // will be an adjusted value for non-Eros cases - } - return rrate -} - -public struct RateEntry { - let totalPulses: Double - let delayBetweenPulses: TimeInterval - - public init(totalPulses: Double, delayBetweenPulses: TimeInterval) { - self.totalPulses = totalPulses - self.delayBetweenPulses = delayBetweenPulses - } - - public var rate: Double { - if totalPulses == 0 { - // Eros zero TB is the only case not using pulses - return 0 - } else { - // Use delayBetweenPulses to compute rate which will also work for non-Eros near zero rates. - // Round the rate calculation to a two digit value to avoid slightly off values for some cases. - return round(((.hours(1) / delayBetweenPulses) / Pod.pulsesPerUnit) * 100) / 100.0 - } - } - - public var duration: TimeInterval { - if totalPulses == 0 { - // Eros zero TB case uses fixed 30 minute rate entries - return TimeInterval(minutes: 30) - } else { - // Use delayBetweenPulses to compute duration which will also work for non-Eros near zero rates. - // Round to nearest second to not be slightly off of the 30 minute rate entry boundary for some cases. - return round(delayBetweenPulses * totalPulses) - } - } - - public var data: Data { - var delayBetweenPulsesInHundredthsOfMillisecondsWithFlag = UInt32(delayBetweenPulses.hundredthsOfMilliseconds) - - // non-Eros near zero basal rates use the nearZeroBasalRateFlag - if delayBetweenPulses == maxTimeBetweenPulses && totalPulses != 0 { - delayBetweenPulsesInHundredthsOfMillisecondsWithFlag |= nearZeroBasalRateFlag - } - - var data = Data() - data.appendBigEndian(UInt16(round(totalPulses * 10))) - data.appendBigEndian(delayBetweenPulsesInHundredthsOfMillisecondsWithFlag) - return data - } - - public static func makeEntries(rate: Double, duration: TimeInterval) -> [RateEntry] { - let maxPulsesPerEntry: Double = 0xffff / 10 // max # of 1/10th pulses encoded in a 2-byte value - var entries = [RateEntry]() - let rrate = roundToSupportedBasalTimingRate(rate: rate) - - var remainingSegments = Int(round(duration.minutes / 30)) - - let pulsesPerSegment = round(rrate / Pod.pulseSize) / 2 - let maxSegmentsPerEntry = pulsesPerSegment > 0 ? Int(maxPulsesPerEntry / pulsesPerSegment) : 1 - - var remainingPulses = rrate * duration.hours / Pod.pulseSize - - while (remainingSegments > 0) { - let entry: RateEntry - if rrate == 0 { - // Eros zero TBR only, one rate entry per segment with no pulses - entry = RateEntry(totalPulses: 0, delayBetweenPulses: maxTimeBetweenPulses) - remainingSegments -= 1 // one rate entry per half hour - } else if rrate == nearZeroBasalRate { - // Non-Eros near zero value temp or scheduled basal, one entry with 1/10 pulse per 1/2 hour of duration - entry = RateEntry(totalPulses: Double(remainingSegments) / 10, delayBetweenPulses: maxTimeBetweenPulses) - remainingSegments = 0 // just a single entry - } else { - let numSegments = min(maxSegmentsPerEntry, Int(round(remainingPulses / pulsesPerSegment))) - remainingSegments -= numSegments - let pulseCount = pulsesPerSegment * Double(numSegments) - let delayBetweenPulses = .hours(1) / rrate * Pod.pulseSize - entry = RateEntry(totalPulses: pulseCount, delayBetweenPulses: delayBetweenPulses) - remainingPulses -= pulseCount - } - entries.append(entry) - } - return entries - } -} - -extension RateEntry: CustomDebugStringConvertible { - public var debugDescription: String { - return "RateEntry(rate:\(rate), duration:\(duration.timeIntervalStr))" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BasalSchedule+LoopKit.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BasalSchedule+LoopKit.swift deleted file mode 100644 index 7e3f8f9e5..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BasalSchedule+LoopKit.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// BasalSchedule+LoopKit.swift -// OmniBLE -// -// From OmniKit/PumpManager/PodCommsSession+LoopKit.swift -// Created by Pete Schwamb on 9/25/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation -import LoopKit - -extension BasalSchedule { - public init(repeatingScheduleValues: [LoopKit.RepeatingScheduleValue]) { - self.init(entries: repeatingScheduleValues.map { BasalScheduleEntry(rate: $0.value, startTime: $0.startTime) }) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BasalSchedule.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BasalSchedule.swift deleted file mode 100644 index 29b437b6a..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BasalSchedule.swift +++ /dev/null @@ -1,135 +0,0 @@ -// -// BasalSchedule.swift -// OmniBLE -// -// From OmniKit/Model/BasalSchedule.swift -// Created by Pete Schwamb on 4/4/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct BasalScheduleEntry: RawRepresentable, Equatable { - - public typealias RawValue = [String: Any] - - let rate: Double - let startTime: TimeInterval - - public init(rate: Double, startTime: TimeInterval) { - var rrate = roundToSupportedBasalRate(rate: rate) - if rrate == 0 && Pod.zeroBasalRate == 0 { - // Got a zero scheduled basal rate for an Eros pod, use the min allowed - rrate = Pod.pulseSize - } - self.rate = rrate - self.startTime = startTime - } - - // MARK: - RawRepresentable - public init?(rawValue: RawValue) { - - guard - let rate = rawValue["rate"] as? Double, - let startTime = rawValue["startTime"] as? Double - else { - return nil - } - - self.rate = rate - self.startTime = startTime - } - - public var rawValue: RawValue { - let rawValue: RawValue = [ - "rate": rate, - "startTime": startTime - ] - - return rawValue - } -} - -// A basal schedule starts at midnight and should contain 24 hours worth of entries -public struct BasalSchedule: RawRepresentable, Equatable { - - public typealias RawValue = [String: Any] - - let entries: [BasalScheduleEntry] - - public func rateAt(offset: TimeInterval) -> Double { - let (_, entry, _) = lookup(offset: offset) - return entry.rate - } - - // Only valid for fixed offset timezones - public func currentRate(using calendar: Calendar, at date: Date = Date()) -> Double { - let midnight = calendar.startOfDay(for: date) - return rateAt(offset: date.timeIntervalSince(midnight)) - } - - // Returns index, entry, and time remaining - func lookup(offset: TimeInterval) -> (Int, BasalScheduleEntry, TimeInterval) { - guard offset >= 0 && offset < .hours(24) else { - fatalError("Schedule offset out of bounds") - } - - var last: TimeInterval = .hours(24) - for (index, entry) in entries.reversed().enumerated() { - if entry.startTime <= offset { - return (entries.count - (index + 1), entry, last - entry.startTime) - } - last = entry.startTime - } - fatalError("Schedule incomplete") - } - - public init(entries: [BasalScheduleEntry]) { - self.entries = entries - } - - public func durations() -> [(rate: Double, duration: TimeInterval, startTime: TimeInterval)] { - var last: TimeInterval = .hours(24) - let durations = entries.reversed().map { (entry) -> (rate: Double, duration: TimeInterval, startTime: TimeInterval) in - let duration = (rate: entry.rate, duration: last - entry.startTime, startTime: entry.startTime) - last = entry.startTime - return duration - } - return durations.reversed() - } - - // MARK: - RawRepresentable - public init?(rawValue: RawValue) { - - guard - let entries = rawValue["entries"] as? [BasalScheduleEntry.RawValue] - else { - return nil - } - - self.entries = entries.compactMap { BasalScheduleEntry(rawValue: $0) } - } - - public var rawValue: RawValue { - let rawValue: RawValue = [ - "entries": entries.map { $0.rawValue } - ] - - return rawValue - } -} - -public extension Sequence where Element == BasalScheduleEntry { - func adjacentEqualRatesMerged() -> [BasalScheduleEntry] { - var output = [BasalScheduleEntry]() - let _ = self.reduce(nil) { (lastRate, entry) -> TimeInterval? in - if entry.rate != lastRate { - output.append(entry) - } - return entry.rate - } - return output - } -} - - diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BeepPreference.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BeepPreference.swift deleted file mode 100644 index 981f4ed0a..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BeepPreference.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// BeepPreference.swift -// OmniBLE -// -// Created by Pete Schwamb on 2/14/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum BeepPreference: Int, CaseIterable { - case silent - case manualCommands - case extended - - var title: String { - switch self { - case .silent: - return LocalizedString("Disabled", comment: "Title string for BeepPreference.silent") - case .manualCommands: - return LocalizedString("Enabled", comment: "Title string for BeepPreference.manualCommands") - case .extended: - return LocalizedString("Extended", comment: "Title string for BeepPreference.extended") - } - } - - var description: String { - switch self { - case .silent: - return LocalizedString("No confidence reminders are used.", comment: "Description for BeepPreference.silent") - case .manualCommands: - return LocalizedString("Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used.", comment: "Description for BeepPreference.manualCommands") - case .extended: - return LocalizedString("Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate.", comment: "Description for BeepPreference.extended") - } - } - - var shouldBeepForManualCommand: Bool { - return self == .extended || self == .manualCommands - } - - var shouldBeepForAutomaticCommands: Bool { - return self == .extended - } - - func shouldBeepForCommand(automatic: Bool) -> Bool { - if automatic { - return shouldBeepForAutomaticCommands - } else { - return shouldBeepForManualCommand - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BeepType.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BeepType.swift deleted file mode 100644 index 0511f2109..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BeepType.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// BeepType.swift -// OmniBLE -// -// From OmniKit/Model/BeepType.swift -// Created by Joseph Moran on 5/12/19. -// Copyright © 2019 Pete Schwamb. All rights reserved. -// - -import Foundation - -// -// BeepType is used for the 0x19 Configure Alerts, 0x1E Set Beep Options and 0x1F Cancel Delivery commands. -// Some beep types values behave differently based on the command & circumstances due to Omnipod internals. -// -// Beep types 0x0, 0x9 & 0xA (as well as 0xE when the pod isn't suspended) will have no beeps or errors -// (when used in 0x19 Configure Alerts with an 'a' bit of 0 or 0x1F Cancel) and will return 0x6 Error -// response, code 7 (when used in 0x19 Configure Alerts with an 'a' bit of 1 or in 0x1E Beep Configure). -// -// Beep type 0xF will will have no beeps or errors (when used in 0x19 Configure Alerts -// or 0x1E Beep Configure), but will generate a 0x37 pod fault when used in 0x1F Cancel! -// -public enum BeepType: UInt8 { - case noBeepCancel = 0x0 // silent for 0x1F Cancel & inactive 0x19 alerts; error for 0x1E Beep Options & active 0x19 alerts - case beepBeepBeepBeep = 0x1 - case bipBeepBipBeepBipBeepBipBeep = 0x2 - case bipBip = 0x3 - case beep = 0x4 - case beepBeepBeep = 0x5 - case beeeeeep = 0x6 - case bipBipBipbipBipBip = 0x7 - case beeepBeeep = 0x8 - case unusedBeepType0x9 = 0x9 // silent for 0x1F Cancel & inactive 0x19 alerts; error for 0x1E Beep Options & active 0x19 alerts - case unusedBeepType0xA = 0xA // silent for 0x1F Cancel & inactive 0x19 alerts; error for 0x1E Beep Options & active 0x19 alerts - case beepBeep = 0xB - case beeep = 0xC - case bipBeeeeep = 0xD - // If pod is currently suspended, 5 second beep for the 0x19, 0x1E & 0x1F commands - // If pod is not suspended, silent for 0x1F Cancel & inactive 0x19 alerts; error for 0x1E Beep Options & active 0x19 alerts - case fiveSecondBeep = 0xE - case noBeepNonCancel = 0xF // silent for 0x1E Beep Options & 0x19 Configure Alerts, 0x37 pod fault for 0x1F Cancel! -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BolusDeliveryTable.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BolusDeliveryTable.swift deleted file mode 100644 index ce5c4db30..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/BolusDeliveryTable.swift +++ /dev/null @@ -1,181 +0,0 @@ -// -// BolusDeliveryTable.swift -// OmniBLE -// -// Created by Joseph Moran on 10/20/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -// Implements the bolus insulin delivery table for 0x1A command (https://github.com/openaps/openomni/wiki/Command-1A-Table-2) - -public struct BolusDeliveryTable { - static let segMinutes = 30 - static let maxDurationHours = 8 - - let entries: [InsulinTableEntry] - - public init(entries: [InsulinTableEntry]) { - self.entries = entries - } - - public init(units: Double, extendedUnits: Double = 0.0, extendedDuration: TimeInterval = 0) { - let immediatePulses = Int(round(units / Pod.pulseSize)) - let extendedPulses = Int(round(extendedUnits / Pod.pulseSize)) - let duration: TimeInterval - - let maxExtendedDuration: TimeInterval = .hours(Double(min(extendedPulses, BolusDeliveryTable.maxDurationHours))) - if extendedDuration > maxExtendedDuration { - // maximum extended bolus duration of one extended pulse per hour capped at 8 hours - duration = maxExtendedDuration - } else { - duration = extendedDuration - } - - self.entries = generateBolusTable(immediatePulses: immediatePulses, extendedPulses: extendedPulses, extendedDuration: duration) - } - - public func numSegments() -> Int { - return entries.reduce(0) { $0 + $1.segments } - } -} - -// Returns the bolus insulin delivery table for the specified bolus parameters as per the PDM. -// See https://github.com/openaps/openomni/wiki/Command-1A-Table-2#Advanced-Extended-Bolus-Encoding for details. -fileprivate func generateBolusTable(immediatePulses: Int, extendedPulses: Int, extendedDuration: TimeInterval) -> [InsulinTableEntry] { - var tableEntries = [InsulinTableEntry]() - - if extendedPulses == 0 || extendedDuration == 0 { - // trivial immediate bolus case ($0ppp) - let entry = InsulinTableEntry(segments: 1, pulses: immediatePulses, alternateSegmentPulse: false) - tableEntries.append(entry) - return tableEntries - } - - // Extended (square wave) bolus or combination (dual wave) bolus case - let ePulsesPerSeg = computeExtendedPulsesPerSeg(extendedPulses: extendedPulses, duration: extendedDuration) - let nseg = ePulsesPerSeg.count - - // The first entry is special as its pulses value always matches the # immediate pulses, - // but it also describes the first 1/2 hour of the extended bolus when the # of extended - // pulses in the first 1/2 hour is one more or the same as the # of immediate pulses. - var pulses = immediatePulses - var segs = 1 - var alternateSegmentPulse = false - if ePulsesPerSeg[0] - 1 == immediatePulses { - // $18ii case - segs += 1 - alternateSegmentPulse = true - } else if ePulsesPerSeg[0] == immediatePulses { - // $x0ii case - segs += 1 - if immediatePulses != 0 { - segs += numMatch(ePulsesPerSeg: ePulsesPerSeg, idx: 0, val: immediatePulses) - } - } // else $00ii case describing just the immediate bolus portion -- nothing to adjust - - let entry = InsulinTableEntry(segments: segs, pulses: pulses, alternateSegmentPulse: alternateSegmentPulse) - tableEntries.append(entry) - - var remainingPulses = (immediatePulses + extendedPulses) - (segs * pulses) - if alternateSegmentPulse { - remainingPulses -= segs/2 - } - - var idx: Int - if alternateSegmentPulse { - idx = 1 - } else { - idx = segs - 1 - } - - // Step through the remaining extended pulses per segment array to generate and append the appropriate insulin table entries - let basePulsesPerSeg = Int(extendedPulses / nseg) // truncated to whole pulses per half hour segment - while idx < nseg && remainingPulses > 0 { - segs = 1 - alternateSegmentPulse = false - pulses = basePulsesPerSeg - if idx < nseg - 1 && ePulsesPerSeg[idx] == pulses && ePulsesPerSeg[idx + 1] == pulses + 1 { - // $n8bb - let numAltPairs = numAltPairMatch(ePulsesPerSeg: ePulsesPerSeg, idx: idx, val: pulses) - alternateSegmentPulse = true - segs += (numAltPairs * 2) - 1 - idx += (numAltPairs * 2) - 1 - remainingPulses -= segs/2 - } else { - // $n0bb - pulses = ePulsesPerSeg[idx] - let numMatched = numMatch(ePulsesPerSeg: ePulsesPerSeg, idx: idx, val: pulses) - if numMatched > 0 { - segs += numMatched - idx += numMatched - } - } - - let entry = InsulinTableEntry(segments: segs, pulses: pulses, alternateSegmentPulse: alternateSegmentPulse) - tableEntries.append(entry) - - idx += 1 - remainingPulses -= segs * pulses - } - - return tableEntries -} - -// Returns an array of pulses to be delivered for each half hour segment for extendedPulses spaced over the given duration -fileprivate func computeExtendedPulsesPerSeg(extendedPulses: Int, duration: TimeInterval) -> [Int] { - let nseg = Int(ceil(duration / .minutes(BolusDeliveryTable.segMinutes))) - let pulseInterval = duration / Double(extendedPulses) - - var ePulsesPerSeg = Array(repeating: 0, count: nseg) - var t = pulseInterval - var ePulses = 0 - for seg in 0.. segTimeStart && t <= segTimeEnd { - ePulsesPerSeg[seg] += 1 - ePulses += 1 - } - t += pulseInterval - } - if t > duration { - break - } - } - - // Any remaining pulses are added to the last half hour segment - if extendedPulses > ePulses { - ePulsesPerSeg[nseg - 1] += extendedPulses - ePulses - } - - return ePulsesPerSeg -} - -// Returns the number of consecutive matched [val, val+1] pairs starting at ePulsesPerSeg[idx] -fileprivate func numAltPairMatch(ePulsesPerSeg: [Int], idx: Int, val: Int) -> Int { - var cnt = 0 - - for i in stride(from: idx, to: ePulsesPerSeg.count - 1, by: 2) { - if ePulsesPerSeg[i] != val || ePulsesPerSeg[i + 1] != val + 1 { - break - } - cnt += 1 - } - return cnt -} - -// Returns the number of consecutive elements matching val starting at ePulsesPerSeg[idx] -fileprivate func numMatch(ePulsesPerSeg: [Int], idx: Int, val: Int) -> Int { - var cnt = 0 - - for i in idx.. UInt16 { - - var acc: UInt16 = 0 - for byte in self { - let idx = (acc ^ UInt16(byte)) & 0xff - acc = (acc >> 8) ^ crc16Table[Int(idx)] - } - return acc - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/FaultEventCode.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/FaultEventCode.swift deleted file mode 100644 index 835ae6e33..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/FaultEventCode.swift +++ /dev/null @@ -1,498 +0,0 @@ -// -// FaultEventCode.swift -// OmniBLE -// -// Based on OmniKit/Model/FaultEventCode.swift -// Created by Pete Schwamb on 9/28/18. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - - -public struct FaultEventCode: CustomStringConvertible, Equatable { - public let rawValue: UInt8 - - public enum FaultEventType: UInt8 { - case noFaults = 0x00 - case failedFlashErase = 0x01 - case failedFlashStore = 0x02 - case tableCorruptionBasalSubcommand = 0x03 - case basalPulseTableCorruption = 0x04 - case corruptionByte720 = 0x05 - case dataCorruptionInTestRTCInterrupt = 0x06 - case rtcInterruptHandlerInconsistentState = 0x07 - case valueGreaterThan8 = 0x08 - case invalidBeepRepeatPattern = 0x09 - case bf0notEqualToBF1 = 0x0A - case tableCorruptionTempBasalSubcommand = 0x0B - - case resetDueToCOP = 0x0D - case resetDueToIllegalOpcode = 0x0E - case resetDueToIllegalAddress = 0x0F - case resetDueToSAWCOP = 0x10 - case corruptionInByte_866 = 0x11 - case resetDueToLVD = 0x12 - case messageLengthTooLong = 0x13 - case occluded = 0x14 - case corruptionInWord129 = 0x15 - case corruptionInByte868 = 0x16 - case corruptionInAValidatedTable = 0x17 - case reservoirEmpty = 0x18 - case badPowerSwitchArrayValue1 = 0x19 - case badPowerSwitchArrayValue2 = 0x1A - case badLoadCnthValue = 0x1B - case exceededMaximumPodLife80Hrs = 0x1C - case badStateCommand1AScheduleParse = 0x1D - case unexpectedStateInRegisterUponReset = 0x1E - case wrongSummaryForTable129 = 0x1F - case validateCountErrorWhenBolusing = 0x20 - case badTimerVariableState = 0x21 - case unexpectedRTCModuleValueDuringReset = 0x22 - case problemCalibrateTimer = 0x23 - case tickcntErrorRTC = 0x24 - case tickFailure = 0x25 - case rtcInterruptHandlerUnexpectedCall = 0x26 - case missing2hourAlertToFillTank = 0x27 - case faultEventSetupPod = 0x28 - case autoOff0 = 0x29 - case autoOff1 = 0x2A - case autoOff2 = 0x2B - case autoOff3 = 0x2C - case autoOff4 = 0x2D - case autoOff5 = 0x2E - case autoOff6 = 0x2F - case autoOff7 = 0x30 - case insulinDeliveryCommandError = 0x31 - case badValueStartupTest = 0x32 - case connectedPodCommandTimeout = 0x33 - case resetFromUnknownCause = 0x34 - case vetoNotSet = 0x35 - case errorFlashInitialization = 0x36 - case badPiezoValue = 0x37 - case unexpectedValueByte358 = 0x38 - case problemWithLoad1and2 = 0x39 - case aGreaterThan7inMessage = 0x3A - case failedTestSawReset = 0x3B - case testInProgress = 0x3C - case problemWithPumpAnchor = 0x3D - case errorFlashWrite = 0x3E - - case encoderCountTooHigh = 0x40 - case encoderCountExcessiveVariance = 0x41 - case encoderCountTooLow = 0x42 - case encoderCountProblem = 0x43 - case checkVoltageOpenWire1 = 0x44 - case checkVoltageOpenWire2 = 0x45 - case problemWithLoad1and2type46 = 0x46 - case problemWithLoad1and2type47 = 0x47 - case badTimerCalibration = 0x48 - case badTimerRatios = 0x49 - case badTimerValues = 0x4A - case trimICSTooCloseTo0x1FF = 0x4B - case problemFindingBestTrimValue = 0x4C - case badSetTPM1MultiCasesValue = 0x4D - case sawTrimError = 0x4E - case unexpectedRFErrorFlagDuringReset = 0x4F - case timerPulseWidthModulatorOverflow = 0x50 - case tickcntError = 0x51 - case badRfmXtalStart = 0x52 - case badRxSensitivity = 0x53 - case packetFrameLengthTooLong = 0x54 - case unexpectedIRQHighinTimerTick = 0x55 - case unexpectedIRQLowinTimerTick = 0x56 - case badArgToGetEntry = 0x57 - case badArgToUpdate37ATable = 0x58 - case errorUpdating37ATable = 0x59 - case occlusionCheckValueTooHigh = 0x5A - case loadTableCorruption = 0x5B - case primeOpenCountTooLow = 0x5C - case badValueByte109 = 0x5D - case disableFlashSecurityFailed = 0x5E - case checkVoltageFailure = 0x5F - case occlusionCheckStartup1 = 0x60 - case occlusionCheckStartup2 = 0x61 - case occlusionCheckTimeouts1 = 0x62 - - case occlusionCheckTimeouts2 = 0x66 - case occlusionCheckTimeouts3 = 0x67 - case occlusionCheckPulseIssue = 0x68 - case occlusionCheckBolusProblem = 0x69 - case occlusionCheckAboveThreshold = 0x6A - - case basalUnderInfusion = 0x80 - case basalOverInfusion = 0x81 - case tempBasalUnderInfusion = 0x82 - case tempBasalOverInfusion = 0x83 - case bolusUnderInfusion = 0x84 - case bolusOverInfusion = 0x85 - case basalOverInfusionPulse = 0x86 - case tempBasalOverInfusionPulse = 0x87 - case bolusOverInfusionPulse = 0x88 - case immediateBolusOverInfusionPulse = 0x89 - case extendedBolusOverInfusionPulse = 0x8A - case corruptionOfTables = 0x8B - case unrecognizedPulse = 0x8D - case syncWithoutTempActive = 0x8E - case command1AParseUnexpectedFailed = 0x8F - case illegalChanParam = 0x90 - case basalPulseChanInactive = 0x91 - case tempPulseChanInactive = 0x92 - case bolusPulseChanInactive = 0x93 - case intSemaphoreNotSet = 0x94 - case illegalInterLockChan = 0x95 - case badStateInClearBolusIST2AndVars = 0x96 - case badStateInMaybeInc33D = 0x97 - - case bleTimeout = 0xA0 - case bleInitiated = 0xA1 - case bleUnkAlarm = 0xA2 - - case bleIaas = 0xA6 - case crcFailure = 0xA8 - case bleWdPingTimeout = 0xA9 - case bleExcessiveResets = 0xAA - case bleNakError = 0xAB - case bleReqHighTimeout = 0xAC - case bleUnknownResp = 0xAD - - case bleReqStuckHigh = 0xAF - case bleStateMachine1 = 0xB1 - case bleStateMachine2 = 0xB2 - case bleArbLost = 0xB4 - case bleEr48DualNack = 0xC0 - case bleQnExceedMaxRetry = 0xC1 - case bleQnCritVarFail = 0xC2 - - case unknown0xCB = 0xCB - - case unknown0xD4 = 0xD4 - case unknown0xD5 = 0xD5 - case resetFault0xD6 = 0xD6 - case resetFault0xD7 = 0xD7 - case unknown0xD8 = 0xD8 - case unknown0xD9 = 0xD9 - - case valuesDoNotMatch = 0xFF - } - - public var faultType: FaultEventType? { - return FaultEventType(rawValue: rawValue) - } - - init(rawValue: UInt8) { - self.rawValue = rawValue - } - - public var faultDescription: String { - switch faultType { - case .noFaults: - return "No fault" - case .failedFlashErase: - return "Flash erase failed" - case .failedFlashStore: - return "Flash store failed" - case .tableCorruptionBasalSubcommand: - return "Basal subcommand table corruption" - case .basalPulseTableCorruption: - return "Basal pulse table corruption" - case .corruptionByte720: - return "Corruption in byte_720" - case .dataCorruptionInTestRTCInterrupt: - return "Data corruption error in test_RTC_interrupt" - case .rtcInterruptHandlerInconsistentState: - return "RTC interrupt handler called with inconstent state" - case .valueGreaterThan8: - return "Value > 8" - case .invalidBeepRepeatPattern: - return "Invalid beep repeat pattern" - case .bf0notEqualToBF1: - return "Corruption in byte_BF0" - case .tableCorruptionTempBasalSubcommand: - return "Temp basal subcommand table corruption" - case .resetDueToCOP: - return "Reset due to COP" - case .resetDueToIllegalOpcode: - return "Reset due to illegal opcode" - case .resetDueToIllegalAddress: - return "Reset due to illegal address" - case .resetDueToSAWCOP: - return "Reset due to SAWCOP" - case .corruptionInByte_866: - return "Corruption in byte_866" - case .resetDueToLVD: - return "Reset due to LVD" - case .messageLengthTooLong: - return "Message length too long" - case .occluded: - return "Occluded" - case .corruptionInWord129: - return "Corruption in word_129 table/word_86A/dword_86E" - case .corruptionInByte868: - return "Corruption in byte_868" - case .corruptionInAValidatedTable: - return "Corruption in a validated table" - case .reservoirEmpty: - return "Reservoir empty or exceeded maximum pulse delivery" - case .badPowerSwitchArrayValue1: - return "Bad Power Switch Array Status and Control Register value 1 before starting pump" - case .badPowerSwitchArrayValue2: - return "Bad Power Switch Array Status and Control Register value 2 before starting pump" - case .badLoadCnthValue: - return "Bad LOADCNTH value when running pump" - case .exceededMaximumPodLife80Hrs: - return "Exceeded maximum Pod life of 80 hours" - case .badStateCommand1AScheduleParse: - return "Unexpected internal state in command_1A_schedule_parse_routine_wrapper" - case .unexpectedStateInRegisterUponReset: - return "Unexpected commissioned state in status and control register upon reset" - case .wrongSummaryForTable129: - return "Sum mismatch for word_129 table" - case .validateCountErrorWhenBolusing: - return "Validate encoder count error when bolusing" - case .badTimerVariableState: - return "Bad timer variable state" - case .unexpectedRTCModuleValueDuringReset: - return "Unexpected RTC Modulo Register value during reset" - case .problemCalibrateTimer: - return "Problem in calibrate_timer_case_3" - case .tickcntErrorRTC: - return "Tick count error RTC" - case .tickFailure: - return "Tick failure" - case .rtcInterruptHandlerUnexpectedCall: - return "RTC interrupt handler unexpectedly called" - case .missing2hourAlertToFillTank: - return "Failed to set up 2 hour alert for tank fill operation" - case .faultEventSetupPod: - return "Bad arg or state in update_insulin_variables, verify_and_start_pump or main_loop_control_pump" - case .autoOff0: - return "Alert #0 auto-off timeout" - case .autoOff1: - return "Alert #1 auto-off timeout" - case .autoOff2: - return "Alert #2 auto-off timeout" - case .autoOff3: - return "Alert #3 auto-off timeout" - case .autoOff4: - return "Alert #4 auto-off timeout" - case .autoOff5: - return "Alert #5 auto-off timeout" - case .autoOff6: - return "Alert #6 auto-off timeout" - case .autoOff7: - return "Alert #7 auto-off timeout" - case .insulinDeliveryCommandError: - return "Incorrect pod state for command or error during insulin command setup" - case .badValueStartupTest: - return "Bad value during startup testing" - case .connectedPodCommandTimeout: - return "Connected Pod command timeout" - case .resetFromUnknownCause: - return "Reset from unknown cause" - case .vetoNotSet: - return "Veto not set" - case .errorFlashInitialization: - return "Flash initialization error" - case .badPiezoValue: - return "Bad piezo value" - case .unexpectedValueByte358: - return "Unexpected byte_358 value" - case .problemWithLoad1and2: - return "Problem with LOAD1/LOAD2" - case .aGreaterThan7inMessage: - return "A > 7 in message processing" - case .failedTestSawReset: - return "SAW reset testing fail" - case .testInProgress: - return "test in progress" - case .problemWithPumpAnchor: - return "Problem with pump anchor" - case .errorFlashWrite: - return "Flash initialization or write error" - case .encoderCountTooHigh: - return "Encoder count too high" - case .encoderCountExcessiveVariance: - return "Encoder count excessive variance" - case .encoderCountTooLow: - return "Encoder count too low" - case .encoderCountProblem: - return "Encoder count problem" - case .checkVoltageOpenWire1: - return "Check voltage open wire 1 problem" - case .checkVoltageOpenWire2: - return "Check voltage open wire 2 problem" - case .problemWithLoad1and2type46: - return "Problem with LOAD1/LOAD2" - case .problemWithLoad1and2type47: - return "Problem with LOAD1/LOAD2" - case .badTimerCalibration: - return "Bad timer calibration" - case .badTimerRatios: - return "Bad timer values: COP timer ratio bad" - case .badTimerValues: - return "Bad timer values" - case .trimICSTooCloseTo0x1FF: - return "ICS trim too close to 0x1FF" - case .problemFindingBestTrimValue: - return "find_best_trim_value problem" - case .badSetTPM1MultiCasesValue: - return "Bad set_TPM1_multi_cases value" - case .unexpectedRFErrorFlagDuringReset: - return "Unexpected TXSCR2 RF Tranmission Error Flag set during reset" - case .timerPulseWidthModulatorOverflow: - return "Timer pulse-width modulator overflow" - case .tickcntError: - return "Bad tick count state before starting pump" - case .badRfmXtalStart: - return "TXOK issue in process_input_buffer" - case .badRxSensitivity: - return "Bad Rx word_107 sensitivity value during input message processing" - case .packetFrameLengthTooLong: - return "Packet frame length too long" - case .unexpectedIRQHighinTimerTick: - return "Unexpected IRQ high in timer_tick" - case .unexpectedIRQLowinTimerTick: - return "Unexpected IRQ low in timer_tick" - case .badArgToGetEntry: - return "Corrupt constants table at byte_37A[] or flash byte_4036[]" - case .badArgToUpdate37ATable: - return "Bad argument to update_37A_table" - case .errorUpdating37ATable: - return "Error updating constants byte_37A table" - case .occlusionCheckValueTooHigh: - return "Occlusion check value too high for detection" - case .loadTableCorruption: - return "Load table corruption" - case .primeOpenCountTooLow: - return "Prime open count too low" - case .badValueByte109: - return "Bad byte_109 value" - case .disableFlashSecurityFailed: - return "Write flash byte to disable flash security failed" - case .checkVoltageFailure: - return "Two check voltage failures before starting pump" - case .occlusionCheckStartup1: - return "Occlusion check startup problem 1" - case .occlusionCheckStartup2: - return "Occlusion check startup problem 2" - case .occlusionCheckTimeouts1: - return "Occlusion check excess timeouts 1" - case .occlusionCheckTimeouts2: - return "Occlusion check excess timeouts 2" - case .occlusionCheckTimeouts3: - return "Occlusion check excess timeouts 3" - case .occlusionCheckPulseIssue: - return "Occlusion check pulse issue" - case .occlusionCheckBolusProblem: - return "Occlusion check bolus problem" - case .occlusionCheckAboveThreshold: - return "Occlusion check above threshold" - case .basalUnderInfusion: - return "Basal under infusion" - case .basalOverInfusion: - return "Basal over infusion" - case .tempBasalUnderInfusion: - return "Temp basal under infusion" - case .tempBasalOverInfusion: - return "Temp basal over infusion" - case .bolusUnderInfusion: - return "Bolus under infusion" - case .bolusOverInfusion: - return "Bolus over infusion" - case .basalOverInfusionPulse: - return "Basal over infusion pulse" - case .tempBasalOverInfusionPulse: - return "Temp basal over infusion pulse" - case .bolusOverInfusionPulse: - return "Bolus over infusion pulse" - case .immediateBolusOverInfusionPulse: - return "Immediate bolus under infusion pulse" - case .extendedBolusOverInfusionPulse: - return "Extended bolus over infusion pulse" - case .corruptionOfTables: - return "Corruption of $283/$2E3/$315 tables" - case .unrecognizedPulse: - return "Bad pulse value to verify_and_start_pump" - case .syncWithoutTempActive: - return "Pump sync req 5 with no temp basal active" - case .command1AParseUnexpectedFailed: - return "Command 1A parse routine unexpected failed" - case .illegalChanParam: - return "Bad parameter for $283/$2E3/$315 channel table specification" - case .basalPulseChanInactive: - return "Pump basal request with basal IST not set" - case .tempPulseChanInactive: - return "Pump temp basal request with temp basal IST not set" - case .bolusPulseChanInactive: - return "Pump bolus request and bolus IST not set" - case .intSemaphoreNotSet: - return "Bad table specifier field6 in 1A command" - case .illegalInterLockChan: - return "Illegal interlock channel" - case .badStateInClearBolusIST2AndVars: - return "Bad variable state in clear_Bolus_IST2_and_vars" - case .badStateInMaybeInc33D: - return "Bad variable state in maybe_inc_33D" - case .bleTimeout: - return "BLE timeout" - case .bleInitiated: - return "BLE initiated" - case .bleUnkAlarm: - return "BLE unknown alarm" - case .bleIaas: - return "BLE IAAS" - case .crcFailure: - return "CRC failure" - case .bleWdPingTimeout: - return "BLE WD ping timeout" - case .bleExcessiveResets: - return "BLE excessive resets" - case .bleNakError: - return "BLE NAK error" - case .bleReqHighTimeout: - return "BLE request high timeout" - case .bleUnknownResp: - return "BLE unknown response" - case .bleReqStuckHigh: - return "BLE request stuck high" - case .bleStateMachine1: - return "BLE state machine 1" - case .bleStateMachine2: - return "BLE state machine 2" - case .bleArbLost: - return "BLE arbitration lost" - case .bleEr48DualNack: - return "BLE dual Nack" - case .bleQnExceedMaxRetry: - return "BLE QN exceed max retry" - case .bleQnCritVarFail: - return "BLE QN critical variable fail" - default: - return "Unknown fault code" - } - } - - public var description: String { - return String(format: "Fault Event Code 0x%02x: %@", rawValue, faultDescription) - } - - public var localizedDescription: String { - if let faultType = faultType { - switch faultType { - case .noFaults: - return LocalizedString("No faults", comment: "Description for Fault Event Code .noFaults") - case .reservoirEmpty: - return LocalizedString("Empty reservoir", comment: "Description for Empty reservoir pod fault") - case .exceededMaximumPodLife80Hrs: - return LocalizedString("Pod expired", comment: "Description for Pod expired pod fault") - case .occluded: - return LocalizedString("Occlusion detected", comment: "Description for Occlusion detected pod fault") - default: - return String(format: LocalizedString("Internal pod fault %1$03d", comment: "The format string for Internal pod fault (1: The fault code value)"), rawValue) - } - } else { - return String(format: LocalizedString("Unknown pod fault %1$03d", comment: "The format string for Unknown pod fault (1: The fault code value)"), rawValue) - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/InsulinTableEntry.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/InsulinTableEntry.swift deleted file mode 100644 index 1ee862387..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/InsulinTableEntry.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// InsulinTableEntry.swift -// OmniBLE -// -// Created by Joseph Moran on 10/26/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -// -// InsulinTableEntry describes the common InsulinScheduleElement in all the 0x1A insulin delivery commands. -// See https://github.com/openaps/openomni/wiki/Command-1A-Insulin-Schedule#InsulinScheduleElement for details. -// Formerly BasalTableEntry when only being used for the basal and temporary basal commands. -// -public struct InsulinTableEntry { - let segments: Int - let pulses: Int - let alternateSegmentPulse: Bool - - public init(encodedData: Data) { - segments = Int(encodedData[0] >> 4) + 1 - pulses = (Int(encodedData[0] & 0b11) << 8) + Int(encodedData[1]) - alternateSegmentPulse = (encodedData[0] >> 3) & 0x1 == 1 - } - - public init(segments: Int, pulses: Int, alternateSegmentPulse: Bool) { - self.segments = segments - self.pulses = pulses - self.alternateSegmentPulse = alternateSegmentPulse - } - - public var data: Data { - let pulsesHighBits = UInt8((pulses >> 8) & 0b11) - let pulsesLowBits = UInt8(pulses & 0xff) - return Data([ - UInt8((segments - 1) << 4) + UInt8((alternateSegmentPulse ? 1 : 0) << 3) + pulsesHighBits, - UInt8(pulsesLowBits) - ]) - } - - public func checksum() -> UInt16 { - let checksumPerSegment = (pulses & 0xff) + (pulses >> 8) - return UInt16(checksumPerSegment * segments + (alternateSegmentPulse ? segments / 2 : 0)) - } -} - -extension InsulinTableEntry: CustomDebugStringConvertible { - public var debugDescription: String { - return "InsulinTableEntry(segments:\(segments), pulses:\(pulses), alternateSegmentPulse:\(alternateSegmentPulse))" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/Message.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/Message.swift deleted file mode 100644 index 2042f5531..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/Message.swift +++ /dev/null @@ -1,134 +0,0 @@ -// -// Message.swift -// OmniBLE -// -// Based on OmniKit/MessageTransport/Message.swift -// Created by Pete Schwamb on 10/14/17. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// -import Foundation - -public enum MessageError: Error { - case notEnoughData - case invalidCrc - case invalidSequence - case invalidAddress(address: UInt32) - case parsingError(offset: Int, data: Data, error: Error) - case unknownValue(value: UInt8, typeDescription: String) - case validationFailed(description: String) -} - -extension MessageError: LocalizedError { - public var errorDescription: String? { - switch self { - case .notEnoughData: - return LocalizedString("Not enough data", comment: "Description for MessageError notEnoughData") - case .invalidCrc: - return LocalizedString("Invalid CRC", comment: "Description for MessageError invalidCrc") - case .invalidSequence: - return LocalizedString("Unexpected message sequence number", comment: "Description for MessageError invalidSequence") - case .invalidAddress(address: let address): - return String(format: LocalizedString("Invalid address: (%1$@)", comment: "Description for MessageError invalidAddress"), String(format: "%08x", address)) - case .parsingError(let offset, let data, let error): - return String(format: LocalizedString("Parsing Error: %1$@ in (%2$@)", comment: "Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset)"), String(describing: error), data.suffix(from: offset).hexadecimalString) - case .unknownValue(let value, let typeDescription): - return String(format: LocalizedString("Unknown Value (%1$@) for type %2$@", comment: "Format string for description of MessageError unknownValue. (1: value) (2: Type)"), String(describing: value), typeDescription) - case .validationFailed(let description): - return String(format: LocalizedString("Validation failed: %1$@", comment: "Format string for description of MessageError validationFailed. (1: description of validation failure)"), description) - } - } -} - -struct Message { - let address: UInt32 - let messageBlocks: [MessageBlock] - let sequenceNum: Int - let expectFollowOnMessage: Bool - - init(address: UInt32, messageBlocks: [MessageBlock], sequenceNum: Int, expectFollowOnMessage: Bool = false) { - self.address = address - self.messageBlocks = messageBlocks - self.sequenceNum = sequenceNum - self.expectFollowOnMessage = expectFollowOnMessage - } - - init(encodedData: Data, checkCRC: Bool = true) throws { - guard encodedData.count >= 10 else { - throw MessageError.notEnoughData - } - self.address = encodedData[0...].toBigEndian(UInt32.self) - let b9 = encodedData[4] - let bodyLen = encodedData[5] - - if bodyLen > encodedData.count - 8 { - throw MessageError.notEnoughData - } - - self.expectFollowOnMessage = (b9 & 0b10000000) != 0 - self.sequenceNum = Int((b9 >> 2) & 0b1111) - let crc = (UInt16(encodedData[encodedData.count-2]) << 8) + UInt16(encodedData[encodedData.count-1]) - let msgWithoutCrc = encodedData.prefix(encodedData.count - 2) - if checkCRC { - guard msgWithoutCrc.crc16() == crc else { - throw MessageError.invalidCrc - } - } - self.messageBlocks = try Message.decodeBlocks(data: Data(msgWithoutCrc.suffix(from: 6))) - } - - static private func decodeBlocks(data: Data) throws -> [MessageBlock] { - var blocks = [MessageBlock]() - var idx = 0 - repeat { - guard let blockType = MessageBlockType(rawValue: data[idx]) else { - throw MessageBlockError.unknownBlockType(rawVal: data[idx]) - } - do { - let block = try blockType.blockType.init(encodedData: Data(data.suffix(from: idx))) - blocks.append(block) - idx += Int(block.data.count) - } catch (let error) { - throw MessageError.parsingError(offset: idx, data: data.suffix(from: idx), error: error) - } - } while idx < data.count - return blocks - } - - func encoded() -> Data { - var bytes = Data(bigEndian: address) - - var cmdData = Data() - for cmd in messageBlocks { - cmdData.append(cmd.data) - } - - let b9: UInt8 = ((expectFollowOnMessage ? 1 : 0) << 7) + (UInt8(sequenceNum & 0b1111) << 2) + UInt8((cmdData.count >> 8) & 0b11) - bytes.append(b9) - bytes.append(UInt8(cmdData.count & 0xff)) - - var data = Data(bytes) + cmdData - let crc: UInt16 = data.crc16() - data.appendBigEndian(crc) - return data - } - - var fault: DetailedStatus? { - if messageBlocks.count > 0 && messageBlocks[0].blockType == .podInfoResponse, - let infoResponse = messageBlocks[0] as? PodInfoResponse, - infoResponse.podInfoResponseSubType == .detailedStatus, - let detailedStatus = infoResponse.podInfo as? DetailedStatus, - detailedStatus.isFaulted - { - return detailedStatus - } else { - return nil - } - } -} - -extension Message: CustomDebugStringConvertible { - var debugDescription: String { - let sequenceNumStr = String(format: "%02d", sequenceNum) - return "Message(\(Data(bigEndian: address).hexadecimalString) seq:\(sequenceNumStr) \(messageBlocks))" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/AcknowledgeAlertCommand.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/AcknowledgeAlertCommand.swift deleted file mode 100644 index 5bab667c2..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/AcknowledgeAlertCommand.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// AcknowledgeAlertCommand.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/AcknowledgeAlertCommand.swift -// Created by Eelke Jager on 18/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct AcknowledgeAlertCommand : NonceResyncableMessageBlock { - // OFF 1 2 3 4 5 6 - // 11 05 NNNNNNNN MM - - public let blockType: MessageBlockType = .acknowledgeAlert - public let length: UInt8 = 5 - public var nonce: UInt32 - public let alerts: AlertSet - - public init(nonce: UInt32, alerts: AlertSet) { - self.nonce = nonce - self.alerts = alerts - } - - public init(encodedData: Data) throws { - if encodedData.count < 7 { - throw MessageBlockError.notEnoughData - } - self.nonce = encodedData[2...].toBigEndian(UInt32.self) - self.alerts = AlertSet(rawValue: encodedData[6]) - } - - public var data: Data { - var data = Data([ - blockType.rawValue, - length - ]) - data.appendBigEndian(nonce) - data.append(alerts.rawValue) - return data - } -} - -extension AcknowledgeAlertCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "AcknowledgeAlertCommand(blockType:\(blockType), length:\(length), alerts:\(alerts))" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/AssignAddressCommand.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/AssignAddressCommand.swift deleted file mode 100644 index 46f42b849..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/AssignAddressCommand.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// AssignAddressCommand.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/AssignAddressCommand.swift -// Created by Pete Schwamb on 2/12/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct AssignAddressCommand : MessageBlock { - - public let blockType: MessageBlockType = .assignAddress - public let length: Int = 6 - - let address: UInt32 - - public var data: Data { - var data = Data([ - blockType.rawValue, - 4 - ]) - data.appendBigEndian(self.address) - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < length { - throw MessageBlockError.notEnoughData - } - - self.address = encodedData[2...].toBigEndian(UInt32.self) - } - - public init(address: UInt32) { - self.address = address - } -} - -extension AssignAddressCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "AssignAddressCommand(address:\(Data(bigEndian: address).hexadecimalString))" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/BasalScheduleExtraCommand.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/BasalScheduleExtraCommand.swift deleted file mode 100644 index 39b503e20..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/BasalScheduleExtraCommand.swift +++ /dev/null @@ -1,110 +0,0 @@ -// -// BasalScheduleExtraCommand.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/BasalScheduleExtraCommand.swift -// Created by Pete Schwamb on 3/30/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct BasalScheduleExtraCommand : MessageBlock { - - public let blockType: MessageBlockType = .basalScheduleExtra - - public let acknowledgementBeep: Bool - public let completionBeep: Bool - public let programReminderInterval: TimeInterval - public let currentEntryIndex: UInt8 - public let remainingPulses: Double - public let delayUntilNextTenthOfPulse: TimeInterval - public let rateEntries: [RateEntry] - - public var data: Data { - let beepOptions = (UInt8(programReminderInterval.minutes) & 0x3f) + (completionBeep ? (1<<6) : 0) + (acknowledgementBeep ? (1<<7) : 0) - var data = Data([ - blockType.rawValue, - UInt8(8 + rateEntries.count * 6), - beepOptions, - currentEntryIndex - ]) - data.appendBigEndian(UInt16(round(remainingPulses * 10))) - data.appendBigEndian(UInt32(round(delayUntilNextTenthOfPulse.milliseconds * 1000))) - for entry in rateEntries { - data.append(entry.data) - } - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 14 { - throw MessageBlockError.notEnoughData - } - let length = encodedData[1] - let numEntries = (length - 8) / 6 - - acknowledgementBeep = encodedData[2] & (1<<7) != 0 - completionBeep = encodedData[2] & (1<<6) != 0 - programReminderInterval = TimeInterval(minutes: Double(encodedData[2] & 0x3f)) - - currentEntryIndex = encodedData[3] - remainingPulses = Double(encodedData[4...].toBigEndian(UInt16.self)) / 10.0 - let timerCounter = encodedData[6...].toBigEndian(UInt32.self) - delayUntilNextTenthOfPulse = TimeInterval(hundredthsOfMilliseconds: Double(timerCounter)) - var entries = [RateEntry]() - for entryIndex in (0..= t && scheduleOffsetNearestSecond <= t + rateEntryDuration { - self.currentEntryIndex = entryIndex - - let timeRemaining = (t + rateEntryDuration) - scheduleOffsetNearestSecond - self.delayUntilNextTenthOfPulse = timeRemaining.truncatingRemainder(dividingBy: (rateEntry.delayBetweenPulses / 10)) - - let pulsesRemaining = rateEntry.totalPulses * (timeRemaining / rateEntryDuration) - self.remainingPulses = pulsesRemaining == 0 ? 0.1 : ceil(pulsesRemaining * 10) / 10 - return - } - t += rateEntryDuration - entryIndex += 1 - } - fatalError("RateEntry schedule incomplete") - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/BeepConfigCommand.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/BeepConfigCommand.swift deleted file mode 100644 index d41f5e1ac..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/BeepConfigCommand.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// BeepConfigCommand.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/BeepConfigCommand.swift -// Created by Joseph Moran on 5/12/19. -// Copyright © 2019 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct BeepConfigCommand : MessageBlock { - // OFF 1 2 3 4 5 - // 1e 04 AABBCCDD - - public let blockType: MessageBlockType = .beepConfig - public let beepType: BeepType - public let basalCompletionBeep: Bool - public let basalIntervalBeep: TimeInterval - public let tempBasalCompletionBeep: Bool - public let tempBasalIntervalBeep: TimeInterval - public let bolusCompletionBeep: Bool - public let bolusIntervalBeep: TimeInterval - - public init(beepType: BeepType, basalCompletionBeep: Bool = false, basalIntervalBeep: TimeInterval = 0, tempBasalCompletionBeep: Bool = false, tempBasalIntervalBeep: TimeInterval = 0, bolusCompletionBeep: Bool = false, bolusIntervalBeep: TimeInterval = 0) { - self.beepType = beepType - self.basalCompletionBeep = basalCompletionBeep - self.basalIntervalBeep = basalIntervalBeep - self.tempBasalCompletionBeep = tempBasalCompletionBeep - self.tempBasalIntervalBeep = tempBasalIntervalBeep - self.bolusCompletionBeep = bolusCompletionBeep - self.bolusIntervalBeep = bolusIntervalBeep - } - - public init(encodedData: Data) throws { - if encodedData.count < 6 { - throw MessageBlockError.notEnoughData - } - if let beepType = BeepType.init(rawValue: encodedData[2]) { - self.beepType = beepType - } else { - throw MessageBlockError.parseError - } - self.basalCompletionBeep = encodedData[3] & (1<<6) != 0 - self.basalIntervalBeep = TimeInterval(minutes: Double(encodedData[3] & 0x3f)) - self.tempBasalCompletionBeep = encodedData[4] & (1<<6) != 0 - self.tempBasalIntervalBeep = TimeInterval(minutes: Double(encodedData[4] & 0x3f)) - self.bolusCompletionBeep = encodedData[5] & (1<<6) != 0 - self.bolusIntervalBeep = TimeInterval(minutes: Double(encodedData[5] & 0x3f)) - } - - public var data: Data { - var data = Data([ - blockType.rawValue, - 4, - ]) - data.append(beepType.rawValue) - data.append((basalCompletionBeep ? (1<<6) : 0) + (UInt8(basalIntervalBeep.minutes) & 0x3f)) - data.append((tempBasalCompletionBeep ? (1<<6) : 0) + (UInt8(tempBasalIntervalBeep.minutes) & 0x3f)) - data.append((bolusCompletionBeep ? (1<<6) : 0) + (UInt8(bolusIntervalBeep.minutes) & 0x3f)) - return data - } -} - -extension BeepConfigCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "BeepConfigCommand(beepType:\(beepType), basalIntervalBeep:\(basalIntervalBeep), tempBasalCompletionBeep:\(tempBasalCompletionBeep), tempBasalIntervalBeep:\(tempBasalIntervalBeep), bolusCompletionBeep:\(bolusCompletionBeep), bolusIntervalBeep:\(bolusIntervalBeep))" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/BolusExtraCommand.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/BolusExtraCommand.swift deleted file mode 100644 index 60887c721..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/BolusExtraCommand.swift +++ /dev/null @@ -1,84 +0,0 @@ -// -// BolusExtraCommand.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/BolusExtraCommand.swift -// Created by Pete Schwamb on 2/24/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct BolusExtraCommand : MessageBlock { - - public let blockType: MessageBlockType = .bolusExtra - - public let acknowledgementBeep: Bool - public let completionBeep: Bool - public let programReminderInterval: TimeInterval - public let units: Double - public let timeBetweenPulses: TimeInterval - public let extendedUnits: Double - public let extendedDuration: TimeInterval - - // 17 0d 7c 1770 00030d40 0000 00000000 - // 0 1 2 3 5 9 13 - public var data: Data { - let beepOptions = (UInt8(programReminderInterval.minutes) & 0x3f) + (completionBeep ? (1<<6) : 0) + (acknowledgementBeep ? (1<<7) : 0) - - var data = Data([ - blockType.rawValue, - 0x0d, - beepOptions - ]) - - data.appendBigEndian(UInt16(round(units * Pod.pulsesPerUnit * 10))) - data.appendBigEndian(UInt32(timeBetweenPulses.hundredthsOfMilliseconds)) - - let pulseCountX10 = UInt16(round(extendedUnits * Pod.pulsesPerUnit * 10)) - data.appendBigEndian(pulseCountX10) - - let timeBetweenExtendedPulses = pulseCountX10 > 0 ? extendedDuration / (Double(pulseCountX10) / 10) : 0 - data.appendBigEndian(UInt32(timeBetweenExtendedPulses.hundredthsOfMilliseconds)) - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 15 { - throw MessageBlockError.notEnoughData - } - - acknowledgementBeep = encodedData[2] & (1<<7) != 0 - completionBeep = encodedData[2] & (1<<6) != 0 - programReminderInterval = TimeInterval(minutes: Double(encodedData[2] & 0x3f)) - - units = Double(encodedData[3...].toBigEndian(UInt16.self)) / (Pod.pulsesPerUnit * 10) - - let delayCounts = encodedData[5...].toBigEndian(UInt32.self) - timeBetweenPulses = TimeInterval(hundredthsOfMilliseconds: Double(delayCounts)) - - let pulseCountX10 = encodedData[9...].toBigEndian(UInt16.self) - extendedUnits = Double(pulseCountX10) / (Pod.pulsesPerUnit * 10) - - let intervalCounts = encodedData[11...].toBigEndian(UInt32.self) - let timeBetweenExtendedPulses = TimeInterval(hundredthsOfMilliseconds: Double(intervalCounts)) - extendedDuration = timeBetweenExtendedPulses * (Double(pulseCountX10) / 10) - } - - public init(units: Double = 0, timeBetweenPulses: TimeInterval = Pod.secondsPerBolusPulse, extendedUnits: Double = 0.0, extendedDuration: TimeInterval = 0, acknowledgementBeep: Bool = false, completionBeep: Bool = false, programReminderInterval: TimeInterval = 0) { - self.acknowledgementBeep = acknowledgementBeep - self.completionBeep = completionBeep - self.programReminderInterval = programReminderInterval - self.units = units - self.timeBetweenPulses = timeBetweenPulses != 0 ? timeBetweenPulses : Pod.secondsPerBolusPulse - self.extendedUnits = extendedUnits - self.extendedDuration = extendedDuration - } -} - - -extension BolusExtraCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "BolusExtraCommand(units:\(units), timeBetweenPulses:\(timeBetweenPulses), extendedUnits:\(extendedUnits), extendedDuration:\(extendedDuration), acknowledgementBeep:\(acknowledgementBeep), completionBeep:\(completionBeep), programReminderInterval:\(programReminderInterval.minutes))" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/CancelDeliveryCommand.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/CancelDeliveryCommand.swift deleted file mode 100644 index d493c7470..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/CancelDeliveryCommand.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// CancelDeliveryCommand.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/CancelDeliveryCommand.swift -// Created by Pete Schwamb on 2/23/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - - -public struct CancelDeliveryCommand : NonceResyncableMessageBlock { - - public let blockType: MessageBlockType = .cancelDelivery - // OFF 1 2 3 4 5 6 - // 1F 05 NNNNNNNN AX - - // Cancel bolus (with confirmation beep) - // 1f 05 be1b741a 64 - - // Cancel temp basal (with confirmation beep) - // 1f 05 f76d34c4 62 - - // Cancel all (before deactivate pod) - // 1f 05 e1f78752 07 - - // Cancel basal & temp basal for a suspend, followed by a configure alerts command (0x19) for alerts 5 & 6 - // 1f 05 50f02312 03 19 10 50f02312 580f 000f 0604 6800 001e 0302 - - public struct DeliveryType: OptionSet, Equatable { - public let rawValue: UInt8 - - public static let none = DeliveryType() - public static let basal = DeliveryType(rawValue: 1 << 0) - public static let tempBasal = DeliveryType(rawValue: 1 << 1) - public static let bolus = DeliveryType(rawValue: 1 << 2) - - public static let allButBasal: DeliveryType = [.tempBasal, .bolus] - public static let all: DeliveryType = [.none, .basal, .tempBasal, .bolus] - - public init(rawValue: UInt8) { - self.rawValue = rawValue - } - - var debugDescription: String { - switch self { - case .none: - return "None" - case .basal: - return "Basal" - case .tempBasal: - return "TempBasal" - case .all: - return "All" - case .allButBasal: - return "AllButBasal" - default: - return "\(self.rawValue)" - } - } - } - - public let deliveryType: DeliveryType - - public let beepType: BeepType - - public var nonce: UInt32 - - public var data: Data { - var data = Data([ - blockType.rawValue, - 5, - ]) - data.appendBigEndian(nonce) - data.append((beepType.rawValue << 4) + deliveryType.rawValue) - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 7 { - throw MessageBlockError.notEnoughData - } - self.nonce = encodedData[2...].toBigEndian(UInt32.self) - self.deliveryType = DeliveryType(rawValue: encodedData[6] & 0xf) - self.beepType = BeepType(rawValue: encodedData[6] >> 4)! - } - - public init(nonce: UInt32, deliveryType: DeliveryType, beepType: BeepType) { - self.nonce = nonce - self.deliveryType = deliveryType - self.beepType = beepType - } -} - -extension CancelDeliveryCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "CancelDeliveryCommand(nonce:\(Data(bigEndian: nonce).hexadecimalString), deliveryType:\(deliveryType.debugDescription), beepType:\(beepType))" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/ConfigureAlertsCommand.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/ConfigureAlertsCommand.swift deleted file mode 100644 index ae2651777..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/ConfigureAlertsCommand.swift +++ /dev/null @@ -1,144 +0,0 @@ -// -// ConfigureAlertsCommand.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/ConfigureAlertsCommand.swift -// Created by Pete Schwamb on 2/22/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct ConfigureAlertsCommand : NonceResyncableMessageBlock { - - public let blockType: MessageBlockType = .configureAlerts - - public var nonce: UInt32 - let configurations: [AlertConfiguration] - - public var data: Data { - var data = Data([ - blockType.rawValue, - UInt8(4 + configurations.count * AlertConfiguration.length), - ]) - data.appendBigEndian(nonce) - // Sorting the alerts not required, but it can be helpful for log analysis - let sorted = configurations.sorted { $0.slot.rawValue < $1.slot.rawValue } - for config in sorted { - data.append(contentsOf: config.data) - } - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 10 { - throw MessageBlockError.notEnoughData - } - self.nonce = encodedData[2...].toBigEndian(UInt32.self) - - let length = Int(encodedData[1]) - - let numConfigs = (length - 4) / AlertConfiguration.length - - var configs = [AlertConfiguration]() - - for i in 0..> 4 - guard let alertType = AlertSlot(rawValue: alertTypeBits) else { - throw MessageError.unknownValue(value: alertTypeBits, typeDescription: "AlertType") - } - self.slot = alertType - - self.active = encodedData[0] & 0b1000 != 0 - - self.autoOffModifier = encodedData[0] & 0b10 != 0 - - self.duration = TimeInterval(minutes: Double((Int(encodedData[0] & 0b1) << 8) + Int(encodedData[1]))) - - let yyyy = (Int(encodedData[2]) << 8) + (Int(encodedData[3])) & 0x3fff - - if encodedData[0] & 0b100 != 0 { - let volume = Double(yyyy * 2) / Pod.pulsesPerUnit - self.trigger = .unitsRemaining(volume) - } else { - self.trigger = .timeUntilAlert(TimeInterval(minutes: Double(yyyy))) - } - - let beepRepeatBits = encodedData[4] - guard let beepRepeat = BeepRepeat(rawValue: beepRepeatBits) else { - throw MessageError.unknownValue(value: beepRepeatBits, typeDescription: "BeepRepeat") - } - self.beepRepeat = beepRepeat - - let beepTypeBits = encodedData[5] - guard let beepType = BeepType(rawValue: beepTypeBits) else { - throw MessageError.unknownValue(value: beepTypeBits, typeDescription: "BeepType") - } - self.beepType = beepType - - self.silent = (beepType == .noBeepNonCancel) - } - - public var data: Data { - var firstByte = slot.rawValue << 4 - firstByte += active ? (1 << 3) : 0 - - if case .unitsRemaining = trigger { - firstByte += 1 << 2 - } - if autoOffModifier { - firstByte += 1 << 1 - } - - // The 9-bit duration is limited to 2^9-1 minutes max value - let durationMinutes = min(UInt(duration.minutes), 0x1ff) - - // High bit of duration - firstByte += UInt8((durationMinutes >> 8) & 0x1) - - var data = Data([ - firstByte, - UInt8(durationMinutes & 0xff) - ]) - - switch trigger { - case .unitsRemaining(let volume): - let ticks = UInt16(volume / Pod.pulseSize / 2) - data.appendBigEndian(ticks) - case .timeUntilAlert(let secondsUntilAlert): - // round the time to alert to the nearest minute - let minutes = UInt16((secondsUntilAlert + 30).minutes) - data.appendBigEndian(minutes) - } - data.append(beepRepeat.rawValue) - let beepTypeToSet: BeepType = silent ? .noBeepNonCancel : beepType - data.append(beepTypeToSet.rawValue) - - return data - } -} - -extension ConfigureAlertsCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "ConfigureAlertsCommand(nonce:\(Data(bigEndian: nonce).hexadecimalString), configurations:\(configurations))" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/DeactivatePodCommand.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/DeactivatePodCommand.swift deleted file mode 100644 index 382dd3a1c..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/DeactivatePodCommand.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// DeactivatePodCommand.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/DeactivatePodCommand.swift -// Created by Pete Schwamb on 2/24/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct DeactivatePodCommand : NonceResyncableMessageBlock { - // OFF 1 2 3 4 5 - // 1C 04 NNNNNNNN - - public let blockType: MessageBlockType = .deactivatePod - - public var nonce: UInt32 - - public var data: Data { - var data = Data([ - blockType.rawValue, - 4, - ]) - data.appendBigEndian(nonce) - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 6 { - throw MessageBlockError.notEnoughData - } - self.nonce = encodedData[2...].toBigEndian(UInt32.self) - } - - public init(nonce: UInt32) { - self.nonce = nonce - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/DetailedStatus.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/DetailedStatus.swift deleted file mode 100644 index 009b92718..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/DetailedStatus.swift +++ /dev/null @@ -1,223 +0,0 @@ -// -// DetailedStatus.swift -// OmniBLE -// -// Based on OmniKit/MessageTransport/MessageBlocks/DetailedStatus.swift -// Created by Pete Schwamb on 2/23/18. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -// DetailedStatus is the PodInfo subtype 2 returned for a type 2 GetStatus command and -// is also returned on a pod fault for any command normally returning a StatusResponse -public struct DetailedStatus : PodInfo, Equatable { - // CMD 1 2 3 4 5 6 7 8 9 10 1112 1314 1516 17 18 19 20 21 2223 - // DATA 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW XX YYYY - - public let podInfoType: PodInfoResponseSubType = .detailedStatus - public let podProgressStatus: PodProgressStatus - public let deliveryStatus: DeliveryStatus - public let bolusNotDelivered: Double - public let lastProgrammingMessageSeqNum: UInt8 // updated by pod for 03, 08, $11, $19, $1A, $1C, $1E & $1F command messages - public let totalInsulinDelivered: Double - public let faultEventCode: FaultEventCode - public let faultEventTimeSinceActivation: TimeInterval? - public let reservoirLevel: Double - public let timeActive: TimeInterval - public let unacknowledgedAlerts: AlertSet - public let faultAccessingTables: Bool - public let errorEventInfo: ErrorEventInfo? - public let receiverLowGain: UInt8 - public let radioRSSI: UInt8 - public let previousPodProgressStatus: PodProgressStatus? - public let possibleFaultCallingAddress: UInt16? - public let data: Data - - public init(encodedData: Data) throws { - guard encodedData.count >= 22 else { - throw MessageBlockError.notEnoughData - } - - guard PodProgressStatus(rawValue: encodedData[1]) != nil else { - throw MessageError.unknownValue(value: encodedData[1], typeDescription: "PodProgressStatus") - } - self.podProgressStatus = PodProgressStatus(rawValue: encodedData[1])! - - self.deliveryStatus = DeliveryStatus(rawValue: encodedData[2] & 0xf)! - - self.bolusNotDelivered = Double((Int(encodedData[3] & 0x3) << 8) | Int(encodedData[4])) / Pod.pulsesPerUnit - - self.lastProgrammingMessageSeqNum = encodedData[5] - - self.totalInsulinDelivered = Double(encodedData[6...7].toBigEndian(UInt16.self)) / Pod.pulsesPerUnit - - self.faultEventCode = FaultEventCode(rawValue: encodedData[8]) - - let minutesSinceActivation = encodedData[9...10].toBigEndian(UInt16.self) - if minutesSinceActivation != 0xffff { - self.faultEventTimeSinceActivation = TimeInterval(minutes: Double(minutesSinceActivation)) - } else { - self.faultEventTimeSinceActivation = nil - } - - self.reservoirLevel = Double((Int(encodedData[11] & 0x3) << 8) + Int(encodedData[12])) / Pod.pulsesPerUnit - - self.timeActive = TimeInterval(minutes: Double(encodedData[13...14].toBigEndian(UInt16.self))) - - self.unacknowledgedAlerts = AlertSet(rawValue: encodedData[15]) - - self.faultAccessingTables = (encodedData[16] & 2) != 0 - - if encodedData[17] == 0x00 { - // no fault has occurred, errorEventInfo and previousPodProgressStatus not valid - self.errorEventInfo = nil - self.previousPodProgressStatus = nil - } else { - // fault has occurred, VV byte contains valid fault info - let errorEventInfo = ErrorEventInfo(rawValue: encodedData[17]) - self.errorEventInfo = errorEventInfo - // errorEventInfo.podProgressStatus is valid for both Eros and Dash on fault - self.previousPodProgressStatus = errorEventInfo.podProgressStatus - } - - // For Dash these values have always been zero - self.receiverLowGain = UInt8(encodedData[18] >> 6) - self.radioRSSI = UInt8(encodedData[18] & 0x3F) - - // For Eros, encodedData[19] (XX) byte is the same previousPodProgressStatus nibble in the VV byte on fault. - // For Dash, encodedData[19] (XX) byte is uninitialized or unknown, so use VV byte for previousPodProgressStatus. - - // Decode YYYY based on whether there was a pod fault - if encodedData[8] == 0 { - // For non-faults, YYYY contents not valid (either uninitialized data for Eros or some unknown content for Dash). - self.possibleFaultCallingAddress = nil - } else { - // For Eros faults, YYYY is always uninitialized data from the previous command/response at the same buffer offset. - // For Dash faults, YYYY could be a calling address of the fault routine for the first return after a pod fault, - // subsequent returns will be byte swapped data from previous command/response at the same buffer offset. - self.possibleFaultCallingAddress = encodedData[20...21].toBigEndian(UInt16.self) // only potentially valid for Dash - } - - self.data = Data(encodedData) - } - - public var isFaulted: Bool { - return faultEventCode.faultType != .noFaults || podProgressStatus == .activationTimeExceeded - } -} - -extension DetailedStatus: CustomDebugStringConvertible { - public typealias RawValue = Data - public var debugDescription: String { - var result = [ - "## DetailedStatus", - "* rawHex: \(data.hexadecimalString)", - "* podProgressStatus: \(podProgressStatus)", - "* deliveryStatus: \(deliveryStatus.description)", - "* bolusNotDelivered: \(bolusNotDelivered.twoDecimals) U", - "* lastProgrammingMessageSeqNum: \(lastProgrammingMessageSeqNum)", - "* totalInsulinDelivered: \(totalInsulinDelivered.twoDecimals) U", - "* reservoirLevel: \(reservoirLevel == Pod.reservoirLevelAboveThresholdMagicNumber ? "50+" : reservoirLevel.twoDecimals) U", - "* timeActive: \(timeActive.timeIntervalStr)", - "* unacknowledgedAlerts: \(unacknowledgedAlerts)", - "", - ].joined(separator: "\n") - if radioRSSI != 0 { - result += [ - "* receiverLowGain: \(receiverLowGain)", - "* radioRSSI: \(radioRSSI)", - "", - ].joined(separator: "\n") - } - if faultEventCode.faultType != .noFaults { - result += [ - "* faultEventCode: \(faultEventCode.description)", - "* faultAccessingTables: \(faultAccessingTables)", - "* faultEventTimeSinceActivation: \(faultEventTimeSinceActivation?.timeIntervalStr ?? "NA")", - "* errorEventInfo: \(errorEventInfo?.description ?? "NA")", - "* previousPodProgressStatus: \(previousPodProgressStatus?.description ?? "NA")", - "* possibleFaultCallingAddress: \(possibleFaultCallingAddress != nil ? String(format: "0x%04x", possibleFaultCallingAddress!) : "NA")", - "", - ].joined(separator: "\n") - } - return result - } -} - -extension DetailedStatus: RawRepresentable { - public init?(rawValue: Data) { - do { - try self.init(encodedData: rawValue) - } catch { - return nil - } - } - - public var rawValue: Data { - return data - } -} - -extension TimeInterval { - var timeIntervalStr: String { - var str: String = "" - let hours = UInt(self / 3600) - let minutes = UInt(self / 60) % 60 - let seconds = UInt(self) % 60 - if hours != 0 { - str += String(format: "%uh", hours) - } - if minutes != 0 || hours != 0 { - str += String(format: "%um", minutes) - } - if seconds != 0 || str.isEmpty { - str += String(format: "%us", seconds) - } - return str - } -} - -extension Double { - var twoDecimals: String { - return String(format: "%.2f", self) - } -} - -// Type for the ErrorEventInfo VV byte if valid -// a: insulin state table corruption found during error logging -// bb: internal 2-bit occlusion type -// c: immediate bolus in progress during error -// dddd: Pod Progress at time of first logged fault event -// -public struct ErrorEventInfo: CustomStringConvertible, Equatable { - public let rawValue: UInt8 - public let insulinStateTableCorruption: Bool // 'a' bit - public let occlusionType: Int // 'bb' 2-bit occlusion type - public let immediateBolusInProgress: Bool // 'c' bit - public let podProgressStatus: PodProgressStatus // 'dddd' bits - - public var errorEventInfo: ErrorEventInfo? { - return ErrorEventInfo(rawValue: rawValue) - } - - public var description: String { - let hexString = String(format: "%02X", rawValue) - return [ - "rawValue: 0x\(hexString)", - "insulinStateTableCorruption: \(insulinStateTableCorruption)", - "occlusionType: \(occlusionType)", - "immediateBolusInProgress: \(immediateBolusInProgress)", - "podProgressStatus: \(podProgressStatus)", - ].joined(separator: ", ") - } - - init(rawValue: UInt8) { - self.rawValue = rawValue - self.insulinStateTableCorruption = (rawValue & 0x80) != 0 - self.occlusionType = Int((rawValue & 0x60) >> 5) - self.immediateBolusInProgress = (rawValue & 0x10) != 0 - self.podProgressStatus = PodProgressStatus(rawValue: rawValue & 0xF)! - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/ErrorResponse.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/ErrorResponse.swift deleted file mode 100644 index 9eb532710..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/ErrorResponse.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// ErrorResponse.swift -// OmniBLE -// -// Based on OmniKit/MessageTransport/MessageBlocks/ErrorResponse.swift -// Created by Pete Schwamb on 2/25/18. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -fileprivate let errorResponseCode_badNonce: UInt8 = 0x14 // only returned on Eros - -public enum ErrorResponseType { - case badNonce(nonceResyncKey: UInt16) // only returned on Eros - case nonretryableError(code: UInt8, faultEventCode: FaultEventCode, podProgress: PodProgressStatus) -} - -// 06 14 WWWW, WWWW is the encoded nonce resync key -// 06 EE FF0P, EE != 0x14, FF = fault code (if any), 0P = pod progress status (1..15) - -public struct ErrorResponse : MessageBlock { - public let blockType: MessageBlockType = .errorResponse - public let errorResponseType: ErrorResponseType - public let data: Data - - public init(encodedData: Data) throws { - let errorCode = encodedData[2] - switch (errorCode) { - case errorResponseCode_badNonce: - // For this error code only the 2 next bytes are the encoded nonce resync key (only returned on Eros) - let nonceResyncKey: UInt16 = encodedData[3...].toBigEndian(UInt16.self) - errorResponseType = .badNonce(nonceResyncKey: nonceResyncKey) - break - default: - // All other error codes are some non-retryable command error. In this case, - // the next 2 bytes are any saved fault code (typically 0) and the pod progress value. - let faultEventCode = FaultEventCode(rawValue: encodedData[3]) - guard let podProgress = PodProgressStatus(rawValue: encodedData[4]) else { - throw MessageError.unknownValue(value: encodedData[4], typeDescription: "ErrorResponse PodProgressStatus") - } - errorResponseType = .nonretryableError(code: errorCode, faultEventCode: faultEventCode, podProgress: podProgress) - break - } - self.data = encodedData - } -} - diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/FaultConfigCommand.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/FaultConfigCommand.swift deleted file mode 100644 index 2f6f87910..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/FaultConfigCommand.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// FaultConfigCommand.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/FaultConfigCommand.swift -// Created by Pete Schwamb on 12/18/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct FaultConfigCommand : NonceResyncableMessageBlock { - // OFF 1 2 3 4 5 6 7 - // 08 06 NNNNNNNN JJ KK - - public let blockType: MessageBlockType = .faultConfig - public let length: UInt8 = 6 - public var nonce: UInt32 - public let tab5Sub16: UInt8 - public let tab5Sub17: UInt8 - - public init(nonce: UInt32, tab5Sub16: UInt8, tab5Sub17: UInt8) { - self.nonce = nonce - self.tab5Sub16 = tab5Sub16 - self.tab5Sub17 = tab5Sub17 - } - - public init(encodedData: Data) throws { - if encodedData.count < 8 { - throw MessageBlockError.notEnoughData - } - - nonce = encodedData[2...].toBigEndian(UInt32.self) - - self.tab5Sub16 = encodedData[6] - self.tab5Sub17 = encodedData[7] - } - - public var data: Data { - var data = Data([ - blockType.rawValue, - length]) - - data.appendBigEndian(nonce) - data.append(tab5Sub16) - data.append(tab5Sub17) - return data - } -} - -extension FaultConfigCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "FaultConfigCommand(nonce:\(Data(bigEndian: nonce).hexadecimalString), tab5Sub16:\(tab5Sub16), tab5Sub17:\(tab5Sub17))" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/GetStatusCommand.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/GetStatusCommand.swift deleted file mode 100644 index 2cc91acc3..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/GetStatusCommand.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// GetStatusCommand.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/GetStatusCommand.swift -// Created by Pete Schwamb on 10/14/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct GetStatusCommand : MessageBlock { - // OFF 1 2 - // Oe 01 TT - - public let blockType: MessageBlockType = .getStatus - public let length: UInt8 = 1 - public let podInfoType: PodInfoResponseSubType - - public init(podInfoType: PodInfoResponseSubType = .normal) { - self.podInfoType = podInfoType - } - - public init(encodedData: Data) throws { - if encodedData.count < 3 { - throw MessageBlockError.notEnoughData - } - guard let podInfoType = PodInfoResponseSubType(rawValue: encodedData[2]) else { - throw MessageError.unknownValue(value: encodedData[2], typeDescription: "PodInfoResponseSubType") - } - self.podInfoType = podInfoType - } - - public var data: Data { - var data = Data([ - blockType.rawValue, - length - ]) - data.append(podInfoType.rawValue) - return data - } -} - -extension GetStatusCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "GetStatusCommand(\(podInfoType))" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/MessageBlock.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/MessageBlock.swift deleted file mode 100644 index c2e1c90e1..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/MessageBlock.swift +++ /dev/null @@ -1,87 +0,0 @@ -// -// MessageBlock.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/MessageBlock.swift -// Created by Pete Schwamb on 10/14/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - -public enum MessageBlockError: Error { - case notEnoughData - case unknownBlockType(rawVal: UInt8) - case parseError -} - -// See https://github.com/openaps/openomni/wiki/Message-Types -public enum MessageBlockType: UInt8 { - case versionResponse = 0x01 - case podInfoResponse = 0x02 - case setupPod = 0x03 - case errorResponse = 0x06 - case assignAddress = 0x07 - case faultConfig = 0x08 - case getStatus = 0x0e - case acknowledgeAlert = 0x11 - case basalScheduleExtra = 0x13 - case tempBasalExtra = 0x16 - case bolusExtra = 0x17 - case configureAlerts = 0x19 - case setInsulinSchedule = 0x1a - case deactivatePod = 0x1c - case statusResponse = 0x1d - case beepConfig = 0x1e - case cancelDelivery = 0x1f - - public var blockType: MessageBlock.Type { - switch self { - case .versionResponse: - return VersionResponse.self - case .acknowledgeAlert: - return AcknowledgeAlertCommand.self - case .podInfoResponse: - return PodInfoResponse.self - case .setupPod: - return SetupPodCommand.self - case .errorResponse: - return ErrorResponse.self - case .assignAddress: - return AssignAddressCommand.self - case .getStatus: - return GetStatusCommand.self - case .basalScheduleExtra: - return BasalScheduleExtraCommand.self - case .bolusExtra: - return BolusExtraCommand.self - case .configureAlerts: - return ConfigureAlertsCommand.self - case .setInsulinSchedule: - return SetInsulinScheduleCommand.self - case .deactivatePod: - return DeactivatePodCommand.self - case .statusResponse: - return StatusResponse.self - case .tempBasalExtra: - return TempBasalExtraCommand.self - case .beepConfig: - return BeepConfigCommand.self - case .cancelDelivery: - return CancelDeliveryCommand.self - case .faultConfig: - return FaultConfigCommand.self - } - } -} - -public protocol MessageBlock { - init(encodedData: Data) throws - - var blockType: MessageBlockType { get } - var data: Data { get } -} - -public protocol NonceResyncableMessageBlock : MessageBlock { - var nonce: UInt32 { get set } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PlaceholderMessageBlock.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PlaceholderMessageBlock.swift deleted file mode 100644 index 2e8864750..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PlaceholderMessageBlock.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// PlaceholderMessageBlock.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/PlaceholderMessageBlock.swift -// Created by Pete Schwamb on 10/24/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct PlaceholderMessageBlock: MessageBlock { - public let blockType: MessageBlockType - public let length: UInt8 - - public let data: Data - - public init(encodedData: Data) throws { - if encodedData.count < 2 { - throw MessageBlockError.notEnoughData - } - guard let blockType = MessageBlockType(rawValue: encodedData[0]) else { - throw MessageBlockError.unknownBlockType(rawVal: encodedData[0]) - } - self.blockType = blockType - length = encodedData[1] - data = encodedData.prefix(upTo: Int(length)) - } -} - diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfo.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfo.swift deleted file mode 100644 index 37915debb..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfo.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// PodInfoResponseSubType.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/PodInfoResponseSubType.swift -// Created by Eelke Jager on 15/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public protocol PodInfo { - init(encodedData: Data) throws - var podInfoType: PodInfoResponseSubType { get } - var data: Data { get } - -} - -public enum PodInfoResponseSubType: UInt8, Equatable { - case normal = 0x00 - case configuredAlerts = 0x01 // Returns information on configured alerts - case detailedStatus = 0x02 // Returned on any pod fault - case pulseLogPlus = 0x03 // Returns up to the last 60 pulse log entries plus additional info - case activationTime = 0x05 // Returns activation date, elapsed time, and fault code - case pulseLogRecent = 0x50 // Returns the last 50 pulse log entries - case pulseLogPrevious = 0x51 // Like 0x50, but returns up to the previous 50 entries before the last 50 - - public var podInfoType: PodInfo.Type { - switch self { - case .normal: - return StatusResponse.self as! PodInfo.Type - case .configuredAlerts: - return PodInfoConfiguredAlerts.self - case .detailedStatus: - return DetailedStatus.self - case .pulseLogPlus: - return PodInfoPulseLogPlus.self - case .activationTime: - return PodInfoActivationTime.self - case .pulseLogRecent: - return PodInfoPulseLogRecent.self - case .pulseLogPrevious: - return PodInfoPulseLogPrevious.self - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfoActivationTime.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfoActivationTime.swift deleted file mode 100644 index 83156e48a..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfoActivationTime.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// PodInfoActivationTime.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/PodInfoResponseSubType.swift -// Created by Eelke Jager on 25/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -// Type 5 PodInfo returns the pod activation time, time pod alive, and the possible fault code -public struct PodInfoActivationTime : PodInfo { - // OFF 1 2 3 4 5 6 7 8 9 10111213 1415161718 - // DATA 0 1 2 3 4 5 6 7 8 9 1011 1213141516 - // 02 11 05 PP QQQQ 00000000 00000000 MMDDYYHHMM - - public let podInfoType: PodInfoResponseSubType = .activationTime - public let faultEventCode: FaultEventCode - public let timeActivation: TimeInterval - public let dateTime: DateComponents - public let data: Data - - public init(encodedData: Data) throws { - guard encodedData.count >= 16 else { - throw MessageBlockError.notEnoughData - } - self.faultEventCode = FaultEventCode(rawValue: encodedData[1]) - self.timeActivation = TimeInterval(minutes: Double((Int(encodedData[2] & 0b1) << 8) + Int(encodedData[3]))) - self.dateTime = DateComponents(encodedDateTime: encodedData.subdata(in: 12..<17)) - self.data = Data(encodedData) - } -} - -extension DateComponents { - init(encodedDateTime: Data) { - self.init() - - year = Int(encodedDateTime[2]) + 2000 - month = Int(encodedDateTime[0]) - day = Int(encodedDateTime[1]) - hour = Int(encodedDateTime[3]) - minute = Int(encodedDateTime[4]) - - calendar = Calendar(identifier: .gregorian) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfoConfiguredAlerts.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfoConfiguredAlerts.swift deleted file mode 100644 index e9989afa0..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfoConfiguredAlerts.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// PodInfoConfiguredAlerts.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/PodInfoConfiguredAlerts.swift -// Created by Eelke Jager on 16/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -// Type 1 Pod Info returns information about the currently configured alerts -public struct PodInfoConfiguredAlerts : PodInfo { - // CMD 1 2 3 4 5 6 7 8 910 1112 1314 1516 1718 1920 - // DATA 0 1 2 3 4 5 6 7 8 910 1112 1314 1516 1718 - // 02 13 01 XXXX VVVV VVVV VVVV VVVV VVVV VVVV VVVV VVVV - - public let podInfoType : PodInfoResponseSubType = .configuredAlerts - public let word_278 : Data - public let alertsActivations : [AlertActivation] - public let data : Data - - public struct AlertActivation { - let beepType: BeepType - let unitsLeft: Double - let timeFromPodStart: UInt8 - - public init(beepType: BeepType, timeFromPodStart: UInt8, unitsLeft: Double) { - self.beepType = beepType - self.timeFromPodStart = timeFromPodStart - self.unitsLeft = unitsLeft - } - } - - public init(encodedData: Data) throws { - guard encodedData.count >= 11 else { - throw MessageBlockError.notEnoughData - } - - self.word_278 = encodedData[1...2] - - let numAlertTypes = 8 - let beepType = BeepType.self - - var activations = [AlertActivation]() - - for alarmType in (0..= logStartByteOffset && (nLogBytesReturned & 0x3) == 0 else { - throw MessageBlockError.notEnoughData // not enough data to start log or a non-integral # of pulse log entries - } - self.nEntries = nLogBytesReturned / MemoryLayout.size - self.indexLastEntry = Int((UInt16(encodedData[1]) << 8) | UInt16(encodedData[2])) - self.pulseLog = createPulseLog(encodedData: encodedData, logStartByteOffset: logStartByteOffset, nEntries: self.nEntries) - self.data = encodedData - } -} - -// Type $51 Pod info returns (up to) the most previous 50 32-bit pulse log entries -public struct PodInfoPulseLogPrevious : PodInfo { - // CMD 1 2 3 4 5 6 7 8 - // DATA 0 1 2 3 4 5 6 - // 02 LL 51 NNNN XXXXXXXX ... - - public let podInfoType : PodInfoResponseSubType = .pulseLogPrevious - public let nEntries : Int // how many 32-bit pulse log entries returned - public let pulseLog : [UInt32] - public let data : Data - - public init(encodedData: Data) throws { - let logStartByteOffset = 3 // starting byte offset of the pulse log in DATA - let nLogBytesReturned = encodedData.count - logStartByteOffset - guard encodedData.count >= logStartByteOffset && (nLogBytesReturned & 0x3) == 0 else { - throw MessageBlockError.notEnoughData // first 3 bytes missing or non-integral # of pulse log entries - } - let nEntriesCalculated = nLogBytesReturned / MemoryLayout.size - self.nEntries = Int((UInt16(encodedData[1]) << 8) | UInt16(encodedData[2])) - // verify we actually got all the reported entries - if self.nEntries > nEntriesCalculated { - throw MessageBlockError.notEnoughData // some pulse log entry count mismatch issue - } - self.pulseLog = createPulseLog(encodedData: encodedData, logStartByteOffset: logStartByteOffset, nEntries: self.nEntries) - self.data = encodedData - } -} - -func createPulseLog(encodedData: Data, logStartByteOffset: Int, nEntries: Int) -> [UInt32] { - var pulseLog: [UInt32] = Array(repeating: 0, count: nEntries) - var index = 0 - while index < nEntries { - pulseLog[index] = encodedData[(logStartByteOffset+(index*4))...].toBigEndian(UInt32.self) - index += 1 - } - return pulseLog -} - -extension BinaryInteger { - var binaryDescription: String { - var binaryString = "" - var internalNumber = self - var counter = 0 - - for _ in (1...self.bitWidth) { - binaryString.insert(contentsOf: "\(internalNumber & 1)", at: binaryString.startIndex) - internalNumber >>= 1 - counter += 1 - if counter % 8 == 0 { - binaryString.insert(contentsOf: " ", at: binaryString.startIndex) - } - } - return binaryString - } -} - -func pulseLogString(pulseLogEntries: [UInt32], lastPulseNumber: Int) -> String { - var str: String = "Pulse eeeeee0a pppliiib cccccccc dfgggggg" - var index = pulseLogEntries.count - 1 - var pulseNumber = lastPulseNumber - while index >= 0 { - str += String(format: "\n%04d:", pulseNumber) + UInt32(pulseLogEntries[index]).binaryDescription - index -= 1 - pulseNumber -= 1 - } - return str -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfoPulseLogPlus.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfoPulseLogPlus.swift deleted file mode 100644 index f73a36579..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfoPulseLogPlus.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// PodInfoPulseLogPlus.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/PodInfoPulseLog.swift -// Created by Eelke Jager on 22/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -// Type 3 Pod Info returns up to the last 60 pulse log entries pulse some additional info -public struct PodInfoPulseLogPlus : PodInfo { - // CMD 1 2 3 4 5 6 7 8 9 10 - // DATA 0 1 2 3 4 5 6 7 8 - // 02 LL 03 PP QQQQ SSSS 04 3c XXXXXXXX ... - - public let podInfoType : PodInfoResponseSubType = .pulseLogPlus - public let faultEventCode: FaultEventCode // fault code - public let timeFaultEvent: TimeInterval // fault time since activation - public let timeActivation: TimeInterval // current time since activation - public let entrySize : Int // always 4 - public let maxEntries : Int // always 60 - public let nEntries : Int // how many 32-bit pulse log entries returned (calculated) - public let pulseLog : [UInt32] - public let data : Data - - public init(encodedData: Data) throws { - guard encodedData[6] == MemoryLayout.size else { - throw MessageError.unknownValue(value: encodedData[6], typeDescription: "pulseLog entry size") - } - let entrySize = Int(encodedData[6]) - let logStartByteOffset = 8 // starting byte offset of the pulse log in DATA - let nLogBytesReturned = encodedData.count - logStartByteOffset - let nEntries = nLogBytesReturned / entrySize - let maxEntries = Int(encodedData[7]) - guard encodedData.count >= logStartByteOffset && (nLogBytesReturned & 0x3) == 0 else { - throw MessageBlockError.notEnoughData // not enough data to start log or a non-integral # of pulse log entries - } - guard maxEntries >= nEntries else { - throw MessageBlockError.parseError - } - self.entrySize = entrySize - self.nEntries = nEntries - self.maxEntries = maxEntries - self.faultEventCode = FaultEventCode(rawValue: encodedData[1]) - self.timeFaultEvent = TimeInterval(minutes: Double((Int(encodedData[2] & 0b1) << 8) + Int(encodedData[3]))) - self.timeActivation = TimeInterval(minutes: Double((Int(encodedData[4] & 0b1) << 8) + Int(encodedData[5]))) - self.pulseLog = createPulseLog(encodedData: encodedData, logStartByteOffset: logStartByteOffset, nEntries: self.nEntries) - self.data = encodedData - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfoResponse.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfoResponse.swift deleted file mode 100644 index 489696580..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/PodInfoResponse.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// PodInfoResponse.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/PodInfoResponse.swift -// Created by Pete Schwamb on 2/23/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct PodInfoResponse : MessageBlock { - - public let blockType : MessageBlockType = .podInfoResponse - public let podInfoResponseSubType : PodInfoResponseSubType - public let podInfo : PodInfo - public let data : Data - - public init(encodedData: Data) throws { - guard let subType = PodInfoResponseSubType(rawValue: encodedData[2]) else { - throw MessageError.unknownValue(value: encodedData[2], typeDescription: "PodInfoResponseSubType") - } - self.podInfoResponseSubType = subType - let len = encodedData.count - podInfo = try podInfoResponseSubType.podInfoType.init(encodedData: encodedData.subdata(in: 2.. ScheduleTypeCode { - switch self { - case .basalSchedule: - return .basalSchedule - case .tempBasal: - return .tempBasal - case .bolus: - return .bolus - } - } - - fileprivate var data: Data { - switch self { - case .basalSchedule(let currentSegment, let secondsRemaining, let pulsesRemaining, let table): - var data = Data([currentSegment]) - data.appendBigEndian(secondsRemaining << 3) - data.appendBigEndian(pulsesRemaining) - for entry in table.entries { - data.append(entry.data) - } - return data - - case .tempBasal(let secondsRemaining, let firstSegmentPulses, let table): - var data = Data([UInt8(table.numSegments())]) - data.appendBigEndian(secondsRemaining << 3) - data.appendBigEndian(firstSegmentPulses) - for entry in table.entries { - data.append(entry.data) - } - return data - - case .bolus(let units, let timeBetweenPulses, let table): - let firstSegmentPulses = UInt16(round(units / Pod.pulseSize)) - let multiplier = UInt16(round(timeBetweenPulses * 8)) - let fieldA = firstSegmentPulses * multiplier - - var data = Data([UInt8(table.numSegments())]) - data.appendBigEndian(fieldA) - data.appendBigEndian(firstSegmentPulses) - for entry in table.entries { - data.append(entry.data) - } - return data - - } - } - - fileprivate func checksum() -> UInt16 { - switch self { - case .basalSchedule( _, _, _, let table), .tempBasal(_, _, let table): - return data[0..<5].reduce(0) { $0 + UInt16($1) } + - table.entries.reduce(0) { $0 + $1.checksum() } - case .bolus(_, _, let table): - return data[0..<5].reduce(0) { $0 + UInt16($1) } + - table.entries.reduce(0) { $0 + $1.checksum() } - } - } - } - - public let blockType: MessageBlockType = .setInsulinSchedule - - public var nonce: UInt32 - public let deliverySchedule: DeliverySchedule - - public var data: Data { - var data = Data([ - blockType.rawValue, - UInt8(7 + deliverySchedule.data.count), - ]) - data.appendBigEndian(nonce) - data.append(deliverySchedule.typeCode().rawValue) - data.appendBigEndian(deliverySchedule.checksum()) - data.append(deliverySchedule.data) - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 6 { - throw MessageBlockError.notEnoughData - } - let length = encodedData[1] - - nonce = encodedData[2...].toBigEndian(UInt32.self) - - let checksum = encodedData[7...].toBigEndian(UInt16.self) - - guard let scheduleTypeCode = ScheduleTypeCode(rawValue: encodedData[6]) else { - throw MessageError.unknownValue(value: encodedData[6], typeDescription: "ScheduleTypeCode") - } - - switch scheduleTypeCode { - case .basalSchedule: - var entries = [InsulinTableEntry]() - let numEntries = (length - 12) / 2 - for i in 0..> 3 - let pulsesRemaining = encodedData[12...].toBigEndian(UInt16.self) - let table = BasalDeliveryTable(entries: entries) - deliverySchedule = .basalSchedule(currentSegment: currentTableIndex, secondsRemaining: secondsRemaining, pulsesRemaining: pulsesRemaining, table: table) - - case .tempBasal: - let secondsRemaining = encodedData[10...].toBigEndian(UInt16.self) >> 3 - let firstSegmentPulses = encodedData[12...].toBigEndian(UInt16.self) - var entries = [InsulinTableEntry]() - let numEntries = (length - 12) / 2 - for i in 0.. 0 ? Double(fieldA / unitRate) / 8 : 0 - - var entries = [InsulinTableEntry]() - let numEntries = (length - 12) / 2 - for i in 0.. 0.0 && timeBetweenPulses > 0) ? timeBetweenPulses : Pod.secondsPerBolusPulse - self.deliverySchedule = SetInsulinScheduleCommand.DeliverySchedule.bolus(units: units, timeBetweenPulses: timeBetweenImmediatePulses, table: table) - } -} - -extension SetInsulinScheduleCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "SetInsulinScheduleCommand(nonce:\(nonce), \(deliverySchedule))" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/SetupPodCommand.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/SetupPodCommand.swift deleted file mode 100644 index 08fea3dd0..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/SetupPodCommand.swift +++ /dev/null @@ -1,93 +0,0 @@ -// -// Setup PodCommand.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/SetupPodCommand.swift -// Created by Pete Schwamb on 2/17/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct SetupPodCommand : MessageBlock { - - public let blockType: MessageBlockType = .setupPod - - let address: UInt32 - let lot: UInt32 - let tid: UInt32 - let dateComponents: DateComponents - let packetTimeoutLimit: UInt8 - - public static func dateComponents(date: Date, timeZone: TimeZone) -> DateComponents { - var cal = Calendar(identifier: .gregorian) - cal.timeZone = timeZone - return cal.dateComponents([.day, .month, .year, .hour, .minute], from: date) - } - - public static func date(from components: DateComponents, timeZone: TimeZone) -> Date? { - var cal = Calendar(identifier: .gregorian) - cal.timeZone = timeZone - return cal.date(from: components) - } - - // 03 13 1f08ced2 14 04 09 0b 11 0b 08 0000a640 00097c27 83e4 - public var data: Data { - var data = Data([ - blockType.rawValue, - 19, - ]) - data.appendBigEndian(self.address) - - let year = UInt8((dateComponents.year ?? 2000) - 2000) - let month = UInt8(dateComponents.month ?? 0) - let day = UInt8(dateComponents.day ?? 0) - let hour = UInt8(dateComponents.hour ?? 0) - let minute = UInt8(dateComponents.minute ?? 0) - - let data2: Data = Data([ - UInt8(0x14), // Unknown - packetTimeoutLimit, - month, - day, - year, - hour, - minute - ]) - data.append(data2) - data.appendBigEndian(self.lot) - data.appendBigEndian(self.tid) - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 21 { - throw MessageBlockError.notEnoughData - } - self.address = encodedData[2...].toBigEndian(UInt32.self) - packetTimeoutLimit = encodedData[7] - var components = DateComponents() - components.month = Int(encodedData[8]) - components.day = Int(encodedData[9]) - components.year = Int(encodedData[10]) + 2000 - components.hour = Int(encodedData[11]) - components.minute = Int(encodedData[12]) - self.dateComponents = components - self.lot = encodedData[13...].toBigEndian(UInt32.self) - self.tid = encodedData[17...].toBigEndian(UInt32.self) - } - - public init(address: UInt32, dateComponents: DateComponents, lot: UInt32, tid: UInt32, packetTimeoutLimit: UInt8 = 4) { - self.address = address - self.dateComponents = dateComponents - self.lot = lot - self.tid = tid - self.packetTimeoutLimit = packetTimeoutLimit - } -} - -extension SetupPodCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "SetupPodCommand(address:\(Data(bigEndian: address).hexadecimalString), dateComponents:\(dateComponents), lot:\(lot), tid:\(tid), packetTimeoutLimit:\(packetTimeoutLimit))" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/StatusResponse.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/StatusResponse.swift deleted file mode 100644 index 0881c1635..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/StatusResponse.swift +++ /dev/null @@ -1,101 +0,0 @@ -// -// StatusResponse.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/StatusResponse.swift -// Created by Pete Schwamb on 10/23/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct StatusResponse : MessageBlock { - public let blockType: MessageBlockType = .statusResponse - public let length: UInt8 = 10 - public let deliveryStatus: DeliveryStatus - public let podProgressStatus: PodProgressStatus - public let timeActive: TimeInterval - public let reservoirLevel: Double - public let insulinDelivered: Double - public let bolusNotDelivered: Double - public let lastProgrammingMessageSeqNum: UInt8 // updated by pod for 03, 08, $11, $19, $1A, $1C, $1E & $1F command messages - public let alerts: AlertSet - - - public let data: Data - - public init(encodedData: Data) throws { - if encodedData.count < length { - throw MessageBlockError.notEnoughData - } - - data = encodedData.prefix(upTo: Int(length)) - - guard let deliveryStatus = DeliveryStatus(rawValue: encodedData[1] >> 4) else { - throw MessageError.unknownValue(value: encodedData[1] >> 4, typeDescription: "DeliveryStatus") - } - self.deliveryStatus = deliveryStatus - - guard let podProgressStatus = PodProgressStatus(rawValue: encodedData[1] & 0xf) else { - throw MessageError.unknownValue(value: encodedData[1] & 0xf, typeDescription: "PodProgressStatus") - } - self.podProgressStatus = podProgressStatus - - let minutes = ((Int(encodedData[7]) & 0x7f) << 6) + (Int(encodedData[8]) >> 2) - self.timeActive = TimeInterval(minutes: Double(minutes)) - - let highInsulinBits = Int(encodedData[2] & 0xf) << 9 - let midInsulinBits = Int(encodedData[3]) << 1 - let lowInsulinBits = Int(encodedData[4] >> 7) - self.insulinDelivered = Double(highInsulinBits | midInsulinBits | lowInsulinBits) / Pod.pulsesPerUnit - - self.lastProgrammingMessageSeqNum = (encodedData[4] >> 3) & 0xf - - self.bolusNotDelivered = Double((Int(encodedData[4] & 0x3) << 8) | Int(encodedData[5])) / Pod.pulsesPerUnit - - self.alerts = AlertSet(rawValue: ((encodedData[6] & 0x7f) << 1) | (encodedData[7] >> 7)) - - self.reservoirLevel = Double((Int(encodedData[8] & 0x3) << 8) + Int(encodedData[9])) / Pod.pulsesPerUnit - } - - public init( - deliveryStatus: DeliveryStatus, - podProgressStatus: PodProgressStatus, - timeActive: TimeInterval, - reservoirLevel: Double, - insulinDelivered: Double, - bolusNotDelivered: Double, - lastProgrammingMessageSeqNum: UInt8, - alerts: AlertSet) - { - self.deliveryStatus = deliveryStatus - self.podProgressStatus = podProgressStatus - self.timeActive = timeActive - self.reservoirLevel = reservoirLevel - self.insulinDelivered = insulinDelivered - self.bolusNotDelivered = bolusNotDelivered - self.lastProgrammingMessageSeqNum = lastProgrammingMessageSeqNum - self.alerts = alerts - self.data = Data() - } - - // convenience function to create a StatusResponse for a DetailedStatus - public init(detailedStatus: DetailedStatus) { - self.deliveryStatus = detailedStatus.deliveryStatus - self.podProgressStatus = detailedStatus.podProgressStatus - self.timeActive = detailedStatus.timeActive - self.reservoirLevel = detailedStatus.reservoirLevel - self.insulinDelivered = detailedStatus.totalInsulinDelivered - self.bolusNotDelivered = detailedStatus.bolusNotDelivered - self.lastProgrammingMessageSeqNum = detailedStatus.lastProgrammingMessageSeqNum - self.alerts = detailedStatus.unacknowledgedAlerts - self.data = Data() - } -} - -extension StatusResponse: CustomDebugStringConvertible { - public var debugDescription: String { - return "StatusResponse(deliveryStatus:\(deliveryStatus.description), progressStatus:\(podProgressStatus), timeActive:\(timeActive.timeIntervalStr), reservoirLevel:\(reservoirLevel == Pod.reservoirLevelAboveThresholdMagicNumber ? "50+" : reservoirLevel.twoDecimals), insulinDelivered:\(insulinDelivered.twoDecimals), bolusNotDelivered:\(bolusNotDelivered.twoDecimals), lastProgrammingMessageSeqNum:\(lastProgrammingMessageSeqNum), alerts:\(alerts))" - } -} - diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/TempBasalExtraCommand.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/TempBasalExtraCommand.swift deleted file mode 100644 index 02d301e6e..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/MessageBlocks/TempBasalExtraCommand.swift +++ /dev/null @@ -1,80 +0,0 @@ -// -// TempBasalExtraCommand.swift -// OmniBLE -// -// From OmniKit/MessageTransport/MessageBlocks/TempBasalExtraCommand.swift -// Created by Pete Schwamb on 6/6/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct TempBasalExtraCommand : MessageBlock { - - public let acknowledgementBeep: Bool - public let completionBeep: Bool - public let programReminderInterval: TimeInterval - public let remainingPulses: Double - public let delayUntilFirstPulse: TimeInterval - public let rateEntries: [RateEntry] - - public let blockType: MessageBlockType = .tempBasalExtra - - public var data: Data { - let beepOptions = (UInt8(programReminderInterval.minutes) & 0x3f) + (completionBeep ? (1<<6) : 0) + (acknowledgementBeep ? (1<<7) : 0) - var data = Data([ - blockType.rawValue, - UInt8(8 + rateEntries.count * 6), - beepOptions, - 0 - ]) - data.appendBigEndian(UInt16(round(remainingPulses * 10))) - data.appendBigEndian(UInt32(delayUntilFirstPulse.hundredthsOfMilliseconds)) - for entry in rateEntries { - data.append(entry.data) - } - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 14 { - throw MessageBlockError.notEnoughData - } - - let length = encodedData[1] - let numEntries = (length - 8) / 6 - - acknowledgementBeep = encodedData[2] & (1<<7) != 0 - completionBeep = encodedData[2] & (1<<6) != 0 - programReminderInterval = TimeInterval(minutes: Double(encodedData[2] & 0x3f)) - - remainingPulses = Double(encodedData[4...].toBigEndian(UInt16.self)) / 10.0 - let timerCounter = encodedData[6...].toBigEndian(UInt32.self) - delayUntilFirstPulse = TimeInterval(hundredthsOfMilliseconds: Double(timerCounter)) - - var entries = [RateEntry]() - for entryIndex in (0..> 6 - rssi = encodedData[18] & 0x3f - address = encodedData[19...].toBigEndian(UInt32.self) - - // These values only included in the longer 0x1B VersionResponse for the 03 SetupPod command. - pulseSize = nil - secondsPerBolusPulse = nil - secondsPerPrimePulse = nil - primeUnits = nil - cannulaInsertionUnits = nil - serviceDuration = nil - - case setupPodVersionLength: - // This is the longer 0x1B response for the 03 SetupPod command. - // 0 1 2 4 5 6 7 8 9 12 15 16 17 21 25 - // 01 LL VVVV BR PR PP CP PL MXMYMZ IXIYIZ ID 0J LLLLLLLL TTTTTTTT IIIIIIII - // 01 1b 1388 10 08 34 0a 50 020700 020700 02 03 0000a62b 00044794 1f00ee87 - // - // LL = 0x1b (setupPodVersionMessageLength) - // VVVV = 0x1388, pulse Volume in micro-units of U100 insulin per tenth of pulse (5000/100000 = 0.05U per pulse) - // BR = 0x10, Basic pulse Rate in # of eighth secs per pulse (16/8 = 2 seconds per pulse) - // PR = 0x08, Prime pulse Rate in # of eighth secs per pulse for priming boluses (8/8 = 1 second per priming pulse) - // PP = 0x34 = 52, # of Prime Pulses (52 pulses x 0.05U/pulse = 2.6U) - // CP = 0x0A = 10, # of Cannula insertion Pulses (10 pulses x 0.05U/pulse = 0.5U) - // PL = 0x50 = 80, # of hours maximum Pod Life - // PM = MX.MY.MZ = 02.07.02 (for PM 2.7.0 for Eros) - // PI = IX.IY.IZ = 02.07.02 (for PI 2.7.0 for Eros) - // ID = Product Id (02 for Eros, 04 for Dash, and perhaps 05 for Omnnipod 5) - // 0J = Pod progress state (should be 03 for this particular response) - // LLLLLLLL = Lot - // TTTTTTTT = Tid - // IIIIIIII = connection ID address - - firmwareVersion = FirmwareVersion(encodedData: encodedData.subdata(in: 9..<12)) - iFirmwareVersion = FirmwareVersion(encodedData: encodedData.subdata(in: 12..<15)) - productId = encodedData[15] - guard let progressStatus = PodProgressStatus(rawValue: encodedData[16]) else { - throw MessageBlockError.parseError - } - podProgressStatus = progressStatus - lot = encodedData[17...].toBigEndian(UInt32.self) - tid = encodedData[21...].toBigEndian(UInt32.self) - address = encodedData[25...].toBigEndian(UInt32.self) - - // These values should be verified elsewhere and appropriately handled. - pulseSize = Double(encodedData[2...].toBigEndian(UInt16.self)) / 100000 - secondsPerBolusPulse = Double(encodedData[4]) / 8 - secondsPerPrimePulse = Double(encodedData[5]) / 8 - primeUnits = Double(encodedData[6]) / Pod.pulsesPerUnit - cannulaInsertionUnits = Double(encodedData[7]) / Pod.pulsesPerUnit - serviceDuration = TimeInterval.hours(Double(encodedData[8])) - - // These values only included in the shorter 0x15 VersionResponse for the AssignAddress command for Eros. - gain = nil - rssi = nil - - default: - throw MessageBlockError.parseError - } - } - - public var isAssignAddressVersionResponse: Bool { - return self.data.count == assignAddressVersionLength + 2 - } - - public var isSetupPodVersionResponse: Bool { - return self.data.count == setupPodVersionLength + 2 - } -} - -extension VersionResponse: CustomDebugStringConvertible { - public var debugDescription: String { - return "VersionResponse(lot:\(lot), tid:\(tid), address:\(Data(bigEndian: address).hexadecimalString), firmwareVersion:\(firmwareVersion), iFirmwareVersion:\(iFirmwareVersion), productId:\(productId), podProgressStatus:\(podProgressStatus), gain:\(gain?.description ?? "NA"), rssi:\(rssi?.description ?? "NA"), pulseSize:\(pulseSize?.description ?? "NA"), secondsPerBolusPulse:\(secondsPerBolusPulse?.description ?? "NA"), secondsPerPrimePulse:\(secondsPerPrimePulse?.description ?? "NA"), primeUnits:\(primeUnits?.description ?? "NA"), cannulaInsertionUnits:\(cannulaInsertionUnits?.description ?? "NA"), serviceDuration:\(serviceDuration?.description ?? "NA"), )" - } -} - diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PendingCommand.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PendingCommand.swift deleted file mode 100644 index fc00d5751..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PendingCommand.swift +++ /dev/null @@ -1,209 +0,0 @@ -// -// PendingCommand.swift -// OmniBLE -// -// Created by Pete Schwamb on 1/18/22. -// Copyright © 2022 Pete Schwamb. All rights reserved. -// - -import Foundation -import LoopKit - - -public enum StartProgram: RawRepresentable { - public typealias RawValue = [String: Any] - - case bolus(volume: Double, automatic: Bool) - case basalProgram(schedule: BasalSchedule) - case tempBasal(unitsPerHour: Double, duration: TimeInterval, isHighTemp: Bool, automatic: Bool) - - private enum StartProgramType: Int { - case bolus, basalProgram, tempBasal - } - - public var rawValue: RawValue { - switch self { - case .bolus(let volume, let automatic): - return [ - "programType": StartProgramType.bolus.rawValue, - "volume": volume, - "automatic": automatic - ] - case .basalProgram(let schedule): - return [ - "programType": StartProgramType.basalProgram.rawValue, - "schedule": schedule.rawValue - ] - case .tempBasal(let unitsPerHour, let duration, let isHighTemp, let automatic): - return [ - "programType": StartProgramType.tempBasal.rawValue, - "unitsPerHour": unitsPerHour, - "duration": duration, - "isHighTemp": isHighTemp, - "automatic": automatic - ] - } - } - - public init?(rawValue: RawValue) { - guard let encodedTypeRaw = rawValue["programType"] as? StartProgramType.RawValue, - let encodedType = StartProgramType(rawValue: encodedTypeRaw) else - { - return nil - } - switch encodedType { - case .bolus: - guard let volume = rawValue["volume"] as? Double, - let automatic = rawValue["automatic"] as? Bool else - { - return nil - } - self = .bolus(volume: volume, automatic: automatic) - case .basalProgram: - guard let rawSchedule = rawValue["schedule"] as? BasalSchedule.RawValue, - let schedule = BasalSchedule(rawValue: rawSchedule) else - { - return nil - } - self = .basalProgram(schedule: schedule) - case .tempBasal: - guard let unitsPerHour = rawValue["unitsPerHour"] as? Double, - let duration = rawValue["duration"] as? TimeInterval, - let isHighTemp = rawValue["isHighTemp"] as? Bool else - { - return nil - } - let automatic = rawValue["automatic"] as? Bool ?? true - self = .tempBasal(unitsPerHour: unitsPerHour, duration: duration, isHighTemp: isHighTemp, automatic: automatic) - } - } - - public static func == (lhs: StartProgram, rhs: StartProgram) -> Bool { - switch(lhs, rhs) { - case (.bolus(let lhsVolume, let lhsAutomatic), .bolus(let rhsVolume, let rhsAutomatic)): - return lhsVolume == rhsVolume && lhsAutomatic == rhsAutomatic - case (.basalProgram(let lhsSchedule), .basalProgram(let rhsSchedule)): - return lhsSchedule == rhsSchedule - case (.tempBasal(let lhsUnitsPerHour, let lhsDuration, let lhsIsHighTemp, let lhsAutomatic), .tempBasal(let rhsUnitsPerHour, let rhsDuration, let rhsIsHighTemp, let rhsAutomatic)): - return lhsUnitsPerHour == rhsUnitsPerHour && lhsDuration == rhsDuration && lhsIsHighTemp == rhsIsHighTemp && lhsAutomatic == rhsAutomatic - default: - return false - } - } -} - -public enum PendingCommand: RawRepresentable, Equatable { - public typealias RawValue = [String: Any] - - case program(StartProgram, Int, Date, Bool = true) - case stopProgram(CancelDeliveryCommand.DeliveryType, Int, Date, Bool = true) - - private enum PendingCommandType: Int { - case startProgram, stopProgram - } - - public var commandDate: Date { - switch self { - case .program(_, _, let date, _): - return date - case .stopProgram(_, _, let date, _): - return date - } - } - - public var sequence: Int { - switch self { - case .program(_, let sequence, _, _): - return sequence - case .stopProgram(_, let sequence, _, _): - return sequence - } - } - - public var isInFlight: Bool { - switch self { - case .program(_, _, _, let inflight): - return inflight - case .stopProgram(_, _, _, let inflight): - return inflight - } - } - - public var commsFinished: PendingCommand { - switch self { - case .program(let program, let sequence, let date, _): - return PendingCommand.program(program, sequence, date, false) - case .stopProgram(let program, let sequence, let date, _): - return PendingCommand.stopProgram(program, sequence, date, false) - } - } - - public init?(rawValue: RawValue) { - guard let rawPendingCommandType = rawValue["type"] as? PendingCommandType.RawValue else { - return nil - } - - guard let commandDate = rawValue["date"] as? Date else { - return nil - } - - guard let sequence = rawValue["sequence"] as? Int else { - return nil - } - - let inflight = rawValue["inflight"] as? Bool ?? false - - switch PendingCommandType(rawValue: rawPendingCommandType) { - case .startProgram?: - guard let rawUnacknowledgedProgram = rawValue["unacknowledgedProgram"] as? StartProgram.RawValue else { - return nil - } - if let program = StartProgram(rawValue: rawUnacknowledgedProgram) { - self = .program(program, sequence, commandDate, inflight) - } else { - return nil - } - case .stopProgram?: - guard let rawDeliveryType = rawValue["unacknowledgedStopProgram"] as? CancelDeliveryCommand.DeliveryType.RawValue else { - return nil - } - let stopProgram = CancelDeliveryCommand.DeliveryType(rawValue: rawDeliveryType) - self = .stopProgram(stopProgram, sequence, commandDate, inflight) - default: - return nil - } - } - - public var rawValue: RawValue { - var rawValue: RawValue = [:] - - switch self { - case .program(let program, let sequence, let date, let inflight): - rawValue["type"] = PendingCommandType.startProgram.rawValue - rawValue["date"] = date - rawValue["sequence"] = sequence - rawValue["inflight"] = inflight - rawValue["unacknowledgedProgram"] = program.rawValue - case .stopProgram(let stopProgram, let sequence, let date, let inflight): - rawValue["type"] = PendingCommandType.stopProgram.rawValue - rawValue["date"] = date - rawValue["sequence"] = sequence - rawValue["inflight"] = inflight - rawValue["unacknowledgedStopProgram"] = stopProgram.rawValue - } - return rawValue - } - - public static func == (lhs: PendingCommand, rhs: PendingCommand) -> Bool { - switch(lhs, rhs) { - case (.program(let lhsProgram, let lhsSequence, let lhsDate, let lhsInflight), .program(let rhsProgram, let rhsSequence, let rhsDate, let rhsInflight)): - return lhsProgram == rhsProgram && lhsSequence == rhsSequence && lhsDate == rhsDate && lhsInflight == rhsInflight - case (.stopProgram(let lhsStopProgram, let lhsSequence, let lhsDate, let lhsInflight), .stopProgram(let rhsStopProgram, let rhsSequence, let rhsDate, let rhsInflight)): - return lhsStopProgram == rhsStopProgram && lhsSequence == rhsSequence && lhsDate == rhsDate && lhsInflight == rhsInflight - default: - return false - } - } -} - - diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/Pod.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/Pod.swift deleted file mode 100644 index 55a5e8dc1..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/Pod.swift +++ /dev/null @@ -1,142 +0,0 @@ -// -// Pod.swift -// OmniBLE -// -// Based on OmniKit/Model/Pod.swift -// Created by Pete Schwamb on 4/4/18. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -public struct Pod { - // Volume of U100 insulin in one motor pulse - // Must agree with value returned by pod during the pairing process. - public static let pulseSize: Double = 0.05 - - // Number of pulses required to deliver one unit of U100 insulin - public static let pulsesPerUnit: Double = 1 / Pod.pulseSize - - // Seconds per pulse for boluses - // Checked to verify it agrees with value returned by pod during the pairing process. - public static let secondsPerBolusPulse: Double = 2 - - // Units per second for boluses - public static let bolusDeliveryRate: Double = Pod.pulseSize / Pod.secondsPerBolusPulse - - // Seconds per pulse for priming/cannula insertion - // Checked to verify it agrees with value returned by pod during the pairing process. - public static let secondsPerPrimePulse: Double = 1 - - // Units per second for priming/cannula insertion - public static let primeDeliveryRate: Double = Pod.pulseSize / Pod.secondsPerPrimePulse - - // Expiration advisory window: time after expiration alert, and end of service imminent alarm - public static let expirationAdvisoryWindow = TimeInterval(hours: 7) - - // End of service imminent window, relative to pod end of service - public static let endOfServiceImminentWindow = TimeInterval(hours: 1) - - // Total pod service time. A fault is triggered if this time is reached before pod deactivation. - // Checked to verify it agrees with value returned by pod during the pairing process. - public static let serviceDuration = TimeInterval(hours: 80) - - // Nomimal pod life (72 hours) - public static let nominalPodLife = Pod.serviceDuration - Pod.endOfServiceImminentWindow - Pod.expirationAdvisoryWindow - - // Maximum reservoir level reading - public static let maximumReservoirReading: Double = 50 - - // Reservoir level magic number indicating 50+ U remaining - public static let reservoirLevelAboveThresholdMagicNumber: Double = 51.15 - - // Reservoir Capacity - public static let reservoirCapacity: Double = 200 - - // Supported basal rates - // Eros minimum scheduled basal rate is 0.05 U/H while for Dash supports 0 U/H. - // Would need to have this value based on productID to be able to share this file with Eros. - public static let supportedBasalRates: [Double] = (0...600).map { Double($0) / Double(pulsesPerUnit) } - - // The internal basal rate used for non-Eros pods - // Would need to have this value based on productID to be able to share this file with Eros. - public static let zeroBasalRate: Double = nearZeroBasalRate - - // Maximum number of basal schedule entries supported - public static let maximumBasalScheduleEntryCount: Int = 24 - - // Minimum duration of a single basal schedule entry - public static let minimumBasalScheduleEntryDuration = TimeInterval.minutes(30) - - // Supported temp basal durations (30m to 12h) - public static let supportedTempBasalDurations: [TimeInterval] = (1...24).map { Double($0) * TimeInterval(minutes: 30) } - - // Default amount for priming bolus using secondsPerPrimePulse timing. - // Checked to verify it agrees with value returned by pod during the pairing process. - public static let primeUnits = 2.6 - - // Default amount for cannula insertion bolus using secondsPerPrimePulse timing. - // Checked to verify it agrees with value returned by pod during the pairing process. - public static let cannulaInsertionUnits = 0.5 - - public static let cannulaInsertionUnitsExtra = 0.0 // edit to add a fixed additional amount of insulin during cannula insertion - - // Default and limits for expiration reminder alerts - public static let defaultExpirationReminderOffset = TimeInterval(hours: 2) - public static let expirationReminderAlertMinHoursBeforeExpiration = 1 - public static let expirationReminderAlertMaxHoursBeforeExpiration = 24 - - // Threshold used to display pod end of life warnings - public static let timeRemainingWarningThreshold = TimeInterval(days: 1) - - // Default low reservoir alert limit in Units - public static let defaultLowReservoirReminder: Double = 10 - - // Allowed Low Reservoir reminder values - public static let allowedLowReservoirReminderValues = Array(stride(from: 10, through: 50, by: 1)) -} - -// DeliveryStatus used in StatusResponse and DetailedStatus -public enum DeliveryStatus: UInt8, CustomStringConvertible { - case suspended = 0 - case scheduledBasal = 1 - case tempBasalRunning = 2 - case priming = 4 - case bolusInProgress = 5 - case bolusAndTempBasal = 6 - case extendedBolusRunning = 9 - case extendedBolusAndTempBasal = 10 - - public var bolusing: Bool { - return self == .bolusInProgress || self == .bolusAndTempBasal || self == .extendedBolusRunning || self == .extendedBolusAndTempBasal - } - - public var tempBasalRunning: Bool { - return self == .tempBasalRunning || self == .bolusAndTempBasal || self == .extendedBolusAndTempBasal - } - - public var extendedBolusRunninng: Bool { - return self == .extendedBolusRunning || self == .extendedBolusAndTempBasal - } - - public var description: String { - switch self { - case .suspended: - return LocalizedString("Suspended", comment: "Delivery status when insulin delivery is suspended") - case .scheduledBasal: - return LocalizedString("Scheduled basal", comment: "Delivery status when scheduled basal is running") - case .tempBasalRunning: - return LocalizedString("Temp basal running", comment: "Delivery status when temp basal is running") - case .priming: - return LocalizedString("Priming", comment: "Delivery status when pod is priming") - case .bolusInProgress: - return LocalizedString("Bolusing", comment: "Delivery status when bolusing") - case .bolusAndTempBasal: - return LocalizedString("Bolusing with temp basal", comment: "Delivery status when bolusing and temp basal is running") - case .extendedBolusRunning: - return LocalizedString("Extended bolus running", comment: "Delivery status when extended bolus is running") - case .extendedBolusAndTempBasal: - return LocalizedString("Extended bolus running with temp basal", comment: "Delivery status when extended bolus and temp basal is running") - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PodDoseProgressEstimator.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PodDoseProgressEstimator.swift deleted file mode 100644 index cfca77ffb..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PodDoseProgressEstimator.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// PodDoseProgressEstimator.swift -// OmniBLE -// -// From OmniKit/PumpManager/PodDoseProgressEstimator.swift -// Created by Pete Schwamb on 3/12/19. -// Copyright © 2019 Pete Schwamb. All rights reserved. -// - -import Foundation -import LoopKit - -class PodDoseProgressEstimator: DoseProgressTimerEstimator { - - let dose: DoseEntry - - weak var pumpManager: PumpManager? - - override var progress: DoseProgress { - let elapsed = -dose.startDate.timeIntervalSinceNow - let duration = dose.endDate.timeIntervalSince(dose.startDate) - let percentComplete = min(elapsed / duration, 1) - let delivered = pumpManager?.roundToSupportedBolusVolume(units: percentComplete * dose.programmedUnits) ?? dose.programmedUnits - return DoseProgress(deliveredUnits: delivered, percentComplete: percentComplete) - } - - init(dose: DoseEntry, pumpManager: PumpManager, reportingQueue: DispatchQueue) { - self.dose = dose - self.pumpManager = pumpManager - super.init(reportingQueue: reportingQueue) - } - - override func timerParameters() -> (delay: TimeInterval, repeating: TimeInterval) { - let timeSinceStart = dose.startDate.timeIntervalSinceNow - let timeBetweenPulses: TimeInterval - switch dose.type { - case .bolus: - timeBetweenPulses = Pod.pulseSize / Pod.bolusDeliveryRate - case .basal, .tempBasal: - timeBetweenPulses = Pod.pulseSize / (dose.unitsPerHour / TimeInterval(hours: 1)) - default: - fatalError("Can only estimate progress on basal rates or boluses.") - } - let delayUntilNextPulse = timeBetweenPulses - timeSinceStart.remainder(dividingBy: timeBetweenPulses) - - return (delay: delayUntilNextPulse, repeating: timeBetweenPulses) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PodInsulinMeasurements.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PodInsulinMeasurements.swift deleted file mode 100644 index 66418827f..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PodInsulinMeasurements.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// PodInsulinMeasurements.swift -// OmniBLE -// -// From OmniKit/PumpManager/PodInsulinMeasurements.swift -// Created by Pete Schwamb on 9/5/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct PodInsulinMeasurements: RawRepresentable, Equatable { - public typealias RawValue = [String: Any] - - public let validTime: Date - public let delivered: Double - public let reservoirLevel: Double? - - public init(insulinDelivered: Double, reservoirLevel: Double?, validTime: Date) { - self.validTime = validTime - self.delivered = insulinDelivered - self.reservoirLevel = reservoirLevel - } - - // RawRepresentable - public init?(rawValue: RawValue) { - guard - let validTime = rawValue["validTime"] as? Date, - let delivered = rawValue["delivered"] as? Double - else { - return nil - } - self.validTime = validTime - self.delivered = delivered - self.reservoirLevel = rawValue["reservoirLevel"] as? Double - } - - public var rawValue: RawValue { - var rawValue: RawValue = [ - "validTime": validTime, - "delivered": delivered - ] - - if let reservoirLevel = reservoirLevel { - rawValue["reservoirLevel"] = reservoirLevel - } - - return rawValue - } -} - diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PodProgressStatus.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PodProgressStatus.swift deleted file mode 100644 index 84ec7e733..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PodProgressStatus.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// PodProgressStatus.swift -// OmniBLE -// -// From OmniKit/Model/PodProgressStatus.swift -// Created by Pete Schwamb on 9/28/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public enum PodProgressStatus: UInt8, CustomStringConvertible, Equatable { - case initialized = 0 - case memoryInitialized = 1 - case reminderInitialized = 2 - case pairingCompleted = 3 - case priming = 4 - case primingCompleted = 5 - case basalInitialized = 6 - case insertingCannula = 7 - case aboveFiftyUnits = 8 - case fiftyOrLessUnits = 9 - case oneNotUsed = 10 - case twoNotUsed = 11 - case threeNotUsed = 12 - case faultEventOccurred = 13 // fault event occurred (a "screamer") - case activationTimeExceeded = 14 // took > 2 hrs from progress 2 to 3 OR > 1 hr from 3 to 8 - case inactive = 15 // pod deactivated or a fatal packet state error - - public var readyForDelivery: Bool { - return self == .fiftyOrLessUnits || self == .aboveFiftyUnits - } - - public var description: String { - switch self { - case .initialized: - return LocalizedString("Initialized", comment: "Pod initialized") - case .memoryInitialized: - return LocalizedString("Memory initialized", comment: "Pod memory initialized") - case .reminderInitialized: - return LocalizedString("Reminder initialized", comment: "Pod pairing reminder initialized") - case .pairingCompleted: - return LocalizedString("Pairing completed", comment: "Pod status when pairing completed") - case .priming: - return LocalizedString("Priming", comment: "Pod status when priming") - case .primingCompleted: - return LocalizedString("Priming completed", comment: "Pod state when priming completed") - case .basalInitialized: - return LocalizedString("Basal initialized", comment: "Pod state when basal initialized") - case .insertingCannula: - return LocalizedString("Inserting cannula", comment: "Pod state when inserting cannula") - case .aboveFiftyUnits: - return LocalizedString("Normal", comment: "Pod state when running above fifty units") - case .fiftyOrLessUnits: - return LocalizedString("Low reservoir", comment: "Pod state when running with fifty or less units") - case .oneNotUsed: - return LocalizedString("oneNotUsed", comment: "Pod state oneNotUsed") - case .twoNotUsed: - return LocalizedString("twoNotUsed", comment: "Pod state twoNotUsed") - case .threeNotUsed: - return LocalizedString("threeNotUsed", comment: "Pod state threeNotUsed") - case .faultEventOccurred: - return LocalizedString("Fault event occurred", comment: "Pod state when fault event has occurred") - case .activationTimeExceeded: - return LocalizedString("Activation time exceeded", comment: "Pod state when activation not completed in the time allowed") - case .inactive: - return LocalizedString("Deactivated", comment: "Pod state when deactivated") - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PumpManagerAlert.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PumpManagerAlert.swift deleted file mode 100644 index 52d46c78d..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/PumpManagerAlert.swift +++ /dev/null @@ -1,232 +0,0 @@ -// -// PumpManagerAlert.swift -// OmniBLE -// -// Created by Pete Schwamb on 7/9/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit -import HealthKit - -public enum PumpManagerAlert: Hashable { - case podExpireImminent(triggeringSlot: AlertSlot?) - case userPodExpiration(triggeringSlot: AlertSlot?, scheduledExpirationReminderOffset: TimeInterval) - case lowReservoir(triggeringSlot: AlertSlot?, lowReservoirReminderValue: Double) - case suspendInProgress(triggeringSlot: AlertSlot?) - case suspendEnded(triggeringSlot: AlertSlot?) - case podExpiring(triggeringSlot: AlertSlot?) - case finishSetupReminder(triggeringSlot: AlertSlot?) - case unexpectedAlert(triggeringSlot: AlertSlot?) - case timeOffsetChangeDetected - - var isRepeating: Bool { - return repeatInterval != nil - } - - var repeatInterval: TimeInterval? { - switch self { - case .suspendEnded: - return .minutes(15) - default: - return nil - } - } - - var contentTitle: String { - switch self { - case .userPodExpiration: - return LocalizedString("Pod Expiration Reminder", comment: "Alert content title for userPodExpiration pod alert") - case .podExpiring: - return LocalizedString("Pod Expired", comment: "Alert content title for podExpiring pod alert") - case .podExpireImminent: - return LocalizedString("Pod Expired", comment: "Alert content title for podExpireImminent pod alert") - case .lowReservoir: - return LocalizedString("Low Reservoir", comment: "Alert content title for lowReservoir pod alert") - case .suspendInProgress: - return LocalizedString("Suspend In Progress Reminder", comment: "Alert content title for suspendInProgress pod alert") - case .suspendEnded: - return LocalizedString("Resume Insulin", comment: "Alert content title for suspendEnded pod alert") - case .finishSetupReminder: - return LocalizedString("Pod Pairing Incomplete", comment: "Alert content title for finishSetupReminder pod alert") - case .unexpectedAlert: - return LocalizedString("Unexpected Alert", comment: "Alert content title for unexpected pod alert") - case .timeOffsetChangeDetected: - return LocalizedString("Time Change Detected", comment: "Alert content title for timeOffsetChangeDetected pod alert") - } - } - - var contentBody: String { - switch self { - case .userPodExpiration(_, let offset): - let formatter = DateComponentsFormatter() - formatter.allowedUnits = [.hour] - formatter.unitsStyle = .full - let timeString = formatter.string(from: TimeInterval(offset))! - return String(format: LocalizedString("Pod expires in %1$@.", comment: "Format string for alert content body for userPodExpiration pod alert. (1: time until expiration)"), timeString) - case .podExpiring: - return LocalizedString("Change Pod now. Pod has been active for 72 hours.", comment: "Alert content body for podExpiring pod alert") - case .podExpireImminent: - return LocalizedString("Change Pod now. Insulin delivery will stop in 1 hour.", comment: "Alert content body for podExpireImminent pod alert") - case .lowReservoir(_, let lowReservoirReminderValue): - let quantityFormatter = QuantityFormatter(for: .internationalUnit()) - let valueString = quantityFormatter.string(from: HKQuantity(unit: .internationalUnit(), doubleValue: lowReservoirReminderValue), for: .internationalUnit()) ?? String(describing: lowReservoirReminderValue) - return String(format: LocalizedString("%1$@ insulin or less remaining in Pod. Change Pod soon.", comment: "Format string for alert content body for lowReservoir pod alert. (1: reminder value)"), valueString) - case .suspendInProgress: - return LocalizedString("Suspend In Progress Reminder", comment: "Alert content body for suspendInProgress pod alert") - case .suspendEnded: - return LocalizedString("The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes.", comment: "Alert content body for suspendEnded pod alert") - case .finishSetupReminder: - return LocalizedString("Please finish pairing your pod.", comment: "Alert content body for finishSetupReminder pod alert") - case .unexpectedAlert(let triggeringSlot): - let slotNumberString = triggeringSlot != nil ? String(describing: triggeringSlot!.rawValue) : "?" - return String(format: LocalizedString("Unexpected Pod Alert #%1@!", comment: "Alert content body for unexpected pod alert (1: slotNumberString)"), slotNumberString) - case .timeOffsetChangeDetected: - return LocalizedString("The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings.", comment: "Alert content body for timeOffsetChangeDetected pod alert") - } - } - - var triggeringSlot: AlertSlot? { - switch self { - case .userPodExpiration(let slot, _): - return slot - case .podExpiring(let slot): - return slot - case .podExpireImminent(let slot): - return slot - case .lowReservoir(let slot, _): - return slot - case .suspendInProgress(let slot): - return slot - case .suspendEnded(let slot): - return slot - case .finishSetupReminder(let slot): - return slot - case .unexpectedAlert(let slot): - return slot - case .timeOffsetChangeDetected: - return nil - } - } - - // Override background (UserNotification) content - - var backgroundContentTitle: String { - return contentTitle - } - - var backgroundContentBody: String { - switch self { - case .suspendEnded: - return LocalizedString("Suspension time is up. Open the app and resume.", comment: "Alert notification body for suspendEnded pod alert user notification") - default: - return contentBody - } - } - - - var actionButtonLabel: String { - return LocalizedString("Ok", comment: "Action button default text for PodAlerts") - } - - var foregroundContent: Alert.Content { - return Alert.Content(title: contentTitle, body: contentBody, acknowledgeActionButtonLabel: actionButtonLabel) - } - - var backgroundContent: Alert.Content { - return Alert.Content(title: backgroundContentTitle, body: backgroundContentBody, acknowledgeActionButtonLabel: actionButtonLabel) - } - - var alertIdentifier: String { - switch self { - case .userPodExpiration: - return "userPodExpiration" - case .podExpiring: - return "podExpiring" - case .podExpireImminent: - return "podExpireImminent" - case .lowReservoir: - return "lowReservoir" - case .suspendInProgress: - return "suspendInProgress" - case .suspendEnded: - return "suspendEnded" - case .finishSetupReminder: - return "finishSetupReminder" - case .unexpectedAlert: - return "unexpectedAlert" - case .timeOffsetChangeDetected: - return "timeOffsetChangeDetected" - } - } - - var repeatingAlertIdentifier: String { - return alertIdentifier + "-repeating" - } -} - -extension PumpManagerAlert: RawRepresentable { - - public typealias RawValue = [String: Any] - - public init?(rawValue: RawValue) { - guard let identifier = rawValue["identifier"] as? String else { - return nil - } - - let slot: AlertSlot? - - if let rawSlot = rawValue["slot"] as? AlertSlot.RawValue { - slot = AlertSlot(rawValue: rawSlot) - } else { - slot = nil - } - - switch identifier { - case "userPodExpiration": - guard let offset = rawValue["offset"] as? TimeInterval, offset > 0 else { - return nil - } - self = .userPodExpiration(triggeringSlot: slot, scheduledExpirationReminderOffset: offset) - case "podExpiring": - self = .podExpiring(triggeringSlot: slot) - case "podExpireImminent": - self = .podExpireImminent(triggeringSlot: slot) - case "lowReservoir": - guard let value = rawValue["value"] as? Double else { - return nil - } - self = .lowReservoir(triggeringSlot: slot, lowReservoirReminderValue: value) - case "suspendInProgress": - self = .suspendInProgress(triggeringSlot: slot) - case "suspendEnded": - self = .suspendEnded(triggeringSlot: slot) - case "unexpectedAlert": - self = .unexpectedAlert(triggeringSlot: slot) - case "timeOffsetChangeDetected": - self = .timeOffsetChangeDetected - default: - return nil - } - } - - public var rawValue: [String : Any] { - var rawValue: RawValue = [ - "identifier": alertIdentifier - ] - - rawValue["slot"] = triggeringSlot?.rawValue - - switch self { - case .lowReservoir(_, lowReservoirReminderValue: let value): - rawValue["value"] = value - case .userPodExpiration(_, scheduledExpirationReminderOffset: let offset): - rawValue["offset"] = offset - default: - break - } - - return rawValue - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/ReservoirLevel.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/ReservoirLevel.swift deleted file mode 100644 index 36b5cbe95..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/ReservoirLevel.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// ReservoirLevel.swift -// OmniBLE -// -// Created by Pete Schwamb on 5/31/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum ReservoirLevel: RawRepresentable, Equatable { - public typealias RawValue = Double - - case valid(Double) - case aboveThreshold - - public var percentage: Double { - switch self { - case .aboveThreshold: - return 1 - case .valid(let value): - // Set 50U as the halfway mark, even though pods can hold 200U. - return min(1, max(0, value / 100)) - } - } - - public init(rawValue: RawValue) { - if rawValue > Pod.maximumReservoirReading { - self = .aboveThreshold - } else { - self = .valid(rawValue) - } - } - - public var rawValue: RawValue { - switch self { - case .valid(let value): - return value - case .aboveThreshold: - return Pod.reservoirLevelAboveThresholdMagicNumber - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/SilencePodPreference.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/SilencePodPreference.swift deleted file mode 100644 index 2596b476f..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/SilencePodPreference.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// SilencePodPreference.swift -// OmniBLE -// -// Created by Joe Moran on 8/30/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum SilencePodPreference: Int, CaseIterable { - case disabled - case enabled - - var title: String { - switch self { - case .disabled: - return LocalizedString("Disabled", comment: "Title string for SilencePodPreference.disabled") - case .enabled: - return LocalizedString("Silenced", comment: "Title string for SilencePodPreference.enabled") - } - } - - var description: String { - switch self { - case .disabled: - return LocalizedString("Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled.", comment: "Description for SilencePodPreference.disabled") - case .enabled: - return LocalizedString("All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts.", comment: "Description for SilencePodPreference.enabled") - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/UnfinalizedDose.swift b/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/UnfinalizedDose.swift deleted file mode 100644 index cc8e2487d..000000000 --- a/Dependencies/OmniBLE/OmniBLE/OmnipodCommon/UnfinalizedDose.swift +++ /dev/null @@ -1,346 +0,0 @@ -// -// UnfinalizedDose.swift -// OmniBLE -// -// From OmniKit/Model/UnfinalizedDose.swift -// Created by Pete Schwamb on 9/5/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation -import LoopKit - -public struct UnfinalizedDose: RawRepresentable, Equatable, CustomStringConvertible { - public typealias RawValue = [String: Any] - - enum DoseType: Int { - case bolus = 0 - case tempBasal - case suspend - case resume - } - - enum ScheduledCertainty: Int { - case certain = 0 - case uncertain - - public var localizedDescription: String { - switch self { - case .certain: - return LocalizedString("Certain", comment: "String describing a dose that was certainly scheduled") - case .uncertain: - return LocalizedString("Uncertain", comment: "String describing a dose that was possibly scheduled") - } - } - } - - private let insulinFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.maximumFractionDigits = 3 - return formatter - }() - - private let shortDateFormatter: DateFormatter = { - let timeFormatter = DateFormatter() - timeFormatter.dateStyle = .short - timeFormatter.timeStyle = .medium - return timeFormatter - }() - - private let dateFormatter = ISO8601DateFormatter() - - fileprivate var uniqueKey: Data { - return "\(doseType) \(scheduledUnits ?? units) \(dateFormatter.string(from: startTime))".data(using: .utf8)! - } - - let doseType: DoseType - public var units: Double - public var automatic: Bool // Tracks if this dose was issued automatically or manually - var scheduledUnits: Double? // Tracks the scheduled units, as boluses may be canceled before finishing, at which point units would reflect actual delivered volume. - var scheduledTempRate: Double? // Tracks the original temp rate, as during finalization the units are discretized to pump pulses, changing the actual rate - let startTime: Date - var duration: TimeInterval? - var scheduledCertainty: ScheduledCertainty - var isHighTemp: Bool = false // Track this for situations where cancelling temp basal is unacknowledged, and recovery fails, and we have to assume the most possible delivery - var insulinType: InsulinType? - - var finishTime: Date? { - get { - return duration != nil ? startTime.addingTimeInterval(duration!) : nil - } - set { - duration = newValue?.timeIntervalSince(startTime) - } - } - - public func progress(at date: Date = Date()) -> Double { - guard let duration = duration else { - return 0 - } - let elapsed = -startTime.timeIntervalSince(date) - return min(elapsed / duration, 1) - } - - public func isFinished(at date: Date = Date()) -> Bool { - return progress(at: date) >= 1 - } - - // Units per hour - public var rate: Double { - guard let duration = duration else { - return 0 - } - return units / duration.hours - } - - public var finalizedUnits: Double? { - guard isFinished() else { - return nil - } - return units - } - - init(bolusAmount: Double, startTime: Date, scheduledCertainty: ScheduledCertainty, insulinType: InsulinType, automatic: Bool = false) { - self.doseType = .bolus - self.units = bolusAmount - self.startTime = startTime - self.duration = TimeInterval(bolusAmount / Pod.bolusDeliveryRate) - self.scheduledCertainty = scheduledCertainty - self.scheduledUnits = nil - self.automatic = automatic - self.insulinType = insulinType - } - - init(tempBasalRate: Double, startTime: Date, duration: TimeInterval, isHighTemp: Bool, automatic: Bool, scheduledCertainty: ScheduledCertainty, insulinType: InsulinType) { - self.doseType = .tempBasal - self.units = tempBasalRate * duration.hours - self.startTime = startTime - self.duration = duration - self.scheduledCertainty = scheduledCertainty - self.scheduledUnits = nil - self.automatic = automatic - self.isHighTemp = isHighTemp - self.insulinType = insulinType - } - - init(suspendStartTime: Date, scheduledCertainty: ScheduledCertainty) { - self.doseType = .suspend - self.units = 0 - self.startTime = suspendStartTime - self.scheduledCertainty = scheduledCertainty - self.automatic = false - } - - init(resumeStartTime: Date, scheduledCertainty: ScheduledCertainty, insulinType: InsulinType) { - self.doseType = .resume - self.units = 0 - self.startTime = resumeStartTime - self.scheduledCertainty = scheduledCertainty - self.automatic = false - self.insulinType = insulinType - } - - public mutating func cancel(at date: Date, withRemaining remaining: Double? = nil) { - guard let finishTime = finishTime, date < finishTime else { - return - } - - scheduledUnits = units - let newDuration = date.timeIntervalSince(startTime) - - switch doseType { - case .bolus: - let oldRate = rate - if let remaining = remaining { - units = units - remaining - } else { - units = oldRate * newDuration.hours - } - case .tempBasal: - scheduledTempRate = rate - units = floor(rate * newDuration.hours * Pod.pulsesPerUnit) / Pod.pulsesPerUnit - print("Temp basal scheduled units: \(String(describing: scheduledUnits)), delivered units: \(units), duration: \(newDuration.minutes)") - default: - break - } - duration = newDuration - } - - public func isMutable(at date: Date = Date()) -> Bool { - switch doseType { - case .bolus, .tempBasal: - return !isFinished(at: date) - default: - return false - } - } - - public var description: String { - let unitsStr = insulinFormatter.string(from: units) ?? "" - let startTimeStr = shortDateFormatter.string(from: startTime) - let durationStr = duration?.format(using: [.minute, .second]) ?? "" - switch doseType { - case .bolus: - if let scheduledUnits = scheduledUnits { - let scheduledUnitsStr = insulinFormatter.string(from: scheduledUnits) ?? "?" - return String(format: LocalizedString("InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@", comment: "The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty)"), unitsStr, scheduledUnitsStr, startTimeStr, durationStr, scheduledCertainty.localizedDescription) - } else { - return String(format: LocalizedString("Bolus: %1$@U %2$@ %3$@ %4$@", comment: "The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty)"), unitsStr, startTimeStr, durationStr, scheduledCertainty.localizedDescription) - } - case .tempBasal: - let volumeStr = insulinFormatter.string(from: units) ?? "?" - let rateStr = NumberFormatter.localizedString(from: NSNumber(value: scheduledTempRate ?? rate), number: .decimal) - return String(format: LocalizedString("TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@", comment: "The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty"), rateStr, startTimeStr, durationStr, volumeStr, scheduledCertainty.localizedDescription) - case .suspend: - return String(format: LocalizedString("Suspend: %1$@ %2$@", comment: "The format string describing a suspend. (1: Time)(2: Scheduled certainty"), startTimeStr, scheduledCertainty.localizedDescription) - case .resume: - return String(format: LocalizedString("Resume: %1$@ %2$@", comment: "The format string describing a resume. (1: Time)(2: Scheduled certainty"), startTimeStr, scheduledCertainty.localizedDescription) - } - } - - public var eventTitle: String { - switch doseType { - case .bolus: - return LocalizedString("Bolus", comment: "Pump Event title for UnfinalizedDose with doseType of .bolus") - case .resume: - return LocalizedString("Resume", comment: "Pump Event title for UnfinalizedDose with doseType of .resume") - case .suspend: - return LocalizedString("Suspend", comment: "Pump Event title for UnfinalizedDose with doseType of .suspend") - case .tempBasal: - return LocalizedString("Temp Basal", comment: "Pump Event title for UnfinalizedDose with doseType of .tempBasal") - } - } - - // RawRepresentable - public init?(rawValue: RawValue) { - guard - let rawDoseType = rawValue["doseType"] as? Int, - let doseType = DoseType(rawValue: rawDoseType), - let units = rawValue["units"] as? Double, - let startTime = rawValue["startTime"] as? Date, - let rawScheduledCertainty = rawValue["scheduledCertainty"] as? Int, - let scheduledCertainty = ScheduledCertainty(rawValue: rawScheduledCertainty) - else { - return nil - } - - self.doseType = doseType - self.units = units - self.startTime = startTime - self.scheduledCertainty = scheduledCertainty - - self.scheduledUnits = rawValue["scheduledUnits"] as? Double - - self.scheduledTempRate = rawValue["scheduledTempRate"] as? Double - - self.duration = rawValue["duration"] as? Double - - if let automatic = rawValue["automatic"] as? Bool { - self.automatic = automatic - } else { - if case .tempBasal = doseType { - self.automatic = true - } else { - self.automatic = false - } - } - - if let isHighTemp = rawValue["isHighTemp"] as? Bool { - self.isHighTemp = isHighTemp - } else { - self.isHighTemp = false - } - - if let rawInsulinType = rawValue["insulinType"] as? InsulinType.RawValue { - self.insulinType = InsulinType(rawValue: rawInsulinType) - } - - } - - public var rawValue: RawValue { - var rawValue: RawValue = [ - "doseType": doseType.rawValue, - "units": units, - "startTime": startTime, - "scheduledCertainty": scheduledCertainty.rawValue, - "automatic": automatic, - "isHighTemp": isHighTemp, - ] - - rawValue["scheduledUnits"] = scheduledUnits - rawValue["scheduledTempRate"] = scheduledTempRate - rawValue["duration"] = duration - rawValue["insulinType"] = insulinType?.rawValue - - return rawValue - } -} - -private extension TimeInterval { - func format(using units: NSCalendar.Unit) -> String? { - let formatter = DateComponentsFormatter() - formatter.allowedUnits = units - formatter.unitsStyle = .full - formatter.zeroFormattingBehavior = .dropLeading - formatter.maximumUnitCount = 2 - - return formatter.string(from: self) - } -} - -extension NewPumpEvent { - init(_ dose: UnfinalizedDose) { - let entry = DoseEntry(dose) - self.init(date: dose.startTime, dose: entry, raw: dose.uniqueKey, title: dose.eventTitle) - } -} - -extension DoseEntry { - init (_ dose: UnfinalizedDose) { - switch dose.doseType { - case .bolus: - self = DoseEntry( - type: .bolus, - startDate: dose.startTime, - endDate: dose.finishTime, - value: dose.scheduledUnits ?? dose.units, - unit: .units, - deliveredUnits: dose.finalizedUnits, - insulinType: dose.insulinType, - automatic: dose.automatic, - isMutable: dose.isMutable() - ) - case .tempBasal: - self = DoseEntry( - type: .tempBasal, - startDate: dose.startTime, - endDate: dose.finishTime, - value: dose.scheduledTempRate ?? dose.rate, - unit: .unitsPerHour, - deliveredUnits: dose.finalizedUnits, - insulinType: dose.insulinType, - automatic: dose.automatic, - isMutable: dose.isMutable() - ) - case .suspend: - self = DoseEntry(suspendDate: dose.startTime) - case .resume: - self = DoseEntry(resumeDate: dose.startTime, insulinType: dose.insulinType) - } - } -} - -extension StartProgram { - func unfinalizedDose(at programDate: Date, withCertainty certainty: UnfinalizedDose.ScheduledCertainty, insulinType: InsulinType) -> UnfinalizedDose? { - switch self { - case .bolus(volume: let volume, automatic: let automatic): - return UnfinalizedDose(bolusAmount: volume, startTime: programDate, scheduledCertainty: certainty, insulinType: insulinType, automatic: automatic) - case .tempBasal(unitsPerHour: let rate, duration: let duration, let isHighTemp, let automatic): - return UnfinalizedDose(tempBasalRate: rate, startTime: programDate, duration: duration, isHighTemp: isHighTemp, automatic: automatic, scheduledCertainty: certainty, insulinType: insulinType) - case .basalProgram: - return UnfinalizedDose(resumeStartTime: programDate, scheduledCertainty: certainty, insulinType: insulinType) - } - } -} - diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManager/DetailedStatus+OmniBLE.swift b/Dependencies/OmniBLE/OmniBLE/PumpManager/DetailedStatus+OmniBLE.swift deleted file mode 100644 index 040cbd1af..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManager/DetailedStatus+OmniBLE.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// DetailedStatus+OmniBLE.swift -// OmniBLE -// -// Created by Joseph Moran on 01/07/2022 -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -// Returns an appropropriate Dash PDM style Ref string for DetailedStatus -extension DetailedStatus { - // For most types, Ref: TT-VVVHH-IIIRR-FFF computed as {20|19|18|17|16|15|14|07|01}-{VV}{SSSS/60}-{NNNN/20}{RRRR/20}-PP - public var pdmRef: String? { - let TT: UInt8 - var VVV: UInt8 = data[17] // default value, can be changed - let HH: UInt8 = UInt8(timeActive.hours) - let III: UInt8 = UInt8(totalInsulinDelivered) - let RR: UInt8 = UInt8(self.reservoirLevel) // special 51.15 value used for > 50U will become 51 as needed - var FFF: UInt8 = faultEventCode.rawValue // default value, can be changed - - switch faultEventCode.faultType { - case .noFaults: - return nil - case .failedFlashErase ,.failedFlashStore, .tableCorruptionBasalSubcommand, .corruptionByte720, .corruptionInWord129, .disableFlashSecurityFailed: - // Ref: 01-VVVHH-IIIRR-FFF - TT = 01 // RAM Ref type - case .badTimerVariableState, .problemCalibrateTimer, .rtcInterruptHandlerUnexpectedCall, .trimICSTooCloseTo0x1FF, - .problemFindingBestTrimValue, .badSetTPM1MultiCasesValue: - // Ref: 07-VVVHH-IIIRR-FFF - TT = 07 // Clock Ref type - case .insulinDeliveryCommandError: - // Ref: 11-144-0018-0049, this fault is treated as a PDM fault with an alternate Ref format - // XXX need to verify these values are still correct with the Dash PDM - return "11-144-0018-00049" // all fixed values for this fault - case .reservoirEmpty: - // Ref: 14-VVVHH-IIIRR-FFF - TT = 14 // PumpVolume Ref type - case .autoOff0, .autoOff1, .autoOff2, .autoOff3, .autoOff4, .autoOff5, .autoOff6, .autoOff7: - // Ref: 15-VVVHH-IIIRR-FFF - TT = 15 // PumpAutoOff Ref type - case .exceededMaximumPodLife80Hrs: - // Ref: 16-VVVHH-IIIRR-FFF - TT = 16 // PumpExpired Ref type - case .occluded: - // Ref: 17-000HH-IIIRR-000 - TT = 17 // PumpOcclusion Ref type - VVV = 0 // no VVV value for an occlusion fault - FFF = 0 // no FFF value for an occlusion fault - case .bleTimeout, .bleInitiated, .bleUnkAlarm, .bleIaas, .crcFailure, .bleWdPingTimeout, .bleExcessiveResets, .bleNakError, .bleReqHighTimeout, .bleUnknownResp, .bleReqStuckHigh, .bleStateMachine1, .bleStateMachine2, .bleArbLost, .bleEr48DualNack, .bleQnExceedMaxRetry, .bleQnCritVarFail: - // Ref: 20-VVVHH-IIIRR-FFF - TT = 20 // PumpCommunications Ref type - default: - // Ref: 19-VVVHH-IIIRR-FFF - TT = 19 // PumpError Ref type - } - - return String(format: "%02d-%03d%02d-%03d%02d-%03d", TT, VVV, HH, III, RR, FFF) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManager/MessageTransport.swift b/Dependencies/OmniBLE/OmniBLE/PumpManager/MessageTransport.swift deleted file mode 100644 index 9a1fa5fba..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManager/MessageTransport.swift +++ /dev/null @@ -1,339 +0,0 @@ -// -// MessageTransport.swift -// OmniBLE -// -// Based on OmniKit/MessageTransport/MessageTransport.swift -// Created by Pete Schwamb on 8/5/18. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import os.log - -protocol MessageLogger: AnyObject { - // Comms logging - func didSend(_ message: Data) - func didReceive(_ message: Data) - func didError(_ message: String) -} - -public struct MessageTransportState: Equatable, RawRepresentable { - public typealias RawValue = [String: Any] - - public var ck: Data? - public var noncePrefix: Data? - public var eapSeq: Int // per session sequence # - public var msgSeq: Int // 8-bit Dash MessagePacket sequence # (with ck) - public var nonceSeq: Int // nonce sequence # (with noncePrefix) - public var messageNumber: Int // 4-bit Omnipod Message # (for Omnipod command/responses Messages) - - init(ck: Data?, noncePrefix: Data?, eapSeq: Int = 1, msgSeq: Int = 0, nonceSeq: Int = 0, messageNumber: Int = 0) { - self.ck = ck - self.noncePrefix = noncePrefix - self.eapSeq = eapSeq - self.msgSeq = msgSeq - self.nonceSeq = nonceSeq - self.messageNumber = messageNumber - } - - // RawRepresentable - public init?(rawValue: RawValue) { - guard - let ckString = rawValue["ck"] as? String, - let noncePrefixString = rawValue["noncePrefix"] as? String, - let msgSeq = rawValue["msgSeq"] as? Int, - let nonceSeq = rawValue["nonceSeq"] as? Int, - let messageNumber = rawValue["messageNumber"] as? Int - else { - return nil - } - self.ck = Data(hex: ckString) - self.noncePrefix = Data(hex: noncePrefixString) - self.eapSeq = rawValue["eapSeq"] as? Int ?? 1 - self.msgSeq = msgSeq - self.nonceSeq = nonceSeq - self.messageNumber = messageNumber - } - - public var rawValue: RawValue { - return [ - "ck": ck?.hexadecimalString ?? "", - "noncePrefix": noncePrefix?.hexadecimalString ?? "", - "eapSeq": eapSeq, - "msgSeq": msgSeq, - "nonceSeq": nonceSeq, - "messageNumber": messageNumber - ] - } - -} - -extension MessageTransportState: CustomDebugStringConvertible { - public var debugDescription: String { - return [ - "## MessageTransportState", - "eapSeq: \(eapSeq)", - "msgSeq: \(msgSeq)", - "nonceSeq: \(nonceSeq)", - "messageNumber: \(messageNumber)", - ].joined(separator: "\n") - } -} - -protocol MessageTransportDelegate: AnyObject { - func messageTransport(_ messageTransport: MessageTransport, didUpdate state: MessageTransportState) -} - -protocol MessageTransport { - var delegate: MessageTransportDelegate? { get set } - - var messageNumber: Int { get } - - func sendMessage(_ message: Message) throws -> Message - - /// Asserts that the caller is currently on the session's queue - func assertOnSessionQueue() -} - -class PodMessageTransport: MessageTransport { - private let COMMAND_PREFIX = "S0.0=" - private let COMMAND_SUFFIX = ",G0.0" - private let RESPONSE_PREFIX = "0.0=" - - private let manager: PeripheralManager - - private var nonce: Nonce? - private var enDecrypt: EnDecrypt? - - private let log = OSLog(category: "PodMessageTransport") - - private(set) var state: MessageTransportState { - didSet { - self.delegate?.messageTransport(self, didUpdate: state) - } - } - - private(set) var ck: Data? { - get { - return state.ck - } - set { - state.ck = newValue - } - } - - private(set) var noncePrefix: Data? { - get { - return state.noncePrefix - } - set { - state.noncePrefix = newValue - } - } - - private(set) var eapSeq: Int { - get { - return state.eapSeq - } - set { - state.eapSeq = newValue - } - } - - private(set) var msgSeq: Int { - get { - return state.msgSeq - } - set { - state.msgSeq = newValue - } - } - - private(set) var nonceSeq: Int { - get { - return state.nonceSeq - } - set { - state.nonceSeq = newValue - } - } - - private(set) var messageNumber: Int { - get { - return state.messageNumber - } - set { - state.messageNumber = newValue - } - } - - private let myId: UInt32 - private let podId: UInt32 - - weak var messageLogger: MessageLogger? - weak var delegate: MessageTransportDelegate? - - init(manager: PeripheralManager, myId: UInt32, podId: UInt32, state: MessageTransportState) { - self.manager = manager - self.myId = myId - self.podId = podId - self.state = state - - guard let noncePrefix = self.noncePrefix, let ck = self.ck else { return } - self.nonce = Nonce(prefix: noncePrefix) - self.enDecrypt = EnDecrypt(nonce: self.nonce!, ck: ck) - } - - private func incrementMsgSeq(_ count: Int = 1) { - msgSeq = ((msgSeq) + count) & 0xff // msgSeq is the 8-bit Dash MessagePacket sequence # - } - - private func incrementNonceSeq(_ count: Int = 1) { - nonceSeq = nonceSeq + count - } - - private func incrementMessageNumber(_ count: Int = 1) { - messageNumber = ((messageNumber) + count) & 0b1111 // messageNumber is the 4-bit Omnipod Message # - } - - /// Sends the given pod message over the encrypted Dash transport and returns the pod's response - func sendMessage(_ message: Message) throws -> Message { - - guard manager.peripheral.state == .connected else { - throw PodCommsError.podNotConnected - } - - messageNumber = message.sequenceNum // reset our Omnipod message # to given value - - incrementMessageNumber() // bump to match expected Omnipod message # in response - - let dataToSend = message.encoded() - log.default("Send(Hex): %{public}@", dataToSend.hexadecimalString) - messageLogger?.didSend(dataToSend) - - let sendMessage = try getCmdMessage(cmd: message) - - let writeResult = manager.sendMessagePacket(sendMessage) - switch writeResult { - case .sentWithAcknowledgment: - break; - case .sentWithError(let error): - messageLogger?.didError("Unacknowledged message. seq:\(message.sequenceNum), error = \(error)") - throw PodCommsError.unacknowledgedMessage(sequenceNumber: message.sequenceNum, error: error) - case .unsentWithError(let error): - throw PodCommsError.commsError(error: error) - } - - do { - let response = try readAndAckResponse() - incrementMessageNumber() // bump the 4-bit Omnipod Message number - return response - } catch { - messageLogger?.didError("Unacknowledged message. seq:\(message.sequenceNum), error = \(error)") - throw PodCommsError.unacknowledgedMessage(sequenceNumber: message.sequenceNum, error: error) - } - } - - private func getCmdMessage(cmd: Message) throws -> MessagePacket { - guard let enDecrypt = self.enDecrypt else { - throw PodCommsError.podNotConnected - } - - incrementMsgSeq() - - let wrapped = StringLengthPrefixEncoding.formatKeys( - keys: [COMMAND_PREFIX, COMMAND_SUFFIX], - payloads: [cmd.encoded(), Data()] - ) - - let msg = MessagePacket( - type: MessageType.ENCRYPTED, - source: self.myId, - destination: self.podId, - payload: wrapped, - sequenceNumber: UInt8(msgSeq), - eqos: 1 - ) - - incrementNonceSeq() - return try enDecrypt.encrypt(msg, nonceSeq) - } - - func readAndAckResponse() throws -> Message { - guard let enDecrypt = self.enDecrypt else { throw PodCommsError.podNotConnected } - - let readResponse = try manager.readMessagePacket() - guard let readMessage = readResponse else { - throw PodProtocolError.messageIOException("Could not read response") - } - - incrementNonceSeq() - let decrypted = try enDecrypt.decrypt(readMessage, nonceSeq) - - let response = try parseResponse(decrypted: decrypted) - - incrementMsgSeq() - incrementNonceSeq() - let ack = try getAck(response: decrypted) - let ackResult = manager.sendMessagePacket(ack) - guard case .sentWithAcknowledgment = ackResult else { - throw PodProtocolError.messageIOException("Could not write $msgType: \(ackResult)") - } - - // verify that the Omnipod message # matches the expected value - guard response.sequenceNum == messageNumber else { - throw MessageError.invalidSequence - } - - return response - } - - private func parseResponse(decrypted: MessagePacket) throws -> Message { - - let data = try StringLengthPrefixEncoding.parseKeys([RESPONSE_PREFIX], decrypted.payload)[0] - log.debug("Received decrypted response: %{public}@ in packet: %{public}@", data.hexadecimalString, decrypted.payload.hexadecimalString) - - // Dash pods generates a CRC16 for Omnipod Messages, but the actual algorithm is not understood and doesn't match the CRC16 - // that the pod enforces for incoming Omnipod command message. The Dash PDM explicitly ignores the CRC16 for incoming messages, - // so we ignore them as well and rely on higher level BLE & Dash message data checking to provide data corruption protection. - let response = try Message(encodedData: data, checkCRC: false) - - log.default("Recv(Hex): %{public}@", data.hexadecimalString) - messageLogger?.didReceive(data) - - return response - } - - private func getAck(response: MessagePacket) throws -> MessagePacket { - guard let enDecrypt = self.enDecrypt else { throw PodCommsError.podNotConnected } - - let ackNumber = (UInt(response.sequenceNumber) + 1) & 0xff - let msg = MessagePacket( - type: MessageType.ENCRYPTED, - source: response.destination.toUInt32(), - destination: response.source.toUInt32(), - payload: Data(), - sequenceNumber: UInt8(msgSeq), - ack: true, - ackNumber: UInt8(ackNumber), - eqos: 0 - ) - return try enDecrypt.encrypt(msg, nonceSeq) - } - - func assertOnSessionQueue() { - dispatchPrecondition(condition: .onQueue(manager.queue)) - } -} - -extension PodMessageTransport: CustomDebugStringConvertible { - public var debugDescription: String { - return [ - "## PodMessageTransport", - "eapSeq: \(eapSeq)", - "msgSeq: \(msgSeq)", - "nonceSeq: \(nonceSeq)", - "messageNumber: \(messageNumber)", - ].joined(separator: "\n") - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManager/OmniBLE.swift b/Dependencies/OmniBLE/OmniBLE/PumpManager/OmniBLE.swift deleted file mode 100644 index 2c8fbe415..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManager/OmniBLE.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// OmniBLE.swift -// OmniBLE -// -// Created by Randall Knutson on 10/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import OSLog - - -public class OmniBLE { - var manager: PeripheralManager - var advertisement: PodAdvertisement? - - private let log = OSLog(category: "OmniBLE") - - init(peripheralManager: PeripheralManager, advertisement: PodAdvertisement?) { - self.manager = peripheralManager - self.advertisement = advertisement - } -} - - -extension OmniBLE: CustomDebugStringConvertible { - public var debugDescription: String { - return "OmniBLE - advertisement: \(String(describing: advertisement))" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManager/OmniBLEPumpManager.swift b/Dependencies/OmniBLE/OmniBLE/PumpManager/OmniBLEPumpManager.swift deleted file mode 100644 index 0683da998..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManager/OmniBLEPumpManager.swift +++ /dev/null @@ -1,2395 +0,0 @@ -// -// OmniBLEPumpManager.swift -// OmniBLE -// -// Based on OmniKit/PumpManager/OmnipodPumpManager.swift -// Created by Pete Schwamb on 8/4/18. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import HealthKit -import LoopKit -import UserNotifications -import os.log -import CoreBluetooth - -public protocol PodStateObserver: AnyObject { - func podStateDidUpdate(_ state: PodState?) - func podConnectionStateDidChange(isConnected: Bool) -} - -public enum PodCommState: Equatable { - case noPod - case activating - case active - case fault(DetailedStatus) - case deactivating -} - -public enum OmniBLEPumpManagerError: Error { - case noPodPaired - case podAlreadyPaired - case insulinTypeNotConfigured - case notReadyForCannulaInsertion - case invalidSetting - case communication(Error) - case state(Error) -} - -extension OmniBLEPumpManagerError: LocalizedError { - public var errorDescription: String? { - switch self { - case .noPodPaired: - return LocalizedString("No pod paired", comment: "Error message shown when no pod is paired") - case .podAlreadyPaired: - return LocalizedString("Pod already paired", comment: "Error message shown when user cannot pair because pod is already paired") - case .insulinTypeNotConfigured: - return LocalizedString("Insulin type not configured", comment: "Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured") - case .notReadyForCannulaInsertion: - return LocalizedString("Pod is not in a state ready for cannula insertion.", comment: "Error message when cannula insertion fails because the pod is in an unexpected state") - case .communication(let error): - if let error = error as? LocalizedError { - return error.errorDescription - } else { - return String(describing: error) - } - case .state(let error): - if let error = error as? LocalizedError { - return error.errorDescription - } else { - return String(describing: error) - } - case .invalidSetting: - return LocalizedString("Invalid Setting", comment: "Error description for OmniBLEPumpManagerError.invalidSetting") - } - } - - public var failureReason: String? { - return nil - } - - public var recoverySuggestion: String? { - switch self { - case .noPodPaired: - return LocalizedString("Please pair a new pod", comment: "Recovery suggestion shown when no pod is paired") - default: - return nil - } - } -} - -public class OmniBLEPumpManager: DeviceManager { - - public let managerIdentifier: String = "Omnipod-Dash" // use a single token to make parsing log files easier - - public let localizedTitle = LocalizedString("Omnipod DASH", comment: "Generic title of the OmniBLE pump manager") - - static let podAlarmNotificationIdentifier = "OmniBLE:\(LoopNotificationCategory.pumpFault.rawValue)" - - public init(state: OmniBLEPumpManagerState, dateGenerator: @escaping () -> Date = Date.init) { - self.lockedState = Locked(state) - - self.dateGenerator = dateGenerator - - let podComms = PodComms(podState: state.podState, myId: state.controllerId, podId: state.podId) - self.lockedPodComms = Locked(podComms) - - self.podComms.delegate = self - self.podComms.messageLogger = self - - } - - public required convenience init?(rawState: PumpManager.RawStateValue) { - guard let state = OmniBLEPumpManagerState(rawValue: rawState) else - { - return nil - } - - self.init(state: state) - } - - public var deviceBLEName: String? { - return self.podComms.manager?.peripheral.name - } - - private var podComms: PodComms { - get { - return lockedPodComms.value - } - set { - lockedPodComms.value = newValue - } - } - private let lockedPodComms: Locked - - private let podStateObservers = WeakSynchronizedSet() - - // Primarily used for testing - public let dateGenerator: () -> Date - - public var state: OmniBLEPumpManagerState { - return lockedState.value - } - - private func setState(_ changes: (_ state: inout OmniBLEPumpManagerState) -> Void) -> Void { - return setStateWithResult(changes) - } - - // Status can change even when state does not, because some status changes - // purely based on time. This provides a mechanism to evaluate status changes - // as time progresses and trigger status updates to clients. - private func evaluateStatus() { - setState { state in - // status is evaluated in the setState call - } - } - - private func setStateWithResult(_ changes: (_ state: inout OmniBLEPumpManagerState) -> ReturnType) -> ReturnType { - var oldValue: OmniBLEPumpManagerState! - var returnType: ReturnType! - var shouldNotifyStatusUpdate = false - var oldStatus: PumpManagerStatus? - - let newValue = lockedState.mutate { (state) in - oldValue = state - let oldStatusEvaluationDate = state.lastStatusChange - let oldHighlight = buildPumpStatusHighlight(for: oldValue, andDate: oldStatusEvaluationDate) - oldStatus = status(for: oldValue) - - returnType = changes(&state) - - let newStatusEvaluationDate = Date() - let newStatus = status(for: state) - let newHighlight = buildPumpStatusHighlight(for: state, andDate: newStatusEvaluationDate) - - if oldStatus != newStatus || oldHighlight != newHighlight { - shouldNotifyStatusUpdate = true - state.lastStatusChange = newStatusEvaluationDate - } - } - - if oldValue.podState != newValue.podState { - podStateObservers.forEach { (observer) in - observer.podStateDidUpdate(newValue.podState) - } - - if oldValue.podState?.lastInsulinMeasurements?.reservoirLevel != newValue.podState?.lastInsulinMeasurements?.reservoirLevel { - if let lastInsulinMeasurements = newValue.podState?.lastInsulinMeasurements, - let reservoirLevel = lastInsulinMeasurements.reservoirLevel, - reservoirLevel != Pod.reservoirLevelAboveThresholdMagicNumber - { - self.pumpDelegate.notify({ (delegate) in - self.log.info("DU: updating reservoir level %{public}@", String(describing: reservoirLevel)) - delegate?.pumpManager(self, didReadReservoirValue: reservoirLevel, at: lastInsulinMeasurements.validTime) { _ in } - }) - } - } - } - - // Ideally we ensure that oldValue.rawValue != newValue.rawValue, but the types aren't - // defined as equatable - pumpDelegate.notify { (delegate) in - delegate?.pumpManagerDidUpdateState(self) - } - - if let oldStatus = oldStatus, shouldNotifyStatusUpdate { - notifyStatusObservers(oldStatus: oldStatus) - } - - return returnType - } - - private let lockedState: Locked - - private let statusObservers = WeakSynchronizedSet() - - private func notifyStatusObservers(oldStatus: PumpManagerStatus) { - let status = self.status - pumpDelegate.notify { (delegate) in - delegate?.pumpManager(self, didUpdate: status, oldStatus: oldStatus) - } - statusObservers.forEach { (observer) in - observer.pumpManager(self, didUpdate: status, oldStatus: oldStatus) - } - } - - private func logDeviceCommunication(_ message: String, type: DeviceLogEntryType = .send) { - let podAddress = String(format: "%04X", self.state.podId) - // Not dispatching here; if delegate queue is blocked, timestamps will be delayed - self.pumpDelegate.delegate?.deviceManager(self, logEventForDeviceIdentifier: podAddress, type: type, message: message, completion: nil) - } - - // Not persisted - var provideHeartbeat: Bool = false - - private var lastHeartbeat: Date = .distantPast - - public func setMustProvideBLEHeartbeat(_ mustProvideBLEHeartbeat: Bool) { - provideHeartbeat = mustProvideBLEHeartbeat - } - - private func issueHeartbeatIfNeeded() { - if self.provideHeartbeat, dateGenerator().timeIntervalSince(lastHeartbeat) > .minutes(2) { - self.pumpDelegate.notify { (delegate) in - delegate?.pumpManagerBLEHeartbeatDidFire(self) - } - self.lastHeartbeat = Date() - } - } - - var isConnected: Bool { - podComms.manager?.peripheral.state == .connected - } - - func omnipodPeripheralDidConnect(manager: PeripheralManager) { - logDeviceCommunication("Pod connected \(manager.peripheral.identifier.uuidString)", type: .connection) - notifyPodConnectionStateDidChange(isConnected: true) - } - - func omnipodPeripheralDidDisconnect(peripheral: CBPeripheral, error: Error?) { - logDeviceCommunication("Pod disconnected \(peripheral.identifier.uuidString) \(String(describing: error))", type: .connection) - notifyPodConnectionStateDidChange(isConnected: false) - } - - func omnipodPeripheralDidFailToConnect(peripheral: CBPeripheral, error: Error?) { - logDeviceCommunication("Pod failed to connect \(peripheral.identifier.uuidString), \(String(describing: error))", type: .connection) - } - - func omnipodPeripheralWasRestored(manager: PeripheralManager) { - logDeviceCommunication("Pod peripheral was restored \(manager.peripheral.identifier.uuidString))", type: .connection) - notifyPodConnectionStateDidChange(isConnected: manager.peripheral.state == .connected) - } - - func notifyPodConnectionStateDidChange(isConnected: Bool) { - podStateObservers.forEach { (observer) in - observer.podConnectionStateDidChange(isConnected: isConnected) - } - } - - private let pumpDelegate = WeakSynchronizedDelegate() - - public let log = OSLog(category: "OmniBLEPumpManager") - - private var lastLoopRecommendation: Date? - - // MARK: - CustomDebugStringConvertible - - public var debugDescription: String { - let lines = [ - "## OmniBLEPumpManager", - "provideHeartbeat: \(provideHeartbeat)", - "connected: \(isConnected)", - "", - "podComms: \(String(reflecting: podComms))", - "statusObservers.count: \(statusObservers.cleanupDeallocatedElements().count)", - "status: \(String(describing: status))", - "", - "podStateObservers.count: \(podStateObservers.cleanupDeallocatedElements().count)", - "state: \(String(reflecting: state))", - ] - return lines.joined(separator: "\n") - } -} - -extension OmniBLEPumpManager { - // MARK: - PodStateObserver - - public func addPodStateObserver(_ observer: PodStateObserver, queue: DispatchQueue) { - podStateObservers.insert(observer, queue: queue) - } - - public func removePodStateObserver(_ observer: PodStateObserver) { - podStateObservers.removeElement(observer) - } - - private func status(for state: OmniBLEPumpManagerState) -> PumpManagerStatus { - return PumpManagerStatus( - timeZone: state.timeZone, - device: device(for: state), - pumpBatteryChargeRemaining: nil, - basalDeliveryState: basalDeliveryState(for: state), - bolusState: bolusState(for: state), - insulinType: state.insulinType, - deliveryIsUncertain: state.podState?.needsCommsRecovery == true - ) - } - - private func device(for state: OmniBLEPumpManagerState) -> HKDevice { - if let podState = state.podState { - return HKDevice( - name: managerIdentifier, - manufacturer: "Insulet", - model: "Dash", - hardwareVersion: String(podState.productId), - firmwareVersion: podState.firmwareVersion + " " + podState.bleFirmwareVersion, - softwareVersion: String(OmniBLEVersionNumber), - localIdentifier: String(format:"%04X", podState.address), - udiDeviceIdentifier: nil - ) - } else { - return HKDevice( - name: managerIdentifier, - manufacturer: "Insulet", - model: "Dash", - hardwareVersion: nil, - firmwareVersion: nil, - softwareVersion: String(OmniBLEVersionNumber), - localIdentifier: nil, - udiDeviceIdentifier: nil - ) - } - } - - private func basalDeliveryState(for state: OmniBLEPumpManagerState) -> PumpManagerStatus.BasalDeliveryState { - guard let podState = state.podState else { - return .active(.distantPast) - } - - switch podCommState(for: state) { - case .fault: - return .active(.distantPast) - default: - break - } - - switch state.suspendEngageState { - case .engaging: - return .suspending - case .disengaging: - return .resuming - case .stable: - break - } - - switch state.tempBasalEngageState { - case .engaging: - return .initiatingTempBasal - case .disengaging: - return .cancelingTempBasal - case .stable: - if let tempBasal = podState.unfinalizedTempBasal { - return .tempBasal(DoseEntry(tempBasal)) - } - switch podState.suspendState { - case .resumed(let date): - return .active(date) - case .suspended(let date): - return .suspended(date) - } - } - } - - private func bolusState(for state: OmniBLEPumpManagerState) -> PumpManagerStatus.BolusState { - guard let podState = state.podState else { - return .noBolus - } - - switch state.bolusEngageState { - case .engaging: - return .initiating - case .disengaging: - return .canceling - case .stable: - if let bolus = podState.unfinalizedBolus { - return .inProgress(DoseEntry(bolus)) - } - } - return .noBolus - } - - // Returns true if there an unfinishedDose for a manual bolus (independent of whether it is finished) - private var hasUnfinalizedManualBolus: Bool { - if let automatic = state.podState?.unfinalizedBolus?.automatic, !automatic { - return true - } - return false - } - - // Returns true if there an unfinishedDose for a manual temp basal (independent of whether it is finished) - private var hasUnfinalizedManualTempBasal: Bool { - if let automatic = state.podState?.unfinalizedTempBasal?.automatic, !automatic { - return true - } - return false - } - - - private var podTime: TimeInterval { - get { - guard let podState = state.podState else { - return 0 - } - let elapsed = -(podState.podTimeUpdated?.timeIntervalSinceNow ?? 0) - let podActiveTime = podState.podTime + elapsed - return podActiveTime - } - } - - // Returns a suitable beep command MessageBlock based the current beep preferences and - // whether there is an unfinializedDose for a manual temp basal &/or a manual bolus. - private func beepMessageBlock(beepType: BeepType) -> MessageBlock? { - guard self.beepPreference.shouldBeepForManualCommand && !self.silencePod else { - return nil - } - - // Enable temp basal & basal completion beeps if there is a cooresponding manual unfinalizedDose - let beepMessageBlock = BeepConfigCommand( - beepType: beepType, - tempBasalCompletionBeep: self.hasUnfinalizedManualTempBasal, - bolusCompletionBeep: self.hasUnfinalizedManualBolus - ) - - return beepMessageBlock - } - - private func podCommState(for state: OmniBLEPumpManagerState) -> PodCommState { - guard let podState = state.podState else { - return .noPod - } - guard podState.fault == nil else { - return .fault(podState.fault!) - } - - if podState.isActive { - return .active - } else if !podState.isSetupComplete { - return .activating - } - return .deactivating - } - - public var podCommState: PodCommState { - return podCommState(for: state) - } - - public var podActivatedAt: Date? { - return state.podState?.activatedAt - } - - public var podExpiresAt: Date? { - return state.podState?.expiresAt - } - - public var hasActivePod: Bool { - return state.hasActivePod - } - - public var hasSetupPod: Bool { - return state.hasSetupPod - } - - // If time remaining is negative, the pod has been expired for that amount of time. - public var podTimeRemaining: TimeInterval? { - guard let expiresAt = state.podState?.expiresAt else { return nil } - return expiresAt.timeIntervalSince(dateGenerator()) - } - - private var shouldWarnPodEOL: Bool { - let eolDisplayActiveTime = Pod.timeRemainingWarningThreshold + (state.scheduledExpirationReminderOffset ?? 0.0) - guard let podTimeRemaining = podTimeRemaining, - podTimeRemaining > 0 && podTimeRemaining <= eolDisplayActiveTime else - { - return false - } - - return true - } - - public var durationBetweenLastPodCommAndActivation: TimeInterval? { - guard let lastPodCommDate = state.podState?.lastInsulinMeasurements?.validTime, - let activationTime = podActivatedAt else - { - return nil - } - - return lastPodCommDate.timeIntervalSince(activationTime) - } - - public var beepPreference: BeepPreference { - get { - return state.confirmationBeeps - } - } - - // Thread-safe - public var silencePod: Bool { - get { - return state.silencePod - } - } - - // From last status response - public var reservoirLevel: ReservoirLevel? { - return state.reservoirLevel - } - - public var podTotalDelivery: HKQuantity? { - guard let delivery = state.podState?.lastInsulinMeasurements?.delivered else { - return nil - } - return HKQuantity(unit: .internationalUnit(), doubleValue: delivery) - } - - public var lastStatusDate: Date? { - guard let date = state.podState?.lastInsulinMeasurements?.validTime else { - return nil - } - return date - } - - public var defaultExpirationReminderOffset: TimeInterval { - set { - setState { (state) in - state.defaultExpirationReminderOffset = newValue - } - } - get { - state.defaultExpirationReminderOffset - } - } - - public var lowReservoirReminderValue: Double { - set { - setState { (state) in - state.lowReservoirReminderValue = newValue - } - } - get { - state.lowReservoirReminderValue - } - } - - public var podAttachmentConfirmed: Bool { - set { - setState { (state) in - state.podAttachmentConfirmed = newValue - } - } - get { - state.podAttachmentConfirmed - } - } - - public var initialConfigurationCompleted: Bool { - set { - setState { (state) in - state.initialConfigurationCompleted = newValue - } - } - get { - state.initialConfigurationCompleted - } - } - - public var expiresAt: Date? { - return state.podState?.expiresAt - } - - public func buildPumpStatusHighlight(for state: OmniBLEPumpManagerState, andDate date: Date = Date()) -> PumpStatusHighlight? { - if state.podState?.needsCommsRecovery == true { - return PumpStatusHighlight( - localizedMessage: LocalizedString("Comms Issue", comment: "Status highlight that delivery is uncertain."), - imageName: "exclamationmark.circle.fill", - state: .critical) - } - - switch podCommState(for: state) { - case .activating: - return PumpStatusHighlight( - localizedMessage: LocalizedString("Finish Pairing", comment: "Status highlight that when pod is activating."), - imageName: "exclamationmark.circle.fill", - state: .warning) - case .deactivating: - return PumpStatusHighlight( - localizedMessage: LocalizedString("Finish Deactivation", comment: "Status highlight that when pod is deactivating."), - imageName: "exclamationmark.circle.fill", - state: .warning) - case .noPod: - return PumpStatusHighlight( - localizedMessage: LocalizedString("No Pod", comment: "Status highlight that when no pod is paired."), - imageName: "exclamationmark.circle.fill", - state: .warning) - case .fault(let detail): - var message: String - switch detail.faultEventCode.faultType { - case .reservoirEmpty: - message = LocalizedString("No Insulin", comment: "Status highlight message for emptyReservoir alarm.") - case .exceededMaximumPodLife80Hrs: - message = LocalizedString("Pod Expired", comment: "Status highlight message for podExpired alarm.") - case .occluded: - message = LocalizedString("Pod Occlusion", comment: "Status highlight message for occlusion alarm.") - default: - message = LocalizedString("Pod Error", comment: "Status highlight message for other alarm.") - } - return PumpStatusHighlight( - localizedMessage: message, - imageName: "exclamationmark.circle.fill", - state: .critical) - case .active: - if let reservoirPercent = state.reservoirLevel?.percentage, reservoirPercent == 0 { - return PumpStatusHighlight( - localizedMessage: LocalizedString("No Insulin", comment: "Status highlight that a pump is out of insulin."), - imageName: "exclamationmark.circle.fill", - state: .critical) - } else if state.podState?.isSuspended == true { - return PumpStatusHighlight( - localizedMessage: LocalizedString("Insulin Suspended", comment: "Status highlight that insulin delivery was suspended."), - imageName: "pause.circle.fill", - state: .warning) - } else if date.timeIntervalSince(state.lastPumpDataReportDate ?? .distantPast) > .minutes(12) { - return PumpStatusHighlight( - localizedMessage: LocalizedString("Signal Loss", comment: "Status highlight when communications with the pod haven't happened recently."), - imageName: "exclamationmark.circle.fill", - state: .critical) - } else if isRunningManualTempBasal(for: state) { - return PumpStatusHighlight( - localizedMessage: LocalizedString("Manual Basal", comment: "Status highlight when manual temp basal is running."), - imageName: "exclamationmark.circle.fill", - state: .warning) - } - return nil - } - } - - public func isRunningManualTempBasal(for state: OmniBLEPumpManagerState) -> Bool { - if let tempBasal = state.podState?.unfinalizedTempBasal, !tempBasal.isFinished(), !tempBasal.automatic { - return true - } - return false - } - - public var reservoirLevelHighlightState: ReservoirLevelHighlightState? { - guard let reservoirLevel = reservoirLevel else { - return nil - } - - switch reservoirLevel { - case .aboveThreshold: - return .normal - case .valid(let value): - if value > state.lowReservoirReminderValue { - return .normal - } else if value > 0 { - return .warning - } else { - return .critical - } - } - } - - public func buildPumpLifecycleProgress(for state: OmniBLEPumpManagerState) -> PumpLifecycleProgress? { - switch podCommState { - case .active: - if shouldWarnPodEOL, - let podTimeRemaining = podTimeRemaining - { - let percentCompleted = max(0, min(1, (1 - (podTimeRemaining / Pod.nominalPodLife)))) - return PumpLifecycleProgress(percentComplete: percentCompleted, progressState: .warning) - } else if let podTimeRemaining = podTimeRemaining, podTimeRemaining <= 0 { - // Pod is expired - return PumpLifecycleProgress(percentComplete: 1, progressState: .critical) - } - return nil - case .fault(let detail): - if detail.faultEventCode.faultType == .exceededMaximumPodLife80Hrs { - return PumpLifecycleProgress(percentComplete: 100, progressState: .critical) - } else { - if shouldWarnPodEOL, - let durationBetweenLastPodCommAndActivation = durationBetweenLastPodCommAndActivation - { - let percentCompleted = max(0, min(1, durationBetweenLastPodCommAndActivation / Pod.nominalPodLife)) - return PumpLifecycleProgress(percentComplete: percentCompleted, progressState: .dimmed) - } - } - return nil - case .noPod, .activating, .deactivating: - return nil - } - } - - - // MARK: - Pod comms - - private func prepForNewPod() { - - setState { state in - state.previousPodState = state.podState - - if state.controllerId == CONTROLLER_ID { - // Switch from using the common fixed controllerId to a created semi-unique one - state.controllerId = createControllerId() - state.podId = state.controllerId + 1 - self.log.info("Switched controllerId from %x to %x", CONTROLLER_ID, state.controllerId) - } else { - // Already have a created controllerId, just need to advance podId for the next pod - let lastPodId = state.podId - state.podId = nextPodId(lastPodId: lastPodId) - self.log.info("Advanced podId from %x to %x", lastPodId, state.podId) - } - } - self.podComms.prepForNewPod(myId: self.state.controllerId, podId: self.state.podId) - } - - public func forgetPod(completion: @escaping () -> Void) { - - self.podComms.forgetPod() - - if let dosesToStore = state.podState?.dosesToStore { - store(doses: dosesToStore, completion: { error in - self.setState({ (state) in - if error != nil { - state.unstoredDoses.append(contentsOf: dosesToStore) - } - state.alertsWithPendingAcknowledgment = [] - }) - self.prepForNewPod() - completion() - }) - } else { - prepForNewPod() - completion() - } - } - - - // MARK: Testing - - #if targetEnvironment(simulator) - private func jumpStartPod(lotNo: UInt32, lotSeq: UInt32, fault: DetailedStatus? = nil, startDate: Date? = nil, mockFault: Bool) { - let start = startDate ?? Date() - let fakeLtk = Data(hexadecimalString: "fedcba98765432100123456789abcdef")! - var podState = PodState(address: state.podId, ltk: fakeLtk, - firmwareVersion: "jumpstarted", bleFirmwareVersion: "jumpstarted", - lotNo: lotNo, lotSeq: lotSeq, productId: dashProductId, - bleIdentifier: "0000-0000", insulinType: insulinType ?? .novolog) - - podState.setupProgress = .podPaired - podState.activatedAt = start - podState.expiresAt = start + .hours(72) - - let fault = mockFault ? try? DetailedStatus(encodedData: Data(hexadecimalString: "020f0000000900345c000103ff0001000005ae056029")!) : nil - podState.fault = fault - - self.podComms = PodComms(podState: podState, myId: state.controllerId, podId: state.podId) - - setState({ (state) in - state.updatePodStateFromPodComms(podState) - state.scheduledExpirationReminderOffset = state.defaultExpirationReminderOffset - }) - } - #endif - - // MARK: - Pairing - - func connectToNewPod(completion: @escaping (Result) -> Void) { - podComms.connectToNewPod { result in - if case .success = result { - self.pumpDelegate.notify { (delegate) in - delegate?.pumpManagerPumpWasReplaced(self) - } - } - completion(result) - } - } - - // Called on the main thread - public func pairAndPrime(completion: @escaping (PumpManagerResult) -> Void) { - #if targetEnvironment(simulator) - // If we're in the simulator, create a mock PodState - let mockFaultDuringPairing = false - let mockCommsErrorDuringPairing = false - DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + .seconds(2)) { - self.jumpStartPod(lotNo: 135601809, lotSeq: 0800525, mockFault: mockFaultDuringPairing) - let fault: DetailedStatus? = self.setStateWithResult({ (state) in - var podState = state.podState - podState?.setupProgress = .priming - state.updatePodStateFromPodComms(podState) - return state.podState?.fault - }) - if let fault = fault { - completion(.failure(PumpManagerError.deviceState(PodCommsError.podFault(fault: fault)))) - } else if mockCommsErrorDuringPairing { - completion(.failure(PumpManagerError.communication(PodCommsError.noResponse))) - } else { - let mockPrimeDuration = TimeInterval(.seconds(3)) - completion(.success(mockPrimeDuration)) - } - } - #else - let primeSession = { (result: PodComms.SessionRunResult) in - switch result { - case .success(let session): - // We're on the session queue - session.assertOnSessionQueue() - - self.log.default("Beginning pod prime") - - // Clean up any previously un-stored doses if needed - let unstoredDoses = self.state.unstoredDoses - if self.store(doses: unstoredDoses, in: session) { - self.setState({ (state) in - state.unstoredDoses.removeAll() - }) - } - - do { - let primeFinishedAt = try session.prime() - completion(.success(primeFinishedAt)) - } catch let error { - completion(.failure(.communication(error as? LocalizedError))) - } - case .failure(let error): - completion(.failure(.communication(error))) - } - } - - let needsPairing = setStateWithResult({ (state) -> Bool in - guard let podState = state.podState else { - return true // Needs pairing - } - - // Return true if not yet paired - return podState.setupProgress.isPaired == false - }) - - if needsPairing { - - self.log.default("Pairing pod before priming") - - guard let insulinType = insulinType else { - completion(.failure(.configuration(OmniBLEPumpManagerError.insulinTypeNotConfigured))) - return - } - - connectToNewPod(completion: { result in - switch result { - case .failure(let error): - completion(.failure(.communication(error as? LocalizedError))) - case .success: - self.podComms.pairAndSetupPod(timeZone: .currentFixed, insulinType: insulinType, messageLogger: self) - { (result) in - - // Calls completion - primeSession(result) - } - - } - - }) - } else { - self.log.default("Pod already paired. Continuing.") - - self.podComms.runSession(withName: "Prime pod") { (result) in - // Calls completion - primeSession(result) - } - } - #endif - } - - // Called on the main thread - public func insertCannula(completion: @escaping (Result) -> Void) { - - #if targetEnvironment(simulator) - let mockDelay = TimeInterval(seconds: 3) - let mockFaultDuringInsertCannula = false - DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + mockDelay) { - let result = self.setStateWithResult({ (state) -> Result in - if mockFaultDuringInsertCannula { - let fault = try! DetailedStatus(encodedData: Data(hexadecimalString: "020d0000000e00c36a020703ff020900002899080082")!) - var podState = state.podState - podState?.fault = fault - state.updatePodStateFromPodComms(podState) - return .failure(OmniBLEPumpManagerError.communication(PodCommsError.podFault(fault: fault))) - } - - // Mock success - var podState = state.podState - podState?.setupProgress = .completed - state.updatePodStateFromPodComms(podState) - return .success(mockDelay) - }) - - completion(result) - } - #else - let preError = setStateWithResult({ (state) -> OmniBLEPumpManagerError? in - guard let podState = state.podState, podState.readyForCannulaInsertion else - { - return .notReadyForCannulaInsertion - } - - state.scheduledExpirationReminderOffset = state.defaultExpirationReminderOffset - - guard podState.setupProgress.needsCannulaInsertion else { - return .podAlreadyPaired - } - - return nil - }) - - if let error = preError { - completion(.failure(.state(error))) - return - } - - let timeZone = self.state.timeZone - - self.podComms.runSession(withName: "Insert cannula") { (result) in - switch result { - case .success(let session): - do { - if self.state.podState?.setupProgress.needsInitialBasalSchedule == true { - let scheduleOffset = timeZone.scheduleOffset(forDate: Date()) - try session.programInitialBasalSchedule(self.state.basalSchedule, scheduleOffset: scheduleOffset) - - session.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: session) - } - } - - let expirationReminderTime = Pod.nominalPodLife - self.state.defaultExpirationReminderOffset - let alerts: [PodAlert] = [ - .expirationReminder(offset: self.podTime, absAlertTime: self.state.defaultExpirationReminderOffset > 0 ? expirationReminderTime : 0), - .lowReservoir(units: self.state.lowReservoirReminderValue) - ] - - let finishWait = try session.insertCannula(optionalAlerts: alerts, silent: self.silencePod) - completion(.success(finishWait)) - } catch let error { - completion(.failure(.communication(error))) - } - case .failure(let error): - completion(.failure(.communication(error))) - } - } - #endif - } - - public func checkCannulaInsertionFinished(completion: @escaping (OmniBLEPumpManagerError?) -> Void) { - #if targetEnvironment(simulator) - completion(nil) - #else - self.podComms.runSession(withName: "Check cannula insertion finished") { (result) in - switch result { - case .success(let session): - do { - try session.checkInsertionCompleted() - completion(nil) - } catch let error { - self.log.error("Failed to fetch pod status: %{public}@", String(describing: error)) - completion(.communication(error)) - } - case .failure(let error): - self.log.error("Failed to fetch pod status: %{public}@", String(describing: error)) - completion(.communication(error)) - } - } - #endif - } - - public func getPodStatus(completion: ((_ result: PumpManagerResult) -> Void)? = nil) { - guard state.hasActivePod else { - completion?(.failure(PumpManagerError.configuration(OmniBLEPumpManagerError.noPodPaired))) - return - } - - podComms.runSession(withName: "Get pod status") { (result) in - do { - switch result { - case .success(let session): - let status = try session.getStatus() - session.dosesForStorage({ (doses) -> Bool in - self.store(doses: doses, in: session) - }) - completion?(.success(status)) - case .failure(let error): - self.evaluateStatus() - throw error - } - self.issueHeartbeatIfNeeded() - } catch let error { - completion?(.failure(.communication(error as? LocalizedError))) - self.log.error("Failed to fetch pod status: %{public}@", String(describing: error)) - } - } - } - - public func getDetailedStatus(completion: ((_ result: PumpManagerResult) -> Void)? = nil) { - - // use hasSetupPod here instead of hasActivePod as DetailedStatus can be read with a faulted Pod - guard self.hasSetupPod else { - completion?(.failure(PumpManagerError.configuration(OmniBLEPumpManagerError.noPodPaired))) - return - } - - podComms.runSession(withName: "Get detailed status") { (result) in - do { - switch result { - case .success(let session): - let beepBlock = self.beepMessageBlock(beepType: .bipBip) - let detailedStatus = try session.getDetailedStatus(beepBlock: beepBlock) - session.dosesForStorage({ (doses) -> Bool in - self.store(doses: doses, in: session) - }) - completion?(.success(detailedStatus)) - case .failure(let error): - throw error - } - } catch let error { - completion?(.failure(.communication(error as? LocalizedError))) - self.log.error("Failed to fetch detailed status: %{public}@", String(describing: error)) - } - } - } - - - // MARK: - Pump Commands - - public func acknowledgePodAlerts(_ alertsToAcknowledge: AlertSet, completion: @escaping (_ alerts: AlertSet?) -> Void) { - guard self.hasActivePod else { - completion(nil) - return - } - - self.podComms.runSession(withName: "Acknowledge Alerts") { (result) in - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure: - completion(nil) - return - } - - do { - let beepBlock = self.beepMessageBlock(beepType: .bipBip) - let alerts = try session.acknowledgeAlerts(alerts: alertsToAcknowledge, beepBlock: beepBlock) - completion(alerts) - } catch { - completion(nil) - } - } - } - - public func setTime(completion: @escaping (OmniBLEPumpManagerError?) -> Void) { - - guard state.hasActivePod else { - completion(OmniBLEPumpManagerError.noPodPaired) - return - } - - guard state.podState?.unfinalizedBolus?.isFinished() != false else { - completion(.state(PodCommsError.unfinalizedBolus)) - return - } - - let timeZone = TimeZone.currentFixed - self.podComms.runSession(withName: "Set time zone") { (result) in - switch result { - case .success(let session): - do { - let beep = self.silencePod ? false : self.beepPreference.shouldBeepForManualCommand - let _ = try session.setTime(timeZone: timeZone, basalSchedule: self.state.basalSchedule, date: Date(), acknowledgementBeep: beep) - self.clearSuspendReminder() - self.setState { (state) in - state.timeZone = timeZone - } - completion(nil) - } catch let error { - completion(.communication(error)) - } - case .failure(let error): - completion(.communication(error)) - } - } - } - - public func setBasalSchedule(_ schedule: BasalSchedule, completion: @escaping (Error?) -> Void) { - let shouldContinue = setStateWithResult({ (state) -> PumpManagerResult in - guard state.hasActivePod else { - // If there's no active pod yet, save the basal schedule anyway - state.basalSchedule = schedule - return .success(false) - } - - guard state.podState?.unfinalizedBolus?.isFinished() != false else { - return .failure(.deviceState(PodCommsError.unfinalizedBolus)) - } - - return .success(true) - }) - - switch shouldContinue { - case .success(true): - break - case .success(false): - completion(nil) - return - case .failure(let error): - completion(error) - return - } - - let timeZone = self.state.timeZone - - self.podComms.runSession(withName: "Save Basal Profile") { (result) in - do { - switch result { - case .success(let session): - let scheduleOffset = timeZone.scheduleOffset(forDate: Date()) - let result = session.cancelDelivery(deliveryType: .all) - switch result { - case .certainFailure(let error): - throw error - case .unacknowledged(let error): - throw error - case .success: - break - } - let beep = self.silencePod ? false : self.beepPreference.shouldBeepForManualCommand - let _ = try session.setBasalSchedule(schedule: schedule, scheduleOffset: scheduleOffset, acknowledgementBeep: beep) - self.clearSuspendReminder() - - self.setState { (state) in - state.basalSchedule = schedule - } - completion(nil) - case .failure(let error): - throw error - } - } catch let error { - self.log.error("Save basal profile failed: %{public}@", String(describing: error)) - completion(error) - } - } - } - - // Called on the main thread. - // The UI is responsible for serializing calls to this method; - // it does not handle concurrent calls. - public func deactivatePod(completion: @escaping (OmniBLEPumpManagerError?) -> Void) { - #if targetEnvironment(simulator) - DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + .seconds(2)) { - completion(nil) - } - #else - guard self.state.podState != nil else { - completion(OmniBLEPumpManagerError.noPodPaired) - return - } - - self.podComms.runSession(withName: "Deactivate pod") { (result) in - switch result { - case .success(let session): - do { - try session.deactivatePod() - completion(nil) - } catch let error { - completion(OmniBLEPumpManagerError.communication(error)) - } - case .failure(let error): - completion(OmniBLEPumpManagerError.communication(error)) - } - } - #endif - } - - public func playTestBeeps(completion: @escaping (Error?) -> Void) { - guard self.hasActivePod else { - completion(OmniBLEPumpManagerError.noPodPaired) - return - } - guard state.podState?.unfinalizedBolus?.scheduledCertainty == .uncertain || state.podState?.unfinalizedBolus?.isFinished() != false else { - self.log.info("Skipping Play Test Beeps due to bolus still in progress.") - completion(PodCommsError.unfinalizedBolus) - return - } - - self.podComms.runSession(withName: "Play Test Beeps") { (result) in - switch result { - case .success(let session): - // preserve the pod's completion beep state which gets reset playing beeps - let enabled: Bool = self.silencePod ? false : self.beepPreference.shouldBeepForManualCommand - let result = session.beepConfig( - beepType: .bipBeepBipBeepBipBeepBipBeep, - tempBasalCompletionBeep: enabled && self.hasUnfinalizedManualTempBasal, - bolusCompletionBeep: enabled && self.hasUnfinalizedManualBolus - ) - - switch result { - case .success: - completion(nil) - case .failure(let error): - completion(error) - } - case .failure(let error): - completion(error) - } - } - } - - public func readPulseLog(completion: @escaping (Result) -> Void) { - // use hasSetupPod to be able to read pulse log from a faulted Pod - guard self.hasSetupPod else { - completion(.failure(OmniBLEPumpManagerError.noPodPaired)) - return - } - guard state.podState?.isFaulted == true || state.podState?.unfinalizedBolus?.scheduledCertainty == .uncertain || state.podState?.unfinalizedBolus?.isFinished() != false else - { - self.log.info("Skipping Read Pulse Log due to bolus still in progress.") - completion(.failure(PodCommsError.unfinalizedBolus)) - return - } - - self.podComms.runSession(withName: "Read Pulse Log") { (result) in - switch result { - case .success(let session): - do { - // read the most recent 50 entries from the pulse log - let beepBlock = self.beepMessageBlock(beepType: .bipBeeeeep) - let podInfoResponse = try session.readPodInfo(podInfoResponseSubType: .pulseLogRecent, beepBlock: beepBlock) - guard let podInfoPulseLogRecent = podInfoResponse.podInfo as? PodInfoPulseLogRecent else { - self.log.error("Unable to decode PulseLogRecent: %s", String(describing: podInfoResponse)) - completion(.failure(PodCommsError.unexpectedResponse(response: .podInfoResponse))) - return - } - let lastPulseNumber = Int(podInfoPulseLogRecent.indexLastEntry) - let str = pulseLogString(pulseLogEntries: podInfoPulseLogRecent.pulseLog, lastPulseNumber: lastPulseNumber) - completion(.success(str)) - } catch let error { - completion(.failure(error)) - } - case .failure(let error): - completion(.failure(error)) - } - } - } - - public func setConfirmationBeeps(newPreference: BeepPreference, completion: @escaping (OmniBLEPumpManagerError?) -> Void) { - - // If there isn't an active pod or the pod is currently silenced, - // just need to update the internal state without any pod commands. - let name = String(format: "Set Beep Preference to %@", String(describing: newPreference)) - if !self.hasActivePod || self.silencePod { - self.log.default("%{public}@ for internal state only", name) - self.setState { state in - state.confirmationBeeps = newPreference - } - completion(nil) - return - } - - self.podComms.runSession(withName: name) { (result) in - switch result { - case .success(let session): - // enable/disable Pod completion beep state for any unfinalized manual insulin delivery - let enabled = newPreference.shouldBeepForManualCommand - let beepType: BeepType = enabled ? .bipBip : .noBeepNonCancel - let result = session.beepConfig( - beepType: beepType, - tempBasalCompletionBeep: enabled && self.hasUnfinalizedManualTempBasal, - bolusCompletionBeep: enabled && self.hasUnfinalizedManualBolus - ) - - switch result { - case .success: - self.setState { state in - state.confirmationBeeps = newPreference - } - completion(nil) - case .failure(let error): - completion(.communication(error)) - } - case .failure(let error): - completion(.communication(error)) - } - } - } - - // Reconfigures all active alerts in pod to be silent or not as well as sets/clears the - // self.silencePod state variable which silences all confirmation beeping when enabled. - public func setSilencePod(silencePod: Bool, completion: @escaping (OmniBLEPumpManagerError?) -> Void) { - - let name = String(format: "%@ Pod", silencePod ? "Silence" : "Unsilence") - // allow Silence Pod changes without an active Pod - guard self.hasActivePod else { - self.log.default("%{public}@", name) - self.setState { state in - state.silencePod = silencePod - } - completion(nil) - return - } - - self.podComms.runSession(withName: name) { (result) in - - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(.communication(error)) - return - } - - guard let configuredAlerts = self.state.podState?.configuredAlerts, - let activeAlertSlots = self.state.podState?.activeAlertSlots, - let reservoirLevel = self.state.podState?.lastInsulinMeasurements?.reservoirLevel?.rawValue else - { - self.log.error("Missing podState") // should never happen - completion(OmniBLEPumpManagerError.noPodPaired) - return - } - - let beepBlock: MessageBlock? - if !self.beepPreference.shouldBeepForManualCommand { - // No enabled completion beeps to worry about for any in-progress manual delivery - beepBlock = nil - } else if silencePod { - // Disable completion beeps for any in-progress manual delivery w/o beeping - beepBlock = BeepConfigCommand(beepType: .noBeepNonCancel) - } else { - // Emit a confirmation beep and enable completion beeps for any in-progress manual delivery - beepBlock = BeepConfigCommand( - beepType: .bipBip, - tempBasalCompletionBeep: self.hasUnfinalizedManualTempBasal, - bolusCompletionBeep: self.hasUnfinalizedManualBolus - ) - } - - let podAlerts = regeneratePodAlerts(silent: silencePod, configuredAlerts: configuredAlerts, activeAlertSlots: activeAlertSlots, currentPodTime: self.podTime, currentReservoirLevel: reservoirLevel) - do { - // Since non-responsive pod comms are currently only resolved for insulin related commands, - // it's possible that a previous pod alert was successfully configured will lose its response - // and thus the alert won't get reset when reconfiguring pod alerts with a new silence pod state. - // So acknowledge all alerts now to be absolutely sure that no triggered alert will be forgotten. - try session.configureAlerts(podAlerts, acknowledgeAll: true, beepBlock: beepBlock) - self.setState { (state) in - state.silencePod = silencePod - } - completion(nil) - } catch { - self.log.error("Configure alerts %{public}@ failed: %{public}@", String(describing: podAlerts), String(describing: error)) - completion(.communication(error)) - } - } - } -} - -// MARK: - PumpManager -extension OmniBLEPumpManager: PumpManager { - - public static var onboardingMaximumBasalScheduleEntryCount: Int { - return Pod.maximumBasalScheduleEntryCount - } - - public static var onboardingSupportedMaximumBolusVolumes: [Double] { - return onboardingSupportedBolusVolumes - } - - public var supportedMaximumBolusVolumes: [Double] { - return supportedBolusVolumes - } - - public static var onboardingSupportedBolusVolumes: [Double] { - // 0.05 units for rates between 0.05-30U - // 0 is not a supported bolus volume - return (1...600).map { Double($0) / Double(Pod.pulsesPerUnit) } - } - - public var supportedBolusVolumes: [Double] { - // 0.05 units for rates between 0.05-30U - // 0 is not a supported bolus volume - return (1...600).map { Double($0) / Double(Pod.pulsesPerUnit) } - } - - public static var onboardingSupportedBasalRates: [Double] { - // 0.05 units for rates between 0.00-30U/hr - // 0 U/hr is a supported scheduled basal rate for Dash, but not for Eros - return (0...600).map { Double($0) / Double(Pod.pulsesPerUnit) } - } - - public var supportedBasalRates: [Double] { - // 0.05 units for rates between 0.00-30U/hr - // 0 U/hr is a supported scheduled basal rate for Dash, but not for Eros - return (0...600).map { Double($0) / Double(Pod.pulsesPerUnit) } - } - - public func roundToSupportedBolusVolume(units: Double) -> Double { - // We do support rounding a 0 U volume to 0 - return supportedBolusVolumes.last(where: { $0 <= units }) ?? 0 - } - - public func roundToSupportedBasalRate(unitsPerHour: Double) -> Double { - // We do support rounding a 0 U/hr rate to 0 - return supportedBasalRates.last(where: { $0 <= unitsPerHour }) ?? 0 - } - - public func estimatedDuration(toBolus units: Double) -> TimeInterval { - TimeInterval(units / Pod.bolusDeliveryRate) - } - - public var maximumBasalScheduleEntryCount: Int { - return Pod.maximumBasalScheduleEntryCount - } - - public var minimumBasalScheduleEntryDuration: TimeInterval { - return Pod.minimumBasalScheduleEntryDuration - } - - public var pumpRecordsBasalProfileStartEvents: Bool { - return false - } - - public var pumpReservoirCapacity: Double { - return Pod.reservoirCapacity - } - - public var isOnboarded: Bool { state.isOnboarded } - - public var insulinType: InsulinType? { - get { - return self.state.insulinType - } - set { - if let insulinType = newValue { - self.setState { (state) in - state.insulinType = insulinType - } - self.podComms.updateInsulinType(insulinType) - } - } - } - - public var lastSync: Date? { - return self.state.podState?.lastInsulinMeasurements?.validTime - } - - public var status: PumpManagerStatus { - // Acquire the lock just once - let state = self.state - - return status(for: state) - } - - public var rawState: PumpManager.RawStateValue { - return state.rawValue - } - - public var pumpManagerDelegate: PumpManagerDelegate? { - get { - return pumpDelegate.delegate - } - set { - pumpDelegate.delegate = newValue - } - } - - public var delegateQueue: DispatchQueue! { - get { - return pumpDelegate.queue - } - set { - pumpDelegate.queue = newValue - } - } - - // MARK: Methods - - public func completeOnboard() { - setState({ (state) in - state.isOnboarded = true - }) - } - - public func suspendDelivery(completion: @escaping (Error?) -> Void) { - let suspendTime: TimeInterval = .minutes(0) // untimed suspend with reminder beeps - suspendDelivery(withSuspendReminders: suspendTime, completion: completion) - } - - // A nil suspendReminder is untimed with no reminders beeps, a suspendReminder of 0 is untimed using reminders beeps, otherwise it - // specifies a suspend duration implemented using an appropriate combination of suspended reminder and suspend time expired beeps. - public func suspendDelivery(withSuspendReminders suspendReminder: TimeInterval? = nil, completion: @escaping (Error?) -> Void) { - guard self.hasActivePod else { - completion(OmniBLEPumpManagerError.noPodPaired) - return - } - - self.podComms.runSession(withName: "Suspend") { (result) in - - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(error) - return - } - - defer { - self.setState({ (state) in - state.suspendEngageState = .stable - }) - } - self.setState({ (state) in - state.suspendEngageState = .engaging - }) - - // Use a beepBlock for the confirmation beep to avoid getting 3 beeps using cancel command beeps! - let beepBlock = self.beepMessageBlock(beepType: .beeeeeep) - let result = session.suspendDelivery(suspendReminder: suspendReminder, silent: self.silencePod, beepBlock: beepBlock) - switch result { - case .certainFailure(let error): - self.log.error("Failed to suspend: %{public}@", String(describing: error)) - completion(error) - case .unacknowledged(let error): - self.log.error("Failed to suspend: %{public}@", String(describing: error)) - completion(error) - case .success: - session.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: session) - } - completion(nil) - } - } - } - - public func resumeDelivery(completion: @escaping (Error?) -> Void) { - guard self.hasActivePod else { - completion(OmniBLEPumpManagerError.noPodPaired) - return - } - - self.podComms.runSession(withName: "Resume") { (result) in - - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(error) - return - } - - defer { - self.setState({ (state) in - state.suspendEngageState = .stable - }) - } - - self.setState({ (state) in - state.suspendEngageState = .disengaging - }) - - do { - let scheduleOffset = self.state.timeZone.scheduleOffset(forDate: Date()) - let beep = self.silencePod ? false : self.beepPreference.shouldBeepForManualCommand - let _ = try session.resumeBasal(schedule: self.state.basalSchedule, scheduleOffset: scheduleOffset, acknowledgementBeep: beep) - self.clearSuspendReminder() - session.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: session) - } - completion(nil) - } catch (let error) { - completion(error) - } - } - } - - fileprivate func clearSuspendReminder() { - self.pumpDelegate.notify { (delegate) in - delegate?.retractAlert(identifier: Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: PumpManagerAlert.suspendEnded(triggeringSlot: nil).alertIdentifier)) - delegate?.retractAlert(identifier: Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: PumpManagerAlert.suspendEnded(triggeringSlot: nil).repeatingAlertIdentifier)) - } - } - - public func addStatusObserver(_ observer: PumpManagerStatusObserver, queue: DispatchQueue) { - statusObservers.insert(observer, queue: queue) - } - - public func removeStatusObserver(_ observer: PumpManagerStatusObserver) { - statusObservers.removeElement(observer) - } - - public func ensureCurrentPumpData(completion: ((Date?) -> Void)?) { - let shouldFetchStatus = setStateWithResult { (state) -> Bool? in - guard state.hasActivePod else { - return nil // No active pod - } - - return state.isPumpDataStale - } - - switch shouldFetchStatus { - case .none: - completion?(lastSync) - return // No active pod - case true?: - log.default("Fetching status because pumpData is too old") - getPodStatus() { (response) in - completion?(self.lastSync) - } - case false?: - log.default("Skipping status update because pumpData is fresh") - completion?(self.lastSync) - silenceAcknowledgedAlerts() - } - } - - - // MARK: - Programming Delivery - - public func enactBolus(units: Double, activationType: BolusActivationType, completion: @escaping (PumpManagerError?) -> Void) { - guard self.hasActivePod else { - completion(.configuration(OmniBLEPumpManagerError.noPodPaired)) - return - } - - // Round to nearest supported volume - let enactUnits = roundToSupportedBolusVolume(units: units) - - let acknowledgementBeep, completionBeep: Bool - if self.silencePod { - acknowledgementBeep = false - completionBeep = false - } else { - acknowledgementBeep = self.beepPreference.shouldBeepForCommand(automatic: activationType.isAutomatic) - completionBeep = beepPreference.shouldBeepForManualCommand && !activationType.isAutomatic - } - - self.podComms.runSession(withName: "Bolus") { (result) in - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(.communication(error)) - return - } - - defer { - self.setState({ (state) in - state.bolusEngageState = .stable - }) - } - self.setState({ (state) in - state.bolusEngageState = .engaging - }) - - if case .some(.suspended) = self.state.podState?.suspendState { - self.log.error("enactBolus: returning pod suspended error for bolus") - completion(.deviceState(PodCommsError.podSuspended)) - return - } - - // Use bits for the program reminder interval (not used by app) - // This trick enables determination, from just the hex messages - // of the log file, whether bolus was manually initiated by the - // user or automatically initiated by app. - // The max possible "reminder" value, 0x3F, would cause the pod to beep - // in 63 minutes if bolus had not completed by then. - let bolusWasAutomaticIndicator: TimeInterval = activationType.isAutomatic ? TimeInterval(minutes: 0x3F) : 0 - - let result = session.bolus(units: enactUnits, automatic: activationType.isAutomatic, acknowledgementBeep: acknowledgementBeep, completionBeep: completionBeep, programReminderInterval: bolusWasAutomaticIndicator) - - switch result { - case .success: - session.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: session) - } - completion(nil) - case .certainFailure(let error): - self.log.error("enactBolus failed: %{public}@", String(describing: error)) - completion(.communication(error)) - case .unacknowledged: - completion(.uncertainDelivery) - } - } - } - - public func cancelBolus(completion: @escaping (PumpManagerResult) -> Void) { - guard self.hasActivePod else { - completion(.failure(.deviceState(OmniBLEPumpManagerError.noPodPaired))) - return - } - - self.podComms.runSession(withName: "Cancel Bolus") { (result) in - - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(.failure(.communication(error))) - return - } - - do { - defer { - self.setState({ (state) in - state.bolusEngageState = .stable - }) - } - self.setState({ (state) in - state.bolusEngageState = .disengaging - }) - - if let bolus = self.state.podState?.unfinalizedBolus, !bolus.isFinished(), bolus.scheduledCertainty == .uncertain { - let status = try session.getStatus() - - if !status.deliveryStatus.bolusing { - completion(.success(nil)) - return - } - } - - // when cancelling a bolus use the built-in type 6 beeeeeep to match PDM if confirmation beeps are enabled - let beepType: BeepType = self.beepPreference.shouldBeepForManualCommand && !self.silencePod ? .beeeeeep : .noBeepCancel - let result = session.cancelDelivery(deliveryType: .bolus, beepType: beepType) - switch result { - case .certainFailure(let error): - throw error - case .unacknowledged(let error): - throw error - case .success(_, let canceledBolus): - session.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: session) - } - - let canceledDoseEntry: DoseEntry? = canceledBolus != nil ? DoseEntry(canceledBolus!) : nil - completion(.success(canceledDoseEntry)) - } - } catch { - completion(.failure(.communication(error as? LocalizedError))) - } - } - } - - public func enactTempBasal(unitsPerHour: Double, for duration: TimeInterval, completion: @escaping (PumpManagerError?) -> Void) { - runTemporaryBasalProgram(unitsPerHour: unitsPerHour, for: duration, automatic: true, completion: completion) - } - - public func runTemporaryBasalProgram(unitsPerHour: Double, for duration: TimeInterval, automatic: Bool, completion: @escaping (PumpManagerError?) -> Void) { - guard self.hasActivePod else { - completion(.deviceState(OmniBLEPumpManagerError.noPodPaired)) - return - } - - // Round to nearest supported rate - let rate = roundToSupportedBasalRate(unitsPerHour: unitsPerHour) - - let acknowledgementBeep, completionBeep: Bool - if self.silencePod { - acknowledgementBeep = false - completionBeep = false - } else { - acknowledgementBeep = beepPreference.shouldBeepForCommand(automatic: automatic) - completionBeep = beepPreference.shouldBeepForManualCommand && !automatic - } - - self.podComms.runSession(withName: "Enact Temp Basal") { (result) in - self.log.info("Enact temp basal %.03fU/hr for %ds", rate, Int(duration)) - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(.communication(error)) - return - } - - do { - if case .some(.suspended) = self.state.podState?.suspendState { - self.log.info("Not enacting temp basal because podState indicates pod is suspended.") - throw PodCommsError.podSuspended - } - - // A resume scheduled basal delivery request is denoted by a 0 duration that cancels any existing temp basal. - let resumingScheduledBasal = duration < .ulpOfOne - - // If a bolus is not finished, fail if not resuming the scheduled basal - guard self.state.podState?.unfinalizedBolus?.isFinished() != false || resumingScheduledBasal else { - self.log.info("Not enacting temp basal because podState indicates unfinalized bolus in progress.") - throw PodCommsError.unfinalizedBolus - } - - // Did the last message have comms issues or is the last delivery status not verified correctly? - let uncertainDeliveryStatus = self.state.podState?.lastCommsOK == false || self.state.podState?.deliveryStatusVerified == false - - // Do the cancel temp basal command if currently running a temp basal OR - // if resuming scheduled basal delivery OR if the delivery status is uncertain. - if self.state.podState?.unfinalizedTempBasal != nil || resumingScheduledBasal || uncertainDeliveryStatus { - let status: StatusResponse - - // if resuming scheduled basal delivery & an acknowledgement beep is needed, use the cancel TB beep - let beepType: BeepType = resumingScheduledBasal && acknowledgementBeep ? .beep : .noBeepCancel - let result = session.cancelDelivery(deliveryType: .tempBasal, beepType: beepType) - switch result { - case .certainFailure(let error): - throw error - case .unacknowledged(let error): - throw error - case .success(let cancelTempStatus, _): - status = cancelTempStatus - } - - // If pod is bolusing, fail if not resuming the scheduled basal - guard !status.deliveryStatus.bolusing || resumingScheduledBasal else { - throw PodCommsError.unfinalizedBolus - } - - guard status.deliveryStatus != .suspended else { - self.log.info("Canceling temp basal because status return indicates pod is suspended.") - throw PodCommsError.podSuspended - } - } else { - self.log.info("Skipped Cancel TB command before enacting temp basal") - } - - defer { - self.setState({ (state) in - state.tempBasalEngageState = .stable - }) - } - - if resumingScheduledBasal { - self.setState({ (state) in - state.tempBasalEngageState = .disengaging - }) - session.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: session) - } - completion(nil) - } else { - self.setState({ (state) in - state.tempBasalEngageState = .engaging - }) - - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = self.state.timeZone - let scheduledRate = self.state.basalSchedule.currentRate(using: calendar, at: self.dateGenerator()) - let isHighTemp = rate > scheduledRate - - let result = session.setTempBasal(rate: rate, duration: duration, isHighTemp: isHighTemp, automatic: automatic, acknowledgementBeep: acknowledgementBeep, completionBeep: completionBeep) - - switch result { - case .success: - session.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: session) - } - completion(nil) - case .unacknowledged(let error): - throw error - case .certainFailure(let error): - throw error - } - } - } catch let error { - self.log.error("Error during temp basal: %{public}@", String(describing: error)) - completion(.communication(error as? LocalizedError)) - } - } - } - - /// Returns a dose estimator for the current bolus, if one is in progress - public func createBolusProgressReporter(reportingOn dispatchQueue: DispatchQueue) -> DoseProgressReporter? { - if case .inProgress(let dose) = bolusState(for: self.state) { - return PodDoseProgressEstimator(dose: dose, pumpManager: self, reportingQueue: dispatchQueue) - } - return nil - } - - public func syncBasalRateSchedule(items scheduleItems: [RepeatingScheduleValue], completion: @escaping (Result) -> Void) { - let newSchedule = BasalSchedule(repeatingScheduleValues: scheduleItems) - setBasalSchedule(newSchedule) { (error) in - if let error = error { - completion(.failure(error)) - } else { - completion(.success(BasalRateSchedule(dailyItems: scheduleItems, timeZone: self.state.timeZone)!)) - } - } - } - - public func syncDeliveryLimits(limits deliveryLimits: DeliveryLimits, completion: @escaping (Result) -> Void) { - setState { state in - if let rate = deliveryLimits.maximumBasalRate?.doubleValue(for: .internationalUnitsPerHour) { - state.maximumTempBasalRate = rate - completion(.success(deliveryLimits)) - } else { - completion(.failure(OmniBLEPumpManagerError.invalidSetting)) - } - } - } - - // MARK: - Alerts - - public var isClockOffset: Bool { - let now = dateGenerator() - return TimeZone.current.secondsFromGMT(for: now) != state.timeZone.secondsFromGMT(for: now) - } - - func checkForTimeOffsetChange() { - let isAlertActive = state.activeAlerts.contains(.timeOffsetChangeDetected) - - if !isAlertActive && isClockOffset && !state.acknowledgedTimeOffsetAlert { - issueAlert(alert: .timeOffsetChangeDetected) - } else if isAlertActive && !isClockOffset { - retractAlert(alert: .timeOffsetChangeDetected) - } - } - - public func updateExpirationReminder(_ intervalBeforeExpiration: TimeInterval?, completion: @escaping (OmniBLEPumpManagerError?) -> Void) { - - guard self.hasActivePod, let podState = state.podState, let expiresAt = podState.expiresAt else { - completion(OmniBLEPumpManagerError.noPodPaired) - return - } - - self.podComms.runSession(withName: "Update Expiration Reminder") { (result) in - - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(.communication(error)) - return - } - - let podTime = self.podTime - var expirationReminderPodTime: TimeInterval = 0 // default to expiration reminder alert inactive - - // If the interval before expiration is not a positive value (e.g., it's in the past), - // then the pod alert will get the default alert time of 0 making this alert inactive. - if let intervalBeforeExpiration = intervalBeforeExpiration, intervalBeforeExpiration > 0 { - let timeUntilReminder = expiresAt.addingTimeInterval(-intervalBeforeExpiration).timeIntervalSince(self.dateGenerator()) - // Only bother to set an expiration reminder pod alert if it is still at least a couple of minutes in the future - if timeUntilReminder > .minutes(2) { - expirationReminderPodTime = podTime + timeUntilReminder - self.log.debug("Update Expiration timeUntilReminder=%@, podTime=%@, expirationReminderPodTime=%@", timeUntilReminder.timeIntervalStr, podTime.timeIntervalStr, expirationReminderPodTime.timeIntervalStr) - } - } - - let expirationReminder = PodAlert.expirationReminder(offset: podTime, absAlertTime: expirationReminderPodTime, silent: self.silencePod) - do { - let beepBlock = self.beepMessageBlock(beepType: .beep) - try session.configureAlerts([expirationReminder], beepBlock: beepBlock) - self.setState({ (state) in - state.scheduledExpirationReminderOffset = intervalBeforeExpiration - }) - completion(nil) - } catch { - completion(.communication(error)) - return - } - } - } - - public var allowedExpirationReminderDates: [Date]? { - guard let expiration = state.podState?.expiresAt else { - return nil - } - - let allDates = Array(stride( - from: -Pod.expirationReminderAlertMaxHoursBeforeExpiration, - through: -Pod.expirationReminderAlertMinHoursBeforeExpiration, - by: 1)).map - { (i: Int) -> Date in - expiration.addingTimeInterval(.hours(Double(i))) - } - let now = dateGenerator() - // Have a couple minutes of slop to avoid confusion trying to set an expiration reminder too close to now - return allDates.filter { $0.timeIntervalSince(now) > .minutes(2) } - } - - public var scheduledExpirationReminder: Date? { - guard let expiration = state.podState?.expiresAt, let offset = state.scheduledExpirationReminderOffset, offset > 0 else { - return nil - } - - // It is possible the scheduledExpirationReminderOffset does not fall on the hour, but instead be a few seconds off - // since the allowedExpirationReminderDates are by the hour, force the offset to be on the hour - return expiration.addingTimeInterval(-.hours(round(offset.hours))) - } - - // Updates the low reservior reminder value both for the current pod (when applicable) and for future pods - public func updateLowReservoirReminder(_ value: Int, completion: @escaping (OmniBLEPumpManagerError?) -> Void) { - - let supportedValue = min(max(0, Double(value)), Pod.maximumReservoirReading) - let setLowReservoirReminderValue = { - self.log.default("Set Low Reservoir Reminder to %d U", value) - self.lowReservoirReminderValue = supportedValue - completion(nil) - } - - guard self.hasActivePod else { - // no active pod, just set the internal state for the next pod - setLowReservoirReminderValue() - return - } - - guard let currentReservoirLevel = self.reservoirLevel?.rawValue, currentReservoirLevel > supportedValue else { - // Since the new low reservoir alert level is not below the current reservoir value, - // just set the internal state for the next pod to prevent an immediate low reservoir alert. - setLowReservoirReminderValue() - return - } - - self.podComms.runSession(withName: "Program Low Reservoir Reminder") { (result) in - - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(.communication(error)) - return - } - - let lowReservoirReminder = PodAlert.lowReservoir(units: supportedValue, silent: self.silencePod) - do { - let beepBlock = self.beepMessageBlock(beepType: .beep) - try session.configureAlerts([lowReservoirReminder], beepBlock: beepBlock) - self.lowReservoirReminderValue = supportedValue - completion(nil) - } catch { - completion(.communication(error)) - return - } - } - } - - func issueAlert(alert: PumpManagerAlert) { - let identifier = Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: alert.alertIdentifier) - let loopAlert = Alert(identifier: identifier, foregroundContent: alert.foregroundContent, backgroundContent: alert.backgroundContent, trigger: .immediate) - pumpDelegate.notify { (delegate) in - delegate?.issueAlert(loopAlert) - } - - if let repeatInterval = alert.repeatInterval { - // Schedule an additional repeating 15 minute reminder for suspend period ended. - let repeatingIdentifier = Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: alert.repeatingAlertIdentifier) - let loopAlert = Alert(identifier: repeatingIdentifier, foregroundContent: alert.foregroundContent, backgroundContent: alert.backgroundContent, trigger: .repeating(repeatInterval: repeatInterval)) - pumpDelegate.notify { (delegate) in - delegate?.issueAlert(loopAlert) - } - } - - self.setState { (state) in - state.activeAlerts.insert(alert) - } - } - - func retractAlert(alert: PumpManagerAlert) { - let identifier = Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: alert.alertIdentifier) - pumpDelegate.notify { (delegate) in - delegate?.retractAlert(identifier: identifier) - } - if alert.isRepeating { - let repeatingIdentifier = Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: alert.repeatingAlertIdentifier) - pumpDelegate.notify { (delegate) in - delegate?.retractAlert(identifier: repeatingIdentifier) - } - } - self.setState { (state) in - state.activeAlerts.remove(alert) - } - } - - private func alertsChanged(oldAlerts: AlertSet, newAlerts: AlertSet) { - guard let podState = state.podState else { - preconditionFailure("trying to manage alerts without podState") - } - - let (added, removed) = oldAlerts.compare(to: newAlerts) - for slot in added { - if let podAlert = podState.configuredAlerts[slot] { - log.default("Alert slot triggered: %{public}@", String(describing: slot)) - if let pumpManagerAlert = getPumpManagerAlert(for: podAlert, slot: slot) { - issueAlert(alert: pumpManagerAlert) - } else { - log.default("Ignoring alert: %{public}@", String(describing: podAlert)) - } - } else { - log.error("Unconfigured alert slot triggered: %{public}@", String(describing: slot)) - let pumpManagerAlert = PumpManagerAlert.unexpectedAlert(triggeringSlot: slot) - issueAlert(alert: pumpManagerAlert) - } - } - for alert in removed { - log.default("Alert slot cleared: %{public}@", String(describing: alert)) - } - } - - private func getPumpManagerAlert(for podAlert: PodAlert, slot: AlertSlot) -> PumpManagerAlert? { - - switch podAlert { - case .shutdownImminent: - return PumpManagerAlert.podExpireImminent(triggeringSlot: slot) - case .expirationReminder: - guard let podState = state.podState, let expiresAt = podState.expiresAt else { - preconditionFailure("trying to lookup expiresAt") - } - let timeToExpiry = TimeInterval(hours: expiresAt.timeIntervalSince(dateGenerator()).hours.rounded()) - return PumpManagerAlert.userPodExpiration(triggeringSlot: slot, scheduledExpirationReminderOffset: timeToExpiry) - case .lowReservoir(let units, _): - return PumpManagerAlert.lowReservoir(triggeringSlot: slot, lowReservoirReminderValue: units) - case .suspendTimeExpired: - return PumpManagerAlert.suspendEnded(triggeringSlot: slot) - case .expired: - return PumpManagerAlert.podExpiring(triggeringSlot: slot) - default: - // No PumpManagerAlerts are used for any other pod alerts (including suspendInProgress). - return nil - } - } - - private func silenceAcknowledgedAlerts() { - // Only attempt to clear one per cycle (more than one should be rare) - if let alert = state.alertsWithPendingAcknowledgment.first { - if let slot = alert.triggeringSlot { - self.podComms.runSession(withName: "Silence already acknowledged alert") { (result) in - switch result { - case .success(let session): - do { - let _ = try session.acknowledgeAlerts(alerts: AlertSet(slots: [slot])) - } catch { - return - } - self.setState { state in - state.activeAlerts.remove(alert) - state.alertsWithPendingAcknowledgment.remove(alert) - } - case .failure: - return - } - } - } - } - } - - private func notifyPodFault(fault: DetailedStatus) { - pumpDelegate.notify { delegate in - let content = Alert.Content(title: fault.faultEventCode.notificationTitle, - body: fault.faultEventCode.notificationBody, - acknowledgeActionButtonLabel: LocalizedString("OK", comment: "Alert acknowledgment OK button")) - delegate?.issueAlert(Alert(identifier: Alert.Identifier(managerIdentifier: OmniBLEPumpManager.podAlarmNotificationIdentifier, - alertIdentifier: fault.faultEventCode.description), - foregroundContent: content, backgroundContent: content, - trigger: .immediate)) - } - } - - // MARK: - Reporting Doses - - // This cannot be called from within the lockedState lock! - func store(doses: [UnfinalizedDose], in session: PodCommsSession) -> Bool { - session.assertOnSessionQueue() - - // We block the session until the data's confirmed stored by the delegate - let semaphore = DispatchSemaphore(value: 0) - var success = false - - store(doses: doses) { (error) in - success = (error == nil) - semaphore.signal() - } - - semaphore.wait() - - if success { - setState { (state) in - state.lastPumpDataReportDate = Date() - } - } - return success - } - - func store(doses: [UnfinalizedDose], completion: @escaping (_ error: Error?) -> Void) { - let lastSync = lastSync - - pumpDelegate.notify { (delegate) in - guard let delegate = delegate else { - preconditionFailure("pumpManagerDelegate cannot be nil") - } - - - delegate.pumpManager(self, hasNewPumpEvents: doses.map { NewPumpEvent($0) }, lastReconciliation: lastSync, completion: { (error) in - if let error = error { - self.log.error("Error storing pod events: %@", String(describing: error)) - } else { - self.log.info("DU: Stored pod events: %@", String(describing: doses)) - } - - completion(error) - }) - } - } -} - -extension OmniBLEPumpManager: MessageLogger { - func didSend(_ message: Data) { - log.default("didSend: %{public}@", message.hexadecimalString) - self.logDeviceCommunication(message.hexadecimalString, type: .send) - } - - func didReceive(_ message: Data) { - log.default("didReceive: %{public}@", message.hexadecimalString) - self.logDeviceCommunication(message.hexadecimalString, type: .receive) - } - - func didError(_ message: String) { - self.logDeviceCommunication(message, type: .error) - } -} - -extension OmniBLEPumpManager: PodCommsDelegate { - - func podCommsDidEstablishSession(_ podComms: PodComms) { - - podComms.runSession(withName: "Post-connect status fetch") { result in - switch result { - case .success(let session): - let _ = try? session.getStatus() - self.silenceAcknowledgedAlerts() - session.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: session) - } - self.issueHeartbeatIfNeeded() - case .failure: - // Errors can be ignored here. - break - } - } - - } - - func podComms(_ podComms: PodComms, didChange podState: PodState?) { - if let podState = podState { - let (newFault, oldAlerts, newAlerts) = setStateWithResult { (state) -> (DetailedStatus?,AlertSet,AlertSet) in - if (state.suspendEngageState == .engaging && podState.isSuspended) || - (state.suspendEngageState == .disengaging && !podState.isSuspended) - { - state.suspendEngageState = .stable - } - - let newFault: DetailedStatus? - - // Check for new fault state - if state.podState?.fault == nil, let fault = podState.fault { - newFault = fault - } else { - newFault = nil - } - - let oldAlerts: AlertSet = state.podState?.activeAlertSlots ?? AlertSet.none - let newAlerts: AlertSet = podState.activeAlertSlots - - state.updatePodStateFromPodComms(podState) - - return (newFault, oldAlerts, newAlerts) - } - - if let newFault = newFault { - notifyPodFault(fault: newFault) - } - - if oldAlerts != newAlerts { - self.alertsChanged(oldAlerts: oldAlerts, newAlerts: newAlerts) - } - } else { - // Resetting podState - setState { state in - state.updatePodStateFromPodComms(podState) - } - } - } -} - -extension OmniBLEPumpManager: AlertSoundVendor { - public func getSoundBaseURL() -> URL? { - return nil - } - - public func getSounds() -> [Alert.Sound] { - return [] - } -} - -// MARK: - AlertResponder implementation -extension OmniBLEPumpManager { - public func acknowledgeAlert(alertIdentifier: Alert.AlertIdentifier, completion: @escaping (Error?) -> Void) { - guard self.hasActivePod else { - completion(OmniBLEPumpManagerError.noPodPaired) - return - } - - for alert in state.activeAlerts { - if alert.alertIdentifier == alertIdentifier { - // If this alert was triggered by the pod find the slot to clear it. - if let slot = alert.triggeringSlot { - if case .some(.suspended) = self.state.podState?.suspendState, slot == .slot6SuspendTimeExpired { - // Don't clear this pod alert here with the pod still suspended so that the suspend time expired - // pod alert beeping will continue until the pod is resumed which will then deactivate this alert. - log.default("Skipping acknowledgement of suspend time expired alert with a suspended pod") - completion(nil) - return - } - self.podComms.runSession(withName: "Acknowledge Alert") { (result) in - switch result { - case .success(let session): - do { - let beepBlock = self.beepMessageBlock(beepType: .beep) - let _ = try session.acknowledgeAlerts(alerts: AlertSet(slots: [slot]), beepBlock: beepBlock) - } catch { - self.setState { state in - state.alertsWithPendingAcknowledgment.insert(alert) - } - completion(error) - return - } - self.setState { state in - state.activeAlerts.remove(alert) - } - completion(nil) - case .failure(let error): - self.setState { state in - state.alertsWithPendingAcknowledgment.insert(alert) - } - completion(error) - } - } - } else { - // Non-pod alert - self.setState { state in - state.activeAlerts.remove(alert) - if alert == .timeOffsetChangeDetected { - state.acknowledgedTimeOffsetAlert = true - } - } - completion(nil) - } - } - } - } -} - -extension FaultEventCode { - public var notificationTitle: String { - switch self.faultType { - case .reservoirEmpty: - return LocalizedString("Empty Reservoir", comment: "The title for Empty Reservoir alarm notification") - case .occluded, .occlusionCheckStartup1, .occlusionCheckStartup2, .occlusionCheckTimeouts1, .occlusionCheckTimeouts2, .occlusionCheckTimeouts3, .occlusionCheckPulseIssue, .occlusionCheckBolusProblem: - return LocalizedString("Occlusion Detected", comment: "The title for Occlusion alarm notification") - case .exceededMaximumPodLife80Hrs: - return LocalizedString("Pod Expired", comment: "The title for Pod Expired alarm notification") - default: - return String(format: LocalizedString("Critical Pod Fault %1$03d", comment: "The title for AlarmCode.other notification: (1: fault code value)"), self.rawValue) - } - } - - public var notificationBody: String { - return LocalizedString("Insulin delivery stopped. Change Pod now.", comment: "The default notification body for AlarmCodes") - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManager/OmniBLEPumpManagerState.swift b/Dependencies/OmniBLE/OmniBLE/PumpManager/OmniBLEPumpManagerState.swift deleted file mode 100644 index d86ce58d9..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManager/OmniBLEPumpManagerState.swift +++ /dev/null @@ -1,328 +0,0 @@ -// -// OmniBLEPumpManagerState.swift -// OmniBLE -// -// Based on OmniKit/PumpManager/OmnipodPumpManagerState.swift -// Created by Pete Schwamb on 8/4/18. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import LoopKit - - -public struct OmniBLEPumpManagerState: RawRepresentable, Equatable { - public typealias RawValue = PumpManager.RawStateValue - - public static let version = 2 - - public var isOnboarded: Bool = false - - private (set) public var podState: PodState? - - // podState should only be modifiable by PodComms - mutating func updatePodStateFromPodComms(_ podState: PodState?) { - self.podState = podState - } - - public var timeZone: TimeZone - - public var basalSchedule: BasalSchedule - - public var unstoredDoses: [UnfinalizedDose] - - public var silencePod: Bool - - public var confirmationBeeps: BeepPreference - - public var controllerId: UInt32 = 0 - - public var podId: UInt32 = 0 - - public var scheduledExpirationReminderOffset: TimeInterval? - - public var defaultExpirationReminderOffset = Pod.defaultExpirationReminderOffset - - public var lowReservoirReminderValue: Double - - public var podAttachmentConfirmed: Bool - - public var activeAlerts: Set - - public var alertsWithPendingAcknowledgment: Set - - public var acknowledgedTimeOffsetAlert: Bool - - internal var lastPumpDataReportDate: Date? - - internal var insulinType: InsulinType? - - // Persistence for the pod state of the previous pod, for - // user review and manufacturer reporting. - internal var previousPodState: PodState? - - // Indicates that the user has completed initial configuration - // which means they have configured any parameters, but may not have paired a pod yet. - public var initialConfigurationCompleted: Bool = false - - internal var maximumTempBasalRate: Double - - - // From last status response - public var reservoirLevel: ReservoirLevel? { - guard let level = podState?.lastInsulinMeasurements?.reservoirLevel else { - return nil - } - return ReservoirLevel(rawValue: level) - } - - // Temporal state not persisted - - internal enum EngageablePumpState: Equatable { - case engaging - case disengaging - case stable - } - - internal var suspendEngageState: EngageablePumpState = .stable - - internal var bolusEngageState: EngageablePumpState = .stable - - internal var tempBasalEngageState: EngageablePumpState = .stable - - internal var lastStatusChange: Date = .distantPast - - // MARK: - - - public init(podState: PodState?, timeZone: TimeZone, basalSchedule: BasalSchedule, controllerId: UInt32? = nil, podId: UInt32? = nil, insulinType: InsulinType?, maximumTempBasalRate: Double) { - self.podState = podState - self.timeZone = timeZone - self.basalSchedule = basalSchedule - self.unstoredDoses = [] - self.silencePod = false - self.confirmationBeeps = .manualCommands - if controllerId != nil && podId != nil { - self.controllerId = controllerId! - self.podId = podId! - } else { - let myId = createControllerId() - self.controllerId = myId - self.podId = myId + 1 - } - self.insulinType = insulinType - self.lowReservoirReminderValue = Pod.defaultLowReservoirReminder - self.podAttachmentConfirmed = false - self.acknowledgedTimeOffsetAlert = false - self.activeAlerts = [] - self.alertsWithPendingAcknowledgment = [] - self.maximumTempBasalRate = maximumTempBasalRate - } - - public init?(rawValue: RawValue) { - - guard let version = rawValue["version"] as? Int else { - return nil - } - - let basalSchedule: BasalSchedule - - if version == 1 { - // migrate: basalSchedule moved from podState to oppm state - if let podStateRaw = rawValue["podState"] as? PodState.RawValue, - let rawBasalSchedule = podStateRaw["basalSchedule"] as? BasalSchedule.RawValue, - let migrateSchedule = BasalSchedule(rawValue: rawBasalSchedule) - { - basalSchedule = migrateSchedule - } else { - return nil - } - } else { - guard let rawBasalSchedule = rawValue["basalSchedule"] as? BasalSchedule.RawValue, - let schedule = BasalSchedule(rawValue: rawBasalSchedule) else - { - return nil - } - basalSchedule = schedule - } - - let podState: PodState? - if let podStateRaw = rawValue["podState"] as? PodState.RawValue { - podState = PodState(rawValue: podStateRaw) - } else { - podState = nil - } - - let timeZone: TimeZone - if let timeZoneSeconds = rawValue["timeZone"] as? Int, - let tz = TimeZone(secondsFromGMT: timeZoneSeconds) { - timeZone = tz - } else { - timeZone = TimeZone.currentFixed - } - - var controllerId = rawValue["controllerId"] as? UInt32 - var podId = rawValue["podId"] as? UInt32 - if controllerId == nil || podId == nil { - // continue using the constant controllerId - // value until this pod is deactivated - controllerId = CONTROLLER_ID - podId = podState?.address - } - - var insulinType: InsulinType? - if let rawInsulinType = rawValue["insulinType"] as? InsulinType.RawValue { - insulinType = InsulinType(rawValue: rawInsulinType) - } - - // If this doesn't exist (early adopters of dev/pre-3.0) set to zero - // Will not let them set a manual temp until a limits sync has been performed. - let maximumTempBasalRate = rawValue["maximumTempBasalRate"] as? Double ?? 0 - - self.init( - podState: podState, - timeZone: timeZone, - basalSchedule: basalSchedule, - controllerId: controllerId, - podId: podId, - insulinType: insulinType ?? .novolog, - maximumTempBasalRate: maximumTempBasalRate - ) - - self.isOnboarded = rawValue["isOnboarded"] as? Bool ?? true // Backward compatibility - - if let rawUnstoredDoses = rawValue["unstoredDoses"] as? [UnfinalizedDose.RawValue] { - self.unstoredDoses = rawUnstoredDoses.compactMap( { UnfinalizedDose(rawValue: $0) } ) - } else { - self.unstoredDoses = [] - } - - self.silencePod = rawValue["silencePod"] as? Bool ?? false - - if let rawBeeps = rawValue["confirmationBeeps"] as? BeepPreference.RawValue, let confirmationBeeps = BeepPreference(rawValue: rawBeeps) { - self.confirmationBeeps = confirmationBeeps - } else { - self.confirmationBeeps = .manualCommands - } - - self.scheduledExpirationReminderOffset = rawValue["scheduledExpirationReminderOffset"] as? TimeInterval - - self.defaultExpirationReminderOffset = rawValue["defaultExpirationReminderOffset"] as? TimeInterval ?? Pod.defaultExpirationReminderOffset - - self.lowReservoirReminderValue = rawValue["lowReservoirReminderValue"] as? Double ?? Pod.defaultLowReservoirReminder - - self.podAttachmentConfirmed = rawValue["podAttachmentConfirmed"] as? Bool ?? false - - self.initialConfigurationCompleted = rawValue["initialConfigurationCompleted"] as? Bool ?? true - - self.acknowledgedTimeOffsetAlert = rawValue["acknowledgedTimeOffsetAlert"] as? Bool ?? false - - if let lastPumpDataReportDate = rawValue["lastPumpDataReportDate"] as? Date { - self.lastPumpDataReportDate = lastPumpDataReportDate - } - - self.activeAlerts = [] - if let rawActiveAlerts = rawValue["activeAlerts"] as? [PumpManagerAlert.RawValue] { - for rawAlert in rawActiveAlerts { - if let alert = PumpManagerAlert(rawValue: rawAlert) { - self.activeAlerts.insert(alert) - } - } - } - - self.alertsWithPendingAcknowledgment = [] - if let rawAlerts = rawValue["alertsWithPendingAcknowledgment"] as? [PumpManagerAlert.RawValue] { - for rawAlert in rawAlerts { - if let alert = PumpManagerAlert(rawValue: rawAlert) { - self.alertsWithPendingAcknowledgment.insert(alert) - } - } - } - - if let prevPodStateRaw = rawValue["previousPodState"] as? PodState.RawValue { - previousPodState = PodState(rawValue: prevPodStateRaw) - } else { - previousPodState = nil - } - } - - public var rawValue: RawValue { - var value: [String : Any] = [ - "version": OmniBLEPumpManagerState.version, - "isOnboarded": isOnboarded, - "timeZone": timeZone.secondsFromGMT(), - "basalSchedule": basalSchedule.rawValue, - "unstoredDoses": unstoredDoses.map { $0.rawValue }, - "silencePod": silencePod, - "confirmationBeeps": confirmationBeeps.rawValue, - "activeAlerts": activeAlerts.map { $0.rawValue }, - "podAttachmentConfirmed": podAttachmentConfirmed, - "acknowledgedTimeOffsetAlert": acknowledgedTimeOffsetAlert, - "alertsWithPendingAcknowledgment": alertsWithPendingAcknowledgment.map { $0.rawValue }, - "initialConfigurationCompleted": initialConfigurationCompleted, - "maximumTempBasalRate": maximumTempBasalRate - ] - - value["insulinType"] = insulinType?.rawValue - value["podState"] = podState?.rawValue - value["controllerId"] = controllerId - value["podId"] = podId - value["scheduledExpirationReminderOffset"] = scheduledExpirationReminderOffset - value["defaultExpirationReminderOffset"] = defaultExpirationReminderOffset - value["lowReservoirReminderValue"] = lowReservoirReminderValue - value["lastPumpDataReportDate"] = lastPumpDataReportDate - value["previousPodState"] = previousPodState?.rawValue - return value - } -} - -extension OmniBLEPumpManagerState { - var hasActivePod: Bool { - return podState?.isActive == true - } - - var hasSetupPod: Bool { - return podState?.isSetupComplete == true - } - - var isPumpDataStale: Bool { - let pumpStatusAgeTolerance = TimeInterval(minutes: 6) - let pumpDataAge = -(self.lastPumpDataReportDate ?? .distantPast).timeIntervalSinceNow - return pumpDataAge > pumpStatusAgeTolerance - } -} - - -extension OmniBLEPumpManagerState: CustomDebugStringConvertible { - public var debugDescription: String { - return [ - "## OmniBLEPumpManagerState", - "* isOnboarded: \(isOnboarded)", - "* timeZone: \(timeZone)", - "* basalSchedule: \(String(describing: basalSchedule))", - "* maximumTempBasalRate: \(maximumTempBasalRate)", - "* unstoredDoses: \(String(describing: unstoredDoses))", - "* suspendEngageState: \(String(describing: suspendEngageState))", - "* bolusEngageState: \(String(describing: bolusEngageState))", - "* tempBasalEngageState: \(String(describing: tempBasalEngageState))", - "* lastPumpDataReportDate: \(String(describing: lastPumpDataReportDate))", - "* isPumpDataStale: \(String(describing: isPumpDataStale))", - "* silencePod: \(String(describing: silencePod))", - "* confirmationBeeps: \(String(describing: confirmationBeeps))", - "* controllerId: \(String(format: "%08X", controllerId))", - "* podId: \(String(format: "%08X", podId))", - "* insulinType: \(String(describing: insulinType))", - "* scheduledExpirationReminderOffset: \(String(describing: scheduledExpirationReminderOffset?.timeIntervalStr))", - "* defaultExpirationReminderOffset: \(defaultExpirationReminderOffset.timeIntervalStr)", - "* lowReservoirReminderValue: \(lowReservoirReminderValue)", - "* podAttachmentConfirmed: \(podAttachmentConfirmed)", - "* activeAlerts: \(activeAlerts)", - "* alertsWithPendingAcknowledgment: \(alertsWithPendingAcknowledgment)", - "* acknowledgedTimeOffsetAlert: \(acknowledgedTimeOffsetAlert)", - "* initialConfigurationCompleted: \(initialConfigurationCompleted)", - "", - "* PodState: " + (podState == nil ? "nil" : String(describing: podState!)), - "", - "* PreviousPodState: " + (previousPodState == nil ? "nil" : String(describing: previousPodState!)), - "", - ].joined(separator: "\n") - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManager/PodAdvertisement.swift b/Dependencies/OmniBLE/OmniBLE/PumpManager/PodAdvertisement.swift deleted file mode 100644 index 1d809adc1..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManager/PodAdvertisement.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// PodAdvertisement.swift -// OmniBLE -// -// Created by Pete Schwamb on 1/13/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation -import CoreBluetooth - -struct PodAdvertisement { - let MAIN_SERVICE_UUID = "4024" - let UNKNOWN_THIRD_SERVICE_UUID = "000A" - - var sequenceNo: UInt32 - var lotNo: UInt64 - var podId: UInt32 - - var serviceUUIDs: [CBUUID] - - var pairable: Bool { - return serviceUUIDs.count >= 5 && serviceUUIDs[3].uuidString == "FFFF" && serviceUUIDs[4].uuidString == "FFFE" - } - - init?(_ advertisementData: [String: Any]) { - guard var serviceUUIDs = advertisementData["kCBAdvDataServiceUUIDs"] as? [CBUUID] else { - return nil - } - - self.serviceUUIDs = serviceUUIDs - - // For some reason the pod simulator doesn't have two values. - if serviceUUIDs.count == 7 { - serviceUUIDs.append(CBUUID(string: "abcd")) - serviceUUIDs.append(CBUUID(string: "dcba")) - } - - guard serviceUUIDs.count == 9 else { - return nil - } - - guard serviceUUIDs[0].uuidString == MAIN_SERVICE_UUID else { - return nil - } - - // TODO understand what is serviceUUIDs[1]. 0x2470. Alarms? - guard serviceUUIDs[2].uuidString == UNKNOWN_THIRD_SERVICE_UUID else { - return nil - } - - guard let decodedPodId = UInt32(serviceUUIDs[3].uuidString + serviceUUIDs[4].uuidString, radix: 16) else { - return nil - } - podId = decodedPodId - - let lotNoString: String = serviceUUIDs[5].uuidString + serviceUUIDs[6].uuidString + serviceUUIDs[7].uuidString - guard let decodedLotNo = UInt64(lotNoString[lotNoString.startIndex.. 0 - } - } - - private var needsSessionEstablishment: Bool = false - - private let bluetoothManager = BluetoothManager() - - private var myId: UInt32 - private var podId: UInt32 - - init(podState: PodState?, myId: UInt32 = 0, podId: UInt32 = 0) { - self.podState = podState - self.delegate = nil - self.messageLogger = nil - self.myId = myId - self.podId = podId - bluetoothManager.connectionDelegate = self - if let podState = podState { - bluetoothManager.connectToDevice(uuidString: podState.bleIdentifier) - } - } - - public func updateInsulinType(_ insulinType: InsulinType) { - podStateLock.lock() - podState?.insulinType = insulinType - podStateLock.unlock() - } - - public func forgetPod() { - if let manager = manager { - self.log.default("Removing %{public}@ from auto-connect ids", manager.peripheral) - bluetoothManager.disconnectFromDevice(uuidString: manager.peripheral.identifier.uuidString) - } - - podStateLock.lock() - podState?.resolveAnyPendingCommandWithUncertainty() - podState?.finalizeAllDoses() - podStateLock.unlock() - } - - public func prepForNewPod(myId: UInt32 = 0, podId: UInt32 = 0) { - self.myId = myId - self.podId = podId - - podStateLock.lock() - self.podState = nil - podStateLock.unlock() - } - - public func connectToNewPod(_ completion: @escaping (Result) -> Void) { - let discoveryStartTime = Date() - - bluetoothManager.discoverPods { error in - if let error = error { - completion(.failure(error)) - } else { - Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in - let devices = self.bluetoothManager.getConnectedDevices() - - if devices.count > 1 { - self.log.default("Multiple pods found while scanning") - self.bluetoothManager.endPodDiscovery() - completion(.failure(PodCommsError.tooManyPodsFound)) - timer.invalidate() - } - - let elapsed = Date().timeIntervalSince(discoveryStartTime) - - // If we've found a pod by 2 seconds, let's go. - if elapsed > TimeInterval(seconds: 2) && devices.count > 0 { - self.log.default("Found pod!") - let targetPod = devices.first! - self.bluetoothManager.connectToDevice(uuidString: targetPod.manager.peripheral.identifier.uuidString) - self.manager = targetPod.manager - targetPod.manager.delegate = self - self.bluetoothManager.endPodDiscovery() - completion(.success(devices.first!)) - timer.invalidate() - } - - if elapsed > TimeInterval(seconds: 10) { - self.log.default("No pods found while scanning") - self.bluetoothManager.endPodDiscovery() - completion(.failure(PodCommsError.noPodsFound)) - timer.invalidate() - } - } - } - } - } - - // Handles all the common work to send and verify the version response for the two pairing pod commands, AssignAddress and SetupPod. - private func sendPairMessage(transport: PodMessageTransport, message: Message) throws -> VersionResponse { - - // We should already be holding podStateLock during calls to this function, so try() should fail - assert(!podStateLock.try(), "\(#function) should be invoked while holding podStateLock") - - - defer { - if self.podState != nil { - log.debug("sendPairMessage saving current message transport state %@", String(reflecting: transport)) - self.podState!.messageTransportState = MessageTransportState(ck: transport.ck, noncePrefix: transport.noncePrefix, msgSeq: transport.msgSeq, nonceSeq: transport.nonceSeq, messageNumber: transport.messageNumber) - } - } - - log.debug("sendPairMessage: attempting to use PodMessageTransport %@ to send message %@", String(reflecting: transport), String(reflecting: message)) - let podMessageResponse = try transport.sendMessage(message) - - if let fault = podMessageResponse.fault { - log.error("sendPairMessage pod fault: %{public}@", String(describing: fault)) - if let podState = self.podState, podState.fault == nil { - self.podState!.fault = fault - } - throw PodCommsError.podFault(fault: fault) - } - - guard let versionResponse = podMessageResponse.messageBlocks[0] as? VersionResponse else { - log.error("sendPairMessage unexpected response: %{public}@", String(describing: podMessageResponse)) - let responseType = podMessageResponse.messageBlocks[0].blockType - throw PodCommsError.unexpectedResponse(response: responseType) - } - - log.debug("sendPairMessage: returning versionResponse %@", String(describing: versionResponse)) - return versionResponse - } - - private func pairPod(insulinType: InsulinType) throws { - // We should already be holding podStateLock during calls to this function, so try() should fail - assert(!podStateLock.try(), "\(#function) should be invoked while holding podStateLock") - - guard let manager = manager else { throw PodCommsError.podNotConnected } - let ids = Ids(myId: self.myId, podId: self.podId) - - let ltkExchanger = LTKExchanger(manager: manager, ids: ids) - let response = try ltkExchanger.negotiateLTK() - let ltk = response.ltk - - guard podId == response.address else { - log.debug("podId 0x%x doesn't match response value!: %{public}@", podId, String(describing: response)) - throw PodCommsError.invalidAddress(address: response.address, expectedAddress: self.podId) - } - - log.info("Establish an Eap Session") - guard let messageTransportState = try establishSession(ltk: ltk, eapSeq: 1, msgSeq: Int(response.msgSeq)) else { - log.debug("pairPod: failed to create messageTransportState!") - throw PodCommsError.noPodPaired - } - - log.info("LTK and encrypted transport now ready, messageTransportState: %@", String(reflecting: messageTransportState)) - - // If we get here, we have the LTK all set up and we should be able use encrypted pod messages - let transport = PodMessageTransport(manager: manager, myId: self.myId, podId: self.podId, state: messageTransportState) - transport.messageLogger = messageLogger - - // For Dash this command is vestigal and doesn't actually assign the address (podId) - // any more as this is done earlier when the LTK is setup. But this Omnipod comamnd is still - // needed albiet using 0xffffffff for the address while the Eros sets the 0x1f0xxxxx ID. - let assignAddress = AssignAddressCommand(address: 0xffffffff) - let message = Message(address: 0xffffffff, messageBlocks: [assignAddress], sequenceNum: transport.messageNumber) - - let versionResponse = try sendPairMessage(transport: transport, message: message) - - // Now create the real PodState using the current transport state and the versionResponse info - log.debug("pairPod: creating PodState for versionResponse %{public}@ and transport %{public}@", String(describing: versionResponse), String(describing: transport.state)) - self.podState = PodState( - address: self.podId, - ltk: ltk, - firmwareVersion: String(describing: versionResponse.firmwareVersion), - bleFirmwareVersion: String(describing: versionResponse.iFirmwareVersion), - lotNo: versionResponse.lot, - lotSeq: versionResponse.tid, - productId: versionResponse.productId, - messageTransportState: transport.state, - bleIdentifier: manager.peripheral.identifier.uuidString, - insulinType: insulinType - ) - // podState setupProgress state should be addressAssigned - - // Now that we have podState, check for an activation timeout condition that can be noted in setupProgress - guard versionResponse.podProgressStatus != .activationTimeExceeded else { - // The 2 hour window for the initial pairing has expired - self.podState?.setupProgress = .activationTimeout - throw PodCommsError.activationTimeExceeded - } - - log.debug("pairPod: self.PodState messageTransportState now: %@", String(reflecting: self.podState?.messageTransportState)) - } - - private func establishSession(ltk: Data, eapSeq: Int, msgSeq: Int = 1) throws -> MessageTransportState? { - // We should already be holding podStateLock during calls to this function, so try() should fail - assert(!podStateLock.try(), "\(#function) should be invoked while holding podStateLock") - - guard let manager = manager else { throw PodCommsError.noPodPaired } - let eapAkaExchanger = try SessionEstablisher(manager: manager, ltk: ltk, eapSqn: eapSeq, myId: self.myId, podId: self.podId, msgSeq: msgSeq) - - let result = try eapAkaExchanger.negotiateSessionKeys() - - switch result { - case .SessionNegotiationResynchronization(let keys): - log.debug("Received EAP SQN resynchronization: %@", keys.synchronizedEapSqn.data.hexadecimalString) - if self.podState != nil { - let eapSeq = keys.synchronizedEapSqn.toInt() - log.debug("Updating EAP SQN to: %d", eapSeq) - self.podState!.messageTransportState.eapSeq = eapSeq - } - return nil - case .SessionKeys(let keys): - log.debug("Session Established") - // log.debug("CK: %@", keys.ck.hexadecimalString) - log.info("msgSequenceNumber: %@", String(keys.msgSequenceNumber)) - // log.info("NoncePrefix: %@", keys.nonce.prefix.hexadecimalString) - - let omnipodMessageNumber = self.podState?.messageTransportState.messageNumber ?? 0 - let messageTransportState = MessageTransportState( - ck: keys.ck, - noncePrefix: keys.nonce.prefix, - eapSeq: eapSeq, - msgSeq: keys.msgSequenceNumber, - messageNumber: omnipodMessageNumber - ) - - if self.podState != nil { - log.debug("Setting podState transport state to %{public}@", String(describing: messageTransportState)) - self.podState!.messageTransportState = messageTransportState - } else { - log.debug("Used keys %@ to create messageTransportState: %@", String(reflecting: keys), String(reflecting: messageTransportState)) - } - return messageTransportState - } - } - - private func establishNewSession() throws { - // We should already be holding podStateLock during calls to this function, so try() should fail - assert(!podStateLock.try(), "\(#function) should be invoked while holding podStateLock") - - guard self.podState != nil else { - throw PodCommsError.noPodPaired - } - - let mts = try establishSession(ltk: self.podState!.ltk, eapSeq: self.podState!.incrementEapSeq()) - if mts == nil { - let mts = try establishSession(ltk: self.podState!.ltk, eapSeq: self.podState!.incrementEapSeq()) - if (mts == nil) { - throw PodCommsError.diagnosticMessage(str: "Received resynchronization SQN for the second time") - } - } - } - - private func setupPod(timeZone: TimeZone) throws { - guard let manager = manager else { throw PodCommsError.podNotConnected } - - // We should already be holding podStateLock during calls to this function, so try() should fail - assert(!podStateLock.try(), "\(#function) should be invoked while holding podStateLock") - - - let transport = PodMessageTransport(manager: manager, myId: self.myId, podId: self.podId, state: podState!.messageTransportState) - transport.messageLogger = messageLogger - - let dateComponents = SetupPodCommand.dateComponents(date: Date(), timeZone: timeZone) - let setupPod = SetupPodCommand(address: podState!.address, dateComponents: dateComponents, lot: UInt32(podState!.lotNo), tid: podState!.lotSeq) - - let message = Message(address: 0xffffffff, messageBlocks: [setupPod], sequenceNum: transport.messageNumber) - - log.debug("setupPod: calling sendPairMessage %@ for message %@", String(reflecting: transport), String(describing: message)) - let versionResponse = try sendPairMessage(transport: transport, message: message) - - // Verify that the fundemental pod constants returned match the expected constant values in the Pod struct. - // To actually be able to handle different fundemental values in Loop things would need to be reworked to save - // these values in some persistent PodState and then make sure that everything properly works using these values. - var errorStrings: [String] = [] - if let pulseSize = versionResponse.pulseSize, pulseSize != Pod.pulseSize { - errorStrings.append(String(format: "Pod reported pulse size of %.3fU different than expected %.3fU", pulseSize, Pod.pulseSize)) - } - if let secondsPerBolusPulse = versionResponse.secondsPerBolusPulse, secondsPerBolusPulse != Pod.secondsPerBolusPulse { - errorStrings.append(String(format: "Pod reported seconds per pulse rate of %.1f different than expected %.1f", secondsPerBolusPulse, Pod.secondsPerBolusPulse)) - } - if let secondsPerPrimePulse = versionResponse.secondsPerPrimePulse, secondsPerPrimePulse != Pod.secondsPerPrimePulse { - errorStrings.append(String(format: "Pod reported seconds per prime pulse rate of %.1f different than expected %.1f", secondsPerPrimePulse, Pod.secondsPerPrimePulse)) - } - if let primeUnits = versionResponse.primeUnits, primeUnits != Pod.primeUnits { - errorStrings.append(String(format: "Pod reported prime bolus of %.2fU different than expected %.2fU", primeUnits, Pod.primeUnits)) - } - if let cannulaInsertionUnits = versionResponse.cannulaInsertionUnits, Pod.cannulaInsertionUnits != cannulaInsertionUnits { - errorStrings.append(String(format: "Pod reported cannula insertion bolus of %.2fU different than expected %.2fU", cannulaInsertionUnits, Pod.cannulaInsertionUnits)) - } - if let serviceDuration = versionResponse.serviceDuration { - if serviceDuration < Pod.serviceDuration { - errorStrings.append(String(format: "Pod reported service duration of %.0f hours shorter than expected %.0f", serviceDuration.hours, Pod.serviceDuration.hours)) - } else if serviceDuration > Pod.serviceDuration { - log.info("Pod reported service duration of %.0f hours limited to expected %.0f", serviceDuration.hours, Pod.serviceDuration.hours) - } - } - - let errMess = errorStrings.joined(separator: ".\n") - if errMess.isEmpty == false { - log.error("%@", errMess) - self.podState?.setupProgress = .podIncompatible - throw PodCommsError.podIncompatible(str: errMess) - } - - if versionResponse.podProgressStatus == .pairingCompleted && self.podState?.setupProgress.isPaired == false { - log.info("Version Response %{public}@ indicates pod pairing is now complete", String(describing: versionResponse)) - self.podState?.setupProgress = .podPaired - } - } - - func pairAndSetupPod( - timeZone: TimeZone, - insulinType: InsulinType, - messageLogger: MessageLogger?, - _ block: @escaping (_ result: SessionRunResult) -> Void - ) { - guard let manager = manager else { - // no available Dash pump to communicate with - block(.failure(PodCommsError.noResponse)) - return - } - - let myId = self.myId - let podId = self.podId - log.info("Attempting to pair using myId %X and podId %X", myId, podId) - - manager.runSession(withName: "Pair and setup pod") { [weak self] in - do { - guard let self = self else { fatalError() } - - // Synchronize access to podState - self.podStateLock.lock() - defer { - self.podStateLock.unlock() - } - - try manager.sendHello(myId: myId) - try manager.enableNotifications() // Seemingly this cannot be done before the hello command, or the pod disconnects - - if (!self.isPaired) { - try self.pairPod(insulinType: insulinType) - } else { - try self.establishNewSession() - } - - guard self.podState != nil else { - block(.failure(PodCommsError.noPodPaired)) - return - } - - if self.podState!.setupProgress.isPaired == false { - try self.setupPod(timeZone: timeZone) - } - - guard self.podState!.setupProgress.isPaired else { - self.log.error("Unexpected podStatus setupProgress value of %{public}@", String(describing: self.podState!.setupProgress)) - throw PodCommsError.invalidData - } - - // Run a session now for any post-pairing commands - let transport = PodMessageTransport(manager: manager, myId: myId, podId: podId, state: self.podState!.messageTransportState) - transport.messageLogger = self.messageLogger - let podSession = PodCommsSession(podState: self.podState!, transport: transport, delegate: self) - - block(.success(session: podSession)) - } catch let error as PodCommsError { - block(.failure(error)) - } catch { - block(.failure(PodCommsError.commsError(error: error))) - } - } - } - - enum SessionRunResult { - case success(session: PodCommsSession) - case failure(PodCommsError) - } - - // Use to serialize a set of Pod Commands for a given session - func runSession(withName name: String, _ block: @escaping (_ result: SessionRunResult) -> Void) { - - guard let manager = manager, manager.peripheral.state == .connected else { - block(.failure(PodCommsError.podNotConnected)) - return - } - - manager.runSession(withName: name) { () in - - // Synchronize access to podState - self.podStateLock.lock() - defer { - self.podStateLock.unlock() - } - - guard self.podState != nil else { - block(.failure(PodCommsError.noPodPaired)) - return - } - - let transport = PodMessageTransport(manager: manager, myId: self.myId, podId: self.podId, state: self.podState!.messageTransportState) - transport.messageLogger = self.messageLogger - let podSession = PodCommsSession(podState: self.podState!, transport: transport, delegate: self) - block(.success(session: podSession)) - } - } - - // MARK: - CustomDebugStringConvertible - - public var debugDescription: String { - return [ - "## PodComms", - "* myId: \(String(format: "%08X", myId))", - "* podId: \(String(format: "%08X", podId))", - "delegate: \(String(describing: delegate != nil))", - "" - ].joined(separator: "\n") - } - -} - -// MARK: - OmniBLEConnectionDelegate - -extension PodComms: OmniBLEConnectionDelegate { - func omnipodPeripheralWasRestored(manager: PeripheralManager) { - if let podState = podState, manager.peripheral.identifier.uuidString == podState.bleIdentifier { - self.manager = manager - self.delegate?.omnipodPeripheralWasRestored(manager: manager) - } - } - - func omnipodPeripheralDidConnect(manager: PeripheralManager) { - if let podState = podState, manager.peripheral.identifier.uuidString == podState.bleIdentifier { - needsSessionEstablishment = true - self.manager = manager - self.delegate?.omnipodPeripheralDidConnect(manager: manager) - } - } - - func omnipodPeripheralDidDisconnect(peripheral: CBPeripheral, error: Error?) { - if let podState = podState, peripheral.identifier.uuidString == podState.bleIdentifier { - self.delegate?.omnipodPeripheralDidDisconnect(peripheral: peripheral, error: error) - log.debug("omnipodPeripheralDidDisconnect... will auto-reconnect") - } - } - - func omnipodPeripheralDidFailToConnect(peripheral: CBPeripheral, error: Error?) { - if let podState = podState, peripheral.identifier.uuidString == podState.bleIdentifier { - self.delegate?.omnipodPeripheralDidFailToConnect(peripheral: peripheral, error: error) - log.debug("omnipodPeripheralDidDisconnect... will auto-reconnect") - } - } - -} - -// MARK: - PeripheralManagerDelegate - -extension PodComms: PeripheralManagerDelegate { - - func completeConfiguration(for manager: PeripheralManager) throws { - log.default("PodComms completeConfiguration: isPaired=%{public}@ needsSessionEstablishment=%{public}@", String(describing: self.isPaired), String(describing: needsSessionEstablishment)) - - if self.isPaired && needsSessionEstablishment { - let myId = self.myId - - self.podStateLock.lock() - defer { - self.podStateLock.unlock() - - } - - do { - try manager.sendHello(myId: myId) - try manager.enableNotifications() // Seemingly this cannot be done before the hello command, or the pod disconnects - try self.establishNewSession() - self.delegate?.podCommsDidEstablishSession(self) - } catch { - self.log.error("Pod session sync error: %{public}@", String(describing: error)) - } - - } else { - log.default("Session already established.") - } - } -} - -extension PodComms: PodCommsSessionDelegate { - // We hold podStateLock for the duration of the PodCommsSession - public func podCommsSession(_ podCommsSession: PodCommsSession, didChange state: PodState) { - - // We should already be holding podStateLock during calls to this function, so try() should fail - assert(!podStateLock.try(), "\(#function) should be invoked while holding podStateLock") - - podCommsSession.assertOnSessionQueue() - self.podState = state - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManager/PodCommsSession.swift b/Dependencies/OmniBLE/OmniBLE/PumpManager/PodCommsSession.swift deleted file mode 100644 index 47e288975..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManager/PodCommsSession.swift +++ /dev/null @@ -1,966 +0,0 @@ -// -// PodCommsSession.swift -// OmniBLE -// -// From OmniKit/PumpManager/PodCommsSession.swift -// Created by Pete Schwamb on 10/13/17. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit -import os.log - -public enum PodCommsError: Error { - case noPodPaired - case invalidData - case noResponse - case emptyResponse - case podAckedInsteadOfReturningResponse - case unexpectedResponse(response: MessageBlockType) - case unknownResponseType(rawType: UInt8) - case invalidAddress(address: UInt32, expectedAddress: UInt32) - case podNotConnected - case unfinalizedBolus - case unfinalizedTempBasal - case nonceResyncFailed - case podSuspended - case podFault(fault: DetailedStatus) - case commsError(error: Error) - case unacknowledgedMessage(sequenceNumber: Int, error: Error) - case unacknowledgedCommandPending - case rejectedMessage(errorCode: UInt8) - case podChange - case activationTimeExceeded - case rssiTooLow - case rssiTooHigh - case diagnosticMessage(str: String) - case podIncompatible(str: String) - case noPodsFound - case tooManyPodsFound -} - -extension PodCommsError: LocalizedError { - public var errorDescription: String? { - switch self { - case .noPodPaired: - return LocalizedString("No pod paired", comment: "Error message shown when no pod is paired") - case .invalidData: - return nil - case .noResponse: - return LocalizedString("No response from pod", comment: "Error message shown when no response from pod was received") - case .emptyResponse: - return LocalizedString("Empty response from pod", comment: "Error message shown when empty response from pod was received") - case .podAckedInsteadOfReturningResponse: - return LocalizedString("Pod sent ack instead of response", comment: "Error message shown when pod sends ack instead of response") - case .unexpectedResponse: - return LocalizedString("Unexpected response from pod", comment: "Error message shown when empty response from pod was received") - case .unknownResponseType: - return nil - case .invalidAddress(address: let address, expectedAddress: let expectedAddress): - return String(format: LocalizedString("Invalid address 0x%x. Expected 0x%x", comment: "Error message for when unexpected address is received (1: received address) (2: expected address)"), address, expectedAddress) - case .podNotConnected: - return LocalizedString("Pod not connected", comment: "Error message shown when the pod is not connected.") - case .unfinalizedBolus: - return LocalizedString("Bolus in progress", comment: "Error message shown when operation could not be completed due to existing bolus in progress") - case .unfinalizedTempBasal: - return LocalizedString("Temp basal in progress", comment: "Error message shown when temp basal could not be set due to existing temp basal in progress") - case .nonceResyncFailed: - return nil - case .podSuspended: - return LocalizedString("Pod is suspended", comment: "Error message action could not be performed because pod is suspended") - case .podFault(let fault): - let faultDescription = String(describing: fault.faultEventCode) - return String(format: LocalizedString("Pod Fault: %1$@", comment: "Format string for pod fault code"), faultDescription) - case .commsError(let error): - return error.localizedDescription - case .unacknowledgedMessage(_, let error): - return error.localizedDescription - case .unacknowledgedCommandPending: - return LocalizedString("Communication issue: Unacknowledged command pending.", comment: "Error message when command is rejected because an unacknowledged command is pending.") - case .rejectedMessage(let errorCode): - return String(format: LocalizedString("Command error %1$u", comment: "Format string for invalid message error code (1: error code number)"), errorCode) - case .podChange: - return LocalizedString("Unexpected pod change", comment: "Format string for unexpected pod change") - case .activationTimeExceeded: - return LocalizedString("Activation time exceeded", comment: "Format string for activation time exceeded") - case .rssiTooLow: // occurs when pod is too far for reliable pairing, but can sometimes occur at other distances & positions - return LocalizedString("Poor signal strength", comment: "Format string for poor pod signal strength") - case .rssiTooHigh: // only occurs when pod is too close for reliable pairing - return LocalizedString("Signal strength too high", comment: "Format string for pod signal strength too high") - case .diagnosticMessage(let str): - return str - case .podIncompatible(let str): - return str - case .noPodsFound: - return LocalizedString("No pods found", comment: "Error message for PodCommsError.noPodsFound") - case .tooManyPodsFound: - return LocalizedString("Too many pods found", comment: "Error message for PodCommsError.tooManyPodsFound") - - } - } - -// public var failureReason: String? { -// return nil -// } - - public var recoverySuggestion: String? { - switch self { - case .noPodPaired: - return nil - case .invalidData: - return nil - case .noResponse: - return LocalizedString("Make sure iPhone is nearby the active pod", comment: "Recovery suggestion when no response is received from pod") - case .emptyResponse: - return nil - case .podAckedInsteadOfReturningResponse: - return LocalizedString("Try again", comment: "Recovery suggestion when ack received instead of response") - case .unexpectedResponse: - return nil - case .unknownResponseType: - return nil - case .invalidAddress: - return LocalizedString("Crosstalk possible. Please move to a new location", comment: "Recovery suggestion when unexpected address received") - case .podNotConnected: - return LocalizedString("Make sure your pod is nearby and try again.", comment: "Recovery suggestion when no pod is available") - case .unfinalizedBolus: - return LocalizedString("Wait for existing bolus to finish, or cancel bolus", comment: "Recovery suggestion when operation could not be completed due to existing bolus in progress") - case .unfinalizedTempBasal: - return LocalizedString("Wait for existing temp basal to finish, or suspend to cancel", comment: "Recovery suggestion when operation could not be completed due to existing temp basal in progress") - case .nonceResyncFailed: - return nil - case .podSuspended: - return LocalizedString("Resume delivery", comment: "Recovery suggestion when pod is suspended") - case .podFault: - return nil - case .commsError: - return nil - case .unacknowledgedMessage: - return nil - case .unacknowledgedCommandPending: - return nil - case .rejectedMessage: - return nil - case .podChange: - return LocalizedString("Please bring only original pod in range or deactivate original pod", comment: "Recovery suggestion on unexpected pod change") - case .activationTimeExceeded: - return nil - case .rssiTooLow: - return LocalizedString("Please reposition iPhone relative to the pod", comment: "Recovery suggestion when pairing signal strength is too low") - case .rssiTooHigh: - return LocalizedString("Please reposition iPhone further from the pod", comment: "Recovery suggestion when pairing signal strength is too high") - case .diagnosticMessage: - return nil - case .podIncompatible: - return nil - case .noPodsFound: - return LocalizedString("Make sure your pod is filled and nearby.", comment: "Recovery suggestion for PodCommsError.noPodsFound") - case .tooManyPodsFound: - return LocalizedString("Move to a new area away from any other pods and try again.", comment: "Recovery suggestion for PodCommsError.tooManyPodsFound") - } - } - - public var isFaulted: Bool { - switch self { - case .podFault, .activationTimeExceeded, .podIncompatible: - return true - default: - return false - } - } -} - -public protocol PodCommsSessionDelegate: AnyObject { - func podCommsSession(_ podCommsSession: PodCommsSession, didChange state: PodState) -} - -public class PodCommsSession { - public let log = OSLog(category: "PodCommsSession") - - private var podState: PodState { - didSet { - assertOnSessionQueue() - delegate.podCommsSession(self, didChange: podState) - } - } - - private unowned let delegate: PodCommsSessionDelegate - private var transport: MessageTransport - - // used for testing - var mockCurrentDate: Date? - var currentDate: Date { - return mockCurrentDate ?? Date() - } - - init(podState: PodState, transport: MessageTransport, delegate: PodCommsSessionDelegate) { - self.podState = podState - self.transport = transport - self.delegate = delegate - self.transport.delegate = self - } - - // Handles updating PodState on first pod fault seen - private func handlePodFault(fault: DetailedStatus) { - if podState.fault == nil { - podState.fault = fault // save the first fault returned - if let activatedAt = podState.activatedAt { - podState.activeTime = currentDate.timeIntervalSince(activatedAt) - } else { - podState.activeTime = fault.faultEventTimeSinceActivation - } - handleCancelDosing(deliveryType: .all, bolusNotDelivered: fault.bolusNotDelivered) - let derivedStatusResponse = StatusResponse(detailedStatus: fault) - if podState.unacknowledgedCommand != nil { - recoverUnacknowledgedCommand(using: derivedStatusResponse) - } - podState.updateFromStatusResponse(derivedStatusResponse, at: currentDate) - } - log.error("Pod Fault: %@", String(describing: fault)) - } - - // Will throw either PodCommsError.podFault or PodCommsError.activationTimeExceeded - private func throwPodFault(fault: DetailedStatus) throws { - handlePodFault(fault: fault) - if fault.podProgressStatus == .activationTimeExceeded { - // avoids a confusing "No fault" error when activation time is exceeded - throw PodCommsError.activationTimeExceeded - } - throw PodCommsError.podFault(fault: fault) - } - - /// Performs a message exchange, handling nonce resync, pod faults - /// - /// - Parameters: - /// - messageBlocks: The message blocks to send - /// - beepBlock: Optional confirmation beep block message to append to the message blocks to send - /// - expectFollowOnMessage: If true, the pod will expect another message within 4 minutes, or will alarm with an 0x33 (51) fault. - /// - Returns: The received message response - /// - Throws: - /// - PodCommsError.noResponse - /// - PodCommsError.podFault - /// - PodCommsError.unexpectedResponse - /// - PodCommsError.rejectedMessage - /// - PodCommsError.nonceResyncFailed - /// - MessageError - func send(_ messageBlocks: [MessageBlock], beepBlock: MessageBlock? = nil, expectFollowOnMessage: Bool = false) throws -> T { - - var triesRemaining = 2 // Retries only happen for nonce resync - var blocksToSend = messageBlocks - - // If a beep block was specified & pod isn't faulted, append the beep block to emit the confirmation beep - if let beepBlock = beepBlock, podState.isFaulted == false { - blocksToSend += [beepBlock] - } - -// if blocksToSend.contains(where: { $0 as? NonceResyncableMessageBlock != nil }) { -// podState.advanceToNextNonce() -// } - - let messageNumber = transport.messageNumber - - var sentNonce: UInt32? - - while (triesRemaining > 0) { - triesRemaining -= 1 - - for command in blocksToSend { - if let nonceBlock = command as? NonceResyncableMessageBlock { - sentNonce = nonceBlock.nonce - break // N.B. all nonce commands in single message should have the same value - } - } - - let message = Message(address: podState.address, messageBlocks: blocksToSend, sequenceNum: messageNumber, expectFollowOnMessage: expectFollowOnMessage) - - self.podState.lastCommsOK = false // mark last comms as not OK until we get the expected response - let response = try transport.sendMessage(message) - - // Simulate fault - //let podInfoResponse = try PodInfoResponse(encodedData: Data(hexadecimalString: "0216020d0000000000ab6a038403ff03860000285708030d0000")!) - //let response = Message(address: podState.address, messageBlocks: [podInfoResponse], sequenceNum: message.sequenceNum) - - if let responseMessageBlock = response.messageBlocks[0] as? T { - log.info("POD Response: %{public}@", String(describing: responseMessageBlock)) - self.podState.lastCommsOK = true // message successfully sent and expected response received - return responseMessageBlock - } - - - if let fault = response.fault { - try throwPodFault(fault: fault) // always throws - } - - let responseType = response.messageBlocks[0].blockType - guard let errorResponse = response.messageBlocks[0] as? ErrorResponse else { - log.error("Unexpected response: %{public}@", String(describing: response.messageBlocks[0])) - throw PodCommsError.unexpectedResponse(response: responseType) - } - - switch errorResponse.errorResponseType { - case .badNonce(let nonceResyncKey): - guard let sentNonce = sentNonce else { - log.error("Unexpected bad nonce response: %{public}@", String(describing: response.messageBlocks[0])) - throw PodCommsError.unexpectedResponse(response: responseType) - } - podState.resyncNonce(syncWord: nonceResyncKey, sentNonce: sentNonce, messageSequenceNum: Int(message.sequenceNum)) - log.info("resyncNonce(syncWord: 0x%02x, sentNonce: 0x%04x, messageSequenceNum: %d) -> 0x%04x", nonceResyncKey, sentNonce, message.sequenceNum, podState.currentNonce) - blocksToSend = blocksToSend.map({ (block) -> MessageBlock in - if var resyncableBlock = block as? NonceResyncableMessageBlock { - log.info("Replaced old nonce 0x%04x with resync nonce 0x%04x", resyncableBlock.nonce, podState.currentNonce) - resyncableBlock.nonce = podState.currentNonce - return resyncableBlock - } - return block - }) - podState.advanceToNextNonce() - break - case .nonretryableError(let errorCode, let faultEventCode, let podProgress): - log.error("Command error: code %u, %{public}@, pod progress %{public}@", errorCode, String(describing: faultEventCode), String(describing: podProgress)) - throw PodCommsError.rejectedMessage(errorCode: errorCode) - } - } - throw PodCommsError.nonceResyncFailed - } - - // Returns time at which prime is expected to finish. - public func prime() throws -> TimeInterval { - let primeDuration: TimeInterval = .seconds(Pod.primeUnits / Pod.primeDeliveryRate) + 3 // as per PDM - - // If priming has never been attempted on this pod, handle the pre-prime setup tasks. - // A FaultConfig can only be done before the prime bolus or the pod will generate an 049 fault. - if podState.setupProgress.primingNeverAttempted { - // This FaultConfig command will set Tab5[$16] to 0 during pairing, which disables $6x faults - let _: StatusResponse = try send([FaultConfigCommand(nonce: podState.currentNonce, tab5Sub16: 0, tab5Sub17: 0)]) - - // Set up the finish pod setup reminder alert which beeps every 5 minutes for 1 hour - let finishSetupReminder = PodAlert.finishSetupReminder - try configureAlerts([finishSetupReminder]) - } else { - // Not the first time through, check to see if prime bolus was successfully started - let status: StatusResponse = try send([GetStatusCommand()]) - podState.updateFromStatusResponse(status, at: currentDate) - if status.podProgressStatus == .priming || status.podProgressStatus == .primingCompleted { - podState.setupProgress = .priming - return podState.primeFinishTime?.timeIntervalSinceNow ?? primeDuration - } - } - - // Mark Pod.primeUnits (2.6U) bolus delivery with Pod.primeDeliveryRate (1) between pulses for prime - - let primeFinishTime = currentDate + primeDuration - podState.primeFinishTime = primeFinishTime - podState.setupProgress = .startingPrime - - let timeBetweenPulses = TimeInterval(seconds: Pod.secondsPerPrimePulse) - let scheduleCommand = SetInsulinScheduleCommand(nonce: podState.currentNonce, units: Pod.primeUnits, timeBetweenPulses: timeBetweenPulses) - let bolusExtraCommand = BolusExtraCommand(units: Pod.primeUnits, timeBetweenPulses: timeBetweenPulses) - let status: StatusResponse = try send([scheduleCommand, bolusExtraCommand]) - podState.updateFromStatusResponse(status, at: currentDate) - podState.setupProgress = .priming - return primeFinishTime.timeIntervalSinceNow - } - - public func programInitialBasalSchedule(_ basalSchedule: BasalSchedule, scheduleOffset: TimeInterval) throws { - if podState.setupProgress == .settingInitialBasalSchedule { - // We started basal schedule programming, but didn't get confirmation somehow, so check status - let status: StatusResponse = try send([GetStatusCommand()]) - podState.updateFromStatusResponse(status, at: currentDate) - if status.podProgressStatus == .basalInitialized { - podState.setupProgress = .initialBasalScheduleSet - return - } - } - - podState.setupProgress = .settingInitialBasalSchedule - // Set basal schedule - let _ = try setBasalSchedule(schedule: basalSchedule, scheduleOffset: scheduleOffset) - podState.setupProgress = .initialBasalScheduleSet - podState.finalizedDoses.append(UnfinalizedDose(resumeStartTime: currentDate, scheduledCertainty: .certain, insulinType: podState.insulinType)) - } - - // Configures the given pod alert(s) and registers the newly configured alert slot(s). - // When re-configuring all the pod alerts for a silence pod toggle, the optional acknowledgeAll can be - // specified to first acknowledge and clear all possible pending pod alerts and pod alert configurations. - @discardableResult - func configureAlerts(_ alerts: [PodAlert], acknowledgeAll: Bool = false, beepBlock: MessageBlock? = nil) throws -> StatusResponse { - let configurations = alerts.map { $0.configuration } - let configureAlerts = ConfigureAlertsCommand(nonce: podState.currentNonce, configurations: configurations) - let blocksToSend: [MessageBlock] - if acknowledgeAll { - // Do the acknowledgeAllAlerts command first to clear all previous pod alert configurations. - let acknowledgeAllAlerts = AcknowledgeAlertCommand(nonce: podState.currentNonce, alerts: AlertSet(rawValue: ~0)) - blocksToSend = [acknowledgeAllAlerts, configureAlerts] - } else { - blocksToSend = [configureAlerts] - } - let status: StatusResponse = try send(blocksToSend, beepBlock: beepBlock) - for alert in alerts { - podState.registerConfiguredAlert(slot: alert.configuration.slot, alert: alert) - } - podState.updateFromStatusResponse(status, at: currentDate) - return status - } - - // emits the specified beep type and sets the completion beep flags, doesn't throw - public func beepConfig(beepType: BeepType, tempBasalCompletionBeep: Bool, bolusCompletionBeep: Bool) -> Result { - if let fault = self.podState.fault { - log.info("Skip beep config with faulted pod") - return .failure(PodCommsError.podFault(fault: fault)) - } - - let beepConfigCommand = BeepConfigCommand(beepType: beepType, tempBasalCompletionBeep: tempBasalCompletionBeep, bolusCompletionBeep: bolusCompletionBeep) - do { - let statusResponse: StatusResponse = try send([beepConfigCommand]) - podState.updateFromStatusResponse(statusResponse, at: currentDate) - return .success(statusResponse) - } catch let error { - return .failure(error) - } - } - - private func markSetupProgressCompleted(statusResponse: StatusResponse) { - if (podState.setupProgress != .completed) { - podState.setupProgress = .completed - podState.setupUnitsDelivered = statusResponse.insulinDelivered // stash the current insulin delivered value as the baseline - log.info("Total setup units delivered: %@", String(describing: statusResponse.insulinDelivered)) - } - } - - public func insertCannula(optionalAlerts: [PodAlert] = [], silent: Bool) throws -> TimeInterval { - let cannulaInsertionUnits = Pod.cannulaInsertionUnits + Pod.cannulaInsertionUnitsExtra - let insertionWait: TimeInterval = .seconds(cannulaInsertionUnits / Pod.primeDeliveryRate) - - guard podState.activatedAt != nil else { - throw PodCommsError.noPodPaired - } - - if podState.setupProgress == .startingInsertCannula || podState.setupProgress == .cannulaInserting { - // We started cannula insertion, but didn't get confirmation somehow, so check status - let status: StatusResponse = try send([GetStatusCommand()]) - if status.podProgressStatus == .insertingCannula { - podState.setupProgress = .cannulaInserting - podState.updateFromStatusResponse(status, at: currentDate) - return insertionWait // Not sure when it started, wait full time to be sure - } - if status.podProgressStatus.readyForDelivery { - markSetupProgressCompleted(statusResponse: status) - podState.updateFromStatusResponse(status, at: currentDate) - return TimeInterval(0) // Already done; no need to wait - } - podState.updateFromStatusResponse(status, at: currentDate) - } else { - let elapsed: TimeInterval = -(podState.podTimeUpdated?.timeIntervalSinceNow ?? 0) - let podTime = podState.podTime + elapsed - - // Configure the mandatory Pod Alerts for shutdown imminent alert (79 hours) and pod expiration alert (72 hours) along with any optional alerts - let shutdownImminentAlarm = PodAlert.shutdownImminent(offset: podTime, absAlertTime: Pod.serviceDuration - Pod.endOfServiceImminentWindow, silent: silent) - let expirationAdvisoryAlarm = PodAlert.expired(offset: podTime, absAlertTime: Pod.nominalPodLife, duration: Pod.expirationAdvisoryWindow, silent: silent) - try configureAlerts([expirationAdvisoryAlarm, shutdownImminentAlarm] + optionalAlerts) - } - - // Mark cannulaInsertionUnits (0.5U) bolus delivery with Pod.secondsPerPrimePulse (1) between pulses for cannula insertion - - let timeBetweenPulses = TimeInterval(seconds: Pod.secondsPerPrimePulse) - let bolusScheduleCommand = SetInsulinScheduleCommand(nonce: podState.currentNonce, units: cannulaInsertionUnits, timeBetweenPulses: timeBetweenPulses) - - podState.setupProgress = .startingInsertCannula - let bolusExtraCommand = BolusExtraCommand(units: cannulaInsertionUnits, timeBetweenPulses: timeBetweenPulses) - let status2: StatusResponse = try send([bolusScheduleCommand, bolusExtraCommand]) - podState.updateFromStatusResponse(status2, at: currentDate) - - podState.setupProgress = .cannulaInserting - return insertionWait - } - - public func checkInsertionCompleted() throws { - if podState.setupProgress == .cannulaInserting { - let response: StatusResponse = try send([GetStatusCommand()]) - if response.podProgressStatus.readyForDelivery { - markSetupProgressCompleted(statusResponse: response) - } - podState.updateFromStatusResponse(response, at: currentDate) - } - } - - // Throws SetBolusError - public enum DeliveryCommandResult { - case success(statusResponse: StatusResponse) - case certainFailure(error: PodCommsError) - case unacknowledged(error: PodCommsError) - } - - public enum CancelDeliveryResult { - case success(statusResponse: StatusResponse, canceledDose: UnfinalizedDose?) - case certainFailure(error: PodCommsError) - case unacknowledged(error: PodCommsError) - } - - - public func bolus(units: Double, automatic: Bool = false, acknowledgementBeep: Bool = false, completionBeep: Bool = false, programReminderInterval: TimeInterval = 0, extendedUnits: Double = 0.0, extendedDuration: TimeInterval = 0) -> DeliveryCommandResult { - - guard podState.unacknowledgedCommand == nil else { - return DeliveryCommandResult.certainFailure(error: .unacknowledgedCommandPending) - } - - let timeBetweenPulses = TimeInterval(seconds: Pod.secondsPerBolusPulse) - let bolusScheduleCommand = SetInsulinScheduleCommand(nonce: podState.currentNonce, units: units, timeBetweenPulses: timeBetweenPulses, extendedUnits: extendedUnits, extendedDuration: extendedDuration) - - // Do a getstatus to verify that there isn't an on-going bolus in progress if the last bolus command is still - // finalized, if the last delivery status wasn't successfully verified or the last comms attempt wasn't OK - if podState.unfinalizedBolus != nil || !podState.deliveryStatusVerified || !podState.lastCommsOK { - var ongoingBolus = true - if let statusResponse: StatusResponse = try? send([GetStatusCommand()]) { - podState.updateFromStatusResponse(statusResponse, at: currentDate) - ongoingBolus = podState.unfinalizedBolus != nil - } - guard !ongoingBolus else { - return DeliveryCommandResult.certainFailure(error: .unfinalizedBolus) - } - } - - let bolusExtraCommand = BolusExtraCommand(units: units, timeBetweenPulses: timeBetweenPulses, extendedUnits: extendedUnits, extendedDuration: extendedDuration, acknowledgementBeep: acknowledgementBeep, completionBeep: completionBeep, programReminderInterval: programReminderInterval) - do { - podState.unacknowledgedCommand = PendingCommand.program(.bolus(volume: units, automatic: automatic), transport.messageNumber, currentDate) - let statusResponse: StatusResponse = try send([bolusScheduleCommand, bolusExtraCommand]) - podState.unacknowledgedCommand = nil - podState.unfinalizedBolus = UnfinalizedDose(bolusAmount: units, startTime: currentDate, scheduledCertainty: .certain, insulinType: podState.insulinType, automatic: automatic) - podState.updateFromStatusResponse(statusResponse, at: currentDate) - return DeliveryCommandResult.success(statusResponse: statusResponse) - } catch PodCommsError.unacknowledgedMessage(let seq, let error) { - podState.unacknowledgedCommand = podState.unacknowledgedCommand?.commsFinished - log.error("Unacknowledged bolus: command seq = %d, error = %{public}@", seq, String(describing: error)) - return DeliveryCommandResult.unacknowledged(error: .commsError(error: error)) - } catch let error { - podState.unacknowledgedCommand = nil - return DeliveryCommandResult.certainFailure(error: .commsError(error: error)) - } - } - - public func setTempBasal(rate: Double, duration: TimeInterval, isHighTemp: Bool, automatic: Bool, acknowledgementBeep: Bool = false, completionBeep: Bool = false, programReminderInterval: TimeInterval = 0) -> DeliveryCommandResult { - - guard podState.unacknowledgedCommand == nil else { - return DeliveryCommandResult.certainFailure(error: .unacknowledgedCommandPending) - } - - let tempBasalCommand = SetInsulinScheduleCommand(nonce: podState.currentNonce, tempBasalRate: rate, duration: duration) - let tempBasalExtraCommand = TempBasalExtraCommand(rate: rate, duration: duration, acknowledgementBeep: acknowledgementBeep, completionBeep: completionBeep, programReminderInterval: programReminderInterval) - - guard podState.unfinalizedBolus?.isFinished() != false else { - return DeliveryCommandResult.certainFailure(error: .unfinalizedBolus) - } - - let startTime = currentDate - - do { - podState.unacknowledgedCommand = PendingCommand.program(.tempBasal(unitsPerHour: rate, duration: duration, isHighTemp: isHighTemp, automatic: automatic), transport.messageNumber, startTime) - let status: StatusResponse = try send([tempBasalCommand, tempBasalExtraCommand]) - podState.unacknowledgedCommand = nil - podState.unfinalizedTempBasal = UnfinalizedDose(tempBasalRate: rate, startTime: startTime, duration: duration, isHighTemp: isHighTemp, automatic: automatic, scheduledCertainty: .certain, insulinType: podState.insulinType) - podState.updateFromStatusResponse(status, at: currentDate) - return DeliveryCommandResult.success(statusResponse: status) - } catch PodCommsError.unacknowledgedMessage(let seq, let error) { - podState.unacknowledgedCommand = podState.unacknowledgedCommand?.commsFinished - log.error("Unacknowledged temp basal: command seq = %d, error = %{public}@", seq, String(describing: error)) - return DeliveryCommandResult.unacknowledged(error: .commsError(error: error)) - } catch let error { - podState.unacknowledgedCommand = nil - return DeliveryCommandResult.certainFailure(error: .commsError(error: error)) - } - } - - @discardableResult - private func handleCancelDosing(deliveryType: CancelDeliveryCommand.DeliveryType, bolusNotDelivered: Double) -> UnfinalizedDose? { - var canceledDose: UnfinalizedDose? = nil - let now = currentDate - - if deliveryType.contains(.basal) { - podState.unfinalizedSuspend = UnfinalizedDose(suspendStartTime: now, scheduledCertainty: .certain) - podState.suspendState = .suspended(now) - } - - if let unfinalizedTempBasal = podState.unfinalizedTempBasal, - let finishTime = unfinalizedTempBasal.finishTime, - deliveryType.contains(.tempBasal), - finishTime > now - { - podState.unfinalizedTempBasal?.cancel(at: now) - if !deliveryType.contains(.basal) { - podState.suspendState = .resumed(now) - } - canceledDose = podState.unfinalizedTempBasal - log.info("Interrupted temp basal: %@", String(describing: canceledDose)) - } - - if let unfinalizedBolus = podState.unfinalizedBolus, - let finishTime = unfinalizedBolus.finishTime, - deliveryType.contains(.bolus), - finishTime > now - { - podState.unfinalizedBolus?.cancel(at: now, withRemaining: bolusNotDelivered) - canceledDose = podState.unfinalizedBolus - log.info("Interrupted bolus: %@", String(describing: canceledDose)) - } - - return canceledDose - } - - // Suspends insulin delivery and sets appropriate podSuspendedReminder & suspendTimeExpired alerts. - // A nil suspendReminder is an untimed suspend with no suspend reminders. - // A suspendReminder of 0 is an untimed suspend which only uses podSuspendedReminder alert beeps. - // A suspendReminder of 1-5 minutes will only use suspendTimeExpired alert beeps. - // A suspendReminder of > 5 min will have periodic podSuspendedReminder beeps followed by suspendTimeExpired alerts. - // The configured alerts will set up as silent pod alerts if silent is true. - public func suspendDelivery(suspendReminder: TimeInterval? = nil, silent: Bool, beepBlock: MessageBlock? = nil) -> CancelDeliveryResult { - - guard podState.unacknowledgedCommand == nil else { - return .certainFailure(error: .unacknowledgedCommandPending) - } - - do { - var alertConfigurations: [AlertConfiguration] = [] - var podSuspendedReminderAlert: PodAlert? = nil - var suspendTimeExpiredAlert: PodAlert? = nil - let suspendTime: TimeInterval = suspendReminder != nil ? suspendReminder! : 0 - let elapsed: TimeInterval = -(podState.podTimeUpdated?.timeIntervalSinceNow ?? 0) - let podTime = podState.podTime + elapsed - log.debug("suspendDelivery: podState.podTime=%@, elapsed=%.2fs, computed timeActive %@", podState.podTime.timeIntervalStr, elapsed, podTime.timeIntervalStr) - - let cancelDeliveryCommand = CancelDeliveryCommand(nonce: podState.currentNonce, deliveryType: .all, beepType: .noBeepCancel) - var commandsToSend: [MessageBlock] = [cancelDeliveryCommand] - - // podSuspendedReminder provides a periodic pod suspended reminder beep until the specified suspend time. - if suspendReminder != nil && (suspendTime == 0 || suspendTime > .minutes(5)) { - // using reminder beeps for an untimed or long enough suspend time requiring pod suspended reminders - podSuspendedReminderAlert = PodAlert.podSuspendedReminder(active: true, offset: podTime, suspendTime: suspendTime, silent: silent) - alertConfigurations += [podSuspendedReminderAlert!.configuration] - } - - // suspendTimeExpired provides suspend time expired alert beeping after the expected suspend time has passed. - if suspendTime > 0 { - // a timed suspend using a suspend time expired alert - suspendTimeExpiredAlert = PodAlert.suspendTimeExpired(offset: podTime, suspendTime: suspendTime, silent: silent) - alertConfigurations += [suspendTimeExpiredAlert!.configuration] - } - - // append a ConfigureAlert command if we have any reminder alerts for this suspend - if alertConfigurations.count != 0 { - let configureAlerts = ConfigureAlertsCommand(nonce: podState.currentNonce, configurations: alertConfigurations) - commandsToSend += [configureAlerts] - } - - podState.unacknowledgedCommand = PendingCommand.stopProgram(.all, transport.messageNumber, currentDate) - let status: StatusResponse = try send(commandsToSend, beepBlock: beepBlock) - podState.unacknowledgedCommand = nil - let canceledDose = handleCancelDosing(deliveryType: .all, bolusNotDelivered: status.bolusNotDelivered) - podState.updateFromStatusResponse(status, at: currentDate) - - if let alert = podSuspendedReminderAlert { - podState.registerConfiguredAlert(slot: alert.configuration.slot, alert: alert) - } - if let alert = suspendTimeExpiredAlert { - podState.registerConfiguredAlert(slot: alert.configuration.slot, alert: alert) - } - - return CancelDeliveryResult.success(statusResponse: status, canceledDose: canceledDose) - - } catch PodCommsError.unacknowledgedMessage(let seq, let error) { - podState.unacknowledgedCommand = podState.unacknowledgedCommand?.commsFinished - log.error("Unacknowledged suspend: command seq = %d, error = %{public}@", seq, String(describing: error)) - return .unacknowledged(error: .commsError(error: error)) - } catch let error { - podState.unacknowledgedCommand = nil - return .certainFailure(error: .commsError(error: error)) - } - } - - // Cancels any suspend related alerts, called when setting a basal schedule with active suspend alerts - @discardableResult - private func cancelSuspendAlerts() throws -> StatusResponse { - - do { - let podSuspendedReminder = PodAlert.podSuspendedReminder(active: false, offset: 0, suspendTime: 0) - let suspendTimeExpired = PodAlert.suspendTimeExpired(offset: 0, suspendTime: 0) // A suspendTime of 0 deactivates this alert - - let status = try configureAlerts([podSuspendedReminder, suspendTimeExpired]) - return status - } catch let error { - throw error - } - } - - // Cancel beeping can be done implemented using beepType (for a single delivery type) or a separate confirmation beep message block (for cancel all). - // N.B., Using the built-in cancel delivery command beepType method when cancelling all insulin delivery will emit 3 different sets of cancel beeps!!! - public func cancelDelivery(deliveryType: CancelDeliveryCommand.DeliveryType, beepType: BeepType = .noBeepCancel, beepBlock: MessageBlock? = nil) -> CancelDeliveryResult { - - guard podState.unacknowledgedCommand == nil else { - return .certainFailure(error: .unacknowledgedCommandPending) - } - - do { - podState.unacknowledgedCommand = PendingCommand.stopProgram(deliveryType, transport.messageNumber, currentDate) - let cancelDeliveryCommand = CancelDeliveryCommand(nonce: podState.currentNonce, deliveryType: deliveryType, beepType: beepType) - let status: StatusResponse = try send([cancelDeliveryCommand], beepBlock: beepBlock) - podState.unacknowledgedCommand = nil - - let canceledDose = handleCancelDosing(deliveryType: deliveryType, bolusNotDelivered: status.bolusNotDelivered) - podState.updateFromStatusResponse(status, at: currentDate) - - return CancelDeliveryResult.success(statusResponse: status, canceledDose: canceledDose) - } catch PodCommsError.unacknowledgedMessage(let seq, let error) { - podState.unacknowledgedCommand = podState.unacknowledgedCommand?.commsFinished - log.debug("Unacknowledged stop program: command seq = %d", seq) - return .unacknowledged(error: .commsError(error: error)) - } catch let error { - podState.unacknowledgedCommand = nil - return .certainFailure(error: .commsError(error: error)) - } - } - - public func setTime(timeZone: TimeZone, basalSchedule: BasalSchedule, date: Date, acknowledgementBeep: Bool = false) throws -> StatusResponse { - guard podState.unacknowledgedCommand == nil else { - throw PodCommsError.unacknowledgedCommandPending - } - - let result = cancelDelivery(deliveryType: .all) - switch result { - case .certainFailure(let error): - throw error - case .unacknowledged(let error): - throw error - case .success: - let scheduleOffset = timeZone.scheduleOffset(forDate: date) - let status = try setBasalSchedule(schedule: basalSchedule, scheduleOffset: scheduleOffset, acknowledgementBeep: acknowledgementBeep) - return status - } - } - - public func setBasalSchedule(schedule: BasalSchedule, scheduleOffset: TimeInterval, acknowledgementBeep: Bool = false, programReminderInterval: TimeInterval = 0) throws -> StatusResponse { - - guard podState.unacknowledgedCommand == nil else { - throw PodCommsError.unacknowledgedCommandPending - } - - let basalScheduleCommand = SetInsulinScheduleCommand(nonce: podState.currentNonce, basalSchedule: schedule, scheduleOffset: scheduleOffset) - let basalExtraCommand = BasalScheduleExtraCommand.init(schedule: schedule, scheduleOffset: scheduleOffset, acknowledgementBeep: acknowledgementBeep, programReminderInterval: programReminderInterval) - - do { - if podState.setupProgress == .completed && !(podState.lastCommsOK && podState.deliveryStatusVerified) { - // The pod setup is complete and the current delivery state can't be trusted so - // do a cancel all to be sure that setting the basal program won't fault the pod. - let _: StatusResponse = try send([CancelDeliveryCommand(nonce: podState.currentNonce, deliveryType: .all, beepType: .noBeepCancel)]) - } - var status: StatusResponse = try send([basalScheduleCommand, basalExtraCommand]) - let now = currentDate - podState.suspendState = .resumed(now) - podState.unfinalizedResume = UnfinalizedDose(resumeStartTime: now, scheduledCertainty: .certain, insulinType: podState.insulinType) - if hasActiveSuspendAlert(configuredAlerts: podState.configuredAlerts), - let cancelStatus = try? cancelSuspendAlerts() - { - status = cancelStatus // update using the latest status - } - podState.updateFromStatusResponse(status, at: currentDate) - return status - } catch PodCommsError.nonceResyncFailed { - throw PodCommsError.nonceResyncFailed - } catch PodCommsError.rejectedMessage(let errorCode) { - throw PodCommsError.rejectedMessage(errorCode: errorCode) - } catch let error { - podState.unfinalizedResume = UnfinalizedDose(resumeStartTime: currentDate, scheduledCertainty: .uncertain, insulinType: podState.insulinType) - throw error - } - } - - public func resumeBasal(schedule: BasalSchedule, scheduleOffset: TimeInterval, acknowledgementBeep: Bool = false, programReminderInterval: TimeInterval = 0) throws -> StatusResponse { - - guard podState.unacknowledgedCommand == nil else { - throw PodCommsError.unacknowledgedCommandPending - } - - - let status = try setBasalSchedule(schedule: schedule, scheduleOffset: scheduleOffset, acknowledgementBeep: acknowledgementBeep, programReminderInterval: programReminderInterval) - - podState.suspendState = .resumed(currentDate) - - return status - } - - // use cancelDelivery with .none to get status as well as to validate & advance the nonce - // Throws PodCommsError - @discardableResult - public func cancelNone(beepBlock: MessageBlock? = nil) throws -> StatusResponse { - var statusResponse: StatusResponse - - let cancelResult: CancelDeliveryResult = cancelDelivery(deliveryType: .none, beepBlock: beepBlock) - switch cancelResult { - case .certainFailure(let error): - throw error - case .unacknowledged(let error): - throw error - case .success(let response, _): - statusResponse = response - } - podState.updateFromStatusResponse(statusResponse, at: currentDate) - return statusResponse - } - - // Throws PodCommsError - @discardableResult - public func getStatus(beepBlock: MessageBlock? = nil) throws -> StatusResponse { - let statusResponse: StatusResponse = try send([GetStatusCommand()], beepBlock: beepBlock) - - if podState.unacknowledgedCommand != nil { - recoverUnacknowledgedCommand(using: statusResponse) - } - podState.updateFromStatusResponse(statusResponse, at: currentDate) - return statusResponse - } - - @discardableResult - public func getDetailedStatus(beepBlock: MessageBlock? = nil) throws -> DetailedStatus { - let infoResponse: PodInfoResponse = try send([GetStatusCommand(podInfoType: .detailedStatus)], beepBlock: beepBlock) - - guard let detailedStatus = infoResponse.podInfo as? DetailedStatus else { - throw PodCommsError.unexpectedResponse(response: .podInfoResponse) - } - if detailedStatus.isFaulted && self.podState.fault == nil { - // just detected that the pod has faulted, handle setting the fault state but don't throw - handlePodFault(fault: detailedStatus) - } else { - let derivedStatusResponse = StatusResponse(detailedStatus: detailedStatus) - if podState.unacknowledgedCommand != nil { - recoverUnacknowledgedCommand(using: derivedStatusResponse) - } - podState.updateFromStatusResponse(derivedStatusResponse, at: currentDate) - } - return detailedStatus - } - - @discardableResult - public func readPodInfo(podInfoResponseSubType: PodInfoResponseSubType, beepBlock: MessageBlock? = nil) throws -> PodInfoResponse { - let podInfoCommand = GetStatusCommand(podInfoType: podInfoResponseSubType) - let podInfoResponse: PodInfoResponse = try send([podInfoCommand], beepBlock: beepBlock) - return podInfoResponse - } - - // Reconnected to the pod, and we know program was successful - private func unacknowledgedCommandWasReceived(pendingCommand: PendingCommand, podStatus: StatusResponse) { - switch pendingCommand { - case .program(let program, _, let commandDate, _): - if let dose = program.unfinalizedDose(at: commandDate, withCertainty: .certain, insulinType: podState.insulinType) { - switch dose.doseType { - case .bolus: - podState.unfinalizedBolus = dose - case .tempBasal: - podState.unfinalizedTempBasal = dose - case .resume: - podState.suspendState = .resumed(commandDate) - default: - break - } - } - case .stopProgram(let stopProgram, _, let commandDate, _): - - if stopProgram.contains(.bolus), let bolus = podState.unfinalizedBolus, !bolus.isFinished(at: commandDate) { - podState.unfinalizedBolus?.cancel(at: commandDate, withRemaining: podStatus.bolusNotDelivered) - } - if stopProgram.contains(.tempBasal), let tempBasal = podState.unfinalizedTempBasal, !tempBasal.isFinished(at: commandDate) { - podState.unfinalizedTempBasal?.cancel(at: commandDate) - } - if stopProgram.contains(.basal) { - podState.finalizedDoses.append(UnfinalizedDose(suspendStartTime: commandDate, scheduledCertainty: .certain)) - podState.suspendState = .suspended(commandDate) - } - } - } - - public func recoverUnacknowledgedCommand(using status: StatusResponse) { - if let pendingCommand = podState.unacknowledgedCommand { - self.log.default("Recovering from unacknowledged command %{public}@, status = %{public}@", String(describing: pendingCommand), String(describing: status)) - - if status.lastProgrammingMessageSeqNum == pendingCommand.sequence { - self.log.debug("Unacknowledged command was received by pump") - unacknowledgedCommandWasReceived(pendingCommand: pendingCommand, podStatus: status) - } else { - self.log.debug("Unacknowledged command was not received by pump") - } - podState.unacknowledgedCommand = nil - } - } - - // Can be called a second time to deactivate a given pod - public func deactivatePod() throws { - - // Don't try to cancel if the pod hasn't completed its setup as it will either receive no response - // (pod progress state <= 2) or creates a $31 pod fault (pod progress states 3 through 7). - if podState.setupProgress == .completed && podState.fault == nil && !podState.isSuspended { - let result = cancelDelivery(deliveryType: .all) - switch result { - case .certainFailure(let error): - throw error - case .unacknowledged(let error): - throw error - default: - break - } - } - - // Try to read the most recent pulse log entries for possible later analysis - _ = try? readPodInfo(podInfoResponseSubType: .pulseLogRecent) - if podState.fault != nil { - // Try to read the previous pulse log entries on the faulted pod - _ = try? readPodInfo(podInfoResponseSubType: .pulseLogPrevious) - } - - do { - let deactivatePod = DeactivatePodCommand(nonce: podState.currentNonce) - let status: StatusResponse = try send([deactivatePod]) - - if podState.unacknowledgedCommand != nil { - recoverUnacknowledgedCommand(using: status) - } - podState.updateFromStatusResponse(status, at: currentDate) - - if podState.activeTime == nil, let activatedAt = podState.activatedAt { - podState.activeTime = currentDate.timeIntervalSince(activatedAt) - } - } catch let error as PodCommsError { - switch error { - case .podFault, .activationTimeExceeded, .unexpectedResponse: - break - default: - throw error - } - } - } - - public func acknowledgeAlerts(alerts: AlertSet, beepBlock: MessageBlock? = nil) throws -> AlertSet { - let cmd = AcknowledgeAlertCommand(nonce: podState.currentNonce, alerts: alerts) - let status: StatusResponse = try send([cmd], beepBlock: beepBlock) - podState.updateFromStatusResponse(status, at: currentDate) - return podState.activeAlertSlots - } - - func dosesForStorage(_ storageHandler: ([UnfinalizedDose]) -> Bool) { - assertOnSessionQueue() - - let dosesToStore = podState.dosesToStore - - if storageHandler(dosesToStore) { - log.info("Stored doses: %@", String(describing: dosesToStore)) - self.podState.finalizedDoses.removeAll() - } - } - - public func assertOnSessionQueue() { - transport.assertOnSessionQueue() - } -} - -extension PodCommsSession: MessageTransportDelegate { - func messageTransport(_ messageTransport: MessageTransport, didUpdate state: MessageTransportState) { - messageTransport.assertOnSessionQueue() - podState.messageTransportState = state - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManager/PodState.swift b/Dependencies/OmniBLE/OmniBLE/PumpManager/PodState.swift deleted file mode 100644 index 31fc77a9f..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManager/PodState.swift +++ /dev/null @@ -1,644 +0,0 @@ -// -// PodState.swift -// OmniBLE -// -// Based on OmniKit/PumpManager/PodState.swift -// Created by Pete Schwamb on 10/13/17. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -public enum SetupProgress: Int { - case addressAssigned = 0 - case podPaired - case startingPrime - case priming - case settingInitialBasalSchedule - case initialBasalScheduleSet - case startingInsertCannula - case cannulaInserting - case completed - case activationTimeout - case podIncompatible - - public var isPaired: Bool { - return self.rawValue >= SetupProgress.podPaired.rawValue - } - - public var primingNeverAttempted: Bool { - return self.rawValue < SetupProgress.startingPrime.rawValue - } - - public var primingNeeded: Bool { - return self.rawValue < SetupProgress.priming.rawValue - } - - public var needsInitialBasalSchedule: Bool { - return self.rawValue < SetupProgress.initialBasalScheduleSet.rawValue - } - - public var needsCannulaInsertion: Bool { - return self.rawValue < SetupProgress.completed.rawValue - } -} - -// TODO: Mutating functions aren't guaranteed to synchronize read/write calls. -// mutating funcs should be moved to something like this: -// extension Locked where T == PodState { -// } -public struct PodState: RawRepresentable, Equatable, CustomDebugStringConvertible { - - public typealias RawValue = [String: Any] - - public let address: UInt32 - public let ltk: Data - - public var bleIdentifier: String - - public var activatedAt: Date? - public var expiresAt: Date? // set based on timeActive and can change with Pod clock drift and/or system time change - public var activeTime: TimeInterval? // Useful after pod deactivated or faulted. - - public var podTime: TimeInterval // pod time from the last response, always whole minute values - public var podTimeUpdated: Date? // time that the podTime value was last updated - - public var setupUnitsDelivered: Double? - - public let firmwareVersion: String - public let bleFirmwareVersion: String - public let lotNo: UInt32 - public let lotSeq: UInt32 - public let productId: UInt8 - public var activeAlertSlots: AlertSet - public var lastInsulinMeasurements: PodInsulinMeasurements? - - public var unacknowledgedCommand: PendingCommand? - - public var unfinalizedBolus: UnfinalizedDose? - public var unfinalizedTempBasal: UnfinalizedDose? - public var unfinalizedSuspend: UnfinalizedDose? - public var unfinalizedResume: UnfinalizedDose? - - var finalizedDoses: [UnfinalizedDose] - - public var dosesToStore: [UnfinalizedDose] { - return finalizedDoses + [unfinalizedTempBasal, unfinalizedSuspend, unfinalizedBolus].compactMap {$0} - } - - public var suspendState: SuspendState - - public var isSuspended: Bool { - if case .suspended = suspendState { - return true - } - return false - } - - public var fault: DetailedStatus? - public var messageTransportState: MessageTransportState - public var primeFinishTime: Date? - public var setupProgress: SetupProgress - public var configuredAlerts: [AlertSlot: PodAlert] - public var insulinType: InsulinType - - // Allow a grace period while the unacknowledged command is first being sent. - public var needsCommsRecovery: Bool { - if let unacknowledgedCommand = unacknowledgedCommand, !unacknowledgedCommand.isInFlight { - return true - } - return false - } - - // the following two vars are not persistent across app restarts - public var deliveryStatusVerified: Bool - public var lastCommsOK: Bool - - public init(address: UInt32, ltk: Data, firmwareVersion: String, bleFirmwareVersion: String, lotNo: UInt32, lotSeq: UInt32, productId: UInt8, messageTransportState: MessageTransportState? = nil, bleIdentifier: String, insulinType: InsulinType) { - self.address = address - self.ltk = ltk - self.firmwareVersion = firmwareVersion - self.bleFirmwareVersion = bleFirmwareVersion - self.lotNo = lotNo - self.lotSeq = lotSeq - self.productId = productId - self.lastInsulinMeasurements = nil - self.finalizedDoses = [] - self.suspendState = .resumed(Date()) - self.fault = nil - self.activeAlertSlots = .none - self.messageTransportState = messageTransportState ?? MessageTransportState(ck: nil, noncePrefix: nil) - self.primeFinishTime = nil - self.setupProgress = .addressAssigned - self.configuredAlerts = [.slot7Expired: .waitingForPairingReminder] - self.bleIdentifier = bleIdentifier - self.insulinType = insulinType - self.deliveryStatusVerified = false - self.lastCommsOK = false - self.podTime = 0 - } - - public var unfinishedSetup: Bool { - return setupProgress != .completed - } - - public var readyForCannulaInsertion: Bool { - guard let primeFinishTime = self.primeFinishTime else { - return false - } - return !setupProgress.primingNeeded && primeFinishTime.timeIntervalSinceNow < 0 - } - - public var isActive: Bool { - return setupProgress == .completed && fault == nil - } - - // variation on isActive that doesn't care if Pod is faulted - public var isSetupComplete: Bool { - return setupProgress == .completed - } - - public var isFaulted: Bool { - return fault != nil || setupProgress == .activationTimeout || setupProgress == .podIncompatible - } - - public mutating func incrementEapSeq() -> Int { - self.messageTransportState.eapSeq += 1 - return messageTransportState.eapSeq - } - - public mutating func advanceToNextNonce() { - // Dash nonce is a fixed value and is never advanced - } - - public var currentNonce: UInt32 { - let fixedNonceValue: UInt32 = 0x494E532E // Dash pods require this particular fixed value - return fixedNonceValue - } - - public mutating func resyncNonce(syncWord: UInt16, sentNonce: UInt32, messageSequenceNum: Int) { - print("resyncNonce expectedly called!") // Should never be called for Dash! - } - - // Saves the current pod timeActive and will initialize the activatedAtComputed at - // pod startup and updates the expiresAt value to account for pod clock differences. - private mutating func updatePodTimes(timeActive: TimeInterval) -> Date { - let now = Date() - - guard timeActive >= self.podTime else { - // The pod active time went backwards and thus we have an apparent reset fault. - // Don't update any times or displayed expiresAt time will expectedly jump. - return now - } - - self.podTime = timeActive - self.podTimeUpdated = now - - let activatedAtComputed = now - timeActive - if activatedAt == nil { - self.activatedAt = activatedAtComputed - } - let expiresAtComputed = activatedAtComputed + Pod.nominalPodLife - if expiresAt == nil { - self.expiresAt = expiresAtComputed - } else if expiresAtComputed < self.expiresAt! || expiresAtComputed > (self.expiresAt! + TimeInterval(minutes: 1)) { - // The computed expiresAt time is earlier than or more than a minute later than the current expiresAt time, - // so use the computed expiresAt time instead to handle Pod clock drift and/or system time changes issues. - // The more than a minute later test prevents oscillation of expiresAt based on the timing of the responses. - self.expiresAt = expiresAtComputed - } - return now - } - - public mutating func updateFromStatusResponse(_ response: StatusResponse, at date: Date = Date()) { - let now = updatePodTimes(timeActive: response.timeActive) - updateDeliveryStatus(deliveryStatus: response.deliveryStatus, podProgressStatus: response.podProgressStatus, bolusNotDelivered: response.bolusNotDelivered, at: date) - - let setupUnits = setupUnitsDelivered ?? Pod.primeUnits + Pod.cannulaInsertionUnits + Pod.cannulaInsertionUnitsExtra - - // Calculated new delivered value which will be a negative value until setup has completed OR after a pod reset fault - let calcDelivered = response.insulinDelivered - setupUnits - - // insulinDelivered should never be a negative value or decrease from the previous saved delivered value - let prevDelivered = lastInsulinMeasurements?.delivered ?? 0 - let insulinDelivered = max(calcDelivered, prevDelivered) - - lastInsulinMeasurements = PodInsulinMeasurements(insulinDelivered: insulinDelivered, reservoirLevel: response.reservoirLevel, validTime: now) - - activeAlertSlots = response.alerts - } - - public mutating func registerConfiguredAlert(slot: AlertSlot, alert: PodAlert) { - configuredAlerts[slot] = alert - } - - public mutating func finalizeAllDoses() { - if let bolus = unfinalizedBolus { - finalizedDoses.append(bolus) - unfinalizedBolus = nil - } - - if let tempBasal = unfinalizedTempBasal { - finalizedDoses.append(tempBasal) - unfinalizedTempBasal = nil - } - } - - // Giving up on pod; we will assume commands failed/succeeded in the direction of positive net delivery - mutating func resolveAnyPendingCommandWithUncertainty() { - guard let pendingCommand = unacknowledgedCommand else { - return - } - - switch pendingCommand { - case .program(let program, _, let commandDate, _): - - if let dose = program.unfinalizedDose(at: commandDate, withCertainty: .uncertain, insulinType: insulinType) { - switch dose.doseType { - case .bolus: - if dose.isFinished() { - finalizedDoses.append(dose) - } else { - unfinalizedBolus = dose - } - case .tempBasal: - // Assume a high temp succeeded, but low temp failed - if case .tempBasal(_, _, let isHighTemp, _) = program, isHighTemp { - if dose.isFinished() { - finalizedDoses.append(dose) - } else { - unfinalizedTempBasal = dose - } - } - case .resume: - finalizedDoses.append(dose) - case .suspend: - break // start program is never a suspend - } - } - case .stopProgram(let stopProgram, _, let commandDate, _): - // All stop programs result in reduced delivery, except for stopping a low temp, so we assume all stop - // commands failed, except for low temp - - - if stopProgram.contains(.tempBasal), - let tempBasal = unfinalizedTempBasal, - tempBasal.isHighTemp, - !tempBasal.isFinished(at: commandDate) - { - unfinalizedTempBasal?.cancel(at: commandDate) - } - } - self.unacknowledgedCommand = nil - } - - - private mutating func updateDeliveryStatus(deliveryStatus: DeliveryStatus, podProgressStatus: PodProgressStatus, bolusNotDelivered: Double, at date: Date) { - - deliveryStatusVerified = true - // See if the pod deliveryStatus indicates an active bolus or temp basal that the PodState isn't tracking (possible Loop restart) - if deliveryStatus.bolusing && unfinalizedBolus == nil { // active bolus that Loop doesn't know about? - if podProgressStatus.readyForDelivery { - deliveryStatusVerified = false // remember that we had inconsistent (bolus) delivery status - // Create an unfinalizedBolus with the remaining bolus amount to capture what we can. - unfinalizedBolus = UnfinalizedDose(bolusAmount: bolusNotDelivered, startTime: date, scheduledCertainty: .certain, insulinType: insulinType, automatic: false) - } - } - if deliveryStatus.tempBasalRunning && unfinalizedTempBasal == nil { // active temp basal that app isn't tracking - deliveryStatusVerified = false // remember that we had inconsistent (temp basal) delivery status - // unfinalizedTempBasal = UnfinalizedDose(tempBasalRate: 0, startTime: Date(), duration: .minutes(30), isHighTemp: false, scheduledCertainty: .certain, insulinType: insulinType) - } - if deliveryStatus != .suspended && isSuspended { // active basal that app isn't tracking - deliveryStatusVerified = false // remember that we had inconsistent (basal) delivery status - let resumeStartTime = Date() - suspendState = .resumed(resumeStartTime) - unfinalizedResume = UnfinalizedDose(resumeStartTime: resumeStartTime, scheduledCertainty: .certain, insulinType: insulinType) - } - - if var bolus = unfinalizedBolus, !deliveryStatus.bolusing { - // Due to clock drift or comms delays, boluses can finish earlier than we expect - if !bolus.isFinished() { - bolus.finishTime = date - } - finalizedDoses.append(bolus) - unfinalizedBolus = nil - } - - if var tempBasal = unfinalizedTempBasal, !deliveryStatus.tempBasalRunning { - if !tempBasal.isFinished() { - tempBasal.finishTime = date - } - finalizedDoses.append(tempBasal) - unfinalizedTempBasal = nil - } - - if let suspend = unfinalizedSuspend { - - if let resume = unfinalizedResume, suspend.startTime < resume.startTime { - finalizedDoses.append(suspend) - finalizedDoses.append(resume) - unfinalizedSuspend = nil - unfinalizedResume = nil - } - } - } - - // MARK: - RawRepresentable - public init?(rawValue: RawValue) { - - guard - let address = rawValue["address"] as? UInt32, - let ltkString = rawValue["ltk"] as? String, - let firmwareVersion = rawValue["firmwareVersion"] as? String, - let bleFirmwareVersion = rawValue["bleFirmwareVersion"] as? String, - let bleIdentifier = rawValue["bleIdentifier"] as? String, - let lotNo = rawValue["lotNo"] as? UInt32, - let lotSeq = rawValue["lotSeq"] as? UInt32 - else { - return nil - } - - let formatVersion: Int = rawValue["version"] as? Int ?? 1 - - self.address = address - self.ltk = Data(hex: ltkString) - self.firmwareVersion = firmwareVersion - self.bleFirmwareVersion = bleFirmwareVersion - self.lotNo = lotNo - self.lotSeq = lotSeq - if let productId = rawValue["productId"] as? UInt8 { - self.productId = productId - } else { - self.productId = dashProductId - } - self.bleIdentifier = bleIdentifier - - self.activeTime = rawValue["activeTime"] as? TimeInterval - - if let activatedAt = rawValue["activatedAt"] as? Date { - self.activatedAt = activatedAt - if let expiresAt = rawValue["expiresAt"] as? Date { - self.expiresAt = expiresAt - } else { - self.expiresAt = activatedAt + Pod.nominalPodLife - } - } - - if let podTime = rawValue["podTime"] as? TimeInterval, - let podTimeUpdated = rawValue["podTimeUpdated"] as? Date - { - self.podTime = podTime - self.podTimeUpdated = podTimeUpdated - } else { - self.podTime = 0 - self.podTimeUpdated = Date() - } - - if let setupUnitsDelivered = rawValue["setupUnitsDelivered"] as? Double { - self.setupUnitsDelivered = setupUnitsDelivered - } - - if let suspended = rawValue["suspended"] as? Bool { - // Migrate old value - if suspended { - suspendState = .suspended(Date()) - } else { - suspendState = .resumed(Date()) - } - } else if let rawSuspendState = rawValue["suspendState"] as? SuspendState.RawValue, let suspendState = SuspendState(rawValue: rawSuspendState) { - self.suspendState = suspendState - } else { - return nil - } - - if let rawPendingCommand = rawValue["unacknowledgedCommand"] as? PendingCommand.RawValue { - // When loading from raw state, we know comms are no longer in progress; this helps recover from a crash - self.unacknowledgedCommand = PendingCommand(rawValue: rawPendingCommand)?.commsFinished - } else { - self.unacknowledgedCommand = nil - } - - if let rawUnfinalizedBolus = rawValue["unfinalizedBolus"] as? UnfinalizedDose.RawValue - { - self.unfinalizedBolus = UnfinalizedDose(rawValue: rawUnfinalizedBolus) - } - - if let rawUnfinalizedTempBasal = rawValue["unfinalizedTempBasal"] as? UnfinalizedDose.RawValue - { - self.unfinalizedTempBasal = UnfinalizedDose(rawValue: rawUnfinalizedTempBasal) - } - - if let rawUnfinalizedSuspend = rawValue["unfinalizedSuspend"] as? UnfinalizedDose.RawValue - { - self.unfinalizedSuspend = UnfinalizedDose(rawValue: rawUnfinalizedSuspend) - } - - if let rawUnfinalizedResume = rawValue["unfinalizedResume"] as? UnfinalizedDose.RawValue - { - self.unfinalizedResume = UnfinalizedDose(rawValue: rawUnfinalizedResume) - } - - if let rawLastInsulinMeasurements = rawValue["lastInsulinMeasurements"] as? PodInsulinMeasurements.RawValue { - self.lastInsulinMeasurements = PodInsulinMeasurements(rawValue: rawLastInsulinMeasurements) - } else { - self.lastInsulinMeasurements = nil - } - - if let rawFinalizedDoses = rawValue["finalizedDoses"] as? [UnfinalizedDose.RawValue] { - self.finalizedDoses = rawFinalizedDoses.compactMap( { UnfinalizedDose(rawValue: $0) } ) - } else { - self.finalizedDoses = [] - } - - if let rawFault = rawValue["fault"] as? DetailedStatus.RawValue, - let fault = DetailedStatus(rawValue: rawFault), - fault.faultEventCode.faultType != .noFaults - { - self.fault = fault - } else { - self.fault = nil - } - - if let alarmsRawValue = rawValue["alerts"] as? UInt8 { - self.activeAlertSlots = AlertSet(rawValue: alarmsRawValue) - } else { - self.activeAlertSlots = .none - } - - if let setupProgressRaw = rawValue["setupProgress"] as? Int, - let setupProgress = SetupProgress(rawValue: setupProgressRaw) - { - self.setupProgress = setupProgress - } else { - // Migrate - self.setupProgress = .completed - } - - if let messageTransportStateRaw = rawValue["messageTransportState"] as? MessageTransportState.RawValue, - let messageTransportState = MessageTransportState(rawValue: messageTransportStateRaw) - { - self.messageTransportState = messageTransportState - } else { - self.messageTransportState = MessageTransportState(ck: nil, noncePrefix: nil) - } - - if let rawConfiguredAlerts = rawValue["configuredAlerts"] as? [String: PodAlert.RawValue], formatVersion >= 2 { - var configuredAlerts = [AlertSlot: PodAlert]() - for (rawSlot, rawAlert) in rawConfiguredAlerts { - if let slotNum = UInt8(rawSlot), let slot = AlertSlot(rawValue: slotNum), let alert = PodAlert(rawValue: rawAlert) { - configuredAlerts[slot] = alert - } - } - self.configuredAlerts = configuredAlerts - } else { - // Assume migration, and set up with alerts that are normally configured - self.configuredAlerts = [ - .slot2ShutdownImminent: .shutdownImminent(offset: 0, absAlertTime: 0), - .slot3ExpirationReminder: .expirationReminder(offset: 0, absAlertTime: 0), - .slot4LowReservoir: .lowReservoir(units: 0), - .slot5SuspendedReminder: .podSuspendedReminder(active: false, offset: 0, suspendTime: 0), - .slot6SuspendTimeExpired: .suspendTimeExpired(offset: 0, suspendTime: 0), - .slot7Expired: .expired(offset: 0, absAlertTime: 0, duration: 0) - ] - } - - self.primeFinishTime = rawValue["primeFinishTime"] as? Date - - if let rawInsulinType = rawValue["insulinType"] as? InsulinType.RawValue, let insulinType = InsulinType(rawValue: rawInsulinType) { - self.insulinType = insulinType - } else { - self.insulinType = .novolog - } - - self.deliveryStatusVerified = false - self.lastCommsOK = false - } - - public var rawValue: RawValue { - var rawValue: RawValue = [ - "version": 2, // Version of encoding format. 1 = old alert names - "address": address, - "ltk": ltk.hexadecimalString, - "eapAkaSequenceNumber": 1, // keep for back migration, was always 1 - "firmwareVersion": firmwareVersion, - "bleFirmwareVersion": bleFirmwareVersion, - "lotNo": lotNo, - "lotSeq": lotSeq, - "suspendState": suspendState.rawValue, - "finalizedDoses": finalizedDoses.map( { $0.rawValue }), - "alerts": activeAlertSlots.rawValue, - "messageTransportState": messageTransportState.rawValue, - "setupProgress": setupProgress.rawValue, - "bleIdentifier": bleIdentifier, - "insulinType": insulinType.rawValue - ] - - rawValue["unacknowledgedCommand"] = unacknowledgedCommand?.rawValue - rawValue["unfinalizedBolus"] = unfinalizedBolus?.rawValue - rawValue["unfinalizedTempBasal"] = unfinalizedTempBasal?.rawValue - rawValue["unfinalizedSuspend"] = unfinalizedSuspend?.rawValue - rawValue["unfinalizedResume"] = unfinalizedResume?.rawValue - rawValue["lastInsulinMeasurements"] = lastInsulinMeasurements?.rawValue - rawValue["fault"] = fault?.rawValue - rawValue["primeFinishTime"] = primeFinishTime - rawValue["activatedAt"] = activatedAt - rawValue["expiresAt"] = expiresAt - rawValue["podTime"] = podTime - rawValue["podTimeUpdated"] = podTimeUpdated - rawValue["setupUnitsDelivered"] = setupUnitsDelivered - rawValue["activeTime"] = activeTime - - if configuredAlerts.count > 0 { - let rawConfiguredAlerts = Dictionary(uniqueKeysWithValues: - configuredAlerts.map { slot, alarm in (String(describing: slot.rawValue), alarm.rawValue) }) - rawValue["configuredAlerts"] = rawConfiguredAlerts - } - - return rawValue - } - - // MARK: - CustomDebugStringConvertible - - public var debugDescription: String { - return [ - "### PodState", - "* address: \(String(format: "%08X", address))", - "* bleIdentifier: \(bleIdentifier)", - "* activatedAt: \(String(reflecting: activatedAt))", - "* expiresAt: \(String(reflecting: expiresAt))", - "* podTime: \(podTime.timeIntervalStr)", - "* podTimeUpdated: \(String(reflecting: podTimeUpdated))", - "* setupUnitsDelivered: \(String(reflecting: setupUnitsDelivered))", - "* firmwareVersion: \(firmwareVersion)", - "* bleFirmwareVersion: \(bleFirmwareVersion)", - "* lotNo: \(lotNo)", - "* lotSeq: \(lotSeq)", - "* suspendState: \(suspendState)", - "* unacknowledgedCommand: \(String(describing: unacknowledgedCommand))", - "* unfinalizedBolus: \(String(describing: unfinalizedBolus))", - "* unfinalizedTempBasal: \(String(describing: unfinalizedTempBasal))", - "* unfinalizedSuspend: \(String(describing: unfinalizedSuspend))", - "* unfinalizedResume: \(String(describing: unfinalizedResume))", - "* finalizedDoses: \(String(describing: finalizedDoses))", - "* activeAlertsSlots: \(alertSetString(alertSet: activeAlertSlots))", - "* messageTransportState: \(String(describing: messageTransportState))", - "* setupProgress: \(setupProgress)", - "* primeFinishTime: \(String(describing: primeFinishTime))", - "* configuredAlerts: \(configuredAlertsString(configuredAlerts: configuredAlerts))", - "* insulinType: \(String(describing: insulinType))", - "* pdmRef: " + (fault?.pdmRef == nil ? "nil" : String(describing: fault!.pdmRef!)), - "* Fault: " + (fault == nil ? "nil" : String(describing: fault!)), - ].joined(separator: "\n") - } -} - -public enum SuspendState: Equatable, RawRepresentable { - public typealias RawValue = [String: Any] - - private enum SuspendStateType: Int { - case suspend, resume - } - - case suspended(Date) - case resumed(Date) - - private var identifier: Int { - switch self { - case .suspended: - return 1 - case .resumed: - return 2 - } - } - - public init?(rawValue: RawValue) { - guard let suspendStateType = rawValue["case"] as? SuspendStateType.RawValue, - let date = rawValue["date"] as? Date else { - return nil - } - switch SuspendStateType(rawValue: suspendStateType) { - case .suspend?: - self = .suspended(date) - case .resume?: - self = .resumed(date) - default: - return nil - } - } - - public var rawValue: RawValue { - switch self { - case .suspended(let date): - return [ - "case": SuspendStateType.suspend.rawValue, - "date": date - ] - case .resumed(let date): - return [ - "case": SuspendStateType.resume.rawValue, - "date": date - ] - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEHUDProvider.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEHUDProvider.swift deleted file mode 100644 index 03501503f..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEHUDProvider.swift +++ /dev/null @@ -1,138 +0,0 @@ -// -// OmniBLEHUDProvider.swift -// OmniBLE -// -// Based on OmniKitUI/PumpManager/OmniBLEHUDProvider.swift -// Created by Pete Schwamb on 11/26/18. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import UIKit -import SwiftUI -import LoopKit -import LoopKitUI - -public enum ReservoirAlertState { - case ok - case lowReservoir - case empty -} - -internal class OmniBLEHUDProvider: NSObject, HUDProvider { - var managerIdentifier: String { - return pumpManager.managerIdentifier - } - - private let pumpManager: OmniBLEPumpManager - - private var reservoirView: OmniBLEReservoirView? - - private let bluetoothProvider: BluetoothProvider - - private let colorPalette: LoopUIColorPalette - - private var refreshTimer: Timer? - - private let allowedInsulinTypes: [InsulinType] - - var visible: Bool = false { - didSet { - if oldValue != visible && visible { - hudDidAppear() - } - } - } - - public init(pumpManager: OmniBLEPumpManager, bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowedInsulinTypes: [InsulinType]) { - self.pumpManager = pumpManager - self.bluetoothProvider = bluetoothProvider - self.colorPalette = colorPalette - self.allowedInsulinTypes = allowedInsulinTypes - super.init() - self.pumpManager.addPodStateObserver(self, queue: .main) - } - - public func createHUDView() -> BaseHUDView? { - reservoirView = OmniBLEReservoirView.instantiate() - updateReservoirView() - - return reservoirView - } - - public func didTapOnHUDView(_ view: BaseHUDView, allowDebugFeatures: Bool) -> HUDTapAction? { - let vc = pumpManager.settingsViewController(bluetoothProvider: bluetoothProvider, colorPalette: colorPalette, allowDebugFeatures: allowDebugFeatures, allowedInsulinTypes: allowedInsulinTypes) - return HUDTapAction.presentViewController(vc) - } - - func hudDidAppear() { - updateReservoirView() - refresh() - } - - public var hudViewRawState: HUDProvider.HUDViewRawState { - var rawValue: HUDProvider.HUDViewRawState = [:] - - rawValue["lastStatusDate"] = pumpManager.lastStatusDate - - if let reservoirLevel = pumpManager.reservoirLevel { - rawValue["reservoirLevel"] = reservoirLevel.rawValue - } - - if let reservoirLevelHighlightState = pumpManager.reservoirLevelHighlightState { - rawValue["reservoirLevelHighlightState"] = reservoirLevelHighlightState.rawValue - } - - return rawValue - } - - public static func createHUDView(rawValue: HUDProvider.HUDViewRawState) -> BaseHUDView? { - guard let rawReservoirLevel = rawValue["reservoirLevel"] as? ReservoirLevel.RawValue, - let rawReservoirLevelHighlightState = rawValue["reservoirLevelHighlightState"] as? ReservoirLevelHighlightState.RawValue, - let reservoirLevelHighlightState = ReservoirLevelHighlightState(rawValue: rawReservoirLevelHighlightState) - else { - return nil - } - - let reservoirView: OmniBLEReservoirView? - - let reservoirLevel = ReservoirLevel(rawValue: rawReservoirLevel) - - if let lastStatusDate = rawValue["lastStatusDate"] as? Date { - reservoirView = OmniBLEReservoirView.instantiate() - reservoirView!.update(level: reservoirLevel, at: lastStatusDate, reservoirLevelHighlightState: reservoirLevelHighlightState) - } else { - reservoirView = nil - } - - return reservoirView - } - - private func refresh() { - pumpManager.getPodStatus() { _ in - DispatchQueue.main.async { - self.updateReservoirView() - } - } - } - - private func updateReservoirView() { - guard let reservoirView = reservoirView, - let lastStatusDate = pumpManager.lastStatusDate, - let reservoirLevelHighlightState = pumpManager.reservoirLevelHighlightState else - { - return - } - - reservoirView.update(level: pumpManager.reservoirLevel, at: lastStatusDate, reservoirLevelHighlightState: reservoirLevelHighlightState) - } -} - -extension OmniBLEHUDProvider: PodStateObserver { - func podConnectionStateDidChange(isConnected: Bool) { - // ignore for now - } - - func podStateDidUpdate(_ state: PodState?) { - updateReservoirView() - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEPumpManager+UI.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEPumpManager+UI.swift deleted file mode 100644 index d1ac630db..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEPumpManager+UI.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// OmniBLEPumpManager+UI.swift -// OmniBLE -// -// Based on OmniKitUI/PumpManager/OmnipodPumpManager+UI.swift -// Created by Pete Schwamb on 8/4/18. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -import UIKit -import LoopKit -import LoopKitUI -import SwiftUI - -extension OmniBLEPumpManager: PumpManagerUI { - public static var onboardingImage: UIImage? { - return UIImage(named: "Onboarding", in: Bundle(for: OmniBLESettingsViewModel.self), compatibleWith: nil) - } - - public static func setupViewController(initialSettings settings: PumpManagerSetupSettings, bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool, allowedInsulinTypes: [InsulinType]) -> SetupUIResult - { - let vc = DashUICoordinator(colorPalette: colorPalette, pumpManagerSettings: settings, allowDebugFeatures: allowDebugFeatures, allowedInsulinTypes: allowedInsulinTypes) - return .userInteractionRequired(vc) - } - - public func settingsViewController(bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool, allowedInsulinTypes: [InsulinType]) -> PumpManagerViewController { - return DashUICoordinator(pumpManager: self, colorPalette: colorPalette, allowDebugFeatures: allowDebugFeatures, allowedInsulinTypes: allowedInsulinTypes) - } - - public func deliveryUncertaintyRecoveryViewController(colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) -> (UIViewController & CompletionNotifying) { - return DashUICoordinator(pumpManager: self, colorPalette: colorPalette, allowDebugFeatures: allowDebugFeatures) - } - - public var smallImage: UIImage? { - return UIImage(named: "Pod", in: Bundle(for: OmniBLESettingsViewModel.self), compatibleWith: nil)! - } - - public func hudProvider(bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowedInsulinTypes: [InsulinType]) -> HUDProvider? { - return OmniBLEHUDProvider(pumpManager: self, bluetoothProvider: bluetoothProvider, colorPalette: colorPalette, allowedInsulinTypes: allowedInsulinTypes) - } - - public static func createHUDView(rawValue: HUDProvider.HUDViewRawState) -> BaseHUDView? { - return OmniBLEHUDProvider.createHUDView(rawValue: rawValue) - } -} - -public enum OmniBLEStatusBadge: DeviceStatusBadge { - case timeSyncNeeded - - public var image: UIImage? { - switch self { - case .timeSyncNeeded: - return UIImage(systemName: "clock.fill") - } - } - - public var state: DeviceStatusBadgeState { - switch self { - case .timeSyncNeeded: - return .warning - } - } -} - -// MARK: - PumpStatusIndicator -extension OmniBLEPumpManager { - - public var pumpStatusHighlight: DeviceStatusHighlight? { - return buildPumpStatusHighlight(for: state) - } - - public var pumpLifecycleProgress: DeviceLifecycleProgress? { - return buildPumpLifecycleProgress(for: state) - } - - public var pumpStatusBadge: DeviceStatusBadge? { - if isClockOffset { - return OmniBLEStatusBadge.timeSyncNeeded - } else { - return nil - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Cannula Inserted.imageset/CannulaInserted.png b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Cannula Inserted.imageset/CannulaInserted.png deleted file mode 100644 index a5cad5892..000000000 Binary files a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Cannula Inserted.imageset/CannulaInserted.png and /dev/null differ diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Cannula Inserted.imageset/Contents.json b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Cannula Inserted.imageset/Contents.json deleted file mode 100644 index 26bf5fbad..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Cannula Inserted.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "CannulaInserted.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Contents.json b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Contents.json deleted file mode 100644 index da4a164c9..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Pod.imageset/Contents.json b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Pod.imageset/Contents.json deleted file mode 100644 index 27c1a878d..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Pod.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "pod1x.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "pod2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "pod3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Pod.imageset/pod1x.png b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Pod.imageset/pod1x.png deleted file mode 100644 index e15cf636c..000000000 Binary files a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Pod.imageset/pod1x.png and /dev/null differ diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Pod.imageset/pod2x.png b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Pod.imageset/pod2x.png deleted file mode 100644 index 7656aef0a..000000000 Binary files a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Pod.imageset/pod2x.png and /dev/null differ diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Pod.imageset/pod3x.png b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Pod.imageset/pod3x.png deleted file mode 100644 index 9d91d8108..000000000 Binary files a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/Pod.imageset/pod3x.png and /dev/null differ diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodBottom.imageset/Contents.json b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodBottom.imageset/Contents.json deleted file mode 100644 index 10c5a72aa..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodBottom.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "filename" : "PodBottom1x.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "filename" : "PodBottom2x.png", - "idiom" : "universal", - "scale" : "2x" - }, - { - "filename" : "PodBottom3x.png", - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodBottom.imageset/PodBottom1x.png b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodBottom.imageset/PodBottom1x.png deleted file mode 100644 index 41fa12c99..000000000 Binary files a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodBottom.imageset/PodBottom1x.png and /dev/null differ diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodBottom.imageset/PodBottom2x.png b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodBottom.imageset/PodBottom2x.png deleted file mode 100644 index 052fe79d1..000000000 Binary files a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodBottom.imageset/PodBottom2x.png and /dev/null differ diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodBottom.imageset/PodBottom3x.png b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodBottom.imageset/PodBottom3x.png deleted file mode 100644 index e8354ce24..000000000 Binary files a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodBottom.imageset/PodBottom3x.png and /dev/null differ diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodLarge.imageset/Contents.json b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodLarge.imageset/Contents.json deleted file mode 100644 index 1249161af..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodLarge.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "PodLarge@1x.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "PodLarge@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "PodLarge@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodLarge.imageset/PodLarge@1x.png b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodLarge.imageset/PodLarge@1x.png deleted file mode 100644 index 5ef798057..000000000 Binary files a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodLarge.imageset/PodLarge@1x.png and /dev/null differ diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodLarge.imageset/PodLarge@2x.png b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodLarge.imageset/PodLarge@2x.png deleted file mode 100644 index 92e6ef21e..000000000 Binary files a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodLarge.imageset/PodLarge@2x.png and /dev/null differ diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodLarge.imageset/PodLarge@3x.png b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodLarge.imageset/PodLarge@3x.png deleted file mode 100644 index f3571b9db..000000000 Binary files a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/PodLarge.imageset/PodLarge@3x.png and /dev/null differ diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/pod_reservoir_mask_swiftui.imageset/Contents.json b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/pod_reservoir_mask_swiftui.imageset/Contents.json deleted file mode 100644 index c20046946..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/pod_reservoir_mask_swiftui.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "filename" : "pod_reservoir_mask.svg", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "preserves-vector-representation" : true, - "template-rendering-intent" : "template" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/pod_reservoir_mask_swiftui.imageset/pod_reservoir_mask.svg b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/pod_reservoir_mask_swiftui.imageset/pod_reservoir_mask.svg deleted file mode 100644 index abe1a576c..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/pod_reservoir_mask_swiftui.imageset/pod_reservoir_mask.svg +++ /dev/null @@ -1,55 +0,0 @@ - -image/svg+xml diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/pod_reservoir_swiftui.imageset/Contents.json b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/pod_reservoir_swiftui.imageset/Contents.json deleted file mode 100644 index 25baae2d3..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/pod_reservoir_swiftui.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "pod_reservoir.svg", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "preserves-vector-representation" : true - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/pod_reservoir_swiftui.imageset/pod_reservoir.svg b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/pod_reservoir_swiftui.imageset/pod_reservoir.svg deleted file mode 100644 index 276ed5c4b..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/OmniBLEUI.xcassets/pod_reservoir_swiftui.imageset/pod_reservoir.svg +++ /dev/null @@ -1,59 +0,0 @@ - -image/svg+xml diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewControllers/DashUICoordinator.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewControllers/DashUICoordinator.swift deleted file mode 100644 index 7dc5f5035..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewControllers/DashUICoordinator.swift +++ /dev/null @@ -1,419 +0,0 @@ -// -// DashSetupViewController.swift -// OmniBLE -// -// Created by Pete Schwamb on 2/16/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -import UIKit -import SwiftUI -import Combine -import LoopKit -import LoopKitUI - -enum DashUIScreen { - case firstRunScreen - case expirationReminderSetup - case lowReservoirReminderSetup - case insulinTypeSelection - case pairPod - case insertCannula - case confirmAttachment - case checkInsertedCannula - case setupComplete - case pendingCommandRecovery - case uncertaintyRecovered - case deactivate - case settings - - func next() -> DashUIScreen? { - switch self { - case .firstRunScreen: - return .expirationReminderSetup - case .expirationReminderSetup: - return .lowReservoirReminderSetup - case .lowReservoirReminderSetup: - return .insulinTypeSelection - case .insulinTypeSelection: - return .pairPod - case .pairPod: - return .confirmAttachment - case .confirmAttachment: - return .insertCannula - case .insertCannula: - return .checkInsertedCannula - case .checkInsertedCannula: - return .setupComplete - case .setupComplete: - return nil - case .pendingCommandRecovery: - return .deactivate - case .uncertaintyRecovered: - return nil - case .deactivate: - return .pairPod - case .settings: - return nil - } - } -} - -protocol DashUINavigator: AnyObject { - func navigateTo(_ screen: DashUIScreen) -} - -class DashUICoordinator: UINavigationController, PumpManagerOnboarding, CompletionNotifying, UINavigationControllerDelegate { - - public weak var pumpManagerOnboardingDelegate: PumpManagerOnboardingDelegate? - - public weak var completionDelegate: CompletionDelegate? - - var pumpManager: OmniBLEPumpManager - - private var disposables = Set() - - var currentScreen: DashUIScreen { - return screenStack.last! - } - - var screenStack = [DashUIScreen]() - - private let colorPalette: LoopUIColorPalette - - private var pumpManagerType: OmniBLEPumpManager.Type? - - private var allowedInsulinTypes: [InsulinType] - - private var allowDebugFeatures: Bool - - private func viewControllerForScreen(_ screen: DashUIScreen) -> UIViewController { - switch screen { - case .firstRunScreen: - let view = PodSetupView(nextAction: { [weak self] in self?.stepFinished() }, - allowDebugFeatures: allowDebugFeatures, - skipOnboarding: { [weak self] in // NOTE: DEBUG FEATURES - DEBUG AND TEST ONLY - guard let self = self else { return } - self.pumpManager.completeOnboard() - self.completionDelegate?.completionNotifyingDidComplete(self) - }) - return hostingController(rootView: view) - case .expirationReminderSetup: - var view = ExpirationReminderSetupView(expirationReminderDefault: Int(pumpManager.defaultExpirationReminderOffset.hours)) - view.valueChanged = { [weak self] value in - self?.pumpManager.defaultExpirationReminderOffset = .hours(Double(value)) - } - view.continueButtonTapped = { [weak self] in - guard let self = self else { return } - if !self.pumpManager.isOnboarded { - self.pumpManager.completeOnboard() - self.pumpManagerOnboardingDelegate?.pumpManagerOnboarding(didOnboardPumpManager: self.pumpManager) - } - self.stepFinished() - } - view.cancelButtonTapped = { [weak self] in - self?.setupCanceled() - } - let hostedView = hostingController(rootView: view) - hostedView.navigationItem.title = LocalizedString("Expiration Reminder", comment: "Title for ExpirationReminderSetupView") - return hostedView - case .lowReservoirReminderSetup: - var view = LowReservoirReminderSetupView(lowReservoirReminderValue: Int(pumpManager.lowReservoirReminderValue)) - view.valueChanged = { [weak self] value in - self?.pumpManager.lowReservoirReminderValue = Double(value) - } - view.continueButtonTapped = { [weak self] in - self?.pumpManager.initialConfigurationCompleted = true - self?.stepFinished() - } - view.cancelButtonTapped = { [weak self] in - self?.setupCanceled() - } - let hostedView = hostingController(rootView: view) - hostedView.navigationItem.title = LocalizedString("Low Reservoir", comment: "Title for LowReservoirReminderSetupView") - hostedView.navigationItem.backButtonDisplayMode = .generic - return hostedView - case .insulinTypeSelection: - let didConfirm: (InsulinType) -> Void = { [weak self] (confirmedType) in - self?.pumpManager.insulinType = confirmedType - self?.stepFinished() - } - let didCancel: () -> Void = { [weak self] in - self?.setupCanceled() - } - - let insulinSelectionView = InsulinTypeConfirmation(initialValue: .novolog, supportedInsulinTypes: allowedInsulinTypes, didConfirm: didConfirm, didCancel: didCancel) - let hostedView = hostingController(rootView: insulinSelectionView) - hostedView.navigationItem.title = LocalizedString("Insulin Type", comment: "Title for insulin type selection screen") - return hostedView - case .deactivate: - let viewModel = DeactivatePodViewModel(podDeactivator: pumpManager, podAttachedToBody: pumpManager.podAttachmentConfirmed, fault: pumpManager.state.podState?.fault) - - viewModel.didFinish = { [weak self] in - self?.stepFinished() - } - viewModel.didCancel = { [weak self] in - self?.setupCanceled() - } - let view = DeactivatePodView(viewModel: viewModel) - let hostedView = hostingController(rootView: view) - hostedView.navigationItem.title = LocalizedString("Deactivate Pod", comment: "Title for deactivate pod screen") - return hostedView - case .settings: - let viewModel = OmniBLESettingsViewModel(pumpManager: pumpManager) - viewModel.didFinish = { [weak self] in - self?.stepFinished() - } - viewModel.navigateTo = { [weak self] (screen) in - self?.navigateTo(screen) - } - let view = OmniBLESettingsView(viewModel: viewModel, supportedInsulinTypes: allowedInsulinTypes) - return hostingController(rootView: view) - case .pairPod: - pumpManagerOnboardingDelegate?.pumpManagerOnboarding(didCreatePumpManager: pumpManager) - - let viewModel = PairPodViewModel(podPairer: pumpManager) - - viewModel.didFinish = { [weak self] in - self?.stepFinished() - } - viewModel.didCancelSetup = { [weak self] in - self?.setupCanceled() - } - viewModel.didRequestDeactivation = { [weak self] in - self?.navigateTo(.deactivate) - } - - let view = hostingController(rootView: PairPodView(viewModel: viewModel)) - view.navigationItem.title = LocalizedString("Pair Pod", comment: "Title for pod pairing screen") - view.navigationItem.backButtonDisplayMode = .generic - return view - case .confirmAttachment: - let view = AttachPodView( - didConfirmAttachment: { [weak self] in - self?.pumpManager.podAttachmentConfirmed = true - self?.stepFinished() - }, - didRequestDeactivation: { [weak self] in - self?.navigateTo(.deactivate) - }) - - let vc = hostingController(rootView: view) - vc.navigationItem.title = LocalizedString("Attach Pod", comment: "Title for Attach Pod screen") - vc.navigationItem.hidesBackButton = true - return vc - - case .insertCannula: - let viewModel = InsertCannulaViewModel(cannulaInserter: pumpManager) - - viewModel.didFinish = { [weak self] in - self?.stepFinished() - } - viewModel.didRequestDeactivation = { [weak self] in - self?.navigateTo(.deactivate) - } - - let view = hostingController(rootView: InsertCannulaView(viewModel: viewModel)) - view.navigationItem.title = LocalizedString("Insert Cannula", comment: "Title for insert cannula screen") - view.navigationItem.hidesBackButton = true - return view - case .checkInsertedCannula: - let view = CheckInsertedCannulaView( - didRequestDeactivation: { [weak self] in - self?.navigateTo(.deactivate) - }, - wasInsertedProperly: { [weak self] in - self?.stepFinished() - } - ) - let hostedView = hostingController(rootView: view) - hostedView.navigationItem.title = LocalizedString("Check Cannula", comment: "Title for check cannula screen") - hostedView.navigationItem.hidesBackButton = true - return hostedView - case .setupComplete: - guard let podExpiresAt = pumpManager.expiresAt, - let allowedExpirationReminderDates = pumpManager.allowedExpirationReminderDates - else { - fatalError("Cannot show setup complete UI without expiration and allowed reminder dates.") - } - let formatter = DateFormatter() - formatter.dateStyle = .medium - formatter.timeStyle = .short - - let view = SetupCompleteView( - scheduledReminderDate: pumpManager.scheduledExpirationReminder, - dateFormatter: formatter, - allowedDates: allowedExpirationReminderDates, - onSaveScheduledExpirationReminder: { [weak self] (newExpirationReminderDate, completion) in - var intervalBeforeExpiration : TimeInterval? - if let newExpirationReminderDate = newExpirationReminderDate { - intervalBeforeExpiration = podExpiresAt.timeIntervalSince(newExpirationReminderDate) - } - self?.pumpManager.updateExpirationReminder(intervalBeforeExpiration, completion: completion) - }, - didFinish: { [weak self] in - self?.stepFinished() - }, - didRequestDeactivation: { [weak self] in - self?.navigateTo(.deactivate) - } - ) - - let hostedView = hostingController(rootView: view) - hostedView.navigationItem.title = LocalizedString("Setup Complete", comment: "Title for setup complete screen") - return hostedView - case .pendingCommandRecovery: - if let pendingCommand = pumpManager.state.podState?.unacknowledgedCommand, pumpManager.state.podState?.needsCommsRecovery == true { - - let model = DeliveryUncertaintyRecoveryViewModel(appName: appName, uncertaintyStartedAt: pendingCommand.commandDate) - model.didRecover = { [weak self] in - self?.navigateTo(.uncertaintyRecovered) - } - model.onDeactivate = { [weak self] in - self?.navigateTo(.deactivate) - } - model.onDismiss = { [weak self] in - if let self = self { - self.completionDelegate?.completionNotifyingDidComplete(self) - } - } - pumpManager.addStatusObserver(model, queue: DispatchQueue.main) - pumpManager.getPodStatus() { _ in } - - let view = DeliveryUncertaintyRecoveryView(model: model) - - let hostedView = hostingController(rootView: view) - hostedView.navigationItem.title = LocalizedString("Unable To Reach Pod", comment: "Title for pending command recovery screen") - return hostedView - } else { - fatalError("Pending command recovery UI attempted without pending command") - } - case .uncertaintyRecovered: - var view = UncertaintyRecoveredView(appName: appName) - view.didFinish = { [weak self] in - self?.stepFinished() - } - let hostedView = hostingController(rootView: view) - hostedView.navigationItem.title = LocalizedString("Comms Recovered", comment: "Title for uncertainty recovered screen") - return hostedView - } - } - - private func hostingController(rootView: Content) -> DismissibleHostingController { - return DismissibleHostingController(rootView: rootView, colorPalette: colorPalette) - } - - private func stepFinished() { - if let nextStep = currentScreen.next() { - navigateTo(nextStep) - } else { - completionDelegate?.completionNotifyingDidComplete(self) - } - } - - private func setupCanceled() { - completionDelegate?.completionNotifyingDidComplete(self) - } - - init(pumpManager: OmniBLEPumpManager? = nil, colorPalette: LoopUIColorPalette, pumpManagerSettings: PumpManagerSetupSettings? = nil, allowDebugFeatures: Bool, allowedInsulinTypes: [InsulinType] = []) - { - if pumpManager == nil, let pumpManagerSettings = pumpManagerSettings { - let basalSchedule = pumpManagerSettings.basalSchedule - let pumpManagerState = OmniBLEPumpManagerState(podState: nil, timeZone: basalSchedule.timeZone, basalSchedule: BasalSchedule(repeatingScheduleValues: basalSchedule.items), insulinType: nil, maximumTempBasalRate: pumpManagerSettings.maxBasalRateUnitsPerHour) - self.pumpManager = OmniBLEPumpManager(state: pumpManagerState) - } else { - guard let pumpManager = pumpManager else { - fatalError("Unable to create Omnipod PumpManager") - } - self.pumpManager = pumpManager - } - - self.colorPalette = colorPalette - - self.allowDebugFeatures = allowDebugFeatures - - self.allowedInsulinTypes = allowedInsulinTypes - - super.init(navigationBarClass: UINavigationBar.self, toolbarClass: UIToolbar.self) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func determineInitialStep() -> DashUIScreen { - if pumpManager.state.podState?.needsCommsRecovery == true { - return .pendingCommandRecovery - } else if pumpManager.podCommState == .activating { - if pumpManager.podAttachmentConfirmed { - return .insertCannula - } else { - return .confirmAttachment - } - } else if !pumpManager.isOnboarded { - if !pumpManager.initialConfigurationCompleted { - return .firstRunScreen - } - return .pairPod - } else { - return .settings - } - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - if screenStack.isEmpty { - screenStack = [determineInitialStep()] - let viewController = viewControllerForScreen(currentScreen) - viewController.isModalInPresentation = false - setViewControllers([viewController], animated: false) - } - } - - var customTraitCollection: UITraitCollection { - // Select height reduced layouts on iPhone SE and iPod Touch, - // and select regular width layouts on larger screens, for list rendering styles - if UIScreen.main.bounds.height <= 640 { - return UITraitCollection(traitsFrom: [super.traitCollection, UITraitCollection(verticalSizeClass: .compact)]) - } else { - return UITraitCollection(traitsFrom: [super.traitCollection, UITraitCollection(horizontalSizeClass: .regular)]) - } - } - - override func viewDidLoad() { - super.viewDidLoad() - self.navigationBar.prefersLargeTitles = true - delegate = self - } - - override func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - completionDelegate?.completionNotifyingDidComplete(self) - } - - public func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { - - setOverrideTraitCollection(customTraitCollection, forChild: viewController) - - if viewControllers.count < screenStack.count { - // Navigation back - let _ = screenStack.popLast() - } - viewController.view.backgroundColor = UIColor.secondarySystemBackground - } - - let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as! String -} - -extension DashUICoordinator: DashUINavigator { - func navigateTo(_ screen: DashUIScreen) { - screenStack.append(screen) - let viewController = viewControllerForScreen(screen) - viewController.isModalInPresentation = false - self.pushViewController(viewController, animated: true) - viewController.view.layoutSubviews() - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/DeactivatePodViewModel.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/DeactivatePodViewModel.swift deleted file mode 100644 index 76064cb3b..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/DeactivatePodViewModel.swift +++ /dev/null @@ -1,197 +0,0 @@ -// -// DeactivatePodViewModel.swift -// OmniBLE -// -// Created by Pete Schwamb on 3/9/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKitUI - -public protocol PodDeactivater { - func deactivatePod(completion: @escaping (OmniBLEPumpManagerError?) -> Void) - func forgetPod(completion: @escaping () -> Void) -} - -extension OmniBLEPumpManager: PodDeactivater {} - - -class DeactivatePodViewModel: ObservableObject, Identifiable { - - enum DeactivatePodViewModelState { - case active - case deactivating - case resultError(DeactivationError) - case finished - - var actionButtonAccessibilityLabel: String { - switch self { - case .active: - return LocalizedString("Deactivate Pod", comment: "Deactivate pod action button accessibility label while ready to deactivate") - case .deactivating: - return LocalizedString("Deactivating.", comment: "Deactivate pod action button accessibility label while deactivating") - case .resultError(let error): - return String(format: "%@ %@", error.errorDescription ?? "", error.recoverySuggestion ?? "") - case .finished: - return LocalizedString("Pod deactivated successfully. Continue.", comment: "Deactivate pod action button accessibility label when deactivation complete") - } - } - - var actionButtonDescription: String { - switch self { - case .active: - return LocalizedString("Deactivate Pod", comment: "Action button description for deactivate while pod still active") - case .resultError: - return LocalizedString("Retry", comment: "Action button description for deactivate after failed attempt") - case .deactivating: - return LocalizedString("Deactivating...", comment: "Action button description while deactivating") - case .finished: - return LocalizedString("Continue", comment: "Action button description when deactivated") - } - } - - var actionButtonStyle: ActionButton.ButtonType { - switch self { - case .active: - return .destructive - default: - return .primary - } - } - - - var progressState: ProgressIndicatorState { - switch self { - case .active, .resultError: - return .hidden - case .deactivating: - return .indeterminantProgress - case .finished: - return .completed - } - } - - var showProgressDetail: Bool { - switch self { - case .active: - return false - default: - return true - } - } - - var isProcessing: Bool { - switch self { - case .deactivating: - return true - default: - return false - } - } - - var isFinished: Bool { - if case .finished = self { - return true - } - return false - } - - } - - @Published var state: DeactivatePodViewModelState = .active - - var error: DeactivationError? { - if case .resultError(let error) = self.state { - return error - } - return nil - } - - var didFinish: (() -> Void)? - - var didCancel: (() -> Void)? - - var podDeactivator: PodDeactivater - - var podAttachedToBody: Bool - - var instructionText: String - - init(podDeactivator: PodDeactivater, podAttachedToBody: Bool, fault: DetailedStatus?) { - - var text: String = "" - if let faultEventCode = fault?.faultEventCode { - let notificationString = faultEventCode.notificationTitle - switch faultEventCode.faultType { - case .exceededMaximumPodLife80Hrs, .reservoirEmpty, .occluded: - // Just prepend a simple sentence with the notification string for these faults. - // Other occluded related 0x6? faults will be treated as a general pod error as per the PDM. - text = String(format: "%@. ", notificationString) - default: - // Display the fault code in decimal and hex, the fault description and the pdmRef string for other errors. - text = String(format: "⚠️ %1$@ (0x%2$02X)\n%3$@\n", notificationString, faultEventCode.rawValue, faultEventCode.faultDescription) - if let pdmRef = fault?.pdmRef { - text += LocalizedString("Ref: ", comment: "PDM Ref string line") + pdmRef + "\n\n" - } - } - } - - if podAttachedToBody { - text += LocalizedString("Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod.", comment: "Instructions for deactivate pod when pod is on body") - } else { - text += LocalizedString("Please deactivate the pod. When deactivation is complete, you may pair a new pod.", comment: "Instructions for deactivate pod when pod not on body") - } - - self.podDeactivator = podDeactivator - self.podAttachedToBody = podAttachedToBody - self.instructionText = text - } - - public func continueButtonTapped() { - if case .finished = state { - didFinish?() - } else { - self.state = .deactivating - podDeactivator.deactivatePod { (error) in - DispatchQueue.main.async { - if let error = error { - self.state = .resultError(DeactivationError.OmniBLEPumpManagerError(error)) - } else { - self.discardPod(navigateOnCompletion: false) - } - } - } - } - } - - public func discardPod(navigateOnCompletion: Bool = true) { - podDeactivator.forgetPod { - DispatchQueue.main.async { - if navigateOnCompletion { - self.didFinish?() - } else { - self.state = .finished - } - } - } - } -} - -enum DeactivationError : LocalizedError { - case OmniBLEPumpManagerError(OmniBLEPumpManagerError) - - var recoverySuggestion: String? { - switch self { - case .OmniBLEPumpManagerError: - return LocalizedString("There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod.", comment: "Format string for recovery suggestion during deactivate pod.") - } - } - - var errorDescription: String? { - switch self { - case .OmniBLEPumpManagerError(let error): - return error.errorDescription - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/DeliveryUncertaintyRecoveryViewModel.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/DeliveryUncertaintyRecoveryViewModel.swift deleted file mode 100644 index efe338803..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/DeliveryUncertaintyRecoveryViewModel.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// DeliveryUncertaintyRecoveryViewModel.swift -// OmniBLE -// -// Created by Pete Schwamb on 8/25/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -class DeliveryUncertaintyRecoveryViewModel: PumpManagerStatusObserver { - - let appName: String - let uncertaintyStartedAt: Date - - var onDismiss: (() -> Void)? - var didRecover: (() -> Void)? - var onDeactivate: (() -> Void)? - - private var finished = false - - init(appName: String, uncertaintyStartedAt: Date) { - self.appName = appName - self.uncertaintyStartedAt = uncertaintyStartedAt - } - - func pumpManager(_ pumpManager: PumpManager, didUpdate status: PumpManagerStatus, oldStatus: PumpManagerStatus) { - if !finished { - if !status.deliveryIsUncertain { - didRecover?() - } - } - } - - func podDeactivationChosen() { - finished = true - self.onDeactivate?() - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/InsertCannulaViewModel.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/InsertCannulaViewModel.swift deleted file mode 100644 index 70b56e50b..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/InsertCannulaViewModel.swift +++ /dev/null @@ -1,234 +0,0 @@ -// -// InsertCannulaViewModel.swift -// OmniBLE -// -// Created by Pete Schwamb on 3/10/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import LoopKit -import LoopKitUI - -public protocol CannulaInserter { - func insertCannula(completion: @escaping (Result) -> ()) - func checkCannulaInsertionFinished(completion: @escaping (OmniBLEPumpManagerError?) -> Void) -} - -extension OmniBLEPumpManager: CannulaInserter { } - -class InsertCannulaViewModel: ObservableObject, Identifiable { - - enum InsertCannulaViewModelState { - case ready - case startingInsertion - case inserting(finishTime: CFTimeInterval) - case checkingInsertion - case error(OmniBLEPumpManagerError) - case finished - - var actionButtonAccessibilityLabel: String { - switch self { - case .ready, .startingInsertion: - return LocalizedString("Insert Cannula", comment: "Insert cannula action button accessibility label while ready to pair") - case .inserting: - return LocalizedString("Inserting. Please wait.", comment: "Insert cannula action button accessibility label while pairing") - case .checkingInsertion: - return LocalizedString("Checking Insertion", comment: "Insert cannula action button accessibility label checking insertion") - case .error(let error): - return String(format: "%@ %@", error.errorDescription ?? "", error.recoverySuggestion ?? "") - case .finished: - return LocalizedString("Cannula inserted successfully. Continue.", comment: "Insert cannula action button accessibility label when cannula insertion succeeded") - } - } - - var instructionsDisabled: Bool { - switch self { - case .ready, .error: - return false - default: - return true - } - } - - var nextActionButtonDescription: String { - switch self { - case .ready: - return LocalizedString("Insert Cannula", comment: "Cannula insertion button text while ready to insert") - case .error: - return LocalizedString("Retry", comment: "Cannula insertion button text while showing error") - case .inserting, .startingInsertion: - return LocalizedString("Inserting...", comment: "Cannula insertion button text while inserting") - case .checkingInsertion: - return LocalizedString("Checking...", comment: "Cannula insertion button text while checking insertion") - case .finished: - return LocalizedString("Continue", comment: "Cannula insertion button text when inserted") - } - } - - var nextActionButtonStyle: ActionButton.ButtonType { - switch self { - case .error(let error): - if !error.recoverable { - return .destructive - } - default: - break - } - return .primary - } - - var progressState: ProgressIndicatorState { - switch self { - case .ready, .error: - return .hidden - case .startingInsertion, .checkingInsertion: - return .indeterminantProgress - case .inserting(let finishTime): - return .timedProgress(finishTime: finishTime) - case .finished: - return .completed - } - } - - var showProgressDetail: Bool { - switch self { - case .ready: - return false - default: - return true - } - } - - var isProcessing: Bool { - switch self { - case .startingInsertion, .inserting: - return true - default: - return false - } - } - - var isFinished: Bool { - if case .finished = self { - return true - } - return false - } - } - - var error: OmniBLEPumpManagerError? { - if case .error(let error) = self.state { - return error - } - return nil - } - - @Published var state: InsertCannulaViewModelState = .ready - - var didFinish: (() -> Void)? - - var didRequestDeactivation: (() -> Void)? - - var cannulaInserter: CannulaInserter - - init(cannulaInserter: CannulaInserter) { - self.cannulaInserter = cannulaInserter - } - -// private func handleEvent(_ event: ActivationStep2Event) { -// switch event { -// case .insertingCannula: -// let finishTime = TimeInterval(Pod.estimatedCannulaInsertionDuration) -// state = .inserting(finishTime: CACurrentMediaTime() + finishTime) -// case .step2Completed: -// state = .finished -// default: -// break -// } -// } - - private func checkCannulaInsertionFinished() { - state = .startingInsertion - cannulaInserter.checkCannulaInsertionFinished() { (error) in - DispatchQueue.main.async { - if let error = error { - self.state = .error(error) - } else { - self.state = .finished - } - } - } - } - - private func insertCannula() { - state = .startingInsertion - - cannulaInserter.insertCannula { (result) in - DispatchQueue.main.async { - switch(result) { - case .success(let finishTime): - self.state = .inserting(finishTime: CACurrentMediaTime() + finishTime) - let delay = finishTime - if delay > 0 { - DispatchQueue.main.asyncAfter(deadline: .now() + delay) { - self.checkCannulaInsertionFinished() // now check if actually ready - } - } else { - self.state = .finished - } - case .failure(let error): - self.state = .error(error) - } - } - - -// switch status { -// case .error(let error): -// self.state = .error(error) -// case .event(let event): -// self.handleEvent(event) -// } - } - } - - public func continueButtonTapped() { - switch state { - case .finished: - didFinish?() - case .error(let error): - if error.recoverable { - insertCannula() - } else { - didRequestDeactivation?() - } - default: - insertCannula() - } - } - -} - -public extension OmniBLEPumpManagerError { - var recoverable: Bool { - //TODO - return true -// switch self { -// case .podIsInAlarm: -// return false -// case .activationError(let activationErrorCode): -// switch activationErrorCode { -// case .podIsLumpOfCoal1Hour, .podIsLumpOfCoal2Hours: -// return false -// default: -// return true -// } -// case .internalError(.incompatibleProductId): -// return false -// case .systemError: -// return false -// default: -// return true -// } - } -} - diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/OmniBLESettingsViewModel.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/OmniBLESettingsViewModel.swift deleted file mode 100644 index 8904dcb26..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/OmniBLESettingsViewModel.swift +++ /dev/null @@ -1,619 +0,0 @@ -// -// OmniBLESettingsViewModel.swift -// OmniBLE -// -// Created by Pete Schwamb on 3/8/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import HealthKit - - -enum DashSettingsViewAlert { - case suspendError(Error) - case resumeError(Error) - case cancelManualBasalError(Error) - case syncTimeError(OmniBLEPumpManagerError) -} - -public enum ReservoirLevelHighlightState: String, Equatable { - case normal - case warning - case critical -} - -struct DashSettingsNotice { - let title: String - let description: String -} - -class OmniBLESettingsViewModel: ObservableObject { - - @Published var lifeState: PodLifeState - - @Published var activatedAt: Date? - - @Published var expiresAt: Date? - - @Published var beepPreference: BeepPreference - - @Published var silencePodPreference: SilencePodPreference - - @Published var podConnected: Bool - - var activatedAtString: String { - if let activatedAt = activatedAt { - return dateFormatter.string(from: activatedAt) - } else { - return "—" - } - } - - var expiresAtString: String { - if let expiresAt = expiresAt { - return dateFormatter.string(from: expiresAt) - } else { - return "—" - } - } - - var serviceTimeRemainingString: String? { - if let serviceTimeRemaining = pumpManager.podServiceTimeRemaining, let serviceTimeRemainingString = timeRemainingFormatter.string(from: serviceTimeRemaining) { - return serviceTimeRemainingString - } else { - return nil - } - } - - // Expiration reminder date for current pod - @Published var expirationReminderDate: Date? - - var allowedScheduledReminderDates: [Date]? { - return pumpManager.allowedExpirationReminderDates - } - - // Hours before expiration - @Published var expirationReminderDefault: Int { - didSet { - self.pumpManager.defaultExpirationReminderOffset = .hours(Double(expirationReminderDefault)) - } - } - - // Units to alert at - @Published var lowReservoirAlertValue: Int - - @Published var basalDeliveryState: PumpManagerStatus.BasalDeliveryState? - - @Published var basalDeliveryRate: Double? - - @Published var activeAlert: DashSettingsViewAlert? = nil { - didSet { - if activeAlert != nil { - alertIsPresented = true - } - } - } - - @Published var alertIsPresented: Bool = false { - didSet { - if !alertIsPresented { - activeAlert = nil - } - } - } - - @Published var reservoirLevel: ReservoirLevel? - - @Published var reservoirLevelHighlightState: ReservoirLevelHighlightState? - - @Published var synchronizingTime: Bool = false - - @Published var podCommState: PodCommState - - @Published var insulinType: InsulinType? - - @Published var podDetails: PodDetails? - - @Published var previousPodDetails: PodDetails? - - - var timeZone: TimeZone { - return pumpManager.status.timeZone - } - - var viewTitle: String { - return pumpManager.localizedTitle - } - - var isClockOffset: Bool { - return pumpManager.isClockOffset - } - - var isPodDataStale: Bool { - return Date().timeIntervalSince(pumpManager.lastSync ?? .distantPast) > .minutes(12) - } - - var recoveryText: String? { - if case .fault = podCommState { - return LocalizedString("⚠️ Insulin delivery stopped. Change Pod now.", comment: "The action string on pod status page when pod faulted") - } else if podOk && isPodDataStale { - return LocalizedString("Make sure your phone and pod are close to each other. If communication issues persist, move to a new area.", comment: "The action string on pod status page when pod data is stale") - } else if let serviceTimeRemaining = pumpManager.podServiceTimeRemaining, serviceTimeRemaining <= Pod.serviceDuration - Pod.nominalPodLife { - if let serviceTimeRemainingString = serviceTimeRemainingString { - return String(format: LocalizedString("Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains.", comment: "Format string for the action string on pod status page when pod expired. (1: service time remaining)"), serviceTimeRemainingString) - } else { - return LocalizedString("Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains.", comment: "The action string on pod status page when pod expired") - } - } else { - return nil - } - } - - var notice: DashSettingsNotice? { - if pumpManager.isClockOffset { - return DashSettingsNotice( - title: LocalizedString("Time Change Detected", comment: "title for time change detected notice"), - description: LocalizedString("The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump.", comment: "description for time change detected notice")) - } else { - return nil - } - } - - var isScheduledBasal: Bool { - switch basalDeliveryState { - case .active(_), .initiatingTempBasal: - return true - case .tempBasal(_), .cancelingTempBasal, .suspending, .suspended(_), .resuming, .none: - return false - } - } - - let dateFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - dateFormatter.timeStyle = .short - dateFormatter.dateStyle = .medium - dateFormatter.doesRelativeDateFormatting = true - return dateFormatter - }() - - let timeFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - dateFormatter.timeStyle = .short - dateFormatter.dateStyle = .none - return dateFormatter - }() - - let timeRemainingFormatter: DateComponentsFormatter = { - let dateComponentsFormatter = DateComponentsFormatter() - dateComponentsFormatter.allowedUnits = [.hour, .minute] - dateComponentsFormatter.unitsStyle = .full - dateComponentsFormatter.zeroFormattingBehavior = .dropAll - return dateComponentsFormatter - }() - - let basalRateFormatter: NumberFormatter = { - let numberFormatter = NumberFormatter() - numberFormatter.numberStyle = .decimal - numberFormatter.minimumFractionDigits = 1 - numberFormatter.minimumIntegerDigits = 1 - return numberFormatter - }() - - var manualBasalTimeRemaining: TimeInterval? { - if case .tempBasal(let dose) = basalDeliveryState, !(dose.automatic ?? true) { - let remaining = dose.endDate.timeIntervalSinceNow - if remaining > 0 { - return remaining - } - } - return nil - } - - let reservoirVolumeFormatter = QuantityFormatter(for: .internationalUnit()) - - var didFinish: (() -> Void)? - - var navigateTo: ((DashUIScreen) -> Void)? - - private let pumpManager: OmniBLEPumpManager - - init(pumpManager: OmniBLEPumpManager) { - self.pumpManager = pumpManager - - lifeState = pumpManager.lifeState - activatedAt = pumpManager.podActivatedAt - expiresAt = pumpManager.expiresAt - basalDeliveryState = pumpManager.status.basalDeliveryState - basalDeliveryRate = self.pumpManager.basalDeliveryRate - reservoirLevel = self.pumpManager.reservoirLevel - reservoirLevelHighlightState = self.pumpManager.reservoirLevelHighlightState - expirationReminderDate = self.pumpManager.scheduledExpirationReminder - expirationReminderDefault = Int(self.pumpManager.defaultExpirationReminderOffset.hours) - lowReservoirAlertValue = Int(self.pumpManager.state.lowReservoirReminderValue) - podCommState = self.pumpManager.podCommState - beepPreference = self.pumpManager.beepPreference - silencePodPreference = self.pumpManager.silencePod ? .enabled : .disabled - podConnected = self.pumpManager.isConnected - insulinType = self.pumpManager.insulinType - podDetails = self.pumpManager.podDetails - previousPodDetails = self.pumpManager.previousPodDetails - pumpManager.addPodStateObserver(self, queue: DispatchQueue.main) - pumpManager.addStatusObserver(self, queue: DispatchQueue.main) - - // Trigger refresh - pumpManager.getPodStatus() { _ in } - } - - func changeTimeZoneTapped() { - synchronizingTime = true - pumpManager.setTime { (error) in - DispatchQueue.main.async { - self.synchronizingTime = false - self.lifeState = self.pumpManager.lifeState - if let error = error { - self.activeAlert = .syncTimeError(error) - } - } - } - } - - func doneTapped() { - self.didFinish?() - } - - func stopUsingOmnipodDashTapped() { - pumpManager.notifyDelegateOfDeactivation { - DispatchQueue.main.async { - self.didFinish?() - } - } - } - - func suspendDelivery(duration: TimeInterval) { - pumpManager.suspendDelivery(withSuspendReminders: duration) { (error) in - DispatchQueue.main.async { - if let error = error { - self.activeAlert = .suspendError(error) - } - } - } - } - - func resumeDelivery() { - pumpManager.resumeDelivery { (error) in - DispatchQueue.main.async { - if let error = error { - self.activeAlert = .resumeError(error) - } - } - } - } - - func runTemporaryBasalProgram(unitsPerHour: Double, for duration: TimeInterval, completion: @escaping (PumpManagerError?) -> Void) { - pumpManager.runTemporaryBasalProgram(unitsPerHour: unitsPerHour, for: duration, automatic: false, completion: completion) - } - - func saveScheduledExpirationReminder(_ selectedDate: Date?, _ completion: @escaping (Error?) -> Void) { - if let podExpiresAt = pumpManager.podExpiresAt { - var intervalBeforeExpiration : TimeInterval? - if let selectedDate = selectedDate { - intervalBeforeExpiration = .hours(round(podExpiresAt.timeIntervalSince(selectedDate).hours)) - } - pumpManager.updateExpirationReminder(intervalBeforeExpiration) { (error) in - DispatchQueue.main.async { - if error == nil { - self.expirationReminderDate = selectedDate - } - completion(error) - } - } - } - } - - func saveLowReservoirReminder(_ selectedValue: Int, _ completion: @escaping (Error?) -> Void) { - pumpManager.updateLowReservoirReminder(selectedValue) { (error) in - DispatchQueue.main.async { - if error == nil { - self.lowReservoirAlertValue = selectedValue - } - completion(error) - } - } - } - - func readPodStatus(_ completion: @escaping (_ result: PumpManagerResult) -> Void) { - pumpManager.getDetailedStatus() { (result) in - DispatchQueue.main.async { - completion(result) - } - } - } - - func readPulseLog(_ completion: @escaping (_ result: Result) -> Void) { - pumpManager.readPulseLog() { (result) in - DispatchQueue.main.async { - completion(result) - } - } - } - - func playTestBeeps(_ completion: @escaping (Error?) -> Void) { - pumpManager.playTestBeeps(completion: completion) - } - - func pumpManagerDetails(_ completion: @escaping (_ result: String) -> Void) { - completion(pumpManager.debugDescription) - } - - func setConfirmationBeeps(_ preference: BeepPreference, _ completion: @escaping (_ error: LocalizedError?) -> Void) { - pumpManager.setConfirmationBeeps(newPreference: preference) { error in - DispatchQueue.main.async { - if error == nil { - self.beepPreference = preference - } - completion(error) - } - } - } - - func setSilencePod(_ silencePodPreference: SilencePodPreference, _ completion: @escaping (_ error: LocalizedError?) -> Void) { - pumpManager.setSilencePod(silencePod: silencePodPreference == .enabled) { error in - DispatchQueue.main.async { - if error == nil { - self.silencePodPreference = silencePodPreference - } - completion(error) - } - } - } - - func didChangeInsulinType(_ newType: InsulinType?) { - self.pumpManager.insulinType = newType - } - - var podOk: Bool { - guard basalDeliveryState != nil else { return false } - - switch podCommState { - case .noPod, .activating, .deactivating, .fault: - return false - default: - return true - } - } - - var noPod: Bool { - return podCommState == .noPod - } - - var podError: String? { - switch podCommState { - case .fault(let status): - switch status.faultEventCode.faultType { - case .reservoirEmpty: - return LocalizedString("No Insulin", comment: "Error message for reservoir view when reservoir empty") - case .exceededMaximumPodLife80Hrs: - return LocalizedString("Pod Expired", comment: "Error message for reservoir view when pod expired") - case .occluded, .occlusionCheckStartup1, .occlusionCheckStartup2, .occlusionCheckTimeouts1, .occlusionCheckTimeouts2, .occlusionCheckTimeouts3, .occlusionCheckPulseIssue, .occlusionCheckBolusProblem, .occlusionCheckAboveThreshold, .occlusionCheckValueTooHigh: - return LocalizedString("Pod Occlusion", comment: "Error message for reservoir view when pod occlusion checks failed") - default: - return String(format: LocalizedString("Pod Fault %1$03d", comment: "Error message for reservoir view during general pod fault: (1: fault code value)"), status.faultEventCode.rawValue) - } - case .active: - if isPodDataStale { - return LocalizedString("Signal Loss", comment: "Error message for reservoir view during signal loss") - } else { - return nil - } - default: - return nil - } - - } - - func reservoirText(for level: ReservoirLevel) -> String { - switch level { - case .aboveThreshold: - let quantity = HKQuantity(unit: .internationalUnit(), doubleValue: Pod.maximumReservoirReading) - let thresholdString = reservoirVolumeFormatter.string(from: quantity, for: .internationalUnit(), includeUnit: false) ?? "" - let unitString = reservoirVolumeFormatter.string(from: .internationalUnit(), forValue: Pod.maximumReservoirReading, avoidLineBreaking: true) - return String(format: LocalizedString("%1$@+ %2$@", comment: "Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units)"), - thresholdString, unitString) - case .valid(let value): - let quantity = HKQuantity(unit: .internationalUnit(), doubleValue: value) - return reservoirVolumeFormatter.string(from: quantity, for: .internationalUnit()) ?? "" - } - } - - var suspendResumeActionText: String { - let defaultText = LocalizedString("Suspend Insulin Delivery", comment: "Text for suspend resume button when insulin delivery active") - - guard podOk else { - return defaultText - } - - switch basalDeliveryState { - case .suspending: - return LocalizedString("Suspending insulin delivery...", comment: "Text for suspend resume button when insulin delivery is suspending") - case .suspended: - return LocalizedString("Resume Insulin Delivery", comment: "Text for suspend resume button when insulin delivery is suspended") - case .resuming: - return LocalizedString("Resuming insulin delivery...", comment: "Text for suspend resume button when insulin delivery is resuming") - default: - return defaultText - } - } - - var basalTransitioning: Bool { - switch basalDeliveryState { - case .suspending, .resuming: - return true - default: - return false - } - } - - func suspendResumeButtonColor(guidanceColors: GuidanceColors) -> Color { - guard podOk else { - return Color.secondary - } - switch basalDeliveryState { - case .suspending, .resuming: - return Color.secondary - case .suspended: - return guidanceColors.warning - default: - return .accentColor - } - } - - func suspendResumeActionColor() -> Color { - guard podOk else { - return Color.secondary - } - switch basalDeliveryState { - case .suspending, .resuming: - return Color.secondary - default: - return Color.accentColor - } - } - - var isSuspendedOrResuming: Bool { - switch basalDeliveryState { - case .suspended, .resuming: - return true - default: - return false - } - } - - public var allowedTempBasalRates: [Double] { - return Pod.supportedBasalRates.filter { $0 <= pumpManager.state.maximumTempBasalRate } - } -} - -extension OmniBLESettingsViewModel: PodStateObserver { - func podStateDidUpdate(_ state: PodState?) { - lifeState = self.pumpManager.lifeState - basalDeliveryRate = self.pumpManager.basalDeliveryRate - reservoirLevel = self.pumpManager.reservoirLevel - activatedAt = state?.activatedAt - expiresAt = state?.expiresAt - reservoirLevelHighlightState = self.pumpManager.reservoirLevelHighlightState - expirationReminderDate = self.pumpManager.scheduledExpirationReminder - podCommState = self.pumpManager.podCommState - beepPreference = self.pumpManager.beepPreference - insulinType = self.pumpManager.insulinType - podDetails = self.pumpManager.podDetails - previousPodDetails = self.pumpManager.previousPodDetails - } - - func podConnectionStateDidChange(isConnected: Bool) { - self.podConnected = isConnected - } -} - -extension OmniBLESettingsViewModel: PumpManagerStatusObserver { - func pumpManager(_ pumpManager: PumpManager, didUpdate status: PumpManagerStatus, oldStatus: PumpManagerStatus) { - basalDeliveryState = self.pumpManager.status.basalDeliveryState - } -} - - - - -extension OmniBLEPumpManager { - var lifeState: PodLifeState { - switch podCommState { - case .fault(let status): - switch status.faultEventCode.faultType { - case .exceededMaximumPodLife80Hrs: - return .expired - default: - let remaining = Pod.nominalPodLife - (status.faultEventTimeSinceActivation ?? Pod.nominalPodLife) - let podTimeUntilReminder = remaining - (state.scheduledExpirationReminderOffset ?? 0) - if remaining > 0 { - return .timeRemaining(timeUntilExpiration: remaining, timeUntilExpirationReminder: podTimeUntilReminder) - } else { - return .expired - } - } - - case .noPod: - return .noPod - case .activating: - return .podActivating - case .deactivating: - return .podDeactivating - case .active: - if let podTimeRemaining = podTimeRemaining { - if podTimeRemaining > 0 { - let podTimeUntilReminder = podTimeRemaining - (state.scheduledExpirationReminderOffset ?? 0) - return .timeRemaining(timeUntilExpiration: podTimeRemaining, timeUntilExpirationReminder: podTimeUntilReminder) - } else { - return .expired - } - } else { - return .podDeactivating - } - } - } - - var basalDeliveryRate: Double? { - if let tempBasal = state.podState?.unfinalizedTempBasal, !tempBasal.isFinished() { - return tempBasal.rate - } else { - switch state.podState?.suspendState { - case .resumed: - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = state.timeZone - return state.basalSchedule.currentRate(using: calendar, at: dateGenerator()) - case .suspended, .none: - return nil - } - } - } - - fileprivate var podServiceTimeRemaining : TimeInterval? { - guard let podTimeRemaining = podTimeRemaining else { - return nil; - } - return max(0, Pod.serviceDuration - Pod.nominalPodLife + podTimeRemaining); - } - - private func podDetails(fromPodState podState: PodState, andDeviceName deviceName: String?) -> PodDetails { - return PodDetails( - lotNumber: podState.lotNo, - sequenceNumber: podState.lotSeq, - firmwareVersion: podState.firmwareVersion, - bleFirmwareVersion: podState.bleFirmwareVersion, - deviceName: deviceName, - totalDelivery: podState.lastInsulinMeasurements?.delivered, - lastStatus: podState.lastInsulinMeasurements?.validTime, - fault: podState.fault?.faultEventCode, - activatedAt: podState.activatedAt, - activeTime: podState.activeTime, - pdmRef: podState.fault?.pdmRef - ) - } - - public var podDetails: PodDetails? { - guard let podState = state.podState else { - return nil - } - return podDetails(fromPodState: podState, andDeviceName: deviceBLEName) - } - - public var previousPodDetails: PodDetails? { - guard let podState = state.previousPodState else { - return nil - } - return podDetails(fromPodState: podState, andDeviceName: nil) - } - -} - diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/PairPodViewModel.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/PairPodViewModel.swift deleted file mode 100644 index dc6a4b912..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/PairPodViewModel.swift +++ /dev/null @@ -1,260 +0,0 @@ -// -// PairPodViewModel.swift -// OmniBLE -// -// Created by Pete Schwamb on 3/2/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI - -class PairPodViewModel: ObservableObject, Identifiable { - - enum NavBarButtonAction { - case cancel - case discard - - var text: String { - switch self { - case .cancel: - return LocalizedString("Cancel", comment: "Pairing interface navigation bar button text for cancel action") - case .discard: - return LocalizedString("Discard Pod", comment: "Pairing interface navigation bar button text for discard pod action") - } - } - - func color(using guidanceColors: GuidanceColors) -> Color? { - switch self { - case .discard: - return guidanceColors.critical - case .cancel: - return nil - } - } - } - - enum PairPodViewModelState { - case ready - case pairing - case priming(finishTime: CFTimeInterval) - case error(DashPairingError) - case finished - - var instructionsDisabled: Bool { - switch self { - case .ready: - return false - case .error(let error): - return !error.recoverable - default: - return true - } - } - - var actionButtonAccessibilityLabel: String { - switch self { - case .ready: - return LocalizedString("Pair pod.", comment: "Pairing action button accessibility label while ready to pair") - case .pairing: - return LocalizedString("Pairing.", comment: "Pairing action button accessibility label while pairing") - case .priming: - return LocalizedString("Priming. Please wait.", comment: "Pairing action button accessibility label while priming") - case .error(let error): - return String(format: "%@ %@", error.errorDescription ?? "", error.recoverySuggestion ?? "") - case .finished: - return LocalizedString("Pod paired successfully. Continue.", comment: "Pairing action button accessibility label when pairing succeeded") - } - } - - var nextActionButtonDescription: String { - switch self { - case .ready: - return LocalizedString("Pair Pod", comment: "Pod pairing action button text while ready to pair") - case .error: - return LocalizedString("Retry", comment: "Pod pairing action button text while showing error") - case .pairing: - return LocalizedString("Pairing...", comment: "Pod pairing action button text while pairing") - case .priming: - return LocalizedString("Priming...", comment: "Pod pairing action button text while priming") - case .finished: - return LocalizedString("Continue", comment: "Pod pairing action button text when paired") - } - } - - var navBarButtonAction: NavBarButtonAction { -// switch self { -// case .error(_, let podCommState): -// if podCommState == .activating { -// return .discard -// } -// default: -// break -// } - return .cancel - } - - var navBarVisible: Bool { - if case .error(let error) = self { - return error.recoverable - } - return true - } - - var showProgressDetail: Bool { - switch self { - case .ready: - return false - default: - return true - } - } - - var progressState: ProgressIndicatorState { - switch self { - case .ready, .error: - return .hidden - case .pairing: - return .indeterminantProgress - case .priming(let finishTime): - return .timedProgress(finishTime: finishTime) - case .finished: - return .completed - } - } - - var isProcessing: Bool { - switch self { - case .pairing, .priming: - return true - default: - return false - } - } - - var isFinished: Bool { - if case .finished = self { - return true - } - return false - } - } - - var error: DashPairingError? { - if case .error(let error) = state { - return error - } - return nil - } - - @Published var state: PairPodViewModelState = .ready - - var podIsActivated: Bool { - return false // podPairer.podCommState != .noPod - } - - var backButtonHidden: Bool { - if case .pairing = state { - return true - } - if podIsActivated { - return true - } - return false - } - - var didFinish: (() -> Void)? - - var didRequestDeactivation: (() -> Void)? - - var didCancelSetup: (() -> Void)? - - var podPairer: PodPairer - - init(podPairer: PodPairer) { - self.podPairer = podPairer - } - - private func pair() { - state = .pairing - - podPairer.pair { (status) in - DispatchQueue.main.async { - switch status { - case .failure(let error): - let pairingError = DashPairingError.pumpManagerError(error) - self.state = .error(pairingError) - case .success(let duration): - - if duration > 0 { - self.state = .priming(finishTime: CACurrentMediaTime() + duration) - DispatchQueue.main.asyncAfter(deadline: .now() + duration) { - self.state = .finished - } - } else { - self.state = .finished - } - } - } - } - } - - public func continueButtonTapped() { - switch state { - case .error(let error): - if !error.recoverable { - self.didRequestDeactivation?() - } else { - // Retry - pair() - } - case .finished: - didFinish?() - default: - pair() - } - } -} - -// Pairing recovery suggestions -enum DashPairingError : LocalizedError { - case pumpManagerError(PumpManagerError) - - var recoverySuggestion: String? { - switch self { - case .pumpManagerError(let error): - return error.recoverySuggestion - } - } - - var errorDescription: String? { - switch self { - case .pumpManagerError(let error): - return error.errorDescription - } - } - - var recoverable: Bool { -// switch self { -// case .pumpManagerError(let error): - // TODO: check which errors are recoverable - return true -// } - } -} - -public protocol PodPairer { - func pair(completion: @escaping (PumpManagerResult) -> Void) - func discardPod(completion: @escaping (Bool) -> ()) -} - -extension OmniBLEPumpManager: PodPairer { - public func discardPod(completion: @escaping (Bool) -> ()) { - } - - public func pair(completion: @escaping (PumpManagerResult) -> Void) { - pairAndPrime(completion: completion) - } -} - diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/PodLifeState.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/PodLifeState.swift deleted file mode 100644 index 4fce7b928..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/ViewModels/PodLifeState.swift +++ /dev/null @@ -1,116 +0,0 @@ -// -// PodLifeState.swift -// OmniBLE -// -// Created by Pete Schwamb on 3/9/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import SwiftUI - -import LoopKitUI - -enum PodLifeState { - case podActivating - // Time remaining - case timeRemaining(timeUntilExpiration: TimeInterval, timeUntilExpirationReminder: TimeInterval) - // Time since expiry - case expired - case podDeactivating - case noPod - - var progress: Double { - switch self { - case .timeRemaining(let timeRemaining, _): - return max(0, min(1, (1 - (timeRemaining / Pod.nominalPodLife)))) - case .expired: - return 1 - case .podDeactivating: - return 1 - case .noPod, .podActivating: - return 0 - } - } - - func progressColor(guidanceColors: GuidanceColors) -> Color { - switch self { - case .expired: - return guidanceColors.critical - case .timeRemaining(_, let timeUntilExpirationReminder): - return timeUntilExpirationReminder <= Pod.timeRemainingWarningThreshold ? guidanceColors.warning : .accentColor - default: - return Color.secondary - } - } - - func labelColor(using guidanceColors: GuidanceColors) -> Color { - switch self { - case .expired: - return guidanceColors.critical - default: - return .secondary - } - } - - - var localizedLabelText: String { - switch self { - case .podActivating: - return LocalizedString("Unfinished Activation", comment: "Label for pod life state when pod not fully activated") - case .timeRemaining: - return LocalizedString("Pod expires in", comment: "Label for pod life state when time remaining") - case .expired: - return LocalizedString("Pod expired", comment: "Label for pod life state when within pod expiration window") - case .podDeactivating: - return LocalizedString("Unfinished deactivation", comment: "Label for pod life state when pod not fully deactivated") - case .noPod: - return LocalizedString("No Pod", comment: "Label for pod life state when no pod paired") - } - } - - var nextPodLifecycleAction: DashUIScreen { - switch self { - case .podActivating, .noPod: - return .pairPod - default: - return .deactivate - } - } - - var nextPodLifecycleActionDescription: String { - switch self { - case .podActivating, .noPod: - return LocalizedString("Pair Pod", comment: "Settings page link description when next lifecycle action is to pair new pod") - case .podDeactivating: - return LocalizedString("Finish deactivation", comment: "Settings page link description when next lifecycle action is to finish deactivation") - default: - return LocalizedString("Deactivate Pod", comment: "Settings page link description when next lifecycle action is to deactivate pod") - } - } - - var nextPodLifecycleActionColor: Color { - switch self { - case .podActivating, .noPod: - return .accentColor - default: - return .red - } - } - - var isActive: Bool { - switch self { - case .expired, .timeRemaining: - return true - default: - return false - } - } - - var allowsPumpManagerRemoval: Bool { - if case .noPod = self { - return true - } - return false - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ActivityView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ActivityView.swift deleted file mode 100644 index 83aa3e5bb..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ActivityView.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// ActivityView.swift -// OmniBLE -// -// Created by Joe Moran on 9/17/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -struct ActivityView: UIViewControllerRepresentable { - @Binding var isPresented: Bool - let activityItems: [Any] - - func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIActivityViewController { - let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: nil) - controller.completionWithItemsHandler = { (_, _, _, _) in - self.isPresented = false - } - return controller - } - - func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext) { - } -} - -fileprivate struct ActivityViewController: UIViewControllerRepresentable { - var activityItems: [Any] - var applicationActivities: [UIActivity]? = nil - - func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIActivityViewController { - return UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities) - } - - func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext) {} -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/AttachPodView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/AttachPodView.swift deleted file mode 100644 index 4d551aa4f..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/AttachPodView.swift +++ /dev/null @@ -1,107 +0,0 @@ -// -// AttachPodView.swift -// OmniBLE -// -// Created by Pete Schwamb on 2/23/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct AttachPodView: View { - - enum Modal: Int, Identifiable { - var id: Int { rawValue } - - case attachConfirmationModal - case cancelModal - } - - @Environment(\.verticalSizeClass) var verticalSizeClass - - var didConfirmAttachment: () -> Void - var didRequestDeactivation: () -> Void - - @State private var activeModal: Modal? - - var body: some View { - GuidePage(content: { - VStack { - LeadingImage("Pod") - - HStack { - InstructionList(instructions: [ - LocalizedString("Prepare site.", comment: "Label text for step one of attach pod instructions"), - LocalizedString("Remove the Pod's blue needle cap and check cannula. Then remove paper backing.", comment: "Label text for step 1 of pair pod instructions "), - LocalizedString("Check Pod, apply to site, then confirm pod attachment.", comment: "Label text for step three of attach pod instructions") - ]) - } - .padding(.bottom, 8) - } - .accessibility(sortPriority: 1) - }) { - Button(action: { - activeModal = .attachConfirmationModal - }) { - FrameworkLocalText("Continue", comment: "Action button title for attach pod view") - .accessibility(identifier: "button_next_action") - .actionButtonStyle(.primary) - } - .animation(nil) - .padding() - .background(Color(UIColor.systemBackground)) - .zIndex(1) - } - .animation(.default) - .alert(item: $activeModal, content: self.alert(for:)) - .navigationBarTitle(LocalizedString("Attach Pod", comment: "navigation bar title attach pod"), displayMode: .automatic) - .navigationBarItems(trailing: cancelButton) - .navigationBarBackButtonHidden(true) - } - - var cancelButton: some View { - Button(LocalizedString("Cancel", comment: "Cancel button text in navigation bar on pair pod UI")) { - activeModal = .cancelModal - } - .accessibility(identifier: "button_cancel") - } - - private func alert(for modal: Modal) -> Alert { - switch modal { - case .attachConfirmationModal: - return confirmationModal - case .cancelModal: - return cancelPairingModal - } - } - - var confirmationModal: Alert { - return Alert( - title: FrameworkLocalText("Confirm Pod Attachment", comment: "Alert title for confirm pod attachment"), - message: FrameworkLocalText("Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached.", comment: "Alert message body for confirm pod attachment"), - primaryButton: .default(FrameworkLocalText("Confirm", comment: "Button title for confirm attachment option"), action: didConfirmAttachment), - secondaryButton: .cancel() - ) - } - - var cancelPairingModal: Alert { - return Alert( - title: FrameworkLocalText("Are you sure you want to cancel Pod setup?", comment: "Alert title for cancel pairing modal"), - message: FrameworkLocalText("If you cancel Pod setup, the current Pod will be deactivated and will be unusable.", comment: "Alert message body for confirm pod attachment"), - primaryButton: .destructive(FrameworkLocalText("Yes, Deactivate Pod", comment: "Button title for confirm deactivation option"), action: didRequestDeactivation), - secondaryButton: .default(FrameworkLocalText("No, Continue With Pod", comment: "Continue pairing button title of in pairing cancel modal")) - ) - } -} - -struct AttachPodView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - ZStack { - Color(UIColor.secondarySystemBackground).edgesIgnoringSafeArea(.all) - AttachPodView(didConfirmAttachment: {}, didRequestDeactivation: {}) - } - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/BasalStateView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/BasalStateView.swift deleted file mode 100644 index f72d873e7..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/BasalStateView.swift +++ /dev/null @@ -1,139 +0,0 @@ -// -// BasalStateView.swift -// Naterade -// -// Created by Nathan Racklyeft on 5/12/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import SwiftUI - -public struct BasalStateSwiftUIView: UIViewRepresentable { - - var netBasalPercent: Double - - public init(netBasalPercent: Double) { - self.netBasalPercent = netBasalPercent - } - - public func makeUIView(context: UIViewRepresentableContext) -> BasalStateView { - let view = BasalStateView() - view.netBasalPercent = netBasalPercent - return view - } - - public func updateUIView(_ uiView: BasalStateView, context: UIViewRepresentableContext) { - uiView.netBasalPercent = netBasalPercent - } -} - - -public final class BasalStateView: UIView { - - var netBasalPercent: Double = 0 { - didSet { - animateToPath(drawPath()) - } - } - - override public class var layerClass : AnyClass { - return CAShapeLayer.self - } - - private var shapeLayer: CAShapeLayer { - return layer as! CAShapeLayer - } - - override init(frame: CGRect) { - super.init(frame: frame) - - shapeLayer.lineWidth = 2 - updateTintColor() - } - - required public init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - - shapeLayer.lineWidth = 2 - updateTintColor() - } - - override public func layoutSubviews() { - super.layoutSubviews() - animateToPath(drawPath()) - } - - public override func tintColorDidChange() { - super.tintColorDidChange() - updateTintColor() - } - - private func updateTintColor() { - shapeLayer.fillColor = tintColor.withAlphaComponent(0.5).cgColor - shapeLayer.strokeColor = tintColor.cgColor - } - - private func drawPath() -> CGPath { - let startX = bounds.minX - let endX = bounds.maxX - let midY = bounds.midY - - let path = UIBezierPath() - path.move(to: CGPoint(x: startX, y: midY)) - - let leftAnchor = startX + 1/6 * bounds.size.width - let rightAnchor = startX + 5/6 * bounds.size.width - - let yAnchor = bounds.midY - CGFloat(netBasalPercent) * (bounds.size.height - shapeLayer.lineWidth) / 2 - - path.addLine(to: CGPoint(x: leftAnchor, y: midY)) - path.addLine(to: CGPoint(x: leftAnchor, y: yAnchor)) - path.addLine(to: CGPoint(x: rightAnchor, y: yAnchor)) - path.addLine(to: CGPoint(x: rightAnchor, y: midY)) - path.addLine(to: CGPoint(x: endX, y: midY)) - - return path.cgPath - } - - private static let animationKey = "com.loudnate.Naterade.shapePathAnimation" - - private func animateToPath(_ path: CGPath) { - // Do not animate first draw - if shapeLayer.path != nil { - let animation = CABasicAnimation(keyPath: "path") - animation.fromValue = shapeLayer.path ?? drawPath() - animation.toValue = path - animation.duration = 1 - animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) - - shapeLayer.add(animation, forKey: type(of: self).animationKey) - } - - // Do not draw when size is zero - if bounds != .zero { - shapeLayer.path = path - } - } -} - -struct BasalStateSwiftUIViewPreviewWrapper: View { - @State private var percent: Double = 1 - - var body: some View { - VStack(spacing: 20) { - BasalStateSwiftUIView(netBasalPercent: percent).frame(width: 100, height: 100, alignment: .center) - Button(action: { - self.percent = self.percent * -1 - }) { - Text("Toggle sign") - } - Text("Percent = \(percent)") - } - } -} -struct BasalStateSwiftUIViewPreview: PreviewProvider { - static var previews: some View { - BasalStateSwiftUIViewPreviewWrapper() - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/BeepPreferenceSelectionView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/BeepPreferenceSelectionView.swift deleted file mode 100644 index 2af381623..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/BeepPreferenceSelectionView.swift +++ /dev/null @@ -1,146 +0,0 @@ -// -// BeepPreferenceSelectionView.swift -// OmniBLE -// -// Created by Pete Schwamb on 2/14/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI - -struct BeepPreferenceSelectionView: View { - - @Environment(\.horizontalSizeClass) var horizontalSizeClass - @Environment(\.presentationMode) var presentationMode: Binding - - private var initialValue: BeepPreference - @State private var preference: BeepPreference - private var onSave: ((_ selectedValue: BeepPreference, _ completion: @escaping (_ error: LocalizedError?) -> Void) -> Void)? - - @State private var alertIsPresented: Bool = false - @State private var error: LocalizedError? - @State private var saving: Bool = false - - - init(initialValue: BeepPreference, onSave: @escaping (_ selectedValue: BeepPreference, _ completion: @escaping (_ error: LocalizedError?) -> Void) -> Void) { - self.initialValue = initialValue - self._preference = State(initialValue: initialValue) - self.onSave = onSave - } - - var body: some View { - contentWithCancel - } - - var content: some View { - VStack { - List { - Section { - Text(LocalizedString("Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced.", comment: "Help text for BeepPreferenceSelectionView")).fixedSize(horizontal: false, vertical: true) - .padding(.vertical, 10) - } - - Section { - ForEach(BeepPreference.allCases, id: \.self) { preference in - HStack { - CheckmarkListItem( - title: Text(preference.title), - description: Text(preference.description), - isSelected: Binding( - get: { self.preference == preference }, - set: { isSelected in - if isSelected { - self.preference = preference - } - } - ) - ) - } - .padding(.vertical, 10) - } - } - .buttonStyle(PlainButtonStyle()) // Disable row highlighting on selection - } - VStack { - Button(action: { - saving = true - onSave?(preference) { (error) in - saving = false - if let error = error { - self.error = error - self.alertIsPresented = true - } else { - self.presentationMode.wrappedValue.dismiss() - } - } - }) { - Text(saveButtonText) - .actionButtonStyle(.primary) - } - .padding() - .disabled(saving || !valueChanged) - } - .padding(self.horizontalSizeClass == .regular ? .bottom : []) - .background(Color(UIColor.secondarySystemGroupedBackground).shadow(radius: 5)) - - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Confidence Reminders", comment: "navigation title for confidence reminders")) - .navigationBarTitleDisplayMode(.inline) - .alert(isPresented: $alertIsPresented, content: { alert(error: error) }) - } - - private var contentWithCancel: some View { - if saving { - return AnyView(content - .navigationBarBackButtonHidden(true) - ) - } else if valueChanged { - return AnyView(content - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: cancelButton) - ) - } else { - return AnyView(content) - } - } - - private var cancelButton: some View { - Button(action: { self.presentationMode.wrappedValue.dismiss() } ) { - Text(LocalizedString("Cancel", comment: "Button title for cancelling confidence reminders edit")) - } - } - - var saveButtonText: String { - if saving { - return LocalizedString("Saving...", comment: "button title for saving confidence reminder while saving") - } else { - return LocalizedString("Save", comment: "button title for saving confidence reminder") - } - } - - private var valueChanged: Bool { - return preference != initialValue - } - - private func alert(error: Error?) -> SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Failed to update confidence reminder preference.", comment: "Alert title for error when updating confidence reminder preference")), - message: Text(error?.localizedDescription ?? "No Error") - ) - } - -} - -struct BeepPreferenceSelectionView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - BeepPreferenceSelectionView(initialValue: .extended) { selectedValue, completion in - print("Selected: \(selectedValue)") - completion(nil) - } - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/CheckInsertedCannulaView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/CheckInsertedCannulaView.swift deleted file mode 100644 index 8d060bbc7..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/CheckInsertedCannulaView.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// CheckInsertedCannulaView.swift -// OmniBLE -// -// Created by Pete Schwamb on 4/3/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct CheckInsertedCannulaView: View { - - - @State private var cancelModalIsPresented: Bool = false - - private var didRequestDeactivation: () -> Void - private var wasInsertedProperly: () -> Void - - init(didRequestDeactivation: @escaping () -> Void, wasInsertedProperly: @escaping () -> Void) { - self.didRequestDeactivation = didRequestDeactivation - self.wasInsertedProperly = wasInsertedProperly - } - - var body: some View { - GuidePage(content: { - VStack { - LeadingImage("Cannula Inserted") - - HStack { - FrameworkLocalText("Is the cannula inserted properly?", comment: "Question to confirm the cannula is inserted properly").bold() - Spacer() - } - HStack { - FrameworkLocalText("The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin.", comment: "Description of proper cannula insertion").fixedSize(horizontal: false, vertical: true) - Spacer() - }.padding(.vertical) - } - - }) { - VStack(spacing: 10) { - Button(action: { - self.wasInsertedProperly() - }) { - Text(LocalizedString("Yes", comment: "Button label for user to answer cannula was properly inserted")) - .actionButtonStyle(.primary) - } - Button(action: { - self.didRequestDeactivation() - }) { - Text(LocalizedString("No", comment: "Button label for user to answer cannula was not properly inserted")) - .actionButtonStyle(.destructive) - } - }.padding() - } - .animation(.default) - .alert(isPresented: $cancelModalIsPresented) { cancelPairingModal } - .navigationBarTitle(LocalizedString("Check Cannula", comment: "navigation bar title for check cannula"), displayMode: .automatic) - .navigationBarItems(trailing: cancelButton) - .navigationBarBackButtonHidden(true) - } - - var cancelButton: some View { - Button(LocalizedString("Cancel", comment: "Cancel button text in navigation bar on insert cannula screen")) { - cancelModalIsPresented = true - } - .accessibility(identifier: "button_cancel") - } - - var cancelPairingModal: Alert { - return Alert( - title: FrameworkLocalText("Are you sure you want to cancel Pod setup?", comment: "Alert title for cancel pairing modal"), - message: FrameworkLocalText("If you cancel Pod setup, the current Pod will be deactivated and will be unusable.", comment: "Alert message body for confirm pod attachment"), - primaryButton: .destructive(FrameworkLocalText("Yes, Deactivate Pod", comment: "Button title for confirm deactivation option"), action: { didRequestDeactivation() } ), - secondaryButton: .default(FrameworkLocalText("No, Continue With Pod", comment: "Continue pairing button title of in pairing cancel modal")) - ) - } - -} - -struct CheckInsertedCannulaView_Previews: PreviewProvider { - static var previews: some View { - CheckInsertedCannulaView(didRequestDeactivation: {}, wasInsertedProperly: {} ) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DeactivatePodView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DeactivatePodView.swift deleted file mode 100644 index 73fa312e6..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DeactivatePodView.swift +++ /dev/null @@ -1,97 +0,0 @@ -// -// DeactivatePodView.swift -// OmniBLE -// -// Created by Pete Schwamb on 3/9/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct DeactivatePodView: View { - - @ObservedObject var viewModel: DeactivatePodViewModel - - @Environment(\.verticalSizeClass) var verticalSizeClass - @Environment(\.guidanceColors) var guidanceColors - - @State private var removePodModalIsPresented: Bool = false - - var body: some View { - GuidePage(content: { - VStack { - LeadingImage("Pod") - - HStack { - Text(viewModel.instructionText) - .fixedSize(horizontal: false, vertical: true) - Spacer() - } - } - .padding(.bottom, 8) - }) { - VStack { - if viewModel.state.showProgressDetail { - VStack { - viewModel.error.map {ErrorView($0).accessibility(sortPriority: 0)} - - if viewModel.error == nil { - VStack { - ProgressIndicatorView(state: viewModel.state.progressState) - if self.viewModel.state.isFinished { - FrameworkLocalText("Deactivated", comment: "Label text showing pod is deactivated") - .bold() - .padding(.top) - } - } - .padding(.bottom, 8) - } - - } - .transition(AnyTransition.opacity.combined(with: .move(edge: .bottom))) - } - if viewModel.error != nil { - Button(action: { - if viewModel.podAttachedToBody { - removePodModalIsPresented = true - } else { - viewModel.discardPod() - } - }) { - FrameworkLocalText("Discard Pod", comment: "Text for discard pod button") - .accessibility(identifier: "button_discard_pod_action") - .actionButtonStyle(.destructive) - } - .disabled(viewModel.state.isProcessing) - } - Button(action: { - viewModel.continueButtonTapped() - }) { - Text(viewModel.state.actionButtonDescription) - .accessibility(identifier: "button_next_action") - .accessibility(label: Text(viewModel.state.actionButtonAccessibilityLabel)) - .actionButtonStyle(viewModel.state.actionButtonStyle) - } - .disabled(viewModel.state.isProcessing) - } - .padding() - } - .alert(isPresented: $removePodModalIsPresented) { removePodModal } - .navigationBarTitle(LocalizedString("Deactivate Pod", comment: "navigation bar title for deactivate pod"), displayMode: .automatic) - .navigationBarItems(trailing: - Button("Cancel") { - viewModel.didCancel?() - } - ) - } - - var removePodModal: Alert { - return Alert( - title: FrameworkLocalText("Remove Pod from Body", comment: "Title for remove pod modal"), - message: FrameworkLocalText("Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“", comment: "Alert message body for confirm pod attachment"), - primaryButton: .cancel(), - secondaryButton: .default(FrameworkLocalText("Continue", comment: "Title of button to continue discard"), action: { viewModel.discardPod() }) - ) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DeliveryUncertaintyRecoveryView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DeliveryUncertaintyRecoveryView.swift deleted file mode 100644 index c4b24a881..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DeliveryUncertaintyRecoveryView.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// DeliveryUncertaintyRecoveryView.swift -// OmniBLE -// -// Created by Pete Schwamb on 8/17/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct DeliveryUncertaintyRecoveryView: View { - - let model: DeliveryUncertaintyRecoveryViewModel - - init(model: DeliveryUncertaintyRecoveryViewModel) { - self.model = model - } - - var body: some View { - GuidePage(content: { - Text(String(format: LocalizedString("%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display.", comment: "Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name)"), self.model.appName, self.uncertaintyDateLocalizedString, self.model.appName)) - .padding([.top, .bottom]) - }) { - VStack { - Text(LocalizedString("Attemping to re-establish communication", comment: "Description string above progress indicator while attempting to re-establish communication from an unacknowledged command")).padding(.top) - ProgressIndicatorView(state: .indeterminantProgress) - Button(action: { - self.model.podDeactivationChosen() - }) { - Text(LocalizedString("Deactivate Pod", comment: "Button title to deactive pod on uncertain program")) - .actionButtonStyle(.destructive) - .padding() - } - } - } - .navigationBarTitle(Text(LocalizedString("Unable to Reach Pod", comment: "Title of delivery uncertainty recovery page")), displayMode: .large) - .navigationBarItems(leading: backButton) - } - - private var uncertaintyDateLocalizedString: String { - DateFormatter.localizedString(from: model.uncertaintyStartedAt, dateStyle: .none, timeStyle: .short) - } - - private var backButton: some View { - Button(LocalizedString("Back", comment: "Back button text on DeliveryUncertaintyRecoveryView"), action: { - self.model.onDismiss?() - }) - } -} - -struct DeliveryUncertaintyRecoveryView_Previews: PreviewProvider { - static var previews: some View { - let model = DeliveryUncertaintyRecoveryViewModel(appName: "Test App", uncertaintyStartedAt: Date()) - return DeliveryUncertaintyRecoveryView(model: model) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DesignElements/ErrorView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DesignElements/ErrorView.swift deleted file mode 100644 index b61a2183c..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DesignElements/ErrorView.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// ErrorView.swift -// OmniBLE -// -// Created by Pete Schwamb on 3/12/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct ErrorView: View { - var error: LocalizedError - - var criticality: ErrorCriticality - - @Environment(\.guidanceColors) var guidanceColors - - public enum ErrorCriticality { - case critical - case normal - - func symbolColor(using guidanceColors: GuidanceColors) -> Color { - switch self { - case .critical: - return guidanceColors.critical - case .normal: - return guidanceColors.warning - } - } - } - - init(_ error: LocalizedError, errorClass: ErrorCriticality = .normal) { - self.error = error - self.criticality = errorClass - } - - var body: some View { - VStack(alignment: .leading, spacing: 15) { - HStack { - Image(systemName: "exclamationmark.triangle.fill") - .foregroundColor(self.criticality.symbolColor(using: guidanceColors)) - Text(self.error.errorDescription ?? "") - .bold() - .accessibility(identifier: "label_error_description") - .fixedSize(horizontal: false, vertical: true) - } - .accessibilityElement(children: .ignore) - .accessibility(label: FrameworkLocalText("Error", comment: "Accessibility label indicating an error occurred")) - - Text(self.error.recoverySuggestion ?? "") - .foregroundColor(.secondary) - .font(.footnote) - .accessibility(identifier: "label_recovery_suggestion") - .fixedSize(horizontal: false, vertical: true) - } - .padding(.bottom) - .accessibilityElement(children: .combine) - } -} - -struct ErrorView_Previews: PreviewProvider { - enum ErrorViewPreviewError: LocalizedError { - case someError - - var localizedDescription: String { "It didn't work" } - var recoverySuggestion: String { "Maybe try turning it on and off." } - } - - static var previews: some View { - ErrorView(ErrorViewPreviewError.someError) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DesignElements/LeadingImage.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DesignElements/LeadingImage.swift deleted file mode 100644 index 7de9f5e40..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DesignElements/LeadingImage.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// LeadingImage.swift -// OmniBLE -// -// Created by Pete Schwamb on 3/12/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -struct LeadingImage: View { - - var name: String - - static let compactScreenImageHeight: CGFloat = 70 - static let regularScreenImageHeight: CGFloat = 150 - - @Environment(\.verticalSizeClass) var verticalSizeClass - - init(_ name: String) { - self.name = name - } - - var body: some View { - Image(frameworkImage: self.name, decorative: true) - .resizable() - .aspectRatio(contentMode: ContentMode.fit) - .frame(height: self.verticalSizeClass == .compact ? LeadingImage.compactScreenImageHeight : LeadingImage.regularScreenImageHeight) - .padding(.vertical, self.verticalSizeClass == .compact ? 0 : nil) - } -} - -struct LeadingImage_Previews: PreviewProvider { - static var previews: some View { - LeadingImage("Pod") - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DesignElements/RoundedCard.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DesignElements/RoundedCard.swift deleted file mode 100644 index 71320ea43..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/DesignElements/RoundedCard.swift +++ /dev/null @@ -1,177 +0,0 @@ -// -// RoundedCard.swift -// OmniBLE -// -// Created by Pete Schwamb on 2/9/21. -// -import SwiftUI - -fileprivate let inset: CGFloat = 16 - -struct RoundedCardTitle: View { - var title: String - - init(_ title: String) { - self.title = title - } - - var body: some View { - Text(title) - .font(.headline) - .foregroundColor(.primary) - } -} - -struct RoundedCardFooter: View { - var text: String - - init(_ text: String) { - self.text = text - } - - var body: some View { - Text(text) - .font(.caption) - .fixedSize(horizontal: false, vertical: true) - .foregroundColor(.secondary) - } -} - -public struct RoundedCardValueRow: View { - var label: String - var value: String - var highlightValue: Bool - var disclosure: Bool - - public init(label: String, value: String, highlightValue: Bool = false, disclosure: Bool = false) { - self.label = label - self.value = value - self.highlightValue = highlightValue - self.disclosure = disclosure - } - - public var body: some View { - HStack { - Text(label) - .fixedSize(horizontal: false, vertical: true) - .foregroundColor(.primary) - Spacer() - Text(value) - .fixedSize(horizontal: true, vertical: true) - .foregroundColor(highlightValue ? .accentColor : .secondary) - if disclosure { - Image(systemName: "chevron.right") - .imageScale(.small) - .font(.headline) - .foregroundColor(.secondary) - .opacity(0.5) - } - } - } -} - -struct RoundedCard: View { - var content: () -> Content? - var alignment: HorizontalAlignment - var title: String? - var footer: String? - @Environment(\.horizontalSizeClass) var horizontalSizeClass - - init(title: String? = nil, footer: String? = nil, alignment: HorizontalAlignment = .leading, @ViewBuilder content: @escaping () -> Content? = { nil }) { - self.content = content - self.alignment = alignment - self.title = title - self.footer = footer - } - - var body: some View { - VStack(spacing: 10) { - if let title = title { - RoundedCardTitle(title) - .frame(maxWidth: .infinity, alignment: Alignment(horizontal: .leading, vertical: .center)) - .padding(.leading, titleInset) - } - - if content() != nil { - if isCompact { - VStack(spacing: 0) { - borderLine - VStack(alignment: alignment, content: content) - .frame(maxWidth: .infinity, alignment: Alignment(horizontal: alignment, vertical: .center)) - .padding(inset) - .background(Color(.secondarySystemGroupedBackground)) - borderLine - } - } else { - VStack(alignment: alignment, content: content) - .frame(maxWidth: .infinity, alignment: Alignment(horizontal: alignment, vertical: .center)) - .padding(.horizontal, inset) - .padding(.vertical, 10) - .background(Color(.secondarySystemGroupedBackground)) - .clipShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)) - } - } - - if let footer = footer { - RoundedCardFooter(footer) - .frame(maxWidth: .infinity, alignment: Alignment(horizontal: alignment, vertical: .center)) - .padding(.horizontal, inset) - } - } - } - - var borderLine: some View { - Rectangle().fill(Color(.quaternaryLabel)) - .frame(height: 0.5) - } - - private var isCompact: Bool { - return self.horizontalSizeClass == .compact - } - - private var titleInset: CGFloat { - return isCompact ? inset : 0 - } - - private var padding: CGFloat { - return isCompact ? 0 : inset - } - - private var cornerRadius: CGFloat { - return isCompact ? 0 : 8 - } - -} - -struct RoundedCardScrollView: View { - var content: () -> Content - var title: String? - @Environment(\.horizontalSizeClass) var horizontalSizeClass - - init(title: String? = nil, @ViewBuilder content: @escaping () -> Content) { - self.title = title - self.content = content - } - - var body: some View { - ScrollView { - if let title = title { - HStack { - Text(title) - .font(Font.largeTitle.weight(.bold)) - .padding(.top) - Spacer() - } - .padding([.leading, .trailing]) - } - VStack(alignment: .leading, spacing: 25, content: content) - .padding(padding) - } - .background(Color(.systemGroupedBackground).edgesIgnoringSafeArea(.all)) - } - - private var padding: CGFloat { - return self.horizontalSizeClass == .regular ? inset : 0 - } - -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ExpirationReminderPickerView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ExpirationReminderPickerView.swift deleted file mode 100644 index 3b8dd06c0..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ExpirationReminderPickerView.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// ExpirationReminderPickerView.swift -// OmniBLE -// -// Created by Pete Schwamb on 5/17/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import HealthKit - -struct ExpirationReminderPickerView: View { - - static let expirationReminderHoursAllowed = 0...24 - - var expirationReminderDefault: Binding - - var collapsible: Bool = true - - @State var showingHourPicker: Bool = false - - var expirationDefaultFormatter = QuantityFormatter(for: .hour()) - - var expirationDefaultString: String { - return expirationReminderHourString(expirationReminderDefault.wrappedValue) - } - - var body: some View { - VStack { - HStack { - Text(LocalizedString("Expiration Reminder Default", comment: "Label text for expiration reminder default row")) - Spacer() - if collapsible { - Button(expirationDefaultString) { - withAnimation { - showingHourPicker.toggle() - } - } - } else { - Text(expirationDefaultString) - } - } - if showingHourPicker { - ResizeablePicker(selection: expirationReminderDefault, - data: Array(Self.expirationReminderHoursAllowed), - formatter: { expirationReminderHourString($0) }) - } - } - } - - private func expirationReminderHourString(_ value: Int) -> String { - if value > 0 { - return expirationDefaultFormatter.string(from: HKQuantity(unit: .hour(), doubleValue: Double(value)), for: .hour())! - } else { - return LocalizedString("No Reminder", comment: "Value text for no expiration reminder") - } - } -} - -struct ExpirationReminderPickerView_Previews: PreviewProvider { - static var previews: some View { - ExpirationReminderPickerView(expirationReminderDefault: .constant(2), showingHourPicker: true) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ExpirationReminderSetupView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ExpirationReminderSetupView.swift deleted file mode 100644 index b5bbd4e1e..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ExpirationReminderSetupView.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// ExpirationReminderSetupView.swift -// OmniBLE -// -// Created by Pete Schwamb on 5/17/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct ExpirationReminderSetupView: View { - @State var expirationReminderDefault: Int = 2 - - public var valueChanged: ((_ value: Int) -> Void)? - public var continueButtonTapped: (() -> Void)? - public var cancelButtonTapped: (() -> Void)? - - var body: some View { - GuidePage(content: { - VStack(alignment: .leading, spacing: 15) { - Text(LocalizedString("The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have.", comment: "Description text on ExpirationReminderSetupView")).fixedSize(horizontal: false, vertical: true) - Divider() - ExpirationReminderPickerView(expirationReminderDefault: $expirationReminderDefault, collapsible: false, showingHourPicker: true) - .onChange(of: expirationReminderDefault) { value in - valueChanged?(value) - } - } - .padding(.vertical, 8) - }) { - VStack { - Button(action: { - continueButtonTapped?() - }) { - Text(LocalizedString("Next", comment: "Text of continue button on ExpirationReminderSetupView")) - .actionButtonStyle(.primary) - } - } - .padding() - } - .navigationBarTitle(LocalizedString("Expiration Reminder", comment: "navigation bar title for expiration reminder"), displayMode: .automatic) - .navigationBarHidden(false) - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(LocalizedString("Cancel", comment: "Cancel button title"), action: { - cancelButtonTapped?() - }) - } - } - } -} - -struct ExpirationReminderSetupView_Previews: PreviewProvider { - static var previews: some View { - ExpirationReminderSetupView() - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/FirstAppear.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/FirstAppear.swift deleted file mode 100644 index 2c042a75c..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/FirstAppear.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// FirstAppear.swift -// OmniBLE -// -// Created by Joe Moran on 9/24/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -extension View { - func onFirstAppear(_ action: @escaping () -> ()) -> some View { - modifier(FirstAppear(action: action)) - } -} - -private struct FirstAppear: ViewModifier { - let action: () -> () - - // State used to insure action is invoked here only once - @State private var hasAppeared = false - - func body(content: Content) -> some View { - content.onAppear { - guard !hasAppeared else { return } - hasAppeared = true - action() - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/Contents.json b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/pod_life/Contents.json b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/pod_life/Contents.json deleted file mode 100644 index da4a164c9..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/pod_life/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/pod_life/pod_life.imageset/Contents.json b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/pod_life/pod_life.imageset/Contents.json deleted file mode 100644 index bd5c9bd61..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/pod_life/pod_life.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "Pod Life.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/pod_life/pod_life.imageset/Pod Life.pdf b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/pod_life/pod_life.imageset/Pod Life.pdf deleted file mode 100644 index c2ce51715..000000000 Binary files a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/pod_life/pod_life.imageset/Pod Life.pdf and /dev/null differ diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/Contents.json b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/Contents.json b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/Contents.json deleted file mode 100644 index 7a65fb9c2..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "reservoir.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/reservoir.pdf b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/reservoir.pdf deleted file mode 100644 index 623015046..000000000 Binary files a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/reservoir.pdf and /dev/null differ diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/Contents.json b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/Contents.json deleted file mode 100644 index e19598694..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "reservoir_mask.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/reservoir_mask.pdf b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/reservoir_mask.pdf deleted file mode 100644 index 040769397..000000000 Binary files a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/reservoir_mask.pdf and /dev/null differ diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/InsertCannulaView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/InsertCannulaView.swift deleted file mode 100644 index bf625b048..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/InsertCannulaView.swift +++ /dev/null @@ -1,107 +0,0 @@ -// -// InsertCannulaView.swift -// OmniBLE -// -// Created by Pete Schwamb on 2/5/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct InsertCannulaView: View { - - @ObservedObject var viewModel: InsertCannulaViewModel - - @Environment(\.verticalSizeClass) var verticalSizeClass - - @State private var cancelModalIsPresented: Bool = false - - var body: some View { - GuidePage(content: { - VStack { - LeadingImage("Pod") - - HStack { - InstructionList(instructions: [ - LocalizedString("Tap below to start cannula insertion.", comment: "Label text for step one of insert cannula instructions"), - LocalizedString("Wait until insertion is completed.", comment: "Label text for step two of insert cannula instructions"), - ]) - .disabled(viewModel.state.instructionsDisabled) - - } - .padding(.bottom, 8) - } - .accessibility(sortPriority: 1) - }) { - VStack { - if self.viewModel.state.showProgressDetail { - self.viewModel.error.map { - ErrorView($0, errorClass: $0.recoverable ? .normal : .critical) - .accessibility(sortPriority: 0) - } - - if self.viewModel.error == nil { - VStack { - ProgressIndicatorView(state: self.viewModel.state.progressState) - if self.viewModel.state.isFinished { - FrameworkLocalText("Inserted", comment: "Label text indicating insertion finished.") - .bold() - .padding(.top) - } - } - .padding(.bottom, 8) - } - } - if self.viewModel.error != nil { - Button(action: { - self.viewModel.didRequestDeactivation?() - }) { - Text(LocalizedString("Deactivate Pod", comment: "Button text for deactivate pod button")) - .accessibility(identifier: "button_deactivate_pod") - .actionButtonStyle(.secondary) - } - .disabled(self.viewModel.state.isProcessing) - } - - if (self.viewModel.error == nil || self.viewModel.error?.recoverable == true) { - Button(action: { - self.viewModel.continueButtonTapped() - }) { - Text(self.viewModel.state.nextActionButtonDescription) - .accessibility(identifier: "button_next_action") - .accessibility(label: Text(self.viewModel.state.actionButtonAccessibilityLabel)) - .actionButtonStyle(.primary) - } - .disabled(self.viewModel.state.isProcessing) - .animation(nil) - .zIndex(1) - } - } - .transition(AnyTransition.opacity.combined(with: .move(edge: .bottom))) - .padding() - } - .animation(.default) - .alert(isPresented: $cancelModalIsPresented) { cancelPairingModal } - .navigationBarTitle(LocalizedString("Insert Cannula", comment: "navigation bar title for insert cannula"), displayMode: .automatic) - .navigationBarBackButtonHidden(true) - .navigationBarItems(trailing: cancelButton) - } - - var cancelButton: some View { - Button(LocalizedString("Cancel", comment: "Cancel button text in navigation bar on insert cannula screen")) { - cancelModalIsPresented = true - } - .accessibility(identifier: "button_cancel") - } - - var cancelPairingModal: Alert { - return Alert( - title: FrameworkLocalText("Are you sure you want to cancel Pod setup?", comment: "Alert title for cancel pairing modal"), - message: FrameworkLocalText("If you cancel Pod setup, the current Pod will be deactivated and will be unusable.", comment: "Alert message body for confirm pod attachment"), - primaryButton: .destructive(FrameworkLocalText("Yes, Deactivate Pod", comment: "Button title for confirm deactivation option"), action: { viewModel.didRequestDeactivation?() } ), - secondaryButton: .default(FrameworkLocalText("No, Continue With Pod", comment: "Continue pairing button title of in pairing cancel modal")) - ) - } - -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/InsulinTypeConfirmation.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/InsulinTypeConfirmation.swift deleted file mode 100644 index 814f1fdba..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/InsulinTypeConfirmation.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// InsulinTypeConfirmation.swift -// MockKitUI -// -// Created by Pete Schwamb on 1/1/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI - -struct InsulinTypeConfirmation: View { - - @State private var insulinType: InsulinType? - private var supportedInsulinTypes: [InsulinType] - private var didConfirm: (InsulinType) -> Void - private var didCancel: () -> Void - - init(initialValue: InsulinType, supportedInsulinTypes: [InsulinType], didConfirm: @escaping (InsulinType) -> Void, didCancel: @escaping () -> Void) { - self._insulinType = State(initialValue: initialValue) - self.supportedInsulinTypes = supportedInsulinTypes - self.didConfirm = didConfirm - self.didCancel = didCancel - } - - func continueWithType(_ insulinType: InsulinType?) { - if let insulinType = insulinType { - didConfirm(insulinType) - } else { - assertionFailure() - } - } - - var body: some View { - VStack { - List { - Section { - Text(LocalizedString("Select the type of insulin that you will be using in this pod.", comment: "Title text for insulin type confirmation page")) - } - Section { - InsulinTypeChooser(insulinType: $insulinType, supportedInsulinTypes: supportedInsulinTypes) - } - .buttonStyle(PlainButtonStyle()) // Disable row highlighting on selection - } - .insetGroupedListStyle() - - Button(action: { self.continueWithType(insulinType) }) { - Text(LocalizedString("Continue", comment: "Text for continue button")) - .actionButtonStyle(.primary) - .padding() - } - } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(LocalizedString("Cancel", comment: "Cancel button title"), action: { - didCancel() - }) - } - } - } -} - -struct InsulinTypeConfirmation_Previews: PreviewProvider { - static var previews: some View { - InsulinTypeConfirmation(initialValue: .humalog, supportedInsulinTypes: InsulinType.allCases, didConfirm: { (newType) in }, didCancel: { }) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/LowReservoirReminderEditView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/LowReservoirReminderEditView.swift deleted file mode 100644 index 9208d6c8d..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/LowReservoirReminderEditView.swift +++ /dev/null @@ -1,155 +0,0 @@ -// -// LowReservoirReminderEditView.swift -// OmniBLE -// -// Created by Pete Schwamb on 2/17/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import HealthKit - -struct LowReservoirReminderEditView: View { - - @Environment(\.horizontalSizeClass) var horizontalSizeClass - - var onSave: ((_ selectedValue: Int, _ completion: @escaping (_ error: Error?) -> Void) -> Void)? - var onFinish: (() -> Void)? - var insulinQuantityFormatter: QuantityFormatter - - private var initialValue: Int - @State private var alertIsPresented: Bool = false - @State private var error: Error? - @State private var saving: Bool = false - @State private var selectedValue: Int - - - init(lowReservoirReminderValue: Int, insulinQuantityFormatter: QuantityFormatter, onSave: ((_ selectedValue: Int, _ completion: @escaping (_ error: Error?) -> Void) -> Void)? = nil, onFinish: (() -> Void)? = nil) - { - self.onSave = onSave - self.onFinish = onFinish - self.insulinQuantityFormatter = insulinQuantityFormatter - self.initialValue = lowReservoirReminderValue - self._selectedValue = State(initialValue: lowReservoirReminderValue) - } - - var body: some View { - contentWithCancel - } - - var content: some View { - VStack { - RoundedCardScrollView(title: LocalizedString("Low Reservoir Reminder", comment: "Title for low reservoir reminder edit page")) { - if self.horizontalSizeClass == .compact { - // Keep picker outside of card in compact view, because it forces full device width. - VStack(spacing: 0) { - RoundedCard { - RoundedCardValueRow( - label: LocalizedString("Low Reservoir Reminder", comment: "Label for low reservoir reminder row"), - value: formatValue(selectedValue), - highlightValue: true - ) - } - picker - .background(Color(.secondarySystemGroupedBackground)) - } - } else { - RoundedCard { - RoundedCardValueRow( - label: LocalizedString("Low Reservoir Reminder", comment: "Label for low reservoir reminder row"), - value: formatValue(selectedValue), - highlightValue: true - ) - picker - } - } - } - Spacer() - Button(action: saveTapped) { - Text(saveButtonText) - .actionButtonStyle() - .padding() - } - .disabled(saving || !valueChanged) - } - .navigationTitle("") - .navigationBarTitleDisplayMode(.inline) - .alert(isPresented: $alertIsPresented, content: { alert(error: error) }) - } - - private var picker: some View { - Picker("", selection: $selectedValue) { - ForEach(Pod.allowedLowReservoirReminderValues, id: \.self) { value in - Text(formatValue(value)) - } - }.pickerStyle(WheelPickerStyle()) - } - - func formatValue(_ value: Int) -> String { - return insulinQuantityFormatter.string(from: HKQuantity(unit: .internationalUnit(), doubleValue: Double(value)), for: .internationalUnit()) ?? "" - } - - var saveButtonText: String { - if saving { - return LocalizedString("Saving...", comment: "button title for saving low reservoir reminder while saving") - } else { - return LocalizedString("Save", comment: "button title for saving low reservoir reminder") - } - } - - private func saveTapped() { - saving = true - self.onSave?(selectedValue) { (error) in - saving = false - if let error = error { - self.error = error - self.alertIsPresented = true - } else { - self.onFinish?() - } - } - } - - private var valueChanged: Bool { - return selectedValue != initialValue - } - - private var contentWithCancel: some View { - if saving { - return AnyView(content - .navigationBarBackButtonHidden(true) - ) - } else if valueChanged { - return AnyView(content - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: cancelButton) - ) - } else { - return AnyView(content) - } - } - - private var cancelButton: some View { - Button(action: { self.onFinish?() } ) { Text(LocalizedString("Cancel", comment: "Button title for cancelling low reservoir reminder edit")) } - } - - private func alert(error: Error?) -> SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Failed to Update Low Reservoir Reminder", comment: "Alert title for error when updating low reservoir reminder")), - message: Text(error?.localizedDescription ?? "No Error") - ) - } -} - -struct LowReservoirReminderEditView_Previews: PreviewProvider { - static var previews: some View { - LowReservoirReminderEditView( - lowReservoirReminderValue: 20, - insulinQuantityFormatter: QuantityFormatter(for: .internationalUnit()), - onSave: { (_, _) in }, - onFinish: { } - ) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/LowReservoirReminderSetupView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/LowReservoirReminderSetupView.swift deleted file mode 100644 index 940fa1ef3..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/LowReservoirReminderSetupView.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// LowReservoirReminderSetupView.swift -// OmniBLE -// -// Created by Pete Schwamb on 5/17/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI -import LoopKit -import HealthKit - -struct LowReservoirReminderSetupView: View { - - @State var lowReservoirReminderValue: Int - - public var valueChanged: ((_ value: Int) -> Void)? - public var continueButtonTapped: (() -> Void)? - public var cancelButtonTapped: (() -> Void)? - - var insulinQuantityFormatter = QuantityFormatter(for: .internationalUnit()) - - func formatValue(_ value: Int) -> String { - return insulinQuantityFormatter.string(from: HKQuantity(unit: .internationalUnit(), doubleValue: Double(value)), for: .internationalUnit()) ?? "" - } - - var body: some View { - GuidePage(content: { - VStack(alignment: .leading, spacing: 15) { - Text(LocalizedString("The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded.", comment: "Description text on LowReservoirReminderSetupView")) - Divider() - HStack { - Text(LocalizedString("Low Reservoir", comment: "Label text for low reservoir value row")) - Spacer() - Text(formatValue(lowReservoirReminderValue)) - } - picker - } - .padding(.vertical, 8) - }) { - VStack { - Button(action: { - continueButtonTapped?() - }) { - Text(LocalizedString("Next", comment: "Text of continue button on ExpirationReminderSetupView")) - .actionButtonStyle(.primary) - } - } - .padding() - } - .navigationBarTitle(LocalizedString("Low Reservoir", comment: "navigation bar title for low reservoir"), displayMode: .automatic) - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(LocalizedString("Cancel", comment: "Cancel button title"), action: { - cancelButtonTapped?() - }) - } - } - } - - private var picker: some View { - Picker("", selection: $lowReservoirReminderValue) { - ForEach(Pod.allowedLowReservoirReminderValues, id: \.self) { value in - Text(formatValue(value)) - } - }.pickerStyle(WheelPickerStyle()) - .onChange(of: lowReservoirReminderValue) { value in - valueChanged?(value) - } - - } - -} -struct LowReservoirReminderSetupView_Previews: PreviewProvider { - static var previews: some View { - LowReservoirReminderSetupView(lowReservoirReminderValue: 10) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ManualTempBasalEntryView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ManualTempBasalEntryView.swift deleted file mode 100644 index aaed7d32b..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ManualTempBasalEntryView.swift +++ /dev/null @@ -1,161 +0,0 @@ -// -// ManualTempBasalEntryView.swift -// OmniBLE -// -// Created by Pete Schwamb on 5/14/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI -import LoopKit -import HealthKit - -struct ManualTempBasalEntryView: View { - - @Environment(\.guidanceColors) var guidanceColors - - var enactBasal: ((Double,TimeInterval,@escaping (PumpManagerError?)->Void) -> Void)? - var didCancel: (() -> Void)? - - @State private var rateEntered: Double = 0.0 - @State private var durationEntered: TimeInterval = .hours(0.5) - @State private var showPicker: Bool = false - @State private var error: PumpManagerError? - @State private var enacting: Bool = false - @State private var showingErrorAlert: Bool = false - @State private var showingMissingConfigAlert: Bool = false - - var allowedRates: [Double] - - init(enactBasal: ((Double,TimeInterval,@escaping (PumpManagerError?)->Void) -> Void)? = nil, didCancel: (() -> Void)? = nil, allowedRates: [Double]) { - self.enactBasal = enactBasal - self.didCancel = didCancel - self.allowedRates = allowedRates - // This is to handle the temporary situation of devs/testers migrating from OmniBLEPumpManagerState with no - // max temp basal set - if allowedRates.count == 1 && allowedRates[0] == 0.0 { - _showingMissingConfigAlert = State(initialValue: true) - } - } - - private static let rateFormatter: QuantityFormatter = { - let quantityFormatter = QuantityFormatter() - quantityFormatter.setPreferredNumberFormatter(for: .internationalUnitsPerHour) - quantityFormatter.numberFormatter.minimumFractionDigits = 2 - return quantityFormatter - }() - - private var rateUnitsLabel: some View { - Text(QuantityFormatter().string(from: .internationalUnitsPerHour)) - .foregroundColor(Color(.secondaryLabel)) - } - - private static let durationFormatter: QuantityFormatter = { - let quantityFormatter = QuantityFormatter() - quantityFormatter.setPreferredNumberFormatter(for: .hour()) - quantityFormatter.numberFormatter.minimumFractionDigits = 1 - quantityFormatter.numberFormatter.maximumFractionDigits = 1 - quantityFormatter.unitStyle = .long - return quantityFormatter - }() - - private var durationUnitsLabel: some View { - Text(QuantityFormatter().string(from: .hour())) - .foregroundColor(Color(.secondaryLabel)) - } - - func formatRate(_ rate: Double) -> String { - let unit = HKUnit.internationalUnitsPerHour - return ManualTempBasalEntryView.rateFormatter.string(from: HKQuantity(unit: unit, doubleValue: rate), for: unit) ?? "" - } - - func formatDuration(_ duration: TimeInterval) -> String { - let unit = HKUnit.hour() - return ManualTempBasalEntryView.durationFormatter.string(from: HKQuantity(unit: unit, doubleValue: duration.hours), for: unit) ?? "" - } - - var body: some View { - NavigationView { - VStack { - List { - HStack { - Text(LocalizedString("Rate", comment: "Label text for basal rate summary")) - Spacer() - Text(String(format: LocalizedString("%1$@ for %2$@", comment: "Summary string for temporary basal rate configuration page"), formatRate(rateEntered), formatDuration(durationEntered))) - } - HStack { - ResizeablePicker(selection: $rateEntered, - data: allowedRates, - formatter: { formatRate($0) }) - ResizeablePicker(selection: $durationEntered, - data: Pod.supportedTempBasalDurations, - formatter: { formatDuration($0) }) - } - .frame(maxHeight: 162.0) - .alert(isPresented: $showingMissingConfigAlert, content: { missingConfigAlert }) - Section { - Text(LocalizedString("Your insulin delivery will not be automatically adjusted until the temporary basal rate finishes or is canceled.", comment: "Description text on manual temp basal action sheet")) - .font(.footnote) - .foregroundColor(.secondary) - .fixedSize(horizontal: false, vertical: true) - } - } - Button(action: { - enacting = true - enactBasal?(rateEntered, durationEntered) { (error) in - if let error = error { - self.error = error - showingErrorAlert = true - } - enacting = false - } - }) { - HStack { - if enacting { - ProgressView() - } else { - Text(LocalizedString("Set Temporary Basal", comment: "Button text for setting manual temporary basal rate")) - } - } - } - .buttonStyle(ActionButtonStyle(.primary)) - .padding() - } - .navigationTitle(LocalizedString("Temporary Basal", comment: "Navigation Title for ManualTempBasalEntryView")) - .navigationBarItems(trailing: cancelButton) - .alert(isPresented: $showingErrorAlert, content: { errorAlert }) - .disabled(enacting) - } - } - - var errorAlert: SwiftUI.Alert { - let errorMessage = errorMessage(error: error!) - return SwiftUI.Alert( - title: Text(LocalizedString("Temporary Basal Failed", comment: "Alert title for a failure to set temporary basal")), - message: errorMessage) - } - - func errorMessage(error: PumpManagerError) -> Text { - if let recovery = error.recoverySuggestion { - return Text(String(format: LocalizedString("Unable to set a temporary basal rate: %1$@\n\n%2$@", comment: "Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text)"), error.localizedDescription, recovery)) - } else { - return Text(String(format: LocalizedString("Unable to set a temporary basal rate: %1$@", comment: "Alert format string for a failure to set temporary basal. (1: error description)"), error.localizedDescription)) - } - } - - var missingConfigAlert: SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Missing Config", comment: "Alert title for missing temp basal configuration")), - message: Text(LocalizedString("This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Pump Settings in the settings CONFIGURATION section to set a new Max Basal.", comment: "Alert format string for missing temp basal configuration.")) - ) - } - - - var cancelButton: some View { - Button(LocalizedString("Cancel", comment: "Cancel button text in navigation bar on insert cannula screen")) { - didCancel?() - } - .accessibility(identifier: "button_cancel") - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/NotificationSettingsView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/NotificationSettingsView.swift deleted file mode 100644 index 087c873fb..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/NotificationSettingsView.swift +++ /dev/null @@ -1,144 +0,0 @@ -// -// NotificationSettingsView.swift -// OmniBLE -// -// Created by Pete Schwamb on 2/3/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import HealthKit - -struct NotificationSettingsView: View { - - var dateFormatter: DateFormatter - - @Binding var expirationReminderDefault: Int - - @State private var showingHourPicker: Bool = false - - var scheduledReminderDate: Date? - - var allowedScheduledReminderDates: [Date]? - - var lowReservoirReminderValue: Int - - var onSaveScheduledExpirationReminder: ((_ selectedDate: Date?, _ completion: @escaping (_ error: Error?) -> Void) -> Void)? - - var onSaveLowReservoirReminder: ((_ selectedValue: Int, _ completion: @escaping (_ error: Error?) -> Void) -> Void)? - - var insulinQuantityFormatter = QuantityFormatter(for: .internationalUnit()) - - var body: some View { - RoundedCardScrollView { - RoundedCard( - title: LocalizedString("Pod Reminders", comment: "Title for pod reminders section"), - footer: LocalizedString("The app configures a reminder on the Pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure by default when pairing a new Pod.", comment: "Footer text for pod reminders section") - ) { - ExpirationReminderPickerView(expirationReminderDefault: $expirationReminderDefault) - } - - if let allowedDates = allowedScheduledReminderDates { - RoundedCard( - footer: LocalizedString("The expiration reminder time for the current Pod.", comment: "Footer text for scheduled reminder area")) - { - Text(LocalizedString("Scheduled Reminder", comment: "Title of scheduled reminder card on NotificationSettingsView")) - Divider() - scheduledReminderRow(scheduledDate: scheduledReminderDate, allowedDates: allowedDates) - } - } - - RoundedCard(footer: LocalizedString("The app notifies you when the amount of insulin in the Pod reaches this level.", comment: "Footer text for low reservoir value row")) { - lowReservoirValueRow - } - - RoundedCard( - title: LocalizedString("Critical Alerts", comment: "Title for critical alerts description"), - footer: LocalizedString("The above reminders will not sound in the app if your device is in Silent or Do Not Disturb mode. There are other critical Pod alerts that will sound in the app even if your device is set to Silent or Do Not Disturb mode.\n\nThe Pod will also use audible beeps for all Pod reminders and alerts except when the Pod is Silenced.", comment: "Description text for critical alerts") - ) - } - .navigationBarTitle(LocalizedString("Notification Settings", comment: "navigation title for notification settings")) - } - - @State private var scheduleReminderDateEditViewIsShown: Bool = false - - private func scheduledReminderRow(scheduledDate: Date?, allowedDates: [Date]) -> some View { - Group { - // Make the expiration reminder time read-only if there aren't any more available times. - if allowedDates.isEmpty { - scheduledReminderRowContents(disclosure: false) - } else { - NavigationLink( - destination: ScheduledExpirationReminderEditView( - scheduledExpirationReminderDate: scheduledDate, - allowedDates: allowedDates, - dateFormatter: dateFormatter, - onSave: onSaveScheduledExpirationReminder, - onFinish: { scheduleReminderDateEditViewIsShown = false }), - isActive: $scheduleReminderDateEditViewIsShown) - { - scheduledReminderRowContents(disclosure: true) - } - } - } - } - - private func scheduledReminderRowContents(disclosure: Bool) -> some View { - RoundedCardValueRow( - label: LocalizedString("Time", comment: "Label for scheduled reminder value row"), - value: scheduledReminderDateString(scheduledReminderDate), - highlightValue: false, - disclosure: disclosure - ) - } - - private func scheduledReminderDateString(_ scheduledDate: Date?) -> String { - if let scheduledDate = scheduledDate { - return dateFormatter.string(from: scheduledDate) - } else { - return LocalizedString("No Reminder", comment: "Value text for no expiration reminder") - } - } - - @State private var lowReservoirReminderEditViewIsShown: Bool = false - - var lowReservoirValueRow: some View { - NavigationLink( - destination: LowReservoirReminderEditView( - lowReservoirReminderValue: lowReservoirReminderValue, - insulinQuantityFormatter: insulinQuantityFormatter, - onSave: onSaveLowReservoirReminder, - onFinish: { lowReservoirReminderEditViewIsShown = false }), - isActive: $lowReservoirReminderEditViewIsShown) - { - RoundedCardValueRow( - label: LocalizedString("Low Reservoir Reminder", comment: "Label for low reservoir reminder row"), - value: insulinQuantityFormatter.string(from: HKQuantity(unit: .internationalUnit(), doubleValue: Double(lowReservoirReminderValue)), for: .internationalUnit()) ?? "", - highlightValue: false, - disclosure: true) - } - } -} - -struct NotificationSettingsView_Previews: PreviewProvider { - static var previews: some View { - return Group { - let now = Date() - NavigationView { - NotificationSettingsView(dateFormatter: DateFormatter(), expirationReminderDefault: .constant(2), scheduledReminderDate: now + TimeInterval(hours: 1), allowedScheduledReminderDates: [now, now - TimeInterval(hours: 2), now - TimeInterval(hours: 3)], lowReservoirReminderValue: 20) - .previewDevice(PreviewDevice(rawValue:"iPod touch (7th generation)")) - .previewDisplayName("iPod touch (7th generation)") - } - - NavigationView { - let now = Date() - NotificationSettingsView(dateFormatter: DateFormatter(), expirationReminderDefault: .constant(2), scheduledReminderDate: now + TimeInterval(hours: 1), allowedScheduledReminderDates: [now, now - TimeInterval(hours: 2), now - TimeInterval(hours: 3)], lowReservoirReminderValue: 20) - .colorScheme(.dark) - .previewDevice(PreviewDevice(rawValue: "iPhone XS Max")) - .previewDisplayName("iPhone XS Max - Dark") - } - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/OmniBLEReservoirView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/OmniBLEReservoirView.swift deleted file mode 100644 index fa3cb328b..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/OmniBLEReservoirView.swift +++ /dev/null @@ -1,126 +0,0 @@ -// -// OmnipodReservoirView.swift -// OmniBLE -// -// Created by Pete Schwamb on 10/22/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import UIKit -import LoopKitUI - -public final class OmniBLEReservoirView: LevelHUDView, NibLoadable { - - override public var orderPriority: HUDViewOrderPriority { - return 11 - } - - @IBOutlet private weak var volumeLabel: UILabel! - - @IBOutlet private weak var alertLabel: UILabel! { - didSet { - alertLabel.alpha = 0 - alertLabel.textColor = UIColor.white - alertLabel.layer.cornerRadius = 9 - alertLabel.clipsToBounds = true - } - } - - public class func instantiate() -> OmniBLEReservoirView { - return nib().instantiate(withOwner: nil, options: nil)[0] as! OmniBLEReservoirView - } - - override public func awakeFromNib() { - super.awakeFromNib() - - volumeLabel.isHidden = true - } - - private var reservoirLevel: ReservoirLevel? - private var lastUpdateDate: Date? - private var reservoirLevelHighlightState = ReservoirLevelHighlightState.normal - - override public func tintColorDidChange() { - super.tintColorDidChange() - - alertLabel?.backgroundColor = tintColor - volumeLabel.textColor = tintColor - levelMaskView.tintColor = tintColor - } - - override public func updateColor() { - switch reservoirLevelHighlightState { - case .normal: - tintColor = stateColors?.normal - case .warning: - tintColor = stateColors?.warning - case .critical: - tintColor = stateColors?.error - } - } - - private lazy var timeFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .none - formatter.timeStyle = .short - - return formatter - }() - - private lazy var numberFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.maximumFractionDigits = 0 - - return formatter - }() - - private func updateViews() { - if let reservoirLevel = reservoirLevel, let date = lastUpdateDate { - - let time = timeFormatter.string(from: date) - caption?.text = time - - switch reservoirLevel { - case .aboveThreshold: - level = nil - volumeLabel.isHidden = true - if let units = numberFormatter.string(from: Pod.maximumReservoirReading) { - volumeLabel.text = String(format: LocalizedString("%@+ U", comment: "Format string for reservoir volume when above maximum reading. (1: The maximum reading)"), units) - accessibilityValue = String(format: LocalizedString("Greater than %1$@ units remaining at %2$@", comment: "Accessibility format string for (1: localized volume)(2: time)"), units, time) - } - case .valid(let value): - level = reservoirLevel.percentage - volumeLabel.isHidden = false - - if let units = numberFormatter.string(from: value) { - volumeLabel.text = String(format: LocalizedString("%@U", comment: "Format string for reservoir volume. (1: The localized volume)"), units) - - accessibilityValue = String(format: LocalizedString("%1$@ units remaining at %2$@", comment: "Accessibility format string for (1: localized volume)(2: time)"), units, time) - } - } - } else { - level = 0 - volumeLabel.isHidden = true - } - - var alertLabelAlpha: CGFloat = 1 - switch reservoirLevelHighlightState { - case .normal: - alertLabelAlpha = 0 - case .warning, .critical: - alertLabel?.text = "!" - } - - UIView.animate(withDuration: 0.25, animations: { - self.alertLabel?.alpha = alertLabelAlpha - }) - } - - public func update(level: ReservoirLevel?, at date: Date, reservoirLevelHighlightState: ReservoirLevelHighlightState) { - self.reservoirLevel = level - self.lastUpdateDate = date - self.reservoirLevelHighlightState = reservoirLevelHighlightState - updateViews() - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/OmniBLEReservoirView.xib b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/OmniBLEReservoirView.xib deleted file mode 100644 index 9b31aeaaf..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/OmniBLEReservoirView.xib +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/OmniBLESettingsView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/OmniBLESettingsView.swift deleted file mode 100644 index 976334b28..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/OmniBLESettingsView.swift +++ /dev/null @@ -1,617 +0,0 @@ -// -// OmniBLESettingsView.swift -// ViewDev -// -// Created by Pete Schwamb on 3/8/20. -// Copyright © 2020 Pete Schwamb. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import HealthKit - -struct OmniBLESettingsView: View { - - @ObservedObject var viewModel: OmniBLESettingsViewModel - - @State private var showingDeleteConfirmation = false - - @State private var showSuspendOptions = false - - @State private var showManualTempBasalOptions = false - - @State private var showSyncTimeOptions = false - - @State private var sendingTestBeepsCommand = false - - @State private var cancelingTempBasal = false - - var supportedInsulinTypes: [InsulinType] - - @Environment(\.guidanceColors) var guidanceColors - @Environment(\.insulinTintColor) var insulinTintColor - - private var daysRemaining: Int? { - if case .timeRemaining(let remaining, _) = viewModel.lifeState, remaining > .days(1) { - return Int(remaining.days) - } - return nil - } - - private var hoursRemaining: Int? { - if case .timeRemaining(let remaining, _) = viewModel.lifeState, remaining > .hours(1) { - return Int(remaining.hours.truncatingRemainder(dividingBy: 24)) - } - return nil - } - - private var minutesRemaining: Int? { - if case .timeRemaining(let remaining, _) = viewModel.lifeState, remaining < .hours(2) { - return Int(remaining.minutes.truncatingRemainder(dividingBy: 60)) - } - return nil - } - - func timeComponent(value: Int, units: String) -> some View { - Group { - Text(String(value)).font(.system(size: 28)).fontWeight(.heavy) - .foregroundColor(viewModel.podOk ? .primary : .secondary) - Text(units).foregroundColor(.secondary) - } - } - - var lifecycleProgress: some View { - VStack(spacing: 2) { - HStack(alignment: .lastTextBaseline, spacing: 3) { - Text(self.viewModel.lifeState.localizedLabelText) - .foregroundColor(self.viewModel.lifeState.labelColor(using: guidanceColors)) - Spacer() - daysRemaining.map { (days) in - timeComponent(value: days, units: days == 1 ? - LocalizedString("day", comment: "Unit for singular day in pod life remaining") : - LocalizedString("days", comment: "Unit for plural days in pod life remaining")) - } - hoursRemaining.map { (hours) in - timeComponent(value: hours, units: hours == 1 ? - LocalizedString("hour", comment: "Unit for singular hour in pod life remaining") : - LocalizedString("hours", comment: "Unit for plural hours in pod life remaining")) - } - minutesRemaining.map { (minutes) in - timeComponent(value: minutes, units: minutes == 1 ? - LocalizedString("minute", comment: "Unit for singular minute in pod life remaining") : - LocalizedString("minutes", comment: "Unit for plural minutes in pod life remaining")) - } - } - ProgressView(progress: CGFloat(self.viewModel.lifeState.progress)).accentColor(self.viewModel.lifeState.progressColor(guidanceColors: guidanceColors)) - } - } - - func cancelDelete() { - showingDeleteConfirmation = false - } - - - var deliverySectionTitle: String { - if self.viewModel.isScheduledBasal { - return LocalizedString("Scheduled Basal", comment: "Title of insulin delivery section") - } else { - return LocalizedString("Insulin Delivery", comment: "Title of insulin delivery section") - } - } - - var deliveryStatus: some View { - VStack(alignment: .leading, spacing: 5) { - Text(deliverySectionTitle) - .foregroundColor(Color(UIColor.secondaryLabel)) - if viewModel.podOk, viewModel.isSuspendedOrResuming { - HStack(alignment: .center) { - Image(systemName: "pause.circle.fill") - .font(.system(size: 34)) - .fixedSize() - .foregroundColor(viewModel.suspendResumeButtonColor(guidanceColors: guidanceColors)) - FrameworkLocalText("Insulin\nSuspended", comment: "Text shown in insulin delivery space when insulin suspended") - .fontWeight(.bold) - .fixedSize() - } - } else if let basalRate = self.viewModel.basalDeliveryRate { - HStack(alignment: .center) { - HStack(alignment: .lastTextBaseline, spacing: 3) { - Text(self.viewModel.basalRateFormatter.string(from: basalRate) ?? "") - .font(.system(size: 28)) - .fontWeight(.heavy) - .fixedSize() - FrameworkLocalText("U/hr", comment: "Units for showing temp basal rate").foregroundColor(.secondary) - } - } - } else { - HStack(alignment: .center) { - Image(systemName: "x.circle.fill") - .font(.system(size: 34)) - .fixedSize() - .foregroundColor(guidanceColors.critical) - FrameworkLocalText("No\nDelivery", comment: "Text shown in insulin remaining space when no pod is paired") - .fontWeight(.bold) - .fixedSize() - } - } - } - } - - func reservoir(filledPercent: CGFloat, fillColor: Color) -> some View { - ZStack(alignment: Alignment(horizontal: .center, vertical: .center)) { - GeometryReader { geometry in - let offset = geometry.size.height * 0.05 - let fillHeight = geometry.size.height * 0.81 - Rectangle() - .fill(fillColor) - .mask( - Image(frameworkImage: "pod_reservoir_mask_swiftui") - .resizable() - .scaledToFit() - ) - .mask( - Rectangle().path(in: CGRect(x: 0, y: offset + fillHeight - fillHeight * filledPercent, width: geometry.size.width, height: fillHeight * filledPercent)) - ) - } - Image(frameworkImage: "pod_reservoir_swiftui") - .renderingMode(.template) - .resizable() - .foregroundColor(fillColor) - .scaledToFit() - }.frame(width: 23, height: 32) - } - - - var reservoirStatus: some View { - VStack(alignment: .leading, spacing: 5) { - Text(LocalizedString("Insulin Remaining", comment: "Header for insulin remaining on pod settings screen")) - .foregroundColor(Color(UIColor.secondaryLabel)) - HStack { - if let podError = viewModel.podError { - Image(systemName: "exclamationmark.circle.fill") - .font(.system(size: 34)) - .fixedSize() - .foregroundColor(guidanceColors.critical) - - Text(podError).fontWeight(.bold) - } else if let reservoirLevel = viewModel.reservoirLevel, let reservoirLevelHighlightState = viewModel.reservoirLevelHighlightState { - reservoir(filledPercent: CGFloat(reservoirLevel.percentage), fillColor: reservoirColor(for: reservoirLevelHighlightState)) - Text(viewModel.reservoirText(for: reservoirLevel)) - .font(.system(size: 28)) - .fontWeight(.heavy) - .fixedSize() - } else { - Image(systemName: "exclamationmark.circle.fill") - .font(.system(size: 34)) - .fixedSize() - .foregroundColor(guidanceColors.warning) - - FrameworkLocalText("No Pod", comment: "Text shown in insulin remaining space when no pod is paired").fontWeight(.bold) - } - - } - } - } - - var manualTempBasalRow: some View { - Button(action: { - self.manualBasalTapped() - }) { - FrameworkLocalText("Set Temporary Basal Rate", comment: "Button title to set temporary basal rate") - } - .sheet(isPresented: $showManualTempBasalOptions) { - ManualTempBasalEntryView( - enactBasal: { rate, duration, completion in - viewModel.runTemporaryBasalProgram(unitsPerHour: rate, for: duration) { error in - completion(error) - if error == nil { - showManualTempBasalOptions = false - } - } - }, - didCancel: { - showManualTempBasalOptions = false - }, - allowedRates: viewModel.allowedTempBasalRates - ) - } - } - - - func suspendResumeRow() -> some View { - HStack { - Button(action: { - self.suspendResumeTapped() - }) { - HStack { - Image(systemName: "pause.circle.fill") - .font(.system(size: 22)) - .foregroundColor(viewModel.suspendResumeButtonColor(guidanceColors: guidanceColors)) - Text(viewModel.suspendResumeActionText) - .foregroundColor(viewModel.suspendResumeActionColor()) - } - } - .actionSheet(isPresented: $showSuspendOptions) { - suspendOptionsActionSheet - } - Spacer() - if viewModel.basalTransitioning { - ActivityIndicator(isAnimating: .constant(true), style: .medium) - } - } - } - - private var doneButton: some View { - Button(LocalizedString("Done", comment: "Title of done button on OmniBLESettingsView"), action: { - self.viewModel.doneTapped() - }) - } - - var headerImage: some View { - VStack(alignment: .center) { - Image(frameworkImage: "Pod") - .resizable() - .aspectRatio(contentMode: ContentMode.fit) - .frame(height: 100) - .padding(.horizontal) - }.frame(maxWidth: .infinity) - } - - var body: some View { - List { - Section() { - VStack(alignment: .trailing) { - Button(action: { - sendingTestBeepsCommand = true - viewModel.playTestBeeps { _ in - sendingTestBeepsCommand = false - } - }) { - Image(systemName: "speaker.wave.2.circle") - .imageScale(.large) - .foregroundColor(viewModel.podConnected ? .accentColor : .secondary) - .padding(.top,5) - } - .buttonStyle(PlainButtonStyle()) - .disabled(!viewModel.podConnected || sendingTestBeepsCommand) - - headerImage - - lifecycleProgress - - HStack(alignment: .top) { - deliveryStatus - Spacer() - reservoirStatus - } - if let faultAction = viewModel.recoveryText { - Divider() - Text(faultAction) - .font(Font.footnote.weight(.semibold)) - .fixedSize(horizontal: false, vertical: true) - .frame(maxWidth: .infinity, alignment: .leading) - } - } - if let notice = viewModel.notice { - VStack(alignment: .leading, spacing: 4) { - Text(notice.title) - .font(Font.subheadline.weight(.bold)) - Text(notice.description) - .font(Font.footnote.weight(.semibold)) - }.padding(.vertical, 8) - } - } - - Section(header: SectionHeader(label: LocalizedString("Activity", comment: "Section header for activity section"))) { - suspendResumeRow() - .disabled(!self.viewModel.podOk) - if self.viewModel.podOk, case .suspended(let suspendDate) = self.viewModel.basalDeliveryState { - HStack { - FrameworkLocalText("Suspended At", comment: "Label for suspended at time") - Spacer() - Text(self.viewModel.timeFormatter.string(from: suspendDate)) - .foregroundColor(Color.secondary) - } - } - } - - Section() { - if let manualTempRemaining = self.viewModel.manualBasalTimeRemaining, let remainingText = self.viewModel.timeRemainingFormatter.string(from: manualTempRemaining) { - HStack { - if cancelingTempBasal { - ProgressView() - .padding(.trailing) - } else { - Image(systemName: "exclamationmark.circle.fill") - .font(.system(size: 22)) - .foregroundColor(guidanceColors.warning) - } - Button(action: { - self.cancelManualBasal() - }) { - FrameworkLocalText("Cancel Manual Basal", comment: "Button title to cancel manual basal") - } - } - HStack { - FrameworkLocalText("Remaining", comment: "Label for remaining time of manual basal") - Spacer() - Text(remainingText) - .foregroundColor(.secondary) - } - } else { - manualTempBasalRow - } - } - .disabled(cancelingTempBasal || !self.viewModel.podOk) - - Section() { - HStack { - FrameworkLocalText("Pod Activated", comment: "Label for pod insertion row") - Spacer() - Text(self.viewModel.activatedAtString) - .foregroundColor(Color.secondary) - } - - HStack { - if let expiresAt = viewModel.expiresAt, expiresAt < Date() { - FrameworkLocalText("Pod Expired", comment: "Label for pod expiration row, past tense") - } else { - FrameworkLocalText("Pod Expires", comment: "Label for pod expiration row") - } - Spacer() - Text(self.viewModel.expiresAtString) - .foregroundColor(Color.secondary) - } - - if let podDetails = self.viewModel.podDetails { - NavigationLink(destination: PodDetailsView(podDetails: podDetails, title: LocalizedString("Pod Details", comment: "title for pod details page"))) { - FrameworkLocalText("Pod Details", comment: "Text for pod details disclosure row").foregroundColor(Color.primary) - } - } else { - HStack { - FrameworkLocalText("Pod Details", comment: "Text for pod details disclosure row") - Spacer() - Text("—") - .foregroundColor(Color.secondary) - } - } - - if let previousPodDetails = viewModel.previousPodDetails { - NavigationLink(destination: PodDetailsView(podDetails: previousPodDetails, title: LocalizedString("Previous Pod", comment: "title for previous pod page"))) { - FrameworkLocalText("Previous Pod Details", comment: "Text for previous pod details row").foregroundColor(Color.primary) - } - } else { - HStack { - FrameworkLocalText("Previous Pod Details", comment: "Text for previous pod details row") - Spacer() - Text("—") - .foregroundColor(Color.secondary) - } - } - } - - Section() { - Button(action: { - self.viewModel.navigateTo?(self.viewModel.lifeState.nextPodLifecycleAction) - }) { - Text(self.viewModel.lifeState.nextPodLifecycleActionDescription) - .foregroundColor(self.viewModel.lifeState.nextPodLifecycleActionColor) - } - } - - Section(header: SectionHeader(label: LocalizedString("Configuration", comment: "Section header for configuration section"))) - { - NavigationLink(destination: - NotificationSettingsView( - dateFormatter: self.viewModel.dateFormatter, - expirationReminderDefault: self.$viewModel.expirationReminderDefault, - scheduledReminderDate: self.viewModel.expirationReminderDate, - allowedScheduledReminderDates: self.viewModel.allowedScheduledReminderDates, - lowReservoirReminderValue: self.viewModel.lowReservoirAlertValue, - onSaveScheduledExpirationReminder: self.viewModel.saveScheduledExpirationReminder, - onSaveLowReservoirReminder: self.viewModel.saveLowReservoirReminder)) - { - FrameworkLocalText("Notification Settings", comment: "Text for pod details disclosure row").foregroundColor(Color.primary) - } - NavigationLink(destination: BeepPreferenceSelectionView(initialValue: viewModel.beepPreference, onSave: viewModel.setConfirmationBeeps)) { - HStack { - FrameworkLocalText("Confidence Reminders", comment: "Text for confidence reminders navigation link").foregroundColor(Color.primary) - Spacer() - Text(viewModel.beepPreference.title) - .foregroundColor(.secondary) - } - } - NavigationLink(destination: SilencePodSelectionView(initialValue: viewModel.silencePodPreference, onSave: viewModel.setSilencePod)) { - HStack { - FrameworkLocalText("Silence Pod", comment: "Text for silence pod navigation link").foregroundColor(Color.primary) - Spacer() - Text(viewModel.silencePodPreference.title) - .foregroundColor(.secondary) - } - } - NavigationLink(destination: InsulinTypeSetting(initialValue: viewModel.insulinType, supportedInsulinTypes: supportedInsulinTypes, allowUnsetInsulinType: false, didChange: viewModel.didChangeInsulinType)) { - HStack { - FrameworkLocalText("Insulin Type", comment: "Text for insulin type navigation link").foregroundColor(Color.primary) - if let currentTitle = viewModel.insulinType?.brandName { - Spacer() - Text(currentTitle) - .foregroundColor(.secondary) - } - } - } - } - - Section() { - HStack { - FrameworkLocalText("Pump Time", comment: "The title of the command to change pump time zone") - Spacer() - if viewModel.isClockOffset { - Image(systemName: "clock.fill") - .foregroundColor(guidanceColors.warning) - } - TimeView(timeZone: viewModel.timeZone) - .foregroundColor( viewModel.isClockOffset ? guidanceColors.warning : nil) - } - if viewModel.synchronizingTime { - HStack { - FrameworkLocalText("Adjusting Pump Time...", comment: "Text indicating ongoing pump time synchronization") - .foregroundColor(.secondary) - Spacer() - ActivityIndicator(isAnimating: .constant(true), style: .medium) - } - } else if self.viewModel.timeZone != TimeZone.currentFixed { - Button(action: { - showSyncTimeOptions = true - }) { - FrameworkLocalText("Sync to Current Time", comment: "The title of the command to change pump time zone") - } - .actionSheet(isPresented: $showSyncTimeOptions) { - syncPumpTimeActionSheet - } - } - } - - Section(header: SectionHeader(label: LocalizedString("Diagnostics", comment: "Section header for diagnostic section"))) { - NavigationLink(destination: ReadPodStatusView(toRun: viewModel.readPodStatus)) { - FrameworkLocalText("Read Pod Status", comment: "Text for read pod status navigation link").foregroundColor(Color.primary) - } - .disabled(self.viewModel.noPod) - NavigationLink(destination: ReadPulseLogView(toRun: viewModel.readPulseLog)) { - FrameworkLocalText("Read Pulse Log", comment: "Text for read pulse log navigation link").foregroundColor(Color.primary) - } - .disabled(self.viewModel.noPod) - NavigationLink(destination: PlayTestBeepsView(toRun: viewModel.playTestBeeps)) { - FrameworkLocalText("Play Test Beeps", comment: "Text for play test beeps navigation link").foregroundColor(Color.primary) - } - .disabled(!self.viewModel.podOk) - NavigationLink(destination: PumpManagerDetailsView(toRun: viewModel.pumpManagerDetails)) { - FrameworkLocalText("Pump Manager Details", comment: "Text for pump manager details navigation link").foregroundColor(Color.primary) - } - } - - if self.viewModel.lifeState.allowsPumpManagerRemoval { - Section() { - Button(action: { - self.showingDeleteConfirmation = true - }) { - FrameworkLocalText("Switch to other insulin delivery device", comment: "Label for PumpManager deletion button") - .foregroundColor(guidanceColors.critical) - } - .actionSheet(isPresented: $showingDeleteConfirmation) { - removePumpManagerActionSheet - } - } - } - } - .alert(isPresented: $viewModel.alertIsPresented, content: { alert(for: viewModel.activeAlert!) }) - .insetGroupedListStyle() - .navigationBarItems(trailing: doneButton) - .navigationBarTitle(self.viewModel.viewTitle) - } - - var syncPumpTimeActionSheet: ActionSheet { - ActionSheet(title: FrameworkLocalText("Time Change Detected", comment: "Title for pod sync time action sheet."), message: FrameworkLocalText("The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?", comment: "Message for pod sync time action sheet"), buttons: [ - .default(FrameworkLocalText("Yes, Sync to Current Time", comment: "Button text to confirm pump time sync")) { - self.viewModel.changeTimeZoneTapped() - }, - .cancel(FrameworkLocalText("No, Keep Pump As Is", comment: "Button text to cancel pump time sync")) - ]) - } - - var removePumpManagerActionSheet: ActionSheet { - ActionSheet(title: FrameworkLocalText("Remove Pump", comment: "Title for Omnipod DASH PumpManager deletion action sheet."), message: FrameworkLocalText("Are you sure you want to stop using Omnipod DASH?", comment: "Message for Omnipod DASH PumpManager deletion action sheet"), buttons: [ - .destructive(FrameworkLocalText("Delete Omnipod DASH", comment: "Button text to confirm Omnipod DASH PumpManager deletion")) { - self.viewModel.stopUsingOmnipodDashTapped() - }, - .cancel() - ]) - } - - var suspendOptionsActionSheet: ActionSheet { - ActionSheet( - title: FrameworkLocalText("Suspend Delivery", comment: "Title for suspend duration selection action sheet"), - message: FrameworkLocalText("Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?", comment: "Message for suspend duration selection action sheet"), - buttons: [ - .default(FrameworkLocalText("30 minutes", comment: "Button text for 30 minute suspend duration"), action: { self.viewModel.suspendDelivery(duration: .minutes(30)) }), - .default(FrameworkLocalText("1 hour", comment: "Button text for 1 hour suspend duration"), action: { self.viewModel.suspendDelivery(duration: .hours(1)) }), - .default(FrameworkLocalText("1 hour 30 minutes", comment: "Button text for 1 hour 30 minute suspend duration"), action: { self.viewModel.suspendDelivery(duration: .hours(1.5)) }), - .default(FrameworkLocalText("2 hours", comment: "Button text for 2 hour suspend duration"), action: { self.viewModel.suspendDelivery(duration: .hours(2)) }), - .cancel() - ]) - } - - func suspendResumeTapped() { - switch self.viewModel.basalDeliveryState { - case .active, .tempBasal: - showSuspendOptions = true - case .suspended: - self.viewModel.resumeDelivery() - default: - break - } - } - - func manualBasalTapped() { - showManualTempBasalOptions = true - } - - func cancelManualBasal() { - cancelingTempBasal = true - viewModel.runTemporaryBasalProgram(unitsPerHour: 0, for: 0) { error in - cancelingTempBasal = false - if let error = error { - self.viewModel.activeAlert = .cancelManualBasalError(error) - } - } - } - - - private func errorText(_ error: Error) -> String { - if let error = error as? LocalizedError { - return [error.localizedDescription, error.recoverySuggestion].compactMap{$0}.joined(separator: ". ") - } else { - return error.localizedDescription - } - } - - private func alert(for alert: DashSettingsViewAlert) -> SwiftUI.Alert { - switch alert { - case .suspendError(let error): - return SwiftUI.Alert( - title: Text("Failed to Suspend Insulin Delivery", comment: "Alert title for suspend error"), - message: Text(errorText(error)) - ) - - case .resumeError(let error): - return SwiftUI.Alert( - title: Text("Failed to Resume Insulin Delivery", comment: "Alert title for resume error"), - message: Text(errorText(error)) - ) - - case .syncTimeError(let error): - return SwiftUI.Alert( - title: Text("Failed to Set Pump Time", comment: "Alert title for time sync error"), - message: Text(errorText(error)) - ) - - case .cancelManualBasalError(let error): - return SwiftUI.Alert( - title: Text("Failed to Cancel Manual Basal", comment: "Alert title for failing to cancel manual basal error"), - message: Text(errorText(error)) - ) - - } - } - - func reservoirColor(for reservoirLevelHighlightState: ReservoirLevelHighlightState) -> Color { - switch reservoirLevelHighlightState { - case .normal: - return insulinTintColor - case .warning: - return guidanceColors.warning - case .critical: - return guidanceColors.critical - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PairPodView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PairPodView.swift deleted file mode 100644 index 1c704cbb0..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PairPodView.swift +++ /dev/null @@ -1,109 +0,0 @@ -// -// PairPodView.swift -// OmniBLE -// -// Created by Pete Schwamb on 2/5/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct PairPodView: View { - - @ObservedObject var viewModel: PairPodViewModel - - @State private var cancelModalIsPresented: Bool = false - - var body: some View { - GuidePage(content: { - VStack { - LeadingImage("PodBottom") - - HStack { - InstructionList(instructions: [ - LocalizedString("Fill a new pod with U-100 Insulin (leave blue Pod needle cap on).", comment: "Label text for step 1 of pair pod instructions"), - LocalizedString("Listen for 2 beeps.", comment: "Label text for step 2 of pair pod instructions") - ]) - .disabled(viewModel.state.instructionsDisabled) - } - .padding(.bottom, 8) - } - .accessibility(sortPriority: 1) - }) { - VStack { - if self.viewModel.state.showProgressDetail { - self.viewModel.error.map { - ErrorView($0, errorClass: $0.recoverable ? .normal : .critical) - .accessibility(sortPriority: 0) - } - - if self.viewModel.error == nil { - VStack { - ProgressIndicatorView(state: self.viewModel.state.progressState) - if self.viewModel.state.isFinished { - FrameworkLocalText("Paired", comment: "Label text indicating pairing finished.") - .bold() - .padding(.top) - } - } - .padding(.bottom, 8) - } - } - if self.viewModel.error != nil && self.viewModel.podIsActivated { - Button(action: { - self.viewModel.didRequestDeactivation?() - }) { - Text(LocalizedString("Deactivate Pod", comment: "Button text for deactivate pod button")) - .accessibility(identifier: "button_deactivate_pod") - .actionButtonStyle(.destructive) - } - .disabled(self.viewModel.state.isProcessing) - } - - if (self.viewModel.error == nil || self.viewModel.error?.recoverable == true) { - Button(action: { - self.viewModel.continueButtonTapped() - }) { - Text(self.viewModel.state.nextActionButtonDescription) - .accessibility(identifier: "button_next_action") - .accessibility(label: Text(self.viewModel.state.actionButtonAccessibilityLabel)) - .actionButtonStyle(.primary) - } - .disabled(self.viewModel.state.isProcessing) - .animation(nil) - .zIndex(1) - } - } - .transition(AnyTransition.opacity.combined(with: .move(edge: .bottom))) - .padding() - } - .animation(.default) - .alert(isPresented: $cancelModalIsPresented) { cancelPairingModal } - .navigationBarTitle(LocalizedString("Pair Pod", comment: "Pair Pod navigationBarTitle"), displayMode: .automatic) - .navigationBarBackButtonHidden(self.viewModel.backButtonHidden) - .navigationBarItems(trailing: self.viewModel.state.navBarVisible ? cancelButton : nil) - } - - var cancelButton: some View { - Button(LocalizedString("Cancel", comment: "Cancel button text in navigation bar on pair pod UI")) { - if viewModel.podIsActivated { - cancelModalIsPresented = true - } else { - viewModel.didCancelSetup?() - } - } - .accessibility(identifier: "button_cancel") - .disabled(self.viewModel.state.isProcessing) - } - - var cancelPairingModal: Alert { - return Alert( - title: FrameworkLocalText("Are you sure you want to cancel Pod setup?", comment: "Alert title for cancel pairing modal"), - message: FrameworkLocalText("If you cancel Pod setup, the current Pod will be deactivated and will be unusable.", comment: "Alert message body for confirm pod attachment"), - primaryButton: .destructive(FrameworkLocalText("Yes, Deactivate Pod", comment: "Button title for confirm deactivation option"), action: { viewModel.didRequestDeactivation?() }), - secondaryButton: .default(FrameworkLocalText("No, Continue With Pod", comment: "Continue pairing button title of in pairing cancel modal")) - ) - } - -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PlayTestBeepsView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PlayTestBeepsView.swift deleted file mode 100644 index e004ee259..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PlayTestBeepsView.swift +++ /dev/null @@ -1,101 +0,0 @@ -// -// PlayTestBeepsView.swift -// OmniBLE -// -// Created by Joe Moran on 9/1/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - - -struct PlayTestBeepsView: View { - @Environment(\.horizontalSizeClass) var horizontalSizeClass - @Environment(\.presentationMode) var presentationMode: Binding - - private var toRun: ((_ completion: @escaping (_ result: Error?) -> Void) -> Void)? - - @State private var alertIsPresented: Bool = false - @State private var displayString: String = "" - @State private var successMessage = LocalizedString("Play test beeps command sent successfully.\n\nIf you did not hear any beeps from your Pod, the piezo speaker in your Pod may be broken or disabled.", comment: "Success message for play test beeps") - @State private var error: Error? = nil - @State private var executing: Bool = false - @State private var showActivityView = false - - init(toRun: @escaping (_ completion: @escaping (_ result: Error?) -> Void) -> Void) { - self.toRun = toRun - } - - var body: some View { - VStack { - List { - Section { - Text(self.displayString).fixedSize(horizontal: false, vertical: true) - } - } - VStack { - Button(action: { - asyncAction() - }) { - Text(buttonText) - .actionButtonStyle(.primary) - } - .padding() - .disabled(executing) - } - .padding(self.horizontalSizeClass == .regular ? .bottom : []) - .background(Color(UIColor.secondarySystemGroupedBackground).shadow(radius: 5)) - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Play Test Beeps", comment: "navigation title for play test beeps")) - .navigationBarTitleDisplayMode(.inline) - .alert(isPresented: $alertIsPresented, content: { alert(error: error) }) - .onFirstAppear { - asyncAction() - } - } - - private func asyncAction () { - DispatchQueue.global(qos: .utility).async { - executing = true - self.displayString = "" - toRun?() { (error) in - if let error = error { - self.displayString = "" - self.error = error - self.alertIsPresented = true - } else { - self.displayString = successMessage - } - executing = false - } - } - } - - private var buttonText: String { - if executing { - return LocalizedString("Playing Test Beeps...", comment: "button title when executing play test beeps") - } else { - return LocalizedString("Play Test Beeps", comment: "button title to play test beeps") - } - } - - private func alert(error: Error?) -> SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Failed to play test beeps.", comment: "Alert title for error when playing test beeps")), - message: Text(error?.localizedDescription ?? "No Error") - ) - } - -} - -struct PlayTestBeepsView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - PlayTestBeepsView() { completion in - completion(nil) - } - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PodDetailsView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PodDetailsView.swift deleted file mode 100644 index dba04387c..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PodDetailsView.swift +++ /dev/null @@ -1,129 +0,0 @@ -// -// PodDetailsView.swift -// OmniBLE -// -// Created by Pete Schwamb on 4/14/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -public struct PodDetails { - var lotNumber: UInt32 - var sequenceNumber: UInt32 - var firmwareVersion: String - var bleFirmwareVersion: String - var deviceName: String? - var totalDelivery: Double? - var lastStatus: Date? - var fault: FaultEventCode? - var activatedAt: Date? - var activeTime: TimeInterval? - var pdmRef: String? -} - -struct PodDetailsView: View { - @Environment(\.guidanceColors) var guidanceColors - - var podDetails: PodDetails - var title: String - - let statusAgeFormatter: DateComponentsFormatter = { - let formatter = DateComponentsFormatter() - - formatter.allowedUnits = [.day, .hour, .minute, .second] - formatter.maximumUnitCount = 1 - formatter.unitsStyle = .short - - return formatter - }() - - let activeTimeFormatter: DateComponentsFormatter = { - let formatter = DateComponentsFormatter() - - formatter.allowedUnits = [.day, .hour, .minute] - formatter.maximumUnitCount = 2 - formatter.unitsStyle = .full - - return formatter - }() - - let dateFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - dateFormatter.timeStyle = .short - dateFormatter.dateStyle = .medium - dateFormatter.doesRelativeDateFormatting = true - return dateFormatter - }() - - private func row(_ label: String, value: String) -> some View { - HStack { - Text(label) - Spacer() - Text(value) - .foregroundColor(.secondary) - } - } - - var totalDeliveryText: String { - if let delivery = podDetails.totalDelivery { - return String(format: LocalizedString("%g U", comment: "Format string for total delivery on pod details screen"), delivery) - } else { - return LocalizedString("NA", comment: "String shown on pod details for total delivery when not available.") - } - } - - func activeTimeText(_ duration: TimeInterval) -> String { - return activeTimeFormatter.string(from: duration) ?? LocalizedString("NA", comment: "String shown on pod details for active time when conversion fails.") - } - - var lastStatusText: String { - if let lastStatus = podDetails.lastStatus, let ageString = statusAgeFormatter.string(from: Date().timeIntervalSince(lastStatus)) { - return String(format: LocalizedString("%@ ago", comment: "Format string for last status date on pod details screen"), ageString) - } else { - return LocalizedString("NA", comment: "String shown on pod details for last status date when not available.") - } - } - - var body: some View { - List { - if let deviceName = podDetails.deviceName { - row(LocalizedString("Device Name", comment: "description label for device name pod details row"), value: deviceName) - } - row(LocalizedString("Lot Number", comment: "description label for lot number pod details row"), value: String(describing: podDetails.lotNumber)) - row(LocalizedString("Sequence Number", comment: "description label for sequence number pod details row"), value: String(format: "%07d", podDetails.sequenceNumber)) - row(LocalizedString("Firmware Version", comment: "description label for firmware version pod details row"), value: podDetails.firmwareVersion) - row(LocalizedString("BLE Firmware Version", comment: "description label for ble firmware version pod details row"), value: podDetails.bleFirmwareVersion) - row(LocalizedString("Total Delivery", comment: "description label for total delivery pod details row"), value: totalDeliveryText) - if let activeTime = podDetails.activeTime, let activatedAt = podDetails.activatedAt { - row(LocalizedString("Pod Activated", comment: "description label for activated at time pod details row"), value: dateFormatter.string(from: activatedAt)) - row(LocalizedString("Active Time", comment: "description label for active time pod details row"), value: activeTimeText(activeTime)) - } else { - row(LocalizedString("Last Status", comment: "description label for last status date pod details row"), value: lastStatusText) - } - if let fault = podDetails.fault, let pdmRef = podDetails.pdmRef { - Section { - VStack(alignment: .leading) { - HStack { - Image(systemName: "exclamationmark.triangle.fill") - .foregroundColor(guidanceColors.critical) - Text(LocalizedString("Pod Fault Details", comment: "description label for pod fault details")) - .fontWeight(.semibold) - }.padding(.vertical, 4) - Text(String(format: LocalizedString("Internal Pod fault code %1$03d\n%2$@\nRef: %3$@\n", comment: "The format string for the pod fault info: (1: fault code) (2: fault description) (3: pdm ref string)"), fault.rawValue, fault.faultDescription, pdmRef)) - .fixedSize(horizontal: false, vertical: true) - .foregroundColor(.secondary) - } - } - } - } - .navigationBarTitle(Text(title), displayMode: .automatic) - } -} - -struct PodDetailsView_Previews: PreviewProvider { - static var previews: some View { - PodDetailsView(podDetails: PodDetails(lotNumber: 123456789, sequenceNumber: 1234567, firmwareVersion: "4.3.2", bleFirmwareVersion: "1.2.3", deviceName: "DashPreviewPod", totalDelivery: 99, lastStatus: Date(), fault: FaultEventCode(rawValue: 064), activatedAt: Date().addingTimeInterval(.days(2)), pdmRef: "19-02448-09951-064"), title: "Device Details") - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PodLifeHUDView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PodLifeHUDView.swift deleted file mode 100644 index a04cbcca6..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PodLifeHUDView.swift +++ /dev/null @@ -1,176 +0,0 @@ -// -// PodLifeHUDView.swift -// OmniBLE -// -// Based on OmniKitUI/Views/PodLifeHUDView.swift -// Created by Pete Schwamb on 10/22/18. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKitUI -import MKRingProgressView - -public enum PodAlertState { - case none - case warning - case fault -} - -public class PodLifeHUDView: BaseHUDView, NibLoadable { - - override public var orderPriority: HUDViewOrderPriority { - return 12 - } - - @IBOutlet private weak var timeLabel: UILabel! { - didSet { - // Setting this color in code because the nib isn't being applied correctly - if #available(iOSApplicationExtension 13.0, *) { - timeLabel.textColor = .label - } - } - } - @IBOutlet private weak var progressRing: RingProgressView! - - @IBOutlet private weak var alertLabel: UILabel! { - didSet { - alertLabel.alpha = 0 - alertLabel.textColor = UIColor.white - alertLabel.layer.cornerRadius = 9 - alertLabel.clipsToBounds = true - } - } - @IBOutlet private weak var backgroundRing: UIImageView! { - didSet { - if #available(iOSApplicationExtension 13.0, iOS 13.0, *) { - backgroundRing.tintColor = .systemGray5 - } else { - backgroundRing.tintColor = UIColor(red: 198 / 255, green: 199 / 255, blue: 201 / 255, alpha: 1) - } - } - } - - private var startTime: Date? - private var lifetime: TimeInterval? - private var timer: Timer? - - public var alertState: PodAlertState = .none { - didSet { - updateAlertStateLabel() - } - } - - public class func instantiate() -> PodLifeHUDView { - return nib().instantiate(withOwner: nil, options: nil)[0] as! PodLifeHUDView - } - - public func setPodLifeCycle(startTime: Date, lifetime: TimeInterval) { - self.startTime = startTime - self.lifetime = lifetime - updateProgressCircle() - - if timer == nil { - self.timer = Timer.scheduledTimer(withTimeInterval: .seconds(10), repeats: true) { [weak self] _ in - self?.updateProgressCircle() - } - } - } - - override open func stateColorsDidUpdate() { - super.stateColorsDidUpdate() - updateProgressCircle() - updateAlertStateLabel() - } - - private var endColor: UIColor? { - didSet { - let primaryColor = endColor ?? UIColor(red: 198 / 255, green: 199 / 255, blue: 201 / 255, alpha: 1) - self.progressRing.endColor = primaryColor - self.progressRing.startColor = primaryColor - } - } - - private lazy var timeFormatter: DateComponentsFormatter = { - let formatter = DateComponentsFormatter() - - formatter.allowedUnits = [.hour, .minute] - formatter.maximumUnitCount = 1 - formatter.unitsStyle = .abbreviated - - return formatter - }() - - private func updateAlertStateLabel() { - var alertLabelAlpha: CGFloat = 1 - - if alertState == .fault { - timer = nil - } - - switch alertState { - case .fault: - alertLabel.text = "!" - alertLabel.backgroundColor = stateColors?.error - case .warning: - alertLabel.text = "!" - alertLabel.backgroundColor = stateColors?.warning - case .none: - alertLabelAlpha = 0 - } - alertLabel.alpha = alertLabelAlpha - UIView.animate(withDuration: 0.25, animations: { - self.alertLabel.alpha = alertLabelAlpha - }) - } - - private func updateProgressCircle() { - - if let startTime = startTime, let lifetime = lifetime { - let age = -startTime.timeIntervalSinceNow - let progress = Double(age / lifetime) - progressRing.progress = progress - - if progress < 0.75 { - self.endColor = stateColors?.normal - progressRing.shadowOpacity = 0 - } else if progress < 1.0 { - self.endColor = stateColors?.warning - progressRing.shadowOpacity = 0.5 - } else { - self.endColor = stateColors?.error - progressRing.shadowOpacity = 0.8 - } - - let remaining = (lifetime - age) - - // Update time label and caption - if alertState == .fault { - timeLabel.isHidden = true - caption.text = LocalizedString("Fault", comment: "Pod life HUD view label") - } else if remaining > .hours(24) { - timeLabel.isHidden = true - caption.text = LocalizedString("Pod Age", comment: "Label describing pod age view") - } else if remaining > 0 { - let remainingFlooredToHour = remaining > .hours(1) ? remaining - remaining.truncatingRemainder(dividingBy: .hours(1)) : remaining - if let timeString = timeFormatter.string(from: remainingFlooredToHour) { - timeLabel.isHidden = false - timeLabel.text = timeString - } - caption.text = LocalizedString("Remaining", comment: "Label describing time remaining view") - } else { - timeLabel.isHidden = true - caption.text = LocalizedString("Replace Pod", comment: "Label indicating pod replacement necessary") - } - } - } - - func pauseUpdates() { - timer?.invalidate() - timer = nil - } - - override public func awakeFromNib() { - super.awakeFromNib() - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PodLifeHUDView.xib b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PodLifeHUDView.xib deleted file mode 100644 index d6bdde9fc..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PodLifeHUDView.xib +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PodSetupView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PodSetupView.swift deleted file mode 100644 index 91021e2da..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PodSetupView.swift +++ /dev/null @@ -1,114 +0,0 @@ -// -// PodSetupView.swift -// OmniBLE -// -// Created by Pete Schwamb on 5/17/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct PodSetupView: View { - @Environment(\.dismissAction) private var dismiss - - private struct AlertIdentifier: Identifiable { - enum Choice { - case skipOnboarding - } - var id: Choice - } - @State private var alertIdentifier: AlertIdentifier? - - let nextAction: () -> Void - let allowDebugFeatures: Bool - let skipOnboarding: () -> Void - - var body: some View { - VStack(alignment: .leading) { - close - ScrollView { - content - } - Spacer() - continueButton - .padding(.bottom) - } - .padding(.horizontal) - .navigationBarHidden(true) - .alert(item: $alertIdentifier) { alert in - switch alert.id { - case .skipOnboarding: - return skipOnboardingAlert - } - } - } - - @ViewBuilder - private var close: some View { - HStack { - Spacer() - cancelButton - } - .padding(.top) - } - - @ViewBuilder - private var content: some View { - VStack(alignment: .leading, spacing: 2) { - title - .padding(.top, 5) - .onLongPressGesture(minimumDuration: 2) { - didLongPressOnTitle() - } - Divider() - bodyText - .foregroundColor(.secondary) - .padding(.top) - } - } - - @ViewBuilder - private var title: some View { - Text(LocalizedString("Pod Setup", comment: "Title for PodSetupView")) - .font(.largeTitle) - .bold() - .padding(.vertical) - } - - @ViewBuilder - private var bodyText: some View { - Text(LocalizedString("You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body.", comment: "bodyText for PodSetupView")) - } - - private var cancelButton: some View { - Button(LocalizedString("Cancel", comment: "Cancel button title"), action: { - self.dismiss() - }) - } - - private var continueButton: some View { - Button(LocalizedString("Continue", comment: "Text for continue button on PodSetupView"), action: nextAction) - .buttonStyle(ActionButtonStyle()) - } - - private var skipOnboardingAlert: Alert { - Alert(title: Text("Skip Omnipod Onboarding?"), - message: Text("Are you sure you want to skip Omnipod Onboarding?"), - primaryButton: .cancel(), - secondaryButton: .destructive(Text("Yes"), action: skipOnboarding)) - } - - private func didLongPressOnTitle() { - if allowDebugFeatures { - alertIdentifier = AlertIdentifier(id: .skipOnboarding) - } - } - -} - -struct PodSetupView_Previews: PreviewProvider { - static var previews: some View { - PodSetupView(nextAction: {}, allowDebugFeatures: true, skipOnboarding: {}) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PumpManagerDetailsView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PumpManagerDetailsView.swift deleted file mode 100644 index 14b8281ab..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/PumpManagerDetailsView.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// PumpManagerDetailsView.swift -// OmniBLE -// -// Created by Joe Moran on 9/26/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - - -struct PumpManagerDetailsView: View { - @Environment(\.horizontalSizeClass) var horizontalSizeClass - @Environment(\.presentationMode) var presentationMode: Binding - - private var toRun: ((_ completion: @escaping (_ result: String) -> Void) -> Void)? - - @State private var displayString: String = "" - @State private var error: Error? = nil - @State private var executing: Bool = false - @State private var showActivityView: Bool = false - - init(toRun: @escaping (_ completion: @escaping (_ result: String) -> Void) -> Void) { - self.toRun = toRun - } - - var body: some View { - VStack { - List { - Section { - let myFont = Font - .system(size: 12) - .monospaced() - Text(self.displayString) - .font(myFont) - } - } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(action: { - self.showActivityView = true - }) { - Image(systemName: "square.and.arrow.up") - } - } - }.sheet(isPresented: $showActivityView) { - ActivityView(isPresented: $showActivityView, activityItems: [self.displayString]) - } - VStack { - Button(action: { - asyncAction() - }) { - Text(buttonText) - .actionButtonStyle(.primary) - } - .padding() - .disabled(executing) - } - .padding(self.horizontalSizeClass == .regular ? .bottom : []) - .background(Color(UIColor.secondarySystemGroupedBackground).shadow(radius: 5)) - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Pump Manager Details", comment: "navigation title for pump manager details")) - .navigationBarTitleDisplayMode(.inline) - .onFirstAppear { - asyncAction() - } - } - - private func asyncAction () { - DispatchQueue.global(qos: .utility).async { - executing = true - self.displayString = "" - toRun?() { (result) in - self.displayString = result - executing = false - } - } - } - - private var buttonText: String { - if executing { - return LocalizedString("Retrieving Pump Manager Details...", comment: "button title when retrieving pump manager details") - } else { - return LocalizedString("Refresh Pump Manager Details", comment: "button title to refresh pump manager details") - } - } -} - -struct PumpManagerDetailsView_Previews: PreviewProvider { - static var previews: some View { - let examplePumpManagerDetails: String = "## OmniBLEPumpManager\nprovideHeartbeat: false\nconnected: true\n\npodComms: ## PodComms\n* myId: 171637F8\n* podId: 171637FB\ndelegate: true\n\nstatusObservers.count: 2\nstatus: ## PumpManagerStatus\n* timeZone: GMT-0700 (fixed)\n* device: <, name:Omnipod-Dash, manufacturer:Insulet, model:Dash, hardware:4, firmware:4.10.0 1.4.0, software:1.0, localIdentifier:171637FB>\n* pumpBatteryChargeRemaining: nil\n* basalDeliveryState: Optional(LoopKit.PumpManagerStatus.BasalDeliveryState.tempBasal(LoopKit.DoseEntry(type: LoopKit.DoseType.tempBasal, startDate: 2023-10-08 00:21:42 +0000, endDate: 2023-10-08 00:51:42 +0000, value: 1.55, unit: LoopKit.DoseUnit.unitsPerHour, deliveredUnits: nil, description: nil, insulinType: Optional(LoopKit.InsulinType.humalog), automatic: Optional(true), manuallyEntered: false, syncIdentifier: nil, isMutable: true, wasProgrammedByPumpUI: false, scheduledBasalRate: nil)))\n* bolusState: noBolus\n* insulinType: Optional(LoopKit.InsulinType.humalog)\n* deliveryIsUncertain: false\n\npodStateObservers.count: 1\nstate: ## OmniBLEPumpManagerState\n* isOnboarded: true\n* timeZone: GMT-0700 (fixed)\n* basalSchedule: BasalSchedule(entries: [OmniBLE.BasalScheduleEntry(rate: 1.0, startTime: 0.0)])\n* maximumTempBasalRate: 5.0\n* unstoredDoses: []\n* suspendEngageState: stable\n* bolusEngageState: stable\n* tempBasalEngageState: stable\n* lastPumpDataReportDate: Optional(2023-09-28 14:03:50 +0000)\n* isPumpDataStale: false\n* silencePod: true\n* confirmationBeeps: extended\n* controllerId: 171637F8\n* podId: 171637FB\n* insulinType: Optional(LoopKit.InsulinType.humalog)\n* scheduledExpirationReminderOffset: Optional(22h0m)\n* defaultExpirationReminderOffset: 24h0m\n* lowReservoirReminderValue: 50.0\n* podAttachmentConfirmed: true\n* activeAlerts: []\n* alertsWithPendingAcknowledgment: []\n* acknowledgedTimeOffsetAlert: false\n* initialConfigurationCompleted: true\n* podState: ### PodState\n* address: 171637FB\n* bleIdentifier: 20672963-16E5-D8F8-9C06-1233FEAA61EB\n* activatedAt: Optional(2023-09-25 06:04:36 +0000)\n* expiresAt: Optional(2023-09-28 06:02:46 +0000)\n* timeActive: 79h59m\n* timeActiveUpdated: Optional(2023-09-28 14:03:50 +0000)\n* setupUnitsDelivered: Optional(2.8)\n* firmwareVersion: 4.10.0\n* bleFirmwareVersion: 1.4.0\n* lotNo: 139865265\n* lotSeq: 2770428\n* suspendState: suspended(2023-09-28 14:02:47 +0000)\n* unacknowledgedCommand: nil\n* unfinalizedBolus: nil\n* unfinalizedTempBasal: nil\n* unfinalizedSuspend: Optional(Suspend: 9/28/23, 7:02:47 AM Certain)\n* unfinalizedResume: Optional(Resume: 9/24/23, 11:06:33 PM Certain)\n* finalizedDoses: []\n* activeAlertsSlots: No alerts\n* messageTransportState: ##\nMessageTransportState\neapSeq: 1059\nmsgSeq: 7\nnonceSeq: 6\nmessageNumber: 14\n* setupProgress: completed\n* primeFinishTime: Optional(2023-10-05 05:46:46 +0000)\n* configuredAlerts: [OmniBLE.AlertSlot.slot7Expired: Pod expired, OmniBLE.AlertSlot.slot2ShutdownImminent: Shutdown imminent, OmniBLE.AlertSlot.slot3ExpirationReminder: Expiration reminder, OmniBLE.AlertSlot.slot4LowReservoir: Low reservoir]\n* insulinType: humalog\n* PdmRef: nil\n* Fault: nil\n\nPreviousPodState: nil" - NavigationView { - PumpManagerDetailsView() { completion in - completion(examplePumpManagerDetails) - } - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ReadPodStatusView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ReadPodStatusView.swift deleted file mode 100644 index 255b638f2..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ReadPodStatusView.swift +++ /dev/null @@ -1,167 +0,0 @@ -// -// ReadPodStatusView.swift -// OmniBLE -// -// Created by Joe Moran on 8/15/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - -private func podStatusString(status: DetailedStatus) -> String { - var result, str: String - - let formatter = DateComponentsFormatter() - formatter.unitsStyle = .full - formatter.allowedUnits = [.hour, .minute] - formatter.unitsStyle = .short - if let timeStr = formatter.string(from: status.timeActive) { - str = timeStr - } else { - str = String(format: LocalizedString("%1$@ minutes", comment: "The format string for minutes (1: number of minutes string)"), String(describing: Int(status.timeActive / 60))) - } - result = String(format: LocalizedString("Pod Active: %1$@", comment: "The format string for Pod Active: (1: formatted time)"), str) - - result += String(format: LocalizedString("\nPod Progress: %1$@", comment: "The format string for Pod Progress: (1: pod progress string)"), String(describing: status.podProgressStatus)) - - result += String(format: LocalizedString("\nDelivery Status: %1$@", comment: "The format string for Delivery Status: (1: delivery status string)"), String(describing: status.deliveryStatus)) - - result += String(format: LocalizedString("\nLast Programming Seq Num: %1$@", comment: "The format string for last programming sequence number: (1: last programming sequence number)"), String(describing: status.lastProgrammingMessageSeqNum)) - - result += String(format: LocalizedString("\nBolus Not Delivered: %1$@ U", comment: "The format string for Bolus Not Delivered: (1: bolus not delivered string)"), status.bolusNotDelivered.twoDecimals) - - result += String(format: LocalizedString("\nPulse Count: %1$d", comment: "The format string for Pulse Count (1: pulse count)"), Int(round(status.totalInsulinDelivered / Pod.pulseSize))) - - result += String(format: LocalizedString("\nReservoir Level: %1$@ U", comment: "The format string for Reservoir Level: (1: reservoir level string)"), status.reservoirLevel == Pod.reservoirLevelAboveThresholdMagicNumber ? "50+" : status.reservoirLevel.twoDecimals) - - result += String(format: LocalizedString("\nAlerts: %1$@", comment: "The format string for Alerts: (1: the alerts string)"), alertSetString(alertSet: status.unacknowledgedAlerts)) - - if status.radioRSSI != 0 { - result += String(format: LocalizedString("\nRSSI: %1$@", comment: "The format string for RSSI: (1: RSSI value)"), String(describing: status.radioRSSI)) - result += String(format: LocalizedString("\nReceiver Low Gain: %1$@", comment: "The format string for receiverLowGain: (1: receiverLowGain)"), String(describing: status.receiverLowGain)) - } - - if status.faultEventCode.faultType != .noFaults { - // report the additional fault related information in a separate section - result += String(format: LocalizedString("\n\n⚠️ Critical Pod Fault %1$03d (0x%2$02X)", comment: "The format string for fault code in decimal and hex: (1: fault code for decimal display) (2: fault code for hex display)"), status.faultEventCode.rawValue, status.faultEventCode.rawValue) - result += String(format: "\n%1$@", status.faultEventCode.faultDescription) - if let faultEventTimeSinceActivation = status.faultEventTimeSinceActivation, - let faultTimeStr = formatter.string(from: faultEventTimeSinceActivation) - { - result += String(format: LocalizedString("\nFault Time: %1$@", comment: "The format string for fault time: (1: fault time string)"), faultTimeStr) - } - if let errorEventInfo = status.errorEventInfo { - result += String(format: LocalizedString("\nFault Event Info: %1$03d (0x%2$02X),", comment: "The format string for fault event info: (1: fault event info)"), errorEventInfo.rawValue, errorEventInfo.rawValue) - result += String(format: LocalizedString("\n Insulin State Table Corrupted: %@", comment: "The format string for insulin state table corrupted: (1: insulin state corrupted)"), String(describing: errorEventInfo.insulinStateTableCorruption)) - result += String(format: LocalizedString("\n Occlusion Type: %1$@", comment: "The format string for occlusion type: (1: occlusion type)"), String(describing: errorEventInfo.occlusionType)) - result += String(format: LocalizedString("\n Immediate Bolus In Progress: %1$@", comment: "The format string for immediate bolus in progress: (1: immediate bolus in progress)"), String(describing: errorEventInfo.immediateBolusInProgress)) - result += String(format: LocalizedString("\n Previous Pod Progress: %1$@", comment: "The format string for previous pod progress: (1: previous pod progress string)"), String(describing: errorEventInfo.podProgressStatus)) - } - if let pdmRef = status.pdmRef { - result += String(format: LocalizedString("\nRef: %@", comment: "The Ref format string (1: pdm ref string)"), pdmRef) - } - } - - return result -} - -struct ReadPodStatusView: View { - @Environment(\.horizontalSizeClass) var horizontalSizeClass - @Environment(\.presentationMode) var presentationMode: Binding - - private var toRun: ((_ completion: @escaping (_ result: PumpManagerResult) -> Void) -> Void)? - - @State private var alertIsPresented: Bool = false - @State private var displayString: String = "" - @State private var error: LocalizedError? = nil - @State private var executing: Bool = false - @State private var showActivityView: Bool = false - - init(toRun: @escaping (_ completion: @escaping (_ result: PumpManagerResult) -> Void) -> Void) { - self.toRun = toRun - } - - var body: some View { - VStack { - List { - Section { - Text(self.displayString).fixedSize(horizontal: false, vertical: true) - } - } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(action: { - self.showActivityView = true - }) { - Image(systemName: "square.and.arrow.up") - } - } - }.sheet(isPresented: $showActivityView) { - ActivityView(isPresented: $showActivityView, activityItems: [self.displayString]) - } - VStack { - Button(action: { - asyncAction() - }) { - Text(buttonText) - .actionButtonStyle(.primary) - } - .padding() - .disabled(executing) - } - .padding(self.horizontalSizeClass == .regular ? .bottom : []) - .background(Color(UIColor.secondarySystemGroupedBackground).shadow(radius: 5)) - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Read Pod Status", comment: "navigation title for read pod status")) - .navigationBarTitleDisplayMode(.inline) - .alert(isPresented: $alertIsPresented, content: { alert(error: error) }) - .onFirstAppear { - asyncAction() - } - } - - private func asyncAction () { - DispatchQueue.global(qos: .utility).async { - executing = true - self.displayString = "" - toRun?() { (result) in - switch result { - case .success(let detailedStatus): - self.displayString = podStatusString(status: detailedStatus) - case .failure(let error): - self.error = error - self.alertIsPresented = true - } - executing = false - } - } - } - - private var buttonText: String { - if executing { - return LocalizedString("Reading Pod Status...", comment: "button title when executing read pod status") - } else { - return LocalizedString("Read Pod Status", comment: "button title to read pod status") - } - } - - private func alert(error: Error?) -> SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Failed to read pod status.", comment: "Alert title for error when reading pod status")), - message: Text(error?.localizedDescription ?? "No Error") - ) - } -} - -struct ReadPodStatusView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - let detailedStatus = try! DetailedStatus(encodedData: Data([0x02, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xc3, 0x6a, 0x02, 0x07, 0x03, 0xff, 0x02, 0x09, 0x20, 0x00, 0x28, 0x00, 0x08, 0x00, 0x82])) - ReadPodStatusView() { completion in - completion(.success(detailedStatus)) - } - } - } - } diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ReadPulseLogView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ReadPulseLogView.swift deleted file mode 100644 index a1220b376..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ReadPulseLogView.swift +++ /dev/null @@ -1,128 +0,0 @@ -// -// ReadPulseLogView.swift -// OmniBLE -// -// Created by Joe Moran on 9/1/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - - -struct ReadPulseLogView: View { - @Environment(\.horizontalSizeClass) var horizontalSizeClass - @Environment(\.presentationMode) var presentationMode: Binding - - private var toRun: ((_ completion: @escaping (_ result: Result) -> Void) -> Void)? - - @State private var alertIsPresented: Bool = false - @State private var displayString: String = "" - @State private var error: Error? = nil - @State private var executing: Bool = false - @State private var showActivityView: Bool = false - - init(toRun: @escaping (_ completion: @escaping (_ result: Result) -> Void) -> Void) { - self.toRun = toRun - } - - var body: some View { - VStack { - List { - Section { - let myFont = Font - .system(size: 12) - .monospaced() - Text(self.displayString) - .font(myFont) - } - } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(action: { - self.showActivityView = true - }) { - Image(systemName: "square.and.arrow.up") - } - } - }.sheet(isPresented: $showActivityView) { - ActivityView(isPresented: $showActivityView, activityItems: [self.displayString]) - } - VStack { - Button(action: { - asyncAction() - }) { - Text(buttonText) - .actionButtonStyle(.primary) - } - .padding() - .disabled(executing) - } - .padding(self.horizontalSizeClass == .regular ? .bottom : []) - .background(Color(UIColor.secondarySystemGroupedBackground).shadow(radius: 5)) - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Read Pulse Log", comment: "navigation title for read pulse log")) - .navigationBarTitleDisplayMode(.inline) - .alert(isPresented: $alertIsPresented, content: { alert(error: error) }) - .onFirstAppear { - asyncAction() - } - } - - private func asyncAction () { - DispatchQueue.global(qos: .utility).async { - executing = true - self.displayString = "" - toRun?() { (result) in - switch result { - case .success(let pulseLogString): - self.displayString = pulseLogString - case .failure(let error): - self.displayString = "" - self.error = error - self.alertIsPresented = true - } - executing = false - } - } - } - - private var buttonText: String { - if executing { - return LocalizedString("Reading Pulse Log...", comment: "button title when executing read pulse log") - } else { - return LocalizedString("Read Pulse Log", comment: "button title to read pulse log") - } - } - - private func alert(error: Error?) -> SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Failed to read pulse log.", comment: "Alert title for error when reading pulse log")), - message: Text(error?.localizedDescription ?? "No Error") - ) - } -} - -struct ReadPulsePodLogView_Previews: PreviewProvider { - static var previews: some View { - ReadPulseLogView() { completion in - let podInfoPulseLogRecent = try! PodInfoPulseLogRecent(encodedData: Data([0x50, 0x03, 0x17, - 0x39, 0x72, 0x58, 0x01, 0x3c, 0x72, 0x43, 0x01, 0x41, 0x72, 0x5a, 0x01, 0x44, 0x71, 0x47, 0x01, - 0x49, 0x51, 0x59, 0x01, 0x4c, 0x51, 0x44, 0x01, 0x51, 0x73, 0x59, 0x01, 0x54, 0x50, 0x43, 0x01, - 0x59, 0x50, 0x5a, 0x81, 0x5c, 0x51, 0x42, 0x81, 0x61, 0x73, 0x59, 0x81, 0x00, 0x75, 0x43, 0x80, - 0x05, 0x70, 0x5a, 0x80, 0x08, 0x50, 0x44, 0x80, 0x0d, 0x50, 0x5b, 0x80, 0x10, 0x75, 0x43, 0x80, - 0x15, 0x72, 0x5e, 0x80, 0x18, 0x73, 0x45, 0x80, 0x1d, 0x72, 0x5b, 0x00, 0x20, 0x70, 0x43, 0x00, - 0x25, 0x50, 0x5c, 0x00, 0x28, 0x50, 0x46, 0x00, 0x2d, 0x50, 0x5a, 0x00, 0x30, 0x75, 0x47, 0x00, - 0x35, 0x72, 0x59, 0x00, 0x38, 0x70, 0x46, 0x00, 0x3d, 0x75, 0x57, 0x00, 0x40, 0x72, 0x43, 0x00, - 0x45, 0x73, 0x55, 0x00, 0x48, 0x73, 0x41, 0x00, 0x4d, 0x70, 0x52, 0x00, 0x50, 0x73, 0x3f, 0x00, - 0x55, 0x74, 0x4d, 0x00, 0x58, 0x72, 0x3d, 0x80, 0x5d, 0x73, 0x4d, 0x80, 0x60, 0x71, 0x3d, 0x80, - 0x01, 0x51, 0x50, 0x80, 0x04, 0x72, 0x3d, 0x80, 0x09, 0x50, 0x4e, 0x80, 0x0c, 0x51, 0x40, 0x80, - 0x11, 0x74, 0x50, 0x80, 0x14, 0x71, 0x40, 0x80, 0x19, 0x50, 0x4d, 0x80, 0x1c, 0x75, 0x3f, 0x00, - 0x21, 0x72, 0x52, 0x00, 0x24, 0x72, 0x40, 0x00, 0x29, 0x71, 0x53, 0x00, 0x2c, 0x50, 0x42, 0x00, - 0x31, 0x51, 0x55, 0x00, 0x34, 0x50, 0x42, 0x00 ])) - let lastPulseNumber = Int(podInfoPulseLogRecent.indexLastEntry) - completion(.success(pulseLogString(pulseLogEntries: podInfoPulseLogRecent.pulseLog, lastPulseNumber: lastPulseNumber))) - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ScheduledExpirationReminderEditView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ScheduledExpirationReminderEditView.swift deleted file mode 100644 index 39162ca2f..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/ScheduledExpirationReminderEditView.swift +++ /dev/null @@ -1,169 +0,0 @@ -// -// ScheduledExpirationReminderEditView.swift -// OmniBLE -// -// Created by Pete Schwamb on 2/17/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -extension Date: Identifiable { - public var id: Self { self } -} - -struct ScheduledExpirationReminderEditView: View { - - @Environment(\.horizontalSizeClass) var horizontalSizeClass - - var allowedDates: [Date] - var dateFormatter: DateFormatter - var onSave: ((_ selectedDate: Date?, _ completion: @escaping (_ error: Error?) -> Void) -> Void)? - var onFinish: (() -> Void)? - - private var initialValue: Date? - @State private var alertIsPresented: Bool = false - @State private var error: Error? - @State private var saving: Bool = false - @State private var selectedDate: Date? - - init(scheduledExpirationReminderDate: Date?, allowedDates: [Date], dateFormatter: DateFormatter, onSave: ((_ selectedDate: Date?, _ completion: @escaping (_ error: Error?) -> Void) -> Void)? = nil, onFinish: (() -> Void)? = nil) - { - self.allowedDates = allowedDates - self.dateFormatter = dateFormatter - self.onSave = onSave - self.onFinish = onFinish - self.initialValue = scheduledExpirationReminderDate - self._selectedDate = State(initialValue: scheduledExpirationReminderDate) - } - - var body: some View { - contentWithCancel - } - - var content: some View { - VStack { - RoundedCardScrollView(title: LocalizedString("Scheduled Reminder", comment: "Title for scheduled expiration reminder edit page")) { - if self.horizontalSizeClass == .compact { - // Keep picker outside of card in compact view, because it forces full device width. - VStack(spacing: 0) { - RoundedCard { - Text(LocalizedString("Scheduled Reminder", comment: "Card title for scheduled reminder")) - Divider() - valueRow - } - picker - .background(Color(.secondarySystemGroupedBackground)) - } - - } else { - RoundedCard { - Text(LocalizedString("Scheduled Reminder", comment: "Card title for scheduled reminder")) - Divider() - valueRow - picker - } - } - } - Spacer() - Button(action: saveTapped) { - Text(saveButtonText) - .actionButtonStyle() - .padding() - } - .disabled(saving || !valueChanged) - } - .navigationBarTitle("", displayMode: .inline) - .alert(isPresented: $alertIsPresented, content: { alert(error: error) }) - } - - var valueRow: some View { - RoundedCardValueRow( - label: LocalizedString("Time", comment: "Label for scheduled expiration reminder row"), - value: scheduledReminderDateString(selectedDate), - highlightValue: true - ) - } - - var picker: some View { - Picker(selection: $selectedDate, label: Text("Numbers")) { - ForEach(self.allowedDates) { date in - Text(scheduledReminderDateString(date)).tag(date as Date?) - } - Text(scheduledReminderDateString(nil)).tag(nil as Date?) - } - .pickerStyle(WheelPickerStyle()) - } - - var saveButtonText: String { - if saving { - return LocalizedString("Saving...", comment: "button title for saving scheduled reminder while saving") - } else { - return LocalizedString("Save", comment: "button title for saving scheduled reminder") - } - } - - private func saveTapped() { - saving = true - self.onSave?(selectedDate) { (error) in - saving = false - if let error = error { - self.error = error - self.alertIsPresented = true - } else { - self.onFinish?() - } - } - } - - private func scheduledReminderDateString(_ scheduledDate: Date?) -> String { - if let scheduledDate = scheduledDate { - return dateFormatter.string(from: scheduledDate) - } else { - return LocalizedString("No Reminder", comment: "Value text for no expiration reminder") - } - } - - private var valueChanged: Bool { - return selectedDate != initialValue - } - - private var contentWithCancel: some View { - if saving { - return AnyView(content - .navigationBarBackButtonHidden(true) - ) - } else if valueChanged { - return AnyView(content - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: cancelButton) - ) - } else { - return AnyView(content) - } - } - - private var cancelButton: some View { - Button(action: { self.onFinish?() } ) { Text(LocalizedString("Cancel", comment: "Button title for cancelling scheduled reminder date edit")) } - } - - private func alert(error: Error?) -> SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Failed to Update Expiration Reminder", comment: "Alert title for error when updating expiration reminder")), - message: Text(error?.localizedDescription ?? "No Error") - ) - } -} - -struct ScheduledExpirationReminderEditView_Previews: PreviewProvider { - static var previews: some View { - ScheduledExpirationReminderEditView( - scheduledExpirationReminderDate: Date(), - allowedDates: [Date()], - dateFormatter: DateFormatter(), - onSave: { (_, _) in }, - onFinish: { } - ) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/SetupCompleteView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/SetupCompleteView.swift deleted file mode 100644 index d23a01cc9..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/SetupCompleteView.swift +++ /dev/null @@ -1,113 +0,0 @@ -// -// SetupCompleteView.swift -// OmniBLE -// -// Created by Pete Schwamb on 3/2/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct SetupCompleteView: View { - - @Environment(\.verticalSizeClass) var verticalSizeClass - @Environment(\.appName) private var appName - - - private var onSaveScheduledExpirationReminder: ((_ selectedDate: Date?, _ completion: @escaping (_ error: Error?) -> Void) -> Void)? - private var didFinish: () -> Void - private var didRequestDeactivation: () -> Void - private var dateFormatter: DateFormatter - - @State private var scheduledReminderDate: Date? - - @State private var scheduleReminderDateEditViewIsShown: Bool = false - - var allowedDates: [Date] - - init(scheduledReminderDate: Date?, dateFormatter: DateFormatter, allowedDates: [Date], onSaveScheduledExpirationReminder: ((_ selectedDate: Date?, _ completion: @escaping (_ error: Error?) -> Void) -> Void)?, didFinish: @escaping () -> Void, didRequestDeactivation: @escaping () -> Void) - { - self._scheduledReminderDate = State(initialValue: scheduledReminderDate) - self.dateFormatter = dateFormatter - self.allowedDates = allowedDates - self.onSaveScheduledExpirationReminder = onSaveScheduledExpirationReminder - self.didFinish = didFinish - self.didRequestDeactivation = didRequestDeactivation - } - - var body: some View { - GuidePage(content: { - VStack { - LeadingImage("Pod") - Text(String(format: LocalizedString("Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you.", comment: "Format string for instructions for setup complete view. (1: app name)"), appName)) - .fixedSize(horizontal: false, vertical: true) - Divider() - VStack(alignment: .leading) { - Text(LocalizedString("Scheduled Reminder", comment: "Scheduled reminder card title on SetupCompleteView")) - Divider() - NavigationLink( - destination: ScheduledExpirationReminderEditView( - scheduledExpirationReminderDate: scheduledReminderDate, - allowedDates: allowedDates, - dateFormatter: dateFormatter, - onSave: { (newDate, completion) in - onSaveScheduledExpirationReminder?(newDate) { (error) in - if error == nil { - scheduledReminderDate = newDate - } - completion(error) - } - }, - onFinish: { scheduleReminderDateEditViewIsShown = false }), - isActive: $scheduleReminderDateEditViewIsShown) - { - RoundedCardValueRow( - label: LocalizedString("Time", comment: "Label for expiration reminder row"), - value: scheduledReminderDateString(scheduledReminderDate), - highlightValue: false - ) - } - } - } - .padding(.bottom, 8) - .accessibility(sortPriority: 1) - }) { - Button(action: { - didFinish() - }) { - Text(LocalizedString("Finish Setup", comment: "Action button title to continue at Setup Complete")) - .actionButtonStyle(.primary) - } - .padding() - .background(Color(UIColor.systemBackground)) - .zIndex(1) - } - .animation(.default) - .navigationBarTitle(LocalizedString("Setup Complete", comment: "Title of SetupCompleteView"), displayMode: .automatic) - } - - private func scheduledReminderDateString(_ scheduledDate: Date?) -> String { - if let scheduledDate = scheduledDate { - return dateFormatter.string(from: scheduledDate) - } else { - return LocalizedString("No Reminder", comment: "Value text for no expiration reminder") - } - } -} - -struct SetupCompleteView_Previews: PreviewProvider { - static var previews: some View { - SetupCompleteView( - scheduledReminderDate: Date(), - dateFormatter: DateFormatter(), - allowedDates: [Date()], - onSaveScheduledExpirationReminder: { (date, completion) in - }, - didFinish: { - }, - didRequestDeactivation: { - } - ) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/SilencePodSelectionView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/SilencePodSelectionView.swift deleted file mode 100644 index 9510992d7..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/SilencePodSelectionView.swift +++ /dev/null @@ -1,143 +0,0 @@ -// -// SilencePodSelectionView.swift -// OmniBLE -// -// Created by Joe Moran 8/30/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI - -struct SilencePodSelectionView: View { - - @Environment(\.horizontalSizeClass) var horizontalSizeClass - @Environment(\.presentationMode) var presentationMode: Binding - - private var initialValue: SilencePodPreference - @State private var preference: SilencePodPreference - private var onSave: ((_ selectedValue: SilencePodPreference, _ completion: @escaping (_ error: LocalizedError?) -> Void) -> Void)? - - @State private var alertIsPresented: Bool = false - @State private var error: LocalizedError? - @State private var saving: Bool = false - - - init(initialValue: SilencePodPreference, onSave: @escaping (_ selectedValue: SilencePodPreference, _ completion: @escaping (_ error: LocalizedError?) -> Void) -> Void) { - self.initialValue = initialValue - self._preference = State(initialValue: initialValue) - self.onSave = onSave - } - - var body: some View { - contentWithCancel - } - - var content: some View { - VStack { - List { - Section { - Text(LocalizedString("Silence Pod mode suppresses all Pod alert and confirmation reminder beeping.", comment: "Help text for Silence Pod view")).fixedSize(horizontal: false, vertical: true) - .padding(.vertical, 10) - } - Section { - ForEach(SilencePodPreference.allCases, id: \.self) { preference in - HStack { - CheckmarkListItem( - title: Text(preference.title), - description: Text(preference.description), - isSelected: Binding( - get: { self.preference == preference }, - set: { isSelected in - if isSelected { - self.preference = preference - } - } - ) - ) - } - .padding(.vertical, 10) - } - } - .buttonStyle(PlainButtonStyle()) // Disable row highlighting on selection - } - VStack { - Button(action: { - saving = true - onSave?(preference) { (error) in - saving = false - if let error = error { - self.error = error - self.alertIsPresented = true - } else { - self.presentationMode.wrappedValue.dismiss() - } - } - }) { - Text(saveButtonText) - .actionButtonStyle(.primary) - } - .padding() - .disabled(saving || !valueChanged) - } - .padding(self.horizontalSizeClass == .regular ? .bottom : []) - .background(Color(UIColor.secondarySystemGroupedBackground).shadow(radius: 5)) - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Silence Pod", comment: "navigation title for Silnce Pod")) - .navigationBarTitleDisplayMode(.inline) - .alert(isPresented: $alertIsPresented, content: { alert(error: error) }) - } - - private var contentWithCancel: some View { - if saving { - return AnyView(content - .navigationBarBackButtonHidden(true) - ) - } else if valueChanged { - return AnyView(content - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: cancelButton) - ) - } else { - return AnyView(content) - } - } - - private var cancelButton: some View { - Button(action: { self.presentationMode.wrappedValue.dismiss() } ) { - Text(LocalizedString("Cancel", comment: "Button title for cancelling silence pod edit")) - } - } - - var saveButtonText: String { - if saving { - return LocalizedString("Saving...", comment: "button title for saving silence pod preference while saving") - } else { - return LocalizedString("Save", comment: "button title for saving silence pod preference") - } - } - - private var valueChanged: Bool { - return preference != initialValue - } - - private func alert(error: Error?) -> SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Failed to update silence pod preference.", comment: "Alert title for error when updating silence pod preference")), - message: Text(error?.localizedDescription ?? "No Error") - ) - } -} - -struct SilencePodSelectionView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - SilencePodSelectionView(initialValue: .disabled) { selectedValue, completion in - print("Selected: \(selectedValue)") - completion(nil) - } - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/TimeView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/TimeView.swift deleted file mode 100644 index 368c0c59c..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/TimeView.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// TimeView.swift -// OmniBLE -// -// Created by Pete Schwamb on 5/10/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -struct TimeView: View { - - let timeZone: TimeZone - - private let shortTimeFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .none - formatter.timeStyle = .short - return formatter - }() - - @State var currentDate = Date() - let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() - - var timeZoneString: String { - shortTimeFormatter.timeZone = timeZone - return shortTimeFormatter.string(from: currentDate) - } - - var body: some View { - Text(timeZoneString).onReceive(timer) { input in - currentDate = input - } - } -} - -struct TimeView_Previews: PreviewProvider { - static var previews: some View { - TimeView(timeZone: .current) - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/UncertaintyRecoveredView.swift b/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/UncertaintyRecoveredView.swift deleted file mode 100644 index 249f6fd95..000000000 --- a/Dependencies/OmniBLE/OmniBLE/PumpManagerUI/Views/UncertaintyRecoveredView.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// UncertaintyRecoveredView.swift -// OmniBLE -// -// Created by Pete Schwamb on 8/25/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct UncertaintyRecoveredView: View { - var appName: String - - var didFinish: (() -> Void)? - - var body: some View { - GuidePage(content: { - Text(String(format: LocalizedString("%1$@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %2$@ normally now.", comment: "Text body for page showing insulin uncertainty has been recovered (1: appName) (2: appName)"), self.appName, self.appName)) - .padding([.top, .bottom]) - }) { - VStack { - Button(action: { - self.didFinish?() - }) { - Text(LocalizedString("Continue", comment: "Button title to continue")) - .actionButtonStyle() - .padding() - } - } - } - .navigationBarTitle(Text("Comms Recovered"), displayMode: .large) - .navigationBarBackButtonHidden(true) - } -} - -struct UncertaintyRecoveredView_Previews: PreviewProvider { - static var previews: some View { - UncertaintyRecoveredView(appName: "Test App") - } -} diff --git a/Dependencies/OmniBLE/OmniBLE/ar.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/ar.lproj/Localizable.strings deleted file mode 100644 index bc1004f36..000000000 --- a/Dependencies/OmniBLE/OmniBLE/ar.lproj/Localizable.strings +++ /dev/null @@ -1,35 +0,0 @@ -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ ago"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "إلغاء"; - -/* Section header for configuration section */ -"Configuration" = "المعطيات"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "توصيل الأنسولين"; - -/* Alert acknowledgment OK button */ -"OK" = "موافق"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "أعد المحاولة"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Setup Complete"; - -/* Units for showing temp basal rate */ -"U/hr" = "وحدة لكل ساعة"; - diff --git a/Dependencies/OmniBLE/OmniBLE/ca.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/ca.lproj/Localizable.strings deleted file mode 100644 index 5bf12da7f..000000000 --- a/Dependencies/OmniBLE/OmniBLE/ca.lproj/Localizable.strings +++ /dev/null @@ -1,1130 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inaktiv)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ vor"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ hat die Kommunikation mit dem Pod an Ihrem Körper wiederhergestellt.\n\nDie Insulinabgabeaufzeichnungen wurden aktualisiert und sollten mit dem übereinstimmen, was tatsächlich abgegeben wurde.\n\nSie können %@ jetzt normal weiter verwenden."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ IE"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ für %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ konnte seit %2$@ nicht mehr mit Ihrem Pod kommunizieren.\n\nOhne Kommunikation mit dem Pod kann die App keine Befehle für die Insulinabgabe senden oder genaue, aktuelle Informationen über Ihr aktives Insulin oder das vom Pod abgegebene Insulin anzeigen.\n\nÜberwachen Sie Ihren Blutzucker für die nächsten 6 oder mehr Stunden genau, da in Ihrem Körper Insulin aktiv sein kann oder auch nicht, das %3$@ nicht anzeigen kann."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ Insulin oder weniger verbleibend im Pod. Pod bald wechseln."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ IE verbleibend bei %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g IE"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 Stunde"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 Stunde 30 Minuten"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 Stunden"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 Minuten"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Aktivierungszeit überschritten"; - -/* description label for active time pod details row */ -"Active Time" = "Laufzeit"; - -/* Section header for activity section */ -"Activity" = "Aktivität"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pumpenzeit einstellen"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Sind Sie sicher, dass Sie die Pod-Einrichtung abbrechen möchten?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Sind Sie sicher, dass Sie das Omnipod Onboarding überspringen wollen?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Sind Sie sicher, dass Sie keinen Omnipod DASH mehr benutzen möchten?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Pod anbringen"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Versuche die Verbindung wieder aufzubauen"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-Off Alarm"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Zurück"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialisiert"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Weniger als 50 Einheiten"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth ist ausgeschaltet"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Bluetooth wird zurückgesetzt"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth ist aus einem unbekannten Grund nicht verfügbar."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth ist nicht verfügbar: %1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "Bluetooth-Nutzung ist nicht erlaubt"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "Bluetooth-Verwendung wird auf diesem Gerät nicht unterstützt"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolusabgabe läuft "; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@IE %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusabgabe"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolus-Abgabe mit temporärer Basalrate"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Abbrechen"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Manuelles Basal abbrechen"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanüle erfolgreich eingeführt. Weiter."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Einsetzen der Kanüle"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Sicher"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Pod jetzt wechseln. Die Insulinabgabe stoppt 8 Stunden nach Ablauf des Pods oder wenn kein Insulin mehr vorhanden ist."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Pod jetzt wechseln. Die Insulinabgabe stoppt in %1$@ oder wenn kein Insulin mehr vorhanden ist."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Pod jetzt wechseln. Die Insulinabgabe stoppt in 1 Stunde."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Pod jetzt wechseln. Der Pod ist seit 72 Stunden aktiv."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Prüfe die Kanüle"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Überprüfe den Pod, bringe ihn an und bestätige dann die Pod-Anbringung."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Prüfe die Einfügung"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Prüfe…"; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Befehlsfehler %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Problem"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Kommunikation wiederhergestellt"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Kommunikationsproblem: Unbestätigter Befehl steht noch aus."; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Sicherheitserinnerung"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Vertrauenserinnerungen sind Pieptöne vom Pod, die verwendet werden können, um ausgewählte Befehle zu bestätigen."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Vertrauenserinnerungen ertönen für von Ihnen initiierte Befehle, wie Bolus, Bolus abbrechen, Unterbrechen, Fortsetzen, Benachrichtigungserinnerungen speichern usw. Wenn Loop die Abgabe automatisch anpasst, werden keine Vertrauenserinnerungen verwendet."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Vertrauenserinnerungen ertönen, wenn Loop die Lieferung automatisch anpasst, sowie für von Ihnen initiierte Befehle."; - -/* Section header for configuration section */ -"Configuration" = "Konfiguration"; - -/* Button title for confirm attachment option */ -"Confirm" = "Bestätige"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bestätige Pod Befestigung"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Weiter"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "Nachrichte konnte nicht analysiert werden: %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritische Warnungen"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritischer Pod-Fehler"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Überlagerungen möglich. Bitte wechseln Sie an einen neuen Standort"; - -/* Unit for singular day in pod life remaining */ -"day" = "Tag"; - -/* Unit for plural days in pod life remaining */ -"days" = "Tage"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Pod deaktivieren"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktiviert"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktiviere."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deaktiviere…"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Omnipod DASH löschen"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Gerätedetails"; - -/* description label for device name pod details row */ -"Device Name" = "Gerätename"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Ausgeschaltet"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Pod verwerfen"; - -/* No comment provided by engineer. */ -"Done" = "Fertig"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Reservoir leer"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Leeres Reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Leere Antwort vom Pod"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Leerer Wert"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Aktiviert"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Fehler"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Fehlerereignis protokolliert, fahre herunter"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Ablaufhinweis"; - -/* Description for expiration alert */ -"Expiration alert" = "Ablaufalarm"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Erinnerung an den Ablauf der Nutzungsdauer"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standard Erinnerung an den Ablauf der Nutzungsdauer"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Verzögerung"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Verzögerter Bolus aktiv"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Verzögerter Bolus mit temporärer Basalrate aktiv"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Fehler beim Abbrechen der manuellen Basalrate"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Wiederaufnahme der Insulinabgabe fehlgeschlagen"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Fehler beim Einstellen der Pumpenzeit"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Fehler beim Anhalten der Insulinabgabe"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Fehler beim Aktualisieren der Einstellung für die Sicherheitserinnerung."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Fehler beim Aktualisieren der Ablauferinnerung"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Fehler beim Aktualisieren der Erinnerung für einen niedrigen Vorratsbehälter"; - -/* Pod life HUD view label */ -"Fault" = "Störung"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fehlerereignis aufgetreten"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Fülle U-100 Insulin in den Pod (lasse die blaue Kappe drauf)"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Deaktivierung abschließen"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Deaktivierung abgeschlossen"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Kopplung abgeschlossen"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Einrichtung abschließen"; - -/* Description for finish setup */ -"Finish setup " = "Einrichtung abgeschlossen"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Einrichtungserinnerung abgeschlossen"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Mehr als %1$@ verbleibende Einheiten um %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "Stunde"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "Stunden"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Wenn Du die Einrichtung abbrichst, dann wird der Pod deaktiviert und unbrauchbar."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Incorrect Packet Exception: %1$@ (location=%2$d)"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Falsche Antwort"; - -/* Pod inititialized */ -"Initialized" = "Initialisiert"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Kanüle einsetzen"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Eingeführt"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Einfügen von Kanüle"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Füge ein, bitte warte…"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Füge ein…"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulinabgabe\nunterbrochen"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulinabgabe wurde gestoppt. Pod jetzt wechseln."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Die Insulinabgabe wird angehalten, bis Sie sie manuell wieder aufnehmen. Wann soll Loop Sie daran erinnern, die Abgabe fortzusetzen?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Verbleibendes Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulinabgabe unterbrochen"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulintyp"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulintyp nicht konfiguriert"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Interner Podfehler %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Abgebrochener Bolus: %1$@ IE (%2$@ IE geplant) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Ungültige Adresse (%1$x). Adresse %2$x erwartet"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Ungültige Adresse (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Ungültiger CRC"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Invalid LTK Key: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ungültige Einstellung"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Wurde der Katheter ordentlich eingeführt?"; - -/* description label for last status date pod details row */ -"Last Status" = "Letzter Status"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Achte auf zwei Pieptöne."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop passt Ihre Insulinabgabe nicht automatisch an, bis die temporäre Basalrate beendet oder abgebrochen wurde."; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Niedriges Reservoir"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Niedriges Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Hinweis auf niedriges Reservior (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Hinweisalarm für fast leeres Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Erinnerung an niedriges Reservoir"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Stellen Sie sicher, dass Ihr iPhone nah am Pod ist"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Stellen Sie sicher, dass sich Ihr iPhone und Ihr Pod nahe beieinander befinden. Wenn die Kommunikationsprobleme bestehen bleiben, dann gehen Sie an einen anderen Ort."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Stellen Sie sicher, dass Ihr Pod gefüllt und in der Nähe ist."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Stellen Sie sicher, dass sich Ihr Pod in der Nähe befindet, und versuchen Sie es erneut."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Stellen Sie sicher, dass sich Ihr RileyLink in der Nähe befindet und eingeschaltet ist"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuelle Basalrate"; - -/* Pod memory initialized */ -"Memory initialized" = "Speicher initialisiert"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Message IO Exception: %1$@"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "Minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "Minuten"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Fehlende Konfiguration"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Begeben Sie sich in einen anderen Bereich, entfernt von anderen Pods und versuchen Sie es erneut."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Warnung bei mehreren Befehlen"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "nicht bestätigt"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Weiter"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nein"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Keine\nAbgabe"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Keine Alarme"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Es werden keine Sicherheitserinnerungen verwendet."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Keine Fehler"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Kein Insulin"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Kein Pod gekoppelt"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Kein Pod gekoppelt"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Keine Pods gefunden"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Keine Erinnerung"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Keine Rückmeldung vom Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Kein RileyLink verfügbar"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nein, mit Pod fortfahren"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nein, Pumpe so lassen wie sie ist"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Nicht genügend Daten"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Benachrichtigungseinstellungen"; - -/* No comment provided by engineer. */ -"Numbers" = "Zahlen"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Verstopfung erkannt"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Verstopfung erkannt"; - -/* Action button default text for PodAlerts */ -"Ok" = "OK"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Erinnerung"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pod koppeln"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pod koppeln."; - -/* Pod status after pairing */ -"Paired" = "Gekoppelt"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Kopplung abgeschlossen"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Kopplungsausnahme: %1$@"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Koppeln"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Koppeln…"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing-Fehler: %1$@ in (%2$@)"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = "Payload crc32 %1$@ does not match computed crc32 %2$@"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percent = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheriegerät nicht bereit"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Bitte nur Original-Pod in Reichweite bringen oder Original-Pod deaktivieren"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Bitte bringen Sie Ihren Pod näher an Ihr RileyLink und versuchen Sie es erneut"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Bitte vergewissern Sie sich, dass der Pod sicher an Ihrem Körper befestigt ist.\n\nDer Katheter kann mit jedem Pod nur einmal eingeführt werden. Tippen Sie auf „Bestätigen“, wenn der Pod angeschlossen ist."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Bitte deaktivieren Sie den Pod. Wenn die Deaktivierung abgeschlossen ist, können Sie einen neuen Pod koppeln."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Bitte deaktivieren Sie den Pod. Wenn die Deaktivierung abgeschlossen ist, können Sie ihn entfernen und einen neuen Pod koppeln."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Bitte aktiviere die Bluetooth-Berechtigungen für diese App in den Systemeinstellungen"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Bitte schließen Sie die Kopplung Ihres Pods ab."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Bitte koppel einen neuen Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Bitte positionieren Sie das iPhone weiter vom Pod entfernt"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Bitte positionieren Sie das iPhone relativ zum Pod neu"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Bitte verwenden Sie ein anderes Gerät mit Bluetooth-Funktion"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod aktiviert"; - -/* Label describing pod age view */ -"Pod Age" = "Pod-Alter"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod bereits gekoppelt"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod bereits gefüllt"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod erfolgreich deaktiviert. Weiter."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Pod-Fehler"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Ablaufalarm des Pods"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Hinweis zum Ablaufen des Pods"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod-Ablauferinnerung"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod abgelaufen"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod abgelaufen"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod läuft ab"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod läufen ab in"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod läuft in %1$@ ab."; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fehlerdetails"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Podfehler: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Der Pod ist nicht bereit zum Einführen der Kanüle."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Der Pod ist nicht bereit zum Befüllen."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod ist angehalten"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "Pod nicht verbunden"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Verstopfung"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod erfolgreich gekoppelt. Weiter."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod-Kopplung unvollständig"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sendet Bestätigung anstelle von Antwort"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Einrichtung"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Das Zeitfenster für die Pod-Einrichtung ist abgelaufen"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Erinnerung über abgelaufenen Pod "; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Schlechte Signalstärke"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Stelle vorbereiten."; - -/* title for previous pod page */ -"Previous Pod" = "Vorheriger Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informationen über den letzten Pod"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Befüllen"; - -/* Pod state when priming completed */ -"Priming completed" = "Befüllen des Pods abgeschlossen"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Befülle, bitte warte."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Befülle…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Uhrzeit der Pumpe"; - -/* Label text for basal rate summary */ -"Rate" = "Rate"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Bereit für die Programmierung der Basalrate"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Bereit zum Einführen der Kanüle"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Verbleibend"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Erinnerung initialisiert"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Entfernte die blaue Kappe und überprüfe den Katheter. Dann entferne das Papier."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Entferne den Pod vom Körper"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Pumpe löschen"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Pod ersetzen"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Fortsetzen"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Insulinabgabe fortsetzen"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Insulinabgabe fortsetzen"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Insulinabgabe wiederaufnehmen"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Fortsetzen: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Nehme Insulinabgabe wieder auf…"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Wiederholen"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Speichern"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Speichere…"; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Geplante Basalrate"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Geplante Basalrate"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Geplante Erinnerung"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Wähle die Insulinart aus, die Du für diesen Pod benutzen möchtest."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequenznummer"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Temporäre Basalrate setzen"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Temporärere Basalrate setzen"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Einrichtung abgeschlossen"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Pod-Abschaltung steht bevor"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarm für die bevorstehende Pod-Abschaltung"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signalverlust"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signalstärke ist zu hoch"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Omnipod-Onboarding überspringen?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Unterbrechen"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Abgabe unterbrechen"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Unterbrechungsfortschritts-Erinnerung"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Insulinabgabe unterbrechen"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Unterbrechungszeit abgelaufen"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Unterbrochen: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Unterbrochen"; - -/* Label for suspended at time */ -"Suspended At" = "Unterbrochen um"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Unterbreche die Insulinabgabe…"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Die Unterbrechungszeit ist abgelaufen. Öffnen Sie die App und fahren Sie fort."; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Zu einer anderen Pumpe wechseln"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Mit aktueller Uhrzeit synchronisieren."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Befüllen des Pods erfolgreich"; - -/* Pod power to motor activated */ -"Tank power activated" = "Energieversorgung für den Podmotor aktiviert"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tippe unten, um das Einführen der Kanüle zu starten."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temporäre Basalrate"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temporäre Basalrate läuft bereits."; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temporäre Basalrate läuft"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ IE/h %2$@ %3$@ %4$@ IE %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporäre Basalrate"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal fehlgeschlagen"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Die App konfiguriert eine Erinnerung auf dem Pod, um Dich vor Ablauf des Pods zu benachrichtigen. Legen die Anzahl der Stunden fest, die Du vor Ablauf des Pods benachrichtigt werden möchtest."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Die App benachrichtigt Dich vor Ablauf des Pods.\n\nScrolle, um die gewünschte Anzahl von Stunden im Voraus festzulegen."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Die App benachrichtigt Dich, wenn die Insulinmenge im Pod diesen Wert erreicht (50-10 IE).\n\nScrolle, um die Anzahl der Einheiten festzulegen, bei der Du erinnert werden möchtest."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Die App benachrichtigt Dich, wenn die Insulinmenge im Pod diesen Wert erreicht."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Die Insulinabschaltung ist beendet.\n\nSie können die Abgabe über das Banner auf dem Startbildschirm oder über den Bildschirm mit den Pumpeneinstellungen fortsetzen. Sie werden in 15 Minuten erneut erinnert."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Die obigen Erinnerungen ertönen nicht, wenn sich Dein Gerät im Lautlos- oder Nicht-Stören-Modus befindet.\n\nEs gibt andere kritische Pod-Warnungen und -Alarme, die auch dann ertönen, wenn Dein Gerät auf „Lautlos“ oder „Nicht stören“ eingestellt ist."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Die Uhrzeit Ihrer Pumpe unterscheidet sich von Ihrer aktuellen Uhrzeit. Möchten Sie die Uhrzeit Ihrer Pumpe auf Ihre aktuelle Uhrzeit aktualisieren?"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Die Uhrzeit Ihrer Pumpe weicht von der aktuellen Uhrzeit ab. Sie können die Uhrzeit der Pumpe überprüfen und in den Einstellungen mit der aktuellen Uhrzeit synchronisieren."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Die Uhrzeit der Pumpe weicht von der aktuellen Uhrzeit ab. Die Zeit der Pumpe steuert die geplanten Therapieeinstellungen. Scrolle nach unten zur Zeile Pumpenzeit, um den Zeitunterschied zu überprüfen und die Pumpe zu konfigurieren."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Das Fenster oben auf dem Pod sollte pinkfarben sein, wenn der Katheter ordentlich in die Haut eingeführt wurde."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Es gab ein Problem bei der Kommunikation mit dem Pod. Wenn dieses Problem weiterhin besteht, tippen Sie auf \"Pod verwerfen\". Sie können dann einen neuen Pod aktivieren."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dies ist eine Erinnerung, die Du beim Koppeln Deines aktuellen Pods eingestellt hast."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Dieser Pumpenmanager wurde nicht mit einer maximalen Basalrate konfiguriert, da er hinzugefügt wurde, bevor die Funktion manuelle temporäre Basalrate hinzugefügt wurde. Bitte gehe zu Therapieeinstellungen -> Abgabegrenzen und stelle eine neue maximale Basalrate ein."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Zeit"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Änderung der Uhrzeit erkannt"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Es ist Zeit Ihren Pod zu wechseln! Der Pod läuft ab in %1$@"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Zeitüberschreitung"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Zeichen umschalten"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Zu viele Pods in Reichweite"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Gesamt Abgabe"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Versuchen Sie es erneut"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Schalte Bluetooth ein"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "IE/h"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Pod kann nicht erreicht werden"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Pod kann nicht erreicht werden"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Eine temporäre Basalrate kann nicht gesetzt werden: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Eine temporäre Basalrate kann nicht gesetzt werden: %1$@\n\n%2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Unsicher"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Unerwartete Sequenznummer der Nachricht"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Unerwarteter Podwechsel"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Unerwartete Antwort vom Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Nicht abgeschlossene Aktivierung"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Nicht abgeschlossene Deaktivierung"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unbekannte Charakteristik"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Unbekannter Podfehler %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Unbekannter Wert ( %1$@ ) für Typ %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Überprüfung fehlgeschlagen: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Warte, bis der aktuelle Bolus abgegeben wurde, oder unterbreche diesen."; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Warten Sie, bis die aktuelle temporäre Basalrate beendet ist, oder unterbrechen Sie diese"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Warte bis das Einführen der Kanüle fertig ist."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Warten auf Kopplungserinnerung"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, deaktiviere Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, mit aktueller Zeit synchronisieren"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Beginne nun damit, die Erinnerungen zu konfigurieren, Dein Pod mit Insulin zu füllen, ihn mit Deinem Gerät zu koppeln und ihn an Deinem Körper zu platzieren."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Dein Pod ist einsatzbereit.\n\n%1$@ erinnert Dich daran, Deinen Pod zu wechseln, bevor er abläuft. Du kannst eine für Dich passende Zeit wählen."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Ihr Pod gibt möglicherweise immer noch Insulin ab.\nEntfernen Sie ihn vom Körper und tippen dann auf „Weiter“."; - diff --git a/Dependencies/OmniBLE/OmniBLE/cs.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/cs.lproj/Localizable.strings deleted file mode 100644 index b728dd928..000000000 --- a/Dependencies/OmniBLE/OmniBLE/cs.lproj/Localizable.strings +++ /dev/null @@ -1,391 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Zpět"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Bazál inicializován"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Méně než 50 jednotek"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Probíhající bolus"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@ U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusování"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolusování dočasným bazálem"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Zrušit"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanyla byla úspěšně zavedena. Pokračovat."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Zavádění kanyly"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Znamá"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Vyměňte pod. Výdej inzulinu se zastaví 8 hodin poté, co pod vypršel, nebo když už v něm nezbývá žádný inzulín."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Vyměňte pod. Výdej inzulínu se zastaví za %1$@ nebo když dojde inzulín."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Zkontrolujte kanylu"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Zkontrolujte pod, aplikujte na místo a potvrďte umístění podu."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Kontrola zavedení"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Zjišťuji..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Komunikace obnovena"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Ujištující upozornění jsou pípnutí podu, které lze použít k potvrzení zadaných příkazů."; - -/* Section header for configuration section */ -"Configuration" = "Konfigurace"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Pokračovat"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritická upozornění"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Deaktivovat Pod"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktivováno"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktivace."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deaktivuji..."; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Podrobnosti o zařízení"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Vyřadit pod"; - -/* No comment provided by engineer. */ -"Done" = "Hotovo"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Prázdný zásobník"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Prázdná odpověď z podu"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Zaprotokolována událost chyby, vypínám"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Doporučení k vypršení"; - -/* Description for expiration alert */ -"Expiration alert" = "Upozornění na vypršení"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Probíhající prodloužený bolus"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Probíhající prodloužený bolus s dočasným bazálem"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Došlo k chybové události"; - -/* Description for finish setup */ -"Finish setup " = "Dokončení nastavení "; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Připomínka k dokončení nastavení"; - -/* Pod inititialized */ -"Initialized" = "Inicializováno"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Zavádím kanylu"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Podávání inzulínu bylo zastaveno. Vyměňte pod nyní."; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Typ inzulínu"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Interní chyba podu %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Přerušený bolus: %1$@ U ( %2$@ U naplánované) %3$@ %4$@ %5$@"; - -/* description label for last status date pod details row */ -"Last Status" = "Poslední stav"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop automaticky neupraví výdej inzulínu, dokud nastavení dočasné bazální dávky neskončí nebo nebude zrušeno."; - -/* description label for lot number pod details row */ -"Lot Number" = "Číslo šarže"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Poloprázdný zásobník"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Upozornění na poloprázdný zásobník"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Ujistěte se, že váš telefon a pod jsou blízko sebe. Pokud problémy s komunikací přetrvávají, zkuste přesunutí na jiné místo."; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Chybějící konfigurace"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "Není k dispozici"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Další"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Ne"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Žádný inzulín"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Žádný pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Žádné upozornění"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Nastavení upozornění"; - -/* No comment provided by engineer. */ -"Numbers" = "Hodnoty"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Upozornění Omnipodu"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Spárovat pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Spárovat pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Páruji."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod je pozastaven"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Platnost okna nastavení podu vypršela"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pozastavená upozornění podu"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Připravuji"; - -/* Pod state when priming completed */ -"Priming completed" = "Příprava dokončena"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Připraveno k programování bazálu"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Připraven k zavedení kanyly"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Upozornění inicializováno"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Obnovit podávání inzulínu"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Pokračovat: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Obnovování podávání inzulínu..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Zkusit znovu"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Uložit"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Ukládám..."; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Plánovaný bazál"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Plánovaný bazál"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Naplánované upozornění"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Vyberte typ inzulinu, který budete v tomto Podu používat."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Pořadové číslo"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Nastavit dočasný bazál"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Nastavení dokončeno"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Vypnutí blížícího "; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Vypnutí blížícího se alarmu"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Ztráta signálu"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Přeskočit onboarding Omnipodu?"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Pozastavit podávání inzulínu..."; - -/* Description for suspend time expired */ -"Suspend time expired" = "Období pozastavení vypršelo"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Pozastavit: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Pozastaveno"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Pozastavení podávání inzulínu..."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Plnění zásobníku dokončeno"; - -/* Pod power to motor activated */ -"Tank power activated" = "Napájení zásobníku aktivováno"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Klepnutím na tlačítko níže zahájíte zavádění kanyly."; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Dočasný bazál v platnosti"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Dočasný bazál v platnosti"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "DočBazál: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Dočasný bazál"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Nastavení dočasného bazálu selhalo"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Aplikace vás předem upozorní na vypršení platnosti Podu. \n\nPosouváním nastavte počet hodin před vypršením, kdy chcete obdržet notifikaci."; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Čas vyměnit pod! Platnost vašeho podu vyprší za %1$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Nejasné"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Neočekávané pořadové číslo zprávy"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Neočekávaná odpověď od podu"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Neznámá chyba podu %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Neznámá hodnota ( %1$@ ) pro typ %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Ověření se nezdařilo: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Počkejte na dokončení podávání stávajícího bolusu nebo bolus zrušte"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Počkejte na dokončení stávajícího dočasného bazálu nebo ho pozastavte pro zrušení."; - diff --git a/Dependencies/OmniBLE/OmniBLE/da.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/da.lproj/Localizable.strings deleted file mode 100644 index e04b4b4ec..000000000 --- a/Dependencies/OmniBLE/OmniBLE/da.lproj/Localizable.strings +++ /dev/null @@ -1,1127 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inaktiv)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ siden"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ har genoprettet kommunikationen med Pod'en på din krop.\n\nHistorik for insulintilførsel er blevet opdateret og skal matche det, der faktisk er leveret.\n\nDu kan fortsætte med at bruge %@ normalt nu."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ E"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ har ikke været i stand til at kommunikere med Pod'en på din krop siden %2$@.\n\nUden kommunikation med Pod'en kan appen ikke fortsætte med at sende kommandoer for insulintilførsel eller vise nøjagtige, nylige oplysninger om dit aktive insulin eller det insulin, der leveres af Pod'en.\n\nOvervåg din glukose nøje i de næste 6 eller flere timer, da der måske eller måske ikke er insulin, der aktivt arbejder i din krop, som %3$@ ikke kan vise."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin eller mindre tilbage i Pod. Skift Pod snart."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ enheder tilbage på %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g E"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 time"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 time 30 minutter"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 timer"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutter"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Aktiveringstid overskredet"; - -/* description label for active time pod details row */ -"Active Time" = "Aktiv tid"; - -/* Section header for activity section */ -"Activity" = "Aktivitet"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Justerer pumpetid..."; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Er du sikker på, at du vil annullere Pod-opsætningen?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Er du sikker på, at du vil springe Omnipod Onboarding over?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Er du sikker på, at du vil stoppe med at bruge Omnipod DASH?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Påfør Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Forsøger at genetablere kommunikationen"; - -/* Description for auto-off */ -"Auto-off" = "Auto-sluk"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-sluk alarm"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Tilbage"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialiseret"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Under 50 enheder"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth er slukket"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Bluetooth nulstilles"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth er ikke tilgængelig af en ukendt årsag."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth ikke tilgængelig: %1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "Brug af Bluetooth er uautoriseret"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "Bluetooth understøttes ikke på denne enhed"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus i gang"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@E %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Indgiver bolus"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Indgiver bolus med midlertidig basal"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Annuller"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Annuller manuel basal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanylen blev indsat korrekt. Fortsæt."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Indfører kanyle"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Sikker"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Skift Pod nu. Insulintilførsel stopper 8 timer efter, at Pod'en er udløbet, eller når der ikke er mere insulin tilbage."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Skift Pod nu. Insulintilførsel stopper om %1$@, eller når der ikke er mere insulin tilbage."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Skift Pod nu. Insulintilførsel stopper om 1 time."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Skift Pod nu. Pod har været aktiv i 72 timer."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Kontroller kanylen"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Tjek Pod, sæt på kroppen og bekræft derefter Pod er sat korrekt på."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Kontrollerer indsættelse"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Kontrollerer..."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Kommandofejl %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Kommunikationsproblem"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Kommunikation genoprettet"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Kommunikationsproblem: Uerkendt kommando afventer."; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Påmindelse om succesfulde aktiviteter"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Påmindelse om succesfulde aktiviteter er bip fra Pod'en, som kan bruges til at bekræfte valgte kommandoer."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Påmindelser om succesfulde handlinger vil lyde for de kommandoer du sætter igang, annulleret, suspenderet, genoptaget bolus, gemme notifikationspåmindelser etc. Når Loop automatisk justerer tilførslen, bliver påmindelser om succesfulde handlinger ikke benyttet."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Påmindelser om succesfulde handlinger vil lyde, når Loop automatisk justerer tilførslen og de kommandoer, du sætter igang."; - -/* Section header for configuration section */ -"Configuration" = "Konfiguration"; - -/* Button title for confirm attachment option */ -"Confirm" = "Bekræft"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bekræft fastgørelse af Pod"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Fortsæt"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "Kunne ikke analysere meddelelsen: %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritiske advarsler"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritisk Pod-fejl"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Kommunikationsfejl. Flyt til et nyt område"; - -/* Unit for singular day in pod life remaining */ -"day" = "dag"; - -/* Unit for plural days in pod life remaining */ -"days" = "dage"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Deaktiver Pod"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktiveret"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktiverer."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deaktiverer..."; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Slet Omnipod DASH"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Enhedsdetaljer"; - -/* description label for device name pod details row */ -"Device Name" = "Enhedsnavn"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Deaktiveret"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Kassér Pod"; - -/* No comment provided by engineer. */ -"Done" = "Udført"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Tomt reservoir"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Tomt reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Tomt svar fra Pod"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Tom værdi"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Aktiveret"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Fejl"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Fejlhændelse logget, lukker ned"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Påmindelse om udløb"; - -/* Description for expiration alert */ -"Expiration alert" = "Udløbs-advarsel"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Påmindelse om udløb"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standard for udløbspåmindelse"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Forlænget"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Forlænget bolus kører"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Forlænget bolus med midlertidig basal"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Kunne ikke annullere manuel basal"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Kunne ikke genoptage insulintilførsel"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Kunne ikke indstille pumpetid"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Kunne ikke suspendere insulintilførsel"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Kunne ikke opdatere påmindelser for succesfulde aktiviteter"; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Kunne ikke opdatere påmindelse om udløb"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Kunne ikke opdatere påmindelse om lavt reservoir"; - -/* Pod life HUD view label */ -"Fault" = "Fejl"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fejlhændelse indtraf"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Fyld en ny pod med E-100 insulin (lad den blå hætte på podnålen sidde på)."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Afslut deaktivering"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Afslut deaktivering"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Afslut parring"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Afslut setup"; - -/* Description for finish setup */ -"Finish setup " = "Afslut opsætning"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Påmindelse om færdiggørelse af opsætning"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware-version"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Flere end %1$@ enheder tilbage ved %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "time"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "Timer"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Hvis du annullerer Pod-opsætningen, deaktiveres den aktuelle Pod og den vil være ubrugelig."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Forkert pakkeundtagelse: %1$@ (placering=%2$d)"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Forkert svar"; - -/* Pod inititialized */ -"Initialized" = "Initialiseret"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Indfør kanyle"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Indsat"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Indsætter kanyle"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Indsætter. Vent venligst."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Indsætter..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin \nsuspenderet"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulintilførsel"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulintilførslen er stoppet. Skift Pod nu."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulintilførsel vil blive stoppet, indtil du genoptager manuelt. Hvornår vil du have Loop til at minde dig om at genoptage leveringen?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin tilbage"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin suspenderet"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulintype"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulintype ikke konfigureret"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Intern Pod-fejl %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "AfbrudtBolus: %1$@ E (%2$@ E planlagt) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Ugyldig adresse 0x%1$x. Forventet 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Ugyldig adresse: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Ugyldig CRC"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Ugyldig LTK-nøgle: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ugyldig indstilling"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Er kanylen indsat korrekt?"; - -/* description label for last status date pod details row */ -"Last Status" = "Sidste status"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Lyt efter 2 bip."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop justerer ikke automatisk din insulindosering, før den midlertidige basalrate er afsluttet eller annulleret."; - -/* description label for lot number pod details row */ -"Lot Number" = "Partinummer"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Lavt reservoir"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Lavt reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Vejledning om lavt reservoir (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Lavt reservoir alarm"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Påmindelse om lavt reservoir"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Sørg for, at iPhone er i nærheden af den aktive Pod"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Sørg for, at din telefon og Pod er tæt på hinanden. Hvis der fortsat er kommunikationsproblemer, skal du flytte til et nyt område."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Sørg for din Pod er fyldt og i nærheden"; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Sørg for, at din Pod er tæt på og prøv igen."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Sørg for, at din RileyLink er i nærheden og tændt"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual basal"; - -/* Pod memory initialized */ -"Memory initialized" = "Hukommelse initialiseret"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Meddelelse IO-undtagelse: %1$@"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minut"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutter"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Manglende konfiguration"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Flyt til et nyt område væk fra andre Pods og prøv igen."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Advarsel om flere kommandoer"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NA"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Næste"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nej"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Ingen\nlevering"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Ingen alarmer"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Ingen påmindelser for succesfulde aktiviteter benyttet"; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Ingen fejl"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Ingen insulin"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Ingen Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Ingen Pod parret"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Ingen Pods fundet"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Ingen påmindelse"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Intet svar fra Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Ingen RileyLink til stede"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nej, fortsæt med Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nej, behold pumpen som den er"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Ikke nok data"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Notifikationsindstillinger"; - -/* No comment provided by engineer. */ -"Numbers" = "Tal"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Blokkering opdaget"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Blokkering opdaget"; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod-påmindelser"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Par Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Par Pod"; - -/* Pod status after pairing */ -"Paired" = "Parret"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Parring afsluttet"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Parringsundtagelse: %1$@"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Parrer..."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Parrer..."; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Indlæsningfejl: %1$@ i %2$@"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = "Payload crc32 %1$@ does not match computed crc32 %2$@"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Procent = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Ekstern enhed er ikke forbundet"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Hav kun den originale Pod tæt på eller deaktiver den original Pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Venligst flyt Pod’en tættere på din RileyLink og prøv igen"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Bekræft venligst, at Pod er sikkert fastgjort til din krop.\n\nKanylen kan kun indsættes én gang med hver Pod. Tryk på \"Bekræft\", når Pod er tilsluttet."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Deaktiver Poden. Når deaktiveringen er fuldført, kan du parre en ny Pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Deaktiver Poden. Når deaktiveringen er fuldført, kan du fjerne den og parre en ny Pod."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Aktivér Bluetooth-tilladelser for denne app i systemindstillinger"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Afslut parringen af din Pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Venligst par med en ny Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Flyt iPhone længere væk fra Poden"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Flyt iPhone i forhold til Pod'en"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Brug en anden enhed med Bluetooth-funktioner"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod aktiveret"; - -/* Label describing pod age view */ -"Pod Age" = "Pod-alder"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod allerede parret"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod allerede klargjort"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deaktiveret med succes. Fortsæt."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Pod-fejl"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod udløbsalarm"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod udløbspåmindelse"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Påmindelse om udløb af Pod"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod udløbet"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod udløbet"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod udløber"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod udløber om"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod udløber om %1$@."; - -/* description label for pod fault details */ -"Pod Fault Details" = "Detaljer om fejl i Pod"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod Fejl: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod er ikke klar til kanyleindførsel."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod er ikke parat til klargøring."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod er pauset"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "Pod ikke tilsluttet"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod er blokeret"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod'en blev parret med succes. Fortsæt."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod-parring ufuldstændig"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sendt acknowledge i stedet for svar"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pod indstillingsvindue udløbet"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Påmindelse om suspenderet Pod "; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Dårlig signalstyrke"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Forbered indstikssted."; - -/* title for previous pod page */ -"Previous Pod" = "Forrige Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Oplysninger om forrige Pod"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Klargør"; - -/* Pod state when priming completed */ -"Priming completed" = "Klargøring afsluttet"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Klargør. Vent venligst."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Klargør…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pumpetid"; - -/* Label text for basal rate summary */ -"Rate" = "Rate"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Klar til basal-indstilling"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Klar til kanyleindførsel"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Tilbage"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Påmindelse initialiseret"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Fjern den blå Pod-nålehætte, og kontrollér kanylen. Fjern derefter papiret."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Fjern Pod fra kroppen"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Fjern pumpe"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Udskift Pod"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Genoptag"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Fortsæt indgivelse"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Genoptag insulin"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Genoptag insulintilførsel..."; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Fortsæt: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Genoptager insulintilførsel..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Forsøg igen"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Gem"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Gemmer..."; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Planlagt basal"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Planlagt basal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Planlagt påmindelse"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Vælg den type insulin, du vil bruge i denne Pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sekvensnummer"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Indstil midlertidig basal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Indstil midlertidig basalrate"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Opsætning fuldført"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Luk akut"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Afbryd akut alarm"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signaltab"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signalstyrken er for høj"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Spring Omnipod Onboarding over?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspender"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Afbryd insulintilførsel"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Påmindelse om igangværende suspension"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Afbryd insulintilførsel"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Suspenderet tid udløbet"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Pause: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspenderet"; - -/* Label for suspended at time */ -"Suspended At" = "Suspenderet"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Afbryder insulintilførsel..."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspensionstiden er udløbet. Åbn appen, og genoptag."; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Skift til en anden insulintilførselsenhed"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synkroniser til aktuel tid"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Reservoirpåfyldning færdig"; - -/* Pod power to motor activated */ -"Tank power activated" = "Reservoir-strøm aktiveret"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tryk nedenfor for at starte kanyleindsættelse."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Midlertidig basal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Midlertidig basal allerede i gang"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Midlertidig basal i gang"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "Midlertidig basal: %1$@ E/time %2$@ %3$@ %4$@ E %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Midlertidig basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Midlertidig basal mislykkedes"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Appen konfigurerer en påmindelse på Pod'en for at give dig besked inden Pod-udløb. Indstil antallet af timer i forvejen, du vil konfigurere, når du parrer en ny Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Appen giver dig besked før Pod'en udløber.\n\nIndstil antallet af timer før udløb som påmindelse."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Appen giver dig besked, når mængden af insulin i Pod'en når dette niveau (50-10 E)\n\nIndstil antallet enheder, du vil bruge som påmindelse. "; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Appen giver dig besked, når mængden af insulin i Pod'en når dette niveau."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Perioden for suspension af insulin er afsluttet.\n\nDu kan genoptage afgivelsen fra den øverste del af startskærmen eller fra skærmen med pumpeindstillinger. Du vil blive mindet om dette igen om 15 minutter."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Tiden på din pumpe er forskellig fra den aktuelle tid. Vil du opdatere tiden på din pumpe til det aktuelle tidspunkt?"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Tiden på din pumpe er forskellig fra den aktuelle tid. Din pumpes tid styrer dine planlagte behandlingsindstillinger. Gå til Pumpetid for at gennemgå tidsforskellen og konfigurere din pumpe."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Tiden på din pumpe er forskellig fra den aktuelle tid. Din pumpes tid styrer dine planlagte behandlingsindstillinger. Gå til Pumpetid for at gennemgå tidsforskellen og konfigurere din pumpe."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Vinduet på toppen af Pod'en skal være farvet pink, når kanylen er korrekt indsat i huden."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Kunne ikke kommunikere med Pod'en. Hvis problemet fortsætter, tryk Afbryd og kassér Pod'en. Du kan herefter aktivere en ny Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dette er en påmindelse om, at du planlagde, hvornår du parrede din nuværende Pod."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Denne PumpManager er ikke konfigureret med en maksimal basalhastighed, fordi den blev tilføjet, før manuel midlertidig basal var en funktion. Gå til Behandlingsindstillinger -> leveringsgrænser og indstil en ny maksimal basalhastighed."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Tid"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Tidsændring registreret"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Tid til udskiftning af Pod! Din Pod udløber om %1$@"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Skift tegn"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Der er fundet for mange Pods"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Samlet indgivelse"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Prøv igen"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Slå bluetooth til"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "E/t"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Kan ikke få kontakt til pumpen"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Kan ikke få kontakt til pumpen"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Kan ikke indstille en midlertidig basalrate: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Kan ikke indstille en midlertidig basalrate: %1$@\n\n%2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Usikker"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Uventet meddelelsessekvensnummer"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Uventet Pod-skifte"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Uventet svar fra Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Uafsluttet aktivering"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Uafsluttet deaktivering"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Ukendt egenskab"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Ukendt Podfejl %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Ukendt værdi (%1$@) for type %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validering mislykkedes: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Vent, indtil eksisterende bolus er færdig, eller annuller bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Vent, indtil den eksisterende midlertidige basal er færdig, eller pause for at annullere"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Vent, indtil indsættelsen er afsluttet."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Venter på parrings-påmindelse"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, deaktiver Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, synkroniser til det aktuelle klokkeslæt"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Du skal nu begynde at konfigurere dine påmindelser, fylde din Pod med insulin, parre den med din enhed og placere den på din krop."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Din pod er klar til brug.\n\n%1$@ minder dig om, at du skal skifte din pod, inden den udløber. Du kan ændre dette til et tidspunkt, der passer dig."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Din Pod leverer muligvis stadig insulin.\nFjern den fra din krop og tryk derefter på \"Fortsæt\"."; - diff --git a/Dependencies/OmniBLE/OmniBLE/de.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/de.lproj/Localizable.strings deleted file mode 100644 index 5d7776566..000000000 --- a/Dependencies/OmniBLE/OmniBLE/de.lproj/Localizable.strings +++ /dev/null @@ -1,1132 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inaktiv)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ vor"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ hat die Kommunikation mit dem Pod an Ihrem Körper wiederhergestellt.\n\nDie Insulinabgabeaufzeichnungen wurden aktualisiert und sollten mit dem übereinstimmen, was tatsächlich abgegeben wurde.\n\nSie können %@ jetzt normal weiter verwenden."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ IE"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ für %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ konnte seit %2$@ nicht mehr mit Ihrem Pod kommunizieren.\n\nOhne Kommunikation mit dem Pod kann die App keine Befehle für die Insulinabgabe senden oder genaue, aktuelle Informationen über Ihr aktives Insulin oder das vom Pod abgegebene Insulin anzeigen.\n\nÜberwachen Sie Ihren Blutzucker für die nächsten 6 oder mehr Stunden genau, da in Ihrem Körper Insulin aktiv sein kann oder auch nicht, das %3$@ nicht anzeigen kann."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ Insulin oder weniger verbleibend im Pod. Pod bald wechseln."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ IE verbleibend bei %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g IE"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 Stunde"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 Stunde 30 Minuten"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 Stunden"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 Minuten"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Aktivierungszeit überschritten"; - -/* description label for active time pod details row */ -"Active Time" = "Laufzeit"; - -/* Section header for activity section */ -"Activity" = "Aktivität"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pumpenzeit einstellen"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Sind Sie sicher, dass Sie die Pod-Einrichtung abbrechen möchten?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Sind Sie sicher, dass Sie das Omnipod Onboarding überspringen wollen?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Sind Sie sicher, dass Sie keinen Omnipod DASH mehr benutzen möchten?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Pod anbringen"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Versuche die Verbindung wieder aufzubauen"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-Off Alarm"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Zurück"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialisiert"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Weniger als 50 Einheiten"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth ist ausgeschaltet"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Bluetooth wird zurückgesetzt"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth ist aus einem unbekannten Grund nicht verfügbar."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth ist nicht verfügbar: %1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "Bluetooth-Nutzung ist nicht erlaubt"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "Bluetooth-Verwendung wird auf diesem Gerät nicht unterstützt"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolusabgabe läuft "; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@IE %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusabgabe"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolus-Abgabe mit temporärer Basalrate"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Abbrechen"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Manuelles Basal abbrechen"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanüle erfolgreich eingeführt. Weiter."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Einsetzen der Kanüle"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Sicher"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Pod jetzt wechseln. Die Insulinabgabe stoppt 8 Stunden nach Ablauf des Pods oder wenn kein Insulin mehr vorhanden ist."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Pod jetzt wechseln. Die Insulinabgabe stoppt in %1$@ oder wenn kein Insulin mehr vorhanden ist."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Pod jetzt wechseln. Die Insulinabgabe stoppt in 1 Stunde."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Pod jetzt wechseln. Der Pod ist seit 72 Stunden aktiv."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Prüfe die Kanüle"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Überprüfe den Pod, bringe ihn an und bestätige dann die Pod-Anbringung."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Prüfe die Einfügung"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Prüfe…"; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Befehlsfehler %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Problem"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Kommunikation wiederhergestellt"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Kommunikationsproblem: Unbestätigter Befehl steht noch aus."; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Sicherheitserinnerung"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Vertrauenserinnerungen sind Pieptöne vom Pod, die verwendet werden können, um ausgewählte Befehle zu bestätigen."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Vertrauenserinnerungen ertönen für von Ihnen initiierte Befehle, wie Bolus, Bolus abbrechen, Unterbrechen, Fortsetzen, Benachrichtigungserinnerungen speichern usw. Wenn Loop die Abgabe automatisch anpasst, werden keine Vertrauenserinnerungen verwendet."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Vertrauenserinnerungen ertönen, wenn Loop die Lieferung automatisch anpasst, sowie für von Ihnen initiierte Befehle."; - -/* Section header for configuration section */ -"Configuration" = "Konfiguration"; - -/* Button title for confirm attachment option */ -"Confirm" = "Bestätige"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bestätige Pod Befestigung"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Weiter"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "Nachrichte konnte nicht analysiert werden: %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritische Warnungen"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritischer Pod-Fehler"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Überlagerungen möglich. Bitte wechseln Sie an einen neuen Standort"; - -/* Unit for singular day in pod life remaining */ -"day" = "Tag"; - -/* Unit for plural days in pod life remaining */ -"days" = "Tage"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Pod deaktivieren"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktiviert"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktiviere."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deaktiviere…"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Omnipod DASH löschen"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Gerätedetails"; - -/* description label for device name pod details row */ -"Device Name" = "Gerätename"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Ausgeschaltet"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Pod verwerfen"; - -/* No comment provided by engineer. */ -"Done" = "Fertig"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Reservoir leer"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Leeres Reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Leere Antwort vom Pod"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Leerer Wert"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Aktiviert"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Fehler"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Fehlerereignis protokolliert, fahre herunter"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Ablaufhinweis"; - -/* Description for expiration alert */ -"Expiration alert" = "Ablaufalarm"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Erinnerung an den Ablauf der Nutzungsdauer"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standard Erinnerung an den Ablauf der Nutzungsdauer"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Verzögerung"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Verzögerter Bolus aktiv"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Verzögerter Bolus mit temporärer Basalrate aktiv"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Fehler beim Abbrechen der manuellen Basalrate"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Wiederaufnahme der Insulinabgabe fehlgeschlagen"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Fehler beim Einstellen der Pumpenzeit"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Fehler beim Anhalten der Insulinabgabe"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Fehler beim Aktualisieren der Einstellung für die Sicherheitserinnerung."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Fehler beim Aktualisieren der Ablauferinnerung"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Fehler beim Aktualisieren der Erinnerung für einen niedrigen Vorratsbehälter"; - -/* Pod life HUD view label */ -"Fault" = "Störung"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fehlerereignis aufgetreten"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Fülle U-100 Insulin in den Pod (lasse die blaue Kappe drauf)"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Deaktivierung abschließen"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Deaktivierung abgeschlossen"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Kopplung abgeschlossen"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Einrichtung abschließen"; - -/* Description for finish setup */ -"Finish setup " = "Einrichtung abgeschlossen"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Einrichtungserinnerung abgeschlossen"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Mehr als %1$@ verbleibende Einheiten um %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "Stunde"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "Stunden"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Wenn Du die Einrichtung abbrichst, dann wird der Pod deaktiviert und unbrauchbar."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Incorrect Packet Exception: %1$@ (location=%2$d)"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Falsche Antwort"; - -/* Pod inititialized */ -"Initialized" = "Initialisiert"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Kanüle einsetzen"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Eingeführt"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Einfügen von Kanüle"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Füge ein, bitte warte…"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Füge ein…"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulinabgabe\nunterbrochen"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulinabgabe wurde gestoppt. Pod jetzt wechseln."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Die Insulinabgabe wird angehalten, bis Sie sie manuell wieder aufnehmen. Wann soll Loop Sie daran erinnern, die Abgabe fortzusetzen?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Verbleibendes Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulinabgabe unterbrochen"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulintyp"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulintyp nicht konfiguriert"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Interner Podfehler %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Abgebrochener Bolus: %1$@ IE (%2$@ IE geplant) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Ungültige Adresse (%1$x). Adresse %2$x erwartet"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Ungültige Adresse (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Ungültiger CRC"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Invalid LTK Key: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ungültige Einstellung"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Wurde der Katheter ordentlich eingeführt?"; - -/* description label for last status date pod details row */ -"Last Status" = "Letzter Status"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Achte auf zwei Pieptöne."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop passt Ihre Insulinabgabe nicht automatisch an, bis die temporäre Basalrate beendet oder abgebrochen wurde."; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Niedriges Reservoir"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Niedriges Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Hinweis auf niedriges Reservior (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Hinweisalarm für fast leeres Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Erinnerung an niedriges Reservoir"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Stellen Sie sicher, dass Ihr iPhone nah am Pod ist"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Stellen Sie sicher, dass sich Ihr iPhone und Ihr Pod nahe beieinander befinden. Wenn die Kommunikationsprobleme bestehen bleiben, dann gehen Sie an einen anderen Ort."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Stellen Sie sicher, dass Ihr Pod gefüllt und in der Nähe ist."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Stellen Sie sicher, dass sich Ihr Pod in der Nähe befindet, und versuchen Sie es erneut."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Stellen Sie sicher, dass sich Ihr RileyLink in der Nähe befindet und eingeschaltet ist"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuelle Basalrate"; - -/* Pod memory initialized */ -"Memory initialized" = "Speicher initialisiert"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Message IO Exception: %1$@"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "Minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "Minuten"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Fehlende Konfiguration"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Begeben Sie sich in einen anderen Bereich, entfernt von anderen Pods und versuchen Sie es erneut."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Warnung bei mehreren Befehlen"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "nicht bestätigt"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Weiter"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nein"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Keine\nAbgabe"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Keine Alarme"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Es werden keine Sicherheitserinnerungen verwendet."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Keine Fehler"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Kein Insulin"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Kein Pod gekoppelt"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Kein Pod gekoppelt"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Keine Pods gefunden"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Keine Erinnerung"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Keine Rückmeldung vom Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Kein RileyLink verfügbar"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nein, mit Pod fortfahren"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nein, Pumpe so lassen wie sie ist"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Nicht genügend Daten"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Benachrichtigungseinstellungen"; - -/* No comment provided by engineer. */ -"Numbers" = "Zahlen"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Verstopfung erkannt"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Verstopfung erkannt"; - -/* Action button default text for PodAlerts */ -"Ok" = "OK"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Erinnerung"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pod koppeln"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pod koppeln."; - -/* Pod status after pairing */ -"Paired" = "Gekoppelt"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Kopplung abgeschlossen"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Kopplungsausnahme: %1$@"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Koppeln"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Koppeln…"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing-Fehler: %1$@ in (%2$@)"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = "Payload crc32 %1$@ does not match computed crc32 %2$@"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percent = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheriegerät nicht bereit"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Bitte nur Original-Pod in Reichweite bringen oder Original-Pod deaktivieren"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Bitte bringen Sie Ihren Pod näher an Ihr RileyLink und versuchen Sie es erneut"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Bitte vergewissern Sie sich, dass der Pod sicher an Ihrem Körper befestigt ist.\n\nDer Katheter kann mit jedem Pod nur einmal eingeführt werden. Tippen Sie auf „Bestätigen“, wenn der Pod angeschlossen ist."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Bitte deaktivieren Sie den Pod. Wenn die Deaktivierung abgeschlossen ist, können Sie einen neuen Pod koppeln."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Bitte deaktivieren Sie den Pod. Wenn die Deaktivierung abgeschlossen ist, können Sie ihn entfernen und einen neuen Pod koppeln."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Bitte aktiviere die Bluetooth-Berechtigungen für diese App in den Systemeinstellungen"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Bitte schließen Sie die Kopplung Ihres Pods ab."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Bitte koppel einen neuen Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Bitte positionieren Sie das iPhone weiter vom Pod entfernt"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Bitte positionieren Sie das iPhone relativ zum Pod neu"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Bitte verwenden Sie ein anderes Gerät mit Bluetooth-Funktion"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod aktiviert"; - -/* Label describing pod age view */ -"Pod Age" = "Pod-Alter"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod bereits gekoppelt"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod bereits gefüllt"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod erfolgreich deaktiviert. Weiter."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Pod-Fehler"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Ablaufalarm des Pods"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Hinweis zum Ablaufen des Pods"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod-Ablauferinnerung"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod abgelaufen"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod abgelaufen"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod läuft ab"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod läufen ab in"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod läuft in %1$@ ab."; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fehlerdetails"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Podfehler: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Der Pod ist nicht bereit zum Einführen der Kanüle."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Der Pod ist nicht bereit zum Befüllen."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod ist angehalten"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "Pod nicht verbunden"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Verstopfung"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod erfolgreich gekoppelt. Weiter."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod-Kopplung unvollständig"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sendet Bestätigung anstelle von Antwort"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Einrichtung"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Das Zeitfenster für die Pod-Einrichtung ist abgelaufen"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Erinnerung über abgelaufenen Pod "; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Schlechte Signalstärke"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Stelle vorbereiten."; - -/* title for previous pod page */ -"Previous Pod" = "Vorheriger Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informationen über den letzten Pod"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Befüllen"; - -/* Pod state when priming completed */ -"Priming completed" = "Befüllen des Pods abgeschlossen"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Befülle, bitte warte."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Befülle…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Uhrzeit der Pumpe"; - -/* Label text for basal rate summary */ -"Rate" = "Rate"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Bereit für die Programmierung der Basalrate"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Bereit zum Einführen der Kanüle"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Verbleibend"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Erinnerung initialisiert"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Entfernte die blaue Kappe und überprüfe den Katheter. Dann entferne das Papier."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Entferne den Pod vom Körper"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Pumpe löschen"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Pod ersetzen"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Fortsetzen"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Insulinabgabe fortsetzen"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Insulinabgabe fortsetzen"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Insulinabgabe wiederaufnehmen"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Fortsetzen: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Nehme Insulinabgabe wieder auf…"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Wiederholen"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Speichern"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Speichere…"; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Geplante Basalrate"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Geplante Basalrate"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Geplante Erinnerung"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Wähle die Insulinart aus, die Du für diesen Pod benutzen möchtest."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequenznummer"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Temporäre Basalrate setzen"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Temporärere Basalrate setzen"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Einrichtung abgeschlossen"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Pod-Abschaltung steht bevor"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarm für die bevorstehende Pod-Abschaltung"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signalverlust"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signalstärke ist zu hoch"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Omnipod-Onboarding überspringen?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Unterbrechen"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Abgabe unterbrechen"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Unterbrechungsfortschritts-Erinnerung"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Insulinabgabe unterbrechen"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Unterbrechungszeit abgelaufen"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Unterbrochen: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Unterbrochen"; - -/* Label for suspended at time */ -"Suspended At" = "Unterbrochen um"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Unterbreche die Insulinabgabe…"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Die Unterbrechungszeit ist abgelaufen. Öffnen Sie die App und fahren Sie fort."; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Zu einer anderen Pumpe wechseln"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Mit aktueller Uhrzeit synchronisieren."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Befüllen des Pods erfolgreich"; - -/* Pod power to motor activated */ -"Tank power activated" = "Energieversorgung für den Podmotor aktiviert"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tippe unten, um das Einführen der Kanüle zu starten."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temporäre Basalrate"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temporäre Basalrate läuft bereits."; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temporäre Basalrate läuft"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ IE/h %2$@ %3$@ %4$@ IE %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporäre Basalrate"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal fehlgeschlagen"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Die App konfiguriert eine Erinnerung auf dem Pod, um Dich vor Ablauf des Pods zu benachrichtigen. Legen die Anzahl der Stunden fest, die Du vor Ablauf des Pods benachrichtigt werden möchtest."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Die App benachrichtigt Dich vor Ablauf des Pods.\n\nScrolle, um die gewünschte Anzahl von Stunden im Voraus festzulegen."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Die App benachrichtigt Dich, wenn die Insulinmenge im Pod diesen Wert erreicht (50-10 IE).\n\nScrolle, um die Anzahl der Einheiten festzulegen, bei der Du erinnert werden möchtest."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Die App benachrichtigt Dich, wenn die Insulinmenge im Pod diesen Wert erreicht."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Die Insulinabschaltung ist beendet.\n\nSie können die Abgabe über das Banner auf dem Startbildschirm oder über den Bildschirm mit den Pumpeneinstellungen fortsetzen. Sie werden in 15 Minuten erneut erinnert."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Die obigen Erinnerungen ertönen nicht, wenn sich Dein Gerät im Lautlos- oder Nicht-Stören-Modus befindet.\n\nEs gibt andere kritische Pod-Warnungen und -Alarme, die auch dann ertönen, wenn Dein Gerät auf „Lautlos“ oder „Nicht stören“ eingestellt ist."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Die Uhrzeit Ihrer Pumpe unterscheidet sich von Ihrer aktuellen Uhrzeit. Möchten Sie die Uhrzeit Ihrer Pumpe auf Ihre aktuelle Uhrzeit aktualisieren?"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Die Uhrzeit Ihrer Pumpe weicht von der aktuellen Uhrzeit ab. Sie können die Uhrzeit der Pumpe überprüfen und in den Einstellungen mit der aktuellen Uhrzeit synchronisieren."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Die Uhrzeit der Pumpe weicht von der aktuellen Uhrzeit ab. Die Zeit der Pumpe steuert die geplanten Therapieeinstellungen. Scrolle nach unten zur Zeile Pumpenzeit, um den Zeitunterschied zu überprüfen und die Pumpe zu konfigurieren."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Das Fenster oben auf dem Pod sollte pinkfarben sein, wenn der Katheter ordentlich in die Haut eingeführt wurde."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Es gab ein Problem bei der Kommunikation mit dem Pod. Wenn dieses Problem weiterhin besteht, tippen Sie auf \"Pod verwerfen\". Sie können dann einen neuen Pod aktivieren."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dies ist eine Erinnerung, die Du beim Koppeln Deines aktuellen Pods eingestellt hast."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Dieser Pumpenmanager wurde nicht mit einer maximalen Basalrate konfiguriert, da er hinzugefügt wurde, bevor die Funktion manuelle temporäre Basalrate hinzugefügt wurde. Bitte gehe zu Therapieeinstellungen -> Abgabegrenzen und stelle eine neue maximale Basalrate ein."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Zeit"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Änderung der Uhrzeit erkannt"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Es ist Zeit Ihren Pod zu wechseln! Der Pod läuft ab in %1$@"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Zeitüberschreitung"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Zeichen umschalten"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Zu viele Pods in Reichweite"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Gesamt Abgabe"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Versuchen Sie es erneut"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Schalte Bluetooth ein"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "IE/h"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Pod kann nicht erreicht werden"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Pod kann nicht erreicht werden"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Eine temporäre Basalrate kann nicht gesetzt werden: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Eine temporäre Basalrate kann nicht gesetzt werden: %1$@\n\n%2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Unsicher"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Unerwartete Sequenznummer der Nachricht"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Unerwarteter Podwechsel"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Unerwartete Antwort vom Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Nicht abgeschlossene Aktivierung"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Nicht abgeschlossene Deaktivierung"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unbekannte Charakteristik"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Unbekannter Podfehler %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Unbekannter Wert ( %1$@ ) für Typ %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Überprüfung fehlgeschlagen: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Warte, bis der aktuelle Bolus abgegeben wurde, oder unterbreche diesen."; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Warten Sie, bis die aktuelle temporäre Basalrate beendet ist, oder unterbrechen Sie diese"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Warte bis das Einführen der Kanüle fertig ist."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Warten auf Kopplungserinnerung"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, deaktiviere Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, mit aktueller Zeit synchronisieren"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Beginne nun damit, die Erinnerungen zu konfigurieren, Dein Pod mit Insulin zu füllen, ihn mit Deinem Gerät zu koppeln und ihn an Deinem Körper zu platzieren."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Dein Pod ist einsatzbereit.\n\n%1$@ erinnert Dich daran, Deinen Pod zu wechseln, bevor er abläuft. Du kannst eine für Dich passende Zeit wählen."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Ihr Pod gibt möglicherweise immer noch Insulin ab.\nEntfernen Sie ihn vom Körper und tippen dann auf „Weiter“."; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; diff --git a/Dependencies/OmniBLE/OmniBLE/en.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/en.lproj/Localizable.strings deleted file mode 100644 index fba519ffe..000000000 --- a/Dependencies/OmniBLE/OmniBLE/en.lproj/Localizable.strings +++ /dev/null @@ -1,184 +0,0 @@ -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-off alarm"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Below 50 units"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusing"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolusing with temp basal"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Cannula inserting"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Certain"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Empty reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Empty response from pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Error event logged, shutting down"; - -/* Description for expiration alert */ -"Expiration alert" = "Expiration alert"; - -/* Description for finish setup */ -"Finish setup " = "Finish setup "; - -/* Pod inititialized */ -"Initialized" = "Initialized"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Internal pod fault %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Low reservoir advisory alarm"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "No alerts"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "No response from pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "No RileyLink available"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Occlusion detected"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Paired"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Please bring your pod closer to the RileyLink and try again"; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod already primed"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod expiration advisory alarm"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod Expiration Notice"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod expired"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod Fault: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod is not in a state ready for priming."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod is suspended"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pod setup window expired"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Priming"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Ready for basal programming"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Ready to insert cannula"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Resume: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Shutdown imminent alarm"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspend: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspended"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Tank fill completed"; - -/* Pod power to motor activated */ -"Tank power activated" = "Tank power activated"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temp basal in progress"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temp basal running"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Time to replace your pod! Your pod will expire in %1$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Uncertain"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Unexpected response from pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Unknown pod fault %1$03d"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Waiting for pairing reminder"; - -/* DASH Pod time ago since last status */ -"%@ ago" = "%@ ago"; diff --git a/Dependencies/OmniBLE/OmniBLE/es.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/es.lproj/Localizable.strings deleted file mode 100644 index 0567fb182..000000000 --- a/Dependencies/OmniBLE/OmniBLE/es.lproj/Localizable.strings +++ /dev/null @@ -1,1127 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactivo)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "Hace %@"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ ha recuperado la comunicación con el Pod que esta adherido a su cuerpo. \n\nLos registros de entrega de insulina se han actualizado y deben coincidir con lo que realmente se entregó. \n\nPuede ahora continuar usando %@ normalmente."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ para %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ no ha podido comunicarse con el Pod que esta adherido a su cuerpo desde %2$@.\n\nSin comunicación con el Pod, la app no puede seguir enviando órdenes de administración de insulina ni mostrar información precisa y reciente sobre su insulina activa o la insulina que está administrando el Pod.\n\nVigile de cerca sus niveles de glucosa durante las próximas 6 horas o más, ya que puede haber o no insulina activa en su cuerpo que %3$@ no puede mostrar."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "Queda %1$@ de insulina o menos en el Pod. Cambie el Pod pronto."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "quedan %1$@ unidades a las %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@ + %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 hora"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hora 30 minutos"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 horas"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutos"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Tiempo de activación excedido"; - -/* description label for active time pod details row */ -"Active Time" = "Tiempo Activo"; - -/* Section header for activity section */ -"Activity" = "Actividad"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Ajustando la hora de la bomba..."; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "¿Está seguro de que desea cancelar la configuración del Pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "¿Está seguro de que desea saltearse de Omnipod Onboarding?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "¿Está seguro de que desea dejar de usar Omnipod DASH?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Coloque el Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Intentando restablecer la comunicación"; - -/* Description for auto-off */ -"Auto-off" = "Apagado automático"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Alarma de apagado automático"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Atrás"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal inicializada"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Menos de 50 unidades"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "Versión del firmware BLE"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth está apagado"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Bluetooth se está reiniciando"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth no está disponible por una razón desconocida."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth no está disponible: %1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "El uso de Bluetooth no está autorizado"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "No se admite el uso de Bluetooth en este dispositivo"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolo"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolo en progreso"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolo: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Poniendo bolo"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Poniendo bolo con basal temporal"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Cancelar"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancelar basal manual"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Cánula insertada con éxito. Continúa."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Cánula insertándose"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Programación acertada"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Cambie el Pod ahora. La administración de insulina se detendrá 8 horas después de que el Pod haya caducado o cuando no quede más insulina."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Cambie el Pod ahora. La administración de insulina se detendrá en %1$@ o cuando no quede más insulina."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Cambie el Pod ahora. La administración de insulina se detendrá en una hora."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Cambie el Pod ahora. El Pod ha estado activo durante 72 horas."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Revise la cánula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Revise el Pod, aplíquelo y, a continuación, confirme que este está bien colocado."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Comprobando inserción"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Comprobando..."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Error de comando %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problema de comunicaciones"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comunicaciones recuperadas"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Problema de comunicación: Pendiente de confirmar comando."; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Recordatorios de confianza"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Los recordatorios de confianza son pitidos que emite el Pod que pueden utilizarse para tener certeza de que se han seleccionado comandos."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Los recordatorios de confianza sonarán para los comandos que seleccione, como bolo, cancelar bolo, suspender, reanudar, guardar recordatorios de notificación, etc. Cuando Loop ajusta automáticamente la administración de insulina, no se utilizan recordatorios de confianza."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Recordatorios de confianza sonarán cuando Loop automáticamente ajuste la administración de insulina, así como para los comandos que selecciones."; - -/* Section header for configuration section */ -"Configuration" = "Configuración"; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirmar"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirme la fijación del Pod"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Continuar"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "No se pudo analizar el mensaje: %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Alertas críticas"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Error crítico del Pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Interferencia posible. Muévase a una nueva ubicación"; - -/* Unit for singular day in pod life remaining */ -"day" = "día"; - -/* Unit for plural days in pod life remaining */ -"days" = "días"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Desactivar Pod"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Pod desactivado"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Desactivando."; - -/* Action button description while deactivating */ -"Deactivating..." = "Desactivando..."; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Borrar Omnipod DASH"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Detalles del dispositivo"; - -/* description label for device name pod details row */ -"Device Name" = "Nombre del dispositivo"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Desactivado"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Descartar Pod"; - -/* No comment provided by engineer. */ -"Done" = "Completado"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Reservorio vacío"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Depósito vacío"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Respuesta vacía del pod"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Valor vacío"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Habilitado"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Error"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Evento de error de registro, apagándose"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Aviso de caducidad"; - -/* Description for expiration alert */ -"Expiration alert" = "Alerta de caducidad"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Recordatorio de Caducidad"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Recordatorio de expiración predeterminado"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extendido"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Bolo extendido ejecutándose"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Bolo extendido ejecutándose con basal temporal"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "No se pudo cancelar la insulina basal manual"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "No se pudo reanudar la administración de insulina"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "No se establecio la hora de la bomba"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "No se pudo suspender la administración de insulina"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "No se ha podido actualizar la preferencia de recordatorio de confianza."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "No se ha podido actualizar el recordatorio de Expiración"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "No se ha podido actualizar el recordatorio de Reserva Baja"; - -/* Pod life HUD view label */ -"Fault" = "Fallo"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Se ha producido un fallo"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Llene un nuevo Pod con insulina U-100 (deje puesta la tapa azul de la aguja del Pod)."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finalizar la desactivación"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Finalizar la desactivación"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Finalizar Emparejamiento"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finalizar la Configuración"; - -/* Description for finish setup */ -"Finish setup " = "Fin de la configuración"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Finalizar recordatorio de configuración"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Versión del programa"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Quedan más de %1$@ unidades a las %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hora"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "horas"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Si cancela la configuración del Pod, el Pod actual se desactivará y quedará inutilizable."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Excepción de paquete incorrecta: %1$@ (localizacion=%2$d)"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Respuesta incorrecta"; - -/* Pod inititialized */ -"Initialized" = " iniciado"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Insertar Cánula"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Insertada"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Insertando cánula"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Insertando. Espere, por favor."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Insertando..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulina Suspendida"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "El suministro de insulina se detuvo. Cambiar Pod ahora."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "La administración de insulina se detendrá hasta que la reanude manualmente. ¿Cuándo desea que Loop le recuerde que debe reanudar la administración?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulina restante"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulina Suspendida"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Tipo de Insulina"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Tipo de insulina no configurada"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Error pod interno %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "BoloInterrumpido: %1$@ U (%2$@ U planeadas) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Dirección no válida 0x %1$x. Esperada 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Dirección no válida: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "CRC no válido"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Clave LTK no válida: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Configuración no válida"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "¿La cánula está insertada correctamente?"; - -/* description label for last status date pod details row */ -"Last Status" = "Último estado"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Escuche 2 pitidos."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop no ajustará automáticamente la administración de insulina hasta que la tasa de administracion de insulina basal temporal finalice o se cancele."; - -/* description label for lot number pod details row */ -"Lot Number" = "Número de lote"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Reserva baja"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Reserva baja"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Aviso de reserva baja (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Alarma de aviso de depósito bajo"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Recordatorio de reserva baja"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Asegúrese de que el iPhone está cerca del pod activo"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Asegúrese de que su teléfono y su pod estén cerca uno del otro. Si los problemas de comunicación persisten, muévase a otra área."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Asegúrese de que su pod esté lleno y cerca."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Asegúrate que tu Pod se encuentra cerca e inténtalo de nuevo."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Asegúrese de que su RileyLink está cerca y encendido"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Basal Manual"; - -/* Pod memory initialized */ -"Memory initialized" = "Memoria inicializada"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Mensaje de excepción de E/S: %1$@"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minuto"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutos"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Configuración faltante"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Muévete a una nueva área lejos de cualquier otro Pod e inténtalo de nuevo."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Alerta de comandos múltiples"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "No disponible"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "No confirmado"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Siguiente"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "No hay administración"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "No hay alertas"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No se utilizan recordatorios de confianza."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Sin fallos"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "No hay insulina"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "No hay Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No hay pod emparejado"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No se encontraron Pods"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Sin recordatorio"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Sin respuesta del pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "No hay RileyLink disponible"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, continúe con el Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, mantenga la bomba como está"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "No hay suficientes datos"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Configuración de las notificaciones"; - -/* No comment provided by engineer. */ -"Numbers" = "Números"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Oclusion detectada"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Oclusión detectada"; - -/* Action button default text for PodAlerts */ -"Ok" = "OK"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Recordatorios Omnipod"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Emparejar Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Emparejar Pod"; - -/* Pod status after pairing */ -"Paired" = "Emparejado"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Emparejamiento completo"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Excepción de emparejamiento: %1$@"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Emparejando."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Emparejando..."; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Error de parseo: %1$@ en (%2$@)"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = "La carga útil crc32 %1$@ no coincide con el crc32 %2$@ calculado."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Porcentaje = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Periférico no preparado"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Por favor, ponga solamente el Pod original en rango o desactivelo"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Por favor, acerque su pod al RileyLink e inténtelo de nuevo"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Compruebe que el Pod está bien adherido a su cuerpo.\n\nLa cánula sólo puede insertarse una vez con cada Pod. Pulse \"Confirmar\" cuando el Pod esté ya bien adherido a su cuerpo."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Por favor desactivar el Pod. Cuando la desactivación se haya completado, puede emparejar un nuevo Pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Por favor desactivar el Pod. Cuando la desactivación se haya completado, puede retirarlo y emparejar un nuevo pod."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Habilite los permisos de bluetooth para esta aplicación en la configuración del sistema"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Por favor, termine de emparejar su Pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Por favor, empareje un nuevo pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Por favor, reposicione el iPhone más lejos del Pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Por favor, cambie la posición del iPhone con respecto al Pod"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Por favor, utilice un dispositivo diferente con capacidades bluetooth"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Activado"; - -/* Label describing pod age view */ -"Pod Age" = "Tiempo de Uso del Pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Ya hay un pod emparejado"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "El pod ya está purgado"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod desactivado correctamente. Continúa"; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Error del Pod"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Alarma de aviso de caducidad de un pod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Aviso de vencimiento de un pod"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Recordatorio de expiración del Pod"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod caducado"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod caducado"; - -/* Label for pod expiration row */ -"Pod Expires" = "El Pod caduca"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "El Pod caduca en"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "El Pod expira en %1$@."; - -/* description label for pod fault details */ -"Pod Fault Details" = "Detalles de la falla del Pod"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Error de pod: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "El Pod no está listo para insertar la cánula"; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "El Pod no está listo para purgar"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "El Pod está suspendido"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "Pod no conectado"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Oclusión del Pod"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod emparejado correctamente. Continúa."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Emparejamiento del Pod incompleto"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod envió acuse de recibo en lugar de respuesta"; - -/* Title for PodSetupView */ -"Pod Setup" = "Configuración del Pod"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "La pantalla de configuración del pod ha caducado"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Recordatorio de que el Pod está suspendido"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Mala señal"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare lugar de inserción"; - -/* title for previous pod page */ -"Previous Pod" = "Pod anterior"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Información anterior del Pod"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Purgando"; - -/* Pod state when priming completed */ -"Priming completed" = "Purgado completado"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Purgando. Por favor, espere."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Purgando..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Hora de la bomba"; - -/* Label text for basal rate summary */ -"Rate" = "Tasa"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Listo para programar basales"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Listo para insertar la cánula"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Restante"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Recordatorio inicializado"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Retire la tapa azul de la aguja del Pod y revise la cánula. A continuación, retire el cobertor de papel."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Quitar el Pod del cuerpo"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Retire la bomba"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Reemplace el Pod"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Reanudar"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Reanudar la entrega de insulina"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Reanudar insulina"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Reanude la administración de insulina"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Reanudar: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Reanudando la administración de insulina..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Reintentar"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Agregar"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Guardando..."; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Insulina basal programada"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Insulina basal programada"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Recordatorio programado"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Seleccione el tipo de insulina que utilizará en esta bomba."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Número de secuencia"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Establecer insulina basal temporal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Establecer tasa basal temporal"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Instalación completada"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Cierre inminente"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Apagar la alarma inminente"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Pérdida de señal"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Intensidad de la señal demasiado alta"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "¿Saltearse el Onboarding de Omnipod?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspender"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspender la infusión"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Recordatorio de Suspensión en curso"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspender la administración de insulina"; - -/* Description for suspend time expired */ -"Suspend time expired" = "El tiempo de suspensión ha expirado"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspender: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspendido"; - -/* Label for suspended at time */ -"Suspended At" = "Suspendido a las"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspendiendo la administración de insulina..."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "El tiempo de suspensión ha terminado. Abra la aplicación y reanúdela."; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Cambiar a otro dispositivo de administración de insulina"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sincronizar con la hora actual"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Completado el llenado del depósito"; - -/* Pod power to motor activated */ -"Tank power activated" = "Depósito encendido"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Toque abajo para iniciar la inserción de la cánula."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Insulina basal temporal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Basal temporal en progreso"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Basal temporal funcionando"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "BasalTemporal: %1$@ U/hora %2$@ %3$@ %4$@ U %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Insulina basal temporal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "La insulina basal temporal ha fallado"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "La aplicación configura un recordatorio en el Pod para notificarle con antelación sobre la expiración del Pod. Establezca el número de horas de antelación con las que desea que le avise para emparejar un nuevo Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "La aplicación le avisa con antelación de la expiración del Pod.\n\nDesplácese para establecer el número de horas de antelación que le gustaría tener."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "La App le avisa cuando la cantidad de insulina en el Pod alcanza este nivel (50-10 U).\n\nDesplácese para establecer el número de unidades en las que desea que la App le avise."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "La aplicación le notifica cuando la cantidad de insulina en el Pod alcanza este nivel."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "El periodo de suspensión de la insulina ha finalizado.\n\nPuedes reanudar la administración desde el banner de la pantalla de inicio o desde la pantalla de ajustes de tu bomba. Se le recordará de nuevo en 15 minutos."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "La hora de la bomba es diferente de la hora actual. Desea actualizar la hora de su bomba a la hora actual?"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "La hora de la bomba es diferente de la hora actual. Puedes revisar la hora de la bomba y sincronizarla con la hora actual en los ajustes."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "La hora de su bomba es diferente de la hora actual. La hora de su bomba controla los ajustes programados de su terapia. Desplácese hacia abajo hasta la fila que muestra la Hora de la Bomba para revisar la diferencia horaria y configurar su bomba."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "La ventana situada en la parte superior del Pod debe volverse de color rosa cuando la cánula esté correctamente insertada en la piel."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Se ha producido un problema de comunicación con el Pod. Si el problema persiste, pulse Descartar Pod. A continuación, puede activar un nuevo Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Este es un recordatorio que programó cuando enlazó su Pod actual."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Este PumpManager no se ha configurado con una tasa basal máxima porque se añadió antes de que la tasa basal manual fuera una función disponible. Vaya a Configuración del tratamiento -> Límites de administración y establezca una nueva tasa basal máxima."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Hora"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Cambio de hora detectado"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Es hora de reemplazar el pod! El pod expira en %1$@"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Se acabó el tiempo"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Botón de alternar"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Se encontraron demasiados Pods"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Dosis total administrada"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Vuelva a intentarlo"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Activar bluetooth"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hra"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "No se puede conectar el Pod"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "No se puede conectar el Pod"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "No se ha podido establecer una tasa de insulina basal temporal: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "No se ha podido establecer una tasa de insulina basal temporal: %1$@\n\n%2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Incierto"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Número de secuencia de mensaje inesperado"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Cambio inesperado de Pod"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Respuesta inesperada del pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Activación no terminada"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Desactivación no terminada"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Característica desconocida"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Fallo de pod desconocido %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Valor Desconocido (%1$@) para el tipo %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "La validación falló: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Espere a que termine el bolo o cancele el bolo"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Espere a que termine la basal temporal existente o suspénda para cancelar"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Espere hasta que finalice la inserción."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Esperando el recordatorio de emperejamiento"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Sí"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Sí, desactivar Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Sí, sincronizar con la hora actual"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Ahora comenzará el proceso de configurar sus recordatorios, llenar su Pod con insulina, emparejarlo con su dispositivo y colocárselo en el cuerpo."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Su Pod está listo para usar.\n\n%1$@ le recordará cambiar su Pod antes de que caduque. Puede cambiarlo cuando sea un momento conveniente para usted."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Es posible que su Pod siga suministrando insulina.\nRetírelo de su cuerpo y pulse \"Continuar\"."; - diff --git a/Dependencies/OmniBLE/OmniBLE/fi.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/fi.lproj/Localizable.strings deleted file mode 100644 index 6069150bb..000000000 --- a/Dependencies/OmniBLE/OmniBLE/fi.lproj/Localizable.strings +++ /dev/null @@ -1,430 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (ei-aktiivinen)"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@ U"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ yksikköä jäljellä klo %2$@"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Aktivointiaika ylitetty"; - -/* description label for active time pod details row */ -"Active Time" = "Aktiivinen aika"; - -/* Section header for activity section */ -"Activity" = "Liikunta"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Autom. pois -varoitus"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Takaisin"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basaali alustettu"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Alle 50 yksikköä"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus vireillä"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Annostellaan bolus"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Annostellaan bolus ja tilap. basaali"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Kumoa"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Asetetaan kanyyli"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Varma"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Tarkistetaan..."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Komentovirhe %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Yhteysongelma"; - -/* Section header for configuration section */ -"Configuration" = "Määritykset"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Jatka"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Deaktivoi pumppu"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktivoitu"; - -/* No comment provided by engineer. */ -"Done" = "Valmis"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Säiliö tyhjä"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Tyhjä vastaus pumpulta"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Käytössä"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Virhe"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Virhetapahtuma, suljetaan"; - -/* Description for expiration alert */ -"Expiration alert" = "Pumppu vanhenee -varoitus"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Vanhenemismuistutus"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Annostelun jatkaminen epäonnistui"; - -/* Pod life HUD view label */ -"Fault" = "Virhe"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Virhetapahtuma"; - -/* Description for finish setup */ -"Finish setup " = "Lopeta asennus"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Laiteohjelmiston versio"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Enemmän kuin %1$@ yksikköä jäljellä klo %2$@"; - -/* Pod inititialized */ -"Initialized" = "Aloitettu"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Aseta kanyyli"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Asetetaan kanyyli"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insuliini pysäytetty"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insuliinityyppi"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Sisäinen pumpun vika %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "KeskeytettyBolus: %1$@ U (%2$@ U ohjelmoitu) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Virheellinen osoite 0x%1$x. Odotettu 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Virheellinen osoite: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Virheellinen CRC"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Säiliö vähissä"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Säiliö lähes tyhjä -tiedotehälytys"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Varmista, että RileyLink on riittävän lähellä ja kytketty päälle"; - -/* Pod memory initialized */ -"Memory initialized" = "Muisti alustettu"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Ei hälytyksiä"; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Ei vikoja"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Ei insuliinia"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Ei pumppua"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Ei yhdistettyä pumppua"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Ei vastausta pumpusta"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Ei RileyLinkiä lähistöllä"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normaali"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Tietoja ei ole tarpeeksi"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Tukos havaittu"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pod status after pairing */ -"Paired" = "Yhdistetty"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Tuo vain alkuperäinen pumppu kantaman sisälle tai poista alkuperäinen pumppu käytöstä"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Vie pumppu ja RileyLink lähemmäksi toisiaan ja yritä uudelleen"; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Yhdistä uusi pumppu"; - -/* Label describing pod age view */ -"Pod Age" = "Pumpun ikä"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pumppu on jo yhdistetty"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pumppu on jo alustettu"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pumppu vanhenemassa -tiedotehälytys"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pumppu vanhenemassa -ilmoitus"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pumppu vanhentunut"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pumppu vanhentunut"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pumppuvirhe: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pumppu ei ole valmis kanyylin asettamiseen."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pumppu ei ole valmis alustukseen."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pumppu on pysäytetty"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pumppu lähetti kuittauksen vastauksen sijaan"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pumpun asennusaika umpeutui"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Heikko signaali"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Alustetaan"; - -/* Pod state when priming completed */ -"Priming completed" = "Alustus valmis"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Valmis basaalin ohjelmointiin"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Valmis kanyylin asetukseen"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Jäljellä"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Muistutus alustettu"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Vaihda pumppu"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Jatka: %1$@ %2$@"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Yritä uudelleen"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Tallenna"; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Ohjelmoitu basaali"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Ohjelmoitu basaali"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Valitse insuliinin tyyppi, jota käytät tässä pumpussa."; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Asennus valmis"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Mykistä hälytys"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signaali liian voimakas"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Pysäytä annostelu"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Pysäytä: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Pysäytetty"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Säiliön täyttö valmis"; - -/* Pod power to motor activated */ -"Tank power activated" = "Säiliön virta aktivoitu"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Tilapäinen basaali"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Tilapäinen basaali meneillään"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Tilapäinen basaali käynnissä"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TilapBasaali: %1$@ U/h %2$@ %3$@ %4$@ U %5$@"; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Aika"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Aika vaihtaa pumppu! Pumppu vanhenee %1$@"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Yritä uudelleen"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/h"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Epävarma"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Odottamaton viestin järjestysnumero"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Odottamaton pumpun vaihto"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Odottamaton vastaus pumpusta"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Tuntematon pumppuvirhe %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Tuntematon arvo (%1$@) tyypille %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Vahvistus epäonnistui: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Odota, että meneillään oleva bolus päättyy tai kumoa bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Odota, että meneillään oleva tilapäinen basaali päättyy tai pysäytä pumppu kumotaksesi"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Odotetaan yhdistämismuistutusta"; - diff --git a/Dependencies/OmniBLE/OmniBLE/fr.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/fr.lproj/Localizable.strings deleted file mode 100644 index 195019eb8..000000000 --- a/Dependencies/OmniBLE/OmniBLE/fr.lproj/Localizable.strings +++ /dev/null @@ -1,1127 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactif)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "Il y a %@"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "La communication entre %@ et le Pod sur votre corps a été rétablie.\n\nLes enregistrements d'administration d'insuline ont été mis à jour et devraient correspondre à ce qui a été effectivement administré.\n\nVous pouvez continuer à utiliser %@ normalement maintenant."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ pendant %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ n'a pas pu communiquer avec le Pod sur votre corps depuis %2$@ . \n\nSans communication avec le Pod, l'application ne peut pas continuer à envoyer des commandes pour l'administration d'insuline ou afficher des informations précises et récentes sur votre insuline active ou l'insuline administrée par le Pod. \n\nSurveillez attentivement votre glycémie pendant les 6 prochaines heures ou plus, car il peut y avoir ou non de l'insuline active dans votre corps que %3$@ ne peut pas afficher."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insuline ou moins restant dans le Pod. Remplacer le Pod bientôt."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unités restantes à %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 heure"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 heure 30 minutes"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 heures"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Délai d'activation dépassé"; - -/* description label for active time pod details row */ -"Active Time" = "Heure d’activation"; - -/* Section header for activity section */ -"Activity" = "Activité"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Ajustement de l'horloge de la pompe..."; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Voulez-vous vraiment annuler la configuration du Pod ?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Voulez-vous vraiment sauter l'intégration Omnipod ?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Voulez-vous vraiment arrêter d'utiliser Omnipod DASH?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Appliquer le Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Tenter de rétablir la communication"; - -/* Description for auto-off */ -"Auto-off" = "Arrêt automatique"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Alarme d’arrêt automatique"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Retour"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialisé"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "en dessous de 50 unités"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "Version du micrologiciel BLE"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth désactivé"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Le Bluetooth se réinitialise"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth n’est pas disponible pour une raison inconnue."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth n’est pas disponible : %1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "L’utilisation de Bluetooth n’est pas autorisée"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "L'utilisation de Bluetooth n'est pas prise en charge sur cet appareil"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus en cours"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolus en cours"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolus en cours avec basal temporaire"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Annuler"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Annulation du débit basal manuel"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "La canule a été insérée correctement. Continuez"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Canule en cours d'insertion"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Certain"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Remplacer le pod maintenant. L'administration d'insuline s'arrêtera 8 heures après l'expiration du pod ou lorsque qu'il ne restera plus d'insuline."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Remplacer le Pod maintenant. L'administration d'insuline s'arrêtera dans %1$@ ou lorsqu'il ne restera plus d'insuline."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Remplacer le Pod maintenant. L'administration d'insuline s'arrêtera dans 1 heure."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Remplacer le Pod maintenant. Le Pod est actif depuis 72 heures."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Vérifier la canule"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Vérifiez le pod, placez-le sur le site, puis confirmez qu'il est bien appliqué."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Vérification de l'insertion en cours"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Vérification en cours..."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Erreur de commande %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problème de com."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Communications récupérées"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Problème de communication : Commande en attente sans accusé de réception."; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Rappels de confiance"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Les rappels de confiance sont des bips émis par le Pod qui peuvent être utilisés pour confirmer l'exécution des commandes sélectionnées."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Les rappels de confiance retentiront pour les commandes que vous initiez, comme administrer ou annuler un bolus, suspendre, reprendre, enregistrer les rappels de notification, etc. Lorsque Loop ajuste automatiquement l'administration, aucun rappel de confiance n’est utilisé."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Des rappels de confiance retentiront lorsque Loop ajustera automatiquement l'administration ainsi que pour les commandes que vous lancez."; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirmer"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirmer l'application du Pod"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Continuer"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "Impossible d'analyser le message : %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Alertes critiques"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Erreur critique du Pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Interférences possibles. Veuillez vous déplacer vers un nouvel emplacement"; - -/* Unit for singular day in pod life remaining */ -"day" = "jour"; - -/* Unit for plural days in pod life remaining */ -"days" = "jours"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Désactiver le Pod"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Désactivé"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Désactivation."; - -/* Action button description while deactivating */ -"Deactivating..." = "Désactivation en cours..."; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Supprimer Omnipod DASH"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Information de l’appareil"; - -/* description label for device name pod details row */ -"Device Name" = "Nom de l'appareil"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Désactivé"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Jeter le Pod"; - -/* No comment provided by engineer. */ -"Done" = "Terminé"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Réservoir vide"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Réservoir vide"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Réponse vide du Pod"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Valeur vide"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Activé"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Erreur"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Erreur enregistrée, arrêt en cours"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Avertissement d'expiration"; - -/* Description for expiration alert */ -"Expiration alert" = "Alerte d'expiration"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Rappel d'expiration"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Rappel d'expiration par défaut"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Étendu"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Bolus étendu en cours"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Bolus étendu en cours avec basal temporaire"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Échec d'annulation du basal manuel"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Échec de la reprise de l’administration d’insuline"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Échec de réglage de l'heure de la pompe"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Échec de la suspension de l'administration d'insuline"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Échec de la mise à jour des préférences de rappel de confiance."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Échec de la mise à jour du rappel d'expiration"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Échec de la mise à jour du rappel de réservoir bas"; - -/* Pod life HUD view label */ -"Fault" = "Erreur"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Une erreur s'est produite"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Remplir un nouveau Pod avec de l'insuline U-100 (laisser le capuchon bleu de l'aiguille du Pod en place)"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Terminer la désactivation"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Terminer la désactivation"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Terminer le jumelage"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Terminer l'installation"; - -/* Description for finish setup */ -"Finish setup " = "Finir l'installation"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Terminer le paramétrage du rappel"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Version du micrologiciel"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Plus de %1$@ unités restantes à %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "heure"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "heures"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Si vous annulez la configuration du Pod, le Pod actuel sera désactivé et sera inutilisable."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Exception de paquet incorrecte : %1$@ (emplacement=%2$d)"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Réponse incorrecte"; - -/* Pod inititialized */ -"Initialized" = "Initialisé"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Insérer la canule"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inrérée"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Insertion de la canule"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Insertion en cours. Attendez."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Insertion en cours..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insuline\nSuspendue"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Administration de l'insuline"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "L'administration d'insuline s'est arrêtée. Changez de Pod maintenant."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "L'administration d'insuline sera interrompue jusqu'à ce que vous la repreniez manuellement. Quand voulez-vous que Loop vous rappelle de reprendre l'administration ?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insuline restante"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insuline suspendue"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Type d'insuline"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Type d'insuline non configuré"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Code d'erreur interne du Pod %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Bolus interrompu: %1$@ U (%2$@ U programmé) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Adresse invalide 0x%1$x. Attendu 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Adresse invalide: ( %1$@ )"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "CRC invalide"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Clé LTK non valide: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Paramètre invalide"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "La canule est-elle insérée correctement?"; - -/* description label for last status date pod details row */ -"Last Status" = "Dernier statut"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Écoutez pour 2 bips."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop n'ajustera pas automatiquement votre administration d'insuline tant que le débit basal temporaire ne sera pas terminé ou annulé."; - -/* description label for lot number pod details row */ -"Lot Number" = "Numéro de lot"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Réservoir bas"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Réservoir bas"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Avis de réservoir bas (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Alarme de réservoir bas"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Rappel de réservoir bas"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Assurez-vous que votre iPhone est à proximité du Pod"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Assurez-vous que votre téléphone et votre Pod sont proches l'un de l'autre. Si les problèmes de communication persistent, déplacez-vous vers un nouvel endroit."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Assurez-vous que votre Pod est rempli et à proximité."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Assurez-vous que votre Pod est à proximité et réessayez."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Assurez-vous que votre RileyLink est à proximité et allumé"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Débit basal manuel"; - -/* Pod memory initialized */ -"Memory initialized" = "Mémoire initialisée"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Exception sur message E/S: %1$@"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Configuration manquante"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Déplacez-vous vers un nouvel endroit éloigné de tout autre Pod et réessayez."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Alerte de commande multiple"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "N.A."; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Suivant"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Non"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Pas d'administration"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Pas d'alarme"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Aucun rappel de confiance n'est utilisé."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Pas de défauts"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Pas d'insuline"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Aucun Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Aucun pod appairé"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Aucun Pod trouvé"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Pas de rappel"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Pas de réponse du Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Aucun RileyLink disponible"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Non, continuez avec le Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Non, garder la pompe telle quelle"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Pas assez de données"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Paramétrage des notifications"; - -/* No comment provided by engineer. */ -"Numbers" = "Nombres"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Occlusion détectée"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusion détectée"; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Rappels Omnipod"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Appairer le Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Appairer le pod."; - -/* Pod status after pairing */ -"Paired" = "Appairé"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Appairage terminé"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Exception pendant l'appairage : %1$@"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Appairage."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Appairage en cours..."; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Erreur d'analyse : %1$@ dans (%2$@)"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = "Payload crc32 %1$@ ne correspond pas au crc32 calculé %2$@"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Pourcentage = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Le périphérique n'est pas prêt"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Veuillez rapprocher le Pod original ou désactiver le Pod d'origine"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Merci de rapprocher votre Pod du RileyLink et d'essayer à nouveau"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Veuillez confirmer que le Pod est solidement attaché à votre corps. \n\n La canule ne peut être insérée qu'une seule fois avec chaque Pod. Appuyez sur \"Confirmer\" lorsque le Pod est appliqué."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Veuillez désactiver le pod. Une fois la désactivation terminée, vous pouvez appairer un nouveau Pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Veuillez désactiver le pod. Une fois la désactivation terminée, vous pouvez le retirer et appairer un nouveau pod."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Veuillez activer les autorisations Bluetooth pour cette application dans les paramètres système"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Veuillez finir d'appairer votre Pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Merci d'appairer un nouveau Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Veuillez repositionner l’iPhone plus loin du Pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Veuillez repositionner l’iPhone par rapport au Pod"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Veuillez utiliser un autre appareil avec Bluetooth"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod activé"; - -/* Label describing pod age view */ -"Pod Age" = "Âge Pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod déjà appairé"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod déjà amorcé"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod désactivé avec succès. Continuez."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Erreur du Pod"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Alarme d'expiration du Pod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Notification de l'expiration du Pod"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Rappel d'expiration du Pod"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod expiré"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod expiré"; - -/* Label for pod expiration row */ -"Pod Expires" = "Péremption du Pod"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Péremption du Pod dans"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Péremption du Pod dans %1$@."; - -/* description label for pod fault details */ -"Pod Fault Details" = "Détails de l'erreur du pod"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Erreur du Pod: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Le Pod n’est pas dans un état prêt pour l’insertion de la canule"; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Le Pod n’est pas dans un état prêt pour l’amorçage"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Le Pod est suspendu"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "Pod non connecté"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Occlusion du Pod"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod appairé avec succès. Continuez."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Appairage du Pod incomplet"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Le Pod a envoyé un ack au lieu d'une réponse"; - -/* Title for PodSetupView */ -"Pod Setup" = "Configuration du Pod"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "La fenêtre de mise en place du Pod a expiré"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Rappel de la suspension du Pod"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Faible intensité du signal"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Préparer le site."; - -/* title for previous pod page */ -"Previous Pod" = "Pod précédent"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informations sur le Pod précédent"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Amorçage"; - -/* Pod state when priming completed */ -"Priming completed" = "Amorçage terminé"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Amorçage. S'il vous plaît, attendez."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Amorçage..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Heure de la pompe"; - -/* Label text for basal rate summary */ -"Rate" = "Débit"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Prêt pour la programmation basal"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Prêt à insérer la canule"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Restant"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Rappel initialisé"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Retirez le capuchon d'aiguille bleu du pod et vérifiez la canule. Retirez ensuite le film en papier de l'autocollant."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Retirer le Pod du corps"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Retirer la pompe"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Remplacer le Pod"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Reprendre"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Reprendre l'administration"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Reprendre l'insuline"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Reprendre l'administration d'insuline"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Reprise : %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Reprise de l'administration d'insuline..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Réessayer"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Sauvegarder"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Sauvegarde en cours..."; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Basal programmé"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Basal programmé"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Rappel programmé"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Sélectionnez le type d'insuline que vous utiliserez dans ce Pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Numéro de séquence"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Régler basal temporaire"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Régler basal temporaire"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "L’installation est terminée"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Arrêt imminent"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarme imminente d’arrêt"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Perte de signal"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Intensité du signal trop forte"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Ignorer la phase d'intégration d'Omnipod ?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspendre"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspendre l'administration"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Rappel de suspension en cours"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspendre l'administration d'insuline"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Délai de suspension expiré"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspension : %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspendu"; - -/* Label for suspended at time */ -"Suspended At" = "Suspendu à"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspension de l'administration d'insuline..."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "La période de suspension est terminée. Ouvrez l'application et reprenez."; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Passer à un autre dispositif d'administration d'insuline"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchroniser avec l'heure actuelle"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Remplissage du réservoir terminé"; - -/* Pod power to motor activated */ -"Tank power activated" = "Charge du réservoir activée"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Appuyez ci-dessous pour commencer l'insertion de la canule."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Débit basal temporaire"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Basal temporaire en cours"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Basal temporaire active"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "Basal temporaire: %1$@ U/heure %2$@ %3$@ %4$@ U %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Basale temporaire"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Échec mise en route basal temporaire"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "L'application configure un rappel pour vous avertir à l'avance de l'expiration du pod. Définissez le nombre d'heures de préavis que vous souhaitez lors de l'appairage d'un nouveau pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "L'application vous avertit à l'avance de l'expiration du pod. \n\n Faites défiler pour définir le nombre d'heures de préavis que vous souhaitez."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "L'application vous avertit lorsque la quantité d'insuline dans le Pod atteint ce niveau (50-10 U).\n\nFaites défiler pour définir le nombre d'unités à partir duquel vous souhaitez être averti."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "L'application vous avertit quand la quantité d'insuline restante dans le pod atteint cette limite"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "La période de suspension de l'insuline est terminée. \n\nVous pouvez relancer l'administration à partir de la bannière sur l'écran d'accueil ou à partir de l'écran des paramètres de votre pompe. Vous recevrez un nouveau rappel dans 15 minutes."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "L'heure de votre pompe est différente de l'heure actuelle. Voulez vous mettre à jour l'heure de votre pompe avec l'heure actuelle ?"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "L'heure de votre pompe est différente de l'heure actuelle. Vous pouvez vérifier l'heure de la pompe et la synchroniser avec l'heure actuelle dans les paramètres."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "L'heure de votre pompe est différente de l'heure actuelle. L'heure de votre pompe contrôle les paramètres de votre traitement. Faites défiler jusqu'à la ligne Heure de Pompe pour vérifier le décalage de l'heure et configurer votre pompe."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "La fenêtre située sur le dessus du Pod est colorée en rose lorsque la canule est correctement insérée dans la peau."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Il y a eu un problème de communication avec le Pod. Si ce problème persiste, appuyez sur Jeter le pod. Vous pourrez ensuite activer un nouveau Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Ceci est un rappel que vous avez programmé quand vous avez appairé votre Pod actuel."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Ce gestionnaire de pompe n'a pas été configuré avec un débit basal maximal parce qu'il a été rajouté avant que le basal temporaire manuel soit une fonctionnalité. Veuillez aller dans Réglages de thérapie -> Limites d'administration et configurer un nouveau débit basal maximal."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Heure"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Changement d'heure détecté"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "C’est le moment de remplacer votre Pod ! Votre Pod va expirer dans %1$@"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Temps expiré"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Bouton de bascule"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Trop de Pods trouvés"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total administré"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Réessayer"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Activer le bluetooth"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/h"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Impossible de joindre le Pod"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Impossible de joindre le Pod"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Impossible de définir un débit basal temporaire: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Impossible de définir un débit basal temporaire: %1$@\n\n%2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Incertain"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Numéro de séquence du message inattendu"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Changement inattendu du pod"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Reponse inattendue du Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Activation inachevée"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Désactivation inachevée"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Caractéristique inconnue"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Erreur de Pod inconnue %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Valeur inconnue (%1$@) pour le type %2$@."; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Échec de la validation: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Attendez que le bolus en cours se termine, ou annulez le bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Attendez que le débit basal temporaire se termine pour quitter, ou mettez en suspens pour annuler"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Attendez que l'insertion soit terminée."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "En attente d'appairage"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Oui"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Oui, désactiver le Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Oui, synchroniser avec l'heure actuelle"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Vous allez maintenant commencer à configurer vos rappels, à remplir votre Pod d'insuline, à l'appairer et à le placer sur votre corps."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Votre Pod est prêt à l'emploi. \n\n %1$@ vous rappellera de le remplacer avant qu'il n'expire. Vous pouvez changer ce rappel qui vous convient."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Votre Pod peut encore délivrer de l'insuline.\nRetirez-le de votre corps, puis appuyez sur \"Continuer\"."; - diff --git a/Dependencies/OmniBLE/OmniBLE/he.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/he.lproj/Localizable.strings deleted file mode 100644 index 4e045d8d1..000000000 --- a/Dependencies/OmniBLE/OmniBLE/he.lproj/Localizable.strings +++ /dev/null @@ -1,357 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ ago"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* description label for active time pod details row */ -"Active Time" = "Active Time"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-off alarm"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Below 50 units"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusing"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolusing with temp basal"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Cancel"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Cannula inserting"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Certain"; - -/* Section header for configuration section */ -"Configuration" = "Configuration"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Continue"; - -/* Unit for singular day in pod life remaining */ -"day" = "יום"; - -/* Unit for plural days in pod life remaining */ -"days" = "ימים"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Empty reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Empty response from pod"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Enabled"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Error"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Error event logged, shutting down"; - -/* Description for expiration alert */ -"Expiration alert" = "Expiration alert"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Description for finish setup */ -"Finish setup " = "Finish setup "; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Greater than %1$@ units remaining at %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "שעה"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "שעות"; - -/* Pod inititialized */ -"Initialized" = "Initialized"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Insert Cannula"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Internal pod fault %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Low reservoir advisory alarm"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "דקה"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "דקות"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "No alerts"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "No response from pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "No RileyLink available"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Occlusion detected"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Paired"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Please bring your pod closer to the RileyLink and try again"; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod already primed"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod expiration advisory alarm"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod Expiration Notice"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod expired"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod Fault: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod is not in a state ready for priming."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod is suspended"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "חסימה בפוד"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pod setup window expired"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Priming"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Ready for basal programming"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Ready to insert cannula"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Remaining"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Resume: %1$@ %2$@"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Retry"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Save"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Setup Complete"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Shutdown imminent alarm"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "אובדן אות"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspend: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspended"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Tank fill completed"; - -/* Pod power to motor activated */ -"Tank power activated" = "Tank power activated"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temp basal in progress"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temp basal running"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "שעה"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Time to replace your pod! Your pod will expire in %1$@"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hr"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "לא ניתן להשיג את פוד"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "לא ניתן להשיג את פוד"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "לא ניתן להגדיר בזאלי זמני:%1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "לא ניתן להגדיר בזאלי זמני: %1$@ \n\n %2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Uncertain"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Unexpected response from pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "הפעלה לא הושלמה"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "השבתה לא הושלמה"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Unknown pod fault %1$03d"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "המתן עד להשלמת ההכנסה."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Waiting for pairing reminder"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "כן"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "כעת מתחילים בתהליך של הגדרת התזכורות שלך, מילוי הפוד שלך באינסולין, שיוך למכשיר שלך והנחתו על גופך."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "הפוד שלך מוכן לשימוש. \n\n %1$@ יזכיר לך להחליף את הפוד שלך לפני שתוקפו יפוג. אתה יכול לשנות את זה לזמן שנוח לך."; - diff --git a/Dependencies/OmniBLE/OmniBLE/hi.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/hi.lproj/Localizable.strings deleted file mode 100644 index 917df1bb9..000000000 --- a/Dependencies/OmniBLE/OmniBLE/hi.lproj/Localizable.strings +++ /dev/null @@ -1,23 +0,0 @@ -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "निरस्त"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "जारी"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "समय"; - diff --git a/Dependencies/OmniBLE/OmniBLE/hu.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/hu.lproj/Localizable.strings deleted file mode 100644 index 5d7776566..000000000 --- a/Dependencies/OmniBLE/OmniBLE/hu.lproj/Localizable.strings +++ /dev/null @@ -1,1132 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inaktiv)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ vor"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ hat die Kommunikation mit dem Pod an Ihrem Körper wiederhergestellt.\n\nDie Insulinabgabeaufzeichnungen wurden aktualisiert und sollten mit dem übereinstimmen, was tatsächlich abgegeben wurde.\n\nSie können %@ jetzt normal weiter verwenden."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ IE"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ für %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ konnte seit %2$@ nicht mehr mit Ihrem Pod kommunizieren.\n\nOhne Kommunikation mit dem Pod kann die App keine Befehle für die Insulinabgabe senden oder genaue, aktuelle Informationen über Ihr aktives Insulin oder das vom Pod abgegebene Insulin anzeigen.\n\nÜberwachen Sie Ihren Blutzucker für die nächsten 6 oder mehr Stunden genau, da in Ihrem Körper Insulin aktiv sein kann oder auch nicht, das %3$@ nicht anzeigen kann."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ Insulin oder weniger verbleibend im Pod. Pod bald wechseln."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ IE verbleibend bei %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g IE"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 Stunde"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 Stunde 30 Minuten"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 Stunden"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 Minuten"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Aktivierungszeit überschritten"; - -/* description label for active time pod details row */ -"Active Time" = "Laufzeit"; - -/* Section header for activity section */ -"Activity" = "Aktivität"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pumpenzeit einstellen"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Sind Sie sicher, dass Sie die Pod-Einrichtung abbrechen möchten?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Sind Sie sicher, dass Sie das Omnipod Onboarding überspringen wollen?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Sind Sie sicher, dass Sie keinen Omnipod DASH mehr benutzen möchten?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Pod anbringen"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Versuche die Verbindung wieder aufzubauen"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-Off Alarm"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Zurück"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialisiert"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Weniger als 50 Einheiten"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth ist ausgeschaltet"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Bluetooth wird zurückgesetzt"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth ist aus einem unbekannten Grund nicht verfügbar."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth ist nicht verfügbar: %1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "Bluetooth-Nutzung ist nicht erlaubt"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "Bluetooth-Verwendung wird auf diesem Gerät nicht unterstützt"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolusabgabe läuft "; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@IE %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusabgabe"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolus-Abgabe mit temporärer Basalrate"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Abbrechen"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Manuelles Basal abbrechen"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanüle erfolgreich eingeführt. Weiter."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Einsetzen der Kanüle"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Sicher"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Pod jetzt wechseln. Die Insulinabgabe stoppt 8 Stunden nach Ablauf des Pods oder wenn kein Insulin mehr vorhanden ist."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Pod jetzt wechseln. Die Insulinabgabe stoppt in %1$@ oder wenn kein Insulin mehr vorhanden ist."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Pod jetzt wechseln. Die Insulinabgabe stoppt in 1 Stunde."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Pod jetzt wechseln. Der Pod ist seit 72 Stunden aktiv."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Prüfe die Kanüle"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Überprüfe den Pod, bringe ihn an und bestätige dann die Pod-Anbringung."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Prüfe die Einfügung"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Prüfe…"; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Befehlsfehler %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Problem"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Kommunikation wiederhergestellt"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Kommunikationsproblem: Unbestätigter Befehl steht noch aus."; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Sicherheitserinnerung"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Vertrauenserinnerungen sind Pieptöne vom Pod, die verwendet werden können, um ausgewählte Befehle zu bestätigen."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Vertrauenserinnerungen ertönen für von Ihnen initiierte Befehle, wie Bolus, Bolus abbrechen, Unterbrechen, Fortsetzen, Benachrichtigungserinnerungen speichern usw. Wenn Loop die Abgabe automatisch anpasst, werden keine Vertrauenserinnerungen verwendet."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Vertrauenserinnerungen ertönen, wenn Loop die Lieferung automatisch anpasst, sowie für von Ihnen initiierte Befehle."; - -/* Section header for configuration section */ -"Configuration" = "Konfiguration"; - -/* Button title for confirm attachment option */ -"Confirm" = "Bestätige"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bestätige Pod Befestigung"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Weiter"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "Nachrichte konnte nicht analysiert werden: %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritische Warnungen"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritischer Pod-Fehler"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Überlagerungen möglich. Bitte wechseln Sie an einen neuen Standort"; - -/* Unit for singular day in pod life remaining */ -"day" = "Tag"; - -/* Unit for plural days in pod life remaining */ -"days" = "Tage"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Pod deaktivieren"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktiviert"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktiviere."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deaktiviere…"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Omnipod DASH löschen"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Gerätedetails"; - -/* description label for device name pod details row */ -"Device Name" = "Gerätename"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Ausgeschaltet"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Pod verwerfen"; - -/* No comment provided by engineer. */ -"Done" = "Fertig"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Reservoir leer"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Leeres Reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Leere Antwort vom Pod"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Leerer Wert"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Aktiviert"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Fehler"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Fehlerereignis protokolliert, fahre herunter"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Ablaufhinweis"; - -/* Description for expiration alert */ -"Expiration alert" = "Ablaufalarm"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Erinnerung an den Ablauf der Nutzungsdauer"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standard Erinnerung an den Ablauf der Nutzungsdauer"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Verzögerung"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Verzögerter Bolus aktiv"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Verzögerter Bolus mit temporärer Basalrate aktiv"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Fehler beim Abbrechen der manuellen Basalrate"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Wiederaufnahme der Insulinabgabe fehlgeschlagen"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Fehler beim Einstellen der Pumpenzeit"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Fehler beim Anhalten der Insulinabgabe"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Fehler beim Aktualisieren der Einstellung für die Sicherheitserinnerung."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Fehler beim Aktualisieren der Ablauferinnerung"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Fehler beim Aktualisieren der Erinnerung für einen niedrigen Vorratsbehälter"; - -/* Pod life HUD view label */ -"Fault" = "Störung"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fehlerereignis aufgetreten"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Fülle U-100 Insulin in den Pod (lasse die blaue Kappe drauf)"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Deaktivierung abschließen"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Deaktivierung abgeschlossen"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Kopplung abgeschlossen"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Einrichtung abschließen"; - -/* Description for finish setup */ -"Finish setup " = "Einrichtung abgeschlossen"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Einrichtungserinnerung abgeschlossen"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Mehr als %1$@ verbleibende Einheiten um %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "Stunde"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "Stunden"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Wenn Du die Einrichtung abbrichst, dann wird der Pod deaktiviert und unbrauchbar."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Incorrect Packet Exception: %1$@ (location=%2$d)"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Falsche Antwort"; - -/* Pod inititialized */ -"Initialized" = "Initialisiert"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Kanüle einsetzen"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Eingeführt"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Einfügen von Kanüle"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Füge ein, bitte warte…"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Füge ein…"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulinabgabe\nunterbrochen"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulinabgabe wurde gestoppt. Pod jetzt wechseln."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Die Insulinabgabe wird angehalten, bis Sie sie manuell wieder aufnehmen. Wann soll Loop Sie daran erinnern, die Abgabe fortzusetzen?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Verbleibendes Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulinabgabe unterbrochen"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulintyp"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulintyp nicht konfiguriert"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Interner Podfehler %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Abgebrochener Bolus: %1$@ IE (%2$@ IE geplant) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Ungültige Adresse (%1$x). Adresse %2$x erwartet"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Ungültige Adresse (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Ungültiger CRC"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Invalid LTK Key: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ungültige Einstellung"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Wurde der Katheter ordentlich eingeführt?"; - -/* description label for last status date pod details row */ -"Last Status" = "Letzter Status"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Achte auf zwei Pieptöne."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop passt Ihre Insulinabgabe nicht automatisch an, bis die temporäre Basalrate beendet oder abgebrochen wurde."; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Niedriges Reservoir"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Niedriges Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Hinweis auf niedriges Reservior (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Hinweisalarm für fast leeres Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Erinnerung an niedriges Reservoir"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Stellen Sie sicher, dass Ihr iPhone nah am Pod ist"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Stellen Sie sicher, dass sich Ihr iPhone und Ihr Pod nahe beieinander befinden. Wenn die Kommunikationsprobleme bestehen bleiben, dann gehen Sie an einen anderen Ort."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Stellen Sie sicher, dass Ihr Pod gefüllt und in der Nähe ist."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Stellen Sie sicher, dass sich Ihr Pod in der Nähe befindet, und versuchen Sie es erneut."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Stellen Sie sicher, dass sich Ihr RileyLink in der Nähe befindet und eingeschaltet ist"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuelle Basalrate"; - -/* Pod memory initialized */ -"Memory initialized" = "Speicher initialisiert"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Message IO Exception: %1$@"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "Minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "Minuten"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Fehlende Konfiguration"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Begeben Sie sich in einen anderen Bereich, entfernt von anderen Pods und versuchen Sie es erneut."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Warnung bei mehreren Befehlen"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "nicht bestätigt"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Weiter"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nein"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Keine\nAbgabe"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Keine Alarme"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Es werden keine Sicherheitserinnerungen verwendet."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Keine Fehler"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Kein Insulin"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Kein Pod gekoppelt"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Kein Pod gekoppelt"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Keine Pods gefunden"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Keine Erinnerung"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Keine Rückmeldung vom Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Kein RileyLink verfügbar"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nein, mit Pod fortfahren"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nein, Pumpe so lassen wie sie ist"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Nicht genügend Daten"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Benachrichtigungseinstellungen"; - -/* No comment provided by engineer. */ -"Numbers" = "Zahlen"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Verstopfung erkannt"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Verstopfung erkannt"; - -/* Action button default text for PodAlerts */ -"Ok" = "OK"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Erinnerung"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pod koppeln"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pod koppeln."; - -/* Pod status after pairing */ -"Paired" = "Gekoppelt"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Kopplung abgeschlossen"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Kopplungsausnahme: %1$@"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Koppeln"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Koppeln…"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing-Fehler: %1$@ in (%2$@)"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = "Payload crc32 %1$@ does not match computed crc32 %2$@"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percent = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheriegerät nicht bereit"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Bitte nur Original-Pod in Reichweite bringen oder Original-Pod deaktivieren"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Bitte bringen Sie Ihren Pod näher an Ihr RileyLink und versuchen Sie es erneut"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Bitte vergewissern Sie sich, dass der Pod sicher an Ihrem Körper befestigt ist.\n\nDer Katheter kann mit jedem Pod nur einmal eingeführt werden. Tippen Sie auf „Bestätigen“, wenn der Pod angeschlossen ist."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Bitte deaktivieren Sie den Pod. Wenn die Deaktivierung abgeschlossen ist, können Sie einen neuen Pod koppeln."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Bitte deaktivieren Sie den Pod. Wenn die Deaktivierung abgeschlossen ist, können Sie ihn entfernen und einen neuen Pod koppeln."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Bitte aktiviere die Bluetooth-Berechtigungen für diese App in den Systemeinstellungen"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Bitte schließen Sie die Kopplung Ihres Pods ab."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Bitte koppel einen neuen Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Bitte positionieren Sie das iPhone weiter vom Pod entfernt"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Bitte positionieren Sie das iPhone relativ zum Pod neu"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Bitte verwenden Sie ein anderes Gerät mit Bluetooth-Funktion"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod aktiviert"; - -/* Label describing pod age view */ -"Pod Age" = "Pod-Alter"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod bereits gekoppelt"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod bereits gefüllt"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod erfolgreich deaktiviert. Weiter."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Pod-Fehler"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Ablaufalarm des Pods"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Hinweis zum Ablaufen des Pods"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod-Ablauferinnerung"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod abgelaufen"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod abgelaufen"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod läuft ab"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod läufen ab in"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod läuft in %1$@ ab."; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fehlerdetails"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Podfehler: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Der Pod ist nicht bereit zum Einführen der Kanüle."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Der Pod ist nicht bereit zum Befüllen."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod ist angehalten"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "Pod nicht verbunden"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Verstopfung"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod erfolgreich gekoppelt. Weiter."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod-Kopplung unvollständig"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sendet Bestätigung anstelle von Antwort"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Einrichtung"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Das Zeitfenster für die Pod-Einrichtung ist abgelaufen"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Erinnerung über abgelaufenen Pod "; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Schlechte Signalstärke"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Stelle vorbereiten."; - -/* title for previous pod page */ -"Previous Pod" = "Vorheriger Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informationen über den letzten Pod"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Befüllen"; - -/* Pod state when priming completed */ -"Priming completed" = "Befüllen des Pods abgeschlossen"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Befülle, bitte warte."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Befülle…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Uhrzeit der Pumpe"; - -/* Label text for basal rate summary */ -"Rate" = "Rate"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Bereit für die Programmierung der Basalrate"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Bereit zum Einführen der Kanüle"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Verbleibend"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Erinnerung initialisiert"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Entfernte die blaue Kappe und überprüfe den Katheter. Dann entferne das Papier."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Entferne den Pod vom Körper"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Pumpe löschen"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Pod ersetzen"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Fortsetzen"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Insulinabgabe fortsetzen"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Insulinabgabe fortsetzen"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Insulinabgabe wiederaufnehmen"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Fortsetzen: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Nehme Insulinabgabe wieder auf…"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Wiederholen"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Speichern"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Speichere…"; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Geplante Basalrate"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Geplante Basalrate"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Geplante Erinnerung"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Wähle die Insulinart aus, die Du für diesen Pod benutzen möchtest."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequenznummer"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Temporäre Basalrate setzen"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Temporärere Basalrate setzen"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Einrichtung abgeschlossen"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Pod-Abschaltung steht bevor"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarm für die bevorstehende Pod-Abschaltung"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signalverlust"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signalstärke ist zu hoch"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Omnipod-Onboarding überspringen?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Unterbrechen"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Abgabe unterbrechen"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Unterbrechungsfortschritts-Erinnerung"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Insulinabgabe unterbrechen"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Unterbrechungszeit abgelaufen"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Unterbrochen: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Unterbrochen"; - -/* Label for suspended at time */ -"Suspended At" = "Unterbrochen um"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Unterbreche die Insulinabgabe…"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Die Unterbrechungszeit ist abgelaufen. Öffnen Sie die App und fahren Sie fort."; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Zu einer anderen Pumpe wechseln"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Mit aktueller Uhrzeit synchronisieren."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Befüllen des Pods erfolgreich"; - -/* Pod power to motor activated */ -"Tank power activated" = "Energieversorgung für den Podmotor aktiviert"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tippe unten, um das Einführen der Kanüle zu starten."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temporäre Basalrate"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temporäre Basalrate läuft bereits."; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temporäre Basalrate läuft"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ IE/h %2$@ %3$@ %4$@ IE %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporäre Basalrate"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal fehlgeschlagen"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Die App konfiguriert eine Erinnerung auf dem Pod, um Dich vor Ablauf des Pods zu benachrichtigen. Legen die Anzahl der Stunden fest, die Du vor Ablauf des Pods benachrichtigt werden möchtest."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Die App benachrichtigt Dich vor Ablauf des Pods.\n\nScrolle, um die gewünschte Anzahl von Stunden im Voraus festzulegen."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Die App benachrichtigt Dich, wenn die Insulinmenge im Pod diesen Wert erreicht (50-10 IE).\n\nScrolle, um die Anzahl der Einheiten festzulegen, bei der Du erinnert werden möchtest."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Die App benachrichtigt Dich, wenn die Insulinmenge im Pod diesen Wert erreicht."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Die Insulinabschaltung ist beendet.\n\nSie können die Abgabe über das Banner auf dem Startbildschirm oder über den Bildschirm mit den Pumpeneinstellungen fortsetzen. Sie werden in 15 Minuten erneut erinnert."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Die obigen Erinnerungen ertönen nicht, wenn sich Dein Gerät im Lautlos- oder Nicht-Stören-Modus befindet.\n\nEs gibt andere kritische Pod-Warnungen und -Alarme, die auch dann ertönen, wenn Dein Gerät auf „Lautlos“ oder „Nicht stören“ eingestellt ist."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Die Uhrzeit Ihrer Pumpe unterscheidet sich von Ihrer aktuellen Uhrzeit. Möchten Sie die Uhrzeit Ihrer Pumpe auf Ihre aktuelle Uhrzeit aktualisieren?"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Die Uhrzeit Ihrer Pumpe weicht von der aktuellen Uhrzeit ab. Sie können die Uhrzeit der Pumpe überprüfen und in den Einstellungen mit der aktuellen Uhrzeit synchronisieren."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Die Uhrzeit der Pumpe weicht von der aktuellen Uhrzeit ab. Die Zeit der Pumpe steuert die geplanten Therapieeinstellungen. Scrolle nach unten zur Zeile Pumpenzeit, um den Zeitunterschied zu überprüfen und die Pumpe zu konfigurieren."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Das Fenster oben auf dem Pod sollte pinkfarben sein, wenn der Katheter ordentlich in die Haut eingeführt wurde."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Es gab ein Problem bei der Kommunikation mit dem Pod. Wenn dieses Problem weiterhin besteht, tippen Sie auf \"Pod verwerfen\". Sie können dann einen neuen Pod aktivieren."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dies ist eine Erinnerung, die Du beim Koppeln Deines aktuellen Pods eingestellt hast."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Dieser Pumpenmanager wurde nicht mit einer maximalen Basalrate konfiguriert, da er hinzugefügt wurde, bevor die Funktion manuelle temporäre Basalrate hinzugefügt wurde. Bitte gehe zu Therapieeinstellungen -> Abgabegrenzen und stelle eine neue maximale Basalrate ein."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Zeit"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Änderung der Uhrzeit erkannt"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Es ist Zeit Ihren Pod zu wechseln! Der Pod läuft ab in %1$@"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Zeitüberschreitung"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Zeichen umschalten"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Zu viele Pods in Reichweite"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Gesamt Abgabe"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Versuchen Sie es erneut"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Schalte Bluetooth ein"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "IE/h"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Pod kann nicht erreicht werden"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Pod kann nicht erreicht werden"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Eine temporäre Basalrate kann nicht gesetzt werden: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Eine temporäre Basalrate kann nicht gesetzt werden: %1$@\n\n%2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Unsicher"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Unerwartete Sequenznummer der Nachricht"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Unerwarteter Podwechsel"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Unerwartete Antwort vom Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Nicht abgeschlossene Aktivierung"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Nicht abgeschlossene Deaktivierung"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unbekannte Charakteristik"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Unbekannter Podfehler %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Unbekannter Wert ( %1$@ ) für Typ %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Überprüfung fehlgeschlagen: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Warte, bis der aktuelle Bolus abgegeben wurde, oder unterbreche diesen."; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Warten Sie, bis die aktuelle temporäre Basalrate beendet ist, oder unterbrechen Sie diese"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Warte bis das Einführen der Kanüle fertig ist."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Warten auf Kopplungserinnerung"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, deaktiviere Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, mit aktueller Zeit synchronisieren"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Beginne nun damit, die Erinnerungen zu konfigurieren, Dein Pod mit Insulin zu füllen, ihn mit Deinem Gerät zu koppeln und ihn an Deinem Körper zu platzieren."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Dein Pod ist einsatzbereit.\n\n%1$@ erinnert Dich daran, Deinen Pod zu wechseln, bevor er abläuft. Du kannst eine für Dich passende Zeit wählen."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Ihr Pod gibt möglicherweise immer noch Insulin ab.\nEntfernen Sie ihn vom Körper und tippen dann auf „Weiter“."; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; diff --git a/Dependencies/OmniBLE/OmniBLE/it.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/it.lproj/Localizable.strings deleted file mode 100644 index 46fadec09..000000000 --- a/Dependencies/OmniBLE/OmniBLE/it.lproj/Localizable.strings +++ /dev/null @@ -1,1127 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = "(inattivo)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ fa"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ ha ripristinato la comunicazione con il Pod sul tuo corpo.\n\nI dati di somministrazione d'insulina sono stati aggiornati e dovrebbero corrispondere a quanto è stato effettivamente erogato.\n\nOra è possibile continuare a utilizzare %@ normalmente."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ per %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ ha perso la comunicazione con il pod sul suo corpo da %2$@.\n\nSenza comunicazione con il Pod, l'app non può continuare a inviare comandi per la somministrazione d'insulina ne far visualizzare informazioni accurate recenti sull'insulina attiva o sull'insulina erogata dal Pod.\n\nMonitorare attentamente la glicemia per le prossime 6 o più ore, poiché potrebbe esserci o meno insulina attiva nel corpo che %3$@ non è in grado di visualizzare."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulina o meno rimanenti nel Pod. Cambia presto il Pod."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unità rimanenti alle ore %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@ + %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 ora"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 ora e 30 minuti"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 ore"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minuti"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Tempo di attivazione superato"; - -/* description label for active time pod details row */ -"Active Time" = "Tempo Attivo"; - -/* Section header for activity section */ -"Activity" = "Attività"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Regolazione Orario Microinfusore..."; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Sei sicuro di voler annullare la configurazione del Pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Sei sicuro di voler saltare la procedura di installazione di Omnipod?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Sei sicuro di voler interrompere l’uso di Omnipod DASH?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Applicare il Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Tentativo in corso di ristabilire la comunicazione"; - -/* Description for auto-off */ -"Auto-off" = "Spegnimento automatico"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Allarme spegnimento automatico"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Indietro"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basale inizializzata"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Inferiore a 50 unità"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "Versione firmware BLE"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth è spento"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Bluetooth si sta riconfigurando"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth non disponibile per ragioni sconosciute."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth non disponibile:%1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "L'uso del Bluetooth non è autorizzato"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "Questo dispositivo non supporta la connessione Bluetooth"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolo"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolo in corso"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolo: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolo in corso"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolo con basale temp"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Annulla"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Annulla basale manuale"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "La cannula è stata inserita con successo. Continua."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Inserimento cannula in corso"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Definita"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Cambiare il Pod ora. L'erogazione dell'insulina si interromperà dopo 8 ore dalla scadenza del Pod o quando non rimane più insulina nel Pod."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Cambiare Pod ora. L' erogazione d'insulina si interromperà tra %1$@ o quando non ci sarà più insulina nel serbatoio."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Cambia Pod ora. L'erogazione dell'insulina si interromperà tra 1 ora."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Cambia Pod ora. Il Pod è attivo da 72 ore."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Controlla la cannula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Controllare il Pod, applicare sul sito e confermare il fissaggio del pod."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Controllo dell'inserimento"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Controllo in corso"; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Errore di comando %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problema di Comunicazione"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comunicazioni recuperate"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Problema di comunicazione: comando di conferma in attesa."; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Promemoria di fiducia"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "I promemoria di fiducia sono segnali acustici emessi dal Pod che possono essere utilizzati per confermare i comandi selezionati."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "I promemoria di fiducia suoneranno per i comandi inoltrati, come boli, cancellazione boli, sospensioni, ripristini erogazione, ecc. Quando Loop invece regola in automatico l'erogazione allora non userà alcun promemoria di fiducia."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "I promemoria di fiducia suonano quando Loop regola automaticamente l'erogazione e per i comandi avviati dall'utente."; - -/* Section header for configuration section */ -"Configuration" = "Configurazione"; - -/* Button title for confirm attachment option */ -"Confirm" = "Conferma"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Conferma collegamento Pod"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Continua"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "Impossibile analizzare il messaggio: %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Avvisi critici"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Errore critico Pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Possibile dialogo incrociato. Si prega di spostarsi in una nuova posizione"; - -/* Unit for singular day in pod life remaining */ -"day" = "giorno"; - -/* Unit for plural days in pod life remaining */ -"days" = "giorni"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Disattiva Pod"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Disattivato"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Disattivazione."; - -/* Action button description while deactivating */ -"Deactivating..." = "Disattivazione..."; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Elimina Omnipod DASH"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Dettagli del dispositivo"; - -/* description label for device name pod details row */ -"Device Name" = "Nome del dispositivo"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabilitato"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Scarta Pod"; - -/* No comment provided by engineer. */ -"Done" = "Fine"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Serbatoio vuoto"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Serbatoio Vuoto"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Risposta senza contenuto dal Pod"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Valore vuoto"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Abilitato"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Errore"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "È stato rilevato un errore. Spegnimento in corso"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Consultivo di scadenza"; - -/* Description for expiration alert */ -"Expiration alert" = "Avviso di scadenza"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Promemoria scadenza"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Promemoria scadenza predef."; - -/* Title string for BeepPreference.extended */ -"Extended" = "Prolungato"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Bolo prolungato in esecuzione"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Bolo prolungato in esecuzione con Basale Temporanea"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Impossibile Cancellare Basale Manuale"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Impossibile riprendere l'erogazione dell'insulina"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Impossibile impostare Orario Microinfusore"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Impossibile Sospendere Erogazione Insulina"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Impossibile aggiornare la preferenza per il promemoria di fiducia."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Impossibile aggiornare Promemoria di Scadenza"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Impossibile aggiornare il Promemoria Livello Serbatoio Basso"; - -/* Pod life HUD view label */ -"Fault" = "Guasto"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Si è verificato un errore"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Riempire un nuovo Pod con insulina U-100 (lasciare il cappuccio blu del Pod)."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Completa la disattivazione"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Disattivazione completata"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Abbinamento completato"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Completa l'installazione"; - -/* Description for finish setup */ -"Finish setup " = "Termina configurazione"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Promemoria configurazione completa"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Versione Firmware"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Più di %1$@ unità rimanenti a %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "ora"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "ore"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Se annulli la configurazione del Pod, il Pod corrente verrà disattivato e sarà inutilizzabile."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Eccezione pacchetto errato: %1$@ (posizione=%2$d)"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Risposta errata"; - -/* Pod inititialized */ -"Initialized" = "Inizializzato"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Inserire Cannula"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserito"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Inserimento Cannula"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Inserimento. Attendere prego."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserimento..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Erogazione Insulina sospesa"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulina Somministrata"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "L'erogazione d'insulina si è interrotta. Cambiare Pod adesso."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "La somministrazione d'insulina verrà interrotta fino a quando non riprenderà manualmente. Quando vuoi che Loop ti ricordi di riprendere la consegna?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulina Rimanente"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Erogazione Insulina sospesa"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Tipo d'insulina"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Tipo d'insulina non Configurato"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Errore interno Pod %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Bolo Interrotto: %1$@ U (%2$@ U previste) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Indirizzo non valido 0x %1$x . Previsto 0x %2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Indirizzo non valido: ( %1$@ )"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "CRC non valido"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Chiave LTK non valida: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Impostazione non valida"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "La cannula è inserita correttamente?"; - -/* description label for last status date pod details row */ -"Last Status" = "Ultimo stato"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Ascolta 2 segnali acustici."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop non regolerà automaticamente l'erogazione d'insulina fino a quando l'impostazione della basale temporanea non sarà terminata o cancellata."; - -/* description label for lot number pod details row */ -"Lot Number" = "Numero di Lotto"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Livello Serbatoio basso"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Livello Serbatoio basso"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Notifica serbatoio basso (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Allarme di avviso livello serbatoio basso"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Promemoria Livello Serbatoio Basso"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Assicurati che l'iPhone sia vicino al Pod attivo"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Assicurati che il tuo telefono e il Pod siano vicini uno all'altro. Se il problema di comunicazione persiste, spostati in un'altra zona."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Assicurati che il tuo Pod sia pieno e nelle vicinanze."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Assicurati che il tuo Pod sia nelle vicinanze e riprova."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Assicurati che RileyLink si trovi nelle vicinanze e sia acceso"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Basale Manuale"; - -/* Pod memory initialized */ -"Memory initialized" = "Memoria inizializzata"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Errore nell'accedere file del tipo IO: %1$@ "; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minuto"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minuti"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Configurazione mancante"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Spostati in una nuova area lontana da qualsiasi altro Pod e riprova."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Avviso di comandi multiplo"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "Non disponibile"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Negativo"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Prossimo"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Non Erogazione"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Nessun avviso"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Non vengono utilizzati promemoria sulla fiducia."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Nessun errore"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Insulina Terminata"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "No Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Nessun Pod abbinato"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Nessun Pod trovato"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Nessun promemoria"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Nessuna risposta da Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Nessun RileyLink disponibile"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continuare con il Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, mantienere la pompa così com'è"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normale"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Dati non sufficienti"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Impostazioni"; - -/* No comment provided by engineer. */ -"Numbers" = "Numeri"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Occlusione rilevata"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Occlusione Rilevata"; - -/* Action button default text for PodAlerts */ -"Ok" = "OK"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Promemoria Omnipod"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Abbina Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Abbina Pod."; - -/* Pod status after pairing */ -"Paired" = "Abbinato"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Abbinamento completato"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Abbinamento non eseguito:%1$@"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Abbinamento in corso."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Abbinamento in corso..."; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Errore di analisi: %1$@ in ( %2$@ )"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = "Il payload crc32 %1$@ non corrisponde al crc32 calcolato %2$@"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percentuale = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Periferica non pronta"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Si prega di portare solo il pod originale nel raggio d'azione o disattivare il pod originale"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Avvicina Pod a RileyLink e riprova"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Si prega di confermare che il Pod è saldamente fissato al corpo.\n\nLa cannula può essere inserita una sola volta con ogni Pod. Tocca \"Conferma\" quando Pod è collegato."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Si prega di disattivare il Pod. Al termine della disattivazione, è possibile associare un nuovo Pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Si prega di disattivare il Pod. Al termine della disattivazione, è possibile rimuoverlo e accoppiare un nuovo Pod."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Si prega di abilitare le autorizzazioni bluetooth per questa app nelle impostazioni di sistema"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Completa l'abbinamento del tuo Pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Abbina nuovo Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Si prega di riposizionare iPhone più lontano dal Pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Si prega di riposizionare iPhone rispetto al Pod"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Si prega di utilizzare un dispositivo diverso con funzionalità Bluetooth"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod attivato"; - -/* Label describing pod age view */ -"Pod Age" = "Età Pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod già abbinato"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod già caricato"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod disattivato con successo. Continua."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Errore Pod"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Allarme di avviso scadenza Pod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Avviso di scadenza Pod"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Promemoria scadenza Pod"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod scaduto"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod Scaduto"; - -/* Label for pod expiration row */ -"Pod Expires" = "Scadenza Pod"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod scade in"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod scade in %1$@."; - -/* description label for pod fault details */ -"Pod Fault Details" = "Dettagli errore Pod"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Errore Pod: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod non è pronto per l’inserimento della cannula."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod non è pronto per il caricamento"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod sospeso"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "Pod non connesso"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Occlusione Pod"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod accoppiato con successo. Continua."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Accoppiamento Pod incompleto"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod ha inviato una conferma anziché una risposta"; - -/* Title for PodSetupView */ -"Pod Setup" = "Configurazione Pod"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Finestra di configurazione Pod scaduta"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Promemoria sospensione Pod"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Scarsa potenza segnale"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Preparare il sito."; - -/* title for previous pod page */ -"Previous Pod" = "Pod precedente"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informazioni Pod precedente"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Caricamento in corso"; - -/* Pod state when priming completed */ -"Priming completed" = "Caricamento completato"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Caricamento in corso. Attendere prego."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Caricamento in corso..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Orario Micro"; - -/* Label text for basal rate summary */ -"Rate" = "Velocità"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Pronto per la programmazione basale"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Pronto per l’inserimento della cannula"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Rimanente"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Promemoria inizializzato"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Rimuovere il cappuccio blu dell'ago del Pod e controllare la cannula. Quindi rimuovere il supporto di carta."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Rimuovi il Pod dal corpo"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Rimuovere microinfusore"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Sostituisci Pod"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Riprendi"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Riprendi erogazione"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Riprendi l'insulina"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Riprendi Erogazione Insulina"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Riprendi: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Ripresa erogazione insulina..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Riprova"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Salva"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Salvataggio..."; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Basale Programmata"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Basale Programmata"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Promemoria Programmato"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Seleziona il tipo d'insulina che utilizzerai in questo Pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Numero progressivo"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Impostazione Base Temporanea"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Impostazione Base Temporanea"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Impostazione completata"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Chiusura imminente"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Allarme di spegnimento imminente"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Perdita Segnale"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Potenza del segnale troppo alta"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Saltare la procedura di installazione di Omnipod?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Blocco Erogazione"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Sospendi erogazione"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Promemoria sospensione in corso"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Sospendi l'erogazione d'insulina"; - -/* Description for suspend time expired */ -"Suspend time expired" = "il tempo della sospensione e' scaduto"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Sospeso: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Sospeso"; - -/* Label for suspended at time */ -"Suspended At" = "Sospeso a"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Sospendere l'erogazione d'insulina..."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Il tempo di sospensione è scaduto. Apri l'app e riprendi."; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Passare ad un altro dispositivo per la somministrazione d'insulina"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sincronizza con l'ora corrente"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Riempimento del serbatoio completato"; - -/* Pod power to motor activated */ -"Tank power activated" = "Alimentazione del serbatoio attivata"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tocca sotto per iniziare l'inserimento della cannula."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Basale Temporanea"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Velocità basale temporanea in corso"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Velocità basale temporanea in esecuzione"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "VelocitàBasaleTemporanea: %1$@ U/ora %2$@ %3$@ %4$@ U %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Basale Temporanea"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Basale Temporanea Fallita"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "L'App puo' configurare un promemoria capace di avvisare in anticipo della scadenza del Pod.\n\nPer impostare il numero di ore preferito per il preavviso dalla voce Omnipod della schermata principale usare i submenu' Configurazione>Impostazioni Notifiche>Notifica Scadenza e sceglire il numero di ore desiderato per l'avviso di scadenza."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "L'App può avvisare in anticipo della scadenza del Pod.\n\nPer impostare il numero di ore in anticipo desiderato scorrere nella lista ore ed impostare il numero di ore desiderato"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "L'App puo' dare un avviso quando la quantità di insulina nel Pod raggiunge un certo determinato livello compreso fra 50-10 Unita'.\n\nPer impostare questo avviso scorrere nella lista delle Unita' di insulina e scegliere il numero per il quale si desidera ricevere l'avviso."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "L'App puo' avvisare quando la quantità di insulina nel Pod raggiunge un predisposto determinato livello."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Il periodo di sospensione dell'insulina è terminato.\n\nSi puo' ripristinare l'erogazione usando direttamente l'avviso nella schermata principale oppure dalla schermata delle impostazioni del microinfusore. Ogni 15 minuti ci sara' un avviso che ti ricordera' di ripristinare l'erogazione."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "l'orario del microinfusore e' diverso da quello del tempo attuale. Vuoi fare un controllo e cambiare l'orario del microinfusore con il tempo attuale?"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "l'orario del microinfusore e' diverso da quello del tempo reale. Controllare l'orario del microinfusore e sincronizzare il settaggio con il l'orario attuale."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "L'orario impostato nel microinfusore è diverso dall'orario corrente. L'orario del microinfusore detta e controlla le impostazioni della terapia programmata e va corretto: Nella lista degli 'orari del microinfusore verificare la differenza di orario e configurare correttamente il microinfusore."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "La finestra nella parte superiore del Pod sara' di colore rosa quando la cannula è stata inserita correttamente nella pelle."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Si è verificato un problema di comunicazione con il Pod. Se il problema persiste, toccare Elimina Pod, e dopo si procedere ad attivare un nuovo Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Questo è un promemoria che hai pianificato quando hai accoppiato il tuo Pod corrente."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Il manager di questo microinfusore non è stato configurato con una dose di basale massima perché questa è stata inserita prima che la basale temporanea manuale diventasse una funzione attiva. Si prega di Andare su Impostazioni terapia - > Limiti erogazione e impostare un nuovo profilo di basale massima."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Tempo"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Rilevato Cambio di orario "; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "È ora di sostituire Pod! Pod scadrà tra %1$@"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Tempo scaduto"; - -/* No comment provided by engineer. */ -"Toggle sign" = "segnale di attivazione/disattivazione"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Trovati Troppi Pods"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Erogazione Totale"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Riprovare"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Attiva il Bluetooth"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/ora"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Impossibile raggiungere Pod"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Impossibile raggiungere Pod"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Impossibile impostare una velocità basale temporanea: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Impossibile impostare una velocità basale temporanea: %1$@\n\n%2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Incerto"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Notifica inaspettata di sequenza numerica "; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Cambio pod imprevisto"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Risposta inaspettata dal Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Attivazione non completata"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Disattivazione non completata"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Caratteristica sconosciuta"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Errore Pod sconosciuto %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Valore sconosciuto%1$@per tipo%2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Convalida fallita: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Attendi il termine del bolo esistente oppure annulla bolo"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Attendi il termine della velocità basale temporanea esistente oppure sospendi per annullare"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Attendere il completamento dell'inserimento."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "In attesa del promemoria di abbinamento"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "sì"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Sì, disattiva il pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Sì, sincronizza con l'ora corrente"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Ora inizierai il processo di configurazione dei tuoi promemoria, riempiendo il tuo Pod d'insulina, accoppiandolo al tuo dispositivo e posizionandolo sul tuo corpo."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Il tuo Pod è pronto per l'uso. \n\n %1$@ ti ricorderà di cambiare il tuo pod prima che scada. Questo orario puo' cambiato per un altro a te piu' conveniente."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Il tuo Pod potrebbe ancora erogare insulina.\n Rimuovilo dal tuo corpo, e poi tocca \"Continua\"."; - diff --git a/Dependencies/OmniBLE/OmniBLE/ja.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/ja.lproj/Localizable.strings deleted file mode 100644 index a933ee71a..000000000 --- a/Dependencies/OmniBLE/OmniBLE/ja.lproj/Localizable.strings +++ /dev/null @@ -1,278 +0,0 @@ -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ 前"; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%2$@の時点で %1$@ U 残っています"; - -/* description label for active time pod details row */ -"Active Time" = "アクティブ時間"; - -/* Section header for activity section */ -"Activity" = "アクティビティ"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "アラーム自動オフ"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "50Uより下"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "ボーラス"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "ボーラスが進行中"; - -/* Delivery status when bolusing */ -"Bolusing" = "ボーラス注入中"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "一時基礎とボーラス"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "キャンセル"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "カニューレ挿入中"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "確実"; - -/* Section header for configuration section */ -"Configuration" = "コンフィグレーション"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "次へ"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "ポッドを無効にする"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "停止されました"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "リザーバが空です"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "ポッドからの反応 - 空"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "有効"; - -/* Accessibility label indicating an error occurred */ -"Error" = "エラー"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "エラーイベントを保存、終了します"; - -/* Description for expiration alert */ -"Expiration alert" = "期限切れアラート"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "有効期限リマインダー"; - -/* Pod life HUD view label */ -"Fault" = "エラー"; - -/* Description for finish setup */ -"Finish setup " = "設定終了"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "ファームウェアバージョン"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "%2$@時点で %1$@U以上残っています"; - -/* Pod inititialized */ -"Initialized" = "初期化完了"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "カニューレを挿入"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "インターナルポッドエラー %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "ボーラス中断: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "リザーバ残量低下アラーム"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "RileyLink が近くにあり電源が入っているか確認"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "アラートなし"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "ポッドペアリングできません"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "ポンド反応なし"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "RileyLinkがありません"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "通常"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "閉塞があります"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "ペアリングされました"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "ポッドを RileyLink に近づけてやり直してください"; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "新しいポッドをペアリングしてください"; - -/* Label describing pod age view */ -"Pod Age" = "ポッド経過時間"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "既にペアリングされています"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "プライミングされています"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "ポッド期限アラーム"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "ポッド期限注意"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "ポッド期限切れ"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "ポッドエラー: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "ポッドがカニューレを挿入できる状態ではありません。"; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "ポッドがプライミングできる状態ではありません。"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "ポッドが一時停止"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "ポッドの設定期限切れ"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "プライミング"; - -/* Pod pairing action button text while priming */ -"Priming..." = "プライミング中"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "基礎レート設定できます"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "カニューレを挿入できます"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "残り"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "ポッドを交換"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "再開: %1$@ %2$@"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "やり直す"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "保存"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "定期基礎"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "設定完了"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "今から鳴るアラームを切る"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "注入を一時停止"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "一時停止: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "一時停止"; - -/* Pod tank fill completed */ -"Tank fill completed" = "タンクが満たされました"; - -/* Pod power to motor activated */ -"Tank power activated" = "タンクがオンになりました"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "一時基礎進行中"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "一時基礎注入中"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "一時基礎: %1$@ U/時 %2$@ %3$@ %4$@ U %5$@"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "ポッドの交換時です。 %1$@でポッドの期限が切れます。"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/時"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "不明"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "ポッドから予期せぬ反応"; - diff --git a/Dependencies/OmniBLE/OmniBLE/nb.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/nb.lproj/Localizable.strings deleted file mode 100644 index 258d3dc9d..000000000 --- a/Dependencies/OmniBLE/OmniBLE/nb.lproj/Localizable.strings +++ /dev/null @@ -1,1130 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = "(inaktiv)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ siden"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ har gjenopprettet kommunikasjonen med pod på kroppen din. \n\n Insulintilførselsjournaler er oppdatert og bør samsvare med det som faktisk ble levert. \n\n Du kan fortsette å bruke %@ normalt nå."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ E"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ har ikke vært i stand til å kommunisere med pod på kroppen din siden %2$@ . \n\n Uten kommunikasjon med pod kan ikke appen fortsette å sende kommandoer for insulintilførsel eller vise nøyaktig, fersk informasjon om ditt aktive insulin eller insulinet som leveres av pod. \n\n Overvåk blodsukkerverdi nøye de neste 6 timene eller mer, siden det kan være insulin som virker aktivt i kroppen din som %3$@ ikke kan vise."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin eller mindre gjenstår i Pod. Bytt Pod snart."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ enheter gjenstår ved %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@ + %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g E"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 time"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 time 30 minutter"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 timer"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutter"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Aktiveringstiden er overskredet"; - -/* description label for active time pod details row */ -"Active Time" = "Aktiv tid"; - -/* Section header for activity section */ -"Activity" = "Aktivitet"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Justerer pumpetid..."; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Er du sikker på at du vil avbryte Pod-oppsettet?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Er du sikker på at du vil hoppe over Omnipod Onboarding?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Er du sikker på at du vil slutte å bruke Omnipod DASH?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Fest Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Prøver å gjenopprette kommunikasjonen"; - -/* Description for auto-off */ -"Auto-off" = "Auto-av"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Alarm for automatisk av"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Tilbake"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialisert"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Under 50 enheter"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE fastvareversjon"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth er slått av"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Bluetooth tilbakestilles"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth er utilgjengelig av en ukjent grunn."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth er utilgjengelig: %1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "Bruk av Bluetooth er uautorisert"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "Bluetooth-bruk støttes ikke på denne enheten"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus pågår"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@E %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Gir bolus"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Gir bolus med temp-basal"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Avbryt"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Avbryt manuell basal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanyle skutt inn vellykket. Fortsett."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Setter inn kanyle"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Sikker"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Bytt Pod nå. Insulintilførselen vil stoppe 8 timer etter at pod har utløpt eller når det ikke er mer insulin igjen."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Bytt Pod nå. Insulintilførselen vil stoppe om %1$@ eller når det ikke er mer insulin igjen."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Bytt Pod nå. Insulintilførselen stoppes om 1 time."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Bytt Pod nå. Pod har vært aktiv i 72 timer."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Sjekk kanyle"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Sjekk pod, påfør, og bekreft deretter at pod er festet."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Kontrollerer innsetting"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Sjekker..."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Kommandofeil %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Kommunikasjonsutgave"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Kommunikasjon gjenopprettet"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Kommunikasjonsproblem: Ukjent kommando venter."; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Bekreftelser"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Tillitspåminnelser er pip fra pod som kan brukes til å bekrefte valgte kommandoer."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Tillitspåminnelser høres for kommandoer du starter, for eksempel bolus, avbryt bolus, suspendere, gjenoppta, lagre varslingspåminnelser osv. Når Loop automatisk justerer leveringen, brukes mistillitspåminnelser."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Tillitspåminnelser vil høres når Loop automatisk justerer leveringen så vel som for kommandoer du starter."; - -/* Section header for configuration section */ -"Configuration" = "Konfigurasjon"; - -/* Button title for confirm attachment option */ -"Confirm" = "Bekreft"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bekreft at Pod er festet"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Fortsett"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "Kunne ikke analysere meldingen: %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritiske varsler"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Pod-feil"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk mulig. Vennligst flytt til et nytt sted"; - -/* Unit for singular day in pod life remaining */ -"day" = "dag"; - -/* Unit for plural days in pod life remaining */ -"days" = "dager"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Deaktiver Pod"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktivert"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktiverer."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deaktiverer..."; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Slett Omnipod DASH"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Enhetsdetaljer"; - -/* description label for device name pod details row */ -"Device Name" = "Enhetsnavn"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Deaktivert"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Kast Pod"; - -/* No comment provided by engineer. */ -"Done" = "Ferdig"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Tomt reservoar"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Tomt reservoar"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Tomt svar fra pod"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Tom verdi"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Aktivert"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Feil"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Feil logget, avslutter"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Veiledning for utløp"; - -/* Description for expiration alert */ -"Expiration alert" = "Utløpsalarm"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Påminnelse om utløp"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Utløpspåminnelse Standard"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Forlenget"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Forlenget boluskjøring"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Forlenget boluskjøring med temp basal"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Kunne ikke avbryte manuell basal"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Kunne ikke gjenoppta insulinlevering"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Kunne ikke stille inn klokkeslett for pumpe"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Kunne ikke stanse insulintilførselen"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Kan ikke oppdatere innstillinger for påminnelsesalarm."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Kunne ikke oppdatere Utløpspåminnelse"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Kunne ikke oppdatere påminnelsen om lavt reservoar"; - -/* Pod life HUD view label */ -"Fault" = "Feil"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Feilhendelse oppstod"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Fyll en ny pod med U-100 insulin (la den blå nålehetten være på)."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Fullfør deaktivering"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Fullfør deaktivering"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Fullfør sammenkoblingen"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Fullfør oppsettet"; - -/* Description for finish setup */ -"Finish setup " = "Ferdigstill oppsett"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Fullfør varselinnstilling"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware versjon"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Større enn %1$@ enheter igjen ved %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "time"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "timer"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Hvis du avbryter Pod-oppsettet, vil gjeldende Pod deaktiveres og bli ubrukelig."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Feil pakkeunntak: %1$@ (lokasjon=%2$d)"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Feil respons"; - -/* Pod inititialized */ -"Initialized" = "Klargjort"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Før inn kanyle"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Ført inn"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Skyter inn kanyle"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Fører inn. Vennligst vent."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Fører inn..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulintilførsel utsatt"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulintilførselen stoppet. Bytt Pod nå."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulintilførselen vil bli stoppet til du gjenopptar manuelt. Når vil du at Loop skal minne deg på å gjenoppta leveringen?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Gjenværende insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulintilførsel utsatt"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulintype"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulintype ikke konfigurert"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Intern pod-feil %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "InterruptedBolus: %1$@ E (%2$@ E planlagt) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Ugyldig adresse 0x%1$x. Forventet 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Ugyldig adresse: ( %1$@ )"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Ugyldig CRC"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Ugyldig LTK-nøkkel: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ugyldig konfigurasjon"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Er kanylen satt inn riktig?"; - -/* description label for last status date pod details row */ -"Last Status" = "Siste status"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Lytt etter 2 pip."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop vil ikke automatisk justere insulintilførselen før den midlertidige basaldosen er ferdig eller avbrytes."; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot-nummer"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Lavt reservoar"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Lavt reservoar"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Varsel om lavt reservoar (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Anbefalt alarm for lavt reservoar"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Påminnelse om lavt reservoar"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Forsikre deg om at iPhone er i nærheten av den aktive pod"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Forsikre deg om at telefonen og pod er nær hverandre. Hvis kommunikasjonsproblemer vedvarer, flytter du til et nytt område."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Sørg for at pod er fylt og i nærheten."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Kontroller at pod er i nærheten, og prøv på nytt."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Pass på at din RileyLink er slått på og er i nærheten"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuell basal"; - -/* Pod memory initialized */ -"Memory initialized" = "Minne initialisert"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Melding IO-unntak: %1$@"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minutt"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutter"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Mangler Konfigurasjon"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Flytt til et nytt område borte fra andre pods og prøv igjen."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Alarm for fler-kommandoer"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "N/A"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Neste"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nei"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Ingen Leveranse"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Ingen alarmer"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Ingen aktive påminnelser."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Ingen feil"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Ingen insulin"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Ingen Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Ingen sammenkoblet pod"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Ingen pod funnet"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Ingen påminnelse"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Ingen svar fra pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Ingen RileyLink tilgjengelig"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nei, fortsett med Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nei, behold pumpen som den er"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Ikke nok data"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Varslingsinnstillinger"; - -/* No comment provided by engineer. */ -"Numbers" = "Tall"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Tilstoppelse oppdaget"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Okklusjon oppdaget"; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Alert acknowledgment OK button */ -"OK" = "Ok"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod-påminnelser"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Par Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Sammenkoble pod."; - -/* Pod status after pairing */ -"Paired" = "Sammenkoblbet"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Sammenkobling fullført"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Paringsunntak: %1$@"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Kobler sammen."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Kobler sammen..."; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Analysefeil: %1$@ i (%2$@)"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = "Payload crc32 %1$@ does not match computed crc32 %2$@"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Prosent = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Periferutstyr ikke klar"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Ta kun med original pod innenfor rekkevidde eller deaktiver original pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Prøv å sette pod og RileyLink nærmere hverandre og prøv så igjen"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Vennligst bekreft at pod er godt festet til kroppen din. \n\n Kanylen kan bare settes inn én gang med hver pod. Trykk på \"Bekreft\" når pod er festet."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Vennligst deaktiver pod. Når deaktiveringen er fullført, kan du pare en ny pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Vennligst deaktiver pod. Når deaktiveringen er fullført, kan du fjerne den og pare en ny pod."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Aktiver Bluetooth-tillatelser for denne appen i systeminnstillingene"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Vennligst fullfør sammenkoblingen av pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Vennligst koble til ny pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Vennligst flytt iPhone lenger fra pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Vennligst flytt iPhone i forhold til pod"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Bruk en annen enhet med Bluetooth-funksjoner"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Aktivert"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Alder"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod er allerede sammenkoblet"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod er allerede fyllt"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod ble deaktivert. Fortsett."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Pod Feil"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Anbefalt utløpsalarm for pod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Utløpsmelding for pod"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod utløpspåminnelse"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod utløpt"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod Utløpt"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod Utløper"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod utløper om"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod utløper om %1$@ ."; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod-feildetaljer"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod-feil: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod er ikke klar for å sette inn kanyle."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod er ikke klar for fylling"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod er suspendert"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "Pod ikke tilkoblet"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Okklusjon"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Vellykket sammenkobling av Pod. Fortsett."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Ufullstendig Pod-sammenkobling"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sendte ack i stedet for svar"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod oppsett"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Tidsvindu for oppsett av pod er utløpt"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pod påminnelse er suspendert"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Dårlig signalstyrke"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Klargjør infusjonsstedet"; - -/* title for previous pod page */ -"Previous Pod" = "Forrige pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informasjon om forrige pod"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Fyller"; - -/* Pod state when priming completed */ -"Priming completed" = "Fylling fullført"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Fyller. Vennligst vent."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Fyller..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pumpetid"; - -/* Label text for basal rate summary */ -"Rate" = "Rate"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Klar for basal-programmering"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Klar for å sette inn kanyle"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Gjenstående"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Påminnelse initialisert"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Fjern den blå nålehetten og sjekk at kanylen ikke stikker ut. Fjern deretter plasterbeskyttelsen."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Fjern pod fra kroppen"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Fjern pumpen"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Bytt pod"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Gjenoppta"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Gjenoppta levering"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Gjenoppta insulin"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Gjenoppta insulintilførsel"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Fortsett: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Gjenopptar insulintilførsel..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Prøv på nytt"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Lagre"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Lagrer..."; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Planlagt basal"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Planlagt basal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Planlagt påminnelse"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Velg hvilken type insulin du skal bruke i denne pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sekvensnummer"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Still inn midlertidig basal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Still inn midlertidig basaldose"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Klargjøring ferdig"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Avslutning nært forestående"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Avslutt forestående alarm"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Tap"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signalstyrken er for høy"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Vil du hoppe over Omnipod Introduseringen?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Utsette"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Pause leveranse"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Varsel om aktivert Utsettelse"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Insulintilførsel utsatt"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Utsettelse utløpt"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Pause: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspendert"; - -/* Label for suspended at time */ -"Suspended At" = "Utsatt klokken"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Utsetter insulintilførselen..."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Utsettelsestiden er over. Åpne appen og gjenoppta."; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Bytt til annen insulintilførselsenhet"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synkroniser til gjeldende tid"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Tankpåfylling komplett"; - -/* Pod power to motor activated */ -"Tank power activated" = "Tank-motor aktivert"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Trykk nedenfor for å starte innsetting av kanyle."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Midlertidig basal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Midlertidig basal pågår"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Midlertidig basal kjører"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "Midlertidig basal: %1$@ E/time %2$@ %3$@ %4$@ E %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Midlertidig basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Midlertidig basal mislyktes"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Appen konfigurerer en påminnelse på pod for å varsle deg før pod utløper. Angi antall timer forhåndsvarsel du vil konfigurere når du parer en ny Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Appen varsler deg før pod utløper.\n\nBla for å angi antall timer forhåndsvarsel du vil ha."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Appen varsler deg når mengden insulin i Pod når dette nivået (50-10 E).\n\nBla for å angi antall enheter du vil bli minnet på."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Appen varsler deg når mengden insulin i pod når dette nivået."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Perioden med insulinsuspensjon er avsluttet.\n\nDu kan gjenoppta leveringen fra banneret på startskjermen eller fra skjermbildet for pumpeinnstillinger. Du vil bli påminnet igjen om 15 minutter."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Påminnelsene ovenfor vil ikke høres hvis enheten er i Stille- eller Ikke forstyrr-modus. \n\n Det er andre kritiske Pod-varsler og alarmer som vil høres selv om enheten er satt til Stille eller Ikke forstyrr-modus."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Klokken på pumpen er forskjellig fra gjeldende tid. Vil du oppdatere tiden på pumpen til gjeldende tid?"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Klokken på pumpen er forskjellig fra gjeldende tid. Du kan se på pumpetiden og og synkronisere med gjeldende tid i innstillingene."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Klokken på pumpen er forskjellig fra gjeldende tid. Pumpens tid styrer dine planlagte behandlingsinnstillinger. Rull ned til Pumpetid-raden for å se tidsforskjellen og konfigurere pumpen."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Vinduet på toppen av Pod-en skal farges rosa når kanylen er riktig satt inn i huden."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Det oppsto et problem med pod-kommunikasjonen. Hvis problemet fortsetter, trykk Forkaste pod. Deretter kan du aktivere en ny pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dette er en påminnelse som du planla når du koblet til din nåværende pod."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Denne PumpManageren er ikke konfigurert med en maksimal basaldose fordi den ble lagt til før manuell temp basal var en funksjon. Vennligst gå til terapiinnstillinger - > leveringsgrenser og angi en ny maksimal basaldose."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "treNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Tid"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Tidsendring oppdaget"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Det er på tide å bytte pod! Pod utløper om %1$@"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Tidsavbrudd"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Vis/skjul"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "For mange poder funnet"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total levering"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Prøv igjen"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Slå på Bluetooth"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "toNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "E/t"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Kan ikke nå pod"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Kan ikke nå pod"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Klarte ikke å angi en midlertidig basal: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Klarte ikke å angi en midlertidig basal: %1$@\n\n%2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Usikker"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Uventet meldings sekvensnummer"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Uventet pod-endring"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Uventet svar fra pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Ufullstendig aktivering"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Ufullstendig deaktivering"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Ukjent karakteristikk"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Ukjent pod-feil %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Ukjent verdi ( %1$@ ) for typen %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Valideringen mislyktes: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Vent til at eksisterende bolus skal bli ferdig, eller kanseler bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Venter på at eksisterende temp-basal skal bli ferdig, eller at pause skal avsluttes"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Vent til innsettingen er fullført."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Venter på påminnelse for sammenkobling"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, deaktiver Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, Synkroniser til gjeldende tid"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Du vil nå begynne prosessen med å konfigurere påminnelsene, fylle pod med insulin, pare til enheten og plassere den på kroppen."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Pod er klar til bruk. \n\n %1$@ vil minne deg på å bytte pod før den utløper. Du kan endre dette til et tidspunkt som passer deg."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Pod kan fortsatt levere insulin.\nFjern den fra kroppen din, og trykk deretter på \"Fortsett\"."; - diff --git a/Dependencies/OmniBLE/OmniBLE/nl.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/nl.lproj/Localizable.strings deleted file mode 100644 index 31df48538..000000000 --- a/Dependencies/OmniBLE/OmniBLE/nl.lproj/Localizable.strings +++ /dev/null @@ -1,1130 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactief)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ geleden"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ heeft de communicatie met de pod op je lichaam hersteld. \n\nDe gegevens over insulinetoediening zijn bijgewerkt en moeten overeenkomen met wat daadwerkelijk is toegediend. \n\nJe kunt %@ nu weer normaal gebruiken."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ E"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ voor %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ kan sinds %2$@ niet communiceren met de pod op je lichaam. \n\nZonder communicatie met de pod kan de app geen opdrachten voor insulinetoediening blijven sturen of nauwkeurige, recente informatie weergeven over je actieve insuline of de insuline die door de pod wordt toegediend. \n\nHoud je glucose de komende 6 uur of langer nauwlettend in de gaten, omdat er wel of geen actieve insuline in je lichaam aanwezig is die %3$@ niet kan weergeven."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insuline of minder resterend in Pod. Vervang Pod spoedig."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ eenheden over om %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g E"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 uur"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 uur 30 minuten"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 uur"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minuten"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Activeringstijd overschreden"; - -/* description label for active time pod details row */ -"Active Time" = "Werkzame Tijd"; - -/* Section header for activity section */ -"Activity" = "Activiteit"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pomptijd Aanpassen..."; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Weet je zeker dat je de Podinstallatie wilt annuleren?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Weet je zeker dat je Omnipod Onboarding wilt overslaan?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Weet je zeker dat je wilt stoppen met het gebruik van Omnipod DASH?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Pod Aanbrengen"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Poging om de communicatie te herstellen"; - -/* Description for auto-off */ -"Auto-off" = "Automatische uitschakeling"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-uit alarm"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Terug"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basaal geïnitialiseerd"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Minder dan 50 eenheden"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmwareversie"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth is uitgeschakeld"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Bluetooth wordt gereset"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth is om een onbekende reden niet beschikbaar."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth is niet beschikbaar: %1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "Bluetooth gebruik is niet toegestaan"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "Bluetooth-gebruik wordt niet ondersteund op dit apparaat"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus in uitvoering"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@E %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolussen"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolussen met tijdelijk basaal"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Annuleer"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Annuleer Handmatige Basaal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Canule succesvol ingebracht. Ga verder."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Canule ingebracht"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Zeker"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Vervang Pod nu. De insulinetoediening stop 8 uur nadat de Pod is verlopen of wanneer er geen insuline meer over is."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Vervang Pod nu. De insulinetoediening stop over %1$@ of wanneer er geen insuline meer over is."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Vervang Pod nu. Insulinetoediening stopt over 1 uur."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Vervang Pod nu. Pod is 72 uur in gebruik geweest."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Controleer Canule"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Controleer de Pod, breng aan op de infusieplaats en bevestig dat de pod goed zit vastgeplakt."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Controleer Inbrengen Canule"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Controleren..."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Opdrachtfout %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Communicatieprobleem"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comms Hersteld"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Communicatieprobleem: niet-bevestigde opdracht in behandeling"; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Bevestigingsherinneringen"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Bevestigingsherinneringen zijn piepjes van de pod die kunnen worden gebruikt ter bevestiging van de geselecteerde opdrachten."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Bevestigingsherinneringen zijn hoorbaar voor opdrachten die je start, zoals bolussen, bolus annuleren, onderbreken, hervatten, meldingsherinneringen opslaan, enz. Wanneer Loop de toediening automatisch aanpast, zijn er geen bevestigingsherinneringen hoorbaar."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Bevestigingsherinneringen zijn hoorbaar wanneer Loop de toediening automatisch aanpast, evenals voor opdrachten die je geeft."; - -/* Section header for configuration section */ -"Configuration" = "Configuratie"; - -/* Button title for confirm attachment option */ -"Confirm" = "Bevestigen"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bevestig Vastgeplakte Pod"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Ga Verder"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "Kon bericht niet parseren: %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritieke Meldingen"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritieke Podfout"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Overspraak mogelijk. Probeer een andere locatie"; - -/* Unit for singular day in pod life remaining */ -"day" = "dag"; - -/* Unit for plural days in pod life remaining */ -"days" = "dagen"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Deactiveer Pod"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Gedeactiveerd"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactiveren."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deactiveren..."; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Verwijder Omnipod DASH"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Apparaatgegevens"; - -/* description label for device name pod details row */ -"Device Name" = "Naam Pod"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Uitgeschakeld"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Gooi Pod Weg"; - -/* No comment provided by engineer. */ -"Done" = "Gereed"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Reservoir leeg"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Reservoir Leeg"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Geen reactie van pod"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Lege Waarde"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Ingeschakeld"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Fout"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Fout geconstateerd, sluit af"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Vervaldatum melding"; - -/* Description for expiration alert */ -"Expiration alert" = "Alarm vervaltijd"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Vervaldatumherinnering"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standaard Herinnering"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Uitgebreid"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Verlengde bolus actief"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Verlengde bolus met tijdelijk basaal actief"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Handmatig Basaal Annuleren Mislukt"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Insulinetoediening Hervatten Mislukt"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Pomptijd Instellen Mislukt"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Insulinetoediening Onderbreken Mislukt"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Bevestigingsherinneringvoorkeuren bijwerken mislukt."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Vervaldatumherinnering Bijwerken Mislukt"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Bijwerken Reservoir Bijna Leeg Herinnering Mislukt"; - -/* Pod life HUD view label */ -"Fault" = "Fout"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fout is opgetreden"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Vul een nieuwe pod met U-100 insuline (laat de blauwe Podnaalddop zitten)."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Voltooi deactivering"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Voltooi Deactivering"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Voltooi Koppelen"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Voltooi Installatie"; - -/* Description for finish setup */ -"Finish setup " = "Voltooi installatie"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Voltooi instelling van herinnering"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmwareversie"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Meer dan %1$@ eenheden resterend om %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "uur"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "uur"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Als je de Podinstallatie annuleert, wordt de huidige Pod gedeactiveerd en onbruikbaar."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Onjuiste pakketuitzondering: %1$@ (locatie=%2$d)"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Onjuiste Reactie"; - -/* Pod inititialized */ -"Initialized" = "Geinitialiseerd"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Canule Inbrengen"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Ingebracht"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Canule inbrengen"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Aan het inbrengen. Wacht even."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Canule wordt ingebracht..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insuline\nOnderbroken"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulinetoediening"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulinetoediening gestopt. Vervang Pod nu."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "De insulinetoediening wordt gestopt totdat je de toediening handmatig hervat. Wanneer wil je dat Loop je eraan herinnert de toediening te hervatten?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Resterende Insuline"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insuline Onderbroken"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulinetype"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulinetype niet ingesteld"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Interne podfout %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "OnderbrokenBolus: %1$@ E (%2$@ E gepland) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Ongeldig adres 0x%1$x. Verwachte 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Ongeldig adres: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Ongeldige CRC"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Ongeldige LTK sleutel: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ongeldige Instelling"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Is de canule juist ingebracht?"; - -/* description label for last status date pod details row */ -"Last Status" = "Laatste Status"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Luister naar 2 piepjes."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop past je insulinetoediening niet meer automatisch aan totdat de tijdelijke basaalsnelheid afloopt of wordt geannuleerd."; - -/* description label for lot number pod details row */ -"Lot Number" = "Lotnummer"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Reservoir bijna leeg"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Reservoir Bijna Leeg"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Reservoir Bijna Leeg Advies (%1$gE)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Reservoir bijna leeg alarm"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Herinnering Reservoir Bijna Leeg"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Zorg ervoor dat iPhone zich in de buurt van de actieve pod bevindt"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Zorg ervoor dat je telefoon en pod zich dicht bij elkaar bevinden. Als de communicatieproblemen aanhouden, ga dan naar een andere plek."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Zorg ervoor dat je pod gevuld en binnen bereik is."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Zorg dat je pod in de buurt is en probeer opnieuw."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Zorg ervoor dat je RileyLink dichtbij is en aan staat"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Handmatig Basaal"; - -/* Pod memory initialized */ -"Memory initialized" = "Geheugen geïnitialiseerd"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Bericht IO Uitzondering: %1$@"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minuut"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minuten"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Configuratie Niet Compleet"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Ga naar een andere plek, weg van andere pods, en probeer opnieuw."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Meerdere Commando's Melding"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NB"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Volgende"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nee"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Geen\nToediening"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Geen Waarschuwingen"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Er worden geen bevestigingsherinneringen gebruikt."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Geen fouten"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Geen Insuline"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Geen Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Geen pod gekoppeld"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Geen pods gevonden"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Geen Herinnering"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Geen reactie van pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Geen RileyLink beschikbaar"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nee, Ga Verder Met Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nee, laat de pomp ongewijzigd"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normaal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Onvoldoende Gegevens"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Meldingsinstellingen"; - -/* No comment provided by engineer. */ -"Numbers" = "Nummers"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Verstopping gedetecteerd"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Verstopping Gedetecteerd"; - -/* Action button default text for PodAlerts */ -"Ok" = "OK"; - -/* Alert acknowledgment OK button */ -"OK" = "Ok"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Herinneringen"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "eenNietGebruikt"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Koppel Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Koppel pod."; - -/* Pod status after pairing */ -"Paired" = "Gekoppeld"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Koppelen voltooid"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Koppelingsuitzondering: %1$@"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Koppelen."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Koppelen…"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parseerfout: %1$@ in (%2$@)"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = "Payload crc32 %1$@ komt niet overeen met berekende crc32 %2$@"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Procent = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Apparaat Niet Gereed"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Breng alleen de oude pod binnen bereik of deactiveer de originele pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Breng de pod dichter bij de RileyLink en probeer opnieuw"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Controleer of de Pod goed op je lichaam vastgeplakt zit.\n\nDe canule kan slechts één keer per Pod worden ingebracht. Tik op \"Bevestigen\" wanneer de Pod is vastgeplakt."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Deactiveer de pod. Wanneer de deactivering voltooid is, kun je een nieuwe pod koppelen."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Deactiveer de pod. Wanneer de deactivering voltooid is, kun je deze verwijderen en een nieuwe pod koppelen."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Schakel bluetooth-toestemmingen in voor deze app in de systeeminstellingen."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Voltooi het koppelen van je pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Koppel een nieuwe pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Plaats Iphone verder van de pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Verplaats de iPhone ten opzichte van de pod"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Gebruik een ander apparaat met bluetooth-mogelijkheden"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Geactiveerd"; - -/* Label describing pod age view */ -"Pod Age" = "Podleeftijd"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod al gekoppeld"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod is al voorbereid"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod succesvol gedeactiveerd. Ga verder."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Podfout"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod vervaltijd advies alarm"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod vervaltijd aankondiging"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Herinnering Vervaldatum Pod"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod is verlopen"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod Verlopen"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod Verloopt"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod verloopt over"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod verloopt over %1$@."; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Foutgegevens"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod fout: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is niet gereed voor inbrengen canule."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod is niet klaar om voorbereid te worden."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod is onderbroken"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "Pod niet verbonden"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Podverstopping"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod succesvol gekoppeld. Ga verder."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Koppeling Pod Onvolledig"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod heeft een bevestiging gestuurd in plaats van een antwoord"; - -/* Title for PodSetupView */ -"Pod Setup" = "Podinstallatie"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Insteltijd van de Pod is verlopen"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Herinnering onderbroken Pod"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Zwak signaalsterkte"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Infusieplaats voorbereiden."; - -/* title for previous pod page */ -"Previous Pod" = "Vorige Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informatie Vorige Pod"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Voorbereiden"; - -/* Pod state when priming completed */ -"Priming completed" = "Voorbereiden voltooid"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Voorbereiden. Wacht even."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Voorbereiden..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pomptijd"; - -/* Label text for basal rate summary */ -"Rate" = "Snelheid"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Klaar voor programmeren basaal"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Gereed voor inbrengen canule"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Resterend"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Herinnering geïnitialiseerd"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Verwijder de blauwe Podnaalddop en controleer de canule. Verwijder vervolgens de beschermlaag van de hechtstrip."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Verwijder Pod van Lichaam"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Verwijder Pomp"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Vervang Pod"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Hervatten"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Hervat toediening"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Hervat Insuline"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Hervat Insulinetoediening"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Hervat: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Insulinetoediening hervatten..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Opnieuw Proberen"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Opslaan"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Opslaan..."; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Gepland basaal"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Ingesteld Basaal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Geplande Herinnering"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Selecteer het type insuline dat je in deze pod gaat gebruiken."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Volgnummer"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Tijdelijk Basaal Instellen"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Tijdelijke Basaalsnelheid Instellen"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Configuratie Voltooid"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Afsluiting nadert"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarm voor naderende afsluiting"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signaalverlies"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signaalsterkte te hoog"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Omnipod Onboarding Overslaan?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Onderbreek"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Onderbreek Toediening"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Onderbreking in Uitvoering Herinnering"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Onderbreek Insulinetoediening"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Onderbrekingstijd verstreken"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Onderbreek: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Onderbroken"; - -/* Label for suspended at time */ -"Suspended At" = "Onderbroken om"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Insulinetoediening Onderbreken..."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "De onderbrekingsperiode is verstreken. Open de app en hervat."; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Schakel over op een ander insulinetoedieningsapparaat"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchroniseer met de huidige tijd"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Opslag vullen compleet"; - -/* Pod power to motor activated */ -"Tank power activated" = "Opslag power geactiveerd"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tik hieronder om het inbrengen van de canule te starten."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Tijdelijk Basaal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Tijdelijk basaal wordt uitgevoerd"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Tijdelijk basaal actief"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "Tijdelijk basaal: %1$@ E/uur %2$@ %3$@ %4$@ E %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Tijdelijke Basaal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Tijdelijk Basaal Mislukt"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "De app stelt een herinnering in op de pod om je van tevoren op de hoogte te stellen van het verlopen van de Pod. Stel het aantal uur in van de vooraankondiging die je wenst in te stellen bij het koppelen van een nieuwe Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "De App kondigt van tevoren aan wanneer de Pod verloopt.\n\nScroll om het aantal uren in te stellen voor de gewenste vooraankondiging."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "De App geeft een melding wanneer de hoeveelheid insuline in de Pod dit niveau bereikt (50-10 E).\n\nScroll om het aantal eenheden in te stellen waarbij je herinnerd wilt worden."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "De App geeft een melding wanneer de hoeveelheid insuline in de Pod dit niveau bereikt."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "De insulineonderbrekingsperiode is verstreken.\n\nJe kunt de toediening hervatten op het startscherm of via je pompinstellingenscherm. Over 15 minuten wordt je er opnieuw aan herinnerd."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Bovenstaande herinneringen zijn niet hoorbaar wanneer je apparaat in de modus Stil of Niet Storen staat.\n\nAndere kritieke Podmeldingen en Podalarmen gaan wel af, zelfs als je apparaat op de modus Stil of Niet Storen staat."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "De tijd op je pomp is anders dan de huidige tijd. Wil je de tijd op je pomp bijwerken naar de huidige tijd?"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "De tijd op je pomp is anders dan de huidige tijd. Je kunt de tijd op de pomp bekijken en synchroniseren met de huidige tijd in instellingen."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "De tijd op je pomp is anders dan de huidige tijd. De tijd van je pomp bepaalt je geplande therapieinstellingen. Scroll omlaag naar de Pomptijd om het tijdsverschil te bekijken en de pomp te configureren."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Het venster aan de bovenkant van de pod moet roze gekleurd zijn wanneer de canule correct in de huid is ingebracht."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Er is een communicatieprobleem opgetreden met de pod. Als dit probleem zich blijft voordoen, tik op Pod Verwijderen. Je kunt dan een nieuwe Pod activeren."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dit is een herinnering die je hebt gepland toen je je huidige Pod koppelde."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Deze pomp is niet geconfigureerd met een maximale basaalsnelheid omdat deze toegevoegd is voordat handmatige tijdelijke basaalsnelheid een functie was. Ga naar therapieinstellingen -> toedieningslimieten en stel een nieuwe maximale basaalsnelheid in."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "drieNietGebruikt"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Tijd"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Tijdsverschil Ontdekt"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Tijd om je pod te vervangen! Vervang je pod in %1$@"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Schakel symbool"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Te veel pods gevonden"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Totaal Toegediend"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Probeer opnieuw"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Zet bluetooth aan"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "tweeNietGebruikt"; - -/* Units for showing temp basal rate */ -"U/hr" = "E/uur"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Kan Pod Niet Bereiken"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Kan Pod niet Bereiken"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Kan geen tijdelijke basaalsnelheid instellen: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Kan geen tijdelijke basaalsnelheid instellen: %1$@ \n\n%2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Onzeker"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Onverwacht volgnummer van bericht"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Onverwachte podwissel"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Onverwachte reactie van pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Onvoltooide Activering"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Onvoltooide deactivering"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Onbekend kenmerk"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Onbekende podfout %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Onbekende waarde (%1$@) voor type %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validatie mislukt: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wacht tot huidige bolus is voltooid, of annuleer bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wacht tot de huidig tijdelijk basaalsnelheid is voltooid, of onderbreek om te annuleren"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wacht tot het inbrengen voltooid is."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Wacht op herinnering om te verbinden"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, Deactiveer Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, Synchroniseer met Huidige Tijd"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Je begint nu met het configureren van je herinneringen, het vullen van je Pod met insuline, het koppelen van je apparaat en het op je lichaam plaatsen."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Je Pod is klaar voor gebruik.\n\n%1$@ zal je eraan herinneren je pod te vervangen voordat deze verloopt. Je kunt dit wijzigen naar een tijdstip dat beter uitkomt."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Je Pod kan nog steeds insuline toedienen.\nVerwijder de Pod van je lichaam en tik vervolgens op \"Ga Verder\"."; - diff --git a/Dependencies/OmniBLE/OmniBLE/pl.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/pl.lproj/Localizable.strings deleted file mode 100644 index 7c3a7beea..000000000 --- a/Dependencies/OmniBLE/OmniBLE/pl.lproj/Localizable.strings +++ /dev/null @@ -1,1130 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (nieaktywny)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ temu"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ odzyskało łączność z POD'em na twoim ciele.\n\nZapisy dotyczące podawania insuliny zostały zaktualizowane i powinny odpowiadać temu, co faktycznie zostało dostarczone.\n\nMożesz teraz normalnie korzystać z %@."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ J"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@J"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ za %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ nie może komunikować się z POD'em na twoim ciele od %2$@ . \n\nBez komunikacji z POD'em aplikacja nie może wysyłać poleceń podania insuliny ani wyświetlać dokładnych, aktualnych informacji o aktywnej insulinie lub insulinie podawanej przez POD'a. \n\nUważnie monitoruj poziom glukozy przez następne 6 lub więcej godzin, ponieważ w organizmie może działać insulina, której %3$@ nie może wyświetlić."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "Pozostało mniej niż 1$@ insuliny w POD. Zmień wkrótce POD'a."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ jednostek pozostaje w %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g/J"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 godzina"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 godzina 30 minut"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 godziny"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minut"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Przekroczono czas aktywacji"; - -/* description label for active time pod details row */ -"Active Time" = "Czas aktywności"; - -/* Section header for activity section */ -"Activity" = "Aktywność"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Synchronizacja czasu pompy..."; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Czy na pewno chcesz anulować konfigurację POD'a?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Czy na pewno chcesz pominąć instalację Omnipod’a?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Czy na pewno chcesz przestać używać Omnipod DASH?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Przyklej POD'a do ciała"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Próba przywrócenia komunikacji"; - -/* Description for auto-off */ -"Auto-off" = "Automatyczne wyłączanie"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Alarm automatycznego wyłączenia"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Powrót"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Zainicjowano bazę"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Poniżej 50 jedn."; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "Wersja oprogramowania BLE"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth jest wyłączony"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Trwa resetowanie Bluetooth"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth jest niedostępny z nieznanego powodu."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth jest niedostępny: %1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "Korzystanie z Bluetooth jest niedozwolone"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "Bluetooth nie jest obsługiwany w tym urządzeniu"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus w toku"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Podawanie bolusa"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Podawanie bolusa z dawką podstawową"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Anuluj"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Anuluj ręczną dawkę podstawową"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kaniula wprowadzona prawidłowo. Kontynuuj."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Wprowadzanie kaniuli"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Pewna"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Zmień POD teraz. Podawanie insuliny zostanie zatrzymane 8 godzin po wygaśnięciu POD'a lub gdy zabraknie insuliny."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Zmień POD. Podawanie insuliny zostanie zatrzymane za %1$@ lub gdy zabraknie insuliny."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Zmień POD'a teraz. Podawanie insuliny zostanie wstrzymane za 1 godzinę."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Zmień teraz POD'a. POD jest aktywny od 72 godzin."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Sprawdź kaniulę"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Przyklej POD'a, następnie potwierdź jego założenie"; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Sprawdzanie wkłucia"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Sprawdzanie..."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Błąd polecenia %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problem z komunikacją"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Odzyskano komunikację"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Problem z komunikacją: Niepotwierdzone polecenie w toku."; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Przypomnienia (sygnały dźwiękowe) z POD'a"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Przypomnienia potwierdzające to sygnały dźwiękowe, z których można korzystać w celu potwierdzania wybranych poleceń."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Przypomnienia (sygnały dźwiękowe) będą emitowane w przypadku poleceń, które zainicjujesz, takich jak bolus, anulowanie bolusa, wstrzymanie, wznowienie, zapisanie przypomnień o powiadomieniach itp. Kiedy Loop automatycznie dostosowuje podawanie, nie są używane żadne sygnały dźwiękowe."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Przypomnienia potwierdzające są emitowane, gdy Loop automatycznie dostosowuje podawanie insuliny, a także w przypadku poleceń inicjowanych przez użytkownika."; - -/* Section header for configuration section */ -"Configuration" = "Konfiguracja"; - -/* Button title for confirm attachment option */ -"Confirm" = "Potwierdź"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Potwierdź założenie POD'a"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Kontynuuj"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "Nie można przeanalizować wiadomości: %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Alerty krytyczne"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Krytyczny błąd POD'a"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Możliwe zakłócenia. Proszę teleportuj się do innego pomieszczenia"; - -/* Unit for singular day in pod life remaining */ -"day" = "dzień"; - -/* Unit for plural days in pod life remaining */ -"days" = "dni"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Dezaktywuj POD'a"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktywowany"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Dezaktywacja."; - -/* Action button description while deactivating */ -"Deactivating..." = "Dezaktywacja..."; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Usuń Omnipod DASH"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Szczegóły urządzenia"; - -/* description label for device name pod details row */ -"Device Name" = "Nazwa urządzenia"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Wyłączony"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Odrzuć POD'a"; - -/* No comment provided by engineer. */ -"Done" = "Gotowe"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Pusty zbiornik"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Pusty zbiorniczek"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Pusta odpowiedź POD"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Pusta wartość"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Włączony"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Błąd"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Zarejestrowano zdarzenie błędu, wyłączanie"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Ostrzeżenie o wygaśnięciu"; - -/* Description for expiration alert */ -"Expiration alert" = "Alert o upływie terminu ważności"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Termin Ważności"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Domyślne przypomnienie o terminie ważności"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Rozszerzony"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Trwa podawanie bolusa przedłużonego"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Bolus przedłużony uruchomiony z tymczasową bazą"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Nie udało się anulować dawki podstawowej ustawionej ręcznie"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Nie udało się wznowić podawania insuliny"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Nie udało się ustawić czasu pompy"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Nie udało się wstrzymać podawania insuliny"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Błąd aktualizacji ustawień dla przypomnień."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Nie udało się zaktualizować przypomnienia o terminie ważności"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Nie udało się zaktualizować przypomnienia o niskim poziomie w zbiorniczku"; - -/* Pod life HUD view label */ -"Fault" = "Usterka"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Wystąpiła usterka"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Napełnij nowego POD'a insuliną U-100 (minimum 80j). Pozostaw niebieską osłonkę igły."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Zakończ dezaktywację"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Zakończ dezaktywację"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Zakończ parowanie"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Zakończ konfigurację"; - -/* Description for finish setup */ -"Finish setup " = "Zakończ konfigurację"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Przypomnienie o zakończeniu konfiguracji"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Wersja oprogramowania"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Więcej niż %1$@ jedn. pozostaje w %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "godzina"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "godziny"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Jeśli anulujesz konfigurację POD'a, bieżący POD zostanie dezaktywowany i nie będzie można go używać."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Wykluczające się dane: %1$@ (lokalizacja= %2$d )"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Nieprawidłowa odpowiedź"; - -/* Pod inititialized */ -"Initialized" = "Zainicjalizowany"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Wprowadź kaniulę"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Wprowadzono"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Wprowadzanie kaniuli"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Wprowadzanie. Proszę czekać."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Wprowadzanie..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Podawanie insuliny zawieszone"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Podawanie insuliny zostało zatrzymane. Wymień POD'a."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Podawanie insuliny zostanie wstrzymane do czasu ręcznego wznowienia. Kiedy chcesz, aby Loop przypomniał Ci o wznowieniu podawania insuliny?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Pozostała ilość insuliny"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Podawanie insuliny zawieszone"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Rodzaj insuliny"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Nie skonfigurowano rodzaju insuliny"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Wewnętrzny błąd POD'a %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Przerwany bolus: %1$@ jedn. (%2$@ jedn. zaplanowanych) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Nieprawidłowy adres 0x %1$x . Oczekiwano 0x %2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Nieprawidłowy adres: ( %1$@ )"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Nieprawidłowy CRC"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Nieprawidłowy klucz LTK: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Nieprawidłowe ustawienie"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Czy kaniula jest prawidłowo wprowadzona?"; - -/* description label for last status date pod details row */ -"Last Status" = "Ostatni status"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Nasłuchuj 2 sygnałów dźwiękowych."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Pętla nie będzie automatycznie dostosowywać dawki insuliny, dopóki tymczasowa dawka podstawowa nie zakończy się lub nie zostanie anulowana."; - -/* description label for lot number pod details row */ -"Lot Number" = "Numer LOT"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Niski poziom w zbiorniczku"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Niski poziom w zbiorniczku"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Ostrzeżenie o niskim poziomie w zbiorniczku (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Alarm informujący o niskim poziomie w zbiorniku"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Przypomnienie o niski poziomie w zbiorniczku"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Upewnij się, że iPhone znajduje się w pobliżu aktywnego POD'a."; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Upewnij się, że telefon i POD znajdują się blisko siebie. Jeśli problemy z komunikacją nie ustąpią, przenieś się w inne miejsce."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Upewnij się, że POD jest wypełniony i znajduje się w pobliżu."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Upewnij się, że POD jest w pobliżu i spróbuj ponownie."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Upewnij się, że RileyLink jest w pobliżu i jest włączony"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Baza podstawowa"; - -/* Pod memory initialized */ -"Memory initialized" = "Zainicjowano pamięć"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Problem z komunikacją I/O: %1$@"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minuta"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minuty"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Brak konfiguracji"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Przenieś się w nowe miejsce z dala od innych POD'ów i spróbuj ponownie."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Alert wielu poleceń"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "Niedostępne"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Następny"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nie"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Brak podawania"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Brak alertów"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Nie są używane żadne przypomnienia."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Brak usterek"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Brak insuliny"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Brak POD'a"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Brak sparowanego PODa"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Nie znaleziono POD'a"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Brak przypomnienia"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Brak odpowiedzi z PODa"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Brak dostępnego RileyLink"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nie, kontynuuj parowanie z POD'em"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nie, pozostaw pompę bez zmian"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normalny"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Za mało danych"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Ustawienia powiadomień"; - -/* No comment provided by engineer. */ -"Numbers" = "Liczby"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Wykryto niedrożność"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Wykryto niedrożność"; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Przypomnienia Omnipod"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Sparuj POD'a"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Sparuj POD'a"; - -/* Pod status after pairing */ -"Paired" = "Sparowany"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Parowanie zakończone"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Problem z parowaniem"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Parowanie."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Parowanie…"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Błąd analizy: %1$@ w (%2$@)"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = "Ładunek crc32 %1$@ nie pasuje do obliczonego crc32 %2$@"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Procent = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Urządzenie peryferyjne nie jest gotowe"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Używaj tylko oryginalny POD w zasięgu sygnału albo dezaktywuj oryginalny POD"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Umieść PODa bliżej RileyLink i spróbuj ponownie"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Potwierdź, że POD jest poprawnie przymocowany do ciała. \n\nKaniulę można wprowadzić tylko raz w każdym POD'dzie. Stuknij „Potwierdź”, gdy POD jest przymocowany."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Proszę dezaktywować POD'a. Po zakończeniu dezaktywacji możesz sparować nowego POD'a."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Proszę dezaktywować POD'a. Po zakończeniu dezaktywacji usuń POD'a i sparuj nowego."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Włącz uprawnienia Bluetooth dla tej aplikacji w ustawieniach systemowych"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Dokończ parowanie POD'a."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Sparuj nowego PODa"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Odsuń dalej POD'a od iPhone'a"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Zmień położenie iPhone'a względem POD'a"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Użyj innego urządzenia z funkcją Bluetooth"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "POD aktywowany"; - -/* Label describing pod age view */ -"Pod Age" = "Wiek POD'a"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "POD już sparowany"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "POD już napełniony"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "POD został dezaktywowany pomyślnie. Kontynuować."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Błąd POD'a"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Alarm informujący o upływie terminu ważności PODa"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Powiadomienie o upływie terminu ważności PODa"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Przypomnienie o terminie ważności POD'a"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Termin ważności POD'a upłynął"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Termin ważności POD'a upłynął"; - -/* Label for pod expiration row */ -"Pod Expires" = "POD kończy działanie"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "POD wygasa za"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod wygasa za %1$@ ."; - -/* description label for pod fault details */ -"Pod Fault Details" = "Szczegóły usterki POD'a"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Usterka PODa: 1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "POD nie znajduje się w stanie gotowości do wprowadzenia kaniuli."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "POD nie znajduje się w stanie gotowości do napełniania."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "POD wstrzymany"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "POD nie jest podłączony"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Niedrożność POD'a"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod został pomyślnie sparowany. Kontynuować."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Parowanie POD'a nie zostało zakończone"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "POD odtworzył sygnał zamiast odpowiedzi zwrotnej"; - -/* Title for PodSetupView */ -"Pod Setup" = "Konfiguracja POD'a"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Upłynął termin ważności okna konfiguracji PODa"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Przypomnienie o zawieszeniu POD'a"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Słaba siła sygnału"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Przygotuj miejsce"; - -/* title for previous pod page */ -"Previous Pod" = "Poprzedni POD"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informacje o poprzednim POD'dzie"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Napełnianie"; - -/* Pod state when priming completed */ -"Priming completed" = "Wypełnianie zakończone"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Wypełnianie. Proszę czekać."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Wypełnianie..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Czas pompy"; - -/* Label text for basal rate summary */ -"Rate" = "Tempo"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Gotowy do zaprogramowania dawki podstawowej"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Gotowy do wprowadzenia kaniuli"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Pozostało"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Zainicjowano przypomnienie"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Usuń niebieską osłonę igły i sprawdź kaniulę. Następnie usuń papierowe zabezpieczenie kleju."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Usuń POD'a z ciała"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Usuń pompę"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Wymień POD'a"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Wznów"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Wznów podawanie"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Wznów insulinę"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Wznów podawanie insuliny"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Wznów: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Wznawianie podawania insuliny..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Spróbuj ponownie"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Zapisz"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Zapisywanie..."; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Zaplanowana dawka podstawowa"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Zaplanowana dawka podstawowa"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Zaplanowane przypomnienie"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Wybierz rodzaj insuliny, której będziesz używać w tym POD."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Numer sekwencji"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Ustaw Bazę Tymczasową"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Ustaw tymczasową dawkę podstawową"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Konfiguracja zakończona"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Informacja o zbliżającym się wyłączeniu"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarm o nadchodzącym wyłączeniu"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Utrata sygnału"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Zbyt wysoka siła sygnału"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Pominąć instalację Omnipod’a?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Wstrzymaj"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Wstrzymaj podawanie"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Przypomnienie o trwającym zawieszeniu"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Wstrzymaj podawanie insuliny"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Upłynął czas zawieszenia"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Wstrzymaj: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Wstrzymane"; - -/* Label for suspended at time */ -"Suspended At" = "Zawieszony o godz."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Wstrzymanie podawania insuliny..."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Czas zawieszenie dobiegł końca. Otwórz Loop i wznów podawanie"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Zmień pompę insulinową na inną"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchronizuj z bieżącym czasem"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Napełnianie zbiornika zakończone"; - -/* Pod power to motor activated */ -"Tank power activated" = "Zasilanie zbiornika włączone"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Stuknij poniżej, aby rozpocząć wprowadzanie kaniuli."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Tymczasowa dawka podstawowa"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Tymczasowa dawka podstawowa w toku"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Tymczasowa dawka podstawowa działa"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "Tymczasowa dawka podstawowa: %1$@ jedn./godz. %2$@ %3$@ %4$@ jedn. %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Baza tymczasowa"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Baza tymczasowa nie powiodła się"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Aplikacja konfiguruje przypomnienie w POD, aby powiadomić Cię z wyprzedzeniem o wygaśnięciu ważności POD'a. Ustaw liczbę godzin wyprzedzenia, które chcesz skonfigurować podczas parowania nowego POD'a."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Aplikacja z wyprzedzeniem powiadomi użytkownika o wygaśnięciu ważności POD'a.\n\nZaplanuj powiadomienie (wybierz liczbę godzin)."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Aplikacja powiadomi Cię, gdy ilość insuliny w POD osiągnie poziom (50-10 J). \n\nUstaw liczbę jednostek, przy których chcesz otrzymywać przypomnienia."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Aplikacja powiadomi Cię, gdy ilość insuliny w POD osiągnie ten poziom."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Okres zawieszenia podawania insuliny dobiegł końca. \n\nPodawanie można wznowić za pomocą banera na ekranie głównym lub na ekranie ustawień pompy. Ponowne przypomnienie pojawi się za 15 minut."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Powyższe przypomnienia nie będą się pojawiały, jeśli urządzenie jest w trybie cichym lub nie przeszkadzać. \n\nIstnieją inne krytyczne alerty i alarmy POD'ów, które będą emitowane, nawet jeśli urządzenie jest ustawione w trybie cichym lub nie przeszkadzać."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Czas na pompie różni się od aktualnego czasu. Czy chcesz zaktualizować czas na pompie do aktualnego czasu?"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Czas na pompie różni się od aktualnego czasu. W ustawieniach można sprawdzić czas pompy i zsynchronizować go z aktualnym czasem."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Czas na pompie różni się od aktualnego czasu. Czas pompy steruje ustawieniami zaplanowanej terapii. Przewiń w dół do wiersza Czas pompy, aby przejrzeć różnicę czasu i skonfigurować pompę."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Okienko na górze POD'a powinno zabarwić się na różowo, gdy kaniula jest prawidłowo wprowadzona pod skórę."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Wystąpił problem z komunikacją z POD'em. Jeśli problem się utrzymuje, wybierz opcję Odrzuć POD'a. Następnie możesz aktywować nowy POD."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "To jest przypomnienie, które zaplanowałeś podczas parowania bieżącego Poda."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Nie ustalono limitu podaży dla dawki podstawowej. Wróć do ustawień terapii i ustaw nowy limit maksymalnej dawki podstawowej (bazy)."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Czas"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Wykryto zmianę czasu"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Pora wymienić PODa! Termin ważności PODa upłynie za %1$@"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Koniec czasu"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Przełącz znak"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Znaleziono zbyt wiele POD'ów"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Łącznie podano"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Spróbuj ponownie"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Włącz bluetooth"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "J/godz"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Nie można połączyć się z Podem"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Nie można połączyć się z Podem"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Nie można ustawić tymczasowej dawki podstawowej: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Nie można ustawić tymczasowej dawki podstawowej: %1$@ \n\n %2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Niepewna"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Nieoczekiwany numer kolejnego komunikatu"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Nieoczekiwana zmiana POD'a"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Nieoczekiwana odpowiedź PODa"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Niedokończona aktywacja"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Niedokończona dezaktywacja"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Nieznane powiadomienie"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Nieznany błąd POD'a %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Nieznana wartość (%1$@) dla typu %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Weryfikacja nie powiodła się: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Poczekaj na zakończenie istniejącego bolusa lub anuluj bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Poczekaj na zakończenie istniejącej dawki podstawowej lub wstrzymaj, aby anulować"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Poczekaj, aż wprowadzanie zostanie zakończone."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Poczekaj na przypomnienie o parowaniu"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Tak"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Tak, dezaktywuj POD'a"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Tak, zsynchronizuj z bieżącym czasem"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Rozpoczynasz proces konfigurowania przypomnień (dźwięków emitowanych przez POD'a), napełniania POD'a insuliną, parowania z telefonem i umieszczania go na ciele."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Twój POD jest gotowy do użycia. \n\n%1$@ przypomni Ci o zmianie POD'a przed jego wygaśnięciem. Możesz dokonać zmiany na dogodny dla Ciebie termin."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Twój POD może nadal dostarczać insulinę.\nUsuń go z ciała, a następnie wybierz \"Kontynuuj\"."; - diff --git a/Dependencies/OmniBLE/OmniBLE/pt-BR.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/pt-BR.lproj/Localizable.strings deleted file mode 100644 index 18fa26388..000000000 --- a/Dependencies/OmniBLE/OmniBLE/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,290 +0,0 @@ -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ atrás"; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unidades restantes em %2$@"; - -/* description label for active time pod details row */ -"Active Time" = "Tempo Ativo"; - -/* Section header for activity section */ -"Activity" = "Atividade"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Alarme de desligamento automático"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Abaixo de 50 unidades"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus em andamento"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Entregando Bolus"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Aplicando bolus com basal temp"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Cancelar"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Inserindo Cânula"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Certo"; - -/* Section header for configuration section */ -"Configuration" = "Configuração"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Continuar"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Desativar Pod"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Desativado"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Reservatório vazio"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Resposta vazia do pod"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Ativado"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Erro"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Evento de erro registrado, desligando"; - -/* Description for expiration alert */ -"Expiration alert" = "Alerta de expiração"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Lembrete de Expiração"; - -/* Pod life HUD view label */ -"Fault" = "Falha"; - -/* Description for finish setup */ -"Finish setup " = "Concluir configuração"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Versão do Firmware"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Mais de %1$@ unidades restantes em %2$@"; - -/* Pod inititialized */ -"Initialized" = "Inicializado"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Inserir Cânula"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Falha interna do pod %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "BolusInterrompido: %1$@ U (%2$@ U agendado) %3$@ %4$@ %5$@"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Alarme de baixo reservatório"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Verifique se o seu RileyLink está próximo e ligado"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Sem alertas"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Nenhum pod emparelhado"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Nenhuma resposta do pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Nenhum RileyLink disponível"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Oclusão detectada"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Emparelhado"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Traga seu pod para mais perto do RileyLink e tente novamente"; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Emparelhe um novo pod"; - -/* Label describing pod age view */ -"Pod Age" = "Idade do Pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod já emparelhado"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod já preparado"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Alarme de expiração do pod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Aviso de Expiração do Pod"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod expirado"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Falha no Pod: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "O Pod não está pronto para a inserção da cânula."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "O Pod não está em um estado pronto para preparação."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "O pod está suspenso"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "A janela de configuração do pod expirou"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Preparando"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Pronto para programação basal"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Pronto para inserir a cânula"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Restante"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Substituir Pod"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Retomar: %1$@ %2$@"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Tentar de Novo"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Salvar"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Basal Agendado"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Instalação Concluída"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarme de desligamento iminente"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspender Entrega"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspender: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspenso"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Enchimento do tanque concluído"; - -/* Pod power to motor activated */ -"Tank power activated" = "Alimentação do tanque ativada"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Basal temporária em andamento"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Executando basal temporária"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "BasalTemp: %1$@ U/hora %2$@ %3$@ %4$@ U %5$@"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Hora de substituir o seu pod! Seu pod expirará em %1$@"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hr"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Incerto"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Resposta inesperada do pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Falha desconhecida do pod %1$03d"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Aguarde a conclusão do bolus existente ou cancele-o"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Aguarde até que a basal temp existente termine ou suspenda para cancelar"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Aguardando lembrete de emparelhamento"; - diff --git a/Dependencies/OmniBLE/OmniBLE/pt-PT.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/pt-PT.lproj/Localizable.strings deleted file mode 100644 index 5bf12da7f..000000000 --- a/Dependencies/OmniBLE/OmniBLE/pt-PT.lproj/Localizable.strings +++ /dev/null @@ -1,1130 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inaktiv)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ vor"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ hat die Kommunikation mit dem Pod an Ihrem Körper wiederhergestellt.\n\nDie Insulinabgabeaufzeichnungen wurden aktualisiert und sollten mit dem übereinstimmen, was tatsächlich abgegeben wurde.\n\nSie können %@ jetzt normal weiter verwenden."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ IE"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ für %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ konnte seit %2$@ nicht mehr mit Ihrem Pod kommunizieren.\n\nOhne Kommunikation mit dem Pod kann die App keine Befehle für die Insulinabgabe senden oder genaue, aktuelle Informationen über Ihr aktives Insulin oder das vom Pod abgegebene Insulin anzeigen.\n\nÜberwachen Sie Ihren Blutzucker für die nächsten 6 oder mehr Stunden genau, da in Ihrem Körper Insulin aktiv sein kann oder auch nicht, das %3$@ nicht anzeigen kann."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ Insulin oder weniger verbleibend im Pod. Pod bald wechseln."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ IE verbleibend bei %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g IE"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 Stunde"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 Stunde 30 Minuten"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 Stunden"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 Minuten"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Aktivierungszeit überschritten"; - -/* description label for active time pod details row */ -"Active Time" = "Laufzeit"; - -/* Section header for activity section */ -"Activity" = "Aktivität"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pumpenzeit einstellen"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Sind Sie sicher, dass Sie die Pod-Einrichtung abbrechen möchten?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Sind Sie sicher, dass Sie das Omnipod Onboarding überspringen wollen?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Sind Sie sicher, dass Sie keinen Omnipod DASH mehr benutzen möchten?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Pod anbringen"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Versuche die Verbindung wieder aufzubauen"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-Off Alarm"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Zurück"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialisiert"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Weniger als 50 Einheiten"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth ist ausgeschaltet"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Bluetooth wird zurückgesetzt"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth ist aus einem unbekannten Grund nicht verfügbar."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth ist nicht verfügbar: %1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "Bluetooth-Nutzung ist nicht erlaubt"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "Bluetooth-Verwendung wird auf diesem Gerät nicht unterstützt"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolusabgabe läuft "; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@IE %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusabgabe"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolus-Abgabe mit temporärer Basalrate"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Abbrechen"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Manuelles Basal abbrechen"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanüle erfolgreich eingeführt. Weiter."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Einsetzen der Kanüle"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Sicher"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Pod jetzt wechseln. Die Insulinabgabe stoppt 8 Stunden nach Ablauf des Pods oder wenn kein Insulin mehr vorhanden ist."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Pod jetzt wechseln. Die Insulinabgabe stoppt in %1$@ oder wenn kein Insulin mehr vorhanden ist."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Pod jetzt wechseln. Die Insulinabgabe stoppt in 1 Stunde."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Pod jetzt wechseln. Der Pod ist seit 72 Stunden aktiv."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Prüfe die Kanüle"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Überprüfe den Pod, bringe ihn an und bestätige dann die Pod-Anbringung."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Prüfe die Einfügung"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Prüfe…"; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Befehlsfehler %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Problem"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Kommunikation wiederhergestellt"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Kommunikationsproblem: Unbestätigter Befehl steht noch aus."; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Sicherheitserinnerung"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Vertrauenserinnerungen sind Pieptöne vom Pod, die verwendet werden können, um ausgewählte Befehle zu bestätigen."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Vertrauenserinnerungen ertönen für von Ihnen initiierte Befehle, wie Bolus, Bolus abbrechen, Unterbrechen, Fortsetzen, Benachrichtigungserinnerungen speichern usw. Wenn Loop die Abgabe automatisch anpasst, werden keine Vertrauenserinnerungen verwendet."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Vertrauenserinnerungen ertönen, wenn Loop die Lieferung automatisch anpasst, sowie für von Ihnen initiierte Befehle."; - -/* Section header for configuration section */ -"Configuration" = "Konfiguration"; - -/* Button title for confirm attachment option */ -"Confirm" = "Bestätige"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bestätige Pod Befestigung"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Weiter"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "Nachrichte konnte nicht analysiert werden: %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritische Warnungen"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritischer Pod-Fehler"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Überlagerungen möglich. Bitte wechseln Sie an einen neuen Standort"; - -/* Unit for singular day in pod life remaining */ -"day" = "Tag"; - -/* Unit for plural days in pod life remaining */ -"days" = "Tage"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Pod deaktivieren"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktiviert"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktiviere."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deaktiviere…"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Omnipod DASH löschen"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Gerätedetails"; - -/* description label for device name pod details row */ -"Device Name" = "Gerätename"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Ausgeschaltet"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Pod verwerfen"; - -/* No comment provided by engineer. */ -"Done" = "Fertig"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Reservoir leer"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Leeres Reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Leere Antwort vom Pod"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Leerer Wert"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Aktiviert"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Fehler"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Fehlerereignis protokolliert, fahre herunter"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Ablaufhinweis"; - -/* Description for expiration alert */ -"Expiration alert" = "Ablaufalarm"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Erinnerung an den Ablauf der Nutzungsdauer"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standard Erinnerung an den Ablauf der Nutzungsdauer"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Verzögerung"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Verzögerter Bolus aktiv"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Verzögerter Bolus mit temporärer Basalrate aktiv"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Fehler beim Abbrechen der manuellen Basalrate"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Wiederaufnahme der Insulinabgabe fehlgeschlagen"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Fehler beim Einstellen der Pumpenzeit"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Fehler beim Anhalten der Insulinabgabe"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Fehler beim Aktualisieren der Einstellung für die Sicherheitserinnerung."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Fehler beim Aktualisieren der Ablauferinnerung"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Fehler beim Aktualisieren der Erinnerung für einen niedrigen Vorratsbehälter"; - -/* Pod life HUD view label */ -"Fault" = "Störung"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fehlerereignis aufgetreten"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Fülle U-100 Insulin in den Pod (lasse die blaue Kappe drauf)"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Deaktivierung abschließen"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Deaktivierung abgeschlossen"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Kopplung abgeschlossen"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Einrichtung abschließen"; - -/* Description for finish setup */ -"Finish setup " = "Einrichtung abgeschlossen"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Einrichtungserinnerung abgeschlossen"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Mehr als %1$@ verbleibende Einheiten um %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "Stunde"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "Stunden"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Wenn Du die Einrichtung abbrichst, dann wird der Pod deaktiviert und unbrauchbar."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Incorrect Packet Exception: %1$@ (location=%2$d)"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Falsche Antwort"; - -/* Pod inititialized */ -"Initialized" = "Initialisiert"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Kanüle einsetzen"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Eingeführt"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Einfügen von Kanüle"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Füge ein, bitte warte…"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Füge ein…"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulinabgabe\nunterbrochen"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulinabgabe wurde gestoppt. Pod jetzt wechseln."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Die Insulinabgabe wird angehalten, bis Sie sie manuell wieder aufnehmen. Wann soll Loop Sie daran erinnern, die Abgabe fortzusetzen?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Verbleibendes Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulinabgabe unterbrochen"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulintyp"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulintyp nicht konfiguriert"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Interner Podfehler %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Abgebrochener Bolus: %1$@ IE (%2$@ IE geplant) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Ungültige Adresse (%1$x). Adresse %2$x erwartet"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Ungültige Adresse (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Ungültiger CRC"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Invalid LTK Key: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ungültige Einstellung"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Wurde der Katheter ordentlich eingeführt?"; - -/* description label for last status date pod details row */ -"Last Status" = "Letzter Status"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Achte auf zwei Pieptöne."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop passt Ihre Insulinabgabe nicht automatisch an, bis die temporäre Basalrate beendet oder abgebrochen wurde."; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Niedriges Reservoir"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Niedriges Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Hinweis auf niedriges Reservior (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Hinweisalarm für fast leeres Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Erinnerung an niedriges Reservoir"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Stellen Sie sicher, dass Ihr iPhone nah am Pod ist"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Stellen Sie sicher, dass sich Ihr iPhone und Ihr Pod nahe beieinander befinden. Wenn die Kommunikationsprobleme bestehen bleiben, dann gehen Sie an einen anderen Ort."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Stellen Sie sicher, dass Ihr Pod gefüllt und in der Nähe ist."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Stellen Sie sicher, dass sich Ihr Pod in der Nähe befindet, und versuchen Sie es erneut."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Stellen Sie sicher, dass sich Ihr RileyLink in der Nähe befindet und eingeschaltet ist"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuelle Basalrate"; - -/* Pod memory initialized */ -"Memory initialized" = "Speicher initialisiert"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Message IO Exception: %1$@"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "Minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "Minuten"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Fehlende Konfiguration"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Begeben Sie sich in einen anderen Bereich, entfernt von anderen Pods und versuchen Sie es erneut."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Warnung bei mehreren Befehlen"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "nicht bestätigt"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Weiter"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nein"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Keine\nAbgabe"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Keine Alarme"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Es werden keine Sicherheitserinnerungen verwendet."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Keine Fehler"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Kein Insulin"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Kein Pod gekoppelt"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Kein Pod gekoppelt"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Keine Pods gefunden"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Keine Erinnerung"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Keine Rückmeldung vom Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Kein RileyLink verfügbar"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nein, mit Pod fortfahren"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nein, Pumpe so lassen wie sie ist"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Nicht genügend Daten"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Benachrichtigungseinstellungen"; - -/* No comment provided by engineer. */ -"Numbers" = "Zahlen"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Verstopfung erkannt"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Verstopfung erkannt"; - -/* Action button default text for PodAlerts */ -"Ok" = "OK"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Erinnerung"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pod koppeln"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pod koppeln."; - -/* Pod status after pairing */ -"Paired" = "Gekoppelt"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Kopplung abgeschlossen"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Kopplungsausnahme: %1$@"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Koppeln"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Koppeln…"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing-Fehler: %1$@ in (%2$@)"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = "Payload crc32 %1$@ does not match computed crc32 %2$@"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percent = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheriegerät nicht bereit"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Bitte nur Original-Pod in Reichweite bringen oder Original-Pod deaktivieren"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Bitte bringen Sie Ihren Pod näher an Ihr RileyLink und versuchen Sie es erneut"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Bitte vergewissern Sie sich, dass der Pod sicher an Ihrem Körper befestigt ist.\n\nDer Katheter kann mit jedem Pod nur einmal eingeführt werden. Tippen Sie auf „Bestätigen“, wenn der Pod angeschlossen ist."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Bitte deaktivieren Sie den Pod. Wenn die Deaktivierung abgeschlossen ist, können Sie einen neuen Pod koppeln."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Bitte deaktivieren Sie den Pod. Wenn die Deaktivierung abgeschlossen ist, können Sie ihn entfernen und einen neuen Pod koppeln."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Bitte aktiviere die Bluetooth-Berechtigungen für diese App in den Systemeinstellungen"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Bitte schließen Sie die Kopplung Ihres Pods ab."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Bitte koppel einen neuen Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Bitte positionieren Sie das iPhone weiter vom Pod entfernt"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Bitte positionieren Sie das iPhone relativ zum Pod neu"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Bitte verwenden Sie ein anderes Gerät mit Bluetooth-Funktion"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod aktiviert"; - -/* Label describing pod age view */ -"Pod Age" = "Pod-Alter"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod bereits gekoppelt"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod bereits gefüllt"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod erfolgreich deaktiviert. Weiter."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Pod-Fehler"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Ablaufalarm des Pods"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Hinweis zum Ablaufen des Pods"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod-Ablauferinnerung"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod abgelaufen"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod abgelaufen"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod läuft ab"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod läufen ab in"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod läuft in %1$@ ab."; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fehlerdetails"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Podfehler: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Der Pod ist nicht bereit zum Einführen der Kanüle."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Der Pod ist nicht bereit zum Befüllen."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod ist angehalten"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "Pod nicht verbunden"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Verstopfung"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod erfolgreich gekoppelt. Weiter."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod-Kopplung unvollständig"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sendet Bestätigung anstelle von Antwort"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Einrichtung"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Das Zeitfenster für die Pod-Einrichtung ist abgelaufen"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Erinnerung über abgelaufenen Pod "; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Schlechte Signalstärke"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Stelle vorbereiten."; - -/* title for previous pod page */ -"Previous Pod" = "Vorheriger Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informationen über den letzten Pod"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Befüllen"; - -/* Pod state when priming completed */ -"Priming completed" = "Befüllen des Pods abgeschlossen"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Befülle, bitte warte."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Befülle…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Uhrzeit der Pumpe"; - -/* Label text for basal rate summary */ -"Rate" = "Rate"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Bereit für die Programmierung der Basalrate"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Bereit zum Einführen der Kanüle"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Verbleibend"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Erinnerung initialisiert"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Entfernte die blaue Kappe und überprüfe den Katheter. Dann entferne das Papier."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Entferne den Pod vom Körper"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Pumpe löschen"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Pod ersetzen"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Fortsetzen"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Insulinabgabe fortsetzen"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Insulinabgabe fortsetzen"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Insulinabgabe wiederaufnehmen"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Fortsetzen: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Nehme Insulinabgabe wieder auf…"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Wiederholen"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Speichern"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Speichere…"; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Geplante Basalrate"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Geplante Basalrate"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Geplante Erinnerung"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Wähle die Insulinart aus, die Du für diesen Pod benutzen möchtest."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequenznummer"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Temporäre Basalrate setzen"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Temporärere Basalrate setzen"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Einrichtung abgeschlossen"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Pod-Abschaltung steht bevor"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarm für die bevorstehende Pod-Abschaltung"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signalverlust"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signalstärke ist zu hoch"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Omnipod-Onboarding überspringen?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Unterbrechen"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Abgabe unterbrechen"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Unterbrechungsfortschritts-Erinnerung"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Insulinabgabe unterbrechen"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Unterbrechungszeit abgelaufen"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Unterbrochen: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Unterbrochen"; - -/* Label for suspended at time */ -"Suspended At" = "Unterbrochen um"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Unterbreche die Insulinabgabe…"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Die Unterbrechungszeit ist abgelaufen. Öffnen Sie die App und fahren Sie fort."; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Zu einer anderen Pumpe wechseln"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Mit aktueller Uhrzeit synchronisieren."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Befüllen des Pods erfolgreich"; - -/* Pod power to motor activated */ -"Tank power activated" = "Energieversorgung für den Podmotor aktiviert"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tippe unten, um das Einführen der Kanüle zu starten."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temporäre Basalrate"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temporäre Basalrate läuft bereits."; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temporäre Basalrate läuft"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ IE/h %2$@ %3$@ %4$@ IE %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporäre Basalrate"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal fehlgeschlagen"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Die App konfiguriert eine Erinnerung auf dem Pod, um Dich vor Ablauf des Pods zu benachrichtigen. Legen die Anzahl der Stunden fest, die Du vor Ablauf des Pods benachrichtigt werden möchtest."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Die App benachrichtigt Dich vor Ablauf des Pods.\n\nScrolle, um die gewünschte Anzahl von Stunden im Voraus festzulegen."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Die App benachrichtigt Dich, wenn die Insulinmenge im Pod diesen Wert erreicht (50-10 IE).\n\nScrolle, um die Anzahl der Einheiten festzulegen, bei der Du erinnert werden möchtest."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Die App benachrichtigt Dich, wenn die Insulinmenge im Pod diesen Wert erreicht."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Die Insulinabschaltung ist beendet.\n\nSie können die Abgabe über das Banner auf dem Startbildschirm oder über den Bildschirm mit den Pumpeneinstellungen fortsetzen. Sie werden in 15 Minuten erneut erinnert."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Die obigen Erinnerungen ertönen nicht, wenn sich Dein Gerät im Lautlos- oder Nicht-Stören-Modus befindet.\n\nEs gibt andere kritische Pod-Warnungen und -Alarme, die auch dann ertönen, wenn Dein Gerät auf „Lautlos“ oder „Nicht stören“ eingestellt ist."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Die Uhrzeit Ihrer Pumpe unterscheidet sich von Ihrer aktuellen Uhrzeit. Möchten Sie die Uhrzeit Ihrer Pumpe auf Ihre aktuelle Uhrzeit aktualisieren?"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Die Uhrzeit Ihrer Pumpe weicht von der aktuellen Uhrzeit ab. Sie können die Uhrzeit der Pumpe überprüfen und in den Einstellungen mit der aktuellen Uhrzeit synchronisieren."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Die Uhrzeit der Pumpe weicht von der aktuellen Uhrzeit ab. Die Zeit der Pumpe steuert die geplanten Therapieeinstellungen. Scrolle nach unten zur Zeile Pumpenzeit, um den Zeitunterschied zu überprüfen und die Pumpe zu konfigurieren."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Das Fenster oben auf dem Pod sollte pinkfarben sein, wenn der Katheter ordentlich in die Haut eingeführt wurde."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Es gab ein Problem bei der Kommunikation mit dem Pod. Wenn dieses Problem weiterhin besteht, tippen Sie auf \"Pod verwerfen\". Sie können dann einen neuen Pod aktivieren."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dies ist eine Erinnerung, die Du beim Koppeln Deines aktuellen Pods eingestellt hast."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Dieser Pumpenmanager wurde nicht mit einer maximalen Basalrate konfiguriert, da er hinzugefügt wurde, bevor die Funktion manuelle temporäre Basalrate hinzugefügt wurde. Bitte gehe zu Therapieeinstellungen -> Abgabegrenzen und stelle eine neue maximale Basalrate ein."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Zeit"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Änderung der Uhrzeit erkannt"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Es ist Zeit Ihren Pod zu wechseln! Der Pod läuft ab in %1$@"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Zeitüberschreitung"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Zeichen umschalten"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Zu viele Pods in Reichweite"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Gesamt Abgabe"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Versuchen Sie es erneut"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Schalte Bluetooth ein"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "IE/h"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Pod kann nicht erreicht werden"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Pod kann nicht erreicht werden"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Eine temporäre Basalrate kann nicht gesetzt werden: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Eine temporäre Basalrate kann nicht gesetzt werden: %1$@\n\n%2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Unsicher"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Unerwartete Sequenznummer der Nachricht"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Unerwarteter Podwechsel"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Unerwartete Antwort vom Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Nicht abgeschlossene Aktivierung"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Nicht abgeschlossene Deaktivierung"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unbekannte Charakteristik"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Unbekannter Podfehler %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Unbekannter Wert ( %1$@ ) für Typ %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Überprüfung fehlgeschlagen: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Warte, bis der aktuelle Bolus abgegeben wurde, oder unterbreche diesen."; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Warten Sie, bis die aktuelle temporäre Basalrate beendet ist, oder unterbrechen Sie diese"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Warte bis das Einführen der Kanüle fertig ist."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Warten auf Kopplungserinnerung"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, deaktiviere Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, mit aktueller Zeit synchronisieren"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Beginne nun damit, die Erinnerungen zu konfigurieren, Dein Pod mit Insulin zu füllen, ihn mit Deinem Gerät zu koppeln und ihn an Deinem Körper zu platzieren."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Dein Pod ist einsatzbereit.\n\n%1$@ erinnert Dich daran, Deinen Pod zu wechseln, bevor er abläuft. Du kannst eine für Dich passende Zeit wählen."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Ihr Pod gibt möglicherweise immer noch Insulin ab.\nEntfernen Sie ihn vom Körper und tippen dann auf „Weiter“."; - diff --git a/Dependencies/OmniBLE/OmniBLE/ro.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/ro.lproj/Localizable.strings deleted file mode 100644 index cb1088023..000000000 --- a/Dependencies/OmniBLE/OmniBLE/ro.lproj/Localizable.strings +++ /dev/null @@ -1,1130 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactiv)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ în urmă"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ a restabilit comunicarea cu Pod-ul de pe corpul tău.\n\nÎnregistrările legate de administrarea insulinei au fost actualizate și ar trebui să corespundă cu ceea ce a fost administrat de fapt.\n\nAcum puteți continua să utilizați %@ în mod normal."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ pentru %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ nu a putut comunica cu Pod-ul de pe corpul tău de la %2$@.\n\nÎn lipsa comunicației cu Pod-ul, aplicația nu poate continua să trimită comenzi pentru administrarea de insulină sau să afișeze informații exacte și recente despre insulina activă sau despre insulina administrată de Pod.\n\nMonitorizați-vă glicemia cu atenție în următoarele 6 sau mai multe ore, deoarece este posibil să existe sau nu insulină care lucrează activ în corpul dumneavoastră și pe care %3$@ nu o poate afișa."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ de insulină sau mai puțin rămase în Pod. Schimbați Pod-ul în curând."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unități rămase la %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 oră"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 oră și 30 de minute"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 ore"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 de minute"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Timpul de activare a fost depășit"; - -/* description label for active time pod details row */ -"Active Time" = "Timp activ"; - -/* Section header for activity section */ -"Activity" = "Activitate"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Reglarea timpului pompei..."; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Sigur doriți să anulați configurarea Pod-ului?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Sunteți sigur că doriți să săriți peste inițierea pompei Omnipod?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Sunteți sigur că nu mai doriți să utilizați Omnipod DASH?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Atașați Pod-ul"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Se încearcă restabilirea comunicațiilor"; - -/* Description for auto-off */ -"Auto-off" = "Oprire automată"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Alarmă Auto-off"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Înapoi"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Bazală inițializată"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Sub 50 de unități"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "Versiune de firmware BLE"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth-ul este oprit"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Bluetooth-ul se resetează"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth nu este disponibil dintr-un motiv necunoscut."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth nu este disponibil: %1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "Utilizarea Bluetooth este neautorizată"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "Utilizarea Bluetooth nu este disponibilă pe acest dispozitiv"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus în derulare"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolus în derulare"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolus în derulare cu rata bazală temporară"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Renunță"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Anulați bazala manuală"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Canula a fost introdusă cu succes. Continuați."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Se inserează canula"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Doză confirmată"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Schimbați Pod-ul acum. Livrarea insulinei se va opri la 8 ore după expirarea Pod-ului sau când nu mai rămâne deloc insulină."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Schimbați Pod-ul acum. Livrarea insulinei se va opri în %1$@ sau când nu mai rămâne insulină."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Schimbați Pod-ul acum. Administrarea insulinei se va opri într-o oră."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Schimbați Pod-ul acum. Pod-ul a fost activ timp de 72 de ore."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Verificați canula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Verificați Pod-ul, puneți-l pe piele, după care confirmați că este lipit."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Se verifică inserția"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Se verifică..."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Eroare comandă %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problemă de comunicații"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comunicații reluate"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Problemă de comunicare: comandă nerecunoscută în așteptare."; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Mementouri de confimare"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Memento-urile de confirmare sunt semnale sonore de la Pod care pot fi folosite pentru confirmarea comenzilor selectate."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Mementourile de confirmare vor suna pentru comenzile pe care le inițiați, precum bolus, anualarea bolusului, suspendare, reluare, salvarea mementourilor de confirmare etc. Când Loop ajustează automat administrarea, nu sunt folosite mementouri de confirmare."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Mementourile de confirmare vor suna atunci când Loop ajustează automat administrare, precum și pentru comenzile pe care le inițiați."; - -/* Section header for configuration section */ -"Configuration" = "Configurare"; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirmați"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirmați atașarea Pod-ului"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Continuă"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "Mesaju nu a putut fi parsat: %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Alerte critice"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Eroare critică Pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Interferență posibilă. Vă rugăm să vă mutați într-o zonă nouă"; - -/* Unit for singular day in pod life remaining */ -"day" = "zi"; - -/* Unit for plural days in pod life remaining */ -"days" = "zile"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Dezactivează Pod"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Dezactivat"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Se dezactivează."; - -/* Action button description while deactivating */ -"Deactivating..." = "Se dezactivează..."; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Ștergeți Omnipod DASH"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Detalii despre dispozitiv"; - -/* description label for device name pod details row */ -"Device Name" = "Denumirea dispozitivului"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Dezactivat"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Renunțați la Pod"; - -/* No comment provided by engineer. */ -"Done" = "Realizat"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Rezervor gol"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Rezervor gol"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Răspuns gol primit de la Pod"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Valoare goală"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Activat"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Eroare"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Eroare înregistrată în jurnal, se oprește"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Aviz de expirare"; - -/* Description for expiration alert */ -"Expiration alert" = "Alertă expirare"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Memento de expirare"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Memento de expirare implicit"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Prelungit"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Bolus prelungit activat"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Bolus prelungit activ împreună cu bazală temporară"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Nu s-a reușit anularea bazalei manuale"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Nu s-a reușit reluarea administrării de insulină"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Nu s-a reușit setarei timpului de pe pompă"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Nu s-a reușit suspendarea administrării de insulină"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Nu s-a reușit actualizarea preferinței în ceea ce privește memento-ul de confirmare."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Nu s-a reușit actualizarea memento-ului de expirare"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Nu s-a reușit actualizarea memento-ului privind rezervorul scăzut"; - -/* Pod life HUD view label */ -"Fault" = "Defecțiune"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "A avut loc un eveniment de eroare"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Umpleți un Pod nou cu insulină U-100 (nu înlăturați capacul albastru al acului de pe Pod)."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finalizați dezactivarea"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Finalizați deactivarea"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Finalizați asocierea"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finalizați configurarea"; - -/* Description for finish setup */ -"Finish setup " = "Finalizare setare"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Memento pentru finalizarea configurării"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Versiunea Firmware"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Au rămas mai mult de %1$@ unități la %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "oră"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "ore"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Dacă anulați configurarea Pod-ului, Pod-ul actual va fi dezactivat și va fi inutilizabil."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Excepție de pachet incorect: %1$@ (locație= %2$d )"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Răspuns incorect"; - -/* Pod inititialized */ -"Initialized" = "Inițializat"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Inserează canula"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserată"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Se inserează canula"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Se inserează. Vă rog așteptați."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Se inserează canula..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Administrarea insulinei suspendată"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Administrarea de insulină s-a oprit. Schimbați Pod-ul acum."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Administrarea de insulină va fi oprită până când veți relua manual. Când doriți ca Loop să vă reamintească să reluați administrarea?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulină rămasă"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Administrarea insulinei suspendată"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Tipul de insulină"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Tipul de insulină nu este configurat"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Defecțiune Pod internă %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "BolusÎntrerupt: %1$@ U (%2$@ U planificat) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Adresă invalidă 0x%1$x. Se aștepta 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Adresă invalidă: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "CRC invalid"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Cheie LTK nevalidă: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Setare invalidă"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Canula este introdusă corect?"; - -/* description label for last status date pod details row */ -"Last Status" = "Ultima stare"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Ascultați 2 semnale sonore."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop nu va ajusta automat administrarea de insulină până când rata bazală temporară nu se termină sau nu este anulată."; - -/* description label for lot number pod details row */ -"Lot Number" = "Numărul lotului"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Rezervor scăzut"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Rezervor scăzut"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Avertizare de rezervor scăzut (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Alarmă nivel scăzut rezervor"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Memento pentru rezervor scăzut"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Asigurați-vă că iPhone-ul este în apropierea Pod-ului activ"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Asigurați-vă că telefonul și Pod-ul sunt aproape unul de celălalt. Dacă problemele de comunicare persistă, mutați-vă într-o zonă nouă."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Asigurați-vă că Pod-ul este umplut și în apropiere."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Asigurați-vă că Pod-ul dumneavoastră este în apropiere și încercați din nou."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Asigurați-vă că RileyLink este pornit și situat în apropriere"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Bazală manuală"; - -/* Pod memory initialized */ -"Memory initialized" = "Memorie inițializată"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Mesaj Excepție IO: %1$@"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minut"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minute"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Lipsă configurare"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Mutați-vă într-o zonă nouă, departe de orice alte Pod-uri și încercați din nou."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Alertă de comandă multiplă"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NA"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Continuați"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nu"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Nicio\nAdministrare"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Nicio alertă"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Nu se folosesc mementouri de confimare."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Nicio defecțiune"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Fără insulină"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Niciun Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Niciun Pod asociat"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Nu s-au găsit Pod-uri"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Niciun memento"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Nu s-a primit răspuns de la Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Nu există un RileyLink disponibil"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nu, continuați cu Pod-ul"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nu, păstrați pompa așa cum este"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Nu sunt suficiente date"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Setări de notificare"; - -/* No comment provided by engineer. */ -"Numbers" = "Numere"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Ocluzie detectată"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Ocluzie detectată"; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Mementouri Omnipod"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Asociază un Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Asociază un Pod"; - -/* Pod status after pairing */ -"Paired" = "Asociat"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Asociere finalizată"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Excepție de asociere: %1$@"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Se asociază."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Se asociază…"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Eroare de parsare: %1$@ în ( %2$@ )"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = "Încărcătura crc32 %1$@ nu se potrivește cu crc32 calculat %2$@"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Procentaj = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Dispozitivul periferic nu este conectat"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Vă rugăm să aduceți doar Pod-ul inițial în rază de acțiune sau dezactivați Pod-ul inițial"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Apropiați Pod-ul de RileyLink și încercați din nou"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Vă rugăm să confirmați că Pod-ul este bine fixat de corpul dumneavoastră. \n\nCanula poate fi introdusă doar o singură dată cu fiecare Pod. Atingeți „Confirmați” când Pod-ul este fixat."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Vă rugăm să dezactivați podul. Când dezactivarea este completă, puteți asocia un nou pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Vă rugăm să dezactivați podul. Când dezactivarea este completă, îl puteți elimina și asociați un nou pod."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Vă rugăm să activați permisiunile bluetooth pentru această aplicație în setările de sistem"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Vă rugăm să terminați asocierea Pod-ului."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Asociați un Pod nou"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Vă rugăm să repoziționați iPhone-ul mai departe de Pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Vă rugăm să repoziționați iPhone-ul mai aproape de Pod"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Vă rugăm să utilizați un alt dispozitiv cu capabilități bluetooth"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod activat"; - -/* Label describing pod age view */ -"Pod Age" = "Vechime Pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod deja asociat"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod deja amorsat"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod-ul a fost dezactivat cu succes."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Eroare Pod"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Alarmă expirare Pod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Notificare expirare Pod"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Memento pentru expirarea Pod-ului"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod-ul a expirat."; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod Expirat"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod-ul expiră"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod-ul expiră în"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod-ul expiră în %1$@."; - -/* description label for pod fault details */ -"Pod Fault Details" = "Detalii despre eroarea Pod-ului"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Defecțiune Pod: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod-ul nu este pregătit pentru inserarea canulei."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod nu este pregătit pentru amorsare."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod-ul este suspendat"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "Pod-ul nu este conectat"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Ocluzie Pod"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod-ul a fost asociat cu succes. Continuați."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Asocierea Pod-ului este nefinalizată."; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod-ul a trimis o confirmare în loc de răspuns"; - -/* Title for PodSetupView */ -"Pod Setup" = "Configurare Pod-ului"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Intervalul de timp în care se poate seta Pod-ul a expirat"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Memento pentru Pod-ul suspendat"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Putere slabă a semnalului"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Pregătiți locul."; - -/* title for previous pod page */ -"Previous Pod" = "Pod-ul anterior"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informații despre Pod-ul anterior"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Se amorsează"; - -/* Pod state when priming completed */ -"Priming completed" = "Inițiere finalizată"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Pregătire în curs. Vă rugăm să așteptați."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Pregătire în curs..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Ora pompei"; - -/* Label text for basal rate summary */ -"Rate" = "Rată"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Pregătit pentru programarea bazalelor"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Pregătit pentru inserarea canulei"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Rămas"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Memento inițializat"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Scoateți capacul albastru de ac de pe Pod și verificați canula. Apoi înlăturați eticheta de hârtie de pe spate."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Înlăturați Pod-ul de pe corp"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Ștergeți pompa"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Înlocuiți Pod-ul"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Reluați"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Reluați administrarea de insulină"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Reluați administrarea de insulină"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Reluați administrarea de insulină"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Reluare: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Se reia administrarea de insulină..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Reîncearcă"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Salvează"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Salvare..."; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Bazala programată"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Bazală programată"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Memento programat"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Selectați tipul de insulină pe care o veți utiliza în acest pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Număr de ordine"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Setați bazala temporară"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Setați bazala temporară"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Configurare finalizată"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Oprirea iminentă"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarmă de oprire iminentă"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Pierdere de semnal"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Puterea semnalului este prea mare"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Săriți peste inițierea pompei Omnipod?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspendați"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspendă administrarea"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Memento pentru suspendarea în curs"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspendați administrarea de insulină"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Timpul de suspendare a expirat"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspendare: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspendat"; - -/* Label for suspended at time */ -"Suspended At" = "Suspendat la"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Administrarea de insulină se suspendă..."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Timpul de suspendare a expirat. Deschideți aplicația și reluați."; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Treceți la alt dispozitiv de administrare a insulinei"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sincronizați cu ora curentă"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Umplere rezervor completă"; - -/* Pod power to motor activated */ -"Tank power activated" = "Putere motor rezervor activată"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Atingeți mai jos pentru a începe introducerea canulei."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Bazală temporară"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Bazală temporară în curs de rulare"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Bazala temporară este în curs de rulare"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "BasalăTemporară: %1$@ U/oră %2$@ %3$@ %4$@ U %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Bazală temporară"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Rata temporară de bazală a eșuat"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Aplicația configurează un memento pe pod pentru a vă notifica înainte de expirarea Pod. Setați numărul de ore înainte de notificare pe care doriți să o configurați atunci când asociați un pod nou."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Aplicația vă notifică în avans de expirarea Pod.\n\nDerulați pentru a seta numărul de ore dorite pentru notificare."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Aplicația vă anunță când cantitatea de insulină din Pod atinge acest nivel (50-10 U). \n\nDerulați pentru a seta numărul de unități la care doriți să fiți notificat."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Aplicația vă notifică când cantitatea de insulină din Pod atinge acest nivel."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Perioada de suspendarea a administrării de insulină s-a încheiat.\n\nPuteți relua administrarea din bannerul de pe ecranul principal sau de pe ecranul de setări al pompei. Vi se va aminti din nou în 15 minute."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Mementourile de mai sus nu vor suna dacă dispozitivul este în modul Silențios sau Nu deranjați.\n\nExistă și alte alerte și alarme critice de Pod care vor suna chiar dacă dispozitivul este setat la modul Silențios sau Nu deranjați."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Ora de pe pompă este diferită de ora curentă. Puteți revizui ora pompei și să o sincronizați cu ora curentă în meniul setări."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Ora de pe pompă este diferită de ora actuală. Puteți revizui ora pompei și să o sincronizați cu ora actuala în meniul setări."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Ora pompei este diferită de ora curentă. Ora pompei dvs. controlează setările de terapie programate. Derulați în jos la rândul Ora pompei pentru a revizui diferența de oră și a configura pompa dvs."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Fereastra din partea superioară a Pod-ului trebuie să fie colorată în roz atunci când canula a fost introdusă corect în piele."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "A apărut o problemă la comunicarea cu podul. Dacă această problemă persistă, atingeți Renunțați la pod. Apoi puteți activa un nou Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Acesta este un memento pe care l-ați programat atunci când ați asociat Pod-ul curent."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Această pompă nu a fost configurată cu o rată maximă de insulină bazală, deoarece a fost adăugată înainte ca rata temporară de insulină bazală să fie o opțiune. Vă rugăm să mergeți la Setări terapie -> limite de livrare și să setați o nouă rată maximă de insulină bazală."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Timp"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "S-a detectat schimbarea orei"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "E timpul să înlocuiți Pod-ul! Acesta va expira în %1$@"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Timeout"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Semn de comutare"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Au fost găsite prea multe Pod-uri"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Administrare totală"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Încercați din nou"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Porniți bluetooth"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/oră"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Nu se poate conecta la Pod"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Nu se poate conecta la Pod"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Nu se poate seta o rată temporară de insulină bazală: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Nu se poate seta o rată temporară de insulină bazală: %1$@ \n\n %2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Doză neconfirmată"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Mesaj neașteptat număr de ordine"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Schimbare neașteptată a podului"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Răspuns neașteptat de la Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Activare neterminată"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Dezactivare neterminată"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Caracteristică necunoscută"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Defecțiune Pod neidentificată %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Valoare necunoscută ( %1$@ ) pentru tipul %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validarea a eșuat: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Așteptați finalizarea bolusului curent sau opriți bolusul"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Așteptați finalizarea bazalei temporare curente sau suspendați pentru oprirea ei"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Așteptați până când inserarea este finalizată."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Se așteaptă mementoul de asociere"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Da"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Da, dezactivați Pod-ul"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Da, sincronizați cu ora curentă"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Veți începe acum procesul de configurare a memento-urilor, umplerea Pod-ului cu insulină, asocierea cu dispozitivul dumneavoastră și amplasarea acestuia pe corp."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Pod-ul dumneavoastră este gata de utilizare. \n\n %1$@ vă va reaminti să vă schimbați Pod-ul înainte de a expira. Puteți schimba într-un moment convenabil pentru dumneavoastră."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Este posibil ca Podul dvs. să administreze în continuare insulină.\nScoateți-l din corpul dumneavoastră, apoi atingeți \"Continuați\"."; - diff --git a/Dependencies/OmniBLE/OmniBLE/ru.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/ru.lproj/Localizable.strings deleted file mode 100644 index 8766306e8..000000000 --- a/Dependencies/OmniBLE/OmniBLE/ru.lproj/Localizable.strings +++ /dev/null @@ -1,1130 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = "(неактивно)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ назад"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ дБ"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ восстановил связь с подом на вашем теле.\n\nЗаписи о поданном инсулине были обновлены и должны соответствовать тому, что было доставлено на самом деле.\n\nТеперь вы можете продолжать использовать %@ в обычном режиме."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ Ед"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@Ед"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ за %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ не может связаться с подом на вашем теле с %2$@.\n\nБез связи с подом приложение не может продолжать отправлять команды на доставку инсулина или отображать точную, свежую информацию о вашем активном инсулине или инсулине, доставляемом подом.\n\nВнимательно следите за уровнем глюкозы в течение следующих 6 или более часов, поскольку в вашем организме может активно работать или не работать инсулин, который %3$@ не может отобразить."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "В поде осталось %1$@ инсулина или меньше. Замените под в ближайшее время."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ ед остается в %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g Ед"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 час"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 час 30 минут"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 часа"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 минут"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Превышено время для активации"; - -/* description label for active time pod details row */ -"Active Time" = "Активирован в"; - -/* Section header for activity section */ -"Activity" = "Нагрузка"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Настройка времени помпы..."; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Вы уверены, что хотите отменить настройку Pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Вы уверены, что хотите пропустить Omnipod Onboarding?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Вы уверены, что хотите прекратить использование Omnipod DASH?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Прикрепить под"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Попытка восстановления связи"; - -/* Description for auto-off */ -"Auto-off" = "Авто выключение"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Авто отключение сигнала"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Назад"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Базал инициирован"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Менее 50 единиц"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "Версия прошивки BLE"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth выключен"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Bluetooth сбрасывается"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth недоступен по неизвестной причине."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth недоступен: %1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "Использование Bluetooth не разрешено"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "Использование Bluetooth не поддерживается на данном устройстве"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Болюс"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Подача болюса"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Болюс: %1$@ед %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Подается болюс"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Подача болюса при подаче ВБС"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Отмена"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Отменить ручную ВБС"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Канюля введена успешно. Продолжить."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Установка катетера"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Определенно"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Замените под сейчас. Подача инсулина прекратится через 8 часов после истечения срока действия пода или когда инсулина больше не останется."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Замените под сейчас. Подача инсулина прекратится через %1$@ или когда инсулина больше не останется."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Замените под сейчас. Подача инсулина прекратится через 1 час."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Замените под сейчас. Под активен в течение уже 72 часов."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Проверьте канюлю"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Проверьте под, приклейте его на место установки, затем подтвердите прикрепление пода."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Проверка ввода канюли"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Проверка..."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Ошибка команды %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Проблемы со связью"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Связь восстановлена"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Проблема со связью: ожидается неподтвержденная команда."; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Напоминания об уверенности"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Напоминания об уверенности - это звуковые сигналы, подаваемые подом, которые можно использовать для подтверждения выбранных команд."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Напоминания будут звучать для инициированных вами команд, таких как болюс, отмена болюса, приостановка, возобновление, напоминания о сохранении уведомлений и т.д. Когда Loop автоматически регулирует подачу инсулина, напоминания не будут использоваться."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Напоминания будут звучать, когда Loop автоматически регулирует подачу инсулина, а также для команд, которые вы инициируете."; - -/* Section header for configuration section */ -"Configuration" = "Конфигурация"; - -/* Button title for confirm attachment option */ -"Confirm" = "Подтвердить"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Подтвердите, что под прикреплен к телу"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Продолжить"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "Не удалось разобрать сообщение: %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Критические оповещения"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Критическая ошибка пода"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Возможны перекрестные помехи. Пожалуйста, переместитесь на новое место"; - -/* Unit for singular day in pod life remaining */ -"day" = "день"; - -/* Unit for plural days in pod life remaining */ -"days" = "дней"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Деактивировать Pod"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Не активен"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Деактивация."; - -/* Action button description while deactivating */ -"Deactivating..." = "Деактивация..."; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Удалить Omnipod DASH"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Сведения об устройстве"; - -/* description label for device name pod details row */ -"Device Name" = "Имя устройства"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Выключено"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Выбросить под"; - -/* No comment provided by engineer. */ -"Done" = "Готово"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Резервуар пуст"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Резервуар пуст"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Пустой ответ от пода"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Пустое значение"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Активировано"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Ошибка"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Ошибка записана в лог, отключение"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Совет по истечению срока действия"; - -/* Description for expiration alert */ -"Expiration alert" = "Оповещение об истечении срока"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Напоминание об истечении срока"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Напоминание об истечении срока действия По умолчанию"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Растянутый"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Вводится растянутый болюс"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Продленный болюс с временной базальной скоростью"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Не удалось отменить ручной базал"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Не удалось возобновить подачу инсулина"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Не удалось установить время в помпе"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Не удалось приостановить подачу инсулина"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Не удалось обновить настройки напоминания о конфиденциальности."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Не удалось обновить напоминание об истечении срока действия"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Не удалось обновить напоминание о низком уровне резервуара"; - -/* Pod life HUD view label */ -"Fault" = "Сбой"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Произошло событие неисправности"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Заправьте новый под инсулином (не менее 100 единиц, голубая крышка канюли должна быть на месте). Дождитесь 2 звуковых сигналов."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Завершение деактивации"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Завершение деактивации"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Завершение сопряжения"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Завершить настройку"; - -/* Description for finish setup */ -"Finish setup " = "Завершение настройки"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Напоминание о завершении настройки"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Более %1$@ ед остается в %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "час"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "часов"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Если вы отмените настройку пода, текущий под будет деактивирован и станет непригодным для использования."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Неправильное исключение пакета: %1$@ (location=%2$d)"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Неправильный ответ"; - -/* Pod inititialized */ -"Initialized" = "Активирован"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Ввести канюлю"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Введено"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Введение катетера"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Введение канюли. Пожалуйста, подождите."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Введение канюли..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Подача инсулина остановлена"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Введение инсулина остановлено. Замените Под."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Подача инсулина будет прекращена до тех пор, пока вы не возобновите ее вручную. Когда вы хотите, чтобы Loop напомнил вам о необходимости возобновить подачу?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Остаток инсулина"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Подача инсулина приостановлена"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Тип инсулина"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Тип инсулина не указан"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Внутренняя ошибка пода %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Болюс прерван%1$@ ед (%2$@ ед намечено) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Неверный адрес 0x%1$x. Ожидаемый адрес 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Неверный адрес: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Неверный CRC"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Неверный ключ LTK: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Неверная настройка"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Правильно ли введен катетер?"; - -/* description label for last status date pod details row */ -"Last Status" = "Последнее состояние"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Прослушайте 2 звуковых сигнала."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop не будет автоматически регулировать подачу инсулина, пока временная базальная скорость не закончится или не будет отменена."; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Мало инсулина в резервуаре"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Мало инсулина в резервуаре"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Предупреждение о низком уровне резервуара (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Оповещение о малом запасе инсулина в резервуаре"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Резервуар помпы пуст"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Убедитесь, что iPhone находится рядом с активным подом"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Убедитесь, что ваш телефон и под находятся рядом друг с другом. Если проблемы со связью сохраняются, перейдите в другое место."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Убедитесь, что ваш под заполнен инсулином и находится рядом."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Убедитесь, что ваш под находится рядом и попробуйте снова."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Убедитесь, что RileyLink находится поблизости и включен"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Ручная ВБС"; - -/* Pod memory initialized */ -"Memory initialized" = "Память инициализирована"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Исключение ввода-вывода сообщения: %1$@"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "минута"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "минут"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Отсутствует конфигурация"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Переместитесь на новое место подальше от других подов и повторите попытку."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Оповещение по нескольким командам"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NA"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Продолжить"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Нет"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Нет подачи"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Активных оповещений нет"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Напоминания о доверии не используются."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Ошибок нет"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Нет инсулина"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Нет пода"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Нет сопряженного пода"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Подов не найдено"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Нет напоминаний"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Нет ответа от пода"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Нет доступного RileyLink"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Нет, продолжить с подом"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Нет, оставить время в помпе как есть"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Норма"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Недостаточно данных"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Настройки уведомлений"; - -/* No comment provided by engineer. */ -"Numbers" = "Цифры"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Обнаружена закупорка"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Обнаружена закупорка"; - -/* Action button default text for PodAlerts */ -"Ok" = "Ок"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Омнипод"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Напоминания пода"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Сопрячь под"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Сопрячь под."; - -/* Pod status after pairing */ -"Paired" = "Сопряжен"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Сопряжение завершено"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Исключение сопряжения: %1$@"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Начать сопряжение"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Сопряжение..."; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Ошибка синтаксического анализа: %1$@ in (%2$@)"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = " crc32 %1$@ не соответствует вычисленному crc32 %2$@"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Процент = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Периферийное устройство не готово"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Пожалуйста, приносите в зону действия только оригинальный под или деактивируйте оригинальный под"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Поднесите Omnipod ближе к RileyLink и попробуйте снова"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Убедитесь, что под надежно приклеен на вашем теле.\n\nКатетер можно ввести только один раз. Нажмите кнопку \"Подтвердить\", когда под приклеен."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Пожалуйста, деактивируйте под. Когда деактивация будет закончена, Вы сможете сопрячь новый."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Пожалуйста, деактивируйте под. Когда деактивация будет закончена, Вы можете снять старый под и сопрячь новый."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Включите разрешения Bluetooth для этого приложения в настройках системы."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Пожалуйста, завершите сопряжение вашего пода."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Начните сопряжение с новым Omnipod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Пожалуйста, переместите iPhone подальше от пода"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Пожалуйста, измените положение iPhone относительно пода"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Пожалуйста, используйте другое устройство с функцией bluetooth"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Под активирован"; - -/* Label describing pod age view */ -"Pod Age" = "Pod проработал"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Omnipod уже сопряжен"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Omnipod уже прокачан инсулином"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Под успешно деактивирован. Продолжить."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Ошибка пода"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Оповещение об окончании срока работы Omnipod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Сообщение об окончании гарантийного срока Omnipod "; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Напоминание об истечении срока"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Срок работы Omnipod истек"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Под истек"; - -/* Label for pod expiration row */ -"Pod Expires" = "Срок действия пода истекает"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Под истекает "; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Под истекает в %1$@"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Детали ошибка пода"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Отказ Omnipod %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Omnipod не готов к установке катетера"; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Omnipod не готов к прокачиванию инсулина"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Omnipod приостановлен"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "Под не подключен"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Закупорка пода"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Под успешно сопряжен. Продолжить."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Сопряжение с подом не выполнено"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod отправил \"ack\" вместо ответа (ему кирдык)"; - -/* Title for PodSetupView */ -"Pod Setup" = "Настройка пода"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Время для ввода настроек Omnipod истекло"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Напоминание о приостановке подачи инсулина"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Плохой уровень сигнала"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Подготовьте место установки помпы"; - -/* title for previous pod page */ -"Previous Pod" = "Предыдущий под"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Предыдущая информация о поде"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Прокачивание инсулина"; - -/* Pod state when priming completed */ -"Priming completed" = "Прокачка инсулина завершена"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Заправка. Пожалуйста, подождите."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Заправить..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Время в помпе"; - -/* Label text for basal rate summary */ -"Rate" = "Rate"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Готов к программированию базала"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Готов к установке катетера"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Остается"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Инициализация напоминания"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Отломите защитную крышку канюли (голубого цвета) и проверьте состояние самой канюли. Далее снимите защитные стикеры с пластыря."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Снимите под с тела"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Удалите помпу"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Заменить Pod"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Возобновление"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Возобновить подачу"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Возобновить подачу"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Возобновить подачу инсулина"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Возобновление: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Возобновление подачи инсулина..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Повторить"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Сохранить"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Сохранение..."; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Запланированный базал"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Запланированная база"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Запланированное напоминание"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Выберите тип инсулина, с которым Вы будете использовать этот под."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Порядковый номер"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Установить ВБС"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Установить ВБС"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Настройка завершена"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Выключение неизбежно"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Оповещение о неизбежном выключении"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Сигнал потерян"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Слишком высокий уровень сигнала"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Пропустить настройку Omnipod?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Приостановка"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Остановить подачу"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Напоминание о приостановке подачи инсулина"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Остановить подачу инсулина"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Время приостановки подачи истекло"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Приостановка: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Остановлено"; - -/* Label for suspended at time */ -"Suspended At" = "Приостановлено в"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Остановка подачи инсулина..."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Время приостановки подачи инсулина истекло. Откройте приложение и возобновите подачу."; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Переключиться на другое устройство для введения инсулина"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Синхронизация с текущим временем"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Заполнение резервуара Omnipod завершено"; - -/* Pod power to motor activated */ -"Tank power activated" = "Питание моторчика резервуара активировано"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Нажмите ниже, чтобы начать ввод канюли."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "ВБС"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Пока еще работает временный базал"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Подается временный базал"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "Врем базал: %1$@ ед/ч %2$@ %3$@ %4$@ ед %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "ВБС"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Ошибка установки ВБС"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Приложение настраивает напоминание на телефоне, чтобы уведомить вас об истечении срока действия Pod. Установите количество часов предварительного уведомления, которое вы хотите сохранить при сопряжении нового Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Приложение заранее уведомит Вас об истечении срока действия Pod.\n\nПрокрутите, чтобы установить количество часов предварительного уведомления, которое вы хотели бы получить."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Приложение уведомит Вас, когда количество инсулина в Pod достигнет этого уровня (50-10 Ед).\n\nПрокрутите, чтобы установить количество единиц, о которых вы хотели бы получить напоминание."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Приложение уведомит Вас, когда количество инсулина в Pod достигнет этого уровня."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Период приостановки подачи инсулина закончилось.\n\nВы можете возобновить введение инсулина с баннера на главном экране приложения или с экрана настроек вашей помпы. Через 15 минут вы получите повторное напоминание."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Приведенные выше напоминания не будут звучать, если ваше устройство находится в режиме Тишина или Не беспокоить.\n\nЕсть и другие критические оповещения и сигналы тревоги Pod, которые будут звучать, даже если ваше устройство настроено в режим Тишина или Не беспокоить."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Время на вашей помпе отличается от текущего времени. Вы хотите обновить время на вашей помпе на текущее?"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Время на вашей помпе отличается от текущего времени. Вы можете проверить время на помпе и синхронизировать его с текущим временем в настройках приложения."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Время на помпе отличается от текущего времени. Время вашей помпы контролирует ваши запланированные настройки терапии. Прокрутите вниз до строки времени помпы, чтобы просмотреть разницу во времени и настроить помпу."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Когда канюля правильно введена под кожу, окошко в верхней части пода должно окраситься в розовый цвет."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Возникла проблема с общением с подом. Если эта проблема сохраняется, нажмите \"Деактивировать Pod\". Затем вы можете активировать новый Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Это напоминание, которое вы запланировали при сопряжении с текущим подом."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Эта помпа не была настроена с максимальным базалом, потому что была добавлена до того, как установка ручной ВБС стала возможной. Пожалуйста, перейдите в настройки терапии -> Лимиты доставки и установите новый максимальный базал."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Время"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Обнаружено изменение времени"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Пора заменить Pod - Срок годности истекает через %1$@"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Тайм-аут"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Переключение входа"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Найдено слишком много подов"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Подано всего"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Попробуйте еще раз"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Включите Bluetooth"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hr"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Невозможно связаться с подом"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Невозможно связаться с подом"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Невозможно установить ВБС: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Невозможно установить ВБС: %1$@\n\n%2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Не подтверждено"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Неожиданный порядковый номер сообщения"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Неожиданная смена пода"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Неожиданный отклик Omnipod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Не закончена активация"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Незавершенная деактивация"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Неизвестная характеристика"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Неизвестная неисправность Omnipod %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Неизвестное значение ( %1$@ ) для типа %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Ошибка проверки: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Дождитесь окончания подачи болюса или отмените его"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Дождитесь окончания введения текущей ВБС или остановите помпу для отмены"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Подождите, пока ввод канюли завершится."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Все еще ожидается сопряжение"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Да"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Деактивировать Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Да, синхронизировать с текущим временем"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Сейчас Вы начнете процесс конфигурирования напоминаний, заправки пода инсулином, сопряжения с телефоном и установкой пода на тело."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Под готов к использованию.\n\n%1$@ напомнит вам о необходимости замены пода до истечения срока его действия. Вы можете изменить это на удобное для вас время."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Ваш под может по-прежнему доставлять инсулин.\n Удалите его с тела, затем нажмите «Продолжить»."; - diff --git a/Dependencies/OmniBLE/OmniBLE/sk.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/sk.lproj/Localizable.strings deleted file mode 100644 index 09e8ac7b2..000000000 --- a/Dependencies/OmniBLE/OmniBLE/sk.lproj/Localizable.strings +++ /dev/null @@ -1,856 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = "{neaktívne}"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "pred %@"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ j"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@ j"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "1 pre 2"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ sa nepodarilo komunikovať s podom na vašom tele od %2$@ . \n\nBez komunikácie s podom, nemôže aplikácia pokračovať v odosielaní príkazov na aplikáciu inzulínu, ani zobrazovať presné a aktuálne informácie o vašom aktívnom inzulíne alebo o inzulíne podávanom podom. \n\nPočas nasledujúcich 6 alebo viac hodín pozorne sledujte svoju glykémiu, pretože vo vašom tele môže alebo nemusí aktívne pôsobiť inzulín, ktorý %3$@ nedokáže zobraziť."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "V podu zostáva %1$@ inzulínu alebo menej. Čoskoro vymeňte pod."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ jednotiek zostávajúcich na %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@ + %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g j"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Čas aktivácie bol prekročený"; - -/* description label for active time pod details row */ -"Active Time" = "Aktívny čas"; - -/* Section header for activity section */ -"Activity" = "Aktivita"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Naozaj chcete preskočiť nastavovanie Omnipodu?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Aplikujte pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Prebieha obnovenie komunikácie"; - -/* Description for auto-off */ -"Auto-off" = "Automatické vypnutie"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Späť"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Bazál inciovaný"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Menej ako 50 jednotiek"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Prebieha bolus"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "\nBolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusovanie"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolusovanie s dočasným bazálom"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Zrušiť"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanyla úspešne zavedená. Pokračovať."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Zavádzanie kanyly"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Zaručené"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Ihneď vymeniť pod. Podávanie inzulínu sa zastaví o 8 hodín alebo keď sa minie inzulín."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Ihneď vymeniť pod. Podávanie inzulínu sa zastaví o %1$@ alebo keď sa minie inzulín."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Treba vymeniť pod. Podávanie inzulínu sa zastaví o 1 hodinu."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Vymeniť pod teraz. Pod bol aktívny 72 hodín."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Skontrolujte kanylu"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Skontrolujte pod, aplikujte ho na telo, potom potvrďte prilepenie podu."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Kontrola zavedenia"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Kontroluje sa..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Príkazy obnovené"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Problém s komunikáciou: Čaká sa na potvrdenie príkazu."; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Potvrdzovacie pripomienky sú pípnutia z podu, ktoré možno použiť pre potvrdenie vybraných príkazov."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Pripomienky spoľahlivosti zaznejú pri príkazoch, ktoré spustíte, ako je bolus, zrušenie bolusu, pozastavenie, obnovenie, uloženie upozornení atď. Keď Loop automaticky upraví podanie, nepoužijú sa žiadne pripomenutia spoľahlivosti."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Keď Loop automaticky upraví podávanie, ako aj prevedie príkazy, ktoré iniciujete, zaznejú pripomenutia spoľahlivosti."; - -/* Section header for configuration section */ -"Configuration" = "Konfigurácia"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Pokračovať"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritické výstrahy"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Možné presluchy. Presuňte sa na iné miesto"; - -/* Unit for singular day in pod life remaining */ -"day" = "deň"; - -/* Unit for plural days in pod life remaining */ -"days" = "dni"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Deaktivovať pod"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktivované"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktivuje sa."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deaktivuje sa..."; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Podrobnosti o zariadení"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Zlikvidujte pod"; - -/* No comment provided by engineer. */ -"Done" = "Hotovo"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Prázdna nádrž"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Prázdna odpoveď z podu"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Chyba"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Zaprotokolovaná udalosť chyby, vypína sa"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Upozornenie na vypršanie platnosti"; - -/* Description for expiration alert */ -"Expiration alert" = "Varovanie o expirácii"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Pripomienka o expirácii"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Predvolené pripomenutie o expirácii"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Prebieha predĺžený bolus"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Predĺžený bolus beží súčasne s dočasným bazálom"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Zrušenie manuálneho bazálu zlyhalo"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Obnovenie podávania inzulínu zlyhalo"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Nastavenie času pumpy zlyhalo"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Pozastavenie podávania inzulínu zlyhalo"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Nepodarilo sa aktualizovať predvoľbu pripomenutia dôveryhodnosti."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Nepodarilo sa aktualizovať pripomenutie o expirácii"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Nepodarilo sa aktualizovať pripomienku nízkej hladiny v rezervoári"; - -/* Pod life HUD view label */ -"Fault" = "Chyba"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Vyskytla sa chybová udalosť"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Dokončiť deaktiváciu"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Dokončiť nastavenie"; - -/* Description for finish setup */ -"Finish setup " = "Dokončiť nastavenie"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Dokončiť nastavenie pripomienky"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Viac ako %1$@ jednotiek zostávajúcich o %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hodina"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hodiny"; - -/* Pod inititialized */ -"Initialized" = "Inicializované"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Zaviesť kanylu"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Kanyla sa zavádza"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Zavádzanie. Počkajte, prosím."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Zavádza sa.."; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Podávanie inzulínu"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Podávanie inzulínu sa zastavilo. Vymeňte modul teraz."; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Zostávajúci inzulín"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Typ inzulínu"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Typ inzulínu nie je nakonfigurovaný"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Interná chyba podu %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "PrerušenýBolus: %1$@ j (%2$@ j naplánované) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Neplatná adresa 0x %1$x . Očakáva sa 0x %2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Neplatná adresa: ( %1$@ )"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Neplatný kód CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Neplatné nastavenie"; - -/* description label for last status date pod details row */ -"Last Status" = "Posledný stav"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop nebude automaticky upravovať podávanie inzulínu, kým dočasná bazálna dávka nebude ukončená alebo zrušená."; - -/* description label for lot number pod details row */ -"Lot Number" = "Číslo šarže"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Nízka hladina v rezervoári"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Nízka hladina v rezervoári"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Nízka hladina v rezervoári (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Nízka hladina v rezervoári"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Pripomienka Nízka hladina v rezervoári"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Uistite sa, že váš telefón a pod sú blízko seba. Ak problémy s komunikáciou pretrvávajú, presuňte sa na iné miesto."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Uistite sa, že je váš pod naplnený a v blízkosti."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Uistite sa, že je váš RileyLink v blízkosti a je zapnutý"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuálny bazál"; - -/* Pod memory initialized */ -"Memory initialized" = "Pamäť inicializovaná"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minúta"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minúty"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Chýba konfigurácia"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Presuňte sa ďalej od ostatných modulov a skúste znova."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Upozornenie na viacero príkazov"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NA"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Ďalej"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nie"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Žiadne upozornenia"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Nepoužívajú sa žiadne pripomenutia spoľahlivosti."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Žiadne chyby"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Žiadny inzulín"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Žiadny pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Nie je spárovaný žiadny pod"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Nenašiel sa žiadny pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Žiadna pripomienka"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Žiadna odpoveď z podu"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Nie je k dispozícii žiadny RileyLink"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normálny"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Nedostatok dát"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Nastavenia oznámení"; - -/* No comment provided by engineer. */ -"Numbers" = "Čísla"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Zistená oklúzia"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Zistená oklúzia"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Pripomienky omnipodu"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "jednoNepoužité"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Párovať pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Párovať pod."; - -/* Pod status after pairing */ -"Paired" = "Spárované"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Párovanie je dokončené"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Párovanie."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Páruje sa…"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Prosím, majte iba pôvodný pod v dosahu alebo deaktivujte pôvodný pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Priblížte pod k RileyLinku a skúste to znova"; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Prosím, deaktivujte pod. Po dokončení deaktivácie, môžete spárovať nový pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Prosím, deaktivujte pod. Po dokončení deaktivácie, ho môžete odstrániť a spárovať nový pod."; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Dokončite párovanie podu."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Spárujte nový pod"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod aktivovaný"; - -/* Label describing pod age view */ -"Pod Age" = "Vek podu"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod je už spárovaný"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod je už pripravený"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deaktivovaný úspešne. Pokračovať."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Chyba podu"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Oznámenie o expirácii podu"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Oznámenie o expirácii podu"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod vypršal"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod expiroval"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expiruje o"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Detaily chyby podu"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Chyba podu: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod nie je v stave pripravenom na zavedenie kanyly."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pumpu nie je v tomto stave možné pripraviť."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod je pozastavený"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Oklúzia podu"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod sprárovaný úspešne. Pokračovať."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Párovanie podu nebolo dokončené"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod poslal potvrdenie namiesto odpovede "; - -/* Title for PodSetupView */ -"Pod Setup" = "Nastavenie podu"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Okno nastavenia podov vypršalo"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pripomenutie pozastaveného podu"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Slabá sila signálu"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Pripravte miesto."; - -/* title for previous pod page */ -"Previous Pod" = "Predchádzajúci Pod"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Príprava podu"; - -/* Pod state when priming completed */ -"Priming completed" = "Príprava podu dokončená"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Pripravuje sa. Prosím čakajte."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Príprava…"; - -/* Label text for basal rate summary */ -"Rate" = "Dávka"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Pripravené na programovanie bazálu"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Pripravené na zavedenie kanyly"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Zostáva"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Pripomienka bola inicializovaná"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Vymeňte pod"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Obnoviť podávanie inzulínu"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Obnoviť podávanie inzulínu"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Obnoviť podávanie inzulínu"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Obnovuje sa podávanie inzulínu..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Skúsiť znova"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Uložiť"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Ukladá sa..."; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Naplánovaný bazál "; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Naplánovaný bazál"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Naplánovaná pripomienka"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Vyberte typ inzulínu, ktorý budete používať v tomto pode."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sekvenčné číslo"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Nastaviť dočasný bazál"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Nastavenie je dokončené"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Vypnutie každú chvilu"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Varovanie bezprostredného vypnutia"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Strata signálu"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Príliš vysoká sila signálu"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Preskočiť Omnipod Onboarding?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Pozastavenie"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Pripomienka prebiehajúceho pozastavenia"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Zastavte podávanie inzulínu"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Čas pozastavenia vypršal"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Pozastaviť: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Pozastavené"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Pozastavenie podávania inzulínu..."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Čas pozastavenia vypršal. Otvorte aplikáciu a pokračujte."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Plnenie nádrže dokončené"; - -/* Pod power to motor activated */ -"Tank power activated" = "Napájanie nádrže je aktivované"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Ťuknutím nižšie spustíte zavádzanie kanyly."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Dočasný bazál"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Prebieha dočasný bazál"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Prebieha dočasný bazál"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "DočasBazál: %1$@ j/hod %2$@ %3$@ %4$@ j %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Dočasný bazál"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Dočasný bazál zlyhal"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Aplikácia nakonfiguruje pripomienku do podu, aby vás vopred upozornila na expiráciu podu. Počas párovania nového podu, nastavte, koľko hodín vopred, by ste chceli pripomienku nakonfigurovať."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Aplikácia vás vopred upozorní na expiráciu podu. \n\nRolovaním nastavte počet hodín vopred, kedy chcete upozornenie dostať."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Aplikácia vás upozorní, keď množstvo inzulínu v pode dosiahne túto úroveň (50 – 10 U). \n\nRolovaním nastavte počet jednotiek, pri ktorých chcete byť upozornení."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Aplikácia vás upozorní, keď množstvo inzulínu v pode dosiahne túto úroveň."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Obdobie pozastavenia inzulínu sa skončilo.\n\nPodávanie inzulínu môžete obnoviť z bannera na domovskej obrazovke alebo z obrazovky nastavení pumpy. Pripomienka sa vám znova zobrazí o 15 minút."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Čas na pumpe sa líši od aktuálneho času. V nastaveniach môžete skontrolovať čas pumpy a synchronizovať sa s aktuálnym časom."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Čas na pumpe je iný ako aktuálny čas. Čas pumpy riadi vaše naplánované liečebné nastavenia. Prejdite nadol na riadok Čas pumpy, pozrite si časový rozdiel a nakonfigurujte pumpu."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Nastal problém s komunikáciou s podom. Ak tento problém pretrváva, ťuknite na položku Zlikvidovať Pod. Potom môžete aktivovať nový pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Toto je pripomienka, ktorú ste naplánovali pri spárovaní aktuálneho Podu."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "triNepoužité"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Čas"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Zistila sa zmena času"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Je čas vymeniť pod! Platnosť vášho podu vyprší o %1$@"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Značka prepnutia"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Našlo sa príliš veľa podov"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Celková dávka"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Skúste znova"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "dveNepoužité"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Pod nie je v dosahu."; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Pod nie je v dosahu."; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Nie je možné nastaviť dočasnú dávku bazálu: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Nie je možné nastaviť dočasnú dávku bazálu: %1$@ \n\n %2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Neisté"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Neočakávané poradové číslo správy"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Neočakávaná zmena podu"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Neočakávaná odpoveď z podu"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Aktivácia neukončená"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Deaktivácia neukončená"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Neznáma chyba podu %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Neznáma hodnota ( %1$@ ) pre typ %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Overenie zlyhalo: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Počkajte na dokončenie bolusu alebo bolus zrušte"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Počkajte, kým sa dokončí dočasný bazál, alebo ho zrušte"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Počkajte kým nie je zavedenie ukončené."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Čaká sa na pripomienku párovania"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Áno"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Teraz začnete s procesom konfigurácie pripomienok, naplnením podu inzulínom, jeho spárovaním s vašim zariadením a umiestnením podu na telo."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Váš pod je pripravený na použitie. \n\n %1$@ vám pripomenie, aby ste vymenili svoj pod pred časom jeho expirácie. Môžete to zmeniť na čas, ktorý vám vyhovuje."; - diff --git a/Dependencies/OmniBLE/OmniBLE/sv.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/sv.lproj/Localizable.strings deleted file mode 100644 index 79374593d..000000000 --- a/Dependencies/OmniBLE/OmniBLE/sv.lproj/Localizable.strings +++ /dev/null @@ -1,430 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inaktiv)"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ sedan"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ E"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ enheter återstår kl. %2$@"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Tid för aktivering överskriden"; - -/* description label for active time pod details row */ -"Active Time" = "Aktiv tid"; - -/* Section header for activity section */ -"Activity" = "Aktivitet"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-av larm"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Tillbaka"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initierad"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Under 50 enheter"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus pågår"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@E %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Ger bolus"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Ger bolus med temporär basal"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Avbryt"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Kanyl förs in"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Säker"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Kontrollerar..."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Kommandofel %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Kommandoproblem"; - -/* Section header for configuration section */ -"Configuration" = "Konfiguration"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Fortsätt"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Inaktivera podd"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Inaktiverad"; - -/* No comment provided by engineer. */ -"Done" = "Färdig"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Podfel, tom reservoarl"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Inget svar från pod"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "På"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Fel"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Felhändelse loggad, stänger ned"; - -/* Description for expiration alert */ -"Expiration alert" = "Larm om utgångsdatum"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Påminnelse om utgångsdatum"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Misslyckades att återuppta insulintillförsel"; - -/* Pod life HUD view label */ -"Fault" = "Fel"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Felhändelse inträffade"; - -/* Description for finish setup */ -"Finish setup " = "Inställning färdig"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Fler än %1$@ enheter återstår kl. %2$@"; - -/* Pod inititialized */ -"Initialized" = "Pod initialiserad"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "För in kanyl"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Kanyl förs in"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulintillförsel pausad"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulintyp"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Internt podfel %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "AvbrutenBolus: %1$@ E (%2$@ E schemalagd) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Ogiltig adress 0x%1$x. Förväntade 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Ogiltig adress: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Ogiltigt CRC"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Låg reservoarvolym"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Larm vid låg reservoarvolym"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Säkerställ att din RileyLink är nära och påslagen"; - -/* Pod memory initialized */ -"Memory initialized" = "Minne initierat"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Inga larm"; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Inga fel"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Inget insulin"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Ingen Podd"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Ingen parkopplad"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Inget svar från pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Ingen RileyLink tillgänglig"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Inte tillräckligt med data"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Ocklusion upptäckt"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pod status after pairing */ -"Paired" = "Parkopplad"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Ha endast din ursprungliga podd inom räckvidd eller inaktivera ursprunglig podd"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "För din pod närmare din RileyLink och försök igen"; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Var god parkoppla ny pod"; - -/* Label describing pod age view */ -"Pod Age" = "Poddålder"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod redan parkopplad"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod redan fylld"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Larm för utgångsdatum för pod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Notis om utgångsdatum för pod"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod har utgått"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Poddens utgångsdatum passerat"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Podfel: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod är inte klar för att föra in kanyl"; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod är inte klar för att fyllas"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod är pausad"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Podd skickade ack istället för svar"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Tid för podinställning är överskriden"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Dålig signalstyrka"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Pod fylls på"; - -/* Pod state when priming completed */ -"Priming completed" = "Podd har fyllts färdigt med insulin"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Klar för programmering av basal"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Klar att föra in kanyl"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Återstår"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Påminnelse initierad"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Byt podd"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Återuppta: %1$@ %2$@"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Försök igen"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Spara"; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Schemalagd basal"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Schemalagd basal"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Välj vilken typ av insulin du kommer att använda."; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Inställning klar"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Larm för omedelbar avstängning"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signalstyrka för hög"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Pausa insulintillförsel"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Pausa: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Pausad"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Pod har fyllts klart"; - -/* Pod power to motor activated */ -"Tank power activated" = "Ström till motor för behållare aktiverad"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temporär basal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temp basal pågår redan"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temp basal pågår"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ E/timme %2$@ %3$@ %4$@ E %5$@"; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Tid"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Byt din pod! Din pod går ut om %1$@"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Försök igen"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "E/timme"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Osäker"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Oväntat meddelandesekvensnummer"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Oväntat poddbyte"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Oväntat svar från din pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Okänt podfel %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Okänt värde (%1$@) av typ %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validering misslyckades: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Vänta på att pågående bolus är färdig, eller avbryt bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Vänta på nuvarande temporära basal, eller pausa för att avbryta"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Väntar på påminnelse för parkoppling"; - diff --git a/Dependencies/OmniBLE/OmniBLE/tr.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/tr.lproj/Localizable.strings deleted file mode 100644 index 1ab6aa045..000000000 --- a/Dependencies/OmniBLE/OmniBLE/tr.lproj/Localizable.strings +++ /dev/null @@ -1,1127 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = "(etkin değil)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ önce"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ vücudunuzdaki pod ile iletişimi yeniden sağladı.\n\nİnsülin iletim kayıtları güncellendi ve gerçekte iletilenlerle eşleşmelidir.\n\nŞimdi normal şekilde %@ kullanmaya devam edebilirsiniz."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ Ü"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@Ü"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%2$@ için %1$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ , %2$@ tarihinden beri vücudunuzdaki pod ile iletişim kuramıyor. \n\nPod ile iletişim olmadan, uygulama insülin iletimi için komutlar göndermeye devam edemez ve aktif insülininiz veya pod tarafından verilen insülin hakkında doğru ve güncel bilgileri görüntüleyemez. \n\n Vücudunuzda aktif olarak çalışan ve %3$@ tarafından görüntülenemeyen insülin olabilir veya olmayabilir, önümüzdeki 6 saat veya daha uzun bir süre boyunca kan şekerinizi yakından takip edin."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insülin veya daha az kaldı. Yakında Pod'u değiştirin."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ ünite kaldı %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%gr Ü"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 saat"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 saat 30 dakika"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 saat"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 dakika"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Aktivasyon süresi aşıldı"; - -/* description label for active time pod details row */ -"Active Time" = "Aktif Zaman"; - -/* Section header for activity section */ -"Activity" = "Aktivite"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pompa Zamanı Ayarlanıyor..."; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Pod kurulumunu iptal etmek istediğinizden emin misiniz?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Omnipod katılımını atlamak istediğinizden emin misiniz?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Omnipod DASH'i kullanmayı bırakmak istediğinizden emin misiniz?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Pod Ekleme"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "İletişim yeniden kuruluyor"; - -/* Description for auto-off */ -"Auto-off" = "Otomatik kapanma"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Oto-kapanma alarmı"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Geri"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Bazal başlatıldı"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "50 ünitenin altında"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Yazılım Sürümü"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth kapalı"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Bluetooth sıfırlanıyor"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth bilinmeyen bir nedenle kullanılamıyor."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth kullanılamıyor: %1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "Bluetooth kullanımı yetkisiz"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "Bluetooth kullanımı bu cihazda desteklenmiyor"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus devam ediyor"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@Ü %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolus iletiliyor"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Geçici bazal ile bolus iletiliyor"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "İptal"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Manuel Bazalı İptal Et"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanül başarıyla yerleştirildi. Devam et."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Kanül takma"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Kesin"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Pod'u şimdi değiştirin. İnsülin iletimi, podun süresi dolduktan 8 saat sonra veya insülin kalmadığında duracaktır."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Pod'u şimdi değiştirin. İnsülin iletimi %1$@ içinde veya insülin kalmadığında duracaktır."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Pod'u şimdi değiştirin. İnsülin iletimi 1 saat içinde duracaktır."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Pod'u şimdi değiştirin. Pod 72 saattir aktif."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Kanülü Kontrol Edin"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Pod'u kontrol edin, uygulayın, ardından pod eklemeyi onaylayın."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Yerleştirmeyi Kontrol Et"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Kontrol ediliyor..."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Komut hatası %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "İletişim Sorunu"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "İletişim Kurtarıldı"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "İletişim sorunu: Onaylanmamış komut beklemede."; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Emniyet Hatırlatıcıları"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Emniyet hatırlatıcıları, poddan gelen ve seçilen komutları onaylamak için kullanılabilen bip sesleridir."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Emniyet hatırlatıcıları, bolus, bolus iptali, askıya alma, devam ettirme, bildirim hatırlatıcılarını kaydetme gibi başlattığınız komutlar için çalacaktır. Loop iletimi otomatik olarak ayarladığında emniyet hatırlatıcıları kullanılmaz."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Emniyet hatırlatıcıları, Başlattığınız komutların yanı sıra Loop iletimi otomatik olarak ayarladığında çalacaktır."; - -/* Section header for configuration section */ -"Configuration" = "Konfigürasyon"; - -/* Button title for confirm attachment option */ -"Confirm" = "Onayla"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Pod Eklemeyi Onayla"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Devam et"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "Mesaj ayrıştırılamadı: %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritik Uyarılar"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritik Pod Hatası"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Karışma mevcut. Lütfen yer değiştririn."; - -/* Unit for singular day in pod life remaining */ -"day" = "gün"; - -/* Unit for plural days in pod life remaining */ -"days" = "gün"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Pod'u devre dışı bırak"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Devre dışı"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Devre dışı bırakılıyor."; - -/* Action button description while deactivating */ -"Deactivating..." = "Devre dışı bırakılıyor..."; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Dash Pompasını Sil"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Cihaz Detayları"; - -/* description label for device name pod details row */ -"Device Name" = "Cihaz ismi"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Devre Dışı"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Podu At"; - -/* No comment provided by engineer. */ -"Done" = "Tamamlandı"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Boş rezervuar"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Boş Rezervuar"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Pod'dan boş yanıt"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Boş Değer"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Etkin"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Hata"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Hata olayı kaydedildi, kapatılıyor"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Süre sonu tavsiyesi"; - -/* Description for expiration alert */ -"Expiration alert" = "Süre sonu uyarısı"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Süre Sonu Hatırlatıcısı"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Varsayılan Süre Sonu Hatırlatıcısı"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Yayma"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Yayma bolus çalışıyor"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Geçici bazal ile çalışan yayma bolus"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Manuel Bazal İptal Edilemedi"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "İnsülin İletimine Devam Edilemedi"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Pompa Zamanı Ayarlanamadı"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "İnsülin İletimi Askıya Alınamadı"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Emniyet hatırlatıcısı tercihi güncellenemedi."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Süre Sonu Hatırlatıcısı Güncellenemedi"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Düşük Rezervuar Hatırlatıcısı Güncellenemedi"; - -/* Pod life HUD view label */ -"Fault" = "Hata"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Hata meydana geldi"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Yeni bir podu U-100 İnsülin ile doldurun (podun mavi iğne kapağını çıkarmayın)."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Devre Dışı Bırakmayı Bitir"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Devre Dışı Bırakmayı Bitir"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Eşleştirmeyi Bitir"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Kurulumu Bitir"; - -/* Description for finish setup */ -"Finish setup " = "Kurulumu bitir"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Hatırlatıcı kurulumunu bitir"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Donanım yazılımı sürümü"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "%2$@ de kalan %1$@ üniteden fazla"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "saat"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "saat"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Pod kurulumunu iptal ederseniz, mevcut Pod devre dışı bırakılır ve kullanılamaz hale gelir."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Hatalı Paket İstisnası: %1$@ (konum= %2$d )"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Hatalı Yanıt"; - -/* Pod inititialized */ -"Initialized" = "Başlatıldı"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Kanül yerleştirin"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Yerleştirildi"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Kanül yerleştiriliyor"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Yerleştiriliyor. Lütfen bekleyin.."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Yerleştiriliyor..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "İnsülin\nAskıya alındı"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "İnsulin İletimi"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "İnsülin iletimi durdu. Pod'u şimdi değiştirin."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Siz manuel olarak devam edene kadar insülin iletimi durdurulacaktır. Loop'un iletime devam etmenizi ne zaman hatırlatmasını istersiniz?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Kalan İnsülin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "İnsülin Askıya Alındı"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "İnsülin Tipi"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "İnsülin tipi yapılandırılmamış"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Dahili pod hatası %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "KesintiliBolus: %1$@ Ü (%2$@ Ü planlandı) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Geçersiz adres 0x %1$x . Beklenen 0x %2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Geçersiz adres: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Geçersiz CRC"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Geçersiz LTK Anahtarı: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Geçersiz Ayar"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Kanül düzgün yerleştirildi mi?"; - -/* description label for last status date pod details row */ -"Last Status" = "Son Durum"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "2 bip sesini dinleyin."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop, geçici bazal oran bitene veya iptal edilene kadar insülin iletiminizi otomatik olarak ayarlamaz."; - -/* description label for lot number pod details row */ -"Lot Number" = "Parti Numarası"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Düşük rezervuar"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Düşük Rezervuar"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Düşük rezervuar tavsiyesi (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Düşük rezervuar uyarı alarmı"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Düşük Rezervuar Hatırlatıcısı"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "iPhone'un etkin podun yakınında olduğundan emin olun"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Telefonunuzun ve podunuzun birbirine yakın olduğundan emin olun. İletişim sorunları devam ederse, yeni bir alana geçin."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Podunuzun dolu ve yakında olduğundan emin olun."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Podunuzun yakında olduğundan emin olun ve tekrar deneyin."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "RileyLink'inizin yakında olduğundan ve açık olduğundan emin olun"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuel Bazal"; - -/* Pod memory initialized */ -"Memory initialized" = "Bellek başlatıldı"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Mesaj GÇ İstisnası: %1$@"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "dakika"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "dakika"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Eksik Yapılandırma"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Diğer podlardan uzakta yeni bir alana gidin ve tekrar deneyin."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Çoklu Komut Uyarısı"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "mev. değil"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "Nack"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Sonraki"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Hayır"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "İletim\nYok"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Uyarı yok"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Emniyet hatırlatıcıları kullanılmaz."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Hata yok"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "İnsülin yok"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Pod Yok"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Eşleştirilmiş pod yok"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Pod bulunamadı"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Hatırlatıcı Yok"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Pod'dan yanıt yok"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "RileyLink yok"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Hayır, Pod ile Devam Et"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Hayır, Pompayı Olduğu Gibi Tutun"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Yeterli veri yok"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Bildirim ayarları"; - -/* No comment provided by engineer. */ -"Numbers" = "Sayılar"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Tıkanma tespit edildi"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Tıkanma tespit edildi"; - -/* Action button default text for PodAlerts */ -"Ok" = "Tamam"; - -/* Alert acknowledgment OK button */ -"OK" = "Tamam"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Hatırlatıcıları"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "birNotKullanıldı"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pod eşleştirme"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pod eşleştir"; - -/* Pod status after pairing */ -"Paired" = "Eşleştirilmiş"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Eşleştirme tamamlandı"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Eşleştirme İstisnası: %1$@"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Eşleştiriliyor."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Eşleştiriliyor…"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Ayrıştırma Hatası: %1$@ içinde (%2$@)"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = "Crc32 %1$@ yükü, hesaplanan crc32 %2$@ ile eşleşmiyor"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Yüzde = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Çevre Birimi Hazır Değil"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Lütfen menzile yalnızca orijinal podu getirin veya orijinal podu devre dışı bırakın"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Lütfen podunuzu RileyLink'e yaklaştırın ve tekrar deneyin"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Lütfen Pod'un vücudunuza güvenli bir şekilde takıldığından emin olun. \n\n Kanül, her Pod ile yalnızca bir kez yerleştirilebilir. Pod eklendiğinde \"Onayla\"ya dokunun."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Lütfen podu devre dışı bırakın. Devre dışı bırakma tamamlandığında, yeni bir podu eşleştirebilirsiniz."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Lütfen podu devre dışı bırakın. Devre dışı bırakma tamamlandığında onu çıkarabilir ve yeni bir podu eşleştirebilirsiniz."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Lütfen sistem ayarlarında bu uygulama için bluetooth izinlerini etkinleştirin"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Lütfen podunuzu eşleştirmeyi bitirin."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Lütfen yeni bir pod eşleştirin"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Lütfen iPhone'u poddan daha uzağa yerleştirin"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Lütfen iPhone'u poda göre yeniden konumlandırın"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Lütfen bluetooth özelliklerine sahip farklı bir cihaz kullanın"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Etkinleştirildi"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Yaşı"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod zaten eşleştirilmiş"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod zaten hazırlandı"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod başarıyla devre dışı bırakıldı. Devam et."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Pod Hatası"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod sona erme uyarı alarmı"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod Süre Sonu Bildirimi"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod Süre Sonu Hatırlatıcısı"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod'un süresi doldu"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod Süresi Doldu"; - -/* Label for pod expiration row */ -"Pod Expires" = "Podun Süresi Doluyor"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Podun süresi şu tarihte doluyor:"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod'un süresi %1$@ içinde doluyor."; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Hata Detayları"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod Hatası: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod, kanül yerleştirmeye hazır durumda değil."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod dolum için hazır durumda değil."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod askıya alındı"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "Pod bağlı değil"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Tıkanıklığı"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod başarıyla eşleştirildi. Devam et."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Eşleştirme Tamamlanmadı"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod yanıt yerine ack gönderdi"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Kurulumu"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pod kurulum penceresinin süresi doldu"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pod askıya alındı hatırlatıcısı"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Zayıf sinyal gücü"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Bölgeyi hazırlayın."; - -/* title for previous pod page */ -"Previous Pod" = "Önceki Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Önceki Pod Bilgileri"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Hazırlanıyor…"; - -/* Pod state when priming completed */ -"Priming completed" = "Hazırlama tamamlandı"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Hazırlanıyor. Lütfen bekleyin."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Hazırlanıyor..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pompa Zamanı"; - -/* Label text for basal rate summary */ -"Rate" = "Oran"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Bazal programlama için hazır"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Kanül yerleştirmeye hazır"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Kalan"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Hatırlatıcı başlatıldı"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Mavi Pod iğne kapağını çıkarın ve kanülü kontrol edin. Ardından yapışkan kağıt desteğini çıkarın."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Podu Vücuttan Çıkarın"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Pompayı Çıkar"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Pod'u Değiştir"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Devam et"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "İletimi Devam Ettir"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "İnsüline Devam Et"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "İnsülin İletimine Devam Et"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Devam: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "İnsülin iletimine devam ediliyor..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Yeniden dene"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Kaydet"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Kaydediliyor..."; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Programlanan Bazal"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Programlanan Bazal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Planlanmış Hatırlatıcı"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Bu pod için kullanacağınız insülin tipini seçin."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sıra numarası"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Geçici Bazal Ayarla"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Geçici Bazal Oranı Ayarla"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Kurulum tamamlandı"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Yakında Kapanma"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Yakında kapanma alarmı"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Sinyal Kaybı"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Sinyal gücü çok yüksek"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Omnipod Katılımı Atlansın mı?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Askıya al"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "İletimi Askıya Al"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Devam Eden Hatırlatıcıyı Askıya Al"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "İnsülin İletimini Askıya Al"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Askıya alma süresi doldu"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Askıya alma: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Askıya alındı"; - -/* Label for suspended at time */ -"Suspended At" = "Askıya Alındı"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "İnsülin iletimi askıya alınıyor..."; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Askıya alma süresi doldu. Uygulamayı açın ve devam edin."; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Diğer insülin iletim cihazına geçin"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Geçerli Saate Senkronize Et"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Hazne dolumu tamamlandı"; - -/* Pod power to motor activated */ -"Tank power activated" = "Hazne gücü etkinleştirildi"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Kanül yerleştirmeyi başlatmak için aşağıya dokunun."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Geçici Bazal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Geçici bazal devam ediyor"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Geçici bazal çalışıyor"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "GeçiciBazal: %1$@ Ü/saat %2$@ %3$@ %4$@ Ü %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Geçici Bazal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Geçici Bazal Başarısız"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Uygulama, Pod süresi dolmadan önce sizi bilgilendirmek için pod üzerinde bir hatırlatıcı yapılandırır. Yeni bir Pod eşleştirirken kaç saat önce bildirim almak istediğinizi yapılandırın."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Uygulama, Pod'un süresinin dolacağını size önceden bildirir.\n\nKaç saat önceden bildirimde bulunmak istediğinizi ayarlamak için kaydırın."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Uygulama, Poddaki insülin miktarı (50-10 U) seviyesine ulaştığında sizi bilgilendirir.\n\nHatırlatılmasını istediğiniz seviyeyi ayarlamak için kaydırın."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Uygulama, Poddaki insülin miktarı bu seviyeye ulaştığında sizi bilgilendirir."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "İnsülin askıya alma süresi sona ermiştir.\n\nAna ekran üzerinden veya pompa ayarları ekranınızdan iletime devam edebilirsiniz. 15 dakika içinde tekrar hatırlatılacaktır."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Pompanızdaki saat geçerli saatten farklı. Pompanızdaki saati geçerli saate güncellemek istiyor musunuz?"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Pompanızdaki saat, geçerli saatten farklı. Pompa süresini gözden geçirebilir ve ayarlarda geçerli saate eşitleyebilirsiniz."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Pompanızdaki saat, geçerli saatten farklı. Pompanızın zamanı, planlanmış tedavi ayarlarınızı kontrol eder. Saat farkını gözden geçirmek ve pompanızı yapılandırmak için Pompa Saati satırına ilerleyin."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Kanül cilde düzgün bir şekilde yerleştirildiğinde Pod'un üst kısmındaki pencere pembe renkte olmalıdır."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Pod ile iletişim kurarken bir sorun oluştu. Bu sorun devam ederse Pod'u At'a dokunun. Daha sonra yeni bir Pod etkinleştirebilirsiniz."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Bu, mevcut Podunuzu eşleştirdiğinizde planladığınız bir hatırlatıcıdır."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Bu pompa, manuel geçici bazal bir özellik olmadan önce eklendiği için maksimum bazal oranla yapılandırılmamıştır. Lütfen tedavi ayarları -> iletim limitleri bölümüne gidin ve yeni bir maksimum bazal oran ayarlayın."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "üçNotKullanıldı"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Zaman"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Zaman Değişikliği Algılandı"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Pod'unuzu değiştirme zamanı! Pod'un süresi %1$@ içinde dolacak"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Zaman aşımı"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Geçiş işareti"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Çok fazla pod bulundu"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Toplam İletim"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Tekrar deneyin"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Bluetooth'u açın"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "ikiNotKullanıldı"; - -/* Units for showing temp basal rate */ -"U/hr" = "Ü/sa"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Pod'a Ulaşılamıyor"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Pod'a Ulaşılamıyor"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Geçici bir bazal oran ayarlanamıyor: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Geçici bir bazal oran ayarlanamıyor: %1$@ \n\n %2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Belirsiz"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Beklenmeyen mesaj sıra numarası"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Beklenmeyen pod değişikliği"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Pod'dan beklenmeyen yanıt"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Tamamlanmamış Etkinleştirme"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Tamamlanmamış devre dışı bırakma"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Bilinmeyen Karakteristik"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Bilinmeyen pod hatası %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "%2$@ tipi için Bilinmeyen Değer ( %1$@ )"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Doğrulama başarısız oldu: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Mevcut bolusun bitmesini bekleyin veya bolusu iptal edin"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Mevcut geçici bazalın bitmesini bekleyin veya iptal etmek için askıya alın"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Yerleştirme işlemi tamamlanana kadar bekleyin."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Eşleştirme hatırlatıcısı bekleniyor"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Evet"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Evet, Pod'u Devre Dışı Bırak"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Evet, Geçerli Saatle Senkronize Et"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Şimdi hatırlatıcılarınızı yapılandırma, Pod'unuzu insülinle doldurma, cihazınızla eşleştirme ve vücudunuza yerleştirme işlemlerine başlayacaksınız."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Pod'unuz kullanıma hazır. \n\n %1$@ Pod'unuzun süresi dolmadan önce değiştirmenizi hatırlatacak. Bunu size uygun bir zamana değiştirebilirsiniz."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Pod'unuz hala İnsülin veriyor olabilir.\nVücudunuzdan çıkarın ve ardından \"Devam\"a dokunun."; - diff --git a/Dependencies/OmniBLE/OmniBLE/uk.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/uk.lproj/Localizable.strings deleted file mode 100644 index 5bf12da7f..000000000 --- a/Dependencies/OmniBLE/OmniBLE/uk.lproj/Localizable.strings +++ /dev/null @@ -1,1130 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inaktiv)"; - -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ vor"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ hat die Kommunikation mit dem Pod an Ihrem Körper wiederhergestellt.\n\nDie Insulinabgabeaufzeichnungen wurden aktualisiert und sollten mit dem übereinstimmen, was tatsächlich abgegeben wurde.\n\nSie können %@ jetzt normal weiter verwenden."; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ IE"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ für %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ konnte seit %2$@ nicht mehr mit Ihrem Pod kommunizieren.\n\nOhne Kommunikation mit dem Pod kann die App keine Befehle für die Insulinabgabe senden oder genaue, aktuelle Informationen über Ihr aktives Insulin oder das vom Pod abgegebene Insulin anzeigen.\n\nÜberwachen Sie Ihren Blutzucker für die nächsten 6 oder mehr Stunden genau, da in Ihrem Körper Insulin aktiv sein kann oder auch nicht, das %3$@ nicht anzeigen kann."; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ Insulin oder weniger verbleibend im Pod. Pod bald wechseln."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ IE verbleibend bei %2$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g IE"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 Stunde"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 Stunde 30 Minuten"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 Stunden"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 Minuten"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Aktivierungszeit überschritten"; - -/* description label for active time pod details row */ -"Active Time" = "Laufzeit"; - -/* Section header for activity section */ -"Activity" = "Aktivität"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pumpenzeit einstellen"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Sind Sie sicher, dass Sie die Pod-Einrichtung abbrechen möchten?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Sind Sie sicher, dass Sie das Omnipod Onboarding überspringen wollen?"; - -/* Message for Omnipod DASH PumpManager deletion action sheet */ -"Are you sure you want to stop using Omnipod DASH?" = "Sind Sie sicher, dass Sie keinen Omnipod DASH mehr benutzen möchten?"; - -/* navigation bar title attach pod - Title for Attach Pod screen */ -"Attach Pod" = "Pod anbringen"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Versuche die Verbindung wieder aufzubauen"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-Off Alarm"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Zurück"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialisiert"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Weniger als 50 Einheiten"; - -/* description label for ble firmware version pod details row */ -"BLE Firmware Version" = "BLE Firmware Version"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Bluetooth is powered off" = "Bluetooth ist ausgeschaltet"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Bluetooth is resetting" = "Bluetooth wird zurückgesetzt"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unknown) */ -"Bluetooth is unavailable for an unknown reason." = "Bluetooth ist aus einem unbekannten Grund nicht verfügbar."; - -/* The format string for BluetoothManagerError.bluetoothNotAvailable for unknown state (1: the unknown state) */ -"Bluetooth is unavailable: %1$@" = "Bluetooth ist nicht verfügbar: %1$@"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Bluetooth use is unauthorized" = "Bluetooth-Nutzung ist nicht erlaubt"; - -/* Error description for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Bluetooth use unsupported on this device" = "Bluetooth-Verwendung wird auf diesem Gerät nicht unterstützt"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolusabgabe läuft "; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@IE %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusabgabe"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolus-Abgabe mit temporärer Basalrate"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Abbrechen"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Manuelles Basal abbrechen"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanüle erfolgreich eingeführt. Weiter."; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Einsetzen der Kanüle"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Sicher"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Pod jetzt wechseln. Die Insulinabgabe stoppt 8 Stunden nach Ablauf des Pods oder wenn kein Insulin mehr vorhanden ist."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Pod jetzt wechseln. Die Insulinabgabe stoppt in %1$@ oder wenn kein Insulin mehr vorhanden ist."; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Pod jetzt wechseln. Die Insulinabgabe stoppt in 1 Stunde."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Pod jetzt wechseln. Der Pod ist seit 72 Stunden aktiv."; - -/* navigation bar title for check cannula - Title for check cannula screen */ -"Check Cannula" = "Prüfe die Kanüle"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Überprüfe den Pod, bringe ihn an und bestätige dann die Pod-Anbringung."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Prüfe die Einfügung"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Prüfe…"; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Befehlsfehler %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Problem"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Kommunikation wiederhergestellt"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Kommunikationsproblem: Unbestätigter Befehl steht noch aus."; - -/* navigation title for confidence reminders - Text for confidence reminders navigation link */ -"Confidence Reminders" = "Sicherheitserinnerung"; - -/* No comment provided by engineer. */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Vertrauenserinnerungen sind Pieptöne vom Pod, die verwendet werden können, um ausgewählte Befehle zu bestätigen."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Vertrauenserinnerungen ertönen für von Ihnen initiierte Befehle, wie Bolus, Bolus abbrechen, Unterbrechen, Fortsetzen, Benachrichtigungserinnerungen speichern usw. Wenn Loop die Abgabe automatisch anpasst, werden keine Vertrauenserinnerungen verwendet."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Vertrauenserinnerungen ertönen, wenn Loop die Lieferung automatisch anpasst, sowie für von Ihnen initiierte Befehle."; - -/* Section header for configuration section */ -"Configuration" = "Konfiguration"; - -/* Button title for confirm attachment option */ -"Confirm" = "Bestätige"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bestätige Pod Befestigung"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Weiter"; - -/* The format string for PodProtocolError.couldNotParseMessageException (1: message associated with error) */ -"Could not parse message: %1$@" = "Nachrichte konnte nicht analysiert werden: %1$@"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritische Warnungen"; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritischer Pod-Fehler"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Überlagerungen möglich. Bitte wechseln Sie an einen neuen Standort"; - -/* Unit for singular day in pod life remaining */ -"day" = "Tag"; - -/* Unit for plural days in pod life remaining */ -"days" = "Tage"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Pod deaktivieren"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktiviert"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktiviere."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deaktiviere…"; - -/* Button text to confirm Omnipod DASH PumpManager deletion */ -"Delete Omnipod DASH" = "Omnipod DASH löschen"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Gerätedetails"; - -/* description label for device name pod details row */ -"Device Name" = "Gerätename"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Ausgeschaltet"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Pod verwerfen"; - -/* No comment provided by engineer. */ -"Done" = "Fertig"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Reservoir leer"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Leeres Reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Leere Antwort vom Pod"; - -/* Error message description for PeripheralManagerError.emptyValue */ -"Empty Value" = "Leerer Wert"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Aktiviert"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Fehler"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Fehlerereignis protokolliert, fahre herunter"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Ablaufhinweis"; - -/* Description for expiration alert */ -"Expiration alert" = "Ablaufalarm"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Erinnerung an den Ablauf der Nutzungsdauer"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standard Erinnerung an den Ablauf der Nutzungsdauer"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Verzögerung"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Verzögerter Bolus aktiv"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Verzögerter Bolus mit temporärer Basalrate aktiv"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Fehler beim Abbrechen der manuellen Basalrate"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Wiederaufnahme der Insulinabgabe fehlgeschlagen"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Fehler beim Einstellen der Pumpenzeit"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Fehler beim Anhalten der Insulinabgabe"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Fehler beim Aktualisieren der Einstellung für die Sicherheitserinnerung."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Fehler beim Aktualisieren der Ablauferinnerung"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Fehler beim Aktualisieren der Erinnerung für einen niedrigen Vorratsbehälter"; - -/* Pod life HUD view label */ -"Fault" = "Störung"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fehlerereignis aufgetreten"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave blue Pod needle cap on)." = "Fülle U-100 Insulin in den Pod (lasse die blaue Kappe drauf)"; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Deaktivierung abschließen"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Deaktivierung abgeschlossen"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Kopplung abgeschlossen"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Einrichtung abschließen"; - -/* Description for finish setup */ -"Finish setup " = "Einrichtung abgeschlossen"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Einrichtungserinnerung abgeschlossen"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Mehr als %1$@ verbleibende Einheiten um %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "Stunde"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "Stunden"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Wenn Du die Einrichtung abbrichst, dann wird der Pod deaktiviert und unbrauchbar."; - -/* The format string for PodProtocolError.incorrectPacketException (1: payload)(2: location) */ -"Incorrect Packet Exception: %1$@ (location=%2$d)" = "Incorrect Packet Exception: %1$@ (location=%2$d)"; - -/* Error message description for PeripheralManagerError.incorrectResponse */ -"Incorrect Response" = "Falsche Antwort"; - -/* Pod inititialized */ -"Initialized" = "Initialisiert"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Kanüle einsetzen"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Eingeführt"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Einfügen von Kanüle"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Füge ein, bitte warte…"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Füge ein…"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulinabgabe\nunterbrochen"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted - The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulinabgabe wurde gestoppt. Pod jetzt wechseln."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Die Insulinabgabe wird angehalten, bis Sie sie manuell wieder aufnehmen. Wann soll Loop Sie daran erinnern, die Abgabe fortzusetzen?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Verbleibendes Insulin"; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulinabgabe unterbrochen"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulintyp"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulintyp nicht konfiguriert"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Interner Podfehler %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Abgebrochener Bolus: %1$@ IE (%2$@ IE geplant) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Ungültige Adresse (%1$x). Adresse %2$x erwartet"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Ungültige Adresse (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Ungültiger CRC"; - -/* The format string for PodProtocolError.invalidLTKKey (1: message associated with error) */ -"Invalid LTK Key: %1$@" = "Invalid LTK Key: %1$@"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ungültige Einstellung"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Wurde der Katheter ordentlich eingeführt?"; - -/* description label for last status date pod details row */ -"Last Status" = "Letzter Status"; - -/* Label text for step 2 of pair pod instructions */ -"Listen for 2 beeps." = "Achte auf zwei Pieptöne."; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop passt Ihre Insulinabgabe nicht automatisch an, bis die temporäre Basalrate beendet oder abgebrochen wurde."; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Niedriges Reservoir"; - -/* Alert content title for lowReservoir pod alert - Label text for low reservoir value row - navigation bar title for low reservoir - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Niedriges Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Hinweis auf niedriges Reservior (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Hinweisalarm für fast leeres Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Erinnerung an niedriges Reservoir"; - -/* Recovery suggestion when no response is received from pod */ -"Make sure iPhone is nearby the active pod" = "Stellen Sie sicher, dass Ihr iPhone nah am Pod ist"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Stellen Sie sicher, dass sich Ihr iPhone und Ihr Pod nahe beieinander befinden. Wenn die Kommunikationsprobleme bestehen bleiben, dann gehen Sie an einen anderen Ort."; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Stellen Sie sicher, dass Ihr Pod gefüllt und in der Nähe ist."; - -/* Recovery suggestion when no pod is available */ -"Make sure your pod is nearby and try again." = "Stellen Sie sicher, dass sich Ihr Pod in der Nähe befindet, und versuchen Sie es erneut."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Stellen Sie sicher, dass sich Ihr RileyLink in der Nähe befindet und eingeschaltet ist"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuelle Basalrate"; - -/* Pod memory initialized */ -"Memory initialized" = "Speicher initialisiert"; - -/* The format string for PodProtocolError.messageIOException (1: message associated with error) */ -"Message IO Exception: %1$@" = "Message IO Exception: %1$@"; - -/* Unit for singular minute in pod life remaining */ -"minute" = "Minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "Minuten"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Fehlende Konfiguration"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Begeben Sie sich in einen anderen Bereich, entfernt von anderen Pods und versuchen Sie es erneut."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Warnung bei mehreren Befehlen"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Error message description for PeripheralManagerError.nack */ -"Nack" = "nicht bestätigt"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Weiter"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nein"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Keine\nAbgabe"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Keine Alarme"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Es werden keine Sicherheitserinnerungen verwendet."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Keine Fehler"; - -/* Error message for reservoir view when reservoir empty - Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Kein Insulin"; - -/* Label for pod life state when no pod paired - Status highlight that when no pod is paired. - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Kein Pod gekoppelt"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Kein Pod gekoppelt"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Keine Pods gefunden"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Keine Erinnerung"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Keine Rückmeldung vom Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Kein RileyLink verfügbar"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nein, mit Pod fortfahren"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nein, Pumpe so lassen wie sie ist"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Nicht genügend Daten"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Benachrichtigungseinstellungen"; - -/* No comment provided by engineer. */ -"Numbers" = "Zahlen"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Verstopfung erkannt"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Verstopfung erkannt"; - -/* Action button default text for PodAlerts */ -"Ok" = "OK"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Generic title of the OmniBLE pump manager */ -"Omnipod DASH" = "Omnipod DASH"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Erinnerung"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pair Pod navigationBarTitle - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pod koppeln"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pod koppeln."; - -/* Pod status after pairing */ -"Paired" = "Gekoppelt"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Kopplung abgeschlossen"; - -/* The format string for PodProtocolError.pairingException (1: message associated with error) */ -"Pairing Exception: %1$@" = "Kopplungsausnahme: %1$@"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Koppeln"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Koppeln…"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing-Fehler: %1$@ in (%2$@)"; - -/* The format string for description of PodProtocolError.invalidCrc (1:payload crc)(2:computed crc) */ -"Payload crc32 %1$@ does not match computed crc32 %2$@" = "Payload crc32 %1$@ does not match computed crc32 %2$@"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percent = %lf"; - -/* Error message description for PeripheralManagerError.notReady */ -"Peripheral Not Ready" = "Peripheriegerät nicht bereit"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Bitte nur Original-Pod in Reichweite bringen oder Original-Pod deaktivieren"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Bitte bringen Sie Ihren Pod näher an Ihr RileyLink und versuchen Sie es erneut"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Bitte vergewissern Sie sich, dass der Pod sicher an Ihrem Körper befestigt ist.\n\nDer Katheter kann mit jedem Pod nur einmal eingeführt werden. Tippen Sie auf „Bestätigen“, wenn der Pod angeschlossen ist."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Bitte deaktivieren Sie den Pod. Wenn die Deaktivierung abgeschlossen ist, können Sie einen neuen Pod koppeln."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Bitte deaktivieren Sie den Pod. Wenn die Deaktivierung abgeschlossen ist, können Sie ihn entfernen und einen neuen Pod koppeln."; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unauthorized) */ -"Please enable bluetooth permissions for this app in system settings" = "Bitte aktiviere die Bluetooth-Berechtigungen für diese App in den Systemeinstellungen"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Bitte schließen Sie die Kopplung Ihres Pods ab."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Bitte koppel einen neuen Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition iPhone further from the pod" = "Bitte positionieren Sie das iPhone weiter vom Pod entfernt"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition iPhone relative to the pod" = "Bitte positionieren Sie das iPhone relativ zum Pod neu"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.unsupported) */ -"Please use a different device with bluetooth capabilities" = "Bitte verwenden Sie ein anderes Gerät mit Bluetooth-Funktion"; - -/* description label for activated at timne pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod aktiviert"; - -/* Label describing pod age view */ -"Pod Age" = "Pod-Alter"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod bereits gekoppelt"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod bereits gefüllt"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod erfolgreich deaktiviert. Weiter."; - -/* Error message for reservoir view during general pod fault - Status highlight message for other alarm. */ -"Pod Error" = "Pod-Fehler"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Ablaufalarm des Pods"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Hinweis zum Ablaufen des Pods"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Pod-Ablauferinnerung"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod abgelaufen"; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Error message for reservoir view when pod expired - Label for pod expiration row, past tense - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod abgelaufen"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod läuft ab"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod läufen ab in"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod läuft in %1$@ ab."; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fehlerdetails"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Podfehler: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Der Pod ist nicht bereit zum Einführen der Kanüle."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Der Pod ist nicht bereit zum Befüllen."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod ist angehalten"; - -/* Error message shown when the pod is not connected. */ -"Pod not connected" = "Pod nicht verbunden"; - -/* Error message for reservoir view when pod occlusion checks failed - Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Verstopfung"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod erfolgreich gekoppelt. Weiter."; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod-Kopplung unvollständig"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sendet Bestätigung anstelle von Antwort"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Einrichtung"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Das Zeitfenster für die Pod-Einrichtung ist abgelaufen"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Erinnerung über abgelaufenen Pod "; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Schlechte Signalstärke"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Stelle vorbereiten."; - -/* title for previous pod page */ -"Previous Pod" = "Vorheriger Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informationen über den letzten Pod"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Befüllen"; - -/* Pod state when priming completed */ -"Priming completed" = "Befüllen des Pods abgeschlossen"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Befülle, bitte warte."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Befülle…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Uhrzeit der Pumpe"; - -/* Label text for basal rate summary */ -"Rate" = "Rate"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Bereit für die Programmierung der Basalrate"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Bereit zum Einführen der Kanüle"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Verbleibend"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Erinnerung initialisiert"; - -/* Label text for step two of attach pod instructions */ -"Remove blue Pod needle cap and check cannula. Then remove paper backing." = "Entfernte die blaue Kappe und überprüfe den Katheter. Dann entferne das Papier."; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Entferne den Pod vom Körper"; - -/* Title for Omnipod DASH PumpManager deletion action sheet. */ -"Remove Pump" = "Pumpe löschen"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Pod ersetzen"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Fortsetzen"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Insulinabgabe fortsetzen"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Insulinabgabe fortsetzen"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Insulinabgabe wiederaufnehmen"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Fortsetzen: %1$@ %2$@"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Nehme Insulinabgabe wieder auf…"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Wiederholen"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Speichern"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Speichere…"; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Geplante Basalrate"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Geplante Basalrate"; - -/* Card title for scheduled reminder - Scheduled reminder card title on SetupCompleteView - Title for scheduled expiration reminder edit page - Title of scheduled reminder card on NotificationSettingsView */ -"Scheduled Reminder" = "Geplante Erinnerung"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Wähle die Insulinart aus, die Du für diesen Pod benutzen möchtest."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequenznummer"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Temporäre Basalrate setzen"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Temporärere Basalrate setzen"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Einrichtung abgeschlossen"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Pod-Abschaltung steht bevor"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarm für die bevorstehende Pod-Abschaltung"; - -/* Error message for reservoir view during general pod fault - Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signalverlust"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signalstärke ist zu hoch"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Omnipod-Onboarding überspringen?"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Unterbrechen"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Abgabe unterbrechen"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Unterbrechungsfortschritts-Erinnerung"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Insulinabgabe unterbrechen"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Unterbrechungszeit abgelaufen"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Unterbrochen: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Unterbrochen"; - -/* Label for suspended at time */ -"Suspended At" = "Unterbrochen um"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Unterbreche die Insulinabgabe…"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Die Unterbrechungszeit ist abgelaufen. Öffnen Sie die App und fahren Sie fort."; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Zu einer anderen Pumpe wechseln"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Mit aktueller Uhrzeit synchronisieren."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Befüllen des Pods erfolgreich"; - -/* Pod power to motor activated */ -"Tank power activated" = "Energieversorgung für den Podmotor aktiviert"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tippe unten, um das Einführen der Kanüle zu starten."; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temporäre Basalrate"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temporäre Basalrate läuft bereits."; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temporäre Basalrate läuft"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ IE/h %2$@ %3$@ %4$@ IE %5$@"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporäre Basalrate"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal fehlgeschlagen"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Die App konfiguriert eine Erinnerung auf dem Pod, um Dich vor Ablauf des Pods zu benachrichtigen. Legen die Anzahl der Stunden fest, die Du vor Ablauf des Pods benachrichtigt werden möchtest."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Die App benachrichtigt Dich vor Ablauf des Pods.\n\nScrolle, um die gewünschte Anzahl von Stunden im Voraus festzulegen."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Die App benachrichtigt Dich, wenn die Insulinmenge im Pod diesen Wert erreicht (50-10 IE).\n\nScrolle, um die Anzahl der Einheiten festzulegen, bei der Du erinnert werden möchtest."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Die App benachrichtigt Dich, wenn die Insulinmenge im Pod diesen Wert erreicht."; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Die Insulinabschaltung ist beendet.\n\nSie können die Abgabe über das Banner auf dem Startbildschirm oder über den Bildschirm mit den Pumpeneinstellungen fortsetzen. Sie werden in 15 Minuten erneut erinnert."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Die obigen Erinnerungen ertönen nicht, wenn sich Dein Gerät im Lautlos- oder Nicht-Stören-Modus befindet.\n\nEs gibt andere kritische Pod-Warnungen und -Alarme, die auch dann ertönen, wenn Dein Gerät auf „Lautlos“ oder „Nicht stören“ eingestellt ist."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Die Uhrzeit Ihrer Pumpe unterscheidet sich von Ihrer aktuellen Uhrzeit. Möchten Sie die Uhrzeit Ihrer Pumpe auf Ihre aktuelle Uhrzeit aktualisieren?"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Die Uhrzeit Ihrer Pumpe weicht von der aktuellen Uhrzeit ab. Sie können die Uhrzeit der Pumpe überprüfen und in den Einstellungen mit der aktuellen Uhrzeit synchronisieren."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Die Uhrzeit der Pumpe weicht von der aktuellen Uhrzeit ab. Die Zeit der Pumpe steuert die geplanten Therapieeinstellungen. Scrolle nach unten zur Zeile Pumpenzeit, um den Zeitunterschied zu überprüfen und die Pumpe zu konfigurieren."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Das Fenster oben auf dem Pod sollte pinkfarben sein, wenn der Katheter ordentlich in die Haut eingeführt wurde."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Es gab ein Problem bei der Kommunikation mit dem Pod. Wenn dieses Problem weiterhin besteht, tippen Sie auf \"Pod verwerfen\". Sie können dann einen neuen Pod aktivieren."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dies ist eine Erinnerung, die Du beim Koppeln Deines aktuellen Pods eingestellt hast."; - -/* Alert format string for missing temp basal configuration. */ -"This PumpManager has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to therapy settings -> delivery limits and set a new maximum basal rate." = "Dieser Pumpenmanager wurde nicht mit einer maximalen Basalrate konfiguriert, da er hinzugefügt wurde, bevor die Funktion manuelle temporäre Basalrate hinzugefügt wurde. Bitte gehe zu Therapieeinstellungen -> Abgabegrenzen und stelle eine neue maximale Basalrate ein."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Zeit"; - -/* Alert content title for timeOffsetChangeDetected pod alert - Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Änderung der Uhrzeit erkannt"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Es ist Zeit Ihren Pod zu wechseln! Der Pod läuft ab in %1$@"; - -/* Error message description for PeripheralManagerError.timeout */ -"Timeout" = "Zeitüberschreitung"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Zeichen umschalten"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Zu viele Pods in Reichweite"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Gesamt Abgabe"; - -/* Recovery suggestion when ack received instead of response - recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.resetting) */ -"Try again" = "Versuchen Sie es erneut"; - -/* recoverySuggestion for BluetoothManagerError.bluetoothNotAvailable(.poweredOff) */ -"Turn bluetooth on" = "Schalte Bluetooth ein"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* Units for showing temp basal rate */ -"U/hr" = "IE/h"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Pod kann nicht erreicht werden"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Pod kann nicht erreicht werden"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Eine temporäre Basalrate kann nicht gesetzt werden: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Eine temporäre Basalrate kann nicht gesetzt werden: %1$@\n\n%2$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Unsicher"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Unerwartete Sequenznummer der Nachricht"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Unerwarteter Podwechsel"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Unerwartete Antwort vom Pod"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Nicht abgeschlossene Aktivierung"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Nicht abgeschlossene Deaktivierung"; - -/* Error message description for PeripheralManagerError.unknownCharacteristic */ -"Unknown Characteristic" = "Unbekannte Charakteristik"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Unbekannter Podfehler %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Unbekannter Wert ( %1$@ ) für Typ %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Überprüfung fehlgeschlagen: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Warte, bis der aktuelle Bolus abgegeben wurde, oder unterbreche diesen."; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Warten Sie, bis die aktuelle temporäre Basalrate beendet ist, oder unterbrechen Sie diese"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Warte bis das Einführen der Kanüle fertig ist."; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Warten auf Kopplungserinnerung"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, deaktiviere Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, mit aktueller Zeit synchronisieren"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Beginne nun damit, die Erinnerungen zu konfigurieren, Dein Pod mit Insulin zu füllen, ihn mit Deinem Gerät zu koppeln und ihn an Deinem Körper zu platzieren."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Dein Pod ist einsatzbereit.\n\n%1$@ erinnert Dich daran, Deinen Pod zu wechseln, bevor er abläuft. Du kannst eine für Dich passende Zeit wählen."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Ihr Pod gibt möglicherweise immer noch Insulin ab.\nEntfernen Sie ihn vom Körper und tippen dann auf „Weiter“."; - diff --git a/Dependencies/OmniBLE/OmniBLE/vi.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/vi.lproj/Localizable.strings deleted file mode 100644 index a256dfcdc..000000000 --- a/Dependencies/OmniBLE/OmniBLE/vi.lproj/Localizable.strings +++ /dev/null @@ -1,290 +0,0 @@ -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ trước đó"; - -/* Format string for reservoir volume when above maximum reading. (1: The maximum reading) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units vẫn đang còn lúc %2$@"; - -/* description label for active time pod details row */ -"Active Time" = "Thời gian Hoạt động"; - -/* Section header for activity section */ -"Activity" = "Hoạt động"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-off alarm"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Dưới 50 units"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Liều Bolus đang được thực hiện"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Đang tiến hành bolus"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Đang thực hiện liều basal tạm thời"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "Hủy bỏ"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Đang gắn Cannula"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Chắc chắn"; - -/* Section header for configuration section */ -"Configuration" = "Cấu hình"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "Tiếp tục"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "Hủy kích hoạt Pod"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Đã hủy kích hoạt"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Ngăn chứa insulin rỗng"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Không có phản hồi từ pod"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Được cấp quyền"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Lỗi"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Lỗi đăng nhập, đang tắt"; - -/* Description for expiration alert */ -"Expiration alert" = "Thông báo hết hạn"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Nhắc nhở Hết hạn"; - -/* Pod life HUD view label */ -"Fault" = "Lỗi"; - -/* Description for finish setup */ -"Finish setup " = "Hoàn tất cấu hình"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Chương trình cơ sở"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Nhiều hơn %1$@ units vẫn còn lúc %2$@"; - -/* Pod inititialized */ -"Initialized" = "Đã được khởi tạo"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "Lắp Cannula"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Lỗi bên trong pod %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Báo động ngăn chứa insulin thấp"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Đảm bảo RileyLink bên cạnh và đã được bật"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Không có cảnh báo nào"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Không có pod nào được kết nối"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Không có tín hiệu phản hồi từ pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Không tìm thấy RileyLink"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Bình thường"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Occlusion detected"; - -/* Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Đã được ghép đôi"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Đề nghị để pod gần với Rileylink và thử lại lần nữa"; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Đề nghị ghép đôi pod mới"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod đã được ghép đôi"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod đã được mồi"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Cảnh báo pod hết hạn"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Thông báo pod hết hạn"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod đã hết hạn"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod lỗi: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod không sẵn sàng để gắn cannula."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod không sẵn sàng để mồi."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod bị tạm ngưng"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Cửa sổ cấu hình pod hết hạn"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Đang mồi"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Sẵn sàng cho việc tính toán liều basal"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Sẵn sàng cho việc gắn cannula"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "Đang còn lại"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "Thay thế Pod"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Tái lập: %1$@ %2$@"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Thử lại"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "Lưu"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Đã lên chương trình cho liều Basal"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "Cấu hình hoàn thành"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Tắt báo động sắp xảy ra"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Tạm ngưng liều insulin"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Tạm ngưng: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Đã tạm ngưng"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Hoàn tất nạp"; - -/* Pod power to motor activated */ -"Tank power activated" = "Pod được kích hoạt"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Liều basal tạm thời đang tiến hành"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Liều basal tạm thời đang thực hiện"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ U/giờ %2$@ %3$@ %4$@ U %5$@"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Thời gian thay pod của bạn! Pod của bạn sẽ hết hạn trong %1$@"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/giờ"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Không chắc chắn"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Phản hồi bất thường từ pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Lỗi không xác định của pod %1$03d"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Chờ đợi liệu bolus hiện tại hoàn tất hoặc hủy liều bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Chờ đợi liều basal tạm thời hoàn tất hoặc chọn ngưng để hủy"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Đang chờ đợi câu thông báo ghép đôi"; - diff --git a/Dependencies/OmniBLE/OmniBLE/zh-Hans.lproj/Localizable.strings b/Dependencies/OmniBLE/OmniBLE/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 2bfd35356..000000000 --- a/Dependencies/OmniBLE/OmniBLE/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,251 +0,0 @@ -/* description label for active time pod details row */ -"Active Time" = "Pod启动时间"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "自动关闭提醒"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "胰岛素已低于50U"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "大剂量输注中"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "大剂量: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "注射中"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "正在运行临时基础并输注大剂量"; - -/* Button title for cancelling low reservoir reminder edit - Button title for cancelling scheduled reminder date edit - Cancel button text in navigation bar on insert cannula screen - Cancel button text in navigation bar on pair pod UI - Cancel button title - Pairing interface navigation bar button text for cancel action */ -"Cancel" = "取消"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "植入管路"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Certain"; - -/* Section header for configuration section */ -"Configuration" = "配置"; - -/* Action button description when deactivated - Action button title for attach pod view - Button title to continue - Cannula insertion button text when inserted - Pod pairing action button text when paired - Text for continue button - Text for continue button on PodSetupView - Title of button to continue discard */ -"Continue" = "继续"; - -/* Action button description for deactivate while pod still active - Button text for deactivate pod button - Button title to deactive pod on uncertain program - Deactivate pod action button accessibility label while ready to deactivate - navigation bar title for deactivate pod - Title for deactivate pod screen */ -"Deactivate Pod" = "解除Pod"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "已解除"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "胰岛素储量为零"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Pod无响应"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Pod错误已记录"; - -/* Description for expiration alert */ -"Expiration alert" = "到期提醒"; - -/* navigation bar title for expiration reminder - Title for ExpirationReminderSetupView */ -"Expiration Reminder" = "Pod到期提醒"; - -/* Pod life HUD view label */ -"Fault" = "错误"; - -/* Description for finish setup */ -"Finish setup " = "完成设置"; - -/* description label for firmware version pod details row */ -"Firmware Version" = "Firmware Version"; - -/* Pod inititialized */ -"Initialized" = "初始化"; - -/* Cannula insertion button text while ready to insert - Insert cannula action button accessibility label while ready to pair - navigation bar title for insert cannula - Title for insert cannula screen */ -"Insert Cannula" = "植入Pod"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Pod内部错误%1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "大剂量输注终端: %1$@ U (%2$@ U 已输注) %3$@ %4$@ %5$@"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "储药量低"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "确保Rileylink与Pod保持比较近的距离"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "运行正常"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "未配对Pod"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Pod无响应"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "没有发现Rileylink"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "正常"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "堵管"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "已配对"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "请确保Rileylink与Pod保持近距离并重试"; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "请配对一个新的Pod"; - -/* Label describing pod age view */ -"Pod Age" = "Pod使用天数"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod已配对"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod充盈已完成"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod到期提醒"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod到期通知"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod已到期"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod错误: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod无法植入"; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod无法充盈"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod已暂停"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pod设置超时"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "充盈中"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "基础率同步已就绪"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Pod可以进行植入操作"; - -/* Label describing time remaining view - Label for remaining time of manual basal */ -"Remaining" = "剩余"; - -/* Label indicating pod replacement necessary - Settings page link description when next lifecycle action is to replace pod */ -"Replace Pod" = "更换Pod"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "恢复输注: %1$@ %2$@"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "重试"; - -/* button title for saving low reservoir reminder - button title for saving scheduled reminder */ -"Save" = "保存"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "预设基础率"; - -/* Title for setup complete screen - Title of SetupCompleteView */ -"Setup Complete" = "设置完成"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "关闭提醒"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "暂停输注: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "暂停"; - -/* Pod tank fill completed */ -"Tank fill completed" = "已向Pod注入胰岛素"; - -/* Pod power to motor activated */ -"Tank power activated" = "Pod已开启"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "正在设置临时基础率"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "临时基础率正在运行"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "临时基础率: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Pod将在%1$@后到期,请准备更换Pod"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "未知"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Pod未知响应"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Pod未知错误"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "请等待大剂量输注完成,或取消大剂量输注"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "请等待临时基础率结束,或暂停以取消临时基础率"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "等待配对提醒"; - diff --git a/Dependencies/OmniBLE/OmniBLEPlugin/Extensions/OSLog.swift b/Dependencies/OmniBLE/OmniBLEPlugin/Extensions/OSLog.swift deleted file mode 100644 index a164053d0..000000000 --- a/Dependencies/OmniBLE/OmniBLEPlugin/Extensions/OSLog.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// OSLog.swift -// OmniBLEPlugin -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import os.log - - -extension OSLog { - convenience init(category: String) { - self.init(subsystem: "com.randallknutson.OmniBLE", category: category) - } - - func debug(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .debug, args) - } - - func info(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .info, args) - } - - func `default`(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .default, args) - } - - func error(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .error, args) - } - - private func log(_ message: StaticString, type: OSLogType, _ args: [CVarArg]) { - switch args.count { - case 0: - os_log(message, log: self, type: type) - case 1: - os_log(message, log: self, type: type, args[0]) - case 2: - os_log(message, log: self, type: type, args[0], args[1]) - case 3: - os_log(message, log: self, type: type, args[0], args[1], args[2]) - case 4: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3]) - case 5: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4]) - default: - os_log(message, log: self, type: type, args) - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLEPlugin/Info.plist b/Dependencies/OmniBLE/OmniBLEPlugin/Info.plist deleted file mode 100644 index ba8cd05ea..000000000 --- a/Dependencies/OmniBLE/OmniBLEPlugin/Info.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright © 2022 LoopKit Authors. All rights reserved. - com.loopkit.Loop.PumpManagerDisplayName - Omnipod DASH - com.loopkit.Loop.PumpManagerIdentifier - Omnipod-Dash - NSPrincipalClass - OmniBLEPlugin.OmnipodPlugin - - diff --git a/Dependencies/OmniBLE/OmniBLEPlugin/OmniBLEPlugin.h b/Dependencies/OmniBLE/OmniBLEPlugin/OmniBLEPlugin.h deleted file mode 100644 index 310b0b0bb..000000000 --- a/Dependencies/OmniBLE/OmniBLEPlugin/OmniBLEPlugin.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// OmniBLEPlugin.h -// OmniBLEPlugin -// -// Created by Pete Schwamb on 1/13/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -#import - -//! Project version number for OmniBLEPlugin. -FOUNDATION_EXPORT double OmniBLEPluginVersionNumber; - -//! Project version string for OmniBLEPlugin. -FOUNDATION_EXPORT const unsigned char OmniBLEPluginVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/OmniBLE/OmniBLEPlugin/OmniBLEPlugin.swift b/Dependencies/OmniBLE/OmniBLEPlugin/OmniBLEPlugin.swift deleted file mode 100644 index c266fc7b5..000000000 --- a/Dependencies/OmniBLE/OmniBLEPlugin/OmniBLEPlugin.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// OmniBLEPlugin.swift -// OmniBLE -// -// Based on OmniKitPlugin/OmniKitPlugin.swift -// Created by Randall Knutson on 09/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKitUI -import OmniBLE -import os.log - -class OmniBLEPlugin: NSObject, PumpManagerUIPlugin { - private let log = OSLog(category: "OmniBLEPlugin") - - public var pumpManagerType: PumpManagerUI.Type? { - return OmniBLEPumpManager.self - } - - public var cgmManagerType: CGMManagerUI.Type? { - return nil - } - - override init() { - super.init() - log.default("OmniBLEPlugin Instantiated") - } -} diff --git a/Dependencies/OmniBLE/OmniBLETests/AcknowledgeAlertsTests.swift b/Dependencies/OmniBLE/OmniBLETests/AcknowledgeAlertsTests.swift deleted file mode 100644 index db0e63072..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/AcknowledgeAlertsTests.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// AcknowledgeAlertsTests.swift -// OmniBLE -// -// Created by Eelke Jager on 18/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// From OmniKitTests/AcknowledgeAlertsTests.swift -// -import Foundation - -import XCTest -@testable import OmniBLE - -class AcknowledgeAlertsTests: XCTestCase { - func testAcknowledgeLowReservoirAlert() { - // 11 05 2f9b5b2f 10 - do { - // Encode - let encoded = AcknowledgeAlertCommand(nonce: 0x2f9b5b2f, alerts: AlertSet(rawValue: 0x10)) - XCTAssertEqual("11052f9b5b2f10", encoded.data.hexadecimalString) - - // Decode - let cmd = try AcknowledgeAlertCommand(encodedData: Data(hexadecimalString: "11052f9b5b2f10")!) - XCTAssertEqual(.acknowledgeAlert,cmd.blockType) - XCTAssertEqual(0x2f9b5b2f, cmd.nonce) - XCTAssert(cmd.alerts.contains(.slot4)) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLETests/BasalScheduleTests.swift b/Dependencies/OmniBLE/OmniBLETests/BasalScheduleTests.swift deleted file mode 100644 index ccf4335fb..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/BasalScheduleTests.swift +++ /dev/null @@ -1,528 +0,0 @@ -// -// BasalScheduleTests.swift -// OmniBLE -// -// Created by Pete Schwamb on 4/4/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// From OmniKitTests/BasalScheduleTests.swift -// - -import XCTest -@testable import OmniBLE - -class BasalScheduleTests: XCTestCase { - - func testInsulinTableEntry() { - let entry = InsulinTableEntry(segments: 2, pulses: 300, alternateSegmentPulse: false) - // $01 $2c $01 $2c = 1 + 44 + 1 + 44 = 90 = $5a - XCTAssertEqual(0x5a, entry.checksum()) - - let entry2 = InsulinTableEntry(segments: 2, pulses: 260, alternateSegmentPulse: true) - // $01 $04 $01 $04 = 1 + 4 + 1 + 5 = 1 = $0b - XCTAssertEqual(0x0b, entry2.checksum()) - } - - func testSetBasalScheduleCommand() { - do { - // Decode 1a 12 77a05551 00 0062 2b 1708 0000 f800 f800 f800 - let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a1277a055510000622b17080000f800f800f800")!) - - XCTAssertEqual(0x77a05551, cmd.nonce) - if case SetInsulinScheduleCommand.DeliverySchedule.basalSchedule(let currentSegment, let secondsRemaining, let pulsesRemaining, let table) = cmd.deliverySchedule { - XCTAssertEqual(0x2b, currentSegment) - XCTAssertEqual(737, secondsRemaining) - XCTAssertEqual(0, pulsesRemaining) - XCTAssertEqual(3, table.entries.count) - } else { - XCTFail("Expected ScheduleEntry.basalSchedule type") - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let scheduleEntry = InsulinTableEntry(segments: 16, pulses: 0, alternateSegmentPulse: true) - let table = BasalDeliveryTable(entries: [scheduleEntry, scheduleEntry, scheduleEntry]) - let deliverySchedule = SetInsulinScheduleCommand.DeliverySchedule.basalSchedule(currentSegment: 0x2b, secondsRemaining: 737, pulsesRemaining: 0, table: table) - let cmd = SetInsulinScheduleCommand(nonce: 0x77a05551, deliverySchedule: deliverySchedule) - XCTAssertEqual("1a1277a055510000622b17080000f800f800f800", cmd.data.hexadecimalString) - } - - func testBasalScheduleCommandFromSchedule() { - // Encode from schedule - let entry = BasalScheduleEntry(rate: 0.05, startTime: 0) - let schedule = BasalSchedule(entries: [entry]) - - let cmd = SetInsulinScheduleCommand(nonce: 0x01020304, basalSchedule: schedule, scheduleOffset: .hours(8.25)) - - XCTAssertEqual(0x01020304, cmd.nonce) - if case SetInsulinScheduleCommand.DeliverySchedule.basalSchedule(let currentSegment, let secondsRemaining, let pulsesRemaining, let table) = cmd.deliverySchedule { - XCTAssertEqual(16, currentSegment) - XCTAssertEqual(UInt16(TimeInterval(minutes: 15)), secondsRemaining) - XCTAssertEqual(0, pulsesRemaining) - XCTAssertEqual(3, table.entries.count) - let tableEntry = table.entries[0] - XCTAssertEqual(true, tableEntry.alternateSegmentPulse) - XCTAssertEqual(0, tableEntry.pulses) - XCTAssertEqual(16, tableEntry.segments) - } else { - XCTFail("Expected ScheduleEntry.basalSchedule type") - } - // 1a LL NNNNNNNN 00 CCCC HH SSSS PPPP napp napp napp napp - // 1a 12 01020304 00 0065 10 1c20 0001 f800 f800 f800 - XCTAssertEqual("1a1201020304000064101c200000f800f800f800", cmd.data.hexadecimalString) - } - - - func testBasalScheduleExtraCommand() { - do { - // Decode 130e40 00 1aea 001e8480 3840005b8d80 - - let cmd = try BasalScheduleExtraCommand(encodedData: Data(hexadecimalString: "130e40001aea001e84803840005b8d80")!) - - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(true, cmd.completionBeep) - XCTAssertEqual(0, cmd.programReminderInterval) - XCTAssertEqual(0, cmd.currentEntryIndex) - XCTAssertEqual(689, cmd.remainingPulses) - XCTAssertEqual(TimeInterval(seconds: 20), cmd.delayUntilNextTenthOfPulse) - XCTAssertEqual(1, cmd.rateEntries.count) - let entry = cmd.rateEntries[0] - XCTAssertEqual(TimeInterval(seconds: 60), entry.delayBetweenPulses) - XCTAssertEqual(1440, entry.totalPulses) - XCTAssertEqual(3.0, entry.rate) - XCTAssertEqual(TimeInterval(hours: 24), entry.duration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let rateEntries = RateEntry.makeEntries(rate: 3.0, duration: TimeInterval(hours: 24)) - let cmd = BasalScheduleExtraCommand(currentEntryIndex: 0, remainingPulses: 689, delayUntilNextTenthOfPulse: TimeInterval(seconds: 20), rateEntries: rateEntries, acknowledgementBeep: false, completionBeep: true, programReminderInterval: 0) - - - XCTAssertEqual("130e40001aea01312d003840005b8d80", cmd.data.hexadecimalString) - } - - func testBasalScheduleExtraCommandFromSchedule() { - // Encode from schedule - let entry = BasalScheduleEntry(rate: 0.05, startTime: 0) - let schedule = BasalSchedule(entries: [entry]) - - let cmd = BasalScheduleExtraCommand(schedule: schedule, scheduleOffset: .hours(8.25), acknowledgementBeep: false, completionBeep: true, programReminderInterval: 60) - - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(true, cmd.completionBeep) - XCTAssertEqual(60, cmd.programReminderInterval) - XCTAssertEqual(0, cmd.currentEntryIndex) - XCTAssertEqual(15.8, cmd.remainingPulses, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 3), cmd.delayUntilNextTenthOfPulse) - XCTAssertEqual(1, cmd.rateEntries.count) - let rateEntry = cmd.rateEntries[0] - XCTAssertEqual(TimeInterval(minutes: 60), rateEntry.delayBetweenPulses) - XCTAssertEqual(24, rateEntry.totalPulses, accuracy: 0.001) - XCTAssertEqual(0.05, rateEntry.rate) - XCTAssertEqual(TimeInterval(hours: 24), rateEntry.duration, accuracy: 0.001) - } - - func testBasalExtraEncoding() { - // Encode - - let schedule = BasalSchedule(entries: [ - BasalScheduleEntry(rate: 1.05, startTime: 0), - BasalScheduleEntry(rate: 0.9, startTime: .hours(10.5)), - BasalScheduleEntry(rate: 1, startTime: .hours(18.5)) - ]) - - let hh = 0x2e - let ssss = 0x1be8 - let offset = TimeInterval(minutes: Double((hh + 1) * 30)) - TimeInterval(seconds: Double(ssss / 8)) - - // 1a LL NNNNNNNN 00 CCCC HH SSSS PPPP napp napp napp napp - // 1a 14 0d6612db 00 0310 2e 1be8 0005 f80a 480a f009 a00a - - let cmd1 = SetInsulinScheduleCommand(nonce: 0x0d6612db, basalSchedule: schedule, scheduleOffset: offset) - XCTAssertEqual("1a140d6612db0003102e1be80005f80a480af009a00a", cmd1.data.hexadecimalString) - - // 13 LL RR MM NNNN XXXXXXXX YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ - // 13 1a 40 02 0096 00a7d8c0 089d 01059449 05a0 01312d00 044c 0112a880 - let cmd2 = BasalScheduleExtraCommand(schedule: schedule, scheduleOffset: offset, acknowledgementBeep: false, completionBeep: true, programReminderInterval: 0) - XCTAssertEqual("131a4002009600a7d8c0089d0105944905a001312d00044c0112a880", cmd2.data.hexadecimalString) // PDM - } - - func checkBasalScheduleExtraCommandDataWithLessPrecision(_ expected: Data, _ data: Data, line: UInt = #line) { - // The XXXXXXXX field is in thousands of a millisecond. Since we use TimeIntervals (floating point) for - // recreating the offset, we can have small errors in reproducing the the encoded output, which we really - // don't care about. - - func extractXXXXXXXX(_ data: Data) -> TimeInterval { - return TimeInterval(Double(data[6...].toBigEndian(UInt32.self)) / 1000000.0) - } - - let xxxxxxxx1 = extractXXXXXXXX(expected) - let xxxxxxxx2 = extractXXXXXXXX(data) - XCTAssertEqual(xxxxxxxx1, xxxxxxxx2, accuracy: 0.01, line: line) - - func blurXXXXXXXX(_ inStr: String) -> String { - let start = inStr.index(inStr.startIndex, offsetBy:12) - let end = inStr.index(start, offsetBy:8) - return inStr.replacingCharacters(in: start.. only one entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 05181992 02 0003 02 0000 0000 1800 17 0d 00 0000 00030d40 000a 0aba9500 - let bolus_0_05U_Ext_0_5Hr = SetInsulinScheduleCommand(nonce: 0x05181992, units: 0.0, extendedUnits: 0.05, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a0e0518199202000302000000001800", bolus_0_05U_Ext_0_5Hr.data.hexadecimalString) - - // 0.10U extended bolus over 1 hour -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 06211961 02 0005 03 0000 0000 1800 0001 - let bolus_0_10U_Ext_1Hr = SetInsulinScheduleCommand(nonce: 0x06211961, units: 0.0, extendedUnits: 0.10, extendedDuration: .hours(1)) - XCTAssertEqual("1a1006211961020005030000000018000001", bolus_0_10U_Ext_1Hr.data.hexadecimalString) - - // 0.10U extended bolus over 1.5 hours - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp -> non-zero first entry - // 1a 10 04111967 02 0006 04 0000 0000 1000 1001 - let bolus_0_10U_Ext_1_5Hr = SetInsulinScheduleCommand(nonce: 0x08121964, units: 0.0, extendedUnits: 0.10, extendedDuration: .hours(1.5)) - XCTAssertEqual("1a1008121964020006040000000010001001", bolus_0_10U_Ext_1_5Hr.data.hexadecimalString) - - // 0.10U extended bolus over 2 hours -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp - // 1a 12 07041776 02 0007 05 0000 0000 1000 0001 1800 - let bolus_0_10U_Ext_2Hr = SetInsulinScheduleCommand(nonce: 0x04111967, units: 0.0, extendedUnits: 0.10, extendedDuration: .hours(2)) - XCTAssertEqual("1a12041119670200070500000000100000011800", bolus_0_10U_Ext_2Hr.data.hexadecimalString) - - // 0.15U extended bolus over 1 hour -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 05181983 02 0006 03 0000 0000 1800 0002 - let bolus_0_15U_Ext_1Hr = SetInsulinScheduleCommand(nonce: 0x05181983, units: 0.0, extendedUnits: 0.15, extendedDuration: .hours(1)) - XCTAssertEqual("1a1005181983020006030000000018000002", bolus_0_15U_Ext_1Hr.data.hexadecimalString) - - // 0.35U extended bolus over 0.5 hours - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 06151215 02 0009 02 0000 0000 0000 0007 - let bolus_0_35U_Ext_0_5Hr = SetInsulinScheduleCommand(nonce: 0x06151215, units: 0.0, extendedUnits: 0.35, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a1006151215020009020000000000000007", bolus_0_35U_Ext_0_5Hr.data.hexadecimalString) - - // 0.35U extended bolus over 4.5 hours -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp - // 1a 14 07211946 02 0011 0a 0000 0000 1000 2001 1800 2001 - let bolus_0_35U_Ext_4_5Hr = SetInsulinScheduleCommand(nonce: 0x07211946, units: 0.0, extendedUnits: 0.35, extendedDuration: .hours(4.5)) - XCTAssertEqual("1a14072119460200110a000000001000200118002001", bolus_0_35U_Ext_4_5Hr.data.hexadecimalString) - - // 0.35U extended bolus over 5.0 hours -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp napp napp - // 1a 18 03231932 02 0012 0b 0000 0000 1000 1001 1800 0001 1800 1001 - let bolus_0_35U_Ext_5_0Hr = SetInsulinScheduleCommand(nonce: 0x03231932, units: 0.0, extendedUnits: 0.35, extendedDuration: .hours(5.0)) - XCTAssertEqual("1a18032319320200120b00000000100010011800000118001001", bolus_0_35U_Ext_5_0Hr.data.hexadecimalString) - - // 0.35U extended bolus over 5.5 hours -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp napp napp napp napp - // 1a 1c 03011936 02 0013 0c 0000 0000 1000 0001 1800 0001 1800 0001 1800 0001 - let bolus_0_35U_Ext_5_5Hr = SetInsulinScheduleCommand(nonce: 0x03011936, units: 0.0, extendedUnits: 0.35, extendedDuration: .hours(5.5)) - XCTAssertEqual("1a1c030119360200130c0000000010000001180000011800000118000001", bolus_0_35U_Ext_5_5Hr.data.hexadecimalString) - - // 0.35U extended bolus over 6.0 hours -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp napp napp - // 1a 18 03231957 02 0014 0d 0000 0000 1000 0001 3800 0001 3800 0001 - let bolus_0_35U_Ext_6_0Hr = SetInsulinScheduleCommand(nonce: 0x03231957, units: 0.0, extendedUnits: 0.35, extendedDuration: .hours(6.0)) - XCTAssertEqual("1a18032319570200140d00000000100000013800000138000001", bolus_0_35U_Ext_6_0Hr.data.hexadecimalString) - - // 0.35U extended bolus over 6.5 hours -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp - // 1a 14 08151959 02 0015 0e 0000 0000 1000 0001 9800 0001 - let bolus_0_35U_Ext_6_5Hr = SetInsulinScheduleCommand(nonce: 0x08151959, units: 0.0, extendedUnits: 0.35, extendedDuration: .hours(6.5)) - XCTAssertEqual("1a14081519590200150e000000001000000198000001", bolus_0_35U_Ext_6_5Hr.data.hexadecimalString) - - // 0.35U extended bolus over 7.0 hours -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp - // 1a 12 12041962 02 0016 0f 0000 0000 1000 0001 b800 - let bolus_0_35U_Ext_7_0Hr = SetInsulinScheduleCommand(nonce: 0x12041962, units: 0.0, extendedUnits: 0.35, extendedDuration: .hours(7.0)) - XCTAssertEqual("1a12120419620200160f0000000010000001b800", bolus_0_35U_Ext_7_0Hr.data.hexadecimalString) - } - - func testBolusDualWave() { - // 6.0U dual wave bolus with 2.0U immediate and 4.0U extended over 3 hours - // 1A LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp napp - // 1a 16 01e475cb 02 0129 07 0280 0028 0028 100d 000e 100d 000e - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 3c 0190 00030d40 0320 00cdfe60 - do { - let insulinCmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a1601e475cb02012907028000280028100d000e100d000e")!) - XCTAssertEqual(0x01e475cb, insulinCmd.nonce) - let schedule = insulinCmd.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(2.0, units) - XCTAssertEqual(Pod.secondsPerBolusPulse, timeBetweenPulses) - XCTAssertEqual(5, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(0x28, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[1].segments) - XCTAssertEqual(0xd, table.entries[1].pulses) - XCTAssertEqual(false, table.entries[1].alternateSegmentPulse) - XCTAssertEqual(1, table.entries[2].segments) - XCTAssertEqual(0xe, table.entries[2].pulses) - XCTAssertEqual(false, table.entries[2].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[3].segments) - XCTAssertEqual(0xd, table.entries[3].pulses) - XCTAssertEqual(false, table.entries[3].alternateSegmentPulse) - XCTAssertEqual(1, table.entries[4].segments) - XCTAssertEqual(0xe, table.entries[4].pulses) - XCTAssertEqual(false, table.entries[4].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - let extraCmd = try BolusExtraCommand(encodedData: Data(hexadecimalString: "170d3c019000030d40032000cdfe60")!) - XCTAssertEqual(2.0, extraCmd.units) - XCTAssertEqual(false, extraCmd.acknowledgementBeep) - XCTAssertEqual(false, extraCmd.completionBeep) - XCTAssertEqual(.hours(1), extraCmd.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, extraCmd.timeBetweenPulses) - XCTAssertEqual(4, extraCmd.extendedUnits) - XCTAssertEqual(.hours(3), extraCmd.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode 0.10 combo bolus with 0.05U immediate, 0.05U over 30 minutes -> only one entry used! - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp - // 1a 0e 06021986 02 0015 02 0010 0001 1001 - let bolusScheduleCommand = SetInsulinScheduleCommand(nonce: 0x06021986, units: 0.05, extendedUnits: 0.05, extendedDuration: .minutes(30)) - XCTAssertEqual("1a0e0602198602001502001000011001", bolusScheduleCommand.data.hexadecimalString) - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 000a 00030d40 000a 0aba9500 - let cmd = BolusExtraCommand(units: 0.05, timeBetweenPulses: Pod.secondsPerBolusPulse, extendedUnits: 0.05, extendedDuration: .hours(0.5), programReminderInterval: .minutes(60)) - XCTAssertEqual("170d3c000a00030d40000a0aba9500", cmd.data.hexadecimalString) - } - - func testLargeExtendedBolus() { - // 12U extended (square wave) bolus over 6 hours with no immediate bolus - // 1A LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 03171958 02 00fd 0d 0000 0000 0000 b014 - do { - let insulinCmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a10031719580200fd0d000000000000b014")!) - XCTAssertEqual(0x03171958, insulinCmd.nonce) - let schedule = insulinCmd.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(0.0, units) - XCTAssertEqual(0, timeBetweenPulses) - XCTAssertEqual(2, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(0, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(12, table.entries[1].segments) - XCTAssertEqual(0x14, table.entries[1].pulses) - XCTAssertEqual(false, table.entries[1].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - } catch (let error) { - XCTFail("insulin command decoding threw error: \(error)") - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 7c 0000 00030d40 0960 00895440 - do { - let extraCmd = try BolusExtraCommand(encodedData: Data(hexadecimalString: "170d7c000000030d40096000895440")!) - XCTAssertEqual(false, extraCmd.acknowledgementBeep) - XCTAssertEqual(true, extraCmd.completionBeep) - XCTAssertEqual(.minutes(60), extraCmd.programReminderInterval) - XCTAssertEqual(0.0, extraCmd.units) - XCTAssertEqual(Pod.secondsPerBolusPulse, extraCmd.timeBetweenPulses) - XCTAssertEqual(12, extraCmd.extendedUnits) - XCTAssertEqual(.hours(6), extraCmd.extendedDuration) - } catch (let error) { - XCTFail("bolus extra command decoding threw error: \(error)") - } - - // Encode 12U extended (square wave) bolus over 6 hours with no immediate bolus - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 07041960 02 00fd 0d 0000 0000 0000 b014 - let bolusScheduleCommand = SetInsulinScheduleCommand(nonce: 0x07041960, units: 0.0, extendedUnits: 12, extendedDuration: .hours(6)) - XCTAssertEqual("1a10070419600200fd0d000000000000b014", bolusScheduleCommand.data.hexadecimalString) - - let extraCmd = BolusExtraCommand(extendedUnits: 12, extendedDuration: .hours(6), completionBeep: true, programReminderInterval: .minutes(60)) - XCTAssertEqual("170d7c000000030d40096000895440", extraCmd.data.hexadecimalString) - } - - func testLargeBolusDualWave() { - // 30U dual bolus 50% extended over 8 hours - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp napp napp napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 1e 11161988 02 0269 11 12c0 012c 012c 1812 1013 1812 1013 1812 1013 1812 1013 17 0d 7c 0bb8 00030d40 0bb8 00927c00 - let insulinCmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a1e111619880202691112c0012c012c18121013181210131812101318121013")!) - XCTAssertEqual(0x11161988, insulinCmd.nonce) - let schedule = insulinCmd.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(15.0, units) - XCTAssertEqual(2, timeBetweenPulses) - XCTAssertEqual(9, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(0x12c, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[1].segments) - XCTAssertEqual(0x12, table.entries[1].pulses) - XCTAssertEqual(true, table.entries[1].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[2].segments) - XCTAssertEqual(0x13, table.entries[2].pulses) - XCTAssertEqual(false, table.entries[2].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[3].segments) - XCTAssertEqual(0x12, table.entries[3].pulses) - XCTAssertEqual(true, table.entries[3].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[4].segments) - XCTAssertEqual(0x13, table.entries[4].pulses) - XCTAssertEqual(false, table.entries[4].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[5].segments) - XCTAssertEqual(0x12, table.entries[5].pulses) - XCTAssertEqual(true, table.entries[5].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[6].segments) - XCTAssertEqual(0x13, table.entries[6].pulses) - XCTAssertEqual(false, table.entries[6].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[7].segments) - XCTAssertEqual(0x12, table.entries[7].pulses) - XCTAssertEqual(true, table.entries[7].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[8].segments) - XCTAssertEqual(0x13, table.entries[8].pulses) - XCTAssertEqual(false, table.entries[8].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 7c 0bb8 00030d40 0bb8 00927c00 - let extraCmd = try BolusExtraCommand(encodedData: Data(hexadecimalString: "170d7c0bb800030d400bb800927c00")!) - XCTAssertEqual(15.0, extraCmd.units) - XCTAssertEqual(false, extraCmd.acknowledgementBeep) - XCTAssertEqual(true, extraCmd.completionBeep) - XCTAssertEqual(.minutes(60), extraCmd.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, extraCmd.timeBetweenPulses) - XCTAssertEqual(15, extraCmd.extendedUnits) - XCTAssertEqual(.hours(8), extraCmd.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testDualBolusDeliveryEncoding() { - // 0.10U dual bolus 50% extended over 0.5 hours (1i 2e) -> only one entry used - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 03231932 02 0015 02 0010 0001 1001 17 0d 00 000a 00030d40 000a 0aba9500 - let bolus_0_10U_50P_ext_30min = SetInsulinScheduleCommand(nonce: 0x03231932, units: 0.05, extendedUnits: 0.05, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a0e0323193202001502001000011001", bolus_0_10U_50P_ext_30min.data.hexadecimalString) - - // 0.10U dual bolus 50% extended over 1.0 hour (1i 2e) -> max duration allowed - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 03011936 02 0016 03 0010 0001 0001 1800 17 0d 00 000a 00030d40 000a 15752a00 - let bolus_0_10U_50P_ext_60min = SetInsulinScheduleCommand(nonce: 0x03011936, units: 0.05, extendedUnits: 0.05, extendedDuration: .hours(1.0)) - XCTAssertEqual("1a1003011936020016030010000100011800", bolus_0_10U_50P_ext_60min.data.hexadecimalString) - - - // 0.15U dual bolus 65% extended over 0.5 hours (1i 2e) -> only one entry used - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 03171958 02 0016 02 0010 0001 1801 17 0d 00 000a 00030d40 0014 055d4a80 - let bolus_0_15U_65P_ext_30min = SetInsulinScheduleCommand(nonce: 0x03171958, units: 0.05, extendedUnits: 0.10, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a0e0317195802001602001000011801", bolus_0_15U_65P_ext_30min.data.hexadecimalString) - - // 0.15U dual bolus 65% extended over 1.0 hour (1i 2e) -> only one entry used - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 08151959 02 0017 03 0010 0001 2001 17 0d 00 000a 00030d40 0014 0aba9500 - let bolus_0_15U_65P_ext_60min = SetInsulinScheduleCommand(nonce: 0x08151959, units: 0.05, extendedUnits: 0.10, extendedDuration: .hours(1.0)) - XCTAssertEqual("1a0e0815195902001703001000012001", bolus_0_15U_65P_ext_60min.data.hexadecimalString) - - // 0.15U dual bolus 65% extended over 1.5 hours (1i 2e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 06211961 02 0018 04 0010 0001 0001 1800 0001 17 0d 00 000a 00030d40 0014 1017df80 - let bolus_0_15U_65P_ext_90min = SetInsulinScheduleCommand(nonce: 0x06211961, units: 0.05, extendedUnits: 0.10, extendedDuration: .hours(1.5)) - XCTAssertEqual("1a12062119610200180400100001000118000001", bolus_0_15U_65P_ext_90min.data.hexadecimalString) - - // 0.15U dual bolus 65% extended over 2.0 hours (1i 2e) -> max duration allowed - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 12041962 02 0019 05 0010 0001 0001 3800 17 0d 00 000a 00030d40 0014 15752a00 - let bolus_0_15U_65P_ext_120min = SetInsulinScheduleCommand(nonce: 0x12041962, units: 0.05, extendedUnits: 0.10, extendedDuration: .hours(2.0)) - XCTAssertEqual("1a1012041962020019050010000100013800", bolus_0_15U_65P_ext_120min.data.hexadecimalString) - - - // 0.20U dual bolus 75% extended over 0.5 hours (1i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 08121964 02 0017 02 0010 0001 0001 0003 17 0d 00 000a 00030d40 001e 03938700 - let bolus_0_20U_75P_ext_30min = SetInsulinScheduleCommand(nonce: 0x08121964, units: 0.05, extendedUnits: 0.15, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a1008121964020017020010000100010003", bolus_0_20U_75P_ext_30min.data.hexadecimalString) - - // 0.20U dual bolus 75% extended over 1.0 hour (1i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 04111967 02 0018 03 0010 0001 1001 0002 17 0d 00 000a 00030d40 001e 07270e00 - let bolus_0_20U_75P_ext_60min = SetInsulinScheduleCommand(nonce: 0x04111967, units: 0.05, extendedUnits: 0.15, extendedDuration: .hours(1.0)) - XCTAssertEqual("1a1004111967020018030010000110010002", bolus_0_20U_75P_ext_60min.data.hexadecimalString) - - // 0.20U dual bolus 75% extended over 1.5 hours (1i 3e) -> only one entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 09301968 02 0019 04 0010 0001 3001 17 0d 00 000a 00030d40 001e 0aba9500 - let bolus_0_20U_75P_ext_90min = SetInsulinScheduleCommand(nonce: 0x09301968, units: 0.05, extendedUnits: 0.15, extendedDuration: .hours(1.5)) - XCTAssertEqual("1a0e0930196802001904001000013001", bolus_0_20U_75P_ext_90min.data.hexadecimalString) - - // 0.20U dual bolus 75% extended over 2.0 hours (1i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 07271971 02 001a 05 0010 0001 0001 1800 1001 17 0d 00 000a 00030d40 001e 0e4e1c00 - let bolus_0_20U_75P_ext_120min = SetInsulinScheduleCommand(nonce: 0x07271971, units: 0.05, extendedUnits: 0.15, extendedDuration: .hours(2.0)) - XCTAssertEqual("1a120727197102001a0500100001000118001001", bolus_0_20U_75P_ext_120min.data.hexadecimalString) - - // 0.20U dual bolus 75% extended over 2.5 hours (1i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 03091975 02 001b 06 0010 0001 0001 3800 0001 17 0d 00 000a 00030d40 001e 11e1a300 - let bolus_0_20U_75P_ext_150min = SetInsulinScheduleCommand(nonce: 0x03091975, units: 0.05, extendedUnits: 0.15, extendedDuration: .hours(2.5)) - XCTAssertEqual("1a120309197502001b0600100001000138000001", bolus_0_20U_75P_ext_150min.data.hexadecimalString) - - // 0.20U dual bolus 75% extended over 3.0 hours (1i 3e) -> max duration allowed - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 01242016 02 001c 07 0010 0001 0001 5800 17 0d 00 000a 00030d40 001e 15752a00 - let bolus_0_20U_75P_ext_180min = SetInsulinScheduleCommand(nonce: 0x01242016, units: 0.05, extendedUnits: 0.15, extendedDuration: .hours(3.0)) - XCTAssertEqual("1a100124201602001c070010000100015800", bolus_0_20U_75P_ext_180min.data.hexadecimalString) - - - // 0.25U dual bolus 80% extended over 0.5 hours (1i 4e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 03211983 02 0018 02 0010 0001 0001 0004 17 0d 00 000a 00030d40 0028 02aea540 - let bolus_0_25U_80P_ext_30min = SetInsulinScheduleCommand(nonce: 0x03211983, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a1003211983020018020010000100010004", bolus_0_25U_80P_ext_30min.data.hexadecimalString) - - // 0.25U dual bolus 80% extended over 1.0 hour (1i 4e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 11041986 02 0019 03 0010 0001 1801 0002 17 0d 00 000a 00030d40 0028 055d4a80 - let bolus_0_25U_80P_ext_60min = SetInsulinScheduleCommand(nonce: 0x11041986, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(1.0)) - XCTAssertEqual("1a1011041986020019030010000118010002", bolus_0_25U_80P_ext_60min.data.hexadecimalString) - - // 0.25U dual bolus 80% extended over 1.5 hours (1i 4e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 05061987 02 001a 04 0010 0001 2001 0002 17 0d 00 000a 00030d40 0028 080befc0 - let bolus_0_25U_80P_ext_90min = SetInsulinScheduleCommand(nonce: 0x05061987, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(1.5)) - XCTAssertEqual("1a100506198702001a040010000120010002", bolus_0_25U_80P_ext_90min.data.hexadecimalString) - - // 0.25U dual bolus 80% extended over 2.0 hours (1i 4e) -> only one entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 10201988 02 001b 05 0010 0001 4001 17 0d 00 000a 00030d40 0028 0aba9500 - let bolus_0_25U_80P_ext_120min = SetInsulinScheduleCommand(nonce: 0x10201988, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(2.0)) - XCTAssertEqual("1a0e1020198802001b05001000014001", bolus_0_25U_80P_ext_120min.data.hexadecimalString) - - // 0.25U dual bolus 80% extended over 2.5 hours (1i 4e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 07051989 02 001c 06 0010 0001 0001 1800 2001 17 0d 00 000a 00030d40 0028 0d693a40 - let bolus_0_25U_80P_ext_150min = SetInsulinScheduleCommand(nonce: 0x07051989, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(2.5)) - XCTAssertEqual("1a120705198902001c0600100001000118002001", bolus_0_25U_80P_ext_150min.data.hexadecimalString) - - // 0.25U dual bolus 80% extended over 3.0 hours (1i 4e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 16 09061990 02 001d 07 0010 0001 0001 1800 0001 1800 0001 17 0d 00 000a 00030d40 0028 1017df80 - let bolus_0_25U_80P_ext_180min = SetInsulinScheduleCommand(nonce: 0x09061990, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(3.0)) - XCTAssertEqual("1a160906199002001d070010000100011800000118000001", bolus_0_25U_80P_ext_180min.data.hexadecimalString) - - // 0.25U dual bolus 80% extended over 3.5 hours (1i 4e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 09061990 02 001e 08 0010 0001 0001 5800 0001 17 0d 00 000a 00030d40 0028 12c684c0 - let bolus_0_25U_80P_ext_210min = SetInsulinScheduleCommand(nonce: 0x09061990, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(3.5)) - XCTAssertEqual("1a120906199002001e0800100001000158000001", bolus_0_25U_80P_ext_210min.data.hexadecimalString) - - // 0.25U dual bolus 80% extended over 4.0 hours (1i 4e) -> max duration allowed - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 01311991 02 001f 09 0010 0001 0001 7800 17 0d 00 000a 00030d40 0028 15752a00 - let bolus_0_25U_80P_ext_240min = SetInsulinScheduleCommand(nonce: 0x01311991, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(4.0)) - XCTAssertEqual("1a100131199102001f090010000100017800", bolus_0_25U_80P_ext_240min.data.hexadecimalString) - - - // 0.15U dual bolus 30% extended over 0.5 hours (2i 1e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 05071991 02 0027 02 0020 0002 0002 0001 17 0d 00 0014 00030d40 000a 0aba9500 - let bolus_0_15U_30P_ext_30min = SetInsulinScheduleCommand(nonce: 0x05071991, units: 0.10, extendedUnits: 0.05, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a1005071991020027020020000200020001", bolus_0_15U_30P_ext_30min.data.hexadecimalString) - - // 0.15U dual bolus 30% extended over 1.0 hour (2i 1e) -> max duration allowed - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 08311995 02 0028 03 0020 0002 0002 1800 17 0d 00 0014 00030d40 000a 15752a00 - let bolus_0_15U_30P_ext_60min = SetInsulinScheduleCommand(nonce: 0x08311995, units: 0.10, extendedUnits: 0.05, extendedDuration: .hours(1.0)) - XCTAssertEqual("1a1008311995020028030020000200021800", bolus_0_15U_30P_ext_60min.data.hexadecimalString) - - - // 0.20U dual bolus 50% extended over 0.5 hours (2i 2e) -> only one entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 10061995 02 0028 02 0020 0002 1002 17 0d 00 0014 00030d40 0014 055d4a80 - let bolus_0_20U_50P_ext_30min = SetInsulinScheduleCommand(nonce: 0x10061995, units: 0.10, extendedUnits: 0.10, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a0e1006199502002802002000021002", bolus_0_20U_50P_ext_30min.data.hexadecimalString) - - // 0.20U dual bolus 50% extended over 1.0 hour (2i 2e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 07132004 02 0029 03 0020 0002 0002 1001 17 0d 00 0014 00030d40 0014 0aba9500 - let bolus_0_20U_50P_ext_60min = SetInsulinScheduleCommand(nonce: 0x07132004, units: 0.10, extendedUnits: 0.10, extendedDuration: .hours(1.0)) - XCTAssertEqual("1a1007132004020029030020000200021001", bolus_0_20U_50P_ext_60min.data.hexadecimalString) - - // 0.20U dual bolus 50% extended over 1.5 hours (2i 2e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 02192008 02 002a 04 0020 0002 0002 1800 0001 17 0d 00 0014 00030d40 0014 1017df80 - let bolus_0_20U_50P_ext_90min = SetInsulinScheduleCommand(nonce: 0x02192008, units: 0.10, extendedUnits: 0.10, extendedDuration: .hours(1.5)) - XCTAssertEqual("1a120219200802002a0400200002000218000001", bolus_0_20U_50P_ext_90min.data.hexadecimalString) - - // 0.20U dual bolus 50% extended over 2.0 hours (2i 2e) -> max duration allowed - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 10092008 02 002b 05 0020 0002 0002 3800 17 0d 00 0014 00030d40 0014 15752a00 - let bolus_0_20U_50P_ext_120min = SetInsulinScheduleCommand(nonce: 0x10092008, units: 0.10, extendedUnits: 0.10, extendedDuration: .hours(2.0)) - XCTAssertEqual("1a101009200802002b050020000200023800", bolus_0_20U_50P_ext_120min.data.hexadecimalString) - - - // 0.25U dual bolus 60% extended over 0.5 hours (2i 3e) -> only one entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 06222009 02 0029 02 0020 0002 1802 17 0d 00 0014 00030d40 001e 03938700 - let bolus_0_25U_60P_ext_30min = SetInsulinScheduleCommand(nonce: 0x06222009, units: 0.10, extendedUnits: 0.15, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a0e0622200902002902002000021802", bolus_0_25U_60P_ext_30min.data.hexadecimalString) - - // 0.25U dual bolus 60% extended over 1.0 hour (2i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 07122009 02 002a 03 0020 0002 0002 1801 17 0d 00 0014 00030d40 001e 07270e00 - let bolus_0_25U_60P_ext_60min = SetInsulinScheduleCommand(nonce: 0x07122009, units: 0.10, extendedUnits: 0.15, extendedDuration: .hours(1.0)) - XCTAssertEqual("1a100712200902002a030020000200021801", bolus_0_25U_60P_ext_60min.data.hexadecimalString) - - // 0.25U dual bolus 60% extended over 1.5 hours (2i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 08102009 02 002b 04 0020 0002 0002 2001 17 0d 00 0014 00030d40 001e 0aba9500 - let bolus_0_25U_60P_ext_90min = SetInsulinScheduleCommand(nonce: 0x08102009, units: 0.10, extendedUnits: 0.15, extendedDuration: .hours(1.5)) - XCTAssertEqual("1a100810200902002b040020000200022001", bolus_0_25U_60P_ext_90min.data.hexadecimalString) - - // 0.25U dual bolus 60% extended over 2.0 hours (2i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 07162010 02 002c 05 0020 0002 0002 1800 1001 17 0d 00 0014 00030d40 001e 0e4e1c00 - let bolus_0_25U_60P_ext_120min = SetInsulinScheduleCommand(nonce: 0x07162010, units: 0.10, extendedUnits: 0.15, extendedDuration: .hours(2.0)) - XCTAssertEqual("1a120716201002002c0500200002000218001001", bolus_0_25U_60P_ext_120min.data.hexadecimalString) - - // 0.25U dual bolus 60% extended over 2.5 hours (2i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 08072010 02 002d 06 0020 0002 0002 3800 0001 17 0d 00 0014 00030d40 001e 11e1a300 - let bolus_0_25U_60P_ext_150min = SetInsulinScheduleCommand(nonce: 0x08072010, units: 0.10, extendedUnits: 0.15, extendedDuration: .hours(2.5)) - XCTAssertEqual("1a120807201002002d0600200002000238000001", bolus_0_25U_60P_ext_150min.data.hexadecimalString) - - // 0.25U dual bolus 60% extended over 3.0 hours (2i 3e) -> max duration allowed - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 05062012 02 002e 07 0020 0002 0002 5800 17 0d 00 0014 00030d40 001e 15752a00 - let bolus_0_25U_60P_ext_180min = SetInsulinScheduleCommand(nonce: 0x05062012, units: 0.10, extendedUnits: 0.15, extendedDuration: .hours(3.0)) - XCTAssertEqual("1a100506201202002e070020000200025800", bolus_0_25U_60P_ext_180min.data.hexadecimalString) - } - - func test_30U_100P_ext() { - // 30U bolus 100% ext over 0.5 hours (0i 600e) - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 494e532e 02 005c 02 0000 0000 0000 0258 - let bolus30U_100P_ext_30min = SetInsulinScheduleCommand(nonce: 0x494e532e, units: 0.0, extendedUnits: 30, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a10494e532e02005c020000000000000258", bolus30U_100P_ext_30min.data.hexadecimalString) - - let bolus30U_100P_ext_30min_encoded = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: bolus30U_100P_ext_30min.data.hexadecimalString)!) - XCTAssertEqual(0x494e532e, bolus30U_100P_ext_30min_encoded.nonce) - let schedule = bolus30U_100P_ext_30min_encoded.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(0.0, units) - XCTAssertEqual(0, timeBetweenPulses) - XCTAssertEqual(2, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(0, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(1, table.entries[1].segments) - XCTAssertEqual(600, table.entries[1].pulses) - XCTAssertEqual(false, table.entries[1].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 0000 00030d40 1770 000493e0 - let bolus30U_100P_ext_30min_extra = BolusExtraCommand(extendedUnits: 30.0, extendedDuration: .hours(0.5)) - XCTAssertEqual("170d00000000030d401770000493e0", bolus30U_100P_ext_30min_extra.data.hexadecimalString) - - let bolus30U_100P_ext_30min_extra_encoded = try BolusExtraCommand(encodedData: Data(hexadecimalString: bolus30U_100P_ext_30min_extra.data.hexadecimalString)!) - XCTAssertEqual(0.0, bolus30U_100P_ext_30min_extra_encoded.units) - XCTAssertEqual(false, bolus30U_100P_ext_30min_extra_encoded.acknowledgementBeep) - XCTAssertEqual(false, bolus30U_100P_ext_30min_extra_encoded.completionBeep) - XCTAssertEqual(0, bolus30U_100P_ext_30min_extra_encoded.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, bolus30U_100P_ext_30min_extra_encoded.timeBetweenPulses) - XCTAssertEqual(30.0, bolus30U_100P_ext_30min_extra_encoded.extendedUnits) - XCTAssertEqual(.hours(0.5), bolus30U_100P_ext_30min_extra_encoded.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func test_30U_75P_ext() { - // 30U bolus 75% ext over 0.5 hours (450i 150e) - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 494e532e 02 025a 02 0960 0096 0096 01c2 - let bolus30U_75P_ext_30min = SetInsulinScheduleCommand(nonce: 0x494e532e, units: 7.5, extendedUnits: 22.5, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a10494e532e02025a0209600096009601c2", bolus30U_75P_ext_30min.data.hexadecimalString) - - let bolus30U_75P_ext_30min_encoded = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: bolus30U_75P_ext_30min.data.hexadecimalString)!) - XCTAssertEqual(0x494e532e, bolus30U_75P_ext_30min_encoded.nonce) - let schedule = bolus30U_75P_ext_30min_encoded.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(7.5, units) - XCTAssertEqual(Pod.secondsPerBolusPulse, timeBetweenPulses) - XCTAssertEqual(2, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(150, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(1, table.entries[1].segments) - XCTAssertEqual(450, table.entries[1].pulses) - XCTAssertEqual(false, table.entries[1].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 05dc 00030d40 1194 00061a80 - let bolus30U_75P_ext_30min_extra = BolusExtraCommand(units: 7.5, extendedUnits: 22.5, extendedDuration: .hours(0.5)) - XCTAssertEqual("170d0005dc00030d40119400061a80", bolus30U_75P_ext_30min_extra.data.hexadecimalString) - - let bolus30U_75P_ext_30min_extra_encoded = try BolusExtraCommand(encodedData: Data(hexadecimalString: bolus30U_75P_ext_30min_extra.data.hexadecimalString)!) - XCTAssertEqual(7.5, bolus30U_75P_ext_30min_extra_encoded.units) - XCTAssertEqual(false, bolus30U_75P_ext_30min_extra_encoded.acknowledgementBeep) - XCTAssertEqual(false, bolus30U_75P_ext_30min_extra_encoded.completionBeep) - XCTAssertEqual(0, bolus30U_75P_ext_30min_extra_encoded.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, bolus30U_75P_ext_30min_extra_encoded.timeBetweenPulses) - XCTAssertEqual(22.5, bolus30U_75P_ext_30min_extra_encoded.extendedUnits) - XCTAssertEqual(.hours(0.5), bolus30U_75P_ext_30min_extra_encoded.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func test_30U_50P_ext() { - // 30U bolus 50% ext over 0.5 hours (300i 300e) - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp - // 1a 0e 494e532e 02 015b 02 12c0 012c 112c - let bolus30U_50P_ext_30min = SetInsulinScheduleCommand(nonce: 0x494e532e, units: 15.0, extendedUnits: 15.0, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a0e494e532e02015b0212c0012c112c", bolus30U_50P_ext_30min.data.hexadecimalString) - - let bolus30U_50P_ext_30min_encoded = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: bolus30U_50P_ext_30min.data.hexadecimalString)!) - XCTAssertEqual(0x494e532e, bolus30U_50P_ext_30min_encoded.nonce) - let schedule = bolus30U_50P_ext_30min_encoded.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(15.0, units) - XCTAssertEqual(Pod.secondsPerBolusPulse, timeBetweenPulses) - XCTAssertEqual(1, table.entries.count) - XCTAssertEqual(2, table.entries[0].segments) - XCTAssertEqual(300, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 0bb8 00030d40 0bb8 000927c0 - let bolus30U_50P_ext_30min_extra = BolusExtraCommand(units: 15.0, extendedUnits: 15.0, extendedDuration: .hours(0.5)) - XCTAssertEqual("170d000bb800030d400bb8000927c0", bolus30U_50P_ext_30min_extra.data.hexadecimalString) - - let bolus30U_50P_ext_30min_extra_encoded = try BolusExtraCommand(encodedData: Data(hexadecimalString: bolus30U_50P_ext_30min_extra.data.hexadecimalString)!) - XCTAssertEqual(15.0, bolus30U_50P_ext_30min_extra_encoded.units) - XCTAssertEqual(false, bolus30U_50P_ext_30min_extra_encoded.acknowledgementBeep) - XCTAssertEqual(false, bolus30U_50P_ext_30min_extra_encoded.completionBeep) - XCTAssertEqual(0, bolus30U_50P_ext_30min_extra_encoded.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, bolus30U_50P_ext_30min_extra_encoded.timeBetweenPulses) - XCTAssertEqual(15.0, bolus30U_50P_ext_30min_extra_encoded.extendedUnits) - XCTAssertEqual(.hours(0.5), bolus30U_50P_ext_30min_extra_encoded.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func test_30U_25P_ext() { - // 30U bolus 25% ext over 0.5 hours (450i 150e) - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 494e532e 02 025a 02 1c20 01c2 01c2 0096 - let bolus30U_25P_ext_30min = SetInsulinScheduleCommand(nonce: 0x494e532e, units: 22.5, extendedUnits: 7.5, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a10494e532e02025a021c2001c201c20096", bolus30U_25P_ext_30min.data.hexadecimalString) - - let bolus30U_25P_ext_30min_encoded = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: bolus30U_25P_ext_30min.data.hexadecimalString)!) - XCTAssertEqual(0x494e532e, bolus30U_25P_ext_30min_encoded.nonce) - let schedule = bolus30U_25P_ext_30min_encoded.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(22.5, units) - XCTAssertEqual(Pod.secondsPerBolusPulse, timeBetweenPulses) - XCTAssertEqual(2, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(450, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(1, table.entries[1].segments) - XCTAssertEqual(150, table.entries[1].pulses) - XCTAssertEqual(false, table.entries[1].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 1194 00030d40 05dc 00124f80 - let bolus30U_25P_ext_30min_extra = BolusExtraCommand(units: 22.5, extendedUnits: 7.5, extendedDuration: .hours(0.5)) - XCTAssertEqual("170d00119400030d4005dc00124f80", bolus30U_25P_ext_30min_extra.data.hexadecimalString) - - let bolus30U_25P_ext_30min_extra_encoded = try BolusExtraCommand(encodedData: Data(hexadecimalString: bolus30U_25P_ext_30min_extra.data.hexadecimalString)!) - XCTAssertEqual(22.5, bolus30U_25P_ext_30min_extra_encoded.units) - XCTAssertEqual(false, bolus30U_25P_ext_30min_extra_encoded.acknowledgementBeep) - XCTAssertEqual(false, bolus30U_25P_ext_30min_extra_encoded.completionBeep) - XCTAssertEqual(0, bolus30U_25P_ext_30min_extra_encoded.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, bolus30U_25P_ext_30min_extra_encoded.timeBetweenPulses) - XCTAssertEqual(7.5, bolus30U_25P_ext_30min_extra_encoded.extendedUnits) - XCTAssertEqual(.hours(0.5), bolus30U_25P_ext_30min_extra_encoded.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func test_1U_immediate_9123secs_remaining() { - // extended bolus of 1.0U over 3.5 hours - // immediate 1.0U bolus with 2:32:05 (9123 seconds) remaining, cancel bolus returns 15 pulses (0.75U) not delivered - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp - // 1a 14 d3039c04 02 007f 07 0140 0014 0014 1802 2003 0001 - let nonce: UInt32 = 0xd3039c04 - let immediateUnits = 1.0 - let remainingExtendedUnits = 0.75 - let remainingExtendedBolusTime: TimeInterval = .seconds(9123) - - let bolus_1U_immediate_9123secs_remaining = SetInsulinScheduleCommand(nonce: nonce, units: immediateUnits, extendedUnits: remainingExtendedUnits, extendedDuration: remainingExtendedBolusTime) - XCTAssertEqual("1a14d3039c0402007f07014000140014180220030001", bolus_1U_immediate_9123secs_remaining.data.hexadecimalString) - - let bolus_1U_immediate_9123secs_remaining_encoded = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: bolus_1U_immediate_9123secs_remaining.data.hexadecimalString)!) - XCTAssertEqual(nonce, bolus_1U_immediate_9123secs_remaining.nonce) - let schedule = bolus_1U_immediate_9123secs_remaining_encoded.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(immediateUnits, units) - XCTAssertEqual(Pod.secondsPerBolusPulse, timeBetweenPulses) - XCTAssertEqual(4, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(20, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[1].segments) - XCTAssertEqual(2, table.entries[1].pulses) - XCTAssertEqual(true, table.entries[1].alternateSegmentPulse) - XCTAssertEqual(3, table.entries[2].segments) - XCTAssertEqual(3, table.entries[2].pulses) - XCTAssertEqual(false, table.entries[2].alternateSegmentPulse) - XCTAssertEqual(1, table.entries[3].segments) - XCTAssertEqual(1, table.entries[3].pulses) - XCTAssertEqual(false, table.entries[3].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 00c8 00030d40 0096 03a00a20 - let bolus_1U_immediate_9123secs_remaining_extra = BolusExtraCommand(units: immediateUnits, extendedUnits: remainingExtendedUnits, extendedDuration: remainingExtendedBolusTime) - XCTAssertEqual("170d0000c800030d40009603a00a20", bolus_1U_immediate_9123secs_remaining_extra.data.hexadecimalString) - let bolus_1U_immediate_9123secs_remaining_extra_encoded = try BolusExtraCommand(encodedData: Data(hexadecimalString: bolus_1U_immediate_9123secs_remaining_extra.data.hexadecimalString)!) - XCTAssertEqual(immediateUnits, bolus_1U_immediate_9123secs_remaining_extra_encoded.units) - XCTAssertEqual(false, bolus_1U_immediate_9123secs_remaining_extra.acknowledgementBeep) - XCTAssertEqual(false, bolus_1U_immediate_9123secs_remaining_extra.completionBeep) - XCTAssertEqual(0, bolus_1U_immediate_9123secs_remaining_extra_encoded.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, bolus_1U_immediate_9123secs_remaining_extra.timeBetweenPulses) - XCTAssertEqual(remainingExtendedUnits, bolus_1U_immediate_9123secs_remaining_extra_encoded.extendedUnits) - XCTAssertEqual(remainingExtendedBolusTime, bolus_1U_immediate_9123secs_remaining_extra.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func test_1U_immediate_3363secs_remaining() { - // extended bolus of 1.0U over 3.5 hours - // immediate 1.0U bolus with 56:03 min (3363 seconds) remaining, cancel bolus returns 6 pulses (0.30U) not delivered - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 1304de22 02 0072 03 0140 0014 0014 1003 - let nonce: UInt32 = 0x1304de22 - let immediateUnits = 1.0 - let remainingExtendedUnits = 0.3 - let remainingExtendedBolusTime: TimeInterval = .seconds(3363) - - let bolus_1U_immediate_3363secs_remaining = SetInsulinScheduleCommand(nonce: nonce, units: immediateUnits, extendedUnits: remainingExtendedUnits, extendedDuration: remainingExtendedBolusTime) - XCTAssertEqual("1a101304de22020072030140001400141003", bolus_1U_immediate_3363secs_remaining.data.hexadecimalString) - - let bolus_1U_immediate_3363secs_remaining_encoded = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: bolus_1U_immediate_3363secs_remaining.data.hexadecimalString)!) - XCTAssertEqual(nonce, bolus_1U_immediate_3363secs_remaining.nonce) - let schedule = bolus_1U_immediate_3363secs_remaining_encoded.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(immediateUnits, units) - XCTAssertEqual(Pod.secondsPerBolusPulse, timeBetweenPulses) - XCTAssertEqual(2, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(20, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[1].segments) - XCTAssertEqual(3, table.entries[1].pulses) - XCTAssertEqual(false, table.entries[1].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 00c8 00030d40 003c 03574150 - let bolus_1U_immediate_3363secs_remaining_extra = BolusExtraCommand(units: immediateUnits, extendedUnits: remainingExtendedUnits, extendedDuration: remainingExtendedBolusTime) - XCTAssertEqual("170d0000c800030d40003c03574150", bolus_1U_immediate_3363secs_remaining_extra.data.hexadecimalString) - let bolus_1U_immediate_3363secs_remaining_extra_encoded = try BolusExtraCommand(encodedData: Data(hexadecimalString: bolus_1U_immediate_3363secs_remaining_extra.data.hexadecimalString)!) - XCTAssertEqual(immediateUnits, bolus_1U_immediate_3363secs_remaining_extra_encoded.units) - XCTAssertEqual(false, bolus_1U_immediate_3363secs_remaining_extra.acknowledgementBeep) - XCTAssertEqual(false, bolus_1U_immediate_3363secs_remaining_extra.completionBeep) - XCTAssertEqual(0, bolus_1U_immediate_3363secs_remaining_extra_encoded.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, bolus_1U_immediate_3363secs_remaining_extra.timeBetweenPulses) - XCTAssertEqual(remainingExtendedUnits, bolus_1U_immediate_3363secs_remaining_extra_encoded.extendedUnits) - XCTAssertEqual(remainingExtendedBolusTime, bolus_1U_immediate_3363secs_remaining_extra.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func test_1U_immediate_382secs_remaining() { - // extended bolus of 1.0U over 3.5 hours - // immediate 1.0U bolus with 6:22 (382 seconds) remaining, cancel bolus returns 1 pulse (0.05U) not delivered - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 10bbea5c 02 006c 02 0140 0014 0014 0001 - let nonce: UInt32 = 0x10bbea5c - let immediateUnits = 1.0 - let remainingExtendedUnits = 0.05 - let remainingExtendedBolusTime: TimeInterval = .seconds(382) - - let bolus_1U_immediate_382secs_remaining = SetInsulinScheduleCommand(nonce: nonce, units: immediateUnits, extendedUnits: remainingExtendedUnits, extendedDuration: remainingExtendedBolusTime) - XCTAssertEqual("1a1010bbea5c02006c020140001400140001", bolus_1U_immediate_382secs_remaining.data.hexadecimalString) - - let bolus_1U_immediate_382secs_remaining_encoded = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: bolus_1U_immediate_382secs_remaining.data.hexadecimalString)!) - XCTAssertEqual(nonce, bolus_1U_immediate_382secs_remaining.nonce) - let schedule = bolus_1U_immediate_382secs_remaining_encoded.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(immediateUnits, units) - XCTAssertEqual(Pod.secondsPerBolusPulse, timeBetweenPulses) - XCTAssertEqual(2, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(20, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(1, table.entries[1].segments) - XCTAssertEqual(1, table.entries[1].pulses) - XCTAssertEqual(false, table.entries[1].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 00c8 00030d40 000a 0246e2c0 - let bolus_1U_immediate_382secs_remaining_extra = BolusExtraCommand(units: immediateUnits, extendedUnits: remainingExtendedUnits, extendedDuration: remainingExtendedBolusTime) - XCTAssertEqual("170d0000c800030d40000a0246e2c0", bolus_1U_immediate_382secs_remaining_extra.data.hexadecimalString) - let bolus_1U_immediate_382secs_remaining_extra_encoded = try BolusExtraCommand(encodedData: Data(hexadecimalString: bolus_1U_immediate_382secs_remaining_extra.data.hexadecimalString)!) - XCTAssertEqual(immediateUnits, bolus_1U_immediate_382secs_remaining_extra_encoded.units) - XCTAssertEqual(false, bolus_1U_immediate_382secs_remaining_extra.acknowledgementBeep) - XCTAssertEqual(false, bolus_1U_immediate_382secs_remaining_extra.completionBeep) - XCTAssertEqual(0, bolus_1U_immediate_382secs_remaining_extra_encoded.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, bolus_1U_immediate_382secs_remaining_extra.timeBetweenPulses) - XCTAssertEqual(remainingExtendedUnits, bolus_1U_immediate_382secs_remaining_extra_encoded.extendedUnits) - XCTAssertEqual(remainingExtendedBolusTime, bolus_1U_immediate_382secs_remaining_extra.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testBolusExtraOddPulseCount() { - // 17 0d 7c 00fa 00030d40 000000000000 - let cmd = BolusExtraCommand(units: 1.25, acknowledgementBeep: false, completionBeep: true, programReminderInterval: .hours(1)) - XCTAssertEqual("170d7c00fa00030d40000000000000", cmd.data.hexadecimalString) - } - - // 1a 0e NNNNNNNN 02 CCCC HH SSSS PPPP 0ppp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 19e4890b 02 0025 01 0020 0002 0002 17 0d 00 001e 00030d40 0000 00000000 - // 0ppp = $0002 -> 2 pulses - // NNNN = $001e = 30 (dec) / 10 -> 3 pulses - func testBolusAndBolusExtraMatch() { - // 1a 0e NNNNNNNN 02 CCCC HH SSSS PPPP 0ppp - // 1a 0e 243085c8 02 0025 01 0020 0002 0002 - let bolusAmount = 0.1 - let bolusCommand = SetInsulinScheduleCommand(nonce: 0x243085c8, units: bolusAmount) - XCTAssertEqual("1a0e243085c802002501002000020002", bolusCommand.data.hexadecimalString) - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 0014 00030d40 0000 00000000 - let bolusExtraCommand = BolusExtraCommand(units: bolusAmount) - XCTAssertEqual("170d00001400030d40000000000000", bolusExtraCommand.data.hexadecimalString) - } - - func testBolusAndBolusExtraMatch2() { - let bolusAmount = 0.15 - let bolusCommand = SetInsulinScheduleCommand(nonce: 0x243085c8, units: bolusAmount) - XCTAssertEqual("1a0e243085c802003701003000030003", bolusCommand.data.hexadecimalString) - - let bolusExtraCommand = BolusExtraCommand(units: bolusAmount) - XCTAssertEqual("170d00001e00030d40000000000000", bolusExtraCommand.data.hexadecimalString) - } - - func testLargeBolus() { - let bolusAmount = 29.95 - let bolusCommand = SetInsulinScheduleCommand(nonce: 0x31204ba7, units: bolusAmount) - XCTAssertEqual("1a0e31204ba702014801257002570257", bolusCommand.data.hexadecimalString) - - let bolusExtraCommand = BolusExtraCommand(units: bolusAmount, acknowledgementBeep: false, completionBeep: true, programReminderInterval: .hours(1)) - XCTAssertEqual("170d7c176600030d40000000000000", bolusExtraCommand.data.hexadecimalString) - } - - func testOddBolus() { - // 1a 0e NNNNNNNN 02 CCCC HH SSSS PPPP 0ppp - // 1a 0e cf9e81ac 02 00e5 01 0290 0029 0029 - - let bolusAmount = 2.05 - let bolusCommand = SetInsulinScheduleCommand(nonce: 0xcf9e81ac, units: bolusAmount) - XCTAssertEqual("1a0ecf9e81ac0200e501029000290029", bolusCommand.data.hexadecimalString) - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 3c 019a 00030d40 0000 00000000 - let bolusExtraCommand = BolusExtraCommand(units: bolusAmount, acknowledgementBeep: false, completionBeep: false, programReminderInterval: .hours(1)) - XCTAssertEqual("170d3c019a00030d40000000000000", bolusExtraCommand.data.hexadecimalString) - } - - func testCancelBolusCommand() { - do { - // Decode 1f 05 4d91f8ff 64 - let cmd = try CancelDeliveryCommand(encodedData: Data(hexadecimalString: "1f054d91f8ff64")!) - XCTAssertEqual(0x4d91f8ff, cmd.nonce) - XCTAssertEqual(.beeeeeep, cmd.beepType) - XCTAssertEqual(.bolus, cmd.deliveryType) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = CancelDeliveryCommand(nonce: 0x4d91f8ff, deliveryType: .bolus, beepType: .beeeeeep) - XCTAssertEqual("1f054d91f8ff64", cmd.data.hexadecimalString) - } -} diff --git a/Dependencies/OmniBLE/OmniBLETests/CRC16Tests.swift b/Dependencies/OmniBLE/OmniBLETests/CRC16Tests.swift deleted file mode 100644 index 716c70134..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/CRC16Tests.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// CRC16Tests.swift -// OmniBLE -// -// Created by Pete Schwamb on 10/14/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// From OmniKitTests/CRC16Tests.swift -// - -import XCTest -@testable import OmniBLE - -class CRC16Tests: XCTestCase { - - func testComputeCRC16() { - let input = Data(hexadecimalString: "1f01482a10030e0100")! - XCTAssertEqual(0x802c, input.crc16()) - } -} - - - diff --git a/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/endecrypt/EnDecryptTests.swift b/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/endecrypt/EnDecryptTests.swift deleted file mode 100644 index 4bccf8368..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/endecrypt/EnDecryptTests.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// EnDecryptTests.swift -// OmniBLE -// -// Created by Bill Gestrich on 12/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import OmniBLE - -class EnDecryptTest: XCTestCase { - - func testDecrypt() { - let received = "54,57,11,a1,0c,16,03,00,08,20,2e,a9,08,20,2e,a8,34,7c,b9,7b,38,5d,45,a3,c4,0e,40,4c,55,71,5e,f3,c3,86,50,17,36,7e,62,3c,7d,0b,46,9e,81,cd,fd,9a".replacingOccurrences(of:",", with:"") - let decryptedPayload = - "30,2e,30,3d,00,12,08,20,2e,a9,1c,0a,1d,05,00,16,b0,00,00,00,0b,ff,01,fe".replacingOccurrences(of:",", with:"") - - let enDecrypt = EnDecrypt( - nonce: Nonce(prefix: - Data(hexadecimalString:"6c,ff,5d,18,b7,61,6c,ae".replacingOccurrences(of:",", with:""))! - ), - ck: Data(hexadecimalString: "55,79,9f,d2,66,64,cb,f6,e4,76,52,5e,2d,ee,52,c6".replacingOccurrences(of:",", with:""))! - ) - let encryptedMessage = Data(hexadecimalString: received)! - let decrypted = Data(hexadecimalString: decryptedPayload)! - do { - let msg = try MessagePacket.parse(payload: encryptedMessage) - //AndroidAPS provides the nonceSequence in the nonce initialer, and increments it when encrypt/decrypt are called - //This implementation increments it in MessageTransport.incrementNonceSeq, before encrypt/decrypt are called. - let decryptedMsg = try enDecrypt.decrypt(msg, 23) - - assert(decrypted.hexadecimalString == decryptedMsg.payload.hexadecimalString) - } catch { - print(error) - } - - } - - - func testEncrypt() { - let enDecrypt = EnDecrypt( - nonce:Nonce(prefix: - Data(hexadecimalString: "dda23c090a0a0a0a")! - ), - ck: Data(hexadecimalString: "ba1283744b6de9fab6d9b77d95a71d6e")! - ) - let expectedEncryptedData = Data(hexadecimalString: - "54571101070003400242000002420001" + "e09158bcb0285a81bf30635f3a17ee73f0afbb3286bc524a8a66" + "fb1bc5b001e56543")! - let command = Data(hexadecimalString:"53302e303d000effffffff00060704ffffffff82b22c47302e30")! - var msg = try! MessagePacket.parse(payload: expectedEncryptedData)//.copy(payload = command) // copy for the headersE - msg.payload = command - //AndroidAPS provides the nonceSequence in the nonce initialer, and increments it when encrypt/decrypt are called - //This implementation increments it in MessageTransport.incrementNonceSeq, before encrypt/decrypt are called. - let encryptedData = try! enDecrypt.encrypt(msg, 1) - - print("Original Encrypted: \(expectedEncryptedData.hexadecimalString)") - print("Test Encrypted: \(encryptedData.asData().hexadecimalString)") - assert(expectedEncryptedData.hexadecimalString == encryptedData.asData().hexadecimalString) - } - -} diff --git a/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/MessagePacketTests.swift b/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/MessagePacketTests.swift deleted file mode 100644 index 72fc91c25..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/MessagePacketTests.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// MessagePacketTests.swift -// OmniBLE -// -// Created by Bill Gestrich on 12/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import OmniBLE - -class MessagePacketTests: XCTestCase { - - let payloadString = "54,57,11,01,07,00,03,40,08,20,2e,a8,08,20,2e,a9,ab,35,d8,31,60,9b,b8,fe,3a,3b,de,5b,18,37,24,9a,16,db,f8,e4,d3,05,e9,75,dc,81,7c,37,07,cc,41,5f,af,8a".replacingOccurrences(of: ",", with: "") - - func testParseMessagePacket() { - let msg = try! MessagePacket.parse(payload: Data(hexadecimalString: payloadString)!) - assert(msg.type == MessageType.ENCRYPTED) - assert(msg.source == Id.fromInt(136326824)) - assert(msg.destination == Id.fromInt(136326825)) - assert(msg.sequenceNumber == 7) - assert(msg.ackNumber == 0) - assert(msg.eqos == 1) - assert(msg.priority == false) - assert(msg.lastMessage == false) - assert(msg.gateway == false) - assert(msg.sas == true) - assert(msg.tfs == false) - assert(msg.version == 0) - let index1 = payloadString.index(payloadString.startIndex, offsetBy: 32) - let toCheck = payloadString[index1...] - assert(msg.payload.hexadecimalString == String(toCheck)) - } - - - func testSerializeMessagePacket() { - let payload = Data(hexadecimalString: payloadString)! - let msg = MessagePacket(type: .ENCRYPTED, - source: Id.fromInt(136326824).toUInt32(), - destination: Id.fromInt(136326825).toUInt32(), - payload: payload, - sequenceNumber: 0, - ack: false, ackNumber: 0, - eqos: 1, - priority: false, - lastMessage: false, - gateway: false, - sas: true, - tfs: false, - version: 0) - - assert(msg.payload.bytes.toHexString() == payloadString) - } - -} diff --git a/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/PayloadJoinerTest.swift b/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/PayloadJoinerTest.swift deleted file mode 100644 index 9a27ffce9..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/PayloadJoinerTest.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// PayloadJoinerTest.swift -// OmniBLE -// -// Created by Bill Gestrich on 12/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import OmniBLE - -class PayloadJoinerTest: XCTestCase { - - func testJoiner() { - - let f1 = Data(hexadecimalString: "00,01,54,57,10,23,03,00,00,c0,ff,ff,ff,fe,08,20,2e,a8,50,30".replacingOccurrences(of: ",", with: ""))! - let f2 = Data(hexadecimalString: "01,04,bc,20,1f,f6,3d,00,01,a5,ff,ff,ff,fe,08,20,2e,a8,50,30".replacingOccurrences(of: ",", with: ""))! - - let payload = "54,57,10,23,03,00,00,c0,ff,ff,ff,fe,08,20,2e,a8,50,30,3d,00,01,a5".replacingOccurrences(of: ",", with: "") - let joiner = try! PayloadJoiner(firstPacket: f1) - try! joiner.accumulate(packet: f2) - let actual = try! joiner.finalize() - assert(payload == actual.hexadecimalString) - } -} diff --git a/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/PayloadSplitJoinTests.swift b/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/PayloadSplitJoinTests.swift deleted file mode 100644 index feb4f6df9..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/PayloadSplitJoinTests.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// PayloadSplitJoinTests.swift -// OmniBLE -// -// Created by Bill Gestrich on 12/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import OmniBLE - -class PayloadSplitJoinTests: XCTestCase { - - func testSplitAndJoinBack() { - for _ in 0...250 { - let payload = Data(hexadecimalString: "54571003010003801781fc00fffffffe5350313d00041781fc012c5350323d000bffc32dbd08030e0100008a")! - let splitter = PayloadSplitter(payload: payload) - let packets = splitter.splitInPackets() - let joiner = try! PayloadJoiner(firstPacket: packets[0].toData()) - for p in packets[1...] { - try! joiner.accumulate(packet: p.toData()) - } - let got = try! joiner.finalize() - assert(got.hexadecimalString == payload.hexadecimalString) - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/PayloadSplitterTest.swift b/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/PayloadSplitterTest.swift deleted file mode 100644 index 08317aa66..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/PayloadSplitterTest.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// PayloadSplitterTest.swift -// OmniBLE -// -// Created by Bill Gestrich on 12/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import OmniBLE - -class PayloadSplitterTest: XCTestCase { - func testSplitter() { - let f1 = "00,01,54,57,10,23,03,00,00,c0,ff,ff,ff,fe,08,20,2e,a8,50,30".replacingOccurrences(of:",", with:"") - let f2 = "01,04,bc,20,1f,f6,3d,00,01,a5,ff,ff,ff,fe,08,20,2e,a8,50,30".replacingOccurrences(of:",", with:"") - let payload = Data(hexadecimalString: "54,57,10,23,03,00,00,c0,ff,ff,ff,fe,08,20,2e,a8,50,30,3d,00,01,a5".replacingOccurrences(of:",", with:""))! - - let splitter = PayloadSplitter(payload: payload) - let packets = splitter.splitInPackets() - - assert(packets.count == 2) - assert(f1 == packets[0].toData().hexadecimalString) - let p2 = packets[1].toData().hexadecimalString - assert(p2.count >= 10) - - assert(f2.substring(startIndex:0, toIndex:20) == p2.substring(startIndex: 0, toIndex: 20)) - } - -} diff --git a/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/StringLengthPrefixEncodingTests.swift b/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/StringLengthPrefixEncodingTests.swift deleted file mode 100644 index 262a6b9cd..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/message/StringLengthPrefixEncodingTests.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// StringLengthPrefixEncodingTests.swift -// OmniBLE -// -// Created by Bill Gestrich on 12/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import OmniBLE - -class StringLengthPrefixEncodingTests: XCTestCase { - - let p0Payload = Data(hexadecimalString: "50,30,3d,00,01,a5".replacingOccurrences(of: ",", with: ""))! - let p0Content = Data(hexadecimalString:"a5")! - - func testFormatKeysP0() { - let payload = StringLengthPrefixEncoding.formatKeys(keys: ["P0="], payloads: [p0Content]) - assert(p0Payload.hexadecimalString == payload.hexadecimalString) - } - - func testParseKeysP0() { - let parsed = try! StringLengthPrefixEncoding.parseKeys(["P0="], p0Payload) - assert(parsed.count == 1) - assert(parsed[0].toHexString() == p0Content.toHexString()) - } -} diff --git a/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/pair/KeyExchangeTests.swift b/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/pair/KeyExchangeTests.swift deleted file mode 100644 index 0bfea1778..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/Driver/Comm/pair/KeyExchangeTests.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// KeyExchangeTests.swift -// OmniBLE -// -// Created by Bill Gestrich on 12/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import OmniBLE - -class KeyExchangeTest: XCTestCase { - - func testKeyExchange() { - - let pdmNonce = Data(hexadecimalString:"edfdacb242c7f4e1d2bc4d93ca3c5706")! - - let privateKey = Data(hexadecimalString: "27ec94b71a201c5e92698d668806ae5ba00594c307cf5566e60c1fc53a6f6bb6")! - let privateKeyGenerator = MockFixedPrivateKeyGenerator(fixedPrivateKey: privateKey, generator: X25519KeyGenerator()) - let randomByteGenerator = MockRandomByteGenerator(fixedData: pdmNonce) - let ke = try! KeyExchange( - privateKeyGenerator, - randomByteGenerator - ) - let podPublicKey = Data(hexadecimalString:"2fe57da347cd62431528daac5fbb290730fff684afc4cfc2ed90995f58cb3b74")! - let podNonce = Data(hexadecimalString: "00000000000000000000000000000000")! - try! ke.updatePodPublicData(podPublicKey + podNonce) - assert(ke.pdmPublic.hexadecimalString == "f2b6940243aba536a66e19fb9a39e37f1e76a1cd50ab59b3e05313b4fc93975e") - assert(ke.pdmConf.hexadecimalString == "5fc3b4da865e838ceaf1e9e8bb85d1ac") - try! ke.validatePodConf(Data(hexadecimalString: "af4f10db5f96e5d9cd6cfc1f54f4a92f")!) - assert(ke.ltk.hexadecimalString == "341e16d13f1cbf73b19d1c2964fee02b") - } -} - - - -struct MockRandomByteGenerator: RandomByteGenerator { - - let fixedData: Data - - func nextBytes(length: Int) -> Data { - return fixedData - } -} - -struct MockFixedPrivateKeyGenerator: PrivateKeyGenerator { - - let fixedPrivateKey: Data - private let realGenerator: PrivateKeyGenerator - - init(fixedPrivateKey: Data, generator: PrivateKeyGenerator){ - self.fixedPrivateKey = fixedPrivateKey - self.realGenerator = generator - } - - func generatePrivateKey() -> Data { - return fixedPrivateKey - } - - func publicFromPrivate(_ privateKey: Data) throws -> Data { - assert(privateKey == self.fixedPrivateKey) - return try realGenerator.publicFromPrivate(privateKey) - } - - func computeSharedSecret(_ privateKey: Data, _ publicKey: Data) throws -> Data { - assert(privateKey == self.fixedPrivateKey) - return try realGenerator.computeSharedSecret(privateKey, publicKey) - } - -} diff --git a/Dependencies/OmniBLE/OmniBLETests/HexConversionTests.swift b/Dependencies/OmniBLE/OmniBLETests/HexConversionTests.swift deleted file mode 100644 index 8be989dc2..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/HexConversionTests.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// HexConversionTests.swift -// OmniBLE -// -// Created by Bill Gestrich on 12/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import OmniBLE - -class HexConversionTests: XCTestCase { - - func testConversion(){ - let hexString = "00,01,54,57,10,23,03,00,00,c0,ff,ff,ff,fe,08,20,2e,a8,50,30".replacingOccurrences(of: ",", with: "") - let f1 = Data(hexadecimalString: hexString)! - assert(f1.hexadecimalString == hexString) - } -} diff --git a/Dependencies/OmniBLE/OmniBLETests/Info.plist b/Dependencies/OmniBLE/OmniBLETests/Info.plist deleted file mode 100644 index 64d65ca49..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - 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/Dependencies/OmniBLE/OmniBLETests/MessageTests.swift b/Dependencies/OmniBLE/OmniBLETests/MessageTests.swift deleted file mode 100644 index da5569acc..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/MessageTests.swift +++ /dev/null @@ -1,324 +0,0 @@ -// -// MessageTests.swift -// OmniBLE -// -// Created by Pete Schwamb on 10/14/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// From OmniKitTests/MessageTests.swift -// - -import XCTest -@testable import OmniBLE - -class MessageTests: XCTestCase { - - func testMessageData() { - // 2016-06-26T20:33:28.412197 ID1:1f01482a PTYPE:PDM SEQ:13 ID2:1f01482a B9:10 BLEN:3 BODY:0e0100802c CRC:88 - - let msg = Message(address: 0x1f01482a, messageBlocks: [GetStatusCommand()], sequenceNum: 4) - - XCTAssertEqual("1f01482a10030e0100802c", msg.encoded().hexadecimalString) - } - - func testMessageDecoding() { - do { - let msg = try Message(encodedData: Data(hexadecimalString: "1f00ee84300a1d18003f1800004297ff8128")!) - - XCTAssertEqual(0x1f00ee84, msg.address) - XCTAssertEqual(12, msg.sequenceNum) - - let messageBlocks = msg.messageBlocks - - XCTAssertEqual(1, messageBlocks.count) - - let statusResponse = messageBlocks[0] as! StatusResponse - - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, statusResponse.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 4261), statusResponse.timeActive) - - XCTAssertEqual(.scheduledBasal, statusResponse.deliveryStatus) - XCTAssertEqual(.aboveFiftyUnits, statusResponse.podProgressStatus) - XCTAssertEqual(6.3, statusResponse.insulinDelivered, accuracy: 0.01) - XCTAssertEqual(0, statusResponse.bolusNotDelivered) - XCTAssertEqual(3, statusResponse.lastProgrammingMessageSeqNum) - XCTAssert(statusResponse.alerts.isEmpty) - - XCTAssertEqual("1f00ee84300a1d18003f1800004297ff8128", msg.encoded().hexadecimalString) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testParsingShortErosVersionResponse() { - do { - let config = try VersionResponse(encodedData: Data(hexadecimalString: "011502070002070002020000a64000097c279c1f08ced2")!) - XCTAssertEqual(23, config.data.count) - XCTAssertEqual("2.7.0", String(describing: config.firmwareVersion)) - XCTAssertEqual("2.7.0", String(describing: config.iFirmwareVersion)) - XCTAssertEqual(42560, config.lot) - XCTAssertEqual(621607, config.tid) - XCTAssertEqual(0x1f08ced2, config.address) - XCTAssertEqual(erosProductId, config.productId) - XCTAssertEqual(.reminderInitialized, config.podProgressStatus) - XCTAssertEqual(2, config.gain) - XCTAssertEqual(0x1c, config.rssi) - XCTAssertNil(config.pulseSize) - XCTAssertNil(config.secondsPerBolusPulse) - XCTAssertNil(config.secondsPerPrimePulse) - XCTAssertNil(config.primeUnits) - XCTAssertNil(config.cannulaInsertionUnits) - XCTAssertNil(config.serviceDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testParsingLongErosVersionResponse() { - do { - let message = try Message(encodedData: Data(hexadecimalString: "ffffffff041d011b13881008340a5002070002070002030000a62b000447941f00ee878352")!) - let config = message.messageBlocks[0] as! VersionResponse - XCTAssertEqual(29, config.data.count) - XCTAssertEqual("2.7.0", String(describing: config.firmwareVersion)) - XCTAssertEqual("2.7.0", String(describing: config.iFirmwareVersion)) - XCTAssertEqual(42539, config.lot) - XCTAssertEqual(280468, config.tid) - XCTAssertEqual(0x1f00ee87, config.address) - XCTAssertEqual(erosProductId, config.productId) - XCTAssertEqual(.pairingCompleted, config.podProgressStatus) - XCTAssertNil(config.rssi) - XCTAssertNil(config.gain) - XCTAssertEqual(Pod.pulseSize, config.pulseSize) - XCTAssertEqual(Pod.secondsPerBolusPulse, config.secondsPerBolusPulse) - XCTAssertEqual(Pod.secondsPerPrimePulse, config.secondsPerPrimePulse) - XCTAssertEqual(Pod.primeUnits, config.primeUnits) - XCTAssertEqual(Pod.cannulaInsertionUnits, config.cannulaInsertionUnits) - XCTAssertEqual(Pod.serviceDuration, config.serviceDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testParsingShortDashVersionResponse() { - do { - let config = try VersionResponse(encodedData: Data(hexadecimalString: "0115031b0008080004020812a011000c175700ffffffff")!) - XCTAssertEqual(23, config.data.count) - XCTAssertEqual("3.27.0", String(describing: config.firmwareVersion)) - XCTAssertEqual("8.8.0", String(describing: config.iFirmwareVersion)) - XCTAssertEqual(135438353, config.lot) - XCTAssertEqual(792407, config.tid) - XCTAssertEqual(0xFFFFFFFF, config.address) - XCTAssertEqual(dashProductId, config.productId) - XCTAssertEqual(.reminderInitialized, config.podProgressStatus) - XCTAssertEqual(0, config.gain) - XCTAssertEqual(0, config.rssi) - XCTAssertNil(config.pulseSize) - XCTAssertNil(config.secondsPerBolusPulse) - XCTAssertNil(config.secondsPerPrimePulse) - XCTAssertNil(config.primeUnits) - XCTAssertNil(config.cannulaInsertionUnits) - XCTAssertNil(config.serviceDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testParsingLongDashVersionResponse() { - do { - let message = try Message(encodedData: Data(hexadecimalString: "ffffffff0c1d011b13881008340a50031b0008080004030812a011000c175717244389816c")!) - let config = message.messageBlocks[0] as! VersionResponse - XCTAssertEqual(29, config.data.count) - XCTAssertEqual("3.27.0", String(describing: config.firmwareVersion)) - XCTAssertEqual("8.8.0", String(describing: config.iFirmwareVersion)) - XCTAssertEqual(135438353, config.lot) - XCTAssertEqual(792407, config.tid) - XCTAssertEqual(0x17244389, config.address) - XCTAssertEqual(dashProductId, config.productId) - XCTAssertEqual(.pairingCompleted, config.podProgressStatus) - XCTAssertNil(config.rssi) - XCTAssertNil(config.gain) - XCTAssertEqual(Pod.pulseSize, config.pulseSize) - XCTAssertEqual(Pod.secondsPerBolusPulse, config.secondsPerBolusPulse) - XCTAssertEqual(Pod.secondsPerPrimePulse, config.secondsPerPrimePulse) - XCTAssertEqual(Pod.primeUnits, config.primeUnits) - XCTAssertEqual(Pod.cannulaInsertionUnits, config.cannulaInsertionUnits) - XCTAssertEqual(Pod.serviceDuration, config.serviceDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testParsingConfigWithPairingExpired() { - do { - let message = try Message(encodedData: Data(hexadecimalString: "ffffffff04170115020700020700020e0000a5ad00053030971f08686301fd")!) - let config = message.messageBlocks[0] as! VersionResponse - XCTAssertEqual("2.7.0", String(describing: config.firmwareVersion)) - XCTAssertEqual("2.7.0", String(describing: config.iFirmwareVersion)) - XCTAssertEqual(0x0000a5ad, config.lot) - XCTAssertEqual(0x00053030, config.tid) - XCTAssertEqual(0x1f086863, config.address) - XCTAssertEqual(erosProductId, config.productId) - XCTAssertEqual(.activationTimeExceeded, config.podProgressStatus) - XCTAssertEqual(2, config.gain) - XCTAssertEqual(0x17, config.rssi) - XCTAssertNil(config.pulseSize) - XCTAssertNil(config.secondsPerBolusPulse) - XCTAssertNil(config.secondsPerPrimePulse) - XCTAssertNil(config.primeUnits) - XCTAssertNil(config.cannulaInsertionUnits) - XCTAssertNil(config.serviceDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testAssignAddressCommand() { - do { - // Encode - let encoded = AssignAddressCommand(address: 0x1f01482a) - XCTAssertEqual("07041f01482a", encoded.data.hexadecimalString) - - // Decode - let decoded = try AssignAddressCommand(encodedData: Data(hexadecimalString: "07041f01482a")!) - XCTAssertEqual(0x1f01482a, decoded.address) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testSetupPodCommand() { - do { - var components = DateComponents() - components.day = 12 - components.month = 6 - components.year = 2016 - components.hour = 13 - components.minute = 47 - - // Decode - let decoded = try SetupPodCommand(encodedData: Data(hexadecimalString: "03131f0218c31404060c100d2f0000a4be0004e4a1")!) - XCTAssertEqual(0x1f0218c3, decoded.address) - XCTAssertEqual(components, decoded.dateComponents) - XCTAssertEqual(0x0000a4be, decoded.lot) - XCTAssertEqual(0x0004e4a1, decoded.tid) - - // Encode - let encoded = SetupPodCommand(address: 0x1f0218c3, dateComponents: components, lot: 0x0000a4be, tid: 0x0004e4a1) - XCTAssertEqual("03131f0218c31404060c100d2f0000a4be0004e4a1", encoded.data.hexadecimalString) - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPrime() { - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP 0ppp - // 1a 0e bed2e16b 02 010a 01 01a0 0034 0034 - // Decode - let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a0ebed2e16b02010a0101a000340034")!) - XCTAssertEqual(0xbed2e16b, cmd.nonce) - - if case SetInsulinScheduleCommand.DeliverySchedule.bolus(let units, let timeBetweenPulses, let table) = cmd.deliverySchedule { - XCTAssertEqual(Pod.primeUnits, units) - XCTAssertEqual(Pod.secondsPerPrimePulse, timeBetweenPulses) - XCTAssertEqual(1, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(Int(Pod.primeUnits / Pod.pulseSize), table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - - } else { - XCTFail("Expected ScheduleEntry.bolus type") - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testInsertCannula() { - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP 0ppp - // 1a 0e 7e30bf16 02 0065 01 0050 000a 000a - // Decode - let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a0e7e30bf16020065010050000a000a")!) - XCTAssertEqual(0x7e30bf16, cmd.nonce) - - if case SetInsulinScheduleCommand.DeliverySchedule.bolus(let units, let timeBetweenPulses, let table) = cmd.deliverySchedule { - XCTAssertEqual(Pod.cannulaInsertionUnits, units) - XCTAssertEqual(Pod.secondsPerPrimePulse, timeBetweenPulses) - XCTAssertEqual(1, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(Int(Pod.cannulaInsertionUnits / Pod.pulseSize), table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - } else { - XCTFail("Expected ScheduleEntry.bolus type") - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testStatusResponseAlarmsParsing() { - // 1d 28 0082 00 0044 46eb ff - - do { - // Decode - let status = try StatusResponse(encodedData: Data(hexadecimalString: "1d28008200004446ebff")!) - XCTAssert(status.alerts.contains(.slot3)) - XCTAssert(status.alerts.contains(.slot7)) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testConfigureAlertsCommand() { - // 79a4 10df 0502 - // Pod expires 1 minute short of 3 days - let podSoftExpirationTime = TimeInterval(hours:72) - TimeInterval(minutes:1) - let alertConfig1 = AlertConfiguration(alertType: .slot7, active: true, autoOffModifier: false, duration: .hours(7), trigger: .timeUntilAlert(podSoftExpirationTime), beepRepeat: .every60Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep) - XCTAssertEqual("79a410df0502", alertConfig1.data.hexadecimalString) - - // 2800 1283 0602 - let podHardExpirationTime = TimeInterval(hours:79) - TimeInterval(minutes:1) - let alertConfig2 = AlertConfiguration(alertType: .slot2, active: true, autoOffModifier: false, duration: .minutes(0), trigger: .timeUntilAlert(podHardExpirationTime), beepRepeat: .every15Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep) - XCTAssertEqual("280012830602", alertConfig2.data.hexadecimalString) - - // 020f 0000 0202 - let alertConfig3 = AlertConfiguration(alertType: .slot0, active: false, autoOffModifier: true, duration: .minutes(15), trigger: .timeUntilAlert(0), beepRepeat: .every1MinuteFor15Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep) - XCTAssertEqual("020f00000202", alertConfig3.data.hexadecimalString) - - let configureAlerts = ConfigureAlertsCommand(nonce: 0xfeb6268b, configurations:[alertConfig1, alertConfig2, alertConfig3]) - XCTAssertEqual("1916feb6268b79a410df0502280012830602020f00000202", configureAlerts.data.hexadecimalString) - - do { - let decoded = try ConfigureAlertsCommand(encodedData: Data(hexadecimalString: "1916feb6268b79a410df0502280012830602020f00000202")!) - XCTAssertEqual(3, decoded.configurations.count) - - let config1 = decoded.configurations[0] - XCTAssertEqual(.slot7, config1.slot) - XCTAssertEqual(true, config1.active) - XCTAssertEqual(false, config1.autoOffModifier) - XCTAssertEqual(.hours(7), config1.duration) - if case AlertTrigger.timeUntilAlert(let duration) = config1.trigger { - XCTAssertEqual(podSoftExpirationTime, duration) - } - XCTAssertEqual(.every60Minutes, config1.beepRepeat) - XCTAssertEqual(.bipBeepBipBeepBipBeepBipBeep, config1.beepType) - - let cfg = try AlertConfiguration(encodedData: Data(hexadecimalString: "4c0000640102")!) - XCTAssertEqual(.slot4, cfg.slot) - XCTAssertEqual(true, cfg.active) - XCTAssertEqual(false, cfg.autoOffModifier) - XCTAssertEqual(0, cfg.duration) - if case AlertTrigger.unitsRemaining(let volume) = cfg.trigger { - XCTAssertEqual(10, volume) - } - XCTAssertEqual(.every1MinuteFor3MinutesAndRepeatEvery60Minutes, cfg.beepRepeat) - XCTAssertEqual(.bipBeepBipBeepBipBeepBipBeep, cfg.beepType) - - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } -} - diff --git a/Dependencies/OmniBLE/OmniBLETests/OmniBLETests.swift b/Dependencies/OmniBLE/OmniBLETests/OmniBLETests.swift deleted file mode 100644 index 2c57e764c..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/OmniBLETests.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// OmnipodTests.swift -// OmniBLE -// -// Created by Randall Knutson on 9/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import OmniBLE - -class OmnipodTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - } - - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } - } - -} diff --git a/Dependencies/OmniBLE/OmniBLETests/PodCommsSessionTests.swift b/Dependencies/OmniBLE/OmniBLETests/PodCommsSessionTests.swift deleted file mode 100644 index f5b7c9d24..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/PodCommsSessionTests.swift +++ /dev/null @@ -1,98 +0,0 @@ -// -// PodCommsSessionTests.swift -// OmniBLE -// -// Created by Pete Schwamb on 3/25/19. -// Copyright © 2019 Pete Schwamb. All rights reserved. -// From OmniKitTests/PodCommsSessionTests.swift -// - -import Foundation - -import XCTest -@testable import OmniBLE - -class MockMessageTransport: MessageTransport { - var delegate: MessageTransportDelegate? - - var messageNumber: Int - - var responseMessageBlocks = [MessageBlock]() - public var sentMessages = [Message]() - - var address: UInt32 - - var sentMessageHandler: ((Message) -> Void)? - - init(address: UInt32, messageNumber: Int) { - self.address = address - self.messageNumber = messageNumber - } - - func sendMessage(_ message: Message) throws -> Message { - sentMessages.append(message) - if responseMessageBlocks.isEmpty { - throw PodCommsError.noResponse - } - return Message(address: address, messageBlocks: [responseMessageBlocks.removeFirst()], sequenceNum: messageNumber) - } - - func addResponse(_ messageBlock: MessageBlock) { - responseMessageBlocks.append(messageBlock) - } - - func assertOnSessionQueue() { - // Do nothing in tests - } -} - -class PodCommsSessionTests: XCTestCase, PodCommsSessionDelegate { - - var lastPodStateUpdate: PodState? - - let address: UInt32 = 521580830 - let fakeLtk = Data(hexadecimalString: "fedcba98765432100123456789abcdef")! - var mockTransport: MockMessageTransport! = nil - var podState: PodState! = nil - - override func setUp() { - mockTransport = MockMessageTransport(address: address, messageNumber: 1) - podState = PodState(address: address, ltk: fakeLtk, firmwareVersion: "2.7.0", bleFirmwareVersion: "2.7.0", lotNo: 43620, lotSeq: 560313, productId: dashProductId, bleIdentifier: "0000-0000", insulinType: .novolog) - } - - func podCommsSession(_ podCommsSession: PodCommsSession, didChange state: PodState) { - lastPodStateUpdate = state - } - - func testBolusFinishedEarlyOnPodIsMarkedNonMutable() { - let mockStart = Date() - podState.unfinalizedBolus = UnfinalizedDose(bolusAmount: 4.45, startTime: mockStart, scheduledCertainty: .certain, insulinType: .novolog) - let session = PodCommsSession(podState: podState, transport: mockTransport, delegate: self) - - // Simulate a status request a bit before the bolus is expected to finish - let statusRequestTime = podState.unfinalizedBolus!.finishTime!.addingTimeInterval(-5) - session.mockCurrentDate = statusRequestTime - - let statusResponse = StatusResponse( - deliveryStatus: .scheduledBasal, - podProgressStatus: .aboveFiftyUnits, - timeActive: .minutes(10), - reservoirLevel: Pod.reservoirLevelAboveThresholdMagicNumber, - insulinDelivered: 25, - bolusNotDelivered: 0, - lastProgrammingMessageSeqNum: 5, - alerts: AlertSet(slots: [])) - - mockTransport.addResponse(statusResponse) - - let _ = try! session.getStatus() - - XCTAssertEqual(1, lastPodStateUpdate!.finalizedDoses.count) - - let finalizedBolus = lastPodStateUpdate!.finalizedDoses[0] - - XCTAssertTrue(finalizedBolus.isFinished(at: statusRequestTime)) - XCTAssertFalse(finalizedBolus.isMutable(at: statusRequestTime)) - } - -} diff --git a/Dependencies/OmniBLE/OmniBLETests/PodInfoTests.swift b/Dependencies/OmniBLE/OmniBLETests/PodInfoTests.swift deleted file mode 100644 index 7355c2219..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/PodInfoTests.swift +++ /dev/null @@ -1,476 +0,0 @@ -// -// PodInfoTests.swift -// OmniBLE -// -// Created by Eelke Jager on 18/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// From OmniKitTests/PodInfoTests.swift -// - -import Foundation - -import XCTest -@testable import OmniBLE - -class PodInfoTests: XCTestCase { - func testFullMessage() { - do { - // Decode - let infoResponse = try PodInfoResponse(encodedData: Data(hexadecimalString: "0216020d0000000000ab6a038403ff03860000285708030d0000")!) - XCTAssertEqual(infoResponse.podInfoResponseSubType, .detailedStatus) - let faultEvent = infoResponse.podInfo as! DetailedStatus - XCTAssertEqual(faultEvent.faultAccessingTables, false) - XCTAssertEqual(faultEvent.podProgressStatus, .faultEventOccurred) - XCTAssertEqual(faultEvent.errorEventInfo?.insulinStateTableCorruption, false) - XCTAssertEqual(faultEvent.errorEventInfo?.occlusionType, 1) - XCTAssertEqual(faultEvent.errorEventInfo?.immediateBolusInProgress, false) - XCTAssertEqual(faultEvent.errorEventInfo?.podProgressStatus, .aboveFiftyUnits) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoConfiguredAlertsNoAlerts() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 1516 1718 - // 02 13 // 01 XXXX VVVV VVVV VVVV VVVV VVVV VVVV VVVV VVVV - // 02 13 // 01 0000 0000 0000 0000 0000 0000 0000 0000 0000 - do { - // Decode - let decoded = try PodInfoConfiguredAlerts(encodedData: Data(hexadecimalString: "01000000000000000000000000000000000000")!) - XCTAssertEqual(.configuredAlerts, decoded.podInfoType) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoConfiguredAlertsSuspendStillActive() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 1516 1718 - // 02 13 // 01 XXXX VVVV VVVV VVVV VVVV VVVV VVVV VVVV VVVV - // 02 13 // 01 0000 0000 0000 0000 0000 0000 0bd7 0c40 0000 // real alert value after 2 hour suspend - // 02 13 // 01 0000 0102 0304 0506 0708 090a 0bd7 0c40 0000 // used as a tester to find each alarm - do { - // Decode - let decoded = try PodInfoConfiguredAlerts(encodedData: Data(hexadecimalString: "010000000000000000000000000bd70c400000")!) - XCTAssertEqual(.configuredAlerts, decoded.podInfoType) - XCTAssertEqual(.beepBeepBeep, decoded.alertsActivations[5].beepType) - XCTAssertEqual(11, decoded.alertsActivations[5].timeFromPodStart) // in minutes - XCTAssertEqual(10.75, decoded.alertsActivations[5].unitsLeft) //, accuracy: 1) - XCTAssertEqual(.beeeeeep, decoded.alertsActivations[6].beepType) - XCTAssertEqual(12, decoded.alertsActivations[6].timeFromPodStart) // in minutes - XCTAssertEqual(3.2, decoded.alertsActivations[6].unitsLeft) //, accuracy: 1) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoConfiguredAlertsReplacePodAfter3DaysAnd8Hours() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 1516 1718 - // 02 13 // 01 XXXX VVVV VVVV VVVV VVVV VVVV VVVV VVVV VVVV - // 02 13 // 01 0000 0000 0000 0000 0000 0000 0000 0000 10e1 - do { - let decoded = try PodInfoConfiguredAlerts(encodedData: Data(hexadecimalString: "010000000000000000000000000000000010e1")!) - XCTAssertEqual(.configuredAlerts, decoded.podInfoType) - XCTAssertEqual(.bipBipBipbipBipBip, decoded.alertsActivations[7].beepType) - XCTAssertEqual(16, decoded.alertsActivations[7].timeFromPodStart) // in 2 hours steps - XCTAssertEqual(11.25, decoded.alertsActivations[7].unitsLeft, accuracy: 1) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoConfiguredAlertsReplacePodAfterReservoirEmpty() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 1516 1718 - // 02 13 // 01 XXXX VVVV VVVV VVVV VVVV VVVV VVVV VVVV VVVV - // 02 13 // 01 0000 0000 0000 1285 0000 11c7 0000 0000 119c - do { - let decoded = try PodInfoConfiguredAlerts(encodedData: Data(hexadecimalString: "010000000000001285000011c700000000119c")!) - XCTAssertEqual(.configuredAlerts, decoded.podInfoType) - XCTAssertEqual(.bipBeepBipBeepBipBeepBipBeep, decoded.alertsActivations[2].beepType) - XCTAssertEqual(18, decoded.alertsActivations[2].timeFromPodStart) // in 2 hours steps - XCTAssertEqual(6.6, decoded.alertsActivations[2].unitsLeft, accuracy: 1) - XCTAssertEqual(.beep, decoded.alertsActivations[4].beepType) - XCTAssertEqual(17, decoded.alertsActivations[4].timeFromPodStart) // in 2 hours steps - XCTAssertEqual(9.95, decoded.alertsActivations[4].unitsLeft, accuracy: 2) - XCTAssertEqual(.bipBipBipbipBipBip, decoded.alertsActivations[7].beepType) - XCTAssertEqual(17, decoded.alertsActivations[7].timeFromPodStart) // in 2 hours steps - XCTAssertEqual(7.8, decoded.alertsActivations[7].unitsLeft, accuracy: 1) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoConfiguredAlertsReplacePod() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 1516 1718 - // 02 13 // 01 XXXX VVVV VVVV VVVV VVVV VVVV VVVV VVVV VVVV - // 02 13 // 01 0000 0000 0000 1284 0000 0000 0000 0000 10e0 - do { - let decoded = try PodInfoConfiguredAlerts(encodedData: Data(hexadecimalString: "010000000000001284000000000000000010e0")!) - XCTAssertEqual(.configuredAlerts, decoded.podInfoType) - XCTAssertEqual(.bipBeepBipBeepBipBeepBipBeep, decoded.alertsActivations[2].beepType) - XCTAssertEqual(18, decoded.alertsActivations[2].timeFromPodStart) // in 2 hours steps - XCTAssertEqual(6.6, decoded.alertsActivations[2].unitsLeft, accuracy: 1) - XCTAssertEqual(.bipBipBipbipBipBip, decoded.alertsActivations[7].beepType) - XCTAssertEqual(16, decoded.alertsActivations[7].timeFromPodStart) // in 2 hours steps - XCTAssertEqual(11.2, decoded.alertsActivations[7].unitsLeft, accuracy: 1) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoNoFaultAlerts() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 08 01 0000 0a 0038 00 0000 03ff 0087 00 00 00 95 ff 0000 - do { - // Decode - let decoded = try DetailedStatus(encodedData: Data(hexadecimalString: "02080100000a003800000003ff008700000095ff0000")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - XCTAssertEqual(.aboveFiftyUnits, decoded.podProgressStatus) - XCTAssertEqual(.scheduledBasal, decoded.deliveryStatus) - XCTAssertEqual(0000, decoded.bolusNotDelivered) - XCTAssertEqual(0x0a, decoded.lastProgrammingMessageSeqNum) - XCTAssertEqual(.noFaults, decoded.faultEventCode.faultType) - XCTAssertEqual(TimeInterval(minutes: 0x0000), decoded.faultEventTimeSinceActivation) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, decoded.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(8100, decoded.timeActive) - XCTAssertEqual(TimeInterval(minutes: 0x0087), decoded.timeActive) - XCTAssertEqual("02:15", decoded.timeActive.stringValue) - XCTAssertEqual(0, decoded.unacknowledgedAlerts.rawValue) - XCTAssertEqual(false, decoded.faultAccessingTables) - XCTAssertNil(decoded.errorEventInfo) - XCTAssertEqual(0b10, decoded.receiverLowGain) - XCTAssertEqual(0x15, decoded.radioRSSI) - XCTAssertNil(decoded.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoDeliveryErrorDuringPriming() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 0f 00 0000 09 0034 5c 0001 03ff 0001 00 00 05 ae 05 6029 - do { - // Decode - let decoded = try DetailedStatus(encodedData: Data(hexadecimalString: "020f0000000900345c000103ff0001000005ae056029")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - XCTAssertEqual(.inactive, decoded.podProgressStatus) - XCTAssertEqual(.suspended, decoded.deliveryStatus) - XCTAssertEqual(0000, decoded.bolusNotDelivered) - XCTAssertEqual(9, decoded.lastProgrammingMessageSeqNum) - XCTAssertEqual(.primeOpenCountTooLow, decoded.faultEventCode.faultType) - XCTAssertEqual(TimeInterval(minutes: 0x0001), decoded.faultEventTimeSinceActivation) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, decoded.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 0x0001), decoded.timeActive) - XCTAssertEqual(60, decoded.timeActive) - XCTAssertEqual(00, decoded.unacknowledgedAlerts.rawValue) - XCTAssertEqual(false, decoded.faultAccessingTables) - XCTAssertEqual(false, decoded.errorEventInfo?.insulinStateTableCorruption) - XCTAssertEqual(0, decoded.errorEventInfo?.occlusionType) - XCTAssertEqual(false, decoded.errorEventInfo?.immediateBolusInProgress) - XCTAssertEqual(.primingCompleted, decoded.errorEventInfo?.podProgressStatus) - XCTAssertEqual(0b10, decoded.receiverLowGain) - XCTAssertEqual(0x2e, decoded.radioRSSI) - XCTAssertEqual(.primingCompleted, decoded.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoDuringPriming() { - // Needle cap accidentally removed before priming started leaking and gave error: - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 0d 00 0000 06 0000 8f 0000 03ff 0000 00 00 03 a2 03 86a0 - do { - // Decode - let decoded = try DetailedStatus(encodedData: Data(hexadecimalString: "020d0000000600008f000003ff0000000003a20386a0")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - XCTAssertEqual(.faultEventOccurred, decoded.podProgressStatus) - XCTAssertEqual(.suspended, decoded.deliveryStatus) - XCTAssertEqual(0, decoded.bolusNotDelivered, accuracy: 0.01) - XCTAssertEqual(6, decoded.lastProgrammingMessageSeqNum) - XCTAssertEqual(.command1AParseUnexpectedFailed, decoded.faultEventCode.faultType) - XCTAssertEqual(TimeInterval(minutes: 0x0000), decoded.faultEventTimeSinceActivation) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, decoded.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 0x0000), decoded.timeActive) - XCTAssertEqual(0, decoded.unacknowledgedAlerts.rawValue) - XCTAssertEqual(false, decoded.faultAccessingTables) - XCTAssertEqual(false, decoded.errorEventInfo?.insulinStateTableCorruption) - XCTAssertEqual(0, decoded.errorEventInfo?.occlusionType) - XCTAssertEqual(PodProgressStatus.pairingCompleted, decoded.errorEventInfo?.podProgressStatus) - XCTAssertEqual(0b10, decoded.receiverLowGain) - XCTAssertEqual(0x22, decoded.radioRSSI) - XCTAssertEqual(.pairingCompleted, decoded.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoFaultEventErrorShuttingDown() { - // Failed Pod after 1 day, 18+ hours of live use shortly after installing new omniloop. - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 0d 00 0000 04 07f2 86 09ff 03ff 0a02 00 00 08 23 08 0000 - do { - // Decode - let decoded = try DetailedStatus(encodedData: Data(hexadecimalString: "020d0000000407f28609ff03ff0a0200000823080000")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - XCTAssertEqual(.faultEventOccurred, decoded.podProgressStatus) - XCTAssertEqual(.suspended, decoded.deliveryStatus) - XCTAssertEqual(0, decoded.bolusNotDelivered) - XCTAssertEqual(4, decoded.lastProgrammingMessageSeqNum) - XCTAssertEqual(101.7, decoded.totalInsulinDelivered, accuracy: 0.01) - XCTAssertEqual(.basalOverInfusionPulse, decoded.faultEventCode.faultType) - XCTAssertEqual(0, decoded.unacknowledgedAlerts.rawValue) - XCTAssertEqual(TimeInterval(minutes: 0x09ff), decoded.faultEventTimeSinceActivation) - XCTAssertEqual("1 day plus 18:39", decoded.faultEventTimeSinceActivation?.stringValue) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, decoded.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 0x0a02), decoded.timeActive) - XCTAssertEqual(false, decoded.faultAccessingTables) - XCTAssertEqual(false, decoded.errorEventInfo?.insulinStateTableCorruption) - XCTAssertEqual(0, decoded.errorEventInfo?.occlusionType) - XCTAssertEqual(false, decoded.errorEventInfo?.immediateBolusInProgress) - XCTAssertEqual(.aboveFiftyUnits, decoded.errorEventInfo?.podProgressStatus) - XCTAssertEqual(0b00, decoded.receiverLowGain) - XCTAssertEqual(0x23, decoded.radioRSSI) - XCTAssertEqual(.aboveFiftyUnits, decoded.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoFaultEventCheckAboveThreshold() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 0d 00 0000 04 07eb 6a 0e0c 03ff 0e14 00 00 28 17 08 0000 - do { - // Decode - let decoded = try DetailedStatus(encodedData: Data(hexadecimalString: "020d0000000407eb6a0e0c03ff0e1400002817080000")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - XCTAssertEqual(.faultEventOccurred, decoded.podProgressStatus) - XCTAssertEqual(.suspended, decoded.deliveryStatus) - XCTAssertEqual(0, decoded.bolusNotDelivered) - XCTAssertEqual(4, decoded.lastProgrammingMessageSeqNum) - XCTAssertEqual(101.35, decoded.totalInsulinDelivered, accuracy: 0.01) - XCTAssertEqual(.occlusionCheckAboveThreshold, decoded.faultEventCode.faultType) - XCTAssertEqual(0, decoded.unacknowledgedAlerts.rawValue) - XCTAssertEqual(TimeInterval(minutes: 0x0e0c), decoded.faultEventTimeSinceActivation) - XCTAssertEqual("2 days plus 11:56", decoded.faultEventTimeSinceActivation?.stringValue) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, decoded.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 0x0e14), decoded.timeActive) - XCTAssertEqual(false, decoded.faultAccessingTables) - XCTAssertEqual(false, decoded.errorEventInfo?.insulinStateTableCorruption) - XCTAssertEqual(1, decoded.errorEventInfo?.occlusionType) - XCTAssertEqual(false, decoded.errorEventInfo?.immediateBolusInProgress) - XCTAssertEqual(.aboveFiftyUnits, decoded.errorEventInfo?.podProgressStatus) - XCTAssertEqual(0b00, decoded.receiverLowGain) - XCTAssertEqual(0x17, decoded.radioRSSI) - XCTAssertEqual(.aboveFiftyUnits, decoded.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoFaultEventBolusNotDelivered() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 0f 00 0001 02 00ec 6a 0268 03ff 026b 00 00 28 a7 08 2023 - do { - // Decode - let decoded = try DetailedStatus(encodedData: Data(hexadecimalString: "020f0000010200ec6a026803ff026b000028a7082023")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - XCTAssertEqual(.inactive, decoded.podProgressStatus) - XCTAssertEqual(.suspended, decoded.deliveryStatus) - XCTAssertEqual(0.05, decoded.bolusNotDelivered) - XCTAssertEqual(2, decoded.lastProgrammingMessageSeqNum) - XCTAssertEqual(11.8, decoded.totalInsulinDelivered, accuracy: 0.01) - XCTAssertEqual(.occlusionCheckAboveThreshold, decoded.faultEventCode.faultType) - XCTAssertEqual(0, decoded.unacknowledgedAlerts.rawValue) - XCTAssertEqual(TimeInterval(minutes: 0x0268), decoded.faultEventTimeSinceActivation) - XCTAssertEqual("10:16", decoded.faultEventTimeSinceActivation?.stringValue) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, decoded.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 0x026b), decoded.timeActive) - XCTAssertEqual(false, decoded.faultAccessingTables) - XCTAssertEqual(false, decoded.errorEventInfo?.insulinStateTableCorruption) - XCTAssertEqual(1, decoded.errorEventInfo?.occlusionType) - XCTAssertEqual(false, decoded.errorEventInfo?.immediateBolusInProgress) - XCTAssertEqual(.aboveFiftyUnits, decoded.errorEventInfo?.podProgressStatus) - XCTAssertEqual(0b10, decoded.receiverLowGain) - XCTAssertEqual(0x27, decoded.radioRSSI) - XCTAssertEqual(.aboveFiftyUnits, decoded.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoFaultEventResetDueToLowVoltageDetect() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 0D 00 0000 00 0000 12 FFFF 03FF 0016 00 00 87 9A 07 0000 - do { - // Decode - let decoded = try DetailedStatus(encodedData: Data(hexadecimalString: "020D00000000000012FFFF03FF00160000879A070000")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - XCTAssertEqual(.faultEventOccurred, decoded.podProgressStatus) - XCTAssertEqual(.suspended, decoded.deliveryStatus) - XCTAssertEqual(0.00, decoded.bolusNotDelivered) - XCTAssertEqual(0, decoded.lastProgrammingMessageSeqNum) - XCTAssertEqual(0.00, decoded.totalInsulinDelivered, accuracy: 0.01) - XCTAssertEqual(.resetDueToLVD, decoded.faultEventCode.faultType) - XCTAssertNil(decoded.faultEventTimeSinceActivation) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, decoded.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 0x16), decoded.timeActive) - XCTAssertEqual(0, decoded.unacknowledgedAlerts.rawValue) - XCTAssertEqual(false, decoded.faultAccessingTables) - XCTAssertEqual(true, decoded.errorEventInfo?.insulinStateTableCorruption) - XCTAssertEqual(0, decoded.errorEventInfo?.occlusionType) - XCTAssertEqual(false, decoded.errorEventInfo?.immediateBolusInProgress) - XCTAssertEqual(.insertingCannula, decoded.errorEventInfo?.podProgressStatus) - XCTAssertEqual(0b10, decoded.receiverLowGain) - XCTAssertEqual(0x1A, decoded.radioRSSI) - XCTAssertEqual(.insertingCannula, decoded.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoPulseLogPlusPartial() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 - // 02 LL // 03 PP QQQQ SSSS 04 3c XXXXXXXX ... - // 02 e4 // 03 00 0000 0003 04 3c 00622a80 01612980 00612480 01602680 00611f00 01601a00 00611f00 01602600 00602000 01602600 00602200 01612700 00602000 01602500 00602000 01612500 00612180 01612680 00612080 01612780 00612080 01602680 00612080 01602580 00612080 05612500 08602000 0d612600 10602200 15602800 18612100 1d602800 20602100 25612700 28612100 2d602800 30612200 35602800 38602400 3d602700 40612400 45612c80 48612680 4d602d80 00602780 05632b80 08612680 0d602c80 10612580 15602d80 18602300 1d612100 20612200 25612900 28602300 - do { - let decoded = try PodInfoPulseLogPlus(encodedData: Data(hexadecimalString: "030000000003043c00622a8001612980006124800160268000611f0001601a0000611f0001602600006020000160260000602200016127000060200001602500006020000161250000612180016126800061208001612780006120800160268000612080016025800061208005612500086020000d6126001060220015602800186121001d6028002060210025612700286121002d6028003061220035602800386024003d6027004061240045612c80486126804d602d800060278005632b80086126800d602c801061258015602d80186023001d612100206122002561290028602300")!) - XCTAssertEqual(.pulseLogPlus, decoded.podInfoType) - XCTAssertEqual(.noFaults, decoded.faultEventCode.faultType) - XCTAssertEqual(0000*60, decoded.timeFaultEvent) - XCTAssertEqual(0003*60, decoded.timeActivation) - XCTAssertEqual(4, decoded.entrySize) - XCTAssertEqual(0x3c, decoded.maxEntries) - XCTAssertEqual(0x00622a80, decoded.pulseLog[0]) - XCTAssertEqual(0x01602600, decoded.pulseLog[9]) - XCTAssertEqual(0x01612780, decoded.pulseLog[19]) - XCTAssertEqual(0x15602800, decoded.pulseLog[29]) - XCTAssertEqual(0x3d602700, decoded.pulseLog[39]) - XCTAssertEqual(0x15602d80, decoded.pulseLog[49]) - XCTAssertEqual(0x28602300, decoded.pulseLog[54]) - XCTAssertEqual(55, decoded.nEntries) // a calculated value that is not directly in raw hex data - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoPulseLogPlus() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 - // 02 LL // 03 PP QQQQ SSSS 04 3c XXXXXXXX ... - // 02 f8 // 03 00 0000 0075 04 3c 54402600 59402d80 5c412480 61402d80 00412380 05402d80 08402780 0d402c80 10412480 15412b80 18412400 1d402800 20402400 25412c00 28412500 2d412b00 30402700 35412d00 38402600 3d412c00 40412500 45402c00 48402400 4d412c00 50412400 55412e00 58412680 5d402f80 60402680 01402f80 04402680 09412e80 0c402580 11402e80 14402780 19402e00 1c402400 21412d00 24402600 29412f00 2c412600 31643000 34622600 39623000 3c622600 41622f00 44622600 49622e00 4c632600 51632d00 54602800 59413080 5c412780 61403180 00402880 05413080 08402780 0d413180 10412680 15412f80 - do { - let decoded = try PodInfoPulseLogPlus(encodedData: Data(hexadecimalString: "030000000075043c5440260059402d805c41248061402d800041238005402d80084027800d402c801041248015412b80184124001d4028002040240025412c00284125002d412b003040270035412d00384026003d412c004041250045402c00484024004d412c005041240055412e00584126805d402f806040268001402f800440268009412e800c40258011402e801440278019402e001c40240021412d002440260029412f002c4126003164300034622600396230003c62260041622f004462260049622e004c63260051632d0054602800594130805c412780614031800040288005413080084027800d4131801041268015412f80")!) - XCTAssertEqual(.pulseLogPlus, decoded.podInfoType) - XCTAssertEqual(.noFaults, decoded.faultEventCode.faultType) - XCTAssertEqual(TimeInterval(minutes: 0x0000), decoded.timeFaultEvent) - XCTAssertEqual(TimeInterval(minutes: 0x0075), decoded.timeActivation) - XCTAssertEqual(4, decoded.entrySize) - XCTAssertEqual(0x3c, decoded.maxEntries) - XCTAssertEqual(0x54402600, decoded.pulseLog[0]) - XCTAssertEqual(0x15412b80, decoded.pulseLog[9]) - XCTAssertEqual(0x3d412c00, decoded.pulseLog[19]) - XCTAssertEqual(0x01402f80, decoded.pulseLog[29]) - XCTAssertEqual(0x29412f00, decoded.pulseLog[39]) - XCTAssertEqual(0x51632d00, decoded.pulseLog[49]) - XCTAssertEqual(0x15412f80, decoded.pulseLog[59]) - XCTAssertEqual(0x3c, decoded.nEntries) // a calculated value - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoActivationTime() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 91011 1213141516 - // 02 11 // 05 PP QQQQ 00000000 00000000 MMDDYYHHMM - // 02 11 // 05 92 0001 00000000 00000000 091912170e - // 09-25-18 23:14 int values for datetime - do { - // Decode - let decoded = try PodInfoActivationTime(encodedData: Data(hexadecimalString: "059200010000000000000000091912170e")!) - XCTAssertEqual(.activationTime, decoded.podInfoType) - XCTAssertEqual(.tempPulseChanInactive, decoded.faultEventCode.faultType) - XCTAssertEqual(TimeInterval(minutes: 0x0001), decoded.timeActivation) - let decodedDateTime = decoded.dateTime - XCTAssertEqual(2018, decodedDateTime.year) - XCTAssertEqual(09, decodedDateTime.month) - XCTAssertEqual(25, decodedDateTime.day) - XCTAssertEqual(23, decodedDateTime.hour) - XCTAssertEqual(14, decodedDateTime.minute) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoPulseLogRecent() { - //02 cb 50 0086 34212e00 39203100 3c212d00 41203000 44202c00 49212e00 4c212b00 51202f00 54212c00 59203080 5c202d80 61203080 00212e80 05213180 08202f80 0d203280 10202f80 15213180 18202f80 1d213180 20202e80 25213300 28203200 2d213500 30213100 35213400 38213100 3d203500 40203100 45213300 48203000 4d213200 50212f00 55203300 58203080 5d213280 60202f80 01203080 04202c80 09213180 0c213080 11213280 14203180 19213380 1c203180 21203280 24213200 29203500 2c213100 31213400" - do { - // Decode - let decoded = try PodInfoPulseLogRecent(encodedData: Data(hexadecimalString: "50008634212e00392031003c212d004120300044202c0049212e004c212b0051202f0054212c00592030805c202d806120308000212e800521318008202f800d20328010202f801521318018202f801d21318020202e8025213300282032002d2135003021310035213400382131003d2035004020310045213300482030004d21320050212f0055203300582030805d21328060202f800120308004202c80092131800c2130801121328014203180192133801c2031802120328024213200292035002c21310031213400")!) - XCTAssertEqual(.pulseLogRecent, decoded.podInfoType) - XCTAssertEqual(134, decoded.indexLastEntry) - XCTAssertEqual(0x34212e00, decoded.pulseLog[0]) - XCTAssertEqual(0x59203080, decoded.pulseLog[9]) - XCTAssertEqual(0x1d213180, decoded.pulseLog[19]) - XCTAssertEqual(0x45213300, decoded.pulseLog[29]) - XCTAssertEqual(0x09213180, decoded.pulseLog[39]) - XCTAssertEqual(0x31213400, decoded.pulseLog[49]) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoPulseLogPrevious() { - //02 cb 51 0032 14602500 19612800 1c612400 21612800 24612500 29612900 2c602600 31602a00 34602600 39612a80 3c612680 41602c80 00602780 05632880 08602580 0d612880 10612580 15612780 18602380 1d602680 20612280 25602700 28612400 2d212800 30202700 35202a00 38202700 3d202a00 40202900 45202c00 48202a00 4d212c00 50212900 55212c00 58212980 5d202b80 60202880 01202d80 04212a80 09202d80 0c212980 11212a80 14212980 1921801c 212a8021 212c8024 202c0029 212f002c 212d0031 20310082 - do { - // Decode - let decoded = try PodInfoPulseLogPrevious(encodedData: Data(hexadecimalString: "51003214602500196128001c6124002161280024612500296129002c60260031602a003460260039612a803c61268041602c800060278005632880086025800d6128801061258015612780186023801d6026802061228025602700286124002d2128003020270035202a00382027003d202a004020290045202c0048202a004d212c005021290055212c00582129805d202b806020288001202d8004212a8009202d800c21298011212a80142129801921801c212a8021212c8024202c0029212f002c212d003120310082")!) - XCTAssertEqual(.pulseLogPrevious, decoded.podInfoType) - XCTAssertEqual(50, decoded.nEntries) - XCTAssertEqual(0x14602500, decoded.pulseLog[0]) - XCTAssertEqual(0x39612a80, decoded.pulseLog[9]) - XCTAssertEqual(0x1d602680, decoded.pulseLog[19]) - XCTAssertEqual(0x45202c00, decoded.pulseLog[29]) - XCTAssertEqual(0x09202d80, decoded.pulseLog[39]) - XCTAssertEqual(0x20310082, decoded.pulseLog[49]) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodFault12() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 0d 00 0000 00 0000 12 ffff 03ff 0000 00 00 87 92 07 0000 - do { - // Decode - let faultEvent = try DetailedStatus(encodedData: Data(hexadecimalString: "020d00000000000012ffff03ff000000008792070000")!) - XCTAssertEqual(.detailedStatus, faultEvent.podInfoType) - XCTAssertEqual(.faultEventOccurred, faultEvent.podProgressStatus) - XCTAssertEqual(.suspended, faultEvent.deliveryStatus) - XCTAssertEqual(0.00, faultEvent.bolusNotDelivered) - XCTAssertEqual(0, faultEvent.lastProgrammingMessageSeqNum) - XCTAssertEqual(0.00, faultEvent.totalInsulinDelivered, accuracy: 0.01) - XCTAssertEqual(.resetDueToLVD, faultEvent.faultEventCode.faultType) - XCTAssertNil(faultEvent.faultEventTimeSinceActivation) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, faultEvent.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 0x0000), faultEvent.timeActive) - XCTAssertEqual(0, faultEvent.unacknowledgedAlerts.rawValue) - XCTAssertEqual(false, faultEvent.faultAccessingTables) - XCTAssertEqual(true, faultEvent.errorEventInfo?.insulinStateTableCorruption) - XCTAssertEqual(0, faultEvent.errorEventInfo?.occlusionType) - XCTAssertEqual(false, faultEvent.errorEventInfo?.immediateBolusInProgress) - XCTAssertEqual(.insertingCannula, faultEvent.errorEventInfo?.podProgressStatus) - XCTAssertEqual(0b10, faultEvent.receiverLowGain) - XCTAssertEqual(0x12, faultEvent.radioRSSI) - XCTAssertEqual(.insertingCannula, faultEvent.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLETests/PodStateTests.swift b/Dependencies/OmniBLE/OmniBLETests/PodStateTests.swift deleted file mode 100644 index c3e12aef5..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/PodStateTests.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// PodStateTests.swift -// OmniBLE -// -// Created by Pete Schwamb on 10/13/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// From OmniKitTests/PodStateTests.swift -// - -import XCTest -@testable import OmniBLE - -class PodStateTests: XCTestCase { - - func testErrorResponse() { - do { - let errorResponse = try ErrorResponse(encodedData: Data(hexadecimalString: "0603070008019a")!) - - switch errorResponse.errorResponseType { - case .nonretryableError(let errorCode, let faultEventCode, let podProgress): - XCTAssertEqual(7, errorCode) - XCTAssertEqual(.noFaults, faultEventCode.faultType) - XCTAssertEqual(.aboveFiftyUnits, podProgress) - break - default: - XCTFail("Unexpected bad nonce response") - break - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } -} - diff --git a/Dependencies/OmniBLE/OmniBLETests/StatusTests.swift b/Dependencies/OmniBLE/OmniBLETests/StatusTests.swift deleted file mode 100644 index 96179d41b..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/StatusTests.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// StatusTests.swift -// OmniBLE -// -// Created by Eelke Jager on 08/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// From OmniKitTests/StatusTests.swift -// -import Foundation - -import XCTest -@testable import OmniBLE - -class StatusTests: XCTestCase { - - func testStatusRequestCommand() { - // 0e 01 00 - do { - // Encode - let encoded = GetStatusCommand(podInfoType: .normal) - XCTAssertEqual("0e0100", encoded.data.hexadecimalString) - - // Decode - let decoded = try GetStatusCommand(encodedData: Data(hexadecimalString: "0e0100")!) - XCTAssertEqual(.normal, decoded.podInfoType) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testStatusResponse46UnitsLeft() { - /// 1d19050ec82c08376f9801dc - do { - // Decode - let decoded = try StatusResponse(encodedData: Data(hexadecimalString: "1d19050ec82c08376f9801dc")!) - XCTAssertEqual(TimeInterval(minutes: 3547), decoded.timeActive) - XCTAssertEqual(.scheduledBasal, decoded.deliveryStatus) - XCTAssertEqual(.fiftyOrLessUnits, decoded.podProgressStatus) - XCTAssertEqual(129.45, decoded.insulinDelivered, accuracy: 0.01) - XCTAssertEqual(46.00, decoded.reservoirLevel) - XCTAssertEqual(2.2, decoded.bolusNotDelivered) - XCTAssertEqual(9, decoded.lastProgrammingMessageSeqNum) - //XCTAssert(,decoded.alarms) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testStatusRequestCommandConfiguredAlerts() { - // 0e 01 01 - do { - // Encode - let encoded = GetStatusCommand(podInfoType: .configuredAlerts) - XCTAssertEqual("0e0101", encoded.data.hexadecimalString) - - // Decode - let decoded = try GetStatusCommand(encodedData: Data(hexadecimalString: "0e0101")!) - XCTAssertEqual(.configuredAlerts, decoded.podInfoType) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testStatusRequestCommandFaultEvents() { - // 0e 01 02 - do { - // Encode - let encoded = GetStatusCommand(podInfoType: .detailedStatus) - XCTAssertEqual("0e0102", encoded.data.hexadecimalString) - - // Decode - let decoded = try GetStatusCommand(encodedData: Data(hexadecimalString: "0e0102")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } -} diff --git a/Dependencies/OmniBLE/OmniBLETests/TempBasalTests.swift b/Dependencies/OmniBLE/OmniBLETests/TempBasalTests.swift deleted file mode 100644 index b57619865..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/TempBasalTests.swift +++ /dev/null @@ -1,363 +0,0 @@ -// -// TempBasalTests.swift -// OmniBLE -// -// Created by Pete Schwamb on 6/5/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// From OmniKitTests/TempBasalTests.swift -// - -import Foundation - -import XCTest -@testable import OmniBLE - -class TempBasalTests: XCTestCase { - - func testAlternatingSegmentFlag() { - // Encode 0.05U/hr 30mins - let cmd = SetInsulinScheduleCommand(nonce: 0x9746c65b, tempBasalRate: 0.05, duration: .hours(0.5)) - // 1a 0e 9746c65b 01 0079 01 3840 0000 0000 - XCTAssertEqual("1a0e9746c65b01007901384000000000", cmd.data.hexadecimalString) - - // Encode 0.05U/hr 8.5hours - let cmd2 = SetInsulinScheduleCommand(nonce: 0x9746c65b, tempBasalRate: 0.05, duration: .hours(8.5)) - // 1a 10 9746c65b 01 0091 11 3840 0000 f800 0000 - XCTAssertEqual("1a109746c65b0100911138400000f8000000", cmd2.data.hexadecimalString) - - // Encode 0.05U/hr 16.5hours - let cmd3 = SetInsulinScheduleCommand(nonce: 0x9746c65b, tempBasalRate: 0.05, duration: .hours(16.5)) - // 1a 12 9746c65b 01 00a9 21 3840 0000 f800 f800 0000 - XCTAssertEqual("1a129746c65b0100a92138400000f800f8000000", cmd3.data.hexadecimalString) - } - - func testTempBasalThreeTenthsUnitPerHour() { - let cmd = SetInsulinScheduleCommand(nonce: 0xeac79411, tempBasalRate: 0.3, duration: .hours(0.5)) - XCTAssertEqual("1a0eeac7941101007f01384000030003", cmd.data.hexadecimalString) - } - - func testSetTempBasalCommand() { - do { - // Decode 1a 0e ea2d0a3b 01 007d 01 3840 0002 0002 - // 1a 0e 9746c65b 01 0079 01 3840 0000 0000 160e7c00000515752a - let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a0eea2d0a3b01007d01384000020002")!) - - XCTAssertEqual(0xea2d0a3b, cmd.nonce) - if case SetInsulinScheduleCommand.DeliverySchedule.tempBasal(let secondsRemaining, let firstSegmentPulses, let table) = cmd.deliverySchedule { - - XCTAssertEqual(1800, secondsRemaining) - XCTAssertEqual(2, firstSegmentPulses) - let entry = table.entries[0] - XCTAssertEqual(1, entry.segments) - XCTAssertEqual(2, entry.pulses) - } else { - XCTFail("Expected ScheduleEntry.tempBasal type") - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = SetInsulinScheduleCommand(nonce: 0xea2d0a3b, tempBasalRate: 0.20, duration: .hours(0.5)) - XCTAssertEqual("1a0eea2d0a3b01007d01384000020002", cmd.data.hexadecimalString) - } - - func testSetTempBasalWithAlternatingPulse() { - do { - // 0.05U/hr for 2.5 hours - // Decode 1a 0e 4e2c2717 01 007f 05 3840 0000 4800 - let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a0e4e2c271701007f05384000004800")!) - - XCTAssertEqual(0x4e2c2717, cmd.nonce) - if case SetInsulinScheduleCommand.DeliverySchedule.tempBasal(let secondsRemaining, let firstSegmentPulses, let table) = cmd.deliverySchedule { - - XCTAssertEqual(1800, secondsRemaining) - XCTAssertEqual(0, firstSegmentPulses) - XCTAssertEqual(1, table.entries.count) - XCTAssertEqual(5, table.entries[0].segments) - XCTAssertEqual(0, table.entries[0].pulses) - XCTAssertEqual(true, table.entries[0].alternateSegmentPulse) - } else { - XCTFail("Expected ScheduleEntry.tempBasal type") - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = SetInsulinScheduleCommand(nonce: 0x4e2c2717, tempBasalRate: 0.05, duration: .hours(2.5)) - XCTAssertEqual("1a0e4e2c271701007f05384000004800", cmd.data.hexadecimalString) - } - - func testLargerTempBasalCommand() { - do { - // 2.00 U/h for 1.5h - // Decode 1a 0e 87e8d03a 01 00cb 03 3840 0014 2014 - let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a0e87e8d03a0100cb03384000142014")!) - - XCTAssertEqual(0x87e8d03a, cmd.nonce) - if case SetInsulinScheduleCommand.DeliverySchedule.tempBasal(let secondsRemaining, let firstSegmentPulses, let table) = cmd.deliverySchedule { - - XCTAssertEqual(1800, secondsRemaining) - XCTAssertEqual(0x14, firstSegmentPulses) - let entry = table.entries[0] - XCTAssertEqual(3, entry.segments) - XCTAssertEqual(20, entry.pulses) - } else { - XCTFail("Expected ScheduleEntry.tempBasal type") - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = SetInsulinScheduleCommand(nonce: 0x87e8d03a, tempBasalRate: 2, duration: .hours(1.5)) - XCTAssertEqual("1a0e87e8d03a0100cb03384000142014", cmd.data.hexadecimalString) - } - - func testCancelTempBasalCommand() { - do { - // Decode 1f 05 f76d34c4 62 - let cmd = try CancelDeliveryCommand(encodedData: Data(hexadecimalString: "1f05f76d34c462")!) - XCTAssertEqual(0xf76d34c4, cmd.nonce) - XCTAssertEqual(.beeeeeep, cmd.beepType) - XCTAssertEqual(.tempBasal, cmd.deliveryType) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = CancelDeliveryCommand(nonce: 0xf76d34c4, deliveryType: .tempBasal, beepType: .beeeeeep) - XCTAssertEqual("1f05f76d34c462", cmd.data.hexadecimalString) - } - - func testCancelTempBasalnoBeepCommand() { - do { - let cmd = try CancelDeliveryCommand(encodedData: Data(hexadecimalString: "1f05f76d34c402")!) - XCTAssertEqual(0xf76d34c4, cmd.nonce) - XCTAssertEqual(.noBeepCancel, cmd.beepType) - XCTAssertEqual(.tempBasal, cmd.deliveryType) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = CancelDeliveryCommand(nonce: 0xf76d34c4, deliveryType: .tempBasal, beepType: .noBeepCancel) - XCTAssertEqual("1f05f76d34c402", cmd.data.hexadecimalString) - } - - func testDashZeroTempExtraCommand() { - do { - // 0 U/h for 0.5 hours - // 16 LL RR MM NNNN XXXXXXXX YYYY ZZZZZZZZ - // Decode 16 0e 7c 00 0001 6b49d200 0001 eb49d200 - - let cmd = try TempBasalExtraCommand(encodedData: Data(hexadecimalString: "160e7c0000016b49d2000001eb49d200")!) - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(true, cmd.completionBeep) - XCTAssertEqual(.minutes(60), cmd.programReminderInterval) - XCTAssertEqual(TimeInterval(hours: 5), cmd.delayUntilFirstPulse) - XCTAssertEqual(0.10, cmd.remainingPulses, accuracy: 0.01) - XCTAssertEqual(1, cmd.rateEntries.count) - let entry = cmd.rateEntries[0] - XCTAssertEqual(0.1, entry.totalPulses) - XCTAssertEqual(TimeInterval(hours: 5), entry.delayBetweenPulses) - XCTAssertEqual(TimeInterval(minutes: 30), entry.duration) - XCTAssertEqual(0.01, entry.rate) - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = TempBasalExtraCommand(rate: 0, duration: .hours(0.5), acknowledgementBeep: false, completionBeep: true, programReminderInterval: .minutes(60)) - XCTAssertEqual("160e7c0000016b49d2000001eb49d200", cmd.data.hexadecimalString) - } - - func testDashZeroTempThreeHoursExtraCommand() { - do { - // 0 U/h for 3 hours - // 16 LL RR MM NNNN XXXXXXXX YYYY ZZZZZZZZ - // Decode 16 0e 7c 00 0006 6b49d200 0006 eb49d200 - let cmd = try TempBasalExtraCommand(encodedData: Data(hexadecimalString: "160e7c0000066b49d2000006eb49d2008180")!) - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(true, cmd.completionBeep) - XCTAssertEqual(.minutes(60), cmd.programReminderInterval) - XCTAssertEqual(TimeInterval(hours: 5), cmd.delayUntilFirstPulse) - XCTAssertEqual(0.6, cmd.remainingPulses) - XCTAssertEqual(1, cmd.rateEntries.count) - let entry = cmd.rateEntries[0] - XCTAssertEqual(0.6, entry.totalPulses) - XCTAssertEqual(TimeInterval(hours: 5), entry.delayBetweenPulses) - XCTAssertEqual(TimeInterval(hours: 3), entry.duration) - XCTAssertEqual(0.01, entry.rate) - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = TempBasalExtraCommand(rate: 0, duration: .hours(3), acknowledgementBeep: false, completionBeep: true, programReminderInterval: .minutes(60)) - XCTAssertEqual("160e7c0000066b49d2000006eb49d200", cmd.data.hexadecimalString) - } - - func testDashZeroTempTwelveHoursExtraCommand() { - do { - // 0 U/h for 12 hours - // 16 LL RR MM NNNN XXXXXXXX YYYY ZZZZZZZZ - // Decode 16 0e 7c 00 0018 6b49d200 0018 eb49d200 - let cmd = try TempBasalExtraCommand(encodedData: Data(hexadecimalString: "160e7c0000186b49d2000018eb49d200")!) - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(true, cmd.completionBeep) - XCTAssertEqual(.minutes(60), cmd.programReminderInterval) - XCTAssertEqual(TimeInterval(hours: 5), cmd.delayUntilFirstPulse) - XCTAssertEqual(2.4, cmd.remainingPulses) - XCTAssertEqual(1, cmd.rateEntries.count) - let entry = cmd.rateEntries[0] - XCTAssertEqual(2.4, entry.totalPulses) - XCTAssertEqual(TimeInterval(hours: 5), entry.delayBetweenPulses) - XCTAssertEqual(TimeInterval(hours: 12), entry.duration) - XCTAssertEqual(0.01, entry.rate) - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = TempBasalExtraCommand(rate: 0, duration: .hours(12), acknowledgementBeep: false, completionBeep: true, programReminderInterval: .minutes(60)) - XCTAssertEqual("160e7c0000186b49d2000018eb49d200", cmd.data.hexadecimalString) - } - - func testTempBasalExtremeValues() { - do { - // 30 U/h for 12 hours - // Decode 1a 10 a958c5ad 01 04f5 18 3840 012c f12c 712c - let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a10a958c5ad0104f5183840012cf12c712c")!) - - XCTAssertEqual(0xa958c5ad, cmd.nonce) - if case SetInsulinScheduleCommand.DeliverySchedule.tempBasal(let secondsRemaining, let firstSegmentPulses, let table) = cmd.deliverySchedule { - - XCTAssertEqual(1800, secondsRemaining) - XCTAssertEqual(300, firstSegmentPulses) - XCTAssertEqual(2, table.entries.count) - let entry1 = table.entries[0] - XCTAssertEqual(16, entry1.segments) - XCTAssertEqual(300, entry1.pulses) - let entry2 = table.entries[1] - XCTAssertEqual(8, entry2.segments) - XCTAssertEqual(300, entry2.pulses) - } else { - XCTFail("Expected ScheduleEntry.tempBasal type") - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = SetInsulinScheduleCommand(nonce: 0xa958c5ad, tempBasalRate: 30, duration: .hours(12)) - XCTAssertEqual("1a10a958c5ad0104f5183840012cf12c712c", cmd.data.hexadecimalString) - } - - func testTempBasalExtraCommand() { - do { - // 30 U/h for 0.5 hours - // 16 LL RR MM NNNN XXXXXXXX YYYY ZZZZZZZZ - // Decode 16 0e 7c 00 0bb8 000927c0 0bb8 000927c0 - let cmd = try TempBasalExtraCommand(encodedData: Data(hexadecimalString: "160e7c000bb8000927c00bb8000927c0")!) - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(true, cmd.completionBeep) - XCTAssertEqual(.minutes(60), cmd.programReminderInterval) - XCTAssertEqual(TimeInterval(seconds: 6), cmd.delayUntilFirstPulse) - XCTAssertEqual(300, cmd.remainingPulses) - XCTAssertEqual(1, cmd.rateEntries.count) - let entry = cmd.rateEntries[0] - XCTAssertEqual(TimeInterval(seconds: 6), entry.delayBetweenPulses) - XCTAssertEqual(TimeInterval(minutes: 30), entry.duration) - XCTAssertEqual(30, entry.rate) - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = TempBasalExtraCommand(rate: 30, duration: .hours(0.5), acknowledgementBeep: false, completionBeep: true, programReminderInterval: .minutes(60)) - XCTAssertEqual("160e7c000bb8000927c00bb8000927c0", cmd.data.hexadecimalString) - } - - func testBasalExtraCommandForOddPulseCountRate() { - - let cmd1 = TempBasalExtraCommand(rate: 0.05, duration: .hours(0.5), acknowledgementBeep: false, completionBeep: true, programReminderInterval: .minutes(60)) - XCTAssertEqual("160e7c00000515752a00000515752a00", cmd1.data.hexadecimalString) - - let cmd2 = TempBasalExtraCommand(rate: 2.05, duration: .hours(0.5), acknowledgementBeep: false, completionBeep: false, programReminderInterval: .minutes(60)) - XCTAssertEqual("160e3c0000cd0085fac700cd0085fac7", cmd2.data.hexadecimalString) - - let cmd3 = TempBasalExtraCommand(rate: 2.10, duration: .hours(0.5), acknowledgementBeep: false, completionBeep: false, programReminderInterval: .minutes(60)) - XCTAssertEqual("160e3c0000d20082ca2400d20082ca24", cmd3.data.hexadecimalString) - - let cmd4 = TempBasalExtraCommand(rate: 2.15, duration: .hours(0.5), acknowledgementBeep: false, completionBeep: false, programReminderInterval: .minutes(60)) - XCTAssertEqual("160e3c0000d7007fbf7d00d7007fbf7d", cmd4.data.hexadecimalString) - } - - func testBasalExtraCommandPulseCount() { - // 16 LL RR MM NNNN XXXXXXXX YYYY ZZZZZZZZ YYYY ZZZZZZZZ - // 16 14 00 00 f5b9 000a0ad7 f5b9 000a0ad7 0aaf 000a0ad7 - let cmd2 = TempBasalExtraCommand(rate: 27.35, duration: .hours(12), acknowledgementBeep: false, completionBeep: false, programReminderInterval: 0) - XCTAssertEqual("16140000f5b9000a0ad7f5b9000a0ad70aaf000a0ad7", cmd2.data.hexadecimalString) - } - - func testTempBasalExtraCommandExtremeValues() { - do { - // 30 U/h for 12 hours - // 16 LL BO MM NNNN XXXXXXXX YYYY ZZZZZZZZ YYYY ZZZZZZZZ - // Decode 16 14 3c 00 f618 000927c0 f618 000927c0 2328 000927c0 - let cmd = try TempBasalExtraCommand(encodedData: Data(hexadecimalString: "16143c00f618000927c0f618000927c02328000927c0")!) - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(false, cmd.completionBeep) - XCTAssertEqual(.minutes(60), cmd.programReminderInterval) - XCTAssertEqual(TimeInterval(seconds: 6), cmd.delayUntilFirstPulse) - XCTAssertEqual(6300, cmd.remainingPulses) - XCTAssertEqual(2, cmd.rateEntries.count) - let entry1 = cmd.rateEntries[0] - XCTAssertEqual(TimeInterval(seconds: 6), entry1.delayBetweenPulses) - XCTAssertEqual(TimeInterval(hours: 10.5), entry1.duration) - XCTAssertEqual(30, entry1.rate) - let entry2 = cmd.rateEntries[1] - XCTAssertEqual(TimeInterval(seconds: 6), entry2.delayBetweenPulses) - XCTAssertEqual(TimeInterval(hours: 1.5), entry2.duration) - XCTAssertEqual(30, entry2.rate) - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = TempBasalExtraCommand(rate: 30, duration: .hours(12), acknowledgementBeep: false, completionBeep: false, programReminderInterval: .minutes(60)) - XCTAssertEqual("16143c00f618000927c0f618000927c02328000927c0", cmd.data.hexadecimalString) - } - - func testTempBasalExtraCommandExtremeValues2() { - do { - // 29.95 U/h for 12 hours - // 16 LL BO MM NNNN XXXXXXXX YYYY ZZZZZZZZ YYYY ZZZZZZZZ - // Decode 16 14 3c 00 f5af 00092ba9 f5af 00092ba9 2319 00092ba9 - let cmd = try TempBasalExtraCommand(encodedData: Data(hexadecimalString: "16143c00f5af00092ba9f5af00092ba9231900092ba9")!) - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(false, cmd.completionBeep) - XCTAssertEqual(.minutes(60), cmd.programReminderInterval) - XCTAssertEqual(TimeInterval(seconds: 6.01001), cmd.delayUntilFirstPulse) - XCTAssertEqual(6289.5, cmd.remainingPulses) - XCTAssertEqual(2, cmd.rateEntries.count) - let entry1 = cmd.rateEntries[0] - let entry2 = cmd.rateEntries[1] - XCTAssertEqual(TimeInterval(seconds: 6.01001), entry1.delayBetweenPulses, accuracy: .ulpOfOne) - XCTAssertEqual(TimeInterval(hours: 12), entry1.duration + entry2.duration, accuracy: 1) - XCTAssertEqual(29.95, entry1.rate, accuracy: 0.025) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - let cmd = TempBasalExtraCommand(rate: 29.95, duration: .hours(12), acknowledgementBeep: false, completionBeep: false, programReminderInterval: .minutes(60)) - XCTAssertEqual("16143c00f5af00092ba9f5af00092ba9231900092ba9", cmd.data.hexadecimalString) - } -} diff --git a/Dependencies/OmniBLE/OmniBLETests/TestUtilities.swift b/Dependencies/OmniBLE/OmniBLETests/TestUtilities.swift deleted file mode 100644 index 533046e8f..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/TestUtilities.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// TestUtilities.swift -// OmniBLE -// -// Created by Bill Gestrich on 12/11/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -extension String { - //From start to, but not including, toIndex - func substring(startIndex _startIndexInt: Int, toIndex _toIndexInt: Int) -> String? { - assert(_startIndexInt < _toIndexInt) - let startIndex = index(self.startIndex, offsetBy: _startIndexInt) - let endIndex = index(self.startIndex, offsetBy: _toIndexInt - 1) - return String(self[startIndex...endIndex]) - } -} diff --git a/Dependencies/OmniBLE/OmniBLETests/ZeroBasalScheduleTest.swift b/Dependencies/OmniBLE/OmniBLETests/ZeroBasalScheduleTest.swift deleted file mode 100644 index a05b8c640..000000000 --- a/Dependencies/OmniBLE/OmniBLETests/ZeroBasalScheduleTest.swift +++ /dev/null @@ -1,217 +0,0 @@ -// -// ZeroBasalScheduleTests.swift -// OmniBLE -// -// Created by Joseph Moran on 03/19/2022. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import XCTest -@testable import OmniBLE - -class ZeroBasalScheduleTests: XCTestCase { - - func checkBasalScheduleExtraCommandDataWithLessPrecision(_ data: Data, _ expected: Data, line: UInt = #line) { - // The XXXXXXXX field is in thousands of a millisecond. Since we use TimeIntervals (floating point) for - // recreating the offset, we can have small errors in reproducing the the encoded output, which we really - // don't care about. - - func extractXXXXXXXX(_ data: Data) -> TimeInterval { - return TimeInterval(Double(data[6...].toBigEndian(UInt32.self)) / 1000000.0) - } - - let xxxxxxxx1 = extractXXXXXXXX(data) - let xxxxxxxx2 = extractXXXXXXXX(expected) - XCTAssertEqual(xxxxxxxx1, xxxxxxxx2, accuracy: 0.01, line: line) - - func blurXXXXXXXX(_ inStr: String) -> String { - let start = inStr.index(inStr.startIndex, offsetBy:12) - let end = inStr.index(start, offsetBy:8) - return inStr.replacingCharacters(in: start.. - - - - diff --git a/Dependencies/OmniKit/OmniKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dependencies/OmniKit/OmniKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Dependencies/OmniKit/OmniKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Dependencies/OmniKit/OmniKit/Extensions/Data.swift b/Dependencies/OmniKit/OmniKit/Extensions/Data.swift deleted file mode 100644 index 8e29be543..000000000 --- a/Dependencies/OmniKit/OmniKit/Extensions/Data.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// Data.swift -// OmniKit -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension Data { - private func toDefaultEndian(_: T.Type) -> T { - return self.withUnsafeBytes({ (rawBufferPointer: UnsafeRawBufferPointer) -> T in - let bufferPointer = rawBufferPointer.bindMemory(to: T.self) - guard let pointer = bufferPointer.baseAddress else { - return 0 - } - return T(pointer.pointee) - }) - } - - func to(_ type: T.Type) -> T { - return T(littleEndian: toDefaultEndian(type)) - } - - func toBigEndian(_ type: T.Type) -> T { - return T(bigEndian: toDefaultEndian(type)) - } - - mutating func append(_ newElement: T) { - var element = newElement.littleEndian - append(Data(bytes: &element, count: element.bitWidth / 8)) - } - - mutating func appendBigEndian(_ newElement: T) { - var element = newElement.bigEndian - append(Data(bytes: &element, count: element.bitWidth / 8)) - } - - init(_ value: T) { - var value = value.littleEndian - self.init(bytes: &value, count: value.bitWidth / 8) - } - - init(bigEndian value: T) { - var value = value.bigEndian - self.init(bytes: &value, count: value.bitWidth / 8) - } -} - -// String conversion methods, adapted from https://stackoverflow.com/questions/40276322/hex-binary-string-conversion-in-swift/40278391#40278391 -extension Data { - init?(hexadecimalString: String) { - self.init(capacity: hexadecimalString.utf16.count / 2) - - // Convert 0 ... 9, a ... f, A ...F to their decimal value, - // return nil for all other input characters - func decodeNibble(u: UInt16) -> UInt8? { - switch u { - case 0x30 ... 0x39: // '0'-'9' - return UInt8(u - 0x30) - case 0x41 ... 0x46: // 'A'-'F' - return UInt8(u - 0x41 + 10) // 10 since 'A' is 10, not 0 - case 0x61 ... 0x66: // 'a'-'f' - return UInt8(u - 0x61 + 10) // 10 since 'a' is 10, not 0 - default: - return nil - } - } - - var even = true - var byte: UInt8 = 0 - for c in hexadecimalString.utf16 { - guard let val = decodeNibble(u: c) else { return nil } - if even { - byte = val << 4 - } else { - byte += val - self.append(byte) - } - even = !even - } - guard even else { return nil } - } - - var hexadecimalString: String { - return map { String(format: "%02hhx", $0) }.joined() - } -} diff --git a/Dependencies/OmniKit/OmniKit/Extensions/HKUnit.swift b/Dependencies/OmniKit/OmniKit/Extensions/HKUnit.swift deleted file mode 100644 index 8311b6c6e..000000000 --- a/Dependencies/OmniKit/OmniKit/Extensions/HKUnit.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// HKUnit.swift -// OmniKit -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import HealthKit - -extension HKUnit { - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: .literUnit(with: .deci)) - }() - - static let millimolesPerLiter: HKUnit = { - return HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: .liter()) - }() - - static let internationalUnitsPerHour: HKUnit = { - return HKUnit.internationalUnit().unitDivided(by: .hour()) - }() - -} diff --git a/Dependencies/OmniKit/OmniKit/Extensions/Notification.swift b/Dependencies/OmniKit/OmniKit/Extensions/Notification.swift deleted file mode 100644 index 96785b37e..000000000 --- a/Dependencies/OmniKit/OmniKit/Extensions/Notification.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// Notification.swift -// OmniKit -// -// Created by Pete Schwamb on 2/22/18. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension Notification.Name { - static let DeviceRadioConfigDidChange = Notification.Name(rawValue: "com.rileylink.RileyLinkKit.DeviceRadioConfigDidChange") -} diff --git a/Dependencies/OmniKit/OmniKit/Extensions/NumberFormatter.swift b/Dependencies/OmniKit/OmniKit/Extensions/NumberFormatter.swift deleted file mode 100644 index 9e5d78895..000000000 --- a/Dependencies/OmniKit/OmniKit/Extensions/NumberFormatter.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// NumberFormatter.swift -// OmniKit -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension NumberFormatter { - func decibleString(from decibles: Int?) -> String? { - if let decibles = decibles, let formatted = string(from: NSNumber(value: decibles)) { - return String(format: LocalizedString("%@ dB", comment: "Unit format string for an RSSI value in decibles"), formatted) - } else { - return nil - } - } - - func string(from number: Double) -> String? { - return string(from: NSNumber(value: number)) - } -} diff --git a/Dependencies/OmniKit/OmniKit/Extensions/OSLog.swift b/Dependencies/OmniKit/OmniKit/Extensions/OSLog.swift deleted file mode 100644 index 4590d796b..000000000 --- a/Dependencies/OmniKit/OmniKit/Extensions/OSLog.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// OSLog.swift -// OmniKit -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import os.log - -extension OSLog { - convenience init(category: String) { - self.init(subsystem: "com.randallknutson.OmniBLE", category: category) - } - - func debug(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .debug, args) - } - - func info(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .info, args) - } - - func `default`(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .default, args) - } - - func error(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .error, args) - } - - private func log(_ message: StaticString, type: OSLogType, _ args: [CVarArg]) { - switch args.count { - case 0: - os_log(message, log: self, type: type) - case 1: - os_log(message, log: self, type: type, args[0]) - case 2: - os_log(message, log: self, type: type, args[0], args[1]) - case 3: - os_log(message, log: self, type: type, args[0], args[1], args[2]) - case 4: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3]) - case 5: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4]) - default: - os_log(message, log: self, type: type, args) - } - } -} diff --git a/Dependencies/OmniKit/OmniKit/Extensions/TimeInterval.swift b/Dependencies/OmniKit/OmniKit/Extensions/TimeInterval.swift deleted file mode 100644 index b2fd35889..000000000 --- a/Dependencies/OmniKit/OmniKit/Extensions/TimeInterval.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// TimeInterval.swift -// OmniKit -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension TimeInterval { - - static func days(_ days: Double) -> TimeInterval { - return self.init(days: days) - } - - static func hours(_ hours: Double) -> TimeInterval { - return self.init(hours: hours) - } - - static func minutes(_ minutes: Int) -> TimeInterval { - return self.init(minutes: Double(minutes)) - } - - static func minutes(_ minutes: Double) -> TimeInterval { - return self.init(minutes: minutes) - } - - static func seconds(_ seconds: Double) -> TimeInterval { - return self.init(seconds) - } - - static func milliseconds(_ milliseconds: Double) -> TimeInterval { - return self.init(milliseconds / 1000) - } - - init(days: Double) { - self.init(hours: days * 24) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - init(minutes: Double) { - self.init(minutes * 60) - } - - init(seconds: Double) { - self.init(seconds) - } - - init(milliseconds: Double) { - self.init(milliseconds / 1000) - } - - var milliseconds: Double { - return self * 1000 - } - - init(hundredthsOfMilliseconds: Double) { - self.init(hundredthsOfMilliseconds / 100000) - } - - var hundredthsOfMilliseconds: Double { - return self * 100000 - } - - var minutes: Double { - return self / 60.0 - } - - var hours: Double { - return minutes / 60.0 - } - - var days: Double { - return hours / 24.0 - } - -} diff --git a/Dependencies/OmniKit/OmniKit/Extensions/TimeZone.swift b/Dependencies/OmniKit/OmniKit/Extensions/TimeZone.swift deleted file mode 100644 index 0f572cb9e..000000000 --- a/Dependencies/OmniKit/OmniKit/Extensions/TimeZone.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// TimeZone.swift -// OmniKit -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension TimeZone { - static var currentFixed: TimeZone { - return TimeZone(secondsFromGMT: TimeZone.current.secondsFromGMT())! - } - - var fixed: TimeZone { - return TimeZone(secondsFromGMT: secondsFromGMT())! - } - - /// This only works for fixed utc offset timezones - func scheduleOffset(forDate date: Date) -> TimeInterval { - var calendar = Calendar.current - calendar.timeZone = self - let components = calendar.dateComponents([.day , .month, .year], from: date) - guard let startOfSchedule = calendar.date(from: components) else { - fatalError("invalid date") - } - return date.timeIntervalSince(startOfSchedule) - } - -} diff --git a/Dependencies/OmniKit/OmniKit/Info.plist b/Dependencies/OmniKit/OmniKit/Info.plist deleted file mode 100644 index 7a3ea75eb..000000000 --- a/Dependencies/OmniKit/OmniKit/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Dependencies/OmniKit/OmniKit/LocalizedString.swift b/Dependencies/OmniKit/OmniKit/LocalizedString.swift deleted file mode 100644 index 116e1d792..000000000 --- a/Dependencies/OmniKit/OmniKit/LocalizedString.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// LocalizedString.swift -// OmniKit -// -// Created by Pete Schwamb on 3/19/23. -// - -import Foundation - -private class LocalBundle { - /// Returns the resource bundle associated with the current Swift module. - static var main: Bundle = { - if let mainResourceURL = Bundle.main.resourceURL, - let bundle = Bundle(url: mainResourceURL.appendingPathComponent("OmniKit_OmniKit.bundle")) - { - return bundle - } - return Bundle(for: LocalBundle.self) - }() -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, comment: comment) - } -} diff --git a/Dependencies/OmniKit/OmniKit/MessageTransport/CRC8.swift b/Dependencies/OmniKit/OmniKit/MessageTransport/CRC8.swift deleted file mode 100644 index 46889130d..000000000 --- a/Dependencies/OmniKit/OmniKit/MessageTransport/CRC8.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// CRC8.swift -// OmniKit -// -// Created by Pete Schwamb on 10/14/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - -fileprivate let crcTable: [UInt8] = [ - 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, - 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, - 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, - 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, - 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, - 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, - 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, - 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, - 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, - 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, - 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, - 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, - 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, - 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, - 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, - 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 -] - -public extension Sequence where Element == UInt8 { - - func crc8() -> UInt8 { - - var crc: UInt8 = 0 - for byte in self { - crc = crcTable[Int((crc ^ byte) & 0xff)] - } - return crc - } -} diff --git a/Dependencies/OmniKit/OmniKit/MessageTransport/MessageTransport.swift b/Dependencies/OmniKit/OmniKit/MessageTransport/MessageTransport.swift deleted file mode 100644 index ce132266a..000000000 --- a/Dependencies/OmniKit/OmniKit/MessageTransport/MessageTransport.swift +++ /dev/null @@ -1,313 +0,0 @@ -// -// MessageTransport.swift -// OmniKit -// -// Created by Pete Schwamb on 8/5/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation -import os.log - -import RileyLinkBLEKit - -protocol MessageLogger: AnyObject { - // Comms logging - func didSend(_ message: Data) - func didReceive(_ message: Data) - func didError(_ message: String) -} - -public struct MessageTransportState: Equatable, RawRepresentable { - public typealias RawValue = [String: Any] - - public var packetNumber: Int - public var messageNumber: Int - - init(packetNumber: Int, messageNumber: Int) { - self.packetNumber = packetNumber - self.messageNumber = messageNumber - } - - // RawRepresentable - public init?(rawValue: RawValue) { - guard - let packetNumber = rawValue["packetNumber"] as? Int, - let messageNumber = rawValue["messageNumber"] as? Int - else { - return nil - } - self.packetNumber = packetNumber - self.messageNumber = messageNumber - } - - public var rawValue: RawValue { - return [ - "packetNumber": packetNumber, - "messageNumber": messageNumber - ] - } - -} - -protocol MessageTransportDelegate: AnyObject { - func messageTransport(_ messageTransport: MessageTransport, didUpdate state: MessageTransportState) -} - -protocol MessageTransport { - var delegate: MessageTransportDelegate? { get set } - - var messageNumber: Int { get } - - func sendMessage(_ message: Message) throws -> Message - - /// Asserts that the caller is currently on the session's queue - func assertOnSessionQueue() -} - -class PodMessageTransport: MessageTransport { - - private let session: CommandSession - - private let log = OSLog(category: "PodMessageTransport") - - private var state: MessageTransportState { - didSet { - self.delegate?.messageTransport(self, didUpdate: state) - } - } - - private(set) var packetNumber: Int { - get { - return state.packetNumber - } - set { - state.packetNumber = newValue - } - } - - private(set) var messageNumber: Int { - get { - return state.messageNumber - } - set { - state.messageNumber = newValue - } - } - - private let address: UInt32 - private var ackAddress: UInt32 // During pairing, PDM acks with address it is assigning to channel - - weak var messageLogger: MessageLogger? - weak var delegate: MessageTransportDelegate? - - init(session: CommandSession, address: UInt32 = 0xffffffff, ackAddress: UInt32? = nil, state: MessageTransportState) { - self.session = session - self.address = address - self.ackAddress = ackAddress ?? address - self.state = state - } - - private func incrementPacketNumber(_ count: Int = 1) { - packetNumber = (packetNumber + count) & 0b11111 - } - - private func incrementMessageNumber(_ count: Int = 1) { - messageNumber = (messageNumber + count) & 0b1111 - } - - func makeAckPacket() -> Packet { - return Packet(address: address, packetType: .ack, sequenceNum: packetNumber, data: Data(bigEndian: ackAddress)) - } - - func ackUntilQuiet() { - - let packetData = makeAckPacket().encoded() - - var lastHeardAt = Date() - let quietWindow = TimeInterval(milliseconds: 300) - while lastHeardAt.timeIntervalSinceNow > -quietWindow { - do { - let rfPacket = try session.sendAndListen(packetData, repeatCount: 1, timeout: quietWindow, retryCount: 0, preambleExtension: TimeInterval(milliseconds: 40)) - let packet = try Packet(rfPacket: rfPacket) - if packet.address == address { - lastHeardAt = Date() // Pod still sending - } - } catch RileyLinkDeviceError.responseTimeout { - // Haven't heard anything in 300ms. POD heard our ack. - break - } catch { - continue - } - } - incrementPacketNumber() - } - - - /// Encodes and sends a packet to the pod, and receives and decodes its response - /// - /// - Parameters: - /// - packet: The packet to send - /// - repeatCount: Number of times to repeat packet before listening for a response. 0 = send once and do not repeat. - /// - packetResponseTimeout: The amount of time to wait before retrying - /// - exchangeTimeout: The amount of time to continue retrying before giving up - /// - preambleExtension: Duration of preamble. Default is 127ms - /// - Returns: The received response packet - /// - Throws: - /// - PodCommsError.noResponse - /// - RileyLinkDeviceError - func exchangePackets(packet: Packet, repeatCount: Int = 0, packetResponseTimeout: TimeInterval = .milliseconds(333), exchangeTimeout:TimeInterval = .seconds(9), preambleExtension: TimeInterval = .milliseconds(127)) throws -> Packet { - let packetData = packet.encoded() - let radioRetryCount = 9 - - let start = Date() - - incrementPacketNumber() - - while (-start.timeIntervalSinceNow < exchangeTimeout) { - do { - let rfPacket = try session.sendAndListen(packetData, repeatCount: repeatCount, timeout: packetResponseTimeout, retryCount: radioRetryCount, preambleExtension: preambleExtension) - - let candidatePacket: Packet - - do { - candidatePacket = try Packet(rfPacket: rfPacket) - log.default("Received packet (%d): %@", rfPacket.rssi, rfPacket.data.hexadecimalString) - } catch PacketError.insufficientData { - log.default("Insufficient packet data: %@", rfPacket.data.hexadecimalString) - continue - } catch let error { - log.default("Packet error: %@", String(describing: error)) - continue - } - - guard candidatePacket.address == packet.address || candidatePacket.address == 0xFFFFFFFF else { - log.default("Packet address 0x%x does not match 0x%x", candidatePacket.address, packet.address) - continue - } - - guard candidatePacket.sequenceNum == ((packet.sequenceNum + 1) & 0b11111) else { - log.default("Packet sequence %@ does not match %@", String(describing: candidatePacket.sequenceNum), String(describing: ((packet.sequenceNum + 1) & 0b11111))) - continue - } - - // Once we have verification that the POD heard us, we can increment our counters - incrementPacketNumber() - - return candidatePacket - } catch RileyLinkDeviceError.responseTimeout { - continue - } - } - - throw PodCommsError.noResponse - } - - /// Packetizes a message, and performs a set of packet exchanges to send a message and receive the response - /// - /// - Parameters: - /// - message: The message to send - /// - Returns: The received message response - /// - Throws: - /// - PodCommsError.noResponse - /// - PodCommsError.podAckedInsteadOfReturningResponse - /// - PodCommsError.unexpectedPacketType - /// - PodCommsError.emptyResponse - /// - PodCommsError.unacknowledgedMessage - /// - PodCommsError.commsError - func sendMessage(_ message: Message) throws -> Message { - - messageNumber = message.sequenceNum - incrementMessageNumber() - var sentFullMessage = false - - do { - let responsePacket = try { () throws -> Packet in - var firstPacket = true - log.debug("Send: %@", String(describing: message)) - var dataRemaining = message.encoded() - log.default("Send(Hex): %@", dataRemaining.hexadecimalString) - messageLogger?.didSend(dataRemaining) - while true { - let packetType: PacketType = firstPacket ? .pdm : .con - let sendPacket = Packet(address: address, packetType: packetType, sequenceNum: self.packetNumber, data: dataRemaining) - dataRemaining = dataRemaining.subdata(in: sendPacket.data.count.. Message in - var responseData = responsePacket.data - while true { - do { - let msg = try Message(encodedData: responseData) - log.default("Recv(Hex): %@", responseData.hexadecimalString) - guard msg.address == address else { - throw MessageError.invalidAddress(address: msg.address) - } - guard msg.sequenceNum == messageNumber else { - throw MessageError.invalidSequence - } - messageLogger?.didReceive(responseData) - return msg - } catch MessageError.notEnoughData { - log.debug("Sending ACK for CON") - let conPacket = try self.exchangePackets(packet: makeAckPacket(), repeatCount: 3, preambleExtension:TimeInterval(milliseconds: 40)) - - guard conPacket.packetType == .con else { - log.default("Expected CON packet, received; %@", String(describing: conPacket)) - throw PodCommsError.unexpectedPacketType(packetType: conPacket.packetType) - } - responseData += conPacket.data - } catch MessageError.invalidCrc { - // throw the error without any logging for a garbage message - throw MessageError.invalidCrc - } catch let error { - // log any other non-garbage messages that generate errors - log.error("Error (%{public}@) Recv(Hex): %@", String(describing: error), responseData.hexadecimalString) - messageLogger?.didReceive(responseData) - throw error - } - } - }() - - ackUntilQuiet() - - guard response.messageBlocks.count > 0 else { - log.default("Empty response") - throw PodCommsError.emptyResponse - } - - incrementMessageNumber() - - return response - } catch let error { - if sentFullMessage { - messageLogger?.didError("Unacknowledged message. seq:\(message.sequenceNum), error = \(error)") - throw PodCommsError.unacknowledgedMessage(sequenceNumber: message.sequenceNum, error: error) - } else if let podCommsError = error as? PodCommsError { - throw podCommsError - } else { - throw PodCommsError.commsError(error: error) - } - } - } - - func assertOnSessionQueue() { - session.assertOnSessionQueue() - } -} diff --git a/Dependencies/OmniKit/OmniKit/MessageTransport/Packet+RFPacket.swift b/Dependencies/OmniKit/OmniKit/MessageTransport/Packet+RFPacket.swift deleted file mode 100644 index e403f560c..000000000 --- a/Dependencies/OmniKit/OmniKit/MessageTransport/Packet+RFPacket.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// Packet+RFPacket.swift -// OmniKit -// -// Created by Pete Schwamb on 12/19/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation -import RileyLinkBLEKit - -// Extensions for RFPacket support -extension Packet { - init(rfPacket: RFPacket) throws { - try self.init(encodedData: rfPacket.data) - } -} diff --git a/Dependencies/OmniKit/OmniKit/MessageTransport/Packet.swift b/Dependencies/OmniKit/OmniKit/MessageTransport/Packet.swift deleted file mode 100644 index cb601a237..000000000 --- a/Dependencies/OmniKit/OmniKit/MessageTransport/Packet.swift +++ /dev/null @@ -1,93 +0,0 @@ -// -// Packet.swift -// OmniKit -// -// Created by Pete Schwamb on 10/14/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// -import Foundation - -public enum PacketError: Error { - case insufficientData - case crcMismatch - case unknownPacketType(rawType: UInt8) -} - - -public enum PacketType: UInt8 { - case pod = 0b111 - case pdm = 0b101 - case con = 0b100 - case ack = 0b010 - - func maxBodyLen() -> Int { - switch self { - case .ack: - return 4 - case .con, .pdm, .pod: - return 31 - } - } -} - -public struct Packet { - - let address: UInt32 - let packetType: PacketType - let sequenceNum: Int - let data: Data - - init(address: UInt32, packetType: PacketType, sequenceNum: Int, data: Data = Data()) { - self.address = address - self.packetType = packetType - self.sequenceNum = sequenceNum - - let bodyMaxLen = packetType.maxBodyLen() - if data.count > bodyMaxLen { - self.data = data.subdata(in: 0..= 7 else { - // Not enough data for packet - throw PacketError.insufficientData - } - - self.address = encodedData[0...].toBigEndian(UInt32.self) - - guard let packetType = PacketType(rawValue: encodedData[4] >> 5) else { - throw PacketError.unknownPacketType(rawType: encodedData[4]) - } - self.packetType = packetType - self.sequenceNum = Int(encodedData[4] & 0b11111) - - let len = encodedData.count - - // Check crc - guard encodedData[0.. Data { - var output = Data(bigEndian: address) - output.append(UInt8(packetType.rawValue << 5) + UInt8(sequenceNum & 0b11111)) - output.append(data) - output.append(output.crc8()) - return output - } -} - -extension Packet: CustomDebugStringConvertible { - public var debugDescription: String { - let sequenceNumStr = String(format: "%02d", sequenceNum) - return "Packet(\(Data(bigEndian: address).hexadecimalString) packetType:\(packetType) seq:\(sequenceNumStr) data:\(data.hexadecimalString))" - } -} - diff --git a/Dependencies/OmniKit/OmniKit/OmniKit.h b/Dependencies/OmniKit/OmniKit/OmniKit.h deleted file mode 100644 index b353125fd..000000000 --- a/Dependencies/OmniKit/OmniKit/OmniKit.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// OmniKit.h -// OmniKit -// -// Created by Pete Schwamb on 8/26/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -#import - -//! Project version number for OmniKit. -FOUNDATION_EXPORT double OmniKitVersionNumber; - -//! Project version string for OmniKit. -FOUNDATION_EXPORT const unsigned char OmniKitVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/AlertSlot.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/AlertSlot.swift deleted file mode 100644 index b22e7066c..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/AlertSlot.swift +++ /dev/null @@ -1,718 +0,0 @@ -// -// Alert.swift -// OmniKit -// -// Created by Pete Schwamb on 10/24/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -fileprivate let defaultShutdownImminentTime = Pod.serviceDuration - Pod.endOfServiceImminentWindow -fileprivate let defaultExpirationReminderTime = Pod.nominalPodLife - Pod.defaultExpirationReminderOffset -fileprivate let defaultExpiredTime = Pod.nominalPodLife - -// PDM and pre-SwiftUI use every1MinuteFor3MinutesAndRepeatEvery15Minutes, but with SwiftUI use every15Minutes -fileprivate let suspendTimeExpiredBeepRepeat = BeepRepeat.every15Minutes - -public enum AlertTrigger { - case unitsRemaining(Double) - case timeUntilAlert(TimeInterval) -} - -extension AlertTrigger: CustomDebugStringConvertible { - public var debugDescription: String { - switch self { - case .unitsRemaining(let units): - return "\(Int(units))U" - case .timeUntilAlert(let triggerTime): - return "triggerTime=\(triggerTime.timeIntervalStr)" - } - } -} - -public enum BeepRepeat: UInt8 { - case once = 0 - case every1MinuteFor3MinutesAndRepeatEvery60Minutes = 1 - case every1MinuteFor15Minutes = 2 - case every1MinuteFor3MinutesAndRepeatEvery15Minutes = 3 - case every3MinutesFor60minutesStartingAt2Minutes = 4 - case every60Minutes = 5 - case every15Minutes = 6 - case every15MinutesFor60minutesStartingAt14Minutes = 7 - case every5Minutes = 8 -} - - -public struct AlertConfiguration { - - let slot: AlertSlot - let active: Bool - let duration: TimeInterval - let trigger: AlertTrigger - let beepRepeat: BeepRepeat - let beepType: BeepType - let silent: Bool - let autoOffModifier: Bool - - static let length = 6 - - public init(alertType: AlertSlot, active: Bool = true, duration: TimeInterval = 0, trigger: AlertTrigger, beepRepeat: BeepRepeat, beepType: BeepType, silent: Bool = false, autoOffModifier: Bool = false) - { - self.slot = alertType - self.active = active - self.duration = duration - self.trigger = trigger - self.beepRepeat = beepRepeat - self.beepType = beepType - self.silent = silent - self.autoOffModifier = autoOffModifier - } -} - -extension AlertConfiguration: CustomDebugStringConvertible { - public var debugDescription: String { - var str = "slot:\(slot)" - if !active { - str += ", active:\(active)" - } - if duration != 0 { - str += ", duration:\(duration.timeIntervalStr)" - } - str += ", trigger:\(trigger), beepRepeat:\(beepRepeat)" - if beepType != .noBeepNonCancel { - str += ", beepType:\(beepType)" - } else { - str += ", silent:\(silent)" - } - if autoOffModifier { - str += ", autoOffModifier:\(autoOffModifier)" - } - return "\nAlertConfiguration(\(str))" - } -} - - - -public enum PodAlert: CustomStringConvertible, RawRepresentable, Equatable { - public typealias RawValue = [String: Any] - - // slot0AutoOff: auto-off timer; requires user input every x minutes -- NOT IMPLEMENTED - case autoOff(active: Bool, offset: TimeInterval, countdownDuration: TimeInterval, silent: Bool = false) - - // slot1NotUsed - case notUsed - - // slot2ShutdownImminent: 79 hour alarm (1 hour before shutdown) - // 2 sets of beeps every 15 minutes for 1 hour - case shutdownImminent(offset: TimeInterval, absAlertTime: TimeInterval, silent: Bool = false) - - // slot3ExpirationReminder: User configurable with PDM (1-24 hours before 72 hour expiration) - // 2 sets of beeps every minute for 3 minutes and repeat every 15 minutes - // The PDM doesn't use a duration for this alert (presumably because it is limited to 2^9-1 minutes or 8h31m) - case expirationReminder(offset: TimeInterval, absAlertTime: TimeInterval, duration: TimeInterval = 0, silent: Bool = false) - - // slot4LowReservoir: reservoir below configured value alert - case lowReservoir(units: Double, silent: Bool = false) - - // slot5SuspendedReminder: pod suspended reminder, before suspendTime; - // short beep every 15 minutes if > 30 min, else short beep every 5 minutes - case podSuspendedReminder(active: Bool, offset: TimeInterval, suspendTime: TimeInterval, timePassed: TimeInterval = 0, silent: Bool = false) - - // slot6SuspendTimeExpired: pod suspend time expired alarm, after suspendTime; - // 2 sets of beeps every minute for 3 minutes repeated every 15 minutes (PDM & pre-SwiftUI implementations) - // 2 sets of beeps every 15 minutes (for SwiftUI PumpManagerAlerts implementations) - case suspendTimeExpired(offset: TimeInterval, suspendTime: TimeInterval, silent: Bool = false) - - // slot7Expired: 2 hours long, time for user to start pairing process - case waitingForPairingReminder - - // slot7Expired: 1 hour long, time for user to finish priming, cannula insertion - case finishSetupReminder - - // slot7Expired: 72 hour alarm - case expired(offset: TimeInterval, absAlertTime: TimeInterval, duration: TimeInterval, silent: Bool = false) - - public var description: String { - var alertName: String - switch self { - // slot0AutoOff - case .autoOff: - alertName = LocalizedString("Auto-off", comment: "Description for auto-off alert") - // slot1NotUsed - case .notUsed: - alertName = LocalizedString("Not used", comment: "Description for not used slot alert") - // slot2ShutdownImminent - case .shutdownImminent: - alertName = LocalizedString("Shutdown imminent", comment: "Description for shutdown imminent alert") - // slot3ExpirationReminder - case .expirationReminder: - alertName = LocalizedString("Expiration reminder", comment: "Description for expiration reminder alert") - // slot4LowReservoir - case .lowReservoir: - alertName = LocalizedString("Low reservoir", comment: "Format string for description for low reservoir alert") - // slot5SuspendedReminder - case .podSuspendedReminder: - alertName = LocalizedString("Pod suspended reminder", comment: "Description for pod suspended reminder alert") - // slot6SuspendTimeExpired - case .suspendTimeExpired: - alertName = LocalizedString("Suspend time expired", comment: "Description for suspend time expired alert") - // slot7Expired - case .waitingForPairingReminder: - alertName = LocalizedString("Waiting for pairing reminder", comment: "Description waiting for pairing reminder alert") - case .finishSetupReminder: - alertName = LocalizedString("Finish setup reminder", comment: "Description for finish setup reminder alert") - case .expired: - alertName = LocalizedString("Pod expired", comment: "Description for pod expired alert") - } - if self.configuration.active == false { - alertName += LocalizedString(" (inactive)", comment: "Description for an inactive alert modifier") - } - return alertName - } - - public var configuration: AlertConfiguration { - switch self { - // slot0AutoOff - case .autoOff(let active, _, let countdownDuration, let silent): - return AlertConfiguration(alertType: .slot0AutoOff, active: active, duration: .minutes(15), trigger: .timeUntilAlert(countdownDuration), beepRepeat: .every1MinuteFor15Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep, silent: silent, autoOffModifier: true) - - // slot1NotUsed - case .notUsed: - return AlertConfiguration(alertType: .slot1NotUsed, duration: .minutes(55), trigger: .timeUntilAlert(.minutes(5)), beepRepeat: .every5Minutes, beepType: .noBeepNonCancel) - - // slot2ShutdownImminent - case .shutdownImminent(let offset, let absAlertTime, let silent): - let active = absAlertTime != 0 // disable if absAlertTime is 0 - let triggerTime: TimeInterval - if active { - triggerTime = absAlertTime - offset - } else { - triggerTime = 0 - } - return AlertConfiguration(alertType: .slot2ShutdownImminent, active: active, trigger: .timeUntilAlert(triggerTime), beepRepeat: .every15Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep, silent: silent) - - // slot3ExpirationReminder - case .expirationReminder(let offset, let absAlertTime, let duration, let silent): - let active = absAlertTime != 0 // disable if absAlertTime is 0 - let triggerTime: TimeInterval - if active { - triggerTime = absAlertTime - offset - } else { - triggerTime = 0 - } - return AlertConfiguration(alertType: .slot3ExpirationReminder, active: active, duration: duration, trigger: .timeUntilAlert(triggerTime), beepRepeat: .every1MinuteFor3MinutesAndRepeatEvery15Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep, silent: silent) - - // slot4LowReservoir - case .lowReservoir(let units, let silent): - let active = units != 0 // disable if units is 0 - return AlertConfiguration(alertType: .slot4LowReservoir, active: active, trigger: .unitsRemaining(units), beepRepeat: .every1MinuteFor3MinutesAndRepeatEvery60Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep, silent: silent) - - // slot5SuspendedReminder - // A suspendTime of 0 is an untimed suspend - // timePassed will be > 0 for an existing pod suspended reminder changing its silent state - case .podSuspendedReminder(let active, _, let suspendTime, let timePassed, let silent): - let reminderInterval, duration: TimeInterval - var beepRepeat: BeepRepeat - let beepType: BeepType - let trigger: AlertTrigger - var isActive: Bool = active - - if suspendTime == 0 || suspendTime >= TimeInterval(minutes: 30) { - // Use 15-minute pod suspended reminder beeps for untimed or longer scheduled suspend times. - reminderInterval = TimeInterval(minutes: 15) - beepRepeat = .every15Minutes - } else { - // Use 5-minute pod suspended reminder beeps for shorter scheduled suspend times. - reminderInterval = TimeInterval(minutes: 5) - beepRepeat = .every5Minutes - } - - // Make alert inactive if there isn't enough remaining in suspend time for a reminder beep. - let suspendTimeRemaining = suspendTime - timePassed - if suspendTime != 0 && suspendTimeRemaining <= reminderInterval { - isActive = false - } - - if isActive { - // Compute the alert trigger time as the interval until the next upcoming reminder interval - let triggerTime: TimeInterval = .seconds(reminderInterval - Double((Int(timePassed) % Int(reminderInterval)))) - - if suspendTime == 0 { - duration = 0 // Untimed suspend, no duration - } else { - // duration is from triggerTime to suspend time remaining - duration = suspendTimeRemaining - triggerTime - } - trigger = .timeUntilAlert(triggerTime) // time to next reminder interval with the suspend time - beepType = .beep - } else { - beepRepeat = .once - duration = 0 - trigger = .timeUntilAlert(.minutes(0)) - beepType = .noBeepCancel - } - return AlertConfiguration(alertType: .slot5SuspendedReminder, active: isActive, duration: duration, trigger: trigger, beepRepeat: beepRepeat, beepType: beepType, silent: silent) - - // slot6SuspendTimeExpired - case .suspendTimeExpired(_, let suspendTime, let silent): - let active = suspendTime != 0 // disable if suspendTime is 0 - let trigger: AlertTrigger - let beepRepeat: BeepRepeat - let beepType: BeepType - if active { - trigger = .timeUntilAlert(suspendTime) - beepRepeat = suspendTimeExpiredBeepRepeat - beepType = .bipBeepBipBeepBipBeepBipBeep - } else { - trigger = .timeUntilAlert(.minutes(0)) - beepRepeat = .once - beepType = .noBeepCancel - } - return AlertConfiguration(alertType: .slot6SuspendTimeExpired, active: active, trigger: trigger, beepRepeat: beepRepeat, beepType: beepType, silent: silent) - - // slot7Expired - case .waitingForPairingReminder: - // After pod is powered up, beep every 10 minutes for up to 2 hours before pairing before failing - let totalDuration: TimeInterval = .hours(2) - let startOffset: TimeInterval = .minutes(10) - return AlertConfiguration(alertType: .slot7Expired, duration: totalDuration - startOffset, trigger: .timeUntilAlert(startOffset), beepRepeat: .every5Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep) - case .finishSetupReminder: - // After pod is paired, beep every 5 minutes for up to 1 hour for pod setup to complete before failing - let totalDuration: TimeInterval = .hours(1) - let startOffset: TimeInterval = .minutes(5) - return AlertConfiguration(alertType: .slot7Expired, duration: totalDuration - startOffset, trigger: .timeUntilAlert(startOffset), beepRepeat: .every5Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep) - case .expired(let offset, let absAlertTime, let duration, let silent): - // Normally used to alert at Pod.nominalPodLife (72 hours) for Pod.expirationAdvisoryWindow (7 hours) - // 2 sets of beeps repeating every 60 minutes - let active = absAlertTime != 0 // disable if absAlertTime is 0 - let triggerTime: TimeInterval - if active { - triggerTime = absAlertTime - offset - } else { - triggerTime = .minutes(0) - } - return AlertConfiguration(alertType: .slot7Expired, active: active, duration: duration, trigger: .timeUntilAlert(triggerTime), beepRepeat: .every60Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep, silent: silent) - } - } - - - // MARK: - RawRepresentable - public init?(rawValue: RawValue) { - - guard let name = rawValue["name"] as? String else { - return nil - } - - switch name { - case "autoOff": - guard let active = rawValue["active"] as? Bool, - let countdownDuration = rawValue["countdownDuration"] as? TimeInterval else - { - return nil - } - let offset = rawValue["offset"] as? TimeInterval ?? 0 - let silent = rawValue["silent"] as? Bool ?? false - self = .autoOff(active: active, offset: offset, countdownDuration: countdownDuration, silent: silent) - case "shutdownImminent": - guard let alarmTime = rawValue["alarmTime"] as? TimeInterval else { - return nil - } - let offset = rawValue["offset"] as? TimeInterval ?? 0 - let offsetToUse, absAlertTime: TimeInterval - if offset == 0 { - // use default values as no offset value was found - absAlertTime = defaultShutdownImminentTime - offsetToUse = absAlertTime - alarmTime - } else { - absAlertTime = offset + alarmTime - offsetToUse = offset - } - let silent = rawValue["silent"] as? Bool ?? false - self = .shutdownImminent(offset: offsetToUse, absAlertTime: absAlertTime, silent: silent) - case "expirationReminder": - guard let alertTime = rawValue["alertTime"] as? TimeInterval else { - return nil - } - let offset = rawValue["offset"] as? TimeInterval ?? 0 - let offsetToUse, absAlertTime: TimeInterval - if offset == 0 { - // use default values as no offset value was found - absAlertTime = defaultExpirationReminderTime - offsetToUse = absAlertTime - alertTime - } else { - absAlertTime = offset + alertTime - offsetToUse = offset - } - let duration = rawValue["duration"] as? TimeInterval ?? 0 - let silent = rawValue["silent"] as? Bool ?? false - self = .expirationReminder(offset: offsetToUse, absAlertTime: absAlertTime, duration: duration, silent: silent) - case "lowReservoir": - guard let units = rawValue["units"] as? Double else { - return nil - } - let silent = rawValue["silent"] as? Bool ?? false - self = .lowReservoir(units: units, silent: silent) - case "podSuspendedReminder": - guard let active = rawValue["active"] as? Bool, - let suspendTime = rawValue["suspendTime"] as? TimeInterval else - { - return nil - } - let offset = rawValue["offset"] as? TimeInterval ?? 0 - let silent = rawValue["silent"] as? Bool ?? false - self = .podSuspendedReminder(active: active, offset: offset, suspendTime: suspendTime, silent: silent) - case "suspendTimeExpired": - guard let suspendTime = rawValue["suspendTime"] as? Double else { - return nil - } - let offset = rawValue["offset"] as? TimeInterval ?? 0 - let silent = rawValue["silent"] as? Bool ?? false - self = .suspendTimeExpired(offset: offset, suspendTime: suspendTime, silent: silent) - case "waitingForPairingReminder": - self = .waitingForPairingReminder - case "finishSetupReminder": - self = .finishSetupReminder - case "expired": - guard let alarmTime = rawValue["alarmTime"] as? TimeInterval, - let duration = rawValue["duration"] as? TimeInterval else - { - return nil - } - let offset = rawValue["offset"] as? TimeInterval ?? 0 - let offsetToUse, absAlertTime: TimeInterval - if offset == 0 { - // use default values as no offset value was found - absAlertTime = defaultExpiredTime - offsetToUse = absAlertTime - alarmTime - } else { - absAlertTime = offset + alarmTime - offsetToUse = offset - } - let silent = rawValue["silent"] as? Bool ?? false - self = .expired(offset: offsetToUse, absAlertTime: absAlertTime, duration: duration, silent: silent) - default: - return nil - } - } - - public var rawValue: RawValue { - - let name: String = { - switch self { - case .autoOff: - return "autoOff" - case .notUsed: - return "notUsed" - case .shutdownImminent: - return "shutdownImminent" - case .expirationReminder: - return "expirationReminder" - case .lowReservoir: - return "lowReservoir" - case .podSuspendedReminder: - return "podSuspendedReminder" - case .suspendTimeExpired: - return "suspendTimeExpired" - case .waitingForPairingReminder: - return "waitingForPairingReminder" - case .finishSetupReminder: - return "finishSetupReminder" - case .expired: - return "expired" - } - }() - - var rawValue: RawValue = [ - "name": name, - ] - - switch self { - case .autoOff(let active, let offset, let countdownDuration, let silent): - rawValue["active"] = active - rawValue["offset"] = offset - rawValue["countdownDuration"] = countdownDuration - rawValue["silent"] = silent - case .shutdownImminent(let offset, let absAlertTime, let silent): - rawValue["offset"] = offset - rawValue["alarmTime"] = absAlertTime - offset - rawValue["silent"] = silent - case .expirationReminder(let offset, let absAlertTime, let duration, let silent): - rawValue["offset"] = offset - rawValue["alertTime"] = absAlertTime - offset - rawValue["duration"] = duration - rawValue["silent"] = silent - case .lowReservoir(let units, let silent): - rawValue["units"] = units - rawValue["silent"] = silent - case .podSuspendedReminder(let active, let offset, let suspendTime, _, let silent): - rawValue["active"] = active - rawValue["offset"] = offset - rawValue["suspendTime"] = suspendTime - rawValue["silent"] = silent - case .suspendTimeExpired(let offset, let suspendTime, let silent): - rawValue["offset"] = offset - rawValue["suspendTime"] = suspendTime - rawValue["silent"] = silent - case .expired(let offset, let absAlertTime, let duration, let silent): - rawValue["offset"] = offset - rawValue["alarmTime"] = absAlertTime - offset - rawValue["duration"] = duration - rawValue["silent"] = silent - default: - break - } - - return rawValue - } -} - -public enum AlertSlot: UInt8 { - case slot0AutoOff = 0x00 - case slot1NotUsed = 0x01 - case slot2ShutdownImminent = 0x02 - case slot3ExpirationReminder = 0x03 - case slot4LowReservoir = 0x04 - case slot5SuspendedReminder = 0x05 - case slot6SuspendTimeExpired = 0x06 - case slot7Expired = 0x07 - - public var bitMaskValue: UInt8 { - return 1< AlertSlot { - return elements[index] - } - - public func index(after i: Int) -> Int { - return i+1 - } - - public var description: String { - if elements.count == 0 { - return LocalizedString("No alerts", comment: "Pod alert state when no alerts are active") - } else { - let alarmDescriptions = elements.map { String(describing: $0) } - return alarmDescriptions.joined(separator: ", ") - } - } - - public func compare(to other: AlertSet) -> (added: AlertSet, removed: AlertSet) { - let added = Set(other.elements).subtracting(Set(elements)) - let removed = Set(elements).subtracting(Set(other.elements)) - return (added: AlertSet(slots: Array(added)), removed: AlertSet(slots: Array(removed))) - } -} - -// Returns true if there are any active suspend related alerts -public func hasActiveSuspendAlert(configuredAlerts: [AlertSlot : PodAlert]) -> Bool { - if configuredAlerts.contains(where: { ($0.key == .slot5SuspendedReminder || $0.key == .slot6SuspendTimeExpired) && $0.value.configuration.active }) - { - return true - } - return false -} - -// Returns a descriptive string for all the alerts in alertSet -public func alertSetString(alertSet: AlertSet) -> String { - - if alertSet.isEmpty { - // Don't bother displaying any additional info for an inactive alert - return String(describing: alertSet) - } - - let alertDescription = alertSet.map { (slot) -> String in - switch slot { - case .slot0AutoOff: - return PodAlert.autoOff(active: true, offset: 0, countdownDuration: 0).description - case .slot1NotUsed: - return PodAlert.notUsed.description - case .slot2ShutdownImminent: - return PodAlert.shutdownImminent(offset: 0, absAlertTime: defaultShutdownImminentTime).description - case .slot3ExpirationReminder: - return PodAlert.expirationReminder(offset: 0, absAlertTime: defaultExpirationReminderTime).description - case .slot4LowReservoir: - return PodAlert.lowReservoir(units: Pod.maximumReservoirReading).description - case .slot5SuspendedReminder: - return PodAlert.podSuspendedReminder(active: true, offset: 0, suspendTime: .minutes(30)).description - case .slot6SuspendTimeExpired: - return PodAlert.suspendTimeExpired(offset: 0, suspendTime: .minutes(30)).description - case .slot7Expired: - return PodAlert.expired(offset: 0, absAlertTime: defaultExpiredTime, duration: Pod.expirationAdvisoryWindow).description - } - } - - return alertDescription.joined(separator: ", ") -} - -func configuredAlertsString(configuredAlerts: [AlertSlot : PodAlert]) -> String { - - if configuredAlerts.isEmpty { - return String(describing: configuredAlerts) - } - - let configuredAlertString = configuredAlerts.map { (configuredAlert) -> String in - - let podAlert = configuredAlert.value - let description = podAlert.description - guard podAlert.configuration.active else { - return description - } - - switch podAlert { - case .shutdownImminent(_, let absAlertTime, _): - return String(format: "%@ @ %@", description, absAlertTime.timeIntervalStr) - case .expirationReminder(_, let absAlertTime, _, _): - return String(format: "%@ @ %@", description, absAlertTime.timeIntervalStr) - case .lowReservoir(let unitTrigger, _): - return String(format: "%@ @ %dU", description, Int(unitTrigger)) - case .podSuspendedReminder(_, let offset, let suspendTime, _, _): - return String(format: "%@ ending @ %@ after %@", description, (offset + suspendTime).timeIntervalStr, suspendTime.timeIntervalStr) - case .suspendTimeExpired(let offset, let suspendTime, _): - return String(format: "%@ @ %@ after %@", description, (offset + suspendTime).timeIntervalStr, suspendTime.timeIntervalStr) - case .expired(_, let absAlertTime, _, _): - return String(format: "%@ @ %@", description, absAlertTime.timeIntervalStr) - default: - return "" - } - } - - return configuredAlertString.joined(separator: ", ") -} - -// Returns an array of appropriate PodAlerts with the specified silent value -// for all the configuredAlerts given all the current pod conditions. -func regeneratePodAlerts(silent: Bool, configuredAlerts: [AlertSlot: PodAlert], activeAlertSlots: AlertSet, currentPodTime: TimeInterval, currentReservoirLevel: Double) -> [PodAlert] { - var podAlerts: [PodAlert] = [] - - for alert in configuredAlerts { - // Just skip this alert if not previously active - guard alert.value.configuration.active else { - continue - } - - // Map alerts to corresponding appropriate new ones at the current pod time using the specified silent value. - switch alert.value { - - case .shutdownImminent(let offset, let alertTime, _): - // alertTime is absolute when offset is non-zero, otherwise use default value - var absAlertTime = offset != 0 ? alertTime : defaultShutdownImminentTime - if currentPodTime >= absAlertTime { - // alert trigger is not in the future, make inactive using a 0 value - absAlertTime = 0 - } - // create new shutdownImminent podAlert using the current timeActive and the original absolute alert time - podAlerts.append(PodAlert.shutdownImminent(offset: currentPodTime, absAlertTime: absAlertTime, silent: silent)) - - case .expirationReminder(let offset, let alertTime, let alertDuration, _): - let duration: TimeInterval - - // alertTime is absolute when offset is non-zero, otherwise use default value - var absAlertTime = offset != 0 ? alertTime : defaultExpirationReminderTime - if currentPodTime >= absAlertTime { - // alert trigger is not in the future, make inactive using a 0 value - absAlertTime = 0 - duration = 0 - } else { - duration = alertDuration - } - // create new expirationReminder podAlert using the current active time and the original absolute alert time and duration - podAlerts.append(PodAlert.expirationReminder(offset: currentPodTime, absAlertTime: absAlertTime, duration: duration, silent: silent)) - - case .lowReservoir(let unitTrigger, _): - let units: Double - if currentReservoirLevel > unitTrigger { - units = unitTrigger - } else { - // reservoir is no longer more than the unitTrigger, make inactive using a 0 value - units = 0 - } - podAlerts.append(PodAlert.lowReservoir(units: units, silent: silent)) - - case .podSuspendedReminder(let active, let offset, let suspendTime, _, _): - let timePassed: TimeInterval = min(currentPodTime - offset, .hours(2)) - // Pass along the computed time passed since alert was originally set so creation routine can - // do all the grunt work dealing with varying reminder intervals and time passing scenarios. - podAlerts.append(PodAlert.podSuspendedReminder(active: active, offset: offset, suspendTime: suspendTime, timePassed: timePassed, silent: silent)) - - case .suspendTimeExpired(let lastOffset, let lastSuspendTime, _): - let absAlertTime = lastOffset + lastSuspendTime - let suspendTime: TimeInterval - if currentPodTime >= absAlertTime { - // alert trigger is no longer in the future - if activeAlertSlots.contains(where: { $0 == .slot6SuspendTimeExpired } ) { - // The suspendTimeExpired alert has yet been acknowledged, - // set up a suspendTimeExpired alert for the next 15m interval. - // Compute a new suspendTime that is a multiple of 15 minutes - // from lastOffset which is at least one minute in the future. - let newOffsetSuspendTime = ceil((currentPodTime - lastOffset) / .minutes(15)) * .minutes(15) - let newAbsAlertTime = lastOffset + newOffsetSuspendTime - suspendTime = max(newAbsAlertTime - currentPodTime, .minutes(1)) - } else { - // The suspendTimeExpired alert was already been acknowledged, - // so now make this alert inactive by using a 0 suspendTime. - suspendTime = 0 - } - } else { - // recompute a new suspendTime based on the current pod time - suspendTime = absAlertTime - currentPodTime - print("setting new suspendTimeExpired suspendTime of \(suspendTime) with currentPodTime\(currentPodTime) and absAlertTime=\(absAlertTime)") - } - // create a new suspendTimeExpired PodAlert using the current active time and the computed suspendTime (if any) - podAlerts.append(PodAlert.suspendTimeExpired(offset: currentPodTime, suspendTime: suspendTime, silent: silent)) - - case .expired(let offset, let alertTime, let alertDuration, _): - let duration: TimeInterval - - // alertTime is absolute when offset is non-zero, otherwise use default value - var absAlertTime = offset != 0 ? alertTime : defaultExpiredTime - if currentPodTime >= absAlertTime { - // alert trigger is not in the future, make inactive using a 0 value - absAlertTime = 0 - duration = 0 - } else { - duration = alertDuration - } - // create new expired podAlert using the current active time and the original absolute alert time and duration - podAlerts.append(PodAlert.expired(offset: currentPodTime, absAlertTime: absAlertTime, duration: duration, silent: silent)) - - default: - break - } - } - return podAlerts -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/BasalDeliveryTable.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/BasalDeliveryTable.swift deleted file mode 100644 index 582dbc4e9..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/BasalDeliveryTable.swift +++ /dev/null @@ -1,237 +0,0 @@ -// -// BasalDeliveryTable.swift -// OmniKit -// -// Created by Pete Schwamb on 4/4/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -// Max time between pulses for scheduled basal and temp basal extra timing command -let maxTimeBetweenPulses = TimeInterval(hours: 5) - -// Near zero basal rate used for non-Eros pods for zero scheduled basal rates and temp basals -let nearZeroBasalRate = 0.01 - -// Special flag used for non-Eros pods for near zero basal rates pulse timing for $13 & $16 extra commands -let nearZeroBasalRateFlag: UInt32 = 0x80000000 - - -public struct BasalDeliveryTable { - static let segmentDuration: TimeInterval = .minutes(30) - - let entries: [InsulinTableEntry] - - public init(entries: [InsulinTableEntry]) { - self.entries = entries - } - - - public init(schedule: BasalSchedule) { - - struct TempSegment { - let pulses: Int - } - - let numSegments = 48 - let maxSegmentsPerEntry = 16 - - var halfPulseRemainder = false - - let expandedSegments = stride(from: 0, to: numSegments, by: 1).map { (index) -> TempSegment in - let rate = schedule.rateAt(offset: Double(index) * .minutes(30)) - let pulsesPerHour = Int(round(rate / Pod.pulseSize)) - let pulsesPerSegment = pulsesPerHour >> 1 - let halfPulse = pulsesPerHour & 0b1 != 0 - - let segment = TempSegment(pulses: pulsesPerSegment + ((halfPulseRemainder && halfPulse) ? 1 : 0)) - halfPulseRemainder = halfPulseRemainder != halfPulse - - return segment - } - - var tableEntries = [InsulinTableEntry]() - - let addEntry = { (segments: [TempSegment], alternateSegmentPulse: Bool) in - tableEntries.append(InsulinTableEntry( - segments: segments.count, - pulses: segments.first!.pulses, - alternateSegmentPulse: alternateSegmentPulse - )) - } - - var altSegmentPulse = false - var segmentsToMerge = [TempSegment]() - - for segment in expandedSegments { - guard let firstSegment = segmentsToMerge.first else { - segmentsToMerge.append(segment) - continue - } - - let delta = segment.pulses - firstSegment.pulses - - if segmentsToMerge.count == 1 { - altSegmentPulse = delta == 1 - } - - let expectedDelta: Int - - if !altSegmentPulse { - expectedDelta = 0 - } else { - expectedDelta = segmentsToMerge.count % 2 - } - - if expectedDelta != delta || segmentsToMerge.count == maxSegmentsPerEntry { - addEntry(segmentsToMerge, altSegmentPulse) - segmentsToMerge.removeAll() - } - - segmentsToMerge.append(segment) - } - addEntry(segmentsToMerge, altSegmentPulse) - - self.entries = tableEntries - } - - public init(tempBasalRate: Double, duration: TimeInterval) { - self.entries = BasalDeliveryTable.rateToTableEntries(rate: tempBasalRate, duration: duration) - } - - private static func rateToTableEntries(rate: Double, duration: TimeInterval) -> [InsulinTableEntry] { - var tableEntries = [InsulinTableEntry]() - - let pulsesPerHour = Int(round(rate / Pod.pulseSize)) - let pulsesPerSegment = pulsesPerHour >> 1 - let alternateSegmentPulse = pulsesPerHour & 0b1 != 0 - - var remaining = Int(round(duration / BasalDeliveryTable.segmentDuration)) - - while remaining > 0 { - let segments = min(remaining, 16) - let tableEntry = InsulinTableEntry(segments: segments, pulses: Int(pulsesPerSegment), alternateSegmentPulse: segments > 1 ? alternateSegmentPulse : false) - tableEntries.append(tableEntry) - remaining -= segments - } - return tableEntries - } - - public func numSegments() -> Int { - return entries.reduce(0) { $0 + $1.segments } - } -} - -extension BasalDeliveryTable: CustomDebugStringConvertible { - public var debugDescription: String { - return "BasalDeliveryTable(\(entries))" - } -} - -// Round basal rate by rounding down to pulse size boundary, -// but basal rates within a small delta will be rounded up. -// Rounds down to 0 for both non-Eros and Eros (temp basals). -func roundToSupportedBasalRate(rate: Double) -> Double -{ - let delta = 0.01 - let supportedBasalRates: [Double] = (0...600).map { Double($0) / Double(Pod.pulsesPerUnit) } - return supportedBasalRates.last(where: { $0 <= rate + delta }) ?? 0 -} - -// Return rounded basal rate for pulse timing purposes. -// For non-Eros, returns nearZeroBasalRate (0.01) for a zero basal rate. -func roundToSupportedBasalTimingRate(rate: Double) -> Double { - var rrate = roundToSupportedBasalRate(rate: rate) - if rrate == 0.0 { - rrate = Pod.zeroBasalRate // will be an adjusted value for non-Eros cases - } - return rrate -} - -public struct RateEntry { - let totalPulses: Double - let delayBetweenPulses: TimeInterval - - public init(totalPulses: Double, delayBetweenPulses: TimeInterval) { - self.totalPulses = totalPulses - self.delayBetweenPulses = delayBetweenPulses - } - - public var rate: Double { - if totalPulses == 0 { - // Eros zero TB is the only case not using pulses - return 0 - } else { - // Use delayBetweenPulses to compute rate which will also work for non-Eros near zero rates. - // Round the rate calculation to a two digit value to avoid slightly off values for some cases. - return round(((.hours(1) / delayBetweenPulses) / Pod.pulsesPerUnit) * 100) / 100.0 - } - } - - public var duration: TimeInterval { - if totalPulses == 0 { - // Eros zero TB case uses fixed 30 minute rate entries - return TimeInterval(minutes: 30) - } else { - // Use delayBetweenPulses to compute duration which will also work for non-Eros near zero rates. - // Round to nearest second to not be slightly off of the 30 minute rate entry boundary for some cases. - return round(delayBetweenPulses * totalPulses) - } - } - - public var data: Data { - var delayBetweenPulsesInHundredthsOfMillisecondsWithFlag = UInt32(delayBetweenPulses.hundredthsOfMilliseconds) - - // non-Eros near zero basal rates use the nearZeroBasalRateFlag - if delayBetweenPulses == maxTimeBetweenPulses && totalPulses != 0 { - delayBetweenPulsesInHundredthsOfMillisecondsWithFlag |= nearZeroBasalRateFlag - } - - var data = Data() - data.appendBigEndian(UInt16(round(totalPulses * 10))) - data.appendBigEndian(delayBetweenPulsesInHundredthsOfMillisecondsWithFlag) - return data - } - - public static func makeEntries(rate: Double, duration: TimeInterval) -> [RateEntry] { - let maxPulsesPerEntry: Double = 0xffff / 10 // max # of 1/10th pulses encoded in a 2-byte value - var entries = [RateEntry]() - let rrate = roundToSupportedBasalTimingRate(rate: rate) - - var remainingSegments = Int(round(duration.minutes / 30)) - - let pulsesPerSegment = round(rrate / Pod.pulseSize) / 2 - let maxSegmentsPerEntry = pulsesPerSegment > 0 ? Int(maxPulsesPerEntry / pulsesPerSegment) : 1 - - var remainingPulses = rrate * duration.hours / Pod.pulseSize - - while (remainingSegments > 0) { - let entry: RateEntry - if rrate == 0 { - // Eros zero TBR only, one rate entry per segment with no pulses - entry = RateEntry(totalPulses: 0, delayBetweenPulses: maxTimeBetweenPulses) - remainingSegments -= 1 // one rate entry per half hour - } else if rrate == nearZeroBasalRate { - // Non-Eros near zero value temp or scheduled basal, one entry with 1/10 pulse per 1/2 hour of duration - entry = RateEntry(totalPulses: Double(remainingSegments) / 10, delayBetweenPulses: maxTimeBetweenPulses) - remainingSegments = 0 // just a single entry - } else { - let numSegments = min(maxSegmentsPerEntry, Int(round(remainingPulses / pulsesPerSegment))) - remainingSegments -= numSegments - let pulseCount = pulsesPerSegment * Double(numSegments) - let delayBetweenPulses = .hours(1) / rrate * Pod.pulseSize - entry = RateEntry(totalPulses: pulseCount, delayBetweenPulses: delayBetweenPulses) - remainingPulses -= pulseCount - } - entries.append(entry) - } - return entries - } -} - -extension RateEntry: CustomDebugStringConvertible { - public var debugDescription: String { - return "RateEntry(rate:\(rate), duration:\(duration.timeIntervalStr))" - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/BasalSchedule+LoopKit.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/BasalSchedule+LoopKit.swift deleted file mode 100644 index 24ab54550..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/BasalSchedule+LoopKit.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// BasalSchedule+LoopKit.swift -// OmniKit -// -// Created by Pete Schwamb on 9/25/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation -import LoopKit - -extension BasalSchedule { - public init(repeatingScheduleValues: [LoopKit.RepeatingScheduleValue]) { - self.init(entries: repeatingScheduleValues.map { BasalScheduleEntry(rate: $0.value, startTime: $0.startTime) }) - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/BasalSchedule.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/BasalSchedule.swift deleted file mode 100644 index 6ed56bf07..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/BasalSchedule.swift +++ /dev/null @@ -1,134 +0,0 @@ -// -// BasalSchedule.swift -// OmniKit -// -// Created by Pete Schwamb on 4/4/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct BasalScheduleEntry: RawRepresentable, Equatable { - - public typealias RawValue = [String: Any] - - let rate: Double - let startTime: TimeInterval - - public init(rate: Double, startTime: TimeInterval) { - var rrate = roundToSupportedBasalRate(rate: rate) - if rrate == 0 && Pod.zeroBasalRate == 0 { - // Got a zero scheduled basal rate for an Eros pod, use the min allowed - rrate = Pod.pulseSize - } - self.rate = rrate - self.startTime = startTime - } - - // MARK: - RawRepresentable - public init?(rawValue: RawValue) { - - guard - let rate = rawValue["rate"] as? Double, - let startTime = rawValue["startTime"] as? Double - else { - return nil - } - - self.rate = rate - self.startTime = startTime - } - - public var rawValue: RawValue { - let rawValue: RawValue = [ - "rate": rate, - "startTime": startTime - ] - - return rawValue - } -} - -// A basal schedule starts at midnight and should contain 24 hours worth of entries -public struct BasalSchedule: RawRepresentable, Equatable { - - public typealias RawValue = [String: Any] - - let entries: [BasalScheduleEntry] - - public func rateAt(offset: TimeInterval) -> Double { - let (_, entry, _) = lookup(offset: offset) - return entry.rate - } - - // Only valid for fixed offset timezones - public func currentRate(using calendar: Calendar, at date: Date = Date()) -> Double { - let midnight = calendar.startOfDay(for: date) - return rateAt(offset: date.timeIntervalSince(midnight)) - } - - // Returns index, entry, and time remaining - func lookup(offset: TimeInterval) -> (Int, BasalScheduleEntry, TimeInterval) { - guard offset >= 0 && offset < .hours(24) else { - fatalError("Schedule offset out of bounds") - } - - var last: TimeInterval = .hours(24) - for (index, entry) in entries.reversed().enumerated() { - if entry.startTime <= offset { - return (entries.count - (index + 1), entry, last - entry.startTime) - } - last = entry.startTime - } - fatalError("Schedule incomplete") - } - - public init(entries: [BasalScheduleEntry]) { - self.entries = entries - } - - public func durations() -> [(rate: Double, duration: TimeInterval, startTime: TimeInterval)] { - var last: TimeInterval = .hours(24) - let durations = entries.reversed().map { (entry) -> (rate: Double, duration: TimeInterval, startTime: TimeInterval) in - let duration = (rate: entry.rate, duration: last - entry.startTime, startTime: entry.startTime) - last = entry.startTime - return duration - } - return durations.reversed() - } - - // MARK: - RawRepresentable - public init?(rawValue: RawValue) { - - guard - let entries = rawValue["entries"] as? [BasalScheduleEntry.RawValue] - else { - return nil - } - - self.entries = entries.compactMap { BasalScheduleEntry(rawValue: $0) } - } - - public var rawValue: RawValue { - let rawValue: RawValue = [ - "entries": entries.map { $0.rawValue } - ] - - return rawValue - } -} - -public extension Sequence where Element == BasalScheduleEntry { - func adjacentEqualRatesMerged() -> [BasalScheduleEntry] { - var output = [BasalScheduleEntry]() - let _ = self.reduce(nil) { (lastRate, entry) -> TimeInterval? in - if entry.rate != lastRate { - output.append(entry) - } - return entry.rate - } - return output - } -} - - diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/BeepPreference.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/BeepPreference.swift deleted file mode 100644 index ec8d937b4..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/BeepPreference.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// BeepPreference.swift -// OmniKit -// -// Created by Pete Schwamb on 2/14/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum BeepPreference: Int, CaseIterable { - case silent - case manualCommands - case extended - - public var title: String { - switch self { - case .silent: - return LocalizedString("Disabled", comment: "Title string for BeepPreference.silent") - case .manualCommands: - return LocalizedString("Enabled", comment: "Title string for BeepPreference.manualCommands") - case .extended: - return LocalizedString("Extended", comment: "Title string for BeepPreference.extended") - } - } - - public var description: String { - switch self { - case .silent: - return LocalizedString("No confidence reminders are used.", comment: "Description for BeepPreference.silent") - case .manualCommands: - return LocalizedString("Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used.", comment: "Description for BeepPreference.manualCommands") - case .extended: - return LocalizedString("Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate.", comment: "Description for BeepPreference.extended") - } - } - - var shouldBeepForManualCommand: Bool { - return self == .extended || self == .manualCommands - } - - var shouldBeepForAutomaticCommands: Bool { - return self == .extended - } - - func shouldBeepForCommand(automatic: Bool) -> Bool { - if automatic { - return shouldBeepForAutomaticCommands - } else { - return shouldBeepForManualCommand - } - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/BeepType.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/BeepType.swift deleted file mode 100644 index d02036aab..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/BeepType.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// BeepType.swift -// OmniKit -// -// Created by Joseph Moran on 5/12/19. -// Copyright © 2019 Pete Schwamb. All rights reserved. -// - -import Foundation - -// -// BeepType is used for the 0x19 Configure Alerts, 0x1E Set Beep Options and 0x1F Cancel Delivery commands. -// Some beep types values behave differently based on the command & circumstances due to Omnipod internals. -// -// Beep types 0x0, 0x9 & 0xA (as well as 0xE when the pod isn't suspended) will have no beeps or errors -// (when used in 0x19 Configure Alerts with an 'a' bit of 0 or 0x1F Cancel) and will return 0x6 Error -// response, code 7 (when used in 0x19 Configure Alerts with an 'a' bit of 1 or in 0x1E Beep Configure). -// -// Beep type 0xF will will have no beeps or errors (when used in 0x19 Configure Alerts -// or 0x1E Beep Configure), but will generate a 0x37 pod fault when used in 0x1F Cancel! -// -public enum BeepType: UInt8 { - case noBeepCancel = 0x0 // silent for 0x1F Cancel & inactive 0x19 alerts; error for 0x1E Beep Options & active 0x19 alerts - case beepBeepBeepBeep = 0x1 - case bipBeepBipBeepBipBeepBipBeep = 0x2 - case bipBip = 0x3 - case beep = 0x4 - case beepBeepBeep = 0x5 - case beeeeeep = 0x6 - case bipBipBipbipBipBip = 0x7 - case beeepBeeep = 0x8 - case unusedBeepType0x9 = 0x9 // silent for 0x1F Cancel & inactive 0x19 alerts; error for 0x1E Beep Options & active 0x19 alerts - case unusedBeepType0xA = 0xA // silent for 0x1F Cancel & inactive 0x19 alerts; error for 0x1E Beep Options & active 0x19 alerts - case beepBeep = 0xB - case beeep = 0xC - case bipBeeeeep = 0xD - // If pod is currently suspended, 5 second beep for the 0x19, 0x1E & 0x1F commands - // If pod is not suspended, silent for 0x1F Cancel & inactive 0x19 alerts; error for 0x1E Beep Options & active 0x19 alerts - case fiveSecondBeep = 0xE - case noBeepNonCancel = 0xF // silent for 0x1E Beep Options & 0x19 Configure Alerts, 0x37 pod fault for 0x1F Cancel! -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/BolusDeliveryTable.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/BolusDeliveryTable.swift deleted file mode 100644 index 40bc26826..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/BolusDeliveryTable.swift +++ /dev/null @@ -1,181 +0,0 @@ -// -// BolusDeliveryTable.swift -// OmniKit -// -// Created by Joseph Moran on 10/20/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -// Implements the bolus insulin delivery table for 0x1A command (https://github.com/openaps/openomni/wiki/Command-1A-Table-2) - -public struct BolusDeliveryTable { - static let segMinutes = 30 - static let maxDurationHours = 8 - - let entries: [InsulinTableEntry] - - public init(entries: [InsulinTableEntry]) { - self.entries = entries - } - - public init(units: Double, extendedUnits: Double = 0.0, extendedDuration: TimeInterval = 0) { - let immediatePulses = Int(round(units / Pod.pulseSize)) - let extendedPulses = Int(round(extendedUnits / Pod.pulseSize)) - let duration: TimeInterval - - let maxExtendedDuration: TimeInterval = .hours(Double(min(extendedPulses, BolusDeliveryTable.maxDurationHours))) - if extendedDuration > maxExtendedDuration { - // maximum extended bolus duration of one extended pulse per hour capped at 8 hours - duration = maxExtendedDuration - } else { - duration = extendedDuration - } - - self.entries = generateBolusTable(immediatePulses: immediatePulses, extendedPulses: extendedPulses, extendedDuration: duration) - } - - public func numSegments() -> Int { - return entries.reduce(0) { $0 + $1.segments } - } -} - -// Returns the bolus insulin delivery table for the specified bolus parameters as per the PDM. -// See https://github.com/openaps/openomni/wiki/Command-1A-Table-2#Advanced-Extended-Bolus-Encoding for details. -fileprivate func generateBolusTable(immediatePulses: Int, extendedPulses: Int, extendedDuration: TimeInterval) -> [InsulinTableEntry] { - var tableEntries = [InsulinTableEntry]() - - if extendedPulses == 0 || extendedDuration == 0 { - // trivial immediate bolus case ($0ppp) - let entry = InsulinTableEntry(segments: 1, pulses: immediatePulses, alternateSegmentPulse: false) - tableEntries.append(entry) - return tableEntries - } - - // Extended (square wave) bolus or combination (dual wave) bolus case - let ePulsesPerSeg = computeExtendedPulsesPerSeg(extendedPulses: extendedPulses, duration: extendedDuration) - let nseg = ePulsesPerSeg.count - - // The first entry is special as its pulses value always matches the # immediate pulses, - // but it also describes the first 1/2 hour of the extended bolus when the # of extended - // pulses in the first 1/2 hour is one more or the same as the # of immediate pulses. - var pulses = immediatePulses - var segs = 1 - var alternateSegmentPulse = false - if ePulsesPerSeg[0] - 1 == immediatePulses { - // $18ii case - segs += 1 - alternateSegmentPulse = true - } else if ePulsesPerSeg[0] == immediatePulses { - // $x0ii case - segs += 1 - if immediatePulses != 0 { - segs += numMatch(ePulsesPerSeg: ePulsesPerSeg, idx: 0, val: immediatePulses) - } - } // else $00ii case describing just the immediate bolus portion -- nothing to adjust - - let entry = InsulinTableEntry(segments: segs, pulses: pulses, alternateSegmentPulse: alternateSegmentPulse) - tableEntries.append(entry) - - var remainingPulses = (immediatePulses + extendedPulses) - (segs * pulses) - if alternateSegmentPulse { - remainingPulses -= segs/2 - } - - var idx: Int - if alternateSegmentPulse { - idx = 1 - } else { - idx = segs - 1 - } - - // Step through the remaining extended pulses per segment array to generate and append the appropriate insulin table entries - let basePulsesPerSeg = Int(extendedPulses / nseg) // truncated to whole pulses per half hour segment - while idx < nseg && remainingPulses > 0 { - segs = 1 - alternateSegmentPulse = false - pulses = basePulsesPerSeg - if idx < nseg - 1 && ePulsesPerSeg[idx] == pulses && ePulsesPerSeg[idx + 1] == pulses + 1 { - // $n8bb - let numAltPairs = numAltPairMatch(ePulsesPerSeg: ePulsesPerSeg, idx: idx, val: pulses) - alternateSegmentPulse = true - segs += (numAltPairs * 2) - 1 - idx += (numAltPairs * 2) - 1 - remainingPulses -= segs/2 - } else { - // $n0bb - pulses = ePulsesPerSeg[idx] - let numMatched = numMatch(ePulsesPerSeg: ePulsesPerSeg, idx: idx, val: pulses) - if numMatched > 0 { - segs += numMatched - idx += numMatched - } - } - - let entry = InsulinTableEntry(segments: segs, pulses: pulses, alternateSegmentPulse: alternateSegmentPulse) - tableEntries.append(entry) - - idx += 1 - remainingPulses -= segs * pulses - } - - return tableEntries -} - -// Returns an array of pulses to be delivered for each half hour segment for extendedPulses spaced over the given duration -fileprivate func computeExtendedPulsesPerSeg(extendedPulses: Int, duration: TimeInterval) -> [Int] { - let nseg = Int(ceil(duration / .minutes(BolusDeliveryTable.segMinutes))) - let pulseInterval = duration / Double(extendedPulses) - - var ePulsesPerSeg = Array(repeating: 0, count: nseg) - var t = pulseInterval - var ePulses = 0 - for seg in 0.. segTimeStart && t <= segTimeEnd { - ePulsesPerSeg[seg] += 1 - ePulses += 1 - } - t += pulseInterval - } - if t > duration { - break - } - } - - // Any remaining pulses are added to the last half hour segment - if extendedPulses > ePulses { - ePulsesPerSeg[nseg - 1] += extendedPulses - ePulses - } - - return ePulsesPerSeg -} - -// Returns the number of consecutive matched [val, val+1] pairs starting at ePulsesPerSeg[idx] -fileprivate func numAltPairMatch(ePulsesPerSeg: [Int], idx: Int, val: Int) -> Int { - var cnt = 0 - - for i in stride(from: idx, to: ePulsesPerSeg.count - 1, by: 2) { - if ePulsesPerSeg[i] != val || ePulsesPerSeg[i + 1] != val + 1 { - break - } - cnt += 1 - } - return cnt -} - -// Returns the number of consecutive elements matching val starting at ePulsesPerSeg[idx] -fileprivate func numMatch(ePulsesPerSeg: [Int], idx: Int, val: Int) -> Int { - var cnt = 0 - - for i in idx.. UInt16 { - - var acc: UInt16 = 0 - for byte in self { - let idx = (acc ^ UInt16(byte)) & 0xff - acc = (acc >> 8) ^ crc16Table[Int(idx)] - } - return acc - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/FaultEventCode.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/FaultEventCode.swift deleted file mode 100644 index 8ec484f80..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/FaultEventCode.swift +++ /dev/null @@ -1,433 +0,0 @@ -// -// FaultEventCode.swift -// OmniKit -// -// Created by Pete Schwamb on 9/28/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - - -public struct FaultEventCode: CustomStringConvertible, Equatable { - public let rawValue: UInt8 - - public enum FaultEventType: UInt8 { - case noFaults = 0x00 - case failedFlashErase = 0x01 - case failedFlashStore = 0x02 - case tableCorruptionBasalSubcommand = 0x03 - case basalPulseTableCorruption = 0x04 - case corruptionByte720 = 0x05 - case dataCorruptionInTestRTCInterrupt = 0x06 - case rtcInterruptHandlerInconsistentState = 0x07 - case valueGreaterThan8 = 0x08 - case invalidBeepRepeatPattern = 0x09 - case bf0notEqualToBF1 = 0x0A - case tableCorruptionTempBasalSubcommand = 0x0B - - case resetDueToCOP = 0x0D - case resetDueToIllegalOpcode = 0x0E - case resetDueToIllegalAddress = 0x0F - case resetDueToSAWCOP = 0x10 - case corruptionInByte_866 = 0x11 - case resetDueToLVD = 0x12 - case messageLengthTooLong = 0x13 - case occluded = 0x14 - case corruptionInWord129 = 0x15 - case corruptionInByte868 = 0x16 - case corruptionInAValidatedTable = 0x17 - case reservoirEmpty = 0x18 - case badPowerSwitchArrayValue1 = 0x19 - case badPowerSwitchArrayValue2 = 0x1A - case badLoadCnthValue = 0x1B - case exceededMaximumPodLife80Hrs = 0x1C - case badStateCommand1AScheduleParse = 0x1D - case unexpectedStateInRegisterUponReset = 0x1E - case wrongSummaryForTable129 = 0x1F - case validateCountErrorWhenBolusing = 0x20 - case badTimerVariableState = 0x21 - case unexpectedRTCModuleValueDuringReset = 0x22 - case problemCalibrateTimer = 0x23 - case tickcntErrorRTC = 0x24 - case tickFailure = 0x25 - case rtcInterruptHandlerUnexpectedCall = 0x26 - case missing2hourAlertToFillTank = 0x27 - case faultEventSetupPod = 0x28 - case autoOff0 = 0x29 - case autoOff1 = 0x2A - case autoOff2 = 0x2B - case autoOff3 = 0x2C - case autoOff4 = 0x2D - case autoOff5 = 0x2E - case autoOff6 = 0x2F - case autoOff7 = 0x30 - case insulinDeliveryCommandError = 0x31 - case badValueStartupTest = 0x32 - case connectedPodCommandTimeout = 0x33 - case resetFromUnknownCause = 0x34 - case vetoNotSet = 0x35 - case errorFlashInitialization = 0x36 - case badPiezoValue = 0x37 - case unexpectedValueByte358 = 0x38 - case problemWithLoad1and2 = 0x39 - case aGreaterThan7inMessage = 0x3A - case failedTestSawReset = 0x3B - case testInProgress = 0x3C - case problemWithPumpAnchor = 0x3D - case errorFlashWrite = 0x3E - - case encoderCountTooHigh = 0x40 - case encoderCountExcessiveVariance = 0x41 - case encoderCountTooLow = 0x42 - case encoderCountProblem = 0x43 - case checkVoltageOpenWire1 = 0x44 - case checkVoltageOpenWire2 = 0x45 - case problemWithLoad1and2type46 = 0x46 - case problemWithLoad1and2type47 = 0x47 - case badTimerCalibration = 0x48 - case badTimerRatios = 0x49 - case badTimerValues = 0x4A - case trimICSTooCloseTo0x1FF = 0x4B - case problemFindingBestTrimValue = 0x4C - case badSetTPM1MultiCasesValue = 0x4D - case sawTrimError = 0x4E - case unexpectedRFErrorFlagDuringReset = 0x4F - case timerPulseWidthModulatorOverflow = 0x50 - case tickcntError = 0x51 - case badRfmXtalStart = 0x52 - case badRxSensitivity = 0x53 - case packetFrameLengthTooLong = 0x54 - case unexpectedIRQHighinTimerTick = 0x55 - case unexpectedIRQLowinTimerTick = 0x56 - case badArgToGetEntry = 0x57 - case badArgToUpdate37ATable = 0x58 - case errorUpdating37ATable = 0x59 - case occlusionCheckValueTooHigh = 0x5A - case loadTableCorruption = 0x5B - case primeOpenCountTooLow = 0x5C - case badValueByte109 = 0x5D - case disableFlashSecurityFailed = 0x5E - case checkVoltageFailure = 0x5F - case occlusionCheckStartup1 = 0x60 - case occlusionCheckStartup2 = 0x61 - case occlusionCheckTimeouts1 = 0x62 - - case occlusionCheckTimeouts2 = 0x66 - case occlusionCheckTimeouts3 = 0x67 - case occlusionCheckPulseIssue = 0x68 - case occlusionCheckBolusProblem = 0x69 - case occlusionCheckAboveThreshold = 0x6A - - case basalUnderInfusion = 0x80 - case basalOverInfusion = 0x81 - case tempBasalUnderInfusion = 0x82 - case tempBasalOverInfusion = 0x83 - case bolusUnderInfusion = 0x84 - case bolusOverInfusion = 0x85 - case basalOverInfusionPulse = 0x86 - case tempBasalOverInfusionPulse = 0x87 - case bolusOverInfusionPulse = 0x88 - case immediateBolusOverInfusionPulse = 0x89 - case extendedBolusOverInfusionPulse = 0x8A - case corruptionOfTables = 0x8B - case unrecognizedPulse = 0x8D - case syncWithoutTempActive = 0x8E - case command1AParseUnexpectedFailed = 0x8F - case illegalChanParam = 0x90 - case basalPulseChanInactive = 0x91 - case tempPulseChanInactive = 0x92 - case bolusPulseChanInactive = 0x93 - case intSemaphoreNotSet = 0x94 - case illegalInterLockChan = 0x95 - case badStateInClearBolusIST2AndVars = 0x96 - case badStateInMaybeInc33D = 0x97 - case valuesDoNotMatch = 0xFF - } - - public var faultType: FaultEventType? { - return FaultEventType(rawValue: rawValue) - } - - public init(rawValue: UInt8) { - self.rawValue = rawValue - } - - public var faultDescription: String { - switch faultType { - case .noFaults: - return "No fault" - case .failedFlashErase: - return "Flash erase failed" - case .failedFlashStore: - return "Flash store failed" - case .tableCorruptionBasalSubcommand: - return "Basal subcommand table corruption" - case .basalPulseTableCorruption: - return "Basal pulse table corruption" - case .corruptionByte720: - return "Corruption in byte_720" - case .dataCorruptionInTestRTCInterrupt: - return "Data corruption error in test_RTC_interrupt" - case .rtcInterruptHandlerInconsistentState: - return "RTC interrupt handler called with inconstent state" - case .valueGreaterThan8: - return "Value > 8" - case .invalidBeepRepeatPattern: - return "Invalid beep repeat pattern" - case .bf0notEqualToBF1: - return "Corruption in byte_BF0" - case .tableCorruptionTempBasalSubcommand: - return "Temp basal subcommand table corruption" - case .resetDueToCOP: - return "Reset due to COP" - case .resetDueToIllegalOpcode: - return "Reset due to illegal opcode" - case .resetDueToIllegalAddress: - return "Reset due to illegal address" - case .resetDueToSAWCOP: - return "Reset due to SAWCOP" - case .corruptionInByte_866: - return "Corruption in byte_866" - case .resetDueToLVD: - return "Reset due to LVD" - case .messageLengthTooLong: - return "Message length too long" - case .occluded: - return "Occluded" - case .corruptionInWord129: - return "Corruption in word_129 table/word_86A/dword_86E" - case .corruptionInByte868: - return "Corruption in byte_868" - case .corruptionInAValidatedTable: - return "Corruption in a validated table" - case .reservoirEmpty: - return "Reservoir empty or exceeded maximum pulse delivery" - case .badPowerSwitchArrayValue1: - return "Bad Power Switch Array Status and Control Register value 1 before starting pump" - case .badPowerSwitchArrayValue2: - return "Bad Power Switch Array Status and Control Register value 2 before starting pump" - case .badLoadCnthValue: - return "Bad LOADCNTH value when running pump" - case .exceededMaximumPodLife80Hrs: - return "Exceeded maximum Pod life of 80 hours" - case .badStateCommand1AScheduleParse: - return "Unexpected internal state in command_1A_schedule_parse_routine_wrapper" - case .unexpectedStateInRegisterUponReset: - return "Unexpected commissioned state in status and control register upon reset" - case .wrongSummaryForTable129: - return "Sum mismatch for word_129 table" - case .validateCountErrorWhenBolusing: - return "Validate encoder count error when bolusing" - case .badTimerVariableState: - return "Bad timer variable state" - case .unexpectedRTCModuleValueDuringReset: - return "Unexpected RTC Modulo Register value during reset" - case .problemCalibrateTimer: - return "Problem in calibrate_timer_case_3" - case .tickcntErrorRTC: - return "Tick count error RTC" - case .tickFailure: - return "Tick failure" - case .rtcInterruptHandlerUnexpectedCall: - return "RTC interrupt handler unexpectedly called" - case .missing2hourAlertToFillTank: - return "Failed to set up 2 hour alert for tank fill operation" - case .faultEventSetupPod: - return "Bad arg or state in update_insulin_variables, verify_and_start_pump or main_loop_control_pump" - case .autoOff0: - return "Alert #0 auto-off timeout" - case .autoOff1: - return "Alert #1 auto-off timeout" - case .autoOff2: - return "Alert #2 auto-off timeout" - case .autoOff3: - return "Alert #3 auto-off timeout" - case .autoOff4: - return "Alert #4 auto-off timeout" - case .autoOff5: - return "Alert #5 auto-off timeout" - case .autoOff6: - return "Alert #6 auto-off timeout" - case .autoOff7: - return "Alert #7 auto-off timeout" - case .insulinDeliveryCommandError: - return "Incorrect pod state for command or error during insulin command setup" - case .badValueStartupTest: - return "Bad value during startup testing" - case .connectedPodCommandTimeout: - return "Connected Pod command timeout" - case .resetFromUnknownCause: - return "Reset from unknown cause" - case .vetoNotSet: - return "Veto not set" - case .errorFlashInitialization: - return "Flash initialization error" - case .badPiezoValue: - return "Bad piezo value" - case .unexpectedValueByte358: - return "Unexpected byte_358 value" - case .problemWithLoad1and2: - return "Problem with LOAD1/LOAD2" - case .aGreaterThan7inMessage: - return "A > 7 in message processing" - case .failedTestSawReset: - return "SAW reset testing fail" - case .testInProgress: - return "test in progress" - case .problemWithPumpAnchor: - return "Problem with pump anchor" - case .errorFlashWrite: - return "Flash initialization or write error" - case .encoderCountTooHigh: - return "Encoder count too high" - case .encoderCountExcessiveVariance: - return "Encoder count excessive variance" - case .encoderCountTooLow: - return "Encoder count too low" - case .encoderCountProblem: - return "Encoder count problem" - case .checkVoltageOpenWire1: - return "Check voltage open wire 1 problem" - case .checkVoltageOpenWire2: - return "Check voltage open wire 2 problem" - case .problemWithLoad1and2type46: - return "Problem with LOAD1/LOAD2" - case .problemWithLoad1and2type47: - return "Problem with LOAD1/LOAD2" - case .badTimerCalibration: - return "Bad timer calibration" - case .badTimerRatios: - return "Bad timer values: COP timer ratio bad" - case .badTimerValues: - return "Bad timer values" - case .trimICSTooCloseTo0x1FF: - return "ICS trim too close to 0x1FF" - case .problemFindingBestTrimValue: - return "find_best_trim_value problem" - case .badSetTPM1MultiCasesValue: - return "Bad set_TPM1_multi_cases value" - case .unexpectedRFErrorFlagDuringReset: - return "Unexpected TXSCR2 RF Tranmission Error Flag set during reset" - case .timerPulseWidthModulatorOverflow: - return "Timer pulse-width modulator overflow" - case .tickcntError: - return "Bad tick count state before starting pump" - case .badRfmXtalStart: - return "TXOK issue in process_input_buffer" - case .badRxSensitivity: - return "Bad Rx word_107 sensitivity value during input message processing" - case .packetFrameLengthTooLong: - return "Packet frame length too long" - case .unexpectedIRQHighinTimerTick: - return "Unexpected IRQ high in timer_tick" - case .unexpectedIRQLowinTimerTick: - return "Unexpected IRQ low in timer_tick" - case .badArgToGetEntry: - return "Corrupt constants table at byte_37A[] or flash byte_4036[]" - case .badArgToUpdate37ATable: - return "Bad argument to update_37A_table" - case .errorUpdating37ATable: - return "Error updating constants byte_37A table" - case .occlusionCheckValueTooHigh: - return "Occlusion check value too high for detection" - case .loadTableCorruption: - return "Load table corruption" - case .primeOpenCountTooLow: - return "Prime open count too low" - case .badValueByte109: - return "Bad byte_109 value" - case .disableFlashSecurityFailed: - return "Write flash byte to disable flash security failed" - case .checkVoltageFailure: - return "Two check voltage failures before starting pump" - case .occlusionCheckStartup1: - return "Occlusion check startup problem 1" - case .occlusionCheckStartup2: - return "Occlusion check startup problem 2" - case .occlusionCheckTimeouts1: - return "Occlusion check excess timeouts 1" - case .occlusionCheckTimeouts2: - return "Occlusion check excess timeouts 2" - case .occlusionCheckTimeouts3: - return "Occlusion check excess timeouts 3" - case .occlusionCheckPulseIssue: - return "Occlusion check pulse issue" - case .occlusionCheckBolusProblem: - return "Occlusion check bolus problem" - case .occlusionCheckAboveThreshold: - return "Occlusion check above threshold" - case .basalUnderInfusion: - return "Basal under infusion" - case .basalOverInfusion: - return "Basal over infusion" - case .tempBasalUnderInfusion: - return "Temp basal under infusion" - case .tempBasalOverInfusion: - return "Temp basal over infusion" - case .bolusUnderInfusion: - return "Bolus under infusion" - case .bolusOverInfusion: - return "Bolus over infusion" - case .basalOverInfusionPulse: - return "Basal over infusion pulse" - case .tempBasalOverInfusionPulse: - return "Temp basal over infusion pulse" - case .bolusOverInfusionPulse: - return "Bolus over infusion pulse" - case .immediateBolusOverInfusionPulse: - return "Immediate bolus under infusion pulse" - case .extendedBolusOverInfusionPulse: - return "Extended bolus over infusion pulse" - case .corruptionOfTables: - return "Corruption of $283/$2E3/$315 tables" - case .unrecognizedPulse: - return "Bad pulse value to verify_and_start_pump" - case .syncWithoutTempActive: - return "Pump sync req 5 with no temp basal active" - case .command1AParseUnexpectedFailed: - return "Command 1A parse routine unexpected failed" - case .illegalChanParam: - return "Bad parameter for $283/$2E3/$315 channel table specification" - case .basalPulseChanInactive: - return "Pump basal request with basal IST not set" - case .tempPulseChanInactive: - return "Pump temp basal request with temp basal IST not set" - case .bolusPulseChanInactive: - return "Pump bolus request and bolus IST not set" - case .intSemaphoreNotSet: - return "Bad table specifier field6 in 1A command" - case .illegalInterLockChan: - return "Illegal interlock channel" - case .badStateInClearBolusIST2AndVars: - return "Bad variable state in clear_Bolus_IST2_and_vars" - case .badStateInMaybeInc33D: - return "Bad variable state in maybe_inc_33D" - default: - return "Unknown fault code" - } - } - - public var description: String { - return String(format: "Fault Event Code 0x%02x: %@", rawValue, faultDescription) - } - - public var localizedDescription: String { - if let faultType = faultType { - switch faultType { - case .noFaults: - return LocalizedString("No faults", comment: "Description for Fault Event Code .noFaults") - case .reservoirEmpty: - return LocalizedString("Empty reservoir", comment: "Description for Empty reservoir pod fault") - case .exceededMaximumPodLife80Hrs: - return LocalizedString("Pod expired", comment: "Description for Pod expired pod fault") - case .occluded: - return LocalizedString("Occlusion detected", comment: "Description for Occlusion detected pod fault") - default: - return String(format: LocalizedString("Internal pod fault %1$03d", comment: "The format string for Internal pod fault (1: The fault code value)"), rawValue) - } - } else { - return String(format: LocalizedString("Unknown pod fault %1$03d", comment: "The format string for Unknown pod fault (1: The fault code value)"), rawValue) - } - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/InsulinTableEntry.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/InsulinTableEntry.swift deleted file mode 100644 index 403ddbf04..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/InsulinTableEntry.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// InsulinTableEntry.swift -// OmniKit -// -// Created by Joseph Moran on 10/26/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -// -// InsulinTableEntry describes the common InsulinScheduleElement in all the 0x1A insulin delivery commands. -// See https://github.com/openaps/openomni/wiki/Command-1A-Insulin-Schedule#InsulinScheduleElement for details. -// Formerly BasalTableEntry when only being used for the basal and temporary basal commands. -// -public struct InsulinTableEntry { - let segments: Int - let pulses: Int - let alternateSegmentPulse: Bool - - public init(encodedData: Data) { - segments = Int(encodedData[0] >> 4) + 1 - pulses = (Int(encodedData[0] & 0b11) << 8) + Int(encodedData[1]) - alternateSegmentPulse = (encodedData[0] >> 3) & 0x1 == 1 - } - - public init(segments: Int, pulses: Int, alternateSegmentPulse: Bool) { - self.segments = segments - self.pulses = pulses - self.alternateSegmentPulse = alternateSegmentPulse - } - - public var data: Data { - let pulsesHighBits = UInt8((pulses >> 8) & 0b11) - let pulsesLowBits = UInt8(pulses & 0xff) - return Data([ - UInt8((segments - 1) << 4) + UInt8((alternateSegmentPulse ? 1 : 0) << 3) + pulsesHighBits, - UInt8(pulsesLowBits) - ]) - } - - public func checksum() -> UInt16 { - let checksumPerSegment = (pulses & 0xff) + (pulses >> 8) - return UInt16(checksumPerSegment * segments + (alternateSegmentPulse ? segments / 2 : 0)) - } -} - -extension InsulinTableEntry: CustomDebugStringConvertible { - public var debugDescription: String { - return "InsulinTableEntry(segments:\(segments), pulses:\(pulses), alternateSegmentPulse:\(alternateSegmentPulse))" - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/Message.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/Message.swift deleted file mode 100644 index 7eeca2888..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/Message.swift +++ /dev/null @@ -1,134 +0,0 @@ -// -// Message.swift -// OmniKit -// -// Created by Pete Schwamb on 10/14/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - -public enum MessageError: Error { - case notEnoughData - case invalidCrc - case invalidSequence - case invalidAddress(address: UInt32) - case parsingError(offset: Int, data: Data, error: Error) - case unknownValue(value: UInt8, typeDescription: String) - case validationFailed(description: String) -} - -extension MessageError: LocalizedError { - public var errorDescription: String? { - switch self { - case .notEnoughData: - return LocalizedString("Not enough data", comment: "Description for MessageError notEnoughData") - case .invalidCrc: - return LocalizedString("Invalid CRC", comment: "Description for MessageError invalidCrc") - case .invalidSequence: - return LocalizedString("Unexpected message sequence number", comment: "Description for MessageError invalidSequence") - case .invalidAddress(address: let address): - return String(format: LocalizedString("Invalid address: (%1$@)", comment: "Description for MessageError invalidAddress"), String(format: "%08x", address)) - case .parsingError(let offset, let data, let error): - return String(format: LocalizedString("Parsing Error: %1$@ in (%2$@)", comment: "Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset)"), String(describing: error), data.suffix(from: offset).hexadecimalString) - case .unknownValue(let value, let typeDescription): - return String(format: LocalizedString("Unknown Value (%1$@) for type %2$@", comment: "Format string for description of MessageError unknownValue. (1: value) (2: Type)"), String(describing: value), typeDescription) - case .validationFailed(let description): - return String(format: LocalizedString("Validation failed: %1$@", comment: "Format string for description of MessageError validationFailed. (1: description of validation failure)"), description) - } - } -} - -struct Message { - let address: UInt32 - let messageBlocks: [MessageBlock] - let sequenceNum: Int - let expectFollowOnMessage: Bool - - init(address: UInt32, messageBlocks: [MessageBlock], sequenceNum: Int, expectFollowOnMessage: Bool = false) { - self.address = address - self.messageBlocks = messageBlocks - self.sequenceNum = sequenceNum - self.expectFollowOnMessage = expectFollowOnMessage - } - - init(encodedData: Data, checkCRC: Bool = true) throws { - guard encodedData.count >= 10 else { - throw MessageError.notEnoughData - } - self.address = encodedData[0...].toBigEndian(UInt32.self) - let b9 = encodedData[4] - let bodyLen = encodedData[5] - - if bodyLen > encodedData.count - 8 { - throw MessageError.notEnoughData - } - - self.expectFollowOnMessage = (b9 & 0b10000000) != 0 - self.sequenceNum = Int((b9 >> 2) & 0b1111) - let crc = (UInt16(encodedData[encodedData.count-2]) << 8) + UInt16(encodedData[encodedData.count-1]) - let msgWithoutCrc = encodedData.prefix(encodedData.count - 2) - if checkCRC { - guard msgWithoutCrc.crc16() == crc else { - throw MessageError.invalidCrc - } - } - self.messageBlocks = try Message.decodeBlocks(data: Data(msgWithoutCrc.suffix(from: 6))) - } - - static private func decodeBlocks(data: Data) throws -> [MessageBlock] { - var blocks = [MessageBlock]() - var idx = 0 - repeat { - guard let blockType = MessageBlockType(rawValue: data[idx]) else { - throw MessageBlockError.unknownBlockType(rawVal: data[idx]) - } - do { - let block = try blockType.blockType.init(encodedData: Data(data.suffix(from: idx))) - blocks.append(block) - idx += Int(block.data.count) - } catch (let error) { - throw MessageError.parsingError(offset: idx, data: data.suffix(from: idx), error: error) - } - } while idx < data.count - return blocks - } - - func encoded() -> Data { - var bytes = Data(bigEndian: address) - - var cmdData = Data() - for cmd in messageBlocks { - cmdData.append(cmd.data) - } - - let b9: UInt8 = ((expectFollowOnMessage ? 1 : 0) << 7) + (UInt8(sequenceNum & 0b1111) << 2) + UInt8((cmdData.count >> 8) & 0b11) - bytes.append(b9) - bytes.append(UInt8(cmdData.count & 0xff)) - - var data = Data(bytes) + cmdData - let crc: UInt16 = data.crc16() - data.appendBigEndian(crc) - return data - } - - var fault: DetailedStatus? { - if messageBlocks.count > 0 && messageBlocks[0].blockType == .podInfoResponse, - let infoResponse = messageBlocks[0] as? PodInfoResponse, - infoResponse.podInfoResponseSubType == .detailedStatus, - let detailedStatus = infoResponse.podInfo as? DetailedStatus, - detailedStatus.isFaulted - { - return detailedStatus - } else { - return nil - } - } -} - -extension Message: CustomDebugStringConvertible { - var debugDescription: String { - let sequenceNumStr = String(format: "%02d", sequenceNum) - return "Message(\(Data(bigEndian: address).hexadecimalString) seq:\(sequenceNumStr) \(messageBlocks))" - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/AcknowledgeAlertCommand.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/AcknowledgeAlertCommand.swift deleted file mode 100644 index 038e56dfd..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/AcknowledgeAlertCommand.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// AcknowledgeAlertCommand.swift -// OmniKit -// -// Created by Eelke Jager on 18/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct AcknowledgeAlertCommand : NonceResyncableMessageBlock { - // OFF 1 2 3 4 5 6 - // 11 05 NNNNNNNN MM - - public let blockType: MessageBlockType = .acknowledgeAlert - public let length: UInt8 = 5 - public var nonce: UInt32 - public let alerts: AlertSet - - public init(nonce: UInt32, alerts: AlertSet) { - self.nonce = nonce - self.alerts = alerts - } - - public init(encodedData: Data) throws { - if encodedData.count < 7 { - throw MessageBlockError.notEnoughData - } - self.nonce = encodedData[2...].toBigEndian(UInt32.self) - self.alerts = AlertSet(rawValue: encodedData[6]) - } - - public var data: Data { - var data = Data([ - blockType.rawValue, - length - ]) - data.appendBigEndian(nonce) - data.append(alerts.rawValue) - return data - } -} - -extension AcknowledgeAlertCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "AcknowledgeAlertCommand(blockType:\(blockType), length:\(length), alerts:\(alerts))" - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/AssignAddressCommand.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/AssignAddressCommand.swift deleted file mode 100644 index c18c81205..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/AssignAddressCommand.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// AssignAddressCommand.swift -// OmniKit -// -// Created by Pete Schwamb on 2/12/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct AssignAddressCommand : MessageBlock { - - public let blockType: MessageBlockType = .assignAddress - public let length: Int = 6 - - let address: UInt32 - - public var data: Data { - var data = Data([ - blockType.rawValue, - 4 - ]) - data.appendBigEndian(self.address) - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < length { - throw MessageBlockError.notEnoughData - } - - self.address = encodedData[2...].toBigEndian(UInt32.self) - } - - public init(address: UInt32) { - self.address = address - } -} - -extension AssignAddressCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "AssignAddressCommand(address:\(Data(bigEndian: address).hexadecimalString))" - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/BasalScheduleExtraCommand.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/BasalScheduleExtraCommand.swift deleted file mode 100644 index 021ebecee..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/BasalScheduleExtraCommand.swift +++ /dev/null @@ -1,109 +0,0 @@ -// -// BasalScheduleExtraCommand.swift -// OmniKit -// -// Created by Pete Schwamb on 3/30/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct BasalScheduleExtraCommand : MessageBlock { - - public let blockType: MessageBlockType = .basalScheduleExtra - - public let acknowledgementBeep: Bool - public let completionBeep: Bool - public let programReminderInterval: TimeInterval - public let currentEntryIndex: UInt8 - public let remainingPulses: Double - public let delayUntilNextTenthOfPulse: TimeInterval - public let rateEntries: [RateEntry] - - public var data: Data { - let beepOptions = (UInt8(programReminderInterval.minutes) & 0x3f) + (completionBeep ? (1<<6) : 0) + (acknowledgementBeep ? (1<<7) : 0) - var data = Data([ - blockType.rawValue, - UInt8(8 + rateEntries.count * 6), - beepOptions, - currentEntryIndex - ]) - data.appendBigEndian(UInt16(round(remainingPulses * 10))) - data.appendBigEndian(UInt32(round(delayUntilNextTenthOfPulse.milliseconds * 1000))) - for entry in rateEntries { - data.append(entry.data) - } - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 14 { - throw MessageBlockError.notEnoughData - } - let length = encodedData[1] - let numEntries = (length - 8) / 6 - - acknowledgementBeep = encodedData[2] & (1<<7) != 0 - completionBeep = encodedData[2] & (1<<6) != 0 - programReminderInterval = TimeInterval(minutes: Double(encodedData[2] & 0x3f)) - - currentEntryIndex = encodedData[3] - remainingPulses = Double(encodedData[4...].toBigEndian(UInt16.self)) / 10.0 - let timerCounter = encodedData[6...].toBigEndian(UInt32.self) - delayUntilNextTenthOfPulse = TimeInterval(hundredthsOfMilliseconds: Double(timerCounter)) - var entries = [RateEntry]() - for entryIndex in (0..= t && scheduleOffsetNearestSecond <= t + rateEntryDuration { - self.currentEntryIndex = entryIndex - - let timeRemaining = (t + rateEntryDuration) - scheduleOffsetNearestSecond - self.delayUntilNextTenthOfPulse = timeRemaining.truncatingRemainder(dividingBy: (rateEntry.delayBetweenPulses / 10)) - - let pulsesRemaining = rateEntry.totalPulses * (timeRemaining / rateEntryDuration) - self.remainingPulses = pulsesRemaining == 0 ? 0.1 : ceil(pulsesRemaining * 10) / 10 - return - } - t += rateEntryDuration - entryIndex += 1 - } - fatalError("RateEntry schedule incomplete") - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/BeepConfigCommand.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/BeepConfigCommand.swift deleted file mode 100644 index c58e282b2..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/BeepConfigCommand.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// BeepConfigCommand.swift -// OmniKit -// -// Created by Joseph Moran on 5/12/19. -// Copyright © 2019 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct BeepConfigCommand : MessageBlock { - // OFF 1 2 3 4 5 - // 1e 04 AABBCCDD - - public let blockType: MessageBlockType = .beepConfig - public let beepType: BeepType - public let basalCompletionBeep: Bool - public let basalIntervalBeep: TimeInterval - public let tempBasalCompletionBeep: Bool - public let tempBasalIntervalBeep: TimeInterval - public let bolusCompletionBeep: Bool - public let bolusIntervalBeep: TimeInterval - - public init(beepType: BeepType, basalCompletionBeep: Bool = false, basalIntervalBeep: TimeInterval = 0, tempBasalCompletionBeep: Bool = false, tempBasalIntervalBeep: TimeInterval = 0, bolusCompletionBeep: Bool = false, bolusIntervalBeep: TimeInterval = 0) { - self.beepType = beepType - self.basalCompletionBeep = basalCompletionBeep - self.basalIntervalBeep = basalIntervalBeep - self.tempBasalCompletionBeep = tempBasalCompletionBeep - self.tempBasalIntervalBeep = tempBasalIntervalBeep - self.bolusCompletionBeep = bolusCompletionBeep - self.bolusIntervalBeep = bolusIntervalBeep - } - - public init(encodedData: Data) throws { - if encodedData.count < 6 { - throw MessageBlockError.notEnoughData - } - if let beepType = BeepType.init(rawValue: encodedData[2]) { - self.beepType = beepType - } else { - throw MessageBlockError.parseError - } - self.basalCompletionBeep = encodedData[3] & (1<<6) != 0 - self.basalIntervalBeep = TimeInterval(minutes: Double(encodedData[3] & 0x3f)) - self.tempBasalCompletionBeep = encodedData[4] & (1<<6) != 0 - self.tempBasalIntervalBeep = TimeInterval(minutes: Double(encodedData[4] & 0x3f)) - self.bolusCompletionBeep = encodedData[5] & (1<<6) != 0 - self.bolusIntervalBeep = TimeInterval(minutes: Double(encodedData[5] & 0x3f)) - } - - public var data: Data { - var data = Data([ - blockType.rawValue, - 4, - ]) - data.append(beepType.rawValue) - data.append((basalCompletionBeep ? (1<<6) : 0) + (UInt8(basalIntervalBeep.minutes) & 0x3f)) - data.append((tempBasalCompletionBeep ? (1<<6) : 0) + (UInt8(tempBasalIntervalBeep.minutes) & 0x3f)) - data.append((bolusCompletionBeep ? (1<<6) : 0) + (UInt8(bolusIntervalBeep.minutes) & 0x3f)) - return data - } -} - -extension BeepConfigCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "BeepConfigCommand(beepType:\(beepType), basalIntervalBeep:\(basalIntervalBeep), tempBasalCompletionBeep:\(tempBasalCompletionBeep), tempBasalIntervalBeep:\(tempBasalIntervalBeep), bolusCompletionBeep:\(bolusCompletionBeep), bolusIntervalBeep:\(bolusIntervalBeep))" - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/BolusExtraCommand.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/BolusExtraCommand.swift deleted file mode 100644 index a32670f49..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/BolusExtraCommand.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// BolusExtraCommand.swift -// OmniKit -// -// Created by Pete Schwamb on 2/24/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct BolusExtraCommand : MessageBlock { - - public let blockType: MessageBlockType = .bolusExtra - - public let acknowledgementBeep: Bool - public let completionBeep: Bool - public let programReminderInterval: TimeInterval - public let units: Double - public let timeBetweenPulses: TimeInterval - public let extendedUnits: Double - public let extendedDuration: TimeInterval - - // 17 0d 7c 1770 00030d40 0000 00000000 - // 0 1 2 3 5 9 13 - public var data: Data { - let beepOptions = (UInt8(programReminderInterval.minutes) & 0x3f) + (completionBeep ? (1<<6) : 0) + (acknowledgementBeep ? (1<<7) : 0) - - var data = Data([ - blockType.rawValue, - 0x0d, - beepOptions - ]) - - data.appendBigEndian(UInt16(round(units * Pod.pulsesPerUnit * 10))) - data.appendBigEndian(UInt32(timeBetweenPulses.hundredthsOfMilliseconds)) - - let pulseCountX10 = UInt16(round(extendedUnits * Pod.pulsesPerUnit * 10)) - data.appendBigEndian(pulseCountX10) - - let timeBetweenExtendedPulses = pulseCountX10 > 0 ? extendedDuration / (Double(pulseCountX10) / 10) : 0 - data.appendBigEndian(UInt32(timeBetweenExtendedPulses.hundredthsOfMilliseconds)) - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 15 { - throw MessageBlockError.notEnoughData - } - - acknowledgementBeep = encodedData[2] & (1<<7) != 0 - completionBeep = encodedData[2] & (1<<6) != 0 - programReminderInterval = TimeInterval(minutes: Double(encodedData[2] & 0x3f)) - - units = Double(encodedData[3...].toBigEndian(UInt16.self)) / (Pod.pulsesPerUnit * 10) - - let delayCounts = encodedData[5...].toBigEndian(UInt32.self) - timeBetweenPulses = TimeInterval(hundredthsOfMilliseconds: Double(delayCounts)) - - let pulseCountX10 = encodedData[9...].toBigEndian(UInt16.self) - extendedUnits = Double(pulseCountX10) / (Pod.pulsesPerUnit * 10) - - let intervalCounts = encodedData[11...].toBigEndian(UInt32.self) - let timeBetweenExtendedPulses = TimeInterval(hundredthsOfMilliseconds: Double(intervalCounts)) - extendedDuration = timeBetweenExtendedPulses * (Double(pulseCountX10) / 10) - } - - public init(units: Double = 0, timeBetweenPulses: TimeInterval = Pod.secondsPerBolusPulse, extendedUnits: Double = 0.0, extendedDuration: TimeInterval = 0, acknowledgementBeep: Bool = false, completionBeep: Bool = false, programReminderInterval: TimeInterval = 0) { - self.acknowledgementBeep = acknowledgementBeep - self.completionBeep = completionBeep - self.programReminderInterval = programReminderInterval - self.units = units - self.timeBetweenPulses = timeBetweenPulses != 0 ? timeBetweenPulses : Pod.secondsPerBolusPulse - self.extendedUnits = extendedUnits - self.extendedDuration = extendedDuration - } -} - - -extension BolusExtraCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "BolusExtraCommand(units:\(units), timeBetweenPulses:\(timeBetweenPulses), extendedUnits:\(extendedUnits), extendedDuration:\(extendedDuration), acknowledgementBeep:\(acknowledgementBeep), completionBeep:\(completionBeep), programReminderInterval:\(programReminderInterval.minutes))" - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/CancelDeliveryCommand.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/CancelDeliveryCommand.swift deleted file mode 100644 index 065d0dd7c..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/CancelDeliveryCommand.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// CancelDeliveryCommand.swift -// OmniKit -// -// Created by Pete Schwamb on 2/23/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - - -public struct CancelDeliveryCommand : NonceResyncableMessageBlock { - - public let blockType: MessageBlockType = .cancelDelivery - // OFF 1 2 3 4 5 6 - // 1F 05 NNNNNNNN AX - - // Cancel bolus (with confirmation beep) - // 1f 05 be1b741a 64 - - // Cancel temp basal (with confirmation beep) - // 1f 05 f76d34c4 62 - - // Cancel all (before deactivate pod) - // 1f 05 e1f78752 07 - - // Cancel basal & temp basal for a suspend, followed by a configure alerts command (0x19) for alerts 5 & 6 - // 1f 05 50f02312 03 19 10 50f02312 580f 000f 0604 6800 001e 0302 - - public struct DeliveryType: OptionSet, Equatable { - public let rawValue: UInt8 - - public static let none = DeliveryType() - public static let basal = DeliveryType(rawValue: 1 << 0) - public static let tempBasal = DeliveryType(rawValue: 1 << 1) - public static let bolus = DeliveryType(rawValue: 1 << 2) - - public static let allButBasal: DeliveryType = [.tempBasal, .bolus] - public static let all: DeliveryType = [.none, .basal, .tempBasal, .bolus] - - public init(rawValue: UInt8) { - self.rawValue = rawValue - } - - var debugDescription: String { - switch self { - case .none: - return "None" - case .basal: - return "Basal" - case .tempBasal: - return "TempBasal" - case .all: - return "All" - case .allButBasal: - return "AllButBasal" - default: - return "\(self.rawValue)" - } - } - } - - public let deliveryType: DeliveryType - - public let beepType: BeepType - - public var nonce: UInt32 - - public var data: Data { - var data = Data([ - blockType.rawValue, - 5, - ]) - data.appendBigEndian(nonce) - data.append((beepType.rawValue << 4) + deliveryType.rawValue) - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 7 { - throw MessageBlockError.notEnoughData - } - self.nonce = encodedData[2...].toBigEndian(UInt32.self) - self.deliveryType = DeliveryType(rawValue: encodedData[6] & 0xf) - self.beepType = BeepType(rawValue: encodedData[6] >> 4)! - } - - public init(nonce: UInt32, deliveryType: DeliveryType, beepType: BeepType) { - self.nonce = nonce - self.deliveryType = deliveryType - self.beepType = beepType - } -} - -extension CancelDeliveryCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "CancelDeliveryCommand(nonce:\(Data(bigEndian: nonce).hexadecimalString), deliveryType:\(deliveryType.debugDescription), beepType:\(beepType))" - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/ConfigureAlertsCommand.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/ConfigureAlertsCommand.swift deleted file mode 100644 index 4cf646d42..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/ConfigureAlertsCommand.swift +++ /dev/null @@ -1,143 +0,0 @@ -// -// ConfigureAlertsCommand.swift -// OmniKit -// -// Created by Pete Schwamb on 2/22/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct ConfigureAlertsCommand : NonceResyncableMessageBlock { - - public let blockType: MessageBlockType = .configureAlerts - - public var nonce: UInt32 - let configurations: [AlertConfiguration] - - public var data: Data { - var data = Data([ - blockType.rawValue, - UInt8(4 + configurations.count * AlertConfiguration.length), - ]) - data.appendBigEndian(nonce) - // Sorting the alerts not required, but it can be helpful for log analysis - let sorted = configurations.sorted { $0.slot.rawValue < $1.slot.rawValue } - for config in sorted { - data.append(contentsOf: config.data) - } - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 10 { - throw MessageBlockError.notEnoughData - } - self.nonce = encodedData[2...].toBigEndian(UInt32.self) - - let length = Int(encodedData[1]) - - let numConfigs = (length - 4) / AlertConfiguration.length - - var configs = [AlertConfiguration]() - - for i in 0..> 4 - guard let alertType = AlertSlot(rawValue: alertTypeBits) else { - throw MessageError.unknownValue(value: alertTypeBits, typeDescription: "AlertType") - } - self.slot = alertType - - self.active = encodedData[0] & 0b1000 != 0 - - self.autoOffModifier = encodedData[0] & 0b10 != 0 - - self.duration = TimeInterval(minutes: Double((Int(encodedData[0] & 0b1) << 8) + Int(encodedData[1]))) - - let yyyy = (Int(encodedData[2]) << 8) + (Int(encodedData[3])) & 0x3fff - - if encodedData[0] & 0b100 != 0 { - let volume = Double(yyyy * 2) / Pod.pulsesPerUnit - self.trigger = .unitsRemaining(volume) - } else { - self.trigger = .timeUntilAlert(TimeInterval(minutes: Double(yyyy))) - } - - let beepRepeatBits = encodedData[4] - guard let beepRepeat = BeepRepeat(rawValue: beepRepeatBits) else { - throw MessageError.unknownValue(value: beepRepeatBits, typeDescription: "BeepRepeat") - } - self.beepRepeat = beepRepeat - - let beepTypeBits = encodedData[5] - guard let beepType = BeepType(rawValue: beepTypeBits) else { - throw MessageError.unknownValue(value: beepTypeBits, typeDescription: "BeepType") - } - self.beepType = beepType - - self.silent = (beepType == .noBeepNonCancel) - } - - public var data: Data { - var firstByte = slot.rawValue << 4 - firstByte += active ? (1 << 3) : 0 - - if case .unitsRemaining = trigger { - firstByte += 1 << 2 - } - if autoOffModifier { - firstByte += 1 << 1 - } - - // The 9-bit duration is limited to 2^9-1 minutes max value - let durationMinutes = min(UInt(duration.minutes), 0x1ff) - - // High bit of duration - firstByte += UInt8((durationMinutes >> 8) & 0x1) - - var data = Data([ - firstByte, - UInt8(durationMinutes & 0xff) - ]) - - switch trigger { - case .unitsRemaining(let volume): - let ticks = UInt16(volume / Pod.pulseSize / 2) - data.appendBigEndian(ticks) - case .timeUntilAlert(let secondsUntilAlert): - // round the time to alert to the nearest minute - let minutes = UInt16((secondsUntilAlert + 30).minutes) - data.appendBigEndian(minutes) - } - data.append(beepRepeat.rawValue) - let beepTypeToSet: BeepType = silent ? .noBeepNonCancel : beepType - data.append(beepTypeToSet.rawValue) - - return data - } -} - -extension ConfigureAlertsCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "ConfigureAlertsCommand(nonce:\(Data(bigEndian: nonce).hexadecimalString), configurations:\(configurations))" - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/DeactivatePodCommand.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/DeactivatePodCommand.swift deleted file mode 100644 index 503bc83a2..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/DeactivatePodCommand.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// DeactivatePodCommand.swift -// OmniKit -// -// Created by Pete Schwamb on 2/24/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct DeactivatePodCommand : NonceResyncableMessageBlock { - // OFF 1 2 3 4 5 - // 1C 04 NNNNNNNN - - public let blockType: MessageBlockType = .deactivatePod - - public var nonce: UInt32 - - public var data: Data { - var data = Data([ - blockType.rawValue, - 4, - ]) - data.appendBigEndian(nonce) - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 6 { - throw MessageBlockError.notEnoughData - } - self.nonce = encodedData[2...].toBigEndian(UInt32.self) - } - - public init(nonce: UInt32) { - self.nonce = nonce - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/DetailedStatus.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/DetailedStatus.swift deleted file mode 100644 index 687fbc5ae..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/DetailedStatus.swift +++ /dev/null @@ -1,222 +0,0 @@ -// -// DetailedStatus.swift -// OmniKit -// -// Created by Pete Schwamb on 2/23/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -// DetailedStatus is the PodInfo subtype 2 returned for a type 2 GetStatus command and -// is also returned on a pod fault for any command normally returning a StatusResponse -public struct DetailedStatus : PodInfo, Equatable { - // CMD 1 2 3 4 5 6 7 8 9 10 1112 1314 1516 17 18 19 20 21 2223 - // DATA 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW XX YYYY - - public let podInfoType: PodInfoResponseSubType = .detailedStatus - public let podProgressStatus: PodProgressStatus - public let deliveryStatus: DeliveryStatus - public let bolusNotDelivered: Double - public let lastProgrammingMessageSeqNum: UInt8 // updated by pod for 03, 08, $11, $19, $1A, $1C, $1E & $1F command messages - public let totalInsulinDelivered: Double - public let faultEventCode: FaultEventCode - public let faultEventTimeSinceActivation: TimeInterval? - public let reservoirLevel: Double - public let timeActive: TimeInterval - public let unacknowledgedAlerts: AlertSet - public let faultAccessingTables: Bool - public let errorEventInfo: ErrorEventInfo? - public let receiverLowGain: UInt8 - public let radioRSSI: UInt8 - public let previousPodProgressStatus: PodProgressStatus? - public let possibleFaultCallingAddress: UInt16? - public let data: Data - - public init(encodedData: Data) throws { - guard encodedData.count >= 22 else { - throw MessageBlockError.notEnoughData - } - - guard PodProgressStatus(rawValue: encodedData[1]) != nil else { - throw MessageError.unknownValue(value: encodedData[1], typeDescription: "PodProgressStatus") - } - self.podProgressStatus = PodProgressStatus(rawValue: encodedData[1])! - - self.deliveryStatus = DeliveryStatus(rawValue: encodedData[2] & 0xf)! - - self.bolusNotDelivered = Double((Int(encodedData[3] & 0x3) << 8) | Int(encodedData[4])) / Pod.pulsesPerUnit - - self.lastProgrammingMessageSeqNum = encodedData[5] - - self.totalInsulinDelivered = Double(encodedData[6...7].toBigEndian(UInt16.self)) / Pod.pulsesPerUnit - - self.faultEventCode = FaultEventCode(rawValue: encodedData[8]) - - let minutesSinceActivation = encodedData[9...10].toBigEndian(UInt16.self) - if minutesSinceActivation != 0xffff { - self.faultEventTimeSinceActivation = TimeInterval(minutes: Double(minutesSinceActivation)) - } else { - self.faultEventTimeSinceActivation = nil - } - - self.reservoirLevel = Double((Int(encodedData[11] & 0x3) << 8) + Int(encodedData[12])) / Pod.pulsesPerUnit - - self.timeActive = TimeInterval(minutes: Double(encodedData[13...14].toBigEndian(UInt16.self))) - - self.unacknowledgedAlerts = AlertSet(rawValue: encodedData[15]) - - self.faultAccessingTables = (encodedData[16] & 2) != 0 - - if encodedData[17] == 0x00 { - // no fault has occurred, errorEventInfo and previousPodProgressStatus not valid - self.errorEventInfo = nil - self.previousPodProgressStatus = nil - } else { - // fault has occurred, VV byte contains valid fault info - let errorEventInfo = ErrorEventInfo(rawValue: encodedData[17]) - self.errorEventInfo = errorEventInfo - // errorEventInfo.podProgressStatus is valid for both Eros and Dash on fault - self.previousPodProgressStatus = errorEventInfo.podProgressStatus - } - - // For Dash these values have always been zero - self.receiverLowGain = UInt8(encodedData[18] >> 6) - self.radioRSSI = UInt8(encodedData[18] & 0x3F) - - // For Eros, encodedData[19] (XX) byte is the same previousPodProgressStatus nibble in the VV byte on fault. - // For Dash, encodedData[19] (XX) byte is uninitialized or unknown, so use VV byte for previousPodProgressStatus. - - // Decode YYYY based on whether there was a pod fault - if encodedData[8] == 0 { - // For non-faults, YYYY contents not valid (either uninitialized data for Eros or some unknown content for Dash). - self.possibleFaultCallingAddress = nil - } else { - // For Eros faults, YYYY is always uninitialized data from the previous command/response at the same buffer offset. - // For Dash faults, YYYY could be a calling address of the fault routine for the first return after a pod fault, - // subsequent returns will be byte swapped data from previous command/response at the same buffer offset. - self.possibleFaultCallingAddress = encodedData[20...21].toBigEndian(UInt16.self) // only potentially valid for Dash - } - - self.data = Data(encodedData) - } - - public var isFaulted: Bool { - return faultEventCode.faultType != .noFaults || podProgressStatus == .activationTimeExceeded - } -} - -extension DetailedStatus: CustomDebugStringConvertible { - public typealias RawValue = Data - public var debugDescription: String { - var result = [ - "## DetailedStatus", - "* rawHex: \(data.hexadecimalString)", - "* podProgressStatus: \(podProgressStatus)", - "* deliveryStatus: \(deliveryStatus.description)", - "* bolusNotDelivered: \(bolusNotDelivered.twoDecimals) U", - "* lastProgrammingMessageSeqNum: \(lastProgrammingMessageSeqNum)", - "* totalInsulinDelivered: \(totalInsulinDelivered.twoDecimals) U", - "* reservoirLevel: \(reservoirLevel == Pod.reservoirLevelAboveThresholdMagicNumber ? "50+" : reservoirLevel.twoDecimals) U", - "* timeActive: \(timeActive.timeIntervalStr)", - "* unacknowledgedAlerts: \(unacknowledgedAlerts)", - "", - ].joined(separator: "\n") - if radioRSSI != 0 { - result += [ - "* receiverLowGain: \(receiverLowGain)", - "* radioRSSI: \(radioRSSI)", - "", - ].joined(separator: "\n") - } - if faultEventCode.faultType != .noFaults { - result += [ - "* faultEventCode: \(faultEventCode.description)", - "* faultAccessingTables: \(faultAccessingTables)", - "* faultEventTimeSinceActivation: \(faultEventTimeSinceActivation?.timeIntervalStr ?? "NA")", - "* errorEventInfo: \(errorEventInfo?.description ?? "NA")", - "* previousPodProgressStatus: \(previousPodProgressStatus?.description ?? "NA")", - "* possibleFaultCallingAddress: \(possibleFaultCallingAddress != nil ? String(format: "0x%04x", possibleFaultCallingAddress!) : "NA")", - "", - ].joined(separator: "\n") - } - return result - } -} - -extension DetailedStatus: RawRepresentable { - public init?(rawValue: Data) { - do { - try self.init(encodedData: rawValue) - } catch { - return nil - } - } - - public var rawValue: Data { - return data - } -} - -extension TimeInterval { - var timeIntervalStr: String { - var str: String = "" - let hours = UInt(self / 3600) - let minutes = UInt(self / 60) % 60 - let seconds = UInt(self) % 60 - if hours != 0 { - str += String(format: "%uh", hours) - } - if minutes != 0 || hours != 0 { - str += String(format: "%um", minutes) - } - if seconds != 0 || str.isEmpty { - str += String(format: "%us", seconds) - } - return str - } -} - -extension Double { - public var twoDecimals: String { - return String(format: "%.2f", self) - } -} - -// Type for the ErrorEventInfo VV byte if valid -// a: insulin state table corruption found during error logging -// bb: internal 2-bit occlusion type -// c: immediate bolus in progress during error -// dddd: Pod Progress at time of first logged fault event -// -public struct ErrorEventInfo: CustomStringConvertible, Equatable { - public let rawValue: UInt8 - public let insulinStateTableCorruption: Bool // 'a' bit - public let occlusionType: Int // 'bb' 2-bit occlusion type - public let immediateBolusInProgress: Bool // 'c' bit - public let podProgressStatus: PodProgressStatus // 'dddd' bits - - public var errorEventInfo: ErrorEventInfo? { - return ErrorEventInfo(rawValue: rawValue) - } - - public var description: String { - let hexString = String(format: "%02X", rawValue) - return [ - "rawValue: 0x\(hexString)", - "insulinStateTableCorruption: \(insulinStateTableCorruption)", - "occlusionType: \(occlusionType)", - "immediateBolusInProgress: \(immediateBolusInProgress)", - "podProgressStatus: \(podProgressStatus)", - ].joined(separator: ", ") - } - - init(rawValue: UInt8) { - self.rawValue = rawValue - self.insulinStateTableCorruption = (rawValue & 0x80) != 0 - self.occlusionType = Int((rawValue & 0x60) >> 5) - self.immediateBolusInProgress = (rawValue & 0x10) != 0 - self.podProgressStatus = PodProgressStatus(rawValue: rawValue & 0xF)! - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/ErrorResponse.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/ErrorResponse.swift deleted file mode 100644 index 6f25846bf..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/ErrorResponse.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// ErrorResponse.swift -// OmniKit -// -// Created by Pete Schwamb on 2/25/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -fileprivate let errorResponseCode_badNonce: UInt8 = 0x14 // only returned on Eros - -public enum ErrorResponseType { - case badNonce(nonceResyncKey: UInt16) // only returned on Eros - case nonretryableError(code: UInt8, faultEventCode: FaultEventCode, podProgress: PodProgressStatus) -} - -// 06 14 WWWW, WWWW is the encoded nonce resync key -// 06 EE FF0P, EE != 0x14, FF = fault code (if any), 0P = pod progress status (1..15) - -public struct ErrorResponse : MessageBlock { - public let blockType: MessageBlockType = .errorResponse - public let errorResponseType: ErrorResponseType - public let data: Data - - public init(encodedData: Data) throws { - let errorCode = encodedData[2] - switch (errorCode) { - case errorResponseCode_badNonce: - // For this error code only the 2 next bytes are the encoded nonce resync key (only returned on Eros) - let nonceResyncKey: UInt16 = encodedData[3...].toBigEndian(UInt16.self) - errorResponseType = .badNonce(nonceResyncKey: nonceResyncKey) - break - default: - // All other error codes are some non-retryable command error. In this case, - // the next 2 bytes are any saved fault code (typically 0) and the pod progress value. - let faultEventCode = FaultEventCode(rawValue: encodedData[3]) - guard let podProgress = PodProgressStatus(rawValue: encodedData[4]) else { - throw MessageError.unknownValue(value: encodedData[4], typeDescription: "ErrorResponse PodProgressStatus") - } - errorResponseType = .nonretryableError(code: errorCode, faultEventCode: faultEventCode, podProgress: podProgress) - break - } - self.data = encodedData - } -} - diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/FaultConfigCommand.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/FaultConfigCommand.swift deleted file mode 100644 index d68ce3e42..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/FaultConfigCommand.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// FaultConfigCommand.swift -// OmniKit -// -// Created by Pete Schwamb on 12/18/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct FaultConfigCommand : NonceResyncableMessageBlock { - // OFF 1 2 3 4 5 6 7 - // 08 06 NNNNNNNN JJ KK - - public let blockType: MessageBlockType = .faultConfig - public let length: UInt8 = 6 - public var nonce: UInt32 - public let tab5Sub16: UInt8 - public let tab5Sub17: UInt8 - - public init(nonce: UInt32, tab5Sub16: UInt8, tab5Sub17: UInt8) { - self.nonce = nonce - self.tab5Sub16 = tab5Sub16 - self.tab5Sub17 = tab5Sub17 - } - - public init(encodedData: Data) throws { - if encodedData.count < 8 { - throw MessageBlockError.notEnoughData - } - - nonce = encodedData[2...].toBigEndian(UInt32.self) - - self.tab5Sub16 = encodedData[6] - self.tab5Sub17 = encodedData[7] - } - - public var data: Data { - var data = Data([ - blockType.rawValue, - length]) - - data.appendBigEndian(nonce) - data.append(tab5Sub16) - data.append(tab5Sub17) - return data - } -} - -extension FaultConfigCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "FaultConfigCommand(nonce:\(Data(bigEndian: nonce).hexadecimalString), tab5Sub16:\(tab5Sub16), tab5Sub17:\(tab5Sub17))" - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/GetStatusCommand.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/GetStatusCommand.swift deleted file mode 100644 index d68ebdbbc..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/GetStatusCommand.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// GetStatusCommand.swift -// OmniKit -// -// Created by Pete Schwamb on 10/14/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct GetStatusCommand : MessageBlock { - // OFF 1 2 - // Oe 01 TT - - public let blockType: MessageBlockType = .getStatus - public let length: UInt8 = 1 - public let podInfoType: PodInfoResponseSubType - - public init(podInfoType: PodInfoResponseSubType = .normal) { - self.podInfoType = podInfoType - } - - public init(encodedData: Data) throws { - if encodedData.count < 3 { - throw MessageBlockError.notEnoughData - } - guard let podInfoType = PodInfoResponseSubType(rawValue: encodedData[2]) else { - throw MessageError.unknownValue(value: encodedData[2], typeDescription: "PodInfoResponseSubType") - } - self.podInfoType = podInfoType - } - - public var data: Data { - var data = Data([ - blockType.rawValue, - length - ]) - data.append(podInfoType.rawValue) - return data - } -} - -extension GetStatusCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "GetStatusCommand(\(podInfoType))" - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/MessageBlock.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/MessageBlock.swift deleted file mode 100644 index e83d6408e..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/MessageBlock.swift +++ /dev/null @@ -1,86 +0,0 @@ -// -// MessageBlock.swift -// OmniKit -// -// Created by Pete Schwamb on 10/14/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - -public enum MessageBlockError: Error { - case notEnoughData - case unknownBlockType(rawVal: UInt8) - case parseError -} - -// See https://github.com/openaps/openomni/wiki/Message-Types -public enum MessageBlockType: UInt8 { - case versionResponse = 0x01 - case podInfoResponse = 0x02 - case setupPod = 0x03 - case errorResponse = 0x06 - case assignAddress = 0x07 - case faultConfig = 0x08 - case getStatus = 0x0e - case acknowledgeAlert = 0x11 - case basalScheduleExtra = 0x13 - case tempBasalExtra = 0x16 - case bolusExtra = 0x17 - case configureAlerts = 0x19 - case setInsulinSchedule = 0x1a - case deactivatePod = 0x1c - case statusResponse = 0x1d - case beepConfig = 0x1e - case cancelDelivery = 0x1f - - public var blockType: MessageBlock.Type { - switch self { - case .versionResponse: - return VersionResponse.self - case .acknowledgeAlert: - return AcknowledgeAlertCommand.self - case .podInfoResponse: - return PodInfoResponse.self - case .setupPod: - return SetupPodCommand.self - case .errorResponse: - return ErrorResponse.self - case .assignAddress: - return AssignAddressCommand.self - case .getStatus: - return GetStatusCommand.self - case .basalScheduleExtra: - return BasalScheduleExtraCommand.self - case .bolusExtra: - return BolusExtraCommand.self - case .configureAlerts: - return ConfigureAlertsCommand.self - case .setInsulinSchedule: - return SetInsulinScheduleCommand.self - case .deactivatePod: - return DeactivatePodCommand.self - case .statusResponse: - return StatusResponse.self - case .tempBasalExtra: - return TempBasalExtraCommand.self - case .beepConfig: - return BeepConfigCommand.self - case .cancelDelivery: - return CancelDeliveryCommand.self - case .faultConfig: - return FaultConfigCommand.self - } - } -} - -public protocol MessageBlock { - init(encodedData: Data) throws - - var blockType: MessageBlockType { get } - var data: Data { get } -} - -public protocol NonceResyncableMessageBlock : MessageBlock { - var nonce: UInt32 { get set } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PlaceholderMessageBlock.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PlaceholderMessageBlock.swift deleted file mode 100644 index 21aaacfc0..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PlaceholderMessageBlock.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// PlaceholderMessageBlock.swift -// OmniKit -// -// Created by Pete Schwamb on 10/24/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct PlaceholderMessageBlock: MessageBlock { - public let blockType: MessageBlockType - public let length: UInt8 - - public let data: Data - - public init(encodedData: Data) throws { - if encodedData.count < 2 { - throw MessageBlockError.notEnoughData - } - guard let blockType = MessageBlockType(rawValue: encodedData[0]) else { - throw MessageBlockError.unknownBlockType(rawVal: encodedData[0]) - } - self.blockType = blockType - length = encodedData[1] - data = encodedData.prefix(upTo: Int(length)) - } -} - diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfo.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfo.swift deleted file mode 100644 index ceb2bfeb8..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfo.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// PodInfoResponseSubType.swift -// OmniKit -// -// Created by Eelke Jager on 15/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public protocol PodInfo { - init(encodedData: Data) throws - var podInfoType: PodInfoResponseSubType { get } - var data: Data { get } - -} - -public enum PodInfoResponseSubType: UInt8, Equatable { - case normal = 0x00 - case configuredAlerts = 0x01 // Returns information on configured alerts - case detailedStatus = 0x02 // Returned on any pod fault - case pulseLogPlus = 0x03 // Returns up to the last 60 pulse log entries plus additional info - case activationTime = 0x05 // Returns activation date, elapsed time, and fault code - case pulseLogRecent = 0x50 // Returns the last 50 pulse log entries - case pulseLogPrevious = 0x51 // Like 0x50, but returns up to the previous 50 entries before the last 50 - - public var podInfoType: PodInfo.Type { - switch self { - case .normal: - return StatusResponse.self as! PodInfo.Type - case .configuredAlerts: - return PodInfoConfiguredAlerts.self - case .detailedStatus: - return DetailedStatus.self - case .pulseLogPlus: - return PodInfoPulseLogPlus.self - case .activationTime: - return PodInfoActivationTime.self - case .pulseLogRecent: - return PodInfoPulseLogRecent.self - case .pulseLogPrevious: - return PodInfoPulseLogPrevious.self - } - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfoActivationTime.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfoActivationTime.swift deleted file mode 100644 index cbd2ea2f7..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfoActivationTime.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// PodInfoActivationTime.swift -// OmniKit -// -// Created by Eelke Jager on 25/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -// Type 5 PodInfo returns the pod activation time, time pod alive, and the possible fault code -public struct PodInfoActivationTime : PodInfo { - // OFF 1 2 3 4 5 6 7 8 9 10111213 1415161718 - // DATA 0 1 2 3 4 5 6 7 8 9 1011 1213141516 - // 02 11 05 PP QQQQ 00000000 00000000 MMDDYYHHMM - - public let podInfoType: PodInfoResponseSubType = .activationTime - public let faultEventCode: FaultEventCode - public let timeActivation: TimeInterval - public let dateTime: DateComponents - public let data: Data - - public init(encodedData: Data) throws { - guard encodedData.count >= 16 else { - throw MessageBlockError.notEnoughData - } - self.faultEventCode = FaultEventCode(rawValue: encodedData[1]) - self.timeActivation = TimeInterval(minutes: Double((Int(encodedData[2] & 0b1) << 8) + Int(encodedData[3]))) - self.dateTime = DateComponents(encodedDateTime: encodedData.subdata(in: 12..<17)) - self.data = Data(encodedData) - } -} - -extension DateComponents { - init(encodedDateTime: Data) { - self.init() - - year = Int(encodedDateTime[2]) + 2000 - month = Int(encodedDateTime[0]) - day = Int(encodedDateTime[1]) - hour = Int(encodedDateTime[3]) - minute = Int(encodedDateTime[4]) - - calendar = Calendar(identifier: .gregorian) - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfoConfiguredAlerts.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfoConfiguredAlerts.swift deleted file mode 100644 index 918640fd4..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfoConfiguredAlerts.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// PodInfoConfiguredAlerts.swift -// OmniKit -// -// Created by Eelke Jager on 16/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -// Type 1 Pod Info returns information about the currently configured alerts -public struct PodInfoConfiguredAlerts : PodInfo { - // CMD 1 2 3 4 5 6 7 8 910 1112 1314 1516 1718 1920 - // DATA 0 1 2 3 4 5 6 7 8 910 1112 1314 1516 1718 - // 02 13 01 XXXX VVVV VVVV VVVV VVVV VVVV VVVV VVVV VVVV - - public let podInfoType : PodInfoResponseSubType = .configuredAlerts - public let word_278 : Data - public let alertsActivations : [AlertActivation] - public let data : Data - - public struct AlertActivation { - let beepType: BeepType - let unitsLeft: Double - let timeFromPodStart: UInt8 - - public init(beepType: BeepType, timeFromPodStart: UInt8, unitsLeft: Double) { - self.beepType = beepType - self.timeFromPodStart = timeFromPodStart - self.unitsLeft = unitsLeft - } - } - - public init(encodedData: Data) throws { - guard encodedData.count >= 11 else { - throw MessageBlockError.notEnoughData - } - - self.word_278 = encodedData[1...2] - - let numAlertTypes = 8 - let beepType = BeepType.self - - var activations = [AlertActivation]() - - for alarmType in (0..= logStartByteOffset && (nLogBytesReturned & 0x3) == 0 else { - throw MessageBlockError.notEnoughData // not enough data to start log or a non-integral # of pulse log entries - } - self.nEntries = nLogBytesReturned / MemoryLayout.size - self.indexLastEntry = Int((UInt16(encodedData[1]) << 8) | UInt16(encodedData[2])) - self.pulseLog = createPulseLog(encodedData: encodedData, logStartByteOffset: logStartByteOffset, nEntries: self.nEntries) - self.data = encodedData - } -} - -// Type $51 Pod info returns (up to) the most previous 50 32-bit pulse log entries -public struct PodInfoPulseLogPrevious : PodInfo { - // CMD 1 2 3 4 5 6 7 8 - // DATA 0 1 2 3 4 5 6 - // 02 LL 51 NNNN XXXXXXXX ... - - public let podInfoType : PodInfoResponseSubType = .pulseLogPrevious - public let nEntries : Int // how many 32-bit pulse log entries returned - public let pulseLog : [UInt32] - public let data : Data - - public init(encodedData: Data) throws { - let logStartByteOffset = 3 // starting byte offset of the pulse log in DATA - let nLogBytesReturned = encodedData.count - logStartByteOffset - guard encodedData.count >= logStartByteOffset && (nLogBytesReturned & 0x3) == 0 else { - throw MessageBlockError.notEnoughData // first 3 bytes missing or non-integral # of pulse log entries - } - let nEntriesCalculated = nLogBytesReturned / MemoryLayout.size - self.nEntries = Int((UInt16(encodedData[1]) << 8) | UInt16(encodedData[2])) - // verify we actually got all the reported entries - if self.nEntries > nEntriesCalculated { - throw MessageBlockError.notEnoughData // some pulse log entry count mismatch issue - } - self.pulseLog = createPulseLog(encodedData: encodedData, logStartByteOffset: logStartByteOffset, nEntries: self.nEntries) - self.data = encodedData - } -} - -func createPulseLog(encodedData: Data, logStartByteOffset: Int, nEntries: Int) -> [UInt32] { - var pulseLog: [UInt32] = Array(repeating: 0, count: nEntries) - var index = 0 - while index < nEntries { - pulseLog[index] = encodedData[(logStartByteOffset+(index*4))...].toBigEndian(UInt32.self) - index += 1 - } - return pulseLog -} - -extension BinaryInteger { - var binaryDescription: String { - var binaryString = "" - var internalNumber = self - var counter = 0 - - for _ in (1...self.bitWidth) { - binaryString.insert(contentsOf: "\(internalNumber & 1)", at: binaryString.startIndex) - internalNumber >>= 1 - counter += 1 - if counter % 8 == 0 { - binaryString.insert(contentsOf: " ", at: binaryString.startIndex) - } - } - return binaryString - } -} - -public func pulseLogString(pulseLogEntries: [UInt32], lastPulseNumber: Int) -> String { - var str: String = "Pulse eeeeee0a pppliiib cccccccc dfgggggg" - var index = pulseLogEntries.count - 1 - var pulseNumber = lastPulseNumber - while index >= 0 { - str += String(format: "\n%04d:", pulseNumber) + UInt32(pulseLogEntries[index]).binaryDescription - index -= 1 - pulseNumber -= 1 - } - return str -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfoPulseLogPlus.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfoPulseLogPlus.swift deleted file mode 100644 index 27f2cd709..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfoPulseLogPlus.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// PodInfoPulseLogPlus.swift -// OmniKit -// -// Created by Eelke Jager on 22/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -// Type 3 Pod Info returns up to the last 60 pulse log entries pulse some additional info -public struct PodInfoPulseLogPlus : PodInfo { - // CMD 1 2 3 4 5 6 7 8 9 10 - // DATA 0 1 2 3 4 5 6 7 8 - // 02 LL 03 PP QQQQ SSSS 04 3c XXXXXXXX ... - - public let podInfoType : PodInfoResponseSubType = .pulseLogPlus - public let faultEventCode: FaultEventCode // fault code - public let timeFaultEvent: TimeInterval // fault time since activation - public let timeActivation: TimeInterval // current time since activation - public let entrySize : Int // always 4 - public let maxEntries : Int // always 60 - public let nEntries : Int // how many 32-bit pulse log entries returned (calculated) - public let pulseLog : [UInt32] - public let data : Data - - public init(encodedData: Data) throws { - guard encodedData[6] == MemoryLayout.size else { - throw MessageError.unknownValue(value: encodedData[6], typeDescription: "pulseLog entry size") - } - let entrySize = Int(encodedData[6]) - let logStartByteOffset = 8 // starting byte offset of the pulse log in DATA - let nLogBytesReturned = encodedData.count - logStartByteOffset - let nEntries = nLogBytesReturned / entrySize - let maxEntries = Int(encodedData[7]) - guard encodedData.count >= logStartByteOffset && (nLogBytesReturned & 0x3) == 0 else { - throw MessageBlockError.notEnoughData // not enough data to start log or a non-integral # of pulse log entries - } - guard maxEntries >= nEntries else { - throw MessageBlockError.parseError - } - self.entrySize = entrySize - self.nEntries = nEntries - self.maxEntries = maxEntries - self.faultEventCode = FaultEventCode(rawValue: encodedData[1]) - self.timeFaultEvent = TimeInterval(minutes: Double((Int(encodedData[2] & 0b1) << 8) + Int(encodedData[3]))) - self.timeActivation = TimeInterval(minutes: Double((Int(encodedData[4] & 0b1) << 8) + Int(encodedData[5]))) - self.pulseLog = createPulseLog(encodedData: encodedData, logStartByteOffset: logStartByteOffset, nEntries: self.nEntries) - self.data = encodedData - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfoResponse.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfoResponse.swift deleted file mode 100644 index 2581ab667..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/PodInfoResponse.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// PodInfoResponse.swift -// OmniKit -// -// Created by Pete Schwamb on 2/23/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct PodInfoResponse : MessageBlock { - - public let blockType : MessageBlockType = .podInfoResponse - public let podInfoResponseSubType : PodInfoResponseSubType - public let podInfo : PodInfo - public let data : Data - - public init(encodedData: Data) throws { - guard let subType = PodInfoResponseSubType(rawValue: encodedData[2]) else { - throw MessageError.unknownValue(value: encodedData[2], typeDescription: "PodInfoResponseSubType") - } - self.podInfoResponseSubType = subType - let len = encodedData.count - podInfo = try podInfoResponseSubType.podInfoType.init(encodedData: encodedData.subdata(in: 2.. ScheduleTypeCode { - switch self { - case .basalSchedule: - return .basalSchedule - case .tempBasal: - return .tempBasal - case .bolus: - return .bolus - } - } - - fileprivate var data: Data { - switch self { - case .basalSchedule(let currentSegment, let secondsRemaining, let pulsesRemaining, let table): - var data = Data([currentSegment]) - data.appendBigEndian(secondsRemaining << 3) - data.appendBigEndian(pulsesRemaining) - for entry in table.entries { - data.append(entry.data) - } - return data - - case .tempBasal(let secondsRemaining, let firstSegmentPulses, let table): - var data = Data([UInt8(table.numSegments())]) - data.appendBigEndian(secondsRemaining << 3) - data.appendBigEndian(firstSegmentPulses) - for entry in table.entries { - data.append(entry.data) - } - return data - - case .bolus(let units, let timeBetweenPulses, let table): - let firstSegmentPulses = UInt16(round(units / Pod.pulseSize)) - let multiplier = UInt16(round(timeBetweenPulses * 8)) - let fieldA = firstSegmentPulses * multiplier - - var data = Data([UInt8(table.numSegments())]) - data.appendBigEndian(fieldA) - data.appendBigEndian(firstSegmentPulses) - for entry in table.entries { - data.append(entry.data) - } - return data - - } - } - - fileprivate func checksum() -> UInt16 { - switch self { - case .basalSchedule( _, _, _, let table), .tempBasal(_, _, let table): - return data[0..<5].reduce(0) { $0 + UInt16($1) } + - table.entries.reduce(0) { $0 + $1.checksum() } - case .bolus(_, _, let table): - return data[0..<5].reduce(0) { $0 + UInt16($1) } + - table.entries.reduce(0) { $0 + $1.checksum() } - } - } - } - - public let blockType: MessageBlockType = .setInsulinSchedule - - public var nonce: UInt32 - public let deliverySchedule: DeliverySchedule - - public var data: Data { - var data = Data([ - blockType.rawValue, - UInt8(7 + deliverySchedule.data.count), - ]) - data.appendBigEndian(nonce) - data.append(deliverySchedule.typeCode().rawValue) - data.appendBigEndian(deliverySchedule.checksum()) - data.append(deliverySchedule.data) - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 6 { - throw MessageBlockError.notEnoughData - } - let length = encodedData[1] - - nonce = encodedData[2...].toBigEndian(UInt32.self) - - let checksum = encodedData[7...].toBigEndian(UInt16.self) - - guard let scheduleTypeCode = ScheduleTypeCode(rawValue: encodedData[6]) else { - throw MessageError.unknownValue(value: encodedData[6], typeDescription: "ScheduleTypeCode") - } - - switch scheduleTypeCode { - case .basalSchedule: - var entries = [InsulinTableEntry]() - let numEntries = (length - 12) / 2 - for i in 0..> 3 - let pulsesRemaining = encodedData[12...].toBigEndian(UInt16.self) - let table = BasalDeliveryTable(entries: entries) - deliverySchedule = .basalSchedule(currentSegment: currentTableIndex, secondsRemaining: secondsRemaining, pulsesRemaining: pulsesRemaining, table: table) - - case .tempBasal: - let secondsRemaining = encodedData[10...].toBigEndian(UInt16.self) >> 3 - let firstSegmentPulses = encodedData[12...].toBigEndian(UInt16.self) - var entries = [InsulinTableEntry]() - let numEntries = (length - 12) / 2 - for i in 0.. 0 ? Double(fieldA / unitRate) / 8 : 0 - - var entries = [InsulinTableEntry]() - let numEntries = (length - 12) / 2 - for i in 0.. 0.0 && timeBetweenPulses > 0) ? timeBetweenPulses : Pod.secondsPerBolusPulse - self.deliverySchedule = SetInsulinScheduleCommand.DeliverySchedule.bolus(units: units, timeBetweenPulses: timeBetweenImmediatePulses, table: table) - } -} - -extension SetInsulinScheduleCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "SetInsulinScheduleCommand(nonce:\(nonce), \(deliverySchedule))" - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/SetupPodCommand.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/SetupPodCommand.swift deleted file mode 100644 index 59ba2d3ac..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/SetupPodCommand.swift +++ /dev/null @@ -1,92 +0,0 @@ -// -// Setup PodCommand.swift -// OmniKit -// -// Created by Pete Schwamb on 2/17/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct SetupPodCommand : MessageBlock { - - public let blockType: MessageBlockType = .setupPod - - let address: UInt32 - let lot: UInt32 - let tid: UInt32 - let dateComponents: DateComponents - let packetTimeoutLimit: UInt8 - - public static func dateComponents(date: Date, timeZone: TimeZone) -> DateComponents { - var cal = Calendar(identifier: .gregorian) - cal.timeZone = timeZone - return cal.dateComponents([.day, .month, .year, .hour, .minute], from: date) - } - - public static func date(from components: DateComponents, timeZone: TimeZone) -> Date? { - var cal = Calendar(identifier: .gregorian) - cal.timeZone = timeZone - return cal.date(from: components) - } - - // 03 13 1f08ced2 14 04 09 0b 11 0b 08 0000a640 00097c27 83e4 - public var data: Data { - var data = Data([ - blockType.rawValue, - 19, - ]) - data.appendBigEndian(self.address) - - let year = UInt8((dateComponents.year ?? 2000) - 2000) - let month = UInt8(dateComponents.month ?? 0) - let day = UInt8(dateComponents.day ?? 0) - let hour = UInt8(dateComponents.hour ?? 0) - let minute = UInt8(dateComponents.minute ?? 0) - - let data2: Data = Data([ - UInt8(0x14), // Unknown - packetTimeoutLimit, - month, - day, - year, - hour, - minute - ]) - data.append(data2) - data.appendBigEndian(self.lot) - data.appendBigEndian(self.tid) - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 21 { - throw MessageBlockError.notEnoughData - } - self.address = encodedData[2...].toBigEndian(UInt32.self) - packetTimeoutLimit = encodedData[7] - var components = DateComponents() - components.month = Int(encodedData[8]) - components.day = Int(encodedData[9]) - components.year = Int(encodedData[10]) + 2000 - components.hour = Int(encodedData[11]) - components.minute = Int(encodedData[12]) - self.dateComponents = components - self.lot = encodedData[13...].toBigEndian(UInt32.self) - self.tid = encodedData[17...].toBigEndian(UInt32.self) - } - - public init(address: UInt32, dateComponents: DateComponents, lot: UInt32, tid: UInt32, packetTimeoutLimit: UInt8 = 4) { - self.address = address - self.dateComponents = dateComponents - self.lot = lot - self.tid = tid - self.packetTimeoutLimit = packetTimeoutLimit - } -} - -extension SetupPodCommand: CustomDebugStringConvertible { - public var debugDescription: String { - return "SetupPodCommand(address:\(Data(bigEndian: address).hexadecimalString), dateComponents:\(dateComponents), lot:\(lot), tid:\(tid), packetTimeoutLimit:\(packetTimeoutLimit))" - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/StatusResponse.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/StatusResponse.swift deleted file mode 100644 index bf2474998..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/StatusResponse.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// StatusResponse.swift -// OmniKit -// -// Created by Pete Schwamb on 10/23/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct StatusResponse : MessageBlock { - public let blockType: MessageBlockType = .statusResponse - public let length: UInt8 = 10 - public let deliveryStatus: DeliveryStatus - public let podProgressStatus: PodProgressStatus - public let timeActive: TimeInterval - public let reservoirLevel: Double - public let insulinDelivered: Double - public let bolusNotDelivered: Double - public let lastProgrammingMessageSeqNum: UInt8 // updated by pod for 03, 08, $11, $19, $1A, $1C, $1E & $1F command messages - public let alerts: AlertSet - - - public let data: Data - - public init(encodedData: Data) throws { - if encodedData.count < length { - throw MessageBlockError.notEnoughData - } - - data = encodedData.prefix(upTo: Int(length)) - - guard let deliveryStatus = DeliveryStatus(rawValue: encodedData[1] >> 4) else { - throw MessageError.unknownValue(value: encodedData[1] >> 4, typeDescription: "DeliveryStatus") - } - self.deliveryStatus = deliveryStatus - - guard let podProgressStatus = PodProgressStatus(rawValue: encodedData[1] & 0xf) else { - throw MessageError.unknownValue(value: encodedData[1] & 0xf, typeDescription: "PodProgressStatus") - } - self.podProgressStatus = podProgressStatus - - let minutes = ((Int(encodedData[7]) & 0x7f) << 6) + (Int(encodedData[8]) >> 2) - self.timeActive = TimeInterval(minutes: Double(minutes)) - - let highInsulinBits = Int(encodedData[2] & 0xf) << 9 - let midInsulinBits = Int(encodedData[3]) << 1 - let lowInsulinBits = Int(encodedData[4] >> 7) - self.insulinDelivered = Double(highInsulinBits | midInsulinBits | lowInsulinBits) / Pod.pulsesPerUnit - - self.lastProgrammingMessageSeqNum = (encodedData[4] >> 3) & 0xf - - self.bolusNotDelivered = Double((Int(encodedData[4] & 0x3) << 8) | Int(encodedData[5])) / Pod.pulsesPerUnit - - self.alerts = AlertSet(rawValue: ((encodedData[6] & 0x7f) << 1) | (encodedData[7] >> 7)) - - self.reservoirLevel = Double((Int(encodedData[8] & 0x3) << 8) + Int(encodedData[9])) / Pod.pulsesPerUnit - } - - public init( - deliveryStatus: DeliveryStatus, - podProgressStatus: PodProgressStatus, - timeActive: TimeInterval, - reservoirLevel: Double, - insulinDelivered: Double, - bolusNotDelivered: Double, - lastProgrammingMessageSeqNum: UInt8, - alerts: AlertSet) - { - self.deliveryStatus = deliveryStatus - self.podProgressStatus = podProgressStatus - self.timeActive = timeActive - self.reservoirLevel = reservoirLevel - self.insulinDelivered = insulinDelivered - self.bolusNotDelivered = bolusNotDelivered - self.lastProgrammingMessageSeqNum = lastProgrammingMessageSeqNum - self.alerts = alerts - self.data = Data() - } - - // convenience function to create a StatusResponse for a DetailedStatus - public init(detailedStatus: DetailedStatus) { - self.deliveryStatus = detailedStatus.deliveryStatus - self.podProgressStatus = detailedStatus.podProgressStatus - self.timeActive = detailedStatus.timeActive - self.reservoirLevel = detailedStatus.reservoirLevel - self.insulinDelivered = detailedStatus.totalInsulinDelivered - self.bolusNotDelivered = detailedStatus.bolusNotDelivered - self.lastProgrammingMessageSeqNum = detailedStatus.lastProgrammingMessageSeqNum - self.alerts = detailedStatus.unacknowledgedAlerts - self.data = Data() - } -} - -extension StatusResponse: CustomDebugStringConvertible { - public var debugDescription: String { - return "StatusResponse(deliveryStatus:\(deliveryStatus.description), progressStatus:\(podProgressStatus), timeActive:\(timeActive.timeIntervalStr), reservoirLevel:\(reservoirLevel == Pod.reservoirLevelAboveThresholdMagicNumber ? "50+" : reservoirLevel.twoDecimals), insulinDelivered:\(insulinDelivered.twoDecimals), bolusNotDelivered:\(bolusNotDelivered.twoDecimals), lastProgrammingMessageSeqNum:\(lastProgrammingMessageSeqNum), alerts:\(alerts))" - } -} - diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/TempBasalExtraCommand.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/TempBasalExtraCommand.swift deleted file mode 100644 index f83330f45..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/MessageBlocks/TempBasalExtraCommand.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// TempBasalExtraCommand.swift -// OmniKit -// -// Created by Pete Schwamb on 6/6/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct TempBasalExtraCommand : MessageBlock { - - public let acknowledgementBeep: Bool - public let completionBeep: Bool - public let programReminderInterval: TimeInterval - public let remainingPulses: Double - public let delayUntilFirstPulse: TimeInterval - public let rateEntries: [RateEntry] - - public let blockType: MessageBlockType = .tempBasalExtra - - public var data: Data { - let beepOptions = (UInt8(programReminderInterval.minutes) & 0x3f) + (completionBeep ? (1<<6) : 0) + (acknowledgementBeep ? (1<<7) : 0) - var data = Data([ - blockType.rawValue, - UInt8(8 + rateEntries.count * 6), - beepOptions, - 0 - ]) - data.appendBigEndian(UInt16(round(remainingPulses * 10))) - data.appendBigEndian(UInt32(delayUntilFirstPulse.hundredthsOfMilliseconds)) - for entry in rateEntries { - data.append(entry.data) - } - return data - } - - public init(encodedData: Data) throws { - if encodedData.count < 14 { - throw MessageBlockError.notEnoughData - } - - let length = encodedData[1] - let numEntries = (length - 8) / 6 - - acknowledgementBeep = encodedData[2] & (1<<7) != 0 - completionBeep = encodedData[2] & (1<<6) != 0 - programReminderInterval = TimeInterval(minutes: Double(encodedData[2] & 0x3f)) - - remainingPulses = Double(encodedData[4...].toBigEndian(UInt16.self)) / 10.0 - let timerCounter = encodedData[6...].toBigEndian(UInt32.self) - delayUntilFirstPulse = TimeInterval(hundredthsOfMilliseconds: Double(timerCounter)) - - var entries = [RateEntry]() - for entryIndex in (0..> 6 - rssi = encodedData[18] & 0x3f - address = encodedData[19...].toBigEndian(UInt32.self) - - // These values only included in the longer 0x1B VersionResponse for the 03 SetupPod command. - pulseSize = nil - secondsPerBolusPulse = nil - secondsPerPrimePulse = nil - primeUnits = nil - cannulaInsertionUnits = nil - serviceDuration = nil - - case setupPodVersionLength: - // This is the longer 0x1B response for the 03 SetupPod command. - // 0 1 2 4 5 6 7 8 9 12 15 16 17 21 25 - // 01 LL VVVV BR PR PP CP PL MXMYMZ IXIYIZ ID 0J LLLLLLLL TTTTTTTT IIIIIIII - // 01 1b 1388 10 08 34 0a 50 020700 020700 02 03 0000a62b 00044794 1f00ee87 - // - // LL = 0x1b (setupPodVersionMessageLength) - // VVVV = 0x1388, pulse Volume in micro-units of U100 insulin per tenth of pulse (5000/100000 = 0.05U per pulse) - // BR = 0x10, Basic pulse Rate in # of eighth secs per pulse (16/8 = 2 seconds per pulse) - // PR = 0x08, Prime pulse Rate in # of eighth secs per pulse for priming boluses (8/8 = 1 second per priming pulse) - // PP = 0x34 = 52, # of Prime Pulses (52 pulses x 0.05U/pulse = 2.6U) - // CP = 0x0A = 10, # of Cannula insertion Pulses (10 pulses x 0.05U/pulse = 0.5U) - // PL = 0x50 = 80, # of hours maximum Pod Life - // PM = MX.MY.MZ = 02.07.02 (for PM 2.7.0 for Eros) - // PI = IX.IY.IZ = 02.07.02 (for PI 2.7.0 for Eros) - // ID = Product Id (02 for Eros, 04 for Dash, and perhaps 05 for Omnnipod 5) - // 0J = Pod progress state (should be 03 for this particular response) - // LLLLLLLL = Lot - // TTTTTTTT = Tid - // IIIIIIII = connection ID address - - firmwareVersion = FirmwareVersion(encodedData: encodedData.subdata(in: 9..<12)) - iFirmwareVersion = FirmwareVersion(encodedData: encodedData.subdata(in: 12..<15)) - productId = encodedData[15] - guard let progressStatus = PodProgressStatus(rawValue: encodedData[16]) else { - throw MessageBlockError.parseError - } - podProgressStatus = progressStatus - lot = encodedData[17...].toBigEndian(UInt32.self) - tid = encodedData[21...].toBigEndian(UInt32.self) - address = encodedData[25...].toBigEndian(UInt32.self) - - // These values should be verified elsewhere and appropriately handled. - pulseSize = Double(encodedData[2...].toBigEndian(UInt16.self)) / 100000 - secondsPerBolusPulse = Double(encodedData[4]) / 8 - secondsPerPrimePulse = Double(encodedData[5]) / 8 - primeUnits = Double(encodedData[6]) / Pod.pulsesPerUnit - cannulaInsertionUnits = Double(encodedData[7]) / Pod.pulsesPerUnit - serviceDuration = TimeInterval.hours(Double(encodedData[8])) - - // These values only included in the shorter 0x15 VersionResponse for the AssignAddress command for Eros. - gain = nil - rssi = nil - - default: - throw MessageBlockError.parseError - } - } - - public var isAssignAddressVersionResponse: Bool { - return self.data.count == assignAddressVersionLength + 2 - } - - public var isSetupPodVersionResponse: Bool { - return self.data.count == setupPodVersionLength + 2 - } -} - -extension VersionResponse: CustomDebugStringConvertible { - public var debugDescription: String { - return "VersionResponse(lot:\(lot), tid:\(tid), address:\(Data(bigEndian: address).hexadecimalString), firmwareVersion:\(firmwareVersion), iFirmwareVersion:\(iFirmwareVersion), productId:\(productId), podProgressStatus:\(podProgressStatus), gain:\(gain?.description ?? "NA"), rssi:\(rssi?.description ?? "NA"), pulseSize:\(pulseSize?.description ?? "NA"), secondsPerBolusPulse:\(secondsPerBolusPulse?.description ?? "NA"), secondsPerPrimePulse:\(secondsPerPrimePulse?.description ?? "NA"), primeUnits:\(primeUnits?.description ?? "NA"), cannulaInsertionUnits:\(cannulaInsertionUnits?.description ?? "NA"), serviceDuration:\(serviceDuration?.description ?? "NA"), )" - } -} - diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/PendingCommand.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/PendingCommand.swift deleted file mode 100644 index 34c75ce12..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/PendingCommand.swift +++ /dev/null @@ -1,209 +0,0 @@ -// -// PendingCommand.swift -// OmniKit -// -// Created by Pete Schwamb on 1/18/22. -// Copyright © 2022 Pete Schwamb. All rights reserved. -// - -import Foundation -import LoopKit - - -public enum StartProgram: RawRepresentable { - public typealias RawValue = [String: Any] - - case bolus(volume: Double, automatic: Bool) - case basalProgram(schedule: BasalSchedule) - case tempBasal(unitsPerHour: Double, duration: TimeInterval, isHighTemp: Bool, automatic: Bool) - - private enum StartProgramType: Int { - case bolus, basalProgram, tempBasal - } - - public var rawValue: RawValue { - switch self { - case .bolus(let volume, let automatic): - return [ - "programType": StartProgramType.bolus.rawValue, - "volume": volume, - "automatic": automatic - ] - case .basalProgram(let schedule): - return [ - "programType": StartProgramType.basalProgram.rawValue, - "schedule": schedule.rawValue - ] - case .tempBasal(let unitsPerHour, let duration, let isHighTemp, let automatic): - return [ - "programType": StartProgramType.tempBasal.rawValue, - "unitsPerHour": unitsPerHour, - "duration": duration, - "isHighTemp": isHighTemp, - "automatic": automatic - ] - } - } - - public init?(rawValue: RawValue) { - guard let encodedTypeRaw = rawValue["programType"] as? StartProgramType.RawValue, - let encodedType = StartProgramType(rawValue: encodedTypeRaw) else - { - return nil - } - switch encodedType { - case .bolus: - guard let volume = rawValue["volume"] as? Double, - let automatic = rawValue["automatic"] as? Bool else - { - return nil - } - self = .bolus(volume: volume, automatic: automatic) - case .basalProgram: - guard let rawSchedule = rawValue["schedule"] as? BasalSchedule.RawValue, - let schedule = BasalSchedule(rawValue: rawSchedule) else - { - return nil - } - self = .basalProgram(schedule: schedule) - case .tempBasal: - guard let unitsPerHour = rawValue["unitsPerHour"] as? Double, - let duration = rawValue["duration"] as? TimeInterval, - let isHighTemp = rawValue["isHighTemp"] as? Bool else - { - return nil - } - let automatic = rawValue["automatic"] as? Bool ?? true - self = .tempBasal(unitsPerHour: unitsPerHour, duration: duration, isHighTemp: isHighTemp, automatic: automatic) - } - } - - public static func == (lhs: StartProgram, rhs: StartProgram) -> Bool { - switch(lhs, rhs) { - case (.bolus(let lhsVolume, let lhsAutomatic), .bolus(let rhsVolume, let rhsAutomatic)): - return lhsVolume == rhsVolume && lhsAutomatic == rhsAutomatic - case (.basalProgram(let lhsSchedule), .basalProgram(let rhsSchedule)): - return lhsSchedule == rhsSchedule - case (.tempBasal(let lhsUnitsPerHour, let lhsDuration, let lhsIsHighTemp, let lhsAutomatic), .tempBasal(let rhsUnitsPerHour, let rhsDuration, let rhsIsHighTemp, let rhsAutomatic)): - return lhsUnitsPerHour == rhsUnitsPerHour && lhsDuration == rhsDuration && lhsIsHighTemp == rhsIsHighTemp && lhsAutomatic == rhsAutomatic - default: - return false - } - } -} - -public enum PendingCommand: RawRepresentable, Equatable { - public typealias RawValue = [String: Any] - - case program(StartProgram, Int, Date, Bool = true) - case stopProgram(CancelDeliveryCommand.DeliveryType, Int, Date, Bool = true) - - private enum PendingCommandType: Int { - case startProgram, stopProgram - } - - public var commandDate: Date { - switch self { - case .program(_, _, let date, _): - return date - case .stopProgram(_, _, let date, _): - return date - } - } - - public var sequence: Int { - switch self { - case .program(_, let sequence, _, _): - return sequence - case .stopProgram(_, let sequence, _, _): - return sequence - } - } - - public var isInFlight: Bool { - switch self { - case .program(_, _, _, let inflight): - return inflight - case .stopProgram(_, _, _, let inflight): - return inflight - } - } - - public var commsFinished: PendingCommand { - switch self { - case .program(let program, let sequence, let date, _): - return PendingCommand.program(program, sequence, date, false) - case .stopProgram(let program, let sequence, let date, _): - return PendingCommand.stopProgram(program, sequence, date, false) - } - } - - public init?(rawValue: RawValue) { - guard let rawPendingCommandType = rawValue["type"] as? PendingCommandType.RawValue else { - return nil - } - - guard let commandDate = rawValue["date"] as? Date else { - return nil - } - - guard let sequence = rawValue["sequence"] as? Int else { - return nil - } - - let inflight = rawValue["inflight"] as? Bool ?? false - - switch PendingCommandType(rawValue: rawPendingCommandType) { - case .startProgram?: - guard let rawUnacknowledgedProgram = rawValue["unacknowledgedProgram"] as? StartProgram.RawValue else { - return nil - } - if let program = StartProgram(rawValue: rawUnacknowledgedProgram) { - self = .program(program, sequence, commandDate, inflight) - } else { - return nil - } - case .stopProgram?: - guard let rawDeliveryType = rawValue["unacknowledgedStopProgram"] as? CancelDeliveryCommand.DeliveryType.RawValue else { - return nil - } - let stopProgram = CancelDeliveryCommand.DeliveryType(rawValue: rawDeliveryType) - self = .stopProgram(stopProgram, sequence, commandDate, inflight) - default: - return nil - } - } - - public var rawValue: RawValue { - var rawValue: RawValue = [:] - - switch self { - case .program(let program, let sequence, let date, let inflight): - rawValue["type"] = PendingCommandType.startProgram.rawValue - rawValue["date"] = date - rawValue["sequence"] = sequence - rawValue["inflight"] = inflight - rawValue["unacknowledgedProgram"] = program.rawValue - case .stopProgram(let stopProgram, let sequence, let date, let inflight): - rawValue["type"] = PendingCommandType.stopProgram.rawValue - rawValue["date"] = date - rawValue["sequence"] = sequence - rawValue["inflight"] = inflight - rawValue["unacknowledgedStopProgram"] = stopProgram.rawValue - } - return rawValue - } - - public static func == (lhs: PendingCommand, rhs: PendingCommand) -> Bool { - switch(lhs, rhs) { - case (.program(let lhsProgram, let lhsSequence, let lhsDate, let lhsInflight), .program(let rhsProgram, let rhsSequence, let rhsDate, let rhsInflight)): - return lhsProgram == rhsProgram && lhsSequence == rhsSequence && lhsDate == rhsDate && lhsInflight == rhsInflight - case (.stopProgram(let lhsStopProgram, let lhsSequence, let lhsDate, let lhsInflight), .stopProgram(let rhsStopProgram, let rhsSequence, let rhsDate, let rhsInflight)): - return lhsStopProgram == rhsStopProgram && lhsSequence == rhsSequence && lhsDate == rhsDate && lhsInflight == rhsInflight - default: - return false - } - } -} - - diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/Pod.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/Pod.swift deleted file mode 100644 index b16fe5d79..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/Pod.swift +++ /dev/null @@ -1,144 +0,0 @@ -// -// Pod.swift -// OmniKit -// -// Created by Pete Schwamb on 4/4/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct Pod { - // Volume of U100 insulin in one motor pulse - // Must agree with value returned by pod during the pairing process. - public static let pulseSize: Double = 0.05 - - // Number of pulses required to deliver one unit of U100 insulin - public static let pulsesPerUnit: Double = 1 / Pod.pulseSize - - // Seconds per pulse for boluses - // Checked to verify it agrees with value returned by pod during the pairing process. - public static let secondsPerBolusPulse: Double = 2 - - // Units per second for boluses - public static let bolusDeliveryRate: Double = Pod.pulseSize / Pod.secondsPerBolusPulse - - // Seconds per pulse for priming/cannula insertion - // Checked to verify it agrees with value returned by pod during the pairing process. - public static let secondsPerPrimePulse: Double = 1 - - // Units per second for priming/cannula insertion - public static let primeDeliveryRate: Double = Pod.pulseSize / Pod.secondsPerPrimePulse - - // Expiration advisory window: time after expiration alert, and end of service imminent alarm - public static let expirationAdvisoryWindow = TimeInterval(hours: 7) - - // End of service imminent window, relative to pod end of service - public static let endOfServiceImminentWindow = TimeInterval(hours: 1) - - // Total pod service time. A fault is triggered if this time is reached before pod deactivation. - // Checked to verify it agrees with value returned by pod during the pairing process. - public static let serviceDuration = TimeInterval(hours: 80) - - // Nomimal pod life (72 hours) - public static let nominalPodLife = Pod.serviceDuration - Pod.endOfServiceImminentWindow - Pod.expirationAdvisoryWindow - - // Maximum reservoir level reading - public static let maximumReservoirReading: Double = 50 - - // Reservoir level magic number indicating 50+ U remaining - public static let reservoirLevelAboveThresholdMagicNumber: Double = 51.15 - - // Reservoir Capacity - public static let reservoirCapacity: Double = 200 - - // Supported basal rates - // Eros minimum scheduled basal rate is 0.05 U/H while for Dash supports 0 U/H. - // Would need to have this value based on productID to be able to share this with Eros. - public static let supportedBasalRates: [Double] = (1...600).map { Double($0) / Double(pulsesPerUnit) } - - // Supported temp basal rates - public static let supportedTempBasalRates: [Double] = (0...600).map { Double($0) / Double(pulsesPerUnit) } - - // The internal basal rate used for non-Eros pods - // Would need to have this value based on productID to be able to share this file with Eros. - public static let zeroBasalRate: Double = 0.0 - - // Maximum number of basal schedule entries supported - public static let maximumBasalScheduleEntryCount: Int = 24 - - // Minimum duration of a single basal schedule entry - public static let minimumBasalScheduleEntryDuration = TimeInterval.minutes(30) - - // Supported temp basal durations (30m to 12h) - public static let supportedTempBasalDurations: [TimeInterval] = (1...24).map { Double($0) * TimeInterval(minutes: 30) } - - // Default amount for priming bolus using secondsPerPrimePulse timing. - // Checked to verify it agrees with value returned by pod during the pairing process. - public static let primeUnits = 2.6 - - // Default amount for cannula insertion bolus using secondsPerPrimePulse timing. - // Checked to verify it agrees with value returned by pod during the pairing process. - public static let cannulaInsertionUnits = 0.5 - - public static let cannulaInsertionUnitsExtra = 0.0 // edit to add a fixed additional amount of insulin during cannula insertion - - // Default and limits for expiration reminder alerts - public static let defaultExpirationReminderOffset = TimeInterval(hours: 2) - public static let expirationReminderAlertMinHoursBeforeExpiration = 1 - public static let expirationReminderAlertMaxHoursBeforeExpiration = 24 - - // Threshold used to display pod end of life warnings - public static let timeRemainingWarningThreshold = TimeInterval(days: 1) - - // Default low reservoir alert limit in Units - public static let defaultLowReservoirReminder: Double = 10 - - // Allowed Low Reservoir reminder values - public static let allowedLowReservoirReminderValues = Array(stride(from: 10, through: 50, by: 1)) -} - -// DeliveryStatus used in StatusResponse and DetailedStatus -public enum DeliveryStatus: UInt8, CustomStringConvertible { - case suspended = 0 - case scheduledBasal = 1 - case tempBasalRunning = 2 - case priming = 4 - case bolusInProgress = 5 - case bolusAndTempBasal = 6 - case extendedBolusRunning = 9 - case extendedBolusAndTempBasal = 10 - - public var bolusing: Bool { - return self == .bolusInProgress || self == .bolusAndTempBasal || self == .extendedBolusRunning || self == .extendedBolusAndTempBasal - } - - public var tempBasalRunning: Bool { - return self == .tempBasalRunning || self == .bolusAndTempBasal || self == .extendedBolusAndTempBasal - } - - public var extendedBolusRunninng: Bool { - return self == .extendedBolusRunning || self == .extendedBolusAndTempBasal - } - - public var description: String { - switch self { - case .suspended: - return LocalizedString("Suspended", comment: "Delivery status when insulin delivery is suspended") - case .scheduledBasal: - return LocalizedString("Scheduled basal", comment: "Delivery status when scheduled basal is running") - case .tempBasalRunning: - return LocalizedString("Temp basal running", comment: "Delivery status when temp basal is running") - case .priming: - return LocalizedString("Priming", comment: "Delivery status when pod is priming") - case .bolusInProgress: - return LocalizedString("Bolusing", comment: "Delivery status when bolusing") - case .bolusAndTempBasal: - return LocalizedString("Bolusing with temp basal", comment: "Delivery status when bolusing and temp basal is running") - case .extendedBolusRunning: - return LocalizedString("Extended bolus running", comment: "Delivery status when extended bolus is running") - case .extendedBolusAndTempBasal: - return LocalizedString("Extended bolus running with temp basal", comment: "Delivery status when extended bolus and temp basal is running") - } - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/PodDoseProgressEstimator.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/PodDoseProgressEstimator.swift deleted file mode 100644 index f62d076a8..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/PodDoseProgressEstimator.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// PodDoseProgressEstimator.swift -// OmniKit -// -// Created by Pete Schwamb on 3/12/19. -// Copyright © 2019 Pete Schwamb. All rights reserved. -// - -import Foundation -import LoopKit - -class PodDoseProgressEstimator: DoseProgressTimerEstimator { - - let dose: DoseEntry - - weak var pumpManager: PumpManager? - - override var progress: DoseProgress { - let elapsed = -dose.startDate.timeIntervalSinceNow - let duration = dose.endDate.timeIntervalSince(dose.startDate) - let percentComplete = min(elapsed / duration, 1) - let delivered = pumpManager?.roundToSupportedBolusVolume(units: percentComplete * dose.programmedUnits) ?? dose.programmedUnits - return DoseProgress(deliveredUnits: delivered, percentComplete: percentComplete) - } - - init(dose: DoseEntry, pumpManager: PumpManager, reportingQueue: DispatchQueue) { - self.dose = dose - self.pumpManager = pumpManager - super.init(reportingQueue: reportingQueue) - } - - override func timerParameters() -> (delay: TimeInterval, repeating: TimeInterval) { - let timeSinceStart = dose.startDate.timeIntervalSinceNow - let timeBetweenPulses: TimeInterval - switch dose.type { - case .bolus: - timeBetweenPulses = Pod.pulseSize / Pod.bolusDeliveryRate - case .basal, .tempBasal: - timeBetweenPulses = Pod.pulseSize / (dose.unitsPerHour / TimeInterval(hours: 1)) - default: - fatalError("Can only estimate progress on basal rates or boluses.") - } - let delayUntilNextPulse = timeBetweenPulses - timeSinceStart.remainder(dividingBy: timeBetweenPulses) - - return (delay: delayUntilNextPulse, repeating: timeBetweenPulses) - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/PodInsulinMeasurements.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/PodInsulinMeasurements.swift deleted file mode 100644 index 13fd7d366..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/PodInsulinMeasurements.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// PodInsulinMeasurements.swift -// OmniKit -// -// Created by Pete Schwamb on 9/5/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct PodInsulinMeasurements: RawRepresentable, Equatable { - public typealias RawValue = [String: Any] - - public let validTime: Date - public let delivered: Double - public let reservoirLevel: Double? - - public init(insulinDelivered: Double, reservoirLevel: Double?, validTime: Date) { - self.validTime = validTime - self.delivered = insulinDelivered - self.reservoirLevel = reservoirLevel - } - - // RawRepresentable - public init?(rawValue: RawValue) { - guard - let validTime = rawValue["validTime"] as? Date, - let delivered = rawValue["delivered"] as? Double - else { - return nil - } - self.validTime = validTime - self.delivered = delivered - self.reservoirLevel = rawValue["reservoirLevel"] as? Double - } - - public var rawValue: RawValue { - var rawValue: RawValue = [ - "validTime": validTime, - "delivered": delivered - ] - - if let reservoirLevel = reservoirLevel { - rawValue["reservoirLevel"] = reservoirLevel - } - - return rawValue - } -} - diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/PodProgressStatus.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/PodProgressStatus.swift deleted file mode 100644 index cf21fd607..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/PodProgressStatus.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// PodProgressStatus.swift -// OmniKit -// -// Created by Pete Schwamb on 9/28/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public enum PodProgressStatus: UInt8, CustomStringConvertible, Equatable { - case initialized = 0 - case memoryInitialized = 1 - case reminderInitialized = 2 - case pairingCompleted = 3 - case priming = 4 - case primingCompleted = 5 - case basalInitialized = 6 - case insertingCannula = 7 - case aboveFiftyUnits = 8 - case fiftyOrLessUnits = 9 - case oneNotUsed = 10 - case twoNotUsed = 11 - case threeNotUsed = 12 - case faultEventOccurred = 13 // fault event occurred (a "screamer") - case activationTimeExceeded = 14 // took > 2 hrs from progress 2 to 3 OR > 1 hr from 3 to 8 - case inactive = 15 // pod deactivated or a fatal packet state error - - public var readyForDelivery: Bool { - return self == .fiftyOrLessUnits || self == .aboveFiftyUnits - } - - public var description: String { - switch self { - case .initialized: - return LocalizedString("Initialized", comment: "Pod initialized") - case .memoryInitialized: - return LocalizedString("Memory initialized", comment: "Pod memory initialized") - case .reminderInitialized: - return LocalizedString("Reminder initialized", comment: "Pod pairing reminder initialized") - case .pairingCompleted: - return LocalizedString("Pairing completed", comment: "Pod status when pairing completed") - case .priming: - return LocalizedString("Priming", comment: "Pod status when priming") - case .primingCompleted: - return LocalizedString("Priming completed", comment: "Pod state when priming completed") - case .basalInitialized: - return LocalizedString("Basal initialized", comment: "Pod state when basal initialized") - case .insertingCannula: - return LocalizedString("Inserting cannula", comment: "Pod state when inserting cannula") - case .aboveFiftyUnits: - return LocalizedString("Normal", comment: "Pod state when running above fifty units") - case .fiftyOrLessUnits: - return LocalizedString("Low reservoir", comment: "Pod state when running with fifty or less units") - case .oneNotUsed: - return LocalizedString("oneNotUsed", comment: "Pod state oneNotUsed") - case .twoNotUsed: - return LocalizedString("twoNotUsed", comment: "Pod state twoNotUsed") - case .threeNotUsed: - return LocalizedString("threeNotUsed", comment: "Pod state threeNotUsed") - case .faultEventOccurred: - return LocalizedString("Fault event occurred", comment: "Pod state when fault event has occurred") - case .activationTimeExceeded: - return LocalizedString("Activation time exceeded", comment: "Pod state when activation not completed in the time allowed") - case .inactive: - return LocalizedString("Deactivated", comment: "Pod state when deactivated") - } - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/PumpManagerAlert.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/PumpManagerAlert.swift deleted file mode 100644 index c17ec0e19..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/PumpManagerAlert.swift +++ /dev/null @@ -1,232 +0,0 @@ -// -// PumpManagerAlert.swift -// OmniKit -// -// Created by Pete Schwamb on 7/9/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit -import HealthKit - -public enum PumpManagerAlert: Hashable { - case podExpireImminent(triggeringSlot: AlertSlot?) - case userPodExpiration(triggeringSlot: AlertSlot?, scheduledExpirationReminderOffset: TimeInterval) - case lowReservoir(triggeringSlot: AlertSlot?, lowReservoirReminderValue: Double) - case suspendInProgress(triggeringSlot: AlertSlot?) - case suspendEnded(triggeringSlot: AlertSlot?) - case podExpiring(triggeringSlot: AlertSlot?) - case finishSetupReminder(triggeringSlot: AlertSlot?) - case unexpectedAlert(triggeringSlot: AlertSlot?) - case timeOffsetChangeDetected - - var isRepeating: Bool { - return repeatInterval != nil - } - - var repeatInterval: TimeInterval? { - switch self { - case .suspendEnded: - return .minutes(15) - default: - return nil - } - } - - var contentTitle: String { - switch self { - case .userPodExpiration: - return LocalizedString("Pod Expiration Reminder", comment: "Alert content title for userPodExpiration pod alert") - case .podExpiring: - return LocalizedString("Pod Expired", comment: "Alert content title for podExpiring pod alert") - case .podExpireImminent: - return LocalizedString("Pod Expired", comment: "Alert content title for podExpireImminent pod alert") - case .lowReservoir: - return LocalizedString("Low Reservoir", comment: "Alert content title for lowReservoir pod alert") - case .suspendInProgress: - return LocalizedString("Suspend In Progress Reminder", comment: "Alert content title for suspendInProgress pod alert") - case .suspendEnded: - return LocalizedString("Resume Insulin", comment: "Alert content title for suspendEnded pod alert") - case .finishSetupReminder: - return LocalizedString("Pod Pairing Incomplete", comment: "Alert content title for finishSetupReminder pod alert") - case .unexpectedAlert: - return LocalizedString("Unexpected Alert", comment: "Alert content title for unexpected pod alert") - case .timeOffsetChangeDetected: - return LocalizedString("Time Change Detected", comment: "Alert content title for timeOffsetChangeDetected pod alert") - } - } - - var contentBody: String { - switch self { - case .userPodExpiration(_, let offset): - let formatter = DateComponentsFormatter() - formatter.allowedUnits = [.hour] - formatter.unitsStyle = .full - let timeString = formatter.string(from: TimeInterval(offset))! - return String(format: LocalizedString("Pod expires in %1$@.", comment: "Format string for alert content body for userPodExpiration pod alert. (1: time until expiration)"), timeString) - case .podExpiring: - return LocalizedString("Change Pod now. Pod has been active for 72 hours.", comment: "Alert content body for podExpiring pod alert") - case .podExpireImminent: - return LocalizedString("Change Pod now. Insulin delivery will stop in 1 hour.", comment: "Alert content body for podExpireImminent pod alert") - case .lowReservoir(_, let lowReservoirReminderValue): - let quantityFormatter = QuantityFormatter(for: .internationalUnit()) - let valueString = quantityFormatter.string(from: HKQuantity(unit: .internationalUnit(), doubleValue: lowReservoirReminderValue), for: .internationalUnit()) ?? String(describing: lowReservoirReminderValue) - return String(format: LocalizedString("%1$@ insulin or less remaining in Pod. Change Pod soon.", comment: "Format string for alert content body for lowReservoir pod alert. (1: reminder value)"), valueString) - case .suspendInProgress: - return LocalizedString("Suspend In Progress Reminder", comment: "Alert content body for suspendInProgress pod alert") - case .suspendEnded: - return LocalizedString("The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes.", comment: "Alert content body for suspendEnded pod alert") - case .finishSetupReminder: - return LocalizedString("Please finish pairing your pod.", comment: "Alert content body for finishSetupReminder pod alert") - case .unexpectedAlert(let triggeringSlot): - let slotNumberString = triggeringSlot != nil ? String(describing: triggeringSlot!.rawValue) : "?" - return String(format: LocalizedString("Unexpected Pod Alert #%1@!", comment: "Alert content body for unexpected pod alert (1: slotNumberString)"), slotNumberString) - case .timeOffsetChangeDetected: - return LocalizedString("The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings.", comment: "Alert content body for timeOffsetChangeDetected pod alert") - } - } - - var triggeringSlot: AlertSlot? { - switch self { - case .userPodExpiration(let slot, _): - return slot - case .podExpiring(let slot): - return slot - case .podExpireImminent(let slot): - return slot - case .lowReservoir(let slot, _): - return slot - case .suspendInProgress(let slot): - return slot - case .suspendEnded(let slot): - return slot - case .finishSetupReminder(let slot): - return slot - case .unexpectedAlert(let slot): - return slot - case .timeOffsetChangeDetected: - return nil - } - } - - // Override background (UserNotification) content - - var backgroundContentTitle: String { - return contentTitle - } - - var backgroundContentBody: String { - switch self { - case .suspendEnded: - return LocalizedString("Suspension time is up. Open the app and resume.", comment: "Alert notification body for suspendEnded pod alert user notification") - default: - return contentBody - } - } - - - var actionButtonLabel: String { - return LocalizedString("Ok", comment: "Action button default text for PodAlerts") - } - - var foregroundContent: Alert.Content { - return Alert.Content(title: contentTitle, body: contentBody, acknowledgeActionButtonLabel: actionButtonLabel) - } - - var backgroundContent: Alert.Content { - return Alert.Content(title: backgroundContentTitle, body: backgroundContentBody, acknowledgeActionButtonLabel: actionButtonLabel) - } - - var alertIdentifier: String { - switch self { - case .userPodExpiration: - return "userPodExpiration" - case .podExpiring: - return "podExpiring" - case .podExpireImminent: - return "podExpireImminent" - case .lowReservoir: - return "lowReservoir" - case .suspendInProgress: - return "suspendInProgress" - case .suspendEnded: - return "suspendEnded" - case .finishSetupReminder: - return "finishSetupReminder" - case .unexpectedAlert: - return "unexpectedAlert" - case .timeOffsetChangeDetected: - return "timeOffsetChangeDetected" - } - } - - var repeatingAlertIdentifier: String { - return alertIdentifier + "-repeating" - } -} - -extension PumpManagerAlert: RawRepresentable { - - public typealias RawValue = [String: Any] - - public init?(rawValue: RawValue) { - guard let identifier = rawValue["identifier"] as? String else { - return nil - } - - let slot: AlertSlot? - - if let rawSlot = rawValue["slot"] as? AlertSlot.RawValue { - slot = AlertSlot(rawValue: rawSlot) - } else { - slot = nil - } - - switch identifier { - case "userPodExpiration": - guard let offset = rawValue["offset"] as? TimeInterval, offset > 0 else { - return nil - } - self = .userPodExpiration(triggeringSlot: slot, scheduledExpirationReminderOffset: offset) - case "podExpiring": - self = .podExpiring(triggeringSlot: slot) - case "podExpireImminent": - self = .podExpireImminent(triggeringSlot: slot) - case "lowReservoir": - guard let value = rawValue["value"] as? Double else { - return nil - } - self = .lowReservoir(triggeringSlot: slot, lowReservoirReminderValue: value) - case "suspendInProgress": - self = .suspendInProgress(triggeringSlot: slot) - case "suspendEnded": - self = .suspendEnded(triggeringSlot: slot) - case "unexpectedAlert": - self = .unexpectedAlert(triggeringSlot: slot) - case "timeOffsetChangeDetected": - self = .timeOffsetChangeDetected - default: - return nil - } - } - - public var rawValue: [String : Any] { - var rawValue: RawValue = [ - "identifier": alertIdentifier - ] - - rawValue["slot"] = triggeringSlot?.rawValue - - switch self { - case .lowReservoir(_, lowReservoirReminderValue: let value): - rawValue["value"] = value - case .userPodExpiration(_, scheduledExpirationReminderOffset: let offset): - rawValue["offset"] = offset - default: - break - } - - return rawValue - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/ReservoirLevel.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/ReservoirLevel.swift deleted file mode 100644 index 1f0b6f46d..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/ReservoirLevel.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// ReservoirLevel.swift -// OmniKit -// -// Created by Pete Schwamb on 5/31/19. -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum ReservoirLevel: RawRepresentable, Equatable { - public typealias RawValue = Double - - case valid(Double) - case aboveThreshold - - public var percentage: Double { - switch self { - case .aboveThreshold: - return 1 - case .valid(let value): - // Set 50U as the halfway mark, even though pods can hold 200U. - return min(1, max(0, value / 100)) - } - } - - public init(rawValue: RawValue) { - if rawValue > Pod.maximumReservoirReading { - self = .aboveThreshold - } else { - self = .valid(rawValue) - } - } - - public var rawValue: RawValue { - switch self { - case .valid(let value): - return value - case .aboveThreshold: - return Pod.reservoirLevelAboveThresholdMagicNumber - } - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/SilencePodPreference.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/SilencePodPreference.swift deleted file mode 100644 index 118bbf560..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/SilencePodPreference.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// SilencePodPreference.swift -// OmniKit -// -// Created by Joe Moran on 8/30/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -public enum SilencePodPreference: Int, CaseIterable { - case disabled - case enabled - - public var title: String { - switch self { - case .disabled: - return LocalizedString("Disabled", comment: "Title string for SilencePodPreference.disabled") - case .enabled: - return LocalizedString("Silenced", comment: "Title string for SilencePodPreference.enabled") - } - } - - public var description: String { - switch self { - case .disabled: - return LocalizedString("Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled.", comment: "Description for SilencePodPreference.disabled") - case .enabled: - return LocalizedString("All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts.", comment: "Description for SilencePodPreference.enabled") - } - } -} diff --git a/Dependencies/OmniKit/OmniKit/OmnipodCommon/UnfinalizedDose.swift b/Dependencies/OmniKit/OmniKit/OmnipodCommon/UnfinalizedDose.swift deleted file mode 100644 index d439d9d50..000000000 --- a/Dependencies/OmniKit/OmniKit/OmnipodCommon/UnfinalizedDose.swift +++ /dev/null @@ -1,346 +0,0 @@ -// -// UnfinalizedDose.swift -// OmniKit -// -// From OmniKit/Model/UnfinalizedDose.swift -// Created by Pete Schwamb on 9/5/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation -import LoopKit - -public struct UnfinalizedDose: RawRepresentable, Equatable, CustomStringConvertible { - public typealias RawValue = [String: Any] - - enum DoseType: Int { - case bolus = 0 - case tempBasal - case suspend - case resume - } - - enum ScheduledCertainty: Int { - case certain = 0 - case uncertain - - public var localizedDescription: String { - switch self { - case .certain: - return LocalizedString("Certain", comment: "String describing a dose that was certainly scheduled") - case .uncertain: - return LocalizedString("Uncertain", comment: "String describing a dose that was possibly scheduled") - } - } - } - - private let insulinFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.maximumFractionDigits = 3 - return formatter - }() - - private let shortDateFormatter: DateFormatter = { - let timeFormatter = DateFormatter() - timeFormatter.dateStyle = .short - timeFormatter.timeStyle = .medium - return timeFormatter - }() - - private let dateFormatter = ISO8601DateFormatter() - - fileprivate var uniqueKey: Data { - return "\(doseType) \(scheduledUnits ?? units) \(dateFormatter.string(from: startTime))".data(using: .utf8)! - } - - let doseType: DoseType - public var units: Double - public var automatic: Bool // Tracks if this dose was issued automatically or manually - var scheduledUnits: Double? // Tracks the scheduled units, as boluses may be canceled before finishing, at which point units would reflect actual delivered volume. - var scheduledTempRate: Double? // Tracks the original temp rate, as during finalization the units are discretized to pump pulses, changing the actual rate - let startTime: Date - var duration: TimeInterval? - var scheduledCertainty: ScheduledCertainty - var isHighTemp: Bool = false // Track this for situations where cancelling temp basal is unacknowledged, and recovery fails, and we have to assume the most possible delivery - var insulinType: InsulinType? - - var finishTime: Date? { - get { - return duration != nil ? startTime.addingTimeInterval(duration!) : nil - } - set { - duration = newValue?.timeIntervalSince(startTime) - } - } - - public func progress(at date: Date = Date()) -> Double { - guard let duration = duration else { - return 0 - } - let elapsed = -startTime.timeIntervalSince(date) - return min(elapsed / duration, 1) - } - - public func isFinished(at date: Date = Date()) -> Bool { - return progress(at: date) >= 1 - } - - // Units per hour - public var rate: Double { - guard let duration = duration else { - return 0 - } - return units / duration.hours - } - - public var finalizedUnits: Double? { - guard isFinished() else { - return nil - } - return units - } - - init(bolusAmount: Double, startTime: Date, scheduledCertainty: ScheduledCertainty, insulinType: InsulinType, automatic: Bool = false) { - self.doseType = .bolus - self.units = bolusAmount - self.startTime = startTime - self.duration = TimeInterval(bolusAmount / Pod.bolusDeliveryRate) - self.scheduledCertainty = scheduledCertainty - self.scheduledUnits = nil - self.automatic = automatic - self.insulinType = insulinType - } - - init(tempBasalRate: Double, startTime: Date, duration: TimeInterval, isHighTemp: Bool, automatic: Bool, scheduledCertainty: ScheduledCertainty, insulinType: InsulinType) { - self.doseType = .tempBasal - self.units = tempBasalRate * duration.hours - self.startTime = startTime - self.duration = duration - self.scheduledCertainty = scheduledCertainty - self.scheduledUnits = nil - self.automatic = automatic - self.isHighTemp = isHighTemp - self.insulinType = insulinType - } - - init(suspendStartTime: Date, scheduledCertainty: ScheduledCertainty) { - self.doseType = .suspend - self.units = 0 - self.startTime = suspendStartTime - self.scheduledCertainty = scheduledCertainty - self.automatic = false - } - - init(resumeStartTime: Date, scheduledCertainty: ScheduledCertainty, insulinType: InsulinType) { - self.doseType = .resume - self.units = 0 - self.startTime = resumeStartTime - self.scheduledCertainty = scheduledCertainty - self.automatic = false - self.insulinType = insulinType - } - - public mutating func cancel(at date: Date, withRemaining remaining: Double? = nil) { - guard let finishTime = finishTime, date < finishTime else { - return - } - - scheduledUnits = units - let newDuration = date.timeIntervalSince(startTime) - - switch doseType { - case .bolus: - let oldRate = rate - if let remaining = remaining { - units = units - remaining - } else { - units = oldRate * newDuration.hours - } - case .tempBasal: - scheduledTempRate = rate - units = floor(rate * newDuration.hours * Pod.pulsesPerUnit) / Pod.pulsesPerUnit - print("Temp basal scheduled units: \(String(describing: scheduledUnits)), delivered units: \(units), duration: \(newDuration.minutes)") - default: - break - } - duration = newDuration - } - - public func isMutable(at date: Date = Date()) -> Bool { - switch doseType { - case .bolus, .tempBasal: - return !isFinished(at: date) - default: - return false - } - } - - public var description: String { - let unitsStr = insulinFormatter.string(from: units) ?? "" - let startTimeStr = shortDateFormatter.string(from: startTime) - let durationStr = duration?.format(using: [.minute, .second]) ?? "" - switch doseType { - case .bolus: - if let scheduledUnits = scheduledUnits { - let scheduledUnitsStr = insulinFormatter.string(from: scheduledUnits) ?? "?" - return String(format: LocalizedString("InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@", comment: "The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty)"), unitsStr, scheduledUnitsStr, startTimeStr, durationStr, scheduledCertainty.localizedDescription) - } else { - return String(format: LocalizedString("Bolus: %1$@U %2$@ %3$@ %4$@", comment: "The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty)"), unitsStr, startTimeStr, durationStr, scheduledCertainty.localizedDescription) - } - case .tempBasal: - let volumeStr = insulinFormatter.string(from: units) ?? "?" - let rateStr = NumberFormatter.localizedString(from: NSNumber(value: scheduledTempRate ?? rate), number: .decimal) - return String(format: LocalizedString("TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@", comment: "The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty"), rateStr, startTimeStr, durationStr, volumeStr, scheduledCertainty.localizedDescription) - case .suspend: - return String(format: LocalizedString("Suspend: %1$@ %2$@", comment: "The format string describing a suspend. (1: Time)(2: Scheduled certainty"), startTimeStr, scheduledCertainty.localizedDescription) - case .resume: - return String(format: LocalizedString("Resume: %1$@ %2$@", comment: "The format string describing a resume. (1: Time)(2: Scheduled certainty"), startTimeStr, scheduledCertainty.localizedDescription) - } - } - - public var eventTitle: String { - switch doseType { - case .bolus: - return LocalizedString("Bolus", comment: "Pump Event title for UnfinalizedDose with doseType of .bolus") - case .resume: - return LocalizedString("Resume", comment: "Pump Event title for UnfinalizedDose with doseType of .resume") - case .suspend: - return LocalizedString("Suspend", comment: "Pump Event title for UnfinalizedDose with doseType of .suspend") - case .tempBasal: - return LocalizedString("Temp Basal", comment: "Pump Event title for UnfinalizedDose with doseType of .tempBasal") - } - } - - // RawRepresentable - public init?(rawValue: RawValue) { - guard - let rawDoseType = rawValue["doseType"] as? Int, - let doseType = DoseType(rawValue: rawDoseType), - let units = rawValue["units"] as? Double, - let startTime = rawValue["startTime"] as? Date, - let rawScheduledCertainty = rawValue["scheduledCertainty"] as? Int, - let scheduledCertainty = ScheduledCertainty(rawValue: rawScheduledCertainty) - else { - return nil - } - - self.doseType = doseType - self.units = units - self.startTime = startTime - self.scheduledCertainty = scheduledCertainty - - self.scheduledUnits = rawValue["scheduledUnits"] as? Double - - self.scheduledTempRate = rawValue["scheduledTempRate"] as? Double - - self.duration = rawValue["duration"] as? Double - - if let automatic = rawValue["automatic"] as? Bool { - self.automatic = automatic - } else { - if case .tempBasal = doseType { - self.automatic = true - } else { - self.automatic = false - } - } - - if let isHighTemp = rawValue["isHighTemp"] as? Bool { - self.isHighTemp = isHighTemp - } else { - self.isHighTemp = false - } - - if let rawInsulinType = rawValue["insulinType"] as? InsulinType.RawValue { - self.insulinType = InsulinType(rawValue: rawInsulinType) - } - - } - - public var rawValue: RawValue { - var rawValue: RawValue = [ - "doseType": doseType.rawValue, - "units": units, - "startTime": startTime, - "scheduledCertainty": scheduledCertainty.rawValue, - "automatic": automatic, - "isHighTemp": isHighTemp, - ] - - rawValue["scheduledUnits"] = scheduledUnits - rawValue["scheduledTempRate"] = scheduledTempRate - rawValue["duration"] = duration - rawValue["insulinType"] = insulinType?.rawValue - - return rawValue - } -} - -private extension TimeInterval { - func format(using units: NSCalendar.Unit) -> String? { - let formatter = DateComponentsFormatter() - formatter.allowedUnits = units - formatter.unitsStyle = .full - formatter.zeroFormattingBehavior = .dropLeading - formatter.maximumUnitCount = 2 - - return formatter.string(from: self) - } -} - -extension NewPumpEvent { - init(_ dose: UnfinalizedDose) { - let entry = DoseEntry(dose) - self.init(date: dose.startTime, dose: entry, raw: dose.uniqueKey, title: dose.eventTitle) - } -} - -extension DoseEntry { - init (_ dose: UnfinalizedDose) { - switch dose.doseType { - case .bolus: - self = DoseEntry( - type: .bolus, - startDate: dose.startTime, - endDate: dose.finishTime, - value: dose.scheduledUnits ?? dose.units, - unit: .units, - deliveredUnits: dose.finalizedUnits, - insulinType: dose.insulinType, - automatic: dose.automatic, - isMutable: dose.isMutable() - ) - case .tempBasal: - self = DoseEntry( - type: .tempBasal, - startDate: dose.startTime, - endDate: dose.finishTime, - value: dose.scheduledTempRate ?? dose.rate, - unit: .unitsPerHour, - deliveredUnits: dose.finalizedUnits, - insulinType: dose.insulinType, - automatic: dose.automatic, - isMutable: dose.isMutable() - ) - case .suspend: - self = DoseEntry(suspendDate: dose.startTime) - case .resume: - self = DoseEntry(resumeDate: dose.startTime, insulinType: dose.insulinType) - } - } -} - -extension StartProgram { - func unfinalizedDose(at programDate: Date, withCertainty certainty: UnfinalizedDose.ScheduledCertainty, insulinType: InsulinType) -> UnfinalizedDose? { - switch self { - case .bolus(volume: let volume, automatic: let automatic): - return UnfinalizedDose(bolusAmount: volume, startTime: programDate, scheduledCertainty: certainty, insulinType: insulinType, automatic: automatic) - case .tempBasal(unitsPerHour: let rate, duration: let duration, let isHighTemp, let automatic): - return UnfinalizedDose(tempBasalRate: rate, startTime: programDate, duration: duration, isHighTemp: isHighTemp, automatic: automatic, scheduledCertainty: certainty, insulinType: insulinType) - case .basalProgram: - return UnfinalizedDose(resumeStartTime: programDate, scheduledCertainty: certainty, insulinType: insulinType) - } - } -} - diff --git a/Dependencies/OmniKit/OmniKit/PumpManager/DetailedStatus+OmniKit.swift b/Dependencies/OmniKit/OmniKit/PumpManager/DetailedStatus+OmniKit.swift deleted file mode 100644 index d5d92f379..000000000 --- a/Dependencies/OmniKit/OmniKit/PumpManager/DetailedStatus+OmniKit.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// DetailedStatus+OmniKit.swift -// OmniKit -// -// Created by Joseph Moran on 06/22/2022 -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import Foundation - -// Returns an appropropriate PDM style Ref string for the Detailed Status. -// For most types, Ref: TT-VVVHH-IIIRR-FFF computed as {19|17}-{VV}{SSSS/60}-{NNNN/20}{RRRR/20}-PP -extension DetailedStatus { - public var pdmRef: String? { - let TT, VVV, HH, III, RR, FFF: UInt8 - - switch faultEventCode.faultType { - case .noFaults, .reservoirEmpty, .exceededMaximumPodLife80Hrs: - return nil // no PDM Ref # generated for these cases - case .insulinDeliveryCommandError: - // This fault is treated as a PDM fault which uses an alternate Ref format - return "11-144-0018-00049" // all fixed values for this fault - case .occluded: - // Ref: 17-000HH-IIIRR-000 - TT = 17 // Occlusion detected Ref type - VVV = 0 // no VVV value for an occlusion fault - FFF = 0 // no FFF value for an occlusion fault - default: - // Ref: 19-VVVHH-IIIRR-FFF - TT = 19 // pod fault Ref type - VVV = data[17] // use the raw VV byte value - FFF = faultEventCode.rawValue - } - - HH = UInt8(timeActive.hours) - III = UInt8(totalInsulinDelivered) - - RR = UInt8(self.reservoirLevel) // special 51.15 value used for > 50U will become 51 as needed - - return String(format: "%02d-%03d%02d-%03d%02d-%03d", TT, VVV, HH, III, RR, FFF) - } -} diff --git a/Dependencies/OmniKit/OmniKit/PumpManager/OmnipodPumpManager.swift b/Dependencies/OmniKit/OmniKit/PumpManager/OmnipodPumpManager.swift deleted file mode 100644 index b2a2befce..000000000 --- a/Dependencies/OmniKit/OmniKit/PumpManager/OmnipodPumpManager.swift +++ /dev/null @@ -1,2388 +0,0 @@ -// -// OmnipodPumpManager.swift -// OmniKit -// -// Created by Pete Schwamb on 8/4/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import HealthKit -import LoopKit -import RileyLinkKit -import RileyLinkBLEKit -import UserNotifications -import os.log - - -public enum ReservoirAlertState { - case ok - case lowReservoir - case empty -} - -public protocol PodStateObserver: AnyObject { - func podStateDidUpdate(_ state: PodState?) -} - -public enum PodCommState: Equatable { - case noPod - case activating - case active - case fault(DetailedStatus) - case deactivating -} - -public enum ReservoirLevelHighlightState: String, Equatable { - case normal - case warning - case critical -} - -public enum OmnipodPumpManagerError: Error { - case noPodPaired - case podAlreadyPaired - case insulinTypeNotConfigured - case notReadyForCannulaInsertion - case invalidSetting - case communication(Error) - case state(Error) -} - -extension OmnipodPumpManagerError: LocalizedError { - public var errorDescription: String? { - switch self { - case .noPodPaired: - return LocalizedString("No pod paired", comment: "Error message shown when no pod is paired") - case .podAlreadyPaired: - return LocalizedString("Pod already paired", comment: "Error message shown when user cannot pair because pod is already paired") - case .insulinTypeNotConfigured: - return LocalizedString("Insulin type not configured", comment: "Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured") - case .notReadyForCannulaInsertion: - return LocalizedString("Pod is not in a state ready for cannula insertion.", comment: "Error message when cannula insertion fails because the pod is in an unexpected state") - case .communication(let error): - if let error = error as? LocalizedError { - return error.errorDescription - } else { - return String(describing: error) - } - case .state(let error): - if let error = error as? LocalizedError { - return error.errorDescription - } else { - return String(describing: error) - } - case .invalidSetting: - return LocalizedString("Invalid Setting", comment: "Error description for OmniBLEPumpManagerError.invalidSetting") - } - } - - public var failureReason: String? { - return nil - } - - public var recoverySuggestion: String? { - switch self { - case .noPodPaired: - return LocalizedString("Please pair a new pod", comment: "Recovery suggestion shown when no pod is paired") - default: - return nil - } - } -} - -public class OmnipodPumpManager: RileyLinkPumpManager { - - public let managerIdentifier: String = "Omnipod" - - public let localizedTitle = LocalizedString("Omnipod", comment: "Generic title of the omnipod pump manager") - - public init(state: OmnipodPumpManagerState, rileyLinkDeviceProvider: RileyLinkDeviceProvider, dateGenerator: @escaping () -> Date = Date.init) { - self.lockedState = Locked(state) - self.lockedPodComms = Locked(PodComms(podState: state.podState)) - self.dateGenerator = dateGenerator - super.init(rileyLinkDeviceProvider: rileyLinkDeviceProvider) - - self.podComms.delegate = self - self.podComms.messageLogger = self - } - - public required convenience init?(rawState: PumpManager.RawStateValue) { - guard let state = OmnipodPumpManagerState(rawValue: rawState), - let connectionManagerState = state.rileyLinkConnectionManagerState else - { - return nil - } - - let deviceProvider = RileyLinkBluetoothDeviceProvider(autoConnectIDs: connectionManagerState.autoConnectIDs) - - self.init(state: state, rileyLinkDeviceProvider: deviceProvider) - - deviceProvider.delegate = self - } - - private var podComms: PodComms { - get { - return lockedPodComms.value - } - set { - lockedPodComms.value = newValue - } - } - private let lockedPodComms: Locked - - private let podStateObservers = WeakSynchronizedSet() - - // Primarily used for testing - public let dateGenerator: () -> Date - - public var state: OmnipodPumpManagerState { - return lockedState.value - } - - private func setState(_ changes: (_ state: inout OmnipodPumpManagerState) -> Void) -> Void { - return setStateWithResult(changes) - } - - private func setStateWithResult(_ changes: (_ state: inout OmnipodPumpManagerState) -> ReturnType) -> ReturnType { - var oldValue: OmnipodPumpManagerState! - var returnType: ReturnType! - let newValue = lockedState.mutate { (state) in - oldValue = state - returnType = changes(&state) - } - - guard oldValue != newValue else { - return returnType - } - - if oldValue.podState != newValue.podState { - podStateObservers.forEach { (observer) in - observer.podStateDidUpdate(newValue.podState) - } - - if oldValue.podState?.lastInsulinMeasurements?.reservoirLevel != newValue.podState?.lastInsulinMeasurements?.reservoirLevel { - if let lastInsulinMeasurements = newValue.podState?.lastInsulinMeasurements, - let reservoirLevel = lastInsulinMeasurements.reservoirLevel, - reservoirLevel != Pod.reservoirLevelAboveThresholdMagicNumber - { - self.pumpDelegate.notify({ (delegate) in - self.log.info("DU: updating reservoir level %{public}@", String(describing: reservoirLevel)) - delegate?.pumpManager(self, didReadReservoirValue: reservoirLevel, at: lastInsulinMeasurements.validTime) { _ in } - }) - } - } - } - - - // Ideally we ensure that oldValue.rawValue != newValue.rawValue, but the types aren't - // defined as equatable - pumpDelegate.notify { (delegate) in - delegate?.pumpManagerDidUpdateState(self) - } - - let oldStatus = status(for: oldValue) - let newStatus = status(for: newValue) - - let oldHighlight = buildPumpStatusHighlight(for: oldValue) - let newHighlight = buildPumpStatusHighlight(for: newValue) - - if oldStatus != newStatus || oldHighlight != newHighlight { - notifyStatusObservers(oldStatus: oldStatus) - } - - return returnType - } - private let lockedState: Locked - - private let statusObservers = WeakSynchronizedSet() - - private func notifyStatusObservers(oldStatus: PumpManagerStatus) { - let status = self.status - pumpDelegate.notify { (delegate) in - delegate?.pumpManager(self, didUpdate: status, oldStatus: oldStatus) - } - statusObservers.forEach { (observer) in - observer.pumpManager(self, didUpdate: status, oldStatus: oldStatus) - } - } - - private func logDeviceCommunication(_ message: String, type: DeviceLogEntryType = .send) { - var podAddress = "noPod" - if let podState = self.state.podState { - podAddress = String(format:"%04X", podState.address) - } - - // Not dispatching here; if delegate queue is blocked, timestamps will be delayed - self.pumpDelegate.delegate?.deviceManager(self, logEventForDeviceIdentifier: podAddress, type: type, message: message, completion: nil) - } - - private let pumpDelegate = WeakSynchronizedDelegate() - - public let log = OSLog(category: "OmnipodPumpManager") - - // MARK: - RileyLink Updates - - override public var rileyLinkConnectionManagerState: RileyLinkConnectionState? { - get { - return state.rileyLinkConnectionManagerState - } - set { - setState { (state) in - state.rileyLinkConnectionManagerState = newValue - } - } - } - - override public func deviceTimerDidTick(_ device: RileyLinkDevice) { - pumpDelegate.notify { (delegate) in - delegate?.pumpManagerBLEHeartbeatDidFire(self) - } - } - - public var rileyLinkBatteryAlertLevel: Int? { - get { - return state.rileyLinkBatteryAlertLevel - } - set { - setState { state in - state.rileyLinkBatteryAlertLevel = newValue - } - } - } - - public override func device(_ device: RileyLinkDevice, didUpdateBattery level: Int) { - let repeatInterval: TimeInterval = .hours(1) - - if let alertLevel = state.rileyLinkBatteryAlertLevel, - level <= alertLevel, - state.lastRileyLinkBatteryAlertDate.addingTimeInterval(repeatInterval) < Date() - { - self.setState { state in - state.lastRileyLinkBatteryAlertDate = Date() - } - self.pumpDelegate.notify { delegate in - let identifier = Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: "lowRLBattery") - let alertBody = String(format: LocalizedString("\"%1$@\" has a low battery", comment: "Format string for low battery alert body for RileyLink. (1: device name)"), device.name ?? "unnamed") - let content = Alert.Content(title: LocalizedString("Low RileyLink Battery", comment: "Title for RileyLink low battery alert"), body: alertBody, acknowledgeActionButtonLabel: LocalizedString("OK", comment: "Acknowledge button label for RileyLink low battery alert")) - delegate?.issueAlert(Alert(identifier: identifier, foregroundContent: content, backgroundContent: content, trigger: .immediate)) - } - } - } - - // MARK: - CustomDebugStringConvertible - - override public var debugDescription: String { - let lines = [ - "## OmnipodPumpManager", - "", - super.debugDescription, - "podComms: \(String(reflecting: podComms))", - "statusObservers.count: \(statusObservers.cleanupDeallocatedElements().count)", - "status: \(String(describing: status))", - "", - "podStateObservers.count: \(podStateObservers.cleanupDeallocatedElements().count)", - "state: \(String(reflecting: state))", - ] - return lines.joined(separator: "\n") - } -} - -extension OmnipodPumpManager { - // MARK: - PodStateObserver - - public func addPodStateObserver(_ observer: PodStateObserver, queue: DispatchQueue) { - podStateObservers.insert(observer, queue: queue) - } - - public func removePodStateObserver(_ observer: PodStateObserver) { - podStateObservers.removeElement(observer) - } - - private func updateBLEHeartbeatPreference() { - dispatchPrecondition(condition: .notOnQueue(delegateQueue)) - - rileyLinkDeviceProvider.timerTickEnabled = self.state.isPumpDataStale || pumpDelegate.call({ (delegate) -> Bool in - return delegate?.pumpManagerMustProvideBLEHeartbeat(self) == true - }) - } - - public var expiresAt: Date? { - return state.podState?.expiresAt - } - - public func buildPumpStatusHighlight(for state: OmnipodPumpManagerState, andDate date: Date = Date()) -> PumpStatusHighlight? { - if state.podState?.needsCommsRecovery == true { - return PumpStatusHighlight(localizedMessage: LocalizedString("Comms Issue", comment: "Status highlight that delivery is uncertain."), - imageName: "exclamationmark.circle.fill", - state: .critical) - } - - switch podCommState(for: state) { - case .activating: - return PumpStatusHighlight( - localizedMessage: LocalizedString("Finish Pairing", comment: "Status highlight that when pod is activating."), - imageName: "exclamationmark.circle.fill", - state: .warning) - case .deactivating: - return PumpStatusHighlight( - localizedMessage: LocalizedString("Finish Deactivation", comment: "Status highlight that when pod is deactivating."), - imageName: "exclamationmark.circle.fill", - state: .warning) - case .noPod: - return PumpStatusHighlight( - localizedMessage: LocalizedString("No Pod", comment: "Status highlight that when no pod is paired."), - imageName: "exclamationmark.circle.fill", - state: .warning) - case .fault(let detail): - var message: String - switch detail.faultEventCode.faultType { - case .reservoirEmpty: - message = LocalizedString("No Insulin", comment: "Status highlight message for emptyReservoir alarm.") - case .exceededMaximumPodLife80Hrs: - message = LocalizedString("Pod Expired", comment: "Status highlight message for podExpired alarm.") - case .occluded: - message = LocalizedString("Pod Occlusion", comment: "Status highlight message for occlusion alarm.") - default: - message = LocalizedString("Pod Error", comment: "Status highlight message for other alarm.") - } - return PumpStatusHighlight( - localizedMessage: message, - imageName: "exclamationmark.circle.fill", - state: .critical) - case .active: - if let reservoirPercent = state.reservoirLevel?.percentage, reservoirPercent == 0 { - return PumpStatusHighlight( - localizedMessage: LocalizedString("No Insulin", comment: "Status highlight that a pump is out of insulin."), - imageName: "exclamationmark.circle.fill", - state: .critical) - } else if state.podState?.isSuspended == true { - return PumpStatusHighlight( - localizedMessage: LocalizedString("Insulin Suspended", comment: "Status highlight that insulin delivery was suspended."), - imageName: "pause.circle.fill", - state: .warning) - } else if date.timeIntervalSince(state.lastPumpDataReportDate ?? .distantPast) > .minutes(12) { - return PumpStatusHighlight( - localizedMessage: LocalizedString("Signal Loss", comment: "Status highlight when communications with the pod haven't happened recently."), - imageName: "exclamationmark.circle.fill", - state: .critical) - } else if isRunningManualTempBasal(for: state) { - return PumpStatusHighlight( - localizedMessage: LocalizedString("Manual Basal", comment: "Status highlight when manual temp basal is running."), - imageName: "exclamationmark.circle.fill", - state: .warning) - } - return nil - } - } - - public func isRunningManualTempBasal(for state: OmnipodPumpManagerState) -> Bool { - if let tempBasal = state.podState?.unfinalizedTempBasal, !tempBasal.automatic { - return true - } - return false - } - - public var reservoirLevelHighlightState: ReservoirLevelHighlightState? { - guard let reservoirLevel = reservoirLevel else { - return nil - } - - switch reservoirLevel { - case .aboveThreshold: - return .normal - case .valid(let value): - if value > state.lowReservoirReminderValue { - return .normal - } else if value > 0 { - return .warning - } else { - return .critical - } - } - } - - public func buildPumpLifecycleProgress(for state: OmnipodPumpManagerState) -> PumpLifecycleProgress? { - switch podCommState { - case .active: - if shouldWarnPodEOL, - let podTimeRemaining = podTimeRemaining - { - let percentCompleted = max(0, min(1, (1 - (podTimeRemaining / Pod.nominalPodLife)))) - return PumpLifecycleProgress(percentComplete: percentCompleted, progressState: .warning) - } else if let podTimeRemaining = podTimeRemaining, podTimeRemaining <= 0 { - // Pod is expired - return PumpLifecycleProgress(percentComplete: 1, progressState: .critical) - } - return nil - case .fault(let detail): - if detail.faultEventCode.faultType == .exceededMaximumPodLife80Hrs { - return PumpLifecycleProgress(percentComplete: 100, progressState: .critical) - } else { - if shouldWarnPodEOL, - let durationBetweenLastPodCommAndActivation = durationBetweenLastPodCommAndActivation - { - let percentCompleted = max(0, min(1, durationBetweenLastPodCommAndActivation / Pod.nominalPodLife)) - return PumpLifecycleProgress(percentComplete: percentCompleted, progressState: .dimmed) - } - } - return nil - case .noPod, .activating, .deactivating: - return nil - } - } - - private func status(for state: OmnipodPumpManagerState) -> PumpManagerStatus { - return PumpManagerStatus( - timeZone: state.timeZone, - device: device(for: state), - pumpBatteryChargeRemaining: nil, - basalDeliveryState: basalDeliveryState(for: state), - bolusState: bolusState(for: state), - insulinType: state.insulinType, - deliveryIsUncertain: state.podState?.needsCommsRecovery == true - ) - } - - private func device(for state: OmnipodPumpManagerState) -> HKDevice { - if let podState = state.podState { - return HKDevice( - name: managerIdentifier, - manufacturer: "Insulet", - model: "Eros", - hardwareVersion: nil, - firmwareVersion: podState.piVersion, - softwareVersion: String(OmniKitVersionNumber), - localIdentifier: String(format:"%04X", podState.address), - udiDeviceIdentifier: nil - ) - } else { - return HKDevice( - name: managerIdentifier, - manufacturer: "Insulet", - model: "Eros", - hardwareVersion: nil, - firmwareVersion: nil, - softwareVersion: String(OmniKitVersionNumber), - localIdentifier: nil, - udiDeviceIdentifier: nil - ) - } - } - - private func basalDeliveryState(for state: OmnipodPumpManagerState) -> PumpManagerStatus.BasalDeliveryState { - guard let podState = state.podState else { - return .active(.distantPast) - } - - switch podCommState(for: state) { - case .fault: - return .active(.distantPast) - default: - break - } - - switch state.suspendEngageState { - case .engaging: - return .suspending - case .disengaging: - return .resuming - case .stable: - break - } - - switch state.tempBasalEngageState { - case .engaging: - return .initiatingTempBasal - case .disengaging: - return .cancelingTempBasal - case .stable: - if let tempBasal = podState.unfinalizedTempBasal { - return .tempBasal(DoseEntry(tempBasal)) - } - switch podState.suspendState { - case .resumed(let date): - return .active(date) - case .suspended(let date): - return .suspended(date) - } - } - } - - private func bolusState(for state: OmnipodPumpManagerState) -> PumpManagerStatus.BolusState { - guard let podState = state.podState else { - return .noBolus - } - - switch state.bolusEngageState { - case .engaging: - return .initiating - case .disengaging: - return .canceling - case .stable: - if let bolus = podState.unfinalizedBolus, !bolus.isFinished() { - return .inProgress(DoseEntry(bolus)) - } - } - return .noBolus - } - - // Returns true if there an unfinishedDose for a manual bolus (independent of whether it is finished) - private var hasUnfinalizedManualBolus: Bool { - if let automatic = state.podState?.unfinalizedBolus?.automatic, !automatic { - return true - } - return false - } - - // Returns true if there an unfinishedDose for a manual temp basal (independent of whether it is finished) - private var hasUnfinalizedManualTempBasal: Bool { - if let automatic = state.podState?.unfinalizedTempBasal?.automatic, !automatic { - return true - } - return false - } - - private var podTime: TimeInterval { - get { - guard let podState = state.podState else { - return 0 - } - let elapsed = -(podState.podTimeUpdated?.timeIntervalSinceNow ?? 0) - let podActiveTime = podState.podTime + elapsed - return podActiveTime - } - } - - // Returns a suitable beep command MessageBlock based the current beep preferences and - // whether there is an unfinializedDose for a manual temp basal &/or a manual bolus. - private func beepMessageBlock(beepType: BeepType) -> MessageBlock? { - guard self.beepPreference.shouldBeepForManualCommand && !self.silencePod else { - return nil - } - - // Enable temp basal & basal completion beeps if there is a cooresponding manual unfinalizedDose - let beepMessageBlock = BeepConfigCommand( - beepType: beepType, - tempBasalCompletionBeep: self.hasUnfinalizedManualTempBasal, - bolusCompletionBeep: self.hasUnfinalizedManualBolus - ) - - return beepMessageBlock - } - - private func podCommState(for state: OmnipodPumpManagerState) -> PodCommState { - guard let podState = state.podState else { - return .noPod - } - guard podState.fault == nil else { - return .fault(podState.fault!) - } - - if podState.isActive { - return .active - } else if !podState.isSetupComplete { - return .activating - } - return .deactivating - } - - public var podCommState: PodCommState { - return podCommState(for: state) - } - - public var podActivatedAt: Date? { - return state.podState?.activatedAt - } - - public var podExpiresAt: Date? { - return state.podState?.expiresAt - } - - public var hasActivePod: Bool { - return state.hasActivePod - } - - public var hasSetupPod: Bool { - return state.hasSetupPod - } - - // If time remaining is negative, the pod has been expired for that amount of time. - public var podTimeRemaining: TimeInterval? { - guard let expiresAt = state.podState?.expiresAt else { return nil } - return expiresAt.timeIntervalSince(dateGenerator()) - } - - private var shouldWarnPodEOL: Bool { - let eolDisplayActiveTime = Pod.timeRemainingWarningThreshold + (state.scheduledExpirationReminderOffset ?? 0.0) - guard let podTimeRemaining = podTimeRemaining, - podTimeRemaining > 0 && podTimeRemaining <= eolDisplayActiveTime else - { - return false - } - - return true - } - - public var durationBetweenLastPodCommAndActivation: TimeInterval? { - guard let lastPodCommDate = state.podState?.lastInsulinMeasurements?.validTime, - let activationTime = podActivatedAt else - { - return nil - } - - return lastPodCommDate.timeIntervalSince(activationTime) - } - - // Thread-safe - public var beepPreference: BeepPreference { - get { - return state.confirmationBeeps - } - } - - // Thread-safe - public var silencePod: Bool { - get { - return state.silencePod - } - } - - // From last status response - public var reservoirLevel: ReservoirLevel? { - return state.reservoirLevel - } - - public var podTotalDelivery: HKQuantity? { - guard let delivery = state.podState?.lastInsulinMeasurements?.delivered else { - return nil - } - return HKQuantity(unit: .internationalUnit(), doubleValue: delivery) - } - - public var lastStatusDate: Date? { - guard let date = state.podState?.lastInsulinMeasurements?.validTime else { - return nil - } - return date - } - - - // MARK: - Pod comms - - // Does not support concurrent callers. Not thread-safe. - public func forgetPod(completion: @escaping () -> Void) { - - let resetPodState = { (_ state: inout OmnipodPumpManagerState) in - self.podComms = PodComms(podState: nil) - self.podComms.delegate = self - self.podComms.messageLogger = self - - state.previousPodState = state.podState - state.updatePodStateFromPodComms(nil) - } - - podComms.forgetPod() - - if let dosesToStore = self.state.podState?.dosesToStore { - self.store(doses: dosesToStore, completion: { error in - self.setState({ (state) in - if error != nil { - state.unstoredDoses.append(contentsOf: dosesToStore) - } - - resetPodState(&state) - }) - completion() - }) - } else { - self.setState { (state) in - resetPodState(&state) - } - completion() - } - } - - // MARK: Testing - #if targetEnvironment(simulator) - private func jumpStartPod(address: UInt32, lot: UInt32, tid: UInt32, fault: DetailedStatus? = nil, startDate: Date? = nil, mockFault: Bool) { - let start = startDate ?? Date() - var podState = PodState(address: address, pmVersion: "jumpstarted", piVersion: "jumpstarted", lot: lot, tid: tid, insulinType: .novolog) - podState.setupProgress = .podPaired - podState.activatedAt = start - podState.expiresAt = start + .hours(72) - - let fault = mockFault ? try? DetailedStatus(encodedData: Data(hexadecimalString: "020f0000000900345c000103ff0001000005ae056029")!) : nil - podState.fault = fault - - podComms = PodComms(podState: podState) - - setState({ (state) in - state.updatePodStateFromPodComms(podState) - }) - } - #endif - - // MARK: - Pairing - - // Called on the main thread - public func pairAndPrime(completion: @escaping (PumpManagerResult) -> Void) { - - guard let insulinType = insulinType else { - completion(.failure(.configuration(nil))) - return - } - - #if targetEnvironment(simulator) - // If we're in the simulator, create a mock PodState - let mockFaultDuringPairing = false - let mockCommsErrorDuringPairing = false - DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + .seconds(2)) { - self.jumpStartPod(address: 0x1f0b3557, lot: 40505, tid: 6439, mockFault: mockFaultDuringPairing) - self.podComms.mockPodStateChanges { podState in - podState.setupProgress = .priming - } - if let fault = self.state.podState?.fault { - completion(.failure(PumpManagerError.deviceState(PodCommsError.podFault(fault: fault)))) - } else if mockCommsErrorDuringPairing { - completion(.failure(PumpManagerError.communication(PodCommsError.noResponse))) - } else { - let mockPrimeDuration = TimeInterval(.seconds(3)) - completion(.success(mockPrimeDuration)) - } - } - #else - let deviceSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - let primeSession = { (result: PodComms.SessionRunResult) in - switch result { - case .success(let messageSender): - // We're on the session queue - messageSender.assertOnSessionQueue() - - self.log.default("Beginning pod prime") - - // Clean up any previously un-stored doses if needed - let unstoredDoses = self.state.unstoredDoses - if self.store(doses: unstoredDoses, in: messageSender) { - self.setState({ (state) in - state.unstoredDoses.removeAll() - }) - } - - do { - let primeFinishedAt = try messageSender.prime() - completion(.success(primeFinishedAt)) - } catch let error { - completion(.failure(PumpManagerError.communication(error as? LocalizedError))) - } - case .failure(let error): - completion(.failure(PumpManagerError.communication(error))) - } - } - - let needsPairing = setStateWithResult({ (state) -> Bool in - guard let podState = state.podState else { - return true // Needs pairing - } - - // Return true if not yet paired - return podState.setupProgress.isPaired == false - }) - - if needsPairing { - self.log.default("Pairing pod before priming") - - // Create random address with 20 bits to match PDM, could easily use 24 bits instead - if self.state.pairingAttemptAddress == nil { - self.lockedState.mutate { (state) in - state.pairingAttemptAddress = 0x1f000000 | (arc4random() & 0x000fffff) - } - } - - self.podComms.assignAddressAndSetupPod( - address: self.state.pairingAttemptAddress!, - using: deviceSelector, - timeZone: .currentFixed, - messageLogger: self, - insulinType: insulinType) - { (result) in - - if case .success = result { - self.lockedState.mutate { (state) in - state.pairingAttemptAddress = nil - } - } - - // Calls completion - primeSession(result) - } - } else { - self.log.default("Pod already paired. Continuing.") - - self.podComms.runSession(withName: "Prime pod", using: deviceSelector) { (result) in - // Calls completion - primeSession(result) - } - } - #endif - } - - // Called on the main thread - public func insertCannula(completion: @escaping (Result) -> Void) { - - #if targetEnvironment(simulator) - let mockDelay = TimeInterval(seconds: 3) - let mockFaultDuringInsertCannula = false - DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + mockDelay) { - let result = self.setStateWithResult({ (state) -> Result in - if mockFaultDuringInsertCannula { - let fault = try! DetailedStatus(encodedData: Data(hexadecimalString: "020d0000000e00c36a020703ff020900002899080082")!) - var podState = state.podState - podState?.fault = fault - state.updatePodStateFromPodComms(podState) - return .failure(OmnipodPumpManagerError.communication(PodCommsError.podFault(fault: fault))) - } - - // Mock success - var podState = state.podState - podState?.setupProgress = .completed - state.updatePodStateFromPodComms(podState) - return .success(mockDelay) - }) - - completion(result) - } - #else - let preError = setStateWithResult({ (state) -> OmnipodPumpManagerError? in - guard let podState = state.podState, podState.readyForCannulaInsertion else - { - return .notReadyForCannulaInsertion - } - - state.scheduledExpirationReminderOffset = state.defaultExpirationReminderOffset - - guard podState.setupProgress.needsCannulaInsertion else { - return .podAlreadyPaired - } - - return nil - }) - - if let error = preError { - completion(.failure(.state(error))) - return - } - - let timeZone = self.state.timeZone - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Insert cannula", using: rileyLinkSelector) { (result) in - switch result { - case .success(let messageSender): - do { - if self.state.podState?.setupProgress.needsInitialBasalSchedule == true { - let scheduleOffset = timeZone.scheduleOffset(forDate: Date()) - try messageSender.programInitialBasalSchedule(self.state.basalSchedule, scheduleOffset: scheduleOffset) - - messageSender.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: messageSender) - } - } - - let expirationReminderTime = Pod.nominalPodLife - self.state.defaultExpirationReminderOffset - let alerts: [PodAlert] = [ - .expirationReminder(offset: self.podTime, absAlertTime: self.state.defaultExpirationReminderOffset > 0 ? expirationReminderTime : 0), - .lowReservoir(units: self.state.lowReservoirReminderValue) - ] - - let finishWait = try messageSender.insertCannula(optionalAlerts: alerts, silent: self.silencePod) - completion(.success(finishWait)) - } catch let error { - completion(.failure(.communication(error))) - } - case .failure(let error): - completion(.failure(.communication(error))) - } - } - #endif - } - - public func checkCannulaInsertionFinished(completion: @escaping (OmnipodPumpManagerError?) -> Void) { - #if targetEnvironment(simulator) - completion(nil) - #else - let deviceSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Check cannula insertion finished", using: deviceSelector) { (result) in - switch result { - case .success(let messageSender): - do { - try messageSender.checkInsertionCompleted() - completion(nil) - } catch let error { - self.log.error("Failed to fetch pod status: %{public}@", String(describing: error)) - completion(.communication(error)) - } - case .failure(let error): - self.log.error("Failed to fetch pod status: %{public}@", String(describing: error)) - completion(.communication(error)) - } - } - #endif - } - - // MARK: - Pump Commands - - public func getPodStatus(completion: ((_ result: PumpManagerResult) -> Void)? = nil) { - - guard state.hasActivePod else { - completion?(.failure(PumpManagerError.configuration(OmnipodPumpManagerError.noPodPaired))) - return - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - podComms.runSession(withName: "Get pod status", using: rileyLinkSelector) { (result) in - switch result { - case .success(let session): - do { - let status = try session.getStatus() - session.dosesForStorage({ (doses) -> Bool in - self.store(doses: doses, in: session) - }) - completion?(.success(status)) - } catch let error { - completion?(.failure(PumpManagerError.communication(error as? LocalizedError))) - } - case .failure(let error): - self.log.error("Failed to fetch pod status: %{public}@", String(describing: error)) - completion?(.failure(PumpManagerError.communication(error))) - } - } - } - - public func getDetailedStatus(completion: ((_ result: PumpManagerResult) -> Void)? = nil) { - - // use hasSetupPod here instead of hasActivePod as DetailedStatus can be read with a faulted Pod - guard self.hasSetupPod else { - completion?(.failure(PumpManagerError.configuration(OmnipodPumpManagerError.noPodPaired))) - return - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - podComms.runSession(withName: "Get detailed status", using: rileyLinkSelector) { (result) in - do { - switch result { - case .success(let session): - let beepBlock = self.beepMessageBlock(beepType: .bipBip) - let detailedStatus = try session.getDetailedStatus(beepBlock: beepBlock) - session.dosesForStorage({ (doses) -> Bool in - self.store(doses: doses, in: session) - }) - completion?(.success(detailedStatus)) - case .failure(let error): - throw error - } - } catch let error { - completion?(.failure(.communication(error as? LocalizedError))) - self.log.error("Failed to fetch detailed status: %{public}@", String(describing: error)) - } - } - } - - public func acknowledgePodAlerts(_ alertsToAcknowledge: AlertSet, completion: @escaping (_ alerts: AlertSet?) -> Void) { - guard self.hasActivePod else { - completion(nil) - return - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Acknowledge Alerts", using: rileyLinkSelector) { (result) in - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure: - completion(nil) - return - } - - do { - let beepBlock = self.beepMessageBlock(beepType: .bipBip) - let alerts = try session.acknowledgeAlerts(alerts: alertsToAcknowledge, beepBlock: beepBlock) - completion(alerts) - } catch { - completion(nil) - } - } - } - - public func setTime(completion: @escaping (OmnipodPumpManagerError?) -> Void) { - - guard state.hasActivePod else { - completion(OmnipodPumpManagerError.noPodPaired) - return - } - - guard state.podState?.unfinalizedBolus?.isFinished() != false else { - completion(.state(PodCommsError.unfinalizedBolus)) - return - } - - let timeZone = TimeZone.currentFixed - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Set time zone", using: rileyLinkSelector) { (result) in - switch result { - case .success(let session): - do { - let beep = self.silencePod ? false : self.beepPreference.shouldBeepForManualCommand - let _ = try session.setTime(timeZone: timeZone, basalSchedule: self.state.basalSchedule, date: Date(), acknowledgementBeep: beep) - self.setState { (state) in - state.timeZone = timeZone - } - completion(nil) - } catch let error { - completion(.communication(error)) - } - case .failure(let error): - completion(.communication(error)) - } - } - } - - public func setBasalSchedule(_ schedule: BasalSchedule, completion: @escaping (Error?) -> Void) { - let shouldContinue = setStateWithResult({ (state) -> PumpManagerResult in - guard state.hasActivePod else { - // If there's no active pod yet, save the basal schedule anyway - state.basalSchedule = schedule - return .success(false) - } - - guard state.podState?.unfinalizedBolus?.isFinished() != false else { - return .failure(PumpManagerError.deviceState(PodCommsError.unfinalizedBolus)) - } - - return .success(true) - }) - - switch shouldContinue { - case .success(true): - break - case .success(false): - completion(nil) - return - case .failure(let error): - completion(error) - return - } - - let timeZone = self.state.timeZone - - self.podComms.runSession(withName: "Save Basal Profile", using: self.rileyLinkDeviceProvider.firstConnectedDevice) { (result) in - do { - switch result { - case .success(let session): - let scheduleOffset = timeZone.scheduleOffset(forDate: Date()) - let result = session.cancelDelivery(deliveryType: .all) - switch result { - case .certainFailure(let error): - throw error - case .unacknowledged(let error): - throw error - case .success: - break - } - let beep = self.silencePod ? false : self.beepPreference.shouldBeepForManualCommand - let _ = try session.setBasalSchedule(schedule: schedule, scheduleOffset: scheduleOffset, acknowledgementBeep: beep) - - self.setState { (state) in - state.basalSchedule = schedule - } - completion(nil) - case .failure(let error): - throw error - } - } catch let error { - self.log.error("Save basal profile failed: %{public}@", String(describing: error)) - completion(error) - } - } - } - - // Called on the main thread. - // The UI is responsible for serializing calls to this method; - // it does not handle concurrent calls. - public func deactivatePod(completion: @escaping (OmnipodPumpManagerError?) -> Void) { - #if targetEnvironment(simulator) - DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + .seconds(2)) { - completion(nil) - } - #else - guard self.state.podState != nil else { - completion(OmnipodPumpManagerError.noPodPaired) - return - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Deactivate pod", using: rileyLinkSelector) { (result) in - switch result { - case .success(let messageSender): - do { - try messageSender.deactivatePod() - completion(nil) - } catch let error { - completion(OmnipodPumpManagerError.communication(error)) - } - case .failure(let error): - completion(OmnipodPumpManagerError.communication(error)) - } - } - #endif - } - - public func playTestBeeps(completion: @escaping (Error?) -> Void) { - guard self.hasActivePod else { - completion(OmnipodPumpManagerError.noPodPaired) - return - } - guard state.podState?.unfinalizedBolus?.scheduledCertainty == .uncertain || state.podState?.unfinalizedBolus?.isFinished() != false else { - self.log.info("Skipping Play Test Beeps due to bolus still in progress.") - completion(PodCommsError.unfinalizedBolus) - return - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Play Test Beeps", using: rileyLinkSelector) { (result) in - switch result { - case .success(let session): - // preserve the pod's completion beep state which gets reset playing beeps - let enabled: Bool = self.silencePod ? false : self.beepPreference.shouldBeepForManualCommand - let result = session.beepConfig( - beepType: .bipBeepBipBeepBipBeepBipBeep, - tempBasalCompletionBeep: enabled && self.hasUnfinalizedManualTempBasal, - bolusCompletionBeep: enabled && self.hasUnfinalizedManualBolus - ) - - switch result { - case .success: - completion(nil) - case .failure(let error): - completion(error) - } - case .failure(let error): - completion(error) - } - } - } - - public func readPulseLog(completion: @escaping (Result) -> Void) { - // use hasSetupPod to be able to read the pulse log from a faulted Pod - guard self.hasSetupPod else { - completion(.failure(OmnipodPumpManagerError.noPodPaired)) - return - } - guard state.podState?.isFaulted == true || state.podState?.unfinalizedBolus?.scheduledCertainty == .uncertain || state.podState?.unfinalizedBolus?.isFinished() != false else - { - self.log.info("Skipping Read Pulse Log due to bolus still in progress.") - completion(.failure(PodCommsError.unfinalizedBolus)) - return - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Read Pulse Log", using: rileyLinkSelector) { (result) in - switch result { - case .success(let session): - do { - // read the most recent 50 entries from the pulse log - let beepBlock = self.beepMessageBlock(beepType: .bipBeeeeep) - let podInfoResponse = try session.readPodInfo(podInfoResponseSubType: .pulseLogRecent, beepBlock: beepBlock) - guard let podInfoPulseLogRecent = podInfoResponse.podInfo as? PodInfoPulseLogRecent else { - self.log.error("Unable to decode PulseLogRecent: %s", String(describing: podInfoResponse)) - completion(.failure(PodCommsError.unexpectedResponse(response: .podInfoResponse))) - return - } - let lastPulseNumber = Int(podInfoPulseLogRecent.indexLastEntry) - let str = pulseLogString(pulseLogEntries: podInfoPulseLogRecent.pulseLog, lastPulseNumber: lastPulseNumber) - completion(.success(str)) - } catch let error { - completion(.failure(error)) - } - case .failure(let error): - completion(.failure(error)) - } - } - } - - public func setConfirmationBeeps(newPreference: BeepPreference, completion: @escaping (OmnipodPumpManagerError?) -> Void) { - - // If there isn't an active pod or the pod is currently silenced, - // just need to update the internal state without any pod commands. - let name = String(format: "Set Beep Preference to %@", String(describing: newPreference)) - if !self.hasActivePod || self.silencePod { - self.log.default("%{public}@ for internal state only", name) - self.setState { state in - state.confirmationBeeps = newPreference - } - completion(nil) - return - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: name, using: rileyLinkSelector) { (result) in - switch result { - case .success(let session): - // enable/disable Pod completion beep state for any unfinalized manual insulin delivery - let enabled = newPreference.shouldBeepForManualCommand - let beepType: BeepType = enabled ? .bipBip : .noBeepNonCancel - let result = session.beepConfig( - beepType: beepType, - tempBasalCompletionBeep: enabled && self.hasUnfinalizedManualTempBasal, - bolusCompletionBeep: enabled && self.hasUnfinalizedManualBolus - ) - - switch result { - case .success: - self.setState { state in - state.confirmationBeeps = newPreference - } - completion(nil) - case .failure(let error): - completion(.communication(error)) - } - case .failure(let error): - completion(.communication(error)) - } - } - } - - // Reconfigures all active alerts in pod to be silent or not as well as sets/clears the - // self.silencePod state variable which silences all confirmation beeping when enabled. - public func setSilencePod(silencePod: Bool, completion: @escaping (OmnipodPumpManagerError?) -> Void) { - - let name = String(format: "%@ Pod", silencePod ? "Silence" : "Unsilence") - // allow Silence Pod changes without an active Pod - guard self.hasActivePod else { - self.log.default("%{public}@", name) - self.setState { state in - state.silencePod = silencePod - } - completion(nil) - return - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: name, using: rileyLinkSelector) { (result) in - - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(.communication(error)) - return - } - - guard let configuredAlerts = self.state.podState?.configuredAlerts, - let activeAlertSlots = self.state.podState?.activeAlertSlots, - let reservoirLevel = self.state.podState?.lastInsulinMeasurements?.reservoirLevel?.rawValue else - { - self.log.error("Missing podState") // should never happen - completion(OmnipodPumpManagerError.noPodPaired) - return - } - - let beepBlock: MessageBlock? - if !self.beepPreference.shouldBeepForManualCommand { - // No enabled completion beeps to worry about for any in-progress manual delivery - beepBlock = nil - } else if silencePod { - // Disable completion beeps for any in-progress manual delivery w/o beeping - beepBlock = BeepConfigCommand(beepType: .noBeepNonCancel) - } else { - // Emit a confirmation beep and enable completion beeps for any in-progress manual delivery - beepBlock = BeepConfigCommand( - beepType: .bipBip, - tempBasalCompletionBeep: self.hasUnfinalizedManualTempBasal, - bolusCompletionBeep: self.hasUnfinalizedManualBolus - ) - } - - let podAlerts = regeneratePodAlerts(silent: silencePod, configuredAlerts: configuredAlerts, activeAlertSlots: activeAlertSlots, currentPodTime: self.podTime, currentReservoirLevel: reservoirLevel) - do { - // Since non-responsive pod comms are currently only resolved for insulin related commands, - // it's possible that a previous pod alert was successfully configured will lose its response - // and thus the alert won't get reset when reconfiguring pod alerts with a new silence pod state. - // So acknowledge all alerts now to be absolutely sure that no triggered alert will be forgotten. - try session.configureAlerts(podAlerts, acknowledgeAll: true, beepBlock: beepBlock) - self.setState { (state) in - state.silencePod = silencePod - } - completion(nil) - } catch { - self.log.error("Configure alerts %{public}@ failed: %{public}@", String(describing: podAlerts), String(describing: error)) - completion(.communication(error)) - } - } - } -} - -// MARK: - PumpManager -extension OmnipodPumpManager: PumpManager { - public static var onboardingMaximumBasalScheduleEntryCount: Int { - return Pod.maximumBasalScheduleEntryCount - } - - public static var onboardingSupportedBasalRates: [Double] { - // 0.05 units for rates between 0.05-30U/hr - // 0 is not a supported scheduled basal rate - return (1...600).map { Double($0) / Double(Pod.pulsesPerUnit) } - } - - public static var onboardingSupportedBolusVolumes: [Double] { - // 0.05 units for rates between 0.05-30U/hr - // 0 is not a supported bolus volume - return (1...600).map { Double($0) / Double(Pod.pulsesPerUnit) } - } - - public static var onboardingSupportedMaximumBolusVolumes: [Double] { - return onboardingSupportedBolusVolumes - } - - public var supportedBolusVolumes: [Double] { - // 0.05 units for rates between 0.05-30U/hr - // 0 is not a supported bolus volume - return (1...600).map { Double($0) / Double(Pod.pulsesPerUnit) } - } - - public var supportedMaximumBolusVolumes: [Double] { - supportedBolusVolumes - } - - public var supportedBasalRates: [Double] { - // 0.05 units for rates between 0.05-30U/hr - // 0 is not a supported scheduled basal rate - return (1...600).map { Double($0) / Double(Pod.pulsesPerUnit) } - } - - public func roundToSupportedBolusVolume(units: Double) -> Double { - // We do support rounding a 0 U volume to 0 - return supportedBolusVolumes.last(where: { $0 <= units }) ?? 0 - } - - public func roundToSupportedBasalRate(unitsPerHour: Double) -> Double { - // We do support rounding a 0 U/hr rate to 0 - return supportedBasalRates.last(where: { $0 <= unitsPerHour }) ?? 0 - } - - public func estimatedDuration(toBolus units: Double) -> TimeInterval { - TimeInterval(units / Pod.bolusDeliveryRate) - } - - public var maximumBasalScheduleEntryCount: Int { - return Pod.maximumBasalScheduleEntryCount - } - - public var minimumBasalScheduleEntryDuration: TimeInterval { - return Pod.minimumBasalScheduleEntryDuration - } - - public var pumpRecordsBasalProfileStartEvents: Bool { - return false - } - - public var pumpReservoirCapacity: Double { - return Pod.reservoirCapacity - } - - public var isOnboarded: Bool { state.isOnboarded } - - public var lastSync: Date? { - return self.state.podState?.lastInsulinMeasurements?.validTime - } - - public var insulinType: InsulinType? { - get { - return self.state.insulinType - } - set { - if let insulinType = newValue { - self.setState { (state) in - state.insulinType = insulinType - } - //self.podComms.insulinType = insulinType - } - } - } - - public var defaultExpirationReminderOffset: TimeInterval { - set { - setState { (state) in - state.defaultExpirationReminderOffset = newValue - } - } - get { - state.defaultExpirationReminderOffset - } - } - - public var lowReservoirReminderValue: Double { - set { - setState { (state) in - state.lowReservoirReminderValue = newValue - } - } - get { - state.lowReservoirReminderValue - } - } - - public var podAttachmentConfirmed: Bool { - set { - setState { (state) in - state.podAttachmentConfirmed = newValue - } - } - get { - state.podAttachmentConfirmed - } - } - - public var initialConfigurationCompleted: Bool { - set { - setState { (state) in - state.initialConfigurationCompleted = newValue - } - } - get { - state.initialConfigurationCompleted - } - } - - public var status: PumpManagerStatus { - // Acquire the lock just once - let state = self.state - - return status(for: state) - } - - public var rawState: PumpManager.RawStateValue { - return state.rawValue - } - - public var pumpManagerDelegate: PumpManagerDelegate? { - get { - return pumpDelegate.delegate - } - set { - pumpDelegate.delegate = newValue - - // TODO: is there still a scenario where this is required? - // self.schedulePodExpirationNotification() - } - } - - public var delegateQueue: DispatchQueue! { - get { - return pumpDelegate.queue - } - set { - pumpDelegate.queue = newValue - } - } - - // MARK: Methods - - public func completeOnboard() { - setState({ (state) in - state.isOnboarded = true - }) - } - - public func suspendDelivery(completion: @escaping (Error?) -> Void) { - let suspendTime: TimeInterval = .minutes(0) // untimed suspend with reminder beeps - suspendDelivery(withSuspendReminders: suspendTime, completion: completion) - } - - // A nil suspendReminder is untimed with no reminders beeps, a suspendReminder of 0 is untimed using reminders beeps, otherwise it - // specifies a suspend duration implemented using an appropriate combination of suspended reminder and suspend time expired beeps. - public func suspendDelivery(withSuspendReminders suspendReminder: TimeInterval? = nil, completion: @escaping (Error?) -> Void) { - guard self.hasActivePod else { - completion(OmnipodPumpManagerError.noPodPaired) - return - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Suspend", using: rileyLinkSelector) { (result) in - - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(error) - return - } - - defer { - self.setState({ (state) in - state.suspendEngageState = .stable - }) - } - self.setState({ (state) in - state.suspendEngageState = .engaging - }) - - // Use a beepBlock for the confirmation beep to avoid getting 3 beeps using cancel command beeps! - let beepBlock = self.beepMessageBlock(beepType: .beeeeeep) - let result = session.suspendDelivery(suspendReminder: suspendReminder, silent: self.silencePod, beepBlock: beepBlock) - switch result { - case .certainFailure(let error): - self.log.error("Failed to suspend: %{public}@", String(describing: error)) - completion(error) - case .unacknowledged(let error): - self.log.error("Failed to suspend: %{public}@", String(describing: error)) - completion(error) - case .success: - session.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: session) - } - completion(nil) - } - } - } - - public func resumeDelivery(completion: @escaping (Error?) -> Void) { - guard self.hasActivePod else { - completion(OmnipodPumpManagerError.noPodPaired) - return - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Resume", using: rileyLinkSelector) { (result) in - - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(error) - return - } - - defer { - self.setState({ (state) in - state.suspendEngageState = .stable - }) - } - self.setState({ (state) in - state.suspendEngageState = .disengaging - }) - - do { - let scheduleOffset = self.state.timeZone.scheduleOffset(forDate: Date()) - let beep = self.silencePod ? false : self.beepPreference.shouldBeepForManualCommand - let _ = try session.resumeBasal(schedule: self.state.basalSchedule, scheduleOffset: scheduleOffset, acknowledgementBeep: beep) - self.clearSuspendReminder() - session.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: session) - } - completion(nil) - } catch (let error) { - completion(error) - } - } - } - - fileprivate func clearSuspendReminder() { - self.pumpDelegate.notify { (delegate) in - delegate?.retractAlert(identifier: Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: PumpManagerAlert.suspendEnded(triggeringSlot: nil).alertIdentifier)) - delegate?.retractAlert(identifier: Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: PumpManagerAlert.suspendEnded(triggeringSlot: nil).repeatingAlertIdentifier)) - } - } - - public func addStatusObserver(_ observer: PumpManagerStatusObserver, queue: DispatchQueue) { - statusObservers.insert(observer, queue: queue) - } - - public func removeStatusObserver(_ observer: PumpManagerStatusObserver) { - statusObservers.removeElement(observer) - } - - public func setMustProvideBLEHeartbeat(_ mustProvideBLEHeartbeat: Bool) { - rileyLinkDeviceProvider.timerTickEnabled = self.state.isPumpDataStale || mustProvideBLEHeartbeat - } - - public func ensureCurrentPumpData(completion: ((Date?) -> Void)?) { - let shouldFetchStatus = setStateWithResult { (state) -> Bool? in - guard state.hasActivePod else { - return nil // No active pod - } - - return state.isPumpDataStale - } - - checkRileyLinkBattery() - - switch shouldFetchStatus { - case .none: - completion?(lastSync) - return // No active pod - case true?: - log.default("Fetching status because pumpData is too old") - getPodStatus() { (response) in - completion?(self.lastSync) - self.silenceAcknowledgedAlerts() - } - case false?: - log.default("Skipping status update because pumpData is fresh") - completion?(self.lastSync) - silenceAcknowledgedAlerts() - } - } - - private func checkRileyLinkBattery() { - rileyLinkDeviceProvider.getDevices { devices in - for device in devices { - device.updateBatteryLevel() - } - } - } - - public func enactBolus(units: Double, activationType: BolusActivationType, completion: @escaping (PumpManagerError?) -> Void) { - guard self.hasActivePod else { - completion(.configuration(OmnipodPumpManagerError.noPodPaired)) - return - } - - // Round to nearest supported volume - let enactUnits = roundToSupportedBolusVolume(units: units) - - let acknowledgementBeep, completionBeep: Bool - if self.silencePod { - acknowledgementBeep = false - completionBeep = false - } else { - acknowledgementBeep = self.beepPreference.shouldBeepForCommand(automatic: activationType.isAutomatic) - completionBeep = beepPreference.shouldBeepForManualCommand && !activationType.isAutomatic - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Bolus", using: rileyLinkSelector) { (result) in - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(.communication(error)) - return - } - - defer { - self.setState({ (state) in - state.bolusEngageState = .stable - }) - } - self.setState({ (state) in - state.bolusEngageState = .engaging - }) - - if case .some(.suspended) = self.state.podState?.suspendState { - self.log.error("enactBolus: returning pod suspended error for bolus") - completion(.deviceState(PodCommsError.podSuspended)) - return - } - - // Use a maximum programReminderInterval value of 0x3F to denote an automatic bolus in the communication log - let programReminderInterval: TimeInterval = activationType.isAutomatic ? TimeInterval(minutes: 0x3F) : 0 - - let result = session.bolus(units: enactUnits, automatic: activationType.isAutomatic, acknowledgementBeep: acknowledgementBeep, completionBeep: completionBeep, programReminderInterval: programReminderInterval) - - switch result { - case .success: - completion(nil) - session.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: session) - } - case .certainFailure(let error): - self.log.error("enactBolus failed: %{public}@", String(describing: error)) - completion(.communication(error)) - case .unacknowledged(let error): - completion(.communication(error)) - } - } - } - - public func cancelBolus(completion: @escaping (PumpManagerResult) -> Void) { - guard self.hasActivePod else { - completion(.failure(PumpManagerError.communication(OmnipodPumpManagerError.noPodPaired))) - return - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Cancel Bolus", using: rileyLinkSelector) { (result) in - - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(.failure(PumpManagerError.communication(error))) - return - } - - do { - defer { - self.setState({ (state) in - state.bolusEngageState = .stable - }) - } - self.setState({ (state) in - state.bolusEngageState = .disengaging - }) - - if let bolus = self.state.podState?.unfinalizedBolus, !bolus.isFinished(), bolus.scheduledCertainty == .uncertain { - let status = try session.getStatus() - - if !status.deliveryStatus.bolusing { - completion(.success(nil)) - return - } - } - - // when cancelling a bolus use the built-in type 6 beeeeeep to match PDM if confirmation beeps are enabled - let beepType: BeepType = self.beepPreference.shouldBeepForManualCommand && !self.silencePod ? .beeeeeep : .noBeepCancel - let result = session.cancelDelivery(deliveryType: .bolus, beepType: beepType) - switch result { - case .certainFailure(let error): - throw error - case .unacknowledged(let error): - throw error - case .success(_, let canceledBolus): - session.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: session) - } - - let canceledDoseEntry: DoseEntry? = canceledBolus != nil ? DoseEntry(canceledBolus!) : nil - completion(.success(canceledDoseEntry)) - } - } catch { - self.log.error("cancelBolus failed: %{public}@", String(describing: error)) - completion(.failure(PumpManagerError.communication(error as? LocalizedError))) - } - } - } - - public func enactTempBasal(unitsPerHour: Double, for duration: TimeInterval, completion: @escaping (PumpManagerError?) -> Void) { - runTemporaryBasalProgram(unitsPerHour: unitsPerHour, for: duration, automatic: true, completion: completion) - } - - public func runTemporaryBasalProgram(unitsPerHour: Double, for duration: TimeInterval, automatic: Bool, completion: @escaping (PumpManagerError?) -> Void) { - - guard self.hasActivePod else { - completion(.configuration(OmnipodPumpManagerError.noPodPaired)) - return - } - - // Round to nearest supported rate - let rate = roundToSupportedBasalRate(unitsPerHour: unitsPerHour) - - let acknowledgementBeep, completionBeep: Bool - if self.silencePod { - acknowledgementBeep = false - completionBeep = false - } else { - acknowledgementBeep = beepPreference.shouldBeepForCommand(automatic: automatic) - completionBeep = beepPreference.shouldBeepForManualCommand && !automatic - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Enact Temp Basal", using: rileyLinkSelector) { (result) in - self.log.info("Enact temp basal %.03fU/hr for %ds", rate, Int(duration)) - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(.communication(error)) - return - } - - if case .some(.suspended) = self.state.podState?.suspendState { - self.log.info("Not enacting temp basal because podState indicates pod is suspended.") - completion(.deviceState(PodCommsError.podSuspended)) - return - } - - // A resume scheduled basal delivery request is denoted by a 0 duration that cancels any existing temp basal. - let resumingScheduledBasal = duration < .ulpOfOne - - // If a bolus is not finished, fail if not resuming the scheduled basal - guard self.state.podState?.unfinalizedBolus?.isFinished() != false || resumingScheduledBasal else { - self.log.info("Not enacting temp basal because podState indicates unfinalized bolus in progress.") - completion(.deviceState(PodCommsError.unfinalizedBolus)) - return - } - - // Did the last message have comms issues or is the last delivery status not verified correctly? - let uncertainDeliveryStatus = self.state.podState?.lastCommsOK == false || self.state.podState?.deliveryStatusVerified == false - - // Do the cancel temp basal command if currently running a temp basal OR - // if resuming scheduled basal delivery OR if the delivery status is uncertain. - if self.state.podState?.unfinalizedTempBasal != nil || resumingScheduledBasal || uncertainDeliveryStatus { - let status: StatusResponse - - // if resuming scheduled basal delivery & an acknowledgement beep is needed, use the cancel TB beep - let beepType: BeepType = resumingScheduledBasal && acknowledgementBeep ? .beep : .noBeepCancel - let result = session.cancelDelivery(deliveryType: .tempBasal, beepType: beepType) - switch result { - case .certainFailure(let error): - completion(.communication(error)) - return - case .unacknowledged(let error): - // TODO: Return PumpManagerError.uncertainDelivery and implement recovery - completion(.communication(error)) - return - case .success(let cancelTempStatus, _): - status = cancelTempStatus - } - - // If pod is bolusing, fail if not resuming the scheduled basal - guard !status.deliveryStatus.bolusing || resumingScheduledBasal else { - self.log.info("Canceling temp basal because status return indicates bolus in progress.") - completion(.communication(PodCommsError.unfinalizedBolus)) - return - } - - guard status.deliveryStatus != .suspended else { - self.log.info("Canceling temp basal because status return indicates pod is suspended!") - completion(.communication(PodCommsError.podSuspended)) - return - } - } else { - self.log.info("Skipped Cancel TB command before enacting temp basal") - } - - defer { - self.setState({ (state) in - state.tempBasalEngageState = .stable - }) - } - - if resumingScheduledBasal { - self.setState({ (state) in - state.tempBasalEngageState = .disengaging - }) - session.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: session) - } - completion(nil) - } else { - self.setState({ (state) in - state.tempBasalEngageState = .engaging - }) - - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = self.state.timeZone - let scheduledRate = self.state.basalSchedule.currentRate(using: calendar, at: self.dateGenerator()) - let isHighTemp = rate > scheduledRate - - let result = session.setTempBasal(rate: rate, duration: duration, isHighTemp: isHighTemp, automatic: automatic, acknowledgementBeep: acknowledgementBeep, completionBeep: completionBeep) - switch result { - case .success: - session.dosesForStorage() { (doses) -> Bool in - return self.store(doses: doses, in: session) - } - completion(nil) - case .unacknowledged(let error): - self.log.error("Temp basal uncertain error: %@", String(describing: error)) - completion(nil) - case .certainFailure(let error): - self.log.error("setTempBasal failed: %{public}@", String(describing: error)) - completion(.communication(error)) - } - } - } - } - - /// Returns a dose estimator for the current bolus, if one is in progress - public func createBolusProgressReporter(reportingOn dispatchQueue: DispatchQueue) -> DoseProgressReporter? { - if case .inProgress(let dose) = bolusState(for: self.state) { - return PodDoseProgressEstimator(dose: dose, pumpManager: self, reportingQueue: dispatchQueue) - } - return nil - } - - public func setMaximumTempBasalRate(_ rate: Double) {} - - public func syncBasalRateSchedule(items scheduleItems: [RepeatingScheduleValue], completion: @escaping (Result) -> Void) { - let newSchedule = BasalSchedule(repeatingScheduleValues: scheduleItems) - setBasalSchedule(newSchedule) { (error) in - if let error = error { - completion(.failure(error)) - } else { - completion(.success(BasalRateSchedule(dailyItems: scheduleItems, timeZone: self.state.timeZone)!)) - } - } - } - - public func syncDeliveryLimits(limits deliveryLimits: DeliveryLimits, completion: @escaping (Result) -> Void) { - setState { state in - if let rate = deliveryLimits.maximumBasalRate?.doubleValue(for: .internationalUnitsPerHour) { - state.maximumTempBasalRate = rate - completion(.success(deliveryLimits)) - } else { - completion(.failure(OmnipodPumpManagerError.invalidSetting)) - } - } - } - - // MARK: - Alerts - - public var isClockOffset: Bool { - let now = dateGenerator() - return TimeZone.current.secondsFromGMT(for: now) != state.timeZone.secondsFromGMT(for: now) - } - - func checkForTimeOffsetChange() { - let isAlertActive = state.activeAlerts.contains(.timeOffsetChangeDetected) - - if !isAlertActive && isClockOffset && !state.acknowledgedTimeOffsetAlert { - issueAlert(alert: .timeOffsetChangeDetected) - } else if isAlertActive && !isClockOffset { - retractAlert(alert: .timeOffsetChangeDetected) - } - } - - public func updateExpirationReminder(_ intervalBeforeExpiration: TimeInterval?, completion: @escaping (OmnipodPumpManagerError?) -> Void) { - - guard self.hasActivePod, let podState = state.podState, let expiresAt = podState.expiresAt else { - completion(OmnipodPumpManagerError.noPodPaired) - return - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Update Expiration Reminder", using: rileyLinkSelector) { (result) in - - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(.communication(error)) - return - } - - let podTime = self.podTime - var expirationReminderPodTime: TimeInterval = 0 // default to expiration reminder alert inactive - - // If the interval before expiration is not a positive value (e.g., it's in the past), - // then the pod alert will get the default alert time of 0 making this alert inactive. - if let intervalBeforeExpiration = intervalBeforeExpiration, intervalBeforeExpiration > 0 { - let timeUntilReminder = expiresAt.addingTimeInterval(-intervalBeforeExpiration).timeIntervalSince(self.dateGenerator()) - // Only bother to set an expiration reminder pod alert if it is still at least a couple of minutes in the future - if timeUntilReminder > .minutes(2) { - expirationReminderPodTime = podTime + timeUntilReminder - self.log.debug("Update Expiration timeUntilReminder=%@, podTime=%@, expirationReminderPodTime=%@", timeUntilReminder.timeIntervalStr, podTime.timeIntervalStr, expirationReminderPodTime.timeIntervalStr) - } - } - - let expirationReminder = PodAlert.expirationReminder(offset: podTime, absAlertTime: expirationReminderPodTime, silent: self.silencePod) - do { - let beepBlock = self.beepMessageBlock(beepType: .beep) - try session.configureAlerts([expirationReminder], beepBlock: beepBlock) - self.setState({ (state) in - state.scheduledExpirationReminderOffset = intervalBeforeExpiration - }) - completion(nil) - } catch { - completion(.communication(error)) - return - } - } - } - - public var allowedExpirationReminderDates: [Date]? { - guard let expiration = state.podState?.expiresAt else { - return nil - } - - let allDates = Array(stride( - from: -Pod.expirationReminderAlertMaxHoursBeforeExpiration, - through: -Pod.expirationReminderAlertMinHoursBeforeExpiration, - by: 1)).map - { (i: Int) -> Date in - expiration.addingTimeInterval(.hours(Double(i))) - } - let now = dateGenerator() - // Have a couple minutes of slop to avoid confusion trying to set an expiration reminder too close to now - return allDates.filter { $0.timeIntervalSince(now) > .minutes(2) } - } - - public var scheduledExpirationReminder: Date? { - guard let expiration = state.podState?.expiresAt, let offset = state.scheduledExpirationReminderOffset, offset > 0 else { - return nil - } - - // It is possible the scheduledExpirationReminderOffset does not fall on the hour, but instead be a few seconds off - // since the allowedExpirationReminderDates are by the hour, force the offset to be on the hour - return expiration.addingTimeInterval(-.hours(round(offset.hours))) - } - - // Updates the low reservior reminder value both for the current pod (when applicable) and for future pods - public func updateLowReservoirReminder(_ value: Int, completion: @escaping (OmnipodPumpManagerError?) -> Void) { - - let supportedValue = min(max(0, Double(value)), Pod.maximumReservoirReading) - let setLowReservoirReminderValue = { - self.log.default("Set Low Reservoir Reminder to %d U", value) - self.lowReservoirReminderValue = supportedValue - completion(nil) - } - - guard self.hasActivePod else { - // no active pod, just set the internal state for the next pod - setLowReservoirReminderValue() - return - } - - guard let currentReservoirLevel = self.reservoirLevel?.rawValue, currentReservoirLevel > supportedValue else { - // Since the new low reservoir alert level is not below the current reservoir value, - // just set the internal state for the next pod to prevent an immediate low reservoir alert. - setLowReservoirReminderValue() - return - } - - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Program Low Reservoir Reminder", using: rileyLinkSelector) { (result) in - - let session: PodCommsSession - switch result { - case .success(let s): - session = s - case .failure(let error): - completion(.communication(error)) - return - } - - let lowReservoirReminder = PodAlert.lowReservoir(units: supportedValue, silent: self.silencePod) - do { - let beepBlock = self.beepMessageBlock(beepType: .beep) - try session.configureAlerts([lowReservoirReminder], beepBlock: beepBlock) - self.lowReservoirReminderValue = supportedValue - completion(nil) - } catch { - completion(.communication(error)) - return - } - } - } - - func issueAlert(alert: PumpManagerAlert) { - let identifier = Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: alert.alertIdentifier) - let loopAlert = Alert(identifier: identifier, foregroundContent: alert.foregroundContent, backgroundContent: alert.backgroundContent, trigger: .immediate) - pumpDelegate.notify { (delegate) in - delegate?.issueAlert(loopAlert) - } - - if let repeatInterval = alert.repeatInterval { - // Schedule an additional repeating 15 minute reminder for suspend period ended. - let repeatingIdentifier = Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: alert.repeatingAlertIdentifier) - let loopAlert = Alert(identifier: repeatingIdentifier, foregroundContent: alert.foregroundContent, backgroundContent: alert.backgroundContent, trigger: .repeating(repeatInterval: repeatInterval)) - pumpDelegate.notify { (delegate) in - delegate?.issueAlert(loopAlert) - } - } - - self.setState { (state) in - state.activeAlerts.insert(alert) - } - } - - func retractAlert(alert: PumpManagerAlert) { - let identifier = Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: alert.alertIdentifier) - pumpDelegate.notify { (delegate) in - delegate?.retractAlert(identifier: identifier) - } - if alert.isRepeating { - let repeatingIdentifier = Alert.Identifier(managerIdentifier: self.managerIdentifier, alertIdentifier: alert.repeatingAlertIdentifier) - pumpDelegate.notify { (delegate) in - delegate?.retractAlert(identifier: repeatingIdentifier) - } - } - self.setState { (state) in - state.activeAlerts.remove(alert) - } - } - - private func alertsChanged(oldAlerts: AlertSet, newAlerts: AlertSet) { - guard let podState = state.podState else { - preconditionFailure("trying to manage alerts without podState") - } - - let (added, removed) = oldAlerts.compare(to: newAlerts) - for slot in added { - if let podAlert = podState.configuredAlerts[slot] { - log.default("Alert slot triggered: %{public}@", String(describing: slot)) - if let pumpManagerAlert = getPumpManagerAlert(for: podAlert, slot: slot) { - issueAlert(alert: pumpManagerAlert) - } else { - log.default("Ignoring alert: %{public}@", String(describing: podAlert)) - } - } else { - log.error("Unconfigured alert slot triggered: %{public}@", String(describing: slot)) - let pumpManagerAlert = PumpManagerAlert.unexpectedAlert(triggeringSlot: slot) - issueAlert(alert: pumpManagerAlert) - } - } - for alert in removed { - log.default("Alert slot cleared: %{public}@", String(describing: alert)) - } - } - - private func getPumpManagerAlert(for podAlert: PodAlert, slot: AlertSlot) -> PumpManagerAlert? { - - switch podAlert { - case .shutdownImminent: - return PumpManagerAlert.podExpireImminent(triggeringSlot: slot) - case .expirationReminder: - guard let podState = state.podState, let expiresAt = podState.expiresAt else { - preconditionFailure("trying to lookup expiresAt") - } - let timeToExpiry = TimeInterval(hours: expiresAt.timeIntervalSince(dateGenerator()).hours.rounded()) - return PumpManagerAlert.userPodExpiration(triggeringSlot: slot, scheduledExpirationReminderOffset: timeToExpiry) - case .lowReservoir(let units, _): - return PumpManagerAlert.lowReservoir(triggeringSlot: slot, lowReservoirReminderValue: units) - case .suspendTimeExpired: - return PumpManagerAlert.suspendEnded(triggeringSlot: slot) - case .expired: - return PumpManagerAlert.podExpiring(triggeringSlot: slot) - default: - // No PumpManagerAlerts are used for any other pod alerts (including suspendInProgress). - return nil - } - } - - private func silenceAcknowledgedAlerts() { - // Only attempt to clear one per cycle (more than one should be rare) - if let alert = state.alertsWithPendingAcknowledgment.first { - if let slot = alert.triggeringSlot { - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Silence already acknowledged alert", using: rileyLinkSelector) { (result) in - switch result { - case .success(let session): - do { - let _ = try session.acknowledgeAlerts(alerts: AlertSet(slots: [slot])) - } catch { - return - } - self.setState { state in - state.activeAlerts.remove(alert) - state.alertsWithPendingAcknowledgment.remove(alert) - } - case .failure: - return - } - } - } - } - } - - static let podAlarmNotificationIdentifier = "Omnipod:\(LoopNotificationCategory.pumpFault.rawValue)" - - private func notifyPodFault(fault: DetailedStatus) { - pumpDelegate.notify { delegate in - let content = Alert.Content(title: fault.faultEventCode.notificationTitle, - body: fault.faultEventCode.notificationBody, - acknowledgeActionButtonLabel: LocalizedString("OK", comment: "Alert acknowledgment OK button")) - delegate?.issueAlert(Alert(identifier: Alert.Identifier(managerIdentifier: OmnipodPumpManager.podAlarmNotificationIdentifier, - alertIdentifier: fault.faultEventCode.description), - foregroundContent: content, backgroundContent: content, - trigger: .immediate)) - } - } - - // MARK: - Reporting Doses - - // This cannot be called from within the lockedState lock! - func store(doses: [UnfinalizedDose], in session: PodCommsSession) -> Bool { - session.assertOnSessionQueue() - - // We block the session until the data's confirmed stored by the delegate - let semaphore = DispatchSemaphore(value: 0) - var success = false - - store(doses: doses) { (error) in - success = (error == nil) - semaphore.signal() - } - - semaphore.wait() - - if success { - setState { (state) in - state.lastPumpDataReportDate = Date() - } - } - return success - } - - func store(doses: [UnfinalizedDose], completion: @escaping (_ error: Error?) -> Void) { - let lastSync = lastSync - - pumpDelegate.notify { (delegate) in - guard let delegate = delegate else { - preconditionFailure("pumpManagerDelegate cannot be nil") - } - - delegate.pumpManager(self, hasNewPumpEvents: doses.map { NewPumpEvent($0) }, lastReconciliation: lastSync, completion: { (error) in - if let error = error { - self.log.error("Error storing pod events: %@", String(describing: error)) - } else { - self.log.info("DU: Stored pod events: %@", String(describing: doses)) - } - - completion(error) - }) - } - } -} - -extension OmnipodPumpManager: MessageLogger { - func didSend(_ message: Data) { - log.default("didSend: %{public}@", message.hexadecimalString) - self.logDeviceCommunication(message.hexadecimalString, type: .send) - } - - func didReceive(_ message: Data) { - log.default("didReceive: %{public}@", message.hexadecimalString) - self.logDeviceCommunication(message.hexadecimalString, type: .receive) - } - - func didError(_ message: String) { - self.logDeviceCommunication(message, type: .error) - } -} - -extension OmnipodPumpManager: PodCommsDelegate { - func podComms(_ podComms: PodComms, didChange podState: PodState?) { - if let podState = podState { - let (newFault, oldAlerts, newAlerts) = setStateWithResult { (state) -> (DetailedStatus?,AlertSet,AlertSet) in - if (state.suspendEngageState == .engaging && podState.isSuspended) || - (state.suspendEngageState == .disengaging && !podState.isSuspended) - { - state.suspendEngageState = .stable - } - - let newFault: DetailedStatus? - - // Check for new fault state - if state.podState?.fault == nil, let fault = podState.fault { - newFault = fault - } else { - newFault = nil - } - - let oldAlerts: AlertSet = state.podState?.activeAlertSlots ?? AlertSet.none - let newAlerts: AlertSet = podState.activeAlertSlots - - state.updatePodStateFromPodComms(podState) - - return (newFault, oldAlerts, newAlerts) - } - - if let newFault = newFault { - notifyPodFault(fault: newFault) - } - - if oldAlerts != newAlerts { - self.alertsChanged(oldAlerts: oldAlerts, newAlerts: newAlerts) - } - } else { - // Resetting podState - setState { state in - state.updatePodStateFromPodComms(podState) - } - } - } -} - -// MARK: - AlertResponder implementation -extension OmnipodPumpManager { - public func acknowledgeAlert(alertIdentifier: Alert.AlertIdentifier, completion: @escaping (Error?) -> Void) { - guard self.hasActivePod else { - completion(OmnipodPumpManagerError.noPodPaired) - return - } - - for alert in state.activeAlerts { - if alert.alertIdentifier == alertIdentifier { - // If this alert was triggered by the pod find the slot to clear it. - if let slot = alert.triggeringSlot { - if case .some(.suspended) = self.state.podState?.suspendState, slot == .slot6SuspendTimeExpired { - // Don't clear this pod alert here with the pod still suspended so that the suspend time expired - // pod alert beeping will continue until the pod is resumed which will then deactivate this alert. - log.default("Skipping acknowledgement of suspend time expired alert with a suspended pod") - completion(nil) - return - } - let rileyLinkSelector = self.rileyLinkDeviceProvider.firstConnectedDevice - self.podComms.runSession(withName: "Acknowledge Alert", using: rileyLinkSelector) { (result) in - switch result { - case .success(let session): - do { - let beepBlock = self.beepMessageBlock(beepType: .beep) - let _ = try session.acknowledgeAlerts(alerts: AlertSet(slots: [slot]), beepBlock: beepBlock) - } catch { - self.setState { state in - state.alertsWithPendingAcknowledgment.insert(alert) - } - completion(error) - return - } - self.setState { state in - state.activeAlerts.remove(alert) - } - completion(nil) - case .failure(let error): - self.setState { state in - state.alertsWithPendingAcknowledgment.insert(alert) - } - completion(error) - return - } - } - } else { - // Non-pod alert - self.setState { state in - state.activeAlerts.remove(alert) - if alert == .timeOffsetChangeDetected { - state.acknowledgedTimeOffsetAlert = true - } - } - completion(nil) - } - } - } - } -} - -// MARK: - AlertSoundVendor implementation -extension OmnipodPumpManager { - public func getSoundBaseURL() -> URL? { return nil } - public func getSounds() -> [Alert.Sound] { return [] } -} - -extension FaultEventCode { - public var notificationTitle: String { - switch self.faultType { - case .reservoirEmpty: - return LocalizedString("Empty Reservoir", comment: "The title for Empty Reservoir alarm notification") - case .occluded, .occlusionCheckStartup1, .occlusionCheckStartup2, .occlusionCheckTimeouts1, .occlusionCheckTimeouts2, .occlusionCheckTimeouts3, .occlusionCheckPulseIssue, .occlusionCheckBolusProblem: - return LocalizedString("Occlusion Detected", comment: "The title for Occlusion alarm notification") - case .exceededMaximumPodLife80Hrs: - return LocalizedString("Pod Expired", comment: "The title for Pod Expired alarm notification") - default: - return String(format: LocalizedString("Critical Pod Fault %1$03d", comment: "The title for AlarmCode.other notification: (1: fault code value)"), self.rawValue) - } - } - - public var notificationBody: String { - return LocalizedString("Insulin delivery stopped. Change Pod now.", comment: "The default notification body for AlarmCodes") - } -} diff --git a/Dependencies/OmniKit/OmniKit/PumpManager/OmnipodPumpManagerState.swift b/Dependencies/OmniKit/OmniKit/PumpManager/OmnipodPumpManagerState.swift deleted file mode 100644 index 3b4913d3a..000000000 --- a/Dependencies/OmniKit/OmniKit/PumpManager/OmnipodPumpManagerState.swift +++ /dev/null @@ -1,343 +0,0 @@ -// -// OmnipodPumpManagerState.swift -// OmniKit -// -// Created by Pete Schwamb on 8/4/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import RileyLinkKit -import RileyLinkBLEKit -import LoopKit - - -public struct OmnipodPumpManagerState: RawRepresentable, Equatable { - public typealias RawValue = PumpManager.RawStateValue - - public static let version = 2 - - public var isOnboarded: Bool - - private (set) public var podState: PodState? - - // podState should only be modifiable by PodComms - mutating func updatePodStateFromPodComms(_ podState: PodState?) { - self.podState = podState - } - - public var pairingAttemptAddress: UInt32? - - public var timeZone: TimeZone - - public var basalSchedule: BasalSchedule - - public var rileyLinkConnectionManagerState: RileyLinkConnectionState? - - public var unstoredDoses: [UnfinalizedDose] - - public var silencePod: Bool - - public var confirmationBeeps: BeepPreference - - public var scheduledExpirationReminderOffset: TimeInterval? - - public var defaultExpirationReminderOffset = Pod.defaultExpirationReminderOffset - - public var lowReservoirReminderValue: Double - - public var podAttachmentConfirmed: Bool - - public var activeAlerts: Set - - public var alertsWithPendingAcknowledgment: Set - - public var acknowledgedTimeOffsetAlert: Bool - - // Temporal state not persisted - - internal enum EngageablePumpState: Equatable { - case engaging - case disengaging - case stable - } - - internal var suspendEngageState: EngageablePumpState = .stable - - internal var bolusEngageState: EngageablePumpState = .stable - - internal var tempBasalEngageState: EngageablePumpState = .stable - - internal var lastPumpDataReportDate: Date? - - internal var insulinType: InsulinType? - - // Persistence for the pod state of the previous pod, for - // user review and manufacturer reporting. - public var previousPodState: PodState? - - // Indicates that the user has completed initial configuration - // which means they have configured any parameters, but may not have paired a pod yet. - public var initialConfigurationCompleted: Bool = false - - public var rileyLinkBatteryAlertLevel: Int? - - public var lastRileyLinkBatteryAlertDate: Date = .distantPast - - public var maximumTempBasalRate: Double - - // From last status response - public var reservoirLevel: ReservoirLevel? { - guard let level = podState?.lastInsulinMeasurements?.reservoirLevel else { - return nil - } - return ReservoirLevel(rawValue: level) - } - - // MARK: - - - public init(isOnboarded: Bool, podState: PodState?, timeZone: TimeZone, basalSchedule: BasalSchedule, rileyLinkConnectionManagerState: RileyLinkConnectionState?, insulinType: InsulinType?, maximumTempBasalRate: Double) { - self.isOnboarded = isOnboarded - self.podState = podState - self.timeZone = timeZone - self.basalSchedule = basalSchedule - self.rileyLinkConnectionManagerState = rileyLinkConnectionManagerState - self.unstoredDoses = [] - self.silencePod = false - self.confirmationBeeps = .manualCommands - self.insulinType = insulinType - self.lowReservoirReminderValue = Pod.defaultLowReservoirReminder - self.podAttachmentConfirmed = false - self.activeAlerts = [] - self.alertsWithPendingAcknowledgment = [] - self.acknowledgedTimeOffsetAlert = false - self.maximumTempBasalRate = maximumTempBasalRate - } - - public init?(rawValue: RawValue) { - - guard let version = rawValue["version"] as? Int else { - return nil - } - - let basalSchedule: BasalSchedule - - if version == 1 { - // migrate: basalSchedule moved from podState to oppm state - if let podStateRaw = rawValue["podState"] as? PodState.RawValue, - let rawBasalSchedule = podStateRaw["basalSchedule"] as? BasalSchedule.RawValue, - let migrateSchedule = BasalSchedule(rawValue: rawBasalSchedule) - { - basalSchedule = migrateSchedule - } else { - return nil - } - } else { - guard let rawBasalSchedule = rawValue["basalSchedule"] as? BasalSchedule.RawValue, - let schedule = BasalSchedule(rawValue: rawBasalSchedule) else - { - return nil - } - basalSchedule = schedule - } - - let isOnboarded = rawValue["isOnboarded"] as? Bool ?? true // Backward compatibility - - let podState: PodState? - if let podStateRaw = rawValue["podState"] as? PodState.RawValue { - podState = PodState(rawValue: podStateRaw) - } else { - podState = nil - } - - let timeZone: TimeZone - if let timeZoneSeconds = rawValue["timeZone"] as? Int, - let tz = TimeZone(secondsFromGMT: timeZoneSeconds) { - timeZone = tz - } else { - timeZone = TimeZone.currentFixed - } - - let rileyLinkConnectionManagerState: RileyLinkConnectionState? - if let rileyLinkConnectionManagerStateRaw = rawValue["rileyLinkConnectionManagerState"] as? RileyLinkConnectionState.RawValue { - rileyLinkConnectionManagerState = RileyLinkConnectionState(rawValue: rileyLinkConnectionManagerStateRaw) - } else { - rileyLinkConnectionManagerState = RileyLinkConnectionState(autoConnectIDs: []) - } - - var insulinType: InsulinType? - if let rawInsulinType = rawValue["insulinType"] as? InsulinType.RawValue { - insulinType = InsulinType(rawValue: rawInsulinType) - } - - // If this doesn't exist (early adopters of dev/pre-3.0) set to zero - // Will not let them set a manual temp until a limits sync has been performed. - let maximumTempBasalRate = rawValue["maximumTempBasalRate"] as? Double ?? 0 - - self.init( - isOnboarded: isOnboarded, - podState: podState, - timeZone: timeZone, - basalSchedule: basalSchedule, - rileyLinkConnectionManagerState: rileyLinkConnectionManagerState, - insulinType: insulinType ?? .novolog, - maximumTempBasalRate: maximumTempBasalRate - ) - - if let rawUnstoredDoses = rawValue["unstoredDoses"] as? [UnfinalizedDose.RawValue] { - self.unstoredDoses = rawUnstoredDoses.compactMap( { UnfinalizedDose(rawValue: $0) } ) - } else { - self.unstoredDoses = [] - } - - self.silencePod = rawValue["silencePod"] as? Bool ?? false - - if let oldAutomaticBolusBeeps = rawValue["automaticBolusBeeps"] as? Bool, oldAutomaticBolusBeeps { - self.confirmationBeeps = .extended - } else if let oldConfirmationBeeps = rawValue["confirmationBeeps"] as? Bool, oldConfirmationBeeps { - self.confirmationBeeps = .manualCommands - } else { - if let rawBeeps = rawValue["confirmationBeeps"] as? BeepPreference.RawValue, let confirmationBeeps = BeepPreference(rawValue: rawBeeps) { - self.confirmationBeeps = confirmationBeeps - } else { - self.confirmationBeeps = .manualCommands - } - } - - self.scheduledExpirationReminderOffset = rawValue["scheduledExpirationReminderOffset"] as? TimeInterval - - self.defaultExpirationReminderOffset = rawValue["defaultExpirationReminderOffset"] as? TimeInterval ?? Pod.defaultExpirationReminderOffset - - self.lowReservoirReminderValue = rawValue["lowReservoirReminderValue"] as? Double ?? Pod.defaultLowReservoirReminder - - self.podAttachmentConfirmed = rawValue["podAttachmentConfirmed"] as? Bool ?? false - - self.initialConfigurationCompleted = rawValue["initialConfigurationCompleted"] as? Bool ?? true - - self.acknowledgedTimeOffsetAlert = rawValue["acknowledgedTimeOffsetAlert"] as? Bool ?? false - - if let lastPumpDataReportDate = rawValue["lastPumpDataReportDate"] as? Date { - self.lastPumpDataReportDate = lastPumpDataReportDate - } - - if let pairingAttemptAddress = rawValue["pairingAttemptAddress"] as? UInt32 { - self.pairingAttemptAddress = pairingAttemptAddress - } - - rileyLinkBatteryAlertLevel = rawValue["rileyLinkBatteryAlertLevel"] as? Int - lastRileyLinkBatteryAlertDate = rawValue["lastRileyLinkBatteryAlertDate"] as? Date ?? Date.distantPast - - self.activeAlerts = [] - if let rawActiveAlerts = rawValue["activeAlerts"] as? [PumpManagerAlert.RawValue] { - for rawAlert in rawActiveAlerts { - if let alert = PumpManagerAlert(rawValue: rawAlert) { - self.activeAlerts.insert(alert) - } - } - } - - self.alertsWithPendingAcknowledgment = [] - if let rawAlerts = rawValue["alertsWithPendingAcknowledgment"] as? [PumpManagerAlert.RawValue] { - for rawAlert in rawAlerts { - if let alert = PumpManagerAlert(rawValue: rawAlert) { - self.alertsWithPendingAcknowledgment.insert(alert) - } - } - } - - if let prevPodStateRaw = rawValue["previousPodState"] as? PodState.RawValue { - previousPodState = PodState(rawValue: prevPodStateRaw) - } else { - previousPodState = nil - } - } - - public var rawValue: RawValue { - var value: [String : Any] = [ - "version": OmnipodPumpManagerState.version, - "isOnboarded": isOnboarded, - "timeZone": timeZone.secondsFromGMT(), - "basalSchedule": basalSchedule.rawValue, - "unstoredDoses": unstoredDoses.map { $0.rawValue }, - "silencePod": silencePod, - "confirmationBeeps": confirmationBeeps.rawValue, - "activeAlerts": activeAlerts.map { $0.rawValue }, - "podAttachmentConfirmed": podAttachmentConfirmed, - "acknowledgedTimeOffsetAlert": acknowledgedTimeOffsetAlert, - "alertsWithPendingAcknowledgment": alertsWithPendingAcknowledgment.map { $0.rawValue }, - "initialConfigurationCompleted": initialConfigurationCompleted, - "maximumTempBasalRate": maximumTempBasalRate - ] - - value["insulinType"] = insulinType?.rawValue - value["podState"] = podState?.rawValue - value["scheduledExpirationReminderOffset"] = scheduledExpirationReminderOffset - value["defaultExpirationReminderOffset"] = defaultExpirationReminderOffset - value["lowReservoirReminderValue"] = lowReservoirReminderValue - value["rileyLinkConnectionManagerState"] = rileyLinkConnectionManagerState?.rawValue - value["pairingAttemptAddress"] = pairingAttemptAddress - value["rileyLinkBatteryAlertLevel"] = rileyLinkBatteryAlertLevel - value["lastRileyLinkBatteryAlertDate"] = lastRileyLinkBatteryAlertDate - value["lastPumpDataReportDate"] = lastPumpDataReportDate - value["previousPodState"] = previousPodState?.rawValue - - return value - } -} - -extension OmnipodPumpManagerState { - var hasActivePod: Bool { - return podState?.isActive == true - } - - var hasSetupPod: Bool { - return podState?.isSetupComplete == true - } - - var isPumpDataStale: Bool { - let pumpStatusAgeTolerance = TimeInterval(minutes: 6) - let pumpDataAge = -(self.lastPumpDataReportDate ?? .distantPast).timeIntervalSinceNow - return pumpDataAge > pumpStatusAgeTolerance - } -} - - -extension OmnipodPumpManagerState: CustomDebugStringConvertible { - public var debugDescription: String { - return [ - "## OmnipodPumpManagerState", - "* isOnboarded: \(isOnboarded)", - "* timeZone: \(timeZone)", - "* basalSchedule: \(String(describing: basalSchedule))", - "* maximumTempBasalRate: \(maximumTempBasalRate)", - "* scheduledExpirationReminderOffset: \(String(describing: scheduledExpirationReminderOffset?.timeIntervalStr))", - "* defaultExpirationReminderOffset: \(defaultExpirationReminderOffset.timeIntervalStr)", - "* lowReservoirReminderValue: \(String(describing: lowReservoirReminderValue))", - "* podAttachmentConfirmed: \(podAttachmentConfirmed)", - "* activeAlerts: \(activeAlerts)", - "* alertsWithPendingAcknowledgment: \(alertsWithPendingAcknowledgment)", - "* acknowledgedTimeOffsetAlert: \(acknowledgedTimeOffsetAlert)", - "* initialConfigurationCompleted: \(initialConfigurationCompleted)", - "* unstoredDoses: \(String(describing: unstoredDoses))", - "* suspendEngageState: \(String(describing: suspendEngageState))", - "* bolusEngageState: \(String(describing: bolusEngageState))", - "* tempBasalEngageState: \(String(describing: tempBasalEngageState))", - "* lastPumpDataReportDate: \(String(describing: lastPumpDataReportDate))", - "* isPumpDataStale: \(String(describing: isPumpDataStale))", - "* silencePod: \(String(describing: silencePod))", - "* confirmationBeeps: \(String(describing: confirmationBeeps))", - "* pairingAttemptAddress: \(String(describing: pairingAttemptAddress))", - "* insulinType: \(String(describing: insulinType))", - "* scheduledExpirationReminderOffset: \(String(describing: scheduledExpirationReminderOffset?.timeIntervalStr))", - "* defaultExpirationReminderOffset: \(defaultExpirationReminderOffset.timeIntervalStr)", - "* rileyLinkBatteryAlertLevel: \(String(describing: rileyLinkBatteryAlertLevel))", - "* lastRileyLinkBatteryAlertDate \(String(describing: lastRileyLinkBatteryAlertDate))", - "", - "* RileyLinkConnectionManagerState: " + (rileyLinkConnectionManagerState == nil ? "nil" : String(describing: rileyLinkConnectionManagerState!)), - "", - "* PodState: " + (podState == nil ? "nil" : String(describing: podState!)), - "", - "* PreviousPodState: " + (previousPodState == nil ? "nil" : String(describing: previousPodState!)), - "", - ].joined(separator: "\n") - } -} diff --git a/Dependencies/OmniKit/OmniKit/PumpManager/PodComms.swift b/Dependencies/OmniKit/OmniKit/PumpManager/PodComms.swift deleted file mode 100644 index 0389e3dc1..000000000 --- a/Dependencies/OmniKit/OmniKit/PumpManager/PodComms.swift +++ /dev/null @@ -1,552 +0,0 @@ -// -// PodComms.swift -// OmniKit -// -// Created by Pete Schwamb on 10/7/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation -import RileyLinkBLEKit -import LoopKit -import os.log - -fileprivate var diagnosePairingRssi = false - -protocol PodCommsDelegate: AnyObject { - func podComms(_ podComms: PodComms, didChange podState: PodState?) -} - -class PodComms: CustomDebugStringConvertible { - - private let configuredDevices: Locked> = Locked(Set()) - - weak var delegate: PodCommsDelegate? - - weak var messageLogger: MessageLogger? - - public let log = OSLog(category: "PodComms") - - private var podStateLock = NSLock() - - private var podState: PodState? { - didSet { - if podState != oldValue { - delegate?.podComms(self, didChange: podState) - } - } - } - - private var startingPacketNumber = 0 - - - init(podState: PodState?) { - self.podState = podState - self.delegate = nil - self.messageLogger = nil - } - - public func updateInsulinType(_ insulinType: InsulinType) { - podStateLock.lock() - podState?.insulinType = insulinType - podStateLock.unlock() - } - - func forgetPod() { - podStateLock.lock() - self.podState?.resolveAnyPendingCommandWithUncertainty() - self.podState?.finalizeAllDoses() - podStateLock.unlock() - } - - func mockPodStateChanges(_ changes: (_ podState: inout PodState) -> Void) -> Void { - podStateLock.lock() - changes(&self.podState!) - podStateLock.unlock() - } - - /// Handles all the common work to send and verify the version response for the two pairing commands, AssignAddress and SetupPod. - /// Has side effects of creating pod state, assigning startingPacketNumber, and updating pod state. - /// - /// - parameter address: Address being assigned to the pod - /// - parameter transport: PodMessageTransport used to send messages - /// - parameter message: Message to send; must be an AssignAddress or SetupPod - /// - /// - returns: The VersionResponse from the pod - /// - /// - Throws: - /// - PodCommsError.noResponse - /// - PodCommsError.podAckedInsteadOfReturningResponse - /// - PodCommsError.unexpectedPacketType - /// - PodCommsError.emptyResponse - /// - PodCommsError.unexpectedResponse - /// - PodCommsError.podChange - /// - PodCommsError.activationTimeExceeded - /// - PodCommsError.rssiTooLow - /// - PodCommsError.rssiTooHigh - /// - PodCommsError.podFault - /// - PodCommsError.diagnosticMessage - /// - PodCommsError.podIncompatible - /// - MessageError.invalidCrc - /// - MessageError.invalidSequence - /// - MessageError.invalidAddress - /// - RileyLinkDeviceError - private func sendPairMessage(address: UInt32, transport: PodMessageTransport, message: Message, insulinType: InsulinType) throws -> VersionResponse { - - // We should already be holding podStateLock during calls to this function, so try() should fail - assert(!podStateLock.try(), "\(#function) should be invoked while holding podStateLock") - - defer { - log.debug("sendPairMessage saving current transport packet #%d", transport.packetNumber) - if self.podState != nil { - self.podState!.messageTransportState = MessageTransportState(packetNumber: transport.packetNumber, messageNumber: transport.messageNumber) - } else { - self.startingPacketNumber = transport.packetNumber - } - } - - var didRetry = false - - var rssiRetries = 2 - while true { - let response: Message - do { - response = try transport.sendMessage(message) - } catch let error { - if let podCommsError = error as? PodCommsError { - switch podCommsError { - // These errors can happen some times when the responses are not seen for a long - // enough time. Automatically retrying using the already incremented packet # can - // clear this condition without requiring any user interaction for a pairing failure. - case .podAckedInsteadOfReturningResponse, .noResponse: - if didRetry == false { - didRetry = true - log.debug("sendPairMessage to retry using updated packet #%d", transport.packetNumber) - continue // the transport packet # is already advanced for the retry - } - default: - break - } - } - throw error - } - - if let fault = response.fault { - log.error("Pod Fault: %{public}@", String(describing: fault)) - if let podState = self.podState, podState.fault == nil { - self.podState!.fault = fault - } - throw PodCommsError.podFault(fault: fault) - } - - guard let config = response.messageBlocks[0] as? VersionResponse else { - log.error("sendPairMessage unexpected response: %{public}@", String(describing: response)) - let responseType = response.messageBlocks[0].blockType - throw PodCommsError.unexpectedResponse(response: responseType) - } - - guard config.address == address else { - log.error("sendPairMessage unexpected address return of %{public}@ instead of expected %{public}@", - String(format: "04X", config.address), String(format: "%04X", address)) - throw PodCommsError.invalidAddress(address: config.address, expectedAddress: address) - } - - // If we previously had podState, verify that we are still dealing with the same pod - if let podState = self.podState, (podState.lot != config.lot || podState.tid != config.tid) { - // Have a new pod, could be a pod change w/o deactivation (or we're picking up some other pairing pod!) - log.error("Received pod response for [lot %u tid %u], expected [lot %u tid %u]", config.lot, config.tid, podState.lot, podState.tid) - throw PodCommsError.podChange - } - - // Check the pod RSSI - let maxRssiAllowed = 59 // maximum RSSI limit allowed - let minRssiAllowed = 30 // minimum RSSI limit allowed - if let rssi = config.rssi, let gain = config.gain { - let rssiStr = String(format: "RSSI: %u.\nReceiver Low Gain: %u", rssi, gain) - log.default("%@", rssiStr) - if diagnosePairingRssi { - throw PodCommsError.diagnosticMessage(str: rssiStr) - } - - rssiRetries -= 1 - if rssi < minRssiAllowed { - log.default("RSSI value %d is less than minimum allowed value of %d, %d retries left", rssi, minRssiAllowed, rssiRetries) - if rssiRetries > 0 { - continue - } - throw PodCommsError.rssiTooLow - } - if rssi > maxRssiAllowed { - log.default("RSSI value %d is more than maximum allowed value of %d, %d retries left", rssi, maxRssiAllowed, rssiRetries) - if rssiRetries > 0 { - continue - } - throw PodCommsError.rssiTooHigh - } - } - - if self.podState == nil { - log.default("Creating PodState for address %{public}@ [lot %u tid %u], packet #%d, message #%d", String(format: "%04X", config.address), config.lot, config.tid, transport.packetNumber, transport.messageNumber) - self.podState = PodState( - address: config.address, - pmVersion: String(describing: config.firmwareVersion), - piVersion: String(describing: config.iFirmwareVersion), - lot: config.lot, - tid: config.tid, - packetNumber: transport.packetNumber, - messageNumber: transport.messageNumber, - insulinType: insulinType - ) - // podState setupProgress state should be addressAssigned - } - - // Now that we have podState, check for an activation timeout condition that can be noted in setupProgress - guard config.podProgressStatus != .activationTimeExceeded else { - // The 2 hour window for the initial pairing has expired - self.podState?.setupProgress = .activationTimeout - throw PodCommsError.activationTimeExceeded - } - - // It's unlikely that Insulet will release an updated Eros pod using any different fundemental values, - // so just verify that the fundemental pod constants returned match the expected constant values in the Pod struct. - // To actually be able to handle different fundemental values in Loop things would need to be reworked to save - // these values in some persistent PodState and then make sure that everything properly works using these values. - var errorStrings: [String] = [] - if let pulseSize = config.pulseSize, pulseSize != Pod.pulseSize { - errorStrings.append(String(format: "Pod reported pulse size of %.3fU different than expected %.3fU", pulseSize, Pod.pulseSize)) - } - if let secondsPerBolusPulse = config.secondsPerBolusPulse, secondsPerBolusPulse != Pod.secondsPerBolusPulse { - errorStrings.append(String(format: "Pod reported seconds per pulse rate of %.1f different than expected %.1f", secondsPerBolusPulse, Pod.secondsPerBolusPulse)) - } - if let secondsPerPrimePulse = config.secondsPerPrimePulse, secondsPerPrimePulse != Pod.secondsPerPrimePulse { - errorStrings.append(String(format: "Pod reported seconds per prime pulse rate of %.1f different than expected %.1f", secondsPerPrimePulse, Pod.secondsPerPrimePulse)) - } - if let primeUnits = config.primeUnits, primeUnits != Pod.primeUnits { - errorStrings.append(String(format: "Pod reported prime bolus of %.2fU different than expected %.2fU", primeUnits, Pod.primeUnits)) - } - if let cannulaInsertionUnits = config.cannulaInsertionUnits, Pod.cannulaInsertionUnits != cannulaInsertionUnits { - errorStrings.append(String(format: "Pod reported cannula insertion bolus of %.2fU different than expected %.2fU", cannulaInsertionUnits, Pod.cannulaInsertionUnits)) - } - if let serviceDuration = config.serviceDuration { - if serviceDuration < Pod.serviceDuration { - errorStrings.append(String(format: "Pod reported service duration of %.0f hours shorter than expected %.0f", serviceDuration.hours, Pod.serviceDuration.hours)) - } else if serviceDuration > Pod.serviceDuration { - log.info("Pod reported service duration of %.0f hours limited to expected %.0f", serviceDuration.hours, Pod.serviceDuration.hours) - } - } - - let errMess = errorStrings.joined(separator: ".\n") - if errMess.isEmpty == false { - log.error("%@", errMess) - self.podState?.setupProgress = .podIncompatible - throw PodCommsError.podIncompatible(str: errMess) - } - - if config.podProgressStatus == .pairingCompleted && self.podState?.setupProgress.isPaired == false { - log.info("Version Response %{public}@ indicates pairing is now complete", String(describing: config)) - self.podState?.setupProgress = .podPaired - } - - return config - } - } - - private func assignAddress(address: UInt32, commandSession: CommandSession, insulinType: InsulinType) throws { - // We should already be holding podStateLock during calls to this function, so try() should fail - assert(!podStateLock.try(), "\(#function) should be invoked while holding podStateLock") - - commandSession.assertOnSessionQueue() - - let packetNumber, messageNumber: Int - if let podState = self.podState { - packetNumber = podState.messageTransportState.packetNumber - messageNumber = podState.messageTransportState.messageNumber - } else { - packetNumber = self.startingPacketNumber - messageNumber = 0 - } - - log.debug("Attempting pairing with address %{public}@ using packet #%d", String(format: "%04X", address), packetNumber) - let messageTransportState = MessageTransportState(packetNumber: packetNumber, messageNumber: messageNumber) - let transport = PodMessageTransport(session: commandSession, address: 0xffffffff, ackAddress: address, state: messageTransportState) - transport.messageLogger = messageLogger - - // Create the Assign Address command message - let assignAddress = AssignAddressCommand(address: address) - let message = Message(address: 0xffffffff, messageBlocks: [assignAddress], sequenceNum: transport.messageNumber) - - _ = try sendPairMessage(address: address, transport: transport, message: message, insulinType: insulinType) - } - - private func setupPod(podState: PodState, timeZone: TimeZone, commandSession: CommandSession, insulinType: InsulinType) throws { - // We should already be holding podStateLock during calls to this function, so try() should fail - assert(!podStateLock.try(), "\(#function) should be invoked while holding podStateLock") - - commandSession.assertOnSessionQueue() - - let transport = PodMessageTransport(session: commandSession, address: 0xffffffff, ackAddress: podState.address, state: podState.messageTransportState) - transport.messageLogger = messageLogger - - let dateComponents = SetupPodCommand.dateComponents(date: Date(), timeZone: timeZone) - let setupPod = SetupPodCommand(address: podState.address, dateComponents: dateComponents, lot: podState.lot, tid: podState.tid) - - let message = Message(address: 0xffffffff, messageBlocks: [setupPod], sequenceNum: transport.messageNumber) - - let versionResponse: VersionResponse - do { - versionResponse = try sendPairMessage(address: podState.address, transport: transport, message: message, insulinType: insulinType) - } catch let error { - if case PodCommsError.podAckedInsteadOfReturningResponse = error { - log.default("SetupPod acked instead of returning response.") - if self.podState?.setupProgress.isPaired == false { - log.default("Moving pod to paired state.") - self.podState?.setupProgress = .podPaired - } - return - } - log.error("SetupPod returns error %{public}@", String(describing: error)) - throw error - } - - guard versionResponse.isSetupPodVersionResponse else { - log.error("SetupPod unexpected VersionResponse type: %{public}@", String(describing: versionResponse)) - throw PodCommsError.invalidData - } - } - - func assignAddressAndSetupPod( - address: UInt32, - using deviceSelector: @escaping (_ completion: @escaping (_ device: RileyLinkDevice?) -> Void) -> Void, - timeZone: TimeZone, - messageLogger: MessageLogger?, - insulinType: InsulinType, - _ block: @escaping (_ result: SessionRunResult) -> Void) - { - deviceSelector { (device) in - guard let device = device else { - block(.failure(PodCommsError.noRileyLinkAvailable)) - return - } - - device.runSession(withName: "Pair Pod") { (commandSession) in - // Synchronize access to podState - self.podStateLock.lock() - defer { - self.podStateLock.unlock() - } - - do { - - self.configureDevice(device, with: commandSession) - - if self.podState == nil { - try self.assignAddress(address: address, commandSession: commandSession, insulinType: insulinType) - } - - guard self.podState != nil else { - block(.failure(PodCommsError.noPodPaired)) - return - } - - if self.podState!.setupProgress.isPaired == false { - try self.setupPod(podState: self.podState!, timeZone: timeZone, commandSession: commandSession, insulinType: insulinType) - } - - guard self.podState!.setupProgress.isPaired else { - self.log.error("Unexpected podStatus setupProgress value of %{public}@", String(describing: self.podState!.setupProgress)) - throw PodCommsError.invalidData - } - self.startingPacketNumber = 0 - - // Run a session now for any post-pairing commands - let transport = PodMessageTransport(session: commandSession, address: self.podState!.address, state: self.podState!.messageTransportState) - transport.messageLogger = self.messageLogger - let podSession = PodCommsSession(podState: self.podState!, transport: transport, delegate: self) - - block(.success(session: podSession)) - } catch let error as PodCommsError { - block(.failure(error)) - } catch { - block(.failure(PodCommsError.commsError(error: error))) - } - } - } - } - - enum SessionRunResult { - case success(session: PodCommsSession) - case failure(PodCommsError) - } - - func runSession(withName name: String, using deviceSelector: @escaping (_ completion: @escaping (_ device: RileyLinkDevice?) -> Void) -> Void, _ block: @escaping (_ result: SessionRunResult) -> Void) { - - deviceSelector { (device) in - guard let device = device else { - block(.failure(PodCommsError.noRileyLinkAvailable)) - return - } - - device.runSession(withName: name) { (commandSession) in - - // Synchronize access to podState - self.podStateLock.lock() - defer { - self.podStateLock.unlock() - } - - guard self.podState != nil else { - block(.failure(PodCommsError.noPodPaired)) - return - } - - self.configureDevice(device, with: commandSession) - let transport = PodMessageTransport(session: commandSession, address: self.podState!.address, state: self.podState!.messageTransportState) - transport.messageLogger = self.messageLogger - let podSession = PodCommsSession(podState: self.podState!, transport: transport, delegate: self) - block(.success(session: podSession)) - } - } - } - - // Must be called from within the RileyLinkDevice sessionQueue - private func configureDevice(_ device: RileyLinkDevice, with session: CommandSession) { - session.assertOnSessionQueue() - - guard !self.configuredDevices.value.contains(device.peripheralIdentifier) else { - return - } - - do { - log.debug("configureRadio (omnipod)") - _ = try session.configureRadio() - } catch let error { - log.error("configure Radio failed with error: %{public}@", String(describing: error)) - // Ignore the error and let the block run anyway - return - } - - NotificationCenter.default.post(name: .DeviceRadioConfigDidChange, object: device) - NotificationCenter.default.addObserver(self, selector: #selector(deviceRadioConfigDidChange(_:)), name: .DeviceRadioConfigDidChange, object: device) - NotificationCenter.default.addObserver(self, selector: #selector(deviceRadioConfigDidChange(_:)), name: .DeviceConnectionStateDidChange, object: device) - - log.debug("added device %{public}@ to configuredDevices", device.name ?? "unknown") - _ = configuredDevices.mutate { (value) in - value.insert(device.peripheralIdentifier) - } - } - - @objc private func deviceRadioConfigDidChange(_ note: Notification) { - guard let device = note.object as? RileyLinkDevice else { - return - } - log.debug("removing device %{public}@ from configuredDevices", device.name ?? "unknown") - - NotificationCenter.default.removeObserver(self, name: .DeviceRadioConfigDidChange, object: device) - NotificationCenter.default.removeObserver(self, name: .DeviceConnectionStateDidChange, object: device) - - _ = configuredDevices.mutate { (value) in - value.remove(device.peripheralIdentifier) - } - } - - // MARK: - CustomDebugStringConvertible - - var debugDescription: String { - return [ - "## PodComms", - "configuredDevices: \(configuredDevices.value.map { $0.uuidString })", - "delegate: \(String(describing: delegate != nil))", - "" - ].joined(separator: "\n") - } - -} - -extension PodComms: PodCommsSessionDelegate { - func podCommsSession(_ podCommsSession: PodCommsSession, didChange state: PodState) { - - // We should already be holding podStateLock during calls to this function, so try() should fail - assert(!podStateLock.try(), "\(#function) should be invoked while holding podStateLock") - - podCommsSession.assertOnSessionQueue() - self.podState = state - } -} - - -private extension CommandSession { - - func configureRadio() throws { - - // SYNC1 |0xDF00|0x54|Sync Word, High Byte - // SYNC0 |0xDF01|0xC3|Sync Word, Low Byte - // PKTLEN |0xDF02|0x32|Packet Length - // PKTCTRL1 |0xDF03|0x24|Packet Automation Control - // PKTCTRL0 |0xDF04|0x00|Packet Automation Control - // FSCTRL1 |0xDF07|0x06|Frequency Synthesizer Control - // FREQ2 |0xDF09|0x12|Frequency Control Word, High Byte - // FREQ1 |0xDF0A|0x14|Frequency Control Word, Middle Byte - // FREQ0 |0xDF0B|0x5F|Frequency Control Word, Low Byte - // MDMCFG4 |0xDF0C|0xCA|Modem configuration - // MDMCFG3 |0xDF0D|0xBC|Modem Configuration - // MDMCFG2 |0xDF0E|0x0A|Modem Configuration - // MDMCFG1 |0xDF0F|0x13|Modem Configuration - // MDMCFG0 |0xDF10|0x11|Modem Configuration - // MCSM0 |0xDF14|0x18|Main Radio Control State Machine Configuration - // FOCCFG |0xDF15|0x17|Frequency Offset Compensation Configuration - // AGCCTRL1 |0xDF18|0x70|AGC Control - // FSCAL3 |0xDF1C|0xE9|Frequency Synthesizer Calibration - // FSCAL2 |0xDF1D|0x2A|Frequency Synthesizer Calibration - // FSCAL1 |0xDF1E|0x00|Frequency Synthesizer Calibration - // FSCAL0 |0xDF1F|0x1F|Frequency Synthesizer Calibration - // TEST1 |0xDF24|0x31|Various Test Settings - // TEST0 |0xDF25|0x09|Various Test Settings - // PA_TABLE0 |0xDF2E|0x60|PA Power Setting 0 - // VERSION |0xDF37|0x04|Chip ID[7:0] - - try setSoftwareEncoding(.manchester) - try setPreamble(0x6665) - try setBaseFrequency(Measurement(value: 433.91, unit: .megahertz)) - try updateRegister(.pktctrl1, value: 0x20) - try updateRegister(.pktctrl0, value: 0x00) - try updateRegister(.fsctrl1, value: 0x06) - try updateRegister(.mdmcfg4, value: 0xCA) - try updateRegister(.mdmcfg3, value: 0xBC) // 0xBB for next lower bitrate - try updateRegister(.mdmcfg2, value: 0x06) - try updateRegister(.mdmcfg1, value: 0x70) - try updateRegister(.mdmcfg0, value: 0x11) - try updateRegister(.deviatn, value: 0x44) - try updateRegister(.mcsm0, value: 0x18) - try updateRegister(.foccfg, value: 0x17) - try updateRegister(.fscal3, value: 0xE9) - try updateRegister(.fscal2, value: 0x2A) - try updateRegister(.fscal1, value: 0x00) - try updateRegister(.fscal0, value: 0x1F) - - try updateRegister(.test1, value: 0x31) - try updateRegister(.test0, value: 0x09) - try updateRegister(.paTable0, value: 0x84) - try updateRegister(.sync1, value: 0xA5) - try updateRegister(.sync0, value: 0x5A) - } - - // This is just a testing function for spoofing PDM packets, or other times when you need to generate a custom packet - private func sendPacket() throws { - let packetNumber = 19 - let messageNumber = 0x24 >> 2 - let address: UInt32 = 0x1f0b3554 - - let cmd = GetStatusCommand(podInfoType: .normal) - - let message = Message(address: address, messageBlocks: [cmd], sequenceNum: messageNumber) - - var dataRemaining = message.encoded() - - let sendPacket = Packet(address: address, packetType: .pdm, sequenceNum: packetNumber, data: dataRemaining) - dataRemaining = dataRemaining.subdata(in: sendPacket.data.count..(_ messageBlocks: [MessageBlock], beepBlock: MessageBlock? = nil, expectFollowOnMessage: Bool = false) throws -> T { - - var triesRemaining = 2 // Retries only happen for nonce resync - var blocksToSend = messageBlocks - - // If a beep block was specified & pod isn't faulted, append the beep block to emit the confirmation beep - if let beepBlock = beepBlock, podState.isFaulted == false { - blocksToSend += [beepBlock] - } - - if blocksToSend.contains(where: { $0 as? NonceResyncableMessageBlock != nil }) { - podState.advanceToNextNonce() - } - - let messageNumber = transport.messageNumber - - var sentNonce: UInt32? - - while (triesRemaining > 0) { - triesRemaining -= 1 - - for command in blocksToSend { - if let nonceBlock = command as? NonceResyncableMessageBlock { - sentNonce = nonceBlock.nonce - break // N.B. all nonce commands in single message should have the same value - } - } - - let message = Message(address: podState.address, messageBlocks: blocksToSend, sequenceNum: messageNumber, expectFollowOnMessage: expectFollowOnMessage) - - self.podState.lastCommsOK = false // mark last comms as not OK until we get the expected response - let response = try transport.sendMessage(message) - - // Simulate fault - //let podInfoResponse = try PodInfoResponse(encodedData: Data(hexadecimalString: "0216020d0000000000ab6a038403ff03860000285708030d0000")!) - //let response = Message(address: podState.address, messageBlocks: [podInfoResponse], sequenceNum: message.sequenceNum) - - if let responseMessageBlock = response.messageBlocks[0] as? T { - log.info("POD Response: %{public}@", String(describing: responseMessageBlock)) - self.podState.lastCommsOK = true // message successfully sent and expected response received - return responseMessageBlock - } - - - if let fault = response.fault { - try throwPodFault(fault: fault) // always throws - } - - let responseType = response.messageBlocks[0].blockType - guard let errorResponse = response.messageBlocks[0] as? ErrorResponse else { - log.error("Unexpected response: %{public}@", String(describing: response.messageBlocks[0])) - throw PodCommsError.unexpectedResponse(response: responseType) - } - - switch errorResponse.errorResponseType { - case .badNonce(let nonceResyncKey): - guard let sentNonce = sentNonce else { - log.error("Unexpected bad nonce response: %{public}@", String(describing: response.messageBlocks[0])) - throw PodCommsError.unexpectedResponse(response: responseType) - } - podState.resyncNonce(syncWord: nonceResyncKey, sentNonce: sentNonce, messageSequenceNum: Int(message.sequenceNum)) - log.info("resyncNonce(syncWord: 0x%02x, sentNonce: 0x%04x, messageSequenceNum: %d) -> 0x%04x", nonceResyncKey, sentNonce, message.sequenceNum, podState.currentNonce) - blocksToSend = blocksToSend.map({ (block) -> MessageBlock in - if var resyncableBlock = block as? NonceResyncableMessageBlock { - log.info("Replaced old nonce 0x%04x with resync nonce 0x%04x", resyncableBlock.nonce, podState.currentNonce) - resyncableBlock.nonce = podState.currentNonce - return resyncableBlock - } - return block - }) - podState.advanceToNextNonce() - break - case .nonretryableError(let errorCode, let faultEventCode, let podProgress): - log.error("Command error: code %u, %{public}@, pod progress %{public}@", errorCode, String(describing: faultEventCode), String(describing: podProgress)) - throw PodCommsError.rejectedMessage(errorCode: errorCode) - } - } - throw PodCommsError.nonceResyncFailed - } - - // Returns time at which prime is expected to finish. - public func prime() throws -> TimeInterval { - let primeDuration: TimeInterval = .seconds(Pod.primeUnits / Pod.primeDeliveryRate) + 3 // as per PDM - - // If priming has never been attempted on this pod, handle the pre-prime setup tasks. - // A FaultConfig can only be done before the prime bolus or the pod will generate an 049 fault. - if podState.setupProgress.primingNeverAttempted { - // This FaultConfig command will set Tab5[$16] to 0 during pairing, which disables $6x faults - let _: StatusResponse = try send([FaultConfigCommand(nonce: podState.currentNonce, tab5Sub16: 0, tab5Sub17: 0)]) - - // Set up the finish pod setup reminder alert which beeps every 5 minutes for 1 hour - let finishSetupReminder = PodAlert.finishSetupReminder - try configureAlerts([finishSetupReminder]) - } else { - // Not the first time through, check to see if prime bolus was successfully started - let status: StatusResponse = try send([GetStatusCommand()]) - podState.updateFromStatusResponse(status, at: currentDate) - if status.podProgressStatus == .priming || status.podProgressStatus == .primingCompleted { - podState.setupProgress = .priming - return podState.primeFinishTime?.timeIntervalSinceNow ?? primeDuration - } - } - - // Mark Pod.primeUnits (2.6U) bolus delivery with Pod.primeDeliveryRate (1) between pulses for prime - - let primeFinishTime = currentDate + primeDuration - podState.primeFinishTime = primeFinishTime - podState.setupProgress = .startingPrime - - let timeBetweenPulses = TimeInterval(seconds: Pod.secondsPerPrimePulse) - let scheduleCommand = SetInsulinScheduleCommand(nonce: podState.currentNonce, units: Pod.primeUnits, timeBetweenPulses: timeBetweenPulses) - let bolusExtraCommand = BolusExtraCommand(units: Pod.primeUnits, timeBetweenPulses: timeBetweenPulses) - let status: StatusResponse = try send([scheduleCommand, bolusExtraCommand]) - podState.updateFromStatusResponse(status, at: currentDate) - podState.setupProgress = .priming - return primeFinishTime.timeIntervalSinceNow - } - - public func programInitialBasalSchedule(_ basalSchedule: BasalSchedule, scheduleOffset: TimeInterval) throws { - if podState.setupProgress == .settingInitialBasalSchedule { - // We started basal schedule programming, but didn't get confirmation somehow, so check status - let status: StatusResponse = try send([GetStatusCommand()]) - podState.updateFromStatusResponse(status, at: currentDate) - if status.podProgressStatus == .basalInitialized { - podState.setupProgress = .initialBasalScheduleSet - podState.finalizedDoses.append(UnfinalizedDose(resumeStartTime: currentDate, scheduledCertainty: .certain, insulinType: podState.insulinType)) - return - } - } - - podState.setupProgress = .settingInitialBasalSchedule - // Set basal schedule - let _ = try setBasalSchedule(schedule: basalSchedule, scheduleOffset: scheduleOffset) - podState.setupProgress = .initialBasalScheduleSet - podState.finalizedDoses.append(UnfinalizedDose(resumeStartTime: currentDate, scheduledCertainty: .certain, insulinType: podState.insulinType)) - } - - // Configures the given pod alert(s) and registers the newly configured alert slot(s). - // When re-configuring all the pod alerts for a silence pod toggle, the optional acknowledgeAll can be - // specified to first acknowledge and clear all possible pending pod alerts and pod alert configurations. - @discardableResult - func configureAlerts(_ alerts: [PodAlert], acknowledgeAll: Bool = false, beepBlock: MessageBlock? = nil) throws -> StatusResponse { - let configurations = alerts.map { $0.configuration } - let configureAlerts = ConfigureAlertsCommand(nonce: podState.currentNonce, configurations: configurations) - let blocksToSend: [MessageBlock] - if acknowledgeAll { - // Do the acknowledgeAllAlerts command first to clear all previous pod alert configurations. - let acknowledgeAllAlerts = AcknowledgeAlertCommand(nonce: podState.currentNonce, alerts: AlertSet(rawValue: ~0)) - blocksToSend = [acknowledgeAllAlerts, configureAlerts] - } else { - blocksToSend = [configureAlerts] - } - let status: StatusResponse = try send(blocksToSend, beepBlock: beepBlock) - for alert in alerts { - podState.registerConfiguredAlert(slot: alert.configuration.slot, alert: alert) - } - podState.updateFromStatusResponse(status, at: currentDate) - return status - } - - // emits the specified beep type and sets the completion beep flags, doesn't throw - public func beepConfig(beepType: BeepType, tempBasalCompletionBeep: Bool, bolusCompletionBeep: Bool) -> Result { - if let fault = self.podState.fault { - log.info("Skip beep config with faulted pod") - return .failure(PodCommsError.podFault(fault: fault)) - } - - let beepConfigCommand = BeepConfigCommand(beepType: beepType, tempBasalCompletionBeep: tempBasalCompletionBeep, bolusCompletionBeep: bolusCompletionBeep) - do { - let statusResponse: StatusResponse = try send([beepConfigCommand]) - podState.updateFromStatusResponse(statusResponse, at: currentDate) - return .success(statusResponse) - } catch let error { - return .failure(error) - } - } - - private func markSetupProgressCompleted(statusResponse: StatusResponse) { - if (podState.setupProgress != .completed) { - podState.setupProgress = .completed - podState.setupUnitsDelivered = statusResponse.insulinDelivered // stash the current insulin delivered value as the baseline - log.info("Total setup units delivered: %@", String(describing: statusResponse.insulinDelivered)) - } - } - - public func insertCannula(optionalAlerts: [PodAlert] = [], silent: Bool) throws -> TimeInterval { - let cannulaInsertionUnits = Pod.cannulaInsertionUnits + Pod.cannulaInsertionUnitsExtra - let insertionWait: TimeInterval = .seconds(cannulaInsertionUnits / Pod.primeDeliveryRate) - - guard podState.activatedAt != nil else { - throw PodCommsError.noPodPaired - } - - if podState.setupProgress == .startingInsertCannula || podState.setupProgress == .cannulaInserting { - // We started cannula insertion, but didn't get confirmation somehow, so check status - let status: StatusResponse = try send([GetStatusCommand()]) - if status.podProgressStatus == .insertingCannula { - podState.setupProgress = .cannulaInserting - podState.updateFromStatusResponse(status, at: currentDate) - return insertionWait // Not sure when it started, wait full time to be sure - } - if status.podProgressStatus.readyForDelivery { - markSetupProgressCompleted(statusResponse: status) - podState.updateFromStatusResponse(status, at: currentDate) - return TimeInterval(0) // Already done; no need to wait - } - podState.updateFromStatusResponse(status, at: currentDate) - } else { - let elapsed: TimeInterval = -(podState.podTimeUpdated?.timeIntervalSinceNow ?? 0) - let podTime = podState.podTime + elapsed - - // Configure the mandatory Pod Alerts for shutdown imminent alert (79 hours) and pod expiration alert (72 hours) along with any optional alerts - let shutdownImminentAlarm = PodAlert.shutdownImminent(offset: podTime, absAlertTime: Pod.serviceDuration - Pod.endOfServiceImminentWindow, silent: silent) - let expirationAdvisoryAlarm = PodAlert.expired(offset: podTime, absAlertTime: Pod.nominalPodLife, duration: Pod.expirationAdvisoryWindow, silent: silent) - try configureAlerts([expirationAdvisoryAlarm, shutdownImminentAlarm] + optionalAlerts) - } - - // Mark cannulaInsertionUnits (0.5U) bolus delivery with Pod.secondsPerPrimePulse (1) between pulses for cannula insertion - - let timeBetweenPulses = TimeInterval(seconds: Pod.secondsPerPrimePulse) - let bolusScheduleCommand = SetInsulinScheduleCommand(nonce: podState.currentNonce, units: cannulaInsertionUnits, timeBetweenPulses: timeBetweenPulses) - - podState.setupProgress = .startingInsertCannula - let bolusExtraCommand = BolusExtraCommand(units: cannulaInsertionUnits, timeBetweenPulses: timeBetweenPulses) - let status2: StatusResponse = try send([bolusScheduleCommand, bolusExtraCommand]) - podState.updateFromStatusResponse(status2, at: currentDate) - - podState.setupProgress = .cannulaInserting - return insertionWait - } - - public func checkInsertionCompleted() throws { - if podState.setupProgress == .cannulaInserting { - let response: StatusResponse = try send([GetStatusCommand()]) - if response.podProgressStatus.readyForDelivery { - markSetupProgressCompleted(statusResponse: response) - } - podState.updateFromStatusResponse(response, at: currentDate) - } - } - - // Throws SetBolusError - public enum DeliveryCommandResult { - case success(statusResponse: StatusResponse) - case certainFailure(error: PodCommsError) - case unacknowledged(error: PodCommsError) - } - - public enum CancelDeliveryResult { - case success(statusResponse: StatusResponse, canceledDose: UnfinalizedDose?) - case certainFailure(error: PodCommsError) - case unacknowledged(error: PodCommsError) - } - - - public func bolus(units: Double, automatic: Bool = false, acknowledgementBeep: Bool = false, completionBeep: Bool = false, programReminderInterval: TimeInterval = 0, extendedUnits: Double = 0.0, extendedDuration: TimeInterval = 0) -> DeliveryCommandResult { - - guard podState.unacknowledgedCommand == nil else { - return DeliveryCommandResult.certainFailure(error: .unacknowledgedCommandPending) - } - - let timeBetweenPulses = TimeInterval(seconds: Pod.secondsPerBolusPulse) - let bolusScheduleCommand = SetInsulinScheduleCommand(nonce: podState.currentNonce, units: units, timeBetweenPulses: timeBetweenPulses, extendedUnits: extendedUnits, extendedDuration: extendedDuration) - - // Do a getstatus to verify that there isn't an on-going bolus in progress if the last bolus command is still - // finalized, if the last delivery status wasn't successfully verified or the last comms attempt wasn't OK - if podState.unfinalizedBolus != nil || !podState.deliveryStatusVerified || !podState.lastCommsOK { - var ongoingBolus = true - if let statusResponse: StatusResponse = try? send([GetStatusCommand()]) { - podState.updateFromStatusResponse(statusResponse, at: currentDate) - ongoingBolus = podState.unfinalizedBolus != nil - } - guard !ongoingBolus else { - return DeliveryCommandResult.certainFailure(error: .unfinalizedBolus) - } - } - - let bolusExtraCommand = BolusExtraCommand(units: units, timeBetweenPulses: timeBetweenPulses, extendedUnits: extendedUnits, extendedDuration: extendedDuration, acknowledgementBeep: acknowledgementBeep, completionBeep: completionBeep, programReminderInterval: programReminderInterval) - do { - podState.unacknowledgedCommand = PendingCommand.program(.bolus(volume: units, automatic: automatic), transport.messageNumber, currentDate) - let statusResponse: StatusResponse = try send([bolusScheduleCommand, bolusExtraCommand]) - podState.unacknowledgedCommand = nil - podState.unfinalizedBolus = UnfinalizedDose(bolusAmount: units, startTime: currentDate, scheduledCertainty: .certain, insulinType: podState.insulinType, automatic: automatic) - podState.updateFromStatusResponse(statusResponse, at: currentDate) - return DeliveryCommandResult.success(statusResponse: statusResponse) - } catch PodCommsError.unacknowledgedMessage(let seq, let error) { - podState.unacknowledgedCommand = podState.unacknowledgedCommand?.commsFinished - log.error("Unacknowledged bolus: command seq = %d, error = %{public}@", seq, String(describing: error)) - return DeliveryCommandResult.unacknowledged(error: .commsError(error: error)) - } catch let error { - podState.unacknowledgedCommand = nil - return DeliveryCommandResult.certainFailure(error: .commsError(error: error)) - } - } - - public func setTempBasal(rate: Double, duration: TimeInterval, isHighTemp: Bool, automatic: Bool, acknowledgementBeep: Bool = false, completionBeep: Bool = false, programReminderInterval: TimeInterval = 0) -> DeliveryCommandResult { - - guard podState.unacknowledgedCommand == nil else { - return DeliveryCommandResult.certainFailure(error: .unacknowledgedCommandPending) - } - - let tempBasalCommand = SetInsulinScheduleCommand(nonce: podState.currentNonce, tempBasalRate: rate, duration: duration) - let tempBasalExtraCommand = TempBasalExtraCommand(rate: rate, duration: duration, acknowledgementBeep: acknowledgementBeep, completionBeep: completionBeep, programReminderInterval: programReminderInterval) - - guard podState.unfinalizedBolus?.isFinished() != false else { - return DeliveryCommandResult.certainFailure(error: .unfinalizedBolus) - } - - let startTime = currentDate - - do { - podState.unacknowledgedCommand = PendingCommand.program(.tempBasal(unitsPerHour: rate, duration: duration, isHighTemp: isHighTemp, automatic: automatic), transport.messageNumber, startTime) - let status: StatusResponse = try send([tempBasalCommand, tempBasalExtraCommand]) - podState.unacknowledgedCommand = nil - podState.unfinalizedTempBasal = UnfinalizedDose(tempBasalRate: rate, startTime: startTime, duration: duration, isHighTemp: isHighTemp, automatic: automatic, scheduledCertainty: .certain, insulinType: podState.insulinType) - podState.updateFromStatusResponse(status, at: currentDate) - return DeliveryCommandResult.success(statusResponse: status) - } catch PodCommsError.unacknowledgedMessage(let seq, let error) { - podState.unacknowledgedCommand = podState.unacknowledgedCommand?.commsFinished - log.error("Unacknowledged temp basal: command seq = %d, error = %{public}@", seq, String(describing: error)) - return DeliveryCommandResult.unacknowledged(error: .commsError(error: error)) - } catch let error { - podState.unacknowledgedCommand = nil - return DeliveryCommandResult.certainFailure(error: .commsError(error: error)) - } - } - - @discardableResult - private func handleCancelDosing(deliveryType: CancelDeliveryCommand.DeliveryType, bolusNotDelivered: Double) -> UnfinalizedDose? { - var canceledDose: UnfinalizedDose? = nil - let now = currentDate - - if deliveryType.contains(.basal) { - podState.unfinalizedSuspend = UnfinalizedDose(suspendStartTime: now, scheduledCertainty: .certain) - podState.suspendState = .suspended(now) - } - - if let unfinalizedTempBasal = podState.unfinalizedTempBasal, - let finishTime = unfinalizedTempBasal.finishTime, - deliveryType.contains(.tempBasal), - finishTime > now - { - podState.unfinalizedTempBasal?.cancel(at: now) - if !deliveryType.contains(.basal) { - podState.suspendState = .resumed(now) - } - canceledDose = podState.unfinalizedTempBasal - log.info("Interrupted temp basal: %@", String(describing: canceledDose)) - } - - if let unfinalizedBolus = podState.unfinalizedBolus, - let finishTime = unfinalizedBolus.finishTime, - deliveryType.contains(.bolus), - finishTime > now - { - podState.unfinalizedBolus?.cancel(at: now, withRemaining: bolusNotDelivered) - canceledDose = podState.unfinalizedBolus - log.info("Interrupted bolus: %@", String(describing: canceledDose)) - } - - return canceledDose - } - - // Suspends insulin delivery and sets appropriate podSuspendedReminder & suspendTimeExpired alerts. - // A nil suspendReminder is an untimed suspend with no suspend reminders. - // A suspendReminder of 0 is an untimed suspend which only uses podSuspendedReminder alert beeps. - // A suspendReminder of 1-5 minutes will only use suspendTimeExpired alert beeps. - // A suspendReminder of > 5 min will have periodic podSuspendedReminder beeps followed by suspendTimeExpired alerts. - // The configured alerts will set up as silent pod alerts if silent is true. - public func suspendDelivery(suspendReminder: TimeInterval? = nil, silent: Bool, beepBlock: MessageBlock? = nil) -> CancelDeliveryResult { - - guard podState.unacknowledgedCommand == nil else { - return .certainFailure(error: .unacknowledgedCommandPending) - } - - do { - var alertConfigurations: [AlertConfiguration] = [] - var podSuspendedReminderAlert: PodAlert? = nil - var suspendTimeExpiredAlert: PodAlert? = nil - let suspendTime: TimeInterval = suspendReminder != nil ? suspendReminder! : 0 - let elapsed: TimeInterval = -(podState.podTimeUpdated?.timeIntervalSinceNow ?? 0) - let podTime = podState.podTime + elapsed - log.debug("suspendDelivery: podState.podTime=%@, elapsed=%.2fs, computed timeActive %@", podState.podTime.timeIntervalStr, elapsed, podTime.timeIntervalStr) - - let cancelDeliveryCommand = CancelDeliveryCommand(nonce: podState.currentNonce, deliveryType: .all, beepType: .noBeepCancel) - var commandsToSend: [MessageBlock] = [cancelDeliveryCommand] - - // podSuspendedReminder provides a periodic pod suspended reminder beep until the specified suspend time. - if suspendReminder != nil && (suspendTime == 0 || suspendTime > .minutes(5)) { - // using reminder beeps for an untimed or long enough suspend time requiring pod suspended reminders - podSuspendedReminderAlert = PodAlert.podSuspendedReminder(active: true, offset: podTime, suspendTime: suspendTime, silent: silent) - alertConfigurations += [podSuspendedReminderAlert!.configuration] - } - - // suspendTimeExpired provides suspend time expired alert beeping after the expected suspend time has passed. - if suspendTime > 0 { - // a timed suspend using a suspend time expired alert - suspendTimeExpiredAlert = PodAlert.suspendTimeExpired(offset: podTime, suspendTime: suspendTime, silent: silent) - alertConfigurations += [suspendTimeExpiredAlert!.configuration] - } - - // append a ConfigureAlert command if we have any reminder alerts for this suspend - if alertConfigurations.count != 0 { - let configureAlerts = ConfigureAlertsCommand(nonce: podState.currentNonce, configurations: alertConfigurations) - commandsToSend += [configureAlerts] - } - - podState.unacknowledgedCommand = PendingCommand.stopProgram(.all, transport.messageNumber, currentDate) - let status: StatusResponse = try send(commandsToSend, beepBlock: beepBlock) - podState.unacknowledgedCommand = nil - let canceledDose = handleCancelDosing(deliveryType: .all, bolusNotDelivered: status.bolusNotDelivered) - podState.updateFromStatusResponse(status, at: currentDate) - - if let alert = podSuspendedReminderAlert { - podState.registerConfiguredAlert(slot: alert.configuration.slot, alert: alert) - } - if let alert = suspendTimeExpiredAlert { - podState.registerConfiguredAlert(slot: alert.configuration.slot, alert: alert) - } - - return CancelDeliveryResult.success(statusResponse: status, canceledDose: canceledDose) - - } catch PodCommsError.unacknowledgedMessage(let seq, let error) { - podState.unacknowledgedCommand = podState.unacknowledgedCommand?.commsFinished - log.error("Unacknowledged suspend: command seq = %d, error = %{public}@", seq, String(describing: error)) - return .unacknowledged(error: .commsError(error: error)) - } catch let error { - podState.unacknowledgedCommand = nil - return .certainFailure(error: .commsError(error: error)) - } - } - - // Cancels any suspend related alerts, called when setting a basal schedule with active suspend alerts - @discardableResult - private func cancelSuspendAlerts() throws -> StatusResponse { - - do { - let podSuspendedReminder = PodAlert.podSuspendedReminder(active: false, offset: 0, suspendTime: 0) - let suspendTimeExpired = PodAlert.suspendTimeExpired(offset: 0, suspendTime: 0) // A suspendTime of 0 deactivates this alert - - let status = try configureAlerts([podSuspendedReminder, suspendTimeExpired]) - return status - } catch let error { - throw error - } - } - - // Cancel beeping can be done implemented using beepType (for a single delivery type) or a separate confirmation beep message block (for cancel all). - // N.B., Using the built-in cancel delivery command beepType method when cancelling all insulin delivery will emit 3 different sets of cancel beeps!!! - public func cancelDelivery(deliveryType: CancelDeliveryCommand.DeliveryType, beepType: BeepType = .noBeepCancel, beepBlock: MessageBlock? = nil) -> CancelDeliveryResult { - - guard podState.unacknowledgedCommand == nil else { - return .certainFailure(error: .unacknowledgedCommandPending) - } - - do { - podState.unacknowledgedCommand = PendingCommand.stopProgram(deliveryType, transport.messageNumber, currentDate) - let cancelDeliveryCommand = CancelDeliveryCommand(nonce: podState.currentNonce, deliveryType: deliveryType, beepType: beepType) - let status: StatusResponse = try send([cancelDeliveryCommand], beepBlock: beepBlock) - podState.unacknowledgedCommand = nil - - let canceledDose = handleCancelDosing(deliveryType: deliveryType, bolusNotDelivered: status.bolusNotDelivered) - podState.updateFromStatusResponse(status, at: currentDate) - - return CancelDeliveryResult.success(statusResponse: status, canceledDose: canceledDose) - } catch PodCommsError.unacknowledgedMessage(let seq, let error) { - podState.unacknowledgedCommand = podState.unacknowledgedCommand?.commsFinished - log.debug("Unacknowledged stop program: command seq = %d", seq) - return .unacknowledged(error: .commsError(error: error)) - } catch let error { - podState.unacknowledgedCommand = nil - return .certainFailure(error: .commsError(error: error)) - } - } - - public func setTime(timeZone: TimeZone, basalSchedule: BasalSchedule, date: Date, acknowledgementBeep: Bool = false) throws -> StatusResponse { - guard podState.unacknowledgedCommand == nil else { - throw PodCommsError.unacknowledgedCommandPending - } - - let result = cancelDelivery(deliveryType: .all) - switch result { - case .certainFailure(let error): - throw error - case .unacknowledged(let error): - throw error - case .success: - let scheduleOffset = timeZone.scheduleOffset(forDate: date) - let status = try setBasalSchedule(schedule: basalSchedule, scheduleOffset: scheduleOffset, acknowledgementBeep: acknowledgementBeep) - return status - } - } - - public func setBasalSchedule(schedule: BasalSchedule, scheduleOffset: TimeInterval, acknowledgementBeep: Bool = false, programReminderInterval: TimeInterval = 0) throws -> StatusResponse { - - guard podState.unacknowledgedCommand == nil else { - throw PodCommsError.unacknowledgedCommandPending - } - - let basalScheduleCommand = SetInsulinScheduleCommand(nonce: podState.currentNonce, basalSchedule: schedule, scheduleOffset: scheduleOffset) - let basalExtraCommand = BasalScheduleExtraCommand.init(schedule: schedule, scheduleOffset: scheduleOffset, acknowledgementBeep: acknowledgementBeep, programReminderInterval: programReminderInterval) - - do { - if podState.setupProgress == .completed && !(podState.lastCommsOK && podState.deliveryStatusVerified) { - // The pod setup is complete and the current delivery state can't be trusted so - // do a cancel all to be sure that setting the basal program won't fault the pod. - let _: StatusResponse = try send([CancelDeliveryCommand(nonce: podState.currentNonce, deliveryType: .all, beepType: .noBeepCancel)]) - } - var status: StatusResponse = try send([basalScheduleCommand, basalExtraCommand]) - let now = currentDate - podState.suspendState = .resumed(now) - podState.unfinalizedResume = UnfinalizedDose(resumeStartTime: now, scheduledCertainty: .certain, insulinType: podState.insulinType) - if hasActiveSuspendAlert(configuredAlerts: podState.configuredAlerts), - let cancelStatus = try? cancelSuspendAlerts() - { - status = cancelStatus // update using the latest status - } - podState.updateFromStatusResponse(status, at: currentDate) - return status - } catch PodCommsError.nonceResyncFailed { - throw PodCommsError.nonceResyncFailed - } catch PodCommsError.rejectedMessage(let errorCode) { - throw PodCommsError.rejectedMessage(errorCode: errorCode) - } catch let error { - podState.unfinalizedResume = UnfinalizedDose(resumeStartTime: currentDate, scheduledCertainty: .uncertain, insulinType: podState.insulinType) - throw error - } - } - - public func resumeBasal(schedule: BasalSchedule, scheduleOffset: TimeInterval, acknowledgementBeep: Bool = false, completionBeep: Bool = false, programReminderInterval: TimeInterval = 0) throws -> StatusResponse { - - guard podState.unacknowledgedCommand == nil else { - throw PodCommsError.unacknowledgedCommandPending - } - - - let status = try setBasalSchedule(schedule: schedule, scheduleOffset: scheduleOffset, acknowledgementBeep: acknowledgementBeep, programReminderInterval: programReminderInterval) - - podState.suspendState = .resumed(currentDate) - - return status - } - - // use cancelDelivery with .none to get status as well as to validate & advance the nonce - // Throws PodCommsError - @discardableResult - public func cancelNone(beepBlock: MessageBlock? = nil) throws -> StatusResponse { - var statusResponse: StatusResponse - - let cancelResult: CancelDeliveryResult = cancelDelivery(deliveryType: .none, beepBlock: beepBlock) - switch cancelResult { - case .certainFailure(let error): - throw error - case .unacknowledged(let error): - throw error - case .success(let response, _): - statusResponse = response - } - podState.updateFromStatusResponse(statusResponse, at: currentDate) - return statusResponse - } - - // Throws PodCommsError - @discardableResult - public func getStatus(beepBlock: MessageBlock? = nil) throws -> StatusResponse { - let statusResponse: StatusResponse = try send([GetStatusCommand()], beepBlock: beepBlock) - - if podState.unacknowledgedCommand != nil { - recoverUnacknowledgedCommand(using: statusResponse) - } - podState.updateFromStatusResponse(statusResponse, at: currentDate) - return statusResponse - } - - @discardableResult - public func getDetailedStatus(beepBlock: MessageBlock? = nil) throws -> DetailedStatus { - let infoResponse: PodInfoResponse = try send([GetStatusCommand(podInfoType: .detailedStatus)], beepBlock: beepBlock) - - guard let detailedStatus = infoResponse.podInfo as? DetailedStatus else { - throw PodCommsError.unexpectedResponse(response: .podInfoResponse) - } - if detailedStatus.isFaulted && self.podState.fault == nil { - // just detected that the pod has faulted, handle setting the fault state but don't throw - handlePodFault(fault: detailedStatus) - } else { - let derivedStatusResponse = StatusResponse(detailedStatus: detailedStatus) - if podState.unacknowledgedCommand != nil { - recoverUnacknowledgedCommand(using: derivedStatusResponse) - } - podState.updateFromStatusResponse(derivedStatusResponse, at: currentDate) - } - return detailedStatus - } - - @discardableResult - public func readPodInfo(podInfoResponseSubType: PodInfoResponseSubType, beepBlock: MessageBlock? = nil) throws -> PodInfoResponse { - let podInfoCommand = GetStatusCommand(podInfoType: podInfoResponseSubType) - let podInfoResponse: PodInfoResponse = try send([podInfoCommand], beepBlock: beepBlock) - return podInfoResponse - } - - // Reconnected to the pod, and we know program was successful - private func unacknowledgedCommandWasReceived(pendingCommand: PendingCommand, podStatus: StatusResponse) { - switch pendingCommand { - case .program(let program, _, let commandDate, _): - if let dose = program.unfinalizedDose(at: commandDate, withCertainty: .certain, insulinType: podState.insulinType) { - switch dose.doseType { - case .bolus: - podState.unfinalizedBolus = dose - case .tempBasal: - podState.unfinalizedTempBasal = dose - case .resume: - podState.suspendState = .resumed(commandDate) - default: - break - } - } - case .stopProgram(let stopProgram, _, let commandDate, _): - - if stopProgram.contains(.bolus), let bolus = podState.unfinalizedBolus, !bolus.isFinished(at: commandDate) { - podState.unfinalizedBolus?.cancel(at: commandDate, withRemaining: podStatus.bolusNotDelivered) - } - if stopProgram.contains(.tempBasal), let tempBasal = podState.unfinalizedTempBasal, !tempBasal.isFinished(at: commandDate) { - podState.unfinalizedTempBasal?.cancel(at: commandDate) - } - if stopProgram.contains(.basal) { - podState.finalizedDoses.append(UnfinalizedDose(suspendStartTime: commandDate, scheduledCertainty: .certain)) - podState.suspendState = .suspended(commandDate) - } - } - } - - public func recoverUnacknowledgedCommand(using status: StatusResponse) { - if let pendingCommand = podState.unacknowledgedCommand { - self.log.default("Recovering from unacknowledged command %{public}@, status = %{public}@", String(describing: pendingCommand), String(describing: status)) - - if status.lastProgrammingMessageSeqNum == pendingCommand.sequence { - self.log.default("Unacknowledged command was received by pump") - unacknowledgedCommandWasReceived(pendingCommand: pendingCommand, podStatus: status) - } else { - self.log.default("Unacknowledged command was not received by pump") - } - podState.unacknowledgedCommand = nil - } - } - - // Can be called a second time to deactivate a given pod - public func deactivatePod() throws { - - // Don't try to cancel if the pod hasn't completed its setup as it will either receive no response - // (pod progress state <= 2) or creates a $31 pod fault (pod progress states 3 through 7). - if podState.setupProgress == .completed && podState.fault == nil && !podState.isSuspended { - let result = cancelDelivery(deliveryType: .all) - switch result { - case .certainFailure(let error): - throw error - case .unacknowledged(let error): - throw error - default: - break - } - } - - // Try to read the most recent pulse log entries for possible later analysis - _ = try? readPodInfo(podInfoResponseSubType: .pulseLogRecent) - if podState.fault != nil { - // Try to read the previous pulse log entries on the faulted pod - _ = try? readPodInfo(podInfoResponseSubType: .pulseLogPrevious) - } - - do { - let deactivatePod = DeactivatePodCommand(nonce: podState.currentNonce) - let status: StatusResponse = try send([deactivatePod]) - - if podState.unacknowledgedCommand != nil { - recoverUnacknowledgedCommand(using: status) - } - - podState.updateFromStatusResponse(status, at: currentDate) - - if podState.activeTime == nil, let activatedAt = podState.activatedAt { - podState.activeTime = currentDate.timeIntervalSince(activatedAt) - } - } catch let error as PodCommsError { - switch error { - case .podFault, .activationTimeExceeded, .unexpectedResponse: - break - default: - throw error - } - } - } - - public func acknowledgeAlerts(alerts: AlertSet, beepBlock: MessageBlock? = nil) throws -> AlertSet { - let cmd = AcknowledgeAlertCommand(nonce: podState.currentNonce, alerts: alerts) - let status: StatusResponse = try send([cmd], beepBlock: beepBlock) - podState.updateFromStatusResponse(status, at: currentDate) - return podState.activeAlertSlots - } - - func dosesForStorage(_ storageHandler: ([UnfinalizedDose]) -> Bool) { - assertOnSessionQueue() - - let dosesToStore = podState.dosesToStore - - if storageHandler(dosesToStore) { - log.info("Stored doses: %@", String(describing: dosesToStore)) - self.podState.finalizedDoses.removeAll() - } - } - - public func assertOnSessionQueue() { - transport.assertOnSessionQueue() - } -} - -extension PodCommsSession: MessageTransportDelegate { - func messageTransport(_ messageTransport: MessageTransport, didUpdate state: MessageTransportState) { - messageTransport.assertOnSessionQueue() - podState.messageTransportState = state - } -} diff --git a/Dependencies/OmniKit/OmniKit/PumpManager/PodState.swift b/Dependencies/OmniKit/OmniKit/PumpManager/PodState.swift deleted file mode 100644 index 48622a1fb..000000000 --- a/Dependencies/OmniKit/OmniKit/PumpManager/PodState.swift +++ /dev/null @@ -1,692 +0,0 @@ -// -// PodState.swift -// OmniKit -// -// Created by Pete Schwamb on 10/13/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation -import LoopKit - -public enum SetupProgress: Int { - case addressAssigned = 0 - case podPaired - case startingPrime - case priming - case settingInitialBasalSchedule - case initialBasalScheduleSet - case startingInsertCannula - case cannulaInserting - case completed - case activationTimeout - case podIncompatible - - public var isPaired: Bool { - return self.rawValue >= SetupProgress.podPaired.rawValue - } - - public var primingNeverAttempted: Bool { - return self.rawValue < SetupProgress.startingPrime.rawValue - } - - public var primingNeeded: Bool { - return self.rawValue < SetupProgress.priming.rawValue - } - - public var needsInitialBasalSchedule: Bool { - return self.rawValue < SetupProgress.initialBasalScheduleSet.rawValue - } - - public var needsCannulaInsertion: Bool { - return self.rawValue < SetupProgress.completed.rawValue - } -} - -// TODO: Mutating functions aren't guaranteed to synchronize read/write calls. -// mutating funcs should be moved to something like this: -// extension Locked where T == PodState { -// } -public struct PodState: RawRepresentable, Equatable, CustomDebugStringConvertible { - - public typealias RawValue = [String: Any] - - public let address: UInt32 - fileprivate var nonceState: NonceState - - public var activatedAt: Date? - public var expiresAt: Date? // set based on timeActive and can change with Pod clock drift and/or system time change - public var activeTime: TimeInterval? // Useful after pod deactivated or faulted. - - public var podTime: TimeInterval // pod time from the last response, always whole minute values - public var podTimeUpdated: Date? // time that the podTime value was last updated - - public var setupUnitsDelivered: Double? - - public let pmVersion: String - public let piVersion: String - public let lot: UInt32 - public let tid: UInt32 - public var activeAlertSlots: AlertSet - public var lastInsulinMeasurements: PodInsulinMeasurements? - - public var unacknowledgedCommand: PendingCommand? - - public var unfinalizedBolus: UnfinalizedDose? - public var unfinalizedTempBasal: UnfinalizedDose? - public var unfinalizedSuspend: UnfinalizedDose? - public var unfinalizedResume: UnfinalizedDose? - - var finalizedDoses: [UnfinalizedDose] - - public var dosesToStore: [UnfinalizedDose] { - return finalizedDoses + [unfinalizedTempBasal, unfinalizedSuspend, unfinalizedBolus].compactMap {$0} - } - - public var suspendState: SuspendState - - public var isSuspended: Bool { - if case .suspended = suspendState { - return true - } - return false - } - - public var fault: DetailedStatus? - public var messageTransportState: MessageTransportState - public var primeFinishTime: Date? - public var setupProgress: SetupProgress - public var configuredAlerts: [AlertSlot: PodAlert] - public var insulinType: InsulinType - - // Allow a grace period while the unacknowledged command is first being sent. - public var needsCommsRecovery: Bool { - if let unacknowledgedCommand = unacknowledgedCommand, !unacknowledgedCommand.isInFlight { - return true - } - return false - } - - // the following two vars are not persistent across app restarts - public var deliveryStatusVerified: Bool - public var lastCommsOK: Bool - - public init(address: UInt32, pmVersion: String, piVersion: String, lot: UInt32, tid: UInt32, packetNumber: Int = 0, messageNumber: Int = 0, insulinType: InsulinType) { - self.address = address - self.nonceState = NonceState(lot: lot, tid: tid) - self.pmVersion = pmVersion - self.piVersion = piVersion - self.lot = lot - self.tid = tid - self.lastInsulinMeasurements = nil - self.finalizedDoses = [] - self.suspendState = .resumed(Date()) - self.fault = nil - self.activeAlertSlots = .none - self.messageTransportState = MessageTransportState(packetNumber: packetNumber, messageNumber: messageNumber) - self.primeFinishTime = nil - self.setupProgress = .addressAssigned - self.configuredAlerts = [.slot7Expired: .waitingForPairingReminder] - self.insulinType = insulinType - self.deliveryStatusVerified = false - self.lastCommsOK = false - self.podTime = 0 - } - - public var unfinishedSetup: Bool { - return setupProgress != .completed - } - - public var readyForCannulaInsertion: Bool { - guard let primeFinishTime = self.primeFinishTime else { - return false - } - return !setupProgress.primingNeeded && primeFinishTime.timeIntervalSinceNow < 0 - } - - public var isActive: Bool { - return setupProgress == .completed && fault == nil - } - - // variation on isActive that doesn't care if Pod is faulted - public var isSetupComplete: Bool { - return setupProgress == .completed - } - - public var isFaulted: Bool { - return fault != nil || setupProgress == .activationTimeout || setupProgress == .podIncompatible - } - - public mutating func advanceToNextNonce() { - nonceState.advanceToNextNonce() - } - - public var currentNonce: UInt32 { - return nonceState.currentNonce - } - - public mutating func resyncNonce(syncWord: UInt16, sentNonce: UInt32, messageSequenceNum: Int) { - let sum = (sentNonce & 0xffff) + UInt32(crc16Table[messageSequenceNum]) + (lot & 0xffff) + (tid & 0xffff) - let seed = UInt16(sum & 0xffff) ^ syncWord - nonceState = NonceState(lot: lot, tid: tid, seed: seed) - } - - // Saves the current pod timeActive and will initialize the activatedAtComputed at - // pod startup and updates the expiresAt value to account for pod clock differences. - private mutating func updatePodTimes(timeActive: TimeInterval) -> Date { - let now = Date() - - guard timeActive >= self.podTime else { - // The pod active time went backwards and thus we have an apparent reset fault. - // Don't update any times or displayed expiresAt time will expectedly jump. - return now - } - - self.podTime = timeActive - self.podTimeUpdated = now - - let activatedAtComputed = now - timeActive - if activatedAt == nil { - self.activatedAt = activatedAtComputed - } - let expiresAtComputed = activatedAtComputed + Pod.nominalPodLife - if expiresAt == nil { - self.expiresAt = expiresAtComputed - } else if expiresAtComputed < self.expiresAt! || expiresAtComputed > (self.expiresAt! + TimeInterval(minutes: 1)) { - // The computed expiresAt time is earlier than or more than a minute later than the current expiresAt time, - // so use the computed expiresAt time instead to handle Pod clock drift and/or system time changes issues. - // The more than a minute later test prevents oscillation of expiresAt based on the timing of the responses. - self.expiresAt = expiresAtComputed - } - return now - } - - public mutating func updateFromStatusResponse(_ response: StatusResponse, at date: Date = Date()) { - let now = updatePodTimes(timeActive: response.timeActive) - updateDeliveryStatus(deliveryStatus: response.deliveryStatus, podProgressStatus: response.podProgressStatus, bolusNotDelivered: response.bolusNotDelivered, at: date) - - let setupUnits = setupUnitsDelivered ?? Pod.primeUnits + Pod.cannulaInsertionUnits + Pod.cannulaInsertionUnitsExtra - - // Calculated new delivered value which will be a negative value until setup has completed OR after a pod reset fault - let calcDelivered = response.insulinDelivered - setupUnits - - // insulinDelivered should never be a negative value or decrease from the previous saved delivered value - let prevDelivered = lastInsulinMeasurements?.delivered ?? 0 - let insulinDelivered = max(calcDelivered, prevDelivered) - - lastInsulinMeasurements = PodInsulinMeasurements(insulinDelivered: insulinDelivered, reservoirLevel: response.reservoirLevel, validTime: now) - - activeAlertSlots = response.alerts - } - - public mutating func registerConfiguredAlert(slot: AlertSlot, alert: PodAlert) { - configuredAlerts[slot] = alert - } - - public mutating func finalizeAllDoses() { - if let bolus = unfinalizedBolus { - finalizedDoses.append(bolus) - unfinalizedBolus = nil - } - - if let tempBasal = unfinalizedTempBasal { - finalizedDoses.append(tempBasal) - unfinalizedTempBasal = nil - } - } - - // Giving up on pod; we will assume commands failed/succeeded in the direction of positive net delivery - mutating func resolveAnyPendingCommandWithUncertainty() { - guard let pendingCommand = unacknowledgedCommand else { - return - } - - switch pendingCommand { - case .program(let program, _, let commandDate, _): - - if let dose = program.unfinalizedDose(at: commandDate, withCertainty: .uncertain, insulinType: insulinType) { - switch dose.doseType { - case .bolus: - if dose.isFinished() { - finalizedDoses.append(dose) - } else { - unfinalizedBolus = dose - } - case .tempBasal: - // Assume a high temp succeeded, but low temp failed - if case .tempBasal(_, _, let isHighTemp, _) = program, isHighTemp { - if dose.isFinished() { - finalizedDoses.append(dose) - } else { - unfinalizedTempBasal = dose - } - } - case .resume: - finalizedDoses.append(dose) - case .suspend: - break // start program is never a suspend - } - } - case .stopProgram(let stopProgram, _, let commandDate, _): - // All stop programs result in reduced delivery, except for stopping a low temp, so we assume all stop - // commands failed, except for low temp - - - if stopProgram.contains(.tempBasal), - let tempBasal = unfinalizedTempBasal, - tempBasal.isHighTemp, - !tempBasal.isFinished(at: commandDate) - { - unfinalizedTempBasal?.cancel(at: commandDate) - } - } - self.unacknowledgedCommand = nil - } - - private mutating func updateDeliveryStatus(deliveryStatus: DeliveryStatus, podProgressStatus: PodProgressStatus, bolusNotDelivered: Double, at date: Date) { - - deliveryStatusVerified = true - // See if the pod deliveryStatus indicates an active bolus or temp basal that the PodState isn't tracking (possible Loop restart) - if deliveryStatus.bolusing && unfinalizedBolus == nil { // active bolus that Loop doesn't know about? - if podProgressStatus.readyForDelivery { - deliveryStatusVerified = false // remember that we had inconsistent (bolus) delivery status - // Create an unfinalizedBolus with the remaining bolus amount to capture what we can. - unfinalizedBolus = UnfinalizedDose(bolusAmount: bolusNotDelivered, startTime: date, scheduledCertainty: .certain, insulinType: insulinType, automatic: false) - } - } - if deliveryStatus.tempBasalRunning && unfinalizedTempBasal == nil { // active temp basal that app isn't tracking - deliveryStatusVerified = false // remember that we had inconsistent (temp basal) delivery status - // unfinalizedTempBasal = UnfinalizedDose(tempBasalRate: 0, startTime: Date(), duration: .minutes(30), isHighTemp: false, scheduledCertainty: .certain, insulinType: insulinType) - } - if deliveryStatus != .suspended && isSuspended { // active basal that app isn't tracking - deliveryStatusVerified = false // remember that we had inconsistent (basal) delivery status - let resumeStartTime = Date() - suspendState = .resumed(resumeStartTime) - unfinalizedResume = UnfinalizedDose(resumeStartTime: resumeStartTime, scheduledCertainty: .certain, insulinType: insulinType) - } - - if var bolus = unfinalizedBolus, !deliveryStatus.bolusing { - // Due to clock drift or comms delays, boluses can finish earlier than we expect - if !bolus.isFinished() { - bolus.finishTime = date - } - finalizedDoses.append(bolus) - unfinalizedBolus = nil - } - - if var tempBasal = unfinalizedTempBasal, !deliveryStatus.tempBasalRunning { - if !tempBasal.isFinished() { - tempBasal.finishTime = date - } - finalizedDoses.append(tempBasal) - unfinalizedTempBasal = nil - } - - if let suspend = unfinalizedSuspend { - - if let resume = unfinalizedResume, suspend.startTime < resume.startTime { - finalizedDoses.append(suspend) - finalizedDoses.append(resume) - unfinalizedSuspend = nil - unfinalizedResume = nil - } - } - } - - // MARK: - RawRepresentable - public init?(rawValue: RawValue) { - - guard - let address = rawValue["address"] as? UInt32, - let nonceStateRaw = rawValue["nonceState"] as? NonceState.RawValue, - let nonceState = NonceState(rawValue: nonceStateRaw), - let piVersion = rawValue["piVersion"] as? String, - let pmVersion = rawValue["pmVersion"] as? String, - let lot = rawValue["lot"] as? UInt32, - let tid = rawValue["tid"] as? UInt32 - else { - return nil - } - - self.address = address - self.nonceState = nonceState - self.piVersion = piVersion - self.pmVersion = pmVersion - self.lot = lot - self.tid = tid - - self.activeTime = rawValue["activeTime"] as? TimeInterval - - if let activatedAt = rawValue["activatedAt"] as? Date { - self.activatedAt = activatedAt - if let expiresAt = rawValue["expiresAt"] as? Date { - self.expiresAt = expiresAt - } else { - self.expiresAt = activatedAt + Pod.nominalPodLife - } - } - - if let setupUnitsDelivered = rawValue["setupUnitsDelivered"] as? Double { - self.setupUnitsDelivered = setupUnitsDelivered - } - - if let suspended = rawValue["suspended"] as? Bool { - // Migrate old value - if suspended { - suspendState = .suspended(Date()) - } else { - suspendState = .resumed(Date()) - } - } else if let rawSuspendState = rawValue["suspendState"] as? SuspendState.RawValue, let suspendState = SuspendState(rawValue: rawSuspendState) { - self.suspendState = suspendState - } else { - return nil - } - - if let rawPendingCommand = rawValue["unacknowledgedCommand"] as? PendingCommand.RawValue { - // When loading from raw state, we know comms are no longer in progress; this helps recover from a crash - self.unacknowledgedCommand = PendingCommand(rawValue: rawPendingCommand)?.commsFinished - } else { - self.unacknowledgedCommand = nil - } - - if let rawUnfinalizedBolus = rawValue["unfinalizedBolus"] as? UnfinalizedDose.RawValue - { - self.unfinalizedBolus = UnfinalizedDose(rawValue: rawUnfinalizedBolus) - } - - if let rawUnfinalizedTempBasal = rawValue["unfinalizedTempBasal"] as? UnfinalizedDose.RawValue - { - self.unfinalizedTempBasal = UnfinalizedDose(rawValue: rawUnfinalizedTempBasal) - } - - if let rawUnfinalizedSuspend = rawValue["unfinalizedSuspend"] as? UnfinalizedDose.RawValue - { - self.unfinalizedSuspend = UnfinalizedDose(rawValue: rawUnfinalizedSuspend) - } - - if let rawUnfinalizedResume = rawValue["unfinalizedResume"] as? UnfinalizedDose.RawValue - { - self.unfinalizedResume = UnfinalizedDose(rawValue: rawUnfinalizedResume) - } - - if let rawLastInsulinMeasurements = rawValue["lastInsulinMeasurements"] as? PodInsulinMeasurements.RawValue { - self.lastInsulinMeasurements = PodInsulinMeasurements(rawValue: rawLastInsulinMeasurements) - } else { - self.lastInsulinMeasurements = nil - } - - if let rawFinalizedDoses = rawValue["finalizedDoses"] as? [UnfinalizedDose.RawValue] { - self.finalizedDoses = rawFinalizedDoses.compactMap( { UnfinalizedDose(rawValue: $0) } ) - } else { - self.finalizedDoses = [] - } - - if let rawFault = rawValue["fault"] as? DetailedStatus.RawValue, - let fault = DetailedStatus(rawValue: rawFault), - fault.faultEventCode.faultType != .noFaults - { - self.fault = fault - } else { - self.fault = nil - } - - if let alarmsRawValue = rawValue["alerts"] as? UInt8 { - self.activeAlertSlots = AlertSet(rawValue: alarmsRawValue) - } else { - self.activeAlertSlots = .none - } - - if let podTime = rawValue["podTime"] as? TimeInterval, - let podTimeUpdated = rawValue["podTimeUpdated"] as? Date - { - self.podTime = podTime - self.podTimeUpdated = podTimeUpdated - } else { - self.podTime = 0 - self.podTimeUpdated = nil - } - - if let setupProgressRaw = rawValue["setupProgress"] as? Int, - let setupProgress = SetupProgress(rawValue: setupProgressRaw) - { - self.setupProgress = setupProgress - } else { - // Migrate - self.setupProgress = .completed - } - - if let messageTransportStateRaw = rawValue["messageTransportState"] as? MessageTransportState.RawValue, - let messageTransportState = MessageTransportState(rawValue: messageTransportStateRaw) - { - self.messageTransportState = messageTransportState - } else { - self.messageTransportState = MessageTransportState(packetNumber: 0, messageNumber: 0) - } - - if let rawConfiguredAlerts = rawValue["configuredAlerts"] as? [String: PodAlert.RawValue] { - var configuredAlerts = [AlertSlot: PodAlert]() - for (rawSlot, rawAlert) in rawConfiguredAlerts { - if let slotNum = UInt8(rawSlot), let slot = AlertSlot(rawValue: slotNum), let alert = PodAlert(rawValue: rawAlert) { - configuredAlerts[slot] = alert - } - } - self.configuredAlerts = configuredAlerts - } else { - // Assume migration, and set up with alerts that are normally configured - self.configuredAlerts = [ - .slot2ShutdownImminent: .shutdownImminent(offset: 0, absAlertTime: 0), - .slot3ExpirationReminder: .expirationReminder(offset: 0, absAlertTime: 0), - .slot4LowReservoir: .lowReservoir(units: 0), - .slot5SuspendedReminder: .podSuspendedReminder(active: false, offset: 0, suspendTime: 0), - .slot6SuspendTimeExpired: .suspendTimeExpired(offset: 0, suspendTime: 0), - .slot7Expired: .expired(offset: 0, absAlertTime: 0, duration: 0) - ] - } - - self.primeFinishTime = rawValue["primeFinishTime"] as? Date - - if let rawInsulinType = rawValue["insulinType"] as? InsulinType.RawValue, let insulinType = InsulinType(rawValue: rawInsulinType) { - self.insulinType = insulinType - } else { - self.insulinType = .novolog - } - - self.deliveryStatusVerified = false - self.lastCommsOK = false - } - - public var rawValue: RawValue { - var rawValue: RawValue = [ - "address": address, - "nonceState": nonceState.rawValue, - "piVersion": piVersion, - "pmVersion": pmVersion, - "lot": lot, - "tid": tid, - "suspendState": suspendState.rawValue, - "finalizedDoses": finalizedDoses.map( { $0.rawValue }), - "alerts": activeAlertSlots.rawValue, - "messageTransportState": messageTransportState.rawValue, - "setupProgress": setupProgress.rawValue, - "insulinType": insulinType.rawValue - ] - - rawValue["unacknowledgedCommand"] = unacknowledgedCommand?.rawValue - - rawValue["unfinalizedBolus"] = unfinalizedBolus?.rawValue - - rawValue["unfinalizedTempBasal"] = unfinalizedTempBasal?.rawValue - - rawValue["unfinalizedSuspend"] = unfinalizedSuspend?.rawValue - - rawValue["unfinalizedResume"] = unfinalizedResume?.rawValue - - rawValue["lastInsulinMeasurements"] = lastInsulinMeasurements?.rawValue - - rawValue["fault"] = fault?.rawValue - - rawValue["primeFinishTime"] = primeFinishTime - - rawValue["activeTime"] = activeTime - rawValue["activatedAt"] = activatedAt - rawValue["expiresAt"] = expiresAt - rawValue["podTime"] = podTime - rawValue["podTimeUpdated"] = podTimeUpdated - - rawValue["setupUnitsDelivered"] = setupUnitsDelivered - - if configuredAlerts.count > 0 { - let rawConfiguredAlerts = Dictionary(uniqueKeysWithValues: - configuredAlerts.map { slot, alarm in (String(describing: slot.rawValue), alarm.rawValue) }) - rawValue["configuredAlerts"] = rawConfiguredAlerts - } - - return rawValue - } - - // MARK: - CustomDebugStringConvertible - - public var debugDescription: String { - return [ - "### PodState", - "* address: \(String(format: "%04X", address))", - "* activatedAt: \(String(reflecting: activatedAt))", - "* expiresAt: \(String(reflecting: expiresAt))", - "* podTime: \(podTime.timeIntervalStr)", - "* podTimeUpdated: \(String(reflecting: podTimeUpdated))", - "* setupUnitsDelivered: \(String(reflecting: setupUnitsDelivered))", - "* piVersion: \(piVersion)", - "* pmVersion: \(pmVersion)", - "* lot: \(lot)", - "* tid: \(tid)", - "* suspendState: \(suspendState)", - "* unacknowledgedCommand: \(String(describing: unacknowledgedCommand))", - "* unfinalizedBolus: \(String(describing: unfinalizedBolus))", - "* unfinalizedTempBasal: \(String(describing: unfinalizedTempBasal))", - "* unfinalizedSuspend: \(String(describing: unfinalizedSuspend))", - "* unfinalizedResume: \(String(describing: unfinalizedResume))", - "* finalizedDoses: \(String(describing: finalizedDoses))", - "* activeAlertsSlots: \(alertSetString(alertSet: activeAlertSlots))", - "* messageTransportState: \(String(describing: messageTransportState))", - "* setupProgress: \(setupProgress)", - "* primeFinishTime: \(String(describing: primeFinishTime))", - "* configuredAlerts: \(configuredAlertsString(configuredAlerts: configuredAlerts))", - "* insulinType: \(String(describing: insulinType))", - "* pdmRef: " + (fault?.pdmRef == nil ? "nil" : String(describing: fault!.pdmRef!)), - "* Fault: " + (fault == nil ? "nil" : String(describing: fault!)), - ].joined(separator: "\n") - } -} - -fileprivate struct NonceState: RawRepresentable, Equatable { - public typealias RawValue = [String: Any] - - var table: [UInt32] - var idx: UInt8 - - public init(lot: UInt32 = 0, tid: UInt32 = 0, seed: UInt16 = 0) { - table = Array(repeating: UInt32(0), count: 2 + 16) - table[0] = (lot & 0xFFFF) &+ (lot >> 16) &+ 0x55543DC3 - table[1] = (tid & 0xFFFF) &+ (tid >> 16) &+ 0xAAAAE44E - - idx = 0 - - table[0] += UInt32((seed & 0x00ff)) - table[1] += UInt32((seed & 0xff00) >> 8) - - for i in 0..<16 { - table[2 + i] = generateEntry() - } - - idx = UInt8((table[0] + table[1]) & 0x0F) - } - - private mutating func generateEntry() -> UInt32 { - table[0] = (table[0] >> 16) &+ ((table[0] & 0xFFFF) &* 0x5D7F) - table[1] = (table[1] >> 16) &+ ((table[1] & 0xFFFF) &* 0x8CA0) - return table[1] &+ ((table[0] & 0xFFFF) << 16) - } - - public mutating func advanceToNextNonce() { - let nonce = currentNonce - table[Int(2 + idx)] = generateEntry() - idx = UInt8(nonce & 0x0F) - } - - public var currentNonce: UInt32 { - return table[Int(2 + idx)] - } - - // RawRepresentable - public init?(rawValue: RawValue) { - guard - let table = rawValue["table"] as? [UInt32], - let idx = rawValue["idx"] as? UInt8 - else { - return nil - } - self.table = table - self.idx = idx - } - - public var rawValue: RawValue { - let rawValue: RawValue = [ - "table": table, - "idx": idx, - ] - - return rawValue - } -} - - -public enum SuspendState: Equatable, RawRepresentable { - public typealias RawValue = [String: Any] - - private enum SuspendStateType: Int { - case suspend, resume - } - - case suspended(Date) - case resumed(Date) - - private var identifier: Int { - switch self { - case .suspended: - return 1 - case .resumed: - return 2 - } - } - - public init?(rawValue: RawValue) { - guard let suspendStateType = rawValue["case"] as? SuspendStateType.RawValue, - let date = rawValue["date"] as? Date else { - return nil - } - switch SuspendStateType(rawValue: suspendStateType) { - case .suspend?: - self = .suspended(date) - case .resume?: - self = .resumed(date) - default: - return nil - } - } - - public var rawValue: RawValue { - switch self { - case .suspended(let date): - return [ - "case": SuspendStateType.suspend.rawValue, - "date": date - ] - case .resumed(let date): - return [ - "case": SuspendStateType.resume.rawValue, - "date": date - ] - } - } -} diff --git a/Dependencies/OmniKit/OmniKit/Resources/ar.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/ar.lproj/Localizable.strings deleted file mode 100644 index 496f0367f..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/ar.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactive)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" has a low battery"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Activation time exceeded"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-off alarm"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialized"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Below 50 units"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusing"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolusing with temp basal"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Cannula inserting"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Certain"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Command error %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Communication issue: Unacknowledged command pending."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Empty reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Empty response from pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Error event logged, shutting down"; - -/* Description for expiration alert */ -"Expiration alert" = "Expiration alert"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Extended bolus running"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Extended bolus running with temp basal"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fault event occurred"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Finish Pairing"; - -/* Description for finish setup */ -"Finish setup " = "Finish setup "; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Finish setup reminder"; - -/* Pod inititialized */ -"Initialized" = "Initialized"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Inserting cannula"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Internal pod fault %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Invalid address 0x%x. Expected 0x%x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Invalid address: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Invalid CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Low reservoir advisory (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Low reservoir advisory alarm"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Low RileyLink Battery"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* Pod memory initialized */ -"Memory initialized" = "Memory initialized"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "No alerts"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "No faults"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "No response from pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "No RileyLink available"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Not enough data"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Occlusion detected"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Paired"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Pairing completed"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing Error: %1$@ in (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Please bring your pod closer to the RileyLink and try again"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Please reposition the RileyLink further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Please reposition the RileyLink relative to the pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod already primed"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod expiration advisory alarm"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod Expiration Notice"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod expired"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod Fault: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod is not in a state ready for priming."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod is suspended"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sent ack instead of response"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pod setup window expired"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pod suspended reminder"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Poor signal strength"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Priming"; - -/* Pod state when priming completed */ -"Priming completed" = "Priming completed"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Ready for basal programming"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Ready to insert cannula"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Reminder initialized"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Resume"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Resume delivery"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Resume: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Shutdown imminent"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Shutdown imminent alarm"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signal strength too high"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspend"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Suspend time expired"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspended"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspend: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspended"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Tank fill completed"; - -/* Pod power to motor activated */ -"Tank power activated" = "Tank power activated"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temp Basal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temp basal in progress"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temp basal running"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Time to replace your pod! Your pod will expire in %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Uncertain"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Unexpected message sequence number"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Unexpected pod change"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Unexpected response from pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Unknown pod fault %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Unknown Value (%1$@) for type %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validation failed: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Waiting for pairing reminder"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/ca.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/ca.lproj/Localizable.strings deleted file mode 100644 index e7871f9b3..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/ca.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactive)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" has a low battery"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Activation time exceeded"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-off alarm"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialized"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Below 50 units"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusing"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolusing with temp basal"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Cannula inserting"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Certain"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Command error %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Communication issue: Unacknowledged command pending."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When Loop automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When Loop automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when Loop automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when Loop automatically adjusts delivery as well as for commands you initiate."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Empty reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Empty response from pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Error event logged, shutting down"; - -/* Description for expiration alert */ -"Expiration alert" = "Expiration alert"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Extended bolus running"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Extended bolus running with temp basal"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fault event occurred"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Finish Pairing"; - -/* Description for finish setup */ -"Finish setup " = "Finish setup "; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Finish setup reminder"; - -/* Pod inititialized */ -"Initialized" = "Initialized"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Inserting cannula"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Internal pod fault %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Invalid address 0x%x. Expected 0x%x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Invalid address: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Invalid CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Low reservoir advisory (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Low reservoir advisory alarm"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Low RileyLink Battery"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* Pod memory initialized */ -"Memory initialized" = "Memory initialized"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "No alerts"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "No faults"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "No response from pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "No RileyLink available"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Not enough data"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Occlusion detected"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Paired"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Pairing completed"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing Error: %1$@ in (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Please bring your pod closer to the RileyLink and try again"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Please reposition the RileyLink further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Please reposition the RileyLink relative to the pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod already primed"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod expiration advisory alarm"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod Expiration Notice"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod expired"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod Fault: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod is not in a state ready for priming."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod is suspended"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sent ack instead of response"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pod setup window expired"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pod suspended reminder"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Poor signal strength"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Priming"; - -/* Pod state when priming completed */ -"Priming completed" = "Priming completed"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Ready for basal programming"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Ready to insert cannula"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Reminder initialized"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Resume"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Resume delivery"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Resume: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Shutdown imminent"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Shutdown imminent alarm"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signal strength too high"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspend"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Suspend time expired"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspended"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspend: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspended"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Tank fill completed"; - -/* Pod power to motor activated */ -"Tank power activated" = "Tank power activated"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temp Basal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temp basal in progress"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temp basal running"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Time to replace your pod! Your pod will expire in %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Uncertain"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Unexpected message sequence number"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Unexpected pod change"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Unexpected response from pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Unknown pod fault %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Unknown Value (%1$@) for type %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validation failed: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Waiting for pairing reminder"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/cs.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/cs.lproj/Localizable.strings deleted file mode 100644 index 71de1f337..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/cs.lproj/Localizable.strings +++ /dev/null @@ -1,183 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Bazál inicializován"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Méně než 50 jednotek"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Probíhající bolus"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@ U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusování"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolusování dočasným bazálem"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Zavádění kanyly"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Znamá"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktivováno"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Prázdný zásobník"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Prázdná odpověď z podu"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Zaprotokolována událost chyby, vypínám"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Doporučení k vypršení"; - -/* Description for expiration alert */ -"Expiration alert" = "Upozornění na vypršení"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Probíhající prodloužený bolus"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Probíhající prodloužený bolus s dočasným bazálem"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Došlo k chybové události"; - -/* Description for finish setup */ -"Finish setup " = "Dokončení nastavení "; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Připomínka k dokončení nastavení"; - -/* Pod inititialized */ -"Initialized" = "Inicializováno"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Zavádím kanylu"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Podávání inzulínu bylo zastaveno. Vyměňte pod nyní."; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Interní chyba podu %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Přerušený bolus: %1$@ U ( %2$@ U naplánované) %3$@ %4$@ %5$@"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Poloprázdný zásobník"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Žádný inzulín"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Žádný pod"; - -/* Acknowledge button label for RileyLink low battery alert - Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod je pozastaven"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Platnost okna nastavení podu vypršela"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pozastavená upozornění podu"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Připravuji"; - -/* Pod state when priming completed */ -"Priming completed" = "Příprava dokončena"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Připraveno k programování bazálu"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Připraven k zavedení kanyly"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Upozornění inicializováno"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Pokračovat: %1$@ %2$@"; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Plánovaný bazál"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Plánovaný bazál"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Vypnutí blížícího "; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Vypnutí blížícího se alarmu"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Ztráta signálu"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Období pozastavení vypršelo"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Pozastavit: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Pozastaveno"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Plnění zásobníku dokončeno"; - -/* Pod power to motor activated */ -"Tank power activated" = "Napájení zásobníku aktivováno"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Dočasný bazál v platnosti"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Dočasný bazál v platnosti"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "DočBazál: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Čas vyměnit pod! Platnost vašeho podu vyprší za %1$@"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Nejasné"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Neočekávané pořadové číslo zprávy"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Neočekávaná odpověď od podu"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Neznámá chyba podu %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Neznámá hodnota ( %1$@ ) pro typ %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Ověření se nezdařilo: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Počkejte na dokončení podávání stávajícího bolusu nebo bolus zrušte"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Počkejte na dokončení stávajícího dočasného bazálu nebo ho pozastavte pro zrušení."; - diff --git a/Dependencies/OmniKit/OmniKit/Resources/da.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/da.lproj/Localizable.strings deleted file mode 100644 index eb3e84586..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/da.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inaktiv)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" har lavt batteri"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin eller mindre tilbage i Pod. Skift Pod snart."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Aktiveringstid overskredet"; - -/* Description for auto-off */ -"Auto-off" = "Auto-sluk"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-sluk alarm"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialiseret"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Under 50 enheder"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus i gang"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@E %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Indgiver bolus"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Indgiver bolus med midlertidig basal"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Indfører kanyle"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Sikker"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Skift Pod nu. Insulintilførsel stopper om 1 time."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Skift Pod nu. Pod har været aktiv i 72 timer."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Kommandofejl %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Kommunikationsproblem"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Kommunikationsproblem: Uerkendt kommando afventer."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritisk Pod-fejl"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Kommunikationsfejl. Flyt til et nyt område"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktiveret"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Deaktiveret"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Tomt reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Tomt svar fra Pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Fejlhændelse logget, lukker ned"; - -/* Description for expiration alert */ -"Expiration alert" = "Udløbs-advarsel"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Forlænget"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Forlænget bolus kører"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Forlænget bolus med midlertidig basal"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fejlhændelse indtraf"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Afslut deaktivering"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Afslut parring"; - -/* Description for finish setup */ -"Finish setup " = "Afslut opsætning"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Påmindelse om færdiggørelse af opsætning"; - -/* Pod inititialized */ -"Initialized" = "Initialiseret"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Indsætter kanyle"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulintilførslen er stoppet. Skift Pod nu."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin suspenderet"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulintype ikke konfigureret"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Intern Pod-fejl %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "AfbrudtBolus: %1$@ E (%2$@ E planlagt) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Ugyldig adresse 0x%1$x. Forventet 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Ugyldig adresse: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Ugyldig CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ugyldig indstilling"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Lavt reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Vejledning om lavt reservoir (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Lavt reservoir alarm"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Lavt RileyLink-batteri"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Sørg for, at din RileyLink er i nærheden og tændt"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual basal"; - -/* Pod memory initialized */ -"Memory initialized" = "Hukommelse initialiseret"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Flyt til et nyt område væk fra andre Pods og prøv igen."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Advarsel om flere kommandoer"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Ingen alarmer"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Ingen påmindelser for succesfulde aktiviteter benyttet"; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Ingen fejl"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Ingen insulin"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Ingen Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Ingen Pod parret"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Ingen Pods fundet"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Intet svar fra Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Ingen RileyLink til stede"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Ikke nok data"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Blokkering opdaget"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Parret"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Parring afsluttet"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Indlæsningfejl: %1$@ i %2$@"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Hav kun den originale Pod tæt på eller deaktiver den original Pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Venligst flyt Pod’en tættere på din RileyLink og prøv igen"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Afslut parringen af din Pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Venligst par med en ny Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Flyt RileyLink længere væk fra Pod'en"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Flyt RileyLink i forhold til Pod'en"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod allerede parret"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod allerede klargjort"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod-fejl"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod udløbsalarm"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod udløbspåmindelse"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod udløbet"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod udløber om %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod Fejl: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod er ikke klar til kanyleindførsel."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod er ikke parat til klargøring."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod er pauset"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod er blokeret"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod-parring ufuldstændig"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sendt acknowledge i stedet for svar"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pod indstillingsvindue udløbet"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Påmindelse om suspenderet Pod "; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Dårlig signalstyrke"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Klargør"; - -/* Pod state when priming completed */ -"Priming completed" = "Klargøring afsluttet"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Klar til basal-indstilling"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Klar til kanyleindførsel"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Påmindelse initialiseret"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Genoptag"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Fortsæt indgivelse"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Genoptag insulin"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Fortsæt: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Planlagt basal"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Luk akut"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Afbryd akut alarm"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signaltab"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signalstyrken er for høj"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspender"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Påmindelse om igangværende suspension"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Suspenderet tid udløbet"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspenderet"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Pause: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspenderet"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspensionstiden er udløbet. Åbn appen, og genoptag."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Reservoirpåfyldning færdig"; - -/* Pod power to motor activated */ -"Tank power activated" = "Reservoir-strøm aktiveret"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Midlertidig basal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Midlertidig basal allerede i gang"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Midlertidig basal i gang"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "Midlertidig basal: %1$@ E/time %2$@ %3$@ %4$@ E %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Perioden for suspension af insulin er afsluttet.\n\nDu kan genoptage afgivelsen fra den øverste del af startskærmen eller fra skærmen med pumpeindstillinger. Du vil blive mindet om dette igen om 15 minutter."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Tiden på din pumpe er forskellig fra den aktuelle tid. Din pumpes tid styrer dine planlagte behandlingsindstillinger. Gå til Pumpetid for at gennemgå tidsforskellen og konfigurere din pumpe."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Tidsændring registreret"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Tid til udskiftning af Pod! Din Pod udløber om %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Der er fundet for mange Pods"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Prøv igen"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Usikker"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Uventet meddelelsessekvensnummer"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Uventet Pod-skifte"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Uventet svar fra Pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Ukendt Podfejl %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Ukendt værdi (%1$@) for type %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validering mislykkedes: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Vent, indtil eksisterende bolus er færdig, eller annuller bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Vent, indtil den eksisterende midlertidige basal er færdig, eller pause for at annullere"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Venter på parrings-påmindelse"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/de.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/de.lproj/Localizable.strings deleted file mode 100644 index 8c7de4833..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/de.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inaktiv)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" hat einen niedrigen Akkustand"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ Insulin oder weniger verbleibend im Pod. Pod bald wechseln."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Aktivierungszeit überschritten"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-Off Alarm"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialisiert"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Weniger als 50 Einheiten"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolusabgabe läuft "; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@IE %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusabgabe"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolus-Abgabe mit temporärer Basalrate"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Einsetzen der Kanüle"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Sicher"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Pod jetzt wechseln. Die Insulinabgabe stoppt in 1 Stunde."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Pod jetzt wechseln. Der Pod ist seit 72 Stunden aktiv."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Befehlsfehler %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Problem"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Kommunikationsproblem: Unbestätigter Befehl steht noch aus."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Vertrauenserinnerungen ertönen für von Ihnen initiierte Befehle, wie Bolus, Bolus abbrechen, Unterbrechen, Fortsetzen, Benachrichtigungserinnerungen speichern usw. Wenn Loop die Abgabe automatisch anpasst, werden keine Vertrauenserinnerungen verwendet."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Vertrauenserinnerungen ertönen, wenn Loop die Lieferung automatisch anpasst, sowie für von Ihnen initiierte Befehle."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritischer Pod-Fehler"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Überlagerungen möglich. Bitte wechseln Sie an einen neuen Standort"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktiviert"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Ausgeschaltet"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Reservoir leer"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Leere Antwort vom Pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Fehlerereignis protokolliert, fahre herunter"; - -/* Description for expiration alert */ -"Expiration alert" = "Ablaufalarm"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Verzögerung"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Verzögerter Bolus aktiv"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Verzögerter Bolus mit temporärer Basalrate aktiv"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fehlerereignis aufgetreten"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Deaktivierung abgeschlossen"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Kopplung abgeschlossen"; - -/* Description for finish setup */ -"Finish setup " = "Einrichtung abgeschlossen"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Einrichtungserinnerung abgeschlossen"; - -/* Pod inititialized */ -"Initialized" = "Initialisiert"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Einfügen von Kanüle"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulinabgabe wurde gestoppt. Pod jetzt wechseln."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulinabgabe unterbrochen"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulintyp nicht konfiguriert"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Interner Podfehler %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Abgebrochener Bolus: %1$@ IE (%2$@ IE geplant) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Ungültige Adresse (%1$x). Adresse %2$x erwartet"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Ungültige Adresse (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Ungültiger CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ungültige Einstellung"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Niedriges Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Hinweis auf niedriges Reservior (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Hinweisalarm für fast leeres Reservoir"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Niedriger RileyLink Batteriestatus"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Stellen Sie sicher, dass sich Ihr RileyLink in der Nähe befindet und eingeschaltet ist"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuelle Basalrate"; - -/* Pod memory initialized */ -"Memory initialized" = "Speicher initialisiert"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Begeben Sie sich in einen anderen Bereich, entfernt von anderen Pods und versuchen Sie es erneut."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Warnung bei mehreren Befehlen"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Keine Alarme"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Es werden keine Sicherheitserinnerungen verwendet."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Keine Fehler"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Kein Insulin"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Kein Pod gekoppelt"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Kein Pod gekoppelt"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Keine Pods gefunden"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Keine Rückmeldung vom Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Kein RileyLink verfügbar"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "im Zielbereich"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Nicht genügend Daten"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Verstopfung erkannt"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Gekoppelt"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Kopplung abgeschlossen"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing-Fehler: %1$@ in (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Bitte nur Original-Pod in Reichweite bringen oder Original-Pod deaktivieren"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Bitte bringen Sie Ihren Pod näher an Ihr RileyLink und versuchen Sie es erneut"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Bitte schließen Sie die Kopplung Ihres Pods ab."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Bitte koppel einen neuen Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Bitte positionieren Sie den RileyLink weiter entfernt vom Pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Bitte versuchen Sie, den Pod oder den RileyLink neu zu positionieren und versuchen Sie es erneut."; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod bereits gekoppelt"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod bereits gefüllt"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod-Fehler"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Ablaufalarm des Pods"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Hinweis zum Ablaufen des Pods"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod abgelaufen"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod läuft in %1$@ ab."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Podfehler: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Der Pod ist nicht bereit zum Einführen der Kanüle."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Der Pod ist nicht bereit zum Befüllen."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod ist angehalten"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Verstopfung"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod-Kopplung unvollständig"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sendet Bestätigung anstelle von Antwort"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Das Zeitfenster für die Pod-Einrichtung ist abgelaufen"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Erinnerung über abgelaufenen Pod "; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Schlechte Signalstärke"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Befüllen"; - -/* Pod state when priming completed */ -"Priming completed" = "Befüllen des Pods abgeschlossen"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Bereit für die Programmierung der Basalrate"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Bereit zum Einführen der Kanüle"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Erinnerung initialisiert"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Fortsetzen"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Insulinabgabe fortsetzen"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Insulinabgabe fortsetzen"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Fortsetzen: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Geplante Basalrate"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Pod-Abschaltung steht bevor"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarm für die bevorstehende Pod-Abschaltung"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signalverlust"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signalstärke ist zu hoch"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Unterbrechen"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Unterbrechungsfortschritts-Erinnerung"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Unterbrechungszeit abgelaufen"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Unterbrochen"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Unterbrochen: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Unterbrochen"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Die Unterbrechungszeit ist abgelaufen. Öffnen Sie die App und fahren Sie fort."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Befüllen des Pods erfolgreich"; - -/* Pod power to motor activated */ -"Tank power activated" = "Energieversorgung für den Podmotor aktiviert"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temporäre Basalrate"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temporäre Basalrate läuft bereits."; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temporäre Basalrate läuft"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ IE/h %2$@ %3$@ %4$@ IE %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Die Insulinabschaltung ist beendet.\n\nSie können die Abgabe über das Banner auf dem Startbildschirm oder über den Bildschirm mit den Pumpeneinstellungen fortsetzen. Sie werden in 15 Minuten erneut erinnert."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Die Uhrzeit Ihrer Pumpe weicht von der aktuellen Uhrzeit ab. Sie können die Uhrzeit der Pumpe überprüfen und in den Einstellungen mit der aktuellen Uhrzeit synchronisieren."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Änderung der Uhrzeit erkannt"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Es ist Zeit Ihren Pod zu wechseln! Der Pod läuft ab in %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Zu viele Pods in Reichweite"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Versuchen Sie es erneut"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Unsicher"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Unerwartete Sequenznummer der Nachricht"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Unerwarteter Podwechsel"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Unerwartete Antwort vom Pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Unbekannter Podfehler %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Unbekannter Wert ( %1$@ ) für Typ %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Überprüfung fehlgeschlagen: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Warte, bis der aktuelle Bolus abgegeben wurde, oder unterbreche diesen."; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Warten Sie, bis die aktuelle temporäre Basalrate beendet ist, oder unterbrechen Sie diese"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Warten auf Kopplungserinnerung"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/en.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/en.lproj/Localizable.strings deleted file mode 100644 index 0e1b974d1..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/en.lproj/Localizable.strings +++ /dev/null @@ -1,429 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactive)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" has a low battery"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Activation time exceeded"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-off alarm"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialized"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Below 50 units"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusing"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolusing with temp basal"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Cannula inserting"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Certain"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Command error %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Communication issue: Unacknowledged command pending."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Empty reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Empty response from pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Error event logged, shutting down"; - -/* Description for expiration alert */ -"Expiration alert" = "Expiration alert"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Extended bolus running"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Extended bolus running with temp basal"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fault event occurred"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Finish Pairing"; - -/* Description for finish setup */ -"Finish setup " = "Finish setup "; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Finish setup reminder"; - -/* Pod inititialized */ -"Initialized" = "Initialized"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Inserting cannula"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Internal pod fault %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Invalid address 0x%x. Expected 0x%x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Invalid address: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Invalid CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Low reservoir advisory (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Low reservoir advisory alarm"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Low RileyLink Battery"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* Pod memory initialized */ -"Memory initialized" = "Memory initialized"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "No alerts"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "No faults"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "No response from pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "No RileyLink available"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Not enough data"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Occlusion detected"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Paired"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Pairing completed"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing Error: %1$@ in (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Please bring your pod closer to the RileyLink and try again"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Please reposition the RileyLink further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Please reposition the RileyLink relative to the pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod already primed"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod expiration advisory alarm"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod Expiration Notice"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod expired"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod Fault: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod is not in a state ready for priming."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod is suspended"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sent ack instead of response"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pod setup window expired"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pod suspended reminder"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Poor signal strength"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Priming"; - -/* Pod state when priming completed */ -"Priming completed" = "Priming completed"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Ready for basal programming"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Ready to insert cannula"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Reminder initialized"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Resume"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Resume delivery"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Resume: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Shutdown imminent"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Shutdown imminent alarm"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signal strength too high"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspend"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Suspend time expired"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspended"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspend: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspended"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Tank fill completed"; - -/* Pod power to motor activated */ -"Tank power activated" = "Tank power activated"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temp Basal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temp basal in progress"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temp basal running"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Time to replace your pod! Your pod will expire in %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Uncertain"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Unexpected message sequence number"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Unexpected pod change"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Unexpected response from pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Unknown pod fault %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Unknown Value (%1$@) for type %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validation failed: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Waiting for pairing reminder"; - diff --git a/Dependencies/OmniKit/OmniKit/Resources/es.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/es.lproj/Localizable.strings deleted file mode 100644 index cad5cbcb5..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/es.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactivo)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" tiene batería baja"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "Queda %1$@ de insulina o menos en el Pod. Cambie el Pod pronto."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Tiempo de activación excedido"; - -/* Description for auto-off */ -"Auto-off" = "Apagado automático"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Alarma de apagado automático"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal inicializada"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Menos de 50 unidades"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolo"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolo en progreso"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolo: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Poniendo bolo"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Poniendo bolo con basal temporal"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Cánula insertándose"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Programación acertada"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Cambie el Pod ahora. La administración de insulina se detendrá en una hora."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Cambie el Pod ahora. El Pod ha estado activo durante 72 horas."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Error de comando %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problema de comunicaciones"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Problema de comunicación: Pendiente de confirmar comando."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Error crítico del Pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Interferencia posible. Muévase a una nueva ubicación"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Pod desactivado"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Desactivado"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Reservorio vacío"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Respuesta vacía del pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Evento de error de registro, apagándose"; - -/* Description for expiration alert */ -"Expiration alert" = "Alerta de caducidad"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extendido"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Bolo extendido ejecutándose"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Bolo extendido ejecutándose con basal temporal"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Se ha producido un fallo"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Finalizar la desactivación"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Finalizar Emparejamiento"; - -/* Description for finish setup */ -"Finish setup " = "Fin de la configuración"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Finalizar recordatorio de configuración"; - -/* Pod inititialized */ -"Initialized" = " iniciado"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Insertando cánula"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "El suministro de insulina se detuvo. Cambiar Pod ahora."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulina Suspendida"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Tipo de insulina no configurada"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Error pod interno %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "BoloInterrumpido: %1$@ U (%2$@ U planeadas) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Dirección no válida 0x %1$x. Esperada 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Dirección no válida: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "CRC no válido"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Configuración no válida"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Reserva baja"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Aviso de reserva baja (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Alarma de aviso de depósito bajo"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Batería baja de RileyLink"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Asegúrese de que su RileyLink está cerca y encendido"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Basal Manual"; - -/* Pod memory initialized */ -"Memory initialized" = "Memoria inicializada"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Muévete a una nueva área lejos de cualquier otro Pod e inténtalo de nuevo."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Alerta de comandos múltiples"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "No hay alertas"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No se utilizan recordatorios de confianza."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Sin fallos"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "No hay insulina"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No hay Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No hay pod emparejado"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No se encontraron Pods"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Sin respuesta del pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "No hay RileyLink disponible"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "No hay suficientes datos"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Oclusion detectada"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Emparejado"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Emparejamiento completo"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Error de parseo: %1$@ en (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Por favor, ponga solamente el Pod original en rango o desactivelo"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Por favor, acerque su pod al RileyLink e inténtelo de nuevo"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Por favor, termine de emparejar su Pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Por favor, empareje un nuevo pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Por favor, intente reposicionar el RileyLink más lejos del Pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Por favor, reposicione el RileyLink con respecto al Pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Ya hay un pod emparejado"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "El pod ya está purgado"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Error del Pod"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Alarma de aviso de caducidad de un pod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Aviso de vencimiento de un pod"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod caducado"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "El Pod expira en %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Error de pod: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "El Pod no está listo para insertar la cánula"; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "El Pod no está listo para purgar"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "El Pod está suspendido"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Oclusión del Pod"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Emparejamiento del Pod incompleto"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod envió acuse de recibo en lugar de respuesta"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "La pantalla de configuración del pod ha caducado"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Recordatorio de que el Pod está suspendido"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Mala señal"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Purgando"; - -/* Pod state when priming completed */ -"Priming completed" = "Purgado completado"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Listo para programar basales"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Listo para insertar la cánula"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Recordatorio inicializado"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Reanudar"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Reanudar la entrega de insulina"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Reanudar insulina"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Reanudar: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Insulina basal programada"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Cierre inminente"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Apagar la alarma inminente"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Pérdida de señal"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Intensidad de la señal demasiado alta"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspender"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Recordatorio de Suspensión en curso"; - -/* Description for suspend time expired */ -"Suspend time expired" = "El tiempo de suspensión ha expirado"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspendido"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspender: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspendido"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "El tiempo de suspensión ha terminado. Abra la aplicación y reanúdela."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Completado el llenado del depósito"; - -/* Pod power to motor activated */ -"Tank power activated" = "Depósito encendido"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Insulina basal temporal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Basal temporal en progreso"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Basal temporal funcionando"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "BasalTemporal: %1$@ U/hora %2$@ %3$@ %4$@ U %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "El periodo de suspensión de la insulina ha finalizado.\n\nPuedes reanudar la administración desde el banner de la pantalla de inicio o desde la pantalla de ajustes de tu bomba. Se le recordará de nuevo en 15 minutos."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "La hora de la bomba es diferente de la hora actual. Puedes revisar la hora de la bomba y sincronizarla con la hora actual en los ajustes."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Cambio de hora detectado"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Es hora de reemplazar el pod! El pod expira en %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Se encontraron demasiados Pods"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Vuelva a intentarlo"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Incierto"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Número de secuencia de mensaje inesperado"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Cambio inesperado de Pod"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Respuesta inesperada del pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Fallo de pod desconocido %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Valor Desconocido (%1$@) para el tipo %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "La validación falló: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Espere a que termine el bolo o cancele el bolo"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Espere a que termine la basal temporal existente o suspénda para cancelar"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Esperando el recordatorio de emperejamiento"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/fi.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/fi.lproj/Localizable.strings deleted file mode 100644 index 81c1d07af..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/fi.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (ei-aktiivinen)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" has a low battery"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Aktivointiaika ylitetty"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Autom. pois -varoitus"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basaali alustettu"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Alle 50 yksikköä"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus vireillä"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Annostellaan bolus"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Annostellaan bolus ja tilap. basaali"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Asetetaan kanyyli"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Varma"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Komentovirhe %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Yhteysongelma"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Communication issue: Unacknowledged command pending."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktivoitu"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Säiliö tyhjä"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Tyhjä vastaus pumpulta"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Virhetapahtuma, suljetaan"; - -/* Description for expiration alert */ -"Expiration alert" = "Pumppu vanhenee -varoitus"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Extended bolus running"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Extended bolus running with temp basal"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Virhetapahtuma"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Finish Pairing"; - -/* Description for finish setup */ -"Finish setup " = "Lopeta asennus"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Finish setup reminder"; - -/* Pod inititialized */ -"Initialized" = "Aloitettu"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Asetetaan kanyyli"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insuliini pysäytetty"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Sisäinen pumpun vika %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "KeskeytettyBolus: %1$@ U (%2$@ U ohjelmoitu) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Virheellinen osoite 0x%1$x. Odotettu 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Virheellinen osoite: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Virheellinen CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Low reservoir advisory (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Säiliö lähes tyhjä -tiedotehälytys"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Low RileyLink Battery"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Varmista, että RileyLink on riittävän lähellä ja kytketty päälle"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* Pod memory initialized */ -"Memory initialized" = "Muisti alustettu"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Ei hälytyksiä"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Ei vikoja"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Ei insuliinia"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Ei pumppua"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Ei yhdistettyä pumppua"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Ei vastausta pumpusta"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Ei RileyLinkiä lähistöllä"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normaali"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Tietoja ei ole tarpeeksi"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Tukos havaittu"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Yhdistetty"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Pairing completed"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing Error: %1$@ in (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Tuo vain alkuperäinen pumppu kantaman sisälle tai poista alkuperäinen pumppu käytöstä"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Vie pumppu ja RileyLink lähemmäksi toisiaan ja yritä uudelleen"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Yhdistä uusi pumppu"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Siirrä RileyLink kauemmas pumpusta"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Muuta RileyLinkin paikkaa suhteessa pumppuun"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pumppu on jo yhdistetty"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pumppu on jo alustettu"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pumppu vanhenemassa -tiedotehälytys"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pumppu vanhenemassa -ilmoitus"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pumppu vanhentunut"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pumppuvirhe: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pumppu ei ole valmis kanyylin asettamiseen."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pumppu ei ole valmis alustukseen."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pumppu on pysäytetty"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pumppu lähetti kuittauksen vastauksen sijaan"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pumpun asennusaika umpeutui"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pod suspended reminder"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Heikko signaali"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Alustetaan"; - -/* Pod state when priming completed */ -"Priming completed" = "Alustus valmis"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Valmis basaalin ohjelmointiin"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Valmis kanyylin asetukseen"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Muistutus alustettu"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Resume"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Resume delivery"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Jatka: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Ohjelmoitu basaali"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Shutdown imminent"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Mykistä hälytys"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signaali liian voimakas"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspend"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Suspend time expired"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Pysäytetty"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Pysäytä: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Pysäytetty"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Säiliön täyttö valmis"; - -/* Pod power to motor activated */ -"Tank power activated" = "Säiliön virta aktivoitu"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Tilapäinen basaali"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Tilapäinen basaali meneillään"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Tilapäinen basaali käynnissä"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TilapBasaali: %1$@ U/h %2$@ %3$@ %4$@ U %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Aika vaihtaa pumppu! Pumppu vanhenee %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Yritä uudelleen"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Epävarma"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Odottamaton viestin järjestysnumero"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Odottamaton pumpun vaihto"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Odottamaton vastaus pumpusta"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Tuntematon pumppuvirhe %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Tuntematon arvo (%1$@) tyypille %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Vahvistus epäonnistui: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Odota, että meneillään oleva bolus päättyy tai kumoa bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Odota, että meneillään oleva tilapäinen basaali päättyy tai pysäytä pumppu kumotaksesi"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Odotetaan yhdistämismuistutusta"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/fr.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/fr.lproj/Localizable.strings deleted file mode 100644 index eba55ebb3..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/fr.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactif)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" a un niveau de batterie bas"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insuline ou moins restant dans le Pod. Remplacer le Pod bientôt."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Délai d'activation dépassé"; - -/* Description for auto-off */ -"Auto-off" = "Arrêt automatique"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Alarme d’arrêt automatique"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialisé"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "en dessous de 50 unités"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus en cours"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolus en cours"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolus en cours avec basal temporaire"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Canule en cours d'insertion"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Certain"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Remplacer le Pod maintenant. L'administration d'insuline s'arrêtera dans 1 heure."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Remplacer le Pod maintenant. Le Pod est actif depuis 72 heures."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Erreur de commande %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problème de com."; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Problème de communication : Commande en attente sans accusé de réception."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Les rappels de confiance retentissent pour les commandes que vous initiez, comme le bolus, l'annulation du bolus, la suspension, la reprise, l'enregistrement des rappels de notification, etc. Lorsque l'application ajuste automatiquement l'administration, aucun rappel de confiance n'est utilisé."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Des rappels de confiance retentissent lorsque l'application ajuste automatiquement la livraison ainsi que pour les commandes que vous lancez."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Erreur critique du Pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Interférences possibles. Veuillez vous déplacer vers un nouvel emplacement"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Désactivé"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Désactivé"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Réservoir vide"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Réponse vide du Pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Erreur enregistrée, arrêt en cours"; - -/* Description for expiration alert */ -"Expiration alert" = "Alerte d'expiration"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Étendu"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Bolus étendu en cours"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Bolus étendu en cours avec basal temporaire"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Une erreur s'est produite"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Terminer la désactivation"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Terminer le jumelage"; - -/* Description for finish setup */ -"Finish setup " = "Finir l'installation"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Terminer le paramétrage du rappel"; - -/* Pod inititialized */ -"Initialized" = "Initialisé"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Insertion de la canule"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "L'administration d'insuline s'est arrêtée. Changez de Pod maintenant."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insuline suspendue"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Type d'insuline non configuré"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Code d'erreur interne du Pod %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Bolus interrompu: %1$@ U (%2$@ U programmé) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Adresse invalide 0x%1$x. Attendu 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Adresse invalide: ( %1$@ )"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "CRC invalide"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Paramètre invalide"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Réservoir bas"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Avis de réservoir bas (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Alarme de réservoir bas"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Batterie RileyLink faible"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Assurez-vous que votre RileyLink est à proximité et allumé"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Débit basal manuel"; - -/* Pod memory initialized */ -"Memory initialized" = "Mémoire initialisée"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Déplacez-vous vers un nouvel endroit éloigné de tout autre Pod et réessayez."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Alerte de commande multiple"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Pas d'alarme"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Aucun rappel de confiance n'est utilisé."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Pas de défauts"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Pas d'insuline"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Aucun Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Aucun pod appairé"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Aucun Pod trouvé"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Pas de réponse du Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Aucun RileyLink disponible"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Pas assez de données"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Occlusion détectée"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Appairé"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Appairage terminé"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Erreur d'analyse : %1$@ dans (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Veuillez rapprocher le Pod original ou désactiver le Pod d'origine"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Merci de rapprocher votre Pod du RileyLink et d'essayer à nouveau"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Veuillez finir d'appairer votre Pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Merci d'appairer un nouveau Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Veuillez repositionner le RileyLink plus loin du Pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Veuillez repositionner le RileyLink par rapport au Pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod déjà appairé"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod déjà amorcé"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Erreur du Pod"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Alarme d'expiration du Pod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Notification de l'expiration du Pod"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod expiré"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Péremption du Pod dans %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Erreur du Pod: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Le Pod n’est pas dans un état prêt pour l’insertion de la canule"; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Le Pod n’est pas dans un état prêt pour l’amorçage"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Le Pod est suspendu"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Occlusion du Pod"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Appairage du Pod incomplet"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Le Pod a envoyé un ack au lieu d'une réponse"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "La fenêtre de mise en place du Pod a expiré"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Rappel de la suspension du Pod"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Faible intensité du signal"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Amorçage"; - -/* Pod state when priming completed */ -"Priming completed" = "Amorçage terminé"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Prêt pour la programmation basal"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Prêt à insérer la canule"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Rappel initialisé"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Reprendre"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Reprendre l'administration"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Reprendre l'insuline"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Reprise : %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Basal programmé"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Arrêt imminent"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarme imminente d’arrêt"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Perte de signal"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Intensité du signal trop forte"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspendre"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Rappel de suspension en cours"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Délai de suspension expiré"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspendu"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspension : %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspendu"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "La période de suspension est terminée. Ouvrez l'application et reprenez."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Remplissage du réservoir terminé"; - -/* Pod power to motor activated */ -"Tank power activated" = "Charge du réservoir activée"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Débit basal temporaire"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Basal temporaire en cours"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Basal temporaire active"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "Basal temporaire: %1$@ U/heure %2$@ %3$@ %4$@ U %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "La période de suspension de l'insuline est terminée. \n\nVous pouvez relancer l'administration à partir de la bannière sur l'écran d'accueil ou à partir de l'écran des paramètres de votre pompe. Vous recevrez un nouveau rappel dans 15 minutes."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "L'heure de votre pompe est différente de l'heure actuelle. Vous pouvez vérifier l'heure de la pompe et la synchroniser avec l'heure actuelle dans les paramètres."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Changement d'heure détecté"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "C’est le moment de remplacer votre Pod ! Votre Pod va expirer dans %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Trop de Pods trouvés"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Réessayer"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Incertain"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Numéro de séquence du message inattendu"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Changement inattendu du pod"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Reponse inattendue du Pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Erreur de Pod inconnue %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Valeur inconnue (%1$@) pour le type %2$@."; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Échec de la validation: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Attendez que le bolus en cours se termine, ou annulez le bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Attendez que le débit basal temporaire se termine pour quitter, ou mettez en suspens pour annuler"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "En attente d'appairage"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/he.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/he.lproj/Localizable.strings deleted file mode 100644 index cad728158..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/he.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactive)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" has a low battery"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Activation time exceeded"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-off alarm"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialized"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Below 50 units"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusing"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolusing with temp basal"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Cannula inserting"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Certain"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Command error %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Communication issue: Unacknowledged command pending."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Empty reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Empty response from pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Error event logged, shutting down"; - -/* Description for expiration alert */ -"Expiration alert" = "Expiration alert"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Extended bolus running"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Extended bolus running with temp basal"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fault event occurred"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Finish Pairing"; - -/* Description for finish setup */ -"Finish setup " = "Finish setup "; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Finish setup reminder"; - -/* Pod inititialized */ -"Initialized" = "Initialized"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Inserting cannula"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Internal pod fault %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Invalid address 0x%x. Expected 0x%x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Invalid address: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Invalid CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Low reservoir advisory (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Low reservoir advisory alarm"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Low RileyLink Battery"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* Pod memory initialized */ -"Memory initialized" = "Memory initialized"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "No alerts"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "No faults"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "No response from pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "No RileyLink available"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Not enough data"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Occlusion detected"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Paired"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Pairing completed"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing Error: %1$@ in (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Please bring your pod closer to the RileyLink and try again"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Please reposition the RileyLink further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Please reposition the RileyLink relative to the pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod already primed"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod expiration advisory alarm"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod Expiration Notice"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod expired"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod Fault: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod is not in a state ready for priming."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod is suspended"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "חסימה בפוד"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sent ack instead of response"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pod setup window expired"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pod suspended reminder"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Poor signal strength"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Priming"; - -/* Pod state when priming completed */ -"Priming completed" = "Priming completed"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Ready for basal programming"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Ready to insert cannula"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Reminder initialized"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Resume"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Resume delivery"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Resume: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Shutdown imminent"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Shutdown imminent alarm"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "אובדן אות"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signal strength too high"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspend"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Suspend time expired"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspended"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspend: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspended"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Tank fill completed"; - -/* Pod power to motor activated */ -"Tank power activated" = "Tank power activated"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temp Basal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temp basal in progress"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temp basal running"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Time to replace your pod! Your pod will expire in %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Uncertain"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Unexpected message sequence number"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Unexpected pod change"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Unexpected response from pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Unknown pod fault %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Unknown Value (%1$@) for type %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validation failed: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Waiting for pairing reminder"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/hu.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/hu.lproj/Localizable.strings deleted file mode 100644 index a2771255f..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/hu.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactive)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" has a low battery"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Activation time exceeded"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-off alarm"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialized"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Below 50 units"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bólus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Beadás"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolusing with temp basal"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Cannula inserting"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Certain"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Command error %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Communication issue: Unacknowledged command pending."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Empty reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Empty response from pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Error event logged, shutting down"; - -/* Description for expiration alert */ -"Expiration alert" = "Expiration alert"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Extended bolus running"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Extended bolus running with temp basal"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fault event occurred"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Finish Pairing"; - -/* Description for finish setup */ -"Finish setup " = "Finish setup "; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Finish setup reminder"; - -/* Pod inititialized */ -"Initialized" = "Initialized"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Inserting cannula"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Internal pod fault %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Invalid address 0x%x. Expected 0x%x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Invalid address: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Invalid CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Low reservoir advisory (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Low reservoir advisory alarm"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Low RileyLink Battery"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* Pod memory initialized */ -"Memory initialized" = "Memory initialized"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "No alerts"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "No faults"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "No response from pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "No RileyLink available"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Not enough data"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Occlusion detected"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Paired"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Pairing completed"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing Error: %1$@ in (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Please bring your pod closer to the RileyLink and try again"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Please reposition the RileyLink further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Please reposition the RileyLink relative to the pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod already primed"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod expiration advisory alarm"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod Expiration Notice"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod expired"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod Fault: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod is not in a state ready for priming."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod is suspended"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sent ack instead of response"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pod setup window expired"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pod suspended reminder"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Poor signal strength"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Priming"; - -/* Pod state when priming completed */ -"Priming completed" = "Priming completed"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Ready for basal programming"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Ready to insert cannula"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Reminder initialized"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Visszatérés"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Resume delivery"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Resume: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Shutdown imminent"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Shutdown imminent alarm"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signal strength too high"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Felfüggesztés"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Suspend time expired"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspended"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspend: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspended"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Tank fill completed"; - -/* Pod power to motor activated */ -"Tank power activated" = "Tank power activated"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temp Basal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temp basal in progress"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temp basal running"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Time to replace your pod! Your pod will expire in %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Uncertain"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Unexpected message sequence number"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Unexpected pod change"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Unexpected response from pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Unknown pod fault %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Unknown Value (%1$@) for type %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validation failed: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Waiting for pairing reminder"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/it.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/it.lproj/Localizable.strings deleted file mode 100644 index d69dcecd6..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/it.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = "(inattivo)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "%1$@ ha la batteria quasi scarica"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulina o meno rimanenti nel Pod. Cambia presto il Pod."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Tempo di attivazione superato"; - -/* Description for auto-off */ -"Auto-off" = "Spegnimento automatico"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Allarme spegnimento automatico"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basale inizializzata"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Inferiore a 50 unità"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolo"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolo in corso"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolo: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolo in corso"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolo con basale temp"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Inserimento cannula in corso"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Definita"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Cambia Pod ora. L'erogazione dell'insulina si interromperà tra 1 ora."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Cambia Pod ora. Il Pod è attivo da 72 ore."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Errore di comando %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problema di Comunicazione"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Problema di comunicazione: comando di conferma in attesa."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "I promemoria di fiducia suoneranno per i comandi inoltrati, come boli, cancellazione boli, sospensioni, ripristini erogazione, salvataggi di promemoria, etc. Quando iAPS invece regolerà in automatico l'erogazione allora non userà alcun promemoria di fiducia."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "I promemoria di fiducia suonano quando iAPS regola automaticamente l'erogazione e per i comandi avviati dall'utente."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Errore critico Pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Possibile dialogo incrociato. Si prega di spostarsi in una nuova posizione"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Disattivato"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabilitato"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Serbatoio vuoto"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Risposta senza contenuto dal Pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "È stato rilevato un errore. Spegnimento in corso"; - -/* Description for expiration alert */ -"Expiration alert" = "Avviso di scadenza"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Prolungato"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Bolo prolungato in esecuzione"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Bolo prolungato in esecuzione con Basale Temporanea"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Si è verificato un errore"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Disattivazione completata"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Abbinamento completato"; - -/* Description for finish setup */ -"Finish setup " = "Termina configurazione"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Promemoria configurazione completa"; - -/* Pod inititialized */ -"Initialized" = "Inizializzato"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Inserimento Cannula"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "L'erogazione d'insulina si è interrotta. Cambiare Pod adesso."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Erogazione Insulina sospesa"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Tipo d'insulina non Configurato"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Errore interno Pod %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Bolo Interrotto: %1$@ U (%2$@ U previste) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Indirizzo non valido 0x %1$x . Previsto 0x %2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Indirizzo non valido: ( %1$@ )"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "CRC non valido"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Impostazione non valida"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Livello Serbatoio basso"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Notifica serbatoio basso (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Allarme di avviso livello serbatoio basso"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Batteria Rileylink quasi scarica"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Assicurati che RileyLink si trovi nelle vicinanze e sia acceso"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Basale Manuale"; - -/* Pod memory initialized */ -"Memory initialized" = "Memoria inizializzata"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Spostati in una nuova area lontana da qualsiasi altro Pod e riprova."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Avviso di comandi multiplo"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Nessun avviso"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Non vengono utilizzati promemoria sulla fiducia."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Nessun errore"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Insulina Terminata"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Nessun Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Nessun Pod abbinato"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Nessun Pod trovato"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Nessuna risposta da Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Nessun RileyLink disponibile"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normale"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Dati non sufficienti"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Occlusione rilevata"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Abbinato"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Abbinamento completato"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Errore di analisi: %1$@ in ( %2$@ )"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Si prega di portare solo il pod originale nel raggio d'azione o disattivare il pod originale"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Avvicina Pod a RileyLink e riprova"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Completa l'abbinamento del tuo Pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Abbina nuovo Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Si prega di riposizionare il RileyLink più lontano dal Pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Si prega di riposizionare il RileyLink rispetto al Pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod già abbinato"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod già caricato"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Errore Pod"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Allarme di avviso scadenza Pod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Avviso di scadenza Pod"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod scaduto"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod scade in %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Errore Pod: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod non è pronto per l’inserimento della cannula."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod non è pronto per il caricamento"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod sospeso"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Occlusione Pod"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Accoppiamento Pod incompleto"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod ha inviato una conferma anziché una risposta"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Finestra di configurazione Pod scaduta"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Promemoria sospensione Pod"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Scarsa potenza segnale"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Caricamento in corso"; - -/* Pod state when priming completed */ -"Priming completed" = "Caricamento completato"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Pronto per la programmazione basale"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Pronto per l’inserimento della cannula"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Promemoria inizializzato"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Riprendi"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Riprendi erogazione"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Riprendi l'insulina"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Riprendi: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Basale Programmata"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Chiusura imminente"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Allarme di spegnimento imminente"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Perdita Segnale"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Potenza del segnale troppo alta"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Blocco Erogazione"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Promemoria sospensione in corso"; - -/* Description for suspend time expired */ -"Suspend time expired" = "il tempo della sospensione e' scaduto"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Sospeso"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Sospeso: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Sospeso"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Il tempo di sospensione è scaduto. Apri l'app e riprendi."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Riempimento del serbatoio completato"; - -/* Pod power to motor activated */ -"Tank power activated" = "Alimentazione del serbatoio attivata"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Basale Temporanea"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Velocità basale temporanea in corso"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Velocità basale temporanea in esecuzione"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "VelocitàBasaleTemporanea: %1$@ U/ora %2$@ %3$@ %4$@ U %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Il periodo di sospensione dell'insulina è terminato.\n\nSi puo' ripristinare l'erogazione usando direttamente l'avviso nella schermata principale oppure dalla schermata delle impostazioni del microinfusore. Ogni 15 minuti ci sara' un avviso che ti ricordera' di ripristinare l'erogazione."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "l'orario del microinfusore e' diverso da quello del tempo reale. Controllare l'orario del microinfusore e sincronizzare il settaggio con il l'orario attuale."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Rilevato Cambio di orario "; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "È ora di sostituire Pod! Pod scadrà tra %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Trovati Troppi Pods"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Riprovare"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Incerto"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Notifica inaspettata di sequenza numerica "; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Cambio pod imprevisto"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Risposta inaspettata dal Pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Errore Pod sconosciuto %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Valore sconosciuto%1$@per tipo%2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Convalida fallita: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Attendi il termine del bolo esistente oppure annulla bolo"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Attendi il termine della velocità basale temporanea esistente oppure sospendi per annullare"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "In attesa del promemoria di abbinamento"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/ja.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/ja.lproj/Localizable.strings deleted file mode 100644 index 42f946971..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/ja.lproj/Localizable.strings +++ /dev/null @@ -1,174 +0,0 @@ -/* Description for auto-off alarm */ -"Auto-off alarm" = "アラーム自動オフ"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "50Uより下"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "ボーラス"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "ボーラスが進行中"; - -/* Delivery status when bolusing */ -"Bolusing" = "ボーラス注入中"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "一時基礎とボーラス"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "カニューレ挿入中"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "確実"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "停止されました"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "リザーバが空です"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "ポッドからの反応 - 空"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "有効"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "エラーイベントを保存、終了します"; - -/* Description for expiration alert */ -"Expiration alert" = "期限切れアラート"; - -/* Description for finish setup */ -"Finish setup " = "設定終了"; - -/* Pod inititialized */ -"Initialized" = "初期化完了"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "インターナルポッドエラー %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "ボーラス中断: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "リザーバ残量低下アラーム"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "RileyLink が近くにあり電源が入っているか確認"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "アラートなし"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "ポッドペアリングできません"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "ポンド反応なし"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "RileyLinkがありません"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "通常"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "閉塞があります"; - -/* Acknowledge button label for RileyLink low battery alert - Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "ペアリングされました"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "ポッドを RileyLink に近づけてやり直してください"; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "新しいポッドをペアリングしてください"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "既にペアリングされています"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "プライミングされています"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "ポッド期限アラーム"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "ポッド期限注意"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "ポッド期限切れ"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "ポッドエラー: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "ポッドがカニューレを挿入できる状態ではありません。"; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "ポッドがプライミングできる状態ではありません。"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "ポッドが一時停止"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "ポッドの設定期限切れ"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "プライミング"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "基礎レート設定できます"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "カニューレを挿入できます"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "再開: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "定期基礎"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "今から鳴るアラームを切る"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "一時停止: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "一時停止"; - -/* Pod tank fill completed */ -"Tank fill completed" = "タンクが満たされました"; - -/* Pod power to motor activated */ -"Tank power activated" = "タンクがオンになりました"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "一時基礎進行中"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "一時基礎注入中"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "一時基礎: %1$@ U/時 %2$@ %3$@ %4$@ U %5$@"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "ポッドの交換時です。 %1$@でポッドの期限が切れます。"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "不明"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "ポッドから予期せぬ反応"; - diff --git a/Dependencies/OmniKit/OmniKit/Resources/nb.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/nb.lproj/Localizable.strings deleted file mode 100644 index eeb705f2a..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/nb.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = "(inaktiv)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\" %1$@ \" har lavt batterinivå"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin eller mindre gjenstår i Pod. Bytt Pod snart."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Aktiveringstiden er overskredet"; - -/* Description for auto-off */ -"Auto-off" = "Auto-av"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Alarm for automatisk av"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialisert"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Under 50 enheter"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus pågår"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@E %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Gir bolus"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Gir bolus med temp-basal"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Setter inn kanyle"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Sikker"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Bytt Pod nå. Insulintilførselen stoppes om 1 time."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Bytt Pod nå. Pod har vært aktiv i 72 timer."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Kommandofeil %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Kommunikasjonsutgave"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Kommunikasjonsproblem: Ukjent kommando venter."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Pod-feil"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk mulig. Vennligst flytt til et nytt sted"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktivert"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Deaktivert"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Tomt reservoar"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Tomt svar fra pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Feil logget, avslutter"; - -/* Description for expiration alert */ -"Expiration alert" = "Utløpsalarm"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Forlenget"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Forlenget boluskjøring"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Forlenget boluskjøring med temp basal"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Feilhendelse oppstod"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Fullfør deaktivering"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Fullfør sammenkoblingen"; - -/* Description for finish setup */ -"Finish setup " = "Ferdigstill oppsett"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Fullfør varselinnstilling"; - -/* Pod inititialized */ -"Initialized" = "Klargjort"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Skyter inn kanyle"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulintilførselen stoppet. Bytt Pod nå."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulintilførsel utsatt"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulintype ikke konfigurert"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Intern pod-feil %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "InterruptedBolus: %1$@ E (%2$@ E planlagt) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Ugyldig adresse 0x%1$x. Forventet 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Ugyldig adresse: ( %1$@ )"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Ugyldig CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ugyldig konfigurasjon"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Lavt reservoar"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Varsel om lavt reservoar (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Anbefalt alarm for lavt reservoar"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Lavt RileyLink-batteri"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Pass på at din RileyLink er slått på og er i nærheten"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuell basal"; - -/* Pod memory initialized */ -"Memory initialized" = "Minne initialisert"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Flytt til et nytt område borte fra andre pods og prøv igjen."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Alarm for fler-kommandoer"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Ingen alarmer"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Ingen aktive påminnelser."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Ingen feil"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Ingen insulin"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Ingen Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Ingen sammenkoblet pod"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Ingen pod funnet"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Ingen svar fra pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Ingen RileyLink tilgjengelig"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normalt"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Ikke nok data"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Tilstoppelse oppdaget"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Sammenkoblbet"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Sammenkobling fullført"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Analysefeil: %1$@ i (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Ta kun med original pod innenfor rekkevidde eller deaktiver original pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Prøv å sette pod og RileyLink nærmere hverandre og prøv så igjen"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Vennligst fullfør sammenkoblingen av pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Vennligst koble til ny pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Vennligst flytt RileyLink lenger fra pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Vennligst flytt RileyLink i forhold til pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod er allerede sammenkoblet"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod er allerede fyllt"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Feil"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Anbefalt utløpsalarm for pod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Utløpsmelding for pod"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod utløpt"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod utløper om %1$@ ."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod-feil: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod er ikke klar for å sette inn kanyle."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod er ikke klar for fylling"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod er suspendert"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Okklusjon"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Ufullstendig Pod-sammenkobling"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sendte ack i stedet for svar"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Tidsvindu for oppsett av pod er utløpt"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pod påminnelse er suspendert"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Dårlig signalstyrke"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Fyller"; - -/* Pod state when priming completed */ -"Priming completed" = "Fylling fullført"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Klar for basal-programmering"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Klar for å sette inn kanyle"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Påminnelse initialisert"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Gjenoppta"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Gjenoppta levering"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Gjenoppta insulin"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Fortsett: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Planlagt basal"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Avslutning nært forestående"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Avslutt forestående alarm"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Tap"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signalstyrken er for høy"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Utsette"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Varsel om aktivert Utsettelse"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Utsettelse utløpt"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspendert"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Pause: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspendert"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Utsettelsestiden er over. Åpne appen og gjenoppta."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Tankpåfylling komplett"; - -/* Pod power to motor activated */ -"Tank power activated" = "Tank-motor aktivert"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Midlertidig basal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Midlertidig basal pågår"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Midlertidig basal kjører"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "Midlertidig basal: %1$@ E/time %2$@ %3$@ %4$@ E %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Perioden med insulinsuspensjon er avsluttet.\n\nDu kan gjenoppta leveringen fra banneret på startskjermen eller fra skjermbildet for pumpeinnstillinger. Du vil bli påminnet igjen om 15 minutter."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Klokken på pumpen er forskjellig fra gjeldende tid. Du kan se på pumpetiden og og synkronisere med gjeldende tid i innstillingene."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Tidsendring oppdaget"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Det er på tide å bytte pod! Pod utløper om %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "For mange poder funnet"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Prøv igjen"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Usikker"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Uventet meldings sekvensnummer"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Uventet pod-endring"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Uventet svar fra pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Ukjent pod-feil %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Ukjent verdi ( %1$@ ) for typen %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Valideringen mislyktes: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Vent til at eksisterende bolus skal bli ferdig, eller kanseler bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Venter på at eksisterende temp-basal skal bli ferdig, eller at pause skal avsluttes"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Venter på påminnelse for sammenkobling"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/nl.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/nl.lproj/Localizable.strings deleted file mode 100644 index 3fd6ea304..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/nl.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactief)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" batterij bijna leeg"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insuline of minder resterend in Pod. Vervang Pod spoedig."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Activeringstijd overschreden"; - -/* Description for auto-off */ -"Auto-off" = "Automatische uitschakeling"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-uit alarm"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basaal geïnitialiseerd"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Minder dan 50 eenheden"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus in uitvoering"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@E %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolussen"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolussen met tijdelijk basaal"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Canule wordt geplaatst"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Zeker"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Vervang Pod nu. Insulinetoediening stopt over 1 uur."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Vervang Pod nu. Pod is 72 uur in gebruik geweest."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Opdrachtfout %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Communicatieprobleem"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Communicatieprobleem: niet-bevestigde opdracht in behandeling"; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Piepjes uit de Pod zullen klinken voor commando's die je hebt geïnitieerd, zoals bolus, annulering, geschorst, hervatten, opslaan van meldingen etc. Als iAPS automatisch de levering wijzigt, worden er geen piepjes gebruikt."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Piepjes zullen klinken als iAPS de levering automatisch aanpast evenals voor commando's die je initieert."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritieke Pod fout"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Ruis mogelijk. Verplaats alsjeblieft naar een andere locatie"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Gedeactiveerd"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Uitgeschakeld"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Reservoir leeg"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Geen reactie van pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Fout geconstateerd, sluit af"; - -/* Description for expiration alert */ -"Expiration alert" = "Alarm vervaltijd"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Uitgebreid"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Verlengde bolus actief"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Verlengde bolus met tijdelijk basaal actief"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fout is opgetreden"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Voltooi deactivering"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Voltooi koppelen"; - -/* Description for finish setup */ -"Finish setup " = "Voltooi installatie"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Voltooi instelling van herinnering"; - -/* Pod inititialized */ -"Initialized" = "Geinitialiseerd"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Canule inbrengen"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulinetoediening gestopt. Vervang pod nu."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insuline onderbroken"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulinetype niet ingesteld"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Interne Pod fout %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Onderbroken bolus: %1$@ E (%2$@ E gepland) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Ongeldig adres 0x%1$x. Verwachtte 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Ongeldig adres: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Ongeldige CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ongeldige Instelling"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Reservoir bijna leeg"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Reservoir bijna leeg advies (%1$gE)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Reservoir bijna leeg alarm"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Batterij RileyLink bijna leeg"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Zorg ervoor dat je RileyLink dicht bij is en aan staat"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Handmatig basaal"; - -/* Pod memory initialized */ -"Memory initialized" = "Geheugen geïnitialiseerd"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Ga naar een andere plek, weg van andere pods en probeer opnieuw."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Waarschuwing voor meerdere commando's"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Geen waarschuwingen"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Er worden geen meldingen met piepjes gebruikt."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Geen fouten"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Geen insuline"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Geen pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Geen Pod gekoppeld"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Geen Pods gevonden"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Geen reactie van Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Geen RileyLink beschikbaar"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normaal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Onvoldoende gegevens"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Verstopping gedetecteerd"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Gekoppeld"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Koppelen voltooid"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parseerfout: %1$@ in (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Breng alleen de oude Pod binnen bereik of deactiveer de originele Pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Breng de Pod dichter bij de RileyLink en probeer opnieuw"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Voltooi het koppelen van je Pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Koppel een nieuwe Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Plaats de RileyLink verder van de Pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Verplaats de RileyLink ten opzichte van de Pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod al gekoppeld"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod is al voorbereid"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod fout"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod vervaltijd advies alarm"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod vervaltijd aankondiging"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod is verlopen"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod verloopt over %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod fout: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is niet gereed voor inbrengen canule."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod is niet klaar om voorbereid te worden."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod is onderbroken"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod verstopping"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Koppeling Pod Onvolledig"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod heeft een bevestiging gestuurd in plaats van een antwoord"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Insteltijd van de Pod is verlopen"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Herinnering onderbroken Pod"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Zwakke signaalsterkte"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Voorbereiden"; - -/* Pod state when priming completed */ -"Priming completed" = "Voorbereiden voltooid"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Klaar voor programmeren basaal"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Gereed voor inbrengen canule"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Herinnering geïnitialiseerd"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Hervatten"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Hervat toediening"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Hervat insuline"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Hervat: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Ingesteld basaal"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Afsluiting nadert"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarm voor naderende afsluiting"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signaalverlies"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signaalsterkte te hoog"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Onderbreek"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Herinnering 'Onderbreking in uitvoering'"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Onderbrekingstijd verstreken"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Onderbroken"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Onderbreek: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Onderbroken"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "De onderbrekingsperiode is verstreken. Open iAPS en hervat."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Opslag vullen compleet"; - -/* Pod power to motor activated */ -"Tank power activated" = "Opslag power geactiveerd"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Tijdelijk basaal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Tijdelijk basaal wordt uitgevoerd"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Tijdelijk basaal actief"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "Tijdelijk basaal: %1$@ E/uur %2$@ %3$@ %4$@ E %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "De insulineonderbrekingsperiode is verstreken.\n\nJe kunt de toediening hervatten op het startscherm of via je pompinstellingenscherm. Over 15 minuten word je er opnieuw aan herinnerd."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "De tijd op je pomp is anders dan de huidige tijd. Je kunt de tijd op de pomp bekijken en synchroniseren met de huidige tijd in instellingen."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Tijdsverschil ontdekt"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Tijd om je pod te vervangen! Vervang je pod in %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Te veel pods gevonden"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Probeer opnieuw"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Onzeker"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Onverwacht volgnummer van bericht"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Onverwachte Pod wissel"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Onverwachte reactie van Pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Onbekende Pod fout %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Onbekende waarde (%1$@) voor type %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validatie mislukt: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wacht tot huidige bolus is voltooid, of annuleer bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wacht tot de huidig tijdelijk basaalsnelheid is voltooid, of onderbreek om te annuleren"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Wacht op herinnering om te verbinden"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/pl.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/pl.lproj/Localizable.strings deleted file mode 100644 index b4708a58d..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/pl.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (nieaktywny)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "„ %1$@ ” ma słabą baterię"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "Pozostało mniej niż 1$@ insuliny w POD. Zmień wkrótce POD'a."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Przekroczono czas aktywacji"; - -/* Description for auto-off */ -"Auto-off" = "Automatyczne wyłączanie"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Alarm automatycznego wyłączenia"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Zainicjowano bazę"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Poniżej 50 jedn."; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus w toku"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Podawanie bolusa"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Podawanie bolusa z dawką podstawową"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Wprowadzanie kaniuli"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Pewna"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Zmień POD'a teraz. Podawanie insuliny zostanie wstrzymane za 1 godzinę."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Zmień teraz POD'a. POD jest aktywny od 72 godzin."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Błąd polecenia %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problem z komunikacją"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Problem z komunikacją: Niepotwierdzone polecenie w toku."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Krytyczny błąd POD'a"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Możliwe zakłócenia. Proszę teleportuj się do innego pomieszczenia"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktywowany"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Wyłączony"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Pusty zbiornik"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Pusta odpowiedź POD"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Zarejestrowano zdarzenie błędu, wyłączanie"; - -/* Description for expiration alert */ -"Expiration alert" = "Alert o upływie terminu ważności"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Rozszerzony"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Trwa podawanie bolusa przedłużonego"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Bolus przedłużony uruchomiony z tymczasową bazą"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Wystąpiła usterka"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Zakończ dezaktywację"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Zakończ parowanie"; - -/* Description for finish setup */ -"Finish setup " = "Zakończ konfigurację"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Przypomnienie o zakończeniu konfiguracji"; - -/* Pod inititialized */ -"Initialized" = "Zainicjalizowany"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Wprowadzanie kaniuli"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Podawanie insuliny zostało zatrzymane. Wymień POD'a."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Podawanie insuliny zawieszone"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Nie skonfigurowano rodzaju insuliny"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Wewnętrzny błąd POD'a %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Przerwany bolus: %1$@ jedn. (%2$@ jedn. zaplanowanych) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Nieprawidłowy adres 0x %1$x . Oczekiwano 0x %2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Nieprawidłowy adres: ( %1$@ )"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Nieprawidłowy CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Nieprawidłowe ustawienie"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Niski poziom w zbiorniczku"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Ostrzeżenie o niskim poziomie w zbiorniczku (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Alarm informujący o niskim poziomie w zbiorniku"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Niski poziom baterii RileyLink"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Upewnij się, że RileyLink jest w pobliżu i jest włączony"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Baza podstawowa"; - -/* Pod memory initialized */ -"Memory initialized" = "Zainicjowano pamięć"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Przenieś się w nowe miejsce z dala od innych POD'ów i spróbuj ponownie."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Alert wielu poleceń"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Brak alertów"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Nie są używane żadne przypomnienia."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Brak usterek"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Brak insuliny"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Brak POD'a"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Brak sparowanego PODa"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Nie znaleziono POD'a"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Brak odpowiedzi z PODa"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Brak dostępnego RileyLink"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normalny"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Za mało danych"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Wykryto niedrożność"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Sparowany"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Parowanie zakończone"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Błąd analizy: %1$@ w (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Używaj tylko oryginalny POD w zasięgu sygnału albo dezaktywuj oryginalny POD"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Umieść PODa bliżej RileyLink i spróbuj ponownie"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Dokończ parowanie POD'a."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Sparuj nowego PODa"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Proszę przesunąć RileyLink dalej od POD'a."; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Proszę zmienić położenie RileyLink względem POD'a."; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "POD już sparowany"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "POD już napełniony"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Błąd POD'a"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Alarm informujący o upływie terminu ważności PODa"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Powiadomienie o upływie terminu ważności PODa"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Termin ważności POD'a upłynął"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod wygasa za %1$@ ."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Usterka PODa: 1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "POD nie znajduje się w stanie gotowości do wprowadzenia kaniuli."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "POD nie znajduje się w stanie gotowości do napełniania."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "POD wstrzymany"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Niedrożność POD'a"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Parowanie POD'a nie zostało zakończone"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "POD odtworzył sygnał zamiast odpowiedzi zwrotnej"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Upłynął termin ważności okna konfiguracji PODa"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Przypomnienie o zawieszeniu POD'a"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Słaba siła sygnału"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Napełnianie"; - -/* Pod state when priming completed */ -"Priming completed" = "Wypełnianie zakończone"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Gotowy do zaprogramowania dawki podstawowej"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Gotowy do wprowadzenia kaniuli"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Zainicjowano przypomnienie"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Wznów"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Wznów podawanie"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Wznów insulinę"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Wznów: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Zaplanowana dawka podstawowa"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Informacja o zbliżającym się wyłączeniu"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarm o nadchodzącym wyłączeniu"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Utrata sygnału"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Zbyt wysoka siła sygnału"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Wstrzymaj"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Przypomnienie o trwającym zawieszeniu"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Upłynął czas zawieszenia"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Wstrzymane"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Wstrzymaj: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Wstrzymane"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Czas zawieszenie dobiegł końca. Otwórz Loop i wznów podawanie"; - -/* Pod tank fill completed */ -"Tank fill completed" = "Napełnianie zbiornika zakończone"; - -/* Pod power to motor activated */ -"Tank power activated" = "Zasilanie zbiornika włączone"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Tymczasowa dawka podstawowa"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Tymczasowa dawka podstawowa w toku"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Tymczasowa dawka podstawowa działa"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "Tymczasowa dawka podstawowa: %1$@ jedn./godz. %2$@ %3$@ %4$@ jedn. %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Okres zawieszenia podawania insuliny dobiegł końca. \n\nPodawanie można wznowić za pomocą banera na ekranie głównym lub na ekranie ustawień pompy. Ponowne przypomnienie pojawi się za 15 minut."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Czas na pompie różni się od aktualnego czasu. W ustawieniach można sprawdzić czas pompy i zsynchronizować go z aktualnym czasem."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Wykryto zmianę czasu"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Pora wymienić PODa! Termin ważności PODa upłynie za %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Znaleziono zbyt wiele POD'ów"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Spróbuj ponownie"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Niepewna"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Nieoczekiwany numer kolejnego komunikatu"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Nieoczekiwana zmiana POD'a"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Nieoczekiwana odpowiedź PODa"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Nieznany błąd POD'a %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Nieznana wartość (%1$@) dla typu %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Weryfikacja nie powiodła się: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Poczekaj na zakończenie istniejącego bolusa lub anuluj bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Poczekaj na zakończenie istniejącej dawki podstawowej lub wstrzymaj, aby anulować"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Poczekaj na przypomnienie o parowaniu"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/pt-BR.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/pt-BR.lproj/Localizable.strings deleted file mode 100644 index 6e7f03859..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactive)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" has a low battery"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Activation time exceeded"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Alarme de desligamento automático"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialized"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Abaixo de 50 unidades"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus em andamento"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Entregando Bolus"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Aplicando bolus com basal temp"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Inserindo Cânula"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Certo"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Command error %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Communication issue: Unacknowledged command pending."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Desativado"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Reservatório vazio"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Resposta vazia do pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Evento de erro registrado, desligando"; - -/* Description for expiration alert */ -"Expiration alert" = "Alerta de expiração"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Extended bolus running"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Extended bolus running with temp basal"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fault event occurred"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Finish Pairing"; - -/* Description for finish setup */ -"Finish setup " = "Concluir configuração"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Finish setup reminder"; - -/* Pod inititialized */ -"Initialized" = "Inicializado"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Inserting cannula"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Falha interna do pod %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "BolusInterrompido: %1$@ U (%2$@ U agendado) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Invalid address 0x%x. Expected 0x%x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Invalid address: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Invalid CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Low reservoir advisory (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Alarme de baixo reservatório"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Low RileyLink Battery"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Verifique se o seu RileyLink está próximo e ligado"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* Pod memory initialized */ -"Memory initialized" = "Memory initialized"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Sem alertas"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "No faults"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Nenhum pod emparelhado"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Nenhuma resposta do pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Nenhum RileyLink disponível"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Not enough data"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Oclusão detectada"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Emparelhado"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Pairing completed"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing Error: %1$@ in (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Traga seu pod para mais perto do RileyLink e tente novamente"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Emparelhe um novo pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Please reposition the RileyLink further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Please reposition the RileyLink relative to the pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod já emparelhado"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod já preparado"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Alarme de expiração do pod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Aviso de Expiração do Pod"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod expirado"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Falha no Pod: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "O Pod não está pronto para a inserção da cânula."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "O Pod não está em um estado pronto para preparação."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "O pod está suspenso"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sent ack instead of response"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "A janela de configuração do pod expirou"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pod suspended reminder"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Poor signal strength"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Preparando"; - -/* Pod state when priming completed */ -"Priming completed" = "Priming completed"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Pronto para programação basal"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Pronto para inserir a cânula"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Reminder initialized"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Resume"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Resume delivery"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Retomar: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Basal Agendado"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Shutdown imminent"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarme de desligamento iminente"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signal strength too high"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspend"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Suspend time expired"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspenso"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspender: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspenso"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Enchimento do tanque concluído"; - -/* Pod power to motor activated */ -"Tank power activated" = "Alimentação do tanque ativada"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temp Basal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Basal temporária em andamento"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Executando basal temporária"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "BasalTemp: %1$@ U/hora %2$@ %3$@ %4$@ U %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Hora de substituir o seu pod! Seu pod expirará em %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Incerto"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Unexpected message sequence number"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Unexpected pod change"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Resposta inesperada do pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Falha desconhecida do pod %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Unknown Value (%1$@) for type %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validation failed: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Aguarde a conclusão do bolus existente ou cancele-o"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Aguarde até que a basal temp existente termine ou suspenda para cancelar"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Aguardando lembrete de emparelhamento"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/pt-PT.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/pt-PT.lproj/Localizable.strings deleted file mode 100644 index c84ab1321..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/pt-PT.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactive)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" has a low battery"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin or less remaining in Pod. Change Pod soon."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Activation time exceeded"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-off alarm"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialized"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Below 50 units"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus in progress"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Aplicando bolus"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolusing with temp basal"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Cannula inserting"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Certain"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Change Pod now. Insulin delivery will stop in 1 hour."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Change Pod now. Pod has been active for 72 hours."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Command error %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Communication issue: Unacknowledged command pending."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deactivated"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Empty reservoir"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Empty response from pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Error event logged, shutting down"; - -/* Description for expiration alert */ -"Expiration alert" = "Expiration alert"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Extended bolus running"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Extended bolus running with temp basal"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fault event occurred"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Finish Pairing"; - -/* Description for finish setup */ -"Finish setup " = "Finish setup "; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Finish setup reminder"; - -/* Pod inititialized */ -"Initialized" = "Initialized"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Inserting cannula"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Internal pod fault %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Invalid address 0x%x. Expected 0x%x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Invalid address: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Invalid CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Low reservoir advisory (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Low reservoir advisory alarm"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Low RileyLink Battery"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Make sure your RileyLink is nearby and powered on"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* Pod memory initialized */ -"Memory initialized" = "Memory initialized"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "No alerts"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "No faults"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "No Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "No pod paired"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "No response from pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "No RileyLink available"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Not enough data"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Occlusion detected"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Paired"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Pairing completed"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing Error: %1$@ in (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Please bring your pod closer to the RileyLink and try again"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Please finish pairing your pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Please pair a new pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Please reposition the RileyLink further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Please reposition the RileyLink relative to the pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod already paired"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod already primed"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod expiration advisory alarm"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod Expiration Notice"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod expired"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod expires in %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod Fault: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod is not in a state ready for cannula insertion."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod is not in a state ready for priming."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod is suspended"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Pairing Incomplete"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sent ack instead of response"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pod setup window expired"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pod suspended reminder"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Poor signal strength"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Priming"; - -/* Pod state when priming completed */ -"Priming completed" = "Priming completed"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Ready for basal programming"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Ready to insert cannula"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Reminder initialized"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Resume"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Resume delivery"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Resume Insulin"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Resume: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Shutdown imminent"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Shutdown imminent alarm"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signal strength too high"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspend"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Suspend time expired"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspended"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspend: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspended"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Suspension time is up. Open the app and resume."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Tank fill completed"; - -/* Pod power to motor activated */ -"Tank power activated" = "Tank power activated"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temp Basal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temp basal in progress"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temp basal running"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Time Change Detected"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Time to replace your pod! Your pod will expire in %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Uncertain"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Unexpected message sequence number"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Unexpected pod change"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Unexpected response from pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Unknown pod fault %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Unknown Value (%1$@) for type %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validation failed: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Wait for existing bolus to finish, or cancel bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Wait for existing temp basal to finish, or suspend to cancel"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Waiting for pairing reminder"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/ro.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/ro.lproj/Localizable.strings deleted file mode 100644 index 017cd6bb1..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/ro.lproj/Localizable.strings +++ /dev/null @@ -1,475 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactiv)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" are o baterie scăzută"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ de insulină sau mai puțin rămase în Pod. Schimbați Pod-ul în curând."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Timpul de activare a fost depășit"; - -/* Description for auto-off */ -"Auto-off" = "Oprire automată"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Alarmă Auto-off"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Bazală inițializată"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Sub 50 de unități"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus în derulare"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolus în derulare"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolus în derulare cu rata bazală temporară"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Se inserează canula"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Doză confirmată"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Schimbați Pod-ul acum. Administrarea insulinei se va opri într-o oră."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Schimbați Pod-ul acum. Pod-ul a fost activ timp de 72 de ore."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Eroare comandă %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problemă de comunicații"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Problemă de comunicare: comandă nerecunoscută în așteptare."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Mementourile de confirmare vor suna pentru comenzile pe care le inițiați, precum bolus, anualarea bolusului, suspendare, reluare, salvarea mementourilor de confirmare etc. Când Loop ajustează automat administrarea, nu sunt folosite mementouri de confirmare."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Mementourile de confirmare vor suna atunci când Loop ajustează automat administrare, precum și pentru comenzile pe care le inițiați."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Eroare critică Pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Interferență posibilă. Vă rugăm să vă mutați într-o zonă nouă"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Dezactivat"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Dezactivat"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Rezervor gol"; - -/* The title for Empty Reservoir alarm notification */ -"Empty Reservoir" = "Rezervor gol"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Răspuns gol primit de la Pod"; - -/* Title string for BeepPreference.manualCommands */ -"Enabled" = "Activat"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Eroare înregistrată în jurnal, se oprește"; - -/* Description for expiration advisory */ -"Expiration advisory" = "Aviz de expirare"; - -/* Description for expiration alert */ -"Expiration alert" = "Alertă expirare"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Prelungit"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Bolus prelungit activat"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Bolus prelungit activ împreună cu bazală temporară"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "A avut loc un eveniment de eroare"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Finalizați deactivarea"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Finalizați asocierea"; - -/* Description for finish setup */ -"Finish setup " = "Finalizare setare"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Memento pentru finalizarea configurării"; - -/* Pod inititialized */ -"Initialized" = "Inițializat"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Se inserează canula"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Administrarea de insulină s-a oprit. Schimbați Pod-ul acum."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Administrarea insulinei suspendată"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Tipul de insulină nu este configurat"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Defecțiune Pod internă %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "BolusÎntrerupt: %1$@ U (%2$@ U planificat) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Adresă invalidă 0x%1$x. Se aștepta 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Adresă invalidă: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "CRC invalid"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Setare invalidă"; - -/* Pod state when running with fifty or less units */ -"Low reservoir" = "Rezervor scăzut"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Rezervor scăzut"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Avertizare de rezervor scăzut (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Alarmă nivel scăzut rezervor"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Baterie RileyLink scăzută"; - -/* Recovery suggestion for PodCommsError.noPodsFound */ -"Make sure your pod is filled and nearby." = "Asigurați-vă că Pod-ul este umplut și în apropiere."; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Asigurați-vă că RileyLink este pornit și situat în apropriere"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Bazală manuală"; - -/* Pod memory initialized */ -"Memory initialized" = "Memorie inițializată"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Mutați-vă într-o zonă nouă, departe de orice alte Pod-uri și încercați din nou."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Alertă de comandă multiplă"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Nicio alertă"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Nu se folosesc mementouri de confimare."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Nicio defecțiune"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Fără insulină"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Niciun Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Niciun Pod asociat"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Nu s-au găsit Pod-uri"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Nu s-a primit răspuns de la Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Nu există un RileyLink disponibil"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Nu sunt suficiente date"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Ocluzie detectată"; - -/* The title for Occlusion alarm notification */ -"Occlusion Detected" = "Ocluzie detectată"; - -/* Action button default text for PodAlerts */ -"Ok" = "Ok"; - -/* Acknowledge button label for RileyLink low battery alert - Alert acknowledgment OK button */ -"OK" = "OK"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod state oneNotUsed */ -"oneNotUsed" = "oneNotUsed"; - -/* Pod status after pairing */ -"Paired" = "Asociat"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Asociere finalizată"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Eroare de parsare: %1$@ în ( %2$@ )"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Vă rugăm să aduceți doar Pod-ul inițial în rază de acțiune sau dezactivați Pod-ul inițial"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Apropiați Pod-ul de RileyLink și încercați din nou"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Vă rugăm să terminați asocierea Pod-ului."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Asociați un Pod nou"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Vă rugăm să poziționați RileyLink mai departe de pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Va rugăm să poziționați RileyLink mai aproape de pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please try repositioning the pod or the RileyLink and try again" = "Vă rugăm să încercați să repoziționați pod-ul sau RileyLink și să încercați din nou"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod deja asociat"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod deja amorsat"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Eroare Pod"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Alarmă expirare Pod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Notificare expirare Pod"; - -/* Alert content title for userPodExpiration pod alert */ -"Pod Expiration Reminder" = "Memento pentru expirarea Pod-ului"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod-ul a expirat."; - -/* Alert content title for podExpireImminent pod alert - Alert content title for podExpiring pod alert - Status highlight message for podExpired alarm. - The title for Pod Expired alarm notification */ -"Pod Expired" = "Pod Expirat"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod-ul expiră în %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Defecțiune Pod: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod-ul nu este pregătit pentru inserarea canulei."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod nu este pregătit pentru amorsare."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod-ul este suspendat"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Ocluzie Pod"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Asocierea Pod-ului este nefinalizată."; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod-ul a trimis o confirmare în loc de răspuns"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Intervalul de timp în care se poate seta Pod-ul a expirat"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Memento pentru Pod-ul suspendat"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Putere slabă a semnalului"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Se amorsează"; - -/* Pod state when priming completed */ -"Priming completed" = "Inițiere finalizată"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Pregătit pentru programarea bazalelor"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Pregătit pentru inserarea canulei"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Memento inițializat"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Reluați"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Reluați administrarea de insulină"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Reluați administrarea de insulină"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Reluare: %1$@ %2$@"; - -/* Delivery status when scheduled basal is running */ -"Scheduled basal" = "Bazala programată"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Bazală programată"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Oprirea iminentă"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Alarmă de oprire iminentă"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Pierdere de semnal"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Puterea semnalului este prea mare"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Suspendați"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Memento pentru suspendarea în curs"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Timpul de suspendare a expirat"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Suspendare: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Suspendat"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Timpul de suspendare a expirat. Deschideți aplicația și reluați."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Umplere rezervor completă"; - -/* Pod power to motor activated */ -"Tank power activated" = "Putere motor rezervor activată"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Bazală temporară"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Bazală temporară în curs de rulare"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Bazala temporară este în curs de rulare"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "BasalăTemporară: %1$@ U/oră %2$@ %3$@ %4$@ U %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Perioada de suspendarea a administrării de insulină s-a încheiat.\n\nPuteți relua administrarea din bannerul de pe ecranul principal sau de pe ecranul de setări al pompei. Vi se va aminti din nou în 15 minute."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Ora de pe pompă este diferită de ora actuală. Puteți revizui ora pompei și să o sincronizați cu ora actuala în meniul setări."; - -/* Pod state threeNotUsed */ -"threeNotUsed" = "threeNotUsed"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "S-a detectat schimbarea orei"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "E timpul să înlocuiți Pod-ul! Acesta va expira în %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Au fost găsite prea multe Pod-uri"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Încercați din nou"; - -/* Pod state twoNotUsed */ -"twoNotUsed" = "twoNotUsed"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Doză neconfirmată"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Mesaj neașteptat număr de ordine"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Schimbare neașteptată a podului"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Răspuns neașteptat de la Pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Defecțiune Pod neidentificată %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Valoare necunoscută ( %1$@ ) pentru tipul %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validarea a eșuat: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Așteptați finalizarea bolusului curent sau opriți bolusul"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Așteptați finalizarea bazalei temporare curente sau suspendați pentru oprirea ei"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Se așteaptă mementoul de asociere"; - diff --git a/Dependencies/OmniKit/OmniKit/Resources/ru.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/ru.lproj/Localizable.strings deleted file mode 100644 index 07866cf7f..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/ru.lproj/Localizable.strings +++ /dev/null @@ -1,432 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = "(неактивно)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" имеет низкий заряд батареи"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ дБ"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "В поде осталось %1$@ инсулина или меньше. Замените под в ближайшее время."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Превышено время для активации"; - -/* Description for auto-off */ -"Auto-off" = "Авто выключение"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Авто отключение сигнала"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Базал инициирован"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Менее 50 единиц"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Болюс"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Подача болюса"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Болюс: %1$@ед %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Подается болюс"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Подача болюса при подаче ВБС"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Установка катетера"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Определенно"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Замените под сейчас. Подача инсулина прекратится через 1 час."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Замените под сейчас. Под активен в течение уже 72 часов."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Ошибка команды %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Проблемы со связью"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Проблема со связью: ожидается неподтвержденная команда."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Доверенные звуковые сигналы сработают для операций, которые Вы инициируете - Болюс, Отмена Болюса, Приостановка подачи, Возобновление подачи, Сохранение напоминаний и т. д. Когда петля автоматически меняет подачу инсулина - звуковые сигналы не используются."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Доверенные звуковые сигналы сработают даже тогда, когда петля автоматически изменит подачу инсулина, а также для команд, которые Вы инициируете."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Доверенные звуковые сигналы сработают даже тогда, когда петля автоматически изменит подачу инсулина, а также для команд, которые Вы инициируете."; ->>>>>>> 420dc4ed (Crowdin (#362)) - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Критическая ошибка пода"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Возможны перекрестные помехи. Пожалуйста, переместитесь на новое место"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Не активен"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Выключено"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Резервуар пуст"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Пустой ответ от пода"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Ошибка записана в лог, отключение"; - -/* Description for expiration alert */ -"Expiration alert" = "Оповещение об истечении срока"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Растянутый"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Вводится растянутый болюс"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Продленный болюс с временной базальной скоростью"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Произошло событие неисправности"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Завершение деактивации"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Завершение сопряжения"; - -/* Description for finish setup */ -"Finish setup " = "Завершение настройки"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Напоминание о завершении настройки"; - -/* Pod inititialized */ -"Initialized" = "Активирован"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Введение катетера"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Введение инсулина остановлено. Замените Под."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Подача инсулина приостановлена"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Тип инсулина не указан"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Внутренняя ошибка пода %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Болюс прерван%1$@ ед (%2$@ ед намечено) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Неверный адрес 0x%1$x. Ожидаемый адрес 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Неверный адрес: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Неверный CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Неверная настройка"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Мало инсулина в резервуаре"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Предупреждение о низком уровне резервуара (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Оповещение о малом запасе инсулина в резервуаре"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Низкий заряд батареи RileyLink"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Убедитесь, что RileyLink находится поблизости и включен"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Ручная ВБС"; - -/* Pod memory initialized */ -"Memory initialized" = "Память инициализирована"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Переместитесь на новое место подальше от других подов и повторите попытку."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Оповещение по нескольким командам"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Активных оповещений нет"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Напоминания о доверии не используются."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Ошибок нет"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Нет инсулина"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Нет пода"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Нет сопряженного пода"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Подов не найдено"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Нет ответа от пода"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Нет доступного RileyLink"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Норма"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Недостаточно данных"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Обнаружена закупорка"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Омнипод"; - -/* Pod status after pairing */ -"Paired" = "Сопряжен"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Сопряжение завершено"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Ошибка синтаксического анализа: %1$@ in (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Пожалуйста, приносите в зону действия только оригинальный под или деактивируйте оригинальный под"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Поднесите Omnipod ближе к RileyLink и попробуйте снова"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Пожалуйста, завершите сопряжение вашего пода."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Начните сопряжение с новым Omnipod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Пожалуйста, переместите RileyLink подальше от пода"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Пожалуйста, измените положение RileyLink относительно пода"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Omnipod уже сопряжен"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Omnipod уже прокачан инсулином"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Ошибка пода"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Оповещение об окончании срока работы Omnipod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Сообщение об окончании гарантийного срока Omnipod "; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Срок работы Omnipod истек"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Под истекает в %1$@"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Отказ Omnipod %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Omnipod не готов к установке катетера"; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Omnipod не готов к прокачиванию инсулина"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Omnipod приостановлен"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Закупорка пода"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Сопряжение с подом не выполнено"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod отправил \"ack\" вместо ответа (ему кирдык)"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Время для ввода настроек Omnipod истекло"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Напоминание о приостановке подачи инсулина"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Плохой уровень сигнала"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Прокачивание инсулина"; - -/* Pod state when priming completed */ -"Priming completed" = "Прокачка инсулина завершена"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Готов к программированию базала"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Готов к установке катетера"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Инициализация напоминания"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Возобновление"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Возобновить подачу"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Возобновить подачу"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Возобновление: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Запланированная база"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Выключение неизбежно"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Оповещение о неизбежном выключении"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Сигнал потерян"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Слишком высокий уровень сигнала"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Приостановка"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Напоминание о приостановке подачи инсулина"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Время приостановки подачи истекло"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Остановлено"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Приостановка: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Остановлено"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Время приостановки подачи инсулина истекло. Откройте приложение и возобновите подачу."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Заполнение резервуара Omnipod завершено"; - -/* Pod power to motor activated */ -"Tank power activated" = "Питание моторчика резервуара активировано"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "ВБС"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Пока еще работает временный базал"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Подается временный базал"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "Врем базал: %1$@ ед/ч %2$@ %3$@ %4$@ ед %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Период приостановки подачи инсулина закончилось.\n\nВы можете возобновить введение инсулина с баннера на главном экране приложения или с экрана настроек вашей помпы. Через 15 минут вы получите повторное напоминание."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Время на вашей помпе отличается от текущего времени. Вы можете проверить время на помпе и синхронизировать его с текущим временем в настройках приложения."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Обнаружено изменение времени"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Пора заменить Pod - Срок годности истекает через %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Найдено слишком много подов"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Попробуйте еще раз"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Не подтверждено"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Неожиданный порядковый номер сообщения"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Неожиданная смена пода"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Неожиданный отклик Omnipod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Неизвестная неисправность Omnipod %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Неизвестное значение ( %1$@ ) для типа %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Ошибка проверки: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Дождитесь окончания подачи болюса или отмените его"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Дождитесь окончания введения текущей ВБС или остановите помпу для отмены"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Все еще ожидается сопряжение"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/sk.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/sk.lproj/Localizable.strings deleted file mode 100644 index 33fb8ddc6..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/sk.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = "{neaktívne}"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" má slabú batériu"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "V podu zostáva %1$@ inzulínu alebo menej. Čoskoro vymeňte pod."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Čas aktivácie bol prekročený"; - -/* Description for auto-off */ -"Auto-off" = "Automatické vypnutie"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Alarm auto-vypnutý"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Bazál inciovaný"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Menej ako 50 jednotiek"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Dávka"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Prebieha bolus"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "\nBolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolusovanie"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Bolusovanie s dočasným bazálom"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Zavádzanie kanyly"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Zaručené"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Treba vymeniť pod. Podávanie inzulínu sa zastaví o 1 hodinu."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Vymeniť pod teraz. Pod bol aktívny 72 hodín."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Chyba príkazu %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Problém s komunikáciou"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Problém s komunikáciou: Čaká sa na potvrdenie príkazu."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Tieto upozornenia s pípnutím zo zariadenia Pod zaznejú pri spustení príkazov, ako je bolus, zrušenie bolusu, pozastavenie, obnovenie, uloženie pripomienky s upozornením atď. Keď aplikácia automaticky zmení správu, nepoužívajú sa žiadne oznámenia."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Tieto zvukové upozornenia zo zariadenia Pod zaznejú, keď aplikácia automaticky upraví dodávku, ako aj pri príkazoch, ktoré iniciujete."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritická chyba zariadenia Pod"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Možné presluchy. Presuňte sa na iné miesto"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Deaktivované"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Vypnuté"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Prázdna nádrž"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Prázdna odpoveď z podu"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Zaprotokolovaná udalosť chyby, vypína sa"; - -/* Description for expiration alert */ -"Expiration alert" = "Varovanie o expirácii"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Rozšírený"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Prebieha predĺžený bolus"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Predĺžený bolus beží súčasne s dočasným bazálom"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Vyskytla sa chybová udalosť"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Dokončiť deaktiváciu"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Dokončiť párovanie"; - -/* Description for finish setup */ -"Finish setup " = "Dokončiť nastavenie"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Dokončiť nastavenie pripomienky"; - -/* Pod inititialized */ -"Initialized" = "Inicializované"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Kanyla sa zavádza"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Podávanie inzulínu sa zastavilo. Vymeňte modul teraz."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Inzulín Suspendovaný"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Typ inzulínu nie je nakonfigurovaný"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Interná chyba podu %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "PrerušenýBolus: %1$@ j (%2$@ j naplánované) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Neplatná adresa 0x %1$x . Očakáva sa 0x %2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Neplatná adresa: ( %1$@ )"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Neplatný kód CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Neplatné nastavenie"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Nízka hladina v rezervoári"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Nízka hladina v rezervoári (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Nízka hladina v rezervoári"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Nízky stav batérie RileyLinku"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Uistite sa, že je váš RileyLink v blízkosti a je zapnutý"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuálny bazál"; - -/* Pod memory initialized */ -"Memory initialized" = "Pamäť inicializovaná"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Presuňte sa ďalej od ostatných modulov a skúste znova."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Upozornenie na viacero príkazov"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Žiadne upozornenia"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Nepoužívajú sa žiadne pripomenutia spoľahlivosti."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Žiadne chyby"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Žiadny inzulín"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Žiadny pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Nie je spárovaný žiadny pod"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Nenašiel sa žiadny pod"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Žiadna odpoveď z podu"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Nie je k dispozícii žiadny RileyLink"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normálny"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Nedostatok dát"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Zistená oklúzia"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Spárované"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Párovanie je dokončené"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Chyba pri analyzovaní: %1$@ v (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Prosím, majte iba pôvodný pod v dosahu alebo deaktivujte pôvodný pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Priblížte pod k RileyLinku a skúste to znova"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Dokončite párovanie podu."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Spárujte nový pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Premiestnite RileyLink ďalej od podu"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Zmeňte polohu RileyLink vzhľadom k podu"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod je už spárovaný"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod je už pripravený"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Chyba podu"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Oznámenie o expirácii podu"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Oznámenie o expirácii podu"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod vypršal"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod vyprší za %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Chyba podu: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod nie je v stave pripravenom na zavedenie kanyly."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pumpu nie je v tomto stave možné pripraviť."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod je pozastavený"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Oklúzia podu"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Párovanie podu nebolo dokončené"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod poslal potvrdenie namiesto odpovede "; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Okno nastavenia podov vypršalo"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pripomenutie pozastaveného podu"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Slabá sila signálu"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Príprava podu"; - -/* Pod state when priming completed */ -"Priming completed" = "Príprava podu dokončená"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Pripravené na programovanie bazálu"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Pripravené na zavedenie kanyly"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Pripomienka bola inicializovaná"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Pokračovať"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Obnoviť podávanie inzulínu"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Obnoviť podávanie inzulínu"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Obnoviť: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Naplánovaný bazál"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Vypnutie každú chvilu"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Varovanie bezprostredného vypnutia"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Strata signálu"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Príliš vysoká sila signálu"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Pozastavenie"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Pripomienka prebiehajúceho pozastavenia"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Čas pozastavenia vypršal"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Pozastavené"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Pozastaviť: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Pozastavené"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Čas pozastavenia vypršal. Otvorte aplikáciu a pokračujte."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Plnenie nádrže dokončené"; - -/* Pod power to motor activated */ -"Tank power activated" = "Napájanie nádrže je aktivované"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Dočasný bazál"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Prebieha dočasný bazál"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Prebieha dočasný bazál"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "DočasBazál: %1$@ j/hod %2$@ %3$@ %4$@ j %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Obdobie pozastavenia inzulínu sa skončilo.\n\nPodávanie inzulínu môžete obnoviť z bannera na domovskej obrazovke alebo z obrazovky nastavení pumpy. Pripomienka sa vám znova zobrazí o 15 minút."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Čas na pumpe sa líši od aktuálneho času. V nastaveniach môžete skontrolovať čas pumpy a synchronizovať sa s aktuálnym časom."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Zistila sa zmena času"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Je čas vymeniť pod! Platnosť vášho podu vyprší o %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Našlo sa príliš veľa podov"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Skúste znova"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Neisté"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Neočakávané poradové číslo správy"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Neočakávaná zmena podu"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Neočakávaná odpoveď z podu"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Neznáma chyba podu %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Neznáma hodnota ( %1$@ ) pre typ %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Overenie zlyhalo: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Počkajte na dokončenie bolusu alebo bolus zrušte"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Počkajte, kým sa dokončí dočasný bazál, alebo ho zrušte"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Čaká sa na pripomienku párovania"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/sv.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/sv.lproj/Localizable.strings deleted file mode 100644 index 4989d732b..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/sv.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inaktiv)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" har låg batterinivå"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin eller mindre kvar i podden. Byt podd snart."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Tid för aktivering överskriden"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Av"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Auto-av larm"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initierad"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Under 50 enheter"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus pågår"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@E %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Ger bolus"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Ger bolus med temporär basal"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Kanyl förs in"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Säker"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Byt podd nu. Insulintillförsel stoppas om 1 timme."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Byt podd nu. Podden har använts i 72 timmar."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Kommandofel %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Kommunikationsproblem"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Kommunikationsproblem: Obekräftat kommando väntar."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Bekräftelseljud kommer att pipa för för ala pumpkommandon du ger, som bolus, avbryt bolus, pausa pump, återuppta insulintillförsel, spara påminnelser etc. När iAPS automatiskt justerar insulintillförsel kommer inga pip att ljuda."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Bekräftelsepip kommer att ljuda även vid automatiska pumpkommandon såväl som vid manuella."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritiskt poddfel"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Potentiell radiostörning. Pröva att flytta dig till ett annat rum/annan plats"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Inaktiverad"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Av"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Poddfel; tom reservoar"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Inget svar från podden"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Felhändelse loggad, stänger ned"; - -/* Description for expiration alert */ -"Expiration alert" = "Larm om utgångsdatum"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Utökad"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Utökad bolus pågår"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Utökad bolus pågår med temp. basal"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Felhändelse inträffade"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Avsluta inaktivering"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Avsluta parkoppling"; - -/* Description for finish setup */ -"Finish setup " = "Inställning färdig"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Påminnelse om att slutföra inställning"; - -/* Pod inititialized */ -"Initialized" = "Podd initialiserad"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Kanyl förs in"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulintillförsel stoppad. Byt podd nu."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulintillförsel pausad"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Du måste välja typ av insulin"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Internt poddfel %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "AvbrutenBolus: %1$@ E (%2$@ E schemalagd) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Ogiltig adress 0x%1$x. Förväntade 0x%2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Ogiltig adress: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Ogiltigt CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Ogiltig inställning"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Låg reservoarvolym"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Low reservoir advisory (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Larm vid låg reservoarvolym"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Lågt batteri i RileyLink"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Säkerställ att din RileyLink är nära och påslagen"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuell temporär basal"; - -/* Pod memory initialized */ -"Memory initialized" = "Minne initierat"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Pröva att gå till ett annat rum och försök igen."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Multipla kommandoaviseringar"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Inga larm"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Inga ljud på."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Inga fel"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Inget insulin"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Ingen Podd"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Ingen parkopplad"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Hittade ingen podd"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Inget svar från pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Ingen RileyLink tillgänglig"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normalvärde"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Inte tillräckligt med data"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Ocklusion upptäckt"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Parkopplad"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Parkoppling lyckades"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Fel vid tolkning: %1$@ i (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Ha endast din ursprungliga podd inom räckvidd eller inaktivera ursprunglig podd"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "För din pod närmare din RileyLink och försök igen"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Vänligen avsluta parkopplingen av din podd."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Var god parkoppla ny pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Flytta din RileyLink längre från podden"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Flytta din RileyLink i förhållande till podden"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod redan parkopplad"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod redan fylld"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Poddfel"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Larm för utgångsdatum för pod"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Notis om utgångsdatum för pod"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod har utgått"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Podd går ut om %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Podfel: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod är inte klar för att föra in kanyl"; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod är inte klar för att fyllas"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod är pausad"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Ocklusion i podd"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Parkoppling inte färdig"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Podd skickade ack istället för svar"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Tid för podinställning är överskriden"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Påminnelse om pausad pump"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Dålig signalstyrka"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Pod fylls på"; - -/* Pod state when priming completed */ -"Priming completed" = "Podd har fyllts färdigt med insulin"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Klar för programmering av basal"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Klar att föra in kanyl"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Påminnelse initierad"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Återuppta"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Återuppta insulintillförsel"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Återuppta insulintillförsel"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Återuppta: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Schemalagd basal"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Podd kommer snart att stängas av"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Larm för omedelbar avstängning"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signalförlust"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signalstyrka för hög"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Pausa"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Påminnelse om pausad pump"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Tid för pausad pump har löpt ut"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Pausad"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Pausa: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Pausad"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Planerad paus är över. Öppna app och återuppta insulintillförsel."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Pod har fyllts klart"; - -/* Pod power to motor activated */ -"Tank power activated" = "Ström till motor för behållare aktiverad"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Temporär basal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Temp basal pågår redan"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Temp basal pågår"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ E/timme %2$@ %3$@ %4$@ E %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Planerad period av paus av pump är slut.\n\nDu kan återuppta insulintillförsel i pumpinställningar. Du kommer bli påmind igen om 15 minuter."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Tiden på din pump skiljer sig från den aktuella tiden. Du kan granska pumpens tid och synkronisera till aktuell tid i pumpinställningar."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Tidsändring upptäckt"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Byt din pod! Din pod går ut om %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "För många poddar hittades"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Försök igen"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Osäker"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Oväntat meddelandesekvensnummer"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Oväntat poddbyte"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Oväntat svar från din pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Okänt podfel %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Okänt värde (%1$@) av typ %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validering misslyckades: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Vänta på att pågående bolus är färdig, eller avbryt bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Vänta på nuvarande temporära basal, eller pausa för att avbryta"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Väntar på påminnelse för parkoppling"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/tr.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/tr.lproj/Localizable.strings deleted file mode 100644 index 9ac00194d..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/tr.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = "(etkin değil)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\" %1$@ \" pili zayıf"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insülin veya daha az kaldı. Yakında Pod'u değiştirin."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Aktivasyon süresi aşıldı"; - -/* Description for auto-off */ -"Auto-off" = "Otomatik kapanma"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Oto-kapanma alarmı"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Bazal başlatıldı"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "50 ünitenin altında"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Bolus devam ediyor"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@Ü %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Bolus iletiliyor"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Geçici bazal ile bolus iletiliyor"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Kanül takma"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Kesin"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Pod'u şimdi değiştirin. İnsülin iletimi 1 saat içinde duracaktır."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Pod'u şimdi değiştirin. Pod 72 saattir aktif."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Komut hatası %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "İletişim Sorunu"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "İletişim sorunu: Onaylanmamış komut beklemede."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Kritik Pod Hatası"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Karışma mevcut. Lütfen yer değiştririn."; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Devre dışı"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Devre Dışı"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Boş rezervuar"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Pod'dan boş yanıt"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Hata olayı kaydedildi, kapatılıyor"; - -/* Description for expiration alert */ -"Expiration alert" = "Süre sonu uyarısı"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Yayma"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Yayma bolus çalışıyor"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Geçici bazal ile çalışan yayma bolus"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Hata meydana geldi"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Devre Dışı Bırakmayı Bitir"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Eşleştirmeyi Bitir"; - -/* Description for finish setup */ -"Finish setup " = "Kurulumu bitir"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Hatırlatıcı kurulumunu bitir"; - -/* Pod inititialized */ -"Initialized" = "Başlatıldı"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Kanül yerleştiriliyor"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "İnsülin iletimi durdu. Pod'u şimdi değiştirin."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "İnsülin Askıya Alındı"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "İnsülin tipi yapılandırılmamış"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Dahili pod hatası %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "KesintiliBolus: %1$@ Ü (%2$@ Ü planlandı) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Geçersiz adres 0x %1$x . Beklenen 0x %2$x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Geçersiz adres: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Geçersiz CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Geçersiz Ayar"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Düşük Rezervuar"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Düşük rezervuar tavsiyesi (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Düşük rezervuar uyarı alarmı"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Düşük RileyLink Pili"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "RileyLink'inizin yakında olduğundan ve açık olduğundan emin olun"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manuel Bazal"; - -/* Pod memory initialized */ -"Memory initialized" = "Bellek başlatıldı"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Diğer podlardan uzakta yeni bir alana gidin ve tekrar deneyin."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Çoklu Komut Uyarısı"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Uyarı yok"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Emniyet hatırlatıcıları kullanılmaz."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Hata yok"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "İnsülin yok"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Pod Yok"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Eşleştirilmiş pod yok"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Pod bulunamadı"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Pod'dan yanıt yok"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "RileyLink yok"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Normal"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Yeterli veri yok"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Tıkanma tespit edildi"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Eşleştirilmiş"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Eşleştirme tamamlandı"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Ayrıştırma Hatası: %1$@ içinde (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Lütfen menzile yalnızca orijinal podu getirin veya orijinal podu devre dışı bırakın"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Lütfen podunuzu RileyLink'e yaklaştırın ve tekrar deneyin"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Lütfen podunuzu eşleştirmeyi bitirin."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Lütfen yeni bir pod eşleştirin"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Lütfen RileyLink'i pod'dan daha uzağa yerleştirin"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Lütfen RileyLink'i pod'a göre yeniden konumlandırın"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod zaten eşleştirilmiş"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod zaten hazırlandı"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Hatası"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod sona erme uyarı alarmı"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod Süre Sonu Bildirimi"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod'un süresi doldu"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod'un süresi %1$@ içinde doluyor."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod Hatası: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod, kanül yerleştirmeye hazır durumda değil."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod dolum için hazır durumda değil."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod askıya alındı"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Tıkanıklığı"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod Eşleştirme Tamamlanmadı"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod yanıt yerine ack gönderdi"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pod kurulum penceresinin süresi doldu"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pod askıya alındı hatırlatıcısı"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Zayıf sinyal gücü"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Hazırlanıyor…"; - -/* Pod state when priming completed */ -"Priming completed" = "Hazırlama tamamlandı"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Bazal programlama için hazır"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Kanül yerleştirmeye hazır"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Hatırlatıcı başlatıldı"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Devam et"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "İletimi Devam Ettir"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "İnsüline Devam Et"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Devam: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Programlanan Bazal"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Yakında Kapanma"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Yakında kapanma alarmı"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Sinyal Kaybı"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Sinyal gücü çok yüksek"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Askıya al"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Devam Eden Hatırlatıcıyı Askıya Al"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Askıya alma süresi doldu"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Askıya alındı"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Askıya alma: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Askıya alındı"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Askıya alma süresi doldu. Uygulamayı açın ve devam edin."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Hazne dolumu tamamlandı"; - -/* Pod power to motor activated */ -"Tank power activated" = "Hazne gücü etkinleştirildi"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Geçici Bazal"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Geçici bazal devam ediyor"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Geçici bazal çalışıyor"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "GeçiciBazal: %1$@ Ü/saat %2$@ %3$@ %4$@ Ü %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "İnsülin askıya alma süresi sona ermiştir.\n\nAna ekran üzerinden veya pompa ayarları ekranınızdan iletime devam edebilirsiniz. 15 dakika içinde tekrar hatırlatılacaktır."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Pompanızdaki saat, geçerli saatten farklı. Pompa süresini gözden geçirebilir ve ayarlarda geçerli saate eşitleyebilirsiniz."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Zaman Değişikliği Algılandı"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Pod'unuzu değiştirme zamanı! Pod'un süresi %1$@ içinde dolacak"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Çok fazla pod bulundu"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Tekrar deneyin"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Belirsiz"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Beklenmeyen mesaj sıra numarası"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Beklenmeyen pod değişikliği"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Pod'dan beklenmeyen yanıt"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Bilinmeyen pod hatası %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "%2$@ tipi için Bilinmeyen Değer ( %1$@ )"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Doğrulama başarısız oldu: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Mevcut bolusun bitmesini bekleyin veya bolusu iptal edin"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Mevcut geçici bazalın bitmesini bekleyin veya iptal etmek için askıya alın"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Eşleştirme hatırlatıcısı bekleniyor"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/uk.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/uk.lproj/Localizable.strings deleted file mode 100644 index bece69afe..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/uk.lproj/Localizable.strings +++ /dev/null @@ -1,432 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (неактивний)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" має низький заряд акумулятора"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ або менше інсуліна в Podʼі. Замініть Pod найближчим часом."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Час активації перевищений"; - -/* Description for auto-off */ -"Auto-off" = "Авто вимкнення"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Авто-відключення сигналу"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Базал ініціалізовано"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Менше 50 одиниць"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Болюс"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Подання болюса"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Болюс: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Подача болюса"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Подача болюса при подачі ТБШ"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Встановлення канюлі"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Безперечно"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Замінити Pod зараз. Подачу інсуліну буде зупинено через 1 годину."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Замініть під зараз. Pod активний вже протягом 72 годин."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Помилка команди %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Помилка звʼязку"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Проблема комунікації: не визнана команда в очікуванні."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Нагадування про достовірність лунатимуть для команд, які ви ініціюєте, як-от болюс, скасування болюсу, призупинення, відновлення, збереження сповіщень тощо. Коли Loop автоматично регулює доставку, нагадування про довіру не використовуються."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Нагадування про довіру лунатимуть, коли Loop автоматично регулює доставку, а також для команд, які ви ініціюєте."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Нагадування про довіру лунатимуть, коли Loop автоматично регулює доставку, а також для команд, які ви ініціюєте."; ->>>>>>> 7f4d47c8 (Crowdin (#334)) - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Критична Помилка"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Можливі перехресні перешкоди. Будь ласка, перейдіть на нове місце"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Деактивовано"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Вимкнено"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Порожній резервуар"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Немає відповіді від Pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Помилка записана в лог, відключення"; - -/* Description for expiration alert */ -"Expiration alert" = "Сповіщення про закінчення терміну дії"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Подовжено"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Вводиться розтягнутий болюс"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Подовжений болюс із Тимчасовою Базальною Швидкістю"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Виникла помилка"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Завершити деактивацію"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Завершити створення пари"; - -/* Description for finish setup */ -"Finish setup " = "Завершити налаштування "; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Нагадування про завершення налаштування"; - -/* Pod inititialized */ -"Initialized" = "Активований"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Введення канюлі"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Подачу інсуліну припинено. Замініть Pod зараз."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Подання інсуліну призупинено"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Тип інсуліну не налаштований"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Внутрішня помилка Pod %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "Перерваний Болюс: %1$@ U (%2$@ U заплановано) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Некоректна адреса 0x%x. Очікувалось 0x%x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Недійсна адреса: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Некоректний CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Непридатні параметри"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Мало інсуліну в резервуарі"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Попередження про низький рівень резервуара (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Оповіщення про малий запас інсуліну у резервуарі"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Низький заряд RileyLink"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Впевніться, що RileyLink увімкнений та знаходиться поруч"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Ручна Тимчасова Базальна Швидкість (ТБШ)"; - -/* Pod memory initialized */ -"Memory initialized" = "Пам'ять ініціалізовано"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Перейдіть у інше місце подалі від будь-яких інших Pods і спробуйте ще раз."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Попередження про кілька команд"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Немає сповіщень"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Нагадування про довіру не використовуються."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Нема помилок"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Без інсуліну"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Немає Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Немає підключеного Pod"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Pod не знайдено"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Немає відповіді від Pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "RileyLink недоступний"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Нормальний"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Недостатньо даних"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Виявлено закупорку"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Пов'язані"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Спаровування завершено"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Помилка обробки: %1$@ в (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Будь ласка, приносите в зону дії лише оригінальний Pod або деактивуйте оригінальний Pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Будь ласка, піднесіть свій Pod до RileyLink і повторіть спробу"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Будь Ласка, завершіть підключення Pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Будь ласка, підключіть новий Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Перемістіть RileyLink далі від Pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Змініть розташування RileyLink відносно Pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod вже з'єднано"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod вже з'єднано"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Помилка Pod"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Попереджувальний сигнал про закінчення строку придатності"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Повідомлення про закінчення строку придатності"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Термін дії Pod минув"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod закінчується через %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Помилка Pod: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod не готовий для введення канюли."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Omnipod не готовий до прокачування інсуліну"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod призупинено"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Закупорка Pod"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Створення пари не завершено"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod надіслав \"ack\" замість відповіді"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Час для введення налаштувань Omnipod закінчився"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Нагадування про призупинення Pod"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Низький рівень сигналу"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Прокачування інсуліну"; - -/* Pod state when priming completed */ -"Priming completed" = "Прокачування інсуліну завершено"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Готовий до програмування Базалу"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Готовий до введення канюлі"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Нагадування ініціалізовано"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Відновити"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Відновити доставку"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Відновити подачу"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Поновлено: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Запланована База"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Завершення роботи неминучі"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Завершення роботи неминучі"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Втрата сигналу"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Зависока потужність сигналу"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Призупинити"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Нагадування про призупинення"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Час припинення подачі минув"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Призупинено"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Призупинено: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Призупинено"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Час призупинення вже вичерпано. Відкрийте додаток та продовжуйте роботу."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Наповнення Pod завершено"; - -/* Pod power to motor activated */ -"Tank power activated" = "Живлення моторчика резервуара активоване"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Тимчасова Базальна Швидкість"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Поки що працює тимчасовий базал"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Подається тимчасовий базал"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "Тимчасовий Базал: %1$@ ед/ч %2$@ %3$@ %4$@ ед %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Період призупинення подачі інсуліну закінчився.\n\nВи можете відновити інсулін з банеру на головному екрані програми або з екрана налаштувань вашої помпи. За 15 хвилин ви отримаєте повторне нагадування."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Час на вашоій помпі відрізняється від поточного часу. Ви можете переглянути час помпи та синхронізувати його з поточним часом у налаштуваннях."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Виявлено зміну часу"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Час замінити Pod - Термін придатності спливає через %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Знайдено забагато Pods"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Спробуйте знову"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Невизначений"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Несподіваний номер повідомлення"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Несподівана зміна Pod"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Несподіваний відгук Pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Невідома несправність Pod %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Невідоме значення ( %1$@ ) для типу %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Помилка перевірки: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Дочекайтеся закінчення подачі болюса або скасуйте його"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Дочекайтеся закінчення введення поточної ТБШ або зупиніть помпу для скасування"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Очікую нагадування про створення пари"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/vi.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/vi.lproj/Localizable.strings deleted file mode 100644 index 6bf56b90f..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/vi.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (không hoạt động)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" gần hết pin"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ insulin hoặc ít hơn còn lại trong Pod. Thay Pod ngay."; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Đã quá thời gian kích hoạt"; - -/* Description for auto-off */ -"Auto-off" = "Tự động tắt"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "Tự động tắt cảnh báo"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Liều basal được khởi tạo"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "Dưới 50 units"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "Liều bolus"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "Liều Bolus đang được thực hiện"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "Bolus: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "Đang tiến hành bolus"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "Đang thực hiện liều basal tạm thời"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "Đang gắn Cannula"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Chắc chắn"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "Thay pod ngay. Insulin sẽ ngừng trong 1 giờ tới."; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "Thay pod ngay. Pod đã hoạt động 72 giờ qua."; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Câu lệnh lỗi %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Câu lệnh có vấn đề"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Sự cố giao tiếp: Lệnh chưa được xác nhận đang chờ xử lý."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Các tác vụ sẽ có âm thanh như khi bạn bolus, hủy bỏ bolus, tạm dừng bơm, hoạt động lại hay lưu các lời nhắc thông báo... sẽ không có âm thanh khi ứng dụng chạy tự động."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Sẽ có âm thanh báo nhắc khi ứng dụng tự động điều chỉnh liều cũng như khi bạn khởi tạo ứng dụng."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Pod lỗi nghiêm trọng"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Có nhiễu xuyên âm. Vui lòng di chuyển đến địa điểm mới"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "Đã hủy kích hoạt"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Vô hiệu hóa"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "Ngăn chứa insulin rỗng"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Không có phản hồi từ pod"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Lỗi đăng nhập, đang tắt"; - -/* Description for expiration alert */ -"Expiration alert" = "Thông báo hết hạn"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Mở rộng"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Mở rộng chạy liều bolus"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Mở rộng chạy liều bolus với liều nền tạm thời"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Đã có lỗi"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Hoàn tất việc ngưng kích hoạt"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Hoàn tất ghép đôi"; - -/* Description for finish setup */ -"Finish setup " = "Hoàn tất cấu hình"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Hoàn tất thiết lập lời nhắc"; - -/* Pod inititialized */ -"Initialized" = "Đã được khởi tạo"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Thay cannula"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin ngừng. Thay Pod ngay."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Đã tạm ngưng"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Loại insulin chưa được khai báo"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Lỗi bên trong pod %1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Địa chỉ không tồn tại 0x%x. Dự kiến 0x%x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Địa chỉ không tồn tại: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "CRC không tồn tại"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Cài đặt không tồn tại"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Sắp hết thuốc"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Báo động hết thuốc (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "Báo động ngăn chứa insulin thấp"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Báo động pin RileyLink thấp"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "Đảm bảo RileyLink bên cạnh và đã được bật"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Liều Basal thủ công"; - -/* Pod memory initialized */ -"Memory initialized" = "Bộ nhớ được khởi tạo"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Chuyển pod đến vị trí mới và thử lại."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "Multiple Command Alert"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "Không có cảnh báo nào"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "Không có lời nhắc nào được sử dụng."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "Không có lỗi"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "Hết thuốc"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "Không pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "Không có pod nào được kết nối"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "Không tìm thấy Pod"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Không có tín hiệu phản hồi từ pod"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "Không tìm thấy RileyLink"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "Bình thường"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Không đủ dữ liệu"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "Phát hiện tắc nghẽn"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "Đã được ghép đôi"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Ghép đôi hoàn thành"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Lỗi cú pháp: %1$@ in (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Chỉ mang pod gốc trong phạm vi hoạt động hoặc hủy kích hoạt pod gốc"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "Đề nghị để pod gần với Rileylink và thử lại lần nữa"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "Đề nghị hoàn thành ghép đôi pod."; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "Đề nghị ghép đôi pod mới"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Đặt RileyLink xa khỏi pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Đặt RileyLink lại gần pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod đã được ghép đôi"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod đã được mồi"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Lỗi Pod"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Cảnh báo pod hết hạn"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Thông báo pod hết hạn"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod đã hết hạn"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod sẽ hết hạn trong: %1$@."; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod lỗi: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod không sẵn sàng để gắn cannula."; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod không sẵn sàng để mồi."; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod bị tạm ngưng"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod ghép nối không thành công"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod gửi ack thay vì phản hồi"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Cửa sổ cấu hình pod hết hạn"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Lời nhắc Pod tạm dừng"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Tín hiệu yếu"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "Đang mồi"; - -/* Pod state when priming completed */ -"Priming completed" = "Priming hoàn tất"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "Sẵn sàng cho việc tính toán liều basal"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Sẵn sàng cho việc gắn cannula"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Lời nhắc đã được khởi tạo"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "Tiếp tục"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Tiếp tục lại việc tiêm insulin"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "Tiếp tục lại việc tiêm insulin"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "Tái lập: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "Đã lên chương trình cho liều Basal"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Tắt báo động sắp xảy ra"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "Tắt báo động sắp xảy ra"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Mất tín hiệu"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Sóng tín hiệu quá cao"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "Đã tạm ngưng"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "Suspend In Progress Reminder"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Thời gian tạm dừng hết hạn"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Đã tạm ngưng"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "Tạm ngưng: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "Đã tạm ngưng"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "Thời gian tạm dừng hết. Mở ứng dụng và tiếp tục lại."; - -/* Pod tank fill completed */ -"Tank fill completed" = "Hoàn tất nạp"; - -/* Pod power to motor activated */ -"Tank power activated" = "Pod được kích hoạt"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "Liều cơ bản tạm thời"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "Liều basal tạm thời đang tiến hành"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "Liều basal tạm thời đang thực hiện"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "TempBasal: %1$@ U/giờ %2$@ %3$@ %4$@ U %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "Thời gian tạm ngưng insulin đã kết thúc.\n\n Bạn có thể phục hồi việc tiêm thuốc từ màn hình chính hoặc từ màn hình cài đặt bơm. Sẽ có thông báo nhắc trong vòng 15 phút."; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "Thời gian trên bơm khác so với thời gian thực tế. Bạn có thể xem thời gian trên bơm và sync thời gian hiện hành trong cài đặt."; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "Thay đổi thời gian được phát hiện"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Thời gian thay pod của bạn! Pod của bạn sẽ hết hạn trong %1$@"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Phát hiện quá nhiều pod"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Thử lại"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "Không chắc chắn"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Thứ tự tin nhắn không mong đợi"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Không mong đợi thay thế pod"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Phản hồi bất thường từ pod"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Lỗi không xác định của pod %1$03d"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Giá trị không xác định (%1$@) cho loại %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Xác thực không thành công: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "Chờ đợi liệu bolus hiện tại hoàn tất hoặc hủy liều bolus"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "Chờ đợi liều basal tạm thời hoàn tất hoặc chọn ngưng để hủy"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "Đang chờ đợi câu thông báo ghép đôi"; diff --git a/Dependencies/OmniKit/OmniKit/Resources/zh-Hans.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKit/Resources/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index a7ed35da1..000000000 --- a/Dependencies/OmniKit/OmniKit/Resources/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,428 +0,0 @@ -/* Description for an inactive alert modifier */ -" (inactive)" = " (inactive)"; - -/* Format string for low battery alert body for RileyLink. (1: device name) */ -"\"%1$@\" has a low battery" = "\"%1$@\" has a low battery"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for alert content body for lowReservoir pod alert. (1: reminder value) */ -"%1$@ insulin or less remaining in Pod. Change Pod soon." = "%1$@ 或更少胰岛素剩余,请即刻更换Pod"; - -/* Format string for activation time exceeded - Pod state when activation not completed in the time allowed */ -"Activation time exceeded" = "Activation time exceeded"; - -/* Description for auto-off */ -"Auto-off" = "Auto-Off"; - -/* Description for auto-off alarm */ -"Auto-off alarm" = "自动关闭提醒"; - -/* Pod state when basal initialized */ -"Basal initialized" = "Basal initialized"; - -/* Pod state when running below fifty units */ -"Below 50 units" = "胰岛素已低于50U"; - -/* Pump Event title for UnfinalizedDose with doseType of .bolus */ -"Bolus" = "大剂量"; - -/* Error message shown when operation could not be completed due to existing bolus in progress */ -"Bolus in progress" = "大剂量输注中"; - -/* The format string describing a bolus. (1: The amount delivered)(2: Start time of the dose)(3: duration)(4: scheduled certainty) */ -"Bolus: %1$@U %2$@ %3$@ %4$@" = "大剂量: %1$@U %2$@ %3$@ %4$@"; - -/* Delivery status when bolusing */ -"Bolusing" = "注射中"; - -/* Delivery status when bolusing and temp basal is running */ -"Bolusing with temp basal" = "正在运行临时基础并输注大剂量"; - -/* Pod state when inserting cannula */ -"Cannula inserting" = "植入管路"; - -/* String describing a dose that was certainly scheduled */ -"Certain" = "Certain"; - -/* Alert content body for podExpireImminent pod alert */ -"Change Pod now. Insulin delivery will stop in 1 hour." = "请立刻更改Pod ,胰岛素输注将在 1 小时后停止"; - -/* Alert content body for podExpiring pod alert */ -"Change Pod now. Pod has been active for 72 hours." = "立即更换 Pod ,Pod 已使用72小时"; - -/* Format string for invalid message error code (1: error code number) */ -"Command error %1$u" = "Command error %1$u"; - -/* Status highlight that delivery is uncertain. */ -"Comms Issue" = "Comms Issue"; - -/* Error message when command is rejected because an unacknowledged command is pending. */ -"Communication issue: Unacknowledged command pending." = "Communication issue: Unacknowledged command pending."; - -/* Description for BeepPreference.manualCommands */ -"Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used." = "Confidence reminders will sound for commands you initiate, like bolus, cancel bolus, suspend, resume, save notification reminders, etc. When the app automatically adjusts delivery, no confidence reminders are used."; - -/* Description for BeepPreference.extended */ -"Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate." = "Confidence reminders will sound when the app automatically adjusts delivery as well as for commands you initiate."; - -/* The title for AlarmCode.other notification */ -"Critical Pod Error" = "Critical Pod Error"; - -/* Recovery suggestion when unexpected address received */ -"Crosstalk possible. Please move to a new location" = "Crosstalk possible. Please move to a new location"; - -/* Pod state when pod has been deactivated */ -"Deactivated" = "已解除"; - -/* Title string for BeepPreference.silent */ -"Disabled" = "Disabled"; - -/* Description for Empty reservoir pod fault */ -"Empty reservoir" = "胰岛素储量为零"; - -/* Error message shown when empty response from pod was received */ -"Empty response from pod" = "Pod无响应"; - -/* Pod state error event logged shutting down */ -"Error event logged, shutting down" = "Pod错误已记录"; - -/* Description for expiration alert */ -"Expiration alert" = "到期提醒"; - -/* Title string for BeepPreference.extended */ -"Extended" = "Extended"; - -/* Delivery status when extended bolus is running */ -"Extended bolus running" = "Extended bolus running"; - -/* Delivery status when extended bolus and temp basal is running */ -"Extended bolus running with temp basal" = "Extended bolus running with temp basal"; - -/* Pod state when fault event has occurred */ -"Fault event occurred" = "Fault event occurred"; - -/* Status highlight that when pod is deactivating. */ -"Finish Deactivation" = "Finish Deactivation"; - -/* Status highlight that when pod is activating. */ -"Finish Pairing" = "Finish Pairing"; - -/* Description for finish setup */ -"Finish setup " = "完成设置"; - -/* Description for finish setup reminder */ -"Finish setup reminder" = "Finish setup reminder"; - -/* Pod inititialized */ -"Initialized" = "初始化"; - -/* Pod state when inserting cannula */ -"Inserting cannula" = "Inserting cannula"; - -/* The default notification body for AlarmCodes */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Status highlight that insulin delivery was suspended. */ -"Insulin Suspended" = "Insulin Suspended"; - -/* Error description for OmniBLEPumpManagerError.insulinTypeNotConfigured */ -"Insulin type not configured" = "Insulin type not configured"; - -/* The format string for Internal pod fault (1: The fault code value) */ -"Internal pod fault %1$03d" = "Pod内部错误%1$03d"; - -/* The format string describing a bolus that was interrupted. (1: The amount delivered)(2: The amount scheduled)(3: Start time of the dose)(4: duration)(5: scheduled certainty) */ -"InterruptedBolus: %1$@ U (%2$@ U scheduled) %3$@ %4$@ %5$@" = "大剂量输注终端: %1$@ U (%2$@ U 已输注) %3$@ %4$@ %5$@"; - -/* Error message for when unexpected address is received (1: received address) (2: expected address) */ -"Invalid address 0x%x. Expected 0x%x" = "Invalid address 0x%x. Expected 0x%x"; - -/* Description for MessageError invalidAddress */ -"Invalid address: (%1$@)" = "Invalid address: (%1$@)"; - -/* Description for MessageError invalidCrc */ -"Invalid CRC" = "Invalid CRC"; - -/* Error description for OmniBLEPumpManagerError.invalidSetting */ -"Invalid Setting" = "Invalid Setting"; - -/* Alert content title for lowReservoir pod alert */ -"Low Reservoir" = "Low Reservoir"; - -/* Format string for description for low reservoir advisory (1: reminder units) */ -"Low reservoir advisory (%1$gU)" = "Low reservoir advisory (%1$gU)"; - -/* Description for low reservoir alarm */ -"Low reservoir advisory alarm" = "储药量低"; - -/* Title for RileyLink low battery alert */ -"Low RileyLink Battery" = "Low RileyLink Battery"; - -/* Recovery suggestion when no RileyLink is available */ -"Make sure your RileyLink is nearby and powered on" = "确保Rileylink与Pod保持比较近的距离"; - -/* Status highlight when manual temp basal is running. */ -"Manual Basal" = "Manual Basal"; - -/* Pod memory initialized */ -"Memory initialized" = "Memory initialized"; - -/* Recovery suggestion for PodCommsError.tooManyPodsFound */ -"Move to a new area away from any other pods and try again." = "Move to a new area away from any other pods and try again."; - -/* Alert content body for multiCommand pod alert - Alert content title for multiCommand pod alert */ -"Multiple Command Alert" = "多个命令警报"; - -/* Pod alert state when no alerts are active */ -"No alerts" = "运行正常"; - -/* Description for BeepPreference.silent */ -"No confidence reminders are used." = "No confidence reminders are used."; - -/* Description for Fault Event Code .noFaults */ -"No faults" = "No faults"; - -/* Status highlight message for emptyReservoir alarm. - Status highlight that a pump is out of insulin. */ -"No Insulin" = "No Insulin"; - -/* Status highlight that when no pod is paired. */ -"No Pod" = "无Pod"; - -/* Error message shown when no pod is paired */ -"No pod paired" = "未配对Pod"; - -/* Error message for PodCommsError.noPodsFound */ -"No pods found" = "No pods found"; - -/* Error message shown when no response from pod was received */ -"No response from pod" = "Pod无响应"; - -/* Error message shown when no response from pod was received */ -"No RileyLink available" = "没有发现Rileylink"; - -/* Delivery status when basal is running - Pod state when running above fifty units */ -"Normal" = "正常"; - -/* Description for MessageError notEnoughData */ -"Not enough data" = "Not enough data"; - -/* Description for Occlusion detected pod fault */ -"Occlusion detected" = "堵管"; - -/* Generic title of the omnipod pump manager */ -"Omnipod" = "Omnipod"; - -/* Pod status after pairing */ -"Paired" = "已配对"; - -/* Pod status when pairing completed */ -"Pairing completed" = "Pairing completed"; - -/* Description for MessageError parsingError. (1: decription of error), (2: hexadecimal data starting at offset) */ -"Parsing Error: %1$@ in (%2$@)" = "Parsing Error: %1$@ in (%2$@)"; - -/* Recovery suggestion on unexpected pod change */ -"Please bring only original pod in range or deactivate original pod" = "Please bring only original pod in range or deactivate original pod"; - -/* Recovery suggestion when no response is received from pod */ -"Please bring your pod closer to the RileyLink and try again" = "请确保Rileylink与Pod保持近距离并重试"; - -/* Alert content body for finishSetupReminder pod alert */ -"Please finish pairing your pod." = "请完成配对您的pod"; - -/* Recover suggestion shown when no pod is paired */ -"Please pair a new pod" = "请配对一个新的Pod"; - -/* Recovery suggestion when pairing signal strength is too high */ -"Please reposition the RileyLink further from the pod" = "Please reposition the RileyLink further from the pod"; - -/* Recovery suggestion when pairing signal strength is too low */ -"Please reposition the RileyLink relative to the pod" = "Please reposition the RileyLink relative to the pod"; - -/* Error message shown when user cannot pair because pod is already paired */ -"Pod already paired" = "Pod已配对"; - -/* Error message shown when prime is attempted, but pod is already primed */ -"Pod already primed" = "Pod充盈已完成"; - -/* Status highlight message for other alarm. */ -"Pod Error" = "Pod Error"; - -/* Description for expiration advisory alarm */ -"Pod expiration advisory alarm" = "Pod到期提醒"; - -/* The title for pod expiration notification */ -"Pod Expiration Notice" = "Pod到期通知"; - -/* Description for Pod expired pod fault */ -"Pod expired" = "Pod已到期"; - -/* Format string for alert content body for userPodExpiration pod alert. (1: time until expiration) */ -"Pod expires in %1$@." = "Pod 将于 %1$@到期"; - -/* Format string for pod fault code */ -"Pod Fault: %1$@" = "Pod错误: %1$@"; - -/* Error message when cannula insertion fails because the pod is in an unexpected state */ -"Pod is not in a state ready for cannula insertion." = "Pod无法植入"; - -/* Error message when prime fails because the pod is in an unexpected state */ -"Pod is not in a state ready for priming." = "Pod无法充盈"; - -/* Error message action could not be performed because pod is suspended */ -"Pod is suspended" = "Pod已暂停"; - -/* Status highlight message for occlusion alarm. */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Alert content title for finishSetupReminder pod alert */ -"Pod Pairing Incomplete" = "Pod 配对未完成"; - -/* Error message shown when pod sends ack instead of response */ -"Pod sent ack instead of response" = "Pod sent ack instead of response"; - -/* Pod state when prime or cannula insertion has not completed in the time allotted */ -"Pod setup window expired" = "Pod设置超时"; - -/* Description for pod suspended reminder */ -"Pod suspended reminder" = "Pod suspended reminder"; - -/* Format string for poor pod signal strength */ -"Poor signal strength" = "Poor signal strength"; - -/* Delivery status when pod is priming - Pod status when priming */ -"Priming" = "充盈中"; - -/* Pod state when priming completed */ -"Priming completed" = "Priming completed"; - -/* Pod state when ready for basal programming */ -"Ready for basal programming" = "基础率同步已就绪"; - -/* Pod state when ready for cannula insertion */ -"Ready to insert cannula" = "Pod可以进行植入操作"; - -/* Pod pairing reminder initialized */ -"Reminder initialized" = "Reminder initialized"; - -/* Pump Event title for UnfinalizedDose with doseType of .resume */ -"Resume" = "恢复"; - -/* Recovery suggestion when pod is suspended */ -"Resume delivery" = "Resume delivery"; - -/* Alert content title for suspendEnded pod alert */ -"Resume Insulin" = "恢复输注"; - -/* The format string describing a resume. (1: Time)(2: Scheduled certainty */ -"Resume: %1$@ %2$@" = "恢复输注: %1$@ %2$@"; - -/* Delivery status when basal is running */ -"Scheduled Basal" = "预设基础率"; - -/* Description for shutdown imminent */ -"Shutdown imminent" = "Shutdown imminent"; - -/* Description for shutdown imminent alarm */ -"Shutdown imminent alarm" = "关闭提醒"; - -/* Status highlight when communications with the pod haven't happened recently. */ -"Signal Loss" = "Signal Loss"; - -/* Format string for pod signal strength too high */ -"Signal strength too high" = "Signal strength too high"; - -/* Pump Event title for UnfinalizedDose with doseType of .suspend */ -"Suspend" = "暂停"; - -/* Alert content body for suspendInProgress pod alert - Alert content title for suspendInProgress pod alert */ -"Suspend In Progress Reminder" = "泵暂停中 的提醒"; - -/* Description for suspend time expired */ -"Suspend time expired" = "Suspend time expired"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "暂停"; - -/* The format string describing a suspend. (1: Time)(2: Scheduled certainty */ -"Suspend: %1$@ %2$@" = "暂停输注: %1$@ %2$@"; - -/* Delivery status when insulin delivery is suspended */ -"Suspended" = "暂停"; - -/* Alert notification body for suspendEnded pod alert user notification */ -"Suspension time is up. Open the app and resume." = "输注暂停已经结束,打开应用程序并恢复输注"; - -/* Pod tank fill completed */ -"Tank fill completed" = "已向Pod注入胰岛素"; - -/* Pod power to motor activated */ -"Tank power activated" = "Pod已开启"; - -/* Pump Event title for UnfinalizedDose with doseType of .tempBasal */ -"Temp Basal" = "临时基础率"; - -/* Error message shown when temp basal could not be set due to existing temp basal in progress */ -"Temp basal in progress" = "正在设置临时基础率"; - -/* Delivery status when temp basal is running */ -"Temp basal running" = "临时基础率正在运行"; - -/* The format string describing a temp basal. (1: The rate)(2: Start time)(3: duration)(4: volume)(5: scheduled certainty */ -"TempBasal: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@" = "临时基础率: %1$@ U/hour %2$@ %3$@ %4$@ U %5$@"; - -/* Alert content body for suspendEnded pod alert */ -"The insulin suspension period has ended.\n\nYou can resume delivery from the banner on the home screen or from your pump settings screen. You will be reminded again in 15 minutes." = "胰岛素输注暂停期已经结束,\n\n您可以从屏幕上方的横幅或者从您的泵设置屏幕上恢复输注,您将在 15 分钟内再次被提醒"; - -/* Alert content body for timeOffsetChangeDetected pod alert */ -"The time on your pump is different from the current time. You can review the pump time and and sync to current time in settings." = "您泵上的时间不同于当前时间。您可以在设置里将泵时间并同步到当前时间。"; - -/* Alert content title for timeOffsetChangeDetected pod alert */ -"Time Change Detected" = "检测到时间变化"; - -/* The format string for pod expiration notification body (1: time until expiration) */ -"Time to replace your pod! Your pod will expire in %1$@" = "Pod将在%1$@后到期,请准备更换Pod"; - -/* Error message for PodCommsError.tooManyPodsFound */ -"Too many pods found" = "Too many pods found"; - -/* Recovery suggestion when ack received instead of response */ -"Try again" = "Try again"; - -/* String describing a dose that was possibly scheduled */ -"Uncertain" = "未知"; - -/* Description for MessageError invalidSequence */ -"Unexpected message sequence number" = "Unexpected message sequence number"; - -/* Format string for unexpected pod change */ -"Unexpected pod change" = "Unexpected pod change"; - -/* Error message shown when empty response from pod was received */ -"Unexpected response from pod" = "Pod未知响应"; - -/* The format string for Unknown pod fault (1: The fault code value) */ -"Unknown pod fault %1$03d" = "Pod未知错误"; - -/* Format string for description of MessageError unknownValue. (1: value) (2: Type) */ -"Unknown Value (%1$@) for type %2$@" = "Unknown Value (%1$@) for type %2$@"; - -/* Format string for description of MessageError validationFailed. (1: description of validation failure) */ -"Validation failed: %1$@" = "Validation failed: %1$@"; - -/* Recovery suggestion when operation could not be completed due to existing bolus in progress */ -"Wait for existing bolus to finish, or cancel bolus" = "请等待大剂量输注完成,或取消大剂量输注"; - -/* Recovery suggestion when operation could not be completed due to existing temp basal in progress */ -"Wait for existing temp basal to finish, or suspend to cancel" = "请等待临时基础率结束,或暂停以取消临时基础率"; - -/* Description waiting for pairing reminder */ -"Waiting for pairing reminder" = "等待配对提醒"; diff --git a/Dependencies/OmniKit/OmniKitPacketParser/main.swift b/Dependencies/OmniKit/OmniKitPacketParser/main.swift deleted file mode 100644 index 40a394d15..000000000 --- a/Dependencies/OmniKit/OmniKitPacketParser/main.swift +++ /dev/null @@ -1,314 +0,0 @@ -// -// main.swift -// OmniKitPacketParser -// -// Created by Pete Schwamb on 12/19/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -let printRepeats = true - -enum ParsingError: Error { - case invalidPacketType(str: String) -} - -extension PacketType { - init(rtlomniString: String) throws { - switch rtlomniString { - case "PTYPE:POD": - self = .pod - case "PTYPE:PDM": - self = .pdm - case "PTYPE:CON": - self = .con - case "PTYPE:ACK": - self = .ack - default: - throw ParsingError.invalidPacketType(str: rtlomniString) - } - } -} - -extension String { - func valPart() -> String { - return String(split(separator: ":")[1]) - } -} - -extension Int { - func nextPacketNumber(_ increment: Int) -> Int { - return (self + increment) & 0b11111 - } -} - -//from NSHipster - http://nshipster.com/swift-literal-convertible/ -struct Regex { - let pattern: String - let options: NSRegularExpression.Options! - - private var matcher: NSRegularExpression { - return try! NSRegularExpression(pattern: self.pattern, options: self.options) - } - - init(_ pattern: String, options: NSRegularExpression.Options = []) { - self.pattern = pattern - self.options = options - } - - func match(string: String, options: NSRegularExpression.MatchingOptions = []) -> Bool { - return self.matcher.numberOfMatches(in: string, options: options, range: NSMakeRange(0, string.count)) != 0 - } -} - -protocol RegularExpressionMatchable { - func match(regex: Regex) -> Bool -} - -extension String: RegularExpressionMatchable { - func match(regex: Regex) -> Bool { - return regex.match(string: self) - } -} - -func ~=(pattern: Regex, matchable: T) -> Bool { - return matchable.match(regex: pattern) -} - - -class LoopIssueReportParser { - // * 2018-12-27 01:46:56 +0000 send 1f0e41a6101f1a0e81ed50b102010a0101a000340034170d000208000186a00000000000000111 - func parseLine(_ line: String) { - let components = line.components(separatedBy: .whitespaces) - if components.count == 8, let data = Data(hexadecimalString: components[7]) { - let direction = components[6].padding(toLength: 7, withPad: " ", startingAt: 0) - guard direction.lowercased() == "send " || direction.lowercased() == "receive" else { - return - } - let date = components[1..<4].joined(separator: " ") - do { - let message = try Message(encodedData: data, checkCRC: false) - print("\(date) \(direction) \(message)") - } catch let error as MessageError { - if let packet = try? Packet(encodedData: data) { - print("\(date) \(direction) packet \(packet)") - } else { - switch error { - case .notEnoughData: - if data.count == 4 { - // This is from a packet, not a message, and we don't have the full packet info here - print("\(date) \(direction) ack \(components[7])") - } else { - print("Could not parse \(line)") - } - default: - print("Could not parse \(line): \(error.localizedDescription)") - } - } - } catch let error { - print("Could not parse \(line): \(error)") - } - } - } -} - -class RTLOmniLineParser { - private var lastPacket: ArraySlice? = nil - private var messageDate: String = "" - private var lastMessageData = Data() - private var messageData = Data() - private var messageSource: PacketType = .pdm - private var address: String = "" - private var packetNumber: Int = 0 - private var repeatCount: Int = 0 - - func parseLine(_ line: String) { - let components = line.components(separatedBy: .whitespaces) - if components.count > 3, let packetType = try? PacketType(rtlomniString: components[2]) { - if lastPacket == components[1...] { - return - } - lastPacket = components[1...] - switch packetType { - case .pod, .pdm: - if components.count != 9 { - print("Invalid line:\(line)") - return - } - // 2018-12-19T20:50:48.3d ID1:1f0b3557 PTYPE:POD SEQ:31 ID2:1f0b3557 B9:00 BLEN:205 BODY:02cb510032602138800120478004213c80092045800c203980 CRC:a8 - // 2018-05-25T13:03:51.765792 ID1:ffffffff PTYPE:POD SEQ:01 ID2:ffffffff B9:04 BLEN:23 BODY:011502070002070002020000aa6400088cb98f1f16b11e82a5 CRC:72 - messageDate = components[0] - messageSource = packetType - address = String(components[1].valPart()) - packetNumber = Int(components[3].valPart())! - let messageAddress = String(components[4].valPart()) - let b9 = String(components[5].valPart()) - if messageData.count > 0 { - print("Dropping incomplete message data: \(messageData.hexadecimalString)") - } - messageData = Data(hexadecimalString: messageAddress + b9)! - let messageLen = UInt8(components[6].valPart())! - messageData.append(messageLen) - let packetData = Data(hexadecimalString: components[7].valPart())! - messageData.append(packetData) - case .con: - // 2018-12-19T05:19:04.3d ID1:1f0b3557 PTYPE:CON SEQ:12 CON:0000000000000126 CRC:60 - let packetAddress = String(components[1].valPart()) - let nextPacketNumber = Int(components[3].valPart())! - if (packetAddress == address) && (nextPacketNumber == packetNumber.nextPacketNumber(2)) { - packetNumber = nextPacketNumber - let packetData = Data(hexadecimalString: components[4].valPart())! - messageData.append(packetData) - } else if packetAddress != address { - print("mismatched address: \(line)") - } else if nextPacketNumber != packetNumber.nextPacketNumber(2) { - print("mismatched packet number: \(nextPacketNumber) != \(packetNumber.nextPacketNumber(2)) \(line)") - } - case .ack: - print("Ack: \(line)") - } - do { - let message = try Message(encodedData: messageData) - let messageStr = "\(messageDate) \(messageSource) \(message)" - if lastMessageData == messageData { - repeatCount += 1 - if printRepeats { - print(messageStr + " repeat:\(repeatCount)") - } - } else { - lastMessageData = messageData - repeatCount = 0 - print(messageStr) - } - messageData = Data() - } catch MessageError.notEnoughData { - return - } catch let error { - print("Error decoding message: \(error)") - } - } - } -} - -class XcodeLogParser { - private var lastPacket: ArraySlice? = nil - private var messageDate: String = "" - private var sendMessageData = Data() - private var recvMessageData = Data() - private var messageSource: PacketType = .pdm - private var address: String = "" - private var packetNumber: Int = 0 - private var repeatCount: Int = 0 - - func parseLine(_ line: String) { - let components = line.components(separatedBy: .whitespaces) - if let rlCmd = components.last { - let direction = components[5].prefix(4) - let timeStamp = "\(components[0]) \(components[1])" - - switch direction { - case "Send": - let cmdCode = rlCmd.prefix(4).suffix(2) - switch(cmdCode) { - case "05": // SendAndListen - let packetData = Data(hexadecimalString: String(rlCmd.suffix(rlCmd.count - 28)))! - do { - let packet = try Packet(encodedData: packetData) - print("\(timeStamp) \(direction) \(packet)") - if packet.packetType == .con { - sendMessageData.append(packet.data) - } else { - sendMessageData = packet.data - } - if let message = try? Message(encodedData: sendMessageData) { - print("\(timeStamp) \(direction) \(message)") - sendMessageData = Data() - } - if packet.packetType == .ack { - sendMessageData = Data() - } - } catch let error { - print("Error parsing \(rlCmd): \(error)") - } - case "06": - print("Configure Register: \(cmdCode) \(rlCmd)") - default: - print("Unhandled command: \(direction) \(cmdCode) \(rlCmd)") - } - case "Recv": - let status = rlCmd.prefix(2) - switch(status) { - case "dd": - if rlCmd.count > 6 { - let packetData = Data(hexadecimalString: String(rlCmd.suffix(rlCmd.count - 6)))! - do { - let packet = try Packet(encodedData: packetData) - print("\(timeStamp) \(direction) \(packet)") - if packet.packetType == .con { - recvMessageData.append(packet.data) - } else { - recvMessageData = packet.data - } - do { - let message = try Message(encodedData: recvMessageData) - print("\(timeStamp) \(direction) \(message)") - recvMessageData = Data() - } catch MessageError.notEnoughData { - break - } catch let error { - print("Message not parsed from packet data \(recvMessageData.hexadecimalString): \(error)") - } - } catch let error { - print("Error parsing \(rlCmd): \(error)") - } - } else { - //print("\(timeStamp) \(direction) \(rlCmd)") - } - case "aa": - print("\(timeStamp) Receive Timeout") - default: - print("Unhandled response type: \(direction) \(rlCmd)") - } - default: - break - } - } - } -} - - -for filename in CommandLine.arguments[1...] { - let rtlOmniParser = RTLOmniLineParser() - let loopIssueReportParser = LoopIssueReportParser() - let xcodeLogParser = XcodeLogParser() - print("Parsing \(filename)") - - do { - let data = try String(contentsOfFile: filename, encoding: .utf8) - let lines = data.components(separatedBy: .newlines) - - for line in lines { - switch line { - case Regex("ID1:[0-9a-fA-F]+ PTYPE:"): - // 2018-12-24T10:58:41.3d ID1:1f0f407e PTYPE:POD SEQ:02 ID2:1f0f407e B9:3c BLEN:24 BODY:0216020d0000000000d23102b103ff02b1000008ab08016e83 CRC:c2 - // 2018-05-25T13:03:51.765792 ID1:ffffffff PTYPE:POD SEQ:01 ID2:ffffffff B9:04 BLEN:23 BODY:011502070002070002020000aa6400088cb98f1f16b11e82a5 CRC:72 - rtlOmniParser.parseLine(line) - case Regex("(send|receive) [0-9a-fA-F]+"): - // 2018-12-27 01:46:56 +0000 send 1f0e41a6101f1a0e81ed50b102010a0101a000340034170d000208000186a00000000000000111 - loopIssueReportParser.parseLine(line) - case Regex("RL (Send|Recv) ?\\(single\\): [0-9a-fA-F]+"): -// 2019-02-09 08:23:27.605518-0800 Loop[2978:2294033] [PeripheralManager+RileyLink] RL Send (single): 17050005000000000002580000281f0c27a4591f0c27a447 -// 2019-02-09 08:23:28.262888-0800 Loop[2978:2294816] [PeripheralManager+RileyLink] RL Recv(single): dd0c2f1f079e674b1f079e6769 - xcodeLogParser.parseLine(line) - default: - break - } - - - } - } catch let error { - print("Error: \(error)") - } -} - diff --git a/Dependencies/OmniKit/OmniKitPlugin/Extensions/OSLog.swift b/Dependencies/OmniKit/OmniKitPlugin/Extensions/OSLog.swift deleted file mode 100644 index b3313f0d2..000000000 --- a/Dependencies/OmniKit/OmniKitPlugin/Extensions/OSLog.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// OSLog.swift -// OmniKitPlugin -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import os.log - -extension OSLog { - convenience init(category: String) { - self.init(subsystem: "com.randallknutson.OmniBLE", category: category) - } - - func debug(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .debug, args) - } - - func info(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .info, args) - } - - func `default`(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .default, args) - } - - func error(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .error, args) - } - - private func log(_ message: StaticString, type: OSLogType, _ args: [CVarArg]) { - switch args.count { - case 0: - os_log(message, log: self, type: type) - case 1: - os_log(message, log: self, type: type, args[0]) - case 2: - os_log(message, log: self, type: type, args[0], args[1]) - case 3: - os_log(message, log: self, type: type, args[0], args[1], args[2]) - case 4: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3]) - case 5: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4]) - default: - os_log(message, log: self, type: type, args) - } - } -} diff --git a/Dependencies/OmniKit/OmniKitPlugin/Info.plist b/Dependencies/OmniKit/OmniKitPlugin/Info.plist deleted file mode 100644 index 94c4d6fb2..000000000 --- a/Dependencies/OmniKit/OmniKitPlugin/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - com.loopkit.Loop.PumpManagerIdentifier - Omnipod - com.loopkit.Loop.PumpManagerDisplayName - Omnipod - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - - diff --git a/Dependencies/OmniKit/OmniKitPlugin/OmniKitPlugin.swift b/Dependencies/OmniKit/OmniKitPlugin/OmniKitPlugin.swift deleted file mode 100644 index 06180a9fd..000000000 --- a/Dependencies/OmniKit/OmniKitPlugin/OmniKitPlugin.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// OmniKitPlugin.swift -// OmniKitPlugin -// -// Created by Pete Schwamb on 8/24/19. -// Copyright © 2019 Pete Schwamb. All rights reserved. -// - -import os.log -import LoopKitUI -import OmniKit -import OmniKitUI - -class OmniKitPlugin: NSObject, PumpManagerUIPlugin { - private let log = OSLog(category: "OmniKitPlugin") - - public var pumpManagerType: PumpManagerUI.Type? { - return OmnipodPumpManager.self - } - - override init() { - super.init() - log.default("Instantiated") - } -} diff --git a/Dependencies/OmniKit/OmniKitTests/AcknowledgeAlertsTests.swift b/Dependencies/OmniKit/OmniKitTests/AcknowledgeAlertsTests.swift deleted file mode 100644 index 6c1ba859e..000000000 --- a/Dependencies/OmniKit/OmniKitTests/AcknowledgeAlertsTests.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// AcknowledgeAlertsTests.swift -// OmniKitTests -// -// Created by Eelke Jager on 18/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// -import Foundation - -import XCTest -@testable import OmniKit - -class AcknowledgeAlertsTests: XCTestCase { - func testAcknowledgeLowReservoirAlert() { - // 11 05 2f9b5b2f 10 - do { - // Encode - let encoded = AcknowledgeAlertCommand(nonce: 0x2f9b5b2f, alerts: AlertSet(rawValue: 0x10)) - XCTAssertEqual("11052f9b5b2f10", encoded.data.hexadecimalString) - - // Decode - let cmd = try AcknowledgeAlertCommand(encodedData: Data(hexadecimalString: "11052f9b5b2f10")!) - XCTAssertEqual(.acknowledgeAlert,cmd.blockType) - XCTAssertEqual(0x2f9b5b2f, cmd.nonce) - XCTAssert(cmd.alerts.contains(.slot4)) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } -} diff --git a/Dependencies/OmniKit/OmniKitTests/BasalScheduleTests.swift b/Dependencies/OmniKit/OmniKitTests/BasalScheduleTests.swift deleted file mode 100644 index f844356f6..000000000 --- a/Dependencies/OmniKit/OmniKitTests/BasalScheduleTests.swift +++ /dev/null @@ -1,527 +0,0 @@ -// -// BasalScheduleTests.swift -// OmniKitTests -// -// Created by Pete Schwamb on 4/4/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import XCTest -@testable import OmniKit - -class BasalScheduleTests: XCTestCase { - - func testInsulinTableEntry() { - let entry = InsulinTableEntry(segments: 2, pulses: 300, alternateSegmentPulse: false) - // $01 $2c $01 $2c = 1 + 44 + 1 + 44 = 90 = $5a - XCTAssertEqual(0x5a, entry.checksum()) - - let entry2 = InsulinTableEntry(segments: 2, pulses: 260, alternateSegmentPulse: true) - // $01 $04 $01 $04 = 1 + 4 + 1 + 5 = 1 = $0b - XCTAssertEqual(0x0b, entry2.checksum()) - } - - func testSetBasalScheduleCommand() { - do { - // Decode 1a 12 77a05551 00 0062 2b 1708 0000 f800 f800 f800 - let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a1277a055510000622b17080000f800f800f800")!) - - XCTAssertEqual(0x77a05551, cmd.nonce) - if case SetInsulinScheduleCommand.DeliverySchedule.basalSchedule(let currentSegment, let secondsRemaining, let pulsesRemaining, let table) = cmd.deliverySchedule { - XCTAssertEqual(0x2b, currentSegment) - XCTAssertEqual(737, secondsRemaining) - XCTAssertEqual(0, pulsesRemaining) - XCTAssertEqual(3, table.entries.count) - } else { - XCTFail("Expected ScheduleEntry.basalSchedule type") - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let scheduleEntry = InsulinTableEntry(segments: 16, pulses: 0, alternateSegmentPulse: true) - let table = BasalDeliveryTable(entries: [scheduleEntry, scheduleEntry, scheduleEntry]) - let deliverySchedule = SetInsulinScheduleCommand.DeliverySchedule.basalSchedule(currentSegment: 0x2b, secondsRemaining: 737, pulsesRemaining: 0, table: table) - let cmd = SetInsulinScheduleCommand(nonce: 0x77a05551, deliverySchedule: deliverySchedule) - XCTAssertEqual("1a1277a055510000622b17080000f800f800f800", cmd.data.hexadecimalString) - } - - func testBasalScheduleCommandFromSchedule() { - // Encode from schedule - let entry = BasalScheduleEntry(rate: 0.05, startTime: 0) - let schedule = BasalSchedule(entries: [entry]) - - let cmd = SetInsulinScheduleCommand(nonce: 0x01020304, basalSchedule: schedule, scheduleOffset: .hours(8.25)) - - XCTAssertEqual(0x01020304, cmd.nonce) - if case SetInsulinScheduleCommand.DeliverySchedule.basalSchedule(let currentSegment, let secondsRemaining, let pulsesRemaining, let table) = cmd.deliverySchedule { - XCTAssertEqual(16, currentSegment) - XCTAssertEqual(UInt16(TimeInterval(minutes: 15)), secondsRemaining) - XCTAssertEqual(0, pulsesRemaining) - XCTAssertEqual(3, table.entries.count) - let tableEntry = table.entries[0] - XCTAssertEqual(true, tableEntry.alternateSegmentPulse) - XCTAssertEqual(0, tableEntry.pulses) - XCTAssertEqual(16, tableEntry.segments) - } else { - XCTFail("Expected ScheduleEntry.basalSchedule type") - } - // 1a LL NNNNNNNN 00 CCCC HH SSSS PPPP napp napp napp napp - // 1a 12 01020304 00 0065 10 1c20 0001 f800 f800 f800 - XCTAssertEqual("1a1201020304000064101c200000f800f800f800", cmd.data.hexadecimalString) - } - - - func testBasalScheduleExtraCommand() { - do { - // Decode 130e40 00 1aea 001e8480 3840005b8d80 - - let cmd = try BasalScheduleExtraCommand(encodedData: Data(hexadecimalString: "130e40001aea001e84803840005b8d80")!) - - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(true, cmd.completionBeep) - XCTAssertEqual(0, cmd.programReminderInterval) - XCTAssertEqual(0, cmd.currentEntryIndex) - XCTAssertEqual(689, cmd.remainingPulses) - XCTAssertEqual(TimeInterval(seconds: 20), cmd.delayUntilNextTenthOfPulse) - XCTAssertEqual(1, cmd.rateEntries.count) - let entry = cmd.rateEntries[0] - XCTAssertEqual(TimeInterval(seconds: 60), entry.delayBetweenPulses) - XCTAssertEqual(1440, entry.totalPulses) - XCTAssertEqual(3.0, entry.rate) - XCTAssertEqual(TimeInterval(hours: 24), entry.duration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let rateEntries = RateEntry.makeEntries(rate: 3.0, duration: TimeInterval(hours: 24)) - let cmd = BasalScheduleExtraCommand(currentEntryIndex: 0, remainingPulses: 689, delayUntilNextTenthOfPulse: TimeInterval(seconds: 20), rateEntries: rateEntries, acknowledgementBeep: false, completionBeep: true, programReminderInterval: 0) - - - XCTAssertEqual("130e40001aea01312d003840005b8d80", cmd.data.hexadecimalString) - } - - func testBasalScheduleExtraCommandFromSchedule() { - // Encode from schedule - let entry = BasalScheduleEntry(rate: 0.05, startTime: 0) - let schedule = BasalSchedule(entries: [entry]) - - let cmd = BasalScheduleExtraCommand(schedule: schedule, scheduleOffset: .hours(8.25), acknowledgementBeep: false, completionBeep: true, programReminderInterval: 60) - - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(true, cmd.completionBeep) - XCTAssertEqual(60, cmd.programReminderInterval) - XCTAssertEqual(0, cmd.currentEntryIndex) - XCTAssertEqual(15.8, cmd.remainingPulses, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 3), cmd.delayUntilNextTenthOfPulse) - XCTAssertEqual(1, cmd.rateEntries.count) - let rateEntry = cmd.rateEntries[0] - XCTAssertEqual(TimeInterval(minutes: 60), rateEntry.delayBetweenPulses) - XCTAssertEqual(24, rateEntry.totalPulses, accuracy: 0.001) - XCTAssertEqual(0.05, rateEntry.rate) - XCTAssertEqual(TimeInterval(hours: 24), rateEntry.duration, accuracy: 0.001) - } - - func testBasalExtraEncoding() { - // Encode - - let schedule = BasalSchedule(entries: [ - BasalScheduleEntry(rate: 1.05, startTime: 0), - BasalScheduleEntry(rate: 0.9, startTime: .hours(10.5)), - BasalScheduleEntry(rate: 1, startTime: .hours(18.5)) - ]) - - let hh = 0x2e - let ssss = 0x1be8 - let offset = TimeInterval(minutes: Double((hh + 1) * 30)) - TimeInterval(seconds: Double(ssss / 8)) - - // 1a LL NNNNNNNN 00 CCCC HH SSSS PPPP napp napp napp napp - // 1a 14 0d6612db 00 0310 2e 1be8 0005 f80a 480a f009 a00a - - let cmd1 = SetInsulinScheduleCommand(nonce: 0x0d6612db, basalSchedule: schedule, scheduleOffset: offset) - XCTAssertEqual("1a140d6612db0003102e1be80005f80a480af009a00a", cmd1.data.hexadecimalString) - - // 13 LL RR MM NNNN XXXXXXXX YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ - // 13 1a 40 02 0096 00a7d8c0 089d 01059449 05a0 01312d00 044c 0112a880 - let cmd2 = BasalScheduleExtraCommand(schedule: schedule, scheduleOffset: offset, acknowledgementBeep: false, completionBeep: true, programReminderInterval: 0) - XCTAssertEqual("131a4002009600a7d8c0089d0105944905a001312d00044c0112a880", cmd2.data.hexadecimalString) // PDM - } - - func checkBasalScheduleExtraCommandDataWithLessPrecision(_ expected: Data, _ data: Data, line: UInt = #line) { - // The XXXXXXXX field is in thousands of a millisecond. Since we use TimeIntervals (floating point) for - // recreating the offset, we can have small errors in reproducing the the encoded output, which we really - // don't care about. - - func extractXXXXXXXX(_ data: Data) -> TimeInterval { - return TimeInterval(Double(data[6...].toBigEndian(UInt32.self)) / 1000000.0) - } - - let xxxxxxxx1 = extractXXXXXXXX(expected) - let xxxxxxxx2 = extractXXXXXXXX(data) - XCTAssertEqual(xxxxxxxx1, xxxxxxxx2, accuracy: 0.01, line: line) - - func blurXXXXXXXX(_ inStr: String) -> String { - let start = inStr.index(inStr.startIndex, offsetBy:12) - let end = inStr.index(start, offsetBy:8) - return inStr.replacingCharacters(in: start.. only one entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 05181992 02 0003 02 0000 0000 1800 17 0d 00 0000 00030d40 000a 0aba9500 - let bolus_0_05U_Ext_0_5Hr = SetInsulinScheduleCommand(nonce: 0x05181992, units: 0.0, extendedUnits: 0.05, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a0e0518199202000302000000001800", bolus_0_05U_Ext_0_5Hr.data.hexadecimalString) - - // 0.10U extended bolus over 1 hour -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 06211961 02 0005 03 0000 0000 1800 0001 - let bolus_0_10U_Ext_1Hr = SetInsulinScheduleCommand(nonce: 0x06211961, units: 0.0, extendedUnits: 0.10, extendedDuration: .hours(1)) - XCTAssertEqual("1a1006211961020005030000000018000001", bolus_0_10U_Ext_1Hr.data.hexadecimalString) - - // 0.10U extended bolus over 1.5 hours - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp -> non-zero first entry - // 1a 10 04111967 02 0006 04 0000 0000 1000 1001 - let bolus_0_10U_Ext_1_5Hr = SetInsulinScheduleCommand(nonce: 0x08121964, units: 0.0, extendedUnits: 0.10, extendedDuration: .hours(1.5)) - XCTAssertEqual("1a1008121964020006040000000010001001", bolus_0_10U_Ext_1_5Hr.data.hexadecimalString) - - // 0.10U extended bolus over 2 hours -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp - // 1a 12 07041776 02 0007 05 0000 0000 1000 0001 1800 - let bolus_0_10U_Ext_2Hr = SetInsulinScheduleCommand(nonce: 0x04111967, units: 0.0, extendedUnits: 0.10, extendedDuration: .hours(2)) - XCTAssertEqual("1a12041119670200070500000000100000011800", bolus_0_10U_Ext_2Hr.data.hexadecimalString) - - // 0.15U extended bolus over 1 hour -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 05181983 02 0006 03 0000 0000 1800 0002 - let bolus_0_15U_Ext_1Hr = SetInsulinScheduleCommand(nonce: 0x05181983, units: 0.0, extendedUnits: 0.15, extendedDuration: .hours(1)) - XCTAssertEqual("1a1005181983020006030000000018000002", bolus_0_15U_Ext_1Hr.data.hexadecimalString) - - // 0.35U extended bolus over 0.5 hours - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 06151215 02 0009 02 0000 0000 0000 0007 - let bolus_0_35U_Ext_0_5Hr = SetInsulinScheduleCommand(nonce: 0x06151215, units: 0.0, extendedUnits: 0.35, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a1006151215020009020000000000000007", bolus_0_35U_Ext_0_5Hr.data.hexadecimalString) - - // 0.35U extended bolus over 4.5 hours -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp - // 1a 14 07211946 02 0011 0a 0000 0000 1000 2001 1800 2001 - let bolus_0_35U_Ext_4_5Hr = SetInsulinScheduleCommand(nonce: 0x07211946, units: 0.0, extendedUnits: 0.35, extendedDuration: .hours(4.5)) - XCTAssertEqual("1a14072119460200110a000000001000200118002001", bolus_0_35U_Ext_4_5Hr.data.hexadecimalString) - - // 0.35U extended bolus over 5.0 hours -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp napp napp - // 1a 18 03231932 02 0012 0b 0000 0000 1000 1001 1800 0001 1800 1001 - let bolus_0_35U_Ext_5_0Hr = SetInsulinScheduleCommand(nonce: 0x03231932, units: 0.0, extendedUnits: 0.35, extendedDuration: .hours(5.0)) - XCTAssertEqual("1a18032319320200120b00000000100010011800000118001001", bolus_0_35U_Ext_5_0Hr.data.hexadecimalString) - - // 0.35U extended bolus over 5.5 hours -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp napp napp napp napp - // 1a 1c 03011936 02 0013 0c 0000 0000 1000 0001 1800 0001 1800 0001 1800 0001 - let bolus_0_35U_Ext_5_5Hr = SetInsulinScheduleCommand(nonce: 0x03011936, units: 0.0, extendedUnits: 0.35, extendedDuration: .hours(5.5)) - XCTAssertEqual("1a1c030119360200130c0000000010000001180000011800000118000001", bolus_0_35U_Ext_5_5Hr.data.hexadecimalString) - - // 0.35U extended bolus over 6.0 hours -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp napp napp - // 1a 18 03231957 02 0014 0d 0000 0000 1000 0001 3800 0001 3800 0001 - let bolus_0_35U_Ext_6_0Hr = SetInsulinScheduleCommand(nonce: 0x03231957, units: 0.0, extendedUnits: 0.35, extendedDuration: .hours(6.0)) - XCTAssertEqual("1a18032319570200140d00000000100000013800000138000001", bolus_0_35U_Ext_6_0Hr.data.hexadecimalString) - - // 0.35U extended bolus over 6.5 hours -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp - // 1a 14 08151959 02 0015 0e 0000 0000 1000 0001 9800 0001 - let bolus_0_35U_Ext_6_5Hr = SetInsulinScheduleCommand(nonce: 0x08151959, units: 0.0, extendedUnits: 0.35, extendedDuration: .hours(6.5)) - XCTAssertEqual("1a14081519590200150e000000001000000198000001", bolus_0_35U_Ext_6_5Hr.data.hexadecimalString) - - // 0.35U extended bolus over 7.0 hours -> non-zero first entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp - // 1a 12 12041962 02 0016 0f 0000 0000 1000 0001 b800 - let bolus_0_35U_Ext_7_0Hr = SetInsulinScheduleCommand(nonce: 0x12041962, units: 0.0, extendedUnits: 0.35, extendedDuration: .hours(7.0)) - XCTAssertEqual("1a12120419620200160f0000000010000001b800", bolus_0_35U_Ext_7_0Hr.data.hexadecimalString) - } - - func testBolusDualWave() { - // 6.0U dual wave bolus with 2.0U immediate and 4.0U extended over 3 hours - // 1A LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp napp - // 1a 16 01e475cb 02 0129 07 0280 0028 0028 100d 000e 100d 000e - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 3c 0190 00030d40 0320 00cdfe60 - do { - let insulinCmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a1601e475cb02012907028000280028100d000e100d000e")!) - XCTAssertEqual(0x01e475cb, insulinCmd.nonce) - let schedule = insulinCmd.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(2.0, units) - XCTAssertEqual(Pod.secondsPerBolusPulse, timeBetweenPulses) - XCTAssertEqual(5, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(0x28, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[1].segments) - XCTAssertEqual(0xd, table.entries[1].pulses) - XCTAssertEqual(false, table.entries[1].alternateSegmentPulse) - XCTAssertEqual(1, table.entries[2].segments) - XCTAssertEqual(0xe, table.entries[2].pulses) - XCTAssertEqual(false, table.entries[2].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[3].segments) - XCTAssertEqual(0xd, table.entries[3].pulses) - XCTAssertEqual(false, table.entries[3].alternateSegmentPulse) - XCTAssertEqual(1, table.entries[4].segments) - XCTAssertEqual(0xe, table.entries[4].pulses) - XCTAssertEqual(false, table.entries[4].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - let extraCmd = try BolusExtraCommand(encodedData: Data(hexadecimalString: "170d3c019000030d40032000cdfe60")!) - XCTAssertEqual(2.0, extraCmd.units) - XCTAssertEqual(false, extraCmd.acknowledgementBeep) - XCTAssertEqual(false, extraCmd.completionBeep) - XCTAssertEqual(.hours(1), extraCmd.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, extraCmd.timeBetweenPulses) - XCTAssertEqual(4, extraCmd.extendedUnits) - XCTAssertEqual(.hours(3), extraCmd.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode 0.10 combo bolus with 0.05U immediate, 0.05U over 30 minutes -> only one entry used! - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp - // 1a 0e 06021986 02 0015 02 0010 0001 1001 - let bolusScheduleCommand = SetInsulinScheduleCommand(nonce: 0x06021986, units: 0.05, extendedUnits: 0.05, extendedDuration: .minutes(30)) - XCTAssertEqual("1a0e0602198602001502001000011001", bolusScheduleCommand.data.hexadecimalString) - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 000a 00030d40 000a 0aba9500 - let cmd = BolusExtraCommand(units: 0.05, timeBetweenPulses: Pod.secondsPerBolusPulse, extendedUnits: 0.05, extendedDuration: .hours(0.5), programReminderInterval: .minutes(60)) - XCTAssertEqual("170d3c000a00030d40000a0aba9500", cmd.data.hexadecimalString) - } - - func testLargeExtendedBolus() { - // 12U extended (square wave) bolus over 6 hours with no immediate bolus - // 1A LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 03171958 02 00fd 0d 0000 0000 0000 b014 - do { - let insulinCmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a10031719580200fd0d000000000000b014")!) - XCTAssertEqual(0x03171958, insulinCmd.nonce) - let schedule = insulinCmd.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(0.0, units) - XCTAssertEqual(0, timeBetweenPulses) - XCTAssertEqual(2, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(0, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(12, table.entries[1].segments) - XCTAssertEqual(0x14, table.entries[1].pulses) - XCTAssertEqual(false, table.entries[1].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - } catch (let error) { - XCTFail("insulin command decoding threw error: \(error)") - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 7c 0000 00030d40 0960 00895440 - do { - let extraCmd = try BolusExtraCommand(encodedData: Data(hexadecimalString: "170d7c000000030d40096000895440")!) - XCTAssertEqual(false, extraCmd.acknowledgementBeep) - XCTAssertEqual(true, extraCmd.completionBeep) - XCTAssertEqual(.minutes(60), extraCmd.programReminderInterval) - XCTAssertEqual(0.0, extraCmd.units) - XCTAssertEqual(Pod.secondsPerBolusPulse, extraCmd.timeBetweenPulses) - XCTAssertEqual(12, extraCmd.extendedUnits) - XCTAssertEqual(.hours(6), extraCmd.extendedDuration) - } catch (let error) { - XCTFail("bolus extra command decoding threw error: \(error)") - } - - // Encode 12U extended (square wave) bolus over 6 hours with no immediate bolus - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 07041960 02 00fd 0d 0000 0000 0000 b014 - let bolusScheduleCommand = SetInsulinScheduleCommand(nonce: 0x07041960, units: 0.0, extendedUnits: 12, extendedDuration: .hours(6)) - XCTAssertEqual("1a10070419600200fd0d000000000000b014", bolusScheduleCommand.data.hexadecimalString) - - let extraCmd = BolusExtraCommand(extendedUnits: 12, extendedDuration: .hours(6), completionBeep: true, programReminderInterval: .minutes(60)) - XCTAssertEqual("170d7c000000030d40096000895440", extraCmd.data.hexadecimalString) - } - - func testLargeBolusDualWave() { - // 30U dual bolus 50% extended over 8 hours - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp napp napp napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 1e 11161988 02 0269 11 12c0 012c 012c 1812 1013 1812 1013 1812 1013 1812 1013 17 0d 7c 0bb8 00030d40 0bb8 00927c00 - let insulinCmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a1e111619880202691112c0012c012c18121013181210131812101318121013")!) - XCTAssertEqual(0x11161988, insulinCmd.nonce) - let schedule = insulinCmd.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(15.0, units) - XCTAssertEqual(2, timeBetweenPulses) - XCTAssertEqual(9, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(0x12c, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[1].segments) - XCTAssertEqual(0x12, table.entries[1].pulses) - XCTAssertEqual(true, table.entries[1].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[2].segments) - XCTAssertEqual(0x13, table.entries[2].pulses) - XCTAssertEqual(false, table.entries[2].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[3].segments) - XCTAssertEqual(0x12, table.entries[3].pulses) - XCTAssertEqual(true, table.entries[3].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[4].segments) - XCTAssertEqual(0x13, table.entries[4].pulses) - XCTAssertEqual(false, table.entries[4].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[5].segments) - XCTAssertEqual(0x12, table.entries[5].pulses) - XCTAssertEqual(true, table.entries[5].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[6].segments) - XCTAssertEqual(0x13, table.entries[6].pulses) - XCTAssertEqual(false, table.entries[6].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[7].segments) - XCTAssertEqual(0x12, table.entries[7].pulses) - XCTAssertEqual(true, table.entries[7].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[8].segments) - XCTAssertEqual(0x13, table.entries[8].pulses) - XCTAssertEqual(false, table.entries[8].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 7c 0bb8 00030d40 0bb8 00927c00 - let extraCmd = try BolusExtraCommand(encodedData: Data(hexadecimalString: "170d7c0bb800030d400bb800927c00")!) - XCTAssertEqual(15.0, extraCmd.units) - XCTAssertEqual(false, extraCmd.acknowledgementBeep) - XCTAssertEqual(true, extraCmd.completionBeep) - XCTAssertEqual(.minutes(60), extraCmd.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, extraCmd.timeBetweenPulses) - XCTAssertEqual(15, extraCmd.extendedUnits) - XCTAssertEqual(.hours(8), extraCmd.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testDualBolusDeliveryEncoding() { - // 0.10U dual bolus 50% extended over 0.5 hours (1i 2e) -> only one entry used - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 03231932 02 0015 02 0010 0001 1001 17 0d 00 000a 00030d40 000a 0aba9500 - let bolus_0_10U_50P_ext_30min = SetInsulinScheduleCommand(nonce: 0x03231932, units: 0.05, extendedUnits: 0.05, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a0e0323193202001502001000011001", bolus_0_10U_50P_ext_30min.data.hexadecimalString) - - // 0.10U dual bolus 50% extended over 1.0 hour (1i 2e) -> max duration allowed - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 03011936 02 0016 03 0010 0001 0001 1800 17 0d 00 000a 00030d40 000a 15752a00 - let bolus_0_10U_50P_ext_60min = SetInsulinScheduleCommand(nonce: 0x03011936, units: 0.05, extendedUnits: 0.05, extendedDuration: .hours(1.0)) - XCTAssertEqual("1a1003011936020016030010000100011800", bolus_0_10U_50P_ext_60min.data.hexadecimalString) - - - // 0.15U dual bolus 65% extended over 0.5 hours (1i 2e) -> only one entry used - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 03171958 02 0016 02 0010 0001 1801 17 0d 00 000a 00030d40 0014 055d4a80 - let bolus_0_15U_65P_ext_30min = SetInsulinScheduleCommand(nonce: 0x03171958, units: 0.05, extendedUnits: 0.10, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a0e0317195802001602001000011801", bolus_0_15U_65P_ext_30min.data.hexadecimalString) - - // 0.15U dual bolus 65% extended over 1.0 hour (1i 2e) -> only one entry used - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 08151959 02 0017 03 0010 0001 2001 17 0d 00 000a 00030d40 0014 0aba9500 - let bolus_0_15U_65P_ext_60min = SetInsulinScheduleCommand(nonce: 0x08151959, units: 0.05, extendedUnits: 0.10, extendedDuration: .hours(1.0)) - XCTAssertEqual("1a0e0815195902001703001000012001", bolus_0_15U_65P_ext_60min.data.hexadecimalString) - - // 0.15U dual bolus 65% extended over 1.5 hours (1i 2e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 06211961 02 0018 04 0010 0001 0001 1800 0001 17 0d 00 000a 00030d40 0014 1017df80 - let bolus_0_15U_65P_ext_90min = SetInsulinScheduleCommand(nonce: 0x06211961, units: 0.05, extendedUnits: 0.10, extendedDuration: .hours(1.5)) - XCTAssertEqual("1a12062119610200180400100001000118000001", bolus_0_15U_65P_ext_90min.data.hexadecimalString) - - // 0.15U dual bolus 65% extended over 2.0 hours (1i 2e) -> max duration allowed - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 12041962 02 0019 05 0010 0001 0001 3800 17 0d 00 000a 00030d40 0014 15752a00 - let bolus_0_15U_65P_ext_120min = SetInsulinScheduleCommand(nonce: 0x12041962, units: 0.05, extendedUnits: 0.10, extendedDuration: .hours(2.0)) - XCTAssertEqual("1a1012041962020019050010000100013800", bolus_0_15U_65P_ext_120min.data.hexadecimalString) - - - // 0.20U dual bolus 75% extended over 0.5 hours (1i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 08121964 02 0017 02 0010 0001 0001 0003 17 0d 00 000a 00030d40 001e 03938700 - let bolus_0_20U_75P_ext_30min = SetInsulinScheduleCommand(nonce: 0x08121964, units: 0.05, extendedUnits: 0.15, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a1008121964020017020010000100010003", bolus_0_20U_75P_ext_30min.data.hexadecimalString) - - // 0.20U dual bolus 75% extended over 1.0 hour (1i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 04111967 02 0018 03 0010 0001 1001 0002 17 0d 00 000a 00030d40 001e 07270e00 - let bolus_0_20U_75P_ext_60min = SetInsulinScheduleCommand(nonce: 0x04111967, units: 0.05, extendedUnits: 0.15, extendedDuration: .hours(1.0)) - XCTAssertEqual("1a1004111967020018030010000110010002", bolus_0_20U_75P_ext_60min.data.hexadecimalString) - - // 0.20U dual bolus 75% extended over 1.5 hours (1i 3e) -> only one entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 09301968 02 0019 04 0010 0001 3001 17 0d 00 000a 00030d40 001e 0aba9500 - let bolus_0_20U_75P_ext_90min = SetInsulinScheduleCommand(nonce: 0x09301968, units: 0.05, extendedUnits: 0.15, extendedDuration: .hours(1.5)) - XCTAssertEqual("1a0e0930196802001904001000013001", bolus_0_20U_75P_ext_90min.data.hexadecimalString) - - // 0.20U dual bolus 75% extended over 2.0 hours (1i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 07271971 02 001a 05 0010 0001 0001 1800 1001 17 0d 00 000a 00030d40 001e 0e4e1c00 - let bolus_0_20U_75P_ext_120min = SetInsulinScheduleCommand(nonce: 0x07271971, units: 0.05, extendedUnits: 0.15, extendedDuration: .hours(2.0)) - XCTAssertEqual("1a120727197102001a0500100001000118001001", bolus_0_20U_75P_ext_120min.data.hexadecimalString) - - // 0.20U dual bolus 75% extended over 2.5 hours (1i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 03091975 02 001b 06 0010 0001 0001 3800 0001 17 0d 00 000a 00030d40 001e 11e1a300 - let bolus_0_20U_75P_ext_150min = SetInsulinScheduleCommand(nonce: 0x03091975, units: 0.05, extendedUnits: 0.15, extendedDuration: .hours(2.5)) - XCTAssertEqual("1a120309197502001b0600100001000138000001", bolus_0_20U_75P_ext_150min.data.hexadecimalString) - - // 0.20U dual bolus 75% extended over 3.0 hours (1i 3e) -> max duration allowed - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 01242016 02 001c 07 0010 0001 0001 5800 17 0d 00 000a 00030d40 001e 15752a00 - let bolus_0_20U_75P_ext_180min = SetInsulinScheduleCommand(nonce: 0x01242016, units: 0.05, extendedUnits: 0.15, extendedDuration: .hours(3.0)) - XCTAssertEqual("1a100124201602001c070010000100015800", bolus_0_20U_75P_ext_180min.data.hexadecimalString) - - - // 0.25U dual bolus 80% extended over 0.5 hours (1i 4e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 03211983 02 0018 02 0010 0001 0001 0004 17 0d 00 000a 00030d40 0028 02aea540 - let bolus_0_25U_80P_ext_30min = SetInsulinScheduleCommand(nonce: 0x03211983, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a1003211983020018020010000100010004", bolus_0_25U_80P_ext_30min.data.hexadecimalString) - - // 0.25U dual bolus 80% extended over 1.0 hour (1i 4e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 11041986 02 0019 03 0010 0001 1801 0002 17 0d 00 000a 00030d40 0028 055d4a80 - let bolus_0_25U_80P_ext_60min = SetInsulinScheduleCommand(nonce: 0x11041986, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(1.0)) - XCTAssertEqual("1a1011041986020019030010000118010002", bolus_0_25U_80P_ext_60min.data.hexadecimalString) - - // 0.25U dual bolus 80% extended over 1.5 hours (1i 4e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 05061987 02 001a 04 0010 0001 2001 0002 17 0d 00 000a 00030d40 0028 080befc0 - let bolus_0_25U_80P_ext_90min = SetInsulinScheduleCommand(nonce: 0x05061987, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(1.5)) - XCTAssertEqual("1a100506198702001a040010000120010002", bolus_0_25U_80P_ext_90min.data.hexadecimalString) - - // 0.25U dual bolus 80% extended over 2.0 hours (1i 4e) -> only one entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 10201988 02 001b 05 0010 0001 4001 17 0d 00 000a 00030d40 0028 0aba9500 - let bolus_0_25U_80P_ext_120min = SetInsulinScheduleCommand(nonce: 0x10201988, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(2.0)) - XCTAssertEqual("1a0e1020198802001b05001000014001", bolus_0_25U_80P_ext_120min.data.hexadecimalString) - - // 0.25U dual bolus 80% extended over 2.5 hours (1i 4e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 07051989 02 001c 06 0010 0001 0001 1800 2001 17 0d 00 000a 00030d40 0028 0d693a40 - let bolus_0_25U_80P_ext_150min = SetInsulinScheduleCommand(nonce: 0x07051989, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(2.5)) - XCTAssertEqual("1a120705198902001c0600100001000118002001", bolus_0_25U_80P_ext_150min.data.hexadecimalString) - - // 0.25U dual bolus 80% extended over 3.0 hours (1i 4e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 16 09061990 02 001d 07 0010 0001 0001 1800 0001 1800 0001 17 0d 00 000a 00030d40 0028 1017df80 - let bolus_0_25U_80P_ext_180min = SetInsulinScheduleCommand(nonce: 0x09061990, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(3.0)) - XCTAssertEqual("1a160906199002001d070010000100011800000118000001", bolus_0_25U_80P_ext_180min.data.hexadecimalString) - - // 0.25U dual bolus 80% extended over 3.5 hours (1i 4e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 09061990 02 001e 08 0010 0001 0001 5800 0001 17 0d 00 000a 00030d40 0028 12c684c0 - let bolus_0_25U_80P_ext_210min = SetInsulinScheduleCommand(nonce: 0x09061990, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(3.5)) - XCTAssertEqual("1a120906199002001e0800100001000158000001", bolus_0_25U_80P_ext_210min.data.hexadecimalString) - - // 0.25U dual bolus 80% extended over 4.0 hours (1i 4e) -> max duration allowed - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 01311991 02 001f 09 0010 0001 0001 7800 17 0d 00 000a 00030d40 0028 15752a00 - let bolus_0_25U_80P_ext_240min = SetInsulinScheduleCommand(nonce: 0x01311991, units: 0.05, extendedUnits: 0.20, extendedDuration: .hours(4.0)) - XCTAssertEqual("1a100131199102001f090010000100017800", bolus_0_25U_80P_ext_240min.data.hexadecimalString) - - - // 0.15U dual bolus 30% extended over 0.5 hours (2i 1e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 05071991 02 0027 02 0020 0002 0002 0001 17 0d 00 0014 00030d40 000a 0aba9500 - let bolus_0_15U_30P_ext_30min = SetInsulinScheduleCommand(nonce: 0x05071991, units: 0.10, extendedUnits: 0.05, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a1005071991020027020020000200020001", bolus_0_15U_30P_ext_30min.data.hexadecimalString) - - // 0.15U dual bolus 30% extended over 1.0 hour (2i 1e) -> max duration allowed - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 08311995 02 0028 03 0020 0002 0002 1800 17 0d 00 0014 00030d40 000a 15752a00 - let bolus_0_15U_30P_ext_60min = SetInsulinScheduleCommand(nonce: 0x08311995, units: 0.10, extendedUnits: 0.05, extendedDuration: .hours(1.0)) - XCTAssertEqual("1a1008311995020028030020000200021800", bolus_0_15U_30P_ext_60min.data.hexadecimalString) - - - // 0.20U dual bolus 50% extended over 0.5 hours (2i 2e) -> only one entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 10061995 02 0028 02 0020 0002 1002 17 0d 00 0014 00030d40 0014 055d4a80 - let bolus_0_20U_50P_ext_30min = SetInsulinScheduleCommand(nonce: 0x10061995, units: 0.10, extendedUnits: 0.10, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a0e1006199502002802002000021002", bolus_0_20U_50P_ext_30min.data.hexadecimalString) - - // 0.20U dual bolus 50% extended over 1.0 hour (2i 2e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 07132004 02 0029 03 0020 0002 0002 1001 17 0d 00 0014 00030d40 0014 0aba9500 - let bolus_0_20U_50P_ext_60min = SetInsulinScheduleCommand(nonce: 0x07132004, units: 0.10, extendedUnits: 0.10, extendedDuration: .hours(1.0)) - XCTAssertEqual("1a1007132004020029030020000200021001", bolus_0_20U_50P_ext_60min.data.hexadecimalString) - - // 0.20U dual bolus 50% extended over 1.5 hours (2i 2e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 02192008 02 002a 04 0020 0002 0002 1800 0001 17 0d 00 0014 00030d40 0014 1017df80 - let bolus_0_20U_50P_ext_90min = SetInsulinScheduleCommand(nonce: 0x02192008, units: 0.10, extendedUnits: 0.10, extendedDuration: .hours(1.5)) - XCTAssertEqual("1a120219200802002a0400200002000218000001", bolus_0_20U_50P_ext_90min.data.hexadecimalString) - - // 0.20U dual bolus 50% extended over 2.0 hours (2i 2e) -> max duration allowed - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 10092008 02 002b 05 0020 0002 0002 3800 17 0d 00 0014 00030d40 0014 15752a00 - let bolus_0_20U_50P_ext_120min = SetInsulinScheduleCommand(nonce: 0x10092008, units: 0.10, extendedUnits: 0.10, extendedDuration: .hours(2.0)) - XCTAssertEqual("1a101009200802002b050020000200023800", bolus_0_20U_50P_ext_120min.data.hexadecimalString) - - - // 0.25U dual bolus 60% extended over 0.5 hours (2i 3e) -> only one entry - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 06222009 02 0029 02 0020 0002 1802 17 0d 00 0014 00030d40 001e 03938700 - let bolus_0_25U_60P_ext_30min = SetInsulinScheduleCommand(nonce: 0x06222009, units: 0.10, extendedUnits: 0.15, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a0e0622200902002902002000021802", bolus_0_25U_60P_ext_30min.data.hexadecimalString) - - // 0.25U dual bolus 60% extended over 1.0 hour (2i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 07122009 02 002a 03 0020 0002 0002 1801 17 0d 00 0014 00030d40 001e 07270e00 - let bolus_0_25U_60P_ext_60min = SetInsulinScheduleCommand(nonce: 0x07122009, units: 0.10, extendedUnits: 0.15, extendedDuration: .hours(1.0)) - XCTAssertEqual("1a100712200902002a030020000200021801", bolus_0_25U_60P_ext_60min.data.hexadecimalString) - - // 0.25U dual bolus 60% extended over 1.5 hours (2i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 08102009 02 002b 04 0020 0002 0002 2001 17 0d 00 0014 00030d40 001e 0aba9500 - let bolus_0_25U_60P_ext_90min = SetInsulinScheduleCommand(nonce: 0x08102009, units: 0.10, extendedUnits: 0.15, extendedDuration: .hours(1.5)) - XCTAssertEqual("1a100810200902002b040020000200022001", bolus_0_25U_60P_ext_90min.data.hexadecimalString) - - // 0.25U dual bolus 60% extended over 2.0 hours (2i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 07162010 02 002c 05 0020 0002 0002 1800 1001 17 0d 00 0014 00030d40 001e 0e4e1c00 - let bolus_0_25U_60P_ext_120min = SetInsulinScheduleCommand(nonce: 0x07162010, units: 0.10, extendedUnits: 0.15, extendedDuration: .hours(2.0)) - XCTAssertEqual("1a120716201002002c0500200002000218001001", bolus_0_25U_60P_ext_120min.data.hexadecimalString) - - // 0.25U dual bolus 60% extended over 2.5 hours (2i 3e) - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 12 08072010 02 002d 06 0020 0002 0002 3800 0001 17 0d 00 0014 00030d40 001e 11e1a300 - let bolus_0_25U_60P_ext_150min = SetInsulinScheduleCommand(nonce: 0x08072010, units: 0.10, extendedUnits: 0.15, extendedDuration: .hours(2.5)) - XCTAssertEqual("1a120807201002002d0600200002000238000001", bolus_0_25U_60P_ext_150min.data.hexadecimalString) - - // 0.25U dual bolus 60% extended over 3.0 hours (2i 3e) -> max duration allowed - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 10 05062012 02 002e 07 0020 0002 0002 5800 17 0d 00 0014 00030d40 001e 15752a00 - let bolus_0_25U_60P_ext_180min = SetInsulinScheduleCommand(nonce: 0x05062012, units: 0.10, extendedUnits: 0.15, extendedDuration: .hours(3.0)) - XCTAssertEqual("1a100506201202002e070020000200025800", bolus_0_25U_60P_ext_180min.data.hexadecimalString) - } - - func test_30U_100P_ext() { - // 30U bolus 100% ext over 0.5 hours (0i 600e) - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 494e532e 02 005c 02 0000 0000 0000 0258 - let bolus30U_100P_ext_30min = SetInsulinScheduleCommand(nonce: 0x494e532e, units: 0.0, extendedUnits: 30, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a10494e532e02005c020000000000000258", bolus30U_100P_ext_30min.data.hexadecimalString) - - let bolus30U_100P_ext_30min_encoded = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: bolus30U_100P_ext_30min.data.hexadecimalString)!) - XCTAssertEqual(0x494e532e, bolus30U_100P_ext_30min_encoded.nonce) - let schedule = bolus30U_100P_ext_30min_encoded.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(0.0, units) - XCTAssertEqual(0, timeBetweenPulses) - XCTAssertEqual(2, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(0, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(1, table.entries[1].segments) - XCTAssertEqual(600, table.entries[1].pulses) - XCTAssertEqual(false, table.entries[1].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 0000 00030d40 1770 000493e0 - let bolus30U_100P_ext_30min_extra = BolusExtraCommand(extendedUnits: 30.0, extendedDuration: .hours(0.5)) - XCTAssertEqual("170d00000000030d401770000493e0", bolus30U_100P_ext_30min_extra.data.hexadecimalString) - - let bolus30U_100P_ext_30min_extra_encoded = try BolusExtraCommand(encodedData: Data(hexadecimalString: bolus30U_100P_ext_30min_extra.data.hexadecimalString)!) - XCTAssertEqual(0.0, bolus30U_100P_ext_30min_extra_encoded.units) - XCTAssertEqual(false, bolus30U_100P_ext_30min_extra_encoded.acknowledgementBeep) - XCTAssertEqual(false, bolus30U_100P_ext_30min_extra_encoded.completionBeep) - XCTAssertEqual(0, bolus30U_100P_ext_30min_extra_encoded.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, bolus30U_100P_ext_30min_extra_encoded.timeBetweenPulses) - XCTAssertEqual(30.0, bolus30U_100P_ext_30min_extra_encoded.extendedUnits) - XCTAssertEqual(.hours(0.5), bolus30U_100P_ext_30min_extra_encoded.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func test_30U_75P_ext() { - // 30U bolus 75% ext over 0.5 hours (450i 150e) - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 494e532e 02 025a 02 0960 0096 0096 01c2 - let bolus30U_75P_ext_30min = SetInsulinScheduleCommand(nonce: 0x494e532e, units: 7.5, extendedUnits: 22.5, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a10494e532e02025a0209600096009601c2", bolus30U_75P_ext_30min.data.hexadecimalString) - - let bolus30U_75P_ext_30min_encoded = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: bolus30U_75P_ext_30min.data.hexadecimalString)!) - XCTAssertEqual(0x494e532e, bolus30U_75P_ext_30min_encoded.nonce) - let schedule = bolus30U_75P_ext_30min_encoded.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(7.5, units) - XCTAssertEqual(Pod.secondsPerBolusPulse, timeBetweenPulses) - XCTAssertEqual(2, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(150, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(1, table.entries[1].segments) - XCTAssertEqual(450, table.entries[1].pulses) - XCTAssertEqual(false, table.entries[1].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 05dc 00030d40 1194 00061a80 - let bolus30U_75P_ext_30min_extra = BolusExtraCommand(units: 7.5, extendedUnits: 22.5, extendedDuration: .hours(0.5)) - XCTAssertEqual("170d0005dc00030d40119400061a80", bolus30U_75P_ext_30min_extra.data.hexadecimalString) - - let bolus30U_75P_ext_30min_extra_encoded = try BolusExtraCommand(encodedData: Data(hexadecimalString: bolus30U_75P_ext_30min_extra.data.hexadecimalString)!) - XCTAssertEqual(7.5, bolus30U_75P_ext_30min_extra_encoded.units) - XCTAssertEqual(false, bolus30U_75P_ext_30min_extra_encoded.acknowledgementBeep) - XCTAssertEqual(false, bolus30U_75P_ext_30min_extra_encoded.completionBeep) - XCTAssertEqual(0, bolus30U_75P_ext_30min_extra_encoded.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, bolus30U_75P_ext_30min_extra_encoded.timeBetweenPulses) - XCTAssertEqual(22.5, bolus30U_75P_ext_30min_extra_encoded.extendedUnits) - XCTAssertEqual(.hours(0.5), bolus30U_75P_ext_30min_extra_encoded.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func test_30U_50P_ext() { - // 30U bolus 50% ext over 0.5 hours (300i 300e) - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp - // 1a 0e 494e532e 02 015b 02 12c0 012c 112c - let bolus30U_50P_ext_30min = SetInsulinScheduleCommand(nonce: 0x494e532e, units: 15.0, extendedUnits: 15.0, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a0e494e532e02015b0212c0012c112c", bolus30U_50P_ext_30min.data.hexadecimalString) - - let bolus30U_50P_ext_30min_encoded = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: bolus30U_50P_ext_30min.data.hexadecimalString)!) - XCTAssertEqual(0x494e532e, bolus30U_50P_ext_30min_encoded.nonce) - let schedule = bolus30U_50P_ext_30min_encoded.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(15.0, units) - XCTAssertEqual(Pod.secondsPerBolusPulse, timeBetweenPulses) - XCTAssertEqual(1, table.entries.count) - XCTAssertEqual(2, table.entries[0].segments) - XCTAssertEqual(300, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 0bb8 00030d40 0bb8 000927c0 - let bolus30U_50P_ext_30min_extra = BolusExtraCommand(units: 15.0, extendedUnits: 15.0, extendedDuration: .hours(0.5)) - XCTAssertEqual("170d000bb800030d400bb8000927c0", bolus30U_50P_ext_30min_extra.data.hexadecimalString) - - let bolus30U_50P_ext_30min_extra_encoded = try BolusExtraCommand(encodedData: Data(hexadecimalString: bolus30U_50P_ext_30min_extra.data.hexadecimalString)!) - XCTAssertEqual(15.0, bolus30U_50P_ext_30min_extra_encoded.units) - XCTAssertEqual(false, bolus30U_50P_ext_30min_extra_encoded.acknowledgementBeep) - XCTAssertEqual(false, bolus30U_50P_ext_30min_extra_encoded.completionBeep) - XCTAssertEqual(0, bolus30U_50P_ext_30min_extra_encoded.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, bolus30U_50P_ext_30min_extra_encoded.timeBetweenPulses) - XCTAssertEqual(15.0, bolus30U_50P_ext_30min_extra_encoded.extendedUnits) - XCTAssertEqual(.hours(0.5), bolus30U_50P_ext_30min_extra_encoded.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func test_30U_25P_ext() { - // 30U bolus 25% ext over 0.5 hours (450i 150e) - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 494e532e 02 025a 02 1c20 01c2 01c2 0096 - let bolus30U_25P_ext_30min = SetInsulinScheduleCommand(nonce: 0x494e532e, units: 22.5, extendedUnits: 7.5, extendedDuration: .hours(0.5)) - XCTAssertEqual("1a10494e532e02025a021c2001c201c20096", bolus30U_25P_ext_30min.data.hexadecimalString) - - let bolus30U_25P_ext_30min_encoded = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: bolus30U_25P_ext_30min.data.hexadecimalString)!) - XCTAssertEqual(0x494e532e, bolus30U_25P_ext_30min_encoded.nonce) - let schedule = bolus30U_25P_ext_30min_encoded.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(22.5, units) - XCTAssertEqual(Pod.secondsPerBolusPulse, timeBetweenPulses) - XCTAssertEqual(2, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(450, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(1, table.entries[1].segments) - XCTAssertEqual(150, table.entries[1].pulses) - XCTAssertEqual(false, table.entries[1].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 1194 00030d40 05dc 00124f80 - let bolus30U_25P_ext_30min_extra = BolusExtraCommand(units: 22.5, extendedUnits: 7.5, extendedDuration: .hours(0.5)) - XCTAssertEqual("170d00119400030d4005dc00124f80", bolus30U_25P_ext_30min_extra.data.hexadecimalString) - - let bolus30U_25P_ext_30min_extra_encoded = try BolusExtraCommand(encodedData: Data(hexadecimalString: bolus30U_25P_ext_30min_extra.data.hexadecimalString)!) - XCTAssertEqual(22.5, bolus30U_25P_ext_30min_extra_encoded.units) - XCTAssertEqual(false, bolus30U_25P_ext_30min_extra_encoded.acknowledgementBeep) - XCTAssertEqual(false, bolus30U_25P_ext_30min_extra_encoded.completionBeep) - XCTAssertEqual(0, bolus30U_25P_ext_30min_extra_encoded.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, bolus30U_25P_ext_30min_extra_encoded.timeBetweenPulses) - XCTAssertEqual(7.5, bolus30U_25P_ext_30min_extra_encoded.extendedUnits) - XCTAssertEqual(.hours(0.5), bolus30U_25P_ext_30min_extra_encoded.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func test_1U_immediate_9123secs_remaining() { - // extended bolus of 1.0U over 3.5 hours - // immediate 1.0U bolus with 2:32:05 (9123 seconds) remaining, cancel bolus returns 15 pulses (0.75U) not delivered - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp napp napp - // 1a 14 d3039c04 02 007f 07 0140 0014 0014 1802 2003 0001 - let nonce: UInt32 = 0xd3039c04 - let immediateUnits = 1.0 - let remainingExtendedUnits = 0.75 - let remainingExtendedBolusTime: TimeInterval = .seconds(9123) - - let bolus_1U_immediate_9123secs_remaining = SetInsulinScheduleCommand(nonce: nonce, units: immediateUnits, extendedUnits: remainingExtendedUnits, extendedDuration: remainingExtendedBolusTime) - XCTAssertEqual("1a14d3039c0402007f07014000140014180220030001", bolus_1U_immediate_9123secs_remaining.data.hexadecimalString) - - let bolus_1U_immediate_9123secs_remaining_encoded = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: bolus_1U_immediate_9123secs_remaining.data.hexadecimalString)!) - XCTAssertEqual(nonce, bolus_1U_immediate_9123secs_remaining.nonce) - let schedule = bolus_1U_immediate_9123secs_remaining_encoded.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(immediateUnits, units) - XCTAssertEqual(Pod.secondsPerBolusPulse, timeBetweenPulses) - XCTAssertEqual(4, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(20, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[1].segments) - XCTAssertEqual(2, table.entries[1].pulses) - XCTAssertEqual(true, table.entries[1].alternateSegmentPulse) - XCTAssertEqual(3, table.entries[2].segments) - XCTAssertEqual(3, table.entries[2].pulses) - XCTAssertEqual(false, table.entries[2].alternateSegmentPulse) - XCTAssertEqual(1, table.entries[3].segments) - XCTAssertEqual(1, table.entries[3].pulses) - XCTAssertEqual(false, table.entries[3].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 00c8 00030d40 0096 03a00a20 - let bolus_1U_immediate_9123secs_remaining_extra = BolusExtraCommand(units: immediateUnits, extendedUnits: remainingExtendedUnits, extendedDuration: remainingExtendedBolusTime) - XCTAssertEqual("170d0000c800030d40009603a00a20", bolus_1U_immediate_9123secs_remaining_extra.data.hexadecimalString) - let bolus_1U_immediate_9123secs_remaining_extra_encoded = try BolusExtraCommand(encodedData: Data(hexadecimalString: bolus_1U_immediate_9123secs_remaining_extra.data.hexadecimalString)!) - XCTAssertEqual(immediateUnits, bolus_1U_immediate_9123secs_remaining_extra_encoded.units) - XCTAssertEqual(false, bolus_1U_immediate_9123secs_remaining_extra.acknowledgementBeep) - XCTAssertEqual(false, bolus_1U_immediate_9123secs_remaining_extra.completionBeep) - XCTAssertEqual(0, bolus_1U_immediate_9123secs_remaining_extra_encoded.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, bolus_1U_immediate_9123secs_remaining_extra.timeBetweenPulses) - XCTAssertEqual(remainingExtendedUnits, bolus_1U_immediate_9123secs_remaining_extra_encoded.extendedUnits) - XCTAssertEqual(remainingExtendedBolusTime, bolus_1U_immediate_9123secs_remaining_extra.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func test_1U_immediate_3363secs_remaining() { - // extended bolus of 1.0U over 3.5 hours - // immediate 1.0U bolus with 56:03 min (3363 seconds) remaining, cancel bolus returns 6 pulses (0.30U) not delivered - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 1304de22 02 0072 03 0140 0014 0014 1003 - let nonce: UInt32 = 0x1304de22 - let immediateUnits = 1.0 - let remainingExtendedUnits = 0.3 - let remainingExtendedBolusTime: TimeInterval = .seconds(3363) - - let bolus_1U_immediate_3363secs_remaining = SetInsulinScheduleCommand(nonce: nonce, units: immediateUnits, extendedUnits: remainingExtendedUnits, extendedDuration: remainingExtendedBolusTime) - XCTAssertEqual("1a101304de22020072030140001400141003", bolus_1U_immediate_3363secs_remaining.data.hexadecimalString) - - let bolus_1U_immediate_3363secs_remaining_encoded = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: bolus_1U_immediate_3363secs_remaining.data.hexadecimalString)!) - XCTAssertEqual(nonce, bolus_1U_immediate_3363secs_remaining.nonce) - let schedule = bolus_1U_immediate_3363secs_remaining_encoded.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(immediateUnits, units) - XCTAssertEqual(Pod.secondsPerBolusPulse, timeBetweenPulses) - XCTAssertEqual(2, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(20, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(2, table.entries[1].segments) - XCTAssertEqual(3, table.entries[1].pulses) - XCTAssertEqual(false, table.entries[1].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 00c8 00030d40 003c 03574150 - let bolus_1U_immediate_3363secs_remaining_extra = BolusExtraCommand(units: immediateUnits, extendedUnits: remainingExtendedUnits, extendedDuration: remainingExtendedBolusTime) - XCTAssertEqual("170d0000c800030d40003c03574150", bolus_1U_immediate_3363secs_remaining_extra.data.hexadecimalString) - let bolus_1U_immediate_3363secs_remaining_extra_encoded = try BolusExtraCommand(encodedData: Data(hexadecimalString: bolus_1U_immediate_3363secs_remaining_extra.data.hexadecimalString)!) - XCTAssertEqual(immediateUnits, bolus_1U_immediate_3363secs_remaining_extra_encoded.units) - XCTAssertEqual(false, bolus_1U_immediate_3363secs_remaining_extra.acknowledgementBeep) - XCTAssertEqual(false, bolus_1U_immediate_3363secs_remaining_extra.completionBeep) - XCTAssertEqual(0, bolus_1U_immediate_3363secs_remaining_extra_encoded.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, bolus_1U_immediate_3363secs_remaining_extra.timeBetweenPulses) - XCTAssertEqual(remainingExtendedUnits, bolus_1U_immediate_3363secs_remaining_extra_encoded.extendedUnits) - XCTAssertEqual(remainingExtendedBolusTime, bolus_1U_immediate_3363secs_remaining_extra.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func test_1U_immediate_382secs_remaining() { - // extended bolus of 1.0U over 3.5 hours - // immediate 1.0U bolus with 6:22 (382 seconds) remaining, cancel bolus returns 1 pulse (0.05U) not delivered - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP napp napp - // 1a 10 10bbea5c 02 006c 02 0140 0014 0014 0001 - let nonce: UInt32 = 0x10bbea5c - let immediateUnits = 1.0 - let remainingExtendedUnits = 0.05 - let remainingExtendedBolusTime: TimeInterval = .seconds(382) - - let bolus_1U_immediate_382secs_remaining = SetInsulinScheduleCommand(nonce: nonce, units: immediateUnits, extendedUnits: remainingExtendedUnits, extendedDuration: remainingExtendedBolusTime) - XCTAssertEqual("1a1010bbea5c02006c020140001400140001", bolus_1U_immediate_382secs_remaining.data.hexadecimalString) - - let bolus_1U_immediate_382secs_remaining_encoded = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: bolus_1U_immediate_382secs_remaining.data.hexadecimalString)!) - XCTAssertEqual(nonce, bolus_1U_immediate_382secs_remaining.nonce) - let schedule = bolus_1U_immediate_382secs_remaining_encoded.deliverySchedule - switch schedule { - case .bolus(let units, let timeBetweenPulses, let table): - XCTAssertEqual(immediateUnits, units) - XCTAssertEqual(Pod.secondsPerBolusPulse, timeBetweenPulses) - XCTAssertEqual(2, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(20, table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - XCTAssertEqual(1, table.entries[1].segments) - XCTAssertEqual(1, table.entries[1].pulses) - XCTAssertEqual(false, table.entries[1].alternateSegmentPulse) - default: - XCTFail("unexpected insulin delivery type \(schedule)") - break - } - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 00c8 00030d40 000a 0246e2c0 - let bolus_1U_immediate_382secs_remaining_extra = BolusExtraCommand(units: immediateUnits, extendedUnits: remainingExtendedUnits, extendedDuration: remainingExtendedBolusTime) - XCTAssertEqual("170d0000c800030d40000a0246e2c0", bolus_1U_immediate_382secs_remaining_extra.data.hexadecimalString) - let bolus_1U_immediate_382secs_remaining_extra_encoded = try BolusExtraCommand(encodedData: Data(hexadecimalString: bolus_1U_immediate_382secs_remaining_extra.data.hexadecimalString)!) - XCTAssertEqual(immediateUnits, bolus_1U_immediate_382secs_remaining_extra_encoded.units) - XCTAssertEqual(false, bolus_1U_immediate_382secs_remaining_extra.acknowledgementBeep) - XCTAssertEqual(false, bolus_1U_immediate_382secs_remaining_extra.completionBeep) - XCTAssertEqual(0, bolus_1U_immediate_382secs_remaining_extra_encoded.programReminderInterval) - XCTAssertEqual(Pod.secondsPerBolusPulse, bolus_1U_immediate_382secs_remaining_extra.timeBetweenPulses) - XCTAssertEqual(remainingExtendedUnits, bolus_1U_immediate_382secs_remaining_extra_encoded.extendedUnits) - XCTAssertEqual(remainingExtendedBolusTime, bolus_1U_immediate_382secs_remaining_extra.extendedDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testBolusExtraOddPulseCount() { - // 17 0d 7c 00fa 00030d40 000000000000 - let cmd = BolusExtraCommand(units: 1.25, acknowledgementBeep: false, completionBeep: true, programReminderInterval: .hours(1)) - XCTAssertEqual("170d7c00fa00030d40000000000000", cmd.data.hexadecimalString) - } - - // 1a 0e NNNNNNNN 02 CCCC HH SSSS PPPP 0ppp 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 1a 0e 19e4890b 02 0025 01 0020 0002 0002 17 0d 00 001e 00030d40 0000 00000000 - // 0ppp = $0002 -> 2 pulses - // NNNN = $001e = 30 (dec) / 10 -> 3 pulses - func testBolusAndBolusExtraMatch() { - // 1a 0e NNNNNNNN 02 CCCC HH SSSS PPPP 0ppp - // 1a 0e 243085c8 02 0025 01 0020 0002 0002 - let bolusAmount = 0.1 - let bolusCommand = SetInsulinScheduleCommand(nonce: 0x243085c8, units: bolusAmount) - XCTAssertEqual("1a0e243085c802002501002000020002", bolusCommand.data.hexadecimalString) - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 00 0014 00030d40 0000 00000000 - let bolusExtraCommand = BolusExtraCommand(units: bolusAmount) - XCTAssertEqual("170d00001400030d40000000000000", bolusExtraCommand.data.hexadecimalString) - } - - func testBolusAndBolusExtraMatch2() { - let bolusAmount = 0.15 - let bolusCommand = SetInsulinScheduleCommand(nonce: 0x243085c8, units: bolusAmount) - XCTAssertEqual("1a0e243085c802003701003000030003", bolusCommand.data.hexadecimalString) - - let bolusExtraCommand = BolusExtraCommand(units: bolusAmount) - XCTAssertEqual("170d00001e00030d40000000000000", bolusExtraCommand.data.hexadecimalString) - } - - func testLargeBolus() { - let bolusAmount = 29.95 - let bolusCommand = SetInsulinScheduleCommand(nonce: 0x31204ba7, units: bolusAmount) - XCTAssertEqual("1a0e31204ba702014801257002570257", bolusCommand.data.hexadecimalString) - - let bolusExtraCommand = BolusExtraCommand(units: bolusAmount, acknowledgementBeep: false, completionBeep: true, programReminderInterval: .hours(1)) - XCTAssertEqual("170d7c176600030d40000000000000", bolusExtraCommand.data.hexadecimalString) - } - - func testOddBolus() { - // 1a 0e NNNNNNNN 02 CCCC HH SSSS PPPP 0ppp - // 1a 0e cf9e81ac 02 00e5 01 0290 0029 0029 - - let bolusAmount = 2.05 - let bolusCommand = SetInsulinScheduleCommand(nonce: 0xcf9e81ac, units: bolusAmount) - XCTAssertEqual("1a0ecf9e81ac0200e501029000290029", bolusCommand.data.hexadecimalString) - - // 17 LL BO NNNN XXXXXXXX YYYY ZZZZZZZZ - // 17 0d 3c 019a 00030d40 0000 00000000 - let bolusExtraCommand = BolusExtraCommand(units: bolusAmount, acknowledgementBeep: false, completionBeep: false, programReminderInterval: .hours(1)) - XCTAssertEqual("170d3c019a00030d40000000000000", bolusExtraCommand.data.hexadecimalString) - } - - func testCancelBolusCommand() { - do { - // Decode 1f 05 4d91f8ff 64 - let cmd = try CancelDeliveryCommand(encodedData: Data(hexadecimalString: "1f054d91f8ff64")!) - XCTAssertEqual(0x4d91f8ff, cmd.nonce) - XCTAssertEqual(.beeeeeep, cmd.beepType) - XCTAssertEqual(.bolus, cmd.deliveryType) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = CancelDeliveryCommand(nonce: 0x4d91f8ff, deliveryType: .bolus, beepType: .beeeeeep) - XCTAssertEqual("1f054d91f8ff64", cmd.data.hexadecimalString) - } -} diff --git a/Dependencies/OmniKit/OmniKitTests/CRC16Tests.swift b/Dependencies/OmniKit/OmniKitTests/CRC16Tests.swift deleted file mode 100644 index 491f959e2..000000000 --- a/Dependencies/OmniKit/OmniKitTests/CRC16Tests.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// CRC16Tests.swift -// OmniKitTests -// -// Created by Pete Schwamb on 10/14/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import XCTest -@testable import OmniKit - -class CRC16Tests: XCTestCase { - - func testComputeCRC16() { - let input = Data(hexadecimalString: "1f01482a10030e0100")! - XCTAssertEqual(0x802c, input.crc16()) - } -} - - - diff --git a/Dependencies/OmniKit/OmniKitTests/CRC8Tests.swift b/Dependencies/OmniKit/OmniKitTests/CRC8Tests.swift deleted file mode 100644 index cc4c3e009..000000000 --- a/Dependencies/OmniKit/OmniKitTests/CRC8Tests.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// CRC8Tests.swift -// OmniKitTests -// -// Created by Pete Schwamb on 10/14/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import XCTest -@testable import OmniKit - -class CRC8Tests: XCTestCase { - - func testComputeCRC8() { - let input = Data(hexadecimalString: "1f07b1eeae1f07b1ee181f1a0eeb5701b202010a0101a000340034170d000208000186a0")! - XCTAssertEqual(0x19, input.crc8()) - } -} - diff --git a/Dependencies/OmniKit/OmniKitTests/Info.plist b/Dependencies/OmniKit/OmniKitTests/Info.plist deleted file mode 100644 index 713b7c93b..000000000 --- a/Dependencies/OmniKit/OmniKitTests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 3.0 - CFBundleVersion - 1 - - diff --git a/Dependencies/OmniKit/OmniKitTests/MessageTests.swift b/Dependencies/OmniKit/OmniKitTests/MessageTests.swift deleted file mode 100644 index 1a2aefc54..000000000 --- a/Dependencies/OmniKit/OmniKitTests/MessageTests.swift +++ /dev/null @@ -1,349 +0,0 @@ -// -// MessageTests.swift -// OmniKitTests -// -// Created by Pete Schwamb on 10/14/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import XCTest -@testable import OmniKit - -class MessageTests: XCTestCase { - - func testMessageData() { - // 2016-06-26T20:33:28.412197 ID1:1f01482a PTYPE:PDM SEQ:13 ID2:1f01482a B9:10 BLEN:3 BODY:0e0100802c CRC:88 - - let msg = Message(address: 0x1f01482a, messageBlocks: [GetStatusCommand()], sequenceNum: 4) - - XCTAssertEqual("1f01482a10030e0100802c", msg.encoded().hexadecimalString) - } - - func testMessageDecoding() { - do { - let msg = try Message(encodedData: Data(hexadecimalString: "1f00ee84300a1d18003f1800004297ff8128")!) - - XCTAssertEqual(0x1f00ee84, msg.address) - XCTAssertEqual(12, msg.sequenceNum) - - let messageBlocks = msg.messageBlocks - - XCTAssertEqual(1, messageBlocks.count) - - let statusResponse = messageBlocks[0] as! StatusResponse - - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, statusResponse.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 4261), statusResponse.timeActive) - - XCTAssertEqual(.scheduledBasal, statusResponse.deliveryStatus) - XCTAssertEqual(.aboveFiftyUnits, statusResponse.podProgressStatus) - XCTAssertEqual(6.3, statusResponse.insulinDelivered, accuracy: 0.01) - XCTAssertEqual(0, statusResponse.bolusNotDelivered) - XCTAssertEqual(3, statusResponse.lastProgrammingMessageSeqNum) - XCTAssert(statusResponse.alerts.isEmpty) - - XCTAssertEqual("1f00ee84300a1d18003f1800004297ff8128", msg.encoded().hexadecimalString) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testAssemblingMultiPacketMessage() { - do { - let packet1 = try Packet(encodedData: Data(hexadecimalString: "ffffffffe4ffffffff041d011b13881008340a5002070002070002030000a62b0004479420")!) - XCTAssertEqual(packet1.data.hexadecimalString, "ffffffff041d011b13881008340a5002070002070002030000a62b00044794") - XCTAssertEqual(packet1.packetType, .pod) - - XCTAssertThrowsError(try Message(encodedData: packet1.data)) { error in - XCTAssertEqual(String(describing: error), "notEnoughData") - } - - let packet2 = try Packet(encodedData: Data(hexadecimalString: "ffffffff861f00ee878352ff")!) - XCTAssertEqual(packet2.address, 0xffffffff) - XCTAssertEqual(packet2.data.hexadecimalString, "1f00ee878352") - XCTAssertEqual(packet2.packetType, .con) - - let messageBody = packet1.data + packet2.data - XCTAssertEqual(messageBody.hexadecimalString, "ffffffff041d011b13881008340a5002070002070002030000a62b000447941f00ee878352") - - let message = try Message(encodedData: messageBody) - XCTAssertEqual(message.messageBlocks.count, 1) - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testParsingShortErosVersionResponse() { - do { - let config = try VersionResponse(encodedData: Data(hexadecimalString: "011502070002070002020000a64000097c279c1f08ced2")!) - XCTAssertEqual(23, config.data.count) - XCTAssertEqual("2.7.0", String(describing: config.firmwareVersion)) - XCTAssertEqual("2.7.0", String(describing: config.iFirmwareVersion)) - XCTAssertEqual(42560, config.lot) - XCTAssertEqual(621607, config.tid) - XCTAssertEqual(0x1f08ced2, config.address) - XCTAssertEqual(2, config.productId) - XCTAssertEqual(.reminderInitialized, config.podProgressStatus) - XCTAssertEqual(2, config.gain) - XCTAssertEqual(0x1c, config.rssi) - XCTAssertNil(config.pulseSize) - XCTAssertNil(config.secondsPerBolusPulse) - XCTAssertNil(config.secondsPerPrimePulse) - XCTAssertNil(config.primeUnits) - XCTAssertNil(config.cannulaInsertionUnits) - XCTAssertNil(config.serviceDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testParsingLongErosVersionResponse() { - do { - let message = try Message(encodedData: Data(hexadecimalString: "ffffffff041d011b13881008340a5002070002070002030000a62b000447941f00ee878352")!) - let config = message.messageBlocks[0] as! VersionResponse - XCTAssertEqual(29, config.data.count) - XCTAssertEqual("2.7.0", String(describing: config.firmwareVersion)) - XCTAssertEqual("2.7.0", String(describing: config.iFirmwareVersion)) - XCTAssertEqual(42539, config.lot) - XCTAssertEqual(280468, config.tid) - XCTAssertEqual(0x1f00ee87, config.address) - XCTAssertEqual(2, config.productId) - XCTAssertEqual(.pairingCompleted, config.podProgressStatus) - XCTAssertNil(config.rssi) - XCTAssertNil(config.gain) - XCTAssertEqual(Pod.pulseSize, config.pulseSize) - XCTAssertEqual(Pod.secondsPerBolusPulse, config.secondsPerBolusPulse) - XCTAssertEqual(Pod.secondsPerPrimePulse, config.secondsPerPrimePulse) - XCTAssertEqual(Pod.primeUnits, config.primeUnits) - XCTAssertEqual(Pod.cannulaInsertionUnits, config.cannulaInsertionUnits) - XCTAssertEqual(Pod.serviceDuration, config.serviceDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testParsingShortDashVersionResponse() { - do { - let config = try VersionResponse(encodedData: Data(hexadecimalString: "0115031b0008080004020812a011000c175700ffffffff")!) - XCTAssertEqual(23, config.data.count) - XCTAssertEqual("3.27.0", String(describing: config.firmwareVersion)) - XCTAssertEqual("8.8.0", String(describing: config.iFirmwareVersion)) - XCTAssertEqual(135438353, config.lot) - XCTAssertEqual(792407, config.tid) - XCTAssertEqual(0xFFFFFFFF, config.address) - XCTAssertEqual(4, config.productId) - XCTAssertEqual(.reminderInitialized, config.podProgressStatus) - XCTAssertEqual(0, config.gain) - XCTAssertEqual(0, config.rssi) - XCTAssertNil(config.pulseSize) - XCTAssertNil(config.secondsPerBolusPulse) - XCTAssertNil(config.secondsPerPrimePulse) - XCTAssertNil(config.primeUnits) - XCTAssertNil(config.cannulaInsertionUnits) - XCTAssertNil(config.serviceDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testParsingLongDashVersionResponse() { - do { - let message = try Message(encodedData: Data(hexadecimalString: "ffffffff0c1d011b13881008340a50031b0008080004030812a011000c175717244389816c")!) - let config = message.messageBlocks[0] as! VersionResponse - XCTAssertEqual(29, config.data.count) - XCTAssertEqual("3.27.0", String(describing: config.firmwareVersion)) - XCTAssertEqual("8.8.0", String(describing: config.iFirmwareVersion)) - XCTAssertEqual(135438353, config.lot) - XCTAssertEqual(792407, config.tid) - XCTAssertEqual(0x17244389, config.address) - XCTAssertEqual(4, config.productId) - XCTAssertEqual(.pairingCompleted, config.podProgressStatus) - XCTAssertNil(config.rssi) - XCTAssertNil(config.gain) - XCTAssertEqual(Pod.pulseSize, config.pulseSize) - XCTAssertEqual(Pod.secondsPerBolusPulse, config.secondsPerBolusPulse) - XCTAssertEqual(Pod.secondsPerPrimePulse, config.secondsPerPrimePulse) - XCTAssertEqual(Pod.primeUnits, config.primeUnits) - XCTAssertEqual(Pod.cannulaInsertionUnits, config.cannulaInsertionUnits) - XCTAssertEqual(Pod.serviceDuration, config.serviceDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testParsingConfigWithPairingExpired() { - do { - let message = try Message(encodedData: Data(hexadecimalString: "ffffffff04170115020700020700020e0000a5ad00053030971f08686301fd")!) - let config = message.messageBlocks[0] as! VersionResponse - XCTAssertEqual("2.7.0", String(describing: config.firmwareVersion)) - XCTAssertEqual("2.7.0", String(describing: config.iFirmwareVersion)) - XCTAssertEqual(0x0000a5ad, config.lot) - XCTAssertEqual(0x00053030, config.tid) - XCTAssertEqual(0x1f086863, config.address) - XCTAssertEqual(2, config.productId) - XCTAssertEqual(.activationTimeExceeded, config.podProgressStatus) - XCTAssertEqual(2, config.gain) - XCTAssertEqual(0x17, config.rssi) - XCTAssertNil(config.pulseSize) - XCTAssertNil(config.secondsPerBolusPulse) - XCTAssertNil(config.secondsPerPrimePulse) - XCTAssertNil(config.primeUnits) - XCTAssertNil(config.cannulaInsertionUnits) - XCTAssertNil(config.serviceDuration) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testAssignAddressCommand() { - do { - // Encode - let encoded = AssignAddressCommand(address: 0x1f01482a) - XCTAssertEqual("07041f01482a", encoded.data.hexadecimalString) - - // Decode - let decoded = try AssignAddressCommand(encodedData: Data(hexadecimalString: "07041f01482a")!) - XCTAssertEqual(0x1f01482a, decoded.address) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testSetupPodCommand() { - do { - var components = DateComponents() - components.day = 12 - components.month = 6 - components.year = 2016 - components.hour = 13 - components.minute = 47 - - // Decode - let decoded = try SetupPodCommand(encodedData: Data(hexadecimalString: "03131f0218c31404060c100d2f0000a4be0004e4a1")!) - XCTAssertEqual(0x1f0218c3, decoded.address) - XCTAssertEqual(components, decoded.dateComponents) - XCTAssertEqual(0x0000a4be, decoded.lot) - XCTAssertEqual(0x0004e4a1, decoded.tid) - - // Encode - let encoded = SetupPodCommand(address: 0x1f0218c3, dateComponents: components, lot: 0x0000a4be, tid: 0x0004e4a1) - XCTAssertEqual("03131f0218c31404060c100d2f0000a4be0004e4a1", encoded.data.hexadecimalString) - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPrime() { - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP 0ppp - // 1a 0e bed2e16b 02 010a 01 01a0 0034 0034 - // Decode - let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a0ebed2e16b02010a0101a000340034")!) - XCTAssertEqual(0xbed2e16b, cmd.nonce) - - if case SetInsulinScheduleCommand.DeliverySchedule.bolus(let units, let timeBetweenPulses, let table) = cmd.deliverySchedule { - XCTAssertEqual(Pod.primeUnits, units) - XCTAssertEqual(Pod.secondsPerPrimePulse, timeBetweenPulses) - XCTAssertEqual(1, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(Int(Pod.primeUnits / Pod.pulseSize), table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - - } else { - XCTFail("Expected ScheduleEntry.bolus type") - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testInsertCannula() { - do { - // 1a LL NNNNNNNN 02 CCCC HH SSSS PPPP 0ppp - // 1a 0e 7e30bf16 02 0065 01 0050 000a 000a - // Decode - let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a0e7e30bf16020065010050000a000a")!) - XCTAssertEqual(0x7e30bf16, cmd.nonce) - - if case SetInsulinScheduleCommand.DeliverySchedule.bolus(let units, let timeBetweenPulses, let table) = cmd.deliverySchedule { - XCTAssertEqual(Pod.cannulaInsertionUnits, units) - XCTAssertEqual(Pod.secondsPerPrimePulse, timeBetweenPulses) - XCTAssertEqual(1, table.entries.count) - XCTAssertEqual(1, table.entries[0].segments) - XCTAssertEqual(Int(Pod.cannulaInsertionUnits / Pod.pulseSize), table.entries[0].pulses) - XCTAssertEqual(false, table.entries[0].alternateSegmentPulse) - } else { - XCTFail("Expected ScheduleEntry.bolus type") - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testStatusResponseAlarmsParsing() { - // 1d 28 0082 00 0044 46eb ff - - do { - // Decode - let status = try StatusResponse(encodedData: Data(hexadecimalString: "1d28008200004446ebff")!) - XCTAssert(status.alerts.contains(.slot3)) - XCTAssert(status.alerts.contains(.slot7)) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testConfigureAlertsCommand() { - // 79a4 10df 0502 - // Pod expires 1 minute short of 3 days - let podSoftExpirationTime = TimeInterval(hours:72) - TimeInterval(minutes:1) - let alertConfig1 = AlertConfiguration(alertType: .slot7, active: true, autoOffModifier: false, duration: .hours(7), trigger: .timeUntilAlert(podSoftExpirationTime), beepRepeat: .every60Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep) - XCTAssertEqual("79a410df0502", alertConfig1.data.hexadecimalString) - - // 2800 1283 0602 - let podHardExpirationTime = TimeInterval(hours:79) - TimeInterval(minutes:1) - let alertConfig2 = AlertConfiguration(alertType: .slot2, active: true, autoOffModifier: false, duration: .minutes(0), trigger: .timeUntilAlert(podHardExpirationTime), beepRepeat: .every15Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep) - XCTAssertEqual("280012830602", alertConfig2.data.hexadecimalString) - - // 020f 0000 0202 - let alertConfig3 = AlertConfiguration(alertType: .slot0, active: false, autoOffModifier: true, duration: .minutes(15), trigger: .timeUntilAlert(0), beepRepeat: .every1MinuteFor15Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep) - XCTAssertEqual("020f00000202", alertConfig3.data.hexadecimalString) - - let configureAlerts = ConfigureAlertsCommand(nonce: 0xfeb6268b, configurations:[alertConfig1, alertConfig2, alertConfig3]) - XCTAssertEqual("1916feb6268b79a410df0502280012830602020f00000202", configureAlerts.data.hexadecimalString) - - do { - let decoded = try ConfigureAlertsCommand(encodedData: Data(hexadecimalString: "1916feb6268b79a410df0502280012830602020f00000202")!) - XCTAssertEqual(3, decoded.configurations.count) - - let config1 = decoded.configurations[0] - XCTAssertEqual(.slot7, config1.slot) - XCTAssertEqual(true, config1.active) - XCTAssertEqual(false, config1.autoOffModifier) - XCTAssertEqual(.hours(7), config1.duration) - if case AlertTrigger.timeUntilAlert(let duration) = config1.trigger { - XCTAssertEqual(podSoftExpirationTime, duration) - } - XCTAssertEqual(.every60Minutes, config1.beepRepeat) - XCTAssertEqual(.bipBeepBipBeepBipBeepBipBeep, config1.beepType) - - let cfg = try AlertConfiguration(encodedData: Data(hexadecimalString: "4c0000640102")!) - XCTAssertEqual(.slot4, cfg.slot) - XCTAssertEqual(true, cfg.active) - XCTAssertEqual(false, cfg.autoOffModifier) - XCTAssertEqual(0, cfg.duration) - if case AlertTrigger.unitsRemaining(let volume) = cfg.trigger { - XCTAssertEqual(10, volume) - } - XCTAssertEqual(.every1MinuteFor3MinutesAndRepeatEvery60Minutes, cfg.beepRepeat) - XCTAssertEqual(.bipBeepBipBeepBipBeepBipBeep, cfg.beepType) - - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } -} - diff --git a/Dependencies/OmniKit/OmniKitTests/OmniKitTests-Bridging-Header.h b/Dependencies/OmniKit/OmniKitTests/OmniKitTests-Bridging-Header.h deleted file mode 100644 index 1b2cb5d6d..000000000 --- a/Dependencies/OmniKit/OmniKitTests/OmniKitTests-Bridging-Header.h +++ /dev/null @@ -1,4 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - diff --git a/Dependencies/OmniKit/OmniKitTests/OmniKitTests.swift b/Dependencies/OmniKit/OmniKitTests/OmniKitTests.swift deleted file mode 100644 index b2f5e169d..000000000 --- a/Dependencies/OmniKit/OmniKitTests/OmniKitTests.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// OmniKitTests.swift -// OmniKitTests -// -// Created by Pete Schwamb on 3/19/23. -// - -import XCTest - -final class OmniKitTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. - } - - func testPerformanceExample() throws { - // This is an example of a performance test case. - measure { - // Put the code you want to measure the time of here. - } - } - -} diff --git a/Dependencies/OmniKit/OmniKitTests/PacketTests.swift b/Dependencies/OmniKit/OmniKitTests/PacketTests.swift deleted file mode 100644 index 3b97bf458..000000000 --- a/Dependencies/OmniKit/OmniKitTests/PacketTests.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// PacketTests.swift -// OmniKitTests -// -// Created by Pete Schwamb on 10/14/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import XCTest -@testable import OmniKit - -class PacketTests: XCTestCase { - - func testPacketData() { - // 2016-06-26T20:33:28.412197 ID1:1f01482a PTYPE:PDM SEQ:13 ID2:1f01482a B9:10 BLEN:3 BODY:0e0100802c CRC:88 - - let msg = Message(address: 0x1f01482a, messageBlocks: [GetStatusCommand()], sequenceNum: 4) - - let packet = Packet(address: 0x1f01482a, packetType: .pdm, sequenceNum: 13, data: msg.encoded()) - - XCTAssertEqual("1f01482aad1f01482a10030e0100802c88", packet.encoded().hexadecimalString) - - XCTAssertEqual("1f01482a10030e0100802c", packet.data.hexadecimalString) - - } - - func testPacketDecoding() { - do { - let packet = try Packet(encodedData: Data(hexadecimalString:"1f01482aad1f01482a10030e0100802c88")!) - XCTAssertEqual(0x1f01482a, packet.address) - XCTAssertEqual(13, packet.sequenceNum) - XCTAssertEqual(.pdm, packet.packetType) - XCTAssertEqual("1f01482a10030e0100802c", packet.data.hexadecimalString) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPacketFragmenting() { - let longMessageData = Data(hexadecimalString:"02cb5000c92162368024632d8029623f002c62320031623b003463320039633d003c63310041623e0044633200496340004c6333005163448101627c8104627c8109627c810c62198111627c811460198103fe")! - let packet = Packet(address: 0x1f01482a, packetType: .pdm, sequenceNum: 13, data: longMessageData) - XCTAssertEqual(31, packet.data.count) - XCTAssertEqual("02cb5000c92162368024632d8029623f002c62320031623b00346332003963", packet.data.hexadecimalString) - let con1 = Packet(address: 0x1f01482a, packetType: .con, sequenceNum: 14, data: longMessageData.subdata(in: 31.. Void)? - - init(address: UInt32, messageNumber: Int) { - self.address = address - self.messageNumber = messageNumber - } - - func sendMessage(_ message: Message) throws -> Message { - sentMessages.append(message) - - if let error = throwSendMessageError { - throw error - } - - if responseMessageBlocks.isEmpty { - throw PodCommsError.noResponse - } - return Message(address: address, messageBlocks: [responseMessageBlocks.removeFirst()], sequenceNum: messageNumber) - } - - func addResponse(_ messageBlock: MessageBlock) { - responseMessageBlocks.append(messageBlock) - } - - func assertOnSessionQueue() { - // Do nothing in tests - } -} - diff --git a/Dependencies/OmniKit/OmniKitTests/PodInfoTests.swift b/Dependencies/OmniKit/OmniKitTests/PodInfoTests.swift deleted file mode 100644 index 6b81209aa..000000000 --- a/Dependencies/OmniKit/OmniKitTests/PodInfoTests.swift +++ /dev/null @@ -1,475 +0,0 @@ -// -// PodInfoTests.swift -// OmniKitTests -// -// Created by Eelke Jager on 18/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -import XCTest -@testable import OmniKit - -class PodInfoTests: XCTestCase { - func testFullMessage() { - do { - // Decode - let infoResponse = try PodInfoResponse(encodedData: Data(hexadecimalString: "0216020d0000000000ab6a038403ff03860000285708030d0000")!) - XCTAssertEqual(infoResponse.podInfoResponseSubType, .detailedStatus) - let faultEvent = infoResponse.podInfo as! DetailedStatus - XCTAssertEqual(faultEvent.faultAccessingTables, false) - XCTAssertEqual(faultEvent.podProgressStatus, .faultEventOccurred) - XCTAssertEqual(faultEvent.errorEventInfo?.insulinStateTableCorruption, false) - XCTAssertEqual(faultEvent.errorEventInfo?.occlusionType, 1) - XCTAssertEqual(faultEvent.errorEventInfo?.immediateBolusInProgress, false) - XCTAssertEqual(faultEvent.errorEventInfo?.podProgressStatus, .aboveFiftyUnits) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoConfiguredAlertsNoAlerts() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 1516 1718 - // 02 13 // 01 XXXX VVVV VVVV VVVV VVVV VVVV VVVV VVVV VVVV - // 02 13 // 01 0000 0000 0000 0000 0000 0000 0000 0000 0000 - do { - // Decode - let decoded = try PodInfoConfiguredAlerts(encodedData: Data(hexadecimalString: "01000000000000000000000000000000000000")!) - XCTAssertEqual(.configuredAlerts, decoded.podInfoType) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoConfiguredAlertsSuspendStillActive() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 1516 1718 - // 02 13 // 01 XXXX VVVV VVVV VVVV VVVV VVVV VVVV VVVV VVVV - // 02 13 // 01 0000 0000 0000 0000 0000 0000 0bd7 0c40 0000 // real alert value after 2 hour suspend - // 02 13 // 01 0000 0102 0304 0506 0708 090a 0bd7 0c40 0000 // used as a tester to find each alarm - do { - // Decode - let decoded = try PodInfoConfiguredAlerts(encodedData: Data(hexadecimalString: "010000000000000000000000000bd70c400000")!) - XCTAssertEqual(.configuredAlerts, decoded.podInfoType) - XCTAssertEqual(.beepBeepBeep, decoded.alertsActivations[5].beepType) - XCTAssertEqual(11, decoded.alertsActivations[5].timeFromPodStart) // in minutes - XCTAssertEqual(10.75, decoded.alertsActivations[5].unitsLeft) //, accuracy: 1) - XCTAssertEqual(.beeeeeep, decoded.alertsActivations[6].beepType) - XCTAssertEqual(12, decoded.alertsActivations[6].timeFromPodStart) // in minutes - XCTAssertEqual(3.2, decoded.alertsActivations[6].unitsLeft) //, accuracy: 1) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoConfiguredAlertsReplacePodAfter3DaysAnd8Hours() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 1516 1718 - // 02 13 // 01 XXXX VVVV VVVV VVVV VVVV VVVV VVVV VVVV VVVV - // 02 13 // 01 0000 0000 0000 0000 0000 0000 0000 0000 10e1 - do { - let decoded = try PodInfoConfiguredAlerts(encodedData: Data(hexadecimalString: "010000000000000000000000000000000010e1")!) - XCTAssertEqual(.configuredAlerts, decoded.podInfoType) - XCTAssertEqual(.bipBipBipbipBipBip, decoded.alertsActivations[7].beepType) - XCTAssertEqual(16, decoded.alertsActivations[7].timeFromPodStart) // in 2 hours steps - XCTAssertEqual(11.25, decoded.alertsActivations[7].unitsLeft, accuracy: 1) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoConfiguredAlertsReplacePodAfterReservoirEmpty() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 1516 1718 - // 02 13 // 01 XXXX VVVV VVVV VVVV VVVV VVVV VVVV VVVV VVVV - // 02 13 // 01 0000 0000 0000 1285 0000 11c7 0000 0000 119c - do { - let decoded = try PodInfoConfiguredAlerts(encodedData: Data(hexadecimalString: "010000000000001285000011c700000000119c")!) - XCTAssertEqual(.configuredAlerts, decoded.podInfoType) - XCTAssertEqual(.bipBeepBipBeepBipBeepBipBeep, decoded.alertsActivations[2].beepType) - XCTAssertEqual(18, decoded.alertsActivations[2].timeFromPodStart) // in 2 hours steps - XCTAssertEqual(6.6, decoded.alertsActivations[2].unitsLeft, accuracy: 1) - XCTAssertEqual(.beep, decoded.alertsActivations[4].beepType) - XCTAssertEqual(17, decoded.alertsActivations[4].timeFromPodStart) // in 2 hours steps - XCTAssertEqual(9.95, decoded.alertsActivations[4].unitsLeft, accuracy: 2) - XCTAssertEqual(.bipBipBipbipBipBip, decoded.alertsActivations[7].beepType) - XCTAssertEqual(17, decoded.alertsActivations[7].timeFromPodStart) // in 2 hours steps - XCTAssertEqual(7.8, decoded.alertsActivations[7].unitsLeft, accuracy: 1) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoConfiguredAlertsReplacePod() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 1516 1718 - // 02 13 // 01 XXXX VVVV VVVV VVVV VVVV VVVV VVVV VVVV VVVV - // 02 13 // 01 0000 0000 0000 1284 0000 0000 0000 0000 10e0 - do { - let decoded = try PodInfoConfiguredAlerts(encodedData: Data(hexadecimalString: "010000000000001284000000000000000010e0")!) - XCTAssertEqual(.configuredAlerts, decoded.podInfoType) - XCTAssertEqual(.bipBeepBipBeepBipBeepBipBeep, decoded.alertsActivations[2].beepType) - XCTAssertEqual(18, decoded.alertsActivations[2].timeFromPodStart) // in 2 hours steps - XCTAssertEqual(6.6, decoded.alertsActivations[2].unitsLeft, accuracy: 1) - XCTAssertEqual(.bipBipBipbipBipBip, decoded.alertsActivations[7].beepType) - XCTAssertEqual(16, decoded.alertsActivations[7].timeFromPodStart) // in 2 hours steps - XCTAssertEqual(11.2, decoded.alertsActivations[7].unitsLeft, accuracy: 1) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoNoFaultAlerts() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 08 01 0000 0a 0038 00 0000 03ff 0087 00 00 00 95 ff 0000 - do { - // Decode - let decoded = try DetailedStatus(encodedData: Data(hexadecimalString: "02080100000a003800000003ff008700000095ff0000")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - XCTAssertEqual(.aboveFiftyUnits, decoded.podProgressStatus) - XCTAssertEqual(.scheduledBasal, decoded.deliveryStatus) - XCTAssertEqual(0000, decoded.bolusNotDelivered) - XCTAssertEqual(0x0a, decoded.lastProgrammingMessageSeqNum) - XCTAssertEqual(.noFaults, decoded.faultEventCode.faultType) - XCTAssertEqual(TimeInterval(minutes: 0x0000), decoded.faultEventTimeSinceActivation) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, decoded.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(8100, decoded.timeActive) - XCTAssertEqual(TimeInterval(minutes: 0x0087), decoded.timeActive) - XCTAssertEqual("02:15", decoded.timeActive.timeIntervalStr) - XCTAssertEqual(0, decoded.unacknowledgedAlerts.rawValue) - XCTAssertEqual(false, decoded.faultAccessingTables) - XCTAssertNil(decoded.errorEventInfo) - XCTAssertEqual(0b10, decoded.receiverLowGain) - XCTAssertEqual(0x15, decoded.radioRSSI) - XCTAssertNil(decoded.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoDeliveryErrorDuringPriming() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 0f 00 0000 09 0034 5c 0001 03ff 0001 00 00 05 ae 05 6029 - do { - // Decode - let decoded = try DetailedStatus(encodedData: Data(hexadecimalString: "020f0000000900345c000103ff0001000005ae056029")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - XCTAssertEqual(.inactive, decoded.podProgressStatus) - XCTAssertEqual(.suspended, decoded.deliveryStatus) - XCTAssertEqual(0000, decoded.bolusNotDelivered) - XCTAssertEqual(9, decoded.lastProgrammingMessageSeqNum) - XCTAssertEqual(.primeOpenCountTooLow, decoded.faultEventCode.faultType) - XCTAssertEqual(TimeInterval(minutes: 0x0001), decoded.faultEventTimeSinceActivation) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, decoded.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 0x0001), decoded.timeActive) - XCTAssertEqual(60, decoded.timeActive) - XCTAssertEqual(00, decoded.unacknowledgedAlerts.rawValue) - XCTAssertEqual(false, decoded.faultAccessingTables) - XCTAssertEqual(false, decoded.errorEventInfo?.insulinStateTableCorruption) - XCTAssertEqual(0, decoded.errorEventInfo?.occlusionType) - XCTAssertEqual(false, decoded.errorEventInfo?.immediateBolusInProgress) - XCTAssertEqual(.primingCompleted, decoded.errorEventInfo?.podProgressStatus) - XCTAssertEqual(0b10, decoded.receiverLowGain) - XCTAssertEqual(0x2e, decoded.radioRSSI) - XCTAssertEqual(.primingCompleted, decoded.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoDuringPriming() { - // Needle cap accidentally removed before priming started leaking and gave error: - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 0d 00 0000 06 0000 8f 0000 03ff 0000 00 00 03 a2 03 86a0 - do { - // Decode - let decoded = try DetailedStatus(encodedData: Data(hexadecimalString: "020d0000000600008f000003ff0000000003a20386a0")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - XCTAssertEqual(.faultEventOccurred, decoded.podProgressStatus) - XCTAssertEqual(.suspended, decoded.deliveryStatus) - XCTAssertEqual(0, decoded.bolusNotDelivered, accuracy: 0.01) - XCTAssertEqual(6, decoded.lastProgrammingMessageSeqNum) - XCTAssertEqual(.command1AParseUnexpectedFailed, decoded.faultEventCode.faultType) - XCTAssertEqual(TimeInterval(minutes: 0x0000), decoded.faultEventTimeSinceActivation) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, decoded.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 0x0000), decoded.timeActive) - XCTAssertEqual(0, decoded.unacknowledgedAlerts.rawValue) - XCTAssertEqual(false, decoded.faultAccessingTables) - XCTAssertEqual(false, decoded.errorEventInfo?.insulinStateTableCorruption) - XCTAssertEqual(0, decoded.errorEventInfo?.occlusionType) - XCTAssertEqual(PodProgressStatus.pairingCompleted, decoded.errorEventInfo?.podProgressStatus) - XCTAssertEqual(0b10, decoded.receiverLowGain) - XCTAssertEqual(0x22, decoded.radioRSSI) - XCTAssertEqual(.pairingCompleted, decoded.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoFaultEventErrorShuttingDown() { - // Failed Pod after 1 day, 18+ hours of live use shortly after installing new omniloop. - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 0d 00 0000 04 07f2 86 09ff 03ff 0a02 00 00 08 23 08 0000 - do { - // Decode - let decoded = try DetailedStatus(encodedData: Data(hexadecimalString: "020d0000000407f28609ff03ff0a0200000823080000")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - XCTAssertEqual(.faultEventOccurred, decoded.podProgressStatus) - XCTAssertEqual(.suspended, decoded.deliveryStatus) - XCTAssertEqual(0, decoded.bolusNotDelivered) - XCTAssertEqual(4, decoded.lastProgrammingMessageSeqNum) - XCTAssertEqual(101.7, decoded.totalInsulinDelivered, accuracy: 0.01) - XCTAssertEqual(.basalOverInfusionPulse, decoded.faultEventCode.faultType) - XCTAssertEqual(0, decoded.unacknowledgedAlerts.rawValue) - XCTAssertEqual(TimeInterval(minutes: 0x09ff), decoded.faultEventTimeSinceActivation) - XCTAssertEqual("1 day plus 18:39", decoded.faultEventTimeSinceActivation?.timeIntervalStr) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, decoded.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 0x0a02), decoded.timeActive) - XCTAssertEqual(false, decoded.faultAccessingTables) - XCTAssertEqual(false, decoded.errorEventInfo?.insulinStateTableCorruption) - XCTAssertEqual(0, decoded.errorEventInfo?.occlusionType) - XCTAssertEqual(false, decoded.errorEventInfo?.immediateBolusInProgress) - XCTAssertEqual(.aboveFiftyUnits, decoded.errorEventInfo?.podProgressStatus) - XCTAssertEqual(0b00, decoded.receiverLowGain) - XCTAssertEqual(0x23, decoded.radioRSSI) - XCTAssertEqual(.aboveFiftyUnits, decoded.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoFaultEventCheckAboveThreshold() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 0d 00 0000 04 07eb 6a 0e0c 03ff 0e14 00 00 28 17 08 0000 - do { - // Decode - let decoded = try DetailedStatus(encodedData: Data(hexadecimalString: "020d0000000407eb6a0e0c03ff0e1400002817080000")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - XCTAssertEqual(.faultEventOccurred, decoded.podProgressStatus) - XCTAssertEqual(.suspended, decoded.deliveryStatus) - XCTAssertEqual(0, decoded.bolusNotDelivered) - XCTAssertEqual(4, decoded.lastProgrammingMessageSeqNum) - XCTAssertEqual(101.35, decoded.totalInsulinDelivered, accuracy: 0.01) - XCTAssertEqual(.occlusionCheckAboveThreshold, decoded.faultEventCode.faultType) - XCTAssertEqual(0, decoded.unacknowledgedAlerts.rawValue) - XCTAssertEqual(TimeInterval(minutes: 0x0e0c), decoded.faultEventTimeSinceActivation) - XCTAssertEqual("2 days plus 11:56", decoded.faultEventTimeSinceActivation?.timeIntervalStr) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, decoded.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 0x0e14), decoded.timeActive) - XCTAssertEqual(false, decoded.faultAccessingTables) - XCTAssertEqual(false, decoded.errorEventInfo?.insulinStateTableCorruption) - XCTAssertEqual(1, decoded.errorEventInfo?.occlusionType) - XCTAssertEqual(false, decoded.errorEventInfo?.immediateBolusInProgress) - XCTAssertEqual(.aboveFiftyUnits, decoded.errorEventInfo?.podProgressStatus) - XCTAssertEqual(0b00, decoded.receiverLowGain) - XCTAssertEqual(0x17, decoded.radioRSSI) - XCTAssertEqual(.aboveFiftyUnits, decoded.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoFaultEventBolusNotDelivered() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 0f 00 0001 02 00ec 6a 0268 03ff 026b 00 00 28 a7 08 2023 - do { - // Decode - let decoded = try DetailedStatus(encodedData: Data(hexadecimalString: "020f0000010200ec6a026803ff026b000028a7082023")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - XCTAssertEqual(.inactive, decoded.podProgressStatus) - XCTAssertEqual(.suspended, decoded.deliveryStatus) - XCTAssertEqual(0.05, decoded.bolusNotDelivered) - XCTAssertEqual(2, decoded.lastProgrammingMessageSeqNum) - XCTAssertEqual(11.8, decoded.totalInsulinDelivered, accuracy: 0.01) - XCTAssertEqual(.occlusionCheckAboveThreshold, decoded.faultEventCode.faultType) - XCTAssertEqual(0, decoded.unacknowledgedAlerts.rawValue) - XCTAssertEqual(TimeInterval(minutes: 0x0268), decoded.faultEventTimeSinceActivation) - XCTAssertEqual("10:16", decoded.faultEventTimeSinceActivation?.timeIntervalStr) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, decoded.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 0x026b), decoded.timeActive) - XCTAssertEqual(false, decoded.faultAccessingTables) - XCTAssertEqual(false, decoded.errorEventInfo?.insulinStateTableCorruption) - XCTAssertEqual(1, decoded.errorEventInfo?.occlusionType) - XCTAssertEqual(false, decoded.errorEventInfo?.immediateBolusInProgress) - XCTAssertEqual(.aboveFiftyUnits, decoded.errorEventInfo?.podProgressStatus) - XCTAssertEqual(0b10, decoded.receiverLowGain) - XCTAssertEqual(0x27, decoded.radioRSSI) - XCTAssertEqual(.aboveFiftyUnits, decoded.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoFaultEventResetDueToLowVoltageDetect() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 0D 00 0000 00 0000 12 FFFF 03FF 0016 00 00 87 9A 07 0000 - do { - // Decode - let decoded = try DetailedStatus(encodedData: Data(hexadecimalString: "020D00000000000012FFFF03FF00160000879A070000")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - XCTAssertEqual(.faultEventOccurred, decoded.podProgressStatus) - XCTAssertEqual(.suspended, decoded.deliveryStatus) - XCTAssertEqual(0.00, decoded.bolusNotDelivered) - XCTAssertEqual(0, decoded.lastProgrammingMessageSeqNum) - XCTAssertEqual(0.00, decoded.totalInsulinDelivered, accuracy: 0.01) - XCTAssertEqual(.resetDueToLVD, decoded.faultEventCode.faultType) - XCTAssertNil(decoded.faultEventTimeSinceActivation) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, decoded.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 0x16), decoded.timeActive) - XCTAssertEqual(0, decoded.unacknowledgedAlerts.rawValue) - XCTAssertEqual(false, decoded.faultAccessingTables) - XCTAssertEqual(true, decoded.errorEventInfo?.insulinStateTableCorruption) - XCTAssertEqual(0, decoded.errorEventInfo?.occlusionType) - XCTAssertEqual(false, decoded.errorEventInfo?.immediateBolusInProgress) - XCTAssertEqual(.insertingCannula, decoded.errorEventInfo?.podProgressStatus) - XCTAssertEqual(0b10, decoded.receiverLowGain) - XCTAssertEqual(0x1A, decoded.radioRSSI) - XCTAssertEqual(.insertingCannula, decoded.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoPulseLogPlusPartial() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 - // 02 LL // 03 PP QQQQ SSSS 04 3c XXXXXXXX ... - // 02 e4 // 03 00 0000 0003 04 3c 00622a80 01612980 00612480 01602680 00611f00 01601a00 00611f00 01602600 00602000 01602600 00602200 01612700 00602000 01602500 00602000 01612500 00612180 01612680 00612080 01612780 00612080 01602680 00612080 01602580 00612080 05612500 08602000 0d612600 10602200 15602800 18612100 1d602800 20602100 25612700 28612100 2d602800 30612200 35602800 38602400 3d602700 40612400 45612c80 48612680 4d602d80 00602780 05632b80 08612680 0d602c80 10612580 15602d80 18602300 1d612100 20612200 25612900 28602300 - do { - let decoded = try PodInfoPulseLogPlus(encodedData: Data(hexadecimalString: "030000000003043c00622a8001612980006124800160268000611f0001601a0000611f0001602600006020000160260000602200016127000060200001602500006020000161250000612180016126800061208001612780006120800160268000612080016025800061208005612500086020000d6126001060220015602800186121001d6028002060210025612700286121002d6028003061220035602800386024003d6027004061240045612c80486126804d602d800060278005632b80086126800d602c801061258015602d80186023001d612100206122002561290028602300")!) - XCTAssertEqual(.pulseLogPlus, decoded.podInfoType) - XCTAssertEqual(.noFaults, decoded.faultEventCode.faultType) - XCTAssertEqual(0000*60, decoded.timeFaultEvent) - XCTAssertEqual(0003*60, decoded.timeActivation) - XCTAssertEqual(4, decoded.entrySize) - XCTAssertEqual(0x3c, decoded.maxEntries) - XCTAssertEqual(0x00622a80, decoded.pulseLog[0]) - XCTAssertEqual(0x01602600, decoded.pulseLog[9]) - XCTAssertEqual(0x01612780, decoded.pulseLog[19]) - XCTAssertEqual(0x15602800, decoded.pulseLog[29]) - XCTAssertEqual(0x3d602700, decoded.pulseLog[39]) - XCTAssertEqual(0x15602d80, decoded.pulseLog[49]) - XCTAssertEqual(0x28602300, decoded.pulseLog[54]) - XCTAssertEqual(55, decoded.nEntries) // a calculated value that is not directly in raw hex data - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoPulseLogPlus() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 - // 02 LL // 03 PP QQQQ SSSS 04 3c XXXXXXXX ... - // 02 f8 // 03 00 0000 0075 04 3c 54402600 59402d80 5c412480 61402d80 00412380 05402d80 08402780 0d402c80 10412480 15412b80 18412400 1d402800 20402400 25412c00 28412500 2d412b00 30402700 35412d00 38402600 3d412c00 40412500 45402c00 48402400 4d412c00 50412400 55412e00 58412680 5d402f80 60402680 01402f80 04402680 09412e80 0c402580 11402e80 14402780 19402e00 1c402400 21412d00 24402600 29412f00 2c412600 31643000 34622600 39623000 3c622600 41622f00 44622600 49622e00 4c632600 51632d00 54602800 59413080 5c412780 61403180 00402880 05413080 08402780 0d413180 10412680 15412f80 - do { - let decoded = try PodInfoPulseLogPlus(encodedData: Data(hexadecimalString: "030000000075043c5440260059402d805c41248061402d800041238005402d80084027800d402c801041248015412b80184124001d4028002040240025412c00284125002d412b003040270035412d00384026003d412c004041250045402c00484024004d412c005041240055412e00584126805d402f806040268001402f800440268009412e800c40258011402e801440278019402e001c40240021412d002440260029412f002c4126003164300034622600396230003c62260041622f004462260049622e004c63260051632d0054602800594130805c412780614031800040288005413080084027800d4131801041268015412f80")!) - XCTAssertEqual(.pulseLogPlus, decoded.podInfoType) - XCTAssertEqual(.noFaults, decoded.faultEventCode.faultType) - XCTAssertEqual(TimeInterval(minutes: 0x0000), decoded.timeFaultEvent) - XCTAssertEqual(TimeInterval(minutes: 0x0075), decoded.timeActivation) - XCTAssertEqual(4, decoded.entrySize) - XCTAssertEqual(0x3c, decoded.maxEntries) - XCTAssertEqual(0x54402600, decoded.pulseLog[0]) - XCTAssertEqual(0x15412b80, decoded.pulseLog[9]) - XCTAssertEqual(0x3d412c00, decoded.pulseLog[19]) - XCTAssertEqual(0x01402f80, decoded.pulseLog[29]) - XCTAssertEqual(0x29412f00, decoded.pulseLog[39]) - XCTAssertEqual(0x51632d00, decoded.pulseLog[49]) - XCTAssertEqual(0x15412f80, decoded.pulseLog[59]) - XCTAssertEqual(0x3c, decoded.nEntries) // a calculated value - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoActivationTime() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 91011 1213141516 - // 02 11 // 05 PP QQQQ 00000000 00000000 MMDDYYHHMM - // 02 11 // 05 92 0001 00000000 00000000 091912170e - // 09-25-18 23:14 int values for datetime - do { - // Decode - let decoded = try PodInfoActivationTime(encodedData: Data(hexadecimalString: "059200010000000000000000091912170e")!) - XCTAssertEqual(.activationTime, decoded.podInfoType) - XCTAssertEqual(.tempPulseChanInactive, decoded.faultEventCode.faultType) - XCTAssertEqual(TimeInterval(minutes: 0x0001), decoded.timeActivation) - let decodedDateTime = decoded.dateTime - XCTAssertEqual(2018, decodedDateTime.year) - XCTAssertEqual(09, decodedDateTime.month) - XCTAssertEqual(25, decodedDateTime.day) - XCTAssertEqual(23, decodedDateTime.hour) - XCTAssertEqual(14, decodedDateTime.minute) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoPulseLogRecent() { - //02 cb 50 0086 34212e00 39203100 3c212d00 41203000 44202c00 49212e00 4c212b00 51202f00 54212c00 59203080 5c202d80 61203080 00212e80 05213180 08202f80 0d203280 10202f80 15213180 18202f80 1d213180 20202e80 25213300 28203200 2d213500 30213100 35213400 38213100 3d203500 40203100 45213300 48203000 4d213200 50212f00 55203300 58203080 5d213280 60202f80 01203080 04202c80 09213180 0c213080 11213280 14203180 19213380 1c203180 21203280 24213200 29203500 2c213100 31213400" - do { - // Decode - let decoded = try PodInfoPulseLogRecent(encodedData: Data(hexadecimalString: "50008634212e00392031003c212d004120300044202c0049212e004c212b0051202f0054212c00592030805c202d806120308000212e800521318008202f800d20328010202f801521318018202f801d21318020202e8025213300282032002d2135003021310035213400382131003d2035004020310045213300482030004d21320050212f0055203300582030805d21328060202f800120308004202c80092131800c2130801121328014203180192133801c2031802120328024213200292035002c21310031213400")!) - XCTAssertEqual(.pulseLogRecent, decoded.podInfoType) - XCTAssertEqual(134, decoded.indexLastEntry) - XCTAssertEqual(0x34212e00, decoded.pulseLog[0]) - XCTAssertEqual(0x59203080, decoded.pulseLog[9]) - XCTAssertEqual(0x1d213180, decoded.pulseLog[19]) - XCTAssertEqual(0x45213300, decoded.pulseLog[29]) - XCTAssertEqual(0x09213180, decoded.pulseLog[39]) - XCTAssertEqual(0x31213400, decoded.pulseLog[49]) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodInfoPulseLogPrevious() { - //02 cb 51 0032 14602500 19612800 1c612400 21612800 24612500 29612900 2c602600 31602a00 34602600 39612a80 3c612680 41602c80 00602780 05632880 08602580 0d612880 10612580 15612780 18602380 1d602680 20612280 25602700 28612400 2d212800 30202700 35202a00 38202700 3d202a00 40202900 45202c00 48202a00 4d212c00 50212900 55212c00 58212980 5d202b80 60202880 01202d80 04212a80 09202d80 0c212980 11212a80 14212980 1921801c 212a8021 212c8024 202c0029 212f002c 212d0031 20310082 - do { - // Decode - let decoded = try PodInfoPulseLogPrevious(encodedData: Data(hexadecimalString: "51003214602500196128001c6124002161280024612500296129002c60260031602a003460260039612a803c61268041602c800060278005632880086025800d6128801061258015612780186023801d6026802061228025602700286124002d2128003020270035202a00382027003d202a004020290045202c0048202a004d212c005021290055212c00582129805d202b806020288001202d8004212a8009202d800c21298011212a80142129801921801c212a8021212c8024202c0029212f002c212d003120310082")!) - XCTAssertEqual(.pulseLogPrevious, decoded.podInfoType) - XCTAssertEqual(50, decoded.nEntries) - XCTAssertEqual(0x14602500, decoded.pulseLog[0]) - XCTAssertEqual(0x39612a80, decoded.pulseLog[9]) - XCTAssertEqual(0x1d602680, decoded.pulseLog[19]) - XCTAssertEqual(0x45202c00, decoded.pulseLog[29]) - XCTAssertEqual(0x09202d80, decoded.pulseLog[39]) - XCTAssertEqual(0x20310082, decoded.pulseLog[49]) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testPodFault12() { - // 02DATAOFF 0 1 2 3 4 5 6 7 8 910 1112 1314 15 16 17 18 19 2021 - // 02 16 // 02 0J 0K LLLL MM NNNN PP QQQQ RRRR SSSS TT UU VV WW 0X YYYY - // 02 16 // 02 0d 00 0000 00 0000 12 ffff 03ff 0000 00 00 87 92 07 0000 - do { - // Decode - let faultEvent = try DetailedStatus(encodedData: Data(hexadecimalString: "020d00000000000012ffff03ff000000008792070000")!) - XCTAssertEqual(.detailedStatus, faultEvent.podInfoType) - XCTAssertEqual(.faultEventOccurred, faultEvent.podProgressStatus) - XCTAssertEqual(.suspended, faultEvent.deliveryStatus) - XCTAssertEqual(0.00, faultEvent.bolusNotDelivered) - XCTAssertEqual(0, faultEvent.lastProgrammingMessageSeqNum) - XCTAssertEqual(0.00, faultEvent.totalInsulinDelivered, accuracy: 0.01) - XCTAssertEqual(.resetDueToLVD, faultEvent.faultEventCode.faultType) - XCTAssertNil(faultEvent.faultEventTimeSinceActivation) - XCTAssertEqual(Pod.reservoirLevelAboveThresholdMagicNumber, faultEvent.reservoirLevel, accuracy: 0.01) - XCTAssertEqual(TimeInterval(minutes: 0x0000), faultEvent.timeActive) - XCTAssertEqual(0, faultEvent.unacknowledgedAlerts.rawValue) - XCTAssertEqual(false, faultEvent.faultAccessingTables) - XCTAssertEqual(true, faultEvent.errorEventInfo?.insulinStateTableCorruption) - XCTAssertEqual(0, faultEvent.errorEventInfo?.occlusionType) - XCTAssertEqual(false, faultEvent.errorEventInfo?.immediateBolusInProgress) - XCTAssertEqual(.insertingCannula, faultEvent.errorEventInfo?.podProgressStatus) - XCTAssertEqual(0b10, faultEvent.receiverLowGain) - XCTAssertEqual(0x12, faultEvent.radioRSSI) - XCTAssertEqual(.insertingCannula, faultEvent.previousPodProgressStatus) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } -} diff --git a/Dependencies/OmniKit/OmniKitTests/PodStateTests.swift b/Dependencies/OmniKit/OmniKitTests/PodStateTests.swift deleted file mode 100644 index b64a997fb..000000000 --- a/Dependencies/OmniKit/OmniKitTests/PodStateTests.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// PodStateTests.swift -// OmniKitTests -// -// Created by Pete Schwamb on 10/13/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import XCTest -@testable import OmniKit - -class PodStateTests: XCTestCase { - - func testNonceValues() { - var podState = PodState(address: 0x1f000000, pmVersion: "1.1.0", piVersion: "1.1.0", lot: 42560, tid: 661771, insulinType: .novolog) - - XCTAssertEqual(podState.currentNonce, 0x8c61ee59) - podState.advanceToNextNonce() - XCTAssertEqual(podState.currentNonce, 0xc0256620) - podState.advanceToNextNonce() - XCTAssertEqual(podState.currentNonce, 0x15022c8a) - podState.advanceToNextNonce() - XCTAssertEqual(podState.currentNonce, 0xacf076ca) - } - - func testResyncNonce() { - do { - let config = try VersionResponse(encodedData: Data(hexadecimalString: "011502070002070002020000a62b0002249da11f00ee860318")!) - var podState = PodState(address: config.address, pmVersion: config.firmwareVersion.description, piVersion: config.iFirmwareVersion.description, lot: config.lot, tid: config.tid, insulinType: .novolog) - - XCTAssertEqual(42539, config.lot) - XCTAssertEqual(140445, config.tid) - - XCTAssertEqual(0x8fd39264, podState.currentNonce) - - // ID1:1f00ee86 PTYPE:PDM SEQ:26 ID2:1f00ee86 B9:24 BLEN:6 BODY:1c042e07c7c703c1 CRC:f4 - let sentPacket = try Packet(encodedData: Data(hexadecimalString: "1f00ee86ba1f00ee8624061c042e07c7c703c1f4")!) - let sentMessage = try Message(encodedData: sentPacket.data) - let sentCommand = sentMessage.messageBlocks[0] as! DeactivatePodCommand - - let errorResponse = try ErrorResponse(encodedData: Data(hexadecimalString: "06031492c482f5")!) - - XCTAssertEqual(9, sentMessage.sequenceNum) - switch errorResponse.errorResponseType { - case .badNonce(let nonceResyncKey): - podState.resyncNonce(syncWord: nonceResyncKey, sentNonce: sentCommand.nonce, messageSequenceNum: sentMessage.sequenceNum) - XCTAssertEqual(0x40ccdacb, podState.currentNonce) - break - default: - XCTFail("Unexpected non bad nonce response") - break - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testErrorResponse() { - do { - let errorResponse = try ErrorResponse(encodedData: Data(hexadecimalString: "0603070008019a")!) - - switch errorResponse.errorResponseType { - case .nonretryableError(let errorCode, let faultEventCode, let podProgress): - XCTAssertEqual(7, errorCode) - XCTAssertEqual(.noFaults, faultEventCode.faultType) - XCTAssertEqual(.aboveFiftyUnits, podProgress) - break - default: - XCTFail("Unexpected bad nonce response") - break - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } -} - diff --git a/Dependencies/OmniKit/OmniKitTests/StatusTests.swift b/Dependencies/OmniKit/OmniKitTests/StatusTests.swift deleted file mode 100644 index 3a78979ed..000000000 --- a/Dependencies/OmniKit/OmniKitTests/StatusTests.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// StatusTests.swift -// OmniKitTests -// -// Created by Eelke Jager on 08/09/2018. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// -import Foundation - -import XCTest -@testable import OmniKit - -class StatusTests: XCTestCase { - - func testStatusRequestCommand() { - // 0e 01 00 - do { - // Encode - let encoded = GetStatusCommand(podInfoType: .normal) - XCTAssertEqual("0e0100", encoded.data.hexadecimalString) - - // Decode - let decoded = try GetStatusCommand(encodedData: Data(hexadecimalString: "0e0100")!) - XCTAssertEqual(.normal, decoded.podInfoType) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testStatusResponse46UnitsLeft() { - /// 1d19050ec82c08376f9801dc - do { - // Decode - let decoded = try StatusResponse(encodedData: Data(hexadecimalString: "1d19050ec82c08376f9801dc")!) - XCTAssertEqual(TimeInterval(minutes: 3547), decoded.timeActive) - XCTAssertEqual(.scheduledBasal, decoded.deliveryStatus) - XCTAssertEqual(.fiftyOrLessUnits, decoded.podProgressStatus) - XCTAssertEqual(129.45, decoded.insulinDelivered, accuracy: 0.01) - XCTAssertEqual(46.00, decoded.reservoirLevel) - XCTAssertEqual(2.2, decoded.bolusNotDelivered) - XCTAssertEqual(9, decoded.lastProgrammingMessageSeqNum) - //XCTAssert(,decoded.alarms) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testStatusRequestCommandConfiguredAlerts() { - // 0e 01 01 - do { - // Encode - let encoded = GetStatusCommand(podInfoType: .configuredAlerts) - XCTAssertEqual("0e0101", encoded.data.hexadecimalString) - - // Decode - let decoded = try GetStatusCommand(encodedData: Data(hexadecimalString: "0e0101")!) - XCTAssertEqual(.configuredAlerts, decoded.podInfoType) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } - - func testStatusRequestCommandFaultEvents() { - // 0e 01 02 - do { - // Encode - let encoded = GetStatusCommand(podInfoType: .detailedStatus) - XCTAssertEqual("0e0102", encoded.data.hexadecimalString) - - // Decode - let decoded = try GetStatusCommand(encodedData: Data(hexadecimalString: "0e0102")!) - XCTAssertEqual(.detailedStatus, decoded.podInfoType) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - } -} diff --git a/Dependencies/OmniKit/OmniKitTests/TempBasalTests.swift b/Dependencies/OmniKit/OmniKitTests/TempBasalTests.swift deleted file mode 100644 index c996aae14..000000000 --- a/Dependencies/OmniKit/OmniKitTests/TempBasalTests.swift +++ /dev/null @@ -1,362 +0,0 @@ -// -// TempBasalTests.swift -// OmniKitTests -// -// Created by Pete Schwamb on 6/5/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -import XCTest -@testable import OmniKit - -class TempBasalTests: XCTestCase { - - func testRateQuantization() { -// // Test previously failing case -// XCTAssertEqual(0.15, OmnipodPumpManager.roundToDeliveryIncrement(units: 0.15)) -// -// XCTAssertEqual(0.15, OmnipodPumpManager.roundToDeliveryIncrement(units: 0.15000000000000002)) -// -// XCTAssertEqual(0.15, OmnipodPumpManager.roundToDeliveryIncrement(units: 0.145)) - } - - func testAlternatingSegmentFlag() { - // Encode 0.05U/hr 30mins - let cmd = SetInsulinScheduleCommand(nonce: 0x9746c65b, tempBasalRate: 0.05, duration: .hours(0.5)) - // 1a 0e 9746c65b 01 0079 01 3840 0000 0000 - XCTAssertEqual("1a0e9746c65b01007901384000000000", cmd.data.hexadecimalString) - - // Encode 0.05U/hr 8.5hours - let cmd2 = SetInsulinScheduleCommand(nonce: 0x9746c65b, tempBasalRate: 0.05, duration: .hours(8.5)) - // 1a 10 9746c65b 01 0091 11 3840 0000 f800 0000 - XCTAssertEqual("1a109746c65b0100911138400000f8000000", cmd2.data.hexadecimalString) - - // Encode 0.05U/hr 16.5hours - let cmd3 = SetInsulinScheduleCommand(nonce: 0x9746c65b, tempBasalRate: 0.05, duration: .hours(16.5)) - // 1a 12 9746c65b 01 00a9 21 3840 0000 f800 f800 0000 - XCTAssertEqual("1a129746c65b0100a92138400000f800f8000000", cmd3.data.hexadecimalString) - } - - func testTempBasalThreeTenthsUnitPerHour() { - let cmd = SetInsulinScheduleCommand(nonce: 0xeac79411, tempBasalRate: 0.3, duration: .hours(0.5)) - XCTAssertEqual("1a0eeac7941101007f01384000030003", cmd.data.hexadecimalString) - } - - func testSetTempBasalCommand() { - do { - // Decode 1a 0e ea2d0a3b 01 007d 01 3840 0002 0002 - // 1a 0e 9746c65b 01 0079 01 3840 0000 0000 160e7c00000515752a - let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a0eea2d0a3b01007d01384000020002")!) - - XCTAssertEqual(0xea2d0a3b, cmd.nonce) - if case SetInsulinScheduleCommand.DeliverySchedule.tempBasal(let secondsRemaining, let firstSegmentPulses, let table) = cmd.deliverySchedule { - - XCTAssertEqual(1800, secondsRemaining) - XCTAssertEqual(2, firstSegmentPulses) - let entry = table.entries[0] - XCTAssertEqual(1, entry.segments) - XCTAssertEqual(2, entry.pulses) - } else { - XCTFail("Expected ScheduleEntry.tempBasal type") - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = SetInsulinScheduleCommand(nonce: 0xea2d0a3b, tempBasalRate: 0.20, duration: .hours(0.5)) - XCTAssertEqual("1a0eea2d0a3b01007d01384000020002", cmd.data.hexadecimalString) - } - - func testSetTempBasalWithAlternatingPulse() { - do { - // 0.05U/hr for 2.5 hours - // Decode 1a 0e 4e2c2717 01 007f 05 3840 0000 4800 - let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a0e4e2c271701007f05384000004800")!) - - XCTAssertEqual(0x4e2c2717, cmd.nonce) - if case SetInsulinScheduleCommand.DeliverySchedule.tempBasal(let secondsRemaining, let firstSegmentPulses, let table) = cmd.deliverySchedule { - - XCTAssertEqual(1800, secondsRemaining) - XCTAssertEqual(0, firstSegmentPulses) - XCTAssertEqual(1, table.entries.count) - XCTAssertEqual(5, table.entries[0].segments) - XCTAssertEqual(0, table.entries[0].pulses) - XCTAssertEqual(true, table.entries[0].alternateSegmentPulse) - } else { - XCTFail("Expected ScheduleEntry.tempBasal type") - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = SetInsulinScheduleCommand(nonce: 0x4e2c2717, tempBasalRate: 0.05, duration: .hours(2.5)) - XCTAssertEqual("1a0e4e2c271701007f05384000004800", cmd.data.hexadecimalString) - } - - func testLargerTempBasalCommand() { - do { - // 2.00 U/h for 1.5h - // Decode 1a 0e 87e8d03a 01 00cb 03 3840 0014 2014 - let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a0e87e8d03a0100cb03384000142014")!) - - XCTAssertEqual(0x87e8d03a, cmd.nonce) - if case SetInsulinScheduleCommand.DeliverySchedule.tempBasal(let secondsRemaining, let firstSegmentPulses, let table) = cmd.deliverySchedule { - - XCTAssertEqual(1800, secondsRemaining) - XCTAssertEqual(0x14, firstSegmentPulses) - let entry = table.entries[0] - XCTAssertEqual(3, entry.segments) - XCTAssertEqual(20, entry.pulses) - } else { - XCTFail("Expected ScheduleEntry.tempBasal type") - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = SetInsulinScheduleCommand(nonce: 0x87e8d03a, tempBasalRate: 2, duration: .hours(1.5)) - XCTAssertEqual("1a0e87e8d03a0100cb03384000142014", cmd.data.hexadecimalString) - } - - func testCancelTempBasalCommand() { - do { - // Decode 1f 05 f76d34c4 62 - let cmd = try CancelDeliveryCommand(encodedData: Data(hexadecimalString: "1f05f76d34c462")!) - XCTAssertEqual(0xf76d34c4, cmd.nonce) - XCTAssertEqual(.beeeeeep, cmd.beepType) - XCTAssertEqual(.tempBasal, cmd.deliveryType) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = CancelDeliveryCommand(nonce: 0xf76d34c4, deliveryType: .tempBasal, beepType: .beeeeeep) - XCTAssertEqual("1f05f76d34c462", cmd.data.hexadecimalString) - } - - func testCancelTempBasalnoBeepCommand() { - do { - let cmd = try CancelDeliveryCommand(encodedData: Data(hexadecimalString: "1f05f76d34c402")!) - XCTAssertEqual(0xf76d34c4, cmd.nonce) - XCTAssertEqual(.noBeepCancel, cmd.beepType) - XCTAssertEqual(.tempBasal, cmd.deliveryType) - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = CancelDeliveryCommand(nonce: 0xf76d34c4, deliveryType: .tempBasal, beepType: .noBeepCancel) - XCTAssertEqual("1f05f76d34c402", cmd.data.hexadecimalString) - } - - func testZeroTempExtraCommand() { - do { - // 0 U/h for 0.5 hours - // 16 LL RR MM NNNN XXXXXXXX YYYY ZZZZZZZZ - // Decode 16 0e 7c 00 0000 6b49d200 0000 6b49d200 - - let cmd = try TempBasalExtraCommand(encodedData: Data(hexadecimalString: "160e7c0000006b49d20000006b49d200")!) - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(true, cmd.completionBeep) - XCTAssertEqual(.minutes(60), cmd.programReminderInterval) - XCTAssertEqual(TimeInterval(hours: 5), cmd.delayUntilFirstPulse) - XCTAssertEqual(0, cmd.remainingPulses) - XCTAssertEqual(1, cmd.rateEntries.count) - let entry = cmd.rateEntries[0] - XCTAssertEqual(TimeInterval(hours: 5), entry.delayBetweenPulses) - XCTAssertEqual(TimeInterval(minutes: 30), entry.duration) - XCTAssertEqual(0, entry.rate) - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = TempBasalExtraCommand(rate: 0, duration: .hours(0.5), acknowledgementBeep: false, completionBeep: true, programReminderInterval: .minutes(60)) - XCTAssertEqual("160e7c0000006b49d20000006b49d200", cmd.data.hexadecimalString) - } - - func testZeroTempThreeHoursExtraCommand() { - do { - // 0 U/h for 3 hours - let cmd = try TempBasalExtraCommand(encodedData: Data(hexadecimalString: "162c7c0000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d200")!) - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(true, cmd.completionBeep) - XCTAssertEqual(.minutes(60), cmd.programReminderInterval) - XCTAssertEqual(TimeInterval(hours: 5), cmd.delayUntilFirstPulse) - XCTAssertEqual(0, cmd.remainingPulses) - XCTAssertEqual(6, cmd.rateEntries.count) - for entry in cmd.rateEntries { - XCTAssertEqual(TimeInterval(hours: 5), entry.delayBetweenPulses) - XCTAssertEqual(TimeInterval(minutes: 30), entry.duration) - XCTAssertEqual(0, entry.rate) - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = TempBasalExtraCommand(rate: 0, duration: .hours(3), acknowledgementBeep: false, completionBeep: true, programReminderInterval: .minutes(60)) - XCTAssertEqual("162c7c0000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d200", cmd.data.hexadecimalString) - } - - func testZeroTempTwelveHoursExtraCommand() { - do { - // 0 U/h for 12 hours - // 16 LL RR MM NNNN XXXXXXXX YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ YYYY ZZZZZZZZ - // 16 98 7c 00 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 0000 6b49d200 - let cmd = try TempBasalExtraCommand(encodedData: Data(hexadecimalString: "16987c0000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d200")!) - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(true, cmd.completionBeep) - XCTAssertEqual(.minutes(60), cmd.programReminderInterval) - XCTAssertEqual(TimeInterval(hours: 5), cmd.delayUntilFirstPulse) - XCTAssertEqual(0, cmd.remainingPulses) - XCTAssertEqual(24, cmd.rateEntries.count) - for entry in cmd.rateEntries { - XCTAssertEqual(0, entry.totalPulses) - XCTAssertEqual(TimeInterval(hours: 5), entry.delayBetweenPulses) - XCTAssertEqual(TimeInterval(minutes: 30), entry.duration) - XCTAssertEqual(0, entry.rate) - } - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = TempBasalExtraCommand(rate: 0, duration: .hours(12), acknowledgementBeep: false, completionBeep: true, programReminderInterval: .minutes(60)) - XCTAssertEqual("16987c0000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d20000006b49d200", cmd.data.hexadecimalString) - } - - func testTempBasalExtremeValues() { - do { - // 30 U/h for 12 hours - // Decode 1a 10 a958c5ad 01 04f5 18 3840 012c f12c 712c - let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a10a958c5ad0104f5183840012cf12c712c")!) - - XCTAssertEqual(0xa958c5ad, cmd.nonce) - if case SetInsulinScheduleCommand.DeliverySchedule.tempBasal(let secondsRemaining, let firstSegmentPulses, let table) = cmd.deliverySchedule { - - XCTAssertEqual(1800, secondsRemaining) - XCTAssertEqual(300, firstSegmentPulses) - XCTAssertEqual(2, table.entries.count) - let entry1 = table.entries[0] - XCTAssertEqual(16, entry1.segments) - XCTAssertEqual(300, entry1.pulses) - let entry2 = table.entries[1] - XCTAssertEqual(8, entry2.segments) - XCTAssertEqual(300, entry2.pulses) - } else { - XCTFail("Expected ScheduleEntry.tempBasal type") - } - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = SetInsulinScheduleCommand(nonce: 0xa958c5ad, tempBasalRate: 30, duration: .hours(12)) - XCTAssertEqual("1a10a958c5ad0104f5183840012cf12c712c", cmd.data.hexadecimalString) - } - - func testTempBasalExtraCommand() { - do { - // 30 U/h for 0.5 hours - // Decode 16 0e 7c 00 0bb8 000927c0 0bb8 000927c0 - let cmd = try TempBasalExtraCommand(encodedData: Data(hexadecimalString: "160e7c000bb8000927c00bb8000927c0")!) - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(true, cmd.completionBeep) - XCTAssertEqual(.minutes(60), cmd.programReminderInterval) - XCTAssertEqual(TimeInterval(seconds: 6), cmd.delayUntilFirstPulse) - XCTAssertEqual(300, cmd.remainingPulses) - XCTAssertEqual(1, cmd.rateEntries.count) - let entry = cmd.rateEntries[0] - XCTAssertEqual(TimeInterval(seconds: 6), entry.delayBetweenPulses) - XCTAssertEqual(TimeInterval(minutes: 30), entry.duration) - XCTAssertEqual(30, entry.rate) - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = TempBasalExtraCommand(rate: 30, duration: .hours(0.5), acknowledgementBeep: false, completionBeep: true, programReminderInterval: .minutes(60)) - XCTAssertEqual("160e7c000bb8000927c00bb8000927c0", cmd.data.hexadecimalString) - } - - func testBasalExtraCommandForOddPulseCountRate() { - - let cmd1 = TempBasalExtraCommand(rate: 0.05, duration: .hours(0.5), acknowledgementBeep: false, completionBeep: true, programReminderInterval: .minutes(60)) - XCTAssertEqual("160e7c00000515752a00000515752a00", cmd1.data.hexadecimalString) - - let cmd2 = TempBasalExtraCommand(rate: 2.05, duration: .hours(0.5), acknowledgementBeep: false, completionBeep: false, programReminderInterval: .minutes(60)) - XCTAssertEqual("160e3c0000cd0085fac700cd0085fac7", cmd2.data.hexadecimalString) - - let cmd3 = TempBasalExtraCommand(rate: 2.10, duration: .hours(0.5), acknowledgementBeep: false, completionBeep: false, programReminderInterval: .minutes(60)) - XCTAssertEqual("160e3c0000d20082ca2400d20082ca24", cmd3.data.hexadecimalString) - - let cmd4 = TempBasalExtraCommand(rate: 2.15, duration: .hours(0.5), acknowledgementBeep: false, completionBeep: false, programReminderInterval: .minutes(60)) - XCTAssertEqual("160e3c0000d7007fbf7d00d7007fbf7d", cmd4.data.hexadecimalString) - } - - func testBasalExtraCommandPulseCount() { - // 16 LL RR MM NNNN XXXXXXXX YYYY ZZZZZZZZ YYYY ZZZZZZZZ - // 16 14 00 00 f5b9 000a0ad7 f5b9 000a0ad7 0aaf 000a0ad7 - // 16 14 00 00 f618 000a0ad7 f618 000a0ad7 0a50 000a0ad7 - let cmd2 = TempBasalExtraCommand(rate: 27.35, duration: .hours(12), acknowledgementBeep: false, completionBeep: false, programReminderInterval: 0) - XCTAssertEqual("16140000f5b9000a0ad7f5b9000a0ad70aaf000a0ad7", cmd2.data.hexadecimalString) - } - - func testTempBasalExtraCommandExtremeValues() { - do { - // 30 U/h for 12 hours - // Decode 16 14 3c 00 f618 000927c0 f618 000927c0 2328 000927c0 - let cmd = try TempBasalExtraCommand(encodedData: Data(hexadecimalString: "16143c00f618000927c0f618000927c02328000927c0")!) - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(false, cmd.completionBeep) - XCTAssertEqual(.minutes(60), cmd.programReminderInterval) - XCTAssertEqual(TimeInterval(seconds: 6), cmd.delayUntilFirstPulse) - XCTAssertEqual(6300, cmd.remainingPulses) - XCTAssertEqual(2, cmd.rateEntries.count) - let entry = cmd.rateEntries[0] - XCTAssertEqual(TimeInterval(seconds: 6), entry.delayBetweenPulses) - XCTAssertEqual(TimeInterval(hours: 10.5), entry.duration) - XCTAssertEqual(30, entry.rate) - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - // Encode - let cmd = TempBasalExtraCommand(rate: 30, duration: .hours(12), acknowledgementBeep: false, completionBeep: false, programReminderInterval: .minutes(60)) - XCTAssertEqual("16143c00f618000927c0f618000927c02328000927c0", cmd.data.hexadecimalString) - } - - func testTempBasalExtraCommandExtremeValues2() { - do { - // 29.95 U/h for 12 hours - let cmd = try TempBasalExtraCommand(encodedData: Data(hexadecimalString: "16143c00f5af00092ba9f5af00092ba9231900092ba9")!) - XCTAssertEqual(false, cmd.acknowledgementBeep) - XCTAssertEqual(false, cmd.completionBeep) - XCTAssertEqual(.minutes(60), cmd.programReminderInterval) - XCTAssertEqual(TimeInterval(seconds: 6.01001), cmd.delayUntilFirstPulse) - XCTAssertEqual(6289.5, cmd.remainingPulses) - XCTAssertEqual(2, cmd.rateEntries.count) - let entry1 = cmd.rateEntries[0] - let entry2 = cmd.rateEntries[1] - XCTAssertEqual(TimeInterval(seconds: 6.01001), entry1.delayBetweenPulses, accuracy: .ulpOfOne) - XCTAssertEqual(TimeInterval(hours: 12), entry1.duration + entry2.duration, accuracy: 1) - XCTAssertEqual(29.95, entry1.rate, accuracy: 0.025) - - } catch (let error) { - XCTFail("message decoding threw error: \(error)") - } - - let cmd = TempBasalExtraCommand(rate: 29.95, duration: .hours(12), acknowledgementBeep: false, completionBeep: false, programReminderInterval: .minutes(60)) - XCTAssertEqual("16143c00f5af00092ba9f5af00092ba9231900092ba9", cmd.data.hexadecimalString) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Common/FrameworkLocalText.swift b/Dependencies/OmniKit/OmniKitUI/Common/FrameworkLocalText.swift deleted file mode 100644 index 5523e9a4b..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Common/FrameworkLocalText.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// FrameworkLocalText.swift -// OmniKit -// -// Created by Pete Schwamb on 7/21/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import SwiftUI - -private class FrameworkReferenceClass { - static let bundle = Bundle(for: FrameworkReferenceClass.self) -} - -func FrameworkLocalText(_ key: LocalizedStringKey, comment: StaticString) -> Text { - return Text(key, bundle: FrameworkReferenceClass.bundle, comment: comment) -} diff --git a/Dependencies/OmniKit/OmniKitUI/Extensions/HKUnit.swift b/Dependencies/OmniKit/OmniKitUI/Extensions/HKUnit.swift deleted file mode 100644 index 7bf65cd66..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Extensions/HKUnit.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// HKUnit.swift -// OmniKitUI -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import HealthKit - -extension HKUnit { - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: .literUnit(with: .deci)) - }() - - static let millimolesPerLiter: HKUnit = { - return HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: .liter()) - }() - - static let internationalUnitsPerHour: HKUnit = { - return HKUnit.internationalUnit().unitDivided(by: .hour()) - }() - -} diff --git a/Dependencies/OmniKit/OmniKitUI/Extensions/IdentifiableClass.swift b/Dependencies/OmniKit/OmniKitUI/Extensions/IdentifiableClass.swift deleted file mode 100644 index bb077df0e..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Extensions/IdentifiableClass.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// IdentifiableClass.swift -// OmniKitUI -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -protocol IdentifiableClass: AnyObject { - static var className: String { get } -} - - -extension IdentifiableClass { - static var className: String { - return NSStringFromClass(self).components(separatedBy: ".").last! - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Extensions/Image.swift b/Dependencies/OmniKit/OmniKitUI/Extensions/Image.swift deleted file mode 100644 index 435cd12c2..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Extensions/Image.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// Image.swift -// OmniKitUI -// -// Created by Pete Schwamb on 2/7/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -private class FrameworkBundle { - static let main = Bundle(for: FrameworkBundle.self) -} - -extension Image { - init(frameworkImage name: String, decorative: Bool = false) { - if decorative { - self.init(decorative: name, bundle: FrameworkBundle.main) - } else { - self.init(name, bundle: FrameworkBundle.main) - } - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Extensions/NibLoadable.swift b/Dependencies/OmniKit/OmniKitUI/Extensions/NibLoadable.swift deleted file mode 100644 index cf1b621e9..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Extensions/NibLoadable.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// NibLoadable.swift -// OmniKitUI -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import UIKit - -protocol NibLoadable: IdentifiableClass { - static func nib() -> UINib -} - - -extension NibLoadable { - static func nib() -> UINib { - return UINib(nibName: className, bundle: Bundle(for: self)) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Extensions/NumberFormatter.swift b/Dependencies/OmniKit/OmniKitUI/Extensions/NumberFormatter.swift deleted file mode 100644 index bcac17c04..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Extensions/NumberFormatter.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// NumberFormatter.swift -// OmniKitUI -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension NumberFormatter { - func decibleString(from decibles: Int?) -> String? { - if let decibles = decibles, let formatted = string(from: NSNumber(value: decibles)) { - return String(format: LocalizedString("%@ dB", comment: "Unit format string for an RSSI value in decibles"), formatted) - } else { - return nil - } - } - - func string(from number: Double) -> String? { - return string(from: NSNumber(value: number)) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Extensions/TimeInterval.swift b/Dependencies/OmniKit/OmniKitUI/Extensions/TimeInterval.swift deleted file mode 100644 index 9e0e9607d..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Extensions/TimeInterval.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// TimeInterval.swift -// OmniKitUI -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension TimeInterval { - - static func days(_ days: Double) -> TimeInterval { - return self.init(days: days) - } - - static func hours(_ hours: Double) -> TimeInterval { - return self.init(hours: hours) - } - - static func minutes(_ minutes: Int) -> TimeInterval { - return self.init(minutes: Double(minutes)) - } - - static func minutes(_ minutes: Double) -> TimeInterval { - return self.init(minutes: minutes) - } - - static func seconds(_ seconds: Double) -> TimeInterval { - return self.init(seconds) - } - - static func milliseconds(_ milliseconds: Double) -> TimeInterval { - return self.init(milliseconds / 1000) - } - - init(days: Double) { - self.init(hours: days * 24) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - init(minutes: Double) { - self.init(minutes * 60) - } - - init(seconds: Double) { - self.init(seconds) - } - - init(milliseconds: Double) { - self.init(milliseconds / 1000) - } - - var milliseconds: Double { - return self * 1000 - } - - init(hundredthsOfMilliseconds: Double) { - self.init(hundredthsOfMilliseconds / 100000) - } - - var hundredthsOfMilliseconds: Double { - return self * 100000 - } - - var minutes: Double { - return self / 60.0 - } - - var hours: Double { - return minutes / 60.0 - } - - var days: Double { - return hours / 24.0 - } - -} diff --git a/Dependencies/OmniKit/OmniKitUI/Extensions/TimeZone.swift b/Dependencies/OmniKit/OmniKitUI/Extensions/TimeZone.swift deleted file mode 100644 index 9e4ffb6f1..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Extensions/TimeZone.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// TimeZone.swift -// OmniKitUI -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -extension TimeZone { - static var currentFixed: TimeZone { - return TimeZone(secondsFromGMT: TimeZone.current.secondsFromGMT())! - } - - var fixed: TimeZone { - return TimeZone(secondsFromGMT: secondsFromGMT())! - } - - /// This only works for fixed utc offset timezones - func scheduleOffset(forDate date: Date) -> TimeInterval { - var calendar = Calendar.current - calendar.timeZone = self - let components = calendar.dateComponents([.day , .month, .year], from: date) - guard let startOfSchedule = calendar.date(from: components) else { - fatalError("invalid date") - } - return date.timeIntervalSince(startOfSchedule) - } - -} diff --git a/Dependencies/OmniKit/OmniKitUI/Info.plist b/Dependencies/OmniKit/OmniKitUI/Info.plist deleted file mode 100644 index 7a3ea75eb..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Dependencies/OmniKit/OmniKitUI/LocalizedString.swift b/Dependencies/OmniKit/OmniKitUI/LocalizedString.swift deleted file mode 100644 index b6f1363e9..000000000 --- a/Dependencies/OmniKit/OmniKitUI/LocalizedString.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// LocalizedString.swift -// OmniKitUI -// -// Created by Pete Schwamb on 3/19/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import Foundation - -private class LocalBundle { - /// Returns the resource bundle associated with the current Swift module. - static var main: Bundle = { - if let mainResourceURL = Bundle.main.resourceURL, - let bundle = Bundle(url: mainResourceURL.appendingPathComponent("OmniKitUI_OmniKitUI.bundle")) - { - return bundle - } - return Bundle(for: LocalBundle.self) - }() -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: LocalBundle.main, comment: comment) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/OmniKitUI.h b/Dependencies/OmniKit/OmniKitUI/OmniKitUI.h deleted file mode 100644 index 02da72a59..000000000 --- a/Dependencies/OmniKit/OmniKitUI/OmniKitUI.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// OmniKitUI.h -// OmniKitUI -// -// Created by Pete Schwamb on 8/26/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -#import - -//! Project version number for OmniKitUI. -FOUNDATION_EXPORT double OmniKitUIVersionNumber; - -//! Project version string for OmniKitUI. -FOUNDATION_EXPORT const unsigned char OmniKitUIVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/OmniKit/OmniKitUI/PumpManager/OmniPodPumpManager+UI.swift b/Dependencies/OmniKit/OmniKitUI/PumpManager/OmniPodPumpManager+UI.swift deleted file mode 100644 index 6036bd5d1..000000000 --- a/Dependencies/OmniKit/OmniKitUI/PumpManager/OmniPodPumpManager+UI.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// OmniPodPumpManager+UI.swift -// OmniKitUI -// -// Created by Pete Schwamb on 8/4/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation -import SwiftUI -import UIKit -import LoopKit -import LoopKitUI -import OmniKit -import RileyLinkKitUI - -extension OmnipodPumpManager: PumpManagerUI { - public static var onboardingImage: UIImage? { - return UIImage(named: "Onboarding", in: Bundle(for: OmnipodSettingsViewModel.self), compatibleWith: nil) - } - - public static func setupViewController(initialSettings settings: PumpManagerSetupSettings, bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool, allowedInsulinTypes: [InsulinType]) -> SetupUIResult - { - let vc = OmnipodUICoordinator(colorPalette: colorPalette, pumpManagerSettings: settings, allowDebugFeatures: allowDebugFeatures, allowedInsulinTypes: allowedInsulinTypes) - return .userInteractionRequired(vc) - } - - public func settingsViewController(bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool, allowedInsulinTypes: [InsulinType]) -> PumpManagerViewController { - return OmnipodUICoordinator(pumpManager: self, colorPalette: colorPalette, allowDebugFeatures: allowDebugFeatures, allowedInsulinTypes: allowedInsulinTypes) - } - - public func deliveryUncertaintyRecoveryViewController(colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) -> (UIViewController & CompletionNotifying) { - return OmnipodUICoordinator(pumpManager: self, colorPalette: colorPalette, allowDebugFeatures: allowDebugFeatures) - } - - public var smallImage: UIImage? { - return UIImage(named: "Pod", in: Bundle(for: OmnipodSettingsViewModel.self), compatibleWith: nil)! - } - - public func hudProvider(bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowedInsulinTypes: [InsulinType]) -> HUDProvider? { - return OmnipodHUDProvider(pumpManager: self, bluetoothProvider: bluetoothProvider, colorPalette: colorPalette, allowedInsulinTypes: allowedInsulinTypes) - } - - public static func createHUDView(rawValue: HUDProvider.HUDViewRawState) -> BaseHUDView? { - return OmnipodHUDProvider.createHUDView(rawValue: rawValue) - } - -} - -// MARK: - PumpStatusIndicator -extension OmnipodPumpManager { - public var pumpStatusHighlight: DeviceStatusHighlight? { - buildPumpStatusHighlight(for: state) - } - - public var pumpLifecycleProgress: DeviceLifecycleProgress? { - return buildPumpLifecycleProgress(for: state) - } - - public var pumpStatusBadge: DeviceStatusBadge? { - return nil - } - -} diff --git a/Dependencies/OmniKit/OmniKitUI/PumpManager/OmnipodHUDProvider.swift b/Dependencies/OmniKit/OmniKitUI/PumpManager/OmnipodHUDProvider.swift deleted file mode 100644 index 02596eb39..000000000 --- a/Dependencies/OmniKit/OmniKitUI/PumpManager/OmnipodHUDProvider.swift +++ /dev/null @@ -1,139 +0,0 @@ -// -// OmnipodHUDProvider.swift -// OmniKitUI -// -// Based on OmniKitUI/PumpManager/OmniBLEHUDProvider.swift -// Created by Pete Schwamb on 11/26/18. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import UIKit -import SwiftUI -import LoopKit -import LoopKitUI -import OmniKit - -public enum ReservoirAlertState { - case ok - case lowReservoir - case empty -} - -internal class OmnipodHUDProvider: NSObject, HUDProvider { - var managerIdentifier: String { - return pumpManager.managerIdentifier - } - - private let pumpManager: OmnipodPumpManager - - private var reservoirView: OmnipodReservoirView? - - private let bluetoothProvider: BluetoothProvider - - private let colorPalette: LoopUIColorPalette - - private var refreshTimer: Timer? - - private let allowedInsulinTypes: [InsulinType] - - var visible: Bool = false { - didSet { - if oldValue != visible && visible { - hudDidAppear() - } - } - } - - public init(pumpManager: OmnipodPumpManager, bluetoothProvider: BluetoothProvider, colorPalette: LoopUIColorPalette, allowedInsulinTypes: [InsulinType]) { - self.pumpManager = pumpManager - self.bluetoothProvider = bluetoothProvider - self.colorPalette = colorPalette - self.allowedInsulinTypes = allowedInsulinTypes - super.init() - self.pumpManager.addPodStateObserver(self, queue: .main) - } - - public func createHUDView() -> BaseHUDView? { - reservoirView = OmnipodReservoirView.instantiate() - updateReservoirView() - - return reservoirView - } - - public func didTapOnHUDView(_ view: BaseHUDView, allowDebugFeatures: Bool) -> HUDTapAction? { - let vc = pumpManager.settingsViewController(bluetoothProvider: bluetoothProvider, colorPalette: colorPalette, allowDebugFeatures: allowDebugFeatures, allowedInsulinTypes: allowedInsulinTypes) - return HUDTapAction.presentViewController(vc) - } - - func hudDidAppear() { - updateReservoirView() - refresh() - } - - public var hudViewRawState: HUDProvider.HUDViewRawState { - var rawValue: HUDProvider.HUDViewRawState = [:] - - rawValue["lastStatusDate"] = pumpManager.lastStatusDate - - if let reservoirLevel = pumpManager.reservoirLevel { - rawValue["reservoirLevel"] = reservoirLevel.rawValue - } - - if let reservoirLevelHighlightState = pumpManager.reservoirLevelHighlightState { - rawValue["reservoirLevelHighlightState"] = reservoirLevelHighlightState.rawValue - } - - return rawValue - } - - public static func createHUDView(rawValue: HUDProvider.HUDViewRawState) -> BaseHUDView? { - guard let rawReservoirLevel = rawValue["reservoirLevel"] as? ReservoirLevel.RawValue, - let rawReservoirLevelHighlightState = rawValue["reservoirLevelHighlightState"] as? ReservoirLevelHighlightState.RawValue, - let reservoirLevelHighlightState = ReservoirLevelHighlightState(rawValue: rawReservoirLevelHighlightState) - else { - return nil - } - - let reservoirView: OmnipodReservoirView? - - let reservoirLevel = ReservoirLevel(rawValue: rawReservoirLevel) - - if let lastStatusDate = rawValue["lastStatusDate"] as? Date { - reservoirView = OmnipodReservoirView.instantiate() - reservoirView!.update(level: reservoirLevel, at: lastStatusDate, reservoirLevelHighlightState: reservoirLevelHighlightState) - } else { - reservoirView = nil - } - - return reservoirView - } - - private func refresh() { - pumpManager.getPodStatus() { _ in - DispatchQueue.main.async { - self.updateReservoirView() - } - } - } - - private func updateReservoirView() { - guard let reservoirView = reservoirView, - let lastStatusDate = pumpManager.lastStatusDate, - let reservoirLevelHighlightState = pumpManager.reservoirLevelHighlightState else - { - return - } - - reservoirView.update(level: pumpManager.reservoirLevel, at: lastStatusDate, reservoirLevelHighlightState: reservoirLevelHighlightState) - } -} - -extension OmnipodHUDProvider: PodStateObserver { - func podConnectionStateDidChange(isConnected: Bool) { - // ignore for now - } - - func podStateDidUpdate(_ state: PodState?) { - updateReservoirView() - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/Contents.json b/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/pod_life/Contents.json b/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/pod_life/Contents.json deleted file mode 100644 index da4a164c9..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/pod_life/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/pod_life/pod_life.imageset/Contents.json b/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/pod_life/pod_life.imageset/Contents.json deleted file mode 100644 index bd5c9bd61..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/pod_life/pod_life.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "Pod Life.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/pod_life/pod_life.imageset/Pod Life.pdf b/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/pod_life/pod_life.imageset/Pod Life.pdf deleted file mode 100644 index c2ce51715..000000000 Binary files a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/pod_life/pod_life.imageset/Pod Life.pdf and /dev/null differ diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/Contents.json b/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/Contents.json b/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/Contents.json deleted file mode 100644 index 7a65fb9c2..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "reservoir.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/reservoir.pdf b/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/reservoir.pdf deleted file mode 100644 index 623015046..000000000 Binary files a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/pod_reservoir.imageset/reservoir.pdf and /dev/null differ diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/Contents.json b/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/Contents.json deleted file mode 100644 index e19598694..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "reservoir_mask.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/reservoir_mask.pdf b/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/reservoir_mask.pdf deleted file mode 100644 index 040769397..000000000 Binary files a/Dependencies/OmniKit/OmniKitUI/Resources/HUDAssets.xcassets/reservoir/pod_reservoir_mask.imageset/reservoir_mask.pdf and /dev/null differ diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Cannula Inserted.imageset/CannulaInserted.png b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Cannula Inserted.imageset/CannulaInserted.png deleted file mode 100644 index a5cad5892..000000000 Binary files a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Cannula Inserted.imageset/CannulaInserted.png and /dev/null differ diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Cannula Inserted.imageset/Contents.json b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Cannula Inserted.imageset/Contents.json deleted file mode 100644 index 26bf5fbad..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Cannula Inserted.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "CannulaInserted.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Contents.json b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Contents.json deleted file mode 100644 index da4a164c9..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Pod.imageset/Contents.json b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Pod.imageset/Contents.json deleted file mode 100644 index 27c1a878d..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Pod.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "pod1x.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "pod2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "pod3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Pod.imageset/pod1x.png b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Pod.imageset/pod1x.png deleted file mode 100644 index e15cf636c..000000000 Binary files a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Pod.imageset/pod1x.png and /dev/null differ diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Pod.imageset/pod2x.png b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Pod.imageset/pod2x.png deleted file mode 100644 index 7656aef0a..000000000 Binary files a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Pod.imageset/pod2x.png and /dev/null differ diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Pod.imageset/pod3x.png b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Pod.imageset/pod3x.png deleted file mode 100644 index 9d91d8108..000000000 Binary files a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/Pod.imageset/pod3x.png and /dev/null differ diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodBottom.imageset/Contents.json b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodBottom.imageset/Contents.json deleted file mode 100644 index 00500888f..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodBottom.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "PodBottom1x.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "PodBottom2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "PodBottom3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodBottom.imageset/PodBottom1x.png b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodBottom.imageset/PodBottom1x.png deleted file mode 100644 index 109d65d8a..000000000 Binary files a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodBottom.imageset/PodBottom1x.png and /dev/null differ diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodBottom.imageset/PodBottom2x.png b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodBottom.imageset/PodBottom2x.png deleted file mode 100644 index 33024fcc8..000000000 Binary files a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodBottom.imageset/PodBottom2x.png and /dev/null differ diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodBottom.imageset/PodBottom3x.png b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodBottom.imageset/PodBottom3x.png deleted file mode 100644 index 57d238250..000000000 Binary files a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodBottom.imageset/PodBottom3x.png and /dev/null differ diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodLarge.imageset/Contents.json b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodLarge.imageset/Contents.json deleted file mode 100644 index 1249161af..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodLarge.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "PodLarge@1x.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "PodLarge@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "PodLarge@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodLarge.imageset/PodLarge@1x.png b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodLarge.imageset/PodLarge@1x.png deleted file mode 100644 index 5ef798057..000000000 Binary files a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodLarge.imageset/PodLarge@1x.png and /dev/null differ diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodLarge.imageset/PodLarge@2x.png b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodLarge.imageset/PodLarge@2x.png deleted file mode 100644 index 92e6ef21e..000000000 Binary files a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodLarge.imageset/PodLarge@2x.png and /dev/null differ diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodLarge.imageset/PodLarge@3x.png b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodLarge.imageset/PodLarge@3x.png deleted file mode 100644 index f3571b9db..000000000 Binary files a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/PodLarge.imageset/PodLarge@3x.png and /dev/null differ diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/pod_reservoir_mask_swiftui.imageset/Contents.json b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/pod_reservoir_mask_swiftui.imageset/Contents.json deleted file mode 100644 index c20046946..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/pod_reservoir_mask_swiftui.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "filename" : "pod_reservoir_mask.svg", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "preserves-vector-representation" : true, - "template-rendering-intent" : "template" - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/pod_reservoir_mask_swiftui.imageset/pod_reservoir_mask.svg b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/pod_reservoir_mask_swiftui.imageset/pod_reservoir_mask.svg deleted file mode 100644 index abe1a576c..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/pod_reservoir_mask_swiftui.imageset/pod_reservoir_mask.svg +++ /dev/null @@ -1,55 +0,0 @@ - -image/svg+xml diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/pod_reservoir_swiftui.imageset/Contents.json b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/pod_reservoir_swiftui.imageset/Contents.json deleted file mode 100644 index 25baae2d3..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/pod_reservoir_swiftui.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "pod_reservoir.svg", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "preserves-vector-representation" : true - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/pod_reservoir_swiftui.imageset/pod_reservoir.svg b/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/pod_reservoir_swiftui.imageset/pod_reservoir.svg deleted file mode 100644 index 276ed5c4b..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/OmniKitUI.xcassets/pod_reservoir_swiftui.imageset/pod_reservoir.svg +++ /dev/null @@ -1,59 +0,0 @@ - -image/svg+xml diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/OmnipodReservoirView.xib b/Dependencies/OmniKit/OmniKitUI/Resources/OmnipodReservoirView.xib deleted file mode 100644 index a27a2ddb6..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/OmnipodReservoirView.xib +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/PodLifeHUDView.xib b/Dependencies/OmniKit/OmniKitUI/Resources/PodLifeHUDView.xib deleted file mode 100644 index d6bdde9fc..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/PodLifeHUDView.xib +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/ar.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/ar.lproj/Localizable.strings deleted file mode 100644 index a214c7991..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/ar.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ ago"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (Finished)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%@ U of %@ U (%@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/hour"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Insulin delivery has stopped. Please deactivate and remove pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 hour"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Active Time"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarms"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Are you sure you want to shutdown this pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Are you sure you want to skip Omnipod Onboarding?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Are you sure you want to stop using Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Assigned Address"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Attach Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Attemping to re-establish communication"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Back"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Basal Delivery"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "الضخ المستمر"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Bolus Delivery"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "إلغاء"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Cannula inserted successfully. Continue."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Change Time Zone"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Changing time…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Check Cannula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Checking Insertion"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comms Recovered"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced."; - -/* The title of the configuration section in settings */ -"Configuration" = "المعطيات"; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Continue"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Critical Alerts"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Deactivate"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Deactivated"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deactivating..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Delete Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "حدود الضخ"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Device Details"; - -/* The title of the device information section in settings */ -"Device Information" = "Device Information"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Devices"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Disable Bolus Beeps"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* No comment provided by engineer. */ -"Done" = "Done"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Enable Bolus Beeps"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Error"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Error disabling bolus beeps"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Error enabling bolus beeps"; - -/* The alert title for a resume error */ -"Error Resuming" = "خطأ في الاستئناف"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspending"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Expired"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Expires"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Failed to update confidence reminder preference."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Failed to Update Expiration Reminder"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Failed to Update Low Reservoir Reminder"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Finish pod setup"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Greater than %1$@ units remaining at %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hours"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Insert Cannula"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Inserting. Please wait."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insulin Delivered"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "توصيل الأنسولين"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulin Type"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Invalid entry"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Keep the RileyLink about 6 inches from the pod during pairing."; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lot"; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Low Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Next"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "No\nDelivery"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "No Insulin"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "No Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "None"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Notification Settings"; - -/* No comment provided by engineer. */ -"Numbers" = "Numbers"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Button title to pair with pod during setup */ -"Pair" = "Pair"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Pair New Pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Paired"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PI Version"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Play Test Beeps"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Play Test Beeps…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PM Version"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Activated"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Pod Error"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod Expired"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod Expires"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Pod Settings"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Primed"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* The text of the loading label when priming */ -"Priming…" = "Priming…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Label text for basal rate summary */ -"Rate" = "Rate"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Remove the Pod's clear needle cap and check cannula. Then remove paper backing."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Replace Pod Now"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "الخزان"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "أعد المحاولة"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Retry Pod Deactivation"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink allows for communication with the pump over Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink Setup"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Save"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Saving..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Schedule"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Select the type of insulin that you will be using in this pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Title for setup complete screen */ -"Setup Complete" = "Setup Complete"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Signal Loss"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* The title of the status section in settings */ -"Status" = "الحالة"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Succeeded"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Suspended"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Switch from Omnipod Pumps"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Sync With Pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* The title of the command to run the test command */ -"Test Command" = "Test Command"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Testing Commands…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Time"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Time Change Detected"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Toggle sign"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Too many entries"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* Units for showing temp basal rate */ -"U/hr" = "وحدة لكل ساعة"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Unable to deactivate pod. Please continue and pair a new one."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Unable to Reach Pod"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Unknown"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/ca.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/ca.lproj/Localizable.strings deleted file mode 100644 index 454edcaf8..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/ca.lproj/Localizable.strings +++ /dev/null @@ -1,766 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ ago"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (Finished)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%@ U of %@ U (%@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/hour"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Insulin delivery has stopped. Please deactivate and remove pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 hour"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Active Time"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarms"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Are you sure you want to shutdown this pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Are you sure you want to skip Omnipod Onboarding?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Are you sure you want to stop using Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Assigned Address"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Attach Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Attemping to re-establish communication"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Back"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Basal Delivery"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basal Rates"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Bolus Delivery"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancel"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Cannula inserted successfully. Continue."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Change Time Zone"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Changing time…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Check Cannula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Checking Insertion"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comms Recovered"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the pod which can be used to acknowledge selected commands." = "Confidence reminders are beeps from the pod which can be used to acknowledge selected commands."; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuration"; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Continue"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Critical Alerts"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Deactivate"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Deactivated"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deactivating..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Delete Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Delivery Limits"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Device Details"; - -/* The title of the device information section in settings */ -"Device Information" = "Device Information"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Devices"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Disable Bolus Beeps"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* No comment provided by engineer. */ -"Done" = "Done"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Enable Bolus Beeps"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Error"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Error disabling bolus beeps"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Error enabling bolus beeps"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Resuming"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspending"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Expired"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Expires"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Failed to update confidence reminder preference."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Failed to Update Expiration Reminder"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Failed to Update Low Reservoir Reminder"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Finish pod setup"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Greater than %1$@ units remaining at %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hours"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Insert Cannula"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Inserting. Please wait."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insulin Delivered"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulin Type"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Invalid entry"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Keep the RileyLink about 6 inches from the pod during pairing."; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lot"; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Low Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Next"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "No\nDelivery"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "No Insulin"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "No Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "None"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Notification Settings"; - -/* No comment provided by engineer. */ -"Numbers" = "Numbers"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Button title to pair with pod during setup */ -"Pair" = "Pair"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Pair New Pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Paired"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PI Version"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Play Test Beeps"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Play Test Beeps…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PM Version"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Activated"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Pod Error"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod Expired"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod Expires"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Pod Settings"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Primed"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* The text of the loading label when priming */ -"Priming…" = "Priming…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Label text for basal rate summary */ -"Rate" = "Rate"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Label text for step two of attach pod instructions */ -"Remove the pod's needle cap and check cannula. Then remove paper backing." = "Remove the pod's needle cap and check cannula. Then remove paper backing."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Replace Pod Now"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Reservoir"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Retry"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Retry Pod Deactivation"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink allows for communication with the pump over Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink Setup"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Save"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Saving..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Schedule"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Select the type of insulin that you will be using in this pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Title for setup complete screen */ -"Setup Complete" = "Setup Complete"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Signal Loss"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* The title of the status section in settings */ -"Status" = "Status"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Succeeded"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Suspended"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Switch from Omnipod Pumps"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Sync With Pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* The title of the command to run the test command */ -"Test Command" = "Test Command"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Testing Commands…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Time"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Time Change Detected"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Toggle sign"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Too many entries"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hr"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Unable to deactivate pod. Please continue and pair a new one."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Unable to Reach Pod"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Unknown"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/cs.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/cs.lproj/Localizable.strings deleted file mode 100644 index c11489e84..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/cs.lproj/Localizable.strings +++ /dev/null @@ -1,303 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@ %%"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Zpět"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Podávání bazálu"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Úrovně bazálu"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Podávání bolusu"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Zrušit"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanyla byla úspěšně zavedena. Pokračovat."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Vyměňte pod. Výdej inzulinu se zastaví 8 hodin poté, co pod vypršel, nebo když už v něm nezbývá žádný inzulín."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Vyměňte pod. Výdej inzulínu se zastaví za %1$@ nebo když dojde inzulín."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Změnit časové pásmo"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Měním čas…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Zkontrolujte kanylu"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Zkontrolujte pod, aplikujte na místo a potvrďte umístění podu."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Kontrola zavedení"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Zjišťuji..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Komunikace obnovena"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Ujištující upozornění jsou pípnutí podu, které lze použít k potvrzení zadaných příkazů."; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfigurace"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Pokračovat"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritická upozornění"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Deaktivovat"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Deaktivovat Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Deaktivováno"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktivace."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deaktivuji..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Smazat Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Limity podávání"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Podrobnosti o zařízení"; - -/* The title of the device information section in settings */ -"Device Information" = "Informace o zařízení"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Zakázat pípání bolusu"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Vyřadit pod"; - -/* No comment provided by engineer. */ -"Done" = "Hotovo"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Povolit pípání bolusu"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Podávání inzulínu bylo zastaveno. Vyměňte pod nyní."; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Typ inzulínu"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Neplatná hodnota"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Během párování udržujte RileyLink asi 15 centimetrů od podu."; - -/* description label for last status date pod details row */ -"Last Status" = "Poslední stav"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop automaticky neupraví výdej inzulínu, dokud nastavení dočasné bazální dávky neskončí nebo nebude zrušeno."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Šarže"; - -/* description label for lot number pod details row */ -"Lot Number" = "Číslo šarže"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Poloprázdný zásobník"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Upozornění na poloprázdný zásobník"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Ujistěte se, že váš telefon a pod jsou blízko sebe. Pokud problémy s komunikací přetrvávají, zkuste přesunutí na jiné místo."; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Chybějící konfigurace"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "Není k dispozici"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Další"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Ne"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Žádný inzulín"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Žádný pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Žádné upozornění"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Žádný"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Nastavení upozornění"; - -/* No comment provided by engineer. */ -"Numbers" = "Hodnoty"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Upozornění Omnipodu"; - -/* Button title to pair with pod during setup */ -"Pair" = "Spárovat"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Spárovat nový pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Spárovat pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Spárovat pod."; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Páruji."; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "Verze PI"; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "Verze PM"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Obnovit podávání inzulínu"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Obnovování podávání inzulínu..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Zkusit znovu"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Zopakovat deaktivaci podu"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink umožňuje komunikaci s pumpou přes Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "Nastavení RileyLinku"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Uložit"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Ukládám..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Rozvrh"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Plánovaný bazál"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Naplánované upozornění"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Vyberte typ inzulinu, který budete v tomto Podu používat."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Pořadové číslo"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Nastavit dočasný bazál"; - -/* Title for setup complete screen */ -"Setup Complete" = "Nastavení dokončeno"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Ztráta signálu"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Přeskočit onboarding Omnipodu?"; - -/* The title of the status section in settings */ -"Status" = "Status"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Úspěšně ukončeno"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Pozastavit podávání inzulínu..."; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Pozastaveno"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Pozastavení podávání inzulínu..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Přepnout z Omnipod pumpy"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Synchronizace s Podem"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Klepnutím na tlačítko níže zahájíte zavádění kanyly."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Dočasný bazál"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Nastavení dočasného bazálu selhalo"; - -/* The title of the command to run the test command */ -"Test Command" = "Testovací příkaz"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Testování příkazů…"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Aplikace vás předem upozorní na vypršení platnosti Podu. \n\nPosouváním nastavte počet hodin před vypršením, kdy chcete obdržet notifikaci."; - diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/da.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/da.lproj/Localizable.strings deleted file mode 100644 index 1311c51c6..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/da.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ siden"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%1$@ har genoprettet kommunikationen med Pod'en på din krop.\n\nHistorik for insulintilførsel er blevet opdateret og skal matche det, der faktisk er leveret.\n\nDu kan fortsætte med at bruge %2$@ normalt nu."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ E"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ E (Færdig)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ E af %2$@ E (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ E/time"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ E"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ i %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ har ikke været i stand til at kommunikere med Pod'en på din krop siden %2$@.\n\nUden kommunikation med Pod'en kan appen ikke fortsætte med at sende kommandoer for insulintilførsel eller vise nøjagtige, nylige oplysninger om dit aktive insulin eller det insulin, der leveres af Pod'en.\n\nOvervåg din glukose nøje i de næste 6 eller flere timer, da der måske eller måske ikke er insulin, der aktivt arbejder i din krop, som %3$@ ikke kan vise."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ enheder tilbage på %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Insulin indgivelse er stoppet. Venligst deaktiver og fjern Pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g E"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 time"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 time 30 minutter"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 timer"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutter"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Aktiv tid"; - -/* Section header for activity section */ -"Activity" = "Aktivitet"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Justerer pumpetid..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarmer"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Er du sikker på, at du vil annullere Pod-opsætningen?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Er du sikker på, at du vil slukke for denne Pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Er du sikker på, at du vil springe Omnipod Onboarding over?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Er du sikker på, at du vil stoppe med at bruge Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Tildelt adresse"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Påfør Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Forsøger at genetablere kommunikationen"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Tilbage"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Basalindgivelse"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basalrater"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Bolusindgivelse"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuller"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Annuller manuel basal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanylen blev indsat korrekt. Fortsæt."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Skift Pod nu. Insulintilførsel stopper 8 timer efter, at Pod'en er udløbet, eller når der ikke er mere insulin tilbage."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Skift Pod nu. Insulintilførsel stopper om %1$@, eller når der ikke er mere insulin tilbage."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Skift tidszone"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Ændrer tid..."; - -/* Title for check cannula screen */ -"Check Cannula" = "Kontroller kanylen"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Tjek Pod, sæt på kroppen og bekræft derefter Pod er sat korrekt på."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Kontrollerer indsættelse"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Kontrollerer..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Kommunikation genoprettet"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Påmindelse om succesfulde aktiviteter"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced."; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfiguration"; - -/* Button title for confirm attachment option */ -"Confirm" = "Bekræft"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bekræft fastgørelse af Pod"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Fortsæt"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritiske advarsler"; - -/* Unit for singular day in pod life remaining */ -"day" = "dag"; - -/* Unit for plural days in pod life remaining */ -"days" = "dage"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Deaktiver"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Deaktiver Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Deaktiveret"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktiverer."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deaktiverer..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Slet Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Insulingrænser"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Enhedsdetaljer"; - -/* The title of the device information section in settings */ -"Device Information" = "Oplysninger om enheden"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Enheder"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Deaktiver bolus bip"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Kassér Pod"; - -/* No comment provided by engineer. */ -"Done" = "Udført"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Aktiver bolus bip"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Fejl"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Fejl ved deaktivering af bolus bip"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Fejl under aktivering af bolus bip"; - -/* The alert title for a resume error */ -"Error Resuming" = "Fejl ved genoptagelse"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Fejl ved suspendering"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Påmindelse om udløb"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standard for udløbspåmindelse"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Udløbet"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Udløber"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Kunne ikke annullere manuel basal"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Kunne ikke genoptage insulintilførsel"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Kunne ikke indstille pumpetid"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Kunne ikke suspendere insulintilførsel"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Kunne ikke opdatere påmindelser for succesfulde aktiviteter"; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Kunne ikke opdatere påmindelse om udløb"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Kunne ikke opdatere påmindelse om lavt reservoir"; - -/* Pod life HUD view label */ -"Fault" = "Fejl"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Fyld en ny Pod med 100 E insulin (lad podnålehætten sidde på). Lyt efter 2 bip."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Afslut deaktivering"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Afslut Pod-indstilling"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Afslut setup"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Flere end %1$@ enheder tilbage ved %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "time"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "Timer"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Hvis du annullerer Pod-opsætningen, deaktiveres den aktuelle Pod og den vil være ubrugelig."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Ufuldstændigt indstillet Pod skal først deaktiveres, før der kan parres med en ny. Venligst deaktiver og fjern Pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Ufuldstændigt indstillet Pod skal først deaktiveres, før der kan parres med en ny. Venligst deaktiver og fjern Pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Indfør kanyle"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Indsat"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Indsætter. Vent venligst."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Indsætter..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin \nsuspenderet"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insulin leveret"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulintilførsel"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulintilførslen er stoppet. Skift Pod nu."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulintilførsel vil blive stoppet, indtil du genoptager manuelt. Hvornår vil du have Loop til at minde dig om at genoptage leveringen?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin tilbage"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulintype"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Ugyldig indtastning"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Er kanylen indsat korrekt?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Hold RileyLink ca. 15 cm fra Pod, når der parres."; - -/* description label for last status date pod details row */ -"Last Status" = "Sidste status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop justerer ikke automatisk din insulindosering, før den midlertidige basalrate er afsluttet eller annulleret."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Parti"; - -/* description label for lot number pod details row */ -"Lot Number" = "Partinummer"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Lavt reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Påmindelse om lavt reservoir"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Sørg for, at din telefon og Pod er tæt på hinanden. Hvis der fortsat er kommunikationsproblemer, skal du flytte til et nyt område."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minut"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutter"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Manglende konfiguration"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NA"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Næste"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nej"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Ingen\nlevering"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Ingen insulin"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Ingen Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Ingen påmindelse"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nej, fortsæt med Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nej, behold pumpen som den er"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Ingen"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Notifikationsindstillinger"; - -/* No comment provided by engineer. */ -"Numbers" = "Tal"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod-påmindelser"; - -/* Button title to pair with pod during setup */ -"Pair" = "Par"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Par ny Pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Par Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Par Pod"; - -/* Label text indicating pairing finished. */ -"Paired" = "Parret"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Parrer..."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Parrer..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Procent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PI Version"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Afspil test-bip"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Afspiller test-bip…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Bekræft venligst, at Pod er sikkert fastgjort til din krop.\n\nKanylen kan kun indsættes én gang med hver Pod. Tryk på \"Bekræft\", når Pod er tilsluttet."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Deaktiver Poden. Når deaktiveringen er fuldført, kan du parre en ny Pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Deaktiver Poden. Når deaktiveringen er fuldført, kan du fjerne den og parre en ny Pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PM Version"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod aktiveret"; - -/* Label describing pod age view */ -"Pod Age" = "Pod-alder"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deaktiveret med succes. Fortsæt."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Pod-fejl"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod udløbet"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod udløbet"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod udløber"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod udløber om"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Detaljer om fejl i Pod"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Pod er blokeret"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod'en blev parret med succes. Fortsæt."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Pod-Indstillinger"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pumpe Setup"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Forbered indstikssted."; - -/* title for previous pod page */ -"Previous Pod" = "Forrige Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Oplysninger om forrige Pod"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Klargjort"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Klargør. Vent venligst."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Klargør…"; - -/* The text of the loading label when priming */ -"Priming…" = "Klargør…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pumpetid"; - -/* Label text for basal rate summary */ -"Rate" = "Værdi"; - -/* Label describing time remaining view */ -"Remaining" = "Tilbage"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Fjern Pod fra kroppen"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Fjern pumpe"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Remove the Pod's clear needle cap and check cannula. Then remove paper backing."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Udskift Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Udskift Pod nu"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Reservoir"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Genoptag insulintilførsel..."; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Genoptager insulintilførsel..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Forsøg igen"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Forsøg deaktivering af Pod igen"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink giver mulighed for kommunikation med pumpen via Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink indstilling"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Gem"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Gemmer..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Tidsplan"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Planlagt basal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Planlagt påmindelse"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Vælg den type insulin, du vil bruge i denne Pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sekvensnummer"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Indstil midlertidig basal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Indstil midlertidig basalrate"; - -/* Title for setup complete screen */ -"Setup Complete" = "Opsætning fuldført"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Signaltab"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Spring Omnipod Onboarding over?"; - -/* The title of the status section in settings */ -"Status" = "Status"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Gennemført"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Afbryd insulintilførsel"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Afbryd insulintilførsel"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Suspenderet"; - -/* Label for suspended at time */ -"Suspended At" = "Suspenderet"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Afbryder insulintilførsel..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Skift fra Omnipod-pumper"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Skift til en anden insulintilførselsenhed"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synkroniser til aktuel tid"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Synkroniser med Pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tryk nedenfor for at starte kanyleindsættelse."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Midlertidig basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Midlertidig basal mislykkedes"; - -/* The title of the command to run the test command */ -"Test Command" = "Testkommando"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Tester kommandoer…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Appen konfigurerer en påmindelse på Pod'en for at give dig besked inden Pod-udløb. Indstil antallet af timer i forvejen, du vil konfigurere, når du parrer en ny Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Appen giver dig besked før Pod'en udløber.\n\nIndstil antallet af timer før udløb som påmindelse."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Appen giver dig besked, når mængden af insulin i Pod'en når dette niveau (50-10 E)\n\nIndstil antallet enheder, du vil bruge som påmindelse. "; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Appen giver dig besked, når mængden af insulin i Pod'en når dette niveau."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Påmindelserne ovenfor vil ikke lyde, hvis din enhed er i lydløs tilstand eller Forstyr ikke.\n\nDer er andre kritiske Pod alarmer og alarmer, der vil lyde, selvom din enhed er indstillet til Lydløs eller Forstyr ikke."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Tiden på din pumpe er forskellig fra den aktuelle tid. Vil du opdatere tiden på din pumpe til det aktuelle tidspunkt?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Tiden på din pumpe er forskellig fra den aktuelle tid. Din pumpes tid styrer dine planlagte behandlingsindstillinger. Gå til Pumpetid for at gennemgå tidsforskellen og konfigurere din pumpe."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Vinduet på toppen af Pod'en skal være farvet pink, når kanylen er korrekt indsat i huden."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Kunne ikke kommunikere med Pod'en. Hvis problemet fortsætter, tryk Afbryd og kassér Pod'en. Du kan herefter aktivere en ny Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dette er en påmindelse om, at du planlagde, hvornår du parrede din nuværende Pod."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "Denne pumpe er ikke blevet konfigureret med en maksimal basalrate, fordi den blev tilføjet, før manuel en manuel midlertidig basal var en funktion. Gå venligst til Behandlingsindstillinger - > Leveringsgrænser og indstil en ny maksimal basalrate."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Tid"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Tidsændring registreret"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Skift tegn"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "For mange indtastninger"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Samlet indgivelse"; - -/* Units for showing temp basal rate */ -"U/hr" = "E/t"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Kan ikke deaktivere Pod. Venligst fortsæt og par med en ny."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Kan ikke få kontakt til pumpen"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Kan ikke indstille en midlertidig basalrate: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Kan ikke indstille en midlertidig basalrate: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Uafsluttet aktivering"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Uafsluttet deaktivering"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Ukendt"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Vent, indtil indsættelsen er afsluttet."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, deaktiver Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, synkroniser til det aktuelle klokkeslæt"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Du skal nu begynde at konfigurere dine påmindelser, fylde din Pod med insulin, parre den med din enhed og placere den på din krop."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Din pod er klar til brug.\n\n%1$@ minder dig om, at du skal skifte din pod, inden den udløber. Du kan ændre dette til et tidspunkt, der passer dig."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Din Pod leverer muligvis stadig insulin.\nFjern den fra din krop og tryk derefter på \"Fortsæt\"."; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/de.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/de.lproj/Localizable.strings deleted file mode 100644 index e9781baad..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/de.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ vor"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%1$@ hat die Kommunikation mit dem Pod auf Ihrem Körper wiederhergestellt.\n\nDie Insulinabgabeaufzeichnungen wurden aktualisiert und sollten mit dem übereinstimmen, was tatsächlich geliefert wurde.\n\nSie können %2$@ jetzt normal weiter verwenden."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ IE"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ IE (abgegeben)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ IE von %2$@ IE (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ IE/Std."; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ IE"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ für %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ konnte seit %2$@ nicht mehr mit Ihrem Pod kommunizieren.\n\nOhne Kommunikation mit dem Pod kann die App keine Befehle für die Insulinabgabe senden oder genaue, aktuelle Informationen über Ihr aktives Insulin oder das vom Pod abgegebene Insulin anzeigen.\n\nÜberwachen Sie Ihren Blutzucker für die nächsten 6 oder mehr Stunden genau, da in Ihrem Körper Insulin aktiv sein kann oder auch nicht, das %3$@ nicht anzeigen kann."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ IE verbleibend bei %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Die Insulinabgabe wurde gestoppt. Bitte deaktiviere und entferne den Pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g IE"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 Stunde"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 Stunde 30 Minuten"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 Stunden"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 Minuten"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Laufzeit"; - -/* Section header for activity section */ -"Activity" = "Aktivität"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pumpenzeit einstellen"; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarme"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Sind Sie sicher, dass Sie die Pod-Einrichtung abbrechen möchten?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Möchten Sie diesen Pod wirklich deaktivieren?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Sind Sie sicher, dass Sie das Omnipod Onboarding überspringen wollen?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Möchten Sie den Pod wirklich nicht mehr verwenden?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Zugewiesene Adresse"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Pod anbringen"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Versuche die Verbindung wieder aufzubauen"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Zurück"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Basalabgabe"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basalrate"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Bolusabgabe"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Abbrechen"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Manuelles Basal abbrechen"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanüle erfolgreich eingeführt. Weiter."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Pod jetzt wechseln. Die Insulinabgabe stoppt 8 Stunden nach Ablauf des Pods oder wenn kein Insulin mehr vorhanden ist."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Pod jetzt wechseln. Die Insulinabgabe stoppt in %1$@ oder wenn kein Insulin mehr vorhanden ist."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Zeitzone ändern"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Zeit ändern"; - -/* Title for check cannula screen */ -"Check Cannula" = "Prüfe die Kanüle"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Überprüfe den Pod, bringe ihn an und bestätige dann die Pod-Anbringung."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Prüfe die Einfügung"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Prüfe…"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Kommunikation wiederhergestellt"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Sicherheitserinnerung"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Vertrauenserinnerungen sind Pieptöne vom Pod, die verwendet werden können, um ausgewählte Befehle zu bestätigen."; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfiguration"; - -/* Button title for confirm attachment option */ -"Confirm" = "Bestätige"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bestätige Pod Befestigung"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Weiter"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritische Warnungen"; - -/* Unit for singular day in pod life remaining */ -"day" = "Tag"; - -/* Unit for plural days in pod life remaining */ -"days" = "Tage"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Deaktivieren"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Pod deaktivieren"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Deaktiviert"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktiviere."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deaktiviere…"; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Pod löschen"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Abgabelimits"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Gerätedetails"; - -/* The title of the device information section in settings */ -"Device Information" = "Geräteinformation"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Geräte"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Deaktiviere Bolustöne"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Pod verwerfen"; - -/* No comment provided by engineer. */ -"Done" = "Fertig"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Aktiviere Bolustöne"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Fehler"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Fehler beim Deaktivieren der Bolustöne"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Fehler beim Aktivieren der Bolustöne"; - -/* The alert title for a resume error */ -"Error Resuming" = "Fehler beim Fortfahren"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Fehler beim Unterbrechen"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Erinnerung an den Ablauf der Nutzungsdauer"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standard Erinnerung an den Ablauf der Nutzungsdauer"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Abgelaufen"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Läuft ab"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Fehler beim Abbrechen der manuellen Basalrate"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Wiederaufnahme der Insulinabgabe fehlgeschlagen"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Fehler beim Einstellen der Pumpenzeit"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Fehler beim Anhalten der Insulinabgabe"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Fehler beim Aktualisieren der Einstellung für die Sicherheitserinnerung."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Fehler beim Aktualisieren der Ablauferinnerung"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Fehler beim Aktualisieren der Erinnerung für einen niedrigen Vorratsbehälter"; - -/* Pod life HUD view label */ -"Fault" = "Störung"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Füllen Sie einen neuen Pod mit U-100-Insulin (Entfernen Sie nicht den Nadelverschluss). Warten Sie auf 2 Pieptöne."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Deaktivierung abschließen"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Pod-Setup abschließen"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Einrichtung abschließen"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Mehr als %1$@ verbleibende Einheiten um %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "Stunde"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "Stunden"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Wenn Du die Einrichtung abbrichst, dann wird der Pod deaktiviert und unbrauchbar."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Der unvollständig eingerichtete Pod muss vor der Kopplung eines neuen deaktiviert werden. Bitte deaktivieren und verwerfen Sie den Pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Der unvollständig eingerichtete Pod muss vor der Kopplung mit einem neuen deaktiviert werden. Bitte deaktivieren und entfernen Sie den Pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Kanüle einsetzen"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Eingeführt"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Füge ein, bitte warte…"; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Füge ein…"; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulinabgabe\nunterbrochen"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Abgegebenes Insulin"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulinabgabe"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulinabgabe wurde gestoppt. Pod jetzt wechseln."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Die Insulinabgabe wird angehalten, bis Sie sie manuell wieder aufnehmen. Wann soll Loop Sie daran erinnern, die Abgabe fortzusetzen?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Verbleibendes Insulin"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulintyp"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Ungültiger Eintrag"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Wurde der Katheter ordentlich eingeführt?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Halten Sie den RileyLink während des Koppelns ca. 15 cm vom Pod entfernt."; - -/* description label for last status date pod details row */ -"Last Status" = "Letzter Status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop passt Ihre Insulinabgabe nicht automatisch an, bis die temporäre Basalrate beendet oder abgebrochen wurde."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lot"; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Niedriges Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Erinnerung an niedriges Reservoir"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Stellen Sie sicher, dass sich Ihr iPhone und Ihr Pod nahe beieinander befinden. Wenn die Kommunikationsprobleme bestehen bleiben, dann gehen Sie an einen anderen Ort."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "Minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "Minuten"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Fehlende Konfiguration"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Weiter"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nein"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Keine\nAbgabe"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Kein Insulin"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Kein Pod gekoppelt"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Keine Erinnerung"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nein, mit Pod fortfahren"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nein, Pumpe so lassen wie sie ist"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Keiner"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Benachrichtigungseinstellungen"; - -/* No comment provided by engineer. */ -"Numbers" = "Zahlen"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Erinnerung"; - -/* Button title to pair with pod during setup */ -"Pair" = "Koppeln"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Neuen Pod koppeln"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pod koppeln"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pod koppeln."; - -/* Label text indicating pairing finished. */ -"Paired" = "Gekoppelt"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Koppeln"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Koppeln…"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Prozent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PI-Version"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Testtöne abspielen"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Testtöne abspielen…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Bitte vergewissern Sie sich, dass der Pod sicher an Ihrem Körper befestigt ist.\n\nDer Katheter kann mit jedem Pod nur einmal eingeführt werden. Tippen Sie auf „Bestätigen“, wenn der Pod angeschlossen ist."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Bitte deaktivieren Sie den Pod. Wenn die Deaktivierung abgeschlossen ist, können Sie einen neuen Pod koppeln."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Bitte deaktivieren Sie den Pod. Wenn die Deaktivierung abgeschlossen ist, können Sie ihn entfernen und einen neuen Pod koppeln."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PM-Version"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod aktiviert"; - -/* Label describing pod age view */ -"Pod Age" = "Pod-Alter"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod erfolgreich deaktiviert. Weiter."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Pod-Fehler"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod abgelaufen"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod abgelaufen"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod läuft ab"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod läufen ab in"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fehlerdetails"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Pod Verstopfung"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod erfolgreich gekoppelt. Weiter."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Pod-Einstellungen"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Einrichtung"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Stelle vorbereiten."; - -/* title for previous pod page */ -"Previous Pod" = "Vorheriger Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informationen über den letzten Pod"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Gefüllt"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Befülle, bitte warte."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Befülle…"; - -/* The text of the loading label when priming */ -"Priming…" = "Befülle…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Uhrzeit der Pumpe"; - -/* Label text for basal rate summary */ -"Rate" = "BR"; - -/* Label describing time remaining view */ -"Remaining" = "Verbleibend"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Entferne den Pod vom Körper"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Pumpe löschen"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Entfernen Sie die Pod-Nadel Kappe und prüfen Sie die Kanüle. Danach die Klebefolien auf der Rückseite entfernen."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Pod ersetzen"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Pod jetzt ersetzen"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Reservoir"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Insulinabgabe wiederaufnehmen"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Nehme Insulinabgabe wieder auf…"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Wiederholen"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Pod-Deaktivierung wiederholen"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "Der RileyLink ermöglicht die Kommunikation mit der Pumpe über Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink Einrichten"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Speichern"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Speichere…"; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Voreingestellt"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Geplante Basalrate"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Geplante Erinnerung"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Wähle die Insulinart aus, die Du für diesen Pod benutzen möchtest."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequenznummer"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Temporäre Basalrate setzen"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Temporärere Basalrate setzen"; - -/* Title for setup complete screen */ -"Setup Complete" = "Einrichtung abgeschlossen"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Signalverlust"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Omnipod-Onboarding überspringen?"; - -/* The title of the status section in settings */ -"Status" = "Status"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Erfolgreich"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Abgabe unterbrechen"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Insulinabgabe unterbrechen"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Unterbrochen"; - -/* Label for suspended at time */ -"Suspended At" = "Unterbrochen um"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Unterbreche die Insulinabgabe…"; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Omnipod nicht mehr verwenden"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Zu einer anderen Pumpe wechseln"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Mit aktueller Uhrzeit synchronisieren."; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Mit Pod synchronisieren"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tippe unten, um das Einführen der Kanüle zu starten."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporäre Basalrate"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal fehlgeschlagen"; - -/* The title of the command to run the test command */ -"Test Command" = "Befehl testen"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Teste Befehle…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Die App konfiguriert eine Erinnerung auf dem Pod, um Dich vor Ablauf des Pods zu benachrichtigen. Legen die Anzahl der Stunden fest, die Du vor Ablauf des Pods benachrichtigt werden möchtest."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Die App benachrichtigt Dich vor Ablauf des Pods.\n\nScrolle, um die gewünschte Anzahl von Stunden im Voraus festzulegen."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Die App benachrichtigt Dich, wenn die Insulinmenge im Pod diesen Wert erreicht (50-10 IE).\n\nScrolle, um die Anzahl der Einheiten festzulegen, bei der Du erinnert werden möchtest."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Die App benachrichtigt Dich, wenn die Insulinmenge im Pod diesen Wert erreicht."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Die obigen Erinnerungen ertönen nicht, wenn sich Dein Gerät im Lautlos- oder Nicht-Stören-Modus befindet.\n\nEs gibt andere kritische Pod-Warnungen und -Alarme, die auch dann ertönen, wenn Dein Gerät auf „Lautlos“ oder „Nicht stören“ eingestellt ist."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Die Uhrzeit Ihrer Pumpe unterscheidet sich von Ihrer aktuellen Uhrzeit. Möchten Sie die Uhrzeit Ihrer Pumpe auf Ihre aktuelle Uhrzeit aktualisieren?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Die Uhrzeit der Pumpe weicht von der aktuellen Uhrzeit ab. Die Zeit der Pumpe steuert die geplanten Therapieeinstellungen. Scrolle nach unten zur Zeile Pumpenzeit, um den Zeitunterschied zu überprüfen und die Pumpe zu konfigurieren."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Das Fenster oben auf dem Pod sollte pinkfarben sein, wenn der Katheter ordentlich in die Haut eingeführt wurde."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Es gab ein Problem bei der Kommunikation mit dem Pod. Wenn dieses Problem weiterhin besteht, tippen Sie auf \"Pod verwerfen\". Sie können dann einen neuen Pod aktivieren."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dies ist eine Erinnerung, die Du beim Koppeln Deines aktuellen Pods eingestellt hast."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "Diese Pumpe wurde nicht mit einer maximalen Basalrate konfiguriert, da sie hinzugefügt wurde, bevor die Funktion manuelle temporäre Basalrate existierte. Bitte gehe zu Therapieeinstellungen -> Abgabegrenzen und stelle eine neue maximale Basalrate ein."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Zeit"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Änderung der Uhrzeit erkannt"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Zeichen umschalten"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Zu viele Einträge"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Gesamt Abgabe"; - -/* Units for showing temp basal rate */ -"U/hr" = "IE/h"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Pod kann nicht deaktiviert werden. Bitte fahre fort und kopple einen neuen."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Pod kann nicht erreicht werden"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Eine temporäre Basalrate kann nicht gesetzt werden: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Eine temporäre Basalrate kann nicht gesetzt werden: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Nicht abgeschlossene Aktivierung"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Nicht abgeschlossene Deaktivierung"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Unbekannt"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Warte bis das Einführen der Kanüle fertig ist."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, deaktiviere Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, mit aktueller Zeit synchronisieren"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Beginne nun damit, die Erinnerungen zu konfigurieren, Dein Pod mit Insulin zu füllen, ihn mit Deinem Gerät zu koppeln und ihn an Deinem Körper zu platzieren."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Dein Pod ist einsatzbereit.\n\n%1$@ erinnert Dich daran, Deinen Pod zu wechseln, bevor er abläuft. Du kannst eine für Dich passende Zeit wählen."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Ihr Pod gibt möglicherweise immer noch Insulin ab.\nEntfernen Sie ihn vom Körper und tippen dann auf „Weiter“."; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Stille"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normaler Operationsmodus, in dem hörbare Pod Signale für alle Pod Alarme verwendet werden und wenn Vertrauenserinnerungen aktiviert sind."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Alle Pod Alarme verwenden keine Signale und Bestätigungssignale werden unterdrückt. Der Pod springt nur bei tödlichen Pod-Fehlern und beim Abspielen von Testsignalen.\n\nWarnung: Warnung - Wann immer der Pod zum Schweigen gebracht wird, muss er innerhalb des Bluetooth-Bereichs dieses Geräts gehalten werden, um Benachrichtigungen für Pod-Benachrichtigungen zu erhalten."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Stille Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod-Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Vorherige Pod-Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump-Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Pumpenmanager Details abrufen..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Pumpenmanager Details aktualisieren"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Fehler beim Aktualisieren der Stille Pod Einstellung."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnose-Infos"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Pod-Status ablesen"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/en.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/en.lproj/Localizable.strings deleted file mode 100644 index e0ed8adda..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/en.lproj/Localizable.strings +++ /dev/null @@ -1,808 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ ago"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (Finished)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%@ U of %@ U (%@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/hour"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Insulin delivery has stopped. Please deactivate and remove pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 hour"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Active Time"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarms"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Are you sure you want to shutdown this pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Are you sure you want to skip Omnipod Onboarding?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Are you sure you want to stop using Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Assigned Address"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Attach Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Attemping to re-establish communication"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Back"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Basal Delivery"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basal Rates"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Bolus Delivery"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancel"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Cannula inserted successfully. Continue."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Change Time Zone"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Changing time…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Check Cannula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Checking Insertion"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comms Recovered"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced."; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuration"; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Continue"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Critical Alerts"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Deactivate"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Deactivated"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deactivating..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Delete Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Delivery Limits"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Device Details"; - -/* The title of the device information section in settings */ -"Device Information" = "Device Information"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Devices"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Disable Bolus Beeps"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* No comment provided by engineer. */ -"Done" = "Done"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Enable Bolus Beeps"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Error"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Error disabling bolus beeps"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Error enabling bolus beeps"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Resuming"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspending"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Expired"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Expires"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Failed to update confidence reminder preference."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Failed to Update Expiration Reminder"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Failed to Update Low Reservoir Reminder"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Finish pod setup"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Greater than %1$@ units remaining at %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hours"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Insert Cannula"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Inserting. Please wait."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insulin Delivered"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulin Type"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Invalid entry"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Keep the RileyLink about 6 inches from the pod during pairing."; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lot"; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Low Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Next"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "No\nDelivery"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "No Insulin"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "No Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "None"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Notification Settings"; - -/* No comment provided by engineer. */ -"Numbers" = "Numbers"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Button title to pair with pod during setup */ -"Pair" = "Pair"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Pair New Pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Paired"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PI Version"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Play Test Beeps"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Play Test Beeps…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PM Version"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Activated"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Pod Error"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod Expired"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod Expires"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Pod Settings"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Primed"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* The text of the loading label when priming */ -"Priming…" = "Priming…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Label text for basal rate summary */ -"Rate" = "Rate"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Remove the Pod's clear needle cap and check cannula. Then remove paper backing."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Replace Pod Now"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Reservoir"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Retry"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Retry Pod Deactivation"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink allows for communication with the pump over Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink Setup"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Save"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Saving..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Schedule"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Select the type of insulin that you will be using in this pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Title for setup complete screen */ -"Setup Complete" = "Setup Complete"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Signal Loss"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* The title of the status section in settings */ -"Status" = "Status"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Succeeded"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Suspended"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Switch from Omnipod Pumps"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Sync With Pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* The title of the command to run the test command */ -"Test Command" = "Test Command"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Testing Commands…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Time"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Time Change Detected"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Toggle sign"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Too many entries"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hr"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Unable to deactivate pod. Please continue and pair a new one."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Unable to Reach Pod"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Unknown"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping."; - -/* navigation title for Silnce Pod" */ -"Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; - -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/es.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/es.lproj/Localizable.strings deleted file mode 100644 index eb1bfcadd..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/es.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "Hace %@"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%1$@ ha recuperado la comunicación con el Pod de su cuerpo.\n\nLos registros de suministro de insulina se han actualizado y deberían coincidir con lo que se ha suministrado realmente.\n\nYa puede seguir usando %2$@ con normalidad."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (Completado)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ U de %2$@ U (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/hora"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ para %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ no ha podido comunicarse con el Pod que esta adherido a su cuerpo desde %2$@.\n\nSin comunicación con el Pod, la app no puede seguir enviando órdenes de administración de insulina ni mostrar información precisa y reciente sobre su insulina activa o la insulina que está administrando el Pod.\n\nVigile de cerca sus niveles de glucosa durante las próximas 6 horas o más, ya que puede haber o no insulina activa en su cuerpo que %3$@ no puede mostrar."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "quedan %1$@ unidades a las %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Administración de insulina ha parado. Por favor, desactive y remueva el pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@ + %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 hora"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hora 30 minutos"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 horas"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutos"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Tiempo Activo"; - -/* Section header for activity section */ -"Activity" = "Actividad"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Ajustando la hora de la bomba..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarmas"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "¿Está seguro de que desea cancelar la configuración del Pod?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "¿Está seguro que quiere apagar este pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "¿Está seguro de que desea saltearse de Omnipod Onboarding?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "¿Está seguro que quiere dejar de usar Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Dirección Asignada"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Coloque el Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Intentando restablecer la comunicación"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Atrás"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Basal Administrada"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Tasas basales"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Bolo Administrado"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancelar"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancelar basal manual"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Cánula insertada con éxito. Continúa."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Cambie el Pod ahora. La administración de insulina se detendrá 8 horas después de que el Pod haya caducado o cuando no quede más insulina."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Cambie el Pod ahora. La administración de insulina se detendrá en %1$@ o cuando no quede más insulina."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Cambiar Zona Horaria"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Cambiando hora..."; - -/* Title for check cannula screen */ -"Check Cannula" = "Revise la cánula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Revise el Pod, aplíquelo y, a continuación, confirme que este está bien colocado."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Comprobando inserción"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Comprobando..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comunicaciones recuperadas"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Recordatorios de confianza"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced."; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuración"; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirmar"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirme la fijación del Pod"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Continuar"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Alertas críticas"; - -/* Unit for singular day in pod life remaining */ -"day" = "día"; - -/* Unit for plural days in pod life remaining */ -"days" = "días"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Desactivar"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Desactivar Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Pod desactivado"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Desactivando."; - -/* Action button description while deactivating */ -"Deactivating..." = "Desactivando..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Eliminar Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Límites de Administración de Insulina"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Detalles del dispositivo"; - -/* The title of the device information section in settings */ -"Device Information" = "Información del Dispositivo"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Dispositivos"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Desactivar Pitidos del Bolo"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Descartar Pod"; - -/* No comment provided by engineer. */ -"Done" = "Completado"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Activar Pitidos del Bolo"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Error"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Error desactivando pitidos del bolo"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Error activando pitidos del bolo"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Reanudando"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspendiendo"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Recordatorio de Caducidad"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Recordatorio de expiración predeterminado"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Caducado"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Caduca"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "No se pudo cancelar la insulina basal manual"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "No se pudo reanudar la administración de insulina"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "No se establecio la hora de la bomba"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "No se pudo suspender la administración de insulina"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "No se ha podido actualizar la preferencia de recordatorio de confianza."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "No se ha podido actualizar el recordatorio de Expiración"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "No se ha podido actualizar el recordatorio de Reserva Baja"; - -/* Pod life HUD view label */ -"Fault" = "Fallo"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Llene un nuevo pod con Insulina U-100 (deje puesta la tapa de la aguja del pod). Escuche 2 tonos."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finalizar la desactivación"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Terminar la configuración del pod"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finalizar la Configuración"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Quedan más de %1$@ unidades a las %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hora"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "horas"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Si cancela la configuración del Pod, el Pod actual se desactivará y quedará inutilizable."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Pod con configuración incompleta tiene que desactivarse antes de emparejarse con uno nuevo"; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Pod con configuración incompleta tiene que desactivarse antes de emparejar uno nuevo. Por favor desactive y quítese el pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Insertar Cánula"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Insertada"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Insertando. Espere, por favor."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Insertando..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulina Suspendida"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insulina Administrada"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "El suministro de insulina se detuvo. Cambiar Pod ahora."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "La administración de insulina se detendrá hasta que la reanude manualmente. ¿Cuándo desea que Loop le recuerde que debe reanudar la administración?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulina restante"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Tipo de Insulina"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Entrada inválida"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "¿La cánula está insertada correctamente?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Mantenga el RileyLink a unas 6 pulgadas del Pod durante el emparejamiento."; - -/* description label for last status date pod details row */ -"Last Status" = "Último estado"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop no ajustará automáticamente la administración de insulina hasta que la tasa de administracion de insulina basal temporal finalice o se cancele."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lote"; - -/* description label for lot number pod details row */ -"Lot Number" = "Número de lote"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Reserva baja"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Recordatorio de reserva baja"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Asegúrese de que su teléfono y su pod estén cerca uno del otro. Si los problemas de comunicación persisten, muévase a otra área."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minuto"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutos"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Configuración faltante"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "No disponible"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Siguiente"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "No hay administración"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "No hay insulina"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "No hay Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Sin recordatorio"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, continúe con el Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, mantenga la bomba como está"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Ninguno"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Configuración de las notificaciones"; - -/* No comment provided by engineer. */ -"Numbers" = "Números"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Recordatorios Omnipod"; - -/* Button title to pair with pod during setup */ -"Pair" = "Emparejar"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Emparejar Nuevo Pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Emparejar Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Emparejar Pod"; - -/* Label text indicating pairing finished. */ -"Paired" = "Emparejado"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Emparejando."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Emparejando..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Porcentaje = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "Versión PI del Pod"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Tocar Pitidos de Prueba"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Tocar Pitidos de Prueba..."; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Compruebe que el Pod está bien adherido a su cuerpo.\n\nLa cánula sólo puede insertarse una vez con cada Pod. Pulse \"Confirmar\" cuando el Pod esté ya bien adherido a su cuerpo."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Por favor desactivar el Pod. Cuando la desactivación se haya completado, puede emparejar un nuevo Pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Por favor desactivar el Pod. Cuando la desactivación se haya completado, puede retirarlo y emparejar un nuevo pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "Versión de PM"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Activado"; - -/* Label describing pod age view */ -"Pod Age" = "Tiempo de Uso del Pod"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod desactivado correctamente. Continúa"; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Error del Pod"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod caducado"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod caducado"; - -/* Label for pod expiration row */ -"Pod Expires" = "El Pod caduca"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "El Pod caduca en"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Detalles de la falla del Pod"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Oclusión del Pod"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod emparejado correctamente. Continúa."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Configuración del Pod"; - -/* Title for PodSetupView */ -"Pod Setup" = "Configuración del Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare lugar de inserción"; - -/* title for previous pod page */ -"Previous Pod" = "Pod anterior"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Información anterior del Pod"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Purgado"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Purgando. Por favor, espere."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Purgando..."; - -/* The text of the loading label when priming */ -"Priming…" = "Purgando..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Hora de la bomba"; - -/* Label text for basal rate summary */ -"Rate" = "Tasa"; - -/* Label describing time remaining view */ -"Remaining" = "Restante"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Quitar el Pod del cuerpo"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Retire la bomba"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Remove the Pod's clear needle cap and check cannula. Then remove paper backing."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Reemplace el Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Cambie el Pod Ahora"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Reservorio"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Reanude la administración de insulina"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Reanudando la administración de insulina..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Reintentar"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Reintentar Desactivar el Pod"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink permite la comunicación con la bomba a través de Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "Configuración de RileyLink"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Agregar"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Guardando..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Programa"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Insulina basal programada"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Recordatorio programado"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Seleccione el tipo de insulina que utilizará en esta bomba."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Número de secuencia"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Establecer insulina basal temporal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Establecer tasa basal temporal"; - -/* Title for setup complete screen */ -"Setup Complete" = "Instalación completada"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Pérdida de señal"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "¿Saltearse el Onboarding de Omnipod?"; - -/* The title of the status section in settings */ -"Status" = "Estado"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Logrado"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspender la infusión"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspender la administración de insulina"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Suspendido"; - -/* Label for suspended at time */ -"Suspended At" = "Suspendido a las"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspendiendo la administración de insulina..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Cambiar de Omnipod"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Cambiar a otro dispositivo de administración de insulina"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sincronizar con la hora actual"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Sincronizar con el Pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Toque abajo para iniciar la inserción de la cánula."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Insulina basal temporal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "La insulina basal temporal ha fallado"; - -/* The title of the command to run the test command */ -"Test Command" = "Comando de Prueba"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Probando Comandos..."; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "La aplicación configura un recordatorio en el Pod para notificarle con antelación sobre la expiración del Pod. Establezca el número de horas de antelación con las que desea que le avise para emparejar un nuevo Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "La aplicación le avisa con antelación de la expiración del Pod.\n\nDesplácese para establecer el número de horas de antelación que le gustaría tener."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "La App le avisa cuando la cantidad de insulina en el Pod alcanza este nivel (50-10 U).\n\nDesplácese para establecer el número de unidades en las que desea que la App le avise."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "La aplicación le notifica cuando la cantidad de insulina en el Pod alcanza este nivel."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "La hora de la bomba es diferente de la hora actual. Desea actualizar la hora de su bomba a la hora actual?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "La hora de su bomba es diferente de la hora actual. La hora de su bomba controla los ajustes programados de su terapia. Desplácese hacia abajo hasta la fila que muestra la Hora de la Bomba para revisar la diferencia horaria y configurar su bomba."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "La ventana situada en la parte superior del Pod debe volverse de color rosa cuando la cánula esté correctamente insertada en la piel."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Se ha producido un problema de comunicación con el Pod. Si el problema persiste, pulse Descartar Pod. A continuación, puede activar un nuevo Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Este es un recordatorio que programó cuando enlazó su Pod actual."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "Esta bomba no ha sido configurada con una tasa de administración basal máxima porque fue añadida antes de que la temperatura basal manual estuviese disponible. Por favor vaya a Configuración de Terapia -> Límites de administración y establezca una nueva tasa de administración basal máxima."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Hora"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Cambio de hora detectado"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Botón de alternar"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Demasiadas entradas"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Dosis total administrada"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hra"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Desactivación del pod falló. Por favor, continúe y empareje uno nuevo"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "No se puede conectar el Pod"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "No se ha podido establecer una tasa de insulina basal temporal: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "No se ha podido establecer una tasa de insulina basal temporal: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Activación no terminada"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Desactivación no terminada"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Desconocido"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Espere hasta que finalice la inserción."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Sí"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Sí, desactivar Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Sí, sincronizar con la hora actual"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Ahora comenzará el proceso de configurar sus recordatorios, llenar su Pod con insulina, emparejarlo con su dispositivo y colocárselo en el cuerpo."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Su Pod está listo para usar.\n\n%1$@ le recordará cambiar su Pod antes de que caduque. Puede cambiarlo cuando sea un momento conveniente para usted."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Es posible que su Pod siga suministrando insulina.\nRetírelo de su cuerpo y pulse \"Continuar\"."; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/fi.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/fi.lproj/Localizable.strings deleted file mode 100644 index 2c0f23c2b..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/fi.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (valmis)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ U of %2$@ U (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/tunti"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@ U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ yksikköä jäljellä klo %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Insuliinin annostelu on loppunut. Deaktivoi ja poista pumppu."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 hour"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Aktiivinen aika"; - -/* Section header for activity section */ -"Activity" = "Liikunta"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Hälytykset"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Haluatko varmasti sammuttaa tämän pumpun?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Are you sure you want to skip Omnipod Onboarding?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Haluatko varmasti lopettaa Omnipodin käytön?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Määritetty osoite"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Attach Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Attemping to re-establish communication"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Takaisin"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Basaali"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basaalitasot"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Bolus"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Kumoa"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Cannula inserted successfully. Continue."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Muuta aikavyöhyke"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Muutetaan aikaa…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Check Cannula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Checking Insertion"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Tarkistetaan..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comms Recovered"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced."; - -/* The title of the configuration section in settings */ -"Configuration" = "Määritykset"; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Jatka"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Critical Alerts"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Deaktivoi"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Deaktivoi pumppu"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Deaktivoitu"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deactivating..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Poista Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Annostelurajat"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Device Details"; - -/* The title of the device information section in settings */ -"Device Information" = "Laitteen tiedot"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Laitteet"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Laita bolusäänet pois"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* No comment provided by engineer. */ -"Done" = "Valmis"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Laita bolusäänet päälle"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Virhe"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Virhe laitettaessa bolusäänet pois päältä"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Virhe laitettaessa bolusäänet päälle"; - -/* The alert title for a resume error */ -"Error Resuming" = "Virhe jatkamisessa"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Virhe pysäytyksessä"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Vanhenemismuistutus"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Vanhentunut"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Vanhenee"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Annostelun jatkaminen epäonnistui"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Failed to update confidence reminder preference."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Failed to Update Expiration Reminder"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Failed to Update Low Reservoir Reminder"; - -/* Pod life HUD view label */ -"Fault" = "Virhe"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Lopeta pumpun asennus"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Enemmän kuin %1$@ yksikköä jäljellä klo %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hours"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Puutteellisesti asennettu pumppu täytyy deaktivoida ennen kuin uusi pumppu voidaan yhdistää. Deaktivoi ja hylkää pumppu."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Puutteellisesti asennettu pumppu täytyy deaktivoida ennen kuin uusi pumppu voidaan yhdistää. Deaktivoi ja poista pumppu."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Aseta kanyyli"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Inserting. Please wait."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Annosteltu insuliini"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insuliinityyppi"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Virheellinen merkintä"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Keep the RileyLink about 6 inches from the pod during pairing."; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lot"; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Low Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Next"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "No\nDelivery"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Ei insuliinia"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Ei pumppua"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Ei mitään"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Notification Settings"; - -/* No comment provided by engineer. */ -"Numbers" = "Numbers"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Button title to pair with pod during setup */ -"Pair" = "Yhdistä"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Yhdistä uusi pumppu"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Yhdistetty"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PI-versio"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Soita testiäänet"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Soitetaan testiäänet…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PM-versio"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Activated"; - -/* Label describing pod age view */ -"Pod Age" = "Pumpun ikä"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Pod Error"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pumppu vanhentunut"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pumppu vanhentunut"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod Expires"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Pumpun asetukset"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Alustettu"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* The text of the loading label when priming */ -"Priming…" = "Alustetaan…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Label text for basal rate summary */ -"Rate" = "Rate"; - -/* Label describing time remaining view */ -"Remaining" = "Jäljellä"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Remove the Pod's clear needle cap and check cannula. Then remove paper backing."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Vaihda pumppu"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Vaihda pumppu nyt"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Säiliö"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Yritä uudelleen"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Deaktivoi pumppu uudelleen"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink allows for communication with the pump over Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink-asennus"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Tallenna"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Saving..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Ohjelmoitu"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Ohjelmoitu basaali"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Valitse insuliinin tyyppi, jota käytät tässä pumpussa."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Title for setup complete screen */ -"Setup Complete" = "Asennus valmis"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Signal Loss"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* The title of the status section in settings */ -"Status" = "Tila"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Onnistui"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Pysäytä annostelu"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Pysäytetty"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Lopeta Omnipodin käyttö"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Synkronoi pumpun kanssa"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* The title of the command to run the test command */ -"Test Command" = "Testikomento"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Testataan komentoja…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Aika"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Time Change Detected"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Toggle sign"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Liian monta basaalitasoa määritetty"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/h"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Pumpun deaktivointi ei onnistunut. Jatka ja yhdistä uusi pumppu."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Unable to Reach Pod"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Tuntematon"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/fr.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/fr.lproj/Localizable.strings deleted file mode 100644 index ad431ddb5..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/fr.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "Il y a %@"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "La communication avec le Pod sur votre corps a été rétablie.\n\nLes enregistrements d'administration d'insuline ont été mis à jour et devraient correspondre à ce qui a été effectivement administré.\n\nVous pouvez continuer à utiliser %@ normalement maintenant."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (Terminé)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ U of %2$@ U (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/heure"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ pendant %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ n'a pas pu communiquer avec le Pod sur votre corps depuis %2$@ . \n\nSans communication avec le Pod, l'application ne peut pas continuer à envoyer des commandes pour l'administration d'insuline ou afficher des informations précises et récentes sur votre insuline active ou l'insuline administrée par le Pod. \n\nSurveillez attentivement votre glycémie pendant les 6 prochaines heures ou plus, car il peut y avoir ou non de l'insuline active dans votre corps que %3$@ ne peut pas afficher."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unités restantes à %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. L'administration d’insuline s’est arrêtée. Veuillez désactiver et remplacer le Pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 heure"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 heure 30 minutes"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 heures"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Heure d’activation"; - -/* Section header for activity section */ -"Activity" = "Activité"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Ajustement de l'horloge de la pompe..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarmes"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Voulez-vous vraiment annuler la configuration du Pod ?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Voulez-vous vraiment désactiver ce Pod ?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Voulez-vous vraiment sauter l'intégration Omnipod ?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Voulez-vous vraiment arrêter d’utiliser Omnipod ?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Adresse assignée"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Appliquer le Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Tenter de rétablir la communication"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Retour"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Débit basal"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Débits basaux"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Administration bolus"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuler"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Annulation du débit basal manuel"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "La canule a été insérée correctement. Continuez"; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Remplacer le pod maintenant. L'administration d'insuline s'arrêtera 8 heures après l'expiration du pod ou lorsque qu'il ne restera plus d'insuline."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Remplacer le Pod maintenant. L'administration d'insuline s'arrêtera dans %1$@ ou lorsqu'il ne restera plus d'insuline."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Changement de fuseau horaire"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Changement de l’heure..."; - -/* Title for check cannula screen */ -"Check Cannula" = "Vérifier la canule"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Vérifiez le pod, placez-le sur le site, puis confirmez qu'il est bien appliqué."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Vérification de l'insertion en cours"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Vérification en cours..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Communications récupérées"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Rappels de confiance"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Les rappels de confiance sont des bips émis par le Pod qui peuvent être utilisés pour confirmer l'exécution des commandes sélectionnées."; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuration"; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirmer"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirmer l'application du Pod"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Continuer"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Alertes critiques"; - -/* Unit for singular day in pod life remaining */ -"day" = "jour"; - -/* Unit for plural days in pod life remaining */ -"days" = "jours"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Désactiver"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Désactiver le Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Désactivé"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Désactivation."; - -/* Action button description while deactivating */ -"Deactivating..." = "Désactivation en cours..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Supprimer Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Limites d'Administration"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Information de l’appareil"; - -/* The title of the device information section in settings */ -"Device Information" = "Information de l’appareil"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Dispositifs"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Désactiver les bips de bolus"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Jeter le Pod"; - -/* No comment provided by engineer. */ -"Done" = "Terminé"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Activer les bips de bolus"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Erreur"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Erreur lors de la désactivation des bips de bolus"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Erreur lors de l’activation des bips de bolus"; - -/* The alert title for a resume error */ -"Error Resuming" = "Erreur lors de la reprise"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Erreur lors de la suspension"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Rappel d'expiration"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Rappel d'expiration par défaut"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Expiré"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Expire"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Échec d'annulation du basal manuel"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Échec de la reprise de l’administration d’insuline"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Échec de réglage de l'heure de la pompe"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Échec de la suspension de l'administration d'insuline"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Échec de la mise à jour des préférences de rappel de confiance."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Échec de la mise à jour du rappel d'expiration"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Échec de la mise à jour du rappel de réservoir bas"; - -/* Pod life HUD view label */ -"Fault" = "Erreur"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Remplir un nouveau Pod avec de l'insuline U-100 (laisser le capuchon de l'aiguille du Pod en place). 2 bips se feront entendre."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Terminer la désactivation"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Terminer l’installation du Pod"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Terminer l'installation"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Plus de %1$@ unités restantes à %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "heure"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "heures"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Si vous annulez la configuration du Pod, le Pod actuel sera désactivé et sera inutilisable."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Le Pod mal activé doit être désactivé avant d’en appairer un nouveau. Veuillez le désactiver et le jeter."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Le Pod mal activé doit être désactivé avant d’en appairer un nouveau. Veuillez le désactiver et l’enlever."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Insérer la canule"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inrérée"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Insertion en cours. Attendez."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Insertion en cours..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insuline\nSuspendue"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insuline délivrée"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Administration de l'insuline"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "L'administration d'insuline s'est arrêtée. Changez de Pod maintenant."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "L'administration d'insuline sera interrompue jusqu'à ce que vous la repreniez manuellement. Quand voulez-vous que Loop vous rappelle de reprendre l'administration ?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insuline restante"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Type d'insuline"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Saisie invalide"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "La canule est-elle insérée correctement?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Gardez le RileyLink à environ 6 pouces du Pod pendant le jumelage."; - -/* description label for last status date pod details row */ -"Last Status" = "Dernier statut"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop n'ajustera pas automatiquement votre administration d'insuline tant que le débit basal temporaire ne sera pas terminé ou annulé."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lot"; - -/* description label for lot number pod details row */ -"Lot Number" = "Numéro de lot"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Réservoir bas"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Rappel de réservoir bas"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Assurez-vous que votre téléphone et votre Pod sont proches l'un de l'autre. Si les problèmes de communication persistent, déplacez-vous vers un nouvel endroit."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutes"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Configuration manquante"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "N.A."; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Suivant"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Non"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Pas d'administration"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Pas d'insuline"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Aucun Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Pas de rappel"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Non, continuez avec le Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Non, garder la pompe telle quelle"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Aucun"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Paramétrage des notifications"; - -/* No comment provided by engineer. */ -"Numbers" = "Nombres"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Rappels Omnipod"; - -/* Button title to pair with pod during setup */ -"Pair" = "Appairer"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Appairer un nouveau Pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Appairer le Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Appairer le pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Appairé"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Appairage."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Appairage en cours..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Pourcentage = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "Version PI"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Jouer des bips de test"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Bips de test en cours"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Veuillez confirmer que le Pod est solidement attaché à votre corps. \n\n La canule ne peut être insérée qu'une seule fois avec chaque Pod. Appuyez sur \"Confirmer\" lorsque le Pod est appliqué."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Veuillez désactiver le pod. Une fois la désactivation terminée, vous pouvez appairer un nouveau Pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Veuillez désactiver le pod. Une fois la désactivation terminée, vous pouvez le retirer et appairer un nouveau pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "Version PM"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod activé"; - -/* Label describing pod age view */ -"Pod Age" = "Âge Pod"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod désactivé avec succès. Continuez."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Erreur du Pod"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expiré"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod expiré"; - -/* Label for pod expiration row */ -"Pod Expires" = "Péremption du Pod"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Péremption du Pod dans"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Détails de l'erreur du pod"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Occlusion du Pod"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod appairé avec succès. Continuez."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Réglages du pod"; - -/* Title for PodSetupView */ -"Pod Setup" = "Configuration du Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Préparer le site."; - -/* title for previous pod page */ -"Previous Pod" = "Pod précédent"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informations sur le Pod précédent"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Amorcé"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Amorçage. S'il vous plaît, attendez."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Amorçage..."; - -/* The text of the loading label when priming */ -"Priming…" = "Amorçage en cours..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Heure de la pompe"; - -/* Label text for basal rate summary */ -"Rate" = "Débit"; - -/* Label describing time remaining view */ -"Remaining" = "Restant"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Retirer le Pod du corps"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Retirer la pompe"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Retirez le capuchon transparent de l'aiguille du Pod et vérifiez la canule. Retirer ensuite le support papier. Retirer le capuchon de l'aiguille du pod et vérifier la canule. Retirer ensuite le support papier. Texte de l'étiquette pour la deuxième étape des instructions de fixation du pod."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Remplacer le Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Remplacer le Pod maintenant"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Réservoir"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Reprendre l'administration d'insuline"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Reprise de l'administration d'insuline..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Réessayer"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Réessayez la désactivation du Pod"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink permet la communication avec la pompe via Bluetooth."; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "Configuration de RileyLink"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Sauvegarder"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Sauvegarde en cours..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Programme"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Basal programmé"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Rappel programmé"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Sélectionnez le type d'insuline que vous utiliserez dans ce Pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Numéro de séquence"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Régler basal temporaire"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Régler basal temporaire"; - -/* Title for setup complete screen */ -"Setup Complete" = "L’installation est terminée"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Perte de signal"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Ignorer la phase d'intégration d'Omnipod ?"; - -/* The title of the status section in settings */ -"Status" = "Statut"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Réussi"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspendre l'administration"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspendre l'administration d'insuline"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Suspendu"; - -/* Label for suspended at time */ -"Suspended At" = "Suspendu à"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspension de l'administration d'insuline..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Changer des pompes Omnipod"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Passer à un autre dispositif d'administration d'insuline"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchroniser avec l'heure actuelle"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Synchroniser avec le Pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Appuyez ci-dessous pour commencer l'insertion de la canule."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Basale temporaire"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Échec mise en route basal temporaire"; - -/* The title of the command to run the test command */ -"Test Command" = "Commande de test"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Commandes de test en cours..."; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "L'application configure un rappel pour vous avertir à l'avance de l'expiration du pod. Définissez le nombre d'heures de préavis que vous souhaitez lors de l'appairage d'un nouveau pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "L'application vous avertit à l'avance de l'expiration du pod. \n\n Faites défiler pour définir le nombre d'heures de préavis que vous souhaitez."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "L'application vous avertit lorsque la quantité d'insuline dans le Pod atteint ce niveau (50-10 U).\n\nFaites défiler pour définir le nombre d'unités à partir duquel vous souhaitez être averti."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "L'application vous avertit quand la quantité d'insuline restante dans le pod atteint cette limite"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Les rappels ci-dessus ne sonneront pas si votre appareil est en mode silencieux ou Ne pas déranger.\n\nIl y a d'autres alertes et alarmes de Pod critiques qui sonneront même si votre appareil est réglé sur mode Silencieux ou Ne pas déranger."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "L'heure de votre pompe est différente de l'heure actuelle. Voulez vous mettre à jour l'heure de votre pompe avec l'heure actuelle ?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "L'heure de votre pompe est différente de l'heure actuelle. L'heure de votre pompe contrôle les paramètres de votre traitement. Faites défiler jusqu'à la ligne Heure de Pompe pour vérifier le décalage de l'heure et configurer votre pompe."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "La fenêtre située sur le dessus du Pod est colorée en rose lorsque la canule est correctement insérée dans la peau."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Il y a eu un problème de communication avec le Pod. Si ce problème persiste, appuyez sur Jeter le pod. Vous pourrez ensuite activer un nouveau Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Ceci est un rappel que vous avez programmé quand vous avez appairé votre Pod actuel."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "Cette pompe n'a pas été configurée avec un débit basal maximal parce qu'il a été rajouté avant que le basal temporaire manuel soit une fonctionnalité. Prière d'aller dans Réglages de thérapie -> Limites d'administration et configurer un nouveau débit basal maximal."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Heure"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Changement d'heure détecté"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Bouton de bascule"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Trop d’entrées"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total administré"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/h"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Impossible de désactiver le Pod. Veuillez continuer et en jumeler un nouveau."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Impossible de joindre le Pod"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Impossible de définir un débit basal temporaire: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Impossible de définir un débit basal temporaire: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Activation inachevée"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Désactivation inachevée"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Inconnu"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Attendez que l'insertion soit terminée."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Oui"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Oui, désactiver le Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Oui, synchroniser avec l'heure actuelle"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Vous allez maintenant commencer à configurer vos rappels, à remplir votre Pod d'insuline, à l'appairer et à le placer sur votre corps."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Votre Pod est prêt à l'emploi. \n\n %1$@ vous rappellera de le remplacer avant qu'il n'expire. Vous pouvez changer ce rappel qui vous convient."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Votre Pod peut encore délivrer de l'insuline.\nRetirez-le de votre corps, puis appuyez sur \"Continuer\"."; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Réduit au silence"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Mode de fonctionnement normal où les bips audio Pod sont utilisés pour toutes les alertes de Pod et quand les rappels de confiance sont activés."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Toutes les alertes de Pod n'utilisent aucun bip et les bips de rappel de confirmation sont supprimés. Le Pod ne sera disponible que pour les défauts fataux du Pod et lors de la lecture des bips de test.\n\n⚠️Warning - Chaque fois que le Pod est réduit au silence, il doit être maintenu à portée Bluetooth de cet appareil pour recevoir des notifications pour les alertes de Pod."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Pod silencieux"; - -/* title for pod details page */ -"Pod Details" = "Détails du Pod"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Détails du Pod précédent"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Détails du Gestionnaire de Pompes"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Récupération des détails du gestionnaire de pompe..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Actualiser les détails du Gestionnaire de Pompe"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Impossible de mettre à jour les préférences de rappel de confiance."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostiques"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Lire l’état de la pompe"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/he.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/he.lproj/Localizable.strings deleted file mode 100644 index 7b7c9b6d6..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/he.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ ago"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (Finished)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ U of %2$@ U (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/hour"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Insulin delivery has stopped. Please deactivate and remove pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 hour"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Active Time"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarms"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Are you sure you want to shutdown this pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Are you sure you want to skip Omnipod Onboarding?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Are you sure you want to stop using Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Assigned Address"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Attach Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Attemping to re-establish communication"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Back"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Basal Delivery"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basal Rates"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Bolus Delivery"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancel"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Cannula inserted successfully. Continue."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Change Time Zone"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Changing time…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Check Cannula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Checking Insertion"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comms Recovered"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced."; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuration"; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Continue"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Critical Alerts"; - -/* Unit for singular day in pod life remaining */ -"day" = "יום"; - -/* Unit for plural days in pod life remaining */ -"days" = "ימים"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Deactivate"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Deactivated"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deactivating..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Delete Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Delivery Limits"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Device Details"; - -/* The title of the device information section in settings */ -"Device Information" = "Device Information"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Devices"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Disable Bolus Beeps"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* No comment provided by engineer. */ -"Done" = "Done"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Enable Bolus Beeps"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Error"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Error disabling bolus beeps"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Error enabling bolus beeps"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Resuming"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspending"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Expired"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Expires"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Failed to update confidence reminder preference."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Failed to Update Expiration Reminder"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Failed to Update Low Reservoir Reminder"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Finish pod setup"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Greater than %1$@ units remaining at %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "שעה"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "שעות"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Insert Cannula"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Inserting. Please wait."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insulin Delivered"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulin Type"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Invalid entry"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Keep the RileyLink about 6 inches from the pod during pairing."; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lot"; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Low Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "דקה"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "דקות"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Next"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "No\nDelivery"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "No Insulin"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "No Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "None"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Notification Settings"; - -/* No comment provided by engineer. */ -"Numbers" = "Numbers"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Button title to pair with pod during setup */ -"Pair" = "Pair"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Pair New Pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Paired"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PI Version"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Play Test Beeps"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Play Test Beeps…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PM Version"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Activated"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Pod Error"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod Expired"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod Expires"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "חסימה בפוד"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Pod Settings"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Primed"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* The text of the loading label when priming */ -"Priming…" = "Priming…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Label text for basal rate summary */ -"Rate" = "Rate"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Remove the Pod's clear needle cap and check cannula. Then remove paper backing."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Replace Pod Now"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Reservoir"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Retry"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Retry Pod Deactivation"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink allows for communication with the pump over Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink Setup"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Save"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Saving..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Schedule"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Select the type of insulin that you will be using in this pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Title for setup complete screen */ -"Setup Complete" = "Setup Complete"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "אובדן אות"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* The title of the status section in settings */ -"Status" = "Status"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Succeeded"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Suspended"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Switch from Omnipod Pumps"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Sync With Pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* The title of the command to run the test command */ -"Test Command" = "Test Command"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Testing Commands…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "האפליקציה מגדירה תזכורת כדי להתריע טרם יושבת הפוד. ניתן לקבוע את מספר השעות לקבלת תזכורת בעת הפעלת פוד חדש."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "האפליקציה מתריעה כאשר כמות האינסולין בפוד מגיעה לרמה זו (50-10 U).\n\nניתן להגדיר מספר יחידות אינסולין לקבלת תזכורת."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "האפליקציה מתריעה כאשר כמות האינסולין בפוד מגיעה לרמה זו."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "התזכורות לא יישמעו אם המכשיר שלך נמצא במצב שקט או 'נא לא להפריע'.\n\nישנן התראות נוספות וקריטיות שיישמעו גם אם המכשיר מוגדר למצב שקט או ׳נא לא להפריע׳."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "השעה במשאבה שלך שונה מהשעה הנוכחית. הגדרות הטיפול נקבעות לפי השעה במשאבה. יש לבדוק את הפרשי הזמן ולעדכן את השעה במשאבה."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "קיימת בעיה בתקשורת עם הפוד. אם הבעיה נמשכת, הקש על השבת פוד, לאחר מכן תוכל לחבר פוד חדש."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "זוהי תזכורת שנקבעה בעת הפעלת הפוד הנוכחי."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "במשאבה זו לא הוגדרה מגבלת בזאלי מרבי, מכיוון שהיא נוספה לפני שהייתה אפשרות בזאלי זמני ידני. יש להגדיר בזאלי מירבי חדש\n(הגדרות טיפול -> מגבלות -> בזאלי מירבי)"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "שעה"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Time Change Detected"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Toggle sign"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Too many entries"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "סה״כ הוזרק"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hr"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "לא ניתן להשבית את הפוד. אנא המשך והצמיד אחד חדש."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "אין תקשורת עם הפוד"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "לא ניתן להגדיר בזאלי זמני:%1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "לא ניתן להגדיר בזאלי זמני: %1$@ \n\n %2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "הפעלה לא הושלמה"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "פעולת ביטול הפוד לא הסתיימה"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Unknown"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "המתן עד להשלמת ההכנסה."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "כן"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "כעת מתחילים בתהליך של הגדרת התזכורות שלך, מילוי הפוד שלך באינסולין, שיוך למכשיר שלך והנחתו על גופך."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "הפוד שלך מוכן לשימוש. \n\n %1$@ יזכיר לך להחליף את הפוד שלך לפני שתוקפו יפוג. אתה יכול לשנות את זה לזמן שנוח לך."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/hi.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/hi.lproj/Localizable.strings deleted file mode 100644 index 9f04c279c..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/hi.lproj/Localizable.strings +++ /dev/null @@ -1,11 +0,0 @@ -/* The title of the cancel action in an action sheet */ -"Cancel" = "निरस्त"; - -/* The title of the continue action in an action sheet */ -"Continue" = "जारी"; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "समय"; - diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/hu.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/hu.lproj/Localizable.strings deleted file mode 100644 index 7503963a0..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/hu.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ ago"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (Finished)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%@ U of %@ U (%@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/hour"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Insulin delivery has stopped. Please deactivate and remove pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 hour"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Active Time"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Riasztások"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Are you sure you want to shutdown this pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Are you sure you want to skip Omnipod Onboarding?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Are you sure you want to stop using Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Assigned Address"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Attach Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Attemping to re-establish communication"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Back"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Basal Delivery"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basal Rates"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Bolus Delivery"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Mégse"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Cannula inserted successfully. Continue."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Change Time Zone"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Changing time…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Check Cannula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Checking Insertion"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comms Recovered"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced."; - -/* The title of the configuration section in settings */ -"Configuration" = "Beállítások"; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Continue"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Critical Alerts"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Deactivate"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Deactivated"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deactivating..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Delete Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Delivery Limits"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Device Details"; - -/* The title of the device information section in settings */ -"Device Information" = "Device Information"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Eszközök"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Disable Bolus Beeps"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* No comment provided by engineer. */ -"Done" = "Kész"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Enable Bolus Beeps"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Error"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Error disabling bolus beeps"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Error enabling bolus beeps"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Resuming"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspending"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Expired"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Expires"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Failed to update confidence reminder preference."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Failed to Update Expiration Reminder"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Failed to Update Low Reservoir Reminder"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Finish pod setup"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Greater than %1$@ units remaining at %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "óra"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Insert Cannula"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Inserting. Please wait."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insulin Delivered"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulin Type"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Invalid entry"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Keep the RileyLink about 6 inches from the pod during pairing."; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lot"; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Low Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "perc"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Next"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nem"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "No\nDelivery"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "No Insulin"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "No Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "None"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Notification Settings"; - -/* No comment provided by engineer. */ -"Numbers" = "Numbers"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Button title to pair with pod during setup */ -"Pair" = "Pair"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Pair New Pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Paired"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PI Version"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Play Test Beeps"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Play Test Beeps…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PM Version"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Activated"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Pod Error"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod Expired"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod Expires"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Pod Settings"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Primed"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* The text of the loading label when priming */ -"Priming…" = "Priming…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Label text for basal rate summary */ -"Rate" = "Rate"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Remove the Pod's clear needle cap and check cannula. Then remove paper backing."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Replace Pod Now"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Reservoir"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Retry"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Retry Pod Deactivation"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink allows for communication with the pump over Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink Setup"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Save"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Saving..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Ütemezés"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Select the type of insulin that you will be using in this pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Title for setup complete screen */ -"Setup Complete" = "Setup Complete"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Signal Loss"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* The title of the status section in settings */ -"Status" = "Status"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Succeeded"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Suspended"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Switch from Omnipod Pumps"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Sync With Pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* The title of the command to run the test command */ -"Test Command" = "Test Command"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Testing Commands…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Idő"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Time Change Detected"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Toggle sign"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Too many entries"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/óra"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Unable to deactivate pod. Please continue and pair a new one."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Unable to Reach Pod"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Ismeretlen"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Igen"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/it.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/it.lproj/Localizable.strings deleted file mode 100644 index 09e488b44..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/it.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ fa"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%1$@ ha ripristinato la comunicazione con il Pod sul tuo corpo.\n\nI dati di somministrazione d'insulina sono stati aggiornati e dovrebbero corrispondere a quanto è stato effettivamente erogato.\n\nOra è possibile continuare a utilizzare %2$@ normalmente."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (Terminato)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ U di %2$@ U (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/ora"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@ %%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ per %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ ha perso la comunicazione con il pod sul suo corpo da %2$@.\n\nSenza comunicazione con il Pod, l'app non può continuare a inviare comandi per la somministrazione d'insulina ne far visualizzare informazioni accurate recenti sull'insulina attiva o sull'insulina erogata dal Pod.\n\nMonitorare attentamente la glicemia per le prossime 6 o più ore, poiché potrebbe esserci o meno insulina attiva nel corpo che %3$@ non è in grado di visualizzare."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unità rimanenti alle ore %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. L’iniezione d'insulina è stata interrotta. Disattiva e rimuovi Pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@ + %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 ora"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 ora e 30 minuti"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 ore"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minuti"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Tempo Attivo"; - -/* Section header for activity section */ -"Activity" = "Attività"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Regolazione Orario Microinfusore..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Allarmi"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Sei sicuro di voler annullare la configurazione del Pod?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Sei sicuro di voler spegnere Pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Sei sicuro di voler saltare la procedura di installazione di Omnipod?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Sei sicuro di voler interrompere l’uso di Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Indirizzo assegnato"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Applicare il Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Tentativo in corso di ristabilire la comunicazione"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Indietro"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Erogazione Basale"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Velocità basali"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Erogazione bolo"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annulla"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Annulla basale manuale"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "La cannula è stata inserita con successo. Continua."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Cambiare il Pod ora. L'erogazione dell'insulina si interromperà dopo 8 ore dalla scadenza del Pod o quando non rimane più insulina nel Pod."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Cambiare Pod ora. L' erogazione d'insulina si interromperà tra %1$@ o quando non ci sarà più insulina nel serbatoio."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Cambia fuso orario"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Modifica ora in corso"; - -/* Title for check cannula screen */ -"Check Cannula" = "Controlla la cannula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Controllare il Pod, applicare sul sito e confermare il fissaggio del pod."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Controllo dell'inserimento"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Controllo in corso"; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comunicazioni recuperate"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Promemoria di fiducia"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "I promemoria di fiducia sono segnali acustici emessi dal Pod che possono essere utilizzati per confermare i comandi selezionati quando il Pod non è silenziato."; - -/* The title of the configuration section in settings */ -"Configuration" = "Configurazione"; - -/* Button title for confirm attachment option */ -"Confirm" = "Conferma"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Conferma collegamento Pod"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Continua"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Avvisi critici"; - -/* Unit for singular day in pod life remaining */ -"day" = "giorno"; - -/* Unit for plural days in pod life remaining */ -"days" = "giorni"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Disattiva"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Disattiva Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Disattivato"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Disattivazione."; - -/* Action button description while deactivating */ -"Deactivating..." = "Disattivazione..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Elimina Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Limiti Erogazione"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Dettagli del dispositivo"; - -/* The title of the device information section in settings */ -"Device Information" = "Informazioni sul dispositivo"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Dispositivi"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Disattiva bip bolo"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Scarta Pod"; - -/* No comment provided by engineer. */ -"Done" = "Fine"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Abilita Bip Bolo"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Errore"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Errore durante la disattivazione dei bip bolo"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Errore durante l’attivazione dei bip bolo"; - -/* The alert title for a resume error */ -"Error Resuming" = "Errore durante la Ripresa"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Errore durante l’interruzione"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Promemoria scadenza"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Promemoria scadenza predef."; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Scaduto"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Scadenza"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Impossibile Cancellare Basale Manuale"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Impossibile riprendere l'erogazione dell'insulina"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Impossibile impostare Orario Microinfusore"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Impossibile Sospendere Erogazione Insulina"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Impossibile aggiornare la preferenza per il promemoria di fiducia."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Impossibile aggiornare Promemoria di Scadenza"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Impossibile aggiornare il Promemoria Livello Serbatoio Basso"; - -/* Pod life HUD view label */ -"Fault" = "Guasto"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Riempire un nuovo Pod con insulina U-100 (lasciare il cappuccio dell'ago Pod). Ascolta 2 segnali acustici."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Completa la disattivazione"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Completa configurazione Pod"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Completa l'installazione"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Più di %1$@ unità rimanenti a %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "ora"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "ore"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Se annulli la configurazione del Pod, il Pod corrente verrà disattivato e sarà inutilizzabile."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Prima di abbinare un nuovo Pod è necessario disattivare i Pod non completamente configurati. Disattiva e rimuovi Pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Prima di abbinare un nuovo Pod è necessario disattivare i Pod non completamente configurati. Disattiva e rimuovi Pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Inserire Cannula"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserito"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Inserimento. Attendere prego."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserimento..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Erogazione Insulina sospesa"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insulina somministrata"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulina Somministrata"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "L'erogazione d'insulina si è interrotta. Cambiare Pod adesso."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "La somministrazione d'insulina verrà interrotta fino a quando non riprenderà manualmente. Quando vuoi che Loop ti ricordi di riprendere la consegna?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulina Rimanente"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Tipo d'insulina"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Immissione non valida"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "La cannula è inserita correttamente?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Tieni il RileyLink a circa 15 cm dal Pod durante l'accoppiamento."; - -/* description label for last status date pod details row */ -"Last Status" = "Ultimo stato"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop non regolerà automaticamente l'erogazione d'insulina fino a quando l'impostazione della basale temporanea non sarà terminata o cancellata."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lotto"; - -/* description label for lot number pod details row */ -"Lot Number" = "Numero di Lotto"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Livello Serbatoio basso"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Promemoria Livello Serbatoio Basso"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Assicurati che il tuo telefono e il Pod siano vicini uno all'altro. Se il problema di comunicazione persiste, spostati in un'altra zona."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minuto"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minuti"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Configurazione mancante"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "Non disponibile"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Prossimo"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Non Erogazione"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Insulina Terminata"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Nessun Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Nessun promemoria"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continuare con il Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, mantienere la pompa così com'è"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Nessuno"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Impostazioni"; - -/* No comment provided by engineer. */ -"Numbers" = "Numeri"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Promemoria Omnipod"; - -/* Button title to pair with pod during setup */ -"Pair" = "Abbina"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Abbina nuovo Pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Abbina Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Abbina Pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Abbinato"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Abbinamento in corso."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Abbinamento in corso..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percentuale = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "Versione PI"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Emetti bip di prova"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Emetti bip di prova..."; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Si prega di confermare che il Pod è saldamente fissato al corpo.\n\nLa cannula può essere inserita una sola volta con ogni Pod. Tocca \"Conferma\" quando Pod è collegato."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Si prega di disattivare il Pod. Al termine della disattivazione, è possibile associare un nuovo Pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Si prega di disattivare il Pod. Al termine della disattivazione, è possibile rimuoverlo e accoppiare un nuovo Pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "Versione PM"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod attivato"; - -/* Label describing pod age view */ -"Pod Age" = "Età Pod"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod disattivato con successo. Continua."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Errore Pod"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod scaduto"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod Scaduto"; - -/* Label for pod expiration row */ -"Pod Expires" = "Scadenza Pod"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod scade in"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Dettagli errore Pod"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Occlusione Pod"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod accoppiato con successo. Continua."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Impostazioni Pod"; - -/* Title for PodSetupView */ -"Pod Setup" = "Configurazione Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Preparare il sito."; - -/* title for previous pod page */ -"Previous Pod" = "Pod precedente"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informazioni Pod precedente"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Caricato"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Caricamento in corso. Attendere prego."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Caricamento in corso..."; - -/* The text of the loading label when priming */ -"Priming…" = "Caricamento in corso..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Orario Micro"; - -/* Label text for basal rate summary */ -"Rate" = "Velocità"; - -/* Label describing time remaining view */ -"Remaining" = "Rimanente"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Rimuovi il Pod dal corpo"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Rimuovere microinfusore"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Rimuovere il cappuccio trasparente dell'ago del Pod e controllare la cannula. Quindi rimuovere le due coperture di carta."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Sostituisci Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Sostituisci Pod adesso"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Serbatoio"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Riprendi Erogazione Insulina"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Ripresa erogazione insulina..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Riprova"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Riprova a disattivare Pod"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink consente la comunicazione con la pompa tramite Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "Configurazione"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Salva"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Salvataggio..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Programma"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Basale Programmata"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Promemoria Programmato"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Seleziona il tipo d'insulina che utilizzerai in questo Pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Numero progressivo"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Impostazione Base Temporanea"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Impostazione Base Temporanea"; - -/* Title for setup complete screen */ -"Setup Complete" = "Impostazione completata"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Perdita Segnale"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Saltare la procedura di installazione di Omnipod?"; - -/* The title of the status section in settings */ -"Status" = "Stato"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Effettuato con successo"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Sospendi erogazione"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Sospendi l'erogazione d'insulina"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Sospeso"; - -/* Label for suspended at time */ -"Suspended At" = "Sospeso a"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Sospendere l'erogazione d'insulina..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Passa a pompe diverse da Omnipod"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Passare ad un altro dispositivo per la somministrazione d'insulina"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sincronizza con l'ora corrente"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Sincronizza con Pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tocca sotto per iniziare l'inserimento della cannula."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Basale Temporanea"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Basale Temporanea Fallita"; - -/* The title of the command to run the test command */ -"Test Command" = "Prova Comando"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Prova Comandi..."; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "L'App puo' configurare un promemoria capace di avvisare in anticipo della scadenza del Pod.\n\nPer impostare il numero di ore preferito per il preavviso dalla voce Omnipod della schermata principale usare i submenu' Configurazione>Impostazioni Notifiche>Notifica Scadenza e sceglire il numero di ore desiderato per l'avviso di scadenza."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "L'App può avvisare in anticipo della scadenza del Pod.\n\nPer impostare il numero di ore in anticipo desiderato scorrere nella lista ore ed impostare il numero di ore desiderato"; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "L'App puo' dare un avviso quando la quantità di insulina nel Pod raggiunge un certo determinato livello compreso fra 50-10 Unita'.\n\nPer impostare questo avviso scorrere nella lista delle Unita' di insulina e scegliere il numero per il quale si desidera ricevere l'avviso."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "L'App puo' avvisare quando la quantità di insulina nel Pod raggiunge un predisposto determinato livello."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "I promemoria qui sopra non suoneranno se il dispositivo è in modalità Silenzioso o Non Disturbare.\n\nCi sono altri avvisi e avvisi di Pod critici che suoneranno anche se il dispositivo è impostato in modalità Silenzioso o Non Disturbare."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "l'orario del microinfusore e' diverso da quello del tempo attuale. Vuoi fare un controllo e cambiare l'orario del microinfusore con il tempo attuale?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "L'orario impostato nel microinfusore è diverso dall'orario corrente. L'orario del microinfusore detta e controlla le impostazioni della terapia programmata e va corretto: Nella lista degli 'orari del microinfusore verificare la differenza di orario e configurare correttamente il microinfusore."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "La finestra nella parte superiore del Pod sara' di colore rosa quando la cannula è stata inserita correttamente nella pelle."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Si è verificato un problema di comunicazione con il Pod. Se il problema persiste, toccare Elimina Pod, e dopo si procedere ad attivare un nuovo Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Questo è un promemoria che hai pianificato quando hai accoppiato il tuo Pod corrente."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "Questo microinfusore non è stato configurato con una dose di basale massima perché questa è stata inserita prima che la basale temporanea manuale diventasse una funzione attiva. Andare su Impostazioni terapia - > Limiti erogazione e impostare un nuovo profilo basale massimo."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Tempo"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Rilevato Cambio di orario "; - -/* No comment provided by engineer. */ -"Toggle sign" = "segnale di attivazione/disattivazione"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Troppe voci"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Erogazione Totale"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/ora"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Impossibile disattivare Pod. Continua e abbina un nuovo Pod."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Impossibile raggiungere Pod"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Impossibile impostare una velocità basale temporanea: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Impossibile impostare una velocità basale temporanea: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Attivazione non completata"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Disattivazione non completata"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Sconosciuto"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Attendere il completamento dell'inserimento."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "sì"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Sì, disattiva il pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Sì, sincronizza con l'ora corrente"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Ora inizierai il processo di configurazione dei tuoi promemoria, riempiendo il tuo Pod d'insulina, accoppiandolo al tuo dispositivo e posizionandolo sul tuo corpo."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Il tuo Pod è pronto per l'uso. \n\n %1$@ ti ricorderà di cambiare il tuo pod prima che scada. Questo orario puo' cambiato per un altro a te piu' conveniente."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Il tuo Pod potrebbe ancora erogare insulina.\n Rimuovilo dal tuo corpo, e poi tocca \"Continua\"."; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenziato"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Modalità di funzionamento normale in cui vengono utilizzati segnali acustici del Pod per tutti gli avvisi Pod e quando i promemoria di fiducia sono abilitati."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Tutti gli avvisi Pod non usano alcun segnale acustico e gli avvisi acustici di conferma vengono soppressi. Il Pod sarà solo beep per difetti di Pod fatali e durante la riproduzione di beep di prova.\n\n⚠️Attenzione - Ogni volta che il Pod viene silenziato, deve essere mantenuto entro la gamma Bluetooth di questo dispositivo per ricevere le notifiche per gli avvisi Pod."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Pod Silenziato"; - -/* title for pod details page */ -"Pod Details" = "Dettagli Pod"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Dettagli Pod Precedente"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Dettagli Microinfusore"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Recupero Dettagli Microinfusore..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Recupero Dettagli Microinfusore"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Impossibile aggiornare la preferenza del Pod silenziato."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostica"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Leggi stato microinfusore"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/ja.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/ja.lproj/Localizable.strings deleted file mode 100644 index 0830d96ed..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/ja.lproj/Localizable.strings +++ /dev/null @@ -1,276 +0,0 @@ -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ 前"; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (完了)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ U of %2$@ U (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/時"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%2$@の時点で %1$@ U 残っています"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@。インスリン注入が止まりました。ポッドを停止して取り外してください。."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "アクティブ時間"; - -/* Section header for activity section */ -"Activity" = "アクティビティ"; - -/* The title of the cell showing alarm status */ -"Alarms" = "アラーム"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "ポッドを終了しますか?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Omnipodの使用を終了しますか?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "割り当てアドレス"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "基礎注入"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "基礎レート"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "ボーラス注入"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "キャンセル"; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "タイムゾーンを変更"; - -/* Progress message for changing pod time. */ -"Changing time…" = "時間を変えています"; - -/* The title of the configuration section in settings */ -"Configuration" = "コンフィグレーション"; - -/* The title of the continue action in an action sheet */ -"Continue" = "次へ"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "無効にする"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "ポッドを無効にする"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "停止されました"; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Omnipodを削除"; - -/* Title text for delivery limits */ -"Delivery Limits" = "注入限度"; - -/* The title of the device information section in settings */ -"Device Information" = "デバイス情報"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "デバイス"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "ボーラス音をオフにする"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "ボーラス音をオンにする"; - -/* Accessibility label indicating an error occurred */ -"Error" = "エラー"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "ボーラス音オフエラー"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "ボーラス音オンエラー"; - -/* The alert title for a resume error */ -"Error Resuming" = "再開エラー"; - -/* The alert title for a suspend error */ -"Error Suspending" = "一時中止エラー"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "有効期限リマインダー"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "期限切れ"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "期限"; - -/* Pod life HUD view label */ -"Fault" = "エラー"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "ポッド設定を終了"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "%2$@時点で %1$@U以上残っています"; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "正しく設定されていないポッドはペアリングの前に停止してください。ポッドを停止して処分してください。"; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "正しく設定されていないポッドはペアリングの前に停止してください。ポッドを停止して処分してください。"; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "カニューレを挿入"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "インスリン注入済み"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "入力が無効です"; - -/* The title of the cell showing the pod lot id */ -"Lot" = "ロット"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "なし"; - -/* Button title to pair with pod during setup */ -"Pair" = "ペアリング"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "新しいポッドをペアリング"; - -/* Label text indicating pairing finished. */ -"Paired" = "ペアリングされました"; - -/* The text of the loading label when pairing */ -"Pairing…" = "ペアリングしています"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PIバージョン"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "警告音をテスト"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "警告音をテストしています"; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PMバージョン"; - -/* Label describing pod age view */ -"Pod Age" = "ポッド経過時間"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "ポッド期限切れ"; - -/* Title of the pod settings view controller */ -"Pod Settings" = "ポッド設定"; - -/* The text of the loading label when pod is primed */ -"Primed" = "プライミング完了"; - -/* Pod pairing action button text while priming */ -"Priming..." = "プライミング中"; - -/* Label describing time remaining view */ -"Remaining" = "残り"; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "ポッドを交換"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "すぐにポッドを交換してください"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Reservoir"; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "やり直す"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "ポッドの停止をやり直す"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink 設定"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "保存"; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "パターン"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "定期基礎"; - -/* Title for setup complete screen */ -"Setup Complete" = "設定完了"; - -/* The title of the status section in settings */ -"Status" = "ステータス"; - -/* A message indicating a command succeeded */ -"Succeeded" = "成功"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "注入を一時停止"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "一時停止"; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Omnipodポンプから変更"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "ポッドとシンク"; - -/* The title of the command to run the test command */ -"Test Command" = "テストコマンド"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "コマンドをテストしています"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "入力過多"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/時"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "ポッドの停止ができません。新しいポッドをペアリングしてください。"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "不明"; - diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/nb.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/nb.lproj/Localizable.strings deleted file mode 100644 index f9feed5eb..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/nb.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ siden"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%1$@ har gjenopprettet kommunikasjonen med pod på kroppen din.\n\nInsulintilførselsjournaler er oppdatert og bør samsvare med det som faktisk ble levert. \n\n Du kan fortsette å bruke %2$@ normalt nå."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ E"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ E (Ferdig)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ E av%2$@ E (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ E/time"; - -/* Appends a full-stop to a statement */ -"%@." = "%@ ."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ E"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ i %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ har ikke vært i stand til å kommunisere med pod på kroppen din siden %2$@ . \n\n Uten kommunikasjon med pod kan ikke appen fortsette å sende kommandoer for insulintilførsel eller vise nøyaktig, fersk informasjon om ditt aktive insulin eller insulinet som leveres av pod. \n\n Overvåk blodsukkerverdi nøye de neste 6 timene eller mer, siden det kan være insulin som virker aktivt i kroppen din som %3$@ ikke kan vise."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ enheter gjenstår ved %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Insulintilførsel har stoppet. Vennligst deaktiver og fjern pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@ + %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g E"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 time"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 time 30 minutter"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 timer"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutter"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Aktiv tid"; - -/* Section header for activity section */ -"Activity" = "Aktivitet"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Justerer pumpetid..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarmer"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Er du sikker på at du vil avbryte Pod-oppsettet?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Er du sikker på at du vil avslutte denne pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Er du sikker på at du vil hoppe over Omnipod Onboarding?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Er du sikker på at du vil slutte å bruke Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Tildelt Adresse"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Fest Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Prøver å gjenopprette kommunikasjonen"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Tilbake"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Basalleveranse"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basal-satser"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Bolus-leveranse"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Avbryt"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Avbryt manuell basal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanyle skutt inn vellykket. Fortsett."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Bytt Pod nå. Insulintilførselen vil stoppe 8 timer etter at pod har utløpt eller når det ikke er mer insulin igjen."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Bytt Pod nå. Insulintilførselen vil stoppe om %1$@ eller når det ikke er mer insulin igjen."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Endre tidssone"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Endrer tid..."; - -/* Title for check cannula screen */ -"Check Cannula" = "Sjekk kanyle"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Sjekk pod, påfør, og bekreft deretter at pod er festet."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Kontrollerer innsetting"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Sjekker..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Kommunikasjon gjenopprettet"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Bekreftelser"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced."; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfigurasjon"; - -/* Button title for confirm attachment option */ -"Confirm" = "Bekreft"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bekreft at Pod er festet"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Fortsett"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritiske varsler"; - -/* Unit for singular day in pod life remaining */ -"day" = "dag"; - -/* Unit for plural days in pod life remaining */ -"days" = "dager"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Deaktiver"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Deaktiver Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Deaktivert"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktiverer."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deaktiverer..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Slett Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Leveringsgrenser"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Enhetsdetaljer"; - -/* The title of the device information section in settings */ -"Device Information" = "Enhetsinformasjon"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Enheter"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Slå av lyd ved bolus"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Kast Pod"; - -/* No comment provided by engineer. */ -"Done" = "Ferdig"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Slå på lyd ved bolus"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Feil"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Kunne ikke slå av lyd ved bolus"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Kunne ikke slå på lyd ved bolus"; - -/* The alert title for a resume error */ -"Error Resuming" = "Feil ved gjenopptagelse"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Kunne ikke stoppe"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Påminnelse om utløp"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Utløpspåminnelse Standard"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Utløpt"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Utløper"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Kunne ikke avbryte manuell basal"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Kunne ikke gjenoppta insulinlevering"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Kunne ikke stille inn klokkeslett for pumpe"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Kunne ikke stanse insulintilførselen"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Kan ikke oppdatere innstillinger for påminnelsesalarm."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Kunne ikke oppdatere Utløpspåminnelse"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Kunne ikke oppdatere påminnelsen om lavt reservoar"; - -/* Pod life HUD view label */ -"Fault" = "Feil"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Fyll en ny pod med U-100 insulin (la kanylehetten være på). Lytt etter 2 pip."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Fullfør deaktivering"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Fullfør oppsett for pod"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Fullfør oppsettet"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Større enn %1$@ enheter igjen ved %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "time"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "timer"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Hvis du avbryter Pod-oppsettet, vil gjeldende Pod deaktiveres og bli ubrukelig."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Ufullstendig oppsatt pod må deaktiveres før sammenkobling med en ny. Vennligst deaktiver og kast pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Ufullstendig oppsatt pod må deaktiveres før sammenkobling med en ny. Vennligst deaktiver og fjern pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Før inn kanyle"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Ført inn"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Fører inn. Vennligst vent."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Fører inn..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulintilførsel utsatt"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Levert insulin"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulintilførsel"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulintilførselen stoppet. Bytt Pod nå."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulintilførselen vil bli stoppet til du gjenopptar manuelt. Når vil du at Loop skal minne deg på å gjenoppta leveringen?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Gjenværende insulin"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulintype"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Ugyldig oppføring"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Er kanylen satt inn riktig?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Hold Rileylink ca. 15 cm fra Pod under sammenkobling."; - -/* description label for last status date pod details row */ -"Last Status" = "Siste status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop vil ikke automatisk justere insulintilførselen før den midlertidige basaldosen er ferdig eller avbrytes."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Parti"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot-nummer"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Lavt reservoar"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Påminnelse om lavt reservoar"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Forsikre deg om at telefonen og pod er nær hverandre. Hvis kommunikasjonsproblemer vedvarer, flytter du til et nytt område."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minutt"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutter"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Mangler Konfigurasjon"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "N/A"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Neste"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nei"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Ingen Leveranse"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Ingen insulin"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Ingen Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Ingen påminnelse"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nei, fortsett med Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nei, behold pumpen som den er"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Ingen"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Varslingsinnstillinger"; - -/* No comment provided by engineer. */ -"Numbers" = "Tall"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod-påminnelser"; - -/* Button title to pair with pod during setup */ -"Pair" = "Koble sammen"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Koble sammen ny pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Par Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Sammenkoble pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Sammenkoblbet"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Kobler sammen."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Kobler sammen..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Prosent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PI Versjon"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Spill test-toner"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Spill test-toner..."; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Vennligst bekreft at pod er godt festet til kroppen din. \n\n Kanylen kan bare settes inn én gang med hver pod. Trykk på \"Bekreft\" når pod er festet."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Vennligst deaktiver pod. Når deaktiveringen er fullført, kan du pare en ny pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Vennligst deaktiver pod. Når deaktiveringen er fullført, kan du fjerne den og pare en ny pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PM Versjon"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Aktivert"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Alder"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod ble deaktivert. Fortsett."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Pod Feil"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod utløpt"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod Utløpt"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod Utløper"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod utløper om"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod-feildetaljer"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Pod Okklusjon"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Vellykket sammenkobling av Pod. Fortsett."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Pod-innstillinger"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod oppsett"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Klargjør infusjonsstedet"; - -/* title for previous pod page */ -"Previous Pod" = "Forrige pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informasjon om forrige pod"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Fyllt"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Fyller. Vennligst vent."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Fyller..."; - -/* The text of the loading label when priming */ -"Priming…" = "Fyller..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pumpetid"; - -/* Label text for basal rate summary */ -"Rate" = "Ratio"; - -/* Label describing time remaining view */ -"Remaining" = "Gjenstående"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Fjern pod fra kroppen"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Fjern pumpen"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Remove the Pod's clear needle cap and check cannula. Then remove paper backing."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Bytt pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Bytt pod nå"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Reservoar"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Gjenoppta insulintilførsel"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Gjenopptar insulintilførsel..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Prøv på nytt"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Prøv igjen å deaktivere pod"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink tillater kommunikasjon med pumpen ved hjelp av Bluetooth."; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink-oppsett"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Lagre"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Lagrer..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Tidsplan"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Planlagt basal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Planlagt påminnelse"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Velg hvilken type insulin du skal bruke i denne pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sekvensnummer"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Still inn midlertidig basal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Still inn midlertidig basaldose"; - -/* Title for setup complete screen */ -"Setup Complete" = "Klargjøring ferdig"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Signal Tap"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Vil du hoppe over Omnipod Introduseringen?"; - -/* The title of the status section in settings */ -"Status" = "Status"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Suksess"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Pause leveranse"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Insulintilførsel utsatt"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Suspendert"; - -/* Label for suspended at time */ -"Suspended At" = "Utsatt klokken"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Utsetter insulintilførselen..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Bytt fra Omnipod pumpe"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Bytt til annen insulintilførselsenhet"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synkroniser til gjeldende tid"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Synkroniser med pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Trykk nedenfor for å starte innsetting av kanyle."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Midlertidig basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Midlertidig basal mislyktes"; - -/* The title of the command to run the test command */ -"Test Command" = "Test kommando"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Tester kommandoer..."; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Appen konfigurerer en påminnelse på pod for å varsle deg før pod utløper. Angi antall timer forhåndsvarsel du vil konfigurere når du parer en ny Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Appen varsler deg før pod utløper.\n\nBla for å angi antall timer forhåndsvarsel du vil ha."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Appen varsler deg når mengden insulin i Pod når dette nivået (50-10 E).\n\nBla for å angi antall enheter du vil bli minnet på."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Appen varsler deg når mengden insulin i pod når dette nivået."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Påminnelsene ovenfor vil ikke høres hvis enheten er i Stille- eller Ikke forstyrr-modus. \n\n Det er andre kritiske Pod-varsler og alarmer som vil høres selv om enheten er satt til Stille eller Ikke forstyrr-modus."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Klokken på pumpen er forskjellig fra gjeldende tid. Vil du oppdatere tiden på pumpen til gjeldende tid?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Klokken på pumpen er forskjellig fra gjeldende tid. Pumpens tid styrer dine planlagte behandlingsinnstillinger. Rull ned til Pumpetid-raden for å se tidsforskjellen og konfigurere pumpen."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Vinduet på toppen av Pod-en skal farges rosa når kanylen er riktig satt inn i huden."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Det oppsto et problem med pod-kommunikasjonen. Hvis problemet fortsetter, trykk Forkaste pod. Deretter kan du aktivere en ny pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dette er en påminnelse som du planla når du koblet til din nåværende pod."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "Denne pumpen er ikke konfigurert med maksimal basaldose fordi den ble lagt til før manuell midlertidig basaldose var en tilgjengelig funksjon. Gå til Behandlingsinnstillinger -> Leveringsgrenser og sett en ny maksimal basaldose."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Tid"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Tidsendring oppdaget"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Vis/skjul"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "For mange oppføringer"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total levering"; - -/* Units for showing temp basal rate */ -"U/hr" = "E/t"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Kunne ikke deaktivere pod. Vennligst fortsett og koble sammen med en ny."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Kan ikke nå pod"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Klarte ikke å angi en midlertidig basal: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Klarte ikke å angi en midlertidig basal: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Ufullstendig aktivering"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Ufullstendig deaktivering"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Ukjent"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Vent til innsettingen er fullført."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, deaktiver Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, Synkroniser til gjeldende tid"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Du vil nå begynne prosessen med å konfigurere påminnelsene, fylle pod med insulin, pare til enheten og plassere den på kroppen."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Pod er klar til bruk. \n\n %1$@ vil minne deg på å bytte pod før den utløper. Du kan endre dette til et tidspunkt som passer deg."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Pod kan fortsatt levere insulin.\nFjern den fra kroppen din, og trykk deretter på \"Fortsett\"."; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/nl.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/nl.lproj/Localizable.strings deleted file mode 100644 index 7be4f70dc..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/nl.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ geleden"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%1$@ heeft de communicatie met de pod op je lichaam hersteld. \n\nDe gegevens over insulinetoediening zijn bijgewerkt en moeten overeenkomen met wat daadwerkelijk is toegediend. \n\nJe kunt %2$@ nu weer normaal gebruiken."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ E"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ E (afgerond)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ E van %2$@ E (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ E/uur"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ E"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ voor %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ kan sinds %2$@ niet communiceren met de pod op je lichaam. \n\nZonder communicatie met de pod kan de app geen opdrachten voor insulinetoediening blijven sturen of nauwkeurige, recente informatie weergeven over je actieve insuline of de insuline die door de pod wordt toegediend. \n\nHoud je glucose de komende 6 uur of langer nauwlettend in de gaten, omdat er wel of geen actieve insuline in je lichaam aanwezig is die %3$@ niet kan weergeven."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ eenheden over om %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Insulinetoediening is gestopt. Deactiveer en vervang pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g E"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 uur"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 uur 30 minuten"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 uur"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minuten"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Werkzame tijd"; - -/* Section header for activity section */ -"Activity" = "Activiteit"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pomptijd aanpassen..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarmen"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Weet je zeker dat je de Podinstallatie wilt annuleren?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Weet je zeker dat je deze pod wilt afsluiten"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Weet je zeker dat je Omnipod Onboarding wilt overslaan?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Weet je zeker dat je wilt stoppen met gebruik Omnipod"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Toegewezen adres"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Pod aanbrengen"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Poging om de communicatie te herstellen"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Terug"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Basaaltoediening"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basaalsnelheden"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Bolustoediening"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuleer"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Annuleer handmatige basaal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Canule succesvol ingebracht. Ga verder."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Vervang Pod nu. De insulinetoediening stop 8 uur nadat de Pod is verlopen of wanneer er geen insuline meer over is."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Vervang Pod nu. De insulinetoediening stop over %1$@ of wanneer er geen insuline meer over is."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Verander tijdzone"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Tijd aanpassen..."; - -/* Title for check cannula screen */ -"Check Cannula" = "Controleer canule"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Controleer de Pod, breng aan op de infusieplaats en bevestig dat de pod goed zit vastgeplakt."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Controleer inbrengen canule"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Controleren..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comms hersteld"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Meldingen met piepjes vanuit de Pod"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Dit zijn meldingen die met piepjes uit de Pod komen en kunnen worden gebruikt ter bevestiging van geselecteerde opdrachten."; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuratie"; - -/* Button title for confirm attachment option */ -"Confirm" = "Bevestigen"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Bevestig vastgeplakte pod"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Ga verder"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritieke meldingen"; - -/* Unit for singular day in pod life remaining */ -"day" = "dag"; - -/* Unit for plural days in pod life remaining */ -"days" = "dagen"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Deactiveer"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Deactiveer Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Gedeactiveerd"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactiveren."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deactiveren..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Verwijder Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Toedieningslimieten"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Apparaatgegevens"; - -/* The title of the device information section in settings */ -"Device Information" = "Apparaat informatie"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Apparaten"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Stop gebruik boluspiepjes"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Gooi pod weg"; - -/* No comment provided by engineer. */ -"Done" = "OK"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Boluspiepjes inschakelen"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Fout"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Fout in stoppen gebruik boluspiepjes"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Fout in toepassen gebruik boluspiepjes"; - -/* The alert title for a resume error */ -"Error Resuming" = "Fout bij hervatten"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Fout bij onderbreken"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Melding vervaldatum"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standaard herinnering"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Verlopen"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Vervalt"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Handmatig basaal annuleren mislukt"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Insulinetoediening hervatten mislukt"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Pomptijd instellen mislukt"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Insulinetoediening onderbreken mislukt"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Voorkeuren voor bijwerken van herrineringsmeldingen is mislukt."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Vervaldatumherinnering bijwerken mislukt"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Bijwerken reservoir bijna leeg herinnering mislukt"; - -/* Pod life HUD view label */ -"Fault" = "Fout"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Vul een nieuwe pod met U-100 insuline (laat de Podnaalddop zitten). Luister naar 2 piepjes."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Voltooi deactivering"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Rond Pod installatie af"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Voltooi setup"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Meer dan %1$@ eenheden resterend om %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "uur"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "uur"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Als je de Podinstallatie annuleert, wordt de huidige Pod gedeactiveerd en onbruikbaar."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Een Pod die gedeeltelijk is ingesteld, moet eerst worden uitgeschakeld voordat je probeert een nieuwe pod te koppelen. Deactiveer de Pod uit en gooi hem weg."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Een niet compleet ingestelde Pod, moet eerst worden uitgeschakeld voordat je probeert een nieuwe pod te koppelen. Deactiveer de Pod uit en gooi hem weg."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Canule inbrengen"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Ingebracht"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Aan het inbrengen. Wacht even."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Canule wordt ingebracht..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insuline\nOnderbroken"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Geleverde insuline"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulinetoediening"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulinetoediening gestopt. Vervang Pod nu."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "De insulinetoediening wordt gestopt totdat je de toediening handmatig hervat. Wanneer wil je dat Loop je eraan herinnert de toediening te hervatten?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Resterende insuline"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insuline soort"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Ongeldige invoer"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Is de canule juist ingebracht?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Houd de RileyLink tijdens het koppelen ongeveer 15 cm van de pod verwijderd."; - -/* description label for last status date pod details row */ -"Last Status" = "Laatste Status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop past je insulinetoediening niet meer automatisch aan totdat de tijdelijke basaalsnelheid afloopt of wordt geannuleerd."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lot"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lotnummer"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Reservoir Bijna Leeg"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Herinnering 'Reservoir bijna leeg'"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Zorg ervoor dat je iPhone en Pod zich dicht bij elkaar bevinden. Als de communicatieproblemen aanhouden, ga dan naar een andere plek."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minuut"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minuten"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Configuratie niet compleet"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NB"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Volgende"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nee"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Geen\nToediening"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Geen insuline"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Geen Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Geen herinnering"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nee, ga verder met Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nee, laat de pomp ongewijzigd"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Geen"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Meldingsinstellingen"; - -/* No comment provided by engineer. */ -"Numbers" = "Nummers"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod herinneringen"; - -/* Button title to pair with pod during setup */ -"Pair" = "Koppel"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Koppel nieuwe Pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Koppel Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Koppel Pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Gekoppeld"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Koppelen."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Koppelen…"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Procent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PI versie"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Testpiepjes afspelen"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Speelt testpiepjes…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Controleer of de Pod goed op je lichaam vastgeplakt zit.\n\nDe canule kan slechts één keer per Pod worden ingebracht. Tik op \"Bevestigen\" wanneer de Pod is vastgeplakt."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Deactiveer de pod. Wanneer de deactivering voltooid is, kun je een nieuwe pod koppelen."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Deactiveer de pod. Wanneer de deactivering voltooid is, kun je deze verwijderen en een nieuwe pod koppelen."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PM versie"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod geactiveerd"; - -/* Label describing pod age view */ -"Pod Age" = "Podleeftijd"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod succesvol gedeactiveerd. Ga verder."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Podfout"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod is verlopen"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod verlopen"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod verloopt"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod verloopt over"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod foutgegevens"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Podverstopping"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod succesvol gekoppeld. Ga verder."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Pod instellingen"; - -/* Title for PodSetupView */ -"Pod Setup" = "Podinstallatie"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Infusieplaats voorbereiden."; - -/* title for previous pod page */ -"Previous Pod" = "Vorige Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informatie vorige Pod"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Voorbereid"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Voorbereiden. Wacht even."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Voorbereiden..."; - -/* The text of the loading label when priming */ -"Priming…" = "Voorbereiden..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pomptijd"; - -/* Label text for basal rate summary */ -"Rate" = "Snelheid"; - -/* Label describing time remaining view */ -"Remaining" = "Resterend"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Verwijder Pod van lichaam"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Verwijder Pomp"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Verwijder de transparante naalddop van de Pod en controleer de canule. Verwijder vervolgens de beschermlaag van de hechtstrip."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Vervang Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Vervang Pod nu"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Reservoir"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Hervat insulinetoediening"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Insulinetoediening hervatten..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Opnieuw proberen"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Probeer deactivering Pod opnieuw"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink staat communicatie met de pomp toe via Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink setup"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Opslaan"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Opslaan..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Schema"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Ingesteld basaal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Geplande melding"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Selecteer het type insuline dat je in deze pod gaat gebruiken."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Volgnummer"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Tijdelijk basaal instellen"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Tijdelijke Basaalsnelheid Instellen"; - -/* Title for setup complete screen */ -"Setup Complete" = "Setup voltooid"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Signaalverlies"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Omnipod Onboarding overslaan?"; - -/* The title of the status section in settings */ -"Status" = "Status"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Geslaagd"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Onderbreek toediening"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Onderbreek insulinetoediening"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Onderbroken"; - -/* Label for suspended at time */ -"Suspended At" = "Onderbroken om"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Insulinetoediening onderbreken..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Verwissel Omnipod pompen"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Schakel over op een ander insulinetoedieningsapparaat"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchroniseer met de huidige tijd"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Synchroniseer met pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tik hieronder om het inbrengen van de canule te starten."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Tijdelijke basaal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Tijdelijk basaal mislukt"; - -/* The title of the command to run the test command */ -"Test Command" = "Testcommando"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Commando’s aan het testen..."; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "iAPS configureert melding op de Pod om je op de hoogte te stellen wanneer de Pod verloopt. Stel het aantal uren vooraf in dat je standaard wilt instellen als je een nieuwe Pod koppelt."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "iAPS geeft een melding als de Pod verloopt.\n\nScroll om het aantal uren in te stellen voor de gewenste vooraankondiging."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "iAPS geeft een melding wanneer de hoeveelheid insuline in de Pod dit niveau bereikt (50-10 E).\n\nScroll om het aantal eenheden in te stellen waarbij je herinnerd wilt worden."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "iAPS geeft een melding wanneer de hoeveelheid insuline in de Pod dit niveau bereikt."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Als je apparaat stil is of in de Niet storen-modus staat, hoor je de bovenstaande herinneringen niet in de app. Er zijn echter andere belangrijke waarschuwingen voor de Pod die nog steeds in de app verschijnen, zelfs als je apparaat stil is of in de Niet storen-modus staat. De Pod maakt ook geluid met piepjes voor alle herinneringen en waarschuwingen, behalve als de Pod is uitgeschakeld."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "De tijd op je pomp is anders dan de huidige tijd. Wil je de tijd op je pomp bijwerken naar de huidige tijd?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "De tijd op je pomp is anders dan de huidige tijd. De tijd van je pomp bepaalt je geplande therapieinstellingen. Scroll omlaag naar de Pomptijd om het tijdsverschil te bekijken en de pomp te configureren."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Het venster aan de bovenkant van de pod moet roze gekleurd zijn wanneer de canule correct in de huid is ingebracht."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Er is een communicatieprobleem opgetreden met de pod. Als dit probleem zich blijft voordoen, tik op 'Pod verwijderen'. Je kunt dan een nieuwe Pod activeren."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Dit is een herinnering die je hebt gepland toen je je huidige Pod koppelde."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "Deze pomp is niet geconfigureerd met een maximale basaalsnelheid omdat deze toegevoegd is voordat het handmatig instellen van een tijdelijke basaalsnelheid een functie was. Ga naar Therapieinstellingen -> Toedieningslimieten en stel een nieuwe Maximale Basaalsnelheid in."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Tijd"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Tijdsverschil ontdekt"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Schakel symbool"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Te veel invoer"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Totaal toegediend"; - -/* Units for showing temp basal rate */ -"U/hr" = "E/uur"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Onmogelijk om pod te deactiveren. Ga verder en koppel een nieuwe pod."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Kan Pod niet bereiken"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Kan geen tijdelijke basaalsnelheid instellen: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Kan geen tijdelijke basaalsnelheid instellen: %1$@ \n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Onvoltooide activering"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Onvoltooide deactivering"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Onbekend"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wacht tot het inbrengen voltooid is."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, deactiveer Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, synchroniseer met huidige tijd"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Je begint nu met het configureren van je herinneringen, het vullen van je Pod met insuline, het koppelen van je apparaat en het op je lichaam plaatsen."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Je Pod is klaar voor gebruik.\n\niAPS (%1$@) zal je eraan herinneren je pod te vervangen voordat deze verloopt. Je kunt dit wijzigen naar een tijdstip dat beter uitkomt."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Je Pod kan nog steeds insuline toedienen.\nVerwijder de Pod van je lichaam en tik vervolgens op \"Ga Verder\"."; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Gedempt"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normale bewerkingsmodus waarbij hoorbare piepjes worden gebruikt voor alle Pod waarschuwingen en wanneer meldingen zijn ingeschakeld."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Alle Pod alarmen gebruiken geen piepjes en herinneringen worden gedempt. De Pod zal alleen piepen bij fatale Pod fouten en bij testpiepen.\n\n⚠️Waarschuwing - Wanneer de Pod is gedempt, moet het binnen het Bluetooth-bereik van dit apparaat worden gehouden om meldingen voor Pod te ontvangen."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Gedempt"; - -/* title for pod details page */ -"Pod Details" = "Pod details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Vorige Pod details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pomp manager details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Pomp manager gegevens ophalen..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Ververs details pompmanager"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Kon de voorkeur voor meldingen niet bijwerken."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostische gegevens"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Lees pompstatus"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/pl.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/pl.lproj/Localizable.strings deleted file mode 100644 index 8eee00341..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/pl.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ temu"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%1$@ odzyskał łączność z POD'em, na twoim ciele. \n\nLogi podawania insuliny zostały zaktualizowane i powinny być zgodne z faktycznie podanymi. \n\nMożesz nadal normalnie używać %2$@ ."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ J"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ J (zakończone)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ J z %2$@ J (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ J/godzina"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ J"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@J"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ za %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ nie może komunikować się z POD'em na twoim ciele od %2$@ . \n\nBez komunikacji z POD'em aplikacja nie może wysyłać poleceń podania insuliny ani wyświetlać dokładnych, aktualnych informacji o aktywnej insulinie lub insulinie podawanej przez POD'a. \n\nUważnie monitoruj poziom glukozy przez następne 6 lub więcej godzin, ponieważ w organizmie może działać insulina, której %3$@ nie może wyświetlić."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ jednostek pozostaje w %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Podawanie insuliny zostało zatrzymane. Deaktywuj i zdejmij PODa"; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g/J"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 godzina"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 godzina 30 minut"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 godziny"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minut"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Czas aktywności"; - -/* Section header for activity section */ -"Activity" = "Aktywność"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Synchronizacja czasu pompy..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarmy"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Czy na pewno chcesz anulować konfigurację POD'a?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Czy na pewno chcesz wyłączyć tego PODa?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Czy na pewno chcesz pominąć instalację Omnipod’a?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Czy na pewno chcesz przestać korzystać z Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Przypisany adres"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Przyklej POD'a do ciała"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Próba przywrócenia komunikacji"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Powrót"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Podawanie dawki podstawowej"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Dawka Podstawowa (Baza)"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Podawanie bolusa"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Anuluj"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Anuluj ręczną dawkę podstawową"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kaniula wprowadzona prawidłowo. Kontynuuj."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Zmień POD teraz. Podawanie insuliny zostanie zatrzymane 8 godzin po wygaśnięciu POD'a lub gdy zabraknie insuliny."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Zmień POD. Podawanie insuliny zostanie zatrzymane za %1$@ lub gdy zabraknie insuliny."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Zmień strefę czasową"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Zmiana czasu…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Sprawdź kaniulę"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Przyklej POD'a, następnie potwierdź jego założenie"; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Sprawdzanie wkłucia"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Sprawdzanie..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Odzyskano komunikację"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Przypomnienia (sygnały dźwiękowe) z POD'a"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced."; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfiguracja"; - -/* Button title for confirm attachment option */ -"Confirm" = "Potwierdź"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Potwierdź założenie POD'a"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Kontynuuj"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Alerty krytyczne"; - -/* Unit for singular day in pod life remaining */ -"day" = "dzień"; - -/* Unit for plural days in pod life remaining */ -"days" = "dni"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Dezaktywuj"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Dezaktywuj POD'a"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Deaktywowany"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Dezaktywacja."; - -/* Action button description while deactivating */ -"Deactivating..." = "Dezaktywacja..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Usuń Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Limity podawania"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Szczegóły urządzenia"; - -/* The title of the device information section in settings */ -"Device Information" = "Informacje o urządzeniu"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Urządzenia"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Wyłącz dźwięki bolusa"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Odrzuć POD'a"; - -/* No comment provided by engineer. */ -"Done" = "Gotowe"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Włącz dźwięki bolusa"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Błąd"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Błąd wyłączania dźwięków bolusa"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Błąd włączania dźwięków bolusa"; - -/* The alert title for a resume error */ -"Error Resuming" = "Błąd wznawiania"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Błąd wstrzymywania"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Termin Ważności"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Domyślne przypomnienie o terminie ważności"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Po terminie"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Upływa termin ważności"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Nie udało się anulować dawki podstawowej ustawionej ręcznie"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Nie udało się wznowić podawania insuliny"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Nie udało się ustawić czasu pompy"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Nie udało się wstrzymać podawania insuliny"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Błąd aktualizacji ustawień dla przypomnień."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Nie udało się zaktualizować przypomnienia o terminie ważności"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Nie udało się zaktualizować przypomnienia o niskim poziomie w zbiorniczku"; - -/* Pod life HUD view label */ -"Fault" = "Usterka"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Napełnij nowego POD'a insuliną U-100 (minimum 80j). Pozostaw niebieską osłonkę igły. Powinieneś usłyszeć dwa sygnały dźwiękowe."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Zakończ dezaktywację"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Zakończ konfigurację PODa"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Zakończ konfigurację"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Więcej niż %1$@ jedn. pozostaje w %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "godzina"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "godziny"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Jeśli anulujesz konfigurację POD'a, bieżący POD zostanie dezaktywowany i nie będzie można go używać."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Niekompletną konfigurację PODa należy deaktywować przed sparowaniem z nowym. Deaktywuj i wyrzuć PODa."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Niekompletną konfigurację PODa należy deaktywować przed sparowaniem z nowym. Deaktywuj i usuń PODa."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Wprowadź kaniulę"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Wprowadzono"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Wprowadzanie. Proszę czekać."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Wprowadzanie..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Podawanie insuliny zawieszone"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insulina podana"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Podawanie insuliny zostało zatrzymane. Wymień POD'a."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Podawanie insuliny zostanie wstrzymane do czasu ręcznego wznowienia. Kiedy chcesz, aby Loop przypomniał Ci o wznowieniu podawania insuliny?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Pozostała ilość insuliny"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Rodzaj insuliny"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Nieprawidłowy wpis"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Czy kaniula jest prawidłowo wprowadzona?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Trzymaj RileyLink około 15 cm od POD'a podczas parowania."; - -/* description label for last status date pod details row */ -"Last Status" = "Ostatni status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Pętla nie będzie automatycznie dostosowywać dawki insuliny, dopóki tymczasowa dawka podstawowa nie zakończy się lub nie zostanie anulowana."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Partia"; - -/* description label for lot number pod details row */ -"Lot Number" = "Numer LOT"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Niski poziom w zbiorniczku"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Przypomnienie o niski poziomie w zbiorniczku"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Upewnij się, że telefon i POD znajdują się blisko siebie. Jeśli problemy z komunikacją nie ustąpią, przenieś się w inne miejsce."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minuta"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minuty"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Brak konfiguracji"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "Niedostępne"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Następny"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nie"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Brak podawania"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Brak insuliny"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Brak POD'a"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Brak przypomnienia"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nie, kontynuuj parowanie z POD'em"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nie, pozostaw pompę bez zmian"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Brak"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Ustawienia powiadomień"; - -/* No comment provided by engineer. */ -"Numbers" = "Liczby"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Przypomnienia Omnipod"; - -/* Button title to pair with pod during setup */ -"Pair" = "Paruj"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Sparuj nowego PODa"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Sparuj POD'a"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Sparuj POD'a"; - -/* Label text indicating pairing finished. */ -"Paired" = "Sparowany"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Parowanie."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Parowanie…"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Procent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "Wersja PI"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Odtwarzaj dźwięki testu"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Odtwarzaj dźwięki testu…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Potwierdź, że POD jest poprawnie przymocowany do ciała. \n\nKaniulę można wprowadzić tylko raz w każdym POD'dzie. Stuknij „Potwierdź”, gdy POD jest przymocowany."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Proszę dezaktywować POD'a. Po zakończeniu dezaktywacji możesz sparować nowego POD'a."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Proszę dezaktywować POD'a. Po zakończeniu dezaktywacji usuń POD'a i sparuj nowego."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "Wersja PM"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "POD aktywowany"; - -/* Label describing pod age view */ -"Pod Age" = "Wiek POD'a"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "POD został dezaktywowany pomyślnie. Kontynuować."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Błąd POD'a"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Termin ważności POD'a upłynął"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Termin ważności POD'a upłynął"; - -/* Label for pod expiration row */ -"Pod Expires" = "POD kończy działanie"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "POD wygasa za"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Szczegóły usterki POD'a"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Niedrożność POD'a"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod został pomyślnie sparowany. Kontynuować."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Ustawienia PODa"; - -/* Title for PodSetupView */ -"Pod Setup" = "Konfiguracja POD'a"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Przygotuj miejsce"; - -/* title for previous pod page */ -"Previous Pod" = "Poprzedni POD"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informacje o poprzednim POD'dzie"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Napełniony"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Wypełnianie. Proszę czekać."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Wypełnianie..."; - -/* The text of the loading label when priming */ -"Priming…" = "Napełnianie…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Czas pompy"; - -/* Label text for basal rate summary */ -"Rate" = "Tempo"; - -/* Label describing time remaining view */ -"Remaining" = "Pozostało"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Usuń POD'a z ciała"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Usuń pompę"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Remove the Pod's clear needle cap and check cannula. Then remove paper backing."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Wymień POD'a"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Wymień PODa teraz"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Zbiorniczek"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Wznów podawanie insuliny"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Wznawianie podawania insuliny..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Spróbuj ponownie"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Ponów deaktywację PODa"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink umożliwia komunikację z pompą przez Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "Konfiguracja RileyLink"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Zapisz"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Zapisywanie..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Harmonogram"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Zaplanowana dawka podstawowa"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Zaplanowane przypomnienie"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Wybierz rodzaj insuliny, której będziesz używać w tym POD."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Numer sekwencji"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Ustaw Bazę Tymczasową"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Ustaw tymczasową dawkę podstawową"; - -/* Title for setup complete screen */ -"Setup Complete" = "Konfiguracja zakończona"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Utrata sygnału"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Pominąć instalację Omnipod’a?"; - -/* The title of the status section in settings */ -"Status" = "Status"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Zakończone powodzeniem"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Wstrzymaj podawanie"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Wstrzymaj podawanie insuliny"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Wstrzymane"; - -/* Label for suspended at time */ -"Suspended At" = "Zawieszony o godz."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Wstrzymanie podawania insuliny..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Przełącz z pomp Omnipod"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Zmień pompę insulinową na inną"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchronizuj z bieżącym czasem"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Synchronizuj z PODem"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Stuknij poniżej, aby rozpocząć wprowadzanie kaniuli."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Baza tymczasowa"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Baza tymczasowa nie powiodła się"; - -/* The title of the command to run the test command */ -"Test Command" = "Polecenie testowe"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Testowanie poleceń…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Aplikacja konfiguruje przypomnienie w POD, aby powiadomić Cię z wyprzedzeniem o wygaśnięciu ważności POD'a. Ustaw liczbę godzin wyprzedzenia, które chcesz skonfigurować podczas parowania nowego POD'a."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Aplikacja z wyprzedzeniem powiadomi użytkownika o wygaśnięciu ważności POD'a.\n\nZaplanuj powiadomienie (wybierz liczbę godzin)."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Aplikacja powiadomi Cię, gdy ilość insuliny w POD osiągnie poziom (50-10 J). \n\nUstaw liczbę jednostek, przy których chcesz otrzymywać przypomnienia."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Aplikacja powiadomi Cię, gdy ilość insuliny w POD osiągnie ten poziom."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Powyższe przypomnienia nie będą się pojawiały, jeśli urządzenie jest w trybie cichym lub nie przeszkadzać. \n\nIstnieją inne krytyczne alerty i alarmy POD'ów, które będą emitowane, nawet jeśli urządzenie jest ustawione w trybie cichym lub nie przeszkadzać."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Czas na pompie różni się od aktualnego czasu. Czy chcesz zaktualizować czas na pompie do aktualnego czasu?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Czas na pompie różni się od aktualnego czasu. Czas pompy steruje ustawieniami zaplanowanej terapii. Przewiń w dół do wiersza Czas pompy, aby przejrzeć różnicę czasu i skonfigurować pompę."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Okienko na górze POD'a powinno zabarwić się na różowo, gdy kaniula jest prawidłowo wprowadzona pod skórę."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Wystąpił problem z komunikacją z POD'em. Jeśli problem się utrzymuje, wybierz opcję Odrzuć POD'a. Następnie możesz aktywować nowy POD."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "To jest przypomnienie, które zaplanowałeś podczas parowania bieżącego Poda."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "Limit podaży został ustawiony przed wprowadzeniem bazy tymczasowej. Wróć do ustawień terapii i ustaw nowy limit maksymalnej dawki podstawowej (bazy)."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Czas"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Wykryto zmianę czasu"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Przełącz znak"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Zbyt dużo wpisów"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Łącznie podano"; - -/* Units for showing temp basal rate */ -"U/hr" = "J/godz"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Deaktywacja PODa niemożliwa. Kontynuuj i sparuj nowy."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Nie można połączyć się z Podem"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Nie można ustawić tymczasowej dawki podstawowej: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Nie można ustawić tymczasowej dawki podstawowej: %1$@ \n\n %2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Niedokończona aktywacja"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Niedokończona dezaktywacja"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Nieznany"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Poczekaj, aż wprowadzanie zostanie zakończone."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Tak"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Tak, dezaktywuj POD'a"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Tak, zsynchronizuj z bieżącym czasem"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Rozpoczynasz proces konfigurowania przypomnień (dźwięków emitowanych przez POD'a), napełniania POD'a insuliną, parowania z telefonem i umieszczania go na ciele."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Twój POD jest gotowy do użycia. \n\n%1$@ przypomni Ci o zmianie POD'a przed jego wygaśnięciem. Możesz dokonać zmiany na dogodny dla Ciebie termin."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Twój POD może nadal dostarczać insulinę.\nUsuń go z ciała, a następnie wybierz \"Kontynuuj\"."; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/pt-BR.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/pt-BR.lproj/Localizable.strings deleted file mode 100644 index e888aa5a4..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ atrás"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (Completo)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ U do %2$@ U (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/hora"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unidades restantes em %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. A administração de insulina parou. Desative e remova o pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 hour"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Tempo Ativo"; - -/* Section header for activity section */ -"Activity" = "Atividade"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarmes"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Tem certeza de que deseja encerrar este pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Are you sure you want to skip Omnipod Onboarding?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Tem certeza de que deseja parar de usar o Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Endereço Atribuído"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Attach Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Attemping to re-establish communication"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Back"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Entrega Basal"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Taxas Basais"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Entrega de Bolus"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancelar"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Cannula inserted successfully. Continue."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Alterar Fuso Horário"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Alterando a hora..."; - -/* Title for check cannula screen */ -"Check Cannula" = "Check Cannula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Checking Insertion"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comms Recovered"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced."; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuração"; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Continuar"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Critical Alerts"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Desativar"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Desativar Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Desativado"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deactivating..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Remover Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Limites de Entrega"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Device Details"; - -/* The title of the device information section in settings */ -"Device Information" = "Informação do Dispositivo"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Dispositivos"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Desativar Bipes de Bolus"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* No comment provided by engineer. */ -"Done" = "OK"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Ativar bipes de bolus"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Erro"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Erro ao desativar bipes de bolus"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Erro ao ativar bipes de bolus"; - -/* The alert title for a resume error */ -"Error Resuming" = "Erro ao Retomar"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Erro ao Suspender"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Lembrete de Expiração"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Expirada"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Expira"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Failed to update confidence reminder preference."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Failed to Update Expiration Reminder"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Failed to Update Low Reservoir Reminder"; - -/* Pod life HUD view label */ -"Fault" = "Falha"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Concluir configuração do pod"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Mais de %1$@ unidades restantes em %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "horas"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Pod de configuração incompleta deve ser desativado antes de emparelhar com um novo. Desative e descarte o pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Pod de configuração incompleta deve ser desativado antes de emparelhar com um novo. Desative e remova o pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Inserir Cânula"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Inserting. Please wait."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insulina Entregue"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Tipo de Insulina"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Entrada inválida"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Keep the RileyLink about 6 inches from the pod during pairing."; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lot"; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Low Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutos"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Next"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "No\nDelivery"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "No Insulin"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "No Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Nenhum"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Notification Settings"; - -/* No comment provided by engineer. */ -"Numbers" = "Numbers"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Button title to pair with pod during setup */ -"Pair" = "Emparelhar"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Emparelhe um Novo Pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Emparelhado"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "Versão PI"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Tocar bipes de teste"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Tocar bipes de teste…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "Versão PM"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Activated"; - -/* Label describing pod age view */ -"Pod Age" = "Idade do Pod"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Pod Error"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expirado"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod Expired"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod Expires"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Configurações do Pod"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Preparado"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* The text of the loading label when priming */ -"Priming…" = "Preparando…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Label text for basal rate summary */ -"Rate" = "Taxa"; - -/* Label describing time remaining view */ -"Remaining" = "Restante"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Remove the Pod's clear needle cap and check cannula. Then remove paper backing."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Substituir Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Substituir Pod Agora"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Reservoir"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Tentar de Novo"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Retentar Desativação do Pod"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink allows for communication with the pump over Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "Configuração RileyLink"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Salvar"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Salvando..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Agendada"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Basal Agendado"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Select the type of insulin that you will be using in this pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Title for setup complete screen */ -"Setup Complete" = "Instalação Concluída"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Signal Loss"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* The title of the status section in settings */ -"Status" = "Estado"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Completo"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspender Entrega"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Suspenso"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Mudar de Bombas Omnipod"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Sincronizar com o Pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* The title of the command to run the test command */ -"Test Command" = "Testar Comando"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Testando Comandos…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Hora"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Time Change Detected"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Toggle sign"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Muitas entradas"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hr"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Não foi possível desativar o pod. Continue e emparelhe um novo."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Unable to Reach Pod"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Desconhecido"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/pt-PT.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/pt-PT.lproj/Localizable.strings deleted file mode 100644 index 62cc7db41..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/pt-PT.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ ago"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (Finished)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%@ U of %@ U (%@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/hour"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Insulin delivery has stopped. Please deactivate and remove pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 hour"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hours"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Active Time"; - -/* Section header for activity section */ -"Activity" = "Activity"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarms"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Are you sure you want to cancel Pod setup?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Are you sure you want to shutdown this pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Are you sure you want to skip Omnipod Onboarding?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Are you sure you want to stop using Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Assigned Address"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Attach Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Attemping to re-establish communication"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Back"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Basal Delivery"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basal Rates"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Bolus Delivery"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancelar"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Cannula inserted successfully. Continue."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Change Time Zone"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Changing time…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Check Cannula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Check Pod, apply to site, then confirm pod attachment."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Checking Insertion"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comms Recovered"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced."; - -/* The title of the configuration section in settings */ -"Configuration" = "Ajustes"; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirm"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirm Pod Attachment"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Continue"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Critical Alerts"; - -/* Unit for singular day in pod life remaining */ -"day" = "day"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Deactivate"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Deactivate Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Deactivated"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deactivating."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deactivating..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Delete Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Delivery Limits"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Device Details"; - -/* The title of the device information section in settings */ -"Device Information" = "Device Information"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Dispositivos"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Disable Bolus Beeps"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Discard Pod"; - -/* No comment provided by engineer. */ -"Done" = "OK"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Enable Bolus Beeps"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Error"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Error disabling bolus beeps"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Error enabling bolus beeps"; - -/* The alert title for a resume error */ -"Error Resuming" = "Error Resuming"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Error Suspending"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Expiration Reminder"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Expired"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Expires"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Failed to Cancel Manual Basal"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Failed to Resume Insulin Delivery"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Failed to Set Pump Time"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Failed to update confidence reminder preference."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Failed to Update Expiration Reminder"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Failed to Update Low Reservoir Reminder"; - -/* Pod life HUD view label */ -"Fault" = "Fault"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finish deactivation"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Finish pod setup"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finish Setup"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Greater than %1$@ units remaining at %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hour"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "horas"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "If you cancel Pod setup, the current Pod will be deactivated and will be unusable."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Insert Cannula"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserted"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Inserting. Please wait."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insulin Delivered"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin Remaining"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulin Type"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Invalid entry"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Is the cannula inserted properly?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Keep the RileyLink about 6 inches from the pod during pairing."; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lot"; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Low Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minute"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minutos"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Next"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "No\nDelivery"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "No Insulin"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "No Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "No, Continue With Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "None"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Notification Settings"; - -/* No comment provided by engineer. */ -"Numbers" = "Numbers"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Button title to pair with pod during setup */ -"Pair" = "Pair"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Pair New Pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pair pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Paired"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Pairing."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Pairing..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PI Version"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Play Test Beeps"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Play Test Beeps…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may pair a new pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PM Version"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Activated"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Age"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deactivated successfully. Continue."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Pod Error"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod expired"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod Expired"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod Expires"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expires in"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod paired successfully. Continue."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Pod Settings"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Prepare site."; - -/* title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Primed"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Priming. Please wait."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* The text of the loading label when priming */ -"Priming…" = "Priming…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Label text for basal rate summary */ -"Rate" = "Taxa"; - -/* Label describing time remaining view */ -"Remaining" = "Remaining"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Remove Pod from Body"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Remove the Pod's clear needle cap and check cannula. Then remove paper backing."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Replace Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Replace Pod Now"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Reservoir"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Retry"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Retry Pod Deactivation"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink allows for communication with the pump over Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink Setup"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Salvar"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Salvando..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Agenda"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Scheduled Basal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Select the type of insulin that you will be using in this pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Title for setup complete screen */ -"Setup Complete" = "Setup Complete"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Signal Loss"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* The title of the status section in settings */ -"Status" = "Status"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Succeeded"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspend Delivery"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspend Insulin Delivery"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Suspended"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Switch from Omnipod Pumps"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Sync With Pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tap below to start cannula insertion."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* The title of the command to run the test command */ -"Test Command" = "Test Command"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Testing Commands…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Hora"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Time Change Detected"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Toggle sign"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Too many entries"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/hr"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Unable to deactivate pod. Please continue and pair a new one."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Unable to Reach Pod"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Unfinished Activation"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Unfinished deactivation"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Unknown"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Wait until insertion is completed."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Yes, Deactivate Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/ro.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/ro.lproj/Localizable.strings deleted file mode 100644 index 181c0100a..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/ro.lproj/Localizable.strings +++ /dev/null @@ -1,772 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ în urmă"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%1$@ a restabilit comunicarea cu Pod-ul de pe corpul tău. \n\n Înregistrările privind administrarea de insulină au fost actualizate și ar trebui să se potrivească cu ceea ce a fost administrat efectiv. \n\n Puteți continua să utilizați %2$@ în mod normal acum."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (finalizat)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ U din %2$@ U (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/oră"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ pentru %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ nu a putut comunica cu Pod-ul de pe corpul tău de la %2$@.\n\nÎn lipsa comunicației cu Pod-ul, aplicația nu poate continua să trimită comenzi pentru administrarea de insulină sau să afișeze informații exacte și recente despre insulina activă sau despre insulina administrată de Pod.\n\nMonitorizați-vă glicemia cu atenție în următoarele 6 sau mai multe ore, deoarece este posibil să existe sau nu insulină care lucrează activ în corpul dumneavoastră și pe care %3$@ nu o poate afișa."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ unități rămase la %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Administrarea insulinei a fost oprită. Trebuie să dezactivați și să detașati Pod-ul."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 oră"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 oră și 30 de minute"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 ore"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 de minute"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Timp activ"; - -/* Section header for activity section */ -"Activity" = "Activitate"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Reglarea timpului pompei..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarme"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Sigur doriți să anulați configurarea Pod-ului?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Sigur doriți să opriți acest Pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Sunteți sigur că doriți să săriți peste inițierea pompei Omnipod?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Sunteți sigur că nu mai doriți să utilizați pompa Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Adresă asignată"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Atașați Pod-ul"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Se încearcă restabilirea comunicațiilor"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Înapoi"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Administrare bazală"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Rate bazale"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Administrare bolus"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Renunță"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Anulați bazala manuală"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Canula a fost introdusă cu succes. Continuați."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Schimbați Pod-ul acum. Livrarea insulinei se va opri la 8 ore după expirarea Pod-ului sau când nu mai rămâne deloc insulină."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Schimbați Pod-ul acum. Livrarea insulinei se va opri în %1$@ sau când nu mai rămâne insulină."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Schimbare fus orar"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Se modifică ora…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Verificați canula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Verificați Pod-ul, puneți-l pe piele, după care confirmați că este lipit."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Se verifică inserția"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Se verifică..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comunicații reluate"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Mementouri de confimare"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Memento-urile de confirmare sunt semnale sonore de la Pod care pot fi folosite pentru confirmarea comenzilor selectate."; - -/* The title of the configuration section in settings */ -"Configuration" = "Configurare"; - -/* Button title for confirm attachment option */ -"Confirm" = "Confirmați"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Confirmați atașarea Pod-ului"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Continuă"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Alerte critice"; - -/* Unit for singular day in pod life remaining */ -"day" = "zi"; - -/* Unit for plural days in pod life remaining */ -"days" = "zile"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Dezactivează"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Dezactivează Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Dezactivat"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Se dezactivează."; - -/* Action button description while deactivating */ -"Deactivating..." = "Se dezactivează..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Șterge Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Limite de livrare"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Detalii despre dispozitiv"; - -/* The title of the device information section in settings */ -"Device Information" = "Informații dispozitiv"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Dispozitive"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Dezactivează beep-urile de bolus"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Renunțați la Pod"; - -/* No comment provided by engineer. */ -"Done" = "Realizat"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Activează beep-urile de bolus"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Eroare"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Eroare la dezactivarea beep-urilor de bolus"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Eroare la activarea beep-urilor de bolus"; - -/* The alert title for a resume error */ -"Error Resuming" = "Eroare în timpul reluării"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Eroare în timpul suspendării"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Memento de expirare"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Memento de expirare implicit"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Expirat"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Expiră"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Nu s-a reușit anularea bazalei manuale"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Nu s-a reușit reluarea administrării de insulină"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Nu s-a reușit setarei timpului de pe pompă"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Nu s-a reușit suspendarea administrării de insulină"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Nu s-a reușit actualizarea preferinței în ceea ce privește memento-ul de confirmare."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Nu s-a reușit actualizarea memento-ului de expirare"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Nu s-a reușit actualizarea memento-ului privind rezervorul scăzut"; - -/* Pod life HUD view label */ -"Fault" = "Defecțiune"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Umpleți un pod nou cu U-100 Insulină (nu înlăturați capacul acului de pe Pod). Așteptați să se audă 2 bipuri."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Finalizați dezactivarea"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Finalizare setare Pod"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Finalizați configurarea"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Au rămas mai mult de %1$@ unități la %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "oră"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "ore"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Dacă anulați configurarea Pod-ului, Pod-ul actual va fi dezactivat și va fi inutilizabil."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Înainte de a asocia un Pod nou, trebuie să dezactivați orice Pod setat incomplet. Dezactivați și aruncați Pod-ul curent."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Înainte de a asocia un Pod nou, trebuie să dezactivați orice Pod setat incomplet. Dezactivați și îndepărtați Pod-ul curent."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Inserează canula"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Inserată"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Se inserează. Vă rog așteptați."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Se inserează canula..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Administrarea insulinei suspendată"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insulină livrată"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulin Delivery"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Administrarea de insulină s-a oprit. Schimbați Pod-ul acum."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Administrarea de insulină va fi oprită până când veți relua manual. Când doriți ca Loop să vă reamintească să reluați administrarea?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulină rămasă"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Tipul de insulină"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Rată invalidă"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Canula este introdusă corect?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Țineți RileyLink-ul la aproximativ 15 cm de Pod în timpul asocierii."; - -/* description label for last status date pod details row */ -"Last Status" = "Ultima stare"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop nu va ajusta automat administrarea de insulină până când rata bazală temporară nu se termină sau nu este anulată."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lot"; - -/* description label for lot number pod details row */ -"Lot Number" = "Numărul lotului"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Rezervor scăzut"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Memento pentru rezervor scăzut"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Asigurați-vă că telefonul și Pod-ul sunt aproape unul de celălalt. Dacă problemele de comunicare persistă, mutați-vă într-o zonă nouă."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minut"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minute"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Lipsă configurare"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NA"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Continuați"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nu"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Nicio\nAdministrare"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Fără insulină"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Niciun Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Niciun memento"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nu, continuați cu Pod-ul"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nu, păstrați pompa așa cum este"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Nimic"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Setări de notificare"; - -/* No comment provided by engineer. */ -"Numbers" = "Numere"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Mementouri Omnipod"; - -/* Button title to pair with pod during setup */ -"Pair" = "Asociază"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Asociază un Pod nou"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Asociază un Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Asociază un Pod"; - -/* Label text indicating pairing finished. */ -"Paired" = "Asociat"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Se asociază."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Se asociază…"; - -/* The text of the loading label when pairing */ -"Pairing…" = "Se asociază…"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Procentaj = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "Versiune PI"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Redă beep-uri de test"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Beep-uri de test în desfășurare…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Vă rugăm să confirmați că Pod-ul este bine fixat de corpul dumneavoastră. \n\nCanula poate fi introdusă doar o singură dată cu fiecare Pod. Atingeți „Confirmați” când Pod-ul este fixat."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Vă rugăm să dezactivați podul. Când dezactivarea este completă, puteți asocia un nou pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Vă rugăm să dezactivați podul. Când dezactivarea este completă, îl puteți elimina și asociați un nou pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "Versiune PM"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod activat"; - -/* Label describing pod age view */ -"Pod Age" = "Vechime Pod"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod-ul a fost dezactivat cu succes."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Eroare Pod"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod-ul a expirat."; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod Expirat"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod-ul expiră"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod-ul expiră în"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Detalii despre eroarea Pod-ului"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Ocluzie Pod"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod-ul a fost asociat cu succes. Continuați."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Setări Pod"; - -/* Title for PodSetupView */ -"Pod Setup" = "Configurare Pod-ului"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Pregătiți locul."; - -/* title for previous pod page */ -"Previous Pod" = "Pod-ul anterior"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Informații despre Pod-ul anterior"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Pregătit."; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Pregătire în curs. Vă rugăm să așteptați."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Pregătire în curs..."; - -/* The text of the loading label when priming */ -"Priming…" = "Pregătire în curs..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Ora pompei"; - -/* Label text for basal rate summary */ -"Rate" = "Rată"; - -/* Label describing time remaining view */ -"Remaining" = "Rămas"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Înlăturați Pod-ul de pe corp"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Ștergeți pompa"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Scoateți capacul acului de pe Pod și verificați canula. Apoi înlăturați eticheta de hârtie de pe spate."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Înlocuiți Pod-ul"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Înlocuiți Pod-ul acum"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Rezervor"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Reluați administrarea de insulină"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Se reia administrarea de insulină..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Reîncearcă"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Reîncearcă dezactivarea Pod-ului"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink-ul permite comunicarea cu pompa prin Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "Configurarea RileyLink-ului"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Salvează"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Salvare..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Orar"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Bazală programată"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Memento programat"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Selectați tipul de insulină pe care o veți utiliza în acest pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Număr de ordine"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Setați bazala temporară"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Setați bazala temporară"; - -/* Title for setup complete screen */ -"Setup Complete" = "Configurare finalizată"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Pierdere de semnal"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Săriți peste inițierea pompei Omnipod?"; - -/* The title of the status section in settings */ -"Status" = "Stare"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Succes"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Suspendă administrarea"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Suspendați administrarea de insulină"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Suspendat"; - -/* Label for suspended at time */ -"Suspended At" = "Suspendat la"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Administrarea de insulină se suspendă..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Schimbă de la pompele Omnipod"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Treceți la alt dispozitiv de administrare a insulinei"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sincronizați cu ora curentă"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Sincronizează cu Pod-ul"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Atingeți mai jos pentru a începe introducerea canulei."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Bazală temporară"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Rata temporară de bazală a eșuat"; - -/* The title of the command to run the test command */ -"Test Command" = "Comandă de test"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Se execută comenzile de test…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Aplicația configurează un memento pe pod pentru a vă notifica înainte de expirarea Pod. Setați numărul de ore înainte de notificare pe care doriți să o configurați atunci când asociați un pod nou."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Aplicația vă notifică în avans de expirarea Pod.\n\nDerulați pentru a seta numărul de ore dorite pentru notificare."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Aplicația vă anunță când cantitatea de insulină din Pod atinge acest nivel (50-10 U). \n\nDerulați pentru a seta numărul de unități la care doriți să fiți notificat."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Aplicația vă notifică când cantitatea de insulină din Pod atinge acest nivel."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Mementourile de mai sus nu vor suna dacă dispozitivul este în modul Silențios sau Nu deranjați.\n\nExistă și alte alerte și alarme critice de Pod care vor suna chiar dacă dispozitivul este setat la modul Silențios sau Nu deranjați."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Ora de pe pompă este diferită de ora curentă. Puteți revizui ora pompei și să o sincronizați cu ora curentă în meniul setări."; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Ora pompei este diferită de ora curentă. Ora pompei dvs. controlează setările de terapie programate. Derulați în jos la rândul Ora pompei pentru a revizui diferența de oră și a configura pompa dvs."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Fereastra din partea superioară a Pod-ului trebuie să fie colorată în roz atunci când canula a fost introdusă corect în piele."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "A apărut o problemă la comunicarea cu podul. Dacă această problemă persistă, atingeți Renunțați la pod. Apoi puteți activa un nou Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Acesta este un memento pe care l-ați programat atunci când ați asociat Pod-ul curent."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "Această pompă nu a fost configurată cu o rată maximă de insulină bazală, deoarece a fost adăugată înainte ca rata temporară de insulină bazală să fie o opțiune. Vă rugăm să mergeți la Setări terapie -> limite de livrare și să setați o nouă rată maximă de insulină bazală."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Timp"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "S-a detectat schimbarea orei"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Semn de comutare"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Prea multe înregistrări"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Administrare totală"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/oră"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Nu s-a putut dezactiva Pod-ul. Continuați și asociați un Pod nou."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Nu se poate conecta la Pod"; - -/* Title for pending command recovery screen */ -"Unable To Reach Pod" = "Nu se poate conecta la Pod"; - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Nu se poate seta o rată temporară de insulină bazală: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Nu se poate seta o rată temporară de insulină bazală: %1$@ \n\n %2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Activare neterminată"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Dezactivare neterminată"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Necunoscut"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Așteptați până când inserarea este finalizată."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Da"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Da, dezactivați Pod-ul"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Da, sincronizați cu ora curentă"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Veți începe acum procesul de configurare a memento-urilor, umplerea Pod-ului cu insulină, asocierea cu dispozitivul dumneavoastră și amplasarea acestuia pe corp."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Pod-ul dumneavoastră este gata de utilizare. \n\n %1$@ vă va reaminti să vă schimbați Pod-ul înainte de a expira. Puteți schimba într-un moment convenabil pentru dumneavoastră."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Este posibil ca Podul dvs. să administreze în continuare insulină.\nScoateți-l din corpul dumneavoastră, apoi atingeți \"Continuați\"."; - diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/ru.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/ru.lproj/Localizable.strings deleted file mode 100644 index 3f033a0f7..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/ru.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ назад"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ дБ"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%1$@ восстановил связь с подом на вашем теле.\n\nЗаписи о поданном инсулине были обновлены и должны соответствовать тому, что было доставлено на самом деле.\n\nТеперь вы можете продолжать использовать %2$@ в обычном режиме."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ ед"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ ед (подано)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ ед из %2$@ ед (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ ед/час"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ Ед"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@Ед"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ за %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ не может связаться с подом на вашем теле с %2$@.\n\nБез связи с подом приложение не может продолжать отправлять команды на доставку инсулина или отображать точную, свежую информацию о вашем активном инсулине или инсулине, доставляемом подом.\n\nВнимательно следите за уровнем глюкозы в течение следующих 6 или более часов, поскольку в вашем организме может активно работать или не работать инсулин, который %3$@ не может отобразить."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ ед остается в %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Подача инсулина остановлена. Остановите и снимите Pod"; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g Ед"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 час"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 час 30 минут"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 часа"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 минут"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Активирован в"; - -/* Section header for activity section */ -"Activity" = "Нагрузка"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Настройка времени помпы..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Оповещения"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Вы уверены, что хотите отменить настройку Pod?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Вы уверены, что хотите выключить этот под?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Вы уверены, что хотите пропустить Omnipod Onboarding?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Вы уверены, что хотите прекратить использование Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Присвоенный адрес"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Прикрепить под"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Попытка восстановления связи"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Назад"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Подача базала"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Скорости базала"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Подача болюса"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Отмена"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Отменить ручную ВБС"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Канюля введена успешно. Продолжить."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Замените под сейчас. Подача инсулина прекратится через 8 часов после истечения срока действия пода или когда инсулина больше не останется."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Замените под сейчас. Подача инсулина прекратится через %1$@ или когда инсулина больше не останется."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Изменить часовой пояс"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Выполняется изменение времени"; - -/* Title for check cannula screen */ -"Check Cannula" = "Проверьте канюлю"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Проверьте под, приклейте его на место установки, затем подтвердите прикрепление пода."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Проверка ввода канюли"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Проверка..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Связь восстановлена"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Напоминания об уверенности"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Доверенные звуковые сигналы от Пода, которые позволяют распознать выбранные команды, когда Под не заглушен."; - -/* The title of the configuration section in settings */ -"Configuration" = "Конфигурация"; - -/* Button title for confirm attachment option */ -"Confirm" = "Подтвердить"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Подтвердите, что под прикреплен к телу"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Продолжить"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Критические оповещения"; - -/* Unit for singular day in pod life remaining */ -"day" = "день"; - -/* Unit for plural days in pod life remaining */ -"days" = "дней"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Деактивировать"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Сдвиньте для деактивации"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Деактивировать Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Не активен"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Деактивация."; - -/* Action button description while deactivating */ -"Deactivating..." = "Деактивация..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Удалить Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Пределы подачи"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Сведения об устройстве"; - -/* The title of the device information section in settings */ -"Device Information" = "Информация об устройстве"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Устройства"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Отключить звуковой сигнал болюса"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Выбросить под"; - -/* No comment provided by engineer. */ -"Done" = "Готово"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Включить звуковой сигнал болюса"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Ошибка"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Ошибка при отключении звуковых сигналов болюса"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Ошибка включения звуковых сигналов болюса"; - -/* The alert title for a resume error */ -"Error Resuming" = "Ошибка возобновления"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Ошибка приостановки"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Напоминание об истечении срока"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Напоминание об истечении срока действия По умолчанию"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Срок истек"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Срок истекает"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Не удалось отменить ручной базал"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Не удалось возобновить подачу инсулина"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Не удалось установить время в помпе"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Не удалось приостановить подачу инсулина"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Не удалось обновить настройки напоминания о конфиденциальности."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Не удалось обновить напоминание об истечении срока действия"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Не удалось обновить напоминание о низком уровне резервуара"; - -/* Pod life HUD view label */ -"Fault" = "Сбой"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Заправьте новый под инсулином (не менее 100 единиц, крышка канюли должна быть на месте). Дождитесь 2 звуковых сигналов."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Завершение деактивации"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Завершить настройку Omnipod"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Завершить настройку"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Более %1$@ ед остается в %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "час"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "часов"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Если вы отмените настройку пода, текущий под будет деактивирован и станет непригодным для использования."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Неполностью настроенный Omnipod должен быть отключен до соединения с новым. Отключите и утилизируйте Pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Неполностью настроенный Omnipod должен быть отключен до соединения с новым. Отключите и удалите Pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Ввести канюлю"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Введено"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Введение канюли. Пожалуйста, подождите."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Введение канюли..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Подача инсулина остановлена"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Инсулин подан"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Подача инсулина"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Введение инсулина остановлено. Замените Под."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Подача инсулина будет прекращена до тех пор, пока вы не возобновите ее вручную. Когда вы хотите, чтобы Loop напомнил вам о необходимости возобновить подачу?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Остаток инсулина"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Тип инсулина"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Неверная запись"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Правильно ли введен катетер?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Во время сопряжения держите RileyLink на расстоянии около 20 сантиметров от пода."; - -/* description label for last status date pod details row */ -"Last Status" = "Последнее состояние"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop не будет автоматически регулировать подачу инсулина, пока временная базальная скорость не закончится или не будет отменена."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lot"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot Number"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Мало инсулина в резервуаре"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Резервуар помпы пуст"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Убедитесь, что ваш телефон и под находятся рядом друг с другом. Если проблемы со связью сохраняются, перейдите в другое место."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "минута"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "минут"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Отсутствует конфигурация"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NA"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Продолжить"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Нет"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Нет подачи"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Нет инсулина"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Нет пода"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Нет напоминаний"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Нет, продолжить с подом"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Нет, оставить время в помпе как есть"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Не подан"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Настройки уведомлений"; - -/* No comment provided by engineer. */ -"Numbers" = "Цифры"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Напоминания пода"; - -/* Button title to pair with pod during setup */ -"Pair" = "Сопряжение"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Установить сопряжение"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Сопрячь под"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Сопрячь под."; - -/* Label text indicating pairing finished. */ -"Paired" = "Сопряжен"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Начать сопряжение"; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Сопряжение..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Процент = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "Версия PI"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Включить проверку сигналов"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Проверка тест сигнала"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Убедитесь, что под надежно приклеен на вашем теле.\n\nКатетер можно ввести только один раз. Нажмите кнопку \"Подтвердить\", когда под приклеен."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Пожалуйста, деактивируйте под. Когда деактивация будет закончена, Вы сможете сопрячь новый."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Пожалуйста, деактивируйте под. Когда деактивация будет закончена, Вы можете снять старый под и сопрячь новый."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "Версия PM"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Под активирован"; - -/* Label describing pod age view */ -"Pod Age" = "Pod проработал"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Под успешно деактивирован. Продолжить."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Ошибка пода"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Срок работы Omnipod истек"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Под истек"; - -/* Label for pod expiration row */ -"Pod Expires" = "Срок действия пода истекает"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Под истекает "; - -/* description label for pod fault details */ -"Pod Fault Details" = "Детали ошибка пода"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Закупорка пода"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Под успешно сопряжен. Продолжить."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Настройки пода"; - -/* Title for PodSetupView */ -"Pod Setup" = "Настройка пода"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Подготовьте место установки помпы"; - -/* title for previous pod page */ -"Previous Pod" = "Предыдущий под"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Предыдущая информация о поде"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Заправлено"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Заправка. Пожалуйста, подождите."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Заправить..."; - -/* The text of the loading label when priming */ -"Priming…" = "Заправка..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Время в помпе"; - -/* Label text for basal rate summary */ -"Rate" = "Скорость"; - -/* Label describing time remaining view */ -"Remaining" = "Остается"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Снимите под с тела"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Удалите помпу"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Отломите защитную крышку канюли и проверьте состояние самой канюли. Далее снимите защитные стикеры с пластыря."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Заменить Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Немедленно замените Pod"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Резервуар"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Возобновить подачу инсулина"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Возобновление подачи инсулина..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Повторить"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Повторить деактивацию Pod’a"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "Rileylink необходим для коммуникации с помпой посредством Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "Настройка RilryLink"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Сохранить"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Сохранение..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "По графику"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Запланированная база"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Запланированное напоминание"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Выберите тип инсулина, с которым Вы будете использовать этот под."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Порядковый номер"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Установить ВБС"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Установить ВБС"; - -/* Title for setup complete screen */ -"Setup Complete" = "Настройка завершена"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Сигнал потерян"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Пропустить настройку Omnipod?"; - -/* The title of the status section in settings */ -"Status" = "Статус"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Успешно"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Остановить подачу"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Остановить подачу инсулина"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Остановлено"; - -/* Label for suspended at time */ -"Suspended At" = "Приостановлено в"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Остановка подачи инсулина..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Отключиться от помп Omnipod"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Переключиться на другое устройство для введения инсулина"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Синхронизация с текущим временем"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Синхронизировать с Pod'ом"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Нажмите ниже, чтобы начать ввод канюли."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "ВБС"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Ошибка установки ВБС"; - -/* The title of the command to run the test command */ -"Test Command" = "Провести тест"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Команды тестов"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Приложение настраивает напоминание на телефоне, чтобы уведомить вас об истечении срока действия Pod. Установите количество часов предварительного уведомления, которое вы хотите сохранить при сопряжении нового Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Приложение заранее уведомит Вас об истечении срока действия Pod.\n\nПрокрутите, чтобы установить количество часов предварительного уведомления, которое вы хотели бы получить."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Приложение уведомит Вас, когда количество инсулина в Pod достигнет этого уровня (50-10 Ед).\n\nПрокрутите, чтобы установить количество единиц, о которых вы хотели бы получить напоминание."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Приложение уведомит Вас, когда количество инсулина в Pod достигнет этого уровня."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Приведенные выше напоминания не будут звучать, если ваше устройство находится в режиме Тишина или Не беспокоить.\n\nЕсть и другие критические оповещения и сигналы тревоги Pod, которые будут звучать, даже если ваше устройство настроено в режим Тишина или Не беспокоить."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Время на вашей помпе отличается от текущего времени. Вы хотите обновить время на вашей помпе на текущее?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Время на помпе отличается от текущего времени. Время вашей помпы контролирует ваши запланированные настройки терапии. Прокрутите вниз до строки времени помпы, чтобы просмотреть разницу во времени и настроить помпу."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Когда канюля правильно введена под кожу, окошко в верхней части пода должно окраситься в розовый цвет."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Возникла проблема с общением с подом. Если эта проблема сохраняется, нажмите \"Деактивировать Pod\". Затем вы можете активировать новый Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Это напоминание, которое вы запланировали при сопряжении с текущим подом."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "Эта помпа не была настроена с максимальным базалом, потому что была добавлена до того, как установка ручной ВБС стала возможной. Пожалуйста, перейдите в настройки терапии -> Лимиты доставки и установите новый максимальный базал."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Время"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Обнаружено изменение времени"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Переключение входа"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Слишком много данных"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Подано всего"; - -/* Units for showing temp basal rate */ -"U/hr" = "Ед/ч"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Не удалось деактивировать Pod. Пропустить и начать соединение с новым."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Невозможно связаться с подом"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Невозможно установить ВБС: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Невозможно установить ВБС: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Не закончена активация"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Незавершенная деактивация"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Неизвестно"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Подождите, пока ввод канюли завершится."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Да"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Деактивировать Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Да, синхронизировать с текущим временем"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Сейчас Вы начнете процесс конфигурирования напоминаний, заправки пода инсулином, сопряжения с телефоном и установкой пода на тело."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Под готов к использованию.\n\n%1$@ напомнит вам о необходимости замены пода до истечения срока его действия. Вы можете изменить это на удобное для вас время."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Ваш под может по-прежнему доставлять инсулин.\n Удалите его с тела, затем нажмите «Продолжить»."; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Беззвучно"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Обычный режим работы, при котором звуковые сигналы используются для всех оповещений Пода и при включенных доверенных напоминаниях."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Все уведомления Пода не издают звуковых сигналов и напоминания о подтверждении подавлены. Под будет издавать звуковые сигналы только при критических сбоях Пода и когда проигрываются тестовые звуки.\n\n⚠️Предупреждение — Когда Под заглушен, он должен находиться в пределах Bluetooth-диапазона этого устройства, для получения сигналов уведомлений."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Беззвучный Под"; - -/* title for pod details page */ -"Pod Details" = "Сведения о Поде"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Сведения о предыдущем Поде"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Сведения о помпе"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Получение сведений о помпе..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Обновить сведения о помпе"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Не удалось обновить настройку беззвучного режима Пода."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Диагностика"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Получить статус Пода"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/sk.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/sk.lproj/Localizable.strings deleted file mode 100644 index 827c53da4..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/sk.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "pred %@"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%1$@ obnovil komunikáciu s podom na vašom tele. \n\n Záznamy o podávaní inzulínu boli aktualizované a mali by zodpovedať tomu, čo bolo skutočne podané. \n\nTeraz môžete naďalej normálne používať %2$@ ."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ j"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ j (Dokončené)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ j z %2$@ j ( %3$@ )"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ j/hod"; - -/* Appends a full-stop to a statement */ -"%@." = "%@ ."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@ %%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ j"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@ j"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "1 pre 2"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ sa nepodarilo komunikovať s podom na vašom tele od %2$@ . \n\nBez komunikácie s podom, nemôže aplikácia pokračovať v odosielaní príkazov na aplikáciu inzulínu, ani zobrazovať presné a aktuálne informácie o vašom aktívnom inzulíne alebo o inzulíne podávanom podom. \n\nPočas nasledujúcich 6 alebo viac hodín pozorne sledujte svoju glykémiu, pretože vo vašom tele môže alebo nemusí aktívne pôsobiť inzulín, ktorý %3$@ nedokáže zobraziť."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ jednotiek zostávajúcich na %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Podávanie inzulínu sa zastavilo. Prosím, deaktivujte a odstráňte pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@ %2$@ %3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@ + %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g j"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 hodina"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hodina 30 minút"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 hodiny"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minút"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Aktívny čas"; - -/* Section header for activity section */ -"Activity" = "Aktivita"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Nastavenie času čerpadla..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarmy"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Naozaj chcete zrušiť svoj hlas?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Naozaj chcete vypnúť tento pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Naozaj chcete preskočiť nastavovanie Omnipodu?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Naozaj chcete prestať používať Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Priradená adresa"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Aplikujte pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Prebieha obnovenie komunikácie"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Späť"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Podávanie bazálu"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Bazálne dávky"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Podávanie bolusu"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Zrušiť"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Zrušenie manuálneho bazálneho"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanyla úspešne zavedená. Pokračovať."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Ihneď vymeniť pod. Podávanie inzulínu sa zastaví o 8 hodín alebo keď sa minie inzulín."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Ihneď vymeniť pod. Podávanie inzulínu sa zastaví o %1$@ alebo keď sa minie inzulín."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Zmeniť časové pásmo"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Mení sa čas…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Skontrolujte kanylu"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Skontrolujte pod, aplikujte ho na telo, potom potvrďte prilepenie podu."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Kontrola zavedenia"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Kontroluje sa..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Príkazy obnovené"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Upozornenia s pípnutím zo zariadenia Pod"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Upozornenia s pípnutím zo zariadenia Pod, ktoré možno použiť na potvrdenie vybraných príkazov, keď zariadenie Pod nie je vypnuté."; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfigurácia"; - -/* Button title for confirm attachment option */ -"Confirm" = "Potvrdiť"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Potvrdiť pripojenie zariadenia Pod"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Pokračovať"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritické výstrahy"; - -/* Unit for singular day in pod life remaining */ -"day" = "deň"; - -/* Unit for plural days in pod life remaining */ -"days" = "dni"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Deaktivovať"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Deaktivovať pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Deaktivované"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Deaktivuje sa."; - -/* Action button description while deactivating */ -"Deactivating..." = "Deaktivuje sa..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Odstrániť Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Limity podávania"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Podrobnosti o zariadení"; - -/* The title of the device information section in settings */ -"Device Information" = "Informácie o zariadení"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Zariadenia"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Vypnúť pípanie pri boluse"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Zlikvidujte pod"; - -/* No comment provided by engineer. */ -"Done" = "Hotovo"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Povoliť pípanie pri boluse"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Chyba"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Chyba pri vypnutí bolusových pípnutí"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Chyba pri povoľovaní bolusových pípnutí"; - -/* The alert title for a resume error */ -"Error Resuming" = "Chyba pri obnovení"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Chyba pri pozastavení"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Pripomienka o expirácii"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Predvolené pripomenutie o expirácii"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Expiroval"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Expiruje"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Zrušenie manuálneho bazálu zlyhalo"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Obnovenie podávania inzulínu zlyhalo"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Nastavenie času pumpy zlyhalo"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Pozastavenie podávania inzulínu zlyhalo"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Nepodarilo sa aktualizovať predvoľbu pripomenutia dôveryhodnosti."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Nepodarilo sa aktualizovať pripomenutie o expirácii"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Nepodarilo sa aktualizovať pripomienku nízkej hladiny v rezervoári"; - -/* Pod life HUD view label */ -"Fault" = "Chyba"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Naplňte nový pod inzulínom U-100 (kryt ihly ponechajte nasadený). Budete počuť 2 pípnutia."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Dokončiť deaktiváciu"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Dokončiť nastavenie podu"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Dokončiť nastavenie"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Viac ako %1$@ jednotiek zostávajúcich o %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "hodina"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "hodiny"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Ak zrušíte nastavenie podov, aktuálny pod bude deaktivovaný a nebude možné ho používať."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Neúplne nastavený pod musí byť deaktivovaný pred spárovaním s novým podom. Deaktivujte a zlikvidujte pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Neúplne nastavený pod musí byť deaktivovaný pred spárovaním s novým podom. Deaktivujte a odstráňte pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Zaviesť kanylu"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Vložené do tela"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Zavádzanie. Počkajte, prosím."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Zavádza sa.."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Inzulín\nSuspendovaný"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Inzulín podaný"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Podávanie inzulínu"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Podávanie inzulínu sa zastavilo. Vymeňte modul teraz."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Podávanie inzulínu bude zastavené, kým ho neobnovíte manuálne. Kedy chcete, aby vám slučka pripomenula obnovenie podávania?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Zostávajúci inzulín"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Typ inzulínu"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Neplatný údaj"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Je kanyla správne zavedená?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Počas párovania držte RileyLink približne 6 palcov od podu."; - -/* description label for last status date pod details row */ -"Last Status" = "Posledný stav"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop nebude automaticky upravovať podávanie inzulínu, kým dočasná bazálna dávka nebude ukončená alebo zrušená."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Šarža"; - -/* description label for lot number pod details row */ -"Lot Number" = "Číslo šarže"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Nízka hladina v rezervoári"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Pripomienka Nízka hladina v rezervoári"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Uistite sa, že váš telefón a pod sú blízko seba. Ak problémy s komunikáciou pretrvávajú, presuňte sa na iné miesto."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minúta"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minúty"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Chýba konfigurácia"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NA"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Ďalej"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nie"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Žiadna\ndodávka"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Žiadny inzulín"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Žiadny pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Žiadna pripomienka"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nie, pokračujte so zariadením Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nie, nechajte čerpadlo tak, ako je"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Žiadny"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Nastavenia oznámení"; - -/* No comment provided by engineer. */ -"Numbers" = "Čísla"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Pripomienky omnipodu"; - -/* Button title to pair with pod during setup */ -"Pair" = "Párovať"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Párovať nový pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Párovať pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Párovať pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Spárované"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Párovanie."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Páruje sa…"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percentá = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "Verzia PI"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Prehrať skúšobné pípnutia"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Prehrať skúšobné pípnutia…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Uistite sa, že je pod bezpečne pripevnený k vášmu telu.\n\nKanylu možno do každého podu zaviesť len raz. Keď je Pod pripojený, klepnite na \"Potvrdiť\"."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Prosím, deaktivujte pod. Po dokončení deaktivácie, môžete spárovať nový pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Prosím, deaktivujte pod. Po dokončení deaktivácie, ho môžete odstrániť a spárovať nový pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "Verzia PM"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod aktivovaný"; - -/* Label describing pod age view */ -"Pod Age" = "Vek podu"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod deaktivovaný úspešne. Pokračovať."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Chyba podu"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod vypršal"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod expiroval"; - -/* Label for pod expiration row */ -"Pod Expires" = "Expirácia Podu"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod expiruje o"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Detaily chyby podu"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Oklúzia podu"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod sprárovaný úspešne. Pokračovať."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Nastavenia podu"; - -/* Title for PodSetupView */ -"Pod Setup" = "Nastavenie podu"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Pripravte miesto."; - -/* title for previous pod page */ -"Previous Pod" = "Predchádzajúci Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Predchádzajúce informácie o Pod"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Pripravené"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Pripravuje sa. Prosím čakajte."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Príprava…"; - -/* The text of the loading label when priming */ -"Priming…" = "Príprava…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Čas čerpadla"; - -/* Label text for basal rate summary */ -"Rate" = "Dávka"; - -/* Label describing time remaining view */ -"Remaining" = "Zostáva"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Odstránenie struku z tela"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Odstrániť Pod"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Odstráňte kryt z ihly a skontrolujte kanylu. Potom odstráňte papierovú podložku."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Vymeňte pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Ihneď vymeňte pod"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Rezervoár"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Obnoviť podávanie inzulínu"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Obnovuje sa podávanie inzulínu..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Skúsiť znova"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Opäť deaktivovať pod"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink umožňuje komunikáciu s pumpou cez Bluetooth."; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "Nastavenie RileyLinku"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Uložiť"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Ukladá sa..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Plán "; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Naplánovaný bazál"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Naplánovaná pripomienka"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Vyberte typ inzulínu, ktorý budete používať v tomto pode."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sekvenčné číslo"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Nastaviť dočasný bazál"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Nastavenie dočasnej bazálnej sadzby"; - -/* Title for setup complete screen */ -"Setup Complete" = "Nastavenie je dokončené"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Strata signálu"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Preskočiť Omnipod Onboarding?"; - -/* The title of the status section in settings */ -"Status" = "Stav"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Úspešné"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Pozastavenie dodávky"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Zastavte podávanie inzulínu"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Pozastavené"; - -/* Label for suspended at time */ -"Suspended At" = "Pozastavené na"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Pozastavenie podávania inzulínu..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Prepnúť z púmp Omnipod "; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Prechod na iné zariadenie na podávanie inzulínu"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synchronizácia s aktuálnym časom"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Synchronizovať s podom"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Ťuknutím nižšie spustíte zavádzanie kanyly."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Dočasný bazál"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Dočasný bazál zlyhal"; - -/* The title of the command to run the test command */ -"Test Command" = "Testovať príkaz"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Testovanie príkazov…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Aplikácia nakonfiguruje pripomienku do podu, aby vás vopred upozornila na expiráciu podu. Počas párovania nového podu, nastavte, koľko hodín vopred, by ste chceli pripomienku nakonfigurovať."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Aplikácia vás vopred upozorní na expiráciu podu. \n\nRolovaním nastavte počet hodín vopred, kedy chcete upozornenie dostať."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Aplikácia vás upozorní, keď množstvo inzulínu v pode dosiahne túto úroveň (50 – 10 U). \n\nRolovaním nastavte počet jednotiek, pri ktorých chcete byť upozornení."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Aplikácia vás upozorní, keď množstvo inzulínu v pode dosiahne túto úroveň."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Vyššie uvedené pripomenutia nezaznejú, ak je vaše zariadenie v tichom režime alebo v režime Nerušiť.\n\nExistujú ďalšie kritické upozornenia a alarmy Pod, ktoré zaznejú, aj keď je vaše zariadenie nastavené na tichý režim alebo režim Nerušiť."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Čas na vašej pumpe sa líši od skutočného času. Chcete aktualizovať čas na čerpadle na aktuálny čas?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Čas na pumpe je iný ako aktuálny čas. Čas pumpy riadi vaše naplánované liečebné nastavenia. Prejdite nadol na riadok Čas pumpy, pozrite si časový rozdiel a nakonfigurujte pumpu."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Keď je kanyla správne zavedená do kože, okienko v hornej časti Podu by malo byť sfarbené do ružova."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Nastal problém s komunikáciou s podom. Ak tento problém pretrváva, ťuknite na položku Zlikvidovať Pod. Potom môžete aktivovať nový pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Toto je pripomienka, ktorú ste naplánovali pri spárovaní aktuálneho Podu."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "V tejto pumpe nebola nakonfigurovaná maximálna bazálna dávka, pretože bola pridaná predtým, než bola funkcia manuálneho dočasného bazálu. Prejdite do Liečebné nastavenia - > Limity dávkovania a nastavte novú maximálnu bazálnu dávku."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Čas"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Zistila sa zmena času"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Značka prepnutia"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Príliš veľa záznamov"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Celková dávka"; - -/* Units for showing temp basal rate */ -"U/hr" = "J/hod"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Pod nie je možné deaktivovať. Prosím pokračujte a spárujte nový pod."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Pod nie je v dosahu."; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Nie je možné nastaviť dočasnú dávku bazálu: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Nie je možné nastaviť dočasnú dávku bazálu: %1$@ \n\n %2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Aktivácia neukončená"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Deaktivácia neukončená"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Neznáme"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Počkajte kým nie je zavedenie ukončené."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Áno"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Áno, deaktivujte pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Áno, synchronizujte s aktuálnym časom"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Teraz začnete s procesom konfigurácie pripomienok, naplnením podu inzulínom, jeho spárovaním s vašim zariadením a umiestnením podu na telo."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Váš pod je pripravený na použitie. \n\n %1$@ vám pripomenie, aby ste vymenili svoj pod pred časom jeho expirácie. Môžete to zmeniť na čas, ktorý vám vyhovuje."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Váš Pod môže stále podávať inzulín.\nOdstráňte ho z tela a potom klepnite na \"Pokračova.\""; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Umlčané"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normálny prevádzkový režim, v ktorom sa zvukové signály Pod používajú pre všetky upozornenia Pod a keď sú povolené pripomenutia dôvery."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Všetky upozornenia Pod nepoužívajú žiadne zvukové signály a zvukové signály pripomínajúce potvrdenie sú potlačené. Pod bude pípať len pri fatálnych poruchách Pod a pri prehrávaní testovacích pípnutí.\n\n⚠️Warning - Vždy, keď je Pod stlmený, musí byť v dosahu Bluetooth tohto zariadenia, aby prijímal upozornenia na upozornenia Pod."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Umlčané"; - -/* title for pod details page */ -"Pod Details" = "Detaily Podu"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Predchádzajúci Pod Podrobnosti"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Podrobnosti o manažérovi čerpadla"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Získanie údajov o správcovi čerpadla..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Podrobnosti o manažérovi čerpadla"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Nepodarilo sa aktualizovať predvoľbu pripomenutia dôveryhodnosti."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostiky"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Zistiť stav Podu"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/sv.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/sv.lproj/Localizable.strings deleted file mode 100644 index 91eed0e78..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/sv.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ sedan"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ har återställt kommunikationen med podden på din kropp.\n\nInsulinposterna har uppdaterats och ska matcha det som faktiskt har levererats.\n\nDu kan fortsätta att använda %@ normalt nu."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ E"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ E (Klar)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%@ E av %@ E (%@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ E/h"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ E"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@E"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ i %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ har inte kunnat kommunicera med podden på din kropp sedan %2$@.\n\nUtan kommunikation med podden kan appen inte fortsätta att skicka kommandon för insulin eller visa korrekt och aktuell information om ditt aktiva insulin eller insulin som ges av podd.\n\nÖvervaka dina blodsockervärden noga under de kommande 6 timmarna, eftersom det kan finnas aktivt insulin som %3$@ inte kan visa."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ enheter återstår kl. %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Insulintillförseln har avbrutits. Inaktivera podden och byt till en ny podd."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@: %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g E"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 timme"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 timme 30 minuter"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 timmar"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minuter"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Aktiv tid"; - -/* Section header for activity section */ -"Activity" = "Aktivitet"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Justerar pumptid..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Larm"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Är du säker på att du vill avsluta din poddinställning?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Är du säker att du vill stänga av denna podd?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Är du säker på att du vill hoppa över rundturen?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Är du säker att du vill sluta använda Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Tilldelad adress"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Fäst podden"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Försöker att återupprätta kommunikationen"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Tillbaka"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Basaldos"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Basaldoser"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Bolusdos"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Avbryt"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Avbryt manuell basal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanyl nu införd. Fortsätt."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Byt podd nu. Insulintillförsel kommer att upphöra 8 timmar efter att podd går ut eller så snart insulinet är slut."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Byt podd nu. Insulintillförsel kommer att stoppas om %1$@ eller när insulinet är slut."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Ändra tidszon"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Ändra tid…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Kontrollera kanyl"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Kontrollera din podd, sätt fast den och bekräfta sedan att den sitter bra."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Kontrollerar kanylinförsel"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Kontrollerar..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Återställning av kommunikationen"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Bekräftelseljud"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Bekräftelseljud är pip från podden (när den inte är tystad) som kan användas som bekräftelser på utförda kommandon."; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfiguration"; - -/* Button title for confirm attachment option */ -"Confirm" = "Bekräfta"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Kontrollera att podden sitter bra"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Fortsätt"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Varningar"; - -/* Unit for singular day in pod life remaining */ -"day" = "dag"; - -/* Unit for plural days in pod life remaining */ -"days" = "dagar"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Inaktivera"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Svep för att inaktivera podd"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Inaktivera podd"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Inaktiverad"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Inaktiverar."; - -/* Action button description while deactivating */ -"Deactivating..." = "Inaktiverar..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Radera Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Maxdoser"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Enhetsdetaljer"; - -/* The title of the device information section in settings */ -"Device Information" = "Enhetsinformation"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Enheter"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Stäng av bolusljud"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Kasta podd"; - -/* No comment provided by engineer. */ -"Done" = "Färdig"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Slå på bolusljud"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Fel"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Fel vid avstängning av bolusljud"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Fel vid aktivering av bolusljud"; - -/* The alert title for a resume error */ -"Error Resuming" = "Fel vid återupptagande"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Fel vid försök till paus"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Påminnelse om utgångsdatum"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Standard påminnelsetid"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Utgått"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Utgår"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Misslyckades att avbryta manuell basal"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Misslyckades att återuppta insulintillförsel"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Det gick inte att ställa in pumptid"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Kunde inte pausa pump"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Misslyckades att uppdatera inställning för bekräftelseljud"; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Det gick inte att uppdatera förfallopåminnelse"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Misslyckades att uppdatera påminnelse om låg insulinvolym"; - -/* Pod life HUD view label */ -"Fault" = "Fel"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Fyll en ny podd med U-100 Insulin (låt nålskyddet sitta kvar). Lyssna efter 2 pip."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Avsluta inaktivering"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Gör färdigt poddinställningen"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Gär färdigt inställning"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Fler än %1$@ enheter återstår kl. %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "timme"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "timmar"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Om du avbryter din podinställning, kommer din podd att avaktiveras och sluta fungera."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Ofullständigt inställd podd måste inaktiveras före parkoppling av ny podd. Inaktivera och kasta den gamla podden."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Ofullständigt inställd podd måste inaktiveras före parkoppling av ny podd. Inaktivera och kasta den gamla podden."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "För in kanyl"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Kanyl har förts in"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Nål förs in. Vänligen vänta."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Kanylen förs in..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Pump\npausad"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insulin doserat"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Insulintillförsel"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulintilförsel stoppad. Byt podd nu."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulintillförsel kommer att stoppas tills du återupptar dennamanuellt. När vill du att iAPS ska påminna dig om att återuppta insulintillförsel?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin kvar"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Insulintyp"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Ogiltig inmatning"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Är kanylen införd korrekt?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Placera din RileyLink ca 15 cm från podden under parkoppling."; - -/* description label for last status date pod details row */ -"Last Status" = "Senaste status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "iAPS kommer inte automatiskt att justera dina insulindoser förrän den temporära basalen är färdig eller har avbrytits."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lot"; - -/* description label for lot number pod details row */ -"Lot Number" = "Lot-nummer"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Låg reservoarvolym"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Påminnelse om låg insulinnivå"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Säkerställ att din telefon och podd är nära varandra. Om problemet kvarstår, flytta till annan plats."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "minut"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "minuter"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Konfiguration saknas"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Nästa"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Nej"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Inget\ninsulin"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Inget insulin"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Ingen Podd"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Ingen påminnelse"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Nej, fortsätt med denna podd"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Nej, behåll pumptid"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Ingen"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Notisinställningar"; - -/* No comment provided by engineer. */ -"Numbers" = "Nummer"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod-påminnelser"; - -/* Button title to pair with pod during setup */ -"Pair" = "Parkoppla"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Parkoppla ny podd"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Parkoppla podd"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Parkoppla podd."; - -/* Label text indicating pairing finished. */ -"Paired" = "Parkopplad"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Parkopplar."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Parkopplar..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Procent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PI-version"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Spela upp testljud"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Spelar upp testljud…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Kontrollera att podden sitter bra på din kropp.\n\nKanylen kan bara föras in en gång. Tryck på \"Bekräfta\" när podden sitter fast."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Inaktivera podden. När inaktiveringen är klar kan du parkoppla en ny podd."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Inaktivera din podd. Avlägsna sedan podden från kroppen och parkoppla en ny."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PM-version"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Podd aktiverades"; - -/* Label describing pod age view */ -"Pod Age" = "Poddålder"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Podd avaktiverades. Fortsätt."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Poddfel"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod har utgått"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Poddens utgångsdatum passerat"; - -/* Label for pod expiration row */ -"Pod Expires" = "Podd går ut"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Podd går ut om"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Poddfelsdetaljer "; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Ocklusion i podd"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Podd har parkopplats. Fortsätt."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Poddinställningar"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pumpinställning"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Förbered hud."; - -/* title for previous pod page */ -"Previous Pod" = "Tidigare podd"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Info om tidigare podd"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Podden är fylld"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Fyller podd. Vänligen vänta."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Fyller..."; - -/* The text of the loading label when priming */ -"Priming…" = "Podden fylls..."; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pumptid"; - -/* Label text for basal rate summary */ -"Rate" = "Värde"; - -/* Label describing time remaining view */ -"Remaining" = "Återstår"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Ta bort podd från kroppen"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Ta bort podd"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Ta bort poddens kanylskydd och kontrollera att kanylen inte redan sticker ut. Ta sedan bort skyddspappret."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Byt podd"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Byt podd nu"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Reservoar"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Återuppta pump"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Återupptar pump..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Försök igen"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Försök inaktivera podden igen"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink kommunicerar med pumpen via Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink inställning"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Spara"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Sparar..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Schema"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Schemalagd basal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Schemalagd påminnelse"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Välj vilken typ av insulin du kommer att använda."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sekvensnummer"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Ställ in temporaär basal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Ange temporär basaldos"; - -/* Title for setup complete screen */ -"Setup Complete" = "Inställning klar"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Signalförlust"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Hoppa över Omnipod-introduktionen?"; - -/* The title of the status section in settings */ -"Status" = "Status"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Lyckades"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Pausa insulintillförsel"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Pausa insulintillförsel"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Pausad"; - -/* Label for suspended at time */ -"Suspended At" = "Pausad kl."; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Pausar pump..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Byt från Omnipod-pumpar"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Byt till annan pump/insulinadministrering"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Synkronisera med aktuell tid"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Synkronisera med podd"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Tryck nedan för att föra in kanyl."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporär basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporär basal misslyckades"; - -/* The title of the command to run the test command */ -"Test Command" = "Kommandotest"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Testar att skicka kommandon…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Du kan ange när du vill att appen ska påminna dig om när du behöver byta podd. Ange det antal timmar i förväg du vil ha påminnelsen"; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Appen meddelar dig i förväg om när din podd går ut.\n\nSkrolla för att ställa in hur många timmar i förväg du vill bli påmind."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Appen meddelar dig när mängden insulin i podden når denna nivå (50-10 U).\n\nSkrolla för att ange vid vilket antal enheter som du vill bli påmind."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Appen kommer att visa notis när mängden insulin går ner till denna nivå"; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Påminnelser kommer vara tysta ifall att du har tyst läge eller stör ej - läge på. \n\nDet finns andra varningar som kommer att ljuda även vid tyst läge eller stör ej - läge."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Tiden på din pump skiljer sig från aktuell tid. Vill du uppdatera tiden på din pump till aktuell tid?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Tiden på din pump skiljer sig från verklig tid. Pumpens tid styr dina schemalagda terapiinställningar. Bläddra ner till raden Pump Tid för att ändra."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Det lilla fönstret på podden färgas rosa när kanylen är ordentligt insatt i huden."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Det gick inte att kommunicera med podden. Om problemet kvarstår, tryck på 'Kasta Pod'. Du kan sedan aktivera en ny podd."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Detta är en schemalagd påminnelse som du ställde in när du parkopplade nuvarande podd."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "En maximal basaldos har inte ställts in. Gå till inställningen 'Maxdoser' för att ställa in den maximala basaldosen."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Tid"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Tidsändring upptäckt"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Symbol för knapp"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "För många inmatningar"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total mängd insulin given"; - -/* Units for showing temp basal rate */ -"U/hr" = "E/timme"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Kunde inte deaktivera podden. Var god fortsätt genom att parkoppla en ny podd."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Det går inte att nå podd"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Kunde inte ställa in en temporär basaldos: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Kunde inte ställa in en temporär basaldos: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Aktivering inte färdig"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Inaktivering inte färdig"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Okänd"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Vänta tills kanyl förts in."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Ja"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Ja, inaktivera podden"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Ja, synkronisera med aktuell tid"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Du kommer nu att börja att konfigurera dina påminnelser, fylla din podd med insulin, parkoppla podden och fästa den på kroppen."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Din podd är klar att användas.\n\n%1$@ kommer att påminna dig att byta pod innan den utgår. Du kan ändra påminnelsetiden för detta."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Din podd kan eventuellt fortfarande ge Insulin.\nTa bort den från din kropp och tryck sedan på ”Fortsätt.”"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Tystad"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normalt läge när ljud är på för både varningar och för bekräftelser."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "\"Varningar kommer inte längre använda ljud och även alla bekräftelseljud kommer att vara avstängda. Podden kommer bara att pipa om du väljer att spela upp testljud.\n\n⚠️Varning - när podden är tystad måste du vara inom räckhåll för dina enheter för att få några poddvarningar.\""; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Tysta podden"; - -/* title for pod details page */ -"Pod Details" = "Poddetaljer"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Detaljer om tidigare podd"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Information om pumphanteraren"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Hämtar pumphanterarens detaljer..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Uppdatera pumphanterarens detaljer"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Misslyckades att uppdatera inställning för tystad podd."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostik"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Läd poddstatus"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/tr.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/tr.lproj/Localizable.strings deleted file mode 100644 index 57e1e7557..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/tr.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ önce"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%1$@ vücudunuzdaki pod ile iletişimi yeniden sağladı.\n\nİnsülin iletim kayıtları güncellendi ve gerçekte iletilenlerle eşleşmelidir.\n\nŞimdi normal şekilde %2$@ kullanmaya devam edebilirsiniz."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ Ü"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ Ü (Tamamlandı)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ Ü'si %2$@ Ü'nin (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ Ü/saat"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ Ü"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@Ü"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%2$@ için %1$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ , %2$@ tarihinden beri vücudunuzdaki pod ile iletişim kuramıyor. \n\nPod ile iletişim olmadan, uygulama insülin iletimi için komutlar göndermeye devam edemez ve aktif insülininiz veya pod tarafından verilen insülin hakkında doğru ve güncel bilgileri görüntüleyemez. \n\n Vücudunuzda aktif olarak çalışan ve %3$@ tarafından görüntülenemeyen insülin olabilir veya olmayabilir, önümüzdeki 6 saat veya daha uzun bir süre boyunca kan şekerinizi yakından takip edin."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ ünite kaldı %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. İnsülin iletimi durdu. Lütfen pod'u devre dışı bırakın ve çıkarın."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%gr Ü"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 saat"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 saat 30 dakika"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 saat"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 dakika"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Aktif Zaman"; - -/* Section header for activity section */ -"Activity" = "Aktivite"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Pompa Zamanı Ayarlanıyor..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Alarmlar"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Pod kurulumunu iptal etmek istediğinizden emin misiniz?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Bu pod'u kapatmak istediğinizden emin misiniz?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Omnipod katılımını atlamak istediğinizden emin misiniz?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Omnipod'u kullanmayı bırakmak istediğinizden emin misiniz?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Atanan Adres"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Pod Ekleme"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "İletişim yeniden kuruluyor"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Geri"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Bazal İletimi"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Bazal Oranlar"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Bolus İletimi"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "İptal"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Manuel Bazalı İptal Et"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Kanül başarıyla yerleştirildi. Devam et."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Pod'u şimdi değiştirin. İnsülin iletimi, podun süresi dolduktan 8 saat sonra veya insülin kalmadığında duracaktır."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Pod'u şimdi değiştirin. İnsülin iletimi %1$@ içinde veya insülin kalmadığında duracaktır."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Saat Dilimini Değiştir"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Saat değiştiriliyor…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Kanülü Kontrol Edin"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Pod'u kontrol edin, uygulayın, ardından pod eklemeyi onaylayın."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Yerleştirmeyi Kontrol Et"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Kontrol ediliyor..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "İletişim Kurtarıldı"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Emniyet Hatırlatıcıları"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced."; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfigürasyon"; - -/* Button title for confirm attachment option */ -"Confirm" = "Onayla"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Pod Eklemeyi Onayla"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Devam et"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Kritik Uyarılar"; - -/* Unit for singular day in pod life remaining */ -"day" = "gün"; - -/* Unit for plural days in pod life remaining */ -"days" = "gün"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Devre dışı bırak"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Pod'u devre dışı bırak"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Devre dışı"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Devre dışı bırakılıyor."; - -/* Action button description while deactivating */ -"Deactivating..." = "Devre dışı bırakılıyor..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Omnipod'u Sil"; - -/* Title text for delivery limits */ -"Delivery Limits" = "İletim Limitleri"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Cihaz Detayları"; - -/* The title of the device information section in settings */ -"Device Information" = "Cihaz bilgisi"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Cihazlar"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Bolus Bip Seslerini Devre Dışı Bırak"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Podu At"; - -/* No comment provided by engineer. */ -"Done" = "Tamamlandı"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Bolus Bip Seslerini Etkinleştir"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Hata"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Bolus bip sesleri devre dışı bırakılırken hata oluştu"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Bolus bip sesleri etkinleştirilirken hata oluştu"; - -/* The alert title for a resume error */ -"Error Resuming" = "Sürdürme Hatası"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Askıya Alma Hatası"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Süre Sonu Hatırlatıcısı"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Varsayılan Süre Sonu Hatırlatıcısı"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Süresi doldu"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Süresi doluyor"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Manuel Bazal İptal Edilemedi"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "İnsülin İletimine Devam Edilemedi"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Pompa Zamanı Ayarlanamadı"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "İnsülin İletimi Askıya Alınamadı"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Emniyet hatırlatıcısı tercihi güncellenemedi."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Süre Sonu Hatırlatıcısı Güncellenemedi"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Düşük Rezervuar Hatırlatıcısı Güncellenemedi"; - -/* Pod life HUD view label */ -"Fault" = "Hata"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Yeni bir podu U-100 İnsülin ile doldurun (Pod iğne kapağını çıkarmayın). 2 bip sesini dinleyin."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Devre Dışı Bırakmayı Bitir"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Pod kurulumunu tamamlayın"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Kurulumu Bitir"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "%2$@ de kalan %1$@ üniteden fazla"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "saat"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "saat"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Pod kurulumunu iptal ederseniz, mevcut Pod devre dışı bırakılır ve kullanılamaz hale gelir."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Tam olarak kurulmamış pod, yeni bir pod ile eşleştirilmeden önce devre dışı bırakılmalıdır. Lütfen pod'u devre dışı bırakın ve atın."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Tam olarak kurulmamış pod, yeni bir pod ile eşleştirilmeden önce devre dışı bırakılmalıdır. Lütfen pod'u devre dışı bırakın ve çıkarın."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Kanül yerleştirin"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Yerleştirildi"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Yerleştiriliyor. Lütfen bekleyin.."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Yerleştiriliyor..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "İnsülin\nAskıya alındı"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "İnsülin İletildi"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "İnsulin İletimi"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "İnsülin iletimi durdu. Pod'u şimdi değiştirin."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Siz manuel olarak devam edene kadar insülin iletimi durdurulacaktır. Loop'un iletime devam etmenizi ne zaman hatırlatmasını istersiniz?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Kalan İnsülin"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "İnsülin Tipi"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Geçersiz Girdi"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Kanül düzgün yerleştirildi mi?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Eşleştirme sırasında RileyLink'i pod'dan yaklaşık 15cm uzakta tutun."; - -/* description label for last status date pod details row */ -"Last Status" = "Son Durum"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop, geçici bazal oran bitene veya iptal edilene kadar insülin iletiminizi otomatik olarak ayarlamaz."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Parti"; - -/* description label for lot number pod details row */ -"Lot Number" = "Parti Numarası"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Düşük Rezervuar"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Düşük Rezervuar Hatırlatıcısı"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Telefonunuzun ve podunuzun birbirine yakın olduğundan emin olun. İletişim sorunları devam ederse, yeni bir alana geçin."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "dakika"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "dakika"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Eksik Yapılandırma"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "mev. değil"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Sonraki"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Hayır"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "İletim\nYok"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "İnsülin yok"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Pod Yok"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Hatırlatıcı Yok"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Hayır, Pod ile Devam Et"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Hayır, Pompayı Olduğu Gibi Tutun"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Hiçbiri"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Bildirim ayarları"; - -/* No comment provided by engineer. */ -"Numbers" = "Sayılar"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Hatırlatıcıları"; - -/* Button title to pair with pod during setup */ -"Pair" = "Eşleştir"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Yeni Pod'u Eşleştirme"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pod eşleştirme"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Pod eşleştir"; - -/* Label text indicating pairing finished. */ -"Paired" = "Eşleştirilmiş"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Eşleştiriliyor."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Eşleştiriliyor…"; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Yüzde = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PI Sürümü"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Test Bip Sesi Çal"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Test Bip Sesi Çalınıyor…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Lütfen Pod'un vücudunuza güvenli bir şekilde takıldığından emin olun. \n\n Kanül, her Pod ile yalnızca bir kez yerleştirilebilir. Pod eklendiğinde \"Onayla\"ya dokunun."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Lütfen podu devre dışı bırakın. Devre dışı bırakma tamamlandığında, yeni bir podu eşleştirebilirsiniz."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Lütfen podu devre dışı bırakın. Devre dışı bırakma tamamlandığında onu çıkarabilir ve yeni bir podu eşleştirebilirsiniz."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PM Sürümü"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod Etkinleştirildi"; - -/* Label describing pod age view */ -"Pod Age" = "Pod Yaşı"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod başarıyla devre dışı bırakıldı. Devam et."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Pod Hatası"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod'un süresi doldu"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod Süresi Doldu"; - -/* Label for pod expiration row */ -"Pod Expires" = "Podun Süresi Doluyor"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Podun süresi şu tarihte doluyor:"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Hata Detayları"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Pod Tıkanıklığı"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod başarıyla eşleştirildi. Devam et."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Pod Ayarları"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Kurulumu"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Bölgeyi hazırlayın."; - -/* title for previous pod page */ -"Previous Pod" = "Önceki Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Önceki Pod Bilgileri"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Hazırlandı"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Hazırlanıyor. Lütfen bekleyin."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Hazırlanıyor..."; - -/* The text of the loading label when priming */ -"Priming…" = "Hazırlanıyor…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pompa Zamanı"; - -/* Label text for basal rate summary */ -"Rate" = "Oran"; - -/* Label describing time remaining view */ -"Remaining" = "Kalan"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Podu Vücuttan Çıkarın"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Pompayı Çıkar"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Remove the Pod's clear needle cap and check cannula. Then remove paper backing."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Pod'u Değiştir"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Pod'u Şimdi Değiştirin"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Rezervuar"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "İnsülin İletimine Devam Et"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "İnsülin iletimine devam ediliyor..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Yeniden dene"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Pod Devre Dışı Bırakmayı Yeniden Dene"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink, pompa ile Bluetooth üzerinden iletişim kurulmasını sağlar"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink Kurulumu"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Kaydet"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Kaydediliyor..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Çizelge"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Programlanan Bazal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Planlanmış Hatırlatıcı"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Bu pod için kullanacağınız insülin tipini seçin."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sıra numarası"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Geçici Bazal Ayarla"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Geçici Bazal Oranı Ayarla"; - -/* Title for setup complete screen */ -"Setup Complete" = "Kurulum tamamlandı"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Sinyal Kaybı"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Omnipod Katılımı Atlansın mı?"; - -/* The title of the status section in settings */ -"Status" = "Durum"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Başarılı"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "İletimi Askıya Al"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "İnsülin İletimini Askıya Al"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Askıya alındı"; - -/* Label for suspended at time */ -"Suspended At" = "Askıya Alındı"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "İnsülin iletimi askıya alınıyor..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Omnipod Pompalardan Geçiş"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Diğer insülin iletim cihazına geçin"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Geçerli Saate Senkronize Et"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Pod ile Senkronize Et"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Kanül yerleştirmeyi başlatmak için aşağıya dokunun."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Geçici Bazal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Geçici Bazal Başarısız"; - -/* The title of the command to run the test command */ -"Test Command" = "Komut testi"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Komutlar test ediliyor…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Uygulama, Pod süresi dolmadan önce sizi bilgilendirmek için pod üzerinde bir hatırlatıcı yapılandırır. Yeni bir Pod eşleştirirken kaç saat önce bildirim almak istediğinizi yapılandırın."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Uygulama, Pod'un süresinin dolacağını size önceden bildirir.\n\nKaç saat önceden bildirimde bulunmak istediğinizi ayarlamak için kaydırın."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Uygulama, Poddaki insülin miktarı (50-10 U) seviyesine ulaştığında sizi bilgilendirir.\n\nHatırlatılmasını istediğiniz seviyeyi ayarlamak için kaydırın."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Uygulama, Poddaki insülin miktarı bu seviyeye ulaştığında sizi bilgilendirir."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Pompanızdaki saat geçerli saatten farklı. Pompanızdaki saati geçerli saate güncellemek istiyor musunuz?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Pompanızdaki saat, geçerli saatten farklı. Pompanızın zamanı, planlanmış tedavi ayarlarınızı kontrol eder. Saat farkını gözden geçirmek ve pompanızı yapılandırmak için Pompa Saati satırına ilerleyin."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Kanül cilde düzgün bir şekilde yerleştirildiğinde Pod'un üst kısmındaki pencere pembe renkte olmalıdır."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Pod ile iletişim kurarken bir sorun oluştu. Bu sorun devam ederse Pod'u At'a dokunun. Daha sonra yeni bir Pod etkinleştirebilirsiniz."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Bu, mevcut Podunuzu eşleştirdiğinizde planladığınız bir hatırlatıcıdır."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "Bu Pompa, manuel geçici bazal bir özellik olmadan önce eklendiği için maksimum bazal oranla yapılandırılmamıştır. Lütfen tedavi ayarları -> iletim limitleri bölümüne gidin ve yeni bir maksimum bazal oran ayarlayın."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Zaman"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Zaman Değişikliği Algılandı"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Geçiş işareti"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Çok fazla giriş"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Toplam İletim"; - -/* Units for showing temp basal rate */ -"U/hr" = "Ü/sa"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Pod devre dışı bırakılamıyor. Lütfen devam edin ve yeni bir pod eşleştirin."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Pod'a Ulaşılamıyor"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Geçici bir bazal oran ayarlanamıyor: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Geçici bir bazal oran ayarlanamıyor: %1$@ \n\n %2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Tamamlanmamış Etkinleştirme"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Tamamlanmamış devre dışı bırakma"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Bilinmeyen"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Yerleştirme işlemi tamamlanana kadar bekleyin."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Evet"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Evet, Pod'u Devre Dışı Bırak"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Evet, Geçerli Saatle Senkronize Et"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Şimdi hatırlatıcılarınızı yapılandırma, Pod'unuzu insülinle doldurma, cihazınızla eşleştirme ve vücudunuza yerleştirme işlemlerine başlayacaksınız."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Pod'unuz kullanıma hazır. \n\n %1$@ Pod'unuzun süresi dolmadan önce değiştirmenizi hatırlatacak. Bunu size uygun bir zamana değiştirebilirsiniz."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Pod'unuz hala İnsülin veriyor olabilir.\nVücudunuzdan çıkarın ve ardından \"Devam\"a dokunun."; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/uk.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/uk.lproj/Localizable.strings deleted file mode 100644 index d881fe33a..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/uk.lproj/Localizable.strings +++ /dev/null @@ -1,812 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ тому"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ відновив зв’язок з Podʼом на вашому тілі.\n\nЗаписи про подачу інсуліну оновлені та мають збігатися з фактично поданими.\n\nВи можете продовжувати використовувати %@ у звичайному режимі."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (Завершено)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%@ U з %@ U (%@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = " %@U/год"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ для %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ не зміг зв’язатись з Podʼом на вашому тілі з %2$@.\n\nБез зв’язку з Podʼом програма не може продовжувати надсилати команди для подачі інсуліну або відображати точну, останню інформацію про ваш активний інсулін або інсулін, який подає Pod.\n\nУважно стежте за своїм рівнем глюкози протягом наступних 6 або більше годин, оскільки у вашому організмі може активно працювати або не працювати інсулін, який %3$@ не може відобразити."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ одиниць залишилося на %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Подачу інсуліну припинено. Будь ласка, деактивуйте та зніміть Pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 годину"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 годину 30 хвилин"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 години"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 хвилин"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Активний час"; - -/* Section header for activity section */ -"Activity" = "Активність"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Налаштування часу помпи..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Попередження"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Ви впевнені, що бажаєте скасувати налаштування Podʼа?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Ви впевнені, що хочете вимкнути цей Pod?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Ви впевнені, що хочете пропустити Omnipod Onboarding?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Ви впевнені, що хочете припинити використовувати Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Призначена адреса"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Прикріпіть Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Спроба відновити зв'язок"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Тому"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Подача Базалу"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Швидкості Базалу"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Подача Болюса"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Відмінити"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Відмінити ручну базу"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Канюлю введено успішно. Продовжити."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Замінити Pod зараз. Подача інсуліну припиниться за 8 годин після закінчення Podʼа або коли не залишиться інсуліну."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Замінити Pod зараз. Подача інсуліну припиниться через %1$@ або коли не залишиться інсуліну."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Змінити часовий пояс"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Зміна часу…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Перевірте канюлю"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Перевірте Pod, встановіть на місце, потім підтвердіть встановлення Podʼа."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Перевірка введення канюлі"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Перевірка..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Зв'язок відновлено"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Нагадування про Впевненість"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Сигнали підтвердження — це звукові сигнали Podʼа, які можна використовувати для підтвердження вибраних команд."; - -/* The title of the configuration section in settings */ -"Configuration" = "Налаштування"; - -/* Button title for confirm attachment option */ -"Confirm" = "Підтвердити"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Підтвердити встановлення Podʼа"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Продовжити"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Критичні сповіщення"; - -/* Unit for singular day in pod life remaining */ -"day" = "день"; - -/* Unit for plural days in pod life remaining */ -"days" = "дні"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Деактивувати"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Проведіть, щоб деактивувати Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Деактивувати Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Деактивовано"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Деактивую."; - -/* Action button description while deactivating */ -"Deactivating..." = "Деактивую..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Видалити Omnipod "; - -/* Title text for delivery limits */ -"Delivery Limits" = "Ліміти подачі"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Деталі пристрою"; - -/* The title of the device information section in settings */ -"Device Information" = "Інформація про пристрій"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Пристрої"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Вимкнути сигнал болюса"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Скасувати Pod"; - -/* No comment provided by engineer. */ -"Done" = "Готово"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Увімкнути сигнал болюса"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Помилка"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Помилка вимкнення сигналу болюса"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Помилка увімкнення сигналу болюса"; - -/* The alert title for a resume error */ -"Error Resuming" = "Помилка відновлення"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Помилка призупинення"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Нагадування про термін дії"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Нагадування про закінчення терміну дії за замовчанням"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Минув термін дії"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Термін закінчується"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Не вдалося відмінити ручний базал"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Не вдалося відновити подачу інсуліну"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Не вдалося встановити час помпи"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Не вдалося призупинити подачу інсуліну"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Не вдалося оновити налаштування сигналів підтвердження."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Не вдалося оновити нагадування про закінчення терміну дії"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Не вдалося оновити нагадування про низький рівень резервуару"; - -/* Pod life HUD view label */ -"Fault" = "Збій"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Заправити новий Pod інсуліном (не менше U-100, не знімати кришку канюлі). Дочекатись 2 сигналів."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Завершити деактивацію"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Завершити налаштування Podʼа"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Завершити налаштування"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Залишилось більше %1$@ одиниць на %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "годин"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "годин"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Якщо ви скасуєте налаштування Podʼа, цей Pod буде дезактивовано, він стане непридатним для використання."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Старий Pod має бути деактивований, для створення пари з новим. Будь ласка, деактивуйте та зніміть старий Pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Старий Pod має бути деактивований, для створення пари з новим. Будь ласка, деактивуйте та зніміть старий Pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Ввести канюлю"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Введено"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Введення канюлі. Будь ласка зачекайте."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Введення..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Інсулін\nПризупинено"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Інсулін подано"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Подача інсуліну"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Подачу інсуліну припинено. Замініть Pod зараз."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Подачу інсуліну буде припинено, доки ви не відновите її вручну. Коли ви хочете, щоб петля нагадала вам відновити подачу?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Залишок інсуліну"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Тип інсуліну"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Невірний запис"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Чи правильно введена канюля?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Під час зʼєднання тримайте RileyLink на відстані близько 20 см від Podʼа."; - -/* description label for last status date pod details row */ -"Last Status" = "Останній статус"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Петля не регулюватиме подачу інсуліну автоматично, доки тимчасова база не закінчиться або не буде скасована."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Партія"; - -/* description label for lot number pod details row */ -"Lot Number" = "Номер партії"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Пустий резервуар"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Нагадування про низький рівень резервуару"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Переконайтеся, що ваш телефон і Pod знаходяться поруч один з одним. Якщо проблеми звʼязку не зникають, перейдіть у інше місце."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "хвилин"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "хвилин"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Відсутня конфігурація"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Далі"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Ні"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Без\nДоставки"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Без інсуліну"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Немає Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Немає нагадувань"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Ні, продовжити з Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Ні, залишити як є"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Жоден"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Параметри сповіщень"; - -/* No comment provided by engineer. */ -"Numbers" = "Числа"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Нагадування Omnipod"; - -/* Button title to pair with pod during setup */ -"Pair" = "Зʼєднати"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Зʼєднати новий Pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Зʼєднати Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Зʼєднати Pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Зʼєднано"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Зʼєднання."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Зʼєднання..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Відсоток = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "Версія PI"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Програти тестовий звук"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Програти тестовий звук"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Переконайтесь, що Pod надійно прикріплений до вашого тіла.\n\nКанюлю можна вставити лише один раз з кожним Podʼом. Натисніть «Підтвердити», коли Pod прикріплено."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Будь ласка, деактивуйте Pod. Після завершення деактивації ви можете зʼєднати новий Pod."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Будь ласка, деактивуйте Pod. Після завершення деактивації ви можете зняти його та зʼєднати новий Pod."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "Версія PM"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod активований"; - -/* Label describing pod age view */ -"Pod Age" = "Вік Pod'у"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod успішно деактивовано. Продовжити."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Помилка Podʼа"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Термін дії Podʼа минув"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Термін дії Podʼа минув"; - -/* Label for pod expiration row */ -"Pod Expires" = "Термін дії Podʼа добігає кінця"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod закінчується через"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Деталі несправності Podʼа"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Помпа забита"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod успішно зʼєднано. Продовжити."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Налаштування Podʼа"; - -/* Title for PodSetupView */ -"Pod Setup" = "Налаштування Podʼа"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Підготуйте місце встановлення Pod'a"; - -/* title for previous pod page */ -"Previous Pod" = "Попередній Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Попередня інформація про Pod"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Заправлено"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Заправка. Будь ласка, чекайте."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Заправка..."; - -/* The text of the loading label when priming */ -"Priming…" = "Заправка…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Час помпи"; - -/* Label text for basal rate summary */ -"Rate" = "Швидкість"; - -/* Label describing time remaining view */ -"Remaining" = "Залишок"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Зняти Pod з тіла"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Зніміть Pod"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Видаліть синю кришку голки Podʼа та перевірте канюлю. Потім зніміть паперову підкладку."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Замініть Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Замініть Pod зараз"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Резервуар"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Відновити подачу інсуліну"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Відновлення подачі інсуліну..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Спробувати знову"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Повторити деактивацію Podʼа"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "Rileylink дозволяє звʼязатись з помпою через Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "Налаштування RileyLink"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Зберегти"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Збереження..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Розклад"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Запланований Базал"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Заплановане нагадування"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Виберіть тип інсуліну, який ви будете використовувати у цьому Podʼі."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Порядковий номер"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Встановити Тимчасову Базальну Швидкість"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Встановити Тимчасову Базальну Швидкість"; - -/* Title for setup complete screen */ -"Setup Complete" = "Налаштування завершено"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Втрата сигналу"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Пропустити онборт Omnipod?"; - -/* The title of the status section in settings */ -"Status" = "Статус"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Успішно"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Зупинити подачу"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Зупинити подачу інсуліну"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Зупинено"; - -/* Label for suspended at time */ -"Suspended At" = "Призупинено у"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Призупинення введення інсуліну..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Відключитися від помп Omnipod"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Перейдіть на інший пристрій для введення інсуліну"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Встановити поточний час"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Синхронізація з Pod'ом"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Натисніть нижче, щоб розпочати введення канюлі."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Тимчасова Базальна Швидкість"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Тимчасова Базальна Швідкість не виконана"; - -/* The title of the command to run the test command */ -"Test Command" = "Провести тест"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Команди Тестів"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Програма налаштовує нагадування на телефоні, щоб повідомити вас про закінчення терміну дії Podʼу. Встановіть кількість годин попереднього повідомлення, яку ви хочете зберегти при поєднанні нового Pod'у."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Програма заздалегідь сповіщає вас про закінчення терміну дії Podʼу.\n\nПрокрутіть, щоб установити кількість годин попереднього сповіщення, яке ви хочете отримувати."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Додаток сповістить вас, коли кількість інсуліну в Podʼі досягне цього рівня (50-10 ОД).\n\nПрокрутіть, щоб установити кількість одиниць, про яку ви хочете отримати нагадування."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Програма сповіщає вас, коли кількість інсуліну в Podʼі досягає цього рівня."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Нагадування вище не звучатимуть, якщо ваш пристрій перебуває в беззвучному режимі або режимі «Не турбувати».\n\nІснують інші важливі сповіщення та будильники Pod, які лунатимуть, навіть якщо на вашому пристрої встановлено режим «Без звуку» або «Не турбувати»."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Час на вашому Pod'i відрізняється від поточного часу. Хочете оновити час на Pod'i до поточного?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Час на вашому Pod'i відрізняється від поточного часу. Час вашого Podʼу контролює налаштування запланованої терапії. Прокрутіть униз до рядка Час Podʼу, щоб переглянути різницю в часі та налаштувати Pod."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Віконце у верхній частині Pod'y повинно бути рожевим, коли канюля правильно вставлена в тіло."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Виникла проблема зв’язку з Pod. Якщо проблема не зникає, торкніться «Відхилити Pod». Потім ви можете активувати новий Pod."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Це нагадування, яке ви запланували, коли сполучали свій поточний Pod."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "Цю помпу не було налаштовано на максимальну базальну швидкість, оскільки її було додано до появи функції ручного тимчасового базального введення. Будь ласка, перейдіть до Налаштування терапії -> Обмеження доставки та встановіть нову максимальну базальну дозу."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Час"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Виявлено зміну часу"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Знак перемикання"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Забагато записів"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Подано всього"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/год"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Не вдалося деактивувати Pod. Пропустити та розпочати з'єднання з новим."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Неможливо зв'язатися з Pod"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Неможливо встановити Тимчасову Базальну Швидкість: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Не вдалося встановити Тимчасову Базальну Швидкість: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Незавершена активація"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Незавершена активація"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Невідомий"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Дочекайтеся завершення введення."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Так"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Так, відключити Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Так, синхронізувати з поточним часом"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Тепер ви почнете процес налаштування нагадувань, заправки Podʼа інсуліном, зʼєднання з пристроєм та розміщення його на своєму тілі."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Ваш Pod готовий до використання.\n\n%1$@ нагадає вам замінити Pod до його закінчення. Ви можете змінити це на зручний для вас час."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Ваш Pod може все ще подавати інсулін.\nЗніміть його зі свого тіла, а потім натисніть «Продовжити»"; -<<<<<<< HEAD -<<<<<<< HEAD -======= -======= ->>>>>>> Crowdin - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Сповіщення вимкнено"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Звичайний режим роботи, коли звукові сигнали Pod використовуються для всіх сповіщень Pod і коли ввімкнено нагадування про конфіденційність."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Усі сповіщення Pod не використовують звукові сигнали, а звукові сигнали нагадування про підтвердження пригнічуються. Pod подає звукові сигнали лише у разі фатальних помилок Pod і під час відтворення тестових звукових сигналів.\n\n⚠️Попередження. Щоразу, коли Pod вимкнено, він має залишатися в зоні дії Bluetooth цього пристрою, щоб отримувати сповіщення про сповіщення Pod."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Деталі Pod"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Попередні подробиці Pod"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Деталі менеджера помпи"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Отримання деталей менеджера помп..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Оновити відомості про керування помпами"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Не вдалося оновити налаштування сигналів підтвердження."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Діагностика"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Отримати статус Pod'у"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/vi.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/vi.lproj/Localizable.strings deleted file mode 100644 index 494893f41..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/vi.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ trước đó"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ đã khôi phục liên lạc với pod trên cơ thể bạn.\n\nHồ sơ tiêm insulin đã được cập nhật và phải khớp với việc tiêm thực sự.\n\nBạn có thể tiếp tục sử dụng %@ một cách bình thường ngay bây giờ."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (Đã hoàn tất)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ U of %2$@ U (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/giờ"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ cho %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ đã không thể giao tiếp với pod trên cơ thể bạn kể từ %2$@.\n\nNếu không liên lạc với pod, ứng dụng không thể tiếp tục gửi lệnh tiêm insulin hoặc hiển thị thông tin chính xác, các thông tin gần đây về insulin đang hoạt động của bạn hoặc insulin được Pod tiêm.\n\nTheo dõi chặt chẽ lượng glucose của bạn trong 6 giờ tiếp theo hoặc hơn, vì có thể có hoặc không có insulin hoạt động tích cực trong cơ thể bạn mà %3$@ không thể hiển thị."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units vẫn đang còn lúc %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. Việc tiêm Insulin đã dừng. Hủy kích hoạt và thay pod."; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 giờ"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 giờ 30 phút"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2 giờ"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 phút"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Thời gian Hoạt động"; - -/* Section header for activity section */ -"Activity" = "Hoạt động"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Đang điều chỉnh thời gian của bơm..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "Cảnh báo"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "Bạn có chắc chắn muốn hủy cấu hình pod?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "Bạn có chắc muốn tắt pod này?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Bạn có chắc muốn bỏ qua?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "Bạn có chắc muốn dừng sử dụng Omnipod?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Địa chỉ được chỉ định"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Attach Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Đang cố gắng thiết lập lại giao tiếp"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Quay Lại"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "Liều tiêm basal"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "Lịch biểu tiêm liều nền"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "Liều tiêm bolus"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Hủy bỏ"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Hủy bỏ liều basal thủ công"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Cannula gắn thành công. Tiếp tục."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "Thay pod ngay. Insulin sẽ ngưng khi pod hết hạn 8 giờ tới hoặc khi không còn insulin."; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Thay pod ngay. Insulin sẽ ngưng tiêm trong %1$@ hoặc khi không còn insulin."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "Thay đổi múi giờ"; - -/* Progress message for changing pod time. */ -"Changing time…" = "Đang thay đổi giờ…"; - -/* Title for check cannula screen */ -"Check Cannula" = "Kiểm tra Cannula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "Kiểm tra pod, gắn vào vị trí sau đó xác nhận pod đã được gắn chặt."; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Kiểm tra việc gắn"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Đang kiểm tra..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comms Recovered"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Lời nhắc độ tin cậy"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Lời nhắc là những tiếng bíp từ Pod có thể được sử dụng để xác nhận các lệnh đã chọn khi Pod không ở chế độ im lặng."; - -/* The title of the configuration section in settings */ -"Configuration" = "Cấu hình"; - -/* Button title for confirm attachment option */ -"Confirm" = "Xác nhận"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "Xác nhận pod đã gắn chặt"; - -/* The title of the continue action in an action sheet */ -"Continue" = "Tiếp tục"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Cảnh báo nghiêm trọng"; - -/* Unit for singular day in pod life remaining */ -"day" = "ngày"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "Hủy kích hoạt"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Trượt để vô hiệu hóa Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "Hủy kích hoạt Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "Đã hủy kích hoạt"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "Đang hủy kích hoạt."; - -/* Action button description while deactivating */ -"Deactivating..." = "Đang hủy kích hoạt..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "Xóa Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "Giới hạn liều tiêm"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "Chi tiết thiết bị"; - -/* The title of the device information section in settings */ -"Device Information" = "Thông tin thiết bị"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "Thiết bị"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "Vô hiệu tiếng Beep liều bolus"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "Loại bỏ pod"; - -/* No comment provided by engineer. */ -"Done" = "Hoàn thành"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "Bật tiếng Beep liều bolus"; - -/* Accessibility label indicating an error occurred */ -"Error" = "Lỗi"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "Lỗi trong việc vô hiệu tiếng beep liều bolus"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "Lỗi trong việc bật tiếng beep liều bolus"; - -/* The alert title for a resume error */ -"Error Resuming" = "Lỗi khi đang tái thực hiện"; - -/* The alert title for a suspend error */ -"Error Suspending" = "Lỗi khi đang tạm ngưng"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Nhắc nhở Hết hạn"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Mặc định nhắc nhở hết hạn"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Đã hết hạn"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Hết hạn"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "Không thể hủy liều basal thủ công"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "Không thể tiêm insulin trở lại"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "Không thể cài đặt thời gian cho bơm"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Thất bại khi tạm dừng liều insulin"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Không cập nhật được tùy chọn lời nhắc về độ tin cậy."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Failed to Update Expiration Reminder"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Thất bại cập nhật lời nhắc gần hết thuốc"; - -/* Pod life HUD view label */ -"Fault" = "Lỗi"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Dùng loại insulin U-100 cho pod. Lắng nghe 2 tiếng bíp."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "Hoàn tất việc ngưng kích hoạt"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "Hoàn tất thiết lập pod"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "Hoàn thành cài đặt"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Nhiều hơn %1$@ units vẫn còn lúc %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "giờ"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "giờ"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "Nếu bạn hủy cấu hình pod, pod hiện tại sẽ bị hủy kích hoạt và sẽ không sử dụng được nữa."; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Thiết lập pod không hoàn thành phải được hủy rước khi tiến hành ghép đôi pod mới. Đề nghị hủy và loại pod."; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Thiết lập pod không hoàn thành phải được hủy rước khi tiến hành ghép đôi pod mới. Đề nghị hủy và thay thế pod."; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "Lắp Cannula"; - -/* Label text indicating insertion finished. */ -"Inserted" = "Đã gắn"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Đang gắn. Chờ chút."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Đang gắn..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\n Đã tạm ngưng"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "Insulin đã được tiêm"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "Khối lượng tiêm insulin"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulin ngừng. Thay Pod ngay."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Việc tiêm insulin sẽ bị dừng cho đến khi bạn tiếp tục theo cách thủ công. Vậy khi nào bạn muốn Loop nhắc bạn tiếp tục tiêm?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "Insulin còn lại"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "Loại Insulin"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "Lỗi nhập không hợp lệ"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "Việc gắn cannual chuẩn chưa?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Để Rileylink cách pod 6 inches khi ghép đôi."; - -/* description label for last status date pod details row */ -"Last Status" = "Trạng thái cuối"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop sẽ không tự động điều chỉnh liều insulin đến khi liều nền tạm thời thực hiện xong hoặc bị hủy bỏ."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "Lô"; - -/* description label for lot number pod details row */ -"Lot Number" = "Số Lô"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Sắp hết thuốc"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Báo nhắc gần hết thuốc"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Đảm bảo điện thoại và pod được đặt gần nhau. Nếu kết nối vẫn gặp trở ngại, đặt lại chổ khác."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "phút"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "phút"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Thiếu cấu hình"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Kế tiếp"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "Không"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "Không\n Tiêm"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "Hết thuốc"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "Không pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "Không có lời nhắc"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "Không, tiếp tục"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "Không, Giữ nguyên"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "Không"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "Cài đặt thông báo"; - -/* No comment provided by engineer. */ -"Numbers" = "Số"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Lời nhắc của Omnipod"; - -/* Button title to pair with pod during setup */ -"Pair" = "Ghép đôi"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "Ghép đôi pod mới"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Kết nối Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "Kết nối Pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "Đã được ghép đôi"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "Đang ghép đôi."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "Đang ghép đôi..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Phần trăm = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "Phiên bản PI"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "Kiểm tra tiếng Beep"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "Kiểm tra tiếng Beep…"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "Xác nhận rằng Pod được gắn chặt vào cơ thể bạn.\n\nCannula chỉ có thể lắp một lần. Nhấn vào “Xác nhận” khi Pod đã gắn chặt."; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "Hủy kích hoạt pod. Khi việc hủy kích hoạt hoàn tất, bạn có thể ghép nối pod mới."; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "Hủy kích hoạt pod. Khi việc hủy kích hoạt hoàn tất, gỡ bỏ pod ra khỏi cơ thể và ghép nối pod mới."; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "Phiên bản PM"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod đã kích hoạt"; - -/* Label describing pod age view */ -"Pod Age" = "Tuổi Pod"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod hủy kích hoạt thành công. Tiếp tục."; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Lỗi Pod"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod đã hết hạn"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod đã hết hạn"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod hết hạn"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod sẽ hết hạn trong"; - -/* description label for pod fault details */ -"Pod Fault Details" = "Thông tin lỗi Pod"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod ghép đôi thành công. Tiếp tục."; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Các thiết lập cho pod"; - -/* Title for PodSetupView */ -"Pod Setup" = "Cấu hình Pod"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "Chuẩn bị vị trí."; - -/* title for previous pod page */ -"Previous Pod" = "Pod trước"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Thông tin Pod trước đó"; - -/* The text of the loading label when pod is primed */ -"Primed" = "Đã được mồi"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "Đang priming. Xin chờ."; - -/* Pod pairing action button text while priming */ -"Priming..." = "Priming..."; - -/* The text of the loading label when priming */ -"Priming…" = "Đang mồi…"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Thời gian của Bơm"; - -/* Label text for basal rate summary */ -"Rate" = "Tỷ lệ"; - -/* Label describing time remaining view */ -"Remaining" = "Đang còn lại"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "Gỡ pod khỏi cơ thể"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Thay bơm"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Tháo nắp kim màu xanh và kiểm tra cannula. Sau đó gỡ bỏ lớp giấy phía sau."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "Thay thế Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "Thay thế pod ngay"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "Ngăn chứa insulin"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Phục hồi liều insulin"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Đang phục hồi liều insulin..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "Thử lại"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "Hủy kích hoạt pod lại"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink cho phép giao tiếp với bơm thông qua kết nối bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "Cài đặt RileyLink"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "Lưu"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "Đang lưu..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "Kế hoạch"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "Đã lên chương trình cho liều Basal"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Lịch biểu lời nhắc"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Chọn loại insulin bạn sẽ sử dụng cho pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Số thứ tự"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Cài đặt liều nền tạm thời"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Cài đặt liều nền tạm thời"; - -/* Title for setup complete screen */ -"Setup Complete" = "Cấu hình hoàn thành"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Mất tín hiệu"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Bỏ qua quá trình giới thiệu Omnipod?"; - -/* The title of the status section in settings */ -"Status" = "Tình trạng"; - -/* A message indicating a command succeeded */ -"Succeeded" = "Đã thành công"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "Tạm ngưng liều insulin"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "Tạm dừng insulin"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "Đã tạm ngưng"; - -/* Label for suspended at time */ -"Suspended At" = "Tạm ngưng tại"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Đang tạm dừng liều insulin..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "Chuyển đổ từ bơm Omnipod"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Chuyển đổi sang bơm khác"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Đồng bộ thời gian hiện tại"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "Sync với Pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "Chạm phía dưới để bắt đầu gắn cannula."; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Liều nền tạm thời"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Liều nền tạm thời thất bại"; - -/* The title of the command to run the test command */ -"Test Command" = "Thử nghiệm câu lệnh"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "Thử nghiệm câu lệnh…"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "Ứng dụng cấu hình lời nhắc trên pod để thông báo trước cho bạn khi pod hết hạn. Đặt số giờ bạn muốn cấu hình khi ghép nối pod mới."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "Ứng dụng sẽ thông báo trước cho bạn thời gian pod hết hạn.\n\n Kéo xuống để thiết lập số giờ để ứng dụng thông báo."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "Ứng dụng sẽ thông báo khi lượng insulin trong Pod đạt đến mức này (50-10 U).\n\n Kéo xuống để chọn số Unit mà bạn muốn để nhận thông báo."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "Ứng dụng nhắc nhở bạn khi lượng insulin trong pod đạt đến mức này."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "Lời nhắc ở trên sẽ không phát ra âm thanh nếu thiết bị của bạn ở trạng thái Silent hoặc Do Not Disturb.\n\n Có nhiều cách cảnh báo khác nhau phát ra âm thanh ngay cả khi thiết bị của bạn ở trạng thái Silent hoặc Do Not Disturb."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "Thời gian trên máy bơm của bạn khác với thời gian hiện tại. Bạn có muốn cập nhật thời gian trên máy bơm của mình đến thời điểm hiện tại không?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "Thời gian trên máy bơm của bạn khác với thời gian hiện tại. Thời gian của máy bơm sẽ kiểm soát cài đặt trị liệu theo lịch trình của bạn. Cuộn xuống đến Pump Time để xem lại chênh lệch thời gian và cấu hình bơm của bạn."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "Ô vuông trên đầu của pod sẽ nháy đỏ khi cannual được gắn chuẩn vào trong cơ thể."; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "Đã xảy ra sự cố khi giao tiếp với Pod. Nếu sự cố này vẫn tiếp diễn, hãy nhấn vào Discard Pod. Sau đó, bạn có thể kích hoạt Pod mới."; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "Đây là lời nhắc mà bạn đã lên lịch khi ghép nối Pod hiện tại của mình."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "Máy bơm này chưa được cấu hình với maximum basal rate vì nó đã được thêm vào trước khi manual temp basal được đưa ra. Vui lòng đi tới Therapy Settings -> Delivery Limites và đặt Maximum Basal Rate mới."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "Thời gian"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "Thay đổi thời gian được phát hiện"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Chuyển đổi tín hiệu"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Quá nhiều mục"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Tổng liều"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/giờ"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "Không thể hủy kích hoạt pod. Đề nghị tiếp tục và ghép đôi pod mới."; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Không thể thấy pod"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Không thể cài đặt liều nền tạm thời: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Không thể cài đặt liều nền tạm thời: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "Kích hoạt chưa hoàn thành"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "Vô hiệu hóa chưa hoàn tất"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "Không nhận ra"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "Đợi đến khi việc gắn hoàn tất."; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Có"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "Có, hủy kích hoạt pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Có, đồng bộ với thời gian hiện tại"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "Bạn bắt đầu quá trình cài đặt các lời nhắc, đổ đầy thuốc vào pod, ghép đôi thiết bị và gắn pod lên người."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "Pod đã sẵn sàng hoạt động.\n\n%1$@ sẽ nhắc nhở bạn thay đổi khi pod hết hạn. Bạn có thể thay khi nào tiện."; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "Pod có thể đang tiêm insulin.\n Gỡ pod khỏi người sau đó nhấn \"Continue.\""; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Im lặng"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Chế độ hoạt động bình thường trong đó tiếng bíp của Pod được dùng cho mọi cảnh báo của Pod và khi lời nhắc được bật."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "Tất cả các cảnh báo của Pod đều không sử dụng tiếng bíp và tiếng bíp nhắc nhở sẽ bị chặn. Pod sẽ chỉ phát ra tiếng bíp khi Pod gặp lỗi nghiêm trọng và khi thực hiện kiểm tra tiếng bíp.\n\n⚠️Cảnh báo - Bất cứ khi nào Pod ở chế độ im lặng, nó phải được đặt trong phạm vi hoạt động của Bluetooth để nhận thông báo về các cảnh báo của Pod."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Pod im lặng"; - -/* title for pod details page */ -"Pod Details" = "Các thông tin của Pod"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Thông tin của Pod trước đó"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Đang truy xuất thông tin Pump Manager..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Làm mới Pump Manager Details"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Không thể cập nhật im lặng cho pod."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Chẩn đoán"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Đọc tình trạng pod"; diff --git a/Dependencies/OmniKit/OmniKitUI/Resources/zh-Hans.lproj/Localizable.strings b/Dependencies/OmniKit/OmniKitUI/Resources/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 51edf6dfd..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Resources/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,807 +0,0 @@ -/* No comment provided by engineer. */ -"—" = "—"; - -/* Format string for last status date on pod details screen */ -"%@ ago" = "%@ ago"; - -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* No comment provided by engineer. */ -"%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now." = "%@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %@ normally now."; - -/* Format string for delivered insulin. (1: The localized amount) - Format string for insulin remaining in reservoir. (1: The localized amount) */ -"%@ U" = "%@ U"; - -/* Format string for bolus progress when finished. (1: The localized amount) */ -"%@ U (Finished)" = "%@ U (已输注)"; - -/* Format string for bolus progress. (1: The delivered amount) (2: The programmed amount) (3: the percent progress) */ -"%@ U of %@ U (%@)" = "%1$@ U of %2$@ U (%3$@)"; - -/* Format string for temp basal rate. (1: The localized amount) */ -"%@ U/hour" = "%@ U/小时"; - -/* Appends a full-stop to a statement */ -"%@." = "%@."; - -/* Format string for bolus percent progress. (1: Percent progress) */ -"%@%%" = "%@%%"; - -/* Format string for reservoir reading when above or equal to maximum reading. (1: The localized amount) */ -"%@+ U" = "%@+ U"; - -/* Format string for reservoir volume. (1: The localized volume) */ -"%@U" = "%@U"; - -/* Summary string for temporary basal rate configuration page */ -"%1$@ for %2$@" = "%1$@ for %2$@"; - -/* Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name) */ -"%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display." = "%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display."; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"%1$@ units remaining at %2$@" = "%1$@ units remaining at %2$@"; - -/* Format string providing instructions for replacing pod due to a fault. (1: The fault description) */ -"%1$@. Insulin delivery has stopped. Please deactivate and remove pod." = "%1$@. 胰岛素输注已停止,请移除Pod"; - -/* The format string for displaying an offset from a time zone: (1: GMT)(2: -)(3: 4:00) */ -"%1$@%2$@%3$@" = "%1$@%2$@%3$@"; - -/* Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units) */ -"%1$@+ %2$@" = "%1$@+ %2$@"; - -/* Format string for total delivery on pod details screen */ -"%g U" = "%g U"; - -/* Button text for 1 hour suspend duration */ -"1 hour" = "1 hour"; - -/* Button text for 1 hour 30 minute suspend duration */ -"1 hour 30 minutes" = "1 hour 30 minutes"; - -/* Button text for 2 hour suspend duration */ -"2 hours" = "2小时"; - -/* Button text for 30 minute suspend duration */ -"30 minutes" = "30 minutes"; - -/* The title of the cell showing the pod activated at time */ -"Active Time" = "Pod启动时间"; - -/* Section header for activity section */ -"Activity" = "活动"; - -/* Text indicating ongoing pump time synchronization */ -"Adjusting Pump Time..." = "Adjusting Pump Time..."; - -/* The title of the cell showing alarm status */ -"Alarms" = "提醒"; - -/* Alert title for cancel pairing modal */ -"Are you sure you want to cancel Pod setup?" = "您确定要取消Pod安装吗?"; - -/* Confirmation message for shutting down a pod */ -"Are you sure you want to shutdown this pod?" = "确定要停止这个Pod吗?"; - -/* No comment provided by engineer. */ -"Are you sure you want to skip Omnipod Onboarding?" = "Are you sure you want to skip Omnipod Onboarding?"; - -/* Confirmation message for removing Omnipod PumpManager */ -"Are you sure you want to stop using Omnipod?" = "确定要停止使用这个Pod吗?"; - -/* The title text for the address assigned to the pod */ -"Assigned Address" = "Assigned Address"; - -/* Title for Attach Pod screen */ -"Attach Pod" = "Attach Pod"; - -/* Description string above progress indicator while attempting to re-establish communication from an unacknowledged command */ -"Attemping to re-establish communication" = "Attemping to re-establish communication"; - -/* Back button text on DeliveryUncertaintyRecoveryView */ -"Back" = "Back"; - -/* The title of the cell showing pod basal status */ -"Basal Delivery" = "当前基础率"; - -/* The title text for the basal rate schedule */ -"Basal Rates" = "基础率"; - -/* The title of the cell showing pod bolus status */ -"Bolus Delivery" = "当前大剂量"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "取消"; - -/* Button title to cancel manual basal */ -"Cancel Manual Basal" = "Cancel Manual Basal"; - -/* Insert cannula action button accessibility label when cannula insertion succeeded */ -"Cannula inserted successfully. Continue." = "Cannula inserted successfully. Continue."; - -/* The action string on pod status page when pod expired */ -"Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains." = "现在更换Pod 。Pod 过期后的8小时后胰岛素输注将完全停止。"; - -/* Format string for the action string on pod status page when pod expired. (1: service time remaining) */ -"Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains." = "Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains."; - -/* The title of the command to change pump time zone */ -"Change Time Zone" = "更改时区"; - -/* Progress message for changing pod time. */ -"Changing time…" = "更改时间"; - -/* Title for check cannula screen */ -"Check Cannula" = "Check Cannula"; - -/* Label text for step three of attach pod instructions */ -"Check Pod, apply to site, then confirm pod attachment." = "检查Pod,贴在注射部位上,确保pod已经贴牢"; - -/* Insert cannula action button accessibility label checking insertion */ -"Checking Insertion" = "Checking Insertion"; - -/* Cannula insertion button text while checking insertion */ -"Checking..." = "Checking..."; - -/* Title for uncertainty recovered screen */ -"Comms Recovered" = "Comms Recovered"; - -/* Text for confidence reminders navigation link */ -"Confidence Reminders" = "Confidence Reminders"; - -/* Help text for BeepPreferenceSelectionView */ -"Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced." = "Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced."; - -/* The title of the configuration section in settings */ -"Configuration" = "配置"; - -/* Button title for confirm attachment option */ -"Confirm" = "确认"; - -/* Alert title for confirm pod attachment */ -"Confirm Pod Attachment" = "确认Pod粘贴牢固"; - -/* The title of the continue action in an action sheet */ -"Continue" = "继续"; - -/* Title for critical alerts description */ -"Critical Alerts" = "Critical Alerts"; - -/* Unit for singular day in pod life remaining */ -"day" = "天"; - -/* Unit for plural days in pod life remaining */ -"days" = "days"; - -/* Button title to deactivate pod because of fault during setup */ -"Deactivate" = "解除"; - -/* Action button description for deactivate while pod still active */ -"Slide to Deactivate Pod" = "Slide to Deactivate Pod"; - -/* Button title for pod deactivation - Button title to deactivate pod */ -"Deactivate Pod" = "解除Pod"; - -/* Label text showing pod is deactivated */ -"Deactivated" = "已解除"; - -/* Deactivate pod action button accessibility label while deactivating */ -"Deactivating." = "停用中"; - -/* Action button description while deactivating */ -"Deactivating..." = "Deactivating..."; - -/* Button title to delete Omnipod PumpManager */ -"Delete Omnipod" = "删除Omnipod"; - -/* Title text for delivery limits */ -"Delivery Limits" = "输注限制"; - -/* Text for device details disclosure row - title for device details page */ -"Device Details" = "设备详情"; - -/* The title of the device information section in settings */ -"Device Information" = "设备信息"; - -/* Header for devices section of RileyLinkSetupView */ -"Devices" = "设备"; - -/* Title text for button to disable bolus beeps */ -"Disable Bolus Beeps" = "禁用大剂量输注中提醒"; - -/* Pairing interface navigation bar button text for discard pod action - Text for discard pod button */ -"Discard Pod" = "丢弃Pod"; - -/* No comment provided by engineer. */ -"Done" = "完成"; - -/* Title text for button to enable bolus beeps */ -"Enable Bolus Beeps" = "启动大剂量输注中提醒"; - -/* Accessibility label indicating an error occurred */ -"Error" = "错误"; - -/* The alert title for disable bolus beeps error */ -"Error disabling bolus beeps" = "禁用大剂量输注中提醒错误"; - -/* The alert title for enable bolus beeps error */ -"Error enabling bolus beeps" = "启用大剂量输注中提醒错误"; - -/* The alert title for a resume error */ -"Error Resuming" = "恢复输注错误"; - -/* The alert title for a suspend error */ -"Error Suspending" = "无法暂停"; - -/* The title of the cell showing the pod expiration reminder date */ -"Expiration Reminder" = "Pod到期提醒"; - -/* Label text for expiration reminder default row */ -"Expiration Reminder Default" = "Expiration Reminder Default"; - -/* The title of the cell showing the pod expiration after expiry */ -"Expired" = "Pod已到期"; - -/* The title of the cell showing the pod expiration */ -"Expires" = "Pod即将到期"; - -/* Alert title for failing to cancel manual basal error */ -"Failed to Cancel Manual Basal" = "取消手动基础率失败"; - -/* Alert title for resume error */ -"Failed to Resume Insulin Delivery" = "恢复胰岛素输注失败"; - -/* Alert title for time sync error */ -"Failed to Set Pump Time" = "设置泵时间失败"; - -/* Alert title for suspend error */ -"Failed to Suspend Insulin Delivery" = "Failed to Suspend Insulin Delivery"; - -/* Alert title for error when updating confidence reminder preference */ -"Failed to update confidence reminder preference." = "Failed to update confidence reminder preference."; - -/* Alert title for error when updating expiration reminder */ -"Failed to Update Expiration Reminder" = "Failed to Update Expiration Reminder"; - -/* Alert title for error when updating low reservoir reminder */ -"Failed to Update Low Reservoir Reminder" = "Failed to Update Low Reservoir Reminder"; - -/* Pod life HUD view label */ -"Fault" = "错误"; - -/* Label text for step 1 of pair pod instructions */ -"Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps." = "Fill a new pod with U-100 Insulin (leave Pod needle cap on). Listen for 2 beeps."; - -/* Settings page link description when next lifecycle action is to finish deactivation */ -"Finish deactivation" = "完成停用"; - -/* The title of the command to finish pod setup */ -"Finish pod setup" = "完成设置"; - -/* Action button title to continue at Setup Complete */ -"Finish Setup" = "完成安装"; - -/* Accessibility format string for (1: localized volume)(2: time) */ -"Greater than %1$@ units remaining at %2$@" = "Greater than %1$@ units remaining at %2$@"; - -/* Unit for singular hour in pod life remaining */ -"hour" = "小时"; - -/* Unit for plural hours in pod life remaining */ -"hours" = "小时"; - -/* Alert message body for confirm pod attachment */ -"If you cancel Pod setup, the current Pod will be deactivated and will be unusable." = "如果您现在取消Pod 设置,当前Pod将被停用并报废。"; - -/* Instructions when deactivating pod that has been paired, but not attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and discard pod." = "Pod设置失败,请解除该从身体移除Pod,然后配对新Pod"; - -/* Instructions when deactivating pod that has been paired and possibly attached. */ -"Incompletely set up pod must be deactivated before pairing with a new one. Please deactivate and remove pod." = "Pod设置失败,请解除并从身体移除该Pod,然后配对新Pod"; - -/* Button title to insert cannula during setup */ -"Insert Cannula" = "植入Pod"; - -/* Label text indicating insertion finished. */ -"Inserted" = "插入完毕"; - -/* Insert cannula action button accessibility label while pairing */ -"Inserting. Please wait." = "Inserting. Please wait."; - -/* Cannula insertion button text while inserting */ -"Inserting..." = "Inserting..."; - -/* Text shown in insulin delivery space when insulin suspended */ -"Insulin\nSuspended" = "Insulin\nSuspended"; - -/* The title of the cell showing delivered insulin */ -"Insulin Delivered" = "已输注胰岛素"; - -/* Title of insulin delivery section */ -"Insulin Delivery" = "胰岛素输注"; - -/* The action string on pod status page when pod faulted */ -"Insulin delivery stopped. Change Pod now." = "Insulin delivery stopped. Change Pod now."; - -/* Message for suspend duration selection action sheet */ -"Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?" = "Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?"; - -/* Header for insulin remaining on pod settings screen */ -"Insulin Remaining" = "胰岛素余量"; - -/* Text for confidence reminders navigation link - Title for insulin type selection screen */ -"Insulin Type" = "胰岛素类型"; - -/* The error message shown when Loop's basal schedule has an unsupported rate */ -"Invalid entry" = "无效输入"; - -/* Question to confirm the cannula is inserted properly */ -"Is the cannula inserted properly?" = "软管是否成功插入?"; - -/* Label text for step 2 of pair pod instructions */ -"Keep the RileyLink about 6 inches from the pod during pairing." = "Keep the RileyLink about 6 inches from the pod during pairing."; - -/* description label for last status date pod details row */ -"Last Status" = "Last Status"; - -/* Description text on manual temp basal action sheet */ -"Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled." = "Loop will not automatically adjust your insulin delivery until the temporary basal rate finishes or is canceled."; - -/* The title of the cell showing the pod lot id */ -"Lot" = "批次号"; - -/* description label for lot number pod details row */ -"Lot Number" = "LOT Nummer"; - -/* Label text for low reservoir value row - Navigation bar title for LowReservoirReminderSetupView - Title for LowReservoirReminderSetupView */ -"Low Reservoir" = "Low Reservoir"; - -/* Label for low reservoir reminder row - Title for low reservoir reminder edit page */ -"Low Reservoir Reminder" = "Low Reservoir Reminder"; - -/* The action string on pod status page when pod data is stale */ -"Make sure your phone and pod are close to each other. If communication issues persist, move to a new area." = "Make sure your phone and pod are close to each other. If communication issues persist, move to a new area."; - -/* Unit for singular minute in pod life remaining */ -"minute" = "分钟"; - -/* Unit for plural minutes in pod life remaining */ -"minutes" = "分钟"; - -/* Alert title for missing temp basal configuration */ -"Missing Config" = "Missing Config"; - -/* String shown on pod details for active time when conversion fails. - String shown on pod details for last status date when not available. - String shown on pod details for total delivery when not available. */ -"NA" = "NV"; - -/* Text of continue button on ExpirationReminderSetupView */ -"Next" = "Next"; - -/* Button label for user to answer cannula was not properly inserted */ -"No" = "No"; - -/* Text shown in insulin remaining space when no pod is paired */ -"No\nDelivery" = "No\nDelivery"; - -/* Error message for reservoir view when reservoir empty */ -"No Insulin" = "No Insulin"; - -/* Label for pod life state when no pod paired - Text shown in insulin remaining space when no pod is paired */ -"No Pod" = "无Pod"; - -/* Value text for no expiration reminder */ -"No Reminder" = "No Reminder"; - -/* Continue pairing button title of in pairing cancel modal */ -"No, Continue With Pod" = "否,继续设置 Pod"; - -/* Button text to cancel pump time sync */ -"No, Keep Pump As Is" = "No, Keep Pump As Is"; - -/* The detail text for bolus delivery when no bolus is being delivered */ -"None" = "无"; - -/* navigation title for notification settings - Text for pod details disclosure row */ -"Notification Settings" = "通知设置"; - -/* No comment provided by engineer. */ -"Numbers" = "Numbers"; - -/* Title for omnipod reminders section */ -"Omnipod Reminders" = "Omnipod Reminders"; - -/* Button title to pair with pod during setup */ -"Pair" = "配对"; - -/* The title of the command to pair new pod */ -"Pair New Pod" = "配对新Pod"; - -/* Navigation bar title for PairPodView - Pod pairing action button text while ready to pair - Settings page link description when next lifecycle action is to pair new pod - Title for pod pairing screen */ -"Pair Pod" = "Pair Pod"; - -/* Pairing action button accessibility label while ready to pair */ -"Pair pod." = "配对Pod."; - -/* Label text indicating pairing finished. */ -"Paired" = "已配对"; - -/* Pairing action button accessibility label while pairing */ -"Pairing." = "配对中."; - -/* Pod pairing action button text while pairing */ -"Pairing..." = "配对中..."; - -/* No comment provided by engineer. */ -"Percent = %lf" = "Percent = %lf"; - -/* The title of the cell showing the pod pi version */ -"PI Version" = "PI版本号"; - -/* The title of the command to play test beeps */ -"Play Test Beeps" = "测试提示音"; - -/* Progress message for play test beeps. */ -"Play Test Beeps…" = "提示音测试中"; - -/* Alert message body for confirm pod attachment */ -"Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached." = "请确认Pod 已经安全地粘贴到到你的身体.\n\n每个Pod只能插入一次软管。当Pod被贴牢后,点击\"确认\""; - -/* Instructions for deactivate pod when pod not on body */ -"Please deactivate the pod. When deactivation is complete, you may pair a new pod." = "请先停用Pod, 停用完成后您可以配对一个新的Pod"; - -/* Instructions for deactivate pod when pod is on body */ -"Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod." = "请先停用Pod,停用完成后将Pod从身体上摘除并配对新的Pod"; - -/* The title of the cell showing the pod pm version */ -"PM Version" = "PM版本号"; - -/* description label for activated at time pod details row - Label for pod insertion row */ -"Pod Activated" = "Pod 已激活"; - -/* Label describing pod age view */ -"Pod Age" = "Pod使用天数"; - -/* Deactivate pod action button accessibility label when deactivation complete */ -"Pod deactivated successfully. Continue." = "Pod已成功停用,继续"; - -/* Error message for reservoir view during general pod fault */ -"Pod Error" = "Pod Error"; - -/* Label for pod life state when within pod expiration window */ -"Pod expired" = "Pod已到期"; - -/* Error message for reservoir view when pod expired - Label for pod expiration row, past tense */ -"Pod Expired" = "Pod已到期"; - -/* Label for pod expiration row */ -"Pod Expires" = "Pod有效期限"; - -/* Label for pod life state when time remaining */ -"Pod expires in" = "Pod将过期于 "; - -/* description label for pod fault details */ -"Pod Fault Details" = "Pod Fault Details"; - -/* Error message for reservoir view when pod occlusion checks failed */ -"Pod Occlusion" = "Pod Occlusion"; - -/* Pairing action button accessibility label when pairing succeeded */ -"Pod paired successfully. Continue." = "Pod配对成功,继续"; - -/* Title of the pod settings view controller */ -"Pod Settings" = "Pod设置"; - -/* Title for PodSetupView */ -"Pod Setup" = "Pod Setup"; - -/* Label text for step one of attach pod instructions */ -"Prepare site." = "将注射部位做好准备"; - -/* title for previous pod page */ -"Previous Pod" = "Previous Pod"; - -/* Text for previous pod information row */ -"Previous Pod Information" = "Previous Pod Information"; - -/* The text of the loading label when pod is primed */ -"Primed" = "已充盈"; - -/* Pairing action button accessibility label while priming */ -"Priming. Please wait." = "准备中,请稍候"; - -/* Pod pairing action button text while priming */ -"Priming..." = "充盈中..."; - -/* The text of the loading label when priming */ -"Priming…" = "正在充盈"; - -/* The title of the command to change pump time zone */ -"Pump Time" = "Pump Time"; - -/* Label text for basal rate summary */ -"Rate" = "输注率"; - -/* Label describing time remaining view */ -"Remaining" = "剩余"; - -/* Title for remove pod modal */ -"Remove Pod from Body" = "从身体上取下Pod"; - -/* Title for Omnipod PumpManager deletion action sheet. */ -"Remove Pump" = "Remove Pump"; - -/* Label text for step two of attach pod instructions */ -"Remove the Pod's clear needle cap and check cannula. Then remove paper backing." = "Remove the Pod's clear needle cap and check cannula. Then remove paper backing."; - -/* Label indicating pod replacement necessary - The title of the command to replace pod */ -"Replace Pod" = "更换Pod"; - -/* The title of the command to replace pod when there is a pod fault */ -"Replace Pod Now" = "现在更换Pod"; - -/* The title of the cell showing reservoir status */ -"Reservoir" = "胰岛素容量"; - -/* Text for suspend resume button when insulin delivery is suspended */ -"Resume Insulin Delivery" = "Resume Insulin Delivery"; - -/* Text for suspend resume button when insulin delivery is resuming */ -"Resuming insulin delivery..." = "Resuming insulin delivery..."; - -/* Action button description for deactivate after failed attempt - Cannula insertion button text while showing error - Pod pairing action button text while showing error */ -"Retry" = "重试"; - -/* Button title for retrying pod deactivation */ -"Retry Pod Deactivation" = "重新尝试解绑"; - -/* bodyText for RileyLinkSetupView */ -"RileyLink allows for communication with the pump over Bluetooth" = "RileyLink allows for communication with the pump over Bluetooth"; - -/* Navigation title for RileyLinkSetupView */ -"RileyLink Setup" = "RileyLink设置"; - -/* Title of button to save delivery limit settings - Title of button to sync basal profile when no pod paired */ -"Save" = "保存"; - -/* button title for saving low reservoir reminder while saving - button title for saving scheduled reminder while saving */ -"Saving..." = "正在保存..."; - -/* The detail text of the basal row when pod is running scheduled basal */ -"Schedule" = "预设"; - -/* Title of insulin delivery section */ -"Scheduled Basal" = "预设基础率"; - -/* Card title for scheduled reminder - Scheduled reminder card title on NotificationSettingsView - Title for scheduled expiration reminder edit page - Title of SetupCompleteView */ -"Scheduled Reminder" = "Scheduled Reminder"; - -/* Title text for insulin type confirmation page */ -"Select the type of insulin that you will be using in this pod." = "Select the type of insulin that you will be using in this pod."; - -/* description label for sequence number pod details row */ -"Sequence Number" = "Sequence Number"; - -/* Button text for setting manual temporary basal rate */ -"Set Temporary Basal" = "Set Temporary Basal"; - -/* Button title to set temporary basal rate */ -"Set Temporary Basal Rate" = "Set Temporary Basal Rate"; - -/* Title for setup complete screen */ -"Setup Complete" = "设置完成"; - -/* Error message for reservoir view during general pod fault */ -"Signal Loss" = "Signal Loss"; - -/* No comment provided by engineer. */ -"Skip Omnipod Onboarding?" = "Skip Omnipod Onboarding?"; - -/* The title of the status section in settings */ -"Status" = "状态"; - -/* A message indicating a command succeeded */ -"Succeeded" = "成功"; - -/* Title for suspend duration selection action sheet */ -"Suspend Delivery" = "暂停输注"; - -/* Text for suspend resume button when insulin delivery active */ -"Suspend Insulin Delivery" = "暂停胰岛素输注"; - -/* The detail text of the basal row when pod is suspended */ -"Suspended" = "暂停"; - -/* Label for suspended at time */ -"Suspended At" = "Suspended At"; - -/* Text for suspend resume button when insulin delivery is suspending */ -"Suspending insulin delivery..." = "Suspending insulin delivery..."; - -/* Title text for the button to delete Omnipod PumpManager */ -"Switch from Omnipod Pumps" = "删除Omnipod泵"; - -/* Label for PumpManager deletion button */ -"Switch to other insulin delivery device" = "Switch to other insulin delivery device"; - -/* The title of the command to change pump time zone */ -"Sync to Current Time" = "Sync to Current Time"; - -/* Title of button to sync basal profile from pod */ -"Sync With Pod" = "同步配置到Pod"; - -/* Label text for step one of insert cannula instructions */ -"Tap below to start cannula insertion." = "点击下面的按钮开始插入软管"; - -/* Navigation Title for ManualTempBasalEntryView */ -"Temporary Basal" = "Temporary Basal"; - -/* Alert title for a failure to set temporary basal */ -"Temporary Basal Failed" = "Temporary Basal Failed"; - -/* The title of the command to run the test command */ -"Test Command" = "测试命令"; - -/* Progress message for testing commands. */ -"Testing Commands…" = "测试命令进行中"; - -/* Footer text for omnipod reminders section */ -"The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod." = "The app configures a reminder on the pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure when pairing a new Pod."; - -/* Description text on ExpirationReminderSetupView */ -"The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have." = "The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have."; - -/* Description text on LowReservoirReminderSetupView */ -"The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded." = "The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded."; - -/* Footer text for low reservoir value row */ -"The App notifies you when the amount of insulin in the Pod reaches this level." = "The App notifies you when the amount of insulin in the Pod reaches this level."; - -/* Description text for critical alerts */ -"The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode." = "The reminders above will not sound if your device is in Silent or Do Not Disturb mode.\n\nThere are other critical Pod alerts and alarms that will sound even if your device is set to Silent or Do Not Disturb mode."; - -/* Message for pod sync time action sheet */ -"The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?" = "The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?"; - -/* description for time change detected notice */ -"The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump." = "The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump."; - -/* Description of proper cannula insertion */ -"The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin." = "当软管被正确插入皮肤时,Pod顶部的透明窗口应该有粉红色"; - -/* Format string for recovery suggestion during deactivate pod. */ -"There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod." = "与Pod通讯时出现问题。如果这个问题无法解决,请弃用此Pod,并激活一个新Pod。"; - -/* Footer text for scheduled reminder area */ -"This is a reminder that you scheduled when you paired your current Pod." = "This is a reminder that you scheduled when you paired your current Pod."; - -/* Alert format string for missing temp basal configuration. */ -"This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate." = "This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Therapy Settings -> Delivery Limits and set a new Maximum Basal Rate."; - -/* Label for expiration reminder row - Label for scheduled expiration reminder row - Label for scheduled reminder value row */ -"Time" = "时间"; - -/* Title for pod sync time action sheet. - title for time change detected notice */ -"Time Change Detected" = "检测到时间变化"; - -/* No comment provided by engineer. */ -"Toggle sign" = "Toggle sign"; - -/* The error message shown when Loop's basal schedule has more entries than the pod can support */ -"Too many entries" = "Pod不支持该基础率设置"; - -/* description label for total delivery pod details row */ -"Total Delivery" = "Total Delivery"; - -/* Units for showing temp basal rate */ -"U/hr" = "U/小时"; - -/* Instructions when pod cannot be deactivated */ -"Unable to deactivate pod. Please continue and pair a new one." = "无法解除Pod,请配对新Pod"; - -/* Title of delivery uncertainty recovery page */ -"Unable to Reach Pod" = "Unable to Reach Pod"; - - -/* Alert format string for a failure to set temporary basal. (1: error description) */ -"Unable to set a temporary basal rate: %1$@" = "Unable to set a temporary basal rate: %1$@"; - -/* Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text) */ -"Unable to set a temporary basal rate: %1$@\n\n%2$@" = "Unable to set a temporary basal rate: %1$@\n\n%2$@"; - -/* Label for pod life state when pod not fully activated */ -"Unfinished Activation" = "未完成启用"; - -/* Label for pod life state when pod not fully deactivated */ -"Unfinished deactivation" = "尚未完成停用"; - -/* The detail text for delivered insulin when no measurement is available */ -"Unknown" = "未知"; - -/* Label text for step two of insert cannula instructions */ -"Wait until insertion is completed." = "等待,直到插入完成"; - -/* Button label for user to answer cannula was properly inserted */ -"Yes" = "Yes"; - -/* Button title for confirm deactivation option */ -"Yes, Deactivate Pod" = "是的,解除Pod"; - -/* Button text to confirm pump time sync */ -"Yes, Sync to Current Time" = "Yes, Sync to Current Time"; - -/* bodyText for PodSetupView */ -"You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body." = "You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body."; - -/* Format string for instructions for setup complete view. (1: app name) */ -"Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you." = "您的Pod 已准备好。\n\n%1$@ 将会在Pod到期前发出提醒。 您也可以自行设定到期提醒时间"; - -/* Alert message body for confirm pod attachment */ -"Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“" = "您的Pod 可能仍在输注胰岛素。\n将其从您的身体中取下,然后点击“继续”。"; - -/* Title string for SilencePodPreference.enabled */ -"Silenced" = "Silenced"; - -/* Description for SilencePodPreference.disabled */ -"Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled." = "Normal operation mode where audible Pod beeps are used for all Pod alerts and when confidence reminders are enabled."; - -/* Description for SilencePodPreference.enabled */ -"All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts." = "All Pod alerts use no beeps and confirmation reminder beeps are suppressed. The Pod will only beep for fatal Pod faults and when playing test beeps.\n\n⚠️Warning - Whenever the Pod is silenced it must be kept within Bluetooth range of this device to receive notifications for Pod alerts."; - -/* Help text for Silence Pod view */ -/* navigation title for Silnce Pod" */ - -"Silence Pod mode suppresses all Pod alert and confirmation reminder beeping. -Silence Pod" = "Silence Pod"; - -/* title for pod details page */ -"Pod Details" = "Pod Details"; - -/* Text for previous pod details row" */ -"Previous Pod Details" = "Previous Pod Details"; - -/* Text for pump manager details navigation link */ -"Pump Manager Details" = "Pump Manager Details"; - -/* button title when retrieving pump manager details */ -"Retrieving Pump Manager Details..." = "Retrieving Pump Manager Details..."; -/* button title to refresh pump manager details */ -"Refresh Pump Manager Details" = "Refresh Pump Manager Details"; - -/* Alert title for error when updating silence pod preference */ -"Failed to update silence pod preference." = "Failed to update silence pod preference."; - -/* Section header for diagnostic section */ -"Diagnostics" = "Diagnostics"; - -/* Text for read pod status navigation link */ -"Read Pod Status" = "Read Pod Status"; diff --git a/Dependencies/OmniKit/OmniKitUI/ViewControllers/OmnipodUICoordinator.swift b/Dependencies/OmniKit/OmniKitUI/ViewControllers/OmnipodUICoordinator.swift deleted file mode 100644 index 1101e3d93..000000000 --- a/Dependencies/OmniKit/OmniKitUI/ViewControllers/OmnipodUICoordinator.swift +++ /dev/null @@ -1,469 +0,0 @@ -// -// OmnipodUICoordinator.swift -// OmniKit -// -// Created by Pete Schwamb on 2/16/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation - -import UIKit -import SwiftUI -import Combine -import LoopKit -import LoopKitUI -import OmniKit -import RileyLinkKit -import RileyLinkBLEKit -import RileyLinkKitUI - -enum OmnipodUIScreen { - case firstRunScreen - case expirationReminderSetup - case lowReservoirReminderSetup - case insulinTypeSelection - case rileyLinkSetup - case pairPod - case insertCannula - case confirmAttachment - case checkInsertedCannula - case setupComplete - case pendingCommandRecovery - case uncertaintyRecovered - case deactivate - case settings - - func next() -> OmnipodUIScreen? { - switch self { - case .firstRunScreen: - return .expirationReminderSetup - case .expirationReminderSetup: - return .lowReservoirReminderSetup - case .lowReservoirReminderSetup: - return .insulinTypeSelection - case .insulinTypeSelection: - return .rileyLinkSetup - case .rileyLinkSetup: - return .pairPod - case .pairPod: - return .confirmAttachment - case .confirmAttachment: - return .insertCannula - case .insertCannula: - return .checkInsertedCannula - case .checkInsertedCannula: - return .setupComplete - case .setupComplete: - return nil - case .pendingCommandRecovery: - return .deactivate - case .uncertaintyRecovered: - return nil - case .deactivate: - return .pairPod - case .settings: - return nil - } - } -} - -class OmnipodUICoordinator: UINavigationController, PumpManagerOnboarding, CompletionNotifying, UINavigationControllerDelegate { - - public weak var pumpManagerOnboardingDelegate: PumpManagerOnboardingDelegate? - - public weak var completionDelegate: CompletionDelegate? - - var pumpManager: OmnipodPumpManager - - private var disposables = Set() - - var currentScreen: OmnipodUIScreen { - return screenStack.last! - } - - var screenStack = [OmnipodUIScreen]() - - private let colorPalette: LoopUIColorPalette - - private var pumpManagerType: OmnipodPumpManager.Type? - - private var allowedInsulinTypes: [InsulinType] - - private var allowDebugFeatures: Bool - - private func viewControllerForScreen(_ screen: OmnipodUIScreen) -> UIViewController { - switch screen { - case .firstRunScreen: - let view = PodSetupView(nextAction: { [weak self] in self?.stepFinished() }, - allowDebugFeatures: allowDebugFeatures, - skipOnboarding: { [weak self] in // NOTE: DEBUG FEATURES - DEBUG AND TEST ONLY - guard let self = self else { return } - self.pumpManager.completeOnboard() - self.completionDelegate?.completionNotifyingDidComplete(self) - }) - return hostingController(rootView: view) - case .rileyLinkSetup: - let dataSource = RileyLinkListDataSource(rileyLinkPumpManager: pumpManager) - var view = RileyLinkSetupView( - dataSource: dataSource, - nextAction: { [weak self] in self?.stepFinished() }) - view.cancelButtonTapped = { [weak self] in - self?.setupCanceled() - } - return hostingController(rootView: view) - - case .expirationReminderSetup: - var view = ExpirationReminderSetupView(expirationReminderDefault: Int(pumpManager.defaultExpirationReminderOffset.hours)) - view.valueChanged = { [weak self] value in - self?.pumpManager.defaultExpirationReminderOffset = .hours(Double(value)) - } - view.continueButtonTapped = { [weak self] in - guard let self = self else { return } - if !self.pumpManager.isOnboarded { - self.pumpManager.completeOnboard() - self.pumpManagerOnboardingDelegate?.pumpManagerOnboarding(didOnboardPumpManager: self.pumpManager) - } - self.stepFinished() - } - view.cancelButtonTapped = { [weak self] in - self?.setupCanceled() - } - let hostedView = hostingController(rootView: view) - hostedView.navigationItem.title = LocalizedString("Expiration Reminder", comment: "Title for ExpirationReminderSetupView") - return hostedView - case .lowReservoirReminderSetup: - var view = LowReservoirReminderSetupView(lowReservoirReminderValue: Int(pumpManager.lowReservoirReminderValue)) - view.valueChanged = { [weak self] value in - self?.pumpManager.lowReservoirReminderValue = Double(value) - } - view.continueButtonTapped = { [weak self] in - self?.pumpManager.initialConfigurationCompleted = true - self?.stepFinished() - } - view.cancelButtonTapped = { [weak self] in - self?.setupCanceled() - } - let hostedView = hostingController(rootView: view) - hostedView.navigationItem.title = LocalizedString("Low Reservoir", comment: "Title for LowReservoirReminderSetupView") - hostedView.navigationItem.backButtonDisplayMode = .generic - return hostedView - case .insulinTypeSelection: - let didConfirm: (InsulinType) -> Void = { [weak self] (confirmedType) in - self?.pumpManager.insulinType = confirmedType - self?.stepFinished() - } - let didCancel: () -> Void = { [weak self] in - self?.setupCanceled() - } - - let insulinSelectionView = InsulinTypeConfirmation(initialValue: .novolog, supportedInsulinTypes: allowedInsulinTypes, didConfirm: didConfirm, didCancel: didCancel) - let hostedView = hostingController(rootView: insulinSelectionView) - hostedView.navigationItem.title = LocalizedString("Insulin Type", comment: "Title for insulin type selection screen") - return hostedView - case .deactivate: - let viewModel = DeactivatePodViewModel(podDeactivator: pumpManager, podAttachedToBody: pumpManager.podAttachmentConfirmed, fault: pumpManager.state.podState?.fault) - - viewModel.didFinish = { [weak self] in - self?.stepFinished() - } - viewModel.didCancel = { [weak self] in - self?.setupCanceled() - } - let view = DeactivatePodView(viewModel: viewModel) - let hostedView = hostingController(rootView: view) - hostedView.navigationItem.title = LocalizedString("Deactivate Pod", comment: "Title for deactivate pod screen") - return hostedView - case .settings: - let viewModel = OmnipodSettingsViewModel(pumpManager: pumpManager) - viewModel.didFinish = { [weak self] in - self?.stepFinished() - } - viewModel.navigateTo = { [weak self] (screen) in - self?.navigateTo(screen) - } - let rileyLinkListDataSource = RileyLinkListDataSource(rileyLinkPumpManager: pumpManager) - - let handleRileyLinkSelection = { [weak self] (device: RileyLinkDevice) in - if let self = self { - let vc = RileyLinkDeviceTableViewController( - device: device, - batteryAlertLevel: self.pumpManager.rileyLinkBatteryAlertLevel, - batteryAlertLevelChanged: { [weak self] value in - self?.pumpManager.rileyLinkBatteryAlertLevel = value - } - ) - self.show(vc, sender: self) - } - } - - let view = OmnipodSettingsView(viewModel: viewModel, rileyLinkListDataSource: rileyLinkListDataSource, handleRileyLinkSelection: handleRileyLinkSelection, supportedInsulinTypes: allowedInsulinTypes) - return hostingController(rootView: view) - case .pairPod: - pumpManagerOnboardingDelegate?.pumpManagerOnboarding(didCreatePumpManager: pumpManager) - - let viewModel = PairPodViewModel(podPairer: pumpManager) - - viewModel.didFinish = { [weak self] in - self?.stepFinished() - } - viewModel.didCancelSetup = { [weak self] in - self?.setupCanceled() - } - viewModel.didRequestDeactivation = { [weak self] in - self?.navigateTo(.deactivate) - } - - let view = hostingController(rootView: PairPodView(viewModel: viewModel)) - view.navigationItem.title = LocalizedString("Pair Pod", comment: "Title for pod pairing screen") - view.navigationItem.backButtonDisplayMode = .generic - return view - case .confirmAttachment: - let view = AttachPodView( - didConfirmAttachment: { [weak self] in - self?.pumpManager.podAttachmentConfirmed = true - self?.stepFinished() - }, - didRequestDeactivation: { [weak self] in - self?.navigateTo(.deactivate) - }) - - let vc = hostingController(rootView: view) - vc.navigationItem.title = LocalizedString("Attach Pod", comment: "Title for Attach Pod screen") - vc.navigationItem.hidesBackButton = true - return vc - - case .insertCannula: - let viewModel = InsertCannulaViewModel(cannulaInserter: pumpManager) - - viewModel.didFinish = { [weak self] in - self?.stepFinished() - } - viewModel.didRequestDeactivation = { [weak self] in - self?.navigateTo(.deactivate) - } - - let view = hostingController(rootView: InsertCannulaView(viewModel: viewModel)) - view.navigationItem.title = LocalizedString("Insert Cannula", comment: "Title for insert cannula screen") - view.navigationItem.hidesBackButton = true - return view - case .checkInsertedCannula: - let view = CheckInsertedCannulaView( - didRequestDeactivation: { [weak self] in - self?.navigateTo(.deactivate) - }, - wasInsertedProperly: { [weak self] in - self?.stepFinished() - } - ) - let hostedView = hostingController(rootView: view) - hostedView.navigationItem.title = LocalizedString("Check Cannula", comment: "Title for check cannula screen") - hostedView.navigationItem.hidesBackButton = true - return hostedView - case .setupComplete: - guard let podExpiresAt = pumpManager.expiresAt, - let allowedExpirationReminderDates = pumpManager.allowedExpirationReminderDates - else { - fatalError("Cannot show setup complete UI without expiration and allowed reminder dates.") - } - let formatter = DateFormatter() - formatter.dateStyle = .medium - formatter.timeStyle = .short - - let view = SetupCompleteView( - scheduledReminderDate: pumpManager.scheduledExpirationReminder, - dateFormatter: formatter, - allowedDates: allowedExpirationReminderDates, - onSaveScheduledExpirationReminder: { [weak self] (newExpirationReminderDate, completion) in - var intervalBeforeExpiration : TimeInterval? - if let newExpirationReminderDate = newExpirationReminderDate { - intervalBeforeExpiration = podExpiresAt.timeIntervalSince(newExpirationReminderDate) - } - self?.pumpManager.updateExpirationReminder(intervalBeforeExpiration, completion: completion) - }, - didFinish: { [weak self] in - self?.stepFinished() - }, - didRequestDeactivation: { [weak self] in - self?.navigateTo(.deactivate) - } - ) - - let hostedView = hostingController(rootView: view) - hostedView.navigationItem.title = LocalizedString("Setup Complete", comment: "Title for setup complete screen") - return hostedView - case .pendingCommandRecovery: - if let pendingCommand = pumpManager.state.podState?.unacknowledgedCommand, pumpManager.state.podState?.needsCommsRecovery == true { - - let model = DeliveryUncertaintyRecoveryViewModel(appName: appName, uncertaintyStartedAt: pendingCommand.commandDate) - model.didRecover = { [weak self] in - self?.navigateTo(.uncertaintyRecovered) - } - model.onDeactivate = { [weak self] in - self?.navigateTo(.deactivate) - } - model.onDismiss = { [weak self] in - if let self = self { - self.completionDelegate?.completionNotifyingDidComplete(self) - } - } - pumpManager.getPodStatus() { _ in } - - let handleRileyLinkSelection = { [weak self] (device: RileyLinkDevice) in - if let self = self { - let vc = RileyLinkDeviceTableViewController( - device: device, - batteryAlertLevel: self.pumpManager.rileyLinkBatteryAlertLevel, - batteryAlertLevelChanged: { [weak self] value in - self?.pumpManager.rileyLinkBatteryAlertLevel = value - } - ) - self.show(vc, sender: self) - } - } - - let dataSource = RileyLinkListDataSource(rileyLinkPumpManager: pumpManager) - let view = DeliveryUncertaintyRecoveryView(model: model, rileyLinkListDataSource: dataSource, handleRileyLinkSelection: handleRileyLinkSelection) - - let hostedView = hostingController(rootView: view) - hostedView.navigationItem.title = LocalizedString("Unable To Reach Pod", comment: "Title for pending command recovery screen") - return hostedView - } else { - fatalError("Pending command recovery UI attempted without pending command") - } - case .uncertaintyRecovered: - var view = UncertaintyRecoveredView(appName: appName) - view.didFinish = { [weak self] in - self?.stepFinished() - } - let hostedView = hostingController(rootView: view) - hostedView.navigationItem.title = LocalizedString("Comms Recovered", comment: "Title for uncertainty recovered screen") - return hostedView - } - } - - private func hostingController(rootView: Content) -> DismissibleHostingController { - return DismissibleHostingController(rootView: rootView, colorPalette: colorPalette) - } - - private func stepFinished() { - if let nextStep = currentScreen.next() { - navigateTo(nextStep) - } else { - completionDelegate?.completionNotifyingDidComplete(self) - } - } - - func navigateTo(_ screen: OmnipodUIScreen) { - screenStack.append(screen) - let viewController = viewControllerForScreen(screen) - viewController.isModalInPresentation = false - self.pushViewController(viewController, animated: true) - viewController.view.layoutSubviews() - } - - private func setupCanceled() { - completionDelegate?.completionNotifyingDidComplete(self) - } - - init(pumpManager: OmnipodPumpManager? = nil, colorPalette: LoopUIColorPalette, pumpManagerSettings: PumpManagerSetupSettings? = nil, allowDebugFeatures: Bool, allowedInsulinTypes: [InsulinType] = []) - { - if pumpManager == nil, let pumpManagerSettings = pumpManagerSettings { - let basalSchedule = pumpManagerSettings.basalSchedule - - let deviceProvider = RileyLinkBluetoothDeviceProvider(autoConnectIDs: []) - - let pumpManagerState = OmnipodPumpManagerState( - isOnboarded: false, - podState: nil, - timeZone: basalSchedule.timeZone, - basalSchedule: BasalSchedule(repeatingScheduleValues: basalSchedule.items), - rileyLinkConnectionManagerState: nil, - insulinType: nil, - maximumTempBasalRate: pumpManagerSettings.maxBasalRateUnitsPerHour) - - self.pumpManager = OmnipodPumpManager(state: pumpManagerState, rileyLinkDeviceProvider: deviceProvider) - } else { - guard let pumpManager = pumpManager else { - fatalError("Unable to create Omnipod PumpManager") - } - self.pumpManager = pumpManager - } - - self.colorPalette = colorPalette - - self.allowDebugFeatures = allowDebugFeatures - - self.allowedInsulinTypes = allowedInsulinTypes - - super.init(navigationBarClass: UINavigationBar.self, toolbarClass: UIToolbar.self) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func determineInitialStep() -> OmnipodUIScreen { - if pumpManager.state.podState?.needsCommsRecovery == true { - return .pendingCommandRecovery - } else if pumpManager.podCommState == .activating { - if pumpManager.podAttachmentConfirmed { - return .insertCannula - } else { - return .confirmAttachment - } - } else if !pumpManager.isOnboarded { - if !pumpManager.initialConfigurationCompleted { - return .firstRunScreen - } - return .pairPod - } else { - return .settings - } - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - if screenStack.isEmpty { - screenStack = [determineInitialStep()] - let viewController = viewControllerForScreen(currentScreen) - viewController.isModalInPresentation = false - setViewControllers([viewController], animated: false) - } - } - - override func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - completionDelegate?.completionNotifyingDidComplete(self) - } - - var customTraitCollection: UITraitCollection { - // Select height reduced layouts on iPhone SE and iPod Touch, - // and select regular width layouts on larger screens, for list rendering styles - if UIScreen.main.bounds.height <= 640 { - return UITraitCollection(traitsFrom: [super.traitCollection, UITraitCollection(verticalSizeClass: .compact)]) - } else { - return UITraitCollection(traitsFrom: [super.traitCollection, UITraitCollection(horizontalSizeClass: .regular)]) - } - } - - override func viewDidLoad() { - super.viewDidLoad() - self.navigationBar.prefersLargeTitles = true - delegate = self - } - - public func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { - - setOverrideTraitCollection(customTraitCollection, forChild: viewController) - - if viewControllers.count < screenStack.count { - // Navigation back - let _ = screenStack.popLast() - } - viewController.view.backgroundColor = UIColor.secondarySystemBackground - } - - let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as! String -} diff --git a/Dependencies/OmniKit/OmniKitUI/ViewModels/DeactivatePodViewModel.swift b/Dependencies/OmniKit/OmniKitUI/ViewModels/DeactivatePodViewModel.swift deleted file mode 100644 index 8f42c4626..000000000 --- a/Dependencies/OmniKit/OmniKitUI/ViewModels/DeactivatePodViewModel.swift +++ /dev/null @@ -1,198 +0,0 @@ -// -// DeactivatePodViewModel.swift -// OmniKit -// -// Created by Pete Schwamb on 3/9/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKitUI -import OmniKit - -public protocol PodDeactivater { - func deactivatePod(completion: @escaping (OmnipodPumpManagerError?) -> Void) - func forgetPod(completion: @escaping () -> Void) -} - -extension OmnipodPumpManager: PodDeactivater {} - - -class DeactivatePodViewModel: ObservableObject, Identifiable { - - enum DeactivatePodViewModelState { - case active - case deactivating - case resultError(DeactivationError) - case finished - - var actionButtonAccessibilityLabel: String { - switch self { - case .active: - return LocalizedString("Deactivate Pod", comment: "Deactivate pod action button accessibility label while ready to deactivate") - case .deactivating: - return LocalizedString("Deactivating.", comment: "Deactivate pod action button accessibility label while deactivating") - case .resultError(let error): - return String(format: "%@ %@", error.errorDescription ?? "", error.recoverySuggestion ?? "") - case .finished: - return LocalizedString("Pod deactivated successfully. Continue.", comment: "Deactivate pod action button accessibility label when deactivation complete") - } - } - - var actionButtonDescription: String { - switch self { - case .active: - return LocalizedString("Deactivate Pod", comment: "Action button description for deactivate while pod still active") - case .resultError: - return LocalizedString("Retry", comment: "Action button description for deactivate after failed attempt") - case .deactivating: - return LocalizedString("Deactivating...", comment: "Action button description while deactivating") - case .finished: - return LocalizedString("Continue", comment: "Action button description when deactivated") - } - } - - var actionButtonStyle: ActionButton.ButtonType { - switch self { - case .active: - return .destructive - default: - return .primary - } - } - - - var progressState: ProgressIndicatorState { - switch self { - case .active, .resultError: - return .hidden - case .deactivating: - return .indeterminantProgress - case .finished: - return .completed - } - } - - var showProgressDetail: Bool { - switch self { - case .active: - return false - default: - return true - } - } - - var isProcessing: Bool { - switch self { - case .deactivating: - return true - default: - return false - } - } - - var isFinished: Bool { - if case .finished = self { - return true - } - return false - } - - } - - @Published var state: DeactivatePodViewModelState = .active - - var error: DeactivationError? { - if case .resultError(let error) = self.state { - return error - } - return nil - } - - var didFinish: (() -> Void)? - - var didCancel: (() -> Void)? - - var podDeactivator: PodDeactivater - - var podAttachedToBody: Bool - - var instructionText: String - - init(podDeactivator: PodDeactivater, podAttachedToBody: Bool, fault: DetailedStatus?) { - - var text: String = "" - if let faultEventCode = fault?.faultEventCode { - let notificationString = faultEventCode.notificationTitle - switch faultEventCode.faultType { - case .exceededMaximumPodLife80Hrs, .reservoirEmpty, .occluded: - // Just prepend a simple sentence with the notification string for these faults. - // Other occluded related 0x6? faults will be treated as a general pod error as per the PDM. - text = String(format: "%@. ", notificationString) - default: - // Display the fault code in decimal and hex, the fault description and the pdmRef string for other errors. - text = String(format: "⚠️ %1$@ (0x%2$02X)\n%3$@\n", notificationString, faultEventCode.rawValue, faultEventCode.faultDescription) - if let pdmRef = fault?.pdmRef { - text += LocalizedString("Ref: ", comment: "PDM Ref string line") + pdmRef + "\n\n" - } - } - } - - if podAttachedToBody { - text += LocalizedString("Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod.", comment: "Instructions for deactivate pod when pod is on body") - } else { - text += LocalizedString("Please deactivate the pod. When deactivation is complete, you may pair a new pod.", comment: "Instructions for deactivate pod when pod not on body") - } - - self.podDeactivator = podDeactivator - self.podAttachedToBody = podAttachedToBody - self.instructionText = text - } - - public func continueButtonTapped() { - if case .finished = state { - didFinish?() - } else { - self.state = .deactivating - podDeactivator.deactivatePod { (error) in - DispatchQueue.main.async { - if let error = error { - self.state = .resultError(DeactivationError.OmnipodPumpManagerError(error)) - } else { - self.discardPod(navigateOnCompletion: false) - } - } - } - } - } - - public func discardPod(navigateOnCompletion: Bool = true) { - podDeactivator.forgetPod { - DispatchQueue.main.async { - if navigateOnCompletion { - self.didFinish?() - } else { - self.state = .finished - } - } - } - } -} - -enum DeactivationError : LocalizedError { - case OmnipodPumpManagerError(OmnipodPumpManagerError) - - var recoverySuggestion: String? { - switch self { - case .OmnipodPumpManagerError: - return LocalizedString("There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod.", comment: "Format string for recovery suggestion during deactivate pod.") - } - } - - var errorDescription: String? { - switch self { - case .OmnipodPumpManagerError(let error): - return error.errorDescription - } - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/ViewModels/DeliveryUncertaintyRecoveryViewModel.swift b/Dependencies/OmniKit/OmniKitUI/ViewModels/DeliveryUncertaintyRecoveryViewModel.swift deleted file mode 100644 index b77ca7781..000000000 --- a/Dependencies/OmniKit/OmniKitUI/ViewModels/DeliveryUncertaintyRecoveryViewModel.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// DeliveryUncertaintyRecoveryViewModel.swift -// OmniKit -// -// Created by Pete Schwamb on 8/25/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit - -class DeliveryUncertaintyRecoveryViewModel: PumpManagerStatusObserver { - - let appName: String - let uncertaintyStartedAt: Date - var respondToRecovery: Bool - - var onDismiss: (() -> Void)? - var didRecover: (() -> Void)? - var onDeactivate: (() -> Void)? - - init(appName: String, uncertaintyStartedAt: Date) { - self.appName = appName - self.uncertaintyStartedAt = uncertaintyStartedAt - respondToRecovery = false - } - - func pumpManager(_ pumpManager: PumpManager, didUpdate status: PumpManagerStatus, oldStatus: PumpManagerStatus) { - if !status.deliveryIsUncertain && respondToRecovery { - didRecover?() - } - } - - func podDeactivationChosen() { - self.onDeactivate?() - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/ViewModels/InsertCannulaViewModel.swift b/Dependencies/OmniKit/OmniKitUI/ViewModels/InsertCannulaViewModel.swift deleted file mode 100644 index c35617f50..000000000 --- a/Dependencies/OmniKit/OmniKitUI/ViewModels/InsertCannulaViewModel.swift +++ /dev/null @@ -1,235 +0,0 @@ -// -// InsertCannulaViewModel.swift -// OmniKit -// -// Created by Pete Schwamb on 3/10/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import LoopKit -import LoopKitUI -import OmniKit - -public protocol CannulaInserter { - func insertCannula(completion: @escaping (Result) -> ()) - func checkCannulaInsertionFinished(completion: @escaping (OmnipodPumpManagerError?) -> Void) -} - -extension OmnipodPumpManager: CannulaInserter {} - -class InsertCannulaViewModel: ObservableObject, Identifiable { - - enum InsertCannulaViewModelState { - case ready - case startingInsertion - case inserting(finishTime: CFTimeInterval) - case checkingInsertion - case error(OmnipodPumpManagerError) - case finished - - var actionButtonAccessibilityLabel: String { - switch self { - case .ready, .startingInsertion: - return LocalizedString("Insert Cannula", comment: "Insert cannula action button accessibility label while ready to pair") - case .inserting: - return LocalizedString("Inserting. Please wait.", comment: "Insert cannula action button accessibility label while pairing") - case .checkingInsertion: - return LocalizedString("Checking Insertion", comment: "Insert cannula action button accessibility label checking insertion") - case .error(let error): - return String(format: "%@ %@", error.errorDescription ?? "", error.recoverySuggestion ?? "") - case .finished: - return LocalizedString("Cannula inserted successfully. Continue.", comment: "Insert cannula action button accessibility label when cannula insertion succeeded") - } - } - - var instructionsDisabled: Bool { - switch self { - case .ready, .error: - return false - default: - return true - } - } - - var nextActionButtonDescription: String { - switch self { - case .ready: - return LocalizedString("Insert Cannula", comment: "Cannula insertion button text while ready to insert") - case .error: - return LocalizedString("Retry", comment: "Cannula insertion button text while showing error") - case .inserting, .startingInsertion: - return LocalizedString("Inserting...", comment: "Cannula insertion button text while inserting") - case .checkingInsertion: - return LocalizedString("Checking...", comment: "Cannula insertion button text while checking insertion") - case .finished: - return LocalizedString("Continue", comment: "Cannula insertion button text when inserted") - } - } - - var nextActionButtonStyle: ActionButton.ButtonType { - switch self { - case .error(let error): - if !error.recoverable { - return .destructive - } - default: - break - } - return .primary - } - - var progressState: ProgressIndicatorState { - switch self { - case .ready, .error: - return .hidden - case .startingInsertion, .checkingInsertion: - return .indeterminantProgress - case .inserting(let finishTime): - return .timedProgress(finishTime: finishTime) - case .finished: - return .completed - } - } - - var showProgressDetail: Bool { - switch self { - case .ready: - return false - default: - return true - } - } - - var isProcessing: Bool { - switch self { - case .startingInsertion, .inserting: - return true - default: - return false - } - } - - var isFinished: Bool { - if case .finished = self { - return true - } - return false - } - } - - var error: OmnipodPumpManagerError? { - if case .error(let error) = self.state { - return error - } - return nil - } - - @Published var state: InsertCannulaViewModelState = .ready - - var didFinish: (() -> Void)? - - var didRequestDeactivation: (() -> Void)? - - var cannulaInserter: CannulaInserter - - init(cannulaInserter: CannulaInserter) { - self.cannulaInserter = cannulaInserter - } - -// private func handleEvent(_ event: ActivationStep2Event) { -// switch event { -// case .insertingCannula: -// let finishTime = TimeInterval(Pod.estimatedCannulaInsertionDuration) -// state = .inserting(finishTime: CACurrentMediaTime() + finishTime) -// case .step2Completed: -// state = .finished -// default: -// break -// } -// } - - private func checkCannulaInsertionFinished() { - state = .startingInsertion - cannulaInserter.checkCannulaInsertionFinished() { (error) in - DispatchQueue.main.async { - if let error = error { - self.state = .error(error) - } else { - self.state = .finished - } - } - } - } - - private func insertCannula() { - state = .startingInsertion - - cannulaInserter.insertCannula { (result) in - DispatchQueue.main.async { - switch(result) { - case .success(let finishTime): - self.state = .inserting(finishTime: CACurrentMediaTime() + finishTime) - let delay = finishTime - if delay > 0 { - DispatchQueue.main.asyncAfter(deadline: .now() + delay) { - self.checkCannulaInsertionFinished() // now check if actually ready - } - } else { - self.state = .finished - } - case .failure(let error): - self.state = .error(error) - } - } - - -// switch status { -// case .error(let error): -// self.state = .error(error) -// case .event(let event): -// self.handleEvent(event) -// } - } - } - - public func continueButtonTapped() { - switch state { - case .finished: - didFinish?() - case .error(let error): - if error.recoverable { - insertCannula() - } else { - didRequestDeactivation?() - } - default: - insertCannula() - } - } - -} - -public extension OmnipodPumpManagerError { - var recoverable: Bool { - //TODO - return true -// switch self { -// case .podIsInAlarm: -// return false -// case .activationError(let activationErrorCode): -// switch activationErrorCode { -// case .podIsLumpOfCoal1Hour, .podIsLumpOfCoal2Hours: -// return false -// default: -// return true -// } -// case .internalError(.incompatibleProductId): -// return false -// case .systemError: -// return false -// default: -// return true -// } - } -} - diff --git a/Dependencies/OmniKit/OmniKitUI/ViewModels/OmnipodSettingsViewModel.swift b/Dependencies/OmniKit/OmniKitUI/ViewModels/OmnipodSettingsViewModel.swift deleted file mode 100644 index 0a91c9cba..000000000 --- a/Dependencies/OmniKit/OmniKitUI/ViewModels/OmnipodSettingsViewModel.swift +++ /dev/null @@ -1,634 +0,0 @@ -// -// OmnipodSettingsViewModel.swift -// OmniKit -// -// Created by Pete Schwamb on 3/8/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import HealthKit -import OmniKit -import Combine - -enum OmnipodSettingsViewAlert { - case suspendError(Error) - case resumeError(Error) - case cancelManualBasalError(Error) - case syncTimeError(OmnipodPumpManagerError) -} - -struct OmnipodSettingsNotice { - let title: String - let description: String -} - -class OmnipodSettingsViewModel: ObservableObject { - - @Published var lifeState: PodLifeState - - @Published var activatedAt: Date? - - @Published var expiresAt: Date? - - @Published var beepPreference: BeepPreference - - @Published var silencePodPreference: SilencePodPreference - - @Published var rileylinkConnected: Bool - - var activatedAtString: String { - if let activatedAt = activatedAt { - return dateFormatter.string(from: activatedAt) - } else { - return "—" - } - } - - var expiresAtString: String { - if let expiresAt = expiresAt { - return dateFormatter.string(from: expiresAt) - } else { - return "—" - } - } - - var serviceTimeRemainingString: String? { - if let serviceTimeRemaining = pumpManager.podServiceTimeRemaining, let serviceTimeRemainingString = timeRemainingFormatter.string(from: serviceTimeRemaining) { - return serviceTimeRemainingString - } else { - return nil - } - } - - // Expiration reminder date for current pod - @Published var expirationReminderDate: Date? - - var allowedScheduledReminderDates: [Date]? { - return pumpManager.allowedExpirationReminderDates - } - - // Hours before expiration - @Published var expirationReminderDefault: Int { - didSet { - self.pumpManager.defaultExpirationReminderOffset = .hours(Double(expirationReminderDefault)) - } - } - - // Units to alert at - @Published var lowReservoirAlertValue: Int - - @Published var basalDeliveryState: PumpManagerStatus.BasalDeliveryState? - - @Published var basalDeliveryRate: Double? - - @Published var activeAlert: OmnipodSettingsViewAlert? = nil { - didSet { - if activeAlert != nil { - alertIsPresented = true - } - } - } - - @Published var alertIsPresented: Bool = false { - didSet { - if !alertIsPresented { - activeAlert = nil - } - } - } - - @Published var reservoirLevel: ReservoirLevel? - - @Published var reservoirLevelHighlightState: ReservoirLevelHighlightState? - - @Published var synchronizingTime: Bool = false - - @Published var podCommState: PodCommState - - @Published var insulinType: InsulinType? - - @Published var podDetails: PodDetails? - - @Published var previousPodDetails: PodDetails? - - - var timeZone: TimeZone { - return pumpManager.status.timeZone - } - - var viewTitle: String { - return pumpManager.localizedTitle - } - - var isClockOffset: Bool { - return pumpManager.isClockOffset - } - - var isPodDataStale: Bool { - return Date().timeIntervalSince(pumpManager.lastSync ?? .distantPast) > .minutes(12) - } - - var recoveryText: String? { - if case .fault = podCommState { - return LocalizedString("⚠️ Insulin delivery stopped. Change Pod now.", comment: "The action string on pod status page when pod faulted") - } else if podOk && isPodDataStale { - return LocalizedString("Make sure your phone and pod are close to each other. If communication issues persist, move to a new area.", comment: "The action string on pod status page when pod data is stale") - } else if let serviceTimeRemaining = pumpManager.podServiceTimeRemaining, serviceTimeRemaining <= Pod.serviceDuration - Pod.nominalPodLife { - if let serviceTimeRemainingString = serviceTimeRemainingString { - return String(format: LocalizedString("Change Pod now. Insulin delivery will stop in %1$@ or when no more insulin remains.", comment: "Format string for the action string on pod status page when pod expired. (1: service time remaining)"), serviceTimeRemainingString) - } else { - return LocalizedString("Change Pod now. Insulin delivery will stop 8 hours after the Pod has expired or when no more insulin remains.", comment: "The action string on pod status page when pod expired") - } - } else { - return nil - } - } - - var notice: OmnipodSettingsNotice? { - if pumpManager.isClockOffset { - return OmnipodSettingsNotice( - title: LocalizedString("Time Change Detected", comment: "title for time change detected notice"), - description: LocalizedString("The time on your pump is different from the current time. Your pump’s time controls your scheduled therapy settings. Scroll down to Pump Time row to review the time difference and configure your pump.", comment: "description for time change detected notice")) - } else { - return nil - } - } - - var isScheduledBasal: Bool { - switch basalDeliveryState { - case .active(_), .initiatingTempBasal: - return true - case .tempBasal(_), .cancelingTempBasal, .suspending, .suspended(_), .resuming, .none: - return false - } - } - - let dateFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - dateFormatter.timeStyle = .short - dateFormatter.dateStyle = .medium - dateFormatter.doesRelativeDateFormatting = true - return dateFormatter - }() - - let timeFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - dateFormatter.timeStyle = .short - dateFormatter.dateStyle = .none - return dateFormatter - }() - - let timeRemainingFormatter: DateComponentsFormatter = { - let dateComponentsFormatter = DateComponentsFormatter() - dateComponentsFormatter.allowedUnits = [.hour, .minute] - dateComponentsFormatter.unitsStyle = .full - dateComponentsFormatter.zeroFormattingBehavior = .dropAll - return dateComponentsFormatter - }() - - let basalRateFormatter: NumberFormatter = { - let numberFormatter = NumberFormatter() - numberFormatter.numberStyle = .decimal - numberFormatter.minimumFractionDigits = 1 - numberFormatter.minimumIntegerDigits = 1 - return numberFormatter - }() - - var manualBasalTimeRemaining: TimeInterval? { - if case .tempBasal(let dose) = basalDeliveryState, !(dose.automatic ?? true) { - let remaining = dose.endDate.timeIntervalSinceNow - if remaining > 0 { - return remaining - } - } - return nil - } - - let reservoirVolumeFormatter = QuantityFormatter(for: .internationalUnit()) - - var didFinish: (() -> Void)? - - var navigateTo: ((OmnipodUIScreen) -> Void)? - - private let pumpManager: OmnipodPumpManager - - private lazy var cancellables = Set() - - init(pumpManager: OmnipodPumpManager) { - self.pumpManager = pumpManager - - lifeState = pumpManager.lifeState - activatedAt = pumpManager.podActivatedAt - expiresAt = pumpManager.expiresAt - basalDeliveryState = pumpManager.status.basalDeliveryState - basalDeliveryRate = self.pumpManager.basalDeliveryRate - reservoirLevel = self.pumpManager.reservoirLevel - reservoirLevelHighlightState = self.pumpManager.reservoirLevelHighlightState - expirationReminderDate = self.pumpManager.scheduledExpirationReminder - expirationReminderDefault = Int(self.pumpManager.defaultExpirationReminderOffset.hours) - lowReservoirAlertValue = Int(self.pumpManager.state.lowReservoirReminderValue) - podCommState = self.pumpManager.podCommState - beepPreference = self.pumpManager.beepPreference - silencePodPreference = self.pumpManager.silencePod ? .enabled : .disabled - insulinType = self.pumpManager.insulinType - podDetails = self.pumpManager.podDetails - previousPodDetails = self.pumpManager.previousPodDetails - - // TODO: - rileylinkConnected = false - - pumpManager.addPodStateObserver(self, queue: DispatchQueue.main) - pumpManager.addStatusObserver(self, queue: DispatchQueue.main) - - // Register for device notifications - NotificationCenter.default.publisher(for: .DeviceConnectionStateDidChange) - .sink { [weak self] _ in - self?.updateConnectionStatus() - } - .store(in: &cancellables) - - // Trigger refresh - pumpManager.getPodStatus() { _ in } - updateConnectionStatus() - } - - func updateConnectionStatus() { - pumpManager.rileyLinkDeviceProvider.getDevices { (devices) in - DispatchQueue.main.async { [weak self] in - self?.rileylinkConnected = devices.firstConnected != nil - } - } - } - - func changeTimeZoneTapped() { - synchronizingTime = true - pumpManager.setTime { (error) in - DispatchQueue.main.async { - self.synchronizingTime = false - self.lifeState = self.pumpManager.lifeState - if let error = error { - self.activeAlert = .syncTimeError(error) - } - } - } - } - - func doneTapped() { - self.didFinish?() - } - - func stopUsingOmnipodTapped() { - pumpManager.notifyDelegateOfDeactivation { - DispatchQueue.main.async { - self.didFinish?() - } - } - } - - func suspendDelivery(duration: TimeInterval) { - pumpManager.suspendDelivery(withSuspendReminders: duration) { (error) in - DispatchQueue.main.async { - if let error = error { - self.activeAlert = .suspendError(error) - } - } - } - } - - func resumeDelivery() { - pumpManager.resumeDelivery { (error) in - DispatchQueue.main.async { - if let error = error { - self.activeAlert = .resumeError(error) - } - } - } - } - - func runTemporaryBasalProgram(unitsPerHour: Double, for duration: TimeInterval, completion: @escaping (PumpManagerError?) -> Void) { - pumpManager.runTemporaryBasalProgram(unitsPerHour: unitsPerHour, for: duration, automatic: false, completion: completion) - } - - func saveScheduledExpirationReminder(_ selectedDate: Date?, _ completion: @escaping (Error?) -> Void) { - if let podExpiresAt = pumpManager.podExpiresAt { - var intervalBeforeExpiration : TimeInterval? - if let selectedDate = selectedDate { - intervalBeforeExpiration = .hours(round(podExpiresAt.timeIntervalSince(selectedDate).hours)) - } - pumpManager.updateExpirationReminder(intervalBeforeExpiration) { (error) in - DispatchQueue.main.async { - if error == nil { - self.expirationReminderDate = selectedDate - } - completion(error) - } - } - } - } - - func saveLowReservoirReminder(_ selectedValue: Int, _ completion: @escaping (Error?) -> Void) { - pumpManager.updateLowReservoirReminder(selectedValue) { (error) in - DispatchQueue.main.async { - if error == nil { - self.lowReservoirAlertValue = selectedValue - } - completion(error) - } - } - } - - func readPodStatus(_ completion: @escaping (_ result: PumpManagerResult) -> Void) { - pumpManager.getDetailedStatus() { (result) in - DispatchQueue.main.async { - completion(result) - } - } - } - - func readPulseLog(_ completion: @escaping (_ result: Result) -> Void) { - pumpManager.readPulseLog() { (result) in - DispatchQueue.main.async { - completion(result) - } - } - } - - func playTestBeeps(_ completion: @escaping (Error?) -> Void) { - pumpManager.playTestBeeps(completion: completion) - } - - func pumpManagerDetails(_ completion: @escaping (_ result: String) -> Void) { - completion(pumpManager.debugDescription) - } - - func setConfirmationBeeps(_ preference: BeepPreference, _ completion: @escaping (_ error: LocalizedError?) -> Void) { - pumpManager.setConfirmationBeeps(newPreference: preference) { error in - DispatchQueue.main.async { - if error == nil { - self.beepPreference = preference - } - completion(error) - } - } - } - - func setSilencePod(_ silencePodPreference: SilencePodPreference, _ completion: @escaping (_ error: LocalizedError?) -> Void) { - pumpManager.setSilencePod(silencePod: silencePodPreference == .enabled) { error in - DispatchQueue.main.async { - if error == nil { - self.silencePodPreference = silencePodPreference - } - completion(error) - } - } - } - - func didChangeInsulinType(_ newType: InsulinType?) { - self.pumpManager.insulinType = newType - } - - var podOk: Bool { - guard basalDeliveryState != nil else { return false } - - switch podCommState { - case .noPod, .activating, .deactivating, .fault: - return false - default: - return true - } - } - - var noPod: Bool { - return podCommState == .noPod - } - - var podError: String? { - switch podCommState { - case .fault(let status): - switch status.faultEventCode.faultType { - case .reservoirEmpty: - return LocalizedString("No Insulin", comment: "Error message for reservoir view when reservoir empty") - case .exceededMaximumPodLife80Hrs: - return LocalizedString("Pod Expired", comment: "Error message for reservoir view when pod expired") - case .occluded, .occlusionCheckStartup1, .occlusionCheckStartup2, .occlusionCheckTimeouts1, .occlusionCheckTimeouts2, .occlusionCheckTimeouts3, .occlusionCheckPulseIssue, .occlusionCheckBolusProblem, .occlusionCheckAboveThreshold, .occlusionCheckValueTooHigh: - return LocalizedString("Pod Occlusion", comment: "Error message for reservoir view when pod occlusion checks failed") - default: - return String(format: LocalizedString("Pod Fault %1$03d", comment: "Error message for reservoir view during general pod fault: (1: fault code value)"), status.faultEventCode.rawValue) - } - case .active: - if isPodDataStale { - return LocalizedString("Signal Loss", comment: "Error message for reservoir view during general pod fault") - } else { - return nil - } - default: - return nil - } - - } - - func reservoirText(for level: ReservoirLevel) -> String { - switch level { - case .aboveThreshold: - let quantity = HKQuantity(unit: .internationalUnit(), doubleValue: Pod.maximumReservoirReading) - let thresholdString = reservoirVolumeFormatter.string(from: quantity, for: .internationalUnit(), includeUnit: false) ?? "" - let unitString = reservoirVolumeFormatter.string(from: .internationalUnit(), forValue: Pod.maximumReservoirReading, avoidLineBreaking: true) - return String(format: LocalizedString("%1$@+ %2$@", comment: "Format string for reservoir level above max measurable threshold. (1: measurable reservoir threshold) (2: units)"), - thresholdString, unitString) - case .valid(let value): - let quantity = HKQuantity(unit: .internationalUnit(), doubleValue: value) - return reservoirVolumeFormatter.string(from: quantity, for: .internationalUnit()) ?? "" - } - } - - var suspendResumeActionText: String { - let defaultText = LocalizedString("Suspend Insulin Delivery", comment: "Text for suspend resume button when insulin delivery active") - - guard podOk else { - return defaultText - } - - switch basalDeliveryState { - case .suspending: - return LocalizedString("Suspending insulin delivery...", comment: "Text for suspend resume button when insulin delivery is suspending") - case .suspended: - return LocalizedString("Resume Insulin Delivery", comment: "Text for suspend resume button when insulin delivery is suspended") - case .resuming: - return LocalizedString("Resuming insulin delivery...", comment: "Text for suspend resume button when insulin delivery is resuming") - default: - return defaultText - } - } - - var basalTransitioning: Bool { - switch basalDeliveryState { - case .suspending, .resuming: - return true - default: - return false - } - } - - func suspendResumeButtonColor(guidanceColors: GuidanceColors) -> Color { - guard podOk else { - return Color.secondary - } - switch basalDeliveryState { - case .suspending, .resuming: - return Color.secondary - case .suspended: - return guidanceColors.warning - default: - return .accentColor - } - } - - func suspendResumeActionColor() -> Color { - guard podOk else { - return Color.secondary - } - switch basalDeliveryState { - case .suspending, .resuming: - return Color.secondary - default: - return Color.accentColor - } - } - - var isSuspendedOrResuming: Bool { - switch basalDeliveryState { - case .suspended, .resuming: - return true - default: - return false - } - } - - public var allowedTempBasalRates: [Double] { - return Pod.supportedTempBasalRates.filter { $0 <= pumpManager.state.maximumTempBasalRate } - } -} - -extension OmnipodSettingsViewModel: PodStateObserver { - func podStateDidUpdate(_ state: PodState?) { - lifeState = self.pumpManager.lifeState - basalDeliveryRate = self.pumpManager.basalDeliveryRate - reservoirLevel = self.pumpManager.reservoirLevel - activatedAt = state?.activatedAt - expiresAt = state?.expiresAt - reservoirLevelHighlightState = self.pumpManager.reservoirLevelHighlightState - expirationReminderDate = self.pumpManager.scheduledExpirationReminder - podCommState = self.pumpManager.podCommState - beepPreference = self.pumpManager.beepPreference - insulinType = self.pumpManager.insulinType - podDetails = self.pumpManager.podDetails - previousPodDetails = self.pumpManager.previousPodDetails - } - - func podConnectionStateDidChange(isConnected: Bool) { - self.rileylinkConnected = isConnected - } -} - -extension OmnipodSettingsViewModel: PumpManagerStatusObserver { - func pumpManager(_ pumpManager: PumpManager, didUpdate status: PumpManagerStatus, oldStatus: PumpManagerStatus) { - basalDeliveryState = self.pumpManager.status.basalDeliveryState - } -} - - - - -extension OmnipodPumpManager { - var lifeState: PodLifeState { - switch podCommState { - case .fault(let status): - switch status.faultEventCode.faultType { - case .exceededMaximumPodLife80Hrs: - return .expired - default: - let remaining = Pod.nominalPodLife - (status.faultEventTimeSinceActivation ?? Pod.nominalPodLife) - let podTimeUntilReminder = remaining - (state.scheduledExpirationReminderOffset ?? 0) - if remaining > 0 { - return .timeRemaining(timeUntilExpiration: remaining, timeUntilExpirationReminder: podTimeUntilReminder) - } else { - return .expired - } - } - - case .noPod: - return .noPod - case .activating: - return .podActivating - case .deactivating: - return .podDeactivating - case .active: - if let podTimeRemaining = podTimeRemaining { - if podTimeRemaining > 0 { - let podTimeUntilReminder = podTimeRemaining - (state.scheduledExpirationReminderOffset ?? 0) - return .timeRemaining(timeUntilExpiration: podTimeRemaining, timeUntilExpirationReminder: podTimeUntilReminder) - } else { - return .expired - } - } else { - return .podDeactivating - } - } - } - - var basalDeliveryRate: Double? { - if let tempBasal = state.podState?.unfinalizedTempBasal, !tempBasal.isFinished() { - return tempBasal.rate - } else { - switch state.podState?.suspendState { - case .resumed: - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = state.timeZone - return state.basalSchedule.currentRate(using: calendar, at: dateGenerator()) - case .suspended, .none: - return nil - } - } - } - - fileprivate var podServiceTimeRemaining : TimeInterval? { - guard let podTimeRemaining = podTimeRemaining else { - return nil; - } - return max(0, Pod.serviceDuration - Pod.nominalPodLife + podTimeRemaining); - } - - private func podDetails(fromPodState podState: PodState) -> PodDetails { - return PodDetails( - lotNumber: podState.lot, - sequenceNumber: podState.tid, - piVersion: podState.piVersion, - pmVersion: podState.pmVersion, - totalDelivery: podState.lastInsulinMeasurements?.delivered, - lastStatus: podState.lastInsulinMeasurements?.validTime, - fault: podState.fault?.faultEventCode, - activatedAt: podState.activatedAt, - activeTime: podState.activeTime, - pdmRef: podState.fault?.pdmRef - ) - } - - public var podDetails: PodDetails? { - guard let podState = state.podState else { - return nil - } - return podDetails(fromPodState: podState) - } - - public var previousPodDetails: PodDetails? { - guard let podState = state.previousPodState else { - return nil - } - return podDetails(fromPodState: podState) - } - -} - diff --git a/Dependencies/OmniKit/OmniKitUI/ViewModels/PairPodViewModel.swift b/Dependencies/OmniKit/OmniKitUI/ViewModels/PairPodViewModel.swift deleted file mode 100644 index c7c560b03..000000000 --- a/Dependencies/OmniKit/OmniKitUI/ViewModels/PairPodViewModel.swift +++ /dev/null @@ -1,261 +0,0 @@ -// -// PairPodViewModel.swift -// OmniKit -// -// Created by Pete Schwamb on 3/2/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import OmniKit - -class PairPodViewModel: ObservableObject, Identifiable { - - enum NavBarButtonAction { - case cancel - case discard - - var text: String { - switch self { - case .cancel: - return LocalizedString("Cancel", comment: "Pairing interface navigation bar button text for cancel action") - case .discard: - return LocalizedString("Discard Pod", comment: "Pairing interface navigation bar button text for discard pod action") - } - } - - func color(using guidanceColors: GuidanceColors) -> Color? { - switch self { - case .discard: - return guidanceColors.critical - case .cancel: - return nil - } - } - } - - enum PairPodViewModelState { - case ready - case pairing - case priming(finishTime: CFTimeInterval) - case error(OmnipodPairingError) - case finished - - var instructionsDisabled: Bool { - switch self { - case .ready: - return false - case .error(let error): - return !error.recoverable - default: - return true - } - } - - var actionButtonAccessibilityLabel: String { - switch self { - case .ready: - return LocalizedString("Pair pod.", comment: "Pairing action button accessibility label while ready to pair") - case .pairing: - return LocalizedString("Pairing.", comment: "Pairing action button accessibility label while pairing") - case .priming: - return LocalizedString("Priming. Please wait.", comment: "Pairing action button accessibility label while priming") - case .error(let error): - return String(format: "%@ %@", error.errorDescription ?? "", error.recoverySuggestion ?? "") - case .finished: - return LocalizedString("Pod paired successfully. Continue.", comment: "Pairing action button accessibility label when pairing succeeded") - } - } - - var nextActionButtonDescription: String { - switch self { - case .ready: - return LocalizedString("Pair Pod", comment: "Pod pairing action button text while ready to pair") - case .error: - return LocalizedString("Retry", comment: "Pod pairing action button text while showing error") - case .pairing: - return LocalizedString("Pairing...", comment: "Pod pairing action button text while pairing") - case .priming: - return LocalizedString("Priming...", comment: "Pod pairing action button text while priming") - case .finished: - return LocalizedString("Continue", comment: "Pod pairing action button text when paired") - } - } - - var navBarButtonAction: NavBarButtonAction { -// switch self { -// case .error(_, let podCommState): -// if podCommState == .activating { -// return .discard -// } -// default: -// break -// } - return .cancel - } - - var navBarVisible: Bool { - if case .error(let error) = self { - return error.recoverable - } - return true - } - - var showProgressDetail: Bool { - switch self { - case .ready: - return false - default: - return true - } - } - - var progressState: ProgressIndicatorState { - switch self { - case .ready, .error: - return .hidden - case .pairing: - return .indeterminantProgress - case .priming(let finishTime): - return .timedProgress(finishTime: finishTime) - case .finished: - return .completed - } - } - - var isProcessing: Bool { - switch self { - case .pairing, .priming: - return true - default: - return false - } - } - - var isFinished: Bool { - if case .finished = self { - return true - } - return false - } - } - - var error: OmnipodPairingError? { - if case .error(let error) = state { - return error - } - return nil - } - - @Published var state: PairPodViewModelState = .ready - - var podIsActivated: Bool { - return false // podPairer.podCommState != .noPod - } - - var backButtonHidden: Bool { - if case .pairing = state { - return true - } - if podIsActivated { - return true - } - return false - } - - var didFinish: (() -> Void)? - - var didRequestDeactivation: (() -> Void)? - - var didCancelSetup: (() -> Void)? - - var podPairer: PodPairer - - init(podPairer: PodPairer) { - self.podPairer = podPairer - } - - private func pair() { - state = .pairing - - podPairer.pair { (status) in - DispatchQueue.main.async { - switch status { - case .failure(let error): - let pairingError = OmnipodPairingError.pumpManagerError(error) - self.state = .error(pairingError) - case .success(let duration): - - if duration > 0 { - self.state = .priming(finishTime: CACurrentMediaTime() + duration) - DispatchQueue.main.asyncAfter(deadline: .now() + duration) { - self.state = .finished - } - } else { - self.state = .finished - } - } - } - } - } - - public func continueButtonTapped() { - switch state { - case .error(let error): - if !error.recoverable { - self.didRequestDeactivation?() - } else { - // Retry - pair() - } - case .finished: - didFinish?() - default: - pair() - } - } -} - -// Pairing recovery suggestions -enum OmnipodPairingError : LocalizedError { - case pumpManagerError(PumpManagerError) - - var recoverySuggestion: String? { - switch self { - case .pumpManagerError(let error): - return error.recoverySuggestion - } - } - - var errorDescription: String? { - switch self { - case .pumpManagerError(let error): - return error.errorDescription - } - } - - var recoverable: Bool { -// switch self { -// case .pumpManagerError(let error): - // TODO: check which errors are recoverable - return true -// } - } -} - -public protocol PodPairer { - func pair(completion: @escaping (PumpManagerResult) -> Void) - func discardPod(completion: @escaping (Bool) -> ()) -} - -extension OmnipodPumpManager: PodPairer { - public func discardPod(completion: @escaping (Bool) -> ()) { - } - - public func pair(completion: @escaping (PumpManagerResult) -> Void) { - pairAndPrime(completion: completion) - } -} - diff --git a/Dependencies/OmniKit/OmniKitUI/ViewModels/PodLifeState.swift b/Dependencies/OmniKit/OmniKitUI/ViewModels/PodLifeState.swift deleted file mode 100644 index 76494d146..000000000 --- a/Dependencies/OmniKit/OmniKitUI/ViewModels/PodLifeState.swift +++ /dev/null @@ -1,116 +0,0 @@ -// -// PodLifeState.swift -// OmniKit -// -// Created by Pete Schwamb on 3/9/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import Foundation -import SwiftUI -import OmniKit -import LoopKitUI - -enum PodLifeState { - case podActivating - // Time remaining - case timeRemaining(timeUntilExpiration: TimeInterval, timeUntilExpirationReminder: TimeInterval) - // Time since expiry - case expired - case podDeactivating - case noPod - - var progress: Double { - switch self { - case .timeRemaining(let timeRemaining, _): - return max(0, min(1, (1 - (timeRemaining / Pod.nominalPodLife)))) - case .expired: - return 1 - case .podDeactivating: - return 1 - case .noPod, .podActivating: - return 0 - } - } - - func progressColor(guidanceColors: GuidanceColors) -> Color { - switch self { - case .expired: - return guidanceColors.critical - case .timeRemaining(_, let timeUntilExpirationReminder): - return timeUntilExpirationReminder <= Pod.timeRemainingWarningThreshold ? guidanceColors.warning : .accentColor - default: - return Color.secondary - } - } - - func labelColor(using guidanceColors: GuidanceColors) -> Color { - switch self { - case .expired: - return guidanceColors.critical - default: - return .secondary - } - } - - - var localizedLabelText: String { - switch self { - case .podActivating: - return LocalizedString("Unfinished Activation", comment: "Label for pod life state when pod not fully activated") - case .timeRemaining: - return LocalizedString("Pod expires in", comment: "Label for pod life state when time remaining") - case .expired: - return LocalizedString("Pod expired", comment: "Label for pod life state when within pod expiration window") - case .podDeactivating: - return LocalizedString("Unfinished deactivation", comment: "Label for pod life state when pod not fully deactivated") - case .noPod: - return LocalizedString("No Pod", comment: "Label for pod life state when no pod paired") - } - } - - var nextPodLifecycleAction: OmnipodUIScreen { - switch self { - case .podActivating, .noPod: - return .pairPod - default: - return .deactivate - } - } - - var nextPodLifecycleActionDescription: String { - switch self { - case .podActivating, .noPod: - return LocalizedString("Pair Pod", comment: "Settings page link description when next lifecycle action is to pair new pod") - case .podDeactivating: - return LocalizedString("Finish deactivation", comment: "Settings page link description when next lifecycle action is to finish deactivation") - default: - return LocalizedString("Deactivate Pod", comment: "Settings page link description when next lifecycle action is to deactivate pod") - } - } - - var nextPodLifecycleActionColor: Color { - switch self { - case .podActivating, .noPod: - return .accentColor - default: - return .red - } - } - - var isActive: Bool { - switch self { - case .expired, .timeRemaining: - return true - default: - return false - } - } - - var allowsPumpManagerRemoval: Bool { - if case .noPod = self { - return true - } - return false - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/ViewModels/RileyLinkListDataSource.swift b/Dependencies/OmniKit/OmniKitUI/ViewModels/RileyLinkListDataSource.swift deleted file mode 100644 index 5c31fd39c..000000000 --- a/Dependencies/OmniKit/OmniKitUI/ViewModels/RileyLinkListDataSource.swift +++ /dev/null @@ -1,94 +0,0 @@ -// -// RileyLinkListDataSource.swift -// OmniKitUI -// -// Created by Pete Schwamb on 6/7/22. -// Copyright © 2022 Pete Schwamb. All rights reserved. -// - -import Foundation -import RileyLinkKit -import RileyLinkBLEKit -import SwiftUI - -class RileyLinkListDataSource: ObservableObject { - - public let rileyLinkPumpManager: RileyLinkPumpManager - - @Published private(set) public var devices: [RileyLinkDevice] = [] - - init(rileyLinkPumpManager: RileyLinkPumpManager) { - self.rileyLinkPumpManager = rileyLinkPumpManager - - // Register for manager notifications - NotificationCenter.default.addObserver(self, selector: #selector(reloadDevices), name: .ManagerDevicesDidChange, object: rileyLinkPumpManager.rileyLinkDeviceProvider) - - // Register for device notifications - for name in [.DeviceConnectionStateDidChange, .DeviceRSSIDidChange, .DeviceNameDidChange] as [Notification.Name] { - NotificationCenter.default.addObserver(self, selector: #selector(reloadDevices), name: name, object: nil) - } - - reloadDevices() - } - - func autoconnectBinding(for device: RileyLinkDevice) -> Binding { - return Binding( - get: { [weak self] in - if let connectionManager = self?.rileyLinkPumpManager.rileyLinkDeviceProvider { - return connectionManager.shouldConnect(to: device.peripheralIdentifier.uuidString) - } else { - return false - } - }, - set: { [weak self] in - if $0 { - self?.rileyLinkPumpManager.connectToRileyLink(device) - } else { - self?.rileyLinkPumpManager.disconnectFromRileyLink(device) - } - }) - } - - @objc private func reloadDevices() { - rileyLinkPumpManager.rileyLinkDeviceProvider.getDevices { (devices) in - DispatchQueue.main.async { [weak self] in - self?.devices = devices - } - } - } - - public var isScanningEnabled: Bool = false { - didSet { - rileyLinkPumpManager.rileyLinkDeviceProvider.setScanningEnabled(isScanningEnabled) - - if isScanningEnabled { - rssiFetchTimer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(updateRSSI), userInfo: nil, repeats: true) - updateRSSI() - } else { - rssiFetchTimer = nil - } - } - } - - var connecting: Bool { - #if targetEnvironment(simulator) - return true - #else - - return rileyLinkPumpManager.rileyLinkDeviceProvider.connectingCount > 0 - #endif - } - - - private var rssiFetchTimer: Timer? { - willSet { - rssiFetchTimer?.invalidate() - } - } - - @objc public func updateRSSI() { - for device in devices { - device.readRSSI() - } - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/ActivityView.swift b/Dependencies/OmniKit/OmniKitUI/Views/ActivityView.swift deleted file mode 100644 index 221d31c14..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/ActivityView.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// ActivityView.swift -// OmniKit -// -// Created by Joe Moran on 9/17/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -struct ActivityView: UIViewControllerRepresentable { - @Binding var isPresented: Bool - let activityItems: [Any] - - func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIActivityViewController { - let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: nil) - controller.completionWithItemsHandler = { (_, _, _, _) in - self.isPresented = false - } - return controller - } - - func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext) { - } -} - -fileprivate struct ActivityViewController: UIViewControllerRepresentable { - var activityItems: [Any] - var applicationActivities: [UIActivity]? = nil - - func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIActivityViewController { - return UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities) - } - - func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext) {} -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/AttachPodView.swift b/Dependencies/OmniKit/OmniKitUI/Views/AttachPodView.swift deleted file mode 100644 index b637215b5..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/AttachPodView.swift +++ /dev/null @@ -1,107 +0,0 @@ -// -// AttachPodView.swift -// OmniKit -// -// Created by Pete Schwamb on 2/23/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct AttachPodView: View { - - enum Modal: Int, Identifiable { - var id: Int { rawValue } - - case attachConfirmationModal - case cancelModal - } - - @Environment(\.verticalSizeClass) var verticalSizeClass - - var didConfirmAttachment: () -> Void - var didRequestDeactivation: () -> Void - - @State private var activeModal: Modal? - - var body: some View { - GuidePage(content: { - VStack { - LeadingImage("Pod") - - HStack { - InstructionList(instructions: [ - LocalizedString("Prepare site.", comment: "Label text for step one of attach pod instructions"), - LocalizedString("Remove the Pod's clear needle cap and check cannula. Then remove paper backing.", comment: "Label text for step two of attach pod instructions"), - LocalizedString("Check Pod, apply to site, then confirm pod attachment.", comment: "Label text for step three of attach pod instructions") - ]) - } - .padding(.bottom, 8) - } - .accessibility(sortPriority: 1) - }) { - Button(action: { - activeModal = .attachConfirmationModal - }) { - FrameworkLocalText("Continue", comment: "Action button title for attach pod view") - .accessibility(identifier: "button_next_action") - .actionButtonStyle(.primary) - } - .animation(nil) - .padding() - .background(Color(UIColor.systemBackground)) - .zIndex(1) - } - .animation(.default) - .alert(item: $activeModal, content: self.alert(for:)) - .navigationBarTitle(LocalizedString("Attach Pod", comment: "navigation bar title attach pod"), displayMode: .automatic) - .navigationBarItems(trailing: cancelButton) - .navigationBarBackButtonHidden(true) - } - - var cancelButton: some View { - Button(LocalizedString("Cancel", comment: "Cancel button text in navigation bar on pair pod UI")) { - activeModal = .cancelModal - } - .accessibility(identifier: "button_cancel") - } - - private func alert(for modal: Modal) -> Alert { - switch modal { - case .attachConfirmationModal: - return confirmationModal - case .cancelModal: - return cancelPairingModal - } - } - - var confirmationModal: Alert { - return Alert( - title: FrameworkLocalText("Confirm Pod Attachment", comment: "Alert title for confirm pod attachment"), - message: FrameworkLocalText("Please confirm that the Pod is securely attached to your body.\n\nThe cannula can be inserted only once with each Pod. Tap “Confirm” when Pod is attached.", comment: "Alert message body for confirm pod attachment"), - primaryButton: .default(FrameworkLocalText("Confirm", comment: "Button title for confirm attachment option"), action: didConfirmAttachment), - secondaryButton: .cancel() - ) - } - - var cancelPairingModal: Alert { - return Alert( - title: FrameworkLocalText("Are you sure you want to cancel Pod setup?", comment: "Alert title for cancel pairing modal"), - message: FrameworkLocalText("If you cancel Pod setup, the current Pod will be deactivated and will be unusable.", comment: "Alert message body for confirm pod attachment"), - primaryButton: .destructive(FrameworkLocalText("Yes, Deactivate Pod", comment: "Button title for confirm deactivation option"), action: didRequestDeactivation), - secondaryButton: .default(FrameworkLocalText("No, Continue With Pod", comment: "Continue pairing button title of in pairing cancel modal")) - ) - } -} - -struct AttachPodView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - ZStack { - Color(UIColor.secondarySystemBackground).edgesIgnoringSafeArea(.all) - AttachPodView(didConfirmAttachment: {}, didRequestDeactivation: {}) - } - } - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/BasalStateView.swift b/Dependencies/OmniKit/OmniKitUI/Views/BasalStateView.swift deleted file mode 100644 index f72d873e7..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/BasalStateView.swift +++ /dev/null @@ -1,139 +0,0 @@ -// -// BasalStateView.swift -// Naterade -// -// Created by Nathan Racklyeft on 5/12/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import SwiftUI - -public struct BasalStateSwiftUIView: UIViewRepresentable { - - var netBasalPercent: Double - - public init(netBasalPercent: Double) { - self.netBasalPercent = netBasalPercent - } - - public func makeUIView(context: UIViewRepresentableContext) -> BasalStateView { - let view = BasalStateView() - view.netBasalPercent = netBasalPercent - return view - } - - public func updateUIView(_ uiView: BasalStateView, context: UIViewRepresentableContext) { - uiView.netBasalPercent = netBasalPercent - } -} - - -public final class BasalStateView: UIView { - - var netBasalPercent: Double = 0 { - didSet { - animateToPath(drawPath()) - } - } - - override public class var layerClass : AnyClass { - return CAShapeLayer.self - } - - private var shapeLayer: CAShapeLayer { - return layer as! CAShapeLayer - } - - override init(frame: CGRect) { - super.init(frame: frame) - - shapeLayer.lineWidth = 2 - updateTintColor() - } - - required public init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - - shapeLayer.lineWidth = 2 - updateTintColor() - } - - override public func layoutSubviews() { - super.layoutSubviews() - animateToPath(drawPath()) - } - - public override func tintColorDidChange() { - super.tintColorDidChange() - updateTintColor() - } - - private func updateTintColor() { - shapeLayer.fillColor = tintColor.withAlphaComponent(0.5).cgColor - shapeLayer.strokeColor = tintColor.cgColor - } - - private func drawPath() -> CGPath { - let startX = bounds.minX - let endX = bounds.maxX - let midY = bounds.midY - - let path = UIBezierPath() - path.move(to: CGPoint(x: startX, y: midY)) - - let leftAnchor = startX + 1/6 * bounds.size.width - let rightAnchor = startX + 5/6 * bounds.size.width - - let yAnchor = bounds.midY - CGFloat(netBasalPercent) * (bounds.size.height - shapeLayer.lineWidth) / 2 - - path.addLine(to: CGPoint(x: leftAnchor, y: midY)) - path.addLine(to: CGPoint(x: leftAnchor, y: yAnchor)) - path.addLine(to: CGPoint(x: rightAnchor, y: yAnchor)) - path.addLine(to: CGPoint(x: rightAnchor, y: midY)) - path.addLine(to: CGPoint(x: endX, y: midY)) - - return path.cgPath - } - - private static let animationKey = "com.loudnate.Naterade.shapePathAnimation" - - private func animateToPath(_ path: CGPath) { - // Do not animate first draw - if shapeLayer.path != nil { - let animation = CABasicAnimation(keyPath: "path") - animation.fromValue = shapeLayer.path ?? drawPath() - animation.toValue = path - animation.duration = 1 - animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) - - shapeLayer.add(animation, forKey: type(of: self).animationKey) - } - - // Do not draw when size is zero - if bounds != .zero { - shapeLayer.path = path - } - } -} - -struct BasalStateSwiftUIViewPreviewWrapper: View { - @State private var percent: Double = 1 - - var body: some View { - VStack(spacing: 20) { - BasalStateSwiftUIView(netBasalPercent: percent).frame(width: 100, height: 100, alignment: .center) - Button(action: { - self.percent = self.percent * -1 - }) { - Text("Toggle sign") - } - Text("Percent = \(percent)") - } - } -} -struct BasalStateSwiftUIViewPreview: PreviewProvider { - static var previews: some View { - BasalStateSwiftUIViewPreviewWrapper() - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/BeepPreferenceSelectionView.swift b/Dependencies/OmniKit/OmniKitUI/Views/BeepPreferenceSelectionView.swift deleted file mode 100644 index e9a2e659c..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/BeepPreferenceSelectionView.swift +++ /dev/null @@ -1,147 +0,0 @@ -// -// BeepPreferenceSelectionView.swift -// OmniKit -// -// Created by Pete Schwamb on 2/14/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import OmniKit - -struct BeepPreferenceSelectionView: View { - - @Environment(\.horizontalSizeClass) var horizontalSizeClass - @Environment(\.presentationMode) var presentationMode: Binding - - private var initialValue: BeepPreference - @State private var preference: BeepPreference - private var onSave: ((_ selectedValue: BeepPreference, _ completion: @escaping (_ error: LocalizedError?) -> Void) -> Void)? - - @State private var alertIsPresented: Bool = false - @State private var error: LocalizedError? - @State private var saving: Bool = false - - - init(initialValue: BeepPreference, onSave: @escaping (_ selectedValue: BeepPreference, _ completion: @escaping (_ error: LocalizedError?) -> Void) -> Void) { - self.initialValue = initialValue - self._preference = State(initialValue: initialValue) - self.onSave = onSave - } - - var body: some View { - contentWithCancel - } - - var content: some View { - VStack { - List { - Section { - Text(LocalizedString("Confidence reminders are beeps from the Pod which can be used to acknowledge selected commands when the Pod is not silenced.", comment: "Help text for BeepPreferenceSelectionView")).fixedSize(horizontal: false, vertical: true) - .padding(.vertical, 10) - } - - Section { - ForEach(BeepPreference.allCases, id: \.self) { preference in - HStack { - CheckmarkListItem( - title: Text(preference.title), - description: Text(preference.description), - isSelected: Binding( - get: { self.preference == preference }, - set: { isSelected in - if isSelected { - self.preference = preference - } - } - ) - ) - } - .padding(.vertical, 10) - } - } - .buttonStyle(PlainButtonStyle()) // Disable row highlighting on selection - } - VStack { - Button(action: { - saving = true - onSave?(preference) { (error) in - saving = false - if let error = error { - self.error = error - self.alertIsPresented = true - } else { - self.presentationMode.wrappedValue.dismiss() - } - } - }) { - Text(saveButtonText) - .actionButtonStyle(.primary) - } - .padding() - .disabled(saving || !valueChanged) - } - .padding(self.horizontalSizeClass == .regular ? .bottom : []) - .background(Color(UIColor.secondarySystemGroupedBackground).shadow(radius: 5)) - - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Confidence Reminders", comment: "navigation title for confidence reminders")) - .navigationBarTitleDisplayMode(.inline) - .alert(isPresented: $alertIsPresented, content: { alert(error: error) }) - } - - private var contentWithCancel: some View { - if saving { - return AnyView(content - .navigationBarBackButtonHidden(true) - ) - } else if valueChanged { - return AnyView(content - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: cancelButton) - ) - } else { - return AnyView(content) - } - } - - private var cancelButton: some View { - Button(action: { self.presentationMode.wrappedValue.dismiss() } ) { - Text(LocalizedString("Cancel", comment: "Button title for cancelling confidence reminders edit")) - } - } - - var saveButtonText: String { - if saving { - return LocalizedString("Saving...", comment: "button title for saving confidence reminder while saving") - } else { - return LocalizedString("Save", comment: "button title for saving confidence reminder") - } - } - - private var valueChanged: Bool { - return preference != initialValue - } - - private func alert(error: Error?) -> SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Failed to update confidence reminder preference.", comment: "Alert title for error when updating confidence reminder preference")), - message: Text(error?.localizedDescription ?? "No Error") - ) - } - -} - -struct BeepPreferenceSelectionView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - BeepPreferenceSelectionView(initialValue: .extended) { selectedValue, completion in - print("Selected: \(selectedValue)") - completion(nil) - } - } - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/CheckInsertedCannulaView.swift b/Dependencies/OmniKit/OmniKitUI/Views/CheckInsertedCannulaView.swift deleted file mode 100644 index 6a2a13887..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/CheckInsertedCannulaView.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// CheckInsertedCannulaView.swift -// OmniKit -// -// Created by Pete Schwamb on 4/3/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct CheckInsertedCannulaView: View { - - - @State private var cancelModalIsPresented: Bool = false - - private var didRequestDeactivation: () -> Void - private var wasInsertedProperly: () -> Void - - init(didRequestDeactivation: @escaping () -> Void, wasInsertedProperly: @escaping () -> Void) { - self.didRequestDeactivation = didRequestDeactivation - self.wasInsertedProperly = wasInsertedProperly - } - - var body: some View { - GuidePage(content: { - VStack { - LeadingImage("Cannula Inserted") - - HStack { - FrameworkLocalText("Is the cannula inserted properly?", comment: "Question to confirm the cannula is inserted properly").bold() - Spacer() - } - HStack { - FrameworkLocalText("The window on the top of the Pod should be colored pink when the cannula is properly inserted into the skin.", comment: "Description of proper cannula insertion").fixedSize(horizontal: false, vertical: true) - Spacer() - }.padding(.vertical) - } - - }) { - VStack(spacing: 10) { - Button(action: { - self.wasInsertedProperly() - }) { - Text(LocalizedString("Yes", comment: "Button label for user to answer cannula was properly inserted")) - .actionButtonStyle(.primary) - } - Button(action: { - self.didRequestDeactivation() - }) { - Text(LocalizedString("No", comment: "Button label for user to answer cannula was not properly inserted")) - .actionButtonStyle(.destructive) - } - }.padding() - } - .animation(.default) - .alert(isPresented: $cancelModalIsPresented) { cancelPairingModal } - .navigationBarTitle(LocalizedString("Check Cannula", comment: "navigation bar title for check cannula"), displayMode: .automatic) - .navigationBarItems(trailing: cancelButton) - .navigationBarBackButtonHidden(true) - } - - var cancelButton: some View { - Button(LocalizedString("Cancel", comment: "Cancel button text in navigation bar on insert cannula screen")) { - cancelModalIsPresented = true - } - .accessibility(identifier: "button_cancel") - } - - var cancelPairingModal: Alert { - return Alert( - title: FrameworkLocalText("Are you sure you want to cancel Pod setup?", comment: "Alert title for cancel pairing modal"), - message: FrameworkLocalText("If you cancel Pod setup, the current Pod will be deactivated and will be unusable.", comment: "Alert message body for confirm pod attachment"), - primaryButton: .destructive(FrameworkLocalText("Yes, Deactivate Pod", comment: "Button title for confirm deactivation option"), action: { didRequestDeactivation() } ), - secondaryButton: .default(FrameworkLocalText("No, Continue With Pod", comment: "Continue pairing button title of in pairing cancel modal")) - ) - } - -} - -struct CheckInsertedCannulaView_Previews: PreviewProvider { - static var previews: some View { - CheckInsertedCannulaView(didRequestDeactivation: {}, wasInsertedProperly: {} ) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/DeactivatePodView.swift b/Dependencies/OmniKit/OmniKitUI/Views/DeactivatePodView.swift deleted file mode 100644 index 3d24d0c73..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/DeactivatePodView.swift +++ /dev/null @@ -1,97 +0,0 @@ -// -// DeactivatePodView.swift -// OmniKit -// -// Created by Pete Schwamb on 3/9/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct DeactivatePodView: View { - - @ObservedObject var viewModel: DeactivatePodViewModel - - @Environment(\.verticalSizeClass) var verticalSizeClass - @Environment(\.guidanceColors) var guidanceColors - - @State private var removePodModalIsPresented: Bool = false - - var body: some View { - GuidePage(content: { - VStack { - LeadingImage("Pod") - - HStack { - Text(viewModel.instructionText) - .fixedSize(horizontal: false, vertical: true) - Spacer() - } - } - .padding(.bottom, 8) - }) { - VStack { - if viewModel.state.showProgressDetail { - VStack { - viewModel.error.map {ErrorView($0).accessibility(sortPriority: 0)} - - if viewModel.error == nil { - VStack { - ProgressIndicatorView(state: viewModel.state.progressState) - if self.viewModel.state.isFinished { - FrameworkLocalText("Deactivated", comment: "Label text showing pod is deactivated") - .bold() - .padding(.top) - } - } - .padding(.bottom, 8) - } - - } - .transition(AnyTransition.opacity.combined(with: .move(edge: .bottom))) - } - if viewModel.error != nil { - Button(action: { - if viewModel.podAttachedToBody { - removePodModalIsPresented = true - } else { - viewModel.discardPod() - } - }) { - FrameworkLocalText("Discard Pod", comment: "Text for discard pod button") - .accessibility(identifier: "button_discard_pod_action") - .actionButtonStyle(.destructive) - } - .disabled(viewModel.state.isProcessing) - } - Button(action: { - viewModel.continueButtonTapped() - }) { - Text(viewModel.state.actionButtonDescription) - .accessibility(identifier: "button_next_action") - .accessibility(label: Text(viewModel.state.actionButtonAccessibilityLabel)) - .actionButtonStyle(viewModel.state.actionButtonStyle) - } - .disabled(viewModel.state.isProcessing) - } - .padding() - } - .alert(isPresented: $removePodModalIsPresented) { removePodModal } - .navigationBarTitle(LocalizedString("Deactivate Pod", comment: "navigation bar title for deactivate pod"), displayMode: .automatic) - .navigationBarItems(trailing: - Button("Cancel") { - viewModel.didCancel?() - } - ) - } - - var removePodModal: Alert { - return Alert( - title: FrameworkLocalText("Remove Pod from Body", comment: "Title for remove pod modal"), - message: FrameworkLocalText("Your Pod may still be delivering Insulin.\nRemove it from your body, then tap “Continue.“", comment: "Alert message body for confirm pod attachment"), - primaryButton: .cancel(), - secondaryButton: .default(FrameworkLocalText("Continue", comment: "Title of button to continue discard"), action: { viewModel.discardPod() }) - ) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/DeliveryUncertaintyRecoveryView.swift b/Dependencies/OmniKit/OmniKitUI/Views/DeliveryUncertaintyRecoveryView.swift deleted file mode 100644 index 1370c67f6..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/DeliveryUncertaintyRecoveryView.swift +++ /dev/null @@ -1,107 +0,0 @@ -// -// DeliveryUncertaintyRecoveryView.swift -// OmniKit -// -// Created by Pete Schwamb on 8/17/20. -// Copyright © 2020 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI -import RileyLinkBLEKit - -struct DeliveryUncertaintyRecoveryView: View { - - let model: DeliveryUncertaintyRecoveryViewModel - - @ObservedObject var rileyLinkListDataSource: RileyLinkListDataSource - - var handleRileyLinkSelection: (RileyLinkDevice) -> Void - - @Environment(\.guidanceColors) var guidanceColors - - var body: some View { - GuidePage(content: { - Text(String(format: LocalizedString("%1$@ has been unable to communicate with the pod on your body since %2$@.\n\nWithout communication with the pod, the app cannot continue to send commands for insulin delivery or display accurate, recent information about your active insulin or the insulin being delivered by the Pod.\n\nMonitor your glucose closely for the next 6 or more hours, as there may or may not be insulin actively working in your body that %3$@ cannot display.", comment: "Format string for main text of delivery uncertainty recovery page. (1: app name)(2: date of command)(3: app name)"), self.model.appName, self.uncertaintyDateLocalizedString, self.model.appName)) - .padding([.top, .bottom]) - Section(header: HStack { - FrameworkLocalText("Devices", comment: "Header for devices section of RileyLinkSetupView") - Spacer() - ProgressView() - }) { - ForEach(rileyLinkListDataSource.devices, id: \.peripheralIdentifier) { device in - Toggle(isOn: rileyLinkListDataSource.autoconnectBinding(for: device)) { - HStack { - Text(device.name ?? "Unknown") - Spacer() - - if rileyLinkListDataSource.autoconnectBinding(for: device).wrappedValue { - if device.isConnected { - Text(formatRSSI(rssi:device.rssi)).foregroundColor(.secondary) - } else { - Image(systemName: "wifi.exclamationmark") - .imageScale(.large) - .foregroundColor(guidanceColors.warning) - } - } - } - .contentShape(Rectangle()) - .onTapGesture { - handleRileyLinkSelection(device) - } - } - } - } - .onAppear { - rileyLinkListDataSource.isScanningEnabled = true - model.respondToRecovery = true - } - .onDisappear { - rileyLinkListDataSource.isScanningEnabled = false - model.respondToRecovery = false - } - }) { - VStack { - Text(LocalizedString("Attemping to re-establish communication", comment: "Description string above progress indicator while attempting to re-establish communication from an unacknowledged command")).padding(.top) - ProgressIndicatorView(state: .indeterminantProgress) - Button(action: { - self.model.podDeactivationChosen() - }) { - Text(LocalizedString("Deactivate Pod", comment: "Button title to deactive pod on uncertain program")) - .actionButtonStyle(.destructive) - .padding() - } - } - } - .navigationBarTitle(Text(LocalizedString("Unable to Reach Pod", comment: "Title of delivery uncertainty recovery page")), displayMode: .large) - .navigationBarItems(leading: backButton) - } - - private var uncertaintyDateLocalizedString: String { - DateFormatter.localizedString(from: model.uncertaintyStartedAt, dateStyle: .none, timeStyle: .short) - } - - var decimalFormatter: NumberFormatter = { - let formatter = NumberFormatter() - - formatter.numberStyle = .decimal - formatter.minimumFractionDigits = 0 - formatter.maximumFractionDigits = 2 - - return formatter - }() - - private func formatRSSI(rssi: Int?) -> String { - if let rssi = rssi, let rssiStr = decimalFormatter.decibleString(from: rssi) { - return rssiStr - } else { - return "" - } - } - - private var backButton: some View { - Button(LocalizedString("Back", comment: "Back button text on DeliveryUncertaintyRecoveryView"), action: { - self.model.onDismiss?() - }) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/DesignElements/ErrorView.swift b/Dependencies/OmniKit/OmniKitUI/Views/DesignElements/ErrorView.swift deleted file mode 100644 index f77524a49..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/DesignElements/ErrorView.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// ErrorView.swift -// OmniKit -// -// Created by Pete Schwamb on 3/12/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct ErrorView: View { - var error: LocalizedError - - var criticality: ErrorCriticality - - @Environment(\.guidanceColors) var guidanceColors - - public enum ErrorCriticality { - case critical - case normal - - func symbolColor(using guidanceColors: GuidanceColors) -> Color { - switch self { - case .critical: - return guidanceColors.critical - case .normal: - return guidanceColors.warning - } - } - } - - init(_ error: LocalizedError, errorClass: ErrorCriticality = .normal) { - self.error = error - self.criticality = errorClass - } - - var body: some View { - VStack(alignment: .leading, spacing: 15) { - HStack { - Image(systemName: "exclamationmark.triangle.fill") - .foregroundColor(self.criticality.symbolColor(using: guidanceColors)) - Text(self.error.errorDescription ?? "") - .bold() - .accessibility(identifier: "label_error_description") - .fixedSize(horizontal: false, vertical: true) - } - .accessibilityElement(children: .ignore) - .accessibility(label: FrameworkLocalText("Error", comment: "Accessibility label indicating an error occurred")) - - Text(self.error.recoverySuggestion ?? "") - .foregroundColor(.secondary) - .font(.footnote) - .accessibility(identifier: "label_recovery_suggestion") - .fixedSize(horizontal: false, vertical: true) - } - .padding(.bottom) - .accessibilityElement(children: .combine) - } -} - -struct ErrorView_Previews: PreviewProvider { - enum ErrorViewPreviewError: LocalizedError { - case someError - - var localizedDescription: String { "It didn't work" } - var recoverySuggestion: String { "Maybe try turning it on and off." } - } - - static var previews: some View { - ErrorView(ErrorViewPreviewError.someError) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/DesignElements/LeadingImage.swift b/Dependencies/OmniKit/OmniKitUI/Views/DesignElements/LeadingImage.swift deleted file mode 100644 index 6fd8bc9b3..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/DesignElements/LeadingImage.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// LeadingImage.swift -// OmniKit -// -// Created by Pete Schwamb on 3/12/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -struct LeadingImage: View { - - var name: String - - static let compactScreenImageHeight: CGFloat = 70 - static let regularScreenImageHeight: CGFloat = 150 - - @Environment(\.verticalSizeClass) var verticalSizeClass - - init(_ name: String) { - self.name = name - } - - var body: some View { - Image(frameworkImage: self.name, decorative: true) - .resizable() - .aspectRatio(contentMode: ContentMode.fit) - .frame(height: self.verticalSizeClass == .compact ? LeadingImage.compactScreenImageHeight : LeadingImage.regularScreenImageHeight) - .padding(.vertical, self.verticalSizeClass == .compact ? 0 : nil) - } -} - -struct LeadingImage_Previews: PreviewProvider { - static var previews: some View { - LeadingImage("Pod") - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/DesignElements/RoundedCard.swift b/Dependencies/OmniKit/OmniKitUI/Views/DesignElements/RoundedCard.swift deleted file mode 100644 index 14f2fe908..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/DesignElements/RoundedCard.swift +++ /dev/null @@ -1,177 +0,0 @@ -// -// RoundedCard.swift -// OmniKit -// -// Created by Pete Schwamb on 2/9/21. -// -import SwiftUI - -fileprivate let inset: CGFloat = 16 - -struct RoundedCardTitle: View { - var title: String - - init(_ title: String) { - self.title = title - } - - var body: some View { - Text(title) - .font(.headline) - .foregroundColor(.primary) - } -} - -struct RoundedCardFooter: View { - var text: String - - init(_ text: String) { - self.text = text - } - - var body: some View { - Text(text) - .font(.caption) - .fixedSize(horizontal: false, vertical: true) - .foregroundColor(.secondary) - } -} - -public struct RoundedCardValueRow: View { - var label: String - var value: String - var highlightValue: Bool - var disclosure: Bool - - public init(label: String, value: String, highlightValue: Bool = false, disclosure: Bool = false) { - self.label = label - self.value = value - self.highlightValue = highlightValue - self.disclosure = disclosure - } - - public var body: some View { - HStack { - Text(label) - .fixedSize(horizontal: false, vertical: true) - .foregroundColor(.primary) - Spacer() - Text(value) - .fixedSize(horizontal: true, vertical: true) - .foregroundColor(highlightValue ? .accentColor : .secondary) - if disclosure { - Image(systemName: "chevron.right") - .imageScale(.small) - .font(.headline) - .foregroundColor(.secondary) - .opacity(0.5) - } - } - } -} - -struct RoundedCard: View { - var content: () -> Content? - var alignment: HorizontalAlignment - var title: String? - var footer: String? - @Environment(\.horizontalSizeClass) var horizontalSizeClass - - init(title: String? = nil, footer: String? = nil, alignment: HorizontalAlignment = .leading, @ViewBuilder content: @escaping () -> Content? = { nil }) { - self.content = content - self.alignment = alignment - self.title = title - self.footer = footer - } - - var body: some View { - VStack(spacing: 10) { - if let title = title { - RoundedCardTitle(title) - .frame(maxWidth: .infinity, alignment: Alignment(horizontal: .leading, vertical: .center)) - .padding(.leading, titleInset) - } - - if content() != nil { - if isCompact { - VStack(spacing: 0) { - borderLine - VStack(alignment: alignment, content: content) - .frame(maxWidth: .infinity, alignment: Alignment(horizontal: alignment, vertical: .center)) - .padding(inset) - .background(Color(.secondarySystemGroupedBackground)) - borderLine - } - } else { - VStack(alignment: alignment, content: content) - .frame(maxWidth: .infinity, alignment: Alignment(horizontal: alignment, vertical: .center)) - .padding(.horizontal, inset) - .padding(.vertical, 10) - .background(Color(.secondarySystemGroupedBackground)) - .clipShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)) - } - } - - if let footer = footer { - RoundedCardFooter(footer) - .frame(maxWidth: .infinity, alignment: Alignment(horizontal: alignment, vertical: .center)) - .padding(.horizontal, inset) - } - } - } - - var borderLine: some View { - Rectangle().fill(Color(.quaternaryLabel)) - .frame(height: 0.5) - } - - private var isCompact: Bool { - return self.horizontalSizeClass == .compact - } - - private var titleInset: CGFloat { - return isCompact ? inset : 0 - } - - private var padding: CGFloat { - return isCompact ? 0 : inset - } - - private var cornerRadius: CGFloat { - return isCompact ? 0 : 8 - } - -} - -struct RoundedCardScrollView: View { - var content: () -> Content - var title: String? - @Environment(\.horizontalSizeClass) var horizontalSizeClass - - init(title: String? = nil, @ViewBuilder content: @escaping () -> Content) { - self.title = title - self.content = content - } - - var body: some View { - ScrollView { - if let title = title { - HStack { - Text(title) - .font(Font.largeTitle.weight(.bold)) - .padding(.top) - Spacer() - } - .padding([.leading, .trailing]) - } - VStack(alignment: .leading, spacing: 25, content: content) - .padding(padding) - } - .background(Color(.systemGroupedBackground).edgesIgnoringSafeArea(.all)) - } - - private var padding: CGFloat { - return self.horizontalSizeClass == .regular ? inset : 0 - } - -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/ExpirationReminderPickerView.swift b/Dependencies/OmniKit/OmniKitUI/Views/ExpirationReminderPickerView.swift deleted file mode 100644 index df7613e92..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/ExpirationReminderPickerView.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// ExpirationReminderPickerView.swift -// OmniKit -// -// Created by Pete Schwamb on 5/17/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import HealthKit - -struct ExpirationReminderPickerView: View { - - static let expirationReminderHoursAllowed = 0...24 - - var expirationReminderDefault: Binding - - var collapsible: Bool = true - - @State var showingHourPicker: Bool = false - - var expirationDefaultFormatter = QuantityFormatter(for: .hour()) - - var expirationDefaultString: String { - return expirationReminderHourString(expirationReminderDefault.wrappedValue) - } - - var body: some View { - VStack { - HStack { - Text(LocalizedString("Expiration Reminder Default", comment: "Label text for expiration reminder default row")) - Spacer() - if collapsible { - Button(expirationDefaultString) { - withAnimation { - showingHourPicker.toggle() - } - } - } else { - Text(expirationDefaultString) - } - } - if showingHourPicker { - ResizeablePicker(selection: expirationReminderDefault, - data: Array(Self.expirationReminderHoursAllowed), - formatter: { expirationReminderHourString($0) }) - } - } - } - - private func expirationReminderHourString(_ value: Int) -> String { - if value > 0 { - return expirationDefaultFormatter.string(from: HKQuantity(unit: .hour(), doubleValue: Double(value)), for: .hour())! - } else { - return LocalizedString("No Reminder", comment: "Value text for no expiration reminder") - } - } -} - -struct ExpirationReminderPickerView_Previews: PreviewProvider { - static var previews: some View { - ExpirationReminderPickerView(expirationReminderDefault: .constant(2)) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/ExpirationReminderSetupView.swift b/Dependencies/OmniKit/OmniKitUI/Views/ExpirationReminderSetupView.swift deleted file mode 100644 index 6c508140b..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/ExpirationReminderSetupView.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// ExpirationReminderSetupView.swift -// OmniKit -// -// Created by Pete Schwamb on 5/17/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct ExpirationReminderSetupView: View { - @State var expirationReminderDefault: Int = 2 - - public var valueChanged: ((_ value: Int) -> Void)? - public var continueButtonTapped: (() -> Void)? - public var cancelButtonTapped: (() -> Void)? - - var body: some View { - GuidePage(content: { - VStack(alignment: .leading, spacing: 15) { - Text(LocalizedString("The App notifies you in advance of Pod expiration.\n\nScroll to set the number of hours advance notice you would like to have.", comment: "Description text on ExpirationReminderSetupView")).fixedSize(horizontal: false, vertical: true) - Divider() - ExpirationReminderPickerView(expirationReminderDefault: $expirationReminderDefault, collapsible: false, showingHourPicker: true) - .onChange(of: expirationReminderDefault) { value in - valueChanged?(value) - } - } - .padding(.vertical, 8) - }) { - VStack { - Button(action: { - continueButtonTapped?() - }) { - Text(LocalizedString("Next", comment: "Text of continue button on ExpirationReminderSetupView")) - .actionButtonStyle(.primary) - } - } - .padding() - } - .navigationBarTitle(LocalizedString("Expiration Reminder", comment: "navigation bar title for expiration reminder"), displayMode: .automatic) - .navigationBarHidden(false) - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(LocalizedString("Cancel", comment: "Cancel button title"), action: { - cancelButtonTapped?() - }) - } - } - } -} - -struct ExpirationReminderSetupView_Previews: PreviewProvider { - static var previews: some View { - ExpirationReminderSetupView() - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/FirstAppear.swift b/Dependencies/OmniKit/OmniKitUI/Views/FirstAppear.swift deleted file mode 100644 index 664bde601..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/FirstAppear.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// FirstAppear.swift -// Omnipod -// -// Created by Joe Moran on 9/24/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -extension View { - func onFirstAppear(_ action: @escaping () -> ()) -> some View { - modifier(FirstAppear(action: action)) - } -} - -private struct FirstAppear: ViewModifier { - let action: () -> () - - // State used to insure action is invoked here only once - @State private var hasAppeared = false - - func body(content: Content) -> some View { - content.onAppear { - guard !hasAppeared else { return } - hasAppeared = true - action() - } - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/InsertCannulaView.swift b/Dependencies/OmniKit/OmniKitUI/Views/InsertCannulaView.swift deleted file mode 100644 index 06520b4be..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/InsertCannulaView.swift +++ /dev/null @@ -1,107 +0,0 @@ -// -// InsertCannulaView.swift -// OmniKit -// -// Created by Pete Schwamb on 2/5/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct InsertCannulaView: View { - - @ObservedObject var viewModel: InsertCannulaViewModel - - @Environment(\.verticalSizeClass) var verticalSizeClass - - @State private var cancelModalIsPresented: Bool = false - - var body: some View { - GuidePage(content: { - VStack { - LeadingImage("Pod") - - HStack { - InstructionList(instructions: [ - LocalizedString("Tap below to start cannula insertion.", comment: "Label text for step one of insert cannula instructions"), - LocalizedString("Wait until insertion is completed.", comment: "Label text for step two of insert cannula instructions"), - ]) - .disabled(viewModel.state.instructionsDisabled) - - } - .padding(.bottom, 8) - } - .accessibility(sortPriority: 1) - }) { - VStack { - if self.viewModel.state.showProgressDetail { - self.viewModel.error.map { - ErrorView($0, errorClass: $0.recoverable ? .normal : .critical) - .accessibility(sortPriority: 0) - } - - if self.viewModel.error == nil { - VStack { - ProgressIndicatorView(state: self.viewModel.state.progressState) - if self.viewModel.state.isFinished { - FrameworkLocalText("Inserted", comment: "Label text indicating insertion finished.") - .bold() - .padding(.top) - } - } - .padding(.bottom, 8) - } - } - if self.viewModel.error != nil { - Button(action: { - self.viewModel.didRequestDeactivation?() - }) { - Text(LocalizedString("Deactivate Pod", comment: "Button text for deactivate pod button")) - .accessibility(identifier: "button_deactivate_pod") - .actionButtonStyle(.secondary) - } - .disabled(self.viewModel.state.isProcessing) - } - - if (self.viewModel.error == nil || self.viewModel.error?.recoverable == true) { - Button(action: { - self.viewModel.continueButtonTapped() - }) { - Text(self.viewModel.state.nextActionButtonDescription) - .accessibility(identifier: "button_next_action") - .accessibility(label: Text(self.viewModel.state.actionButtonAccessibilityLabel)) - .actionButtonStyle(.primary) - } - .disabled(self.viewModel.state.isProcessing) - .animation(nil) - .zIndex(1) - } - } - .transition(AnyTransition.opacity.combined(with: .move(edge: .bottom))) - .padding() - } - .animation(.default) - .alert(isPresented: $cancelModalIsPresented) { cancelPairingModal } - .navigationBarTitle(LocalizedString("Insert Cannula", comment: "navigation bar title for insert cannula"), displayMode: .automatic) - .navigationBarBackButtonHidden(true) - .navigationBarItems(trailing: cancelButton) - } - - var cancelButton: some View { - Button(LocalizedString("Cancel", comment: "Cancel button text in navigation bar on insert cannula screen")) { - cancelModalIsPresented = true - } - .accessibility(identifier: "button_cancel") - } - - var cancelPairingModal: Alert { - return Alert( - title: FrameworkLocalText("Are you sure you want to cancel Pod setup?", comment: "Alert title for cancel pairing modal"), - message: FrameworkLocalText("If you cancel Pod setup, the current Pod will be deactivated and will be unusable.", comment: "Alert message body for confirm pod attachment"), - primaryButton: .destructive(FrameworkLocalText("Yes, Deactivate Pod", comment: "Button title for confirm deactivation option"), action: { viewModel.didRequestDeactivation?() } ), - secondaryButton: .default(FrameworkLocalText("No, Continue With Pod", comment: "Continue pairing button title of in pairing cancel modal")) - ) - } - -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/InsulinTypeConfirmation.swift b/Dependencies/OmniKit/OmniKitUI/Views/InsulinTypeConfirmation.swift deleted file mode 100644 index 814f1fdba..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/InsulinTypeConfirmation.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// InsulinTypeConfirmation.swift -// MockKitUI -// -// Created by Pete Schwamb on 1/1/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI - -struct InsulinTypeConfirmation: View { - - @State private var insulinType: InsulinType? - private var supportedInsulinTypes: [InsulinType] - private var didConfirm: (InsulinType) -> Void - private var didCancel: () -> Void - - init(initialValue: InsulinType, supportedInsulinTypes: [InsulinType], didConfirm: @escaping (InsulinType) -> Void, didCancel: @escaping () -> Void) { - self._insulinType = State(initialValue: initialValue) - self.supportedInsulinTypes = supportedInsulinTypes - self.didConfirm = didConfirm - self.didCancel = didCancel - } - - func continueWithType(_ insulinType: InsulinType?) { - if let insulinType = insulinType { - didConfirm(insulinType) - } else { - assertionFailure() - } - } - - var body: some View { - VStack { - List { - Section { - Text(LocalizedString("Select the type of insulin that you will be using in this pod.", comment: "Title text for insulin type confirmation page")) - } - Section { - InsulinTypeChooser(insulinType: $insulinType, supportedInsulinTypes: supportedInsulinTypes) - } - .buttonStyle(PlainButtonStyle()) // Disable row highlighting on selection - } - .insetGroupedListStyle() - - Button(action: { self.continueWithType(insulinType) }) { - Text(LocalizedString("Continue", comment: "Text for continue button")) - .actionButtonStyle(.primary) - .padding() - } - } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(LocalizedString("Cancel", comment: "Cancel button title"), action: { - didCancel() - }) - } - } - } -} - -struct InsulinTypeConfirmation_Previews: PreviewProvider { - static var previews: some View { - InsulinTypeConfirmation(initialValue: .humalog, supportedInsulinTypes: InsulinType.allCases, didConfirm: { (newType) in }, didCancel: { }) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/LowReservoirReminderEditView.swift b/Dependencies/OmniKit/OmniKitUI/Views/LowReservoirReminderEditView.swift deleted file mode 100644 index 9d901ef62..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/LowReservoirReminderEditView.swift +++ /dev/null @@ -1,156 +0,0 @@ -// -// LowReservoirReminderEditView.swift -// OmniKit -// -// Created by Pete Schwamb on 2/17/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import HealthKit -import OmniKit - -struct LowReservoirReminderEditView: View { - - @Environment(\.horizontalSizeClass) var horizontalSizeClass - - var onSave: ((_ selectedValue: Int, _ completion: @escaping (_ error: Error?) -> Void) -> Void)? - var onFinish: (() -> Void)? - var insulinQuantityFormatter: QuantityFormatter - - private var initialValue: Int - @State private var alertIsPresented: Bool = false - @State private var error: Error? - @State private var saving: Bool = false - @State private var selectedValue: Int - - - init(lowReservoirReminderValue: Int, insulinQuantityFormatter: QuantityFormatter, onSave: ((_ selectedValue: Int, _ completion: @escaping (_ error: Error?) -> Void) -> Void)? = nil, onFinish: (() -> Void)? = nil) - { - self.onSave = onSave - self.onFinish = onFinish - self.insulinQuantityFormatter = insulinQuantityFormatter - self.initialValue = lowReservoirReminderValue - self._selectedValue = State(initialValue: lowReservoirReminderValue) - } - - var body: some View { - contentWithCancel - } - - var content: some View { - VStack { - RoundedCardScrollView(title: LocalizedString("Low Reservoir Reminder", comment: "Title for low reservoir reminder edit page")) { - if self.horizontalSizeClass == .compact { - // Keep picker outside of card in compact view, because it forces full device width. - VStack(spacing: 0) { - RoundedCard { - RoundedCardValueRow( - label: LocalizedString("Low Reservoir Reminder", comment: "Label for low reservoir reminder row"), - value: formatValue(selectedValue), - highlightValue: true - ) - } - picker - .background(Color(.secondarySystemGroupedBackground)) - } - } else { - RoundedCard { - RoundedCardValueRow( - label: LocalizedString("Low Reservoir Reminder", comment: "Label for low reservoir reminder row"), - value: formatValue(selectedValue), - highlightValue: true - ) - picker - } - } - } - Spacer() - Button(action: saveTapped) { - Text(saveButtonText) - .actionButtonStyle() - .padding() - } - .disabled(saving || !valueChanged) - } - .navigationTitle("") - .navigationBarTitleDisplayMode(.inline) - .alert(isPresented: $alertIsPresented, content: { alert(error: error) }) - } - - private var picker: some View { - Picker("", selection: $selectedValue) { - ForEach(Pod.allowedLowReservoirReminderValues, id: \.self) { value in - Text(formatValue(value)) - } - }.pickerStyle(WheelPickerStyle()) - } - - func formatValue(_ value: Int) -> String { - return insulinQuantityFormatter.string(from: HKQuantity(unit: .internationalUnit(), doubleValue: Double(value)), for: .internationalUnit()) ?? "" - } - - var saveButtonText: String { - if saving { - return LocalizedString("Saving...", comment: "button title for saving low reservoir reminder while saving") - } else { - return LocalizedString("Save", comment: "button title for saving low reservoir reminder") - } - } - - private func saveTapped() { - saving = true - self.onSave?(selectedValue) { (error) in - saving = false - if let error = error { - self.error = error - self.alertIsPresented = true - } else { - self.onFinish?() - } - } - } - - private var valueChanged: Bool { - return selectedValue != initialValue - } - - private var contentWithCancel: some View { - if saving { - return AnyView(content - .navigationBarBackButtonHidden(true) - ) - } else if valueChanged { - return AnyView(content - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: cancelButton) - ) - } else { - return AnyView(content) - } - } - - private var cancelButton: some View { - Button(action: { self.onFinish?() } ) { Text(LocalizedString("Cancel", comment: "Button title for cancelling low reservoir reminder edit")) } - } - - private func alert(error: Error?) -> SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Failed to Update Low Reservoir Reminder", comment: "Alert title for error when updating low reservoir reminder")), - message: Text(error?.localizedDescription ?? "No Error") - ) - } -} - -struct LowReservoirReminderEditView_Previews: PreviewProvider { - static var previews: some View { - LowReservoirReminderEditView( - lowReservoirReminderValue: 20, - insulinQuantityFormatter: QuantityFormatter(for: .internationalUnit()), - onSave: { (_, _) in }, - onFinish: { } - ) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/LowReservoirReminderSetupView.swift b/Dependencies/OmniKit/OmniKitUI/Views/LowReservoirReminderSetupView.swift deleted file mode 100644 index cb3bd3488..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/LowReservoirReminderSetupView.swift +++ /dev/null @@ -1,80 +0,0 @@ -// -// LowReservoirReminderSetupView.swift -// OmniKit -// -// Created by Pete Schwamb on 5/17/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI -import LoopKit -import HealthKit -import OmniKit - -struct LowReservoirReminderSetupView: View { - - @State var lowReservoirReminderValue: Int - - public var valueChanged: ((_ value: Int) -> Void)? - public var continueButtonTapped: (() -> Void)? - public var cancelButtonTapped: (() -> Void)? - - var insulinQuantityFormatter = QuantityFormatter(for: .internationalUnit()) - - func formatValue(_ value: Int) -> String { - return insulinQuantityFormatter.string(from: HKQuantity(unit: .internationalUnit(), doubleValue: Double(value)), for: .internationalUnit()) ?? "" - } - - var body: some View { - GuidePage(content: { - VStack(alignment: .leading, spacing: 15) { - Text(LocalizedString("The App notifies you when the amount of insulin in the Pod reaches this level (50-10 U).\n\nScroll to set the number of units at which you would like to be reminded.", comment: "Description text on LowReservoirReminderSetupView")) - Divider() - HStack { - Text(LocalizedString("Low Reservoir", comment: "Label text for low reservoir value row")) - Spacer() - Text(formatValue(lowReservoirReminderValue)) - } - picker - } - .padding(.vertical, 8) - }) { - VStack { - Button(action: { - continueButtonTapped?() - }) { - Text(LocalizedString("Next", comment: "Text of continue button on ExpirationReminderSetupView")) - .actionButtonStyle(.primary) - } - } - .padding() - } - .navigationBarTitle(LocalizedString("Low Reservoir", comment: "navigation bar title for low reservoir"), displayMode: .automatic) - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(LocalizedString("Cancel", comment: "Cancel button title"), action: { - cancelButtonTapped?() - }) - } - } - } - - private var picker: some View { - Picker("", selection: $lowReservoirReminderValue) { - ForEach(Pod.allowedLowReservoirReminderValues, id: \.self) { value in - Text(formatValue(value)) - } - }.pickerStyle(WheelPickerStyle()) - .onChange(of: lowReservoirReminderValue) { value in - valueChanged?(value) - } - - } - -} -struct LowReservoirReminderSetupView_Previews: PreviewProvider { - static var previews: some View { - LowReservoirReminderSetupView(lowReservoirReminderValue: 10) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/ManualTempBasalEntryView.swift b/Dependencies/OmniKit/OmniKitUI/Views/ManualTempBasalEntryView.swift deleted file mode 100644 index 84c69cff6..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/ManualTempBasalEntryView.swift +++ /dev/null @@ -1,161 +0,0 @@ -// -// ManualTempBasalEntryView.swift -// OmniKit -// -// Created by Pete Schwamb on 5/14/22. -// Copyright © 2022 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI -import LoopKit -import HealthKit -import OmniKit - -struct ManualTempBasalEntryView: View { - - @Environment(\.guidanceColors) var guidanceColors - - var enactBasal: ((Double,TimeInterval,@escaping (PumpManagerError?)->Void) -> Void)? - var didCancel: (() -> Void)? - - @State private var rateEntered: Double = 0.0 - @State private var durationEntered: TimeInterval = .hours(0.5) - @State private var showPicker: Bool = false - @State private var error: PumpManagerError? - @State private var enacting: Bool = false - @State private var showingErrorAlert: Bool = false - @State private var showingMissingConfigAlert: Bool = false - - var allowedRates: [Double] - - init(enactBasal: ((Double,TimeInterval,@escaping (PumpManagerError?)->Void) -> Void)? = nil, didCancel: (() -> Void)? = nil, allowedRates: [Double]) { - self.enactBasal = enactBasal - self.didCancel = didCancel - self.allowedRates = allowedRates - // This is to handle users migrating from OmnipodPumpManagerState with no max temp basal set - if allowedRates.count <= 1 { - _showingMissingConfigAlert = State(initialValue: true) - } - } - - private static let rateFormatter: QuantityFormatter = { - let quantityFormatter = QuantityFormatter() - quantityFormatter.setPreferredNumberFormatter(for: .internationalUnitsPerHour) - quantityFormatter.numberFormatter.minimumFractionDigits = 2 - return quantityFormatter - }() - - private var rateUnitsLabel: some View { - Text(QuantityFormatter().string(from: .internationalUnitsPerHour)) - .foregroundColor(Color(.secondaryLabel)) - } - - private static let durationFormatter: QuantityFormatter = { - let quantityFormatter = QuantityFormatter() - quantityFormatter.setPreferredNumberFormatter(for: .hour()) - quantityFormatter.numberFormatter.minimumFractionDigits = 1 - quantityFormatter.numberFormatter.maximumFractionDigits = 1 - quantityFormatter.unitStyle = .long - return quantityFormatter - }() - - private var durationUnitsLabel: some View { - Text(QuantityFormatter().string(from: .hour())) - .foregroundColor(Color(.secondaryLabel)) - } - - func formatRate(_ rate: Double) -> String { - let unit = HKUnit.internationalUnitsPerHour - return ManualTempBasalEntryView.rateFormatter.string(from: HKQuantity(unit: unit, doubleValue: rate), for: unit) ?? "" - } - - func formatDuration(_ duration: TimeInterval) -> String { - let unit = HKUnit.hour() - return ManualTempBasalEntryView.durationFormatter.string(from: HKQuantity(unit: unit, doubleValue: duration.hours), for: unit) ?? "" - } - - var body: some View { - NavigationView { - VStack { - List { - HStack { - Text(LocalizedString("Rate", comment: "Label text for basal rate summary")) - Spacer() - Text(String(format: LocalizedString("%1$@ for %2$@", comment: "Summary string for temporary basal rate configuration page"), formatRate(rateEntered), formatDuration(durationEntered))) - } - HStack { - ResizeablePicker(selection: $rateEntered, - data: allowedRates, - formatter: { formatRate($0) }) - ResizeablePicker(selection: $durationEntered, - data: Pod.supportedTempBasalDurations, - formatter: { formatDuration($0) }) - } - .frame(maxHeight: 162.0) - .alert(isPresented: $showingMissingConfigAlert, content: { missingConfigAlert }) - Section { - Text(LocalizedString("Your insulin delivery will not be automatically adjusted until the temporary basal rate finishes or is canceled.", comment: "Description text on manual temp basal action sheet")) - .font(.footnote) - .foregroundColor(.secondary) - .fixedSize(horizontal: false, vertical: true) - } - } - Button(action: { - enacting = true - enactBasal?(rateEntered, durationEntered) { (error) in - if let error = error { - self.error = error - showingErrorAlert = true - } - enacting = false - } - }) { - HStack { - if enacting { - ProgressView() - } else { - Text(LocalizedString("Set Temporary Basal", comment: "Button text for setting manual temporary basal rate")) - } - } - } - .buttonStyle(ActionButtonStyle(.primary)) - .padding() - } - .navigationTitle(LocalizedString("Temporary Basal", comment: "Navigation Title for ManualTempBasalEntryView")) - .navigationBarItems(trailing: cancelButton) - .alert(isPresented: $showingErrorAlert, content: { errorAlert }) - .disabled(enacting) - } - } - - var errorAlert: SwiftUI.Alert { - let errorMessage = errorMessage(error: error!) - return SwiftUI.Alert( - title: Text(LocalizedString("Temporary Basal Failed", comment: "Alert title for a failure to set temporary basal")), - message: errorMessage) - } - - func errorMessage(error: PumpManagerError) -> Text { - if let recovery = error.recoverySuggestion { - return Text(String(format: LocalizedString("Unable to set a temporary basal rate: %1$@\n\n%2$@", comment: "Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text)"), error.localizedDescription, recovery)) - } else { - return Text(String(format: LocalizedString("Unable to set a temporary basal rate: %1$@", comment: "Alert format string for a failure to set temporary basal. (1: error description)"), error.localizedDescription)) - } - } - - var missingConfigAlert: SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Missing Config", comment: "Alert title for missing temp basal configuration")), - message: Text(LocalizedString("This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Pump Settings in the settings CONFIGURATION section to set a new Max Basal.", comment: "Alert format string for missing temp basal configuration.")) - ) - } - - - var cancelButton: some View { - Button(LocalizedString("Cancel", comment: "Cancel button text in navigation bar on insert cannula screen")) { - didCancel?() - } - .accessibility(identifier: "button_cancel") - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/NotificationSettingsView.swift b/Dependencies/OmniKit/OmniKitUI/Views/NotificationSettingsView.swift deleted file mode 100644 index 9e3101aad..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/NotificationSettingsView.swift +++ /dev/null @@ -1,144 +0,0 @@ -// -// NotificationSettingsView.swift -// OmniKit -// -// Created by Pete Schwamb on 2/3/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import HealthKit - -struct NotificationSettingsView: View { - - var dateFormatter: DateFormatter - - @Binding var expirationReminderDefault: Int - - @State private var showingHourPicker: Bool = false - - var scheduledReminderDate: Date? - - var allowedScheduledReminderDates: [Date]? - - var lowReservoirReminderValue: Int - - var onSaveScheduledExpirationReminder: ((_ selectedDate: Date?, _ completion: @escaping (_ error: Error?) -> Void) -> Void)? - - var onSaveLowReservoirReminder: ((_ selectedValue: Int, _ completion: @escaping (_ error: Error?) -> Void) -> Void)? - - var insulinQuantityFormatter = QuantityFormatter(for: .internationalUnit()) - - var body: some View { - RoundedCardScrollView { - RoundedCard( - title: LocalizedString("Pod Reminders", comment: "Title for pod reminders section"), - footer: LocalizedString("The app configures a reminder on the Pod to notify you in advance of Pod expiration. Set the number of hours advance notice you would like to configure by default when pairing a new Pod.", comment: "Footer text for pod reminders section") - ) { - ExpirationReminderPickerView(expirationReminderDefault: $expirationReminderDefault) - } - - if let allowedDates = allowedScheduledReminderDates { - RoundedCard( - footer: LocalizedString("The expiration reminder time for the current Pod.", comment: "Footer text for scheduled reminder area")) - { - Text(LocalizedString("Scheduled Reminder", comment: "Title of scheduled reminder card on NotificationSettingsView")) - Divider() - scheduledReminderRow(scheduledDate: scheduledReminderDate, allowedDates: allowedDates) - } - } - - RoundedCard(footer: LocalizedString("The app notifies you when the amount of insulin in the Pod reaches this level.", comment: "Footer text for low reservoir value row")) { - lowReservoirValueRow - } - - RoundedCard( - title: LocalizedString("Critical Alerts", comment: "Title for critical alerts description"), - footer: LocalizedString("The above reminders will not sound in the app if your device is in Silent or Do Not Disturb mode. There are other critical Pod alerts that will sound in the app even if your device is set to Silent or Do Not Disturb mode.\n\nThe Pod will also use audible beeps for all Pod reminders and alerts except when the Pod is Silenced.", comment: "Description text for critical alerts") - ) - } - .navigationBarTitle(LocalizedString("Notification Settings", comment: "navigation title for notification settings")) - } - - @State private var scheduleReminderDateEditViewIsShown: Bool = false - - private func scheduledReminderRow(scheduledDate: Date?, allowedDates: [Date]) -> some View { - Group { - // Make the expiration reminder time read-only if there aren't any more available times. - if allowedDates.isEmpty { - scheduledReminderRowContents(disclosure: false) - } else { - NavigationLink( - destination: ScheduledExpirationReminderEditView( - scheduledExpirationReminderDate: scheduledDate, - allowedDates: allowedDates, - dateFormatter: dateFormatter, - onSave: onSaveScheduledExpirationReminder, - onFinish: { scheduleReminderDateEditViewIsShown = false }), - isActive: $scheduleReminderDateEditViewIsShown) - { - scheduledReminderRowContents(disclosure: true) - } - } - } - } - - private func scheduledReminderRowContents(disclosure: Bool) -> some View { - RoundedCardValueRow( - label: LocalizedString("Time", comment: "Label for scheduled reminder value row"), - value: scheduledReminderDateString(scheduledReminderDate), - highlightValue: false, - disclosure: disclosure - ) - } - - private func scheduledReminderDateString(_ scheduledDate: Date?) -> String { - if let scheduledDate = scheduledDate { - return dateFormatter.string(from: scheduledDate) - } else { - return LocalizedString("No Reminder", comment: "Value text for no expiration reminder") - } - } - - @State private var lowReservoirReminderEditViewIsShown: Bool = false - - var lowReservoirValueRow: some View { - NavigationLink( - destination: LowReservoirReminderEditView( - lowReservoirReminderValue: lowReservoirReminderValue, - insulinQuantityFormatter: insulinQuantityFormatter, - onSave: onSaveLowReservoirReminder, - onFinish: { lowReservoirReminderEditViewIsShown = false }), - isActive: $lowReservoirReminderEditViewIsShown) - { - RoundedCardValueRow( - label: LocalizedString("Low Reservoir Reminder", comment: "Label for low reservoir reminder row"), - value: insulinQuantityFormatter.string(from: HKQuantity(unit: .internationalUnit(), doubleValue: Double(lowReservoirReminderValue)), for: .internationalUnit()) ?? "", - highlightValue: false, - disclosure: true) - } - } -} - -struct NotificationSettingsView_Previews: PreviewProvider { - static var previews: some View { - return Group { - NavigationView { - let now = Date() - NotificationSettingsView(dateFormatter: DateFormatter(), expirationReminderDefault: .constant(2), scheduledReminderDate: now + TimeInterval(hours: 1), allowedScheduledReminderDates: [now, now - TimeInterval(hours: 2), now - TimeInterval(hours: 3)], lowReservoirReminderValue: 20) - .previewDevice(PreviewDevice(rawValue:"iPod touch (7th generation)")) - .previewDisplayName("iPod touch (7th generation)") - } - - NavigationView { - let now = Date() - NotificationSettingsView(dateFormatter: DateFormatter(), expirationReminderDefault: .constant(2), scheduledReminderDate: now + TimeInterval(hours: 1), allowedScheduledReminderDates: [now, now - TimeInterval(hours: 2), now - TimeInterval(hours: 3)], lowReservoirReminderValue: 20) - .colorScheme(.dark) - .previewDevice(PreviewDevice(rawValue: "iPhone XS Max")) - .previewDisplayName("iPhone XS Max - Dark") - } - } - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/OmnipodReservoirView.swift b/Dependencies/OmniKit/OmniKitUI/Views/OmnipodReservoirView.swift deleted file mode 100644 index 8b584d517..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/OmnipodReservoirView.swift +++ /dev/null @@ -1,127 +0,0 @@ -// -// OmnipodReservoirView.swift -// OmniKit -// -// Created by Pete Schwamb on 10/22/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import UIKit -import LoopKitUI -import OmniKit - -public final class OmnipodReservoirView: LevelHUDView, NibLoadable { - - override public var orderPriority: HUDViewOrderPriority { - return 11 - } - - @IBOutlet private weak var volumeLabel: UILabel! - - @IBOutlet private weak var alertLabel: UILabel! { - didSet { - alertLabel.alpha = 0 - alertLabel.textColor = UIColor.white - alertLabel.layer.cornerRadius = 9 - alertLabel.clipsToBounds = true - } - } - - public class func instantiate() -> OmnipodReservoirView { - return nib().instantiate(withOwner: nil, options: nil)[0] as! OmnipodReservoirView - } - - override public func awakeFromNib() { - super.awakeFromNib() - - volumeLabel.isHidden = true - } - - private var reservoirLevel: ReservoirLevel? - private var lastUpdateDate: Date? - private var reservoirLevelHighlightState = ReservoirLevelHighlightState.normal - - override public func tintColorDidChange() { - super.tintColorDidChange() - - alertLabel?.backgroundColor = tintColor - volumeLabel.textColor = tintColor - levelMaskView.tintColor = tintColor - } - - override public func updateColor() { - switch reservoirLevelHighlightState { - case .normal: - tintColor = stateColors?.normal - case .warning: - tintColor = stateColors?.warning - case .critical: - tintColor = stateColors?.error - } - } - - private lazy var timeFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .none - formatter.timeStyle = .short - - return formatter - }() - - private lazy var numberFormatter: NumberFormatter = { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.maximumFractionDigits = 0 - - return formatter - }() - - private func updateViews() { - if let reservoirLevel = reservoirLevel, let date = lastUpdateDate { - - let time = timeFormatter.string(from: date) - caption?.text = time - - switch reservoirLevel { - case .aboveThreshold: - level = nil - volumeLabel.isHidden = true - if let units = numberFormatter.string(from: Pod.maximumReservoirReading) { - volumeLabel.text = String(format: LocalizedString("%@+ U", comment: "Format string for reservoir volume when above maximum reading. (1: The maximum reading)"), units) - accessibilityValue = String(format: LocalizedString("Greater than %1$@ units remaining at %2$@", comment: "Accessibility format string for (1: localized volume)(2: time)"), units, time) - } - case .valid(let value): - level = reservoirLevel.percentage - volumeLabel.isHidden = false - - if let units = numberFormatter.string(from: value) { - volumeLabel.text = String(format: LocalizedString("%@U", comment: "Format string for reservoir volume. (1: The localized volume)"), units) - - accessibilityValue = String(format: LocalizedString("%1$@ units remaining at %2$@", comment: "Accessibility format string for (1: localized volume)(2: time)"), units, time) - } - } - } else { - level = 0 - volumeLabel.isHidden = true - } - - var alertLabelAlpha: CGFloat = 1 - switch reservoirLevelHighlightState { - case .normal: - alertLabelAlpha = 0 - case .warning, .critical: - alertLabel?.text = "!" - } - - UIView.animate(withDuration: 0.25, animations: { - self.alertLabel?.alpha = alertLabelAlpha - }) - } - - public func update(level: ReservoirLevel?, at date: Date, reservoirLevelHighlightState: ReservoirLevelHighlightState) { - self.reservoirLevel = level - self.lastUpdateDate = date - self.reservoirLevelHighlightState = reservoirLevelHighlightState - updateViews() - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/OmnipodSettingsView.swift b/Dependencies/OmniKit/OmniKitUI/Views/OmnipodSettingsView.swift deleted file mode 100644 index bc105972b..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/OmnipodSettingsView.swift +++ /dev/null @@ -1,673 +0,0 @@ -// -// OmnipodSettingsView.swift -// ViewDev -// -// Created by Pete Schwamb on 3/8/20. -// Copyright © 2020 Pete Schwamb. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import HealthKit -import OmniKit -import RileyLinkBLEKit - -struct OmnipodSettingsView: View { - - @ObservedObject var viewModel: OmnipodSettingsViewModel - - @ObservedObject var rileyLinkListDataSource: RileyLinkListDataSource - - var handleRileyLinkSelection: (RileyLinkDevice) -> Void - - @State private var showingDeleteConfirmation = false - - @State private var showSuspendOptions = false - - @State private var showManualTempBasalOptions = false - - @State private var showSyncTimeOptions = false - - @State private var sendingTestBeepsCommand = false - - @State private var cancelingTempBasal = false - - var supportedInsulinTypes: [InsulinType] - - @Environment(\.guidanceColors) var guidanceColors - @Environment(\.insulinTintColor) var insulinTintColor - - private var daysRemaining: Int? { - if case .timeRemaining(let remaining, _) = viewModel.lifeState, remaining > .days(1) { - return Int(remaining.days) - } - return nil - } - - private var hoursRemaining: Int? { - if case .timeRemaining(let remaining, _) = viewModel.lifeState, remaining > .hours(1) { - return Int(remaining.hours.truncatingRemainder(dividingBy: 24)) - } - return nil - } - - private var minutesRemaining: Int? { - if case .timeRemaining(let remaining, _) = viewModel.lifeState, remaining < .hours(2) { - return Int(remaining.minutes.truncatingRemainder(dividingBy: 60)) - } - return nil - } - - func timeComponent(value: Int, units: String) -> some View { - Group { - Text(String(value)).font(.system(size: 28)).fontWeight(.heavy) - .foregroundColor(viewModel.podOk ? .primary : .secondary) - Text(units).foregroundColor(.secondary) - } - } - - var lifecycleProgress: some View { - VStack(spacing: 2) { - HStack(alignment: .lastTextBaseline, spacing: 3) { - Text(self.viewModel.lifeState.localizedLabelText) - .foregroundColor(self.viewModel.lifeState.labelColor(using: guidanceColors)) - Spacer() - daysRemaining.map { (days) in - timeComponent(value: days, units: days == 1 ? - LocalizedString("day", comment: "Unit for singular day in pod life remaining") : - LocalizedString("days", comment: "Unit for plural days in pod life remaining")) - } - hoursRemaining.map { (hours) in - timeComponent(value: hours, units: hours == 1 ? - LocalizedString("hour", comment: "Unit for singular hour in pod life remaining") : - LocalizedString("hours", comment: "Unit for plural hours in pod life remaining")) - } - minutesRemaining.map { (minutes) in - timeComponent(value: minutes, units: minutes == 1 ? - LocalizedString("minute", comment: "Unit for singular minute in pod life remaining") : - LocalizedString("minutes", comment: "Unit for plural minutes in pod life remaining")) - } - } - ProgressView(progress: CGFloat(self.viewModel.lifeState.progress)).accentColor(self.viewModel.lifeState.progressColor(guidanceColors: guidanceColors)) - } - } - - func cancelDelete() { - showingDeleteConfirmation = false - } - - - var deliverySectionTitle: String { - if self.viewModel.isScheduledBasal { - return LocalizedString("Scheduled Basal", comment: "Title of insulin delivery section") - } else { - return LocalizedString("Insulin Delivery", comment: "Title of insulin delivery section") - } - } - - var deliveryStatus: some View { - VStack(alignment: .leading, spacing: 5) { - Text(deliverySectionTitle) - .foregroundColor(Color(UIColor.secondaryLabel)) - if viewModel.podOk, viewModel.isSuspendedOrResuming { - HStack(alignment: .center) { - Image(systemName: "pause.circle.fill") - .font(.system(size: 34)) - .fixedSize() - .foregroundColor(viewModel.suspendResumeButtonColor(guidanceColors: guidanceColors)) - FrameworkLocalText("Insulin\nSuspended", comment: "Text shown in insulin delivery space when insulin suspended") - .fontWeight(.bold) - .fixedSize() - } - } else if let basalRate = self.viewModel.basalDeliveryRate { - HStack(alignment: .center) { - HStack(alignment: .lastTextBaseline, spacing: 3) { - Text(self.viewModel.basalRateFormatter.string(from: basalRate) ?? "") - .font(.system(size: 28)) - .fontWeight(.heavy) - .fixedSize() - FrameworkLocalText("U/hr", comment: "Units for showing temp basal rate").foregroundColor(.secondary) - } - } - } else { - HStack(alignment: .center) { - Image(systemName: "x.circle.fill") - .font(.system(size: 34)) - .fixedSize() - .foregroundColor(guidanceColors.critical) - FrameworkLocalText("No\nDelivery", comment: "Text shown in insulin remaining space when no pod is paired") - .fontWeight(.bold) - .fixedSize() - } - } - } - } - - func reservoir(filledPercent: CGFloat, fillColor: Color) -> some View { - ZStack(alignment: Alignment(horizontal: .center, vertical: .center)) { - GeometryReader { geometry in - let offset = geometry.size.height * 0.05 - let fillHeight = geometry.size.height * 0.81 - Rectangle() - .fill(fillColor) - .mask( - Image(frameworkImage: "pod_reservoir_mask_swiftui") - .resizable() - .scaledToFit() - ) - .mask( - Rectangle().path(in: CGRect(x: 0, y: offset + fillHeight - fillHeight * filledPercent, width: geometry.size.width, height: fillHeight * filledPercent)) - ) - } - Image(frameworkImage: "pod_reservoir_swiftui") - .renderingMode(.template) - .resizable() - .foregroundColor(fillColor) - .scaledToFit() - }.frame(width: 23, height: 32) - } - - - var reservoirStatus: some View { - VStack(alignment: .leading, spacing: 5) { - Text(LocalizedString("Insulin Remaining", comment: "Header for insulin remaining on pod settings screen")) - .foregroundColor(Color(UIColor.secondaryLabel)) - HStack { - if let podError = viewModel.podError { - Image(systemName: "exclamationmark.circle.fill") - .font(.system(size: 34)) - .fixedSize() - .foregroundColor(guidanceColors.critical) - - Text(podError).fontWeight(.bold) - } else if let reservoirLevel = viewModel.reservoirLevel, let reservoirLevelHighlightState = viewModel.reservoirLevelHighlightState { - reservoir(filledPercent: CGFloat(reservoirLevel.percentage), fillColor: reservoirColor(for: reservoirLevelHighlightState)) - Text(viewModel.reservoirText(for: reservoirLevel)) - .font(.system(size: 28)) - .fontWeight(.heavy) - .fixedSize() - } else { - Image(systemName: "exclamationmark.circle.fill") - .font(.system(size: 34)) - .fixedSize() - .foregroundColor(guidanceColors.warning) - - FrameworkLocalText("No Pod", comment: "Text shown in insulin remaining space when no pod is paired").fontWeight(.bold) - } - - } - } - } - - var manualTempBasalRow: some View { - Button(action: { - self.manualBasalTapped() - }) { - FrameworkLocalText("Set Temporary Basal Rate", comment: "Button title to set temporary basal rate") - } - .sheet(isPresented: $showManualTempBasalOptions) { - ManualTempBasalEntryView( - enactBasal: { rate, duration, completion in - viewModel.runTemporaryBasalProgram(unitsPerHour: rate, for: duration) { error in - completion(error) - if error == nil { - showManualTempBasalOptions = false - } - } - }, - didCancel: { - showManualTempBasalOptions = false - }, - allowedRates: viewModel.allowedTempBasalRates - ) - } - } - - - func suspendResumeRow() -> some View { - HStack { - Button(action: { - self.suspendResumeTapped() - }) { - HStack { - Image(systemName: "pause.circle.fill") - .font(.system(size: 22)) - .foregroundColor(viewModel.suspendResumeButtonColor(guidanceColors: guidanceColors)) - Text(viewModel.suspendResumeActionText) - .foregroundColor(viewModel.suspendResumeActionColor()) - } - } - .actionSheet(isPresented: $showSuspendOptions) { - suspendOptionsActionSheet - } - Spacer() - if viewModel.basalTransitioning { - ActivityIndicator(isAnimating: .constant(true), style: .medium) - } - } - } - - private var doneButton: some View { - Button(LocalizedString("Done", comment: "Title of done button on OmnipodSettingsView"), action: { - self.viewModel.doneTapped() - }) - } - - var headerImage: some View { - VStack(alignment: .center) { - Image(frameworkImage: "Pod") - .resizable() - .aspectRatio(contentMode: ContentMode.fit) - .frame(height: 100) - .padding(.horizontal) - }.frame(maxWidth: .infinity) - } - - var body: some View { - List { - Section() { - VStack(alignment: .trailing) { - Button(action: { - sendingTestBeepsCommand = true - viewModel.playTestBeeps { _ in - sendingTestBeepsCommand = false - } - }) { - Image(systemName: "speaker.wave.2.circle") - .imageScale(.large) - .foregroundColor(viewModel.rileylinkConnected ? .accentColor : .secondary) - .padding(.top,5) - } - .buttonStyle(PlainButtonStyle()) - .disabled(!viewModel.rileylinkConnected || sendingTestBeepsCommand) - - headerImage - - lifecycleProgress - - HStack(alignment: .top) { - deliveryStatus - Spacer() - reservoirStatus - } - if let faultAction = viewModel.recoveryText { - Divider() - Text(faultAction) - .font(Font.footnote.weight(.semibold)) - .fixedSize(horizontal: false, vertical: true) - .frame(maxWidth: .infinity, alignment: .leading) - } - } - if let notice = viewModel.notice { - VStack(alignment: .leading, spacing: 4) { - Text(notice.title) - .font(Font.subheadline.weight(.bold)) - Text(notice.description) - .font(Font.footnote.weight(.semibold)) - }.padding(.vertical, 8) - } - } - - Section(header: SectionHeader(label: LocalizedString("Activity", comment: "Section header for activity section"))) { - suspendResumeRow() - .disabled(!self.viewModel.podOk) - if self.viewModel.podOk, case .suspended(let suspendDate) = self.viewModel.basalDeliveryState { - HStack { - FrameworkLocalText("Suspended At", comment: "Label for suspended at time") - Spacer() - Text(self.viewModel.timeFormatter.string(from: suspendDate)) - .foregroundColor(Color.secondary) - } - } - } - - Section() { - if let manualTempRemaining = self.viewModel.manualBasalTimeRemaining, let remainingText = self.viewModel.timeRemainingFormatter.string(from: manualTempRemaining) { - HStack { - if cancelingTempBasal { - ProgressView() - .padding(.trailing) - } else { - Image(systemName: "exclamationmark.circle.fill") - .font(.system(size: 22)) - .foregroundColor(guidanceColors.warning) - } - Button(action: { - self.cancelManualBasal() - }) { - FrameworkLocalText("Cancel Manual Basal", comment: "Button title to cancel manual basal") - } - } - HStack { - FrameworkLocalText("Remaining", comment: "Label for remaining time of manual basal") - Spacer() - Text(remainingText) - .foregroundColor(.secondary) - } - } else { - manualTempBasalRow - } - } - .disabled(cancelingTempBasal || !self.viewModel.podOk) - - Section(header: HStack { - FrameworkLocalText("Devices", comment: "Header for devices section of RileyLinkSetupView") - Spacer() - ProgressView() - }) { - ForEach(rileyLinkListDataSource.devices, id: \.peripheralIdentifier) { device in - Toggle(isOn: rileyLinkListDataSource.autoconnectBinding(for: device)) { - HStack { - Text(device.name ?? "Unknown") - Spacer() - - if rileyLinkListDataSource.autoconnectBinding(for: device).wrappedValue { - if device.isConnected { - Text(formatRSSI(rssi:device.rssi)).foregroundColor(.secondary) - } else { - Image(systemName: "wifi.exclamationmark") - .imageScale(.large) - .foregroundColor(guidanceColors.warning) - } - } - } - .contentShape(Rectangle()) - .onTapGesture { - handleRileyLinkSelection(device) - } - } - } - } - .onAppear { rileyLinkListDataSource.isScanningEnabled = true } - .onDisappear { rileyLinkListDataSource.isScanningEnabled = false } - - Section() { - HStack { - FrameworkLocalText("Pod Activated", comment: "Label for pod insertion row") - Spacer() - Text(self.viewModel.activatedAtString) - .foregroundColor(Color.secondary) - } - - HStack { - if let expiresAt = viewModel.expiresAt, expiresAt < Date() { - FrameworkLocalText("Pod Expired", comment: "Label for pod expiration row, past tense") - } else { - FrameworkLocalText("Pod Expires", comment: "Label for pod expiration row") - } - Spacer() - Text(self.viewModel.expiresAtString) - .foregroundColor(Color.secondary) - } - - if let podDetails = self.viewModel.podDetails { - NavigationLink(destination: PodDetailsView(podDetails: podDetails, title: LocalizedString("Pod Details", comment: "title for pod details page"))) { - FrameworkLocalText("Pod Details", comment: "Text for pod details disclosure row").foregroundColor(Color.primary) - } - } else { - HStack { - FrameworkLocalText("Pod Details", comment: "Text for pod details disclosure row") - Spacer() - Text("—") - .foregroundColor(Color.secondary) - } - } - - if let previousPodDetails = viewModel.previousPodDetails { - NavigationLink(destination: PodDetailsView(podDetails: previousPodDetails, title: LocalizedString("Previous Pod", comment: "title for previous pod page"))) { - FrameworkLocalText("Previous Pod Details", comment: "Text for previous pod details row").foregroundColor(Color.primary) - } - } else { - HStack { - FrameworkLocalText("Previous Pod Details", comment: "Text for previous pod details row") - Spacer() - Text("—") - .foregroundColor(Color.secondary) - } - } - } - - Section() { - Button(action: { - self.viewModel.navigateTo?(self.viewModel.lifeState.nextPodLifecycleAction) - }) { - Text(self.viewModel.lifeState.nextPodLifecycleActionDescription) - .foregroundColor(self.viewModel.lifeState.nextPodLifecycleActionColor) - } - } - - Section(header: SectionHeader(label: LocalizedString("Configuration", comment: "Section header for configuration section"))) - { - NavigationLink(destination: - NotificationSettingsView( - dateFormatter: self.viewModel.dateFormatter, - expirationReminderDefault: self.$viewModel.expirationReminderDefault, - scheduledReminderDate: self.viewModel.expirationReminderDate, - allowedScheduledReminderDates: self.viewModel.allowedScheduledReminderDates, - lowReservoirReminderValue: self.viewModel.lowReservoirAlertValue, - onSaveScheduledExpirationReminder: self.viewModel.saveScheduledExpirationReminder, - onSaveLowReservoirReminder: self.viewModel.saveLowReservoirReminder)) - { - FrameworkLocalText("Notification Settings", comment: "Text for pod details disclosure row").foregroundColor(Color.primary) - } - NavigationLink(destination: BeepPreferenceSelectionView(initialValue: viewModel.beepPreference, onSave: viewModel.setConfirmationBeeps)) { - HStack { - FrameworkLocalText("Confidence Reminders", comment: "Text for confidence reminders navigation link").foregroundColor(Color.primary) - Spacer() - Text(viewModel.beepPreference.title) - .foregroundColor(.secondary) - } - } - NavigationLink(destination: SilencePodSelectionView(initialValue: viewModel.silencePodPreference, onSave: viewModel.setSilencePod)) { - HStack { - FrameworkLocalText("Silence Pod", comment: "Text for silence pod navigation link").foregroundColor(Color.primary) - Spacer() - Text(viewModel.silencePodPreference.title) - .foregroundColor(.secondary) - } - } - NavigationLink(destination: InsulinTypeSetting(initialValue: viewModel.insulinType, supportedInsulinTypes: supportedInsulinTypes, allowUnsetInsulinType: false, didChange: viewModel.didChangeInsulinType)) { - HStack { - FrameworkLocalText("Insulin Type", comment: "Text for insulin type navigation link").foregroundColor(Color.primary) - if let currentTitle = viewModel.insulinType?.brandName { - Spacer() - Text(currentTitle) - .foregroundColor(.secondary) - } - } - } - } - - Section() { - HStack { - FrameworkLocalText("Pump Time", comment: "The title of the command to change pump time zone") - Spacer() - if viewModel.isClockOffset { - Image(systemName: "clock.fill") - .foregroundColor(guidanceColors.warning) - } - TimeView(timeZone: viewModel.timeZone) - .foregroundColor( viewModel.isClockOffset ? guidanceColors.warning : nil) - } - if viewModel.synchronizingTime { - HStack { - FrameworkLocalText("Adjusting Pump Time...", comment: "Text indicating ongoing pump time synchronization") - .foregroundColor(.secondary) - Spacer() - ActivityIndicator(isAnimating: .constant(true), style: .medium) - } - } else if self.viewModel.timeZone != TimeZone.currentFixed { - Button(action: { - showSyncTimeOptions = true - }) { - FrameworkLocalText("Sync to Current Time", comment: "The title of the command to change pump time zone") - } - .actionSheet(isPresented: $showSyncTimeOptions) { - syncPumpTimeActionSheet - } - } - } - - Section(header: SectionHeader(label: LocalizedString("Diagnostics", comment: "Section header for diagnostic section"))) { - NavigationLink(destination: ReadPodStatusView(toRun: viewModel.readPodStatus)) { - FrameworkLocalText("Read Pod Status", comment: "Text for read pod status navigation link").foregroundColor(Color.primary) - } - .disabled(self.viewModel.noPod) - NavigationLink(destination: ReadPulseLogView(toRun: viewModel.readPulseLog)) { - FrameworkLocalText("Read Pulse Log", comment: "Text for read pulse log navigation link").foregroundColor(Color.primary) - } - .disabled(self.viewModel.noPod) - NavigationLink(destination: PlayTestBeepsView(toRun: viewModel.playTestBeeps)) { - FrameworkLocalText("Play Test Beeps", comment: "Text for play test beeps navigation link").foregroundColor(Color.primary) - } - .disabled(!self.viewModel.podOk) - NavigationLink(destination: PumpManagerDetailsView(toRun: viewModel.pumpManagerDetails)) { - FrameworkLocalText("Pump Manager Details", comment: "Text for pump manager details navigation link").foregroundColor(Color.primary) - } - } - - if self.viewModel.lifeState.allowsPumpManagerRemoval { - Section() { - Button(action: { - self.showingDeleteConfirmation = true - }) { - FrameworkLocalText("Switch to other insulin delivery device", comment: "Label for PumpManager deletion button") - .foregroundColor(guidanceColors.critical) - } - .actionSheet(isPresented: $showingDeleteConfirmation) { - removePumpManagerActionSheet - } - } - } - } - .alert(isPresented: $viewModel.alertIsPresented, content: { alert(for: viewModel.activeAlert!) }) - .insetGroupedListStyle() - .navigationBarItems(trailing: doneButton) - .navigationBarTitle(self.viewModel.viewTitle) - } - - var syncPumpTimeActionSheet: ActionSheet { - ActionSheet(title: FrameworkLocalText("Time Change Detected", comment: "Title for pod sync time action sheet."), message: FrameworkLocalText("The time on your pump is different from the current time. Do you want to update the time on your pump to the current time?", comment: "Message for pod sync time action sheet"), buttons: [ - .default(FrameworkLocalText("Yes, Sync to Current Time", comment: "Button text to confirm pump time sync")) { - self.viewModel.changeTimeZoneTapped() - }, - .cancel(FrameworkLocalText("No, Keep Pump As Is", comment: "Button text to cancel pump time sync")) - ]) - } - - var removePumpManagerActionSheet: ActionSheet { - ActionSheet(title: FrameworkLocalText("Remove Pump", comment: "Title for Omnipod PumpManager deletion action sheet."), message: FrameworkLocalText("Are you sure you want to stop using Omnipod?", comment: "Message for Omnipod PumpManager deletion action sheet"), buttons: [ - .destructive(FrameworkLocalText("Delete Omnipod", comment: "Button text to confirm Omnipod PumpManager deletion")) { - self.viewModel.stopUsingOmnipodTapped() - }, - .cancel() - ]) - } - - var suspendOptionsActionSheet: ActionSheet { - ActionSheet( - title: FrameworkLocalText("Suspend Delivery", comment: "Title for suspend duration selection action sheet"), - message: FrameworkLocalText("Insulin delivery will be stopped until you resume manually. When would you like Loop to remind you to resume delivery?", comment: "Message for suspend duration selection action sheet"), - buttons: [ - .default(FrameworkLocalText("30 minutes", comment: "Button text for 30 minute suspend duration"), action: { self.viewModel.suspendDelivery(duration: .minutes(30)) }), - .default(FrameworkLocalText("1 hour", comment: "Button text for 1 hour suspend duration"), action: { self.viewModel.suspendDelivery(duration: .hours(1)) }), - .default(FrameworkLocalText("1 hour 30 minutes", comment: "Button text for 1 hour 30 minute suspend duration"), action: { self.viewModel.suspendDelivery(duration: .hours(1.5)) }), - .default(FrameworkLocalText("2 hours", comment: "Button text for 2 hour suspend duration"), action: { self.viewModel.suspendDelivery(duration: .hours(2)) }), - .cancel() - ]) - } - - func suspendResumeTapped() { - switch self.viewModel.basalDeliveryState { - case .active, .tempBasal: - showSuspendOptions = true - case .suspended: - self.viewModel.resumeDelivery() - default: - break - } - } - - func manualBasalTapped() { - showManualTempBasalOptions = true - } - - func cancelManualBasal() { - cancelingTempBasal = true - viewModel.runTemporaryBasalProgram(unitsPerHour: 0, for: 0) { error in - cancelingTempBasal = false - if let error = error { - self.viewModel.activeAlert = .cancelManualBasalError(error) - } - } - } - - - private func errorText(_ error: Error) -> String { - if let error = error as? LocalizedError { - return [error.localizedDescription, error.recoverySuggestion].compactMap{$0}.joined(separator: ". ") - } else { - return error.localizedDescription - } - } - - private func alert(for alert: OmnipodSettingsViewAlert) -> SwiftUI.Alert { - switch alert { - case .suspendError(let error): - return SwiftUI.Alert( - title: Text("Failed to Suspend Insulin Delivery", comment: "Alert title for suspend error"), - message: Text(errorText(error)) - ) - - case .resumeError(let error): - return SwiftUI.Alert( - title: Text("Failed to Resume Insulin Delivery", comment: "Alert title for resume error"), - message: Text(errorText(error)) - ) - - case .syncTimeError(let error): - return SwiftUI.Alert( - title: Text("Failed to Set Pump Time", comment: "Alert title for time sync error"), - message: Text(errorText(error)) - ) - - case .cancelManualBasalError(let error): - return SwiftUI.Alert( - title: Text("Failed to Cancel Manual Basal", comment: "Alert title for failing to cancel manual basal error"), - message: Text(errorText(error)) - ) - - } - } - - func reservoirColor(for reservoirLevelHighlightState: ReservoirLevelHighlightState) -> Color { - switch reservoirLevelHighlightState { - case .normal: - return insulinTintColor - case .warning: - return guidanceColors.warning - case .critical: - return guidanceColors.critical - } - } - - var decimalFormatter: NumberFormatter = { - let formatter = NumberFormatter() - - formatter.numberStyle = .decimal - formatter.minimumFractionDigits = 0 - formatter.maximumFractionDigits = 2 - - return formatter - }() - - private func formatRSSI(rssi: Int?) -> String { - if let rssi = rssi, let rssiStr = decimalFormatter.decibleString(from: rssi) { - return rssiStr - } else { - return "" - } - } - -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/PairPodView.swift b/Dependencies/OmniKit/OmniKitUI/Views/PairPodView.swift deleted file mode 100644 index 9abb1e45d..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/PairPodView.swift +++ /dev/null @@ -1,109 +0,0 @@ -// -// PairPodView.swift -// OmniKit -// -// Created by Pete Schwamb on 2/5/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct PairPodView: View { - - @ObservedObject var viewModel: PairPodViewModel - - @State private var cancelModalIsPresented: Bool = false - - var body: some View { - GuidePage(content: { - VStack { - LeadingImage("PodBottom") - - HStack { - InstructionList(instructions: [ - LocalizedString("Fill a new pod with U-100 Insulin (leave clear Pod needle cap on). Listen for 2 beeps.", comment: "Label text for step 1 of pair pod instructions"), - LocalizedString("Keep the RileyLink about 6 inches from the pod during pairing.", comment: "Label text for step 2 of pair pod instructions") - ]) - .disabled(viewModel.state.instructionsDisabled) - } - .padding(.bottom, 8) - } - .accessibility(sortPriority: 1) - }) { - VStack { - if self.viewModel.state.showProgressDetail { - self.viewModel.error.map { - ErrorView($0, errorClass: $0.recoverable ? .normal : .critical) - .accessibility(sortPriority: 0) - } - - if self.viewModel.error == nil { - VStack { - ProgressIndicatorView(state: self.viewModel.state.progressState) - if self.viewModel.state.isFinished { - FrameworkLocalText("Paired", comment: "Label text indicating pairing finished.") - .bold() - .padding(.top) - } - } - .padding(.bottom, 8) - } - } - if self.viewModel.error != nil && self.viewModel.podIsActivated { - Button(action: { - self.viewModel.didRequestDeactivation?() - }) { - Text(LocalizedString("Deactivate Pod", comment: "Button text for deactivate pod button")) - .accessibility(identifier: "button_deactivate_pod") - .actionButtonStyle(.destructive) - } - .disabled(self.viewModel.state.isProcessing) - } - - if (self.viewModel.error == nil || self.viewModel.error?.recoverable == true) { - Button(action: { - self.viewModel.continueButtonTapped() - }) { - Text(self.viewModel.state.nextActionButtonDescription) - .accessibility(identifier: "button_next_action") - .accessibility(label: Text(self.viewModel.state.actionButtonAccessibilityLabel)) - .actionButtonStyle(.primary) - } - .disabled(self.viewModel.state.isProcessing) - .animation(nil) - .zIndex(1) - } - } - .transition(AnyTransition.opacity.combined(with: .move(edge: .bottom))) - .padding() - } - .animation(.default) - .alert(isPresented: $cancelModalIsPresented) { cancelPairingModal } - .navigationBarTitle(LocalizedString("Pair Pod", comment: "Pair Pod navigationBarTitle"), displayMode: .automatic) - .navigationBarBackButtonHidden(self.viewModel.backButtonHidden) - .navigationBarItems(trailing: self.viewModel.state.navBarVisible ? cancelButton : nil) - } - - var cancelButton: some View { - Button(LocalizedString("Cancel", comment: "Cancel button text in navigation bar on pair pod UI")) { - if viewModel.podIsActivated { - cancelModalIsPresented = true - } else { - viewModel.didCancelSetup?() - } - } - .accessibility(identifier: "button_cancel") - .disabled(self.viewModel.state.isProcessing) - } - - var cancelPairingModal: Alert { - return Alert( - title: FrameworkLocalText("Are you sure you want to cancel Pod setup?", comment: "Alert title for cancel pairing modal"), - message: FrameworkLocalText("If you cancel Pod setup, the current Pod will be deactivated and will be unusable.", comment: "Alert message body for confirm pod attachment"), - primaryButton: .destructive(FrameworkLocalText("Yes, Deactivate Pod", comment: "Button title for confirm deactivation option"), action: { viewModel.didRequestDeactivation?() }), - secondaryButton: .default(FrameworkLocalText("No, Continue With Pod", comment: "Continue pairing button title of in pairing cancel modal")) - ) - } - -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/PlayTestBeepsView.swift b/Dependencies/OmniKit/OmniKitUI/Views/PlayTestBeepsView.swift deleted file mode 100644 index bf8dac01d..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/PlayTestBeepsView.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// PlayTestBeepsView.swift -// OmniKit -// -// Created by Joe Moran on 9/1/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - - -struct PlayTestBeepsView: View { - @Environment(\.horizontalSizeClass) var horizontalSizeClass - @Environment(\.presentationMode) var presentationMode: Binding - - private var toRun: ((_ completion: @escaping (_ result: Error?) -> Void) -> Void)? - - @State private var alertIsPresented: Bool = false - @State private var displayString: String = "" - @State private var successMessage = LocalizedString("Play test beeps command sent successfully.\n\nIf you did not hear any beeps from your Pod, the piezo speaker in your Pod may be broken or disabled.", comment: "Success message for play test beeps") - @State private var error: Error? = nil - @State private var executing: Bool = false - @State private var showActivityView = false - - init(toRun: @escaping (_ completion: @escaping (_ result: Error?) -> Void) -> Void) { - self.toRun = toRun - } - - var body: some View { - VStack { - List { - Section { - Text(self.displayString).fixedSize(horizontal: false, vertical: true) - } - } - VStack { - Button(action: { - asyncAction() - }) { - Text(buttonText) - .actionButtonStyle(.primary) - } - .padding() - .disabled(executing) - } - .padding(self.horizontalSizeClass == .regular ? .bottom : []) - .background(Color(UIColor.secondarySystemGroupedBackground).shadow(radius: 5)) - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Play Test Beeps", comment: "navigation title for play test beeps")) - .navigationBarTitleDisplayMode(.inline) - .alert(isPresented: $alertIsPresented, content: { alert(error: error) }) - .onFirstAppear { - asyncAction() - } - } - - private func asyncAction () { - DispatchQueue.global(qos: .utility).async { - executing = true - self.displayString = "" - toRun?() { (error) in - if let error = error { - self.displayString = "" - self.error = error - self.alertIsPresented = true - } else { - self.displayString = successMessage - } - executing = false - } - } - } - - private var buttonText: String { - if executing { - return LocalizedString("Playing Test Beeps...", comment: "button title when executing play test beeps") - } else { - return LocalizedString("Play Test Beeps", comment: "button title to play test beeps") - } - } - - private func alert(error: Error?) -> SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Failed to play test beeps.", comment: "Alert title for error when playing test beeps")), - message: Text(error?.localizedDescription ?? "No Error") - ) - } -} - -struct PlayTestBeepsView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - PlayTestBeepsView() { completion in - completion(nil) - } - } - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/PodDetailsView.swift b/Dependencies/OmniKit/OmniKitUI/Views/PodDetailsView.swift deleted file mode 100644 index 5a5ed77aa..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/PodDetailsView.swift +++ /dev/null @@ -1,126 +0,0 @@ -// -// PodDetailsView.swift -// OmniKit -// -// Created by Pete Schwamb on 4/14/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI -import OmniKit - -public struct PodDetails { - var lotNumber: UInt32 - var sequenceNumber: UInt32 - var piVersion: String - var pmVersion: String - var totalDelivery: Double? - var lastStatus: Date? - var fault: FaultEventCode? - var activatedAt: Date? - var activeTime: TimeInterval? - var pdmRef: String? -} - -struct PodDetailsView: View { - @Environment(\.guidanceColors) var guidanceColors - - var podDetails: PodDetails - var title: String - - let statusAgeFormatter: DateComponentsFormatter = { - let formatter = DateComponentsFormatter() - - formatter.allowedUnits = [.day, .hour, .minute, .second] - formatter.maximumUnitCount = 1 - formatter.unitsStyle = .short - - return formatter - }() - - let activeTimeFormatter: DateComponentsFormatter = { - let formatter = DateComponentsFormatter() - - formatter.allowedUnits = [.day, .hour, .minute] - formatter.maximumUnitCount = 2 - formatter.unitsStyle = .full - - return formatter - }() - - let dateFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - dateFormatter.timeStyle = .short - dateFormatter.dateStyle = .medium - dateFormatter.doesRelativeDateFormatting = true - return dateFormatter - }() - - private func row(_ label: String, value: String) -> some View { - HStack { - Text(label) - Spacer() - Text(value) - .foregroundColor(.secondary) - } - } - - var totalDeliveryText: String { - if let delivery = podDetails.totalDelivery { - return String(format: LocalizedString("%g U", comment: "Format string for total delivery on pod details screen"), delivery) - } else { - return LocalizedString("NA", comment: "String shown on pod details for total delivery when not available.") - } - } - - func activeTimeText(_ duration: TimeInterval) -> String { - return activeTimeFormatter.string(from: duration) ?? LocalizedString("NA", comment: "String shown on pod details for active time when conversion fails.") - } - - var lastStatusText: String { - if let lastStatus = podDetails.lastStatus, let ageString = statusAgeFormatter.string(from: Date().timeIntervalSince(lastStatus)) { - return String(format: LocalizedString("%@ ago", comment: "Format string for last status date on pod details screen"), ageString) - } else { - return LocalizedString("NA", comment: "String shown on pod details for last status date when not available.") - } - } - - var body: some View { - List { - row(LocalizedString("Lot Number", comment: "description label for lot number pod details row"), value: String(describing: podDetails.lotNumber)) - row(LocalizedString("Sequence Number", comment: "description label for sequence number pod details row"), value: String(format: "%07d", podDetails.sequenceNumber)) - row(LocalizedString("PI Version", comment: "description label for pi version pod details row"), value: podDetails.piVersion) - row(LocalizedString("PM Version", comment: "description label for ble firmware version pod details row"), value: podDetails.pmVersion) - row(LocalizedString("Total Delivery", comment: "description label for total delivery pod details row"), value: totalDeliveryText) - if let activeTime = podDetails.activeTime, let activatedAt = podDetails.activatedAt { - row(LocalizedString("Pod Activated", comment: "description label for activated at time pod details row"), value: dateFormatter.string(from: activatedAt)) - row(LocalizedString("Active Time", comment: "description label for active time pod details row"), value: activeTimeText(activeTime)) - } else { - row(LocalizedString("Last Status", comment: "description label for last status date pod details row"), value: lastStatusText) - } - if let fault = podDetails.fault, let pdmRef = podDetails.pdmRef { - Section { - VStack(alignment: .leading) { - HStack { - Image(systemName: "exclamationmark.triangle.fill") - .foregroundColor(guidanceColors.critical) - Text(LocalizedString("Pod Fault Details", comment: "description label for pod fault details")) - .fontWeight(.semibold) - }.padding(.vertical, 4) - Text(String(format: LocalizedString("Internal Pod fault code %1$03d\n%2$@\nRef: %3$@\n", comment: "The format string for the pod fault info: (1: fault code) (2: fault description) (3: pdm ref string)"), fault.rawValue, fault.faultDescription, pdmRef)) - .fixedSize(horizontal: false, vertical: true) - .foregroundColor(.secondary) - } - } - } - } - .navigationBarTitle(Text(title), displayMode: .automatic) - } -} - -struct PodDetailsView_Previews: PreviewProvider { - static var previews: some View { - PodDetailsView(podDetails: PodDetails(lotNumber: 123456789, sequenceNumber: 1234567, piVersion: "2.1.0", pmVersion: "2.1.0", totalDelivery: 99, lastStatus: Date(), fault: FaultEventCode(rawValue: 064), activatedAt: Date().addingTimeInterval(.days(2)), pdmRef: "19-02448-09951-064"), title: "Device Details") - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/PodLifeHUDView.swift b/Dependencies/OmniKit/OmniKitUI/Views/PodLifeHUDView.swift deleted file mode 100644 index 85f360fa3..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/PodLifeHUDView.swift +++ /dev/null @@ -1,176 +0,0 @@ -// -// PodLifeHUDView.swift -// OmniKit -// -// Based on OmniKitUI/Views/PodLifeHUDView.swift -// Created by Pete Schwamb on 10/22/18. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKitUI -import MKRingProgressView - -public enum PodAlertState { - case none - case warning - case fault -} - -public class PodLifeHUDView: BaseHUDView, NibLoadable { - - override public var orderPriority: HUDViewOrderPriority { - return 12 - } - - @IBOutlet private weak var timeLabel: UILabel! { - didSet { - // Setting this color in code because the nib isn't being applied correctly - if #available(iOSApplicationExtension 13.0, *) { - timeLabel.textColor = .label - } - } - } - @IBOutlet private weak var progressRing: RingProgressView! - - @IBOutlet private weak var alertLabel: UILabel! { - didSet { - alertLabel.alpha = 0 - alertLabel.textColor = UIColor.white - alertLabel.layer.cornerRadius = 9 - alertLabel.clipsToBounds = true - } - } - @IBOutlet private weak var backgroundRing: UIImageView! { - didSet { - if #available(iOSApplicationExtension 13.0, iOS 13.0, *) { - backgroundRing.tintColor = .systemGray5 - } else { - backgroundRing.tintColor = UIColor(red: 198 / 255, green: 199 / 255, blue: 201 / 255, alpha: 1) - } - } - } - - private var startTime: Date? - private var lifetime: TimeInterval? - private var timer: Timer? - - public var alertState: PodAlertState = .none { - didSet { - updateAlertStateLabel() - } - } - - public class func instantiate() -> PodLifeHUDView { - return nib().instantiate(withOwner: nil, options: nil)[0] as! PodLifeHUDView - } - - public func setPodLifeCycle(startTime: Date, lifetime: TimeInterval) { - self.startTime = startTime - self.lifetime = lifetime - updateProgressCircle() - - if timer == nil { - self.timer = Timer.scheduledTimer(withTimeInterval: .seconds(10), repeats: true) { [weak self] _ in - self?.updateProgressCircle() - } - } - } - - override open func stateColorsDidUpdate() { - super.stateColorsDidUpdate() - updateProgressCircle() - updateAlertStateLabel() - } - - private var endColor: UIColor? { - didSet { - let primaryColor = endColor ?? UIColor(red: 198 / 255, green: 199 / 255, blue: 201 / 255, alpha: 1) - self.progressRing.endColor = primaryColor - self.progressRing.startColor = primaryColor - } - } - - private lazy var timeFormatter: DateComponentsFormatter = { - let formatter = DateComponentsFormatter() - - formatter.allowedUnits = [.hour, .minute] - formatter.maximumUnitCount = 1 - formatter.unitsStyle = .abbreviated - - return formatter - }() - - private func updateAlertStateLabel() { - var alertLabelAlpha: CGFloat = 1 - - if alertState == .fault { - timer = nil - } - - switch alertState { - case .fault: - alertLabel.text = "!" - alertLabel.backgroundColor = stateColors?.error - case .warning: - alertLabel.text = "!" - alertLabel.backgroundColor = stateColors?.warning - case .none: - alertLabelAlpha = 0 - } - alertLabel.alpha = alertLabelAlpha - UIView.animate(withDuration: 0.25, animations: { - self.alertLabel.alpha = alertLabelAlpha - }) - } - - private func updateProgressCircle() { - - if let startTime = startTime, let lifetime = lifetime { - let age = -startTime.timeIntervalSinceNow - let progress = Double(age / lifetime) - progressRing.progress = progress - - if progress < 0.75 { - self.endColor = stateColors?.normal - progressRing.shadowOpacity = 0 - } else if progress < 1.0 { - self.endColor = stateColors?.warning - progressRing.shadowOpacity = 0.5 - } else { - self.endColor = stateColors?.error - progressRing.shadowOpacity = 0.8 - } - - let remaining = (lifetime - age) - - // Update time label and caption - if alertState == .fault { - timeLabel.isHidden = true - caption.text = LocalizedString("Fault", comment: "Pod life HUD view label") - } else if remaining > .hours(24) { - timeLabel.isHidden = true - caption.text = LocalizedString("Pod Age", comment: "Label describing pod age view") - } else if remaining > 0 { - let remainingFlooredToHour = remaining > .hours(1) ? remaining - remaining.truncatingRemainder(dividingBy: .hours(1)) : remaining - if let timeString = timeFormatter.string(from: remainingFlooredToHour) { - timeLabel.isHidden = false - timeLabel.text = timeString - } - caption.text = LocalizedString("Remaining", comment: "Label describing time remaining view") - } else { - timeLabel.isHidden = true - caption.text = LocalizedString("Replace Pod", comment: "Label indicating pod replacement necessary") - } - } - } - - func pauseUpdates() { - timer?.invalidate() - timer = nil - } - - override public func awakeFromNib() { - super.awakeFromNib() - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/PodSetupView.swift b/Dependencies/OmniKit/OmniKitUI/Views/PodSetupView.swift deleted file mode 100644 index 88c03085e..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/PodSetupView.swift +++ /dev/null @@ -1,114 +0,0 @@ -// -// PodSetupView.swift -// OmniKit -// -// Created by Pete Schwamb on 5/17/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct PodSetupView: View { - @Environment(\.dismissAction) private var dismiss - - private struct AlertIdentifier: Identifiable { - enum Choice { - case skipOnboarding - } - var id: Choice - } - @State private var alertIdentifier: AlertIdentifier? - - let nextAction: () -> Void - let allowDebugFeatures: Bool - let skipOnboarding: () -> Void - - var body: some View { - VStack(alignment: .leading) { - close - ScrollView { - content - } - Spacer() - continueButton - .padding(.bottom) - } - .padding(.horizontal) - .navigationBarHidden(true) - .alert(item: $alertIdentifier) { alert in - switch alert.id { - case .skipOnboarding: - return skipOnboardingAlert - } - } - } - - @ViewBuilder - private var close: some View { - HStack { - Spacer() - cancelButton - } - .padding(.top) - } - - @ViewBuilder - private var content: some View { - VStack(alignment: .leading, spacing: 2) { - title - .padding(.top, 5) - .onLongPressGesture(minimumDuration: 2) { - didLongPressOnTitle() - } - Divider() - bodyText - .foregroundColor(.secondary) - .padding(.top) - } - } - - @ViewBuilder - private var title: some View { - Text(LocalizedString("Pod Setup", comment: "Title for PodSetupView")) - .font(.largeTitle) - .bold() - .padding(.vertical) - } - - @ViewBuilder - private var bodyText: some View { - Text(LocalizedString("You will now begin the process of configuring your reminders, filling your Pod with insulin, pairing to your device and placing it on your body.", comment: "bodyText for PodSetupView")) - } - - private var cancelButton: some View { - Button(LocalizedString("Cancel", comment: "Cancel button title"), action: { - self.dismiss() - }) - } - - private var continueButton: some View { - Button(LocalizedString("Continue", comment: "Text for continue button on PodSetupView"), action: nextAction) - .buttonStyle(ActionButtonStyle()) - } - - private var skipOnboardingAlert: Alert { - Alert(title: Text("Skip Omnipod Onboarding?"), - message: Text("Are you sure you want to skip Omnipod Onboarding?"), - primaryButton: .cancel(), - secondaryButton: .destructive(Text("Yes"), action: skipOnboarding)) - } - - private func didLongPressOnTitle() { - if allowDebugFeatures { - alertIdentifier = AlertIdentifier(id: .skipOnboarding) - } - } - -} - -struct PodSetupView_Previews: PreviewProvider { - static var previews: some View { - PodSetupView(nextAction: {}, allowDebugFeatures: true, skipOnboarding: {}) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/PumpManagerDetailsView.swift b/Dependencies/OmniKit/OmniKitUI/Views/PumpManagerDetailsView.swift deleted file mode 100644 index 805bbd876..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/PumpManagerDetailsView.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// PumpManagerDetailsView.swift -// OmniKit -// -// Created by Joe Moran on 9/26/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit - - -struct PumpManagerDetailsView: View { - @Environment(\.horizontalSizeClass) var horizontalSizeClass - @Environment(\.presentationMode) var presentationMode: Binding - - private var toRun: ((_ completion: @escaping (_ result: String) -> Void) -> Void)? - - @State private var displayString: String = "" - @State private var error: Error? = nil - @State private var executing: Bool = false - @State private var showActivityView: Bool = false - - init(toRun: @escaping (_ completion: @escaping (_ result: String) -> Void) -> Void) { - self.toRun = toRun - } - - var body: some View { - VStack { - List { - Section { - let myFont = Font - .system(size: 12) - .monospaced() - Text(self.displayString) - .font(myFont) - } - } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(action: { - self.showActivityView = true - }) { - Image(systemName: "square.and.arrow.up") - } - } - }.sheet(isPresented: $showActivityView) { - ActivityView(isPresented: $showActivityView, activityItems: [self.displayString]) - } - VStack { - Button(action: { - asyncAction() - }) { - Text(buttonText) - .actionButtonStyle(.primary) - } - .padding() - .disabled(executing) - } - .padding(self.horizontalSizeClass == .regular ? .bottom : []) - .background(Color(UIColor.secondarySystemGroupedBackground).shadow(radius: 5)) - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Pump Manager Details", comment: "navigation title for pump manager details")) - .navigationBarTitleDisplayMode(.inline) - .onFirstAppear { - asyncAction() - } - } - - private func asyncAction () { - DispatchQueue.global(qos: .utility).async { - executing = true - self.displayString = "" - toRun?() { (result) in - self.displayString = result - executing = false - } - } - } - - private var buttonText: String { - if executing { - return LocalizedString("Retrieving Pump Manager Details...", comment: "button title when retrieving pump manager details") - } else { - return LocalizedString("Refresh Pump Manager Details", comment: "button title to refresh pump manager details") - } - } -} - -struct PumpManagerDetailsView_Previews: PreviewProvider { - static var previews: some View { - let examplePumpManagerDetails: String = "## OmnipodPumpManager\n\n## RileyLinkPumpManager\nlastTimerTick: 2023-10-07 22:35:39 +0000\n\n## RileyLinkDeviceManager\n\ncentral: \n\nautoConnectIDs: [\"F0178BCA-967D-504A-8C3A-99E84964B459\"]\n\ntimerTickEnabled: true\n\nidleListeningState: disabled\n\n## RileyLinkDevice\n* name: JPM OrangePro\n* lastIdle: 0001-01-01 00:00:00 +0000\n* isIdleListeningPending: false\n* isTimerTickEnabled: true\n* isTimerTickNotifying: true\n* radioFirmware: Optional(subg_rfspy 2.2)\n* bleFirmware: Optional(ble_rfspy 2.0)\n* peripheralManager: \n* sessionQueue.operationCount: 2\n\npodComms: ## PodComms\nconfiguredDevices: [\"F0178BCA-967D-504A-8C3A-99E84964B459\"]\ndelegate: true\n\nstatusObservers.count: 2\nstatus: ## PumpManagerStatus\n* timeZone: GMT-0700 (fixed)\n* device: <, name:Omnipod, manufacturer:Insulet, model:Eros, firmware:2.10.0, software:1.0, localIdentifier:1F05DD9A>\n* pumpBatteryChargeRemaining: nil\n* basalDeliveryState: Optional(LoopKit.PumpManagerStatus.BasalDeliveryState.active(2023-10-07 22:33:48 +0000))\n* bolusState: noBolus\n* insulinType: Optional(LoopKit.InsulinType.humalog)\n* deliveryIsUncertain: false\n\npodStateObservers.count: 1\nstate: ## OmnipodPumpManagerState\n* isOnboarded: true\n* timeZone: GMT-0700 (fixed)\n* basalSchedule: BasalSchedule(entries: [OmniKit.BasalScheduleEntry(rate: 0.9, startTime: 0.0)])\n* maximumTempBasalRate: 2.0\n* scheduledExpirationReminderOffset: Optional(\"24h0m\")\n* defaultExpirationReminderOffset: 24h0m\n* lowReservoirReminderValue: 50.0\n* podAttachmentConfirmed: true\n* activeAlerts: []\n* alertsWithPendingAcknowledgment: []\n* acknowledgedTimeOffsetAlert: false\n* initialConfigurationCompleted: true\n* unstoredDoses: []\n* suspendEngageState: stable\n* bolusEngageState: stable\n* tempBasalEngageState: stable\n* lastPumpDataReportDate: Optional(2023-10-07 22:35:24 +0000)\n* isPumpDataStale: false\n* silencePod: false\n* confirmationBeeps: manualCommands\n* pairingAttemptAddress: nil\n* insulinType: Optional(LoopKit.InsulinType.humalog)\n* scheduledExpirationReminderOffset: Optional(\"24h0m\")\n* defaultExpirationReminderOffset: 24h0m\n* rileyLinkBatteryAlertLevel: nil\n* lastRileyLinkBatteryAlertDate 0001-01-01 00:00:00 +0000\n* RileyLinkConnectionManagerState: RileyLinkConnectionState(autoConnectIDs: Set([\"F0178BCA-967D-504A-8C3A-99E84964B459\"]))\n* PodState: ### PodState\n* address: 1F05DD9A\n* activatedAt: Optional(2023-10-07 22:31:21 +0000)\n* expiresAt: Optional(2023-10-10 22:30:51 +0000)\n* timeActive: 4m\n* timeActiveUpdated: Optional(2023-10-07 22:35:38 +0000)\n* setupUnitsDelivered: Optional(2.65)\n* piVersion: 2.10.0\n* pmVersion: 2.10.0\n* lot: 72353\n* tid: 3280440\n* suspendState: resumed(2023-10-07 22:33:48 +0000)\n* unacknowledgedCommand: nil\n* unfinalizedBolus: nil\n* unfinalizedTempBasal: nil\n* unfinalizedSuspend: nil\n* unfinalizedResume: Optional(Resume: 10/7/23, 3:33:48 PM Certain)\n* finalizedDoses: []\n* activeAlertsSlots: No alerts\n* messageTransportState: MessageTransportState(packetNumber: 2, messageNumber: 8)\n* setupProgress: completed\n* primeFinishTime: Optional(2023-10-07 22:33:16 +0000)\n* configuredAlerts: [OmniKit.AlertSlot.slot4LowReservoir: Low reservoir, OmniKit.AlertSlot.slot3ExpirationReminder: Expiration reminder, OmniKit.AlertSlot.slot2ShutdownImminent: Shutdown imminent, OmniKit.AlertSlot.slot7Expired: Pod expired]\n* insulinType: humalog\n* PdmRef: nil\n* Fault: nil\n\n* PreviousPodState: nil\n" - NavigationView { - PumpManagerDetailsView() { completion in - completion(examplePumpManagerDetails) - } - } - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/ReadPodStatusView.swift b/Dependencies/OmniKit/OmniKitUI/Views/ReadPodStatusView.swift deleted file mode 100644 index cd4226e7c..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/ReadPodStatusView.swift +++ /dev/null @@ -1,168 +0,0 @@ -// -// ReadPodStatusView.swift -// OmniKit -// -// Created by Joe Moran on 8/15/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import OmniKit - -private func podStatusString(status: DetailedStatus) -> String { - var result, str: String - - let formatter = DateComponentsFormatter() - formatter.unitsStyle = .full - formatter.allowedUnits = [.hour, .minute] - formatter.unitsStyle = .short - if let timeStr = formatter.string(from: status.timeActive) { - str = timeStr - } else { - str = String(format: LocalizedString("%1$@ minutes", comment: "The format string for minutes (1: number of minutes string)"), String(describing: Int(status.timeActive / 60))) - } - result = String(format: LocalizedString("Pod Active: %1$@", comment: "The format string for Pod Active: (1: formatted time)"), str) - - result += String(format: LocalizedString("\nPod Progress: %1$@", comment: "The format string for Pod Progress: (1: pod progress string)"), String(describing: status.podProgressStatus)) - - result += String(format: LocalizedString("\nDelivery Status: %1$@", comment: "The format string for Delivery Status: (1: delivery status string)"), String(describing: status.deliveryStatus)) - - result += String(format: LocalizedString("\nLast Programming Seq Num: %1$@", comment: "The format string for last programming sequence number: (1: last programming sequence number)"), String(describing: status.lastProgrammingMessageSeqNum)) - - result += String(format: LocalizedString("\nBolus Not Delivered: %1$@ U", comment: "The format string for Bolus Not Delivered: (1: bolus not delivered string)"), status.bolusNotDelivered.twoDecimals) - - result += String(format: LocalizedString("\nPulse Count: %1$d", comment: "The format string for Pulse Count (1: pulse count)"), Int(round(status.totalInsulinDelivered / Pod.pulseSize))) - - result += String(format: LocalizedString("\nReservoir Level: %1$@ U", comment: "The format string for Reservoir Level: (1: reservoir level string)"), status.reservoirLevel == Pod.reservoirLevelAboveThresholdMagicNumber ? "50+" : status.reservoirLevel.twoDecimals) - - result += String(format: LocalizedString("\nAlerts: %1$@", comment: "The format string for Alerts: (1: the alerts string)"), alertSetString(alertSet: status.unacknowledgedAlerts)) - - if status.radioRSSI != 0 { - result += String(format: LocalizedString("\nRSSI: %1$@", comment: "The format string for RSSI: (1: RSSI value)"), String(describing: status.radioRSSI)) - result += String(format: LocalizedString("\nReceiver Low Gain: %1$@", comment: "The format string for receiverLowGain: (1: receiverLowGain)"), String(describing: status.receiverLowGain)) - } - - if status.faultEventCode.faultType != .noFaults { - // report the additional fault related information in a separate section - result += String(format: LocalizedString("\n\n⚠️ Critical Pod Fault %1$03d (0x%2$02X)", comment: "The format string for fault code in decimal and hex: (1: fault code for decimal display) (2: fault code for hex display)"), status.faultEventCode.rawValue, status.faultEventCode.rawValue) - result += String(format: "\n%1$@", status.faultEventCode.faultDescription) - if let faultEventTimeSinceActivation = status.faultEventTimeSinceActivation, - let faultTimeStr = formatter.string(from: faultEventTimeSinceActivation) - { - result += String(format: LocalizedString("\nFault Time: %1$@", comment: "The format string for fault time: (1: fault time string)"), faultTimeStr) - } - if let errorEventInfo = status.errorEventInfo { - result += String(format: LocalizedString("\nFault Event Info: %1$03d (0x%2$02X),", comment: "The format string for fault event info: (1: fault event info)"), errorEventInfo.rawValue, errorEventInfo.rawValue) - result += String(format: LocalizedString("\n Insulin State Table Corrupted: %@", comment: "The format string for insulin state table corrupted: (1: insulin state corrupted)"), String(describing: errorEventInfo.insulinStateTableCorruption)) - result += String(format: LocalizedString("\n Occlusion Type: %1$@", comment: "The format string for occlusion type: (1: occlusion type)"), String(describing: errorEventInfo.occlusionType)) - result += String(format: LocalizedString("\n Immediate Bolus In Progress: %1$@", comment: "The format string for immediate bolus in progress: (1: immediate bolus in progress)"), String(describing: errorEventInfo.immediateBolusInProgress)) - result += String(format: LocalizedString("\n Previous Pod Progress: %1$@", comment: "The format string for previous pod progress: (1: previous pod progress string)"), String(describing: errorEventInfo.podProgressStatus)) - } - if let pdmRef = status.pdmRef { - result += String(format: LocalizedString("\nRef: %@", comment: "The Ref format string (1: pdm ref string)"), pdmRef) - } - } - - return result -} - -struct ReadPodStatusView: View { - @Environment(\.horizontalSizeClass) var horizontalSizeClass - @Environment(\.presentationMode) var presentationMode: Binding - - private var toRun: ((_ completion: @escaping (_ result: PumpManagerResult) -> Void) -> Void)? - - @State private var alertIsPresented: Bool = false - @State private var displayString: String = "" - @State private var error: LocalizedError? = nil - @State private var executing: Bool = false - @State private var showActivityView: Bool = false - - init(toRun: @escaping (_ completion: @escaping (_ result: PumpManagerResult) -> Void) -> Void) { - self.toRun = toRun - } - - var body: some View { - VStack { - List { - Section { - Text(self.displayString).fixedSize(horizontal: false, vertical: true) - } - } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(action: { - self.showActivityView = true - }) { - Image(systemName: "square.and.arrow.up") - } - } - }.sheet(isPresented: $showActivityView) { - ActivityView(isPresented: $showActivityView, activityItems: [self.displayString]) - } - VStack { - Button(action: { - asyncAction() - }) { - Text(buttonText) - .actionButtonStyle(.primary) - } - .padding() - .disabled(executing) - } - .padding(self.horizontalSizeClass == .regular ? .bottom : []) - .background(Color(UIColor.secondarySystemGroupedBackground).shadow(radius: 5)) - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Read Pod Status", comment: "navigation title for read pod status")) - .navigationBarTitleDisplayMode(.inline) - .alert(isPresented: $alertIsPresented, content: { alert(error: error) }) - .onFirstAppear { - asyncAction() - } - } - - private func asyncAction () { - DispatchQueue.global(qos: .utility).async { - executing = true - self.displayString = "" - toRun?() { (result) in - switch result { - case .success(let detailedStatus): - self.displayString = podStatusString(status: detailedStatus) - case .failure(let error): - self.error = error - self.alertIsPresented = true - } - executing = false - } - } - } - - private var buttonText: String { - if executing { - return LocalizedString("Reading Pod Status...", comment: "button title when executing read pod status") - } else { - return LocalizedString("Read Pod Status", comment: "button title to read pod status") - } - } - - private func alert(error: Error?) -> SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Failed to read pod status.", comment: "Alert title for error when reading pod status")), - message: Text(error?.localizedDescription ?? "No Error") - ) - } -} - -struct ReadPodStatusView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - let detailedStatus = try! DetailedStatus(encodedData: Data([0x02, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xc3, 0x6a, 0x02, 0x07, 0x03, 0xff, 0x02, 0x09, 0x20, 0x00, 0x28, 0x99, 0x08, 0x00, 0x82])) - ReadPodStatusView() { completion in - completion(.success(detailedStatus)) - } - } - } - } diff --git a/Dependencies/OmniKit/OmniKitUI/Views/ReadPulseLogView.swift b/Dependencies/OmniKit/OmniKitUI/Views/ReadPulseLogView.swift deleted file mode 100644 index acaa00d56..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/ReadPulseLogView.swift +++ /dev/null @@ -1,128 +0,0 @@ -// -// ReadPulseLogView.swift -// OmniKit -// -// Created by Joe Moran on 9/1/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import OmniKit - -struct ReadPulseLogView: View { - @Environment(\.horizontalSizeClass) var horizontalSizeClass - @Environment(\.presentationMode) var presentationMode: Binding - - private var toRun: ((_ completion: @escaping (_ result: Result) -> Void) -> Void)? - - @State private var alertIsPresented: Bool = false - @State private var displayString: String = "" - @State private var error: Error? = nil - @State private var executing: Bool = false - @State private var showActivityView: Bool = false - - init(toRun: @escaping (_ completion: @escaping (_ result: Result) -> Void) -> Void) { - self.toRun = toRun - } - - var body: some View { - VStack { - List { - Section { - let myFont = Font - .system(size: 12) - .monospaced() - Text(self.displayString) - .font(myFont) - } - } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(action: { - self.showActivityView = true - }) { - Image(systemName: "square.and.arrow.up") - } - } - }.sheet(isPresented: $showActivityView) { - ActivityView(isPresented: $showActivityView, activityItems: [self.displayString]) - } - VStack { - Button(action: { - asyncAction() - }) { - Text(buttonText) - .actionButtonStyle(.primary) - } - .padding() - .disabled(executing) - } - .padding(self.horizontalSizeClass == .regular ? .bottom : []) - .background(Color(UIColor.secondarySystemGroupedBackground).shadow(radius: 5)) - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Read Pulse Log", comment: "navigation title for read pulse log")) - .navigationBarTitleDisplayMode(.inline) - .alert(isPresented: $alertIsPresented, content: { alert(error: error) }) - .onFirstAppear { - asyncAction() - } - } - - private func asyncAction () { - DispatchQueue.global(qos: .utility).async { - executing = true - self.displayString = "" - toRun?() { (result) in - switch result { - case .success(let pulseLogString): - self.displayString = pulseLogString - case .failure(let error): - self.displayString = "" - self.error = error - self.alertIsPresented = true - } - executing = false - } - } - } - - private var buttonText: String { - if executing { - return LocalizedString("Reading Pulse Log...", comment: "button title when executing read pulse log") - } else { - return LocalizedString("Read Pulse Log", comment: "button title to read pulse log") - } - } - - private func alert(error: Error?) -> SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Failed to read pulse log.", comment: "Alert title for error when reading pulse log")), - message: Text(error?.localizedDescription ?? "No Error") - ) - } -} - -struct ReadPulsePodLogView_Previews: PreviewProvider { - static var previews: some View { - ReadPulseLogView() { completion in - let podInfoPulseLogRecent = try! PodInfoPulseLogRecent(encodedData: Data([0x50, 0x03, 0x17, - 0x39, 0x72, 0x58, 0x01, 0x3c, 0x72, 0x43, 0x01, 0x41, 0x72, 0x5a, 0x01, 0x44, 0x71, 0x47, 0x01, - 0x49, 0x51, 0x59, 0x01, 0x4c, 0x51, 0x44, 0x01, 0x51, 0x73, 0x59, 0x01, 0x54, 0x50, 0x43, 0x01, - 0x59, 0x50, 0x5a, 0x81, 0x5c, 0x51, 0x42, 0x81, 0x61, 0x73, 0x59, 0x81, 0x00, 0x75, 0x43, 0x80, - 0x05, 0x70, 0x5a, 0x80, 0x08, 0x50, 0x44, 0x80, 0x0d, 0x50, 0x5b, 0x80, 0x10, 0x75, 0x43, 0x80, - 0x15, 0x72, 0x5e, 0x80, 0x18, 0x73, 0x45, 0x80, 0x1d, 0x72, 0x5b, 0x00, 0x20, 0x70, 0x43, 0x00, - 0x25, 0x50, 0x5c, 0x00, 0x28, 0x50, 0x46, 0x00, 0x2d, 0x50, 0x5a, 0x00, 0x30, 0x75, 0x47, 0x00, - 0x35, 0x72, 0x59, 0x00, 0x38, 0x70, 0x46, 0x00, 0x3d, 0x75, 0x57, 0x00, 0x40, 0x72, 0x43, 0x00, - 0x45, 0x73, 0x55, 0x00, 0x48, 0x73, 0x41, 0x00, 0x4d, 0x70, 0x52, 0x00, 0x50, 0x73, 0x3f, 0x00, - 0x55, 0x74, 0x4d, 0x00, 0x58, 0x72, 0x3d, 0x80, 0x5d, 0x73, 0x4d, 0x80, 0x60, 0x71, 0x3d, 0x80, - 0x01, 0x51, 0x50, 0x80, 0x04, 0x72, 0x3d, 0x80, 0x09, 0x50, 0x4e, 0x80, 0x0c, 0x51, 0x40, 0x80, - 0x11, 0x74, 0x50, 0x80, 0x14, 0x71, 0x40, 0x80, 0x19, 0x50, 0x4d, 0x80, 0x1c, 0x75, 0x3f, 0x00, - 0x21, 0x72, 0x52, 0x00, 0x24, 0x72, 0x40, 0x00, 0x29, 0x71, 0x53, 0x00, 0x2c, 0x50, 0x42, 0x00, - 0x31, 0x51, 0x55, 0x00, 0x34, 0x50, 0x42, 0x00 ])) - let lastPulseNumber = Int(podInfoPulseLogRecent.indexLastEntry) - completion(.success(pulseLogString(pulseLogEntries: podInfoPulseLogRecent.pulseLog, lastPulseNumber: lastPulseNumber))) - } - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/RileyLinkSetupView.swift b/Dependencies/OmniKit/OmniKitUI/Views/RileyLinkSetupView.swift deleted file mode 100644 index 211f3078f..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/RileyLinkSetupView.swift +++ /dev/null @@ -1,109 +0,0 @@ -// -// RileyLinkSelectionView.swift -// OmniKitUI -// -// Created by Pete Schwamb on 6/7/22. -// Copyright © 2022 Pete Schwamb. All rights reserved. -// - -import SwiftUI -import LoopKitUI -import RileyLinkKitUI - -struct RileyLinkSetupView: View { - public var cancelButtonTapped: (() -> Void)? - - @Environment(\.dismissAction) private var dismiss - - let nextAction: () -> Void - - @ObservedObject private var dataSource: RileyLinkListDataSource - - init(dataSource: RileyLinkListDataSource, nextAction: @escaping () -> Void) { - self.dataSource = dataSource - self.nextAction = nextAction - } - - @State private var isOn: Bool = false - - - var body: some View { - VStack { - List { - VStack { - Image("RileyLink", bundle: Bundle(for: RileyLinkCell.self)) - .resizable() - .foregroundColor(Color(imageTint)) - .aspectRatio(contentMode: ContentMode.fit) - bodyText - .foregroundColor(.secondary) - } - Section(header: HStack { - FrameworkLocalText("Devices", comment: "Header for devices section of RileyLinkSetupView") - Spacer() - ProgressView() - }) { - ForEach(dataSource.devices, id: \.peripheralIdentifier) { device in - Toggle(isOn: dataSource.autoconnectBinding(for: device)) { - HStack { - Text(device.name ?? "Unknown") - Spacer() - Text(formatRSSI(rssi:device.rssi)).foregroundColor(.secondary) - } - } - } - } - } - Spacer() - continueButton - .padding([.bottom, .horizontal]) - - } - .navigationTitle(LocalizedString("RileyLink Setup", comment: "Navigation title for RileyLinkSetupView")) - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(LocalizedString("Cancel", comment: "Cancel button title"), action: { - cancelButtonTapped?() - }) - } - } - .navigationBarHidden(false) - .onAppear { dataSource.isScanningEnabled = true } - .onDisappear { dataSource.isScanningEnabled = false } - } - - var decimalFormatter: NumberFormatter = { - let formatter = NumberFormatter() - - formatter.numberStyle = .decimal - formatter.minimumFractionDigits = 0 - formatter.maximumFractionDigits = 2 - - return formatter - }() - - private func formatRSSI(rssi: Int?) -> String { - if let rssi = rssi, let rssiStr = decimalFormatter.decibleString(from: rssi) { - return rssiStr - } else { - return "" - } - } - - var imageTint: UIColor { - return UIColor(named: "RileyLink Tint", in: Bundle(for: RileyLinkCell.self), compatibleWith: nil) ?? .gray - } - - @ViewBuilder - private var bodyText: some View { - Text(LocalizedString("RileyLink allows for communication with the pump over Bluetooth", comment: "bodyText for RileyLinkSetupView")) - } - - private var continueButton: some View { - Button(LocalizedString("Continue", comment: "Text for continue button on PodSetupView"), action: nextAction) - .buttonStyle(ActionButtonStyle()) - .disabled(!dataSource.connecting) - - } - -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/ScheduledExpirationReminderEditView.swift b/Dependencies/OmniKit/OmniKitUI/Views/ScheduledExpirationReminderEditView.swift deleted file mode 100644 index f39a2acb1..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/ScheduledExpirationReminderEditView.swift +++ /dev/null @@ -1,169 +0,0 @@ -// -// ScheduledExpirationReminderEditView.swift -// OmniKit -// -// Created by Pete Schwamb on 2/17/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -extension Date: Identifiable { - public var id: Self { self } -} - -struct ScheduledExpirationReminderEditView: View { - - @Environment(\.horizontalSizeClass) var horizontalSizeClass - - var allowedDates: [Date] - var dateFormatter: DateFormatter - var onSave: ((_ selectedDate: Date?, _ completion: @escaping (_ error: Error?) -> Void) -> Void)? - var onFinish: (() -> Void)? - - private var initialValue: Date? - @State private var alertIsPresented: Bool = false - @State private var error: Error? - @State private var saving: Bool = false - @State private var selectedDate: Date? - - init(scheduledExpirationReminderDate: Date?, allowedDates: [Date], dateFormatter: DateFormatter, onSave: ((_ selectedDate: Date?, _ completion: @escaping (_ error: Error?) -> Void) -> Void)? = nil, onFinish: (() -> Void)? = nil) - { - self.allowedDates = allowedDates - self.dateFormatter = dateFormatter - self.onSave = onSave - self.onFinish = onFinish - self.initialValue = scheduledExpirationReminderDate - self._selectedDate = State(initialValue: scheduledExpirationReminderDate) - } - - var body: some View { - contentWithCancel - } - - var content: some View { - VStack { - RoundedCardScrollView(title: LocalizedString("Scheduled Reminder", comment: "Title for scheduled expiration reminder edit page")) { - if self.horizontalSizeClass == .compact { - // Keep picker outside of card in compact view, because it forces full device width. - VStack(spacing: 0) { - RoundedCard { - Text(LocalizedString("Scheduled Reminder", comment: "Card title for scheduled reminder")) - Divider() - valueRow - } - picker - .background(Color(.secondarySystemGroupedBackground)) - } - - } else { - RoundedCard { - Text(LocalizedString("Scheduled Reminder", comment: "Card title for scheduled reminder")) - Divider() - valueRow - picker - } - } - } - Spacer() - Button(action: saveTapped) { - Text(saveButtonText) - .actionButtonStyle() - .padding() - } - .disabled(saving || !valueChanged) - } - .navigationBarTitle("", displayMode: .inline) - .alert(isPresented: $alertIsPresented, content: { alert(error: error) }) - } - - var valueRow: some View { - RoundedCardValueRow( - label: LocalizedString("Time", comment: "Label for scheduled expiration reminder row"), - value: scheduledReminderDateString(selectedDate), - highlightValue: true - ) - } - - var picker: some View { - Picker(selection: $selectedDate, label: Text("Numbers")) { - ForEach(self.allowedDates) { date in - Text(scheduledReminderDateString(date)).tag(date as Date?) - } - Text(scheduledReminderDateString(nil)).tag(nil as Date?) - } - .pickerStyle(WheelPickerStyle()) - } - - var saveButtonText: String { - if saving { - return LocalizedString("Saving...", comment: "button title for saving scheduled reminder while saving") - } else { - return LocalizedString("Save", comment: "button title for saving scheduled reminder") - } - } - - private func saveTapped() { - saving = true - self.onSave?(selectedDate) { (error) in - saving = false - if let error = error { - self.error = error - self.alertIsPresented = true - } else { - self.onFinish?() - } - } - } - - private func scheduledReminderDateString(_ scheduledDate: Date?) -> String { - if let scheduledDate = scheduledDate { - return dateFormatter.string(from: scheduledDate) - } else { - return LocalizedString("No Reminder", comment: "Value text for no expiration reminder") - } - } - - private var valueChanged: Bool { - return selectedDate != initialValue - } - - private var contentWithCancel: some View { - if saving { - return AnyView(content - .navigationBarBackButtonHidden(true) - ) - } else if valueChanged { - return AnyView(content - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: cancelButton) - ) - } else { - return AnyView(content) - } - } - - private var cancelButton: some View { - Button(action: { self.onFinish?() } ) { Text(LocalizedString("Cancel", comment: "Button title for cancelling scheduled reminder date edit")) } - } - - private func alert(error: Error?) -> SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Failed to Update Expiration Reminder", comment: "Alert title for error when updating expiration reminder")), - message: Text(error?.localizedDescription ?? "No Error") - ) - } -} - -struct ScheduledExpirationReminderEditView_Previews: PreviewProvider { - static var previews: some View { - ScheduledExpirationReminderEditView( - scheduledExpirationReminderDate: Date(), - allowedDates: [Date()], - dateFormatter: DateFormatter(), - onSave: { (_, _) in }, - onFinish: { } - ) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/SetupCompleteView.swift b/Dependencies/OmniKit/OmniKitUI/Views/SetupCompleteView.swift deleted file mode 100644 index 6ad9e7f22..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/SetupCompleteView.swift +++ /dev/null @@ -1,113 +0,0 @@ -// -// SetupCompleteView.swift -// OmniKit -// -// Created by Pete Schwamb on 3/2/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct SetupCompleteView: View { - - @Environment(\.verticalSizeClass) var verticalSizeClass - @Environment(\.appName) private var appName - - - private var onSaveScheduledExpirationReminder: ((_ selectedDate: Date?, _ completion: @escaping (_ error: Error?) -> Void) -> Void)? - private var didFinish: () -> Void - private var didRequestDeactivation: () -> Void - private var dateFormatter: DateFormatter - - @State private var scheduledReminderDate: Date? - - @State private var scheduleReminderDateEditViewIsShown: Bool = false - - var allowedDates: [Date] - - init(scheduledReminderDate: Date?, dateFormatter: DateFormatter, allowedDates: [Date], onSaveScheduledExpirationReminder: ((_ selectedDate: Date?, _ completion: @escaping (_ error: Error?) -> Void) -> Void)?, didFinish: @escaping () -> Void, didRequestDeactivation: @escaping () -> Void) - { - self._scheduledReminderDate = State(initialValue: scheduledReminderDate) - self.dateFormatter = dateFormatter - self.allowedDates = allowedDates - self.onSaveScheduledExpirationReminder = onSaveScheduledExpirationReminder - self.didFinish = didFinish - self.didRequestDeactivation = didRequestDeactivation - } - - var body: some View { - GuidePage(content: { - VStack { - LeadingImage("Pod") - Text(String(format: LocalizedString("Your Pod is ready for use.\n\n%1$@ will remind you to change your pod before it expires. You can change this to a time convenient for you.", comment: "Format string for instructions for setup complete view. (1: app name)"), appName)) - .fixedSize(horizontal: false, vertical: true) - Divider() - VStack(alignment: .leading) { - Text(LocalizedString("Scheduled Reminder", comment: "Scheduled reminder card title on SetupCompleteView")) - Divider() - NavigationLink( - destination: ScheduledExpirationReminderEditView( - scheduledExpirationReminderDate: scheduledReminderDate, - allowedDates: allowedDates, - dateFormatter: dateFormatter, - onSave: { (newDate, completion) in - onSaveScheduledExpirationReminder?(newDate) { (error) in - if error == nil { - scheduledReminderDate = newDate - } - completion(error) - } - }, - onFinish: { scheduleReminderDateEditViewIsShown = false }), - isActive: $scheduleReminderDateEditViewIsShown) - { - RoundedCardValueRow( - label: LocalizedString("Time", comment: "Label for expiration reminder row"), - value: scheduledReminderDateString(scheduledReminderDate), - highlightValue: false - ) - } - } - } - .padding(.bottom, 8) - .accessibility(sortPriority: 1) - }) { - Button(action: { - didFinish() - }) { - Text(LocalizedString("Finish Setup", comment: "Action button title to continue at Setup Complete")) - .actionButtonStyle(.primary) - } - .padding() - .background(Color(UIColor.systemBackground)) - .zIndex(1) - } - .animation(.default) - .navigationBarTitle(LocalizedString("Setup Complete", comment: "Title of SetupCompleteView"), displayMode: .automatic) - } - - private func scheduledReminderDateString(_ scheduledDate: Date?) -> String { - if let scheduledDate = scheduledDate { - return dateFormatter.string(from: scheduledDate) - } else { - return LocalizedString("No Reminder", comment: "Value text for no expiration reminder") - } - } -} - -struct SetupCompleteView_Previews: PreviewProvider { - static var previews: some View { - SetupCompleteView( - scheduledReminderDate: Date(), - dateFormatter: DateFormatter(), - allowedDates: [Date()], - onSaveScheduledExpirationReminder: { (date, completion) in - }, - didFinish: { - }, - didRequestDeactivation: { - } - ) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/SilencePodSelectionView.swift b/Dependencies/OmniKit/OmniKitUI/Views/SilencePodSelectionView.swift deleted file mode 100644 index 107316eb2..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/SilencePodSelectionView.swift +++ /dev/null @@ -1,144 +0,0 @@ -// -// SilencePodSelectionView.swift -// OmniKit -// -// Created by Joe Moran 8/30/23. -// Copyright © 2023 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import OmniKit - -struct SilencePodSelectionView: View { - - @Environment(\.horizontalSizeClass) var horizontalSizeClass - @Environment(\.presentationMode) var presentationMode: Binding - - private var initialValue: SilencePodPreference - @State private var preference: SilencePodPreference - private var onSave: ((_ selectedValue: SilencePodPreference, _ completion: @escaping (_ error: LocalizedError?) -> Void) -> Void)? - - @State private var alertIsPresented: Bool = false - @State private var error: LocalizedError? - @State private var saving: Bool = false - - - init(initialValue: SilencePodPreference, onSave: @escaping (_ selectedValue: SilencePodPreference, _ completion: @escaping (_ error: LocalizedError?) -> Void) -> Void) { - self.initialValue = initialValue - self._preference = State(initialValue: initialValue) - self.onSave = onSave - } - - var body: some View { - contentWithCancel - } - - var content: some View { - VStack { - List { - Section { - Text(LocalizedString("Silence Pod mode suppresses all Pod alert and confirmation reminder beeping.", comment: "Help text for Silence Pod view")).fixedSize(horizontal: false, vertical: true) - .padding(.vertical, 10) - } - Section { - ForEach(SilencePodPreference.allCases, id: \.self) { preference in - HStack { - CheckmarkListItem( - title: Text(preference.title), - description: Text(preference.description), - isSelected: Binding( - get: { self.preference == preference }, - set: { isSelected in - if isSelected { - self.preference = preference - } - } - ) - ) - } - .padding(.vertical, 10) - } - } - .buttonStyle(PlainButtonStyle()) // Disable row highlighting on selection - } - VStack { - Button(action: { - saving = true - onSave?(preference) { (error) in - saving = false - if let error = error { - self.error = error - self.alertIsPresented = true - } else { - self.presentationMode.wrappedValue.dismiss() - } - } - }) { - Text(saveButtonText) - .actionButtonStyle(.primary) - } - .padding() - .disabled(saving || !valueChanged) - } - .padding(self.horizontalSizeClass == .regular ? .bottom : []) - .background(Color(UIColor.secondarySystemGroupedBackground).shadow(radius: 5)) - } - .insetGroupedListStyle() - .navigationTitle(LocalizedString("Silence Pod", comment: "navigation title for Silnce Pod")) - .navigationBarTitleDisplayMode(.inline) - .alert(isPresented: $alertIsPresented, content: { alert(error: error) }) - } - - private var contentWithCancel: some View { - if saving { - return AnyView(content - .navigationBarBackButtonHidden(true) - ) - } else if valueChanged { - return AnyView(content - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: cancelButton) - ) - } else { - return AnyView(content) - } - } - - private var cancelButton: some View { - Button(action: { self.presentationMode.wrappedValue.dismiss() } ) { - Text(LocalizedString("Cancel", comment: "Button title for cancelling silence pod edit")) - } - } - - var saveButtonText: String { - if saving { - return LocalizedString("Saving...", comment: "button title for saving silence pod preference while saving") - } else { - return LocalizedString("Save", comment: "button title for saving silence pod preference") - } - } - - private var valueChanged: Bool { - return preference != initialValue - } - - private func alert(error: Error?) -> SwiftUI.Alert { - return SwiftUI.Alert( - title: Text(LocalizedString("Failed to update silence pod preference.", comment: "Alert title for error when updating silence pod preference")), - message: Text(error?.localizedDescription ?? "No Error") - ) - } -} - -struct SilencePodSelectionView_Previews: PreviewProvider { - static var previews: some View { - NavigationView { - SilencePodSelectionView(initialValue: .disabled) { selectedValue, completion in - print("Selected: \(selectedValue)") - completion(nil) - } - } - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/TimeView.swift b/Dependencies/OmniKit/OmniKitUI/Views/TimeView.swift deleted file mode 100644 index c643dccc4..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/TimeView.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// TimeView.swift -// OmniKit -// -// Created by Pete Schwamb on 5/10/21. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI - -struct TimeView: View { - - let timeZone: TimeZone - - private let shortTimeFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .none - formatter.timeStyle = .short - return formatter - }() - - @State var currentDate = Date() - let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() - - var timeZoneString: String { - shortTimeFormatter.timeZone = timeZone - return shortTimeFormatter.string(from: currentDate) - } - - var body: some View { - Text(timeZoneString).onReceive(timer) { input in - currentDate = input - } - } -} - -struct TimeView_Previews: PreviewProvider { - static var previews: some View { - TimeView(timeZone: .current) - } -} diff --git a/Dependencies/OmniKit/OmniKitUI/Views/UncertaintyRecoveredView.swift b/Dependencies/OmniKit/OmniKitUI/Views/UncertaintyRecoveredView.swift deleted file mode 100644 index 7a9e984d1..000000000 --- a/Dependencies/OmniKit/OmniKitUI/Views/UncertaintyRecoveredView.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// UncertaintyRecoveredView.swift -// OmniKit -// -// Created by Pete Schwamb on 8/25/20. -// Copyright © 2021 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKitUI - -struct UncertaintyRecoveredView: View { - var appName: String - - var didFinish: (() -> Void)? - - var body: some View { - GuidePage(content: { - Text(String(format: LocalizedString("%1$@ has recovered communication with the pod on your body.\n\nInsulin delivery records have been updated and should match what has actually been delivered.\n\nYou may continue to use %2$@ normally now.", comment: "Text body for page showing insulin uncertainty has been recovered (1: appName) (2: appName)"), self.appName, self.appName)) - .padding([.top, .bottom]) - }) { - VStack { - Button(action: { - self.didFinish?() - }) { - Text(LocalizedString("Continue", comment: "Button title to continue")) - .actionButtonStyle() - .padding() - } - } - } - .navigationBarTitle(Text("Comms Recovered"), displayMode: .large) - .navigationBarBackButtonHidden(true) - } -} - -struct UncertaintyRecoveredView_Previews: PreviewProvider { - static var previews: some View { - UncertaintyRecoveredView(appName: "Test App") - } -} diff --git a/Dependencies/OmniKit/README.md b/Dependencies/OmniKit/README.md deleted file mode 100644 index 99d5864a4..000000000 --- a/Dependencies/OmniKit/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# OmniKit -Omnipod Eros PumpManager For Loop - -## Status -Supported. Incorporated into Loop - -## For more information -Please join loop zulipchat at https://loop.zulipchat.com/ diff --git a/Dependencies/dexcom-share-client-swift/.gitignore b/Dependencies/dexcom-share-client-swift/.gitignore deleted file mode 100644 index 5c13bfd07..000000000 --- a/Dependencies/dexcom-share-client-swift/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -# OS X -.DS_Store - -# Xcode -build/ -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata -*.xccheckout -profile -*.moved-aside -DerivedData -*.hmap -*.ipa - -# Bundler -.bundle - -Carthage -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control -# -# Note: if you ignore the Pods directory, make sure to uncomment -# `pod install` in .travis.yml -# - -Pods/ -Carthage/ -.gitmodules diff --git a/Dependencies/dexcom-share-client-swift/.travis.yml b/Dependencies/dexcom-share-client-swift/.travis.yml deleted file mode 100644 index 5fd38094b..000000000 --- a/Dependencies/dexcom-share-client-swift/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: objective-c -osx_image: xcode12.2 - -before_script: - - ./Scripts/carthage.sh bootstrap - -script: - # Build Travis project and run tests - - xcodebuild -project ShareClient.xcodeproj -scheme Shared build -destination name="iPhone 8" test diff --git a/Dependencies/dexcom-share-client-swift/Common/LocalizedString.swift b/Dependencies/dexcom-share-client-swift/Common/LocalizedString.swift deleted file mode 100644 index b0e5401a4..000000000 --- a/Dependencies/dexcom-share-client-swift/Common/LocalizedString.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// LocalizedString.swift -// LoopKit -// -// Created by Retina15 on 8/6/18. -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation - -internal class FrameworkBundle { - static let main = Bundle(for: FrameworkBundle.self) -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: FrameworkBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: FrameworkBundle.main, comment: comment) - } -} diff --git a/Dependencies/dexcom-share-client-swift/LICENSE b/Dependencies/dexcom-share-client-swift/LICENSE deleted file mode 100644 index 0d98a1db8..000000000 --- a/Dependencies/dexcom-share-client-swift/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Mark Wilson - -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/Dependencies/dexcom-share-client-swift/ShareClient.xcodeproj/project.pbxproj b/Dependencies/dexcom-share-client-swift/ShareClient.xcodeproj/project.pbxproj deleted file mode 100644 index 75f90fad6..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient.xcodeproj/project.pbxproj +++ /dev/null @@ -1,999 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 4325E9CF210E6A0A00969CE5 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4325E9CE210E6A0A00969CE5 /* HKUnit.swift */; }; - 4325E9D1210E6A3D00969CE5 /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4325E9D0210E6A3D00969CE5 /* TimeInterval.swift */; }; - 4325E9D3210E6ADA00969CE5 /* IdentifiableClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4325E9D2210E6ADA00969CE5 /* IdentifiableClass.swift */; }; - 4325E9D5210E6B4400969CE5 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4325E9D4210E6B4300969CE5 /* UIColor.swift */; }; - 432B0E8C1CDFC3C50045347B /* ShareClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 432B0E8B1CDFC3C50045347B /* ShareClient.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43A8EC7C210E661400A81379 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43A8EC7B210E661400A81379 /* LoopKit.framework */; }; - 43A8EC86210E664300A81379 /* ShareClientUI.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A8EC84210E664300A81379 /* ShareClientUI.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43A8EC8A210E664C00A81379 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43A8EC7B210E661400A81379 /* LoopKit.framework */; }; - 43A8EC8C210E665700A81379 /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43A8EC8B210E665600A81379 /* LoopKitUI.framework */; }; - 43A8EC90210E676500A81379 /* ShareClientSetupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A8EC8D210E676500A81379 /* ShareClientSetupViewController.swift */; }; - 43A8EC91210E676500A81379 /* ShareClientManager+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A8EC8E210E676500A81379 /* ShareClientManager+UI.swift */; }; - 43A8EC92210E676500A81379 /* ShareClientSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A8EC8F210E676500A81379 /* ShareClientSettingsViewController.swift */; }; - 43A8EC93210E679B00A81379 /* ShareClient.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 432B0E881CDFC3C50045347B /* ShareClient.framework */; }; - 43A8EC95210E67B000A81379 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43A8EC94210E67B000A81379 /* HealthKit.framework */; }; - 43A8EC97210E680100A81379 /* ShareService+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A8EC96210E680100A81379 /* ShareService+UI.swift */; }; - 43A8EC99210E682A00A81379 /* ShareService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A8EC98210E682A00A81379 /* ShareService.swift */; }; - 43A8EC9B210E68BA00A81379 /* ShareGlucose+GlucoseKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A8EC9A210E68BA00A81379 /* ShareGlucose+GlucoseKit.swift */; }; - 43A8EC9D210E68CE00A81379 /* ShareClientManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A8EC9C210E68CE00A81379 /* ShareClientManager.swift */; }; - 43AB511B21330D1400B3D58D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 43AB511921330D1400B3D58D /* Localizable.strings */; }; - 43AB5127213315D300B3D58D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 43AB5125213315D300B3D58D /* Localizable.strings */; }; - 43AB51362133177800B3D58D /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43AB51352133177800B3D58D /* LocalizedString.swift */; }; - 43AB51372133177800B3D58D /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43AB51352133177800B3D58D /* LocalizedString.swift */; }; - 43C418AF1CE0488900405B6A /* ShareClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C418AE1CE0488900405B6A /* ShareClient.swift */; }; - A9ED4D93225EB4D30080DEBA /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4325E9CE210E6A0A00969CE5 /* HKUnit.swift */; }; - A9ED4D94225EB4D30080DEBA /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4325E9D0210E6A3D00969CE5 /* TimeInterval.swift */; }; - A9ED4D95225EB4D30080DEBA /* ShareClientManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A8EC9C210E68CE00A81379 /* ShareClientManager.swift */; }; - A9ED4D96225EB4D30080DEBA /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43AB51352133177800B3D58D /* LocalizedString.swift */; }; - A9ED4D97225EB4D30080DEBA /* ShareGlucose+GlucoseKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A8EC9A210E68BA00A81379 /* ShareGlucose+GlucoseKit.swift */; }; - A9ED4D98225EB4D30080DEBA /* ShareClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C418AE1CE0488900405B6A /* ShareClient.swift */; }; - A9ED4D99225EB4D30080DEBA /* ShareService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A8EC98210E682A00A81379 /* ShareService.swift */; }; - A9ED4D9C225EB4D30080DEBA /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43A8EC7B210E661400A81379 /* LoopKit.framework */; }; - A9ED4D9E225EB4D30080DEBA /* ShareClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 432B0E8B1CDFC3C50045347B /* ShareClient.h */; settings = {ATTRIBUTES = (Public, ); }; }; - A9ED4DA0225EB4D30080DEBA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 43AB5125213315D300B3D58D /* Localizable.strings */; }; - A9ED4DAF225EB93A0080DEBA /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9ED4DAE225EB9390080DEBA /* HealthKit.framework */; }; - B40BF26623ABD4E700A43CEE /* ShareClientPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40BF26523ABD4E700A43CEE /* ShareClientPlugin.swift */; }; - B40BF26823ABD55200A43CEE /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40BF26723ABD55200A43CEE /* OSLog.swift */; }; - B40BF26923ABD55200A43CEE /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40BF26723ABD55200A43CEE /* OSLog.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - A9E521F6225E949400EDDEF2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 432B0E7F1CDFC3C50045347B /* Project object */; - proxyType = 1; - remoteGlobalIDString = 432B0E871CDFC3C50045347B; - remoteInfo = ShareClient; - }; - B40BF26A23ABD5E100A43CEE /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 432B0E7F1CDFC3C50045347B /* Project object */; - proxyType = 1; - remoteGlobalIDString = 43A8EC81210E664300A81379; - remoteInfo = ShareClientUI; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 4325E9CE210E6A0A00969CE5 /* HKUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKUnit.swift; sourceTree = ""; }; - 4325E9D0210E6A3D00969CE5 /* TimeInterval.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeInterval.swift; sourceTree = ""; }; - 4325E9D2210E6ADA00969CE5 /* IdentifiableClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentifiableClass.swift; sourceTree = ""; }; - 4325E9D4210E6B4300969CE5 /* UIColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; }; - 432B0E881CDFC3C50045347B /* ShareClient.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ShareClient.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 432B0E8B1CDFC3C50045347B /* ShareClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShareClient.h; sourceTree = ""; }; - 432B0E8D1CDFC3C50045347B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 43A8EC7B210E661400A81379 /* LoopKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LoopKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 43A8EC82210E664300A81379 /* ShareClientUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ShareClientUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 43A8EC84210E664300A81379 /* ShareClientUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShareClientUI.h; sourceTree = ""; }; - 43A8EC85210E664300A81379 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 43A8EC8B210E665600A81379 /* LoopKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LoopKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 43A8EC8D210E676500A81379 /* ShareClientSetupViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShareClientSetupViewController.swift; sourceTree = ""; }; - 43A8EC8E210E676500A81379 /* ShareClientManager+UI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ShareClientManager+UI.swift"; sourceTree = ""; }; - 43A8EC8F210E676500A81379 /* ShareClientSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShareClientSettingsViewController.swift; sourceTree = ""; }; - 43A8EC94210E67B000A81379 /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; }; - 43A8EC96210E680100A81379 /* ShareService+UI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ShareService+UI.swift"; sourceTree = ""; }; - 43A8EC98210E682A00A81379 /* ShareService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShareService.swift; sourceTree = ""; }; - 43A8EC9A210E68BA00A81379 /* ShareGlucose+GlucoseKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ShareGlucose+GlucoseKit.swift"; sourceTree = ""; }; - 43A8EC9C210E68CE00A81379 /* ShareClientManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShareClientManager.swift; sourceTree = ""; }; - 43AB511A21330D1400B3D58D /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; - 43AB511C21330D6800B3D58D /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - 43AB511D21330D6B00B3D58D /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - 43AB511E21330D7000B3D58D /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - 43AB511F21330D7800B3D58D /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - 43AB512021330D7E00B3D58D /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - 43AB512121330D8600B3D58D /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - 43AB512221330D8A00B3D58D /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - 43AB512321330D8E00B3D58D /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - 43AB512421330D9400B3D58D /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - 43AB5126213315D300B3D58D /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; - 43AB51282133161100B3D58D /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - 43AB51292133161200B3D58D /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - 43AB512A2133161300B3D58D /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - 43AB512B2133161600B3D58D /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - 43AB512C2133161700B3D58D /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - 43AB512D2133161800B3D58D /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - 43AB512E2133161900B3D58D /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - 43AB512F2133161A00B3D58D /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - 43AB51302133161A00B3D58D /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - 43AB51352133177800B3D58D /* LocalizedString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizedString.swift; sourceTree = ""; }; - 43C418AE1CE0488900405B6A /* ShareClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShareClient.swift; sourceTree = ""; }; - 7D9BF1232336FF88005DCFD6 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF1242336FF89005DCFD6 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF1252336FF8F005DCFD6 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - 7D9BF1262336FF8F005DCFD6 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - 7D9BF1272336FF96005DCFD6 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF1282336FF96005DCFD6 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF1292336FF9C005DCFD6 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF12A2336FF9C005DCFD6 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF12B2336FFA2005DCFD6 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF12C2336FFA2005DCFD6 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF12D2336FFA9005DCFD6 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF12E2336FFA9005DCFD6 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF12F2336FFAF005DCFD6 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF1302336FFAF005DCFD6 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - A9ED4DA4225EB4D30080DEBA /* ShareClient.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ShareClient.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - A9ED4DAE225EB9390080DEBA /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS.sdk/System/Library/Frameworks/HealthKit.framework; sourceTree = DEVELOPER_DIR; }; - B40BF25E23ABD47400A43CEE /* ShareClientPlugin.loopplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ShareClientPlugin.loopplugin; sourceTree = BUILT_PRODUCTS_DIR; }; - B40BF26023ABD47400A43CEE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - B40BF26423ABD4E600A43CEE /* ShareClientPlugin-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ShareClientPlugin-Bridging-Header.h"; sourceTree = ""; }; - B40BF26523ABD4E700A43CEE /* ShareClientPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareClientPlugin.swift; sourceTree = ""; }; - B40BF26723ABD55200A43CEE /* OSLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; - C121D8CC29C7866D00DA0520 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - C121D8CD29C7866D00DA0520 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - C15A581B29C7866600D3A5A1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; - C15A581C29C7866600D3A5A1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; - C1C247842995823200371B88 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1C247852995823200371B88 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1FAB5BC29C786B000D25073 /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = ""; }; - F5D9C04227DAC15A002E48F6 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - F5D9C04327DAC15A002E48F6 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - F5E0BE3027E1E05E0033557E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; - F5E0BE3127E1E05F0033557E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 432B0E841CDFC3C50045347B /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 43A8EC95210E67B000A81379 /* HealthKit.framework in Frameworks */, - 43A8EC7C210E661400A81379 /* LoopKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43A8EC7E210E664300A81379 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 43A8EC93210E679B00A81379 /* ShareClient.framework in Frameworks */, - 43A8EC8C210E665700A81379 /* LoopKitUI.framework in Frameworks */, - 43A8EC8A210E664C00A81379 /* LoopKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A9ED4D9A225EB4D30080DEBA /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - A9ED4DAF225EB93A0080DEBA /* HealthKit.framework in Frameworks */, - A9ED4D9C225EB4D30080DEBA /* LoopKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - B40BF25B23ABD47400A43CEE /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 432B0E7E1CDFC3C50045347B = { - isa = PBXGroup; - children = ( - 43AB51342133176B00B3D58D /* Common */, - 432B0E8A1CDFC3C50045347B /* ShareClient */, - 43A8EC83210E664300A81379 /* ShareClientUI */, - B40BF25F23ABD47400A43CEE /* ShareClientPlugin */, - 432B0E891CDFC3C50045347B /* Products */, - 43A8EC7A210E661300A81379 /* Frameworks */, - ); - sourceTree = ""; - }; - 432B0E891CDFC3C50045347B /* Products */ = { - isa = PBXGroup; - children = ( - 432B0E881CDFC3C50045347B /* ShareClient.framework */, - 43A8EC82210E664300A81379 /* ShareClientUI.framework */, - A9ED4DA4225EB4D30080DEBA /* ShareClient.framework */, - B40BF25E23ABD47400A43CEE /* ShareClientPlugin.loopplugin */, - ); - name = Products; - sourceTree = ""; - }; - 432B0E8A1CDFC3C50045347B /* ShareClient */ = { - isa = PBXGroup; - children = ( - 43AB5125213315D300B3D58D /* Localizable.strings */, - 4325E9CE210E6A0A00969CE5 /* HKUnit.swift */, - 43C418AE1CE0488900405B6A /* ShareClient.swift */, - 43A8EC9C210E68CE00A81379 /* ShareClientManager.swift */, - 43A8EC9A210E68BA00A81379 /* ShareGlucose+GlucoseKit.swift */, - 43A8EC98210E682A00A81379 /* ShareService.swift */, - 4325E9D0210E6A3D00969CE5 /* TimeInterval.swift */, - 432B0E8B1CDFC3C50045347B /* ShareClient.h */, - 432B0E8D1CDFC3C50045347B /* Info.plist */, - B40BF26723ABD55200A43CEE /* OSLog.swift */, - ); - path = ShareClient; - sourceTree = ""; - }; - 43A8EC7A210E661300A81379 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 43A8EC94210E67B000A81379 /* HealthKit.framework */, - A9ED4DAE225EB9390080DEBA /* HealthKit.framework */, - 43A8EC8B210E665600A81379 /* LoopKitUI.framework */, - 43A8EC7B210E661400A81379 /* LoopKit.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 43A8EC83210E664300A81379 /* ShareClientUI */ = { - isa = PBXGroup; - children = ( - 43AB511921330D1400B3D58D /* Localizable.strings */, - 4325E9D2210E6ADA00969CE5 /* IdentifiableClass.swift */, - 43A8EC84210E664300A81379 /* ShareClientUI.h */, - 43A8EC8E210E676500A81379 /* ShareClientManager+UI.swift */, - 43A8EC8F210E676500A81379 /* ShareClientSettingsViewController.swift */, - 43A8EC8D210E676500A81379 /* ShareClientSetupViewController.swift */, - 43A8EC96210E680100A81379 /* ShareService+UI.swift */, - 4325E9D4210E6B4300969CE5 /* UIColor.swift */, - 43A8EC85210E664300A81379 /* Info.plist */, - ); - path = ShareClientUI; - sourceTree = ""; - }; - 43AB51342133176B00B3D58D /* Common */ = { - isa = PBXGroup; - children = ( - 43AB51352133177800B3D58D /* LocalizedString.swift */, - ); - path = Common; - sourceTree = ""; - }; - B40BF25F23ABD47400A43CEE /* ShareClientPlugin */ = { - isa = PBXGroup; - children = ( - B40BF26023ABD47400A43CEE /* Info.plist */, - B40BF26523ABD4E700A43CEE /* ShareClientPlugin.swift */, - B40BF26423ABD4E600A43CEE /* ShareClientPlugin-Bridging-Header.h */, - ); - path = ShareClientPlugin; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 432B0E851CDFC3C50045347B /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 432B0E8C1CDFC3C50045347B /* ShareClient.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43A8EC7F210E664300A81379 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 43A8EC86210E664300A81379 /* ShareClientUI.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A9ED4D9D225EB4D30080DEBA /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - A9ED4D9E225EB4D30080DEBA /* ShareClient.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 432B0E871CDFC3C50045347B /* ShareClient */ = { - isa = PBXNativeTarget; - buildConfigurationList = 432B0E9C1CDFC3C50045347B /* Build configuration list for PBXNativeTarget "ShareClient" */; - buildPhases = ( - 432B0E851CDFC3C50045347B /* Headers */, - 432B0E831CDFC3C50045347B /* Sources */, - 432B0E841CDFC3C50045347B /* Frameworks */, - 432B0E861CDFC3C50045347B /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ShareClient; - productName = ShareClient; - productReference = 432B0E881CDFC3C50045347B /* ShareClient.framework */; - productType = "com.apple.product-type.framework"; - }; - 43A8EC81210E664300A81379 /* ShareClientUI */ = { - isa = PBXNativeTarget; - buildConfigurationList = 43A8EC87210E664300A81379 /* Build configuration list for PBXNativeTarget "ShareClientUI" */; - buildPhases = ( - 43A8EC7F210E664300A81379 /* Headers */, - 43A8EC7D210E664300A81379 /* Sources */, - 43A8EC7E210E664300A81379 /* Frameworks */, - 43A8EC80210E664300A81379 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - A9E521F7225E949400EDDEF2 /* PBXTargetDependency */, - ); - name = ShareClientUI; - productName = ShareClientUI; - productReference = 43A8EC82210E664300A81379 /* ShareClientUI.framework */; - productType = "com.apple.product-type.framework"; - }; - A9ED4D91225EB4D30080DEBA /* ShareClient-watchOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = A9ED4DA1225EB4D30080DEBA /* Build configuration list for PBXNativeTarget "ShareClient-watchOS" */; - buildPhases = ( - A9ED4D92225EB4D30080DEBA /* Sources */, - A9ED4D9A225EB4D30080DEBA /* Frameworks */, - A9ED4D9D225EB4D30080DEBA /* Headers */, - A9ED4D9F225EB4D30080DEBA /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "ShareClient-watchOS"; - productName = ShareClient; - productReference = A9ED4DA4225EB4D30080DEBA /* ShareClient.framework */; - productType = "com.apple.product-type.framework"; - }; - B40BF25D23ABD47400A43CEE /* ShareClientPlugin */ = { - isa = PBXNativeTarget; - buildConfigurationList = B40BF26323ABD47400A43CEE /* Build configuration list for PBXNativeTarget "ShareClientPlugin" */; - buildPhases = ( - B40BF25A23ABD47400A43CEE /* Sources */, - B40BF25B23ABD47400A43CEE /* Frameworks */, - B40BF25C23ABD47400A43CEE /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - B40BF26B23ABD5E100A43CEE /* PBXTargetDependency */, - ); - name = ShareClientPlugin; - productName = ShareClientPlugin; - productReference = B40BF25E23ABD47400A43CEE /* ShareClientPlugin.loopplugin */; - productType = "com.apple.product-type.bundle"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 432B0E7F1CDFC3C50045347B /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 1330; - ORGANIZATIONNAME = "Mark Wilson"; - TargetAttributes = { - 432B0E871CDFC3C50045347B = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1020; - }; - 43A8EC81210E664300A81379 = { - CreatedOnToolsVersion = 9.4.1; - LastSwiftMigration = 1020; - ProvisioningStyle = Automatic; - }; - B40BF25D23ABD47400A43CEE = { - CreatedOnToolsVersion = 11.0; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = 432B0E821CDFC3C50045347B /* Build configuration list for PBXProject "ShareClient" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - fr, - de, - "zh-Hans", - es, - it, - nl, - nb, - ru, - pl, - ja, - "pt-BR", - sv, - vi, - ro, - fi, - da, - tr, - he, - sk, - ar, - cs, - hi, - ); - mainGroup = 432B0E7E1CDFC3C50045347B; - productRefGroup = 432B0E891CDFC3C50045347B /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 432B0E871CDFC3C50045347B /* ShareClient */, - A9ED4D91225EB4D30080DEBA /* ShareClient-watchOS */, - 43A8EC81210E664300A81379 /* ShareClientUI */, - B40BF25D23ABD47400A43CEE /* ShareClientPlugin */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 432B0E861CDFC3C50045347B /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 43AB5127213315D300B3D58D /* Localizable.strings in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43A8EC80210E664300A81379 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 43AB511B21330D1400B3D58D /* Localizable.strings in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A9ED4D9F225EB4D30080DEBA /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - A9ED4DA0225EB4D30080DEBA /* Localizable.strings in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - B40BF25C23ABD47400A43CEE /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 432B0E831CDFC3C50045347B /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 4325E9CF210E6A0A00969CE5 /* HKUnit.swift in Sources */, - 4325E9D1210E6A3D00969CE5 /* TimeInterval.swift in Sources */, - B40BF26823ABD55200A43CEE /* OSLog.swift in Sources */, - 43A8EC9D210E68CE00A81379 /* ShareClientManager.swift in Sources */, - 43AB51362133177800B3D58D /* LocalizedString.swift in Sources */, - 43A8EC9B210E68BA00A81379 /* ShareGlucose+GlucoseKit.swift in Sources */, - 43C418AF1CE0488900405B6A /* ShareClient.swift in Sources */, - 43A8EC99210E682A00A81379 /* ShareService.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43A8EC7D210E664300A81379 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 43A8EC92210E676500A81379 /* ShareClientSettingsViewController.swift in Sources */, - 4325E9D5210E6B4400969CE5 /* UIColor.swift in Sources */, - 43A8EC97210E680100A81379 /* ShareService+UI.swift in Sources */, - 43AB51372133177800B3D58D /* LocalizedString.swift in Sources */, - 4325E9D3210E6ADA00969CE5 /* IdentifiableClass.swift in Sources */, - 43A8EC91210E676500A81379 /* ShareClientManager+UI.swift in Sources */, - 43A8EC90210E676500A81379 /* ShareClientSetupViewController.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A9ED4D92225EB4D30080DEBA /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - A9ED4D93225EB4D30080DEBA /* HKUnit.swift in Sources */, - A9ED4D94225EB4D30080DEBA /* TimeInterval.swift in Sources */, - A9ED4D95225EB4D30080DEBA /* ShareClientManager.swift in Sources */, - A9ED4D96225EB4D30080DEBA /* LocalizedString.swift in Sources */, - A9ED4D97225EB4D30080DEBA /* ShareGlucose+GlucoseKit.swift in Sources */, - A9ED4D98225EB4D30080DEBA /* ShareClient.swift in Sources */, - A9ED4D99225EB4D30080DEBA /* ShareService.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - B40BF25A23ABD47400A43CEE /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - B40BF26923ABD55200A43CEE /* OSLog.swift in Sources */, - B40BF26623ABD4E700A43CEE /* ShareClientPlugin.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - A9E521F7225E949400EDDEF2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 432B0E871CDFC3C50045347B /* ShareClient */; - targetProxy = A9E521F6225E949400EDDEF2 /* PBXContainerItemProxy */; - }; - B40BF26B23ABD5E100A43CEE /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 43A8EC81210E664300A81379 /* ShareClientUI */; - targetProxy = B40BF26A23ABD5E100A43CEE /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 43AB511921330D1400B3D58D /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 43AB511A21330D1400B3D58D /* Base */, - 43AB511C21330D6800B3D58D /* fr */, - 43AB511D21330D6B00B3D58D /* de */, - 43AB511E21330D7000B3D58D /* zh-Hans */, - 43AB511F21330D7800B3D58D /* es */, - 43AB512021330D7E00B3D58D /* it */, - 43AB512121330D8600B3D58D /* nl */, - 43AB512221330D8A00B3D58D /* nb */, - 43AB512321330D8E00B3D58D /* ru */, - 43AB512421330D9400B3D58D /* pl */, - 7D9BF1242336FF89005DCFD6 /* ja */, - 7D9BF1262336FF8F005DCFD6 /* pt-BR */, - 7D9BF1282336FF96005DCFD6 /* sv */, - 7D9BF12A2336FF9C005DCFD6 /* vi */, - 7D9BF12C2336FFA2005DCFD6 /* ro */, - 7D9BF12E2336FFA9005DCFD6 /* fi */, - 7D9BF1302336FFAF005DCFD6 /* da */, - F5D9C04327DAC15A002E48F6 /* tr */, - F5E0BE3127E1E05F0033557E /* he */, - C1C247852995823200371B88 /* sk */, - C15A581C29C7866600D3A5A1 /* ar */, - C121D8CD29C7866D00DA0520 /* cs */, - C1FAB5BC29C786B000D25073 /* hi */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - 43AB5125213315D300B3D58D /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 43AB5126213315D300B3D58D /* Base */, - 43AB51282133161100B3D58D /* fr */, - 43AB51292133161200B3D58D /* de */, - 43AB512A2133161300B3D58D /* zh-Hans */, - 43AB512B2133161600B3D58D /* es */, - 43AB512C2133161700B3D58D /* it */, - 43AB512D2133161800B3D58D /* nl */, - 43AB512E2133161900B3D58D /* nb */, - 43AB512F2133161A00B3D58D /* ru */, - 43AB51302133161A00B3D58D /* pl */, - 7D9BF1232336FF88005DCFD6 /* ja */, - 7D9BF1252336FF8F005DCFD6 /* pt-BR */, - 7D9BF1272336FF96005DCFD6 /* sv */, - 7D9BF1292336FF9C005DCFD6 /* vi */, - 7D9BF12B2336FFA2005DCFD6 /* ro */, - 7D9BF12D2336FFA9005DCFD6 /* fi */, - 7D9BF12F2336FFAF005DCFD6 /* da */, - F5D9C04227DAC15A002E48F6 /* tr */, - F5E0BE3027E1E05E0033557E /* he */, - C1C247842995823200371B88 /* sk */, - C15A581B29C7866600D3A5A1 /* ar */, - C121D8CC29C7866D00DA0520 /* cs */, - ); - name = Localizable.strings; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 432B0E9A1CDFC3C50045347B /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - 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; - CURRENT_PROJECT_VERSION = 2; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - 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 = 15.1; - LOCALIZED_STRING_MACRO_NAMES = ( - NSLocalizedString, - CFLocalizedString, - LocalizedString, - ); - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - WATCHOS_DEPLOYMENT_TARGET = 4.0; - }; - name = Debug; - }; - 432B0E9B1CDFC3C50045347B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - 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; - CURRENT_PROJECT_VERSION = 2; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - 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 = 15.1; - LOCALIZED_STRING_MACRO_NAMES = ( - NSLocalizedString, - CFLocalizedString, - LocalizedString, - ); - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - WATCHOS_DEPLOYMENT_TARGET = 4.0; - }; - name = Release; - }; - 432B0E9D1CDFC3C50045347B /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_MODULES = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = ShareClient/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.mddub.ShareClient; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 432B0E9E1CDFC3C50045347B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_MODULES = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = ShareClient/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.mddub.ShareClient; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - }; - name = Release; - }; - 43A8EC88210E664300A81379 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = ShareClientUI/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.ShareClientUI; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 43A8EC89210E664300A81379 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = ShareClientUI/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.ShareClientUI; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - A9ED4DA2225EB4D30080DEBA /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = ShareClient/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.mddub.ShareClient; - PRODUCT_NAME = ShareClient; - SDKROOT = watchos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "watchos watchsimulator"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; - TARGETED_DEVICE_FAMILY = 4; - }; - name = Debug; - }; - A9ED4DA3225EB4D30080DEBA /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = ShareClient/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.mddub.ShareClient; - PRODUCT_NAME = ShareClient; - SDKROOT = watchos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "watchos watchsimulator"; - TARGETED_DEVICE_FAMILY = 4; - }; - name = Release; - }; - B40BF26123ABD47400A43CEE /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGNING_ALLOWED = NO; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = ShareClientPlugin/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACH_O_TYPE = mh_dylib; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.ShareClientPlugin; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_OBJC_BRIDGING_HEADER = "ShareClientPlugin/ShareClientPlugin-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - WRAPPER_EXTENSION = loopplugin; - }; - name = Debug; - }; - B40BF26223ABD47400A43CEE /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGNING_ALLOWED = NO; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = ShareClientPlugin/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACH_O_TYPE = mh_dylib; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.ShareClientPlugin; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_OBJC_BRIDGING_HEADER = "ShareClientPlugin/ShareClientPlugin-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - WRAPPER_EXTENSION = loopplugin; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 432B0E821CDFC3C50045347B /* Build configuration list for PBXProject "ShareClient" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 432B0E9A1CDFC3C50045347B /* Debug */, - 432B0E9B1CDFC3C50045347B /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 432B0E9C1CDFC3C50045347B /* Build configuration list for PBXNativeTarget "ShareClient" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 432B0E9D1CDFC3C50045347B /* Debug */, - 432B0E9E1CDFC3C50045347B /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 43A8EC87210E664300A81379 /* Build configuration list for PBXNativeTarget "ShareClientUI" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 43A8EC88210E664300A81379 /* Debug */, - 43A8EC89210E664300A81379 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - A9ED4DA1225EB4D30080DEBA /* Build configuration list for PBXNativeTarget "ShareClient-watchOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - A9ED4DA2225EB4D30080DEBA /* Debug */, - A9ED4DA3225EB4D30080DEBA /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - B40BF26323ABD47400A43CEE /* Build configuration list for PBXNativeTarget "ShareClientPlugin" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - B40BF26123ABD47400A43CEE /* Debug */, - B40BF26223ABD47400A43CEE /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 432B0E7F1CDFC3C50045347B /* Project object */; -} diff --git a/Dependencies/dexcom-share-client-swift/ShareClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Dependencies/dexcom-share-client-swift/ShareClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 699f1fe61..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dependencies/dexcom-share-client-swift/ShareClient.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Dependencies/dexcom-share-client-swift/ShareClient.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index 08de0be8d..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded - - - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/Base.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/Base.lproj/Localizable.strings deleted file mode 100644 index 0c5ccd940..000000000 Binary files a/Dependencies/dexcom-share-client-swift/ShareClient/Base.lproj/Localizable.strings and /dev/null differ diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/HKUnit.swift b/Dependencies/dexcom-share-client-swift/ShareClient/HKUnit.swift deleted file mode 100644 index e3f0ddedd..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/HKUnit.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// HKUnit.swift -// xDripG5 -// -// Created by Nate Racklyeft on 8/6/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -extension HKUnit { - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: HKUnit.literUnit(with: .deci)) - }() -} diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/Info.plist b/Dependencies/dexcom-share-client-swift/ShareClient/Info.plist deleted file mode 100644 index 602d86443..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.2 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/OSLog.swift b/Dependencies/dexcom-share-client-swift/ShareClient/OSLog.swift deleted file mode 100644 index e572460bb..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/OSLog.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// OSLog.swift -// ShareClient -// -// Created by Nathaniel Hamming on 2019-12-19. -// Copyright © 2019 Mark Wilson. All rights reserved. -// - -import os.log - - -extension OSLog { - convenience init(category: String) { - self.init(subsystem: "com.loopkit.ShareClient", category: category) - } - - func debug(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .debug, args) - } - - func info(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .info, args) - } - - func `default`(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .default, args) - } - - func error(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .error, args) - } - - private func log(_ message: StaticString, type: OSLogType, _ args: [CVarArg]) { - switch args.count { - case 0: - os_log(message, log: self, type: type) - case 1: - os_log(message, log: self, type: type, args[0]) - case 2: - os_log(message, log: self, type: type, args[0], args[1]) - case 3: - os_log(message, log: self, type: type, args[0], args[1], args[2]) - case 4: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3]) - case 5: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4]) - default: - os_log(message, log: self, type: type, args) - } - } -} diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/ShareClient.h b/Dependencies/dexcom-share-client-swift/ShareClient/ShareClient.h deleted file mode 100644 index 2d67034b0..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/ShareClient.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// ShareClient.h -// ShareClient -// -// Created by Nathan Racklyeft on 5/8/16. -// Copyright © 2016 Mark Wilson. All rights reserved. -// - -#import - -//! Project version number for ShareClient. -FOUNDATION_EXPORT double ShareClientVersionNumber; - -//! Project version string for ShareClient. -FOUNDATION_EXPORT const unsigned char ShareClientVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/ShareClient.swift b/Dependencies/dexcom-share-client-swift/ShareClient/ShareClient.swift deleted file mode 100644 index 6222c2c73..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/ShareClient.swift +++ /dev/null @@ -1,277 +0,0 @@ -// -// ShareClient.h -// ShareClient -// -// Created by Mark Wilson on 5/7/16. -// Copyright © 2016 Mark Wilson. All rights reserved. -// - -import Foundation - -public struct ShareGlucose { - public let glucose: UInt16 - public let trend: UInt8 - public let timestamp: Date -} - -public enum ShareError: Error { - case httpError(Error) - // some possible values of errorCode: - // SSO_AuthenticateAccountNotFound - // SSO_AuthenticatePasswordInvalid - // SSO_AuthenticateMaxAttemptsExceeed - case loginError(errorCode: String) - case fetchError - case dataError(reason: String) - case dateError -} - - -public enum KnownShareServers: String { - case US="https://share2.dexcom.com" - case NON_US="https://shareous1.dexcom.com" - -} - -// From the Dexcom Share iOS app, via @bewest and @shanselman: -// https://github.com/bewest/share2nightscout-bridge -private let dexcomUserAgent = "Dexcom Share/3.0.2.11 CFNetwork/711.2.23 Darwin/14.0.0" -private let dexcomApplicationId = "d89443d2-327c-4a6f-89e5-496bbb0317db" -private let dexcomAuthenticatePath = "/ShareWebServices/Services/General/AuthenticatePublisherAccount" -private let dexcomLoginByIdPath = "/ShareWebServices/Services/General/LoginPublisherAccountById" -private let dexcomLatestGlucosePath = "/ShareWebServices/Services/Publisher/ReadPublisherLatestGlucoseValues" -private let maxReauthAttempts = 2 - -// TODO use an HTTP library which supports JSON and futures instead of callbacks. -// using cocoapods in a playground appears complicated -// ¯\_(ツ)_/¯ -private func dexcomPOST(_ url: URL, JSONData: [String: AnyObject]? = nil, callback: @escaping (Error?, String?) -> Void) { - var data: Data? - - if let JSONData = JSONData { - guard let encoded = try? JSONSerialization.data(withJSONObject: JSONData, options:[]) else { - return callback(ShareError.dataError(reason: "Failed to encode JSON for POST to " + url.absoluteString), nil) - } - - data = encoded - } - - var request = URLRequest(url: url) - request.httpMethod = "POST" - request.addValue("application/json", forHTTPHeaderField: "Content-Type") - request.addValue("application/json", forHTTPHeaderField: "Accept") - request.addValue(dexcomUserAgent, forHTTPHeaderField: "User-Agent") - request.httpBody = data - - URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in - if error != nil { - callback(error, nil) - } else { - callback(nil, String(data: data!, encoding: .utf8)) - } - }).resume() -} - -public class ShareClient { - public let username: String - public let password: String - - private let shareServer:String - private var token: String? - - public init(username: String, password: String, shareServer:String=KnownShareServers.US.rawValue) { - self.username = username - self.password = password - self.shareServer = shareServer - } - public convenience init(username: String, password: String, shareServer:KnownShareServers=KnownShareServers.US) { - - self.init(username: username, password: password, shareServer:shareServer.rawValue) - - } - - public func fetchLast(_ n: Int, callback: @escaping (ShareError?, [ShareGlucose]?) -> Void) { - fetchLastWithRetries(n, remaining: maxReauthAttempts, callback: callback) - } - - private func ensureToken(_ callback: @escaping (ShareError?) -> Void) { - if token != nil { - callback(nil) - } else { - fetchAccountID { result in - switch result { - case .failure(let error): - callback(error) - case .success(let accountId): - self.fetchTokenByAccountId(accountId) { (error, token) in - if error != nil { - callback(error) - } else { - self.token = token - callback(nil) - } - } - } - } - } - } - - private func fetchAccountID(_ callback: @escaping (Result) -> Void) { - let data = [ - "accountName": username, - "password": password, - "applicationId": dexcomApplicationId - ] - - guard let url = URL(string: shareServer + dexcomAuthenticatePath) else { - return callback(.failure(.fetchError)) - } - - dexcomPOST(url, JSONData: data as [String : AnyObject]?) { (error, response) in - if let error = error { - return callback(.failure(.httpError(error))) - } - - guard let response = response, - let data = response.data(using: .utf8), - let decoded = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) - else { - return callback(.failure(.loginError(errorCode: "unknown"))) - } - - if let token = decoded as? String { - // success is a JSON-encoded string containing the token - callback(.success(token)) - } else { - // failure is a JSON object containing the error reason - let errorCode = (decoded as? [String: String])?["Code"] ?? "unknown" - callback(.failure(.loginError(errorCode: errorCode))) - } - } - } - - private func fetchTokenByAccountId(_ accountId: String, callback: @escaping (ShareError?, String?) -> Void) { - let data = [ - "accountId": accountId, - "password": password, - "applicationId": dexcomApplicationId - ] - - guard let url = URL(string: shareServer + dexcomLoginByIdPath) else { - return callback(ShareError.fetchError, nil) - } - - dexcomPOST(url, JSONData: data as [String : AnyObject]?) { (error, response) in - if let error = error { - return callback(.httpError(error), nil) - } - - guard let response = response, - let data = response.data(using: .utf8), - let decoded = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) - else { - return callback(.loginError(errorCode: "unknown"), nil) - } - - if let token = decoded as? String { - // success is a JSON-encoded string containing the token - callback(nil, token) - } else { - // failure is a JSON object containing the error reason - let errorCode = (decoded as? [String: String])?["Code"] ?? "unknown" - callback(.loginError(errorCode: errorCode), nil) - } - } - } - - private func fetchLastWithRetries(_ n: Int, remaining: Int, callback: @escaping (ShareError?, [ShareGlucose]?) -> Void) { - ensureToken() { (error) in - guard error == nil else { - return callback(error, nil) - } - - guard var components = URLComponents(string: self.shareServer + dexcomLatestGlucosePath) else { - return callback(.fetchError, nil) - } - - components.queryItems = [ - URLQueryItem(name: "sessionId", value: self.token), - URLQueryItem(name: "minutes", value: String(1440)), - URLQueryItem(name: "maxCount", value: String(n)) - ] - - guard let url = components.url else { - return callback(.fetchError, nil) - } - - dexcomPOST(url) { (error, response) in - if let error = error { - return callback(.httpError(error), nil) - } - - do { - guard let response = response else { - throw ShareError.fetchError - } - - let decoded = try? JSONSerialization.jsonObject(with: response.data(using: .utf8)!, options: []) - guard let sgvs = decoded as? Array else { - if remaining > 0 { - self.token = nil - return self.fetchLastWithRetries(n, remaining: remaining - 1, callback: callback) - } else { - throw ShareError.dataError(reason: "Failed to decode SGVs as array after trying to reauth: " + response) - } - } - - var transformed: Array = [] - for sgv in sgvs { - if let glucose = sgv["Value"] as? Int, let wt = sgv["WT"] as? String { - let trend: Int? - if let trendString = sgv["Trend"] as? String { - // Dec 2021, Dexcom Share modified json encoding of Trend from int to string - let trendmap = ["": 0, "DoubleUp":1, "SingleUp":2, "FortyFiveUp":3, "Flat":4, "FortyFiveDown":5, "SingleDown":6, "DoubleDown": 7, "NotComputable":8, "RateOutOfRange":9] - trend = trendmap[trendString, default: 0] - } else { - trend = sgv["Trend"] as? Int - } - - if let trend = trend { - transformed.append(ShareGlucose( - glucose: UInt16(glucose), - trend: UInt8(trend), - timestamp: try self.parseDate(wt) - )) - } else { - throw ShareError.dataError(reason: "Failed to decode. SGV record had bad trend: " + response) - } - } else { - throw ShareError.dataError(reason: "Failed to decode an SGV record: " + response) - } - } - callback(nil, transformed) - } catch let error as ShareError { - callback(error, nil) - } catch { - callback(.fetchError, nil) - } - } - } - } - - private func parseDate(_ wt: String) throws -> Date { - // wt looks like "/Date(1462404576000)/" - let re = try NSRegularExpression(pattern: "\\((.*)\\)") - if let match = re.firstMatch(in: wt, range: NSMakeRange(0, wt.count)) { - #if swift(>=4) - let matchRange = match.range(at: 1) - #else - let matchRange = match.rangeAt(1) - #endif - let epoch = Double((wt as NSString).substring(with: matchRange))! / 1000 - return Date(timeIntervalSince1970: epoch) - } else { - throw ShareError.dateError - } - } -} diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/ShareClientManager.swift b/Dependencies/dexcom-share-client-swift/ShareClient/ShareClientManager.swift deleted file mode 100644 index bcf1d55f6..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/ShareClientManager.swift +++ /dev/null @@ -1,145 +0,0 @@ -// -// ShareClientManager.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import LoopKit -import HealthKit - - -public class ShareClientManager: CGMManager { - - public let managerIdentifier = "DexShareClient" - - public init() { - shareService = ShareService(keychainManager: keychain) - } - - required convenience public init?(rawState: CGMManager.RawStateValue) { - self.init() - } - - public var rawState: CGMManager.RawStateValue { - return [:] - } - - public let isOnboarded = true // No distinction between created and onboarded - - private let keychain = KeychainManager() - - public var shareService: ShareService { - didSet { - try! keychain.setDexcomShareUsername(shareService.username, password: shareService.password, url: shareService.url) - } - } - - public let localizedTitle = LocalizedString("Dexcom Share", comment: "Title for the CGMManager option") - - public let appURL: URL? = nil - - public var cgmManagerDelegate: CGMManagerDelegate? { - get { - return delegate.delegate - } - set { - delegate.delegate = newValue - } - } - - public var delegateQueue: DispatchQueue! { - get { - return delegate.queue - } - set { - delegate.queue = newValue - } - } - - public let delegate = WeakSynchronizedDelegate() - - public let providesBLEHeartbeat = false - - public let shouldSyncToRemoteService = false - - public var glucoseDisplay: GlucoseDisplayable? { - return latestBackfill - } - - public var cgmManagerStatus: CGMManagerStatus { - return CGMManagerStatus(hasValidSensorSession: hasValidSensorSession, device: device) - } - - public var hasValidSensorSession: Bool { - return shareService.isAuthorized - } - - public let managedDataInterval: TimeInterval? = nil - - public private(set) var latestBackfill: ShareGlucose? - - public func fetchNewDataIfNeeded(_ completion: @escaping (CGMReadingResult) -> Void) { - guard let shareClient = shareService.client else { - completion(.noData) - return - } - - // If our last glucose was less than 4.5 minutes ago, don't fetch. - if let latestGlucose = latestBackfill, latestGlucose.startDate.timeIntervalSinceNow > -TimeInterval(minutes: 4.5) { - completion(.noData) - return - } - - shareClient.fetchLast(6) { (error, glucose) in - if let error = error { - completion(.error(error)) - return - } - guard let glucose = glucose else { - completion(.noData) - return - } - - // Ignore glucose values that are up to a minute newer than our previous value, to account for possible time shifting in Share data - let startDate = self.delegate.call { (delegate) -> Date? in - return delegate?.startDateToFilterNewData(for: self)?.addingTimeInterval(TimeInterval(minutes: 1)) - } - let newGlucose = glucose.filterDateRange(startDate, nil) - let newSamples = newGlucose.filter({ $0.isStateValid }).map { - return NewGlucoseSample(date: $0.startDate, quantity: $0.quantity, condition: $0.condition, trend: $0.trendType, trendRate: $0.trendRate, isDisplayOnly: false, wasUserEntered: false, syncIdentifier: "\(Int($0.startDate.timeIntervalSince1970))", device: self.device) - } - - self.latestBackfill = newGlucose.first - - if newSamples.count > 0 { - completion(.newData(newSamples)) - } else { - completion(.noData) - } - } - } - - public var device: HKDevice? = nil - - public var debugDescription: String { - return [ - "## ShareClientManager", - "latestBackfill: \(String(describing: latestBackfill))", - "" - ].joined(separator: "\n") - } -} - -// MARK: - AlertResponder implementation -extension ShareClientManager { - public func acknowledgeAlert(alertIdentifier: Alert.AlertIdentifier, completion: @escaping (Error?) -> Void) { - completion(nil) - } -} - -// MARK: - AlertSoundVendor implementation -extension ShareClientManager { - public func getSoundBaseURL() -> URL? { return nil } - public func getSounds() -> [Alert.Sound] { return [] } -} diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/ShareGlucose+GlucoseKit.swift b/Dependencies/dexcom-share-client-swift/ShareClient/ShareGlucose+GlucoseKit.swift deleted file mode 100644 index 87f04d14d..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/ShareGlucose+GlucoseKit.swift +++ /dev/null @@ -1,72 +0,0 @@ -// -// ShareGlucose+GlucoseKit.swift -// Naterade -// -// Created by Nathan Racklyeft on 5/8/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit -import LoopKit - -enum GlucoseLimits { - static var minimum: UInt16 = 40 - static var maximum: UInt16 = 400 -} - -extension ShareGlucose: GlucoseValue { - public var startDate: Date { - return timestamp - } - - public var quantity: HKQuantity { - return HKQuantity(unit: .milligramsPerDeciliter, doubleValue: Double(min(max(glucose, GlucoseLimits.minimum), GlucoseLimits.maximum))) - } -} - - -extension ShareGlucose: GlucoseDisplayable { - public var isStateValid: Bool { - return glucose >= 39 - } - - public var trendType: GlucoseTrend? { - return GlucoseTrend(rawValue: Int(trend)) - } - - public var trendRate: HKQuantity? { - return nil - } - - public var isLocal: Bool { - return false - } - - // TODO Placeholder. This functionality will come with LOOP-1311 - public var glucoseRangeCategory: GlucoseRangeCategory? { - return nil - } -} - -extension ShareGlucose { - public var condition: GlucoseCondition? { - if glucose < GlucoseLimits.minimum { - return .belowRange - } else if glucose > GlucoseLimits.maximum { - return .aboveRange - } else { - return nil - } - } -} - -extension GlucoseDisplayable { - public var stateDescription: String { - if isStateValid { - return LocalizedString("OK", comment: "Sensor state description for the valid state") - } else { - return LocalizedString("Needs Attention", comment: "Sensor state description for the non-valid state") - } - } -} diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/ShareService.swift b/Dependencies/dexcom-share-client-swift/ShareClient/ShareService.swift deleted file mode 100644 index fc7190b41..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/ShareService.swift +++ /dev/null @@ -1,139 +0,0 @@ -// -// ShareService.swift -// Loop -// -// Created by Nate Racklyeft on 7/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import LoopKit - - -// Encapsulates the Dexcom Share client service and its authentication -public class ShareService: ServiceAuthentication { - public var credentialValues: [String?] - - public let title: String = LocalizedString("Dexcom Share", comment: "The title of the Dexcom Share service") - - public init(username: String?, password: String?, url: URL?) { - credentialValues = [ - username, - password, - url?.absoluteString - ] - - /* - To enable Loop to use a custom share server, change the value of customServer - and remove the comment markers on line 55 and 62. - - You can find installation instructions for one such custom share server at - https://github.com/dabear/NightscoutShareServer - */ - - /* - let customServer = "https://REPLACEME" - let customServerTitle = "Custom" - - credentials[2].options?.append( - (title: LocalizedString(customServerTitle, comment: "Custom share server option title"), - value: customServer)) - */ - - if let username = username, let password = password, let url = url { - isAuthorized = true - client = ShareClient(username: username, password: password, shareServer: url.absoluteString) - } - } - - // The share client, if credentials are present - private(set) var client: ShareClient? - - public var username: String? { - return credentialValues[0] - } - - var password: String? { - return credentialValues[1] - } - - var url: URL? { - guard let urlString = credentialValues[2] else { - return nil - } - - return URL(string: urlString) - } - - public var isAuthorized: Bool = false - - public func verify(_ completion: @escaping (_ success: Bool, _ error: Error?) -> Void) { - guard let username = username, let password = password, let url = url else { - completion(false, nil) - return - } - - let client = ShareClient(username: username, password: password, shareServer: url.absoluteString) - client.fetchLast(1) { (error, _) in - completion(error == nil, error) - } - self.client = client - } - - public func reset() { - isAuthorized = false - client = nil - } -} - - -private let DexcomShareURL = URL(string: KnownShareServers.US.rawValue)! -private let DexcomShareServiceLabel = "DexcomShare2" - - -extension KeychainManager { - func setDexcomShareUsername(_ username: String?, password: String?, url: URL?) throws { - let credentials: InternetCredentials? - - if let username = username, let password = password, let url = url { - credentials = InternetCredentials(username: username, password: password, url: url) - } else { - credentials = nil - } - - // Replace the legacy URL-keyed credentials - try replaceInternetCredentials(nil, forURL: DexcomShareURL) - - try replaceInternetCredentials(credentials, forLabel: DexcomShareServiceLabel) - } - - func getDexcomShareCredentials() -> (username: String, password: String, url: URL)? { - do { // Silence all errors and return nil - do { - let credentials = try getInternetCredentials(label: DexcomShareServiceLabel) - - return (username: credentials.username, password: credentials.password, url: credentials.url) - } catch KeychainManagerError.copy { - // Fetch and replace the legacy URL-keyed credentials - let credentials = try getInternetCredentials(url: DexcomShareURL) - - try setDexcomShareUsername(credentials.username, password: credentials.password, url: credentials.url) - - return (username: credentials.username, password: credentials.password, url: credentials.url) - } - } catch { - return nil - } - } -} - - -extension ShareService { - public convenience init(keychainManager: KeychainManager = KeychainManager()) { - if let (username, password, url) = keychainManager.getDexcomShareCredentials() { - self.init(username: username, password: password, url: url) - } else { - self.init(username: nil, password: nil, url: nil) - } - } -} diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/TimeInterval.swift b/Dependencies/dexcom-share-client-swift/ShareClient/TimeInterval.swift deleted file mode 100644 index 5a8046a6c..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/TimeInterval.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// NSTimeInterval.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension TimeInterval { - static func hours(_ hours: Double) -> TimeInterval { - return self.init(hours: hours) - } - - static func minutes(_ minutes: Int) -> TimeInterval { - return self.init(minutes: Double(minutes)) - } - - static func minutes(_ minutes: Double) -> TimeInterval { - return self.init(minutes: minutes) - } - - static func seconds(_ seconds: Double) -> TimeInterval { - return self.init(seconds) - } - - static func milliseconds(_ milliseconds: Double) -> TimeInterval { - return self.init(milliseconds / 1000) - } - - init(minutes: Double) { - self.init(minutes * 60) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - init(seconds: Double) { - self.init(seconds) - } - - init(milliseconds: Double) { - self.init(milliseconds / 1000) - } - - var milliseconds: Double { - return self * 1000 - } - - var minutes: Double { - return self / 60.0 - } - - var hours: Double { - return minutes / 60.0 - } - -} diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/ar.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/ar.lproj/Localizable.strings deleted file mode 100644 index 03d588157..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/ar.lproj/Localizable.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Sensor state description for the valid state */ -"OK" = "موافق"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/cs.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/cs.lproj/Localizable.strings deleted file mode 100644 index 5c6942918..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/cs.lproj/Localizable.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/da.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/da.lproj/Localizable.strings deleted file mode 100644 index 101a8f4f2..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/da.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Handling påkrævet"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/de.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/de.lproj/Localizable.strings deleted file mode 100644 index 9e481861b..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/de.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Erfordert Aufmerksamkeit"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/es.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/es.lproj/Localizable.strings deleted file mode 100644 index edcf527f9..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/es.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Necesita Atención"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/fi.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/fi.lproj/Localizable.strings deleted file mode 100644 index a31876602..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/fi.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Tarvitsee huomiota"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/fr.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/fr.lproj/Localizable.strings deleted file mode 100644 index 86054aaeb..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/fr.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Demande votre attention"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/he.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/he.lproj/Localizable.strings deleted file mode 100644 index 9a5cce7ec..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/he.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Needs Attention"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/it.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/it.lproj/Localizable.strings deleted file mode 100644 index d1b43727b..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/it.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Esige Attenzione"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/ja.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/ja.lproj/Localizable.strings deleted file mode 100644 index 88ba410a6..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/ja.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "注意してください"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/nb.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/nb.lproj/Localizable.strings deleted file mode 100644 index d9faa7356..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/nb.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Trenger tilsyn"; - -/* Sensor state description for the valid state */ -"OK" = "Ok"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/nl.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/nl.lproj/Localizable.strings deleted file mode 100644 index 613f7e9b8..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/nl.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Aandacht Nodig"; - -/* Sensor state description for the valid state */ -"OK" = "Ok"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/pl.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/pl.lproj/Localizable.strings deleted file mode 100644 index a8cb5f7f8..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/pl.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Potrzebuje uwagi"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/pt-BR.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/pt-BR.lproj/Localizable.strings deleted file mode 100644 index 1c5755341..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Precisa de Atenção"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/ro.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/ro.lproj/Localizable.strings deleted file mode 100644 index 6780b4280..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/ro.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Necesită atenție"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/ru.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/ru.lproj/Localizable.strings deleted file mode 100644 index cb65b52d7..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/ru.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Требует внимания"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/sk.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/sk.lproj/Localizable.strings deleted file mode 100644 index b2a1c7f96..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/sk.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/sv.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/sv.lproj/Localizable.strings deleted file mode 100644 index 632534aca..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/sv.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Kräver uppmärksamhet"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/tr.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/tr.lproj/Localizable.strings deleted file mode 100644 index d43a9a973..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/tr.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "İlgilenmeniz gerekiyor"; - -/* Sensor state description for the valid state */ -"OK" = "Tamam"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/vi.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/vi.lproj/Localizable.strings deleted file mode 100644 index 1e679c068..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/vi.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "Dexcom Share"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "Cần chú ý"; - -/* Sensor state description for the valid state */ -"OK" = "OK"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClient/zh-Hans.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClient/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 257200d22..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClient/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,10 +0,0 @@ -/* The title of the Dexcom Share service - Title for the CGMManager option */ -"Dexcom Share" = "德康远程"; - -/* Sensor state description for the non-valid state */ -"Needs Attention" = "请注意"; - -/* Sensor state description for the valid state */ -"OK" = "好"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientPlugin/Info.plist b/Dependencies/dexcom-share-client-swift/ShareClientPlugin/Info.plist deleted file mode 100644 index 5a3446dde..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientPlugin/Info.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright © 2019 Mark Wilson. All rights reserved. - NSPrincipalClass - ShareClientPlugin - com.loopkit.Loop.CGMManagerDisplayName - Dexcom Share - com.loopkit.Loop.CGMManagerIdentifier - DexShareClient - - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientPlugin/ShareClientPlugin-Bridging-Header.h b/Dependencies/dexcom-share-client-swift/ShareClientPlugin/ShareClientPlugin-Bridging-Header.h deleted file mode 100644 index 1b2cb5d6d..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientPlugin/ShareClientPlugin-Bridging-Header.h +++ /dev/null @@ -1,4 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientPlugin/ShareClientPlugin.swift b/Dependencies/dexcom-share-client-swift/ShareClientPlugin/ShareClientPlugin.swift deleted file mode 100644 index cf5615970..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientPlugin/ShareClientPlugin.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// ShareClientPlugin.swift -// ShareClientPlugin -// -// Created by Nathaniel Hamming on 2019-12-19. -// Copyright © 2019 Mark Wilson. All rights reserved. -// - -import os.log -import LoopKitUI -import ShareClient -import ShareClientUI - -class ShareClientPlugin: NSObject, CGMManagerUIPlugin { - private let log = OSLog(category: "ShareClientPlugin") - - public var cgmManagerType: CGMManagerUI.Type? { - return ShareClientManager.self - } - - override init() { - super.init() - log.default("Instantiated") - } -} diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/Base.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/Base.lproj/Localizable.strings deleted file mode 100644 index da3f31f8f..000000000 Binary files a/Dependencies/dexcom-share-client-swift/ShareClientUI/Base.lproj/Localizable.strings and /dev/null differ diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/IdentifiableClass.swift b/Dependencies/dexcom-share-client-swift/ShareClientUI/IdentifiableClass.swift deleted file mode 100644 index 4f3c5f308..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/IdentifiableClass.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// IdentifiableClass.swift -// Naterade -// -// Created by Nathan Racklyeft on 5/22/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -protocol IdentifiableClass: AnyObject { - static var className: String { get } -} - - -extension IdentifiableClass { - static var className: String { - return NSStringFromClass(self).components(separatedBy: ".").last! - } -} - - -extension UITableViewCell: IdentifiableClass { } diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/Info.plist b/Dependencies/dexcom-share-client-swift/ShareClientUI/Info.plist deleted file mode 100644 index 8c75117c7..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.2 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareClientManager+UI.swift b/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareClientManager+UI.swift deleted file mode 100644 index 6545b5247..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareClientManager+UI.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// ShareClientManager+UI.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import SwiftUI -import LoopKit -import LoopKitUI -import HealthKit -import ShareClient - -extension ShareClientManager: CGMManagerUI { - public static var onboardingImage: UIImage? { - return nil - } - - public static func setupViewController(bluetoothProvider: BluetoothProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) -> SetupUIResult { - return .userInteractionRequired(ShareClientSetupViewController()) - } - - public func settingsViewController(bluetoothProvider: BluetoothProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) ->CGMManagerViewController { - let settings = ShareClientSettingsViewController(cgmManager: self, displayGlucoseUnitObservable: displayGlucoseUnitObservable, allowsDeletion: true) - let nav = CGMManagerSettingsNavigationViewController(rootViewController: settings) - return nav - } - - public var smallImage: UIImage? { - return nil - } - - // TODO Placeholder. - public var cgmStatusHighlight: DeviceStatusHighlight? { - return nil - } - - // TODO Placeholder. - public var cgmStatusBadge: DeviceStatusBadge? { - return nil - } - - // TODO Placeholder. - public var cgmLifecycleProgress: DeviceLifecycleProgress? { - return nil - } -} diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareClientSettingsViewController.swift b/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareClientSettingsViewController.swift deleted file mode 100644 index 269378bc0..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareClientSettingsViewController.swift +++ /dev/null @@ -1,227 +0,0 @@ -// -// ShareClientSettingsViewController.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import Combine -import HealthKit -import LoopKit -import LoopKitUI -import ShareClient - -public class ShareClientSettingsViewController: UITableViewController { - - public let cgmManager: ShareClientManager - - private let displayGlucoseUnitObservable: DisplayGlucoseUnitObservable - - private lazy var cancellables = Set() - - private var glucoseUnit: HKUnit { - displayGlucoseUnitObservable.displayGlucoseUnit - } - - public let allowsDeletion: Bool - - public init(cgmManager: ShareClientManager, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, allowsDeletion: Bool) { - self.cgmManager = cgmManager - self.displayGlucoseUnitObservable = displayGlucoseUnitObservable - self.allowsDeletion = allowsDeletion - - super.init(style: .grouped) - - displayGlucoseUnitObservable.$displayGlucoseUnit - .sink { [weak self] _ in self?.tableView.reloadData() } - .store(in: &cancellables) - } - - required public init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override public func viewDidLoad() { - super.viewDidLoad() - - title = cgmManager.localizedTitle - - tableView.rowHeight = UITableView.automaticDimension - tableView.estimatedRowHeight = 44 - - tableView.sectionHeaderHeight = UITableView.automaticDimension - tableView.estimatedSectionHeaderHeight = 55 - - tableView.register(SettingsTableViewCell.self, forCellReuseIdentifier: SettingsTableViewCell.className) - tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className) - - let button = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped(_:))) - self.navigationItem.setRightBarButton(button, animated: false) - } - - @objc func doneTapped(_ sender: Any) { - complete() - } - - private func complete() { - if let nav = navigationController as? SettingsNavigationViewController { - nav.notifyComplete() - } - } - - // MARK: - UITableViewDataSource - - private enum Section: Int, CaseIterable { - case authentication - case latestReading - case delete - } - - override public func numberOfSections(in tableView: UITableView) -> Int { - return allowsDeletion ? Section.allCases.count : Section.allCases.count - 1 - } - - private enum LatestReadingRow: Int, CaseIterable { - case glucose - case date - case trend - } - - override public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch Section(rawValue: section)! { - case .authentication: - return 1 - case .latestReading: - return LatestReadingRow.allCases.count - case .delete: - return 1 - } - } - - private lazy var glucoseFormatter: QuantityFormatter = { - let formatter = QuantityFormatter() - formatter.setPreferredNumberFormatter(for: glucoseUnit) - return formatter - }() - - private lazy var dateFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateStyle = .long - formatter.timeStyle = .long - formatter.doesRelativeDateFormatting = true - return formatter - }() - - public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch Section(rawValue: indexPath.section)! { - case .authentication: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) as! SettingsTableViewCell - - let service = cgmManager.shareService - - cell.textLabel?.text = LocalizedString("Credentials", comment: "Title of cell to set credentials") - cell.detailTextLabel?.text = service.username ?? SettingsTableViewCell.TapToSetString - cell.accessoryType = .disclosureIndicator - - return cell - case .latestReading: - let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) as! SettingsTableViewCell - let glucose = cgmManager.latestBackfill - - switch LatestReadingRow(rawValue: indexPath.row)! { - case .glucose: - cell.textLabel?.text = LocalizedString("Glucose", comment: "Title describing glucose value") - - if let quantity = glucose?.quantity, let formatted = glucoseFormatter.string(from: quantity, for: glucoseUnit) { - cell.detailTextLabel?.text = formatted - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - case .date: - cell.textLabel?.text = LocalizedString("Date", comment: "Title describing glucose date") - - if let date = glucose?.timestamp { - cell.detailTextLabel?.text = dateFormatter.string(from: date) - } else { - cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString - } - case .trend: - cell.textLabel?.text = LocalizedString("Trend", comment: "Title describing glucose trend") - - cell.detailTextLabel?.text = glucose?.trendType?.localizedDescription ?? SettingsTableViewCell.NoValueString - } - - return cell - case .delete: - let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell - - cell.textLabel?.text = LocalizedString("Delete CGM", comment: "Title text for the button to remove a CGM from Loop") - cell.textLabel?.textAlignment = .center - cell.tintColor = .delete - cell.isEnabled = true - return cell - } - } - - public override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - switch Section(rawValue: section)! { - case .authentication: - return nil - case .latestReading: - return LocalizedString("Latest Reading", comment: "Section title for latest glucose reading") - case .delete: - return nil - } - } - - public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - switch Section(rawValue: indexPath.section)! { - case .authentication: - let vc = AuthenticationViewController(authentication: cgmManager.shareService) - vc.authenticationObserver = { [weak self] (service) in - self?.cgmManager.shareService = service - - self?.tableView.reloadRows(at: [indexPath], with: .none) - } - - show(vc, sender: nil) - case .latestReading: - tableView.deselectRow(at: indexPath, animated: true) - case .delete: - let confirmVC = UIAlertController(cgmDeletionHandler: { - self.cgmManager.notifyDelegateOfDeletion { - DispatchQueue.main.async { - self.complete() - } - } - }) - - present(confirmVC, animated: true) { - tableView.deselectRow(at: indexPath, animated: true) - } - } - } -} - - -private extension UIAlertController { - convenience init(cgmDeletionHandler handler: @escaping () -> Void) { - self.init( - title: nil, - message: LocalizedString("Are you sure you want to delete this CGM?", comment: "Confirmation message for deleting a CGM"), - preferredStyle: .actionSheet - ) - - addAction(UIAlertAction( - title: LocalizedString("Delete CGM", comment: "Button title to delete CGM"), - style: .destructive, - handler: { (_) in - handler() - } - )) - - let cancel = LocalizedString("Cancel", comment: "The title of the cancel action in an action sheet") - addAction(UIAlertAction(title: cancel, style: .cancel, handler: nil)) - } -} diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareClientSetupViewController.swift b/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareClientSetupViewController.swift deleted file mode 100644 index e35b02b7f..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareClientSetupViewController.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// ShareClientSetupViewController.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit -import LoopKitUI -import ShareClient - - -class ShareClientSetupViewController: UINavigationController, CGMManagerOnboarding, CompletionNotifying { - weak var cgmManagerOnboardingDelegate: CGMManagerOnboardingDelegate? - weak var completionDelegate: CompletionDelegate? - - let cgmManager = ShareClientManager() - - init() { - let authVC = AuthenticationViewController(authentication: cgmManager.shareService) - - super.init(rootViewController: authVC) - - authVC.authenticationObserver = { [weak self] (service) in - self?.cgmManager.shareService = service - } - authVC.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancel)) - authVC.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(save)) - } - - override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { - super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - @objc private func cancel() { - completionDelegate?.completionNotifyingDidComplete(self) - } - - @objc private func save() { - cgmManagerOnboardingDelegate?.cgmManagerOnboarding(didCreateCGMManager: cgmManager) - cgmManagerOnboardingDelegate?.cgmManagerOnboarding(didOnboardCGMManager: cgmManager) - completionDelegate?.completionNotifyingDidComplete(self) - } -} diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareClientUI.h b/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareClientUI.h deleted file mode 100644 index 12a7a32d8..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareClientUI.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// ShareClientUI.h -// ShareClientUI -// -// Created by Nathan Racklyeft on 7/29/18. -// Copyright © 2018 Mark Wilson. All rights reserved. -// - -#import - -//! Project version number for ShareClientUI. -FOUNDATION_EXPORT double ShareClientUIVersionNumber; - -//! Project version string for ShareClientUI. -FOUNDATION_EXPORT const unsigned char ShareClientUIVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareService+UI.swift b/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareService+UI.swift deleted file mode 100644 index 63c757a85..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/ShareService+UI.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// ShareService+UI.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import LoopKitUI -import ShareClient - - -extension ShareService: ServiceAuthenticationUI { - public var credentialFormFieldHelperMessage: String? { - return nil - } - - public var credentialFormFields: [ServiceCredential] { - return [ - ServiceCredential( - title: LocalizedString("Username", comment: "The title of the Dexcom share username credential"), - isSecret: false, - keyboardType: .asciiCapable - ), - ServiceCredential( - title: LocalizedString("Password", comment: "The title of the Dexcom share password credential"), - isSecret: true, - keyboardType: .asciiCapable - ), - ServiceCredential( - title: LocalizedString("Server", comment: "The title of the Dexcom share server URL credential"), - isSecret: false, - options: [ - (title: LocalizedString("US", comment: "U.S. share server option title"), - value: KnownShareServers.US.rawValue), - (title: LocalizedString("Outside US", comment: "Outside US share server option title"), - value: KnownShareServers.NON_US.rawValue) - - ] - ) - ] - } -} diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/UIColor.swift b/Dependencies/dexcom-share-client-swift/ShareClientUI/UIColor.swift deleted file mode 100644 index 0095c6b71..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/UIColor.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// UIColor.swift -// LoopKitUI -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - - -extension UIColor { - static let delete = UIColor.higRed() -} - - -// MARK: - HIG colors -// See: https://developer.apple.com/ios/human-interface-guidelines/visual-design/color/ -extension UIColor { - private static func higRed() -> UIColor { - return UIColor(red: 1, green: 59 / 255, blue: 48 / 255, alpha: 1) - } -} diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/ar.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/ar.lproj/Localizable.strings deleted file mode 100644 index 445d89029..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/ar.lproj/Localizable.strings +++ /dev/null @@ -1,13 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "هل أنت متأكد أنك تريد حذف هذا CGM؟"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "إلغاء"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "حذف CGM"; - -/* Title describing glucose value */ -"Glucose" = "قراءات السكر"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/cs.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/cs.lproj/Localizable.strings deleted file mode 100644 index 1ca151913..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/cs.lproj/Localizable.strings +++ /dev/null @@ -1,6 +0,0 @@ -/* The title of the cancel action in an action sheet */ -"Cancel" = "Zrušit"; - -/* Title describing glucose value */ -"Glucose" = "Glukóza"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/da.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/da.lproj/Localizable.strings deleted file mode 100644 index c64e350c8..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/da.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Er du sikker på, at du vil slette denne CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuller"; - -/* Title of cell to set credentials */ -"Credentials" = "Legitimationsoplysninger"; - -/* Title describing glucose date */ -"Date" = "Dato"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Slet CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glukose"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Seneste aflæsning"; - -/* Outside US share server option title */ -"Outside US" = "Uden for USA"; - -/* The title of the Dexcom share password credential */ -"Password" = "Adgangskode"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Server"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* U.S. share server option title */ -"US" = "USA"; - -/* The title of the Dexcom share username credential */ -"Username" = "Brugernavn"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/de.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/de.lproj/Localizable.strings deleted file mode 100644 index 1e5ec0a65..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/de.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Sind Sie sicher, dass Sie dieses CGM löschen wollen?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Abbrechen"; - -/* Title of cell to set credentials */ -"Credentials" = "Logindaten"; - -/* Title describing glucose date */ -"Date" = "Datum"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "CGM löschen"; - -/* Title describing glucose value */ -"Glucose" = "Blutzucker"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Letzter Wert"; - -/* Outside US share server option title */ -"Outside US" = "Außerhalb der USA"; - -/* The title of the Dexcom share password credential */ -"Password" = "Passwort"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Server"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* U.S. share server option title */ -"US" = "USA"; - -/* The title of the Dexcom share username credential */ -"Username" = "Nutzername"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/es.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/es.lproj/Localizable.strings deleted file mode 100644 index 8ac7014f5..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/es.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "¿Está seguro de que quiere eliminar este MCG?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancelar"; - -/* Title of cell to set credentials */ -"Credentials" = "Credenciales"; - -/* Title describing glucose date */ -"Date" = "Fecha"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Eliminar MCG"; - -/* Title describing glucose value */ -"Glucose" = "Glucosa"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Dato más reciente"; - -/* Outside US share server option title */ -"Outside US" = "Fuera de EEUU"; - -/* The title of the Dexcom share password credential */ -"Password" = "Contraseña"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Servidor"; - -/* Title describing glucose trend */ -"Trend" = "Tendencia"; - -/* U.S. share server option title */ -"US" = "EEUU"; - -/* The title of the Dexcom share username credential */ -"Username" = "Usuario"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/fi.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/fi.lproj/Localizable.strings deleted file mode 100644 index 849076707..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/fi.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Haluatko varmasti poistaa CGM:n?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Kumoa"; - -/* Title of cell to set credentials */ -"Credentials" = "Tunnukset"; - -/* Title describing glucose date */ -"Date" = "Aika"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Poista CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glukoosi"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Viimeisin lukema"; - -/* Outside US share server option title */ -"Outside US" = "USA:n ulkopuolella"; - -/* The title of the Dexcom share password credential */ -"Password" = "Salasana"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Palvelin"; - -/* Title describing glucose trend */ -"Trend" = "Suunta"; - -/* U.S. share server option title */ -"US" = "USA"; - -/* The title of the Dexcom share username credential */ -"Username" = "Käyttäjänimi"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/fr.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/fr.lproj/Localizable.strings deleted file mode 100644 index 5af84a77d..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/fr.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Voulez-vous vraiment supprimer ce CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuler"; - -/* Title of cell to set credentials */ -"Credentials" = "Identifiant"; - -/* Title describing glucose date */ -"Date" = "Date"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Effacer le CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glycémie"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Dernière mesure"; - -/* Outside US share server option title */ -"Outside US" = "À l'extérieur des É.-U."; - -/* The title of the Dexcom share password credential */ -"Password" = "Mot de passe"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Serveur"; - -/* Title describing glucose trend */ -"Trend" = "Tendance"; - -/* U.S. share server option title */ -"US" = "É.-U."; - -/* The title of the Dexcom share username credential */ -"Username" = "Nom d'utilisateur"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/he.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/he.lproj/Localizable.strings deleted file mode 100644 index 1c6e68dbe..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/he.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancel"; - -/* Title of cell to set credentials */ -"Credentials" = "Credentials"; - -/* Title describing glucose date */ -"Date" = "Date"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Delete CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glucose"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Latest Reading"; - -/* Outside US share server option title */ -"Outside US" = "Outside US"; - -/* The title of the Dexcom share password credential */ -"Password" = "Password"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Server"; - -/* Title describing glucose trend */ -"Trend" = "מגמה"; - -/* U.S. share server option title */ -"US" = "US"; - -/* The title of the Dexcom share username credential */ -"Username" = "Username"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/hi.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/hi.lproj/Localizable.strings deleted file mode 100644 index 04348dff5..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/hi.lproj/Localizable.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* The title of the cancel action in an action sheet */ -"Cancel" = "निरस्त"; - -/* Title describing glucose value */ -"Glucose" = "शुगर"; - -/* Title describing glucose trend */ -"Trend" = "ट्रेंड"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/it.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/it.lproj/Localizable.strings deleted file mode 100644 index dba367fae..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/it.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Sei sicuro di voler eliminare questo CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annulla"; - -/* Title of cell to set credentials */ -"Credentials" = "Credenziali"; - -/* Title describing glucose date */ -"Date" = "Data"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Elimina CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glicemia"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Ultima lettura"; - -/* Outside US share server option title */ -"Outside US" = "Fuori USA"; - -/* The title of the Dexcom share password credential */ -"Password" = "Parola d'ordine"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Server"; - -/* Title describing glucose trend */ -"Trend" = "Tendenza"; - -/* U.S. share server option title */ -"US" = "USA"; - -/* The title of the Dexcom share username credential */ -"Username" = "Nome Utente"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/ja.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/ja.lproj/Localizable.strings deleted file mode 100644 index 64860f593..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/ja.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "このCGMを削除しますか?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "キャンセル"; - -/* Title of cell to set credentials */ -"Credentials" = "証明"; - -/* Title describing glucose date */ -"Date" = "日付"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "CGMを削除"; - -/* Title describing glucose value */ -"Glucose" = "血糖値"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "最新の読み取り"; - -/* Outside US share server option title */ -"Outside US" = "米国外"; - -/* The title of the Dexcom share password credential */ -"Password" = "パスワード"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "サーバ"; - -/* Title describing glucose trend */ -"Trend" = "トレンド"; - -/* U.S. share server option title */ -"US" = "米国"; - -/* The title of the Dexcom share username credential */ -"Username" = "ユーザー名"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/nb.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/nb.lproj/Localizable.strings deleted file mode 100644 index 186b81338..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/nb.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Er du sikker på at du vil slette CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Avbryt"; - -/* Title of cell to set credentials */ -"Credentials" = "Påloggingsinformasjon"; - -/* Title describing glucose date */ -"Date" = "Dato"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Slett CGM"; - -/* Title describing glucose value */ -"Glucose" = "Blodsukker"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Siste måling"; - -/* Outside US share server option title */ -"Outside US" = "Utenfor USA"; - -/* The title of the Dexcom share password credential */ -"Password" = "Passord"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Tjener"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* U.S. share server option title */ -"US" = "USA"; - -/* The title of the Dexcom share username credential */ -"Username" = "Brukernavn"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/nl.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/nl.lproj/Localizable.strings deleted file mode 100644 index 941e893bf..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/nl.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Weet je zeker dat je deze CGM wilt verwijderen"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Annuleer"; - -/* Title of cell to set credentials */ -"Credentials" = "Toegangsgegevens"; - -/* Title describing glucose date */ -"Date" = "Datum"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Verwijder CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glucose"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Laatste Meting"; - -/* Outside US share server option title */ -"Outside US" = "Buiten de VS"; - -/* The title of the Dexcom share password credential */ -"Password" = "Wachtwoord"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Server"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* U.S. share server option title */ -"US" = "VS"; - -/* The title of the Dexcom share username credential */ -"Username" = "Gebruikersnaam"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/pl.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/pl.lproj/Localizable.strings deleted file mode 100644 index 9161c79ee..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/pl.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Czy na pewno chcesz usunąć ten CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Anuluj"; - -/* Title of cell to set credentials */ -"Credentials" = "Dane uwierzytelniające"; - -/* Title describing glucose date */ -"Date" = "Data"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Usuń CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glukoza"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Ostatni odczyt"; - -/* Outside US share server option title */ -"Outside US" = "Poza USA"; - -/* The title of the Dexcom share password credential */ -"Password" = "Contraseña"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Serwer"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* U.S. share server option title */ -"US" = "USA"; - -/* The title of the Dexcom share username credential */ -"Username" = "Nazwa użytkownika"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/pt-BR.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/pt-BR.lproj/Localizable.strings deleted file mode 100644 index 348e8d4d0..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Você está certo que quer remover este CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Cancelar"; - -/* Title of cell to set credentials */ -"Credentials" = "Credenciais"; - -/* Title describing glucose date */ -"Date" = "Data"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Remover CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glicose"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Leitura mais Recente"; - -/* Outside US share server option title */ -"Outside US" = "Fora dos EUA"; - -/* The title of the Dexcom share password credential */ -"Password" = "Senha"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Servidor"; - -/* Title describing glucose trend */ -"Trend" = "Tendência"; - -/* U.S. share server option title */ -"US" = "US"; - -/* The title of the Dexcom share username credential */ -"Username" = "Usuário"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/ro.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/ro.lproj/Localizable.strings deleted file mode 100644 index aac055afd..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/ro.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Sunteți sigur că doriți să ștergeți acest CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Renunță"; - -/* Title of cell to set credentials */ -"Credentials" = "Autentificare"; - -/* Title describing glucose date */ -"Date" = "Data"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Ștergeți CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glucoza"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Ultima citire"; - -/* Outside US share server option title */ -"Outside US" = "În afara SUA"; - -/* The title of the Dexcom share password credential */ -"Password" = "Parola"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Server"; - -/* Title describing glucose trend */ -"Trend" = "Tendinţă"; - -/* U.S. share server option title */ -"US" = "SUA"; - -/* The title of the Dexcom share username credential */ -"Username" = "Nume de utilizator"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/ru.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/ru.lproj/Localizable.strings deleted file mode 100644 index 5d74f1535..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/ru.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Вы уверены, что хотите удалить этот CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Отмена"; - -/* Title of cell to set credentials */ -"Credentials" = "Учетные данные"; - -/* Title describing glucose date */ -"Date" = "Дата"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Удалить CGM"; - -/* Title describing glucose value */ -"Glucose" = "Глюкоза"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Последние данные"; - -/* Outside US share server option title */ -"Outside US" = "за пределами США"; - -/* The title of the Dexcom share password credential */ -"Password" = "Пароль"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Сервер"; - -/* Title describing glucose trend */ -"Trend" = "Тенденция"; - -/* U.S. share server option title */ -"US" = "США"; - -/* The title of the Dexcom share username credential */ -"Username" = "Имя пользователя"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/sk.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/sk.lproj/Localizable.strings deleted file mode 100644 index ad6dd8e11..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/sk.lproj/Localizable.strings +++ /dev/null @@ -1,37 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Naozaj chcete odstrániť toto CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Zrušiť"; - -/* Title describing glucose date */ -"Date" = "Dátum"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Odstrániť CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glykémia"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Posledné čítanie"; - -/* Outside US share server option title */ -"Outside US" = "Mimo USA"; - -/* The title of the Dexcom share password credential */ -"Password" = "Heslo"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Server"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* U.S. share server option title */ -"US" = "USA"; - -/* The title of the Dexcom share username credential */ -"Username" = "Meno používateľa"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/sv.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/sv.lproj/Localizable.strings deleted file mode 100644 index 04bf3ec15..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/sv.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Är du säker på att du vill radera denna CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Avbryt"; - -/* Title of cell to set credentials */ -"Credentials" = "Inloggningsuppgifter"; - -/* Title describing glucose date */ -"Date" = "Tid"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Radera CGM"; - -/* Title describing glucose value */ -"Glucose" = "Glukos"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Senaste avläsning"; - -/* Outside US share server option title */ -"Outside US" = "Utanför USA"; - -/* The title of the Dexcom share password credential */ -"Password" = "Lösenord"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Server"; - -/* Title describing glucose trend */ -"Trend" = "Trend"; - -/* U.S. share server option title */ -"US" = "USA"; - -/* The title of the Dexcom share username credential */ -"Username" = "Användarnamn"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/tr.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/tr.lproj/Localizable.strings deleted file mode 100644 index 7a46824f7..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/tr.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Bu CGM'i silmek istediğinizden emin misiniz?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "İptal"; - -/* Title of cell to set credentials */ -"Credentials" = "Kimlik bilgileri"; - -/* Title describing glucose date */ -"Date" = "Tarih"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "CGM Sil"; - -/* Title describing glucose value */ -"Glucose" = "Kan şekeri"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Son Okuma"; - -/* Outside US share server option title */ -"Outside US" = "ABD dışında"; - -/* The title of the Dexcom share password credential */ -"Password" = "Parola"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Sunucu"; - -/* Title describing glucose trend */ -"Trend" = "Eğilim"; - -/* U.S. share server option title */ -"US" = "ABD"; - -/* The title of the Dexcom share username credential */ -"Username" = "Kullanıcı adı"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/vi.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/vi.lproj/Localizable.strings deleted file mode 100644 index 242079bf4..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/vi.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Bạn có chắc sẽ xóa CGM này?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "Hủy bỏ"; - -/* Title of cell to set credentials */ -"Credentials" = "Thông tin xác thực"; - -/* Title describing glucose date */ -"Date" = "Ngày"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "Xóa CGM"; - -/* Title describing glucose value */ -"Glucose" = "Đường huyết"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "Kết quả đọc mới nhất"; - -/* Outside US share server option title */ -"Outside US" = "Ngoài lãnh thổ Hoa Kỳ"; - -/* The title of the Dexcom share password credential */ -"Password" = "Mật khẩu"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "Máy chủ"; - -/* Title describing glucose trend */ -"Trend" = "Xu hướng"; - -/* U.S. share server option title */ -"US" = "Hoa Kỳ"; - -/* The title of the Dexcom share username credential */ -"Username" = "Tên tài khoản"; - diff --git a/Dependencies/dexcom-share-client-swift/ShareClientUI/zh-Hans.lproj/Localizable.strings b/Dependencies/dexcom-share-client-swift/ShareClientUI/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index cd0fdbbc3..000000000 --- a/Dependencies/dexcom-share-client-swift/ShareClientUI/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,40 +0,0 @@ -/* Confirmation message for deleting a CGM */ -"Are you sure you want to delete this CGM?" = "Are you sure you want to delete this CGM?"; - -/* The title of the cancel action in an action sheet */ -"Cancel" = "取消"; - -/* Title of cell to set credentials */ -"Credentials" = "密钥"; - -/* Title describing glucose date */ -"Date" = "日期"; - -/* Button title to delete CGM - Title text for the button to remove a CGM from Loop */ -"Delete CGM" = "趋势"; - -/* Title describing glucose value */ -"Glucose" = "葡萄糖"; - -/* Section title for latest glucose reading */ -"Latest Reading" = "最新血糖值"; - -/* Outside US share server option title */ -"Outside US" = "非美国地区"; - -/* The title of the Dexcom share password credential */ -"Password" = "密码"; - -/* The title of the Dexcom share server URL credential */ -"Server" = "服务器"; - -/* Title describing glucose trend */ -"Trend" = "趋势"; - -/* U.S. share server option title */ -"US" = "美国"; - -/* The title of the Dexcom share username credential */ -"Username" = "用户名"; - diff --git a/Dependencies/rileylink_ios/.gitignore b/Dependencies/rileylink_ios/.gitignore deleted file mode 100644 index 72c7458b7..000000000 --- a/Dependencies/rileylink_ios/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -# Xcode -# -build/ -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata -*.xccheckout -*.moved-aside -DerivedData -*.hmap -*.ipa -*.xcuserstate -*.xcscmblueprint -.DS_Store -*.log - -# CocoaPods -# -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control -# -# Pods/ - -Carthage/ -.gitmodules diff --git a/Dependencies/rileylink_ios/.travis.yml b/Dependencies/rileylink_ios/.travis.yml deleted file mode 100644 index eeea17749..000000000 --- a/Dependencies/rileylink_ios/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: objective-c -osx_image: xcode12.2 - -cache: - directories: - - Carthage - -before_script: - - ./Scripts/carthage.sh bootstrap --cache-builds - -script: - - set -o pipefail && xcodebuild -project RileyLink.xcodeproj -scheme Shared build -destination 'name=iPhone 8' test | xcpretty diff --git a/Dependencies/rileylink_ios/Common/CaseCountable.swift b/Dependencies/rileylink_ios/Common/CaseCountable.swift deleted file mode 100644 index 05dbbe6fd..000000000 --- a/Dependencies/rileylink_ios/Common/CaseCountable.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// CaseCountable.swift -// RileyLink -// -// Created by Pete Schwamb on 12/30/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -import Foundation - -protocol CaseCountable: RawRepresentable {} - -extension CaseCountable where RawValue == Int { - static var count: Int { - var i: Int = 0 - while let new = Self(rawValue: i) { i = new.rawValue.advanced(by: 1) } - return i - } -} diff --git a/Dependencies/rileylink_ios/Common/Comparable.swift b/Dependencies/rileylink_ios/Common/Comparable.swift deleted file mode 100644 index 70e8121ad..000000000 --- a/Dependencies/rileylink_ios/Common/Comparable.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// Comparable.swift -// RileyLink -// -// Created by Pete Schwamb on 2/17/19. -// Copyright © 2019 Pete Schwamb. All rights reserved. -// - -import Foundation - -extension Comparable { - func clamped(to range: ClosedRange) -> Self { - if self < range.lowerBound { - return range.lowerBound - } else if self > range.upperBound { - return range.upperBound - } else { - return self - } - } -} diff --git a/Dependencies/rileylink_ios/Common/Data.swift b/Dependencies/rileylink_ios/Common/Data.swift deleted file mode 100644 index 3bcbbc2ee..000000000 --- a/Dependencies/rileylink_ios/Common/Data.swift +++ /dev/null @@ -1,90 +0,0 @@ -// -// NSData.swift -// Naterade -// -// Created by Nathan Racklyeft on 9/2/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension Data { - private func toDefaultEndian(_: T.Type) -> T { - return self.withUnsafeBytes({ (rawBufferPointer: UnsafeRawBufferPointer) -> T in - let bufferPointer = rawBufferPointer.bindMemory(to: T.self) - guard let pointer = bufferPointer.baseAddress else { - return 0 - } - return T(pointer.pointee) - }) - } - - func to(_ type: T.Type) -> T { - return T(littleEndian: toDefaultEndian(type)) - } - - func toBigEndian(_ type: T.Type) -> T { - return T(bigEndian: toDefaultEndian(type)) - } - - mutating func append(_ newElement: T) { - var element = newElement.littleEndian - append(Data(bytes: &element, count: element.bitWidth / 8)) - } - - mutating func appendBigEndian(_ newElement: T) { - var element = newElement.bigEndian - append(Data(bytes: &element, count: element.bitWidth / 8)) - } - - init(_ value: T) { - var value = value.littleEndian - self.init(bytes: &value, count: value.bitWidth / 8) - } - - init(bigEndian value: T) { - var value = value.bigEndian - self.init(bytes: &value, count: value.bitWidth / 8) - } -} - -// String conversion methods, adapted from https://stackoverflow.com/questions/40276322/hex-binary-string-conversion-in-swift/40278391#40278391 -extension Data { - init?(hexadecimalString: String) { - self.init(capacity: hexadecimalString.utf16.count / 2) - - // Convert 0 ... 9, a ... f, A ...F to their decimal value, - // return nil for all other input characters - func decodeNibble(u: UInt16) -> UInt8? { - switch u { - case 0x30 ... 0x39: // '0'-'9' - return UInt8(u - 0x30) - case 0x41 ... 0x46: // 'A'-'F' - return UInt8(u - 0x41 + 10) // 10 since 'A' is 10, not 0 - case 0x61 ... 0x66: // 'a'-'f' - return UInt8(u - 0x61 + 10) // 10 since 'a' is 10, not 0 - default: - return nil - } - } - - var even = true - var byte: UInt8 = 0 - for c in hexadecimalString.utf16 { - guard let val = decodeNibble(u: c) else { return nil } - if even { - byte = val << 4 - } else { - byte += val - self.append(byte) - } - even = !even - } - guard even else { return nil } - } - - var hexadecimalString: String { - return map { String(format: "%02hhx", $0) }.joined() - } -} diff --git a/Dependencies/rileylink_ios/Common/HKUnit.swift b/Dependencies/rileylink_ios/Common/HKUnit.swift deleted file mode 100644 index 1cae44b1b..000000000 --- a/Dependencies/rileylink_ios/Common/HKUnit.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// HKUnit.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/17/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import HealthKit - - -extension HKUnit { - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: .literUnit(with: .deci)) - }() - - static let millimolesPerLiter: HKUnit = { - return HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: .liter()) - }() - - static let internationalUnitsPerHour: HKUnit = { - return HKUnit.internationalUnit().unitDivided(by: .hour()) - }() - - var foundationUnit: Unit? { - if self == HKUnit.milligramsPerDeciliter { - return UnitConcentrationMass.milligramsPerDeciliter - } - - if self == HKUnit.millimolesPerLiter { - return UnitConcentrationMass.millimolesPerLiter(withGramsPerMole: HKUnitMolarMassBloodGlucose) - } - - if self == HKUnit.gram() { - return UnitMass.grams - } - - return nil - } -} diff --git a/Dependencies/rileylink_ios/Common/IdentifiableClass.swift b/Dependencies/rileylink_ios/Common/IdentifiableClass.swift deleted file mode 100644 index d0bf7f297..000000000 --- a/Dependencies/rileylink_ios/Common/IdentifiableClass.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// IdentifiableClass.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -protocol IdentifiableClass: AnyObject { - static var className: String { get } -} - - -extension IdentifiableClass { - static var className: String { - return NSStringFromClass(self).components(separatedBy: ".").last! - } -} diff --git a/Dependencies/rileylink_ios/Common/LocalizedString.swift b/Dependencies/rileylink_ios/Common/LocalizedString.swift deleted file mode 100644 index e0376951c..000000000 --- a/Dependencies/rileylink_ios/Common/LocalizedString.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// LocalizedString.swift -// RileyLink -// -// Created by Kathryn DiSimone on 8/15/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -private class FrameworkBundle { - static let main = Bundle(for: FrameworkBundle.self) -} - -func LocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { - if let value = value { - return NSLocalizedString(key, tableName: tableName, bundle: FrameworkBundle.main, value: value, comment: comment) - } else { - return NSLocalizedString(key, tableName: tableName, bundle: FrameworkBundle.main, comment: comment) - } -} diff --git a/Dependencies/rileylink_ios/Common/NibLoadable.swift b/Dependencies/rileylink_ios/Common/NibLoadable.swift deleted file mode 100644 index 24cf83324..000000000 --- a/Dependencies/rileylink_ios/Common/NibLoadable.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// NibLoadable.swift -// -// Created by Nate Racklyeft on 7/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -protocol NibLoadable: IdentifiableClass { - static func nib() -> UINib -} - - -extension NibLoadable { - static func nib() -> UINib { - return UINib(nibName: className, bundle: Bundle(for: self)) - } -} diff --git a/Dependencies/rileylink_ios/Common/NumberFormatter.swift b/Dependencies/rileylink_ios/Common/NumberFormatter.swift deleted file mode 100644 index b7b855645..000000000 --- a/Dependencies/rileylink_ios/Common/NumberFormatter.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// NumberFormatter.swift -// RileyLink -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - -extension NumberFormatter { - func decibleString(from decibles: Int?) -> String? { - if let decibles = decibles, let formatted = string(from: NSNumber(value: decibles)) { - return String(format: LocalizedString("%@ dB", comment: "Unit format string for an RSSI value in decibles"), formatted) - } else { - return nil - } - } - - func percentString(from percent: Int?) -> String? { - if let percent = percent, let formatted = string(from: NSNumber(value: percent)) { - return String(format: LocalizedString("%@%%", comment: "Unit format string for an value in percent"), formatted) - } else { - return nil - } - } - - func string(from number: Double) -> String? { - return string(from: NSNumber(value: number)) - } -} diff --git a/Dependencies/rileylink_ios/Common/OSLog.swift b/Dependencies/rileylink_ios/Common/OSLog.swift deleted file mode 100644 index 9b7a7c900..000000000 --- a/Dependencies/rileylink_ios/Common/OSLog.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// OSLog.swift -// Loop -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import os.log - - -extension OSLog { - convenience init(category: String) { - self.init(subsystem: "com.ps2.rileylink", category: category) - } - - func debug(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .debug, args) - } - - func info(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .info, args) - } - - func `default`(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .default, args) - } - - func error(_ message: StaticString, _ args: CVarArg...) { - log(message, type: .error, args) - } - - private func log(_ message: StaticString, type: OSLogType, _ args: [CVarArg]) { - switch args.count { - case 0: - os_log(message, log: self, type: type) - case 1: - os_log(message, log: self, type: type, args[0]) - case 2: - os_log(message, log: self, type: type, args[0], args[1]) - case 3: - os_log(message, log: self, type: type, args[0], args[1], args[2]) - case 4: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3]) - case 5: - os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4]) - default: - os_log(message, log: self, type: type, args) - } - } -} diff --git a/Dependencies/rileylink_ios/Common/TimeInterval.swift b/Dependencies/rileylink_ios/Common/TimeInterval.swift deleted file mode 100644 index 02c61c0b4..000000000 --- a/Dependencies/rileylink_ios/Common/TimeInterval.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// NSTimeInterval.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/9/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -extension TimeInterval { - - static func days(_ days: Double) -> TimeInterval { - return self.init(days: days) - } - - static func hours(_ hours: Double) -> TimeInterval { - return self.init(hours: hours) - } - - static func minutes(_ minutes: Int) -> TimeInterval { - return self.init(minutes: Double(minutes)) - } - - static func minutes(_ minutes: Double) -> TimeInterval { - return self.init(minutes: minutes) - } - - static func seconds(_ seconds: Double) -> TimeInterval { - return self.init(seconds) - } - - static func milliseconds(_ milliseconds: Double) -> TimeInterval { - return self.init(milliseconds / 1000) - } - - init(days: Double) { - self.init(hours: days * 24) - } - - init(hours: Double) { - self.init(minutes: hours * 60) - } - - init(minutes: Double) { - self.init(minutes * 60) - } - - init(seconds: Double) { - self.init(seconds) - } - - init(milliseconds: Double) { - self.init(milliseconds / 1000) - } - - var milliseconds: Double { - return self * 1000 - } - - init(hundredthsOfMilliseconds: Double) { - self.init(hundredthsOfMilliseconds / 100000) - } - - var hundredthsOfMilliseconds: Double { - return self * 100000 - } - - var minutes: Double { - return self / 60.0 - } - - var hours: Double { - return minutes / 60.0 - } - - var days: Double { - return hours / 24.0 - } - -} diff --git a/Dependencies/rileylink_ios/Common/TimeZone.swift b/Dependencies/rileylink_ios/Common/TimeZone.swift deleted file mode 100644 index 4dcf778a7..000000000 --- a/Dependencies/rileylink_ios/Common/TimeZone.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// TimeZone.swift -// RileyLink -// -// Created by Nate Racklyeft on 10/2/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -import Foundation - -extension TimeZone { - static var currentFixed: TimeZone { - return TimeZone(secondsFromGMT: TimeZone.current.secondsFromGMT())! - } - - var fixed: TimeZone { - return TimeZone(secondsFromGMT: secondsFromGMT())! - } - - /// This only works for fixed utc offset timezones - func scheduleOffset(forDate date: Date) -> TimeInterval { - var calendar = Calendar.current - calendar.timeZone = self - let components = calendar.dateComponents([.day , .month, .year], from: date) - guard let startOfSchedule = calendar.date(from: components) else { - fatalError("invalid date") - } - return date.timeIntervalSince(startOfSchedule) - } -} diff --git a/Dependencies/rileylink_ios/Common/UIColor.swift b/Dependencies/rileylink_ios/Common/UIColor.swift deleted file mode 100644 index 5049cf18d..000000000 --- a/Dependencies/rileylink_ios/Common/UIColor.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// UIColor.swift -// Naterade -// -// Created by Nathan Racklyeft on 1/23/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -extension UIColor { - @nonobjc static var tintColor: UIColor? = nil - - @nonobjc static let secondaryLabelColor = UIColor(red: 142 / 255, green: 142 / 255, blue: 147 / 255, alpha: 1) - - @nonobjc static let gridColor = UIColor(white: 193 / 255, alpha: 1) - - @nonobjc static let glucoseTintColor = UIColor.HIGTealBlueColor() - - @nonobjc static let IOBTintColor = UIColor.HIGOrangeColor() - - @nonobjc static let COBTintColor = UIColor.HIGYellowColor() - - @nonobjc static let doseTintColor = UIColor.HIGGreenColor() - - @nonobjc static let freshColor = UIColor.HIGGreenColor() - - @nonobjc static let agingColor = UIColor.HIGYellowColor() - - @nonobjc static let staleColor = UIColor.HIGRedColor() - - @nonobjc static let unknownColor = UIColor.HIGGrayColor().withAlphaComponent(0.5) - - @nonobjc static let deleteColor = UIColor.HIGRedColor() - - // MARK: - HIG colors - // See: https://developer.apple.com/ios/human-interface-guidelines/visual-design/color/ - - private static func HIGTealBlueColor() -> UIColor { - return UIColor(red: 90 / 255, green: 200 / 255, blue: 250 / 255, alpha: 1) - } - - private static func HIGYellowColor() -> UIColor { - return UIColor(red: 1, green: 204 / 255, blue: 0 / 255, alpha: 1) - } - - private static func HIGOrangeColor() -> UIColor { - return UIColor(red: 1, green: 149 / 255, blue: 0 / 255, alpha: 1) - } - - private static func HIGPinkColor() -> UIColor { - return UIColor(red: 1, green: 45 / 255, blue: 85 / 255, alpha: 1) - } - - private static func HIGBlueColor() -> UIColor { - return UIColor(red: 0, green: 122 / 255, blue: 1, alpha: 1) - } - - private static func HIGGreenColor() -> UIColor { - return UIColor(red: 76 / 255, green: 217 / 255, blue: 100 / 255, alpha: 1) - } - - private static func HIGRedColor() -> UIColor { - return UIColor(red: 1, green: 59 / 255, blue: 48 / 255, alpha: 1) - } - - private static func HIGPurpleColor() -> UIColor { - return UIColor(red: 88 / 255, green: 86 / 255, blue: 214 / 255, alpha: 1) - } - - private static func HIGGrayColor() -> UIColor { - return UIColor(red: 142 / 255, green: 143 / 255, blue: 147 / 255, alpha: 1) - } - -} diff --git a/Dependencies/rileylink_ios/Images/errors_when_building.png b/Dependencies/rileylink_ios/Images/errors_when_building.png deleted file mode 100644 index f3f0b7bb4..000000000 Binary files a/Dependencies/rileylink_ios/Images/errors_when_building.png and /dev/null differ diff --git a/Dependencies/rileylink_ios/Images/rileylink_ios_omnipod_status.png b/Dependencies/rileylink_ios/Images/rileylink_ios_omnipod_status.png deleted file mode 100644 index 249532600..000000000 Binary files a/Dependencies/rileylink_ios/Images/rileylink_ios_omnipod_status.png and /dev/null differ diff --git a/Dependencies/rileylink_ios/Images/rileylink_ios_paired_omnipod.png b/Dependencies/rileylink_ios/Images/rileylink_ios_paired_omnipod.png deleted file mode 100644 index 6e9ae514c..000000000 Binary files a/Dependencies/rileylink_ios/Images/rileylink_ios_paired_omnipod.png and /dev/null differ diff --git a/Dependencies/rileylink_ios/Images/rileylink_ios_setup.PNG b/Dependencies/rileylink_ios/Images/rileylink_ios_setup.PNG deleted file mode 100644 index b7a39de14..000000000 Binary files a/Dependencies/rileylink_ios/Images/rileylink_ios_setup.PNG and /dev/null differ diff --git a/Dependencies/rileylink_ios/LICENSE b/Dependencies/rileylink_ios/LICENSE deleted file mode 100644 index 11cdf3931..000000000 --- a/Dependencies/rileylink_ios/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Pete Schwamb - -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/Dependencies/rileylink_ios/README.md b/Dependencies/rileylink_ios/README.md deleted file mode 100644 index aa9fb215d..000000000 --- a/Dependencies/rileylink_ios/README.md +++ /dev/null @@ -1,84 +0,0 @@ -# RileyLink iOS App - -[![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://loop.zulipchat.com) [![Build Status](https://travis-ci.org/ps2/rileylink_ios.svg?branch=master)](https://travis-ci.org/ps2/rileylink_ios) - -The main purpose of the RileyLink iOS App is for developers to test and build the device commands. The RileyLink iOS app connects to a [RileyLink](https://github.com/ps2/rileylink) via Bluetooth Low Energy (BLE, or Bluetooth Smart) - -## Features -* Communicate with specific Medtronic Pumps dating before 2012. Read the [Loop documentation](https://loopkit.github.io/loopdocs/setup/requirements/pump/) for more information about which pumps are working. -* Communicate with the OmniPod. - -## How to contibute -#### Test edge cases -Try to test as many use cases as possible by using the test command to send the command to the Pod. -The test command line can be inserted here. It will send the command by using the test command button in the app: -https://github.com/ps2/rileylink_ios/blob/omnikit/OmniKit/PodCommsSession.swift#L133 - -#### Create issues for failing test cases -If there is an error, create an Issue here https://github.com/ps2/rileylink_ios/issues with: -* A description which steps you took. -* The console output from Xcode as a text snippet - -If you own a RTL-SDR USB Device, also try to capture the radio messages as well and adding this to the Issue by using this capture program: https://github.com/Lytrix/openomni/tree/rtlomni which might help as well in trying to see what radio commands were send. - -#### Add unit tests -You can also add your test as a unit test if there is no similiar test written yet here: -https://github.com/ps2/rileylink_ios/tree/omnikit/OmniKitTests - -#### PR new communication commands or refactored code -Always run all Omnikit tests before making a PR request and also solve any errors which the travis build can find. -Create a new [PR](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) to the omnikit branch if you have created a new part in the communication commands. - - -**WARNING the PODs used will fail rapidly, so testing will require a lot of PODs.** - -If you need test pods, please contact @jwedding on https://omniaps.slack.com/ or https://gitter.im/ps2/rileylink - -## Getting Started - -#### Flash the Rileylink Device -Flash your Rileylink device to version 2.0 or greater if you are using an earlier version using the dev branch of https://github.com/ps2/rileylink/tree/dev -subg_rfspy *and* ble113_rfspy (there are two chips) need to be flashed. - -#### Clone this repo to your machine -``` -git clone https://github.com/ps2/rileylink_ios.git -cd rileylink_ios -git checkout omnikit // To switch the branch or do it Xcode using the branch button in the menu on the top left. -``` -#### Install the Rileylink iOS app to your phone - -##### Install Xcode -You'll need Xcode, which is available for free, but will only build apps that last a week. To make your apps run longer, you'll have to sign up for a developer account. Read this tutorial how to sign up: https://loopkit.github.io/loopdocs/setup/build/installing/ - -* Connect your iphone with a usb lightning connector to your laptop -* Select your iphone name at the top page pull down menu (it usually shows generic device) - -You should not need to change bundle id, but you do have to sign the app by your team id on 3 places highlighted in red. -![errors_when_building](Images/errors_when_building.png) -* Then just clicking on the build and run button in Xcode should build and install the app to your connected phone. - -### How to Use - -To use the Rileylink, it has to connect to a Rileylink device first. If you don't see your RileyLink, close any app that uses the Rileylink or reboot your phone. - -![turn on rileylink in command section](Images/rileylink_ios_setup.PNG) - -## Setup an Omnipod - -Click on *Setup POD*. -Follow the same steps as with the PDM, but only push once to insert canula, else the Pod wil fail. -If all went well you should see something like this: - -![turn on rileylink in command section](Images/rileylink_ios_paired_omnipod.png) - -#### Test commands - -To start testing commands you can edit the test command setting in xCode here and issue the command after rebuilding the app on your phone and push the test command button: - -![turn on rileylink in command section](Images/rileylink_ios_omnipod_status.png) - - -## Setup a Medtronic pump - -* Pump ID - Enter in your six digit pump ID diff --git a/Dependencies/rileylink_ios/RileyLink.xcodeproj/project.pbxproj b/Dependencies/rileylink_ios/RileyLink.xcodeproj/project.pbxproj deleted file mode 100644 index e04984db1..000000000 --- a/Dependencies/rileylink_ios/RileyLink.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1743 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 47; - objects = { - -/* Begin PBXBuildFile section */ - 43047FC41FAEC70600508343 /* RadioFirmwareVersionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43047FC31FAEC70600508343 /* RadioFirmwareVersionTests.swift */; }; - 43047FC61FAEC83000508343 /* RFPacketTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43047FC51FAEC83000508343 /* RFPacketTests.swift */; }; - 43047FC71FAEC9BC00508343 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6BA1C826B92006DBA60 /* Data.swift */; }; - 43047FC91FAECA8700508343 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6BA1C826B92006DBA60 /* Data.swift */; }; - 431CE7781F98564200255374 /* RileyLinkBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 431CE76F1F98564100255374 /* RileyLinkBLEKit.framework */; }; - 431CE7811F98564200255374 /* RileyLinkBLEKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 431CE7711F98564100255374 /* RileyLinkBLEKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 431CE7841F98564200255374 /* RileyLinkBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 431CE76F1F98564100255374 /* RileyLinkBLEKit.framework */; }; - 431CE7851F98564200255374 /* RileyLinkBLEKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 431CE76F1F98564100255374 /* RileyLinkBLEKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 431CE78D1F985B5400255374 /* PeripheralManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE78C1F985B5400255374 /* PeripheralManager.swift */; }; - 431CE78F1F985B6E00255374 /* CBPeripheral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE78E1F985B6E00255374 /* CBPeripheral.swift */; }; - 431CE7911F985D8D00255374 /* RileyLinkBluetoothDeviceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE7901F985D8D00255374 /* RileyLinkBluetoothDeviceProvider.swift */; }; - 431CE7931F985DE700255374 /* PeripheralManager+RileyLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE7921F985DE700255374 /* PeripheralManager+RileyLink.swift */; }; - 431CE7961F9B0F0200255374 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE7941F9B0DAE00255374 /* OSLog.swift */; }; - 431CE7981F9B0F0200255374 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE7941F9B0DAE00255374 /* OSLog.swift */; }; - 431CE79A1F9B0F1600255374 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE7941F9B0DAE00255374 /* OSLog.swift */; }; - 431CE79C1F9B21BA00255374 /* RileyLinkDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE79B1F9B21BA00255374 /* RileyLinkDevice.swift */; }; - 431CE79E1F9BE73900255374 /* BLEFirmwareVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE79D1F9BE73900255374 /* BLEFirmwareVersion.swift */; }; - 431CE79F1F9C670600255374 /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43EBE4501EAD238C0073A0B5 /* TimeInterval.swift */; }; - 431CE7A11F9D195600255374 /* CBCentralManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE7A01F9D195600255374 /* CBCentralManager.swift */; }; - 431CE7A31F9D737F00255374 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE7A21F9D737F00255374 /* Command.swift */; }; - 431CE7A51F9D78F500255374 /* RFPacket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE7A41F9D78F500255374 /* RFPacket.swift */; }; - 431CE7A71F9D98F700255374 /* CommandSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE7A61F9D98F700255374 /* CommandSession.swift */; }; - 4322B75620282DA60002837D /* ResponseBufferTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4322B75520282DA60002837D /* ResponseBufferTests.swift */; }; - 432847C11FA1737400CDE69C /* RileyLinkBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 431CE76F1F98564100255374 /* RileyLinkBLEKit.framework */; }; - 432847C31FA57C0F00CDE69C /* RadioFirmwareVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432847C21FA57C0F00CDE69C /* RadioFirmwareVersion.swift */; }; - 432CF9061FF74CCB003AB446 /* RileyLinkKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43722FAE1CB9F7630038B7F2 /* RileyLinkKit.framework */; }; - 43323EA71FA81A0F003FB0FA /* NumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43323EA61FA81A0F003FB0FA /* NumberFormatter.swift */; }; - 43323EAA1FA81C1B003FB0FA /* RileyLinkDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43323EA91FA81C1B003FB0FA /* RileyLinkDevice.swift */; }; - 433ABFFC2016FDF700E6C1FF /* RileyLinkDeviceError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433ABFFB2016FDF700E6C1FF /* RileyLinkDeviceError.swift */; }; - 43462E8B1CCB06F500F958A8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43462E8A1CCB06F500F958A8 /* AppDelegate.swift */; }; - 434AB0C71CBCB76400422F4A /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6BA1C826B92006DBA60 /* Data.swift */; }; - 434FF1DC1CF268BD000DB779 /* IdentifiableClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431185AE1CF25A590059ED98 /* IdentifiableClass.swift */; }; - 4352A74120DED23100CAC200 /* RileyLinkDeviceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4352A74020DED23000CAC200 /* RileyLinkDeviceManager.swift */; }; - 4352A74620DED4AB00CAC200 /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43FB610A20DDF55E002B996B /* LoopKitUI.framework */; }; - 4352A74720DED4AF00CAC200 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43FB610B20DDF55F002B996B /* LoopKit.framework */; }; - 4352A74F20DEDE8400CAC200 /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43FB610A20DDF55E002B996B /* LoopKitUI.framework */; }; - 4352A75020DEDE8700CAC200 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43FB610B20DDF55F002B996B /* LoopKit.framework */; }; - 435535D61FB6D98400CE5A23 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435535D51FB6D98400CE5A23 /* UserDefaults.swift */; }; - 435D26B020DA08CE00891C17 /* RileyLinkPumpManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435D26AF20DA08CE00891C17 /* RileyLinkPumpManager.swift */; }; - 435D26B420DA0AAE00891C17 /* RileyLinkDevicesHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435D26B320DA0AAE00891C17 /* RileyLinkDevicesHeaderView.swift */; }; - 435D26B620DA0BCC00891C17 /* RileyLinkDevicesTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435D26B520DA0BCC00891C17 /* RileyLinkDevicesTableViewDataSource.swift */; }; - 43709ABD20DF1C6400F941B3 /* RileyLinkSetupTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43709ABA20DF1C6400F941B3 /* RileyLinkSetupTableViewController.swift */; }; - 43709ABE20DF1C6400F941B3 /* RileyLinkManagerSetupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43709ABB20DF1C6400F941B3 /* RileyLinkManagerSetupViewController.swift */; }; - 43709ABF20DF1C6400F941B3 /* RileyLinkSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43709ABC20DF1C6400F941B3 /* RileyLinkSettingsViewController.swift */; }; - 43709AE420DF20D500F941B3 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE7941F9B0DAE00255374 /* OSLog.swift */; }; - 43709AE820DF22E700F941B3 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14FFC601D3D75470049CF85 /* UIColor.swift */; }; - 43709AEC20E0056F00F941B3 /* RileyLinkKitUI.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 43709AEB20E0056F00F941B3 /* RileyLinkKitUI.xcassets */; }; - 43709AEE20E008F300F941B3 /* SetupImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43709AED20E008F300F941B3 /* SetupImageTableViewCell.swift */; }; - 43709AF020E0120F00F941B3 /* SetupImageTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43709AEF20E0120F00F941B3 /* SetupImageTableViewCell.xib */; }; - 43709AF120E0127000F941B3 /* NibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14FFC5A1D3D74F90049CF85 /* NibLoadable.swift */; }; - 43722FB11CB9F7640038B7F2 /* RileyLinkKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 43722FB01CB9F7640038B7F2 /* RileyLinkKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43722FC31CB9F7640038B7F2 /* RileyLinkKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43722FAE1CB9F7630038B7F2 /* RileyLinkKit.framework */; }; - 43722FC41CB9F7640038B7F2 /* RileyLinkKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 43722FAE1CB9F7630038B7F2 /* RileyLinkKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 437462391FA9287A00643383 /* RileyLinkDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437462381FA9287A00643383 /* RileyLinkDevice.swift */; }; - 437F540A1FBFDAA60070FF2C /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6BA1C826B92006DBA60 /* Data.swift */; }; - 43BA719B202591A70058961E /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BA719A202591A70058961E /* Response.swift */; }; - 43BA719D2026C9B00058961E /* ResponseBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BA719C2026C9B00058961E /* ResponseBuffer.swift */; }; - 43BF58B31FF6079600499C46 /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43EBE4501EAD238C0073A0B5 /* TimeInterval.swift */; }; - 43C0196C1FA6B8AE007ABFA1 /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43CA93241CB8BB33000026B5 /* CoreBluetooth.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; - 43D5E7881FAEDAC4004ACDB7 /* PeripheralManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D5E7871FAEDAC4004ACDB7 /* PeripheralManagerError.swift */; }; - 43D5E7921FAF7BFB004ACDB7 /* RileyLinkKitUI.h in Headers */ = {isa = PBXBuildFile; fileRef = 43D5E7901FAF7BFB004ACDB7 /* RileyLinkKitUI.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43D5E7951FAF7BFB004ACDB7 /* RileyLinkKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D5E78E1FAF7BFB004ACDB7 /* RileyLinkKitUI.framework */; }; - 43D5E7961FAF7BFB004ACDB7 /* RileyLinkKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 43D5E78E1FAF7BFB004ACDB7 /* RileyLinkKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 43D5E79A1FAF7C47004ACDB7 /* RileyLinkDeviceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 439731261CF21C3C00F474E5 /* RileyLinkDeviceTableViewCell.swift */; }; - 43D5E79C1FAF7C47004ACDB7 /* RileyLinkDeviceTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C170C9981CECD80000F3D8E5 /* RileyLinkDeviceTableViewController.swift */; }; - 43D5E79F1FAF7C98004ACDB7 /* IdentifiableClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431185AE1CF25A590059ED98 /* IdentifiableClass.swift */; }; - 43D5E7A01FAF7CCA004ACDB7 /* NumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43323EA61FA81A0F003FB0FA /* NumberFormatter.swift */; }; - 43D5E7A11FAF7CE0004ACDB7 /* UITableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B4A9581D1E6357003B8985 /* UITableViewCell.swift */; }; - 43D5E7A21FAF7CF2004ACDB7 /* CaseCountable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C659181E16BA9D0025CC58 /* CaseCountable.swift */; }; - 43D5E7A31FAF7D05004ACDB7 /* CBPeripheralState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C170C98D1CECD6F300F3D8E5 /* CBPeripheralState.swift */; }; - 43D8708820DE1A63006B549E /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43FB610B20DDF55F002B996B /* LoopKit.framework */; }; - 43EBE4531EAD23CE0073A0B5 /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43EBE4501EAD238C0073A0B5 /* TimeInterval.swift */; }; - 43EBE4551EAD24410073A0B5 /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43EBE4501EAD238C0073A0B5 /* TimeInterval.swift */; }; - 43F89CA122BDFB8D006BB54E /* UIActivityIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F89CA022BDFB8D006BB54E /* UIActivityIndicatorView.swift */; }; - 7D2366F0212527DA0028B67D /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D2366EF212527DA0028B67D /* LocalizedString.swift */; }; - 7D2366F2212527DA0028B67D /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D2366EF212527DA0028B67D /* LocalizedString.swift */; }; - 7D2366F5212527DA0028B67D /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D2366EF212527DA0028B67D /* LocalizedString.swift */; }; - 7D2366F6212527DA0028B67D /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D2366EF212527DA0028B67D /* LocalizedString.swift */; }; - 7D23679421252EBC0028B67D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7D23679221252EBC0028B67D /* Localizable.strings */; }; - 7D23679721252EBC0028B67D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7D23679521252EBC0028B67D /* Localizable.strings */; }; - 7D7076951FE09311004AC8EA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7D7076971FE09311004AC8EA /* Localizable.strings */; }; - C125728C2121D4D60061BA2F /* UITableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B4A9581D1E6357003B8985 /* UITableViewCell.swift */; }; - C125728D2121D56D0061BA2F /* CaseCountable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C659181E16BA9D0025CC58 /* CaseCountable.swift */; }; - C125728F2121DB7C0061BA2F /* PumpManagerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C125728E2121DB7C0061BA2F /* PumpManagerState.swift */; }; - C12572922121EEEE0061BA2F /* SettingsImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12572912121EEEE0061BA2F /* SettingsImageTableViewCell.swift */; }; - C125729421220FEC0061BA2F /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C125729321220FEC0061BA2F /* MainStoryboard.storyboard */; }; - C1271B071A9A34E900B7C949 /* Log.m in Sources */ = {isa = PBXBuildFile; fileRef = C1271B061A9A34E900B7C949 /* Log.m */; }; - C1274F801D82411C0002912B /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1274F7C1D82411C0002912B /* MainViewController.swift */; }; - C12EA23B198B436800309FA4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C12EA23A198B436800309FA4 /* Foundation.framework */; }; - C12EA23D198B436800309FA4 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C12EA23C198B436800309FA4 /* CoreGraphics.framework */; }; - C12EA23F198B436800309FA4 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C12EA23E198B436800309FA4 /* UIKit.framework */; }; - C136AA76231234E1008A320D /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43FB610B20DDF55F002B996B /* LoopKit.framework */; }; - C1394BA9297E49630042F1A9 /* LoopKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = C1394BA7297E49630042F1A9 /* LoopKit.strings */; }; - C13F0437230B1DE6001413FF /* MKRingProgressView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C13F0436230B1DE6001413FF /* MKRingProgressView.framework */; }; - C14F71D426A675BC00FA09F0 /* CommandResponseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14F71D326A675BC00FA09F0 /* CommandResponseViewController.swift */; }; - C14FFC501D3D6DEF0049CF85 /* ServiceAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14FFC4E1D3D6DEF0049CF85 /* ServiceAuthentication.swift */; }; - C14FFC511D3D6DEF0049CF85 /* ServiceCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14FFC4F1D3D6DEF0049CF85 /* ServiceCredential.swift */; }; - C14FFC551D3D72A50049CF85 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14FFC541D3D72A50049CF85 /* UIViewController.swift */; }; - C14FFC5B1D3D74F90049CF85 /* NibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14FFC5A1D3D74F90049CF85 /* NibLoadable.swift */; }; - C14FFC611D3D75470049CF85 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14FFC601D3D75470049CF85 /* UIColor.swift */; }; - C14FFC631D3D7CE20049CF85 /* NightscoutService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14FFC621D3D7CE20049CF85 /* NightscoutService.swift */; }; - C14FFC651D3D7E250049CF85 /* RemoteDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14FFC641D3D7E250049CF85 /* RemoteDataManager.swift */; }; - C14FFC671D3D7E390049CF85 /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14FFC661D3D7E390049CF85 /* KeychainManager.swift */; }; - C14FFC691D3D7E560049CF85 /* KeychainManager+RileyLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14FFC681D3D7E560049CF85 /* KeychainManager+RileyLink.swift */; }; - C17884611D519F1E00405663 /* BatteryIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17884601D519F1E00405663 /* BatteryIndicator.swift */; }; - C1821695297E55A7001EB097 /* RileyLink-InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C1821693297E55A7001EB097 /* RileyLink-InfoPlist.strings */; }; - C1B383361CD1BA8100CE7782 /* DeviceDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B383351CD1BA8100CE7782 /* DeviceDataManager.swift */; }; - C1B44CA7224BDFDF00DE47E5 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43FB610B20DDF55F002B996B /* LoopKit.framework */; }; - C1BB1460293835A8004CE8DA /* RileyLinkListDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1BB145F293835A8004CE8DA /* RileyLinkListDataSource.swift */; }; - C1CAB67328C696A600F6F715 /* RileyLinkDeviceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CAB67228C696A600F6F715 /* RileyLinkDeviceProvider.swift */; }; - C1CAB67528C696D800F6F715 /* RileyLinkBluetoothDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CAB67428C696D800F6F715 /* RileyLinkBluetoothDevice.swift */; }; - C1EF58881B3F93FE001C8C80 /* Config.m in Sources */ = {isa = PBXBuildFile; fileRef = C1EF58871B3F93FE001C8C80 /* Config.m */; }; - C1FC49EC2135CB2D007D0788 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1FC49EB2135CB2D007D0788 /* LaunchScreen.storyboard */; }; - C1FFAF6F212CB4F100C50C1D /* RileyLinkConnectionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1FFAF6E212CB4F100C50C1D /* RileyLinkConnectionState.swift */; }; - C1FFAF72212FAAEF00C50C1D /* RileyLink.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C1FFAF71212FAAEF00C50C1D /* RileyLink.xcassets */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 431CE7791F98564200255374 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C12EA22F198B436800309FA4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 431CE76E1F98564100255374; - remoteInfo = RileyLinkBLEKit; - }; - 431CE7821F98564200255374 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C12EA22F198B436800309FA4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 431CE76E1F98564100255374; - remoteInfo = RileyLinkBLEKit; - }; - 43722FC11CB9F7640038B7F2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C12EA22F198B436800309FA4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 43722FAD1CB9F7630038B7F2; - remoteInfo = RileyLinkKit; - }; - 43D5E7931FAF7BFB004ACDB7 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C12EA22F198B436800309FA4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 43D5E78D1FAF7BFB004ACDB7; - remoteInfo = RileyLinkKitUI; - }; - A9B839CA22809DB3004E745E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C12EA22F198B436800309FA4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 431CE76E1F98564100255374; - remoteInfo = RileyLinkBLEKit; - }; - A9B839D022809DE7004E745E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C12EA22F198B436800309FA4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 43722FAD1CB9F7630038B7F2; - remoteInfo = RileyLinkKit; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - C10D9BB81C82614F00378342 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 43722FC41CB9F7640038B7F2 /* RileyLinkKit.framework in Embed Frameworks */, - 43D5E7961FAF7BFB004ACDB7 /* RileyLinkKitUI.framework in Embed Frameworks */, - 431CE7851F98564200255374 /* RileyLinkBLEKit.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 193F1E462B44C20400525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; - 193F1E472B44C20400525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; - 193F1E482B44C20500525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; - 43047FC31FAEC70600508343 /* RadioFirmwareVersionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioFirmwareVersionTests.swift; sourceTree = ""; }; - 43047FC51FAEC83000508343 /* RFPacketTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RFPacketTests.swift; sourceTree = ""; }; - 431185AE1CF25A590059ED98 /* IdentifiableClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentifiableClass.swift; sourceTree = ""; }; - 431CE76F1F98564100255374 /* RileyLinkBLEKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RileyLinkBLEKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 431CE7711F98564100255374 /* RileyLinkBLEKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RileyLinkBLEKit.h; sourceTree = ""; }; - 431CE7721F98564100255374 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 431CE7771F98564200255374 /* RileyLinkBLEKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RileyLinkBLEKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 431CE7801F98564200255374 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 431CE78C1F985B5400255374 /* PeripheralManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeripheralManager.swift; sourceTree = ""; }; - 431CE78E1F985B6E00255374 /* CBPeripheral.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CBPeripheral.swift; sourceTree = ""; }; - 431CE7901F985D8D00255374 /* RileyLinkBluetoothDeviceProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RileyLinkBluetoothDeviceProvider.swift; sourceTree = ""; }; - 431CE7921F985DE700255374 /* PeripheralManager+RileyLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PeripheralManager+RileyLink.swift"; sourceTree = ""; }; - 431CE7941F9B0DAE00255374 /* OSLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; - 431CE79B1F9B21BA00255374 /* RileyLinkDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RileyLinkDevice.swift; sourceTree = ""; }; - 431CE79D1F9BE73900255374 /* BLEFirmwareVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BLEFirmwareVersion.swift; sourceTree = ""; }; - 431CE7A01F9D195600255374 /* CBCentralManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CBCentralManager.swift; sourceTree = ""; }; - 431CE7A21F9D737F00255374 /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = ""; }; - 431CE7A41F9D78F500255374 /* RFPacket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RFPacket.swift; sourceTree = ""; }; - 431CE7A61F9D98F700255374 /* CommandSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandSession.swift; sourceTree = ""; }; - 4322B75520282DA60002837D /* ResponseBufferTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseBufferTests.swift; sourceTree = ""; }; - 432847C21FA57C0F00CDE69C /* RadioFirmwareVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioFirmwareVersion.swift; sourceTree = ""; }; - 43323EA61FA81A0F003FB0FA /* NumberFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberFormatter.swift; sourceTree = ""; }; - 43323EA91FA81C1B003FB0FA /* RileyLinkDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RileyLinkDevice.swift; sourceTree = ""; }; - 433ABFFB2016FDF700E6C1FF /* RileyLinkDeviceError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RileyLinkDeviceError.swift; sourceTree = ""; }; - 4345D1CD1DA16AF300BAAD22 /* TimeZone.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeZone.swift; sourceTree = ""; }; - 43462E8A1CCB06F500F958A8 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 4352A73D20DED01700CAC200 /* HKUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKUnit.swift; sourceTree = ""; }; - 4352A74020DED23000CAC200 /* RileyLinkDeviceManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RileyLinkDeviceManager.swift; sourceTree = ""; }; - 435535D51FB6D98400CE5A23 /* UserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaults.swift; sourceTree = ""; }; - 435D26AF20DA08CE00891C17 /* RileyLinkPumpManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RileyLinkPumpManager.swift; sourceTree = ""; }; - 435D26B320DA0AAE00891C17 /* RileyLinkDevicesHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RileyLinkDevicesHeaderView.swift; sourceTree = ""; }; - 435D26B520DA0BCC00891C17 /* RileyLinkDevicesTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RileyLinkDevicesTableViewDataSource.swift; sourceTree = ""; }; - 43709ABA20DF1C6400F941B3 /* RileyLinkSetupTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RileyLinkSetupTableViewController.swift; sourceTree = ""; }; - 43709ABB20DF1C6400F941B3 /* RileyLinkManagerSetupViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RileyLinkManagerSetupViewController.swift; sourceTree = ""; }; - 43709ABC20DF1C6400F941B3 /* RileyLinkSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RileyLinkSettingsViewController.swift; sourceTree = ""; }; - 43709AEB20E0056F00F941B3 /* RileyLinkKitUI.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = RileyLinkKitUI.xcassets; sourceTree = ""; }; - 43709AED20E008F300F941B3 /* SetupImageTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupImageTableViewCell.swift; sourceTree = ""; }; - 43709AEF20E0120F00F941B3 /* SetupImageTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SetupImageTableViewCell.xib; sourceTree = ""; }; - 43722FAE1CB9F7630038B7F2 /* RileyLinkKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RileyLinkKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 43722FB01CB9F7640038B7F2 /* RileyLinkKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RileyLinkKit.h; sourceTree = ""; }; - 43722FB21CB9F7640038B7F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 43722FC01CB9F7640038B7F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 437462381FA9287A00643383 /* RileyLinkDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RileyLinkDevice.swift; sourceTree = ""; }; - 437DE508229C8A05003B1074 /* copy-frameworks.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "copy-frameworks.sh"; sourceTree = ""; }; - 439731261CF21C3C00F474E5 /* RileyLinkDeviceTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RileyLinkDeviceTableViewCell.swift; sourceTree = ""; }; - 43BA719A202591A70058961E /* Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Response.swift; sourceTree = ""; }; - 43BA719C2026C9B00058961E /* ResponseBuffer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseBuffer.swift; sourceTree = ""; }; - 43CA93241CB8BB33000026B5 /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; }; - 43D5E7871FAEDAC4004ACDB7 /* PeripheralManagerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeripheralManagerError.swift; sourceTree = ""; }; - 43D5E78E1FAF7BFB004ACDB7 /* RileyLinkKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RileyLinkKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 43D5E7901FAF7BFB004ACDB7 /* RileyLinkKitUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RileyLinkKitUI.h; sourceTree = ""; }; - 43D5E7911FAF7BFB004ACDB7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 43EBE4501EAD238C0073A0B5 /* TimeInterval.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeInterval.swift; sourceTree = ""; }; - 43F89CA022BDFB8D006BB54E /* UIActivityIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIActivityIndicatorView.swift; sourceTree = ""; }; - 43FB610A20DDF55E002B996B /* LoopKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LoopKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 43FB610B20DDF55F002B996B /* LoopKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LoopKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 7D199DA4212A159900241026 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - 7D199DAF212A159A00241026 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - 7D199DB2212A159A00241026 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; - 7D2366EF212527DA0028B67D /* LocalizedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedString.swift; sourceTree = ""; }; - 7D2366F8212528560028B67D /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; - 7D2366FB212529510028B67D /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - 7D2367072125297B0028B67D /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - 7D236713212529810028B67D /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - 7D23671F212529890028B67D /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - 7D23672B212529950028B67D /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - 7D2367372125299F0028B67D /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - 7D23679321252EBC0028B67D /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - 7D23679621252EBC0028B67D /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - 7D23679821252F050028B67D /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; - 7D23679921252F0D0028B67D /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; - 7D23679A21252FF30028B67D /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - 7D23679B21252FF30028B67D /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - 7D23679C2125300A0028B67D /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - 7D23679D2125300A0028B67D /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - 7D23679E212530160028B67D /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - 7D23679F212530160028B67D /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; - 7D2367A0212530230028B67D /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - 7D2367A1212530230028B67D /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; - 7D2367A2212530300028B67D /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - 7D2367A3212530300028B67D /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - 7D2367A42125303D0028B67D /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - 7D2367A52125303D0028B67D /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - 7D2367A62125304D0028B67D /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - 7D2367A72125304D0028B67D /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; - 7D68AACE1FE31DEB00522C49 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - 7D7076961FE09311004AC8EA /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BEFEA23369382005DCFD6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF00E2336A2D3005DCFD6 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF0102336A2D3005DCFD6 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF0112336A2D3005DCFD6 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF0162336A2E3005DCFD6 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF0182336A2E3005DCFD6 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF0192336A2E3005DCFD6 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF01E2336A2EA005DCFD6 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF0202336A2EA005DCFD6 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF0212336A2EA005DCFD6 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF0262336A2F1005DCFD6 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF0282336A2F2005DCFD6 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF0292336A2F2005DCFD6 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF02E2336A2FB005DCFD6 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF0302336A2FB005DCFD6 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF0312336A2FB005DCFD6 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF0362336A304005DCFD6 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - 7D9BF0382336A304005DCFD6 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - 7D9BF0392336A304005DCFD6 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; - 7D9BF14F23371407005DCFD6 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF15123371408005DCFD6 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - 7D9BF15223371408005DCFD6 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; }; - C11613512983096D00777E7C /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = "nb.lproj/RileyLink-InfoPlist.strings"; sourceTree = ""; }; - C11A2BD329830A3100AC5135 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = "fr.lproj/RileyLink-InfoPlist.strings"; sourceTree = ""; }; - C125728E2121DB7C0061BA2F /* PumpManagerState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpManagerState.swift; sourceTree = ""; }; - C12572912121EEEE0061BA2F /* SettingsImageTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsImageTableViewCell.swift; sourceTree = ""; }; - C125729321220FEC0061BA2F /* MainStoryboard.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = MainStoryboard.storyboard; sourceTree = ""; }; - C12616431B685F0A001FAD87 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; - C126DD162981EE69009A0A64 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/LoopKit.strings; sourceTree = ""; }; - C1271B061A9A34E900B7C949 /* Log.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Log.m; sourceTree = ""; }; - C1271B081A9A350400B7C949 /* Log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Log.h; sourceTree = ""; }; - C1274F7C1D82411C0002912B /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; - C12B52E029C8142E0025DA95 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; - C12BCD0329BBFA490066A158 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - C12BCD0429BBFA490066A158 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/LoopKit.strings; sourceTree = ""; }; - C12BCD0529BBFA490066A158 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = "cs.lproj/RileyLink-InfoPlist.strings"; sourceTree = ""; }; - C12BCD0629BBFA490066A158 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - C12BCD0729BBFA490066A158 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; - C12EA237198B436800309FA4 /* RileyLink.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RileyLink.app; sourceTree = BUILT_PRODUCTS_DIR; }; - C12EA23A198B436800309FA4 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - C12EA23C198B436800309FA4 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - C12EA23E198B436800309FA4 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - C12EA242198B436800309FA4 /* RileyLink-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RileyLink-Info.plist"; sourceTree = ""; }; - C12EA253198B436800309FA4 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; - C12EA25B198B436900309FA4 /* RileyLinkTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RileyLinkTests-Info.plist"; sourceTree = ""; }; - C12EA25F198B436900309FA4 /* RileyLinkTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RileyLinkTests.m; sourceTree = ""; }; - C1394BA8297E49630042F1A9 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/LoopKit.strings; sourceTree = ""; }; - C13F0436230B1DE6001413FF /* MKRingProgressView.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = MKRingProgressView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C145BF9D2219F2EC00A977CB /* Comparable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Comparable.swift; sourceTree = ""; }; - C147B997299581ED00BF55AC /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/LoopKit.strings; sourceTree = ""; }; - C147B998299581ED00BF55AC /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = "he.lproj/RileyLink-InfoPlist.strings"; sourceTree = ""; }; - C14952172995822A0095AA84 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/LoopKit.strings; sourceTree = ""; }; - C14952182995822A0095AA84 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = "ru.lproj/RileyLink-InfoPlist.strings"; sourceTree = ""; }; - C14F71D326A675BC00FA09F0 /* CommandResponseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandResponseViewController.swift; sourceTree = ""; }; - C14FFC4E1D3D6DEF0049CF85 /* ServiceAuthentication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceAuthentication.swift; sourceTree = ""; }; - C14FFC4F1D3D6DEF0049CF85 /* ServiceCredential.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceCredential.swift; sourceTree = ""; }; - C14FFC541D3D72A50049CF85 /* UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = ""; }; - C14FFC5A1D3D74F90049CF85 /* NibLoadable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NibLoadable.swift; sourceTree = ""; }; - C14FFC601D3D75470049CF85 /* UIColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; }; - C14FFC621D3D7CE20049CF85 /* NightscoutService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightscoutService.swift; sourceTree = ""; }; - C14FFC641D3D7E250049CF85 /* RemoteDataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteDataManager.swift; sourceTree = ""; }; - C14FFC661D3D7E390049CF85 /* KeychainManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainManager.swift; sourceTree = ""; }; - C14FFC681D3D7E560049CF85 /* KeychainManager+RileyLink.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "KeychainManager+RileyLink.swift"; sourceTree = ""; }; - C151BED32981EE6000F3A41F /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/LoopKit.strings; sourceTree = ""; }; - C153EBB12981EE6C000BFE9E /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/LoopKit.strings; sourceTree = ""; }; - C15A583529C7866600D3A5A1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; - C15A583629C7866600D3A5A1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/LoopKit.strings; sourceTree = ""; }; - C170C98D1CECD6F300F3D8E5 /* CBPeripheralState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CBPeripheralState.swift; sourceTree = ""; }; - C170C9981CECD80000F3D8E5 /* RileyLinkDeviceTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RileyLinkDeviceTableViewController.swift; sourceTree = ""; }; - C17884601D519F1E00405663 /* BatteryIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatteryIndicator.swift; sourceTree = ""; }; - C1821692297E55A7001EB097 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/LoopKit.strings; sourceTree = ""; }; - C1821694297E55A7001EB097 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = "es.lproj/RileyLink-InfoPlist.strings"; sourceTree = ""; }; - C18700782981EE6100E06588 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/LoopKit.strings; sourceTree = ""; }; - C18886EC29830A5E004C982D /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = "nl.lproj/RileyLink-InfoPlist.strings"; sourceTree = ""; }; - C18B7265299581C600F138D3 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = "da.lproj/RileyLink-InfoPlist.strings"; sourceTree = ""; }; - C192C60929C78711001EFEA6 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/LoopKit.strings; sourceTree = ""; }; - C1AB0C542981EE5B0020FEE5 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/LoopKit.strings; sourceTree = ""; }; - C1B0CFDF29C786BF0045B04D /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/LoopKit.strings; sourceTree = ""; }; - C1B267A32995824000BCB7C1 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/LoopKit.strings; sourceTree = ""; }; - C1B267A42995824000BCB7C1 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = "tr.lproj/RileyLink-InfoPlist.strings"; sourceTree = ""; }; - C1B383351CD1BA8100CE7782 /* DeviceDataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceDataManager.swift; sourceTree = ""; }; - C1B4A9581D1E6357003B8985 /* UITableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITableViewCell.swift; sourceTree = ""; }; - C1BB145F293835A8004CE8DA /* RileyLinkListDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RileyLinkListDataSource.swift; sourceTree = ""; }; - C1BCB5C0298309C4001C50FF /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/LoopKit.strings; sourceTree = ""; }; - C1BCB5C1298309C4001C50FF /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = "it.lproj/RileyLink-InfoPlist.strings"; sourceTree = ""; }; - C1C6038C2983092100FC4128 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = "de.lproj/RileyLink-InfoPlist.strings"; sourceTree = ""; }; - C1C659181E16BA9D0025CC58 /* CaseCountable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaseCountable.swift; sourceTree = ""; }; - C1CAB67228C696A600F6F715 /* RileyLinkDeviceProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RileyLinkDeviceProvider.swift; sourceTree = ""; }; - C1CAB67428C696D800F6F715 /* RileyLinkBluetoothDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RileyLinkBluetoothDevice.swift; sourceTree = ""; }; - C1CB33F72981EE650019F1C3 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/LoopKit.strings; sourceTree = ""; }; - C1DCAF512981EE5D00118AD3 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/LoopKit.strings; sourceTree = ""; }; - C1DEE894298309EA0008194D /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1DEE895298309EA0008194D /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/LoopKit.strings; sourceTree = ""; }; - C1DEE896298309EA0008194D /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = "sk.lproj/RileyLink-InfoPlist.strings"; sourceTree = ""; }; - C1DEE897298309EA0008194D /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1DEE898298309EA0008194D /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; - C1E28AFC2981EE6600758EB3 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/LoopKit.strings; sourceTree = ""; }; - C1E693D529C786E200410918 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/LoopKit.strings"; sourceTree = ""; }; - C1E8ADD32995822300AB9EEB /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = "ro.lproj/RileyLink-InfoPlist.strings"; sourceTree = ""; }; - C1EAD6BA1C826B92006DBA60 /* Data.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; }; - C1EAD6EA1C8409A9006DBA60 /* RileyLink-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RileyLink-Bridging-Header.h"; sourceTree = ""; }; - C1EF58861B3F93FE001C8C80 /* Config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Config.h; sourceTree = ""; }; - C1EF58871B3F93FE001C8C80 /* Config.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Config.m; sourceTree = ""; }; - C1F490042995821600C8BD69 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = "pl.lproj/RileyLink-InfoPlist.strings"; sourceTree = ""; }; - C1FAB5CA29C786B000D25073 /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = ""; }; - C1FAB5CB29C786B000D25073 /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = ""; }; - C1FC49EB2135CB2D007D0788 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; - C1FFAF6E212CB4F100C50C1D /* RileyLinkConnectionState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RileyLinkConnectionState.swift; sourceTree = ""; }; - C1FFAF71212FAAEF00C50C1D /* RileyLink.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = RileyLink.xcassets; sourceTree = ""; }; - F5D9C04627DAC30B002E48F6 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - F5D9C04827DAC30C002E48F6 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - F5D9C04927DAC30C002E48F6 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; - F5E0BE2827E1DF280033557E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; - F5E0BE2A27E1DF280033557E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; - F5E0BE2B27E1DF280033557E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 431CE76B1F98564100255374 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C1B44CA7224BDFDF00DE47E5 /* LoopKit.framework in Frameworks */, - 43C0196C1FA6B8AE007ABFA1 /* CoreBluetooth.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 431CE7741F98564200255374 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 431CE7781F98564200255374 /* RileyLinkBLEKit.framework in Frameworks */, - C136AA76231234E1008A320D /* LoopKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43722FAA1CB9F7630038B7F2 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 432847C11FA1737400CDE69C /* RileyLinkBLEKit.framework in Frameworks */, - 43D8708820DE1A63006B549E /* LoopKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43D5E78A1FAF7BFB004ACDB7 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 432CF9061FF74CCB003AB446 /* RileyLinkKit.framework in Frameworks */, - 4352A75020DEDE8700CAC200 /* LoopKit.framework in Frameworks */, - 4352A74F20DEDE8400CAC200 /* LoopKitUI.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C12EA234198B436800309FA4 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C12EA23D198B436800309FA4 /* CoreGraphics.framework in Frameworks */, - C13F0437230B1DE6001413FF /* MKRingProgressView.framework in Frameworks */, - 43D5E7951FAF7BFB004ACDB7 /* RileyLinkKitUI.framework in Frameworks */, - C12EA23F198B436800309FA4 /* UIKit.framework in Frameworks */, - 43722FC31CB9F7640038B7F2 /* RileyLinkKit.framework in Frameworks */, - C12EA23B198B436800309FA4 /* Foundation.framework in Frameworks */, - 431CE7841F98564200255374 /* RileyLinkBLEKit.framework in Frameworks */, - 4352A74720DED4AF00CAC200 /* LoopKit.framework in Frameworks */, - 4352A74620DED4AB00CAC200 /* LoopKitUI.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 431CE7701F98564100255374 /* RileyLinkBLEKit */ = { - isa = PBXGroup; - children = ( - 431CE7711F98564100255374 /* RileyLinkBLEKit.h */, - 431CE7721F98564100255374 /* Info.plist */, - 7D23679221252EBC0028B67D /* Localizable.strings */, - 431CE79D1F9BE73900255374 /* BLEFirmwareVersion.swift */, - 431CE7A01F9D195600255374 /* CBCentralManager.swift */, - 431CE78E1F985B6E00255374 /* CBPeripheral.swift */, - 431CE7A21F9D737F00255374 /* Command.swift */, - 431CE7A61F9D98F700255374 /* CommandSession.swift */, - 431CE78C1F985B5400255374 /* PeripheralManager.swift */, - 43D5E7871FAEDAC4004ACDB7 /* PeripheralManagerError.swift */, - 431CE7921F985DE700255374 /* PeripheralManager+RileyLink.swift */, - 431CE7A41F9D78F500255374 /* RFPacket.swift */, - 432847C21FA57C0F00CDE69C /* RadioFirmwareVersion.swift */, - 43BA719A202591A70058961E /* Response.swift */, - 43BA719C2026C9B00058961E /* ResponseBuffer.swift */, - 431CE79B1F9B21BA00255374 /* RileyLinkDevice.swift */, - C1CAB67428C696D800F6F715 /* RileyLinkBluetoothDevice.swift */, - 433ABFFB2016FDF700E6C1FF /* RileyLinkDeviceError.swift */, - C1CAB67228C696A600F6F715 /* RileyLinkDeviceProvider.swift */, - 431CE7901F985D8D00255374 /* RileyLinkBluetoothDeviceProvider.swift */, - C1FFAF6E212CB4F100C50C1D /* RileyLinkConnectionState.swift */, - ); - path = RileyLinkBLEKit; - sourceTree = ""; - }; - 431CE77D1F98564200255374 /* RileyLinkBLEKitTests */ = { - isa = PBXGroup; - children = ( - 43047FC51FAEC83000508343 /* RFPacketTests.swift */, - 43047FC31FAEC70600508343 /* RadioFirmwareVersionTests.swift */, - 4322B75520282DA60002837D /* ResponseBufferTests.swift */, - 431CE7801F98564200255374 /* Info.plist */, - ); - path = RileyLinkBLEKitTests; - sourceTree = ""; - }; - 43722FAF1CB9F7630038B7F2 /* RileyLinkKit */ = { - isa = PBXGroup; - children = ( - 43722FB01CB9F7640038B7F2 /* RileyLinkKit.h */, - 43722FB21CB9F7640038B7F2 /* Info.plist */, - 43323EA91FA81C1B003FB0FA /* RileyLinkDevice.swift */, - 4352A74020DED23000CAC200 /* RileyLinkDeviceManager.swift */, - 435D26AF20DA08CE00891C17 /* RileyLinkPumpManager.swift */, - C1BB145F293835A8004CE8DA /* RileyLinkListDataSource.swift */, - ); - path = RileyLinkKit; - sourceTree = ""; - }; - 43722FBD1CB9F7640038B7F2 /* RileyLinkKitTests */ = { - isa = PBXGroup; - children = ( - 43722FC01CB9F7640038B7F2 /* Info.plist */, - ); - path = RileyLinkKitTests; - sourceTree = ""; - }; - 437DE504229C898D003B1074 /* Scripts */ = { - isa = PBXGroup; - children = ( - 437DE508229C8A05003B1074 /* copy-frameworks.sh */, - ); - path = Scripts; - sourceTree = ""; - }; - 43D5E78F1FAF7BFB004ACDB7 /* RileyLinkKitUI */ = { - isa = PBXGroup; - children = ( - 43D5E7901FAF7BFB004ACDB7 /* RileyLinkKitUI.h */, - 43D5E7911FAF7BFB004ACDB7 /* Info.plist */, - 7D23679521252EBC0028B67D /* Localizable.strings */, - 43709AEB20E0056F00F941B3 /* RileyLinkKitUI.xcassets */, - C170C98D1CECD6F300F3D8E5 /* CBPeripheralState.swift */, - C14F71D326A675BC00FA09F0 /* CommandResponseViewController.swift */, - 439731261CF21C3C00F474E5 /* RileyLinkDeviceTableViewCell.swift */, - C170C9981CECD80000F3D8E5 /* RileyLinkDeviceTableViewController.swift */, - 435D26B320DA0AAE00891C17 /* RileyLinkDevicesHeaderView.swift */, - 435D26B520DA0BCC00891C17 /* RileyLinkDevicesTableViewDataSource.swift */, - 43709ABB20DF1C6400F941B3 /* RileyLinkManagerSetupViewController.swift */, - 43709ABC20DF1C6400F941B3 /* RileyLinkSettingsViewController.swift */, - 43709ABA20DF1C6400F941B3 /* RileyLinkSetupTableViewController.swift */, - 43709AED20E008F300F941B3 /* SetupImageTableViewCell.swift */, - 43709AEF20E0120F00F941B3 /* SetupImageTableViewCell.xib */, - C1B4A9581D1E6357003B8985 /* UITableViewCell.swift */, - 43F89CA022BDFB8D006BB54E /* UIActivityIndicatorView.swift */, - ); - path = RileyLinkKitUI; - sourceTree = ""; - }; - 43EBE44F1EAD234F0073A0B5 /* Common */ = { - isa = PBXGroup; - children = ( - C1C659181E16BA9D0025CC58 /* CaseCountable.swift */, - C1EAD6BA1C826B92006DBA60 /* Data.swift */, - 4352A73D20DED01700CAC200 /* HKUnit.swift */, - 431185AE1CF25A590059ED98 /* IdentifiableClass.swift */, - C14FFC5A1D3D74F90049CF85 /* NibLoadable.swift */, - 43323EA61FA81A0F003FB0FA /* NumberFormatter.swift */, - 431CE7941F9B0DAE00255374 /* OSLog.swift */, - 43EBE4501EAD238C0073A0B5 /* TimeInterval.swift */, - 4345D1CD1DA16AF300BAAD22 /* TimeZone.swift */, - C14FFC601D3D75470049CF85 /* UIColor.swift */, - 7D2366EF212527DA0028B67D /* LocalizedString.swift */, - C145BF9D2219F2EC00A977CB /* Comparable.swift */, - ); - path = Common; - sourceTree = ""; - }; - C12572902121EEDE0061BA2F /* Views */ = { - isa = PBXGroup; - children = ( - C12572912121EEEE0061BA2F /* SettingsImageTableViewCell.swift */, - ); - path = Views; - sourceTree = ""; - }; - C1274F7A1D8240D00002912B /* View Controllers */ = { - isa = PBXGroup; - children = ( - C1274F7C1D82411C0002912B /* MainViewController.swift */, - ); - path = "View Controllers"; - sourceTree = ""; - }; - C12EA22E198B436800309FA4 = { - isa = PBXGroup; - children = ( - C12EA240198B436800309FA4 /* RileyLink */, - C12EA259198B436900309FA4 /* RileyLinkTests */, - 43722FAF1CB9F7630038B7F2 /* RileyLinkKit */, - 43722FBD1CB9F7640038B7F2 /* RileyLinkKitTests */, - 43EBE44F1EAD234F0073A0B5 /* Common */, - 431CE7701F98564100255374 /* RileyLinkBLEKit */, - 431CE77D1F98564200255374 /* RileyLinkBLEKitTests */, - 43D5E78F1FAF7BFB004ACDB7 /* RileyLinkKitUI */, - C12EA239198B436800309FA4 /* Frameworks */, - C12EA238198B436800309FA4 /* Products */, - 437DE504229C898D003B1074 /* Scripts */, - ); - sourceTree = ""; - }; - C12EA238198B436800309FA4 /* Products */ = { - isa = PBXGroup; - children = ( - C12EA237198B436800309FA4 /* RileyLink.app */, - 43722FAE1CB9F7630038B7F2 /* RileyLinkKit.framework */, - 431CE76F1F98564100255374 /* RileyLinkBLEKit.framework */, - 431CE7771F98564200255374 /* RileyLinkBLEKitTests.xctest */, - 43D5E78E1FAF7BFB004ACDB7 /* RileyLinkKitUI.framework */, - ); - name = Products; - sourceTree = ""; - }; - C12EA239198B436800309FA4 /* Frameworks */ = { - isa = PBXGroup; - children = ( - C13F0436230B1DE6001413FF /* MKRingProgressView.framework */, - 43FB610B20DDF55F002B996B /* LoopKit.framework */, - 43FB610A20DDF55E002B996B /* LoopKitUI.framework */, - 43CA93241CB8BB33000026B5 /* CoreBluetooth.framework */, - C12616431B685F0A001FAD87 /* CoreData.framework */, - C12EA23A198B436800309FA4 /* Foundation.framework */, - C12EA23C198B436800309FA4 /* CoreGraphics.framework */, - C12EA23E198B436800309FA4 /* UIKit.framework */, - C12EA253198B436800309FA4 /* XCTest.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - C12EA240198B436800309FA4 /* RileyLink */ = { - isa = PBXGroup; - children = ( - C12572902121EEDE0061BA2F /* Views */, - C1274F7A1D8240D00002912B /* View Controllers */, - C14FFC4D1D3D6D8E0049CF85 /* Models */, - C1B383341CD1BA6700CE7782 /* Managers */, - C1AA398B1AB67F6A00BC9E33 /* Extensions */, - C12EA241198B436800309FA4 /* Supporting Files */, - 43462E8A1CCB06F500F958A8 /* AppDelegate.swift */, - C125729321220FEC0061BA2F /* MainStoryboard.storyboard */, - C1FC49EB2135CB2D007D0788 /* LaunchScreen.storyboard */, - C1FFAF71212FAAEF00C50C1D /* RileyLink.xcassets */, - C1EF58861B3F93FE001C8C80 /* Config.h */, - C1EF58871B3F93FE001C8C80 /* Config.m */, - C1271B081A9A350400B7C949 /* Log.h */, - C1271B061A9A34E900B7C949 /* Log.m */, - ); - path = RileyLink; - sourceTree = ""; - }; - C12EA241198B436800309FA4 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 7D7076971FE09311004AC8EA /* Localizable.strings */, - C1EAD6EA1C8409A9006DBA60 /* RileyLink-Bridging-Header.h */, - C12EA242198B436800309FA4 /* RileyLink-Info.plist */, - C1821693297E55A7001EB097 /* RileyLink-InfoPlist.strings */, - C1394BA7297E49630042F1A9 /* LoopKit.strings */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - C12EA259198B436900309FA4 /* RileyLinkTests */ = { - isa = PBXGroup; - children = ( - C12EA25F198B436900309FA4 /* RileyLinkTests.m */, - C12EA25A198B436900309FA4 /* Supporting Files */, - ); - path = RileyLinkTests; - sourceTree = SOURCE_ROOT; - }; - C12EA25A198B436900309FA4 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - C12EA25B198B436900309FA4 /* RileyLinkTests-Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - C14FFC4D1D3D6D8E0049CF85 /* Models */ = { - isa = PBXGroup; - children = ( - C14FFC621D3D7CE20049CF85 /* NightscoutService.swift */, - C14FFC4E1D3D6DEF0049CF85 /* ServiceAuthentication.swift */, - C14FFC4F1D3D6DEF0049CF85 /* ServiceCredential.swift */, - ); - path = Models; - sourceTree = ""; - }; - C1AA398B1AB67F6A00BC9E33 /* Extensions */ = { - isa = PBXGroup; - children = ( - C17884601D519F1E00405663 /* BatteryIndicator.swift */, - 437462381FA9287A00643383 /* RileyLinkDevice.swift */, - C14FFC541D3D72A50049CF85 /* UIViewController.swift */, - 435535D51FB6D98400CE5A23 /* UserDefaults.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - C1B383341CD1BA6700CE7782 /* Managers */ = { - isa = PBXGroup; - children = ( - C14FFC661D3D7E390049CF85 /* KeychainManager.swift */, - C14FFC681D3D7E560049CF85 /* KeychainManager+RileyLink.swift */, - C14FFC641D3D7E250049CF85 /* RemoteDataManager.swift */, - C1B383351CD1BA8100CE7782 /* DeviceDataManager.swift */, - C125728E2121DB7C0061BA2F /* PumpManagerState.swift */, - ); - name = Managers; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 431CE76C1F98564100255374 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 431CE7811F98564200255374 /* RileyLinkBLEKit.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43722FAB1CB9F7630038B7F2 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 43722FB11CB9F7640038B7F2 /* RileyLinkKit.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43D5E78B1FAF7BFB004ACDB7 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 43D5E7921FAF7BFB004ACDB7 /* RileyLinkKitUI.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 431CE76E1F98564100255374 /* RileyLinkBLEKit */ = { - isa = PBXNativeTarget; - buildConfigurationList = 431CE78A1F98564200255374 /* Build configuration list for PBXNativeTarget "RileyLinkBLEKit" */; - buildPhases = ( - 431CE76C1F98564100255374 /* Headers */, - 431CE76A1F98564100255374 /* Sources */, - 431CE76B1F98564100255374 /* Frameworks */, - 431CE76D1F98564100255374 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = RileyLinkBLEKit; - productName = RileyLinkBLEKit; - productReference = 431CE76F1F98564100255374 /* RileyLinkBLEKit.framework */; - productType = "com.apple.product-type.framework"; - }; - 431CE7761F98564200255374 /* RileyLinkBLEKitTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 431CE78B1F98564200255374 /* Build configuration list for PBXNativeTarget "RileyLinkBLEKitTests" */; - buildPhases = ( - 431CE7731F98564200255374 /* Sources */, - 431CE7741F98564200255374 /* Frameworks */, - 431CE7751F98564200255374 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 431CE77A1F98564200255374 /* PBXTargetDependency */, - ); - name = RileyLinkBLEKitTests; - productName = RileyLinkBLEKitTests; - productReference = 431CE7771F98564200255374 /* RileyLinkBLEKitTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 43722FAD1CB9F7630038B7F2 /* RileyLinkKit */ = { - isa = PBXNativeTarget; - buildConfigurationList = 43722FC91CB9F7640038B7F2 /* Build configuration list for PBXNativeTarget "RileyLinkKit" */; - buildPhases = ( - 43722FAB1CB9F7630038B7F2 /* Headers */, - 43722FA91CB9F7630038B7F2 /* Sources */, - 43722FAA1CB9F7630038B7F2 /* Frameworks */, - 43722FAC1CB9F7630038B7F2 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - A9B839CB22809DB3004E745E /* PBXTargetDependency */, - ); - name = RileyLinkKit; - productName = RileyLinkKit; - productReference = 43722FAE1CB9F7630038B7F2 /* RileyLinkKit.framework */; - productType = "com.apple.product-type.framework"; - }; - 43D5E78D1FAF7BFB004ACDB7 /* RileyLinkKitUI */ = { - isa = PBXNativeTarget; - buildConfigurationList = 43D5E7971FAF7BFB004ACDB7 /* Build configuration list for PBXNativeTarget "RileyLinkKitUI" */; - buildPhases = ( - 43D5E78B1FAF7BFB004ACDB7 /* Headers */, - 43D5E7891FAF7BFB004ACDB7 /* Sources */, - 43D5E78A1FAF7BFB004ACDB7 /* Frameworks */, - 43D5E78C1FAF7BFB004ACDB7 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - A9B839D122809DE7004E745E /* PBXTargetDependency */, - ); - name = RileyLinkKitUI; - productName = RileyLinkKitUI; - productReference = 43D5E78E1FAF7BFB004ACDB7 /* RileyLinkKitUI.framework */; - productType = "com.apple.product-type.framework"; - }; - C12EA236198B436800309FA4 /* RileyLink */ = { - isa = PBXNativeTarget; - buildConfigurationList = C12EA263198B436900309FA4 /* Build configuration list for PBXNativeTarget "RileyLink" */; - buildPhases = ( - C12EA233198B436800309FA4 /* Sources */, - C12EA234198B436800309FA4 /* Frameworks */, - C12EA235198B436800309FA4 /* Resources */, - C10D9BB81C82614F00378342 /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 43722FC21CB9F7640038B7F2 /* PBXTargetDependency */, - 431CE7831F98564200255374 /* PBXTargetDependency */, - 43D5E7941FAF7BFB004ACDB7 /* PBXTargetDependency */, - ); - name = RileyLink; - productName = RileyLink; - productReference = C12EA237198B436800309FA4 /* RileyLink.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - C12EA22F198B436800309FA4 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 1030; - LastUpgradeCheck = 1320; - ORGANIZATIONNAME = "Pete Schwamb"; - TargetAttributes = { - 431CE76E1F98564100255374 = { - CreatedOnToolsVersion = 9.0; - LastSwiftMigration = 1020; - ProvisioningStyle = Manual; - }; - 431CE7761F98564200255374 = { - CreatedOnToolsVersion = 9.0; - LastSwiftMigration = 1000; - ProvisioningStyle = Manual; - }; - 43722FAD1CB9F7630038B7F2 = { - CreatedOnToolsVersion = 7.3; - LastSwiftMigration = 1020; - }; - 43D5E78D1FAF7BFB004ACDB7 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1020; - ProvisioningStyle = Manual; - }; - C12EA236198B436800309FA4 = { - LastSwiftMigration = 1020; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = C12EA232198B436800309FA4 /* Build configuration list for PBXProject "RileyLink" */; - compatibilityVersion = "Xcode 6.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - es, - ru, - Base, - fr, - de, - "zh-Hans", - it, - nl, - nb, - pl, - vi, - ja, - sv, - da, - fi, - "pt-BR", - ro, - tr, - he, - sk, - cs, - ar, - hi, - hu, - ); - mainGroup = C12EA22E198B436800309FA4; - productRefGroup = C12EA238198B436800309FA4 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - C12EA236198B436800309FA4 /* RileyLink */, - 431CE76E1F98564100255374 /* RileyLinkBLEKit */, - 431CE7761F98564200255374 /* RileyLinkBLEKitTests */, - 43722FAD1CB9F7630038B7F2 /* RileyLinkKit */, - 43D5E78D1FAF7BFB004ACDB7 /* RileyLinkKitUI */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 431CE76D1F98564100255374 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7D23679421252EBC0028B67D /* Localizable.strings in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 431CE7751F98564200255374 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43722FAC1CB9F7630038B7F2 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43D5E78C1FAF7BFB004ACDB7 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7D23679721252EBC0028B67D /* Localizable.strings in Resources */, - 43709AEC20E0056F00F941B3 /* RileyLinkKitUI.xcassets in Resources */, - 43709AF020E0120F00F941B3 /* SetupImageTableViewCell.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C12EA235198B436800309FA4 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C125729421220FEC0061BA2F /* MainStoryboard.storyboard in Resources */, - C1821695297E55A7001EB097 /* RileyLink-InfoPlist.strings in Resources */, - C1394BA9297E49630042F1A9 /* LoopKit.strings in Resources */, - C1FFAF72212FAAEF00C50C1D /* RileyLink.xcassets in Resources */, - C1FC49EC2135CB2D007D0788 /* LaunchScreen.storyboard in Resources */, - 7D7076951FE09311004AC8EA /* Localizable.strings in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 431CE76A1F98564100255374 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7D2366F5212527DA0028B67D /* LocalizedString.swift in Sources */, - 43BA719D2026C9B00058961E /* ResponseBuffer.swift in Sources */, - C1FFAF6F212CB4F100C50C1D /* RileyLinkConnectionState.swift in Sources */, - 431CE78F1F985B6E00255374 /* CBPeripheral.swift in Sources */, - 431CE79F1F9C670600255374 /* TimeInterval.swift in Sources */, - 433ABFFC2016FDF700E6C1FF /* RileyLinkDeviceError.swift in Sources */, - 43BA719B202591A70058961E /* Response.swift in Sources */, - 43D5E7881FAEDAC4004ACDB7 /* PeripheralManagerError.swift in Sources */, - 431CE79C1F9B21BA00255374 /* RileyLinkDevice.swift in Sources */, - 431CE7A71F9D98F700255374 /* CommandSession.swift in Sources */, - 431CE7A31F9D737F00255374 /* Command.swift in Sources */, - 431CE7A11F9D195600255374 /* CBCentralManager.swift in Sources */, - 431CE7911F985D8D00255374 /* RileyLinkBluetoothDeviceProvider.swift in Sources */, - C1CAB67528C696D800F6F715 /* RileyLinkBluetoothDevice.swift in Sources */, - C1CAB67328C696A600F6F715 /* RileyLinkDeviceProvider.swift in Sources */, - 431CE78D1F985B5400255374 /* PeripheralManager.swift in Sources */, - 431CE79E1F9BE73900255374 /* BLEFirmwareVersion.swift in Sources */, - 432847C31FA57C0F00CDE69C /* RadioFirmwareVersion.swift in Sources */, - 431CE7931F985DE700255374 /* PeripheralManager+RileyLink.swift in Sources */, - 431CE79A1F9B0F1600255374 /* OSLog.swift in Sources */, - 43047FC91FAECA8700508343 /* Data.swift in Sources */, - 431CE7A51F9D78F500255374 /* RFPacket.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 431CE7731F98564200255374 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 4322B75620282DA60002837D /* ResponseBufferTests.swift in Sources */, - 43047FC41FAEC70600508343 /* RadioFirmwareVersionTests.swift in Sources */, - 43047FC71FAEC9BC00508343 /* Data.swift in Sources */, - 43047FC61FAEC83000508343 /* RFPacketTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43722FA91CB9F7630038B7F2 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7D2366F2212527DA0028B67D /* LocalizedString.swift in Sources */, - 43323EAA1FA81C1B003FB0FA /* RileyLinkDevice.swift in Sources */, - C1BB1460293835A8004CE8DA /* RileyLinkListDataSource.swift in Sources */, - 43EBE4531EAD23CE0073A0B5 /* TimeInterval.swift in Sources */, - 434AB0C71CBCB76400422F4A /* Data.swift in Sources */, - 4352A74120DED23100CAC200 /* RileyLinkDeviceManager.swift in Sources */, - 431CE7961F9B0F0200255374 /* OSLog.swift in Sources */, - 435D26B020DA08CE00891C17 /* RileyLinkPumpManager.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 43D5E7891FAF7BFB004ACDB7 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7D2366F6212527DA0028B67D /* LocalizedString.swift in Sources */, - 43BF58B31FF6079600499C46 /* TimeInterval.swift in Sources */, - 43D5E7A11FAF7CE0004ACDB7 /* UITableViewCell.swift in Sources */, - 43709AEE20E008F300F941B3 /* SetupImageTableViewCell.swift in Sources */, - 43709AF120E0127000F941B3 /* NibLoadable.swift in Sources */, - 43D5E7A31FAF7D05004ACDB7 /* CBPeripheralState.swift in Sources */, - 43D5E7A21FAF7CF2004ACDB7 /* CaseCountable.swift in Sources */, - 435D26B620DA0BCC00891C17 /* RileyLinkDevicesTableViewDataSource.swift in Sources */, - 43709AE820DF22E700F941B3 /* UIColor.swift in Sources */, - 43D5E79A1FAF7C47004ACDB7 /* RileyLinkDeviceTableViewCell.swift in Sources */, - 43F89CA122BDFB8D006BB54E /* UIActivityIndicatorView.swift in Sources */, - 43D5E79F1FAF7C98004ACDB7 /* IdentifiableClass.swift in Sources */, - 435D26B420DA0AAE00891C17 /* RileyLinkDevicesHeaderView.swift in Sources */, - 43709ABF20DF1C6400F941B3 /* RileyLinkSettingsViewController.swift in Sources */, - 43709ABD20DF1C6400F941B3 /* RileyLinkSetupTableViewController.swift in Sources */, - 43D5E79C1FAF7C47004ACDB7 /* RileyLinkDeviceTableViewController.swift in Sources */, - 43709ABE20DF1C6400F941B3 /* RileyLinkManagerSetupViewController.swift in Sources */, - 43D5E7A01FAF7CCA004ACDB7 /* NumberFormatter.swift in Sources */, - 43709AE420DF20D500F941B3 /* OSLog.swift in Sources */, - C14F71D426A675BC00FA09F0 /* CommandResponseViewController.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C12EA233198B436800309FA4 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 435535D61FB6D98400CE5A23 /* UserDefaults.swift in Sources */, - 43EBE4551EAD24410073A0B5 /* TimeInterval.swift in Sources */, - C14FFC691D3D7E560049CF85 /* KeychainManager+RileyLink.swift in Sources */, - 437F540A1FBFDAA60070FF2C /* Data.swift in Sources */, - C14FFC511D3D6DEF0049CF85 /* ServiceCredential.swift in Sources */, - C14FFC5B1D3D74F90049CF85 /* NibLoadable.swift in Sources */, - C12572922121EEEE0061BA2F /* SettingsImageTableViewCell.swift in Sources */, - C125728D2121D56D0061BA2F /* CaseCountable.swift in Sources */, - C14FFC611D3D75470049CF85 /* UIColor.swift in Sources */, - 43323EA71FA81A0F003FB0FA /* NumberFormatter.swift in Sources */, - C14FFC671D3D7E390049CF85 /* KeychainManager.swift in Sources */, - C14FFC501D3D6DEF0049CF85 /* ServiceAuthentication.swift in Sources */, - 43462E8B1CCB06F500F958A8 /* AppDelegate.swift in Sources */, - C125728C2121D4D60061BA2F /* UITableViewCell.swift in Sources */, - C14FFC551D3D72A50049CF85 /* UIViewController.swift in Sources */, - 7D2366F0212527DA0028B67D /* LocalizedString.swift in Sources */, - C14FFC651D3D7E250049CF85 /* RemoteDataManager.swift in Sources */, - C17884611D519F1E00405663 /* BatteryIndicator.swift in Sources */, - 437462391FA9287A00643383 /* RileyLinkDevice.swift in Sources */, - C1274F801D82411C0002912B /* MainViewController.swift in Sources */, - 431CE7981F9B0F0200255374 /* OSLog.swift in Sources */, - C1EF58881B3F93FE001C8C80 /* Config.m in Sources */, - C125728F2121DB7C0061BA2F /* PumpManagerState.swift in Sources */, - C14FFC631D3D7CE20049CF85 /* NightscoutService.swift in Sources */, - C1B383361CD1BA8100CE7782 /* DeviceDataManager.swift in Sources */, - C1271B071A9A34E900B7C949 /* Log.m in Sources */, - 434FF1DC1CF268BD000DB779 /* IdentifiableClass.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 431CE77A1F98564200255374 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 431CE76E1F98564100255374 /* RileyLinkBLEKit */; - targetProxy = 431CE7791F98564200255374 /* PBXContainerItemProxy */; - }; - 431CE7831F98564200255374 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 431CE76E1F98564100255374 /* RileyLinkBLEKit */; - targetProxy = 431CE7821F98564200255374 /* PBXContainerItemProxy */; - }; - 43722FC21CB9F7640038B7F2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 43722FAD1CB9F7630038B7F2 /* RileyLinkKit */; - targetProxy = 43722FC11CB9F7640038B7F2 /* PBXContainerItemProxy */; - }; - 43D5E7941FAF7BFB004ACDB7 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 43D5E78D1FAF7BFB004ACDB7 /* RileyLinkKitUI */; - targetProxy = 43D5E7931FAF7BFB004ACDB7 /* PBXContainerItemProxy */; - }; - A9B839CB22809DB3004E745E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 431CE76E1F98564100255374 /* RileyLinkBLEKit */; - targetProxy = A9B839CA22809DB3004E745E /* PBXContainerItemProxy */; - }; - A9B839D122809DE7004E745E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 43722FAD1CB9F7630038B7F2 /* RileyLinkKit */; - targetProxy = A9B839D022809DE7004E745E /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 7D23679221252EBC0028B67D /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 7D23679321252EBC0028B67D /* es */, - 7D23679821252F050028B67D /* Base */, - 7D23679A21252FF30028B67D /* de */, - 7D23679C2125300A0028B67D /* fr */, - 7D23679E212530160028B67D /* it */, - 7D2367A0212530230028B67D /* nb */, - 7D2367A2212530300028B67D /* ru */, - 7D2367A42125303D0028B67D /* zh-Hans */, - 7D2367A62125304D0028B67D /* nl */, - 7D199DAF212A159A00241026 /* pl */, - 7D9BF0102336A2D3005DCFD6 /* vi */, - 7D9BF0182336A2E3005DCFD6 /* ja */, - 7D9BF0202336A2EA005DCFD6 /* sv */, - 7D9BF0282336A2F2005DCFD6 /* da */, - 7D9BF0302336A2FB005DCFD6 /* fi */, - 7D9BF0382336A304005DCFD6 /* pt-BR */, - 7D9BF15123371408005DCFD6 /* ro */, - F5D9C04827DAC30C002E48F6 /* tr */, - F5E0BE2A27E1DF280033557E /* he */, - C1DEE897298309EA0008194D /* sk */, - C12BCD0629BBFA490066A158 /* cs */, - 193F1E472B44C20400525770 /* hu */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - 7D23679521252EBC0028B67D /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 7D23679621252EBC0028B67D /* es */, - 7D23679921252F0D0028B67D /* Base */, - 7D23679B21252FF30028B67D /* de */, - 7D23679D2125300A0028B67D /* fr */, - 7D23679F212530160028B67D /* it */, - 7D2367A1212530230028B67D /* nb */, - 7D2367A3212530300028B67D /* ru */, - 7D2367A52125303D0028B67D /* zh-Hans */, - 7D2367A72125304D0028B67D /* nl */, - 7D199DB2212A159A00241026 /* pl */, - 7D9BF0112336A2D3005DCFD6 /* vi */, - 7D9BF0192336A2E3005DCFD6 /* ja */, - 7D9BF0212336A2EA005DCFD6 /* sv */, - 7D9BF0292336A2F2005DCFD6 /* da */, - 7D9BF0312336A2FB005DCFD6 /* fi */, - 7D9BF0392336A304005DCFD6 /* pt-BR */, - 7D9BF15223371408005DCFD6 /* ro */, - F5D9C04927DAC30C002E48F6 /* tr */, - F5E0BE2B27E1DF280033557E /* he */, - C1DEE898298309EA0008194D /* sk */, - C12BCD0729BBFA490066A158 /* cs */, - C1FAB5CB29C786B000D25073 /* hi */, - C12B52E029C8142E0025DA95 /* ar */, - 193F1E482B44C20500525770 /* hu */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - 7D7076971FE09311004AC8EA /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 7D7076961FE09311004AC8EA /* es */, - 7D68AACE1FE31DEB00522C49 /* ru */, - 7D2366F8212528560028B67D /* Base */, - 7D2366FB212529510028B67D /* fr */, - 7D2367072125297B0028B67D /* de */, - 7D236713212529810028B67D /* zh-Hans */, - 7D23671F212529890028B67D /* it */, - 7D23672B212529950028B67D /* nl */, - 7D2367372125299F0028B67D /* nb */, - 7D199DA4212A159900241026 /* pl */, - 7D9BEFEA23369382005DCFD6 /* en */, - 7D9BF00E2336A2D3005DCFD6 /* vi */, - 7D9BF0162336A2E3005DCFD6 /* ja */, - 7D9BF01E2336A2EA005DCFD6 /* sv */, - 7D9BF0262336A2F1005DCFD6 /* da */, - 7D9BF02E2336A2FB005DCFD6 /* fi */, - 7D9BF0362336A304005DCFD6 /* pt-BR */, - 7D9BF14F23371407005DCFD6 /* ro */, - F5D9C04627DAC30B002E48F6 /* tr */, - F5E0BE2827E1DF280033557E /* he */, - C1DEE894298309EA0008194D /* sk */, - C12BCD0329BBFA490066A158 /* cs */, - C15A583529C7866600D3A5A1 /* ar */, - C1FAB5CA29C786B000D25073 /* hi */, - 193F1E462B44C20400525770 /* hu */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - C1394BA7297E49630042F1A9 /* LoopKit.strings */ = { - isa = PBXVariantGroup; - children = ( - C1394BA8297E49630042F1A9 /* pl */, - C1821692297E55A7001EB097 /* es */, - C1AB0C542981EE5B0020FEE5 /* da */, - C1DCAF512981EE5D00118AD3 /* de */, - C151BED32981EE6000F3A41F /* fi */, - C18700782981EE6100E06588 /* fr */, - C1CB33F72981EE650019F1C3 /* nb */, - C1E28AFC2981EE6600758EB3 /* nl */, - C126DD162981EE69009A0A64 /* ro */, - C153EBB12981EE6C000BFE9E /* sv */, - C1BCB5C0298309C4001C50FF /* it */, - C1DEE895298309EA0008194D /* sk */, - C147B997299581ED00BF55AC /* he */, - C14952172995822A0095AA84 /* ru */, - C1B267A32995824000BCB7C1 /* tr */, - C12BCD0429BBFA490066A158 /* cs */, - C15A583629C7866600D3A5A1 /* ar */, - C1B0CFDF29C786BF0045B04D /* ja */, - C1E693D529C786E200410918 /* pt-BR */, - C192C60929C78711001EFEA6 /* vi */, - ); - name = LoopKit.strings; - sourceTree = ""; - }; - C1821693297E55A7001EB097 /* RileyLink-InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - C1821694297E55A7001EB097 /* es */, - C1C6038C2983092100FC4128 /* de */, - C11613512983096D00777E7C /* nb */, - C1BCB5C1298309C4001C50FF /* it */, - C1DEE896298309EA0008194D /* sk */, - C11A2BD329830A3100AC5135 /* fr */, - C18886EC29830A5E004C982D /* nl */, - C18B7265299581C600F138D3 /* da */, - C147B998299581ED00BF55AC /* he */, - C1F490042995821600C8BD69 /* pl */, - C1E8ADD32995822300AB9EEB /* ro */, - C14952182995822A0095AA84 /* ru */, - C1B267A42995824000BCB7C1 /* tr */, - C12BCD0529BBFA490066A158 /* cs */, - ); - name = "RileyLink-InfoPlist.strings"; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 431CE7861F98564200255374 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - CODE_SIGN_STYLE = Manual; - DEBUG_INFORMATION_FORMAT = dwarf; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 46; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = RileyLinkBLEKit/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkBLEKit; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 431CE7871F98564200255374 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - CODE_SIGN_STYLE = Manual; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 46; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = RileyLinkBLEKit/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkBLEKit; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 431CE7881F98564200255374 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = ""; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = RileyLinkBLEKitTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkBLEKitTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 431CE7891F98564200255374 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = ""; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = RileyLinkBLEKitTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkBLEKitTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 43722FC51CB9F7640038B7F2 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - CURRENT_PROJECT_VERSION = 46; - DEBUG_INFORMATION_FORMAT = dwarf; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 46; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = RileyLinkKit/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkKit; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 43722FC61CB9F7640038B7F2 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 46; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 46; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = RileyLinkKit/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkKit; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 43D5E7981FAF7BFB004ACDB7 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - CODE_SIGN_STYLE = Manual; - DEBUG_INFORMATION_FORMAT = dwarf; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 46; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = RileyLinkKitUI/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkKitUI; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 43D5E7991FAF7BFB004ACDB7 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - CODE_SIGN_STYLE = Manual; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 46; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = RileyLinkKitUI/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkKitUI; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - C12EA261198B436900309FA4 /* 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - 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; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 46; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - 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_SYMBOLS_PRIVATE_EXTERN = NO; - 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 = 15.1; - LOCALIZED_STRING_MACRO_NAMES = ( - NSLocalizedString, - CFLocalizedString, - LocalizedString, - FrameworkLocalText, - ); - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - WARNING_CFLAGS = "-Wall"; - }; - name = Debug; - }; - C12EA262198B436900309FA4 /* 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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - 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; - COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 46; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - 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 = 15.1; - LOCALIZED_STRING_MACRO_NAMES = ( - NSLocalizedString, - CFLocalizedString, - LocalizedString, - FrameworkLocalText, - ); - SDKROOT = iphoneos; - SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - WARNING_CFLAGS = "-Wall"; - }; - name = Release; - }; - C12EA264198B436900309FA4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DEVELOPMENT_TEAM = ""; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = "RileyLink/RileyLink-Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.rlapp; - PRODUCT_NAME = RileyLink; - PROVISIONING_PROFILE = ""; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OBJC_BRIDGING_HEADER = "RileyLink/RileyLink-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - TARGETED_DEVICE_FAMILY = 1; - WRAPPER_EXTENSION = app; - }; - name = Debug; - }; - C12EA265198B436900309FA4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DEVELOPMENT_TEAM = ""; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = "RileyLink/RileyLink-Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.rlapp; - PRODUCT_NAME = RileyLink; - PROVISIONING_PROFILE = ""; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OBJC_BRIDGING_HEADER = "RileyLink/RileyLink-Bridging-Header.h"; - TARGETED_DEVICE_FAMILY = 1; - WRAPPER_EXTENSION = app; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 431CE78A1F98564200255374 /* Build configuration list for PBXNativeTarget "RileyLinkBLEKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 431CE7861F98564200255374 /* Debug */, - 431CE7871F98564200255374 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 431CE78B1F98564200255374 /* Build configuration list for PBXNativeTarget "RileyLinkBLEKitTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 431CE7881F98564200255374 /* Debug */, - 431CE7891F98564200255374 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 43722FC91CB9F7640038B7F2 /* Build configuration list for PBXNativeTarget "RileyLinkKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 43722FC51CB9F7640038B7F2 /* Debug */, - 43722FC61CB9F7640038B7F2 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 43D5E7971FAF7BFB004ACDB7 /* Build configuration list for PBXNativeTarget "RileyLinkKitUI" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 43D5E7981FAF7BFB004ACDB7 /* Debug */, - 43D5E7991FAF7BFB004ACDB7 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C12EA232198B436800309FA4 /* Build configuration list for PBXProject "RileyLink" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C12EA261198B436900309FA4 /* Debug */, - C12EA262198B436900309FA4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C12EA263198B436900309FA4 /* Build configuration list for PBXNativeTarget "RileyLink" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C12EA264198B436900309FA4 /* Debug */, - C12EA265198B436900309FA4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = C12EA22F198B436800309FA4 /* Project object */; -} diff --git a/Dependencies/rileylink_ios/RileyLink.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Dependencies/rileylink_ios/RileyLink.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 94c213d25..000000000 --- a/Dependencies/rileylink_ios/RileyLink.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Dependencies/rileylink_ios/RileyLink.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dependencies/rileylink_ios/RileyLink.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Dependencies/rileylink_ios/RileyLink.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Dependencies/rileylink_ios/RileyLink.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Dependencies/rileylink_ios/RileyLink.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index 08de0be8d..000000000 --- a/Dependencies/rileylink_ios/RileyLink.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded - - - diff --git a/Dependencies/rileylink_ios/RileyLink/AppDelegate.swift b/Dependencies/rileylink_ios/RileyLink/AppDelegate.swift deleted file mode 100644 index 963856ae0..000000000 --- a/Dependencies/rileylink_ios/RileyLink/AppDelegate.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// AppDelegate.swift -// RileyLink -// -// Created by Nathan Racklyeft on 4/22/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -import UIKit -import SwiftUI -import CoreData -import LoopKitUI -import RileyLinkKit - - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - private(set) lazy var deviceDataManager = DeviceDataManager() - - var window: UIWindow? - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - - if let navController = self.window?.rootViewController as? UINavigationController { - let mainViewController = MainViewController(deviceDataManager: deviceDataManager, insulinTintColor: .orange, guidanceColors: GuidanceColors(acceptable: .primary, warning: .yellow, critical: .red)) - navController.pushViewController(mainViewController, animated: false) - } - - return true - } - - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. - NSLog(#function) - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - NSLog(#function) - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - NSLog(#function) - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - NSLog(#function) - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - NSLog(#function) - } - - // MARK: - 3D Touch - - func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) { - completionHandler(false) - } -} - - -private func applicationDocumentsDirectory() -> URL { - return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last! -} - diff --git a/Dependencies/rileylink_ios/RileyLink/AuthenticationViewController.swift b/Dependencies/rileylink_ios/RileyLink/AuthenticationViewController.swift deleted file mode 100644 index 51f6fb8aa..000000000 --- a/Dependencies/rileylink_ios/RileyLink/AuthenticationViewController.swift +++ /dev/null @@ -1,205 +0,0 @@ -// -// AuthenticationViewController.swift -// Loop -// -// Created by Nate Racklyeft on 7/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -class AuthenticationViewController: UITableViewController, IdentifiableClass, UITextFieldDelegate { - - typealias AuthenticationObserver = (authentication: T) -> Void - - var authenticationObserver: AuthenticationObserver? - - var authentication: T - - private var state: AuthenticationState = .Empty { - didSet { - switch (oldValue, state) { - case let (x, y) where x == y: - break - case (_, .Verifying): - let titleView = ValidatingIndicatorView(frame: CGRect.zero) - UIView.animateWithDuration(0.25) { - self.navigationItem.hidesBackButton = true - self.navigationItem.titleView = titleView - } - - tableView.reloadSections(NSIndexSet(indexesInRange: NSRange(0...1)), withRowAnimation: .Automatic) - authentication.verify { [unowned self] (success, error) in - dispatch_async(dispatch_get_main_queue()) { - UIView.animateWithDuration(0.25) { - self.navigationItem.titleView = nil - self.navigationItem.hidesBackButton = false - } - - if success { - self.state = .Authorized - } else { - if let error = error { - self.presentAlertControllerWithError(error) - } - - self.state = .Unauthorized - } - } - } - case (_, .Authorized), (_, .Unauthorized): - authenticationObserver?(authentication: authentication) - tableView.reloadSections(NSIndexSet(indexesInRange: NSRange(0...1)), withRowAnimation: .Automatic) - default: - break - } - } - } - - init(authentication: T) { - self.authentication = authentication - - state = authentication.isAuthorized ? .Authorized : .Unauthorized - - super.init(style: .Grouped) - - title = authentication.title - } - - override func viewDidLoad() { - super.viewDidLoad() - - tableView.registerNib(AuthenticationTableViewCell.nib(), forCellReuseIdentifier: AuthenticationTableViewCell.className) - tableView.registerNib(ButtonTableViewCell.nib(), forCellReuseIdentifier: ButtonTableViewCell.className) - } - - // MARK: - Table view data source - - override func numberOfSectionsInTableView(tableView: UITableView) -> Int { - return Section.count - } - - override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch Section(rawValue: section)! { - case .Credentials: - switch state { - case .Authorized: - return authentication.credentials.filter({ !$0.isSecret }).count - default: - return authentication.credentials.count - } - case .Button: - return 1 - } - } - - override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { - switch Section(rawValue: indexPath.section)! { - case .Button: - let cell = tableView.dequeueReusableCellWithIdentifier(ButtonTableViewCell.className, forIndexPath: indexPath) as! ButtonTableViewCell - - switch state { - case .Authorized: - cell.button.setTitle(NSLocalizedString("Delete Account", comment: "The title of the button to remove the credentials for a service"), forState: .Normal) - cell.button.setTitleColor(UIColor.deleteColor, forState: .Normal) - case .Empty, .Unauthorized, .Verifying: - cell.button.setTitle(NSLocalizedString("Add Account", comment: "The title of the button to add the credentials for a service"), forState: .Normal) - cell.button.setTitleColor(nil, forState: .Normal) - } - - if case .Verifying = state { - cell.button.enabled = false - } else { - cell.button.enabled = true - } - - cell.button.addTarget(self, action: #selector(buttonPressed(_:)), forControlEvents: .TouchUpInside) - - return cell - case .Credentials: - let cell = tableView.dequeueReusableCellWithIdentifier(AuthenticationTableViewCell.className, forIndexPath: indexPath) as! AuthenticationTableViewCell - - let credential = authentication.credentials[indexPath.row] - - cell.titleLabel.text = credential.title - cell.textField.tag = indexPath.row - cell.textField.keyboardType = credential.keyboardType - cell.textField.secureTextEntry = credential.isSecret - cell.textField.returnKeyType = (indexPath.row < authentication.credentials.count - 1) ? .Next : .Done - cell.textField.text = credential.value - cell.textField.placeholder = credential.placeholder ?? NSLocalizedString("Required", comment: "The default placeholder string for a credential") - - cell.textField.delegate = self - - switch state { - case .Authorized, .Verifying, .Empty: - cell.textField.enabled = false - case .Unauthorized: - cell.textField.enabled = true - } - - return cell - } - } - - private func validate() { - state = .Verifying - } - - // MARK: - Actions - - @objc private func buttonPressed(_: AnyObject) { - tableView.endEditing(false) - - switch state { - case .Authorized: - authentication.reset() - state = .Unauthorized - case .Unauthorized: - validate() - default: - break - } - - } - - // MARK: - UITextFieldDelegate - - func textFieldDidEndEditing(textField: UITextField) { - authentication.credentials[textField.tag].value = textField.text - } - - func textFieldShouldReturn(textField: UITextField) -> Bool { - if textField.returnKeyType == .Done { - textField.resignFirstResponder() - } else { - let point = tableView.convertPoint(textField.frame.origin, fromView: textField.superview) - if let indexPath = tableView.indexPathForRowAtPoint(point), - cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: indexPath.row + 1, inSection: indexPath.section)) as? AuthenticationTableViewCell - { - cell.textField.becomeFirstResponder() - - validate() - } - } - - return true - } -} - - -private enum Section: Int { - case Credentials - case Button - - static let count = 2 -} - - -enum AuthenticationState { - case Empty - case Authorized - case Verifying - case Unauthorized -} diff --git a/Dependencies/rileylink_ios/RileyLink/Base.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/Base.lproj/Localizable.strings deleted file mode 100644 index 7b8ff1d7f..000000000 --- a/Dependencies/rileylink_ios/RileyLink/Base.lproj/Localizable.strings +++ /dev/null @@ -1,51 +0,0 @@ -/* The title of the about section */ -"About" = "About"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Add Account"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API Secret"; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuration"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Delete Account"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Enter the 6-digit pump ID"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Fetch CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pump ID"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pumps"; - -/* The default placeholder string for a credential */ -"Required" = "Required"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink Testing"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Setup Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "Site URL"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Tap to set"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Upload To Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/Config.h b/Dependencies/rileylink_ios/RileyLink/Config.h deleted file mode 100644 index 341888c2e..000000000 --- a/Dependencies/rileylink_ios/RileyLink/Config.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// Config.h -// RileyLink -// -// Created by Pete Schwamb on 6/27/15. -// Copyright (c) 2015 Pete Schwamb. All rights reserved. -// - -#import - -@interface Config : NSObject { - NSUserDefaults *_defaults; -} - -+ (nonnull Config *)sharedInstance; - -@property (nonatomic, nullable, strong) NSURL *nightscoutURL; -@property (nonatomic, nullable, strong) NSString *nightscoutAPISecret; -@property (nonatomic, nullable, strong) NSSet *autoConnectIds; -@property (nonatomic, assign) BOOL uploadEnabled; -@property (nonatomic, assign) BOOL fetchCGMEnabled; - -@end diff --git a/Dependencies/rileylink_ios/RileyLink/Config.m b/Dependencies/rileylink_ios/RileyLink/Config.m deleted file mode 100644 index 54673374a..000000000 --- a/Dependencies/rileylink_ios/RileyLink/Config.m +++ /dev/null @@ -1,86 +0,0 @@ -// -// Config.m -// RileyLink -// -// Created by Pete Schwamb on 6/27/15. -// Copyright (c) 2015 Pete Schwamb. All rights reserved. -// - -@import CoreData; -#import "Config.h" -#import - -@implementation Config - -+ (Config *)sharedInstance -{ - // structure used to test whether the block has completed or not - static dispatch_once_t p = 0; - - // initialize sharedObject as nil (first call only) - __strong static Config * _sharedObject = nil; - - // executes a block object once and only once for the lifetime of an application - dispatch_once(&p, ^{ - _sharedObject = [[self alloc] init]; - }); - - // returns the same object each time - return _sharedObject; -} - -- (instancetype)init { - if (self = [super init]) { - _defaults = [NSUserDefaults standardUserDefaults]; - } - - return self; -} - - -- (void) setNightscoutURL:(NSURL *)nightscoutURL { - [_defaults setValue:nightscoutURL.absoluteString forKey:@"nightscoutURL"]; -} - -- (NSURL*) nightscoutURL { - return [NSURL URLWithString:[_defaults stringForKey:@"nightscoutURL"]]; -} - -- (void) setNightscoutAPISecret:(NSString *)nightscoutAPISecret { - [_defaults setValue:nightscoutAPISecret forKey:@"nightscoutAPISecret"]; -} - -- (NSString*) nightscoutAPISecret { - return [_defaults stringForKey:@"nightscoutAPISecret"]; -} - -- (NSSet*) autoConnectIds { - NSSet *set = [[NSUserDefaults standardUserDefaults] objectForKey:@"autoConnectIds"]; - if (!set) { - set = [NSSet set]; - } - return set; -} - -- (void) setAutoConnectIds:(NSSet *)autoConnectIds { - [[NSUserDefaults standardUserDefaults] setObject:[autoConnectIds allObjects] forKey:@"autoConnectIds"]; -} - -- (BOOL) uploadEnabled { - return [[NSUserDefaults standardUserDefaults] boolForKey:@"uploadEnabled"]; -} - -- (void) setUploadEnabled:(BOOL)uploadEnabled { - [[NSUserDefaults standardUserDefaults] setBool:uploadEnabled forKey:@"uploadEnabled"]; -} - -- (BOOL) fetchCGMEnabled { - return [[NSUserDefaults standardUserDefaults] boolForKey:@"fetchCGMEnabled"]; -} - -- (void) setFetchCGMEnabled:(BOOL)fetchCGMEnabled { - [[NSUserDefaults standardUserDefaults] setBool:fetchCGMEnabled forKey:@"fetchCGMEnabled"]; -} - - -@end diff --git a/Dependencies/rileylink_ios/RileyLink/DeviceDataManager.swift b/Dependencies/rileylink_ios/RileyLink/DeviceDataManager.swift deleted file mode 100644 index d388f6d6c..000000000 --- a/Dependencies/rileylink_ios/RileyLink/DeviceDataManager.swift +++ /dev/null @@ -1,131 +0,0 @@ -// -// DeviceDataManager.swift -// RileyLink -// -// Created by Pete Schwamb on 4/27/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -import Foundation -import RileyLinkKit -import RileyLinkKitUI -import RileyLinkBLEKit -import MinimedKit -import MinimedKitUI -import NightscoutKit -import LoopKit -import LoopKitUI -import UserNotifications -import os.log -import UserNotifications - -class DeviceDataManager { - - let rileyLinkDeviceProvider: RileyLinkDeviceProvider - - var pumpManager: PumpManagerUI? { - didSet { - pumpManager?.pumpManagerDelegate = self - UserDefaults.standard.pumpManagerRawValue = pumpManager?.rawValue - } - } - - - public let log = OSLog(category: "DeviceDataManager") - - init() { - - let connectionManagerState = UserDefaults.standard.rileyLinkConnectionManagerState - rileyLinkDeviceProvider = RileyLinkBluetoothDeviceProvider(autoConnectIDs: connectionManagerState?.autoConnectIDs ?? []) - rileyLinkDeviceProvider.delegate = self - rileyLinkDeviceProvider.setScanningEnabled(true) - - if let pumpManagerRawValue = UserDefaults.standard.pumpManagerRawValue { - pumpManager = PumpManagerFromRawValue(pumpManagerRawValue, rileyLinkDeviceProvider: rileyLinkDeviceProvider) as? PumpManagerUI - pumpManager?.pumpManagerDelegate = self - } - } -} - -extension DeviceDataManager: RileyLinkDeviceProviderDelegate { - func rileylinkDeviceProvider(_ rileylinkDeviceProvider: RileyLinkBLEKit.RileyLinkDeviceProvider, didChange state: RileyLinkBLEKit.RileyLinkConnectionState) { - UserDefaults.standard.rileyLinkConnectionManagerState = state - } -} - -extension DeviceDataManager: PumpManagerDelegate { - func pumpManagerPumpWasReplaced(_ pumpManager: LoopKit.PumpManager) { - } - - var detectedSystemTimeOffset: TimeInterval { - return 0; - } - - func pumpManager(_ pumpManager: PumpManager, didAdjustPumpClockBy adjustment: TimeInterval) { - log.debug("didAdjustPumpClockBy %@", adjustment) - } - - func pumpManagerDidUpdateState(_ pumpManager: PumpManager) { - UserDefaults.standard.pumpManagerRawValue = pumpManager.rawValue - } - - func pumpManagerBLEHeartbeatDidFire(_ pumpManager: PumpManager) { - } - - func pumpManagerMustProvideBLEHeartbeat(_ pumpManager: PumpManager) -> Bool { - return true - } - - func pumpManager(_ pumpManager: PumpManager, didUpdate status: PumpManagerStatus, oldStatus: PumpManagerStatus) { - } - - func pumpManagerWillDeactivate(_ pumpManager: PumpManager) { - self.pumpManager = nil - } - - func pumpManager(_ pumpManager: PumpManager, didUpdatePumpRecordsBasalProfileStartEvents pumpRecordsBasalProfileStartEvents: Bool) { - } - - func pumpManager(_ pumpManager: PumpManager, didError error: PumpManagerError) { - log.error("pumpManager didError %@", String(describing: error)) - } - - func pumpManager(_ pumpManager: PumpManager, hasNewPumpEvents events: [NewPumpEvent], lastSync lastReconciliation: Date?, completion: @escaping (_ error: Error?) -> Void) { - } - - func pumpManager(_ pumpManager: PumpManager, didReadReservoirValue units: Double, at date: Date, completion: @escaping (Result<(newValue: ReservoirValue, lastValue: ReservoirValue?, areStoredValuesContinuous: Bool), Error>) -> Void) { - } - - func pumpManagerRecommendsLoop(_ pumpManager: PumpManager) { - } - - func startDateToFilterNewPumpEvents(for manager: PumpManager) -> Date { - return Date().addingTimeInterval(.hours(-2)) - } -} - -// MARK: - DeviceManagerDelegate -extension DeviceDataManager: DeviceManagerDelegate { - func doesIssuedAlertExist(identifier: LoopKit.Alert.Identifier, completion: @escaping (Result) -> Void) { - } - - func lookupAllUnretracted(managerIdentifier: String, completion: @escaping (Result<[LoopKit.PersistedAlert], Error>) -> Void) { - } - - func lookupAllUnacknowledgedUnretracted(managerIdentifier: String, completion: @escaping (Result<[LoopKit.PersistedAlert], Error>) -> Void) { - } - - func recordRetractedAlert(_ alert: LoopKit.Alert, at date: Date) { - } - - func deviceManager(_ manager: DeviceManager, logEventForDeviceIdentifier deviceIdentifier: String?, type: DeviceLogEntryType, message: String, completion: ((Error?) -> Void)?) {} -} - -// MARK: - AlertPresenter -extension DeviceDataManager: AlertIssuer { - func issueAlert(_ alert: Alert) { - } - - func retractAlert(identifier: Alert.Identifier) { - } -} diff --git a/Dependencies/rileylink_ios/RileyLink/Extensions/BatteryIndicator.swift b/Dependencies/rileylink_ios/RileyLink/Extensions/BatteryIndicator.swift deleted file mode 100644 index 39723023b..000000000 --- a/Dependencies/rileylink_ios/RileyLink/Extensions/BatteryIndicator.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// BatteryIndicator.swift -// RileyLink -// -// Created by Pete Schwamb on 8/2/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -import NightscoutKit -import MinimedKit - -public extension BatteryIndicator { - init?(batteryStatus: MinimedKit.BatteryStatus) { - switch batteryStatus { - case .low: - self = .low - case .normal: - self = .normal - default: - return nil - } - } -} diff --git a/Dependencies/rileylink_ios/RileyLink/Extensions/RileyLinkDevice.swift b/Dependencies/rileylink_ios/RileyLink/Extensions/RileyLinkDevice.swift deleted file mode 100644 index fae80993f..000000000 --- a/Dependencies/rileylink_ios/RileyLink/Extensions/RileyLinkDevice.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// RileyLinkDevice.swift -// RileyLink -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import RileyLinkBLEKit - - -extension RileyLinkDevice.IdleListeningState { - static var enabledWithDefaults: RileyLinkDevice.IdleListeningState { - return .enabled(timeout: .minutes(1), channel: 0) - } -} diff --git a/Dependencies/rileylink_ios/RileyLink/Extensions/UIViewController.swift b/Dependencies/rileylink_ios/RileyLink/Extensions/UIViewController.swift deleted file mode 100644 index c3c325e9b..000000000 --- a/Dependencies/rileylink_ios/RileyLink/Extensions/UIViewController.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// UIViewController.swift -// -// Created by Nathan Racklyeft on 1/16/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -extension UIViewController { - /** - Convenience method to present an alert controller on the active view controller - - - parameter title: The title of the alert - - parameter message: The message of the alert - - parameter animated: Whether to animate the alert - - parameter completion: An optional closure to execute after the presentation finishes - */ - public func presentAlertControllerWithTitle(_ title: String?, message: String, animated: Bool = true, completion: (() -> Void)? = nil) { - let alert = UIAlertController( - title: title, - message: message, - preferredStyle: .alert - ) - - let action = UIAlertAction( - title: LocalizedString("com.loudnate.LoopKit.errorAlertActionTitle", tableName: "LoopKit", value: "OK", comment: "The title of the action used to dismiss an error alert"), - style: .default, - handler: nil - ) - - alert.addAction(action) - alert.preferredAction = action - - presentViewControllerOnActiveViewController(alert, animated: animated, completion: completion) - } - - /** - Convenience method to display an error object in an alert controller - - - parameter error: The error to display - - parameter animated: Whether to animate the alert - - parameter completion: An optional closure to execute after the presentation finishes - */ - public func presentAlertControllerWithError(_ error: Error, animated: Bool = true, completion: (() -> Void)? = nil) { - - // See: https://forums.developer.apple.com/thread/17431 - // The compiler automatically emits the code necessary to translate between any ErrorType and NSError. - let castedError: NSError = error as NSError - - presentAlertControllerWithTitle(error.localizedDescription, - message: castedError.userInfo[NSLocalizedRecoverySuggestionErrorKey] as? String ?? String(describing: error), - animated: animated, - completion: completion - ) - } - - /** - Convenience method to present a view controller on the active view controller. - - If the receiver is not in a window, or already has a presented view controller, this method will - attempt to find the most appropriate view controller for presenting. - - - parameter viewControllerToPresent: The view controller to display over the view controller’s content - - parameter animated: Whether to animate the presentation - - parameter completion: An optional closure to execute after the presentation finishes - */ - public func presentViewControllerOnActiveViewController(_ viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Void)?) { - var presentingViewController: UIViewController? = self - - if presentingViewController?.view.window == nil { - presentingViewController = UIApplication.shared.delegate?.window??.rootViewController - } - - while presentingViewController?.presentedViewController != nil { - presentingViewController = presentingViewController?.presentedViewController - } - - presentingViewController?.present(viewControllerToPresent, animated: animated, completion: completion) - } -} diff --git a/Dependencies/rileylink_ios/RileyLink/Extensions/UserDefaults.swift b/Dependencies/rileylink_ios/RileyLink/Extensions/UserDefaults.swift deleted file mode 100644 index 823542a6e..000000000 --- a/Dependencies/rileylink_ios/RileyLink/Extensions/UserDefaults.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// UserDefaults.swift -// RileyLink -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation -import LoopKit -import RileyLinkKit -import RileyLinkBLEKit - -extension UserDefaults { - private enum Key: String { - case pumpManagerRawValue = "com.rileylink.PumpManagerRawValue" - case rileyLinkConnectionManagerState = "com.rileylink.RileyLinkConnectionManagerState" - } - - var pumpManagerRawValue: PumpManager.RawStateValue? { - get { - return dictionary(forKey: Key.pumpManagerRawValue.rawValue) - } - set { - set(newValue, forKey: Key.pumpManagerRawValue.rawValue) - } - } - - var rileyLinkConnectionManagerState: RileyLinkConnectionState? { - get { - guard let rawValue = dictionary(forKey: Key.rileyLinkConnectionManagerState.rawValue) else - { - return nil - } - return RileyLinkConnectionState(rawValue: rawValue) - } - set { - set(newValue?.rawValue, forKey: Key.rileyLinkConnectionManagerState.rawValue) - } - } - -} - diff --git a/Dependencies/rileylink_ios/RileyLink/KeychainManager+RileyLink.swift b/Dependencies/rileylink_ios/RileyLink/KeychainManager+RileyLink.swift deleted file mode 100644 index 867a78da8..000000000 --- a/Dependencies/rileylink_ios/RileyLink/KeychainManager+RileyLink.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// KeychainManager+Loop.swift -// -// Created by Nate Racklyeft on 6/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation - - -private let NightscoutAccount = "NightscoutAPI" - - -extension KeychainManager { - - func setNightscoutURL(_ url: URL?, secret: String?) { - do { - let credentials: InternetCredentials? - - if let url = url, let secret = secret { - credentials = InternetCredentials(username: NightscoutAccount, password: secret, url: url) - } else { - credentials = nil - } - - try replaceInternetCredentials(credentials, forAccount: NightscoutAccount) - } catch { - } - } - - func getNightscoutCredentials() -> (url: URL, secret: String)? { - do { - let credentials = try getInternetCredentials(account: NightscoutAccount) - - return (url: credentials.url, secret: credentials.password) - } catch { - return nil - } - } -} diff --git a/Dependencies/rileylink_ios/RileyLink/KeychainManager.swift b/Dependencies/rileylink_ios/RileyLink/KeychainManager.swift deleted file mode 100644 index ff0e0db0d..000000000 --- a/Dependencies/rileylink_ios/RileyLink/KeychainManager.swift +++ /dev/null @@ -1,290 +0,0 @@ -// -// KeychainManager.swift -// Loop -// -// Created by Nate Racklyeft on 6/26/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import Security - - -enum KeychainManagerError: Error { - case add(OSStatus) - case copy(OSStatus) - case delete(OSStatus) - case unknownResult -} - - -/** - - Influenced by https://github.com/marketplacer/keychain-swift - */ -struct KeychainManager { - typealias Query = [String: NSObject] - - var accessibility: CFString = kSecAttrAccessibleAfterFirstUnlock - - var accessGroup: String? - - struct InternetCredentials { - let username: String - let password: String - let url: URL - } - - // MARK: - Convenience methods - - private func query(by class: CFString) -> Query { - var query: Query = [kSecClass as String: `class`] - - if let accessGroup = accessGroup { - query[kSecAttrAccessGroup as String] = accessGroup as NSObject? - } - - return query - } - - private func queryForGenericPassword(by service: String) -> Query { - var query = self.query(by: kSecClassGenericPassword) - - query[kSecAttrService as String] = service as NSObject? - - return query - } - - private func queryForInternetPassword(account: String? = nil, url: URL? = nil) -> Query { - var query = self.query(by: kSecClassInternetPassword) - - if let account = account { - query[kSecAttrAccount as String] = account as NSObject? - } - - if let url = url, let components = URLComponents(url: url, resolvingAgainstBaseURL: true) { - for (key, value) in components.keychainAttributes { - query[key] = value - } - } - - return query - } - - private func updatedQuery(_ query: Query, withPassword password: String) throws -> Query { - var query = query - - guard let value = password.data(using: String.Encoding.utf8) else { - throw KeychainManagerError.add(errSecDecode) - } - - query[kSecValueData as String] = value as NSObject? - query[kSecAttrAccessible as String] = accessibility - - return query - } - - func delete(_ query: Query) throws { - let statusCode = SecItemDelete(query as CFDictionary) - - guard statusCode == errSecSuccess || statusCode == errSecItemNotFound else { - throw KeychainManagerError.delete(statusCode) - } - } - - // MARK: – Generic Passwords - - func replaceGenericPassword(_ password: String?, forService service: String) throws { - var query = queryForGenericPassword(by: service) - - try delete(query) - - guard let password = password else { - return - } - - query = try updatedQuery(query, withPassword: password) - - let statusCode = SecItemAdd(query as CFDictionary, nil) - - guard statusCode == errSecSuccess else { - throw KeychainManagerError.add(statusCode) - } - } - - func getGenericPasswordForService(_ service: String) throws -> String { - var query = queryForGenericPassword(by: service) - - query[kSecReturnData as String] = kCFBooleanTrue - query[kSecMatchLimit as String] = kSecMatchLimitOne - - var result: AnyObject? - - let statusCode = SecItemCopyMatching(query as CFDictionary, &result) - - guard statusCode == errSecSuccess else { - throw KeychainManagerError.copy(statusCode) - } - - guard let passwordData = result as? Data, let password = String(data: passwordData, encoding: String.Encoding.utf8) else { - throw KeychainManagerError.unknownResult - } - - return password - } - - // MARK – Internet Passwords - - func setInternetPassword(_ password: String, forAccount account: String, atURL url: URL) throws { - var query = try updatedQuery(queryForInternetPassword(account: account, url: url), withPassword: password) - - query[kSecAttrAccount as String] = account as NSObject? - - if let components = URLComponents(url: url, resolvingAgainstBaseURL: true) { - for (key, value) in components.keychainAttributes { - query[key] = value - } - } - - let statusCode = SecItemAdd(query as CFDictionary, nil) - - guard statusCode == errSecSuccess else { - throw KeychainManagerError.add(statusCode) - } - } - - func replaceInternetCredentials(_ credentials: InternetCredentials?, forAccount account: String) throws { - let query = queryForInternetPassword(account: account) - - try delete(query) - - if let credentials = credentials { - try setInternetPassword(credentials.password, forAccount: credentials.username, atURL: credentials.url) - } - } - - func replaceInternetCredentials(_ credentials: InternetCredentials?, forURL url: URL) throws { - let query = queryForInternetPassword(url: url) - - try delete(query) - - if let credentials = credentials { - try setInternetPassword(credentials.password, forAccount: credentials.username, atURL: credentials.url) - } - } - - func getInternetCredentials(account: String? = nil, url: URL? = nil) throws -> InternetCredentials { - var query = queryForInternetPassword(account: account, url: url) - - query[kSecReturnData as String] = kCFBooleanTrue - query[kSecReturnAttributes as String] = kCFBooleanTrue - query[kSecMatchLimit as String] = kSecMatchLimitOne - - var result: AnyObject? - - let statusCode: OSStatus = SecItemCopyMatching(query as CFDictionary, &result) - - guard statusCode == errSecSuccess else { - throw KeychainManagerError.copy(statusCode) - } - - if let result = result as? [AnyHashable: Any], let passwordData = result[kSecValueData as String] as? Data, - let password = String(data: passwordData, encoding: String.Encoding.utf8), - let url = URLComponents(keychainAttributes: result)?.url, - let username = result[kSecAttrAccount as String] as? String - { - return InternetCredentials(username: username, password: password, url: url) - } - - throw KeychainManagerError.unknownResult - } -} - - -private enum SecurityProtocol { - case http - case https - - init?(scheme: String?) { - switch scheme?.lowercased() { - case "http"?: - self = .http - case "https"?: - self = .https - default: - return nil - } - } - - init?(secAttrProtocol: CFString) { - if secAttrProtocol == kSecAttrProtocolHTTP { - self = .http - } else if secAttrProtocol == kSecAttrProtocolHTTPS { - self = .https - } else { - return nil - } - } - - var scheme: String { - switch self { - case .http: - return "http" - case .https: - return "https" - } - } - - var secAttrProtocol: CFString { - switch self { - case .http: - return kSecAttrProtocolHTTP - case .https: - return kSecAttrProtocolHTTPS - } - } -} - - -private extension URLComponents { - init?(keychainAttributes: [AnyHashable: Any]) { - self.init() - - if let secAttProtocol = keychainAttributes[kSecAttrProtocol as String] { - scheme = SecurityProtocol(secAttrProtocol: secAttProtocol as! CFString)?.scheme - } - - host = keychainAttributes[kSecAttrServer as String] as? String - - if let port = keychainAttributes[kSecAttrPort as String] as? Int, port > 0 { - self.port = port - } - - if let path = keychainAttributes[kSecAttrPath as String] as? String { - self.path = path - } - } - - var keychainAttributes: [String: NSObject] { - var query: [String: NSObject] = [:] - - if let `protocol` = SecurityProtocol(scheme: scheme) { - query[kSecAttrProtocol as String] = `protocol`.secAttrProtocol - } - - if let host = host { - query[kSecAttrServer as String] = host as NSObject - } - - if let port = port { - query[kSecAttrPort as String] = port as NSObject - } - - if !path.isEmpty { - query[kSecAttrPath as String] = path as NSObject - } - - return query - } -} - diff --git a/Dependencies/rileylink_ios/RileyLink/LaunchScreen.storyboard b/Dependencies/rileylink_ios/RileyLink/LaunchScreen.storyboard deleted file mode 100644 index 168440827..000000000 --- a/Dependencies/rileylink_ios/RileyLink/LaunchScreen.storyboard +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/rileylink_ios/RileyLink/Log.h b/Dependencies/rileylink_ios/RileyLink/Log.h deleted file mode 100644 index 90b2d686c..000000000 --- a/Dependencies/rileylink_ios/RileyLink/Log.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// Log.h -// GlucoseLink -// -// Created by Pete Schwamb on 2/22/15. -// Copyright (c) 2015 Pete Schwamb. All rights reserved. -// - -#ifndef RILEYLINK_Log_h -#define RILEYLINK_Log_h - -//#define LOG_TO_NS 1 - -#define NSLog(args...) _Log(@"DEBUG ", __FILE__,__LINE__,__PRETTY_FUNCTION__,args); -@interface Log : NSObject - -+ (NSArray*) popLogEntries; - -void _Log(NSString *prefix, const char *file, int lineNumber, const char *funcName, NSString *format,...); -@end - -void logMemUsage(void); - -#endif diff --git a/Dependencies/rileylink_ios/RileyLink/Log.m b/Dependencies/rileylink_ios/RileyLink/Log.m deleted file mode 100644 index 36f672239..000000000 --- a/Dependencies/rileylink_ios/RileyLink/Log.m +++ /dev/null @@ -1,96 +0,0 @@ -// -// Log.m -// GlucoseLink -// -// Created by Pete Schwamb on 2/22/15. -// Copyright (c) 2015 Pete Schwamb. All rights reserved. -// - -#import -#import "mach/mach.h" -#import "Log.h" - -NSMutableArray *logEntries = nil; - -@implementation Log - -vm_size_t usedMemory(void) { - struct task_basic_info info; - mach_msg_type_number_t size = sizeof(info); - kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size); - return (kerr == KERN_SUCCESS) ? info.resident_size : 0; // size in bytes -} - -vm_size_t freeMemory(void) { - mach_port_t host_port = mach_host_self(); - mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t); - vm_size_t pagesize; - vm_statistics_data_t vm_stat; - - host_page_size(host_port, &pagesize); - (void) host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size); - return vm_stat.free_count * pagesize; -} - -void logMemUsage(void) { - // compute memory usage and log if different by >= 100k - static long prevMemUsage = 0; - long curMemUsage = usedMemory(); - long memUsageDiff = curMemUsage - prevMemUsage; - - if (memUsageDiff > 100000 || memUsageDiff < -100000) { - prevMemUsage = curMemUsage; - NSLog(@"Memory used %7.1f (%+5.0f), free %7.1f kb", curMemUsage/1000.0f, memUsageDiff/1000.0f, freeMemory()/1000.0f); - } -} - -+ (NSArray*) popLogEntries { - NSArray *rval = logEntries; - logEntries = [NSMutableArray array]; - if (rval == nil) { - rval = [NSMutableArray array]; - } - return rval; -} - -void append(NSString *msg){ - if (logEntries == nil) { - logEntries = [NSMutableArray array]; - } -#ifdef LOG_TO_NS - [logEntries addObject:msg]; -#endif - // get path to Documents/somefile.txt - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *documentsDirectory = paths[0]; - NSString *path = [documentsDirectory stringByAppendingPathComponent:@"logfile.txt"]; - // create if needed - if (![[NSFileManager defaultManager] fileExistsAtPath:path]){ - fprintf(stderr,"Creating file at %s",path.UTF8String); - [[NSData data] writeToFile:path atomically:YES]; - } - // append - NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:path]; - [handle truncateFileAtOffset:[handle seekToEndOfFile]]; - [handle writeData:[msg dataUsingEncoding:NSUTF8StringEncoding]]; - [handle closeFile]; -} - -void _Log(NSString *prefix, const char *file, int lineNumber, const char *funcName, NSString *format,...) { - - static NSDateFormatter *dateFormat = nil; - if (nil == dateFormat) { - dateFormat = [[NSDateFormatter alloc] init]; // NOT NSDateFormatter *dateFormat = ... - dateFormat.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS"; - } - - va_list ap; - va_start (ap, format); - format = [format stringByAppendingString:@"\n"]; - NSDate *time = [NSDate date]; - NSString *msg = [[NSString alloc] initWithFormat:[NSString stringWithFormat:@"%@: %@", [dateFormat stringFromDate:time], format] arguments:ap]; - va_end (ap); - fprintf(stderr,"%s", msg.UTF8String); - append(msg); -} -@end \ No newline at end of file diff --git a/Dependencies/rileylink_ios/RileyLink/MainStoryboard.storyboard b/Dependencies/rileylink_ios/RileyLink/MainStoryboard.storyboard deleted file mode 100644 index fae14a8ab..000000000 --- a/Dependencies/rileylink_ios/RileyLink/MainStoryboard.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/rileylink_ios/RileyLink/Models/NightscoutService.swift b/Dependencies/rileylink_ios/RileyLink/Models/NightscoutService.swift deleted file mode 100644 index c6730f306..000000000 --- a/Dependencies/rileylink_ios/RileyLink/Models/NightscoutService.swift +++ /dev/null @@ -1,88 +0,0 @@ -// -// NightscoutService.swift -// Loop -// -// Created by Nate Racklyeft on 7/3/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import NightscoutKit - - -// Encapsulates a Nightscout site and its authentication -struct NightscoutService: ServiceAuthentication { - var credentials: [ServiceCredential] - - let title: String = LocalizedString("Nightscout", comment: "The title of the Nightscout service") - - init(siteURL: URL?, APISecret: String?) { - credentials = [ - ServiceCredential( - title: LocalizedString("Site URL", comment: "The title of the nightscout site URL credential"), - placeholder: LocalizedString("http://mysite.herokuapp.com", comment: "The placeholder text for the nightscout site URL credential"), - isSecret: false, - keyboardType: .URL, - value: siteURL?.absoluteString - ), - ServiceCredential( - title: LocalizedString("API Secret", comment: "The title of the nightscout API secret credential"), - placeholder: nil, - isSecret: false, - keyboardType: .asciiCapable, - value: APISecret - ) - ] - - verify { _, _ in } - } - - // The uploader instance, if credentials are present - private(set) var uploader: NightscoutClient? { - didSet { - uploader?.errorHandler = { (error: Error, context: String) -> Void in - print("Error \(error), while \(context)") - } - } - } - - var siteURL: URL? { - if let URLString = credentials[0].value { - return URL(string: URLString) - } - - return nil - } - - var APISecret: String? { - return credentials[1].value - } - - private(set) var isAuthorized: Bool = false - - mutating func verify(_ completion: @escaping (_ success: Bool, _ error: Error?) -> Void) { - - guard let siteURL = siteURL, let APISecret = APISecret else { - completion(false, nil) - return - } - self.uploader = NightscoutClient(siteURL: siteURL, apiSecret: APISecret) - - self.uploader?.checkAuth({ (error) in - if let error = error { - // self.isAuthorized = false - completion(false, error) - } else { - // self.isAuthorized = true - completion(true, nil) - } - }) - } - - mutating func reset() { - credentials[0].value = nil - credentials[1].value = nil - isAuthorized = false - uploader = nil - } -} diff --git a/Dependencies/rileylink_ios/RileyLink/Models/ServiceAuthentication.swift b/Dependencies/rileylink_ios/RileyLink/Models/ServiceAuthentication.swift deleted file mode 100644 index cda3338c9..000000000 --- a/Dependencies/rileylink_ios/RileyLink/Models/ServiceAuthentication.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// ServiceAuthentication.swift -// Loop -// -// Created by Nate Racklyeft on 7/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - - -// Defines the authentication for a service -protocol ServiceAuthentication { - // The title of the service - var title: String { get } - - // The credentials (e.g. username, password) used to authenticate - var credentials: [ServiceCredential] { get set } - - // Whether the current credential values are valid authorization - var isAuthorized: Bool { get } - - // Tests the credentials for valid authorization - mutating func verify(_ completion: @escaping (_ success: Bool, _ error: Error?) -> Void) - - // Clears the credential values and authorization status - mutating func reset() -} diff --git a/Dependencies/rileylink_ios/RileyLink/Models/ServiceCredential.swift b/Dependencies/rileylink_ios/RileyLink/Models/ServiceCredential.swift deleted file mode 100644 index 255661754..000000000 --- a/Dependencies/rileylink_ios/RileyLink/Models/ServiceCredential.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// ServiceCredential.swift -// Loop -// -// Created by Nate Racklyeft on 7/2/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -// Represents a credential for a service, including its text input traits -struct ServiceCredential { - // The localized title of the credential (e.g. "Username") - let title: String - - // The localized placeholder text to assist text input - let placeholder: String? - - // Whether the credential is considered secret. Correponds to the `secureTextEntry` trait. - let isSecret: Bool - - // The type of keyboard to use to enter the credential - let keyboardType: UIKeyboardType - - // The credential value - var value: String? -} diff --git a/Dependencies/rileylink_ios/RileyLink/PumpManagerState.swift b/Dependencies/rileylink_ios/RileyLink/PumpManagerState.swift deleted file mode 100644 index 8a7e758a4..000000000 --- a/Dependencies/rileylink_ios/RileyLink/PumpManagerState.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// PumpManagerState.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit -import MinimedKit -import RileyLinkBLEKit -import OmniKit - - -let allPumpManagers: [String: PumpManager.Type] = [ - MinimedPumpManager.managerIdentifier: MinimedPumpManager.self -] - -func PumpManagerFromRawValue(_ rawValue: [String: Any], rileyLinkDeviceProvider: RileyLinkDeviceProvider) -> PumpManager? { - guard let managerIdentifier = rawValue["managerIdentifier"] as? String, - let rawState = rawValue["state"] as? PumpManager.RawStateValue - else { - return nil - } - - switch (managerIdentifier) { - case MinimedPumpManager.managerIdentifier: - guard let state = MinimedPumpManagerState(rawValue: rawState) else { - return nil - } - return MinimedPumpManager(state: state, rileyLinkDeviceProvider: rileyLinkDeviceProvider) - case OmnipodPumpManager.managerIdentifier: - guard let state = OmnipodPumpManagerState(rawValue: rawState) else { - return nil - } - return OmnipodPumpManager(state: state, rileyLinkDeviceProvider: rileyLinkDeviceProvider) - default: - return nil - } -} - -extension PumpManager { - var rawValue: [String: Any] { - return [ - "managerIdentifier": type(of: self).managerIdentifier, - "state": self.rawState - ] - } -} diff --git a/Dependencies/rileylink_ios/RileyLink/RemoteDataManager.swift b/Dependencies/rileylink_ios/RileyLink/RemoteDataManager.swift deleted file mode 100644 index 5458990b4..000000000 --- a/Dependencies/rileylink_ios/RileyLink/RemoteDataManager.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// RemoteDataManager.swift -// Loop -// -// Created by Nate Racklyeft on 6/29/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import NightscoutKit - - -class RemoteDataManager { - - var NightscoutClient: NightscoutClient? { - return nightscoutService.uploader - } - - var nightscoutService: NightscoutService { - didSet { - keychain.setNightscoutURL(nightscoutService.siteURL, secret: nightscoutService.APISecret) - } - } - - private let keychain = KeychainManager() - - init() { - // Migrate config setttings to the Keychain - - if let (siteURL, APISecret) = keychain.getNightscoutCredentials() { - nightscoutService = NightscoutService(siteURL: siteURL, APISecret: APISecret) - } else if let siteURL = Config.sharedInstance().nightscoutURL, - let APISecret = Config.sharedInstance().nightscoutAPISecret - { - keychain.setNightscoutURL(siteURL, secret: APISecret) - nightscoutService = NightscoutService(siteURL: siteURL, APISecret: APISecret) - } else { - nightscoutService = NightscoutService(siteURL: nil, APISecret: nil) - } - - } - -} diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink-Bridging-Header.h b/Dependencies/rileylink_ios/RileyLink/RileyLink-Bridging-Header.h deleted file mode 100644 index cc86ad5b7..000000000 --- a/Dependencies/rileylink_ios/RileyLink/RileyLink-Bridging-Header.h +++ /dev/null @@ -1,7 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - -#import "Config.h" -#import "Log.h" -#import diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink-Info.plist b/Dependencies/rileylink_ios/RileyLink/RileyLink-Info.plist deleted file mode 100644 index 6c9826a3c..000000000 --- a/Dependencies/rileylink_ios/RileyLink/RileyLink-Info.plist +++ /dev/null @@ -1,60 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - ${PRODUCT_NAME} - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleGetInfoString - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - 3.0 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - LSApplicationCategoryType - - LSRequiresIPhoneOS - - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - - UIBackgroundModes - - bluetooth-central - - UIFileSharingEnabled - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - MainStoryboard - UIRequiredDeviceCapabilities - - bluetooth-le - armv7 - - UIStatusBarHidden - - UIStatusBarStyle - UIStatusBarStyleLightContent - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - - - diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/Contents.json b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 88f2478e0..000000000 --- a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "icon_20pt@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "icon_20pt@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "icon_29pt@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "icon_29pt@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "icon_40pt@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "icon_40pt@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "icon_60pt@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "icon_60pt@3x.png", - "scale" : "3x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/Icon.png b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/Icon.png deleted file mode 100644 index 1500aeb6b..000000000 Binary files a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/Icon.png and /dev/null differ diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_20pt@2x.png b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_20pt@2x.png deleted file mode 100644 index 5a6fadfd8..000000000 Binary files a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_20pt@2x.png and /dev/null differ diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_20pt@3x.png b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_20pt@3x.png deleted file mode 100644 index cc5160f58..000000000 Binary files a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_20pt@3x.png and /dev/null differ diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_29pt@2x.png b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_29pt@2x.png deleted file mode 100644 index 7bf874074..000000000 Binary files a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_29pt@2x.png and /dev/null differ diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_29pt@3x.png b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_29pt@3x.png deleted file mode 100644 index 6b88558d7..000000000 Binary files a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_29pt@3x.png and /dev/null differ diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_40pt@2x.png b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_40pt@2x.png deleted file mode 100644 index 2062b649e..000000000 Binary files a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_40pt@2x.png and /dev/null differ diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_40pt@3x.png b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_40pt@3x.png deleted file mode 100644 index fcd8373c1..000000000 Binary files a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_40pt@3x.png and /dev/null differ diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_60pt@2x.png b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_60pt@2x.png deleted file mode 100644 index fcd8373c1..000000000 Binary files a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_60pt@2x.png and /dev/null differ diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_60pt@3x.png b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_60pt@3x.png deleted file mode 100644 index 28a97c49f..000000000 Binary files a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/AppIcon.appiconset/icon_60pt@3x.png and /dev/null differ diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/Contents.json b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/Contents.json deleted file mode 100644 index da4a164c9..000000000 --- a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/RileyLink Tint.colorset/Contents.json b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/RileyLink Tint.colorset/Contents.json deleted file mode 100644 index 9ce21bd7c..000000000 --- a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/RileyLink Tint.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - }, - "colors" : [ - { - "idiom" : "universal", - "color" : { - "color-space" : "srgb", - "components" : { - "red" : "0x57", - "alpha" : "1.000", - "blue" : "0xD5", - "green" : "0x55" - } - } - } - ] -} \ No newline at end of file diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/RileyLink.imageset/Contents.json b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/RileyLink.imageset/Contents.json deleted file mode 100644 index cfe31b855..000000000 --- a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/RileyLink.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "RileyLink.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template" - } -} \ No newline at end of file diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/RileyLink.imageset/RileyLink.pdf b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/RileyLink.imageset/RileyLink.pdf deleted file mode 100644 index 69cc898de..000000000 Binary files a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcassets/RileyLink.imageset/RileyLink.pdf and /dev/null differ diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcdatamodeld/RileyLink.xcdatamodel/contents b/Dependencies/rileylink_ios/RileyLink/RileyLink.xcdatamodeld/RileyLink.xcdatamodel/contents deleted file mode 100644 index 101023af1..000000000 --- a/Dependencies/rileylink_ios/RileyLink/RileyLink.xcdatamodeld/RileyLink.xcdatamodel/contents +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLinkListTableViewController.swift b/Dependencies/rileylink_ios/RileyLink/RileyLinkListTableViewController.swift deleted file mode 100644 index d8ec3db96..000000000 --- a/Dependencies/rileylink_ios/RileyLink/RileyLinkListTableViewController.swift +++ /dev/null @@ -1,155 +0,0 @@ -// -// RileyLinkListTableViewController.swift -// RileyLink -// -// Created by Pete Schwamb on 5/11/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -import UIKit -import RileyLinkKit - -class RileyLinkListTableViewController: UITableViewController { - - // Retreive the managedObjectContext from AppDelegate - let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext - - override func viewDidLoad() { - super.viewDidLoad() - - tableView.registerNib(RileyLinkDeviceTableViewCell.nib(), forCellReuseIdentifier: RileyLinkDeviceTableViewCell.className) - - dataManagerObserver = NSNotificationCenter.defaultCenter().addObserverForName(nil, object: dataManager, queue: nil) { [weak self = self] (note) -> Void in - if let deviceManager = self?.dataManager.rileyLinkManager { - switch note.name { - case RileyLinkDeviceManager.DidDiscoverDeviceNotification: - self?.tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: deviceManager.devices.count - 1, inSection: 0)], withRowAnimation: .Automatic) - case RileyLinkDeviceManager.ConnectionStateDidChangeNotification, - RileyLinkDeviceManager.RSSIDidChangeNotification, - RileyLinkDeviceManager.NameDidChangeNotification: - if let device = note.userInfo?[RileyLinkDeviceManager.RileyLinkDeviceKey] as? RileyLinkDevice, index = deviceManager.devices.indexOf({ $0 === device }) { - self?.tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: index, inSection: 0)], withRowAnimation: .None) - } - default: - break - } - } - } - } - - deinit { - dataManagerObserver = nil - } - - private var dataManagerObserver: AnyObject? { - willSet { - if let observer = dataManagerObserver { - NSNotificationCenter.defaultCenter().removeObserver(observer) - } - } - } - - private var dataManager: DeviceDataManager { - return DeviceDataManager.sharedManager - } - - override func viewDidAppear(animated: Bool) { - super.viewDidAppear(animated) - - dataManager.rileyLinkManager.deviceScanningEnabled = true - } - - override func viewWillDisappear(animated: Bool) { - super.viewWillDisappear(animated) - - dataManager.rileyLinkManager.deviceScanningEnabled = false - } - - // MARK: Table view data source - - override func numberOfSectionsInTableView(tableView: UITableView) -> Int { - return 1 - } - - override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return dataManager.rileyLinkManager.devices.count - } - - override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { - let cell: UITableViewCell - - let deviceCell = tableView.dequeueReusableCellWithIdentifier(RileyLinkDeviceTableViewCell.className) as! RileyLinkDeviceTableViewCell - - let device = dataManager.rileyLinkManager.devices[indexPath.row] - - deviceCell.configureCellWithName(device.name, - signal: device.RSSI, - peripheralState: device.peripheral.state - ) - - deviceCell.connectSwitch.addTarget(self, action: #selector(deviceConnectionChanged(_:)), forControlEvents: .ValueChanged) - - cell = deviceCell - return cell - } - - func deviceConnectionChanged(connectSwitch: UISwitch) { - let switchOrigin = connectSwitch.convertPoint(.zero, toView: tableView) - - if let indexPath = tableView.indexPathForRowAtPoint(switchOrigin) - { - let device = dataManager.rileyLinkManager.devices[indexPath.row] - - if connectSwitch.on { - dataManager.connectToRileyLink(device) - } else { - dataManager.disconnectFromRileyLink(device) - } - } - } - - // MARK: - UITableViewDelegate - - override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { - let vc = RileyLinkDeviceTableViewController() - - vc.device = dataManager.rileyLinkManager.devices[indexPath.row] - - showViewController(vc, sender: indexPath) - } - - /* - // Override to support conditional editing of the table view. - - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { - // Return NO if you do not want the specified item to be editable. - return YES; - } - */ - - /* - // Override to support editing the table view. - - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { - if (editingStyle == UITableViewCellEditingStyleDelete) { - // Delete the row from the data source - [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; - } else if (editingStyle == UITableViewCellEditingStyleInsert) { - // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view - } - } - */ - - /* - // Override to support rearranging the table view. - - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { - } - */ - - /* - // Override to support conditional rearranging of the table view. - - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { - // Return NO if you do not want the item to be re-orderable. - return YES; - } - */ - -} \ No newline at end of file diff --git a/Dependencies/rileylink_ios/RileyLink/RileyLinkModel.xcdatamodeld/RileyLinkModel.xcdatamodel/contents b/Dependencies/rileylink_ios/RileyLink/RileyLinkModel.xcdatamodeld/RileyLinkModel.xcdatamodel/contents deleted file mode 100644 index c4b2298a0..000000000 --- a/Dependencies/rileylink_ios/RileyLink/RileyLinkModel.xcdatamodeld/RileyLinkModel.xcdatamodel/contents +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Dependencies/rileylink_ios/RileyLink/SettingsTableViewController.swift b/Dependencies/rileylink_ios/RileyLink/SettingsTableViewController.swift deleted file mode 100644 index d75d89a18..000000000 --- a/Dependencies/rileylink_ios/RileyLink/SettingsTableViewController.swift +++ /dev/null @@ -1,199 +0,0 @@ -// -// SettingsTableViewController.swift -// RileyLink -// -// Created by Nathan Racklyeft on 8/29/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import RileyLinkKit - -private let ConfigCellIdentifier = "ConfigTableViewCell" - -private let TapToSetString = NSLocalizedString("Tap to set", comment: "The empty-state text for a configuration value") - -class SettingsTableViewController: UITableViewController, TextFieldTableViewControllerDelegate { - - private enum Section: Int { - case About = 0 - case Upload - case Configuration - - static let count = 3 - } - - private enum AboutRow: Int { - case Version = 0 - - static let count = 1 - } - - private enum UploadRow: Int { - case Upload = 0 - - static let count = 1 - } - - private enum ConfigurationRow: Int { - case PumpID = 0 - case Nightscout - static let count = 2 - } - - private var dataManager: DeviceDataManager { - return DeviceDataManager.sharedManager - } - - // MARK: - UITableViewDataSource - - override func numberOfSectionsInTableView(tableView: UITableView) -> Int { - return Section.count - } - - override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch Section(rawValue: section)! { - case .About: - return AboutRow.count - case .Upload: - return UploadRow.count - case .Configuration: - return ConfigurationRow.count - } - } - - override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { - let cell: UITableViewCell - - switch Section(rawValue: indexPath.section)! { - case .About: - switch AboutRow(rawValue: indexPath.row)! { - case .Version: - let versionCell = UITableViewCell(style: .Default, reuseIdentifier: "Version") - versionCell.selectionStyle = .None - let version = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString")! - versionCell.textLabel?.text = "RileyLink iOS v\(version)" - - return versionCell - } - case .Upload: - switch UploadRow(rawValue: indexPath.row)! { - case .Upload: - let switchCell = tableView.dequeueReusableCellWithIdentifier(SwitchTableViewCell.className, forIndexPath: indexPath) as! SwitchTableViewCell - - switchCell.`switch`?.on = Config.sharedInstance().uploadEnabled - switchCell.titleLabel.text = NSLocalizedString("Upload To Nightscout", comment: "The title text for the nightscout upload enabled switch cell") - switchCell.`switch`?.addTarget(self, action: #selector(uploadEnabledChanged(_:)), forControlEvents: .ValueChanged) - - return switchCell - } - case .Configuration: - let configCell = tableView.dequeueReusableCellWithIdentifier(ConfigCellIdentifier, forIndexPath: indexPath) - - switch ConfigurationRow(rawValue: indexPath.row)! { - case .PumpID: - configCell.textLabel?.text = NSLocalizedString("Pump ID", comment: "The title text for the pump ID config value") - configCell.detailTextLabel?.text = DeviceDataManager.sharedManager.pumpID ?? TapToSetString - case .Nightscout: - let nightscoutService = dataManager.remoteDataManager.nightscoutService - - configCell.textLabel?.text = nightscoutService.title - configCell.detailTextLabel?.text = nightscoutService.siteURL?.absoluteString ?? TapToSetString - } - cell = configCell - } - return cell - } - - override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - switch Section(rawValue: section)! { - case .About: - return NSLocalizedString("About", comment: "The title of the about section") - case .Upload: - return nil - case .Configuration: - return NSLocalizedString("Configuration", comment: "The title of the configuration section in settings") - } - } - - // MARK: - UITableViewDelegate - - override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { - switch Section(rawValue: indexPath.section)! { - case .Configuration: - let sender = tableView.cellForRowAtIndexPath(indexPath) - - switch ConfigurationRow(rawValue: indexPath.row)! { - case .PumpID: - performSegueWithIdentifier(TextFieldTableViewController.className, sender: sender) - case .Nightscout: - let service = dataManager.remoteDataManager.nightscoutService - let vc = AuthenticationViewController(authentication: service) - vc.authenticationObserver = { [unowned self] (service) in - self.dataManager.remoteDataManager.nightscoutService = service - - self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None) - } - - showViewController(vc, sender: indexPath) - } - case .Upload, .About: - break - } - } - - override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - switch Section(rawValue: section)! { - case .Upload, .Configuration, .About: - return nil - } - } - - // MARK: - Navigation - - override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { - if let - cell = sender as? UITableViewCell, - indexPath = tableView.indexPathForCell(cell) - { - switch segue.destinationViewController { - case let vc as TextFieldTableViewController: - switch ConfigurationRow(rawValue: indexPath.row)! { - case .PumpID: - vc.placeholder = NSLocalizedString("Enter the 6-digit pump ID", comment: "The placeholder text instructing users how to enter a pump ID") - vc.value = DeviceDataManager.sharedManager.pumpID - default: - break - } - - vc.title = cell.textLabel?.text - vc.indexPath = indexPath - vc.delegate = self - default: - break - } - } - } - - // MARK: - Uploader mangement - - func uploadEnabledChanged(sender: UISwitch) { - Config.sharedInstance().uploadEnabled = sender.on - } - - // MARK: - TextFieldTableViewControllerDelegate - - func textFieldTableViewControllerDidEndEditing(controller: TextFieldTableViewController) { - if let indexPath = controller.indexPath { - switch ConfigurationRow(rawValue: indexPath.row)! { - case .PumpID: - DeviceDataManager.sharedManager.pumpID = controller.value - default: - break - } - } - - tableView.reloadData() - } - -} diff --git a/Dependencies/rileylink_ios/RileyLink/TextFieldTableViewController.swift b/Dependencies/rileylink_ios/RileyLink/TextFieldTableViewController.swift deleted file mode 100644 index b6ca443a8..000000000 --- a/Dependencies/rileylink_ios/RileyLink/TextFieldTableViewController.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// TextFieldTableViewController.swift -// Naterade -// -// Created by Nathan Racklyeft on 8/30/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import RileyLinkKit - -protocol TextFieldTableViewControllerDelegate: class { - func textFieldTableViewControllerDidEndEditing(controller: TextFieldTableViewController) -} - - -class TextFieldTableViewController: UITableViewController, IdentifiableClass, UITextFieldDelegate { - - @IBOutlet weak var textField: UITextField! - - var indexPath: NSIndexPath? - - var placeholder: String? - - var value: String? { - didSet { - delegate?.textFieldTableViewControllerDidEndEditing(self) - } - } - - var keyboardType = UIKeyboardType.Default - var autocapitalizationType = UITextAutocapitalizationType.None - - weak var delegate: TextFieldTableViewControllerDelegate? - - override func viewDidLoad() { - super.viewDidLoad() - - textField.text = value - textField.keyboardType = keyboardType - textField.placeholder = placeholder - textField.autocapitalizationType = autocapitalizationType - } - - override func viewWillAppear(animated: Bool) { - super.viewWillAppear(animated) - - textField.becomeFirstResponder() - } - - // MARK: - UITextFieldDelegate - - func textFieldShouldEndEditing(textField: UITextField) -> Bool { - value = textField.text - - return true - } - - func textFieldShouldReturn(textField: UITextField) -> Bool { - value = textField.text - - textField.delegate = nil - - navigationController?.popViewControllerAnimated(true) - - return false - } -} diff --git a/Dependencies/rileylink_ios/RileyLink/View Controllers/MainViewController.swift b/Dependencies/rileylink_ios/RileyLink/View Controllers/MainViewController.swift deleted file mode 100644 index a80af4228..000000000 --- a/Dependencies/rileylink_ios/RileyLink/View Controllers/MainViewController.swift +++ /dev/null @@ -1,235 +0,0 @@ -// -// MainViewController.swift -// RileyLink -// -// Created by Pete Schwamb on 5/11/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// -import UIKit -import SwiftUI -import MinimedKit -import MinimedKitUI -import RileyLinkBLEKit -import RileyLinkKit -import RileyLinkKitUI -import LoopKit -import LoopKitUI -import OmniKitUI - -class MainViewController: RileyLinkSettingsViewController { - - let deviceDataManager: DeviceDataManager - - let insulinTintColor: Color - - let guidanceColors: GuidanceColors - - init(deviceDataManager: DeviceDataManager, insulinTintColor: Color, guidanceColors: GuidanceColors) { - self.deviceDataManager = deviceDataManager - self.insulinTintColor = insulinTintColor - self.guidanceColors = guidanceColors - let rileyLinkPumpManager = RileyLinkPumpManager(rileyLinkDeviceProvider: deviceDataManager.rileyLinkConnectionManager.deviceProvider, rileyLinkConnectionManager: deviceDataManager.rileyLinkConnectionManager) - - super.init(rileyLinkPumpManager: rileyLinkPumpManager, devicesSectionIndex: Section.rileyLinks.rawValue, style: .grouped) - - self.title = LocalizedString("RileyLink Testing", comment: "Title for RileyLink Testing main view controller") - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - tableView.backgroundColor = UIColor.white - tableView.separatorStyle = .none - tableView.rowHeight = UITableView.automaticDimension - tableView.estimatedRowHeight = 44 - - tableView.sectionHeaderHeight = UITableView.automaticDimension - tableView.estimatedSectionHeaderHeight = 55 - - tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className) - tableView.register(SettingsImageTableViewCell.self, forCellReuseIdentifier: SettingsImageTableViewCell.className) - - let rlImage = UIImage(named: "RileyLink", in: Bundle.main, compatibleWith: tableView.traitCollection) - let imageView = UIImageView(image: rlImage) - imageView.tintColor = UIColor.white - imageView.contentMode = .center - imageView.frame.size.height += 30 // feels right - imageView.backgroundColor = UIColor(named: "RileyLink Tint", in: Bundle.main, compatibleWith: tableView.traitCollection) - tableView.tableHeaderView = imageView - - tableView.register(RileyLinkDeviceTableViewCell.self, forCellReuseIdentifier: RileyLinkDeviceTableViewCell.className) - - NotificationCenter.default.addObserver(self, selector: #selector(deviceConnectionStateDidChange), name: .DeviceConnectionStateDidChange, object: nil) - } - - override func viewWillAppear(_ animated: Bool) { - // Manually invoke the delegate for rows deselecting on appear - for indexPath in tableView.indexPathsForSelectedRows ?? [] { - _ = tableView(tableView, willDeselectRowAt: indexPath) - } - - super.viewWillAppear(animated) - } - - fileprivate enum Section: Int, CaseCountable { - case rileyLinks = 0 - case pump - } - - fileprivate enum PumpActionRow: Int, CaseCountable { - case addMinimedPump = 0 - case setupOmnipod - } - - weak var rileyLinkManager: RileyLinkBluetoothDeviceProvider! - - @objc private func deviceConnectionStateDidChange() { - DispatchQueue.main.async { - self.tableView.reloadSections(IndexSet([Section.pump.rawValue]), with: .none) - } - } - - private var shouldAllowAddingPump: Bool { - return rileyLinkManager.connectingCount > 0 - } - - // MARK: Data Source - - override func numberOfSections(in tableView: UITableView) -> Int { - return Section.count - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch Section(rawValue: section)! { - case .rileyLinks: - return super.tableView(tableView, numberOfRowsInSection: section) - case .pump: - if let _ = deviceDataManager.pumpManager { - return 1 - } else { - return PumpActionRow.count - } - } - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell: UITableViewCell - - switch(Section(rawValue: indexPath.section)!) { - case .rileyLinks: - return super.tableView(tableView, cellForRowAt: indexPath) - case .pump: - if let pumpManager = deviceDataManager.pumpManager { - cell = tableView.dequeueReusableCell(withIdentifier: SettingsImageTableViewCell.className, for: indexPath) - cell.imageView?.image = pumpManager.smallImage - cell.textLabel?.text = pumpManager.localizedTitle - cell.detailTextLabel?.text = nil - cell.accessoryType = .disclosureIndicator - } else { - switch(PumpActionRow(rawValue: indexPath.row)!) { - case .addMinimedPump: - cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) - let textButtonCell = cell as? TextButtonTableViewCell - textButtonCell?.isEnabled = shouldAllowAddingPump - textButtonCell?.isUserInteractionEnabled = shouldAllowAddingPump - cell.textLabel?.text = LocalizedString("Add Minimed Pump", comment: "Title text for button to set up a new minimed pump") - case .setupOmnipod: - cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) - let textButtonCell = cell as? TextButtonTableViewCell - textButtonCell?.isEnabled = shouldAllowAddingPump - textButtonCell?.isUserInteractionEnabled = shouldAllowAddingPump - cell.textLabel?.text = LocalizedString("Setup Omnipod", comment: "Title text for button to set up omnipod") - } - } - } - return cell - } - - public override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - switch Section(rawValue: section)! { - case .rileyLinks: - return super.tableView(tableView, titleForHeaderInSection: section) - case .pump: - return LocalizedString("Pumps", comment: "Title text for section listing configured pumps") - } - } - - public override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - switch Section(rawValue: section)! { - case .rileyLinks: - return super.tableView(tableView, viewForHeaderInSection: section) - case .pump: - return nil - } - } - - public override func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat { - return devicesDataSource.tableView(tableView, estimatedHeightForHeaderInSection: section) - } - - // MARK: - UITableViewDelegate - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - switch Section(rawValue: indexPath.section)! { - case .rileyLinks: - let device = devicesDataSource.devices[indexPath.row] - let vc = RileyLinkDeviceTableViewController(device: device, batteryAlertLevel: nil, batteryAlertLevelChanged: nil) - show(vc, sender: indexPath) - case .pump: - if let pumpManager = deviceDataManager.pumpManager { - var settings = pumpManager.settingsViewController(insulinTintColor: insulinTintColor, guidanceColors: guidanceColors) - settings.completionDelegate = self - present(settings, animated: true) - } else { - var setupViewController: UIViewController & PumpManagerOnboarding & CompletionNotifying - switch PumpActionRow(rawValue: indexPath.row)! { - case .addMinimedPump: - setupViewController = UIStoryboard(name: "MinimedPumpManager", bundle: Bundle(for: MinimedPumpManagerSetupViewController.self)).instantiateViewController(withIdentifier: "DevelopmentPumpSetup") as! MinimedPumpManagerSetupViewController - case .setupOmnipod: - setupViewController = UIStoryboard(name: "OmnipodPumpManager", bundle: Bundle(for: OmnipodPumpManagerSetupViewController.self)).instantiateViewController(withIdentifier: "DevelopmentPumpSetup") as! OmnipodPumpManagerSetupViewController - } - if let rileyLinkManagerViewController = setupViewController as? RileyLinkManagerSetupViewController { - rileyLinkManagerViewController.rileyLinkPumpManager = RileyLinkPumpManager(rileyLinkDeviceProvider: deviceDataManager.rileyLinkConnectionManager.deviceProvider) - } - setupViewController.setupDelegate = self - setupViewController.completionDelegate = self - present(setupViewController, animated: true, completion: nil) - } - } - } - - override func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? { - switch Section(rawValue: indexPath.section)! { - case .rileyLinks: - break - case .pump: - tableView.reloadSections(IndexSet([Section.pump.rawValue]), with: .none) - } - - return indexPath - } -} - -extension MainViewController: CompletionDelegate { - func completionNotifyingDidComplete(_ object: CompletionNotifying) { - if let vc = object as? UIViewController, presentedViewController === vc { - dismiss(animated: true, completion: nil) - } - } -} - -extension MainViewController: PumpManagerCreateDelegate { - func pumpManagerOnboarding(_ notifying: PumpManagerCreateNotifying, didCreatePumpManager pumpManager: PumpManagerUI) { - deviceDataManager.pumpManager = pumpManager - } -} - -extension MainViewController: PumpManagerOnboardingDelegate { - func pumpManagerOnboarding(_ notifying: PumpManagerOnboarding, didOnboardPumpManager pumpManager: PumpManagerUI, withSettings settings: PumpManagerSetupSettings) { - show(pumpManager.settingsViewController(insulinTintColor: insulinTintColor, guidanceColors: guidanceColors), sender: nil) - tableView.reloadSections(IndexSet([Section.pump.rawValue]), with: .none) - } -} diff --git a/Dependencies/rileylink_ios/RileyLink/Views/SettingsImageTableViewCell.swift b/Dependencies/rileylink_ios/RileyLink/Views/SettingsImageTableViewCell.swift deleted file mode 100644 index bb6f4b80a..000000000 --- a/Dependencies/rileylink_ios/RileyLink/Views/SettingsImageTableViewCell.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// SettingsImageTableViewCell.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - - -class SettingsImageTableViewCell: UITableViewCell { - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: .default, reuseIdentifier: reuseIdentifier) - - setup() - } - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - - setup() - } - - private func setup() { - guard let textLabel = textLabel, let imageView = imageView else { - return - } - - textLabel.adjustsFontForContentSizeCategory = true - textLabel.font = UIFont.preferredFont(forTextStyle: .body) - textLabel.translatesAutoresizingMaskIntoConstraints = false - imageView.translatesAutoresizingMaskIntoConstraints = false - - let parent = contentView.layoutMarginsGuide - NSLayoutConstraint.activate([ - imageView.leadingAnchor.constraint(equalTo: parent.leadingAnchor), - imageView.topAnchor.constraint(greaterThanOrEqualTo: parent.topAnchor), - parent.bottomAnchor.constraint(greaterThanOrEqualTo: imageView.bottomAnchor), - imageView.centerYAnchor.constraint(equalTo: parent.centerYAnchor), - textLabel.leadingAnchor.constraint(equalToSystemSpacingAfter: imageView.trailingAnchor, multiplier: 2), - textLabel.topAnchor.constraint(greaterThanOrEqualTo: parent.topAnchor), - parent.bottomAnchor.constraint(greaterThanOrEqualTo: textLabel.bottomAnchor), - parent.trailingAnchor.constraint(equalTo: textLabel.trailingAnchor), - textLabel.centerYAnchor.constraint(equalTo: parent.centerYAnchor) - ]) - } - - override func prepareForReuse() { - super.prepareForReuse() - - imageView?.image = nil - } -} diff --git a/Dependencies/rileylink_ios/RileyLink/ar.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/ar.lproj/Localizable.strings deleted file mode 100644 index e2b3b2b4f..000000000 --- a/Dependencies/rileylink_ios/RileyLink/ar.lproj/Localizable.strings +++ /dev/null @@ -1,18 +0,0 @@ -/* The title of the nightscout API secret credential */ -"API Secret" = "API Secret"; - -/* The title of the configuration section in settings */ -"Configuration" = "المعطيات"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Enter the 6-digit pump ID"; - -/* The title of the Nightscout service */ -"Nightscout" = "نايتسكاوت"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pump ID"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "رابط الموقع"; - diff --git a/Dependencies/rileylink_ios/RileyLink/ar.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/ar.lproj/LoopKit.strings deleted file mode 100644 index ea1deea9c..000000000 --- a/Dependencies/rileylink_ios/RileyLink/ar.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "موافق"; - diff --git a/Dependencies/rileylink_ios/RileyLink/cs.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/cs.lproj/Localizable.strings deleted file mode 100644 index afd4d461f..000000000 --- a/Dependencies/rileylink_ios/RileyLink/cs.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@ %%"; - -/* The title of the about section */ -"About" = "Podrobnosti"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Přidat účet"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Přidat pumpu Minimed"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API Secret"; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfigurace"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Smazat účet"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Zadejte 6místné ID pumpy"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Načíst CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mojestranka.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID pumpy"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pumpy"; - -/* The default placeholder string for a credential */ -"Required" = "Povinné"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "Testování RileyLinku"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Nastavit Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "URL adresa webu"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Klepnutím nastavit"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Nahrát do Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/cs.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/cs.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/cs.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/cs.lproj/RileyLink-InfoPlist.strings b/Dependencies/rileylink_ios/RileyLink/cs.lproj/RileyLink-InfoPlist.strings deleted file mode 100644 index 8f88cab42..000000000 --- a/Dependencies/rileylink_ios/RileyLink/cs.lproj/RileyLink-InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "RileyLink"; - -/* Get Info string */ -"CFBundleGetInfoString" = "Prázdné"; - -/* Bundle name */ -"CFBundleName" = "RileyLink"; - diff --git a/Dependencies/rileylink_ios/RileyLink/da.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/da.lproj/Localizable.strings deleted file mode 100644 index d82d7a123..000000000 --- a/Dependencies/rileylink_ios/RileyLink/da.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "Om"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Tilføj konto"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Tilføj MiniMed pumpe"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API kodeord"; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfiguration"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Slet konto"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Indtast det 6-cifrede pumpe ID"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Hent CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pumpe ID"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pumper"; - -/* The default placeholder string for a credential */ -"Required" = "Påkrævet"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink Testing"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Omnipod Setup"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "Side-URL"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Tryk for at gemme"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Upload til Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/da.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/da.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/da.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/da.lproj/RileyLink-InfoPlist.strings b/Dependencies/rileylink_ios/RileyLink/da.lproj/RileyLink-InfoPlist.strings deleted file mode 100644 index ab582a289..000000000 --- a/Dependencies/rileylink_ios/RileyLink/da.lproj/RileyLink-InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "RileyLink"; - -/* Get Info string */ -"CFBundleGetInfoString" = "Tom"; - -/* Bundle name */ -"CFBundleName" = "RileyLink"; - diff --git a/Dependencies/rileylink_ios/RileyLink/de.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/de.lproj/Localizable.strings deleted file mode 100644 index 5539eb7c9..000000000 --- a/Dependencies/rileylink_ios/RileyLink/de.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "Über"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Konto hinzufügen"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Minimed Pumpe hinzufügen"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API Secret"; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfiguration"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Konto löschen"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Geben Sie die 6-stellige Pumpen-ID ein"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "CGM abrufen"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pumpen-ID"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pumpen"; - -/* The default placeholder string for a credential */ -"Required" = "Erforderlich"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink Testen"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Setup Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "Website URL"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Klicken zum setzten"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Upload zu NightScout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/de.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/de.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/de.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/de.lproj/RileyLink-InfoPlist.strings b/Dependencies/rileylink_ios/RileyLink/de.lproj/RileyLink-InfoPlist.strings deleted file mode 100644 index cc5150f88..000000000 --- a/Dependencies/rileylink_ios/RileyLink/de.lproj/RileyLink-InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "RileyLink"; - -/* Get Info string */ -"CFBundleGetInfoString" = "Leer"; - -/* Bundle name */ -"CFBundleName" = "RileyLink"; - diff --git a/Dependencies/rileylink_ios/RileyLink/en.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/en.lproj/Localizable.strings deleted file mode 100644 index 7b8ff1d7f..000000000 --- a/Dependencies/rileylink_ios/RileyLink/en.lproj/Localizable.strings +++ /dev/null @@ -1,51 +0,0 @@ -/* The title of the about section */ -"About" = "About"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Add Account"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API Secret"; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuration"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Delete Account"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Enter the 6-digit pump ID"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Fetch CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pump ID"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pumps"; - -/* The default placeholder string for a credential */ -"Required" = "Required"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink Testing"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Setup Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "Site URL"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Tap to set"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Upload To Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/es.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/es.lproj/Localizable.strings deleted file mode 100644 index eddcf7b12..000000000 --- a/Dependencies/rileylink_ios/RileyLink/es.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "Respecto a"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Agregar Cuenta"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Añadir la bomba Minimed"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "Clave secreta API"; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuración"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Eliminar Cuenta"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Ingrese ID de 6 dígitios de la microinfusora"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Obtener de CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID de Bomba"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Microinfusoras"; - -/* The default placeholder string for a credential */ -"Required" = "Requerido"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "Preubas de RileyLink"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Setup Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "URL de Sitio"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Toca para definir"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Subir a Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/es.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/es.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/es.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/es.lproj/RileyLink-InfoPlist.strings b/Dependencies/rileylink_ios/RileyLink/es.lproj/RileyLink-InfoPlist.strings deleted file mode 100644 index f2dd0c99f..000000000 --- a/Dependencies/rileylink_ios/RileyLink/es.lproj/RileyLink-InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Rileylink"; - -/* Get Info string */ -"CFBundleGetInfoString" = "Vacio"; - -/* Bundle name */ -"CFBundleName" = "Rileylink"; - diff --git a/Dependencies/rileylink_ios/RileyLink/fi.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/fi.lproj/Localizable.strings deleted file mode 100644 index 9dda886d8..000000000 --- a/Dependencies/rileylink_ios/RileyLink/fi.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "Tietoja"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Lisää tili"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Lisää Minimed-pumppu"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API-salasana"; - -/* The title of the configuration section in settings */ -"Configuration" = "Määritykset"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Poista tili"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Syötä 6-numeroinen pumpun tunniste"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Hae CGM-data"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://omaosoite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pumpun tunniste"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pumput"; - -/* The default placeholder string for a credential */ -"Required" = "Pakollinen"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink-testaus"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Asenna Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "URL"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Napauta asettaaksesi"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Lataa Nightscoutiin"; - diff --git a/Dependencies/rileylink_ios/RileyLink/fi.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/fi.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/fi.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/fr.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/fr.lproj/Localizable.strings deleted file mode 100644 index a182d7c28..000000000 --- a/Dependencies/rileylink_ios/RileyLink/fr.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "À propos"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Ajouter un compte"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Ajouter une pompe Minimed"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "Secret API"; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuration"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Supprimer le compte"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Entrée l’ID de pompe de 6 chiffres"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Obtenir CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID de la pompe"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pompes"; - -/* The default placeholder string for a credential */ -"Required" = "Obligatoire"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "Test Rileylink"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Configuration Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "URL du site"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Appuyez pour définir"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Télécharger vers Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/fr.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/fr.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/fr.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/fr.lproj/RileyLink-InfoPlist.strings b/Dependencies/rileylink_ios/RileyLink/fr.lproj/RileyLink-InfoPlist.strings deleted file mode 100644 index 7a8523f1e..000000000 --- a/Dependencies/rileylink_ios/RileyLink/fr.lproj/RileyLink-InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Rileylink"; - -/* Get Info string */ -"CFBundleGetInfoString" = "Vide"; - -/* Bundle name */ -"CFBundleName" = "Rileylink"; - diff --git a/Dependencies/rileylink_ios/RileyLink/he.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/he.lproj/Localizable.strings deleted file mode 100644 index 5d50b95c2..000000000 --- a/Dependencies/rileylink_ios/RileyLink/he.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "אודות"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Add Account"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "הוסף משאבת מינימד"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API Secret"; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuration"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Delete Account"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "הזן את מספר זיהוי המשאבה בן 6 הספרות"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Fetch CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "נייטסקאוט"; - -/* The title text for the pump ID config value */ -"Pump ID" = "מספר זיהוי המשאבה"; - -/* Title text for section listing configured pumps */ -"Pumps" = "משאבות"; - -/* The default placeholder string for a credential */ -"Required" = "Required"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "בדיקת ריילילינק"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "הגדרת אומניפוד"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "כתובת האתר"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Tap to set"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "העלה לנייטסקאוט"; - diff --git a/Dependencies/rileylink_ios/RileyLink/he.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/he.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/he.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/he.lproj/RileyLink-InfoPlist.strings b/Dependencies/rileylink_ios/RileyLink/he.lproj/RileyLink-InfoPlist.strings deleted file mode 100644 index 883c1d8cb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/he.lproj/RileyLink-InfoPlist.strings +++ /dev/null @@ -1,6 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "ריילילינק"; - -/* Bundle name */ -"CFBundleName" = "ריילילינק"; - diff --git a/Dependencies/rileylink_ios/RileyLink/hi.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/hi.lproj/Localizable.strings deleted file mode 100644 index 5563df583..000000000 --- a/Dependencies/rileylink_ios/RileyLink/hi.lproj/Localizable.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the nightscout API secret credential */ -"API Secret" = "एपीआई पास्वर्ड"; - diff --git a/Dependencies/rileylink_ios/RileyLink/hu.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/hu.lproj/Localizable.strings deleted file mode 100644 index 7b8ff1d7f..000000000 --- a/Dependencies/rileylink_ios/RileyLink/hu.lproj/Localizable.strings +++ /dev/null @@ -1,51 +0,0 @@ -/* The title of the about section */ -"About" = "About"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Add Account"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API Secret"; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuration"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Delete Account"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Enter the 6-digit pump ID"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Fetch CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pump ID"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pumps"; - -/* The default placeholder string for a credential */ -"Required" = "Required"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink Testing"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Setup Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "Site URL"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Tap to set"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Upload To Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/it.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/it.lproj/Localizable.strings deleted file mode 100644 index fd91b39e3..000000000 --- a/Dependencies/rileylink_ios/RileyLink/it.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@ %%"; - -/* The title of the about section */ -"About" = "Informazioni"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Aggiungi Account"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Agg. Microinfusore Minimed"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "Chiave personale API"; - -/* The title of the configuration section in settings */ -"Configuration" = "Configurazione"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Cancella Account"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Inserire 6-cifre ID micro"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Sincronizza CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID microinfusore"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Microinfusore"; - -/* The default placeholder string for a credential */ -"Required" = "Necessario"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "Collaudo RileyLink"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Configura OmniPod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "Sito URL"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Imposta"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Carica su Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/it.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/it.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/it.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/it.lproj/RileyLink-InfoPlist.strings b/Dependencies/rileylink_ios/RileyLink/it.lproj/RileyLink-InfoPlist.strings deleted file mode 100644 index 20b164d67..000000000 --- a/Dependencies/rileylink_ios/RileyLink/it.lproj/RileyLink-InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "Rileylink"; - -/* Get Info string */ -"CFBundleGetInfoString" = "Vuoto"; - -/* Bundle name */ -"CFBundleName" = "Rileylink"; - diff --git a/Dependencies/rileylink_ios/RileyLink/ja.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/ja.lproj/Localizable.strings deleted file mode 100644 index 0e2d1428d..000000000 --- a/Dependencies/rileylink_ios/RileyLink/ja.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "情報"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "アカウントを追加"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "APIシークレット"; - -/* The title of the configuration section in settings */ -"Configuration" = "コンフィグレーション"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "アカウントを削除"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "6桁のポンプ ID"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "CGMを取得"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ポンプ ID"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pumps"; - -/* The default placeholder string for a credential */ -"Required" = "必須"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink Testing"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Setup Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "URL"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "タップして確定"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "NightScoutをアップロード"; - diff --git a/Dependencies/rileylink_ios/RileyLink/ja.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/ja.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/ja.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/nb.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/nb.lproj/Localizable.strings deleted file mode 100644 index 9f8ce6c13..000000000 --- a/Dependencies/rileylink_ios/RileyLink/nb.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "Om"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Legg Til Konto"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Legg til Minimed Pumpe"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API Hemmelighet"; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfigurasjon"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Slett Konto"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Skriv 6-siffret pumpe-ID"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Hent CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pumpe ID"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pumper"; - -/* The default placeholder string for a credential */ -"Required" = "Påkrevd"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink Testing"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Sett opp Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "Nettstedslenke (URL)"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Trykk for å angi"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Last opp til Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/nb.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/nb.lproj/LoopKit.strings deleted file mode 100644 index bbf0a776f..000000000 --- a/Dependencies/rileylink_ios/RileyLink/nb.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "Ok"; - diff --git a/Dependencies/rileylink_ios/RileyLink/nb.lproj/RileyLink-InfoPlist.strings b/Dependencies/rileylink_ios/RileyLink/nb.lproj/RileyLink-InfoPlist.strings deleted file mode 100644 index ab582a289..000000000 --- a/Dependencies/rileylink_ios/RileyLink/nb.lproj/RileyLink-InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "RileyLink"; - -/* Get Info string */ -"CFBundleGetInfoString" = "Tom"; - -/* Bundle name */ -"CFBundleName" = "RileyLink"; - diff --git a/Dependencies/rileylink_ios/RileyLink/nl.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/nl.lproj/Localizable.strings deleted file mode 100644 index 8b49503f0..000000000 --- a/Dependencies/rileylink_ios/RileyLink/nl.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "Over"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Voeg account toe"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Voeg Minimed-pomp toe"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API Secret"; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuratie"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Verwijder Account"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Voer het 6-cijferige pompserienummer in"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Haal CGM op"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pompserienummer"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pompen"; - -/* The default placeholder string for a credential */ -"Required" = "Vereist"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink Testing"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Omnipod Instellen"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "Site URL"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Instellen…"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Uploaden naar Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/nl.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/nl.lproj/LoopKit.strings deleted file mode 100644 index bbf0a776f..000000000 --- a/Dependencies/rileylink_ios/RileyLink/nl.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "Ok"; - diff --git a/Dependencies/rileylink_ios/RileyLink/nl.lproj/RileyLink-InfoPlist.strings b/Dependencies/rileylink_ios/RileyLink/nl.lproj/RileyLink-InfoPlist.strings deleted file mode 100644 index be8b33fce..000000000 --- a/Dependencies/rileylink_ios/RileyLink/nl.lproj/RileyLink-InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "RileyLink"; - -/* Get Info string */ -"CFBundleGetInfoString" = "Leeg"; - -/* Bundle name */ -"CFBundleName" = "RileyLink"; - diff --git a/Dependencies/rileylink_ios/RileyLink/pl.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/pl.lproj/Localizable.strings deleted file mode 100644 index a5d085aa4..000000000 --- a/Dependencies/rileylink_ios/RileyLink/pl.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "O aplikacji"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Dodaj konto"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Dodaj pompę Minimed"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API Secret"; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfiguracja"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Usuń konto"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Wprowadź 6-cyfrowy numer pompy"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Pobierz dane z CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID pompy"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pumps"; - -/* The default placeholder string for a credential */ -"Required" = "Wymagane"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink Testing"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Setup Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "Strona URL"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Kliknij, aby ustawić"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Wysyłaj do Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/pl.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/pl.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/pl.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/pl.lproj/RileyLink-InfoPlist.strings b/Dependencies/rileylink_ios/RileyLink/pl.lproj/RileyLink-InfoPlist.strings deleted file mode 100644 index f5ee1c8bf..000000000 --- a/Dependencies/rileylink_ios/RileyLink/pl.lproj/RileyLink-InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "RileyLink"; - -/* Get Info string */ -"CFBundleGetInfoString" = "Pusty"; - -/* Bundle name */ -"CFBundleName" = "RileyLink"; - diff --git a/Dependencies/rileylink_ios/RileyLink/pt-BR.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/pt-BR.lproj/Localizable.strings deleted file mode 100644 index da89ba750..000000000 --- a/Dependencies/rileylink_ios/RileyLink/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "Sobre"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Adicionar Conta"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "Chave API"; - -/* The title of the configuration section in settings */ -"Configuration" = "Configuração"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Remover Conta"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Digite o ID da bomba de 6 dígitos"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Buscar CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID da Bomba"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Bombas"; - -/* The default placeholder string for a credential */ -"Required" = "Obrigatório"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink Testing"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Setup Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "Site URL"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Toque para Definir"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Enviar para Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/pt-BR.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/pt-BR.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/pt-BR.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/ro.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/ro.lproj/Localizable.strings deleted file mode 100644 index 772012909..000000000 --- a/Dependencies/rileylink_ios/RileyLink/ro.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "Despre"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Adaugă cont"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Adaugă pompă Minimed"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "Secretul API"; - -/* The title of the configuration section in settings */ -"Configuration" = "Configurare"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Șterge cont"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Introduceți ID-ul de pompă din 6 cifre"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Transferă din CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://siteulmeu.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID pompă"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pompe"; - -/* The default placeholder string for a credential */ -"Required" = "Necesar"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink Testing"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Setup Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "URL site"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Apăsați pentru setare"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Încărcare în Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/ro.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/ro.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/ro.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/ro.lproj/RileyLink-InfoPlist.strings b/Dependencies/rileylink_ios/RileyLink/ro.lproj/RileyLink-InfoPlist.strings deleted file mode 100644 index 9327bc799..000000000 --- a/Dependencies/rileylink_ios/RileyLink/ro.lproj/RileyLink-InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "RileyLink"; - -/* Get Info string */ -"CFBundleGetInfoString" = "Gol"; - -/* Bundle name */ -"CFBundleName" = "RileyLink"; - diff --git a/Dependencies/rileylink_ios/RileyLink/ru.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/ru.lproj/Localizable.strings deleted file mode 100644 index 3643bfc5f..000000000 --- a/Dependencies/rileylink_ios/RileyLink/ru.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ дБ"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "Про"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Добавить пользователя"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Добавить помпу Minimed"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API Секрет"; - -/* The title of the configuration section in settings */ -"Configuration" = "Конфигурация"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Удалить аккаунт"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Ввести 6-значный ID помпы"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Получить данные мониторинга"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Идентификатор ID помпы"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Помпы"; - -/* The default placeholder string for a credential */ -"Required" = "обязательный"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "Тестирование RileyLink"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Настроить Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "URL сайта"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Щелкнуть для ввода"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Загружать в Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/ru.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/ru.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/ru.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/ru.lproj/RileyLink-InfoPlist.strings b/Dependencies/rileylink_ios/RileyLink/ru.lproj/RileyLink-InfoPlist.strings deleted file mode 100644 index 57f4bd986..000000000 --- a/Dependencies/rileylink_ios/RileyLink/ru.lproj/RileyLink-InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "RileyLink"; - -/* Get Info string */ -"CFBundleGetInfoString" = "Пусто"; - -/* Bundle name */ -"CFBundleName" = "RileyLink"; - diff --git a/Dependencies/rileylink_ios/RileyLink/sk.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/sk.lproj/Localizable.strings deleted file mode 100644 index 6db7ee275..000000000 --- a/Dependencies/rileylink_ios/RileyLink/sk.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@ %%"; - -/* The title of the about section */ -"About" = "O sekcii"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Pridať účet"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Pridať pumpu Minimed"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API Secret"; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfigurácia"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Odstrániť účet"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Zadajte 6-miestne ID pumpy"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Načítať CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "ID pumpy"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pumpy"; - -/* The default placeholder string for a credential */ -"Required" = "Povinné"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "Rileylink testovanie"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Nastaviť Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "URL adresa webu"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Ťuknutím nastavte"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Nahrať do Nightscoutu"; - diff --git a/Dependencies/rileylink_ios/RileyLink/sk.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/sk.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/sk.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/sk.lproj/RileyLink-InfoPlist.strings b/Dependencies/rileylink_ios/RileyLink/sk.lproj/RileyLink-InfoPlist.strings deleted file mode 100644 index e935e91cb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/sk.lproj/RileyLink-InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "RileyLink"; - -/* Get Info string */ -"CFBundleGetInfoString" = "Prázdne"; - -/* Bundle name */ -"CFBundleName" = "RileyLink"; - diff --git a/Dependencies/rileylink_ios/RileyLink/sv.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/sv.lproj/Localizable.strings deleted file mode 100644 index 4d906297a..000000000 --- a/Dependencies/rileylink_ios/RileyLink/sv.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "Om"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Lägg till konto"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Lägg till Minimed-pump"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API Secret"; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfiguration"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Radera konto"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Ange 6-siffrigt pump-ID"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Hämta CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "https://min-nightscoutsida.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pump-ID"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pumpar"; - -/* The default placeholder string for a credential */ -"Required" = "Krävs"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink-testning"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Omnipod-konfiguration"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "Nightscout-URL"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Klicka för att ange"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Nightscout-uppladdning"; - diff --git a/Dependencies/rileylink_ios/RileyLink/sv.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/sv.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/sv.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/tr.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/tr.lproj/Localizable.strings deleted file mode 100644 index 50375ffe9..000000000 --- a/Dependencies/rileylink_ios/RileyLink/tr.lproj/Localizable.strings +++ /dev/null @@ -1,60 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "Hakkında"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Hesap Ekle"; - -/* Title text for button to set up a new minimed pump */ -"Add Minimed Pump" = "Minimed Pompa Ekle"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API Secret"; - -/* The title of the configuration section in settings */ -"Configuration" = "Konfigürasyon"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Hesabı sil"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "6 haneli pompa kimliğini girin"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "CGM verilerini getir"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://site_adresim.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Pompa Kimliği"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pompalar"; - -/* The default placeholder string for a credential */ -"Required" = "Gerekli"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink Testi"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Omnipod Kurulumu"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "Nightscout URL"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Ayarlamak için dokunun"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Nightscout'a Yükle"; - diff --git a/Dependencies/rileylink_ios/RileyLink/tr.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/tr.lproj/LoopKit.strings deleted file mode 100644 index 661f38238..000000000 --- a/Dependencies/rileylink_ios/RileyLink/tr.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "Tamam"; - diff --git a/Dependencies/rileylink_ios/RileyLink/tr.lproj/RileyLink-InfoPlist.strings b/Dependencies/rileylink_ios/RileyLink/tr.lproj/RileyLink-InfoPlist.strings deleted file mode 100644 index fd742976b..000000000 --- a/Dependencies/rileylink_ios/RileyLink/tr.lproj/RileyLink-InfoPlist.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* Bundle display name */ -"CFBundleDisplayName" = "RileyLink"; - -/* Get Info string */ -"CFBundleGetInfoString" = "Boş"; - -/* Bundle name */ -"CFBundleName" = "RileyLink"; - diff --git a/Dependencies/rileylink_ios/RileyLink/vi.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/vi.lproj/Localizable.strings deleted file mode 100644 index 52ccfd251..000000000 --- a/Dependencies/rileylink_ios/RileyLink/vi.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the about section */ -"About" = "About"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "Thêm Tài khoản"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API Secret"; - -/* The title of the configuration section in settings */ -"Configuration" = "Cấu hình"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "Xóa Tài khoản"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "Nhập 6 số ID của bơm"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "Lấy dữ liệu từ CGM"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "Số ID của bơm"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pumps"; - -/* The default placeholder string for a credential */ -"Required" = "Bắt buộc"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink Testing"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Setup Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "Site URL"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "Chạm để cài đặt"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "Upload To Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLink/vi.lproj/LoopKit.strings b/Dependencies/rileylink_ios/RileyLink/vi.lproj/LoopKit.strings deleted file mode 100644 index bc1fda9fb..000000000 --- a/Dependencies/rileylink_ios/RileyLink/vi.lproj/LoopKit.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* The title of the action used to dismiss an error alert */ -"com.loudnate.LoopKit.errorAlertActionTitle" = "OK"; - diff --git a/Dependencies/rileylink_ios/RileyLink/zh-Hans.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLink/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 7c95e631d..000000000 --- a/Dependencies/rileylink_ios/RileyLink/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,51 +0,0 @@ -/* The title of the about section */ -"About" = "关于"; - -/* The title of the button to add the credentials for a service */ -"Add Account" = "添加账户"; - -/* The title of the nightscout API secret credential */ -"API Secret" = "API密码"; - -/* The title of the configuration section in settings */ -"Configuration" = "配置"; - -/* The title of the button to remove the credentials for a service */ -"Delete Account" = "删除账户"; - -/* The placeholder text instructing users how to enter a pump ID */ -"Enter the 6-digit pump ID" = "输入六位数字的泵ID"; - -/* The title text for the pull cgm Data cell */ -"Fetch CGM" = "获取动态血糖数据"; - -/* The placeholder text for the nightscout site URL credential */ -"http://mysite.herokuapp.com" = "http://mysite.herokuapp.com"; - -/* The title of the Nightscout service */ -"Nightscout" = "Nightscout"; - -/* The title text for the pump ID config value */ -"Pump ID" = "胰岛素泵序列号"; - -/* Title text for section listing configured pumps */ -"Pumps" = "Pumps"; - -/* The default placeholder string for a credential */ -"Required" = "需要"; - -/* Title for RileyLink Testing main view controller */ -"RileyLink Testing" = "RileyLink Testing"; - -/* Title text for button to set up omnipod */ -"Setup Omnipod" = "Setup Omnipod"; - -/* The title of the nightscout site URL credential */ -"Site URL" = "网址"; - -/* The empty-state text for a configuration value */ -"Tap to set" = "点击设置"; - -/* The title text for the nightscout upload enabled switch cell */ -"Upload To Nightscout" = "上传到Nightscout"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/BLEFirmwareVersion.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/BLEFirmwareVersion.swift deleted file mode 100644 index 83e2cc435..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/BLEFirmwareVersion.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// BLEFirmwareVersion.swift -// RileyLinkBLEKit -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -public struct BLEFirmwareVersion { - private static let prefix = "ble_rfspy " - - let components: [Int] - - let versionString: String - - init?(versionString: String) { - guard - versionString.hasPrefix(BLEFirmwareVersion.prefix), - let versionIndex = versionString.index(versionString.startIndex, offsetBy: BLEFirmwareVersion.prefix.count, limitedBy: versionString.endIndex) - else { - return nil - } - - self.init( - components: versionString[versionIndex...].split(separator: ".").compactMap({ Int($0) }), - versionString: versionString - ) - } - - init(components: [Int], versionString: String) { - self.components = components - self.versionString = versionString - } -} - - -extension BLEFirmwareVersion { - static var unknown: BLEFirmwareVersion { - return self.init(components: [0], versionString: "Unknown") - } - - public var isUnknown: Bool { - return self == BLEFirmwareVersion.unknown - } -} - - -extension BLEFirmwareVersion: CustomStringConvertible { - public var description: String { - return versionString - } -} - - -extension BLEFirmwareVersion: Equatable { - public static func ==(lhs: BLEFirmwareVersion, rhs: BLEFirmwareVersion) -> Bool { - return lhs.components == rhs.components - } -} - - -extension BLEFirmwareVersion { - var responseType: PeripheralManager.ResponseType { - guard let major = components.first, major >= 2 else { - return .buffered - } - - return .single - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/Base.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/Base.lproj/Localizable.strings deleted file mode 100644 index b8344eccc..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/Base.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Data exceeded maximum size of %@ bytes"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Input %@ is invalid"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Make sure the device is nearby, and the issue should resolve automatically"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Peripheral did not respond in time"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Peripheral isnʼt connected"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Pump did not respond in time"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Response %@ is invalid"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "RileyLink firmware does not support the %@ command"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "The RileyLink was temporarily disconnected"; - -/* Error description */ -"Unknown characteristic" = "Unknown characteristic"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/CBCentralManager.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/CBCentralManager.swift deleted file mode 100644 index 9504df977..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/CBCentralManager.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// CBCentralManager.swift -// RileyLinkBLEKit -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import CoreBluetooth - - -// MARK: - It's only valid to call these methods on the central manager's queue -extension CBCentralManager { - func connectIfNecessary(_ peripheral: CBPeripheral, options: [String: Any]? = nil) { - guard case .poweredOn = state else { - return - } - - switch peripheral.state { - case .connected: - delegate?.centralManager?(self, didConnect: peripheral) - case .connecting, .disconnected, .disconnecting: - fallthrough - @unknown default: - connect(peripheral, options: options) - } - } - - func cancelPeripheralConnectionIfNecessary(_ peripheral: CBPeripheral) { - guard case .poweredOn = state else { - return - } - - switch peripheral.state { - case .disconnected: - delegate?.centralManager?(self, didDisconnectPeripheral: peripheral, error: nil) - case .connected, .connecting, .disconnecting: - fallthrough - @unknown default: - cancelPeripheralConnection(peripheral) - } - } -} - - -extension CBManagerState { - var description: String { - switch self { - case .poweredOff: - return "Powered Off" - case .poweredOn: - return "Powered On" - case .resetting: - return "Resetting" - case .unauthorized: - return "Unauthorized" - case .unknown: - return "Unknown" - case .unsupported: - return "Unsupported" - @unknown default: - return "Unknown: \(rawValue)" - } - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/CBPeripheral.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/CBPeripheral.swift deleted file mode 100644 index 921462232..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/CBPeripheral.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// CBPeripheral.swift -// xDripG5 -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import CoreBluetooth - - -// MARK: - Discovery helpers. -extension CBPeripheral { - func servicesToDiscover(from serviceUUIDs: [CBUUID]) -> [CBUUID] { - let knownServiceUUIDs = services?.compactMap({ $0.uuid }) ?? [] - return serviceUUIDs.filter({ !knownServiceUUIDs.contains($0) }) - } - - func characteristicsToDiscover(from characteristicUUIDs: [CBUUID], for service: CBService) -> [CBUUID] { - let knownCharacteristicUUIDs = service.characteristics?.compactMap({ $0.uuid }) ?? [] - return characteristicUUIDs.filter({ !knownCharacteristicUUIDs.contains($0) }) - } -} - - -extension Collection where Element: CBAttribute { - func itemWithUUID(_ uuid: CBUUID) -> Element? { - for attribute in self { - if attribute.uuid == uuid { - return attribute - } - } - - return nil - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/Command.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/Command.swift deleted file mode 100644 index 2d82c099e..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/Command.swift +++ /dev/null @@ -1,331 +0,0 @@ -// -// Command.swift -// RileyLinkBLEKit -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - - -// CmdBase -enum RileyLinkCommand: UInt8 { - case getState = 1 - case getVersion = 2 - case getPacket = 3 - case sendPacket = 4 - case sendAndListen = 5 - case updateRegister = 6 - case reset = 7 - case setLEDMode = 8 - case readRegister = 9 - case setModeRegisters = 10 - case setSWEncoding = 11 - case setPreamble = 12 - case resetRadioConfig = 13 - case getStatistics = 14 -} - -enum RileyLinkLEDType: UInt8 { - case green = 0 - case blue = 1 -} - -protocol Command { - associatedtype ResponseType: Response - - var data: Data { get } -} - -struct GetPacket: Command { - typealias ResponseType = PacketResponse - - let listenChannel: UInt8 - let timeoutMS: UInt32 - - init(listenChannel: UInt8, timeoutMS: UInt32) { - self.listenChannel = listenChannel - self.timeoutMS = timeoutMS - } - - var data: Data { - var data = Data([ - RileyLinkCommand.getPacket.rawValue, - listenChannel - ]) - data.appendBigEndian(timeoutMS) - - return data - } -} - -struct GetVersion: Command { - typealias ResponseType = GetVersionResponse - - var data: Data { - return Data([RileyLinkCommand.getVersion.rawValue]) - } -} - -struct SendAndListen: Command { - typealias ResponseType = PacketResponse - - let outgoing: Data - - /// In general, 0 = meter, cgm. 2 = pump - let sendChannel: UInt8 - - /// 0 = no repeat, i.e. only one packet. 1 repeat = 2 packets sent total. - let repeatCount: UInt8 - let delayBetweenPacketsMS: UInt16 - let listenChannel: UInt8 - let timeoutMS: UInt32 - let retryCount: UInt8 - let preambleExtensionMS: UInt16 - let firmwareVersion: RadioFirmwareVersion - - init(outgoing: Data, sendChannel: UInt8, repeatCount: UInt8, delayBetweenPacketsMS: UInt16, listenChannel: UInt8, timeoutMS: UInt32, retryCount: UInt8, preambleExtensionMS: UInt16, firmwareVersion: RadioFirmwareVersion) { - self.outgoing = outgoing - self.sendChannel = sendChannel - self.repeatCount = repeatCount - self.delayBetweenPacketsMS = delayBetweenPacketsMS - self.listenChannel = listenChannel - self.timeoutMS = timeoutMS - self.retryCount = retryCount - self.preambleExtensionMS = preambleExtensionMS - self.firmwareVersion = firmwareVersion - } - - var data: Data { - var data = Data([ - RileyLinkCommand.sendAndListen.rawValue, - sendChannel, - repeatCount - ]) - - if firmwareVersion.supports16BitPacketDelay { - data.appendBigEndian(delayBetweenPacketsMS) - } else { - data.append(UInt8(clamping: Int(delayBetweenPacketsMS))) - } - - data.append(listenChannel); - data.appendBigEndian(timeoutMS) - data.append(retryCount) - if firmwareVersion.supportsPreambleExtension { - data.appendBigEndian(preambleExtensionMS) - } - data.append(outgoing) - - return data - } -} - -struct SendPacket: Command { - typealias ResponseType = CodeResponse - - let outgoing: Data - - /// In general, 0 = meter, cgm. 2 = pump - let sendChannel: UInt8 - - /// 0 = no repeat, i.e. only one packet. 1 repeat = 2 packets sent total. - let repeatCount: UInt8 - let delayBetweenPacketsMS: UInt16 - let preambleExtensionMS: UInt16 - let firmwareVersion: RadioFirmwareVersion - - init(outgoing: Data, sendChannel: UInt8, repeatCount: UInt8, delayBetweenPacketsMS: UInt16, preambleExtensionMS: UInt16, firmwareVersion: RadioFirmwareVersion) { - self.outgoing = outgoing - self.sendChannel = sendChannel - self.repeatCount = repeatCount - self.delayBetweenPacketsMS = delayBetweenPacketsMS - self.preambleExtensionMS = preambleExtensionMS - self.firmwareVersion = firmwareVersion; - } - - var data: Data { - var data = Data([ - RileyLinkCommand.sendPacket.rawValue, - sendChannel, - repeatCount, - ]) - if firmwareVersion.supports16BitPacketDelay { - data.appendBigEndian(delayBetweenPacketsMS) - } else { - data.append(UInt8(clamping: Int(delayBetweenPacketsMS))) - } - - if firmwareVersion.supportsPreambleExtension { - data.appendBigEndian(preambleExtensionMS) - } - data.append(outgoing) - - return data - } -} - -struct RegisterSetting { - let address: CC111XRegister - let value: UInt8 -} - -struct UpdateRegister: Command { - typealias ResponseType = UpdateRegisterResponse - - enum Response: UInt8 { - case success = 1 - case invalidRegister = 2 - } - - let register: RegisterSetting - let firmwareVersion: RadioFirmwareVersion - - - init(_ address: CC111XRegister, value: UInt8, firmwareVersion: RadioFirmwareVersion) { - register = RegisterSetting(address: address, value: value) - self.firmwareVersion = firmwareVersion - } - - var data: Data { - var data = Data([ - RileyLinkCommand.updateRegister.rawValue, - register.address.rawValue, - register.value - ]) - if firmwareVersion.needsExtraByteForUpdateRegisterCommand { - data.append(0) - } - return data - } -} - -struct ReadRegister: Command { - typealias ResponseType = ReadRegisterResponse - - enum Response: UInt8 { - case success = 1 - case invalidRegister = 2 - } - - let address: CC111XRegister - let firmwareVersion: RadioFirmwareVersion - - init(_ address: CC111XRegister, firmwareVersion: RadioFirmwareVersion) { - self.address = address - self.firmwareVersion = firmwareVersion - } - - var data: Data { - var data = Data([ - RileyLinkCommand.readRegister.rawValue, - address.rawValue, - ]) - if firmwareVersion.needsExtraByteForReadRegisterCommand { - data.append(address.rawValue) - } - return data - } -} - - -struct SetModeRegisters: Command { - typealias ResponseType = UpdateRegisterResponse - - enum RegisterModeType: UInt8 { - case tx = 0x01 - case rx = 0x02 - } - - private var settings: [RegisterSetting] = [] - - let registerMode: RegisterModeType - - mutating func append(_ registerSetting: RegisterSetting) { - settings.append(registerSetting) - } - - var data: Data { - var data = Data([ - RileyLinkCommand.setModeRegisters.rawValue, - registerMode.rawValue - ]) - - for setting in settings { - data.append(setting.address.rawValue) - data.append(setting.value) - } - - return data - } -} - -struct SetSoftwareEncoding: Command { - typealias ResponseType = CodeResponse - - let encodingType: SoftwareEncodingType - - - init(_ encodingType: SoftwareEncodingType) { - self.encodingType = encodingType - } - - var data: Data { - return Data([ - RileyLinkCommand.setSWEncoding.rawValue, - encodingType.rawValue - ]) - } -} - -struct SetPreamble: Command { - typealias ResponseType = CodeResponse - - let preambleValue: UInt16 - - - init(_ value: UInt16) { - self.preambleValue = value - } - - var data: Data { - var data = Data([RileyLinkCommand.setPreamble.rawValue]) - data.appendBigEndian(preambleValue) - return data - - } -} - -struct SetLEDMode: Command { - typealias ResponseType = CodeResponse - - let led: RileyLinkLEDType - let mode: RileyLinkLEDMode - - - init(_ led: RileyLinkLEDType, mode: RileyLinkLEDMode) { - self.led = led - self.mode = mode - } - - var data: Data { - return Data([RileyLinkCommand.setLEDMode.rawValue, led.rawValue, mode.rawValue]) - } -} - - -struct ResetRadioConfig: Command { - typealias ResponseType = CodeResponse - - var data: Data { - return Data([RileyLinkCommand.resetRadioConfig.rawValue]) - } -} - -struct GetStatistics: Command { - typealias ResponseType = GetStatisticsResponse - - var data: Data { - return Data([RileyLinkCommand.getStatistics.rawValue]) - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/CommandSession.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/CommandSession.swift deleted file mode 100644 index 7ab034f54..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/CommandSession.swift +++ /dev/null @@ -1,316 +0,0 @@ -// -// RileyLinkCmdSession.swift -// RileyLinkBLEKit -// -// Created by Pete Schwamb on 10/8/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - -public enum RXFilterMode: UInt8 { - case wide = 0x50 // 300KHz - case narrow = 0x90 // 150KHz -} - -public enum SoftwareEncodingType: UInt8 { - case none = 0x00 - case manchester = 0x01 - case fourbsixb = 0x02 -} - -public enum CC111XRegister: UInt8 { - case sync1 = 0x00 - case sync0 = 0x01 - case pktlen = 0x02 - case pktctrl1 = 0x03 - case pktctrl0 = 0x04 - case fsctrl1 = 0x07 - case freq2 = 0x09 - case freq1 = 0x0a - case freq0 = 0x0b - case mdmcfg4 = 0x0c - case mdmcfg3 = 0x0d - case mdmcfg2 = 0x0e - case mdmcfg1 = 0x0f - case mdmcfg0 = 0x10 - case deviatn = 0x11 - case mcsm0 = 0x14 - case foccfg = 0x15 - case agcctrl2 = 0x17 - case agcctrl1 = 0x18 - case agcctrl0 = 0x19 - case frend1 = 0x1a - case frend0 = 0x1b - case fscal3 = 0x1c - case fscal2 = 0x1d - case fscal1 = 0x1e - case fscal0 = 0x1f - case test1 = 0x24 - case test0 = 0x25 - case paTable0 = 0x2e -} - -public struct RileyLinkStatistics { - public let uptime: TimeInterval - public let radioRxOverflowCount: UInt16 - public let radioRxFifoOverflowCount: UInt16 - public let packetRxCount: UInt16 - public let packetTxCount: UInt16 - public let crcFailureCount: UInt16 - public let spiSyncFailureCount: UInt16 - - public init(uptime: TimeInterval, radioRxOverflowCount: UInt16, radioRxFifoOverflowCount: UInt16, packetRxCount: UInt16, packetTxCount: UInt16, crcFailureCount: UInt16, spiSyncFailureCount: UInt16) { - self.uptime = uptime - self.radioRxOverflowCount = radioRxOverflowCount - self.radioRxFifoOverflowCount = radioRxFifoOverflowCount - self.packetRxCount = packetRxCount - self.packetTxCount = packetTxCount - self.crcFailureCount = crcFailureCount - self.spiSyncFailureCount = spiSyncFailureCount - } - -} - -public struct CommandSession { - let manager: PeripheralManager - let responseType: PeripheralManager.ResponseType - public let firmwareVersion: RadioFirmwareVersion - - /// Invokes a command expecting a response - /// - /// Unsuccessful responses are thrown as errors. - /// - /// - Parameters: - /// - command: The command - /// - timeout: The amount of time to wait for the pump to respond before throwing a timeout error. This should not include any expected BLE latency. - /// - Returns: The successful response - /// - Throws: RileyLinkDeviceError - private func writeCommand(_ command: C, timeout: TimeInterval) throws -> C.ResponseType { - let response = try manager.writeCommand(command, - timeout: timeout + PeripheralManager.expectedMaxBLELatency, - responseType: responseType - ) - - switch response.code { - case .rxTimeout: - throw RileyLinkDeviceError.responseTimeout - case .commandInterrupted: - throw RileyLinkDeviceError.responseTimeout - case .zeroData: - throw RileyLinkDeviceError.invalidResponse(Data()) - case .invalidParam: - throw RileyLinkDeviceError.errorResponse("RileyLink reported invalid param: " + command.data.hexadecimalString) - case .unknownCommand: - throw RileyLinkDeviceError.errorResponse("RileyLink reported unknown command: " + command.data.hexadecimalString) - case .success: - return response - } - } - - /// Invokes a command expecting an RF packet response - /// - /// - Parameters: - /// - command: The command - /// - timeout: The amount of time to wait for the pump to respond before throwing a timeout error. This should not include any expected BLE latency. - /// - Returns: The successful packet response - /// - Throws: RileyLinkDeviceError - private func writeCommand(_ command: C, timeout: TimeInterval) throws -> RFPacket where C.ResponseType == PacketResponse { - let response: C.ResponseType = try writeCommand(command, timeout: timeout) - - guard let packet = response.packet else { - throw RileyLinkDeviceError.invalidResponse(Data()) - } - return packet - } - - /// - Throws: RileyLinkDeviceError - public func updateRegister(_ address: CC111XRegister, value: UInt8) throws { - let command = UpdateRegister(address, value: value, firmwareVersion: firmwareVersion) - _ = try writeCommand(command, timeout: 0) - } - - /// - Throws: RileyLinkDeviceError - public func readRegister(_ address: CC111XRegister) throws -> UInt8 { - guard firmwareVersion.supportsReadRegister else { - throw RileyLinkDeviceError.unsupportedCommand(String(describing: RileyLinkCommand.readRegister)) - } - - let command = ReadRegister(address, firmwareVersion: firmwareVersion) - let response: ReadRegisterResponse = try writeCommand(command, timeout: 0) - - guard response.code == .success else { - throw RileyLinkDeviceError.errorResponse("Unsupported register: \(String(describing: address))") - } - - return response.value - } - - - /// - Throws: RileyLinkDeviceError - public func setCCLEDMode(_ mode: RileyLinkLEDMode) throws { - let ccMode: RileyLinkLEDMode - - switch mode { - case .on: - ccMode = .auto - default: - ccMode = .off - } - - let enableBlue = SetLEDMode(.blue, mode: ccMode) - _ = try writeCommand(enableBlue, timeout: 0) - let enableGreen = SetLEDMode(.green, mode: ccMode) - _ = try writeCommand(enableGreen, timeout: 0) - } - - private static let xtalFrequency = Measurement(value: 24, unit: .megahertz) - - /// - Throws: RileyLinkDeviceError - public func setBaseFrequency(_ frequency: Measurement) throws { - let val = Int( - frequency.converted(to: .hertz).value / - (CommandSession.xtalFrequency / pow(2, 16)).converted(to: .hertz).value) - - try updateRegister(.freq0, value: UInt8(val & 0xff)) - try updateRegister(.freq1, value: UInt8((val >> 8) & 0xff)) - try updateRegister(.freq2, value: UInt8((val >> 16) & 0xff)) - } - - public func readBaseFrequency() throws -> Measurement { - let freq0 = try readRegister(.freq0) - let freq1 = try readRegister(.freq1) - let freq2 = try readRegister(.freq2) - - let value = Double(UInt32(freq0) + (UInt32(freq1) << 8) + (UInt32(freq2) << 16)) - - let frequency = value * (CommandSession.xtalFrequency / pow(2, 16)).converted(to: .hertz).value - - return Measurement(value: frequency, unit: .hertz).converted(to: .megahertz) - } - - /// Sends data to the pump, listening for a reply - /// - /// - Parameters: - /// - data: The data to send - /// - repeatCount: The number of times to repeat the message before listening begins - /// - timeout: The length of time to listen for a response before timing out - /// - retryCount: The number of times to repeat the send & listen sequence - /// - preambleExtension: If set, the length of time to continuously send preamble data. Overrides the register based preamble settings. - /// - Returns: The packet reply - /// - Throws: RileyLinkDeviceError - public func sendAndListen(_ data: Data, repeatCount: Int, timeout: TimeInterval, retryCount: Int, preambleExtension: TimeInterval?) throws -> RFPacket { - let delayBetweenPackets: TimeInterval = 0 - - let command = SendAndListen( - outgoing: data, - sendChannel: 0, - repeatCount: UInt8(clamping: repeatCount), - delayBetweenPacketsMS: UInt16(clamping: Int(delayBetweenPackets)), - listenChannel: 0, - timeoutMS: UInt32(clamping: Int(timeout.milliseconds)), - retryCount: UInt8(clamping: retryCount), - preambleExtensionMS: UInt16(clamping: Int(preambleExtension?.milliseconds ?? 0)), - firmwareVersion: firmwareVersion - ) - - // At least 17 ms between packets for radio to stop/start - let radioTimeBetweenPackets = TimeInterval(milliseconds: 17) - let timeBetweenPackets = delayBetweenPackets + radioTimeBetweenPackets - - // 16384 = bitrate, 8 = bits per byte - let singlePacketSendTime: TimeInterval = (Double(data.count * 8) / 16_384) - let preambleTime = preambleExtension ?? 0 - let totalRepeatSendTime: TimeInterval = (singlePacketSendTime + timeBetweenPackets + preambleTime) * Double(repeatCount+1) - let totalTimeout = (totalRepeatSendTime + timeout) * Double(retryCount + 1) - return try writeCommand(command, timeout: totalTimeout) - } - - /// Sends data to the pump, listening for a reply - /// - /// - Parameters: - /// - data: The data to send - /// - repeatCount: The number of times to repeat the message before listening begins - /// - timeout: The length of time to listen for a response before timing out - /// - retryCount: The number of times to repeat the send & listen sequence if no response is heard - /// - Returns: The packet reply - /// - Throws: RileyLinkDeviceError - public func sendAndListen(_ data: Data, repeatCount: Int, timeout: TimeInterval, retryCount: Int) throws -> RFPacket { - return try sendAndListen(data, repeatCount: repeatCount, timeout: timeout, retryCount: retryCount, preambleExtension: nil) - } - - - /// - Throws: RileyLinkDeviceError - public func listen(onChannel channel: Int, timeout: TimeInterval) throws -> RFPacket? { - let command = GetPacket( - listenChannel: 0, - timeoutMS: UInt32(clamping: Int(timeout.milliseconds)) - ) - - return try writeCommand(command, timeout: timeout) - } - - /// - Throws: RileyLinkDeviceError - public func send(_ data: Data, onChannel channel: Int, timeout: TimeInterval) throws { - let command = SendPacket( - outgoing: data, - sendChannel: UInt8(clamping: channel), - repeatCount: 0, - delayBetweenPacketsMS: 0, - preambleExtensionMS: 0, - firmwareVersion: firmwareVersion - ) - - _ = try writeCommand(command, timeout: timeout) - } - - /// - Throws: RileyLinkDeviceError - public func setSoftwareEncoding(_ swEncodingType: SoftwareEncodingType) throws { - guard firmwareVersion.supportsSoftwareEncoding else { - throw RileyLinkDeviceError.unsupportedCommand(String(describing: RileyLinkCommand.setSWEncoding)) - } - - let command = SetSoftwareEncoding(swEncodingType) - - let response = try writeCommand(command, timeout: 0) - - guard response.code == .success else { - throw RileyLinkDeviceError.unsupportedCommand("Set Software Encoding error") - } - } - - public func resetRadioConfig() throws { - guard firmwareVersion.supportsResetRadioConfig else { - return - } - - let command = ResetRadioConfig() - _ = try writeCommand(command, timeout: 0) - } - - public func getRileyLinkStatistics() throws -> RileyLinkStatistics { - guard firmwareVersion.supportsRileyLinkStatistics else { - throw RileyLinkDeviceError.unsupportedCommand(String(describing: RileyLinkCommand.getStatistics)) - } - - let command = GetStatistics() - let response: GetStatisticsResponse = try writeCommand(command, timeout: 0) - - return response.statistics - } - - public func setPreamble(_ preambleValue: UInt16) throws { - guard firmwareVersion.supportsCustomPreamble else { - throw RileyLinkDeviceError.unsupportedCommand(String(describing: RileyLinkCommand.setPreamble)) - } - - let command = SetPreamble(preambleValue) - - _ = try writeCommand(command, timeout: 0) - } - - /// Asserts that the caller is currently on the session's queue - public func assertOnSessionQueue() { - dispatchPrecondition(condition: .onQueue(manager.queue)) - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/Info.plist b/Dependencies/rileylink_ios/RileyLinkBLEKit/Info.plist deleted file mode 100644 index 7a3ea75eb..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/PeripheralManager+RileyLink.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/PeripheralManager+RileyLink.swift deleted file mode 100644 index 3f69f2c09..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/PeripheralManager+RileyLink.swift +++ /dev/null @@ -1,667 +0,0 @@ -// -// PeripheralManager+RileyLink.swift -// xDripG5 -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import CoreBluetooth -import os.log - - -protocol CBUUIDRawValue: RawRepresentable {} -extension CBUUIDRawValue where RawValue == String { - var cbUUID: CBUUID { - return CBUUID(string: rawValue.uppercased()) - } -} - - -enum RileyLinkServiceUUID: String, CBUUIDRawValue { - case main - = "0235733B-99C5-4197-B856-69219C2A3845" - case battery = "180F" - case orange = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" - case secureDFU = "FE59" -} - -enum MainServiceCharacteristicUUID: String, CBUUIDRawValue { - case data = "C842E849-5028-42E2-867C-016ADADA9155" - case responseCount = "6E6C7910-B89E-43A5-A0FE-50C5E2B81F4A" - case customName = "D93B2AF0-1E28-11E4-8C21-0800200C9A66" - case timerTick = "6E6C7910-B89E-43A5-78AF-50C5E2B86F7E" - case firmwareVersion = "30D99DC9-7C91-4295-A051-0A104D238CF2" - case ledMode = "C6D84241-F1A7-4F9C-A25F-FCE16732F14E" -} - -enum BatteryServiceCharacteristicUUID: String, CBUUIDRawValue { - case battery_level = "2A19" -} - -enum OrangeServiceCharacteristicUUID: String, CBUUIDRawValue { - case orangeRX = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" - case orangeTX = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" -} - -enum SecureDFUCharacteristicUUID: String, CBUUIDRawValue { - case control = "8EC90001-F315-4F60-9FB8-838830DAEA50" -} - - -public enum OrangeLinkCommand: UInt8 { - case yellow = 0x1 - case red = 0x2 - case off = 0x3 - case shake = 0x4 - case shakeOff = 0x5 - case fw_hw = 0x9 -} - -public enum OrangeLinkRequestType: UInt8 { - case fctStartLoop = 0xaa // Fct_StartLoop - case fctHeader = 0xbb // Fct_PutReq - case fctStopLoop = 0xcc // Fct_StopLoop - case cfgHeader = 0xdd // Cfg_PutReq -} - -public enum OrangeLinkConfigurationSetting: UInt8 { - case connectionLED = 0x00 - case connectionVibrate = 0x01 -} - -public enum RileyLinkLEDMode: UInt8 { - case off = 0x00 - case on = 0x01 - case auto = 0x02 -} - - -extension PeripheralManager.Configuration { - static var rileyLink: PeripheralManager.Configuration { - return PeripheralManager.Configuration( - serviceCharacteristics: [ - RileyLinkServiceUUID.main.cbUUID: [ - MainServiceCharacteristicUUID.data.cbUUID, - MainServiceCharacteristicUUID.responseCount.cbUUID, - MainServiceCharacteristicUUID.customName.cbUUID, - MainServiceCharacteristicUUID.timerTick.cbUUID, - MainServiceCharacteristicUUID.firmwareVersion.cbUUID, - MainServiceCharacteristicUUID.ledMode.cbUUID - ], - RileyLinkServiceUUID.battery.cbUUID: [ - BatteryServiceCharacteristicUUID.battery_level.cbUUID - ], - RileyLinkServiceUUID.orange.cbUUID: [ - OrangeServiceCharacteristicUUID.orangeRX.cbUUID, - OrangeServiceCharacteristicUUID.orangeTX.cbUUID, - ], - RileyLinkServiceUUID.secureDFU.cbUUID: [ - SecureDFUCharacteristicUUID.control.cbUUID, - ] - - ], - notifyingCharacteristics: [ - RileyLinkServiceUUID.main.cbUUID: [ - MainServiceCharacteristicUUID.responseCount.cbUUID - ], - RileyLinkServiceUUID.orange.cbUUID: [ - OrangeServiceCharacteristicUUID.orangeTX.cbUUID, - ] - ], - valueUpdateMacros: [ - // When the responseCount changes, the data characteristic should be read. - MainServiceCharacteristicUUID.responseCount.cbUUID: { (manager: PeripheralManager) in - log.debug("responseCount valueUpdated") - guard let dataCharacteristic = manager.peripheral.getCharacteristicWithUUID(.data) - else { - log.debug("could not get data characteristic") - return - } - log.debug("Reading data characteristic") - manager.peripheral.readValue(for: dataCharacteristic) - } - ] - ) - } -} - -fileprivate extension CBPeripheral { - func getBatteryCharacteristic(_ uuid: BatteryServiceCharacteristicUUID) -> CBCharacteristic? { - guard let service = services?.itemWithUUID(RileyLinkServiceUUID.battery.cbUUID) else { - return nil - } - - return service.characteristics?.itemWithUUID(uuid.cbUUID) - } - - func getOrangeCharacteristic(_ uuid: OrangeServiceCharacteristicUUID) -> CBCharacteristic? { - guard let service = services?.itemWithUUID(RileyLinkServiceUUID.orange.cbUUID) else { - return nil - } - - return service.characteristics?.itemWithUUID(uuid.cbUUID) - } - - func getCharacteristicWithUUID(_ uuid: MainServiceCharacteristicUUID, serviceUUID: RileyLinkServiceUUID = .main) -> CBCharacteristic? { - guard let service = services?.itemWithUUID(serviceUUID.cbUUID) else { - return nil - } - - return service.characteristics?.itemWithUUID(uuid.cbUUID) - } -} - - -extension CBCentralManager { - func scanForPeripherals(withOptions options: [String: Any]? = nil) { - scanForPeripherals(withServices: [RileyLinkServiceUUID.main.cbUUID], options: options) - } -} - - -extension Command { - /// Encodes a command's data by validating and prepending its length - /// - /// - Returns: Writable command data - /// - Throws: RileyLinkDeviceError.writeSizeLimitExceeded if the command data is too long - fileprivate func writableData() throws -> Data { - var data = self.data - - guard data.count <= 220 else { - throw RileyLinkDeviceError.writeSizeLimitExceeded(maxLength: 220) - } - - data.insert(UInt8(clamping: data.count), at: 0) - return data - } -} - - -private let log = OSLog(category: "PeripheralManager+RileyLink") - - -extension PeripheralManager { - static let expectedMaxBLELatency: TimeInterval = 2 - - func readBatteryLevel(completion: @escaping (Int?) -> Void) { - perform { (manager) in - guard let characteristic = self.peripheral.getBatteryCharacteristic(.battery_level) else { - completion(nil) - return - } - - do { - guard let data = try self.readValue(for: characteristic, timeout: PeripheralManager.expectedMaxBLELatency) else { - completion(nil) - return - } - - completion(Int(data[0])) - } catch { - completion(nil) - } - } - } - - func readDiagnosticLEDMode(completion: @escaping (RileyLinkLEDMode?) -> Void) { - perform { (manager) in - do { - guard - let characteristic = self.peripheral.getCharacteristicWithUUID(.ledMode), - let data = try self.readValue(for: characteristic, timeout: PeripheralManager.expectedMaxBLELatency), - let mode = RileyLinkLEDMode(rawValue: data[0]) else - { - completion(nil) - return - } - completion(mode) - } catch { - completion(nil) - } - } - } - - var timerTickEnabled: Bool { - return peripheral.getCharacteristicWithUUID(.timerTick)?.isNotifying ?? false - } - - func setTimerTickEnabled(_ enabled: Bool, timeout: TimeInterval = expectedMaxBLELatency, completion: ((_ error: RileyLinkDeviceError?) -> Void)? = nil) { - perform { (manager) in - do { - guard let characteristic = manager.peripheral.getCharacteristicWithUUID(.timerTick) else { - throw PeripheralManagerError.unknownCharacteristic(MainServiceCharacteristicUUID.timerTick.cbUUID) - } - - try manager.setNotifyValue(enabled, for: characteristic, timeout: timeout) - completion?(nil) - } catch let error as PeripheralManagerError { - completion?(.peripheralManagerError(error)) - } catch { - assertionFailure() - } - } - } - - func setLEDMode(mode: RileyLinkLEDMode) { - perform { (manager) in - do { - guard let characteristic = manager.peripheral.getCharacteristicWithUUID(.ledMode) else { - throw PeripheralManagerError.unknownCharacteristic(MainServiceCharacteristicUUID.ledMode.cbUUID) - } - let value = Data([mode.rawValue]) - try manager.writeValue(value, for: characteristic, type: .withResponse, timeout: PeripheralManager.expectedMaxBLELatency) - } catch (let error) { - assertionFailure(String(describing: error)) - } - } - } - - - - func startIdleListening(idleTimeout: TimeInterval, channel: UInt8, timeout: TimeInterval = expectedMaxBLELatency, completion: @escaping (_ error: RileyLinkDeviceError?) -> Void) { - perform { (manager) in - let command = GetPacket(listenChannel: channel, timeoutMS: UInt32(clamping: Int(idleTimeout.milliseconds))) - - do { - try manager.writeCommandWithoutResponse(command, timeout: timeout) - completion(nil) - } catch let error as RileyLinkDeviceError { - completion(error) - } catch { - assertionFailure() - } - } - } - - func setCustomName(_ name: String, timeout: TimeInterval = expectedMaxBLELatency, completion: ((_ error: RileyLinkDeviceError?) -> Void)? = nil) { - guard let value = name.data(using: .utf8) else { - completion?(.errorResponse(name)) - return - } - - perform { (manager) in - do { - guard let characteristic = manager.peripheral.getCharacteristicWithUUID(.customName) else { - throw PeripheralManagerError.unknownCharacteristic(MainServiceCharacteristicUUID.customName.cbUUID) - } - - try manager.writeValue(value, for: characteristic, type: .withResponse, timeout: timeout) - completion?(nil) - } catch let error as PeripheralManagerError { - completion?(.peripheralManagerError(error)) - } catch { - assertionFailure() - } - } - } -} - - - -// MARK: - Synchronous commands -extension PeripheralManager { - enum ResponseType { - case single - case buffered - } - - /// Invokes a command expecting a response - /// - /// - Parameters: - /// - command: The command - /// - timeout: The amount of time to wait for the peripheral to respond before throwing a timeout error - /// - responseType: The BLE response value framing method - /// - Returns: The received response - /// - Throws: - /// - RileyLinkDeviceError.invalidResponse - /// - RileyLinkDeviceError.peripheralManagerError - /// - RileyLinkDeviceError.writeSizeLimitExceeded - func writeCommand(_ command: C, timeout: TimeInterval, responseType: ResponseType) throws -> C.ResponseType { - guard let characteristic = peripheral.getCharacteristicWithUUID(.data) else { - throw RileyLinkDeviceError.peripheralManagerError(PeripheralManagerError.unknownCharacteristic(MainServiceCharacteristicUUID.data.cbUUID)) - } - - let value = try command.writableData() - - - switch responseType { - case .single: - log.debug("RL Send (single): %@", value.hexadecimalString) - return try writeCommand(value, - for: characteristic, - timeout: timeout - ) - case .buffered: - log.debug("RL Send (buffered): %@", value.hexadecimalString) - return try writeLegacyCommand(value, - for: characteristic, - timeout: timeout, - endOfResponseMarker: 0x00 - ) - } - } - - /// Invokes a command without waiting for its response - /// - /// - Parameters: - /// - command: The command - /// - timeout: The amount of time to wait for the peripheral to confirm the write before throwing a timeout error - /// - Throws: - /// - RileyLinkDeviceError.invalidResponse - /// - RileyLinkDeviceError.peripheralManagerError - /// - RileyLinkDeviceError.writeSizeLimitExceeded - fileprivate func writeCommandWithoutResponse(_ command: C, timeout: TimeInterval) throws { - guard let characteristic = peripheral.getCharacteristicWithUUID(.data) else { - throw RileyLinkDeviceError.peripheralManagerError(PeripheralManagerError.unknownCharacteristic(MainServiceCharacteristicUUID.data.cbUUID)) - } - - let value = try command.writableData() - - log.debug("RL Send (no response expected): %@", value.hexadecimalString) - - do { - try writeValue(value, for: characteristic, type: .withResponse, timeout: timeout) - } catch let error as PeripheralManagerError { - throw RileyLinkDeviceError.peripheralManagerError(error) - } - } - - /// - Throws: - /// - RileyLinkDeviceError.invalidResponse - /// - RileyLinkDeviceError.peripheralManagerError - func readRadioFirmwareVersion(timeout: TimeInterval, responseType: ResponseType) throws -> String { - let response = try writeCommand(GetVersion(), timeout: timeout, responseType: responseType) - return response.version - } - - /// - Throws: - /// - RileyLinkDeviceError.invalidResponse - /// - RileyLinkDeviceError.peripheralManagerError - func readBluetoothFirmwareVersion(timeout: TimeInterval) throws -> String { - guard let characteristic = peripheral.getCharacteristicWithUUID(.firmwareVersion) else { - throw RileyLinkDeviceError.peripheralManagerError(PeripheralManagerError.unknownCharacteristic(MainServiceCharacteristicUUID.firmwareVersion.cbUUID)) - } - - do { - guard let data = try readValue(for: characteristic, timeout: timeout) else { - throw RileyLinkDeviceError.peripheralManagerError(PeripheralManagerError.emptyValue) - } - - guard let version = String(bytes: data, encoding: .utf8) else { - throw RileyLinkDeviceError.invalidResponse(data) - } - - return version - } catch let error as PeripheralManagerError { - throw RileyLinkDeviceError.peripheralManagerError(error) - } - } -} - - -// MARK: - Lower-level helper operations -extension PeripheralManager { - - func setOrangeNotifyOn() throws { - perform { [self] (manager) in - guard let characteristicNotif = peripheral.getOrangeCharacteristic(.orangeTX) else { - return - } - - do { - try setNotifyValue(true, for: characteristicNotif, timeout: 2) - } catch { - log.error("setOrangeNotifyOn failed: %@", error.localizedDescription) - } - } - } - - func orangeAction(_ command: OrangeLinkCommand) { - if command != .off, command != .shakeOff { - orangeWritePwd() - } - perform { [self] (manager) in - do { - guard let characteristic = peripheral.getOrangeCharacteristic(.orangeRX) else { - throw PeripheralManagerError.unknownCharacteristic(OrangeServiceCharacteristicUUID.orangeRX.cbUUID) - } - let value = Data([OrangeLinkRequestType.fctHeader.rawValue, command.rawValue]) - try writeValue(value, for: characteristic, type: .withResponse, timeout: PeripheralManager.expectedMaxBLELatency) - } catch (_) { - log.debug("orangeAction failed") - } - } - if command == .off, command == .shakeOff { - orangeClose() - } - } - - func findDevice() { - perform { [self] (manager) in - do { - guard let characteristic = peripheral.getOrangeCharacteristic(.orangeRX) else { - throw PeripheralManagerError.unknownCharacteristic(OrangeServiceCharacteristicUUID.orangeRX.cbUUID) - } - let value = Data([OrangeLinkRequestType.cfgHeader.rawValue, 0x04]) - try writeValue(value, for: characteristic, type: .withResponse, timeout: PeripheralManager.expectedMaxBLELatency) - } catch (_) { - log.debug("findDevice failed") - } - } - } - - func setOrangeConfig(_ config: OrangeLinkConfigurationSetting, isOn: Bool) { - perform { [self] (manager) in - do { - guard let characteristic = peripheral.getOrangeCharacteristic(.orangeRX) else { - throw PeripheralManagerError.unknownCharacteristic(OrangeServiceCharacteristicUUID.orangeRX.cbUUID) - } - let value = Data([OrangeLinkRequestType.cfgHeader.rawValue, 0x02, config.rawValue, isOn ? 1 : 0]) - try writeValue(value, for: characteristic, type: .withResponse, timeout: PeripheralManager.expectedMaxBLELatency) - } catch (_) { - log.debug("setOrangeConfig failed") - } - } - } - - func orangeWritePwd() { - perform { [self] (manager) in - do { - guard let characteristic = peripheral.getOrangeCharacteristic(.orangeRX) else { - throw PeripheralManagerError.unknownCharacteristic(OrangeServiceCharacteristicUUID.orangeRX.cbUUID) - } - let value = Data([0xAA]) - try writeValue(value, for: characteristic, type: .withResponse, timeout: PeripheralManager.expectedMaxBLELatency) - } catch (_) { - log.debug("orangeWritePwd failed") - } - } - } - - func orangeReadSet() { - perform { [self] (manager) in - do { - guard let characteristic = peripheral.getOrangeCharacteristic(.orangeRX) else { - throw PeripheralManagerError.unknownCharacteristic(OrangeServiceCharacteristicUUID.orangeRX.cbUUID) - } - let value = Data([OrangeLinkRequestType.cfgHeader.rawValue, 0x01]) - log.debug("orangeReadSet write: %@", value.hexadecimalString) - try writeValue(value, for: characteristic, type: .withResponse, timeout: PeripheralManager.expectedMaxBLELatency) - } catch (_) { - log.debug("orangeReadSet failed") - } - } - } - - func orangeReadVDC() { - perform { [self] (manager) in - do { - guard let characteristic = peripheral.getOrangeCharacteristic(.orangeRX) else { - throw PeripheralManagerError.unknownCharacteristic(OrangeServiceCharacteristicUUID.orangeRX.cbUUID) - } - let value = Data([OrangeLinkRequestType.cfgHeader.rawValue, 0x03]) - try writeValue(value, for: characteristic, type: .withResponse, timeout: PeripheralManager.expectedMaxBLELatency) - } catch (_) { - log.debug("orangeReadVDC failed") - } - } - } - - func orangeClose() { - perform { [self] (manager) in - do { - guard let characteristic = peripheral.getOrangeCharacteristic(.orangeRX) else { - throw PeripheralManagerError.unknownCharacteristic(OrangeServiceCharacteristicUUID.orangeRX.cbUUID) - } - let value = Data([0xcc]) - try writeValue(value, for: characteristic, type: .withResponse, timeout: PeripheralManager.expectedMaxBLELatency) - } catch (_) { - log.debug("orangeClose failed") - } - } - } - - /// Writes command data expecting a single response - /// - /// - Parameters: - /// - data: The command data - /// - characteristic: The peripheral characteristic to write - /// - type: The type of characteristic write - /// - timeout: The amount of time to wait for the peripheral to respond before throwing a timeout error - /// - Returns: The recieved response - /// - Throws: - /// - RileyLinkDeviceError.invalidResponse - /// - RileyLinkDeviceError.peripheralManagerError - private func writeCommand(_ data: Data, - for characteristic: CBCharacteristic, - type: CBCharacteristicWriteType = .withResponse, - timeout: TimeInterval - ) throws -> R - { - var capturedResponse: R? - - do { - try runCommand(timeout: timeout) { - if case .withResponse = type { - addCondition(.write(characteristic: characteristic)) - } - - addCondition(.valueUpdate(characteristic: characteristic, matching: { value in - guard let value = value, value.count > 0 else { - log.debug("Empty response from RileyLink. Continuing to listen for command response.") - return false - } - - log.debug("RL Recv(single): %@", value.hexadecimalString) - - guard let code = ResponseCode(rawValue: value[0]) else { - let unknownCode = value[0..<1].hexadecimalString - log.error("Unknown response code from RileyLink: %{public}@. Continuing to listen for command response.", unknownCode) - return false - } - - switch code { - case .commandInterrupted: - // This is expected in cases where an "Idle" GetPacket command is running - log.debug("Idle command interrupted. Continuing to listen for command response.") - return false - default: - guard let response = R(data: value) else { - log.error("Unable to parse response: %{public}@", value.hexadecimalString) - // We don't recognize the contents. Keep listening. - return false - } - log.debug("writeCommand response: %{public}@", String(describing: response)) - capturedResponse = response - return true - } - })) - - peripheral.writeValue(data, for: characteristic, type: type) - } - } catch let error as PeripheralManagerError { - // If the write succeeded, but we get no response, BLE comms are working but RL command channel is hung - if case .timeout(let unmetConditions) = error, - let firstUnmetCondition = unmetConditions.first, - case .valueUpdate = firstUnmetCondition - { - throw RileyLinkDeviceError.commandsBlocked - } else { - throw RileyLinkDeviceError.peripheralManagerError(error) - } - } - - guard let response = capturedResponse else { - throw RileyLinkDeviceError.invalidResponse(characteristic.value ?? Data()) - } - - return response - } - - /// Writes command data expecting a bufferred response - /// - /// - Parameters: - /// - data: The command data - /// - characteristic: The peripheral characteristic to write - /// - type: The type of characteristic write - /// - timeout: The amount of time to wait for the peripheral to respond before throwing a timeout error - /// - endOfResponseMarker: The marker delimiting the end of a response in the buffer - /// - Returns: The received response. In the event of multiple responses in the buffer, the first parsable response is returned. - /// - Throws: - /// - RileyLinkDeviceError.invalidResponse - /// - RileyLinkDeviceError.peripheralManagerError - private func writeLegacyCommand(_ data: Data, - for characteristic: CBCharacteristic, - type: CBCharacteristicWriteType = .withResponse, - timeout: TimeInterval, - endOfResponseMarker: UInt8 - ) throws -> R - { - var capturedResponse: R? - var buffer = ResponseBuffer(endMarker: endOfResponseMarker) - - do { - try runCommand(timeout: timeout) { - if case .withResponse = type { - addCondition(.write(characteristic: characteristic)) - } - - addCondition(.valueUpdate(characteristic: characteristic, matching: { value in - guard let value = value else { - return false - } - - log.debug("RL Recv(buffered): %@", value.hexadecimalString) - buffer.append(value) - - for response in buffer.responses { - switch response.code { - case .rxTimeout, .zeroData, .invalidParam, .unknownCommand: - log.debug("writeLegacyCommand response: %{public}@", String(describing: response)) - capturedResponse = response - return true - case .commandInterrupted: - // This is expected in cases where an "Idle" GetPacket command is running - log.debug("writeLegacyCommand response (commandInterrupted): %{public}@", String(describing: response)) - case .success: - capturedResponse = response - return true - } - } - - return false - })) - - peripheral.writeValue(data, for: characteristic, type: type) - } - } catch let error as PeripheralManagerError { - throw RileyLinkDeviceError.peripheralManagerError(error) - } - - guard let response = capturedResponse else { - throw RileyLinkDeviceError.invalidResponse(characteristic.value ?? Data()) - } - - return response - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/PeripheralManager.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/PeripheralManager.swift deleted file mode 100644 index 35dceea78..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/PeripheralManager.swift +++ /dev/null @@ -1,465 +0,0 @@ -// -// PeripheralManager.swift -// xDripG5 -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import CoreBluetooth -import Foundation -import os.log - - -class PeripheralManager: NSObject { - - private let log = OSLog(category: "PeripheralManager") - - /// - /// This is mutable, because CBPeripheral instances can seemingly become invalid, and need to be periodically re-fetched from CBCentralManager - var peripheral: CBPeripheral { - didSet { - guard oldValue !== peripheral else { - return - } - - log.error("Replacing peripheral reference %{public}@ -> %{public}@", oldValue, peripheral) - - oldValue.delegate = nil - peripheral.delegate = self - - queue.sync { - self.needsConfiguration = true - } - } - } - - /// The dispatch queue used to serialize operations on the peripheral - let queue: DispatchQueue - - /// The condition used to signal command completion - private let commandLock = NSCondition() - - /// The required conditions for the operation to complete - private var commandConditions = [CommandCondition]() - - /// Any error surfaced during the active operation - private var commandError: Error? - - private(set) weak var central: CBCentralManager? - - let configuration: Configuration - - // Confined to `queue` - private var needsConfiguration = true - - weak var delegate: PeripheralManagerDelegate? { - didSet { - queue.sync { - needsConfiguration = true - } - } - } - - // Called from RileyLinkDeviceManager.managerQueue - init(peripheral: CBPeripheral, configuration: Configuration, centralManager: CBCentralManager, queue: DispatchQueue) { - self.peripheral = peripheral - self.central = centralManager - self.configuration = configuration - self.queue = queue - - super.init() - - peripheral.delegate = self - - assertConfiguration() - } -} - - -// MARK: - Nested types -extension PeripheralManager { - struct Configuration { - var serviceCharacteristics: [CBUUID: [CBUUID]] = [:] - var notifyingCharacteristics: [CBUUID: [CBUUID]] = [:] - var valueUpdateMacros: [CBUUID: (_ manager: PeripheralManager) -> Void] = [:] - } - - enum CommandCondition { - case notificationStateUpdate(characteristic: CBCharacteristic, enabled: Bool) - case valueUpdate(characteristic: CBCharacteristic, matching: ((Data?) -> Bool)?) - case write(characteristic: CBCharacteristic) - case discoverServices - case discoverCharacteristicsForService(serviceUUID: CBUUID) - } -} - -protocol PeripheralManagerDelegate: AnyObject { - func peripheralManager(_ manager: PeripheralManager, didUpdateValueFor characteristic: CBCharacteristic) - - func peripheralManager(_ manager: PeripheralManager, didUpdateNotificationStateFor characteristic: CBCharacteristic) - - func peripheralManager(_ manager: PeripheralManager, didReadRSSI RSSI: NSNumber, error: Error?) - - func peripheralManagerDidUpdateName(_ manager: PeripheralManager) - - func completeConfiguration(for manager: PeripheralManager) throws -} - - -// MARK: - Operation sequence management -extension PeripheralManager { - func configureAndRun(_ block: @escaping (_ manager: PeripheralManager) -> Void) -> (() -> Void) { - return { - if self.needsConfiguration || self.peripheral.services == nil { - self.log.default("Configuring peripheral %{public}@, needsConfiguration=%{public}@, has services = %{public}@", self.peripheral, String(describing: self.needsConfiguration), String(describing: self.peripheral.services != nil)) - do { - try self.applyConfiguration() - self.log.default("Peripheral configuration completed: %{public}@", self.peripheral) - } catch let error { - self.log.error("Error applying peripheral configuration: %{public}@", String(describing: error)) - // Will retry - } - - do { - if let delegate = self.delegate { - try delegate.completeConfiguration(for: self) - self.log.default("Delegate configuration completed") - self.needsConfiguration = false - } else { - self.log.error("No delegate set for configuration") - } - } catch let error { - self.log.error("Error applying delegate configuration: %{public}@", String(describing: error)) - // Will retry - } - } - - block(self) - } - } - - func perform(_ block: @escaping (_ manager: PeripheralManager) -> Void) { - queue.async(execute: configureAndRun(block)) - } - - private func assertConfiguration() { - if peripheral.state == .connected { - perform { (_) in - // Intentionally empty to trigger configuration if necessary - } - } - } - - private func applyConfiguration(discoveryTimeout: TimeInterval = 2) throws { - try discoverServices(configuration.serviceCharacteristics.keys.map { $0 }, timeout: discoveryTimeout) - - for service in peripheral.services ?? [] { - guard let characteristics = configuration.serviceCharacteristics[service.uuid] else { - // Not all services have characteristics - continue - } - - try discoverCharacteristics(characteristics, for: service, timeout: discoveryTimeout) - } - - // Subscribe to notifying characteristics - for (serviceUUID, characteristicUUIDs) in configuration.notifyingCharacteristics { - guard let service = peripheral.services?.itemWithUUID(serviceUUID) else { - // Not all RL's have OrangeLink service - continue - } - - for characteristicUUID in characteristicUUIDs { - guard let characteristic = service.characteristics?.itemWithUUID(characteristicUUID) else { - throw PeripheralManagerError.unknownCharacteristic(characteristicUUID) - } - - guard !characteristic.isNotifying else { - continue - } - - try setNotifyValue(true, for: characteristic, timeout: discoveryTimeout) - } - } - } -} - - -// MARK: - Synchronous Commands -extension PeripheralManager { - /// - Throws: PeripheralManagerError - func runCommand(timeout: TimeInterval, command: () -> Void) throws { - // Prelude - dispatchPrecondition(condition: .onQueue(queue)) - guard central?.state == .poweredOn && peripheral.state == .connected else { - throw PeripheralManagerError.notReady - } - - commandLock.lock() - - defer { - commandLock.unlock() - } - - guard commandConditions.isEmpty else { - throw PeripheralManagerError.busy - } - - // Run - command() - - guard !commandConditions.isEmpty else { - // If the command didn't add any conditions, then finish immediately - return - } - - // Postlude - let signaled = commandLock.wait(until: Date(timeIntervalSinceNow: timeout)) - - defer { - commandError = nil - commandConditions = [] - } - - guard signaled else { - throw PeripheralManagerError.timeout(commandConditions) - } - - if let error = commandError { - throw PeripheralManagerError.cbPeripheralError(error) - } - } - - /// It's illegal to call this without first acquiring the commandLock - /// - /// - Parameter condition: The condition to add - func addCondition(_ condition: CommandCondition) { - dispatchPrecondition(condition: .onQueue(queue)) - commandConditions.append(condition) - } - - func discoverServices(_ serviceUUIDs: [CBUUID], timeout: TimeInterval) throws { - let servicesToDiscover = peripheral.servicesToDiscover(from: serviceUUIDs) - - guard servicesToDiscover.count > 0 else { - return - } - - try runCommand(timeout: timeout) { - addCondition(.discoverServices) - - peripheral.discoverServices(serviceUUIDs) - } - } - - func discoverCharacteristics(_ characteristicUUIDs: [CBUUID], for service: CBService, timeout: TimeInterval) throws { - let characteristicsToDiscover = peripheral.characteristicsToDiscover(from: characteristicUUIDs, for: service) - - guard characteristicsToDiscover.count > 0 else { - return - } - - try runCommand(timeout: timeout) { - addCondition(.discoverCharacteristicsForService(serviceUUID: service.uuid)) - - peripheral.discoverCharacteristics(characteristicsToDiscover, for: service) - } - } - - /// - Throws: PeripheralManagerError - func setNotifyValue(_ enabled: Bool, for characteristic: CBCharacteristic, timeout: TimeInterval) throws { - try runCommand(timeout: timeout) { - addCondition(.notificationStateUpdate(characteristic: characteristic, enabled: enabled)) - - peripheral.setNotifyValue(enabled, for: characteristic) - } - } - - /// - Throws: PeripheralManagerError - func readValue(for characteristic: CBCharacteristic, timeout: TimeInterval) throws -> Data? { - try runCommand(timeout: timeout) { - addCondition(.valueUpdate(characteristic: characteristic, matching: nil)) - - peripheral.readValue(for: characteristic) - } - - return characteristic.value - } - - - /// - Throws: PeripheralManagerError - func writeValue(_ value: Data, for characteristic: CBCharacteristic, type: CBCharacteristicWriteType, timeout: TimeInterval) throws { - try runCommand(timeout: timeout) { - if case .withResponse = type { - addCondition(.write(characteristic: characteristic)) - } - - peripheral.writeValue(value, for: characteristic, type: type) - } - } -} - - -// MARK: - Delegate methods executed on the central's queue -extension PeripheralManager: CBPeripheralDelegate { - - func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .discoverServices = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .discoverCharacteristicsForService(serviceUUID: service.uuid) = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .notificationStateUpdate(characteristic: characteristic, enabled: characteristic.isNotifying) = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - delegate?.peripheralManager(self, didUpdateNotificationStateFor: characteristic) - } - - func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { - commandLock.lock() - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .write(characteristic: characteristic) = condition { - return true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } - - commandLock.unlock() - } - - func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { - commandLock.lock() - - var notifyDelegate = false - - if let index = commandConditions.firstIndex(where: { (condition) -> Bool in - if case .valueUpdate(characteristic: characteristic, matching: let matching) = condition { - return matching?(characteristic.value) ?? true - } else { - return false - } - }) { - commandConditions.remove(at: index) - commandError = error - - if commandConditions.isEmpty { - commandLock.broadcast() - } - } else if let macro = configuration.valueUpdateMacros[characteristic.uuid] { - macro(self) - } else { - notifyDelegate = true // execute after the unlock - } - - commandLock.unlock() - - if notifyDelegate { - // If we weren't expecting this notification, pass it along to the delegate - delegate?.peripheralManager(self, didUpdateValueFor: characteristic) - } - } - - func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) { - delegate?.peripheralManager(self, didReadRSSI: RSSI, error: error) - } - - func peripheralDidUpdateName(_ peripheral: CBPeripheral) { - delegate?.peripheralManagerDidUpdateName(self) - } -} - - -extension PeripheralManager: CBCentralManagerDelegate { - func centralManagerDidUpdateState(_ central: CBCentralManager) { - switch central.state { - case .poweredOn: - assertConfiguration() - default: - break - } - } - - func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { - switch peripheral.state { - case .connected: - assertConfiguration() - default: - break - } - } -} - -extension PeripheralManager { - - public override var debugDescription: String { - var items = [ - "## PeripheralManager", - "peripheral: \(peripheral)" - ] - queue.sync { - items.append("needsConfiguration: \(needsConfiguration)") - } - return items.joined(separator: "\n") - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/PeripheralManagerError.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/PeripheralManagerError.swift deleted file mode 100644 index ab995e69d..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/PeripheralManagerError.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// PeripheralManagerError.swift -// RileyLinkBLEKit -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import CoreBluetooth - - -enum PeripheralManagerError: Error { - case cbPeripheralError(Error) - case notReady - case busy - case timeout([PeripheralManager.CommandCondition]) - case emptyValue - case unknownCharacteristic(CBUUID) - case unknownService(CBUUID) -} - - -extension PeripheralManagerError: LocalizedError { - public var errorDescription: String? { - switch self { - case .cbPeripheralError(let error): - return error.localizedDescription - case .notReady: - return LocalizedString("RileyLink is not connected", comment: "PeripheralManagerError.notReady error description") - case .busy: - return LocalizedString("RileyLink is busy", comment: "PeripheralManagerError.busy error description") - case .timeout: - return LocalizedString("RileyLink did not respond in time", comment: "PeripheralManagerError.timeout error description") - case .emptyValue: - return LocalizedString("Characteristic value was empty", comment: "PeripheralManagerError.emptyValue error description") - case .unknownCharacteristic(let cbuuid): - return String(format: LocalizedString("Unknown characteristic: %@", comment: "PeripheralManagerError.unknownCharacteristic error description"), cbuuid.uuidString) - case .unknownService(let cbuuid): - return String(format: LocalizedString("Unknown service: %@", comment: "PeripheralManagerError.unknownCharacteristic error description"), cbuuid.uuidString) - } - } - - public var failureReason: String? { - switch self { - case .cbPeripheralError(let error as NSError): - return error.localizedFailureReason - case .unknownCharacteristic: - return LocalizedString("The RileyLink was temporarily disconnected", comment: "Failure reason: unknown peripheral characteristic") - default: - return nil - } - } - - public var recoverySuggestion: String? { - switch self { - case .cbPeripheralError(let error as NSError): - return error.localizedRecoverySuggestion - case .unknownCharacteristic: - return LocalizedString("Make sure the device is nearby, and the issue should resolve automatically", comment: "Recovery suggestion for unknown peripheral characteristic") - default: - return nil - } - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/RFPacket.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/RFPacket.swift deleted file mode 100644 index e945d3f56..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/RFPacket.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// RFPacket.swift -// RileyLinkBLEKit -// -// Created by Pete Schwamb on 9/16/17. -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct RFPacket : CustomStringConvertible { - public let data: Data - let packetCounter: Int - public let rssi: Int - - public init?(rfspyResponse: Data) { - guard rfspyResponse.count >= 2 else { - return nil - } - - let startIndex = rfspyResponse.startIndex - - let rssiDec = Int(rfspyResponse[startIndex]) - let rssiOffset = 73 - if rssiDec >= 128 { - self.rssi = (rssiDec - 256) / 2 - rssiOffset - } else { - self.rssi = rssiDec / 2 - rssiOffset - } - - self.packetCounter = Int(rfspyResponse[startIndex.advanced(by: 1)]) - - self.data = rfspyResponse.subdata(in: startIndex.advanced(by: 2).. Bool { - return lhs.components == rhs.components - } -} - -// Version 2 changes -extension RadioFirmwareVersion { - - private var atLeastV2: Bool { - guard let major = components.first, major >= 2 else { - return false - } - return true - } - - private var atLeastV2_2: Bool { - guard components.count >= 2 else { - return false; - } - let major = components[0] - let minor = components[1] - return major > 2 || (major == 2 && minor >= 2) - } - - - var supportsPreambleExtension: Bool { - return atLeastV2 - } - - var supportsSoftwareEncoding: Bool { - return atLeastV2 - } - - var supportsResetRadioConfig: Bool { - return atLeastV2 - } - - var supports16BitPacketDelay: Bool { - return atLeastV2 - } - - var needsExtraByteForUpdateRegisterCommand: Bool { - // Fixed in 2.2 - return !atLeastV2 - } - - var needsExtraByteForReadRegisterCommand: Bool { - // Fixed in 2.3 - guard components.count >= 2 else { - return true; - } - let major = components[0] - let minor = components[1] - return major < 2 || (major == 2 && minor <= 2) - } - - var supportsRileyLinkStatistics: Bool { - return atLeastV2_2 - } - - var supportsCustomPreamble: Bool { - return atLeastV2 - } - - var supportsReadRegister: Bool { - return atLeastV2 - } - -} - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/Response.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/Response.swift deleted file mode 100644 index 4181de32e..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/Response.swift +++ /dev/null @@ -1,213 +0,0 @@ -// -// Response.swift -// RileyLinkBLEKit -// -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -enum ResponseCode: UInt8 { - case rxTimeout = 0xaa - case commandInterrupted = 0xbb - case zeroData = 0xcc - case success = 0xdd - case invalidParam = 0x11 - case unknownCommand = 0x22 -} - -protocol Response { - var code: ResponseCode { get } - - init?(data: Data) - - init?(legacyData data: Data) -} - -struct CodeResponse: Response { - let code: ResponseCode - - init?(data: Data) { - guard data.count == 1, let code = ResponseCode(rawValue: data[data.startIndex]) else { - return nil - } - - self.code = code - } - - init?(legacyData data: Data) { - guard data.count == 0 else { - return nil - } - - self.code = .success - } -} - -struct ReadRegisterResponse: Response { - let code: ResponseCode - let value: UInt8 - - init?(data: Data) { - guard data.count > 1, let code = ResponseCode(rawValue: data[data.startIndex]) else { - return nil - } - - self.init(code: code, value: data[data.startIndex.advanced(by: 1)]) - } - - init?(legacyData data: Data) { - self.init(code: .success, value: data[0]) - } - - private init?(code: ResponseCode, value: UInt8) { - self.code = code - self.value = value - } -} - -struct UpdateRegisterResponse: Response { - let code: ResponseCode - - init?(data: Data) { - guard data.count > 0, let code = ResponseCode(rawValue: data[data.startIndex]) else { - return nil - } - - self.code = code - } - - private enum LegacyCode: UInt8 { - case success = 1 - case invalidRegister = 2 - - var responseCode: ResponseCode { - switch self { - case .success: - return .success - case .invalidRegister: - return .invalidParam - } - } - } - - init?(legacyData data: Data) { - guard data.count > 0, let code = LegacyCode(rawValue: data[data.startIndex])?.responseCode else { - return nil - } - - self.code = code - } -} - -struct GetVersionResponse: Response { - let code: ResponseCode - let version: String - - init?(data: Data) { - guard data.count > 1, let code = ResponseCode(rawValue: data[data.startIndex]) else { - return nil - } - - self.init(code: code, versionData: data[data.startIndex.advanced(by: 1)...]) - } - - init?(legacyData data: Data) { - self.init(code: .success, versionData: data) - } - - private init?(code: ResponseCode, versionData: Data) { - self.code = code - - guard let version = String(bytes: versionData, encoding: .utf8) else { - return nil - } - - self.version = version - } -} - -struct GetStatisticsResponse: Response { - let code: ResponseCode - - let statistics: RileyLinkStatistics - - init?(data: Data) { - guard data.count > 1, let code = ResponseCode(rawValue: data[data.startIndex]) else { - return nil - } - - self.init(code: code, data: data[data.startIndex.advanced(by: 1)...]) - } - - init?(legacyData data: Data) { - self.init(code: .success, data: data) - } - - private init?(code: ResponseCode, data: Data) { - self.code = code - - guard data.count >= 16 else { - return nil - } - - let uptime = TimeInterval(milliseconds: Double(data[data.startIndex...].toBigEndian(UInt32.self))) - let radioRxOverflowCount = data[data.startIndex.advanced(by: 4)...].toBigEndian(UInt16.self) - let radioRxFifoOverflowCount = data[data.startIndex.advanced(by: 6)...].toBigEndian(UInt16.self) - let packetRxCount = data[data.startIndex.advanced(by: 8)...].toBigEndian(UInt16.self) - let packetTxCount = data[data.startIndex.advanced(by: 10)...].toBigEndian(UInt16.self) - let crcFailureCount = data[data.startIndex.advanced(by: 12)...].toBigEndian(UInt16.self) - let spiSyncFailureCount = data[data.startIndex.advanced(by: 14)...].toBigEndian(UInt16.self) - - self.statistics = RileyLinkStatistics(uptime: uptime, radioRxOverflowCount: radioRxOverflowCount, radioRxFifoOverflowCount: radioRxFifoOverflowCount, packetRxCount: packetRxCount, packetTxCount: packetTxCount, crcFailureCount: crcFailureCount, spiSyncFailureCount: spiSyncFailureCount) - } -} - - -struct PacketResponse: Response { - let code: ResponseCode - let packet: RFPacket? - - init?(data: Data) { - guard data.count > 0, let code = ResponseCode(rawValue: data[data.startIndex]) else { - return nil - } - - switch code { - case .success: - guard data.count > 1, let packet = RFPacket(rfspyResponse: data[data.startIndex.advanced(by: 1)...]) else { - return nil - } - self.packet = packet - case .rxTimeout, - .commandInterrupted, - .zeroData, - .invalidParam, - .unknownCommand: - self.packet = nil - } - - self.code = code - } - - init?(legacyData data: Data) { - guard data.count > 0 else { - return nil - } - - packet = RFPacket(rfspyResponse: data) - - if packet != nil { - code = .success - } else { - guard let code = ResponseCode(rawValue: data[data.startIndex]) else { - return nil - } - - self.code = code - } - } - - init(code: ResponseCode, packet: RFPacket?) { - self.code = code - self.packet = packet - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/ResponseBuffer.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/ResponseBuffer.swift deleted file mode 100644 index 3fa388098..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/ResponseBuffer.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// ResponseBuffer.swift -// RileyLinkBLEKit -// -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - - -/// Represents a data buffer containing one or more responses -struct ResponseBuffer { - let endMarker: UInt8 - private var data = Data() - - init(endMarker: UInt8) { - self.endMarker = endMarker - } - - mutating func append(_ other: Data) { - data.append(other) - } - - var responses: [R] { - let segments = data.split(separator: endMarker, omittingEmptySubsequences: false) - - // If we haven't received at least one endMarker, we don't have a response. - guard segments.count > 1 else { - return [] - } - - return segments.compactMap { R(legacyData: $0) } - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkBLEKit.h b/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkBLEKit.h deleted file mode 100644 index 191e90389..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkBLEKit.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// RileyLinkBLEKit.h -// RileyLinkBLEKit -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -#import - -//! Project version number for RileyLinkBLEKit. -FOUNDATION_EXPORT double RileyLinkBLEKitVersionNumber; - -//! Project version string for RileyLinkBLEKit. -FOUNDATION_EXPORT const unsigned char RileyLinkBLEKitVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkBluetoothDevice.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkBluetoothDevice.swift deleted file mode 100644 index 355cb3924..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkBluetoothDevice.swift +++ /dev/null @@ -1,616 +0,0 @@ -// -// RileyLinkBluetoothDevice.swift -// RileyLinkBLEKit -// -// Created by Pete Schwamb on 9/5/22. -// Copyright © 2022 Pete Schwamb. All rights reserved. -// - -import CoreBluetooth -import os.log - -public class RileyLinkBluetoothDevice: RileyLinkDevice { - private let manager: PeripheralManager - - private let log = OSLog(category: "RileyLinkDevice") - - // Confined to `manager.queue` - private var bleFirmwareVersion: BLEFirmwareVersion? - - // Confined to `manager.queue` - private var radioFirmwareVersion: RadioFirmwareVersion? - - public var isConnected: Bool { - return manager.peripheral.state == .connected - } - - func setPeripheral(_ peripheral: CBPeripheral) { - manager.peripheral = peripheral - } - - public var rlFirmwareDescription: String { - let versions = [radioFirmwareVersion, bleFirmwareVersion].compactMap { (version: CustomStringConvertible?) -> String? in - if let version = version { - return String(describing: version) - } else { - return nil - } - } - - return versions.joined(separator: " / ") - } - - private var version: String { - switch hardwareType { - case .riley, .ema, .none: - return rlFirmwareDescription - case .orange: - return orangeLinkFirmwareHardwareVersion - } - } - - // Confined to `lock` - private var idleListeningState: IdleListeningState = .disabled - - // Confined to `lock` - private var lastIdle: Date? - - // Confined to `lock` - // TODO: Tidy up this state/preference machine - private var isIdleListeningPending = false - - // Confined to `lock` - private var isTimerTickEnabled = true - - /// Serializes access to device state - private var lock = os_unfair_lock() - - private var orangeLinkFirmwareHardwareVersion = "v1.x" - private var orangeLinkHardwareVersionMajorMinor: [Int]? - private var ledOn: Bool = false - private var vibrationOn: Bool = false - private var voltage: Float? - private var batteryLevel: Int? - private var hasPiezo: Bool { - if let olHW = orangeLinkHardwareVersionMajorMinor, olHW[0] == 1, olHW[1] >= 1 { - return true - } else if let olHW = orangeLinkHardwareVersionMajorMinor, olHW[0] == 2, olHW[1] == 6 { - return true - } - return false - } - - public var hasOrangeLinkService: Bool { - return self.manager.peripheral.services?.itemWithUUID(RileyLinkServiceUUID.orange.cbUUID) != nil - } - - public var hardwareType: RileyLinkHardwareType? { - guard let services = self.manager.peripheral.services else { - return nil - } - - guard let bleComponents = self.bleFirmwareVersion else { - return nil - } - - if services.itemWithUUID(RileyLinkServiceUUID.secureDFU.cbUUID) != nil { - return .orange - } else if bleComponents.components[0] == 3 { - // this returns true for riley with ema firmware, but that is OK - return .ema - } else { - // as long as riley ble remains at 2.x with ema at 3.x this will work - return .riley - } - } - - /// The queue used to serialize sessions and observe when they've drained - private let sessionQueue: OperationQueue = { - let queue = OperationQueue() - queue.name = "com.rileylink.RileyLinkBLEKit.RileyLinkDevice.sessionQueue" - queue.maxConcurrentOperationCount = 1 - - return queue - }() - - private var sessionQueueOperationCountObserver: NSKeyValueObservation! - - public var rssi: Int? - - init(peripheralManager: PeripheralManager, rssi: Int?) { - self.manager = peripheralManager - self.rssi = rssi - sessionQueue.underlyingQueue = peripheralManager.queue - - peripheralManager.delegate = self - - sessionQueueOperationCountObserver = sessionQueue.observe(\.operationCount, options: [.new]) { [weak self] (queue, change) in - if let newValue = change.newValue, newValue == 0 { - self?.log.debug("Session queue operation count is now empty") - self?.assertIdleListening(forceRestart: true) - } - } - } -} - - -// MARK: - Peripheral operations. Thread-safe. -extension RileyLinkBluetoothDevice { - public var name: String? { - return manager.peripheral.name - } - - public var deviceURI: String { - return "rileylink://\(name ?? peripheralIdentifier.uuidString)" - } - - public var peripheralIdentifier: UUID { - return manager.peripheral.identifier - } - - public var peripheralState: CBPeripheralState { - return manager.peripheral.state - } - - public func readRSSI() { - guard case .connected = manager.peripheral.state, case .poweredOn? = manager.central?.state else { - return - } - manager.peripheral.readRSSI() - } - - public func setCustomName(_ name: String) { - manager.setCustomName(name) - } - - public func updateBatteryLevel() { - manager.readBatteryLevel { value in - if let batteryLevel = value { - self.batteryLevel = batteryLevel - NotificationCenter.default.post( - name: .DeviceBatteryLevelUpdated, - object: self, - userInfo: [RileyLinkBluetoothDevice.batteryLevelKey: batteryLevel] - ) - NotificationCenter.default.post(name: .DeviceStatusUpdated, object: self) - } - } - } - - public func orangeAction(_ command: OrangeLinkCommand) { - log.debug("orangeAction: %@", "\(command)") - manager.orangeAction(command) - } - - public func setOrangeConfig(_ config: OrangeLinkConfigurationSetting, isOn: Bool) { - log.debug("setOrangeConfig: %@, %@", "\(String(describing: config))", "\(isOn)") - manager.setOrangeConfig(config, isOn: isOn) - } - - public func orangeWritePwd() { - log.debug("orangeWritePwd") - manager.orangeWritePwd() - } - - public func orangeClose() { - log.debug("orangeClose") - manager.orangeClose() - } - - public func orangeReadSet() { - log.debug("orangeReadSet") - manager.orangeReadSet() - } - - public func orangeReadVDC() { - log.debug("orangeReadVDC") - manager.orangeReadVDC() - } - - public func findDevice() { - log.debug("findDevice") - manager.findDevice() - } - - public func setDiagnosticeLEDModeForBLEChip(_ mode: RileyLinkLEDMode) { - manager.setLEDMode(mode: mode) - } - - public func readDiagnosticLEDModeForBLEChip(completion: @escaping (RileyLinkLEDMode?) -> Void) { - manager.readDiagnosticLEDMode(completion: completion) - } - - /// Asserts that the caller is currently on the session queue - public func assertOnSessionQueue() { - dispatchPrecondition(condition: .onQueue(manager.queue)) - } - - /// Schedules a closure to execute on the session queue after a specified time - /// - /// - Parameters: - /// - deadline: The time after which to execute - /// - execute: The closure to execute - public func sessionQueueAsyncAfter(deadline: DispatchTime, execute: @escaping () -> Void) { - manager.queue.asyncAfter(deadline: deadline, execute: execute) - } -} - - -extension RileyLinkBluetoothDevice: Equatable, Hashable { - public static func ==(lhs: RileyLinkBluetoothDevice, rhs: RileyLinkBluetoothDevice) -> Bool { - return lhs === rhs - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(peripheralIdentifier) - } -} - - -// MARK: - Status management -extension RileyLinkBluetoothDevice { - - public func getStatus(_ completion: @escaping (_ status: RileyLinkDeviceStatus) -> Void) { - os_unfair_lock_lock(&lock) - let lastIdle = self.lastIdle - os_unfair_lock_unlock(&lock) - - self.manager.queue.async { - completion(RileyLinkDeviceStatus( - lastIdle: lastIdle, - name: self.name, - version: self.version, - ledOn: self.ledOn, - vibrationOn: self.vibrationOn, - voltage: self.voltage, - battery: self.batteryLevel, - hasPiezo: self.hasPiezo - )) - } - } -} - - -// MARK: - Command session management -// CommandSessions are a way to serialize access to the RileyLink command/response facility. -// All commands that send data out on the RL data characteristic need to be in a command session. -// Accessing other characteristics on the RileyLink can be done without a command session. -extension RileyLinkBluetoothDevice { - public func runSession(withName name: String, _ block: @escaping (_ session: CommandSession) -> Void) { - self.log.default("Scheduling session %{public}@", name) - sessionQueue.addOperation(manager.configureAndRun({ [weak self] (manager) in - self?.log.default("======================== %{public}@ ===========================", name) - let bleFirmwareVersion = self?.bleFirmwareVersion - let radioFirmwareVersion = self?.radioFirmwareVersion - - if bleFirmwareVersion == nil || radioFirmwareVersion == nil { - self?.log.error("Running session with incomplete configuration: bleFirmwareVersion %{public}@, radioFirmwareVersion: %{public}@", String(describing: bleFirmwareVersion), String(describing: radioFirmwareVersion)) - } - - block(CommandSession(manager: manager, responseType: bleFirmwareVersion?.responseType ?? .buffered, firmwareVersion: radioFirmwareVersion ?? .unknown)) - self?.log.default("------------------------ %{public}@ ---------------------------", name) - })) - } -} - - -// MARK: - Idle management -extension RileyLinkBluetoothDevice { - public enum IdleListeningState { - case enabled(timeout: TimeInterval, channel: UInt8) - case disabled - } - - func setIdleListeningState(_ state: IdleListeningState) { - os_unfair_lock_lock(&lock) - let oldValue = idleListeningState - idleListeningState = state - os_unfair_lock_unlock(&lock) - - switch (oldValue, state) { - case (.disabled, .enabled): - assertIdleListening(forceRestart: true) - case (.enabled, .enabled): - assertIdleListening(forceRestart: false) - default: - break - } - } - - public func assertIdleListening(forceRestart: Bool = false) { - os_unfair_lock_lock(&lock) - guard case .enabled(timeout: let timeout, channel: let channel) = self.idleListeningState else { - os_unfair_lock_unlock(&lock) - return - } - - guard case .connected = self.manager.peripheral.state, case .poweredOn? = self.manager.central?.state else { - os_unfair_lock_unlock(&lock) - return - } - - guard forceRestart || (self.lastIdle ?? .distantPast).timeIntervalSinceNow < -timeout else { - os_unfair_lock_unlock(&lock) - return - } - - guard !self.isIdleListeningPending else { - os_unfair_lock_unlock(&lock) - return - } - - self.isIdleListeningPending = true - os_unfair_lock_unlock(&lock) - - self.manager.startIdleListening(idleTimeout: timeout, channel: channel) { (error) in - os_unfair_lock_lock(&self.lock) - self.isIdleListeningPending = false - - if let error = error { - self.log.error("Unable to start idle listening: %@", String(describing: error)) - os_unfair_lock_unlock(&self.lock) - } else { - self.lastIdle = Date() - self.log.debug("Started idle listening") - os_unfair_lock_unlock(&self.lock) - NotificationCenter.default.post(name: .DeviceDidStartIdle, object: self) - } - } - } -} - - -// MARK: - Timer tick management -extension RileyLinkBluetoothDevice { - func setTimerTickEnabled(_ enabled: Bool) { - os_unfair_lock_lock(&lock) - self.isTimerTickEnabled = enabled - os_unfair_lock_unlock(&lock) - self.assertTimerTick() - } - - func assertTimerTick() { - os_unfair_lock_lock(&self.lock) - let isTimerTickEnabled = self.isTimerTickEnabled - os_unfair_lock_unlock(&self.lock) - - if isTimerTickEnabled != self.manager.timerTickEnabled { - self.manager.setTimerTickEnabled(isTimerTickEnabled) - } - } -} - - -// MARK: - CBCentralManagerDelegate Proxying -extension RileyLinkBluetoothDevice { - func centralManagerDidUpdateState(_ central: CBCentralManager) { - if case .poweredOn = central.state { - assertIdleListening(forceRestart: false) - assertTimerTick() - } - - manager.centralManagerDidUpdateState(central) - } - - func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { - log.default("didConnect %{public}@", peripheral) - if case .connected = peripheral.state { - assertIdleListening(forceRestart: false) - assertTimerTick() - } - - manager.centralManager(central, didConnect: peripheral) - NotificationCenter.default.post(name: .DeviceConnectionStateDidChange, object: self) - } - - func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { - log.default("didDisconnectPeripheral %{public}@", peripheral) - NotificationCenter.default.post(name: .DeviceConnectionStateDidChange, object: self) - } - - func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { - log.default("didFailToConnect %{public}@", peripheral) - NotificationCenter.default.post(name: .DeviceConnectionStateDidChange, object: self) - } -} - - -extension RileyLinkBluetoothDevice: PeripheralManagerDelegate { - func peripheralManager(_ manager: PeripheralManager, didUpdateNotificationStateFor characteristic: CBCharacteristic) { - log.debug("Did didUpdateNotificationStateFor %@", characteristic) - } - - // If PeripheralManager receives a response on the data queue, without an outstanding request, - // it will pass the update to this method, which is called on the central's queue. - // This is how idle listen responses are handled - func peripheralManager(_ manager: PeripheralManager, didUpdateValueFor characteristic: CBCharacteristic) { - let characteristicService: CBService? = characteristic.service - guard let cbService = characteristicService, let service = RileyLinkServiceUUID(rawValue: cbService.uuid.uuidString) else { - log.debug("Update from characteristic on unknown service: %@", String(describing: characteristic.service)) - return - } - - switch service { - case .main: - guard let mainCharacteristic = MainServiceCharacteristicUUID(rawValue: characteristic.uuid.uuidString) else { - log.debug("Update from unknown characteristic %@ on main service.", characteristic.uuid.uuidString) - return - } - handleCharacteristicUpdate(mainCharacteristic, value: characteristic.value) - - case .orange: - guard let orangeCharacteristic = OrangeServiceCharacteristicUUID(rawValue: characteristic.uuid.uuidString) else { - log.debug("Update from unknown characteristic %@ on orange service.", characteristic.uuid.uuidString) - return - } - handleCharacteristicUpdate(orangeCharacteristic, value: characteristic.value) - default: - return - } - } - - private func handleCharacteristicUpdate(_ characteristic: MainServiceCharacteristicUUID, value: Data?) { - switch characteristic { - case .data: - guard let value = value, value.count > 0 else { - return - } - - self.manager.queue.async { - if let responseType = self.bleFirmwareVersion?.responseType { - let response: PacketResponse? - - switch responseType { - case .buffered: - var buffer = ResponseBuffer(endMarker: 0x00) - buffer.append(value) - response = buffer.responses.last - case .single: - response = PacketResponse(data: value) - } - - if let response = response { - switch response.code { - case .commandInterrupted: - self.log.debug("Received commandInterrupted during idle; assuming device is still listening.") - return - case .rxTimeout, .zeroData, .invalidParam, .unknownCommand: - self.log.debug("Idle error received: %@", String(describing: response.code)) - case .success: - if let packet = response.packet { - self.log.default("Idle packet received: %{public}@", String(describing: packet)) - NotificationCenter.default.post( - name: .DevicePacketReceived, - object: self, - userInfo: [RileyLinkBluetoothDevice.notificationPacketKey: packet] - ) - } - } - } else { - self.log.error("Unknown idle response: %{public}@", value.hexadecimalString) - } - } else { - self.log.error("Skipping parsing characteristic value update due to missing BLE firmware version") - } - self.assertIdleListening(forceRestart: true) - } - case .responseCount: - // PeripheralManager.Configuration.valueUpdateMacros is responsible for handling this response. - break - case .timerTick: - NotificationCenter.default.post(name: .DeviceTimerDidTick, object: self) - assertIdleListening(forceRestart: false) - case .customName, .firmwareVersion, .ledMode: - break - } - } - - private func handleCharacteristicUpdate(_ characteristic: OrangeServiceCharacteristicUUID, value: Data?) { - switch characteristic { - case .orangeRX, .orangeTX: - guard let data = value, !data.isEmpty else { return } - if data.first == 0xbb { - guard data.count > 6 else { return } - if data[1] == 0x09, data[2] == 0xaa { - orangeLinkFirmwareHardwareVersion = "FW\(data[3]).\(data[4])/HW\(data[5]).\(data[6])" - orangeLinkHardwareVersionMajorMinor = [Int(data[5]), Int(data[6])] - NotificationCenter.default.post(name: .DeviceStatusUpdated, object: self) - } - } else if data.first == OrangeLinkRequestType.cfgHeader.rawValue { - guard data.count > 2 else { return } - if data[1] == 0x01 { - guard data.count > 5 else { return } - ledOn = (data[3] != 0) - vibrationOn = (data[4] != 0) - NotificationCenter.default.post(name: .DeviceStatusUpdated, object: self) - } else if data[1] == 0x03 { - guard data.count > 4 else { return } - let int = UInt16(bigEndian: Data(data[3...4]).withUnsafeBytes { $0.load(as: UInt16.self) }) - voltage = Float(int) / 1000 - NotificationCenter.default.post(name: .DeviceStatusUpdated, object: self) - } - } - } - } - - func peripheralManager(_ manager: PeripheralManager, didReadRSSI RSSI: NSNumber, error: Error?) { - self.rssi = Int(truncating: RSSI) - NotificationCenter.default.post( - name: .DeviceRSSIDidChange, - object: self, - userInfo: [RileyLinkBluetoothDevice.notificationRSSIKey: RSSI] - ) - } - - func peripheralManagerDidUpdateName(_ manager: PeripheralManager) { - NotificationCenter.default.post( - name: .DeviceNameDidChange, - object: self, - userInfo: nil - ) - } - - func completeConfiguration(for manager: PeripheralManager) throws { - // Read bluetooth version to determine compatibility - log.default("Reading firmware versions for PeripheralManager configuration") - let bleVersionString = try manager.readBluetoothFirmwareVersion(timeout: 1) - bleFirmwareVersion = BLEFirmwareVersion(versionString: bleVersionString) - - let radioVersionString = try manager.readRadioFirmwareVersion(timeout: 1, responseType: bleFirmwareVersion?.responseType ?? .buffered) - radioFirmwareVersion = RadioFirmwareVersion(versionString: radioVersionString) - - try manager.setOrangeNotifyOn() - } -} - - -extension RileyLinkBluetoothDevice: CustomDebugStringConvertible { - - public var debugDescription: String { - os_unfair_lock_lock(&lock) - let lastIdle = self.lastIdle - let isIdleListeningPending = self.isIdleListeningPending - let isTimerTickEnabled = self.isTimerTickEnabled - os_unfair_lock_unlock(&lock) - - return [ - "## RileyLinkDevice", - "* name: \(name ?? "")", - "* lastIdle: \(lastIdle ?? .distantPast)", - "* isIdleListeningPending: \(isIdleListeningPending)", - "* isTimerTickEnabled: \(isTimerTickEnabled)", - "* isTimerTickNotifying: \(manager.timerTickEnabled)", - "* radioFirmware: \(String(describing: radioFirmwareVersion))", - "* bleFirmware: \(String(describing: bleFirmwareVersion))", - "* peripheralManager: \(manager)", - "* sessionQueue.operationCount: \(sessionQueue.operationCount)" - ].joined(separator: "\n") - } -} - -extension RileyLinkBluetoothDevice { - public static let notificationPacketKey = "com.rileylink.RileyLinkBLEKit.RileyLinkDevice.NotificationPacket" - - public static let notificationRSSIKey = "com.rileylink.RileyLinkBLEKit.RileyLinkDevice.NotificationRSSI" - - public static let batteryLevelKey = "com.rileylink.RileyLinkBLEKit.RileyLinkDevice.BatteryLevel" -} - - -extension Notification.Name { - public static let DeviceConnectionStateDidChange = Notification.Name(rawValue: "com.rileylink.RileyLinkBLEKit.ConnectionStateDidChange") - - public static let DeviceDidStartIdle = Notification.Name(rawValue: "com.rileylink.RileyLinkBLEKit.DidStartIdle") - - public static let DeviceNameDidChange = Notification.Name(rawValue: "com.rileylink.RileyLinkBLEKit.NameDidChange") - - public static let DevicePacketReceived = Notification.Name(rawValue: "com.rileylink.RileyLinkBLEKit.PacketReceived") - - public static let DeviceRSSIDidChange = Notification.Name(rawValue: "com.rileylink.RileyLinkBLEKit.RSSIDidChange") - - public static let DeviceTimerDidTick = Notification.Name(rawValue: "com.rileylink.RileyLinkBLEKit.TimerTickDidChange") - - public static let DeviceStatusUpdated = Notification.Name(rawValue: "com.rileylink.RileyLinkBLEKit.DeviceStatusUpdated") - - public static let DeviceBatteryLevelUpdated = Notification.Name(rawValue: "com.rileylink.RileyLinkBLEKit.BatteryLevelUpdated") -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkBluetoothDeviceProvider.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkBluetoothDeviceProvider.swift deleted file mode 100644 index fd733cbb8..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkBluetoothDeviceProvider.swift +++ /dev/null @@ -1,340 +0,0 @@ -// -// RileyLinkDeviceManager.swift -// RileyLinkBLEKit -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import CoreBluetooth -import os.log -import LoopKit - -public class RileyLinkBluetoothDeviceProvider: NSObject { - private let log = OSLog(category: "RileyLinkDeviceManager") - - // Isolated to centralQueue - private var central: CBCentralManager! - - private let centralQueue = DispatchQueue(label: "com.rileylink.RileyLinkBLEKit.BluetoothManager.centralQueue", qos: .unspecified) - - internal let sessionQueue = DispatchQueue(label: "com.rileylink.RileyLinkBLEKit.RileyLinkDeviceManager.sessionQueue", qos: .unspecified) - - public weak var delegate: RileyLinkDeviceProviderDelegate? - - // Isolated to centralQueue - private var devices: [RileyLinkBluetoothDevice] = [] { - didSet { - NotificationCenter.default.post(name: .ManagerDevicesDidChange, object: self) - } - } - - // Isolated to centralQueue - private var autoConnectIDs: Set { - didSet { - delegate?.rileylinkDeviceProvider(self, didChange: RileyLinkConnectionState(autoConnectIDs: autoConnectIDs)) - } - } - - public var connectingCount: Int { - return self.autoConnectIDs.count - } - - // Isolated to centralQueue - private var isScanningEnabled = false - - public init(autoConnectIDs: Set) { - self.autoConnectIDs = autoConnectIDs - - super.init() - - centralQueue.sync { - central = CBCentralManager( - delegate: self, - queue: centralQueue, - options: [ - CBCentralManagerOptionRestoreIdentifierKey: "com.rileylink.CentralManager" - ] - ) - } - } - - // MARK: - Configuration - - public var idleListeningEnabled: Bool { - if case .disabled = idleListeningState { - return false - } else { - return true - } - } - - public var idleListeningState: RileyLinkBluetoothDevice.IdleListeningState { - get { - return lockedIdleListeningState.value - } - set { - lockedIdleListeningState.value = newValue - centralQueue.async { - for device in self.devices { - device.setIdleListeningState(newValue) - } - } - } - } - private let lockedIdleListeningState = Locked(RileyLinkBluetoothDevice.IdleListeningState.disabled) - - public var timerTickEnabled: Bool { - get { - return lockedTimerTickEnabled.value - } - set { - lockedTimerTickEnabled.value = newValue - centralQueue.async { - for device in self.devices { - if device.isConnected { - device.setTimerTickEnabled(newValue) - } - } - } - } - } - private let lockedTimerTickEnabled = Locked(true) -} - - -// MARK: - Connecting -extension RileyLinkBluetoothDeviceProvider { - public func getAutoConnectIDs(_ completion: @escaping (_ autoConnectIDs: Set) -> Void) { - centralQueue.async { - completion(self.autoConnectIDs) - } - } - - /// Asks the central manager for its peripheral instance for a given device. - /// It seems to be possible that this reference changes across a bluetooth reset, and not updating the reference can result in API MISUSE warnings - /// - /// - Parameter device: The device to reload - /// - Returns: The peripheral instance returned by the central manager - private func reloadPeripheral(for device: RileyLinkBluetoothDevice) -> CBPeripheral? { - dispatchPrecondition(condition: .onQueue(centralQueue)) - - guard let peripheral = central.retrievePeripherals(withIdentifiers: [device.peripheralIdentifier]).first else { - return nil - } - - device.setPeripheral(peripheral) - return peripheral - } - - private var hasDiscoveredAllAutoConnectDevices: Bool { - dispatchPrecondition(condition: .onQueue(centralQueue)) - - return autoConnectIDs.isSubset(of: devices.map { $0.peripheralIdentifier.uuidString }) - } - - private func autoConnectDevices() { - dispatchPrecondition(condition: .onQueue(centralQueue)) - - for device in devices where autoConnectIDs.contains(device.peripheralIdentifier.uuidString) { - log.info("Attempting reconnect to %@", String(describing: device)) - connect(device) - } - } - - private func addPeripheral(_ peripheral: CBPeripheral, rssi: Int? = nil) { - dispatchPrecondition(condition: .onQueue(centralQueue)) - - var device: RileyLinkBluetoothDevice! = devices.first(where: { $0.peripheralIdentifier == peripheral.identifier }) - - if let device = device { - device.setPeripheral(peripheral) - } else { - device = RileyLinkBluetoothDevice(peripheralManager: PeripheralManager(peripheral: peripheral, configuration: .rileyLink, centralManager: central, queue: sessionQueue), rssi: rssi) - if peripheral.state == .connected { - device.setTimerTickEnabled(timerTickEnabled) - device.setIdleListeningState(idleListeningState) - } - - devices.append(device) - - log.info("Created device for peripheral %@", peripheral) - } - - if autoConnectIDs.contains(peripheral.identifier.uuidString) { - central.connectIfNecessary(peripheral) - } - } -} - -extension RileyLinkBluetoothDeviceProvider: RileyLinkDeviceProvider { - public func connect(_ device: RileyLinkDevice) { - centralQueue.async { - self.autoConnectIDs.insert(device.peripheralIdentifier.uuidString) - - guard let peripheral = self.reloadPeripheral(for: device as! RileyLinkBluetoothDevice) else { - return - } - - self.central.connectIfNecessary(peripheral) - } - } - - public func disconnect(_ device: RileyLinkDevice) { - centralQueue.async { - self.autoConnectIDs.remove(device.peripheralIdentifier.uuidString) - - guard let peripheral = self.reloadPeripheral(for: device as! RileyLinkBluetoothDevice) else { - return - } - - self.central.cancelPeripheralConnectionIfNecessary(peripheral) - } - } - - public func getDevices(_ completion: @escaping (_ devices: [RileyLinkDevice]) -> Void) { - centralQueue.async { - completion(self.devices) - } - } - - public func deprioritize(_ device: RileyLinkDevice, completion: (() -> Void)? = nil) { - centralQueue.async { - self.devices.deprioritize(device as! RileyLinkBluetoothDevice) - completion?() - } - } - - public func setScanningEnabled(_ enabled: Bool) { - centralQueue.async { - self.isScanningEnabled = enabled - - if case .poweredOn = self.central.state { - if enabled { - self.central.scanForPeripherals() - } else if self.central.isScanning { - self.central.stopScan() - } - } - } - } - - public func assertIdleListening(forcingRestart: Bool) { - centralQueue.async { - for device in self.devices { - device.assertIdleListening(forceRestart: forcingRestart) - } - } - } - - public func shouldConnect(to deviceID: String) -> Bool { - return self.autoConnectIDs.contains(deviceID) - } -} - -extension Array where Element == RileyLinkBluetoothDevice { - mutating func deprioritize(_ element: Element) { - if let index = self.firstIndex(where: { $0 === element }) { - self.swapAt(index, self.count - 1) - } - } -} - - -// MARK: - Delegate methods called on `centralQueue` -extension RileyLinkBluetoothDeviceProvider: CBCentralManagerDelegate { - public func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) { - log.default("%@", #function) - - guard let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey] as? [CBPeripheral] else { - return - } - - for peripheral in peripherals { - addPeripheral(peripheral) - } - } - - public func centralManagerDidUpdateState(_ central: CBCentralManager) { - log.default("%@: %@", #function, central.state.description) - if case .poweredOn = central.state { - autoConnectDevices() - - if isScanningEnabled || !hasDiscoveredAllAutoConnectDevices { - central.scanForPeripherals() - } else if central.isScanning { - central.stopScan() - } - } - - for device in devices { - device.centralManagerDidUpdateState(central) - } - } - - public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { - log.default("Discovered %@ at %@", peripheral, RSSI) - - addPeripheral(peripheral, rssi: Int(truncating: RSSI)) - - // TODO: Should we keep scanning? There's no UI to remove a lost RileyLink, which could result in a battery drain due to indefinite scanning. - if !isScanningEnabled && central.isScanning && hasDiscoveredAllAutoConnectDevices { - log.default("All peripherals discovered") - central.stopScan() - } - } - - public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { - // Notify the device so it can begin configuration - for device in devices where device.peripheralIdentifier == peripheral.identifier { - device.centralManager(central, didConnect: peripheral) - } - } - - public func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { - for device in devices where device.peripheralIdentifier == peripheral.identifier { - device.centralManager(central, didDisconnectPeripheral: peripheral, error: error) - } - - autoConnectDevices() - } - - public func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { - log.error("%@: %@: %@", #function, peripheral, String(describing: error)) - - for device in devices where device.peripheralIdentifier == peripheral.identifier { - device.centralManager(central, didFailToConnect: peripheral, error: error) - } - - autoConnectDevices() - } -} - - -extension RileyLinkBluetoothDeviceProvider { - public override var debugDescription: String { - var report = [ - "## RileyLinkDeviceManager", - "central: \(central!)", - "autoConnectIDs: \(autoConnectIDs)", - "timerTickEnabled: \(timerTickEnabled)", - "idleListeningState: \(idleListeningState)" - ] - - for device in devices { - report.append(String(reflecting: device)) - report.append("") - } - - return report.joined(separator: "\n\n") - } -} - - -extension Notification.Name { - public static let ManagerDevicesDidChange = Notification.Name("com.rileylink.RileyLinkBLEKit.DevicesDidChange") -} - -extension RileyLinkBluetoothDeviceProvider { - public static let autoConnectIDsStateKey = "com.rileylink.RileyLinkBLEKit.AutoConnectIDs" -} - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkConnectionState.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkConnectionState.swift deleted file mode 100644 index d22a32825..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkConnectionState.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// RileyLinkConnectionManagerState.swift -// RileyLinkBLEKit -// -// Created by Pete Schwamb on 8/21/18. -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import Foundation - -public struct RileyLinkConnectionState: RawRepresentable, Equatable { - - public typealias RawValue = RileyLinkDeviceProvider.RawStateValue - - public var autoConnectIDs: Set - - public init(autoConnectIDs: Set) { - self.autoConnectIDs = autoConnectIDs - } - - public init?(rawValue: RileyLinkDeviceProvider.RawStateValue) { - guard - let autoConnectIDs = rawValue["autoConnectIDs"] as? [String] - else { - return nil - } - - self.init(autoConnectIDs: Set(autoConnectIDs)) - } - - public var rawValue: RawValue { - return [ - "autoConnectIDs": Array(autoConnectIDs), - ] - } - - - -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkDevice.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkDevice.swift deleted file mode 100644 index 8bc188a66..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkDevice.swift +++ /dev/null @@ -1,87 +0,0 @@ -// -// RileyLinkDevice.swift -// RileyLinkBLEKit -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import CoreBluetooth - -public enum RileyLinkHardwareType { - case riley - case orange - case ema - - var monitorsBattery: Bool { - if self == .riley { - return false - } - return true - } -} - -public struct RileyLinkDeviceStatus { - public let lastIdle: Date? - public let name: String? - public let version: String - public let ledOn: Bool - public let vibrationOn: Bool - public let voltage: Float? - public let battery: Int? - public let hasPiezo: Bool - - public init(lastIdle: Date?, name: String?, version: String, ledOn: Bool, vibrationOn: Bool, voltage: Float?, battery: Int?, hasPiezo: Bool) { - self.lastIdle = lastIdle - self.name = name - self.version = version - self.ledOn = ledOn - self.vibrationOn = vibrationOn - self.voltage = voltage - self.battery = battery - self.hasPiezo = hasPiezo - } -} - - -public protocol RileyLinkDevice { - - var isConnected: Bool { get } - var rlFirmwareDescription: String { get } - var hasOrangeLinkService: Bool { get } - var hardwareType: RileyLinkHardwareType? { get } - var rssi: Int? { get } - - var name: String? { get } - var deviceURI: String { get } - var peripheralIdentifier: UUID { get } - var peripheralState: CBPeripheralState { get } - - func readRSSI() - func setCustomName(_ name: String) - - func updateBatteryLevel() - - func orangeAction(_ command: OrangeLinkCommand) - func setOrangeConfig(_ config: OrangeLinkConfigurationSetting, isOn: Bool) - func orangeWritePwd() - func orangeClose() - func orangeReadSet() - func orangeReadVDC() - func findDevice() - func setDiagnosticeLEDModeForBLEChip(_ mode: RileyLinkLEDMode) - func readDiagnosticLEDModeForBLEChip(completion: @escaping (RileyLinkLEDMode?) -> Void) - func assertOnSessionQueue() - func sessionQueueAsyncAfter(deadline: DispatchTime, execute: @escaping () -> Void) - - func runSession(withName name: String, _ block: @escaping (_ session: CommandSession) -> Void) - func getStatus(_ completion: @escaping (_ status: RileyLinkDeviceStatus) -> Void) -} - -extension Array where Element == RileyLinkDevice { - public var firstConnected: Element? { - return self.first { (device) -> Bool in - return device.isConnected - } - } -} - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkDeviceError.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkDeviceError.swift deleted file mode 100644 index e2fbf6a78..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkDeviceError.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// RileyLinkDeviceError.swift -// RileyLinkBLEKit -// -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - - -public enum RileyLinkDeviceError: Error { - case peripheralManagerError(LocalizedError) - case errorResponse(String) - case writeSizeLimitExceeded(maxLength: Int) - case invalidResponse(Data) - case responseTimeout - case commandsBlocked - case unsupportedCommand(String) -} - - -extension RileyLinkDeviceError: LocalizedError { - public var errorDescription: String? { - switch self { - case .peripheralManagerError(let error): - return error.errorDescription - case .errorResponse(let message): - return message - case .invalidResponse(let response): - return String(format: LocalizedString("Response %@ is invalid", comment: "Invalid response error description (1: response)"), String(describing: response)) - case .writeSizeLimitExceeded(let maxLength): - return String(format: LocalizedString("Data exceeded maximum size of %@ bytes", comment: "Write size limit exceeded error description (1: size limit)"), NumberFormatter.localizedString(from: NSNumber(value: maxLength), number: .none)) - case .responseTimeout: - return LocalizedString("Pump did not respond in time", comment: "Response timeout error description") - case .commandsBlocked: - return LocalizedString("RileyLink command did not respond", comment: "commandsBlocked error description") - case .unsupportedCommand(let command): - return String(format: LocalizedString("RileyLink firmware does not support the %@ command", comment: "Unsupported command error description"), String(describing: command)) - } - } - - public var failureReason: String? { - switch self { - case .peripheralManagerError(let error): - return error.failureReason - default: - return nil - } - } - - public var recoverySuggestion: String? { - switch self { - case .peripheralManagerError(let error): - return error.recoverySuggestion - case .commandsBlocked: - return LocalizedString("RileyLink may need to be turned off and back on", comment: "commandsBlocked recovery suggestion") - default: - return nil - } - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkDeviceProvider.swift b/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkDeviceProvider.swift deleted file mode 100644 index 487b3079b..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/RileyLinkDeviceProvider.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// RileyLinkDeviceProvider.swift -// RileyLinkBLEKit -// -// Created by Pete Schwamb on 9/5/22. -// Copyright © 2022 Pete Schwamb. All rights reserved. -// - -import Foundation - -public protocol RileyLinkDeviceProviderDelegate : AnyObject { - func rileylinkDeviceProvider(_ rileylinkDeviceProvider: RileyLinkDeviceProvider, didChange state: RileyLinkConnectionState) -} - -public protocol RileyLinkDeviceProvider: AnyObject { - typealias RawStateValue = [String : Any] - - var delegate: RileyLinkDeviceProviderDelegate? { get set } - - var idleListeningState: RileyLinkBluetoothDevice.IdleListeningState { get set } - var idleListeningEnabled: Bool { get } - var timerTickEnabled: Bool { get set } - var connectingCount: Int { get } - - func deprioritize(_ device: RileyLinkDevice, completion: (() -> Void)?) - func assertIdleListening(forcingRestart: Bool) - func getDevices(_ completion: @escaping (_ devices: [RileyLinkDevice]) -> Void) - func connect(_ device: RileyLinkDevice) - func disconnect(_ device: RileyLinkDevice) - func setScanningEnabled(_ enabled: Bool) - func shouldConnect(to deviceID: String) -> Bool - - var debugDescription: String { get } -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/cs.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/cs.lproj/Localizable.strings deleted file mode 100644 index 12dfc72db..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/cs.lproj/Localizable.strings +++ /dev/null @@ -1,15 +0,0 @@ -/* PeripheralManagerError.emptyValue error description */ -"Characteristic value was empty" = "Udávající hodnota byla prázdná"; - -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Data překročila maximální velikost %@ bajtů"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Vstup %@ je neplatný"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Ujistěte se, že je zařízení poblíž, problém by se měl vyřešit automaticky."; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Periferní zařízení nereagovalo včas"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/da.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/da.lproj/Localizable.strings deleted file mode 100644 index c9d81be8a..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/da.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* PeripheralManagerError.emptyValue error description */ -"Characteristic value was empty" = "Karakteristisk værdi var tom"; - -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Data overskred den maksimale størrelse på %@ bytes"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Input %@ er ugyldigt"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Sørg for at enheden er tæt på, så bør problemet blive løst automatisk"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Ekstern enhed svarede ikke i tide"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Ekstern enhed er ikke forbundet"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Pumpe svarede ikke i tide"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Svaret %@ er ugyldigt"; - -/* commandsBlocked error description */ -"RileyLink command did not respond" = "RileyLink svarer ikke"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "RileyLink svarede ikke i tide"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "RileyLink firmware understøtter ikke %@ kommandoen"; - -/* PeripheralManagerError.busy error description */ -"RileyLink is busy" = "RileyLink er optaget"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "RileyLink er ikke tilsluttet"; - -/* commandsBlocked recovery suggestion */ -"RileyLink may need to be turned off and back on" = "Der er måske behov for at slukke og tænde for RileyLink"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "RileyLink blev midlertidigt afbrudt"; - -/* Error description */ -"Unknown characteristic" = "Ukendt karakteristik"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown characteristic: %@" = "Ukendt karakteristik: %@"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown service: %@" = "Ukendt service: %@"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/de.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/de.lproj/Localizable.strings deleted file mode 100644 index d94964f86..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/de.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* PeripheralManagerError.emptyValue error description */ -"Characteristic value was empty" = "Eigenschaftswert war leer"; - -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Datenvolumen übersteigt die Maximalgröße von %@ Bytes"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Eingabe %@ ist ungültig"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Sicherstellen, dass sich das Gerät in der Nähe befindet, um das Problem automatisch zu beheben"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Peripherie antwortet nicht rechtzeitig"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Peripherie ist nicht verbunden"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Pumpe antwortet nicht rechtzeitig"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Antwort %@ ist ungültig"; - -/* commandsBlocked error description */ -"RileyLink command did not respond" = "RileyLink-Befehl reagierte nicht"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "RileyLink hat nicht rechtzeitig geantwortet"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "RileyLink Firmware unterstützt den Befehl %@ nicht"; - -/* PeripheralManagerError.busy error description */ -"RileyLink is busy" = "RileyLink ist beschäftigt"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "RileyLink ist nicht verbunden"; - -/* commandsBlocked recovery suggestion */ -"RileyLink may need to be turned off and back on" = "RileyLink muss möglicherweise aus- und wieder eingeschaltet werden"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "Verbindung zu RileyLink wurde vorübergehend unterbrochen"; - -/* Error description */ -"Unknown characteristic" = "Unbekannte Charakteristik"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown characteristic: %@" = "Unbekannte Charakteristik: %@"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown service: %@" = "Unbekannter Dienst: %@"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/es.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/es.lproj/Localizable.strings deleted file mode 100644 index c411e92af..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/es.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* PeripheralManagerError.emptyValue error description */ -"Characteristic value was empty" = "Valor característico estaba vacío"; - -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "El Dato excede el tamaño de %@ bytes"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "El dato %@ es inválido"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Asegúrate de que los dispositivos estén cercanos. El problema deberá solucionarse automáticamente"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "El dispositivo periférico no respondió a tiempo"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "El dispositivo periférico no está conectado"; - -/* Response timeout error description */ -"Pump did not respond in time" = "La microinfusora no respondió a tiempo"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Le respuesta %@ es inválida"; - -/* commandsBlocked error description */ -"RileyLink command did not respond" = "El comando de RileyLink no respondió"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "RileyLink no respondió a tiempo"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "RileyLink firmware no soporta el comando %@"; - -/* PeripheralManagerError.busy error description */ -"RileyLink is busy" = "RileyLink está ocupado"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "RileyLink no está conectado"; - -/* commandsBlocked recovery suggestion */ -"RileyLink may need to be turned off and back on" = "Es posible que sea necesario apagar y volver a encender RileyLink"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "RileyLink fue temporalmente desconectado"; - -/* Error description */ -"Unknown characteristic" = "Característica desconocida"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown characteristic: %@" = "La característica desconocida: %@"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown service: %@" = "Servicio Desconocido: %@"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/fi.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/fi.lproj/Localizable.strings deleted file mode 100644 index 022e85c15..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/fi.lproj/Localizable.strings +++ /dev/null @@ -1,36 +0,0 @@ -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Tietomäärä ylitti maksimikoon %@ tavua"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Syöte %@ on virheellinen"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Varmista, että laite on lähellä, jolloin ongelman pitäisi ratketa itsestään"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Ulkoinen laite ei vastannut ajoissa"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Ulkoinen laite ei ole yhdistetty"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Pumppu ei vastannut ajoissa"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Vastaus %@ on virheellinen"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "RileyLink ei vastannut ajoissa"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "RileyLink-laiteohelmisto ei tue %@ komentoa"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "RileyLink ei ole yhdistetty"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "Yhteys RileyLinkiin oli tilapäisesti poikki"; - -/* Error description */ -"Unknown characteristic" = "Tuntematon ominaisuus"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/fr.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/fr.lproj/Localizable.strings deleted file mode 100644 index 1f7fb9f3d..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/fr.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* PeripheralManagerError.emptyValue error description */ -"Characteristic value was empty" = "La valeur de la caractéristique est vide"; - -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Les données ont dépasséla taille maximale de %@ bytes"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "L’entrée %@ n’est pas valide"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Assurez-vous que le périphérique est à proximité et le problème devrait se résoudre automatiquement"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Le périphérique n’a pas répondu à temps"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Le périphérique n’est pas connecté"; - -/* Response timeout error description */ -"Pump did not respond in time" = "La pompe n’a pas répondu à temps"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "La réponse %@ n’est pas valide"; - -/* commandsBlocked error description */ -"RileyLink command did not respond" = "La commande RileyLink n'a pas répondu"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "Le RileyLink n'a pas répondu à temps"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "Le firmware du RileyLink ne reconnait pas la commande %@"; - -/* PeripheralManagerError.busy error description */ -"RileyLink is busy" = "Le RileyLink est occupé"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "Le RileyLink n'est pas connecté"; - -/* commandsBlocked recovery suggestion */ -"RileyLink may need to be turned off and back on" = "Le RileyLink pourrait avoir besoin d'être éteint et rallumé"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "Le RileyLink a été temporairement déconnecté"; - -/* Error description */ -"Unknown characteristic" = "Caractéristique inconnue"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown characteristic: %@" = "Caractéristique inconnue: %@"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown service: %@" = "Service inconnu: %@"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/he.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/he.lproj/Localizable.strings deleted file mode 100644 index 421a427fa..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/he.lproj/Localizable.strings +++ /dev/null @@ -1,51 +0,0 @@ -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Data exceeded maximum size of %@ bytes"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "קלט %@ אינו חוקי"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "ודא שהמכשיר נמצא בקרבת מקום, והבעיה אמורה להיפתר אוטומטית"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Peripheral did not respond in time"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Peripheral isnʼt connected"; - -/* Response timeout error description */ -"Pump did not respond in time" = "המשאבה לא הגיבה בזמן"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "התגובה %@ אינה חוקית"; - -/* commandsBlocked error description */ -"RileyLink command did not respond" = "פקודת ריילילינק לא הגיבה"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "ריילילינק לא הגיב בזמן"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "קושחת הריילילינק אינה תומכת בפקודה %@"; - -/* PeripheralManagerError.busy error description */ -"RileyLink is busy" = "ריילילינק עסוק"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "ריילילינק לא מחובר"; - -/* commandsBlocked recovery suggestion */ -"RileyLink may need to be turned off and back on" = "ייתכן שיש צורך לכבות את הריילילינק ולהפעיל אותו מחדש"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "הריילילינק נותק זמנית"; - -/* Error description */ -"Unknown characteristic" = "מאפיין לא ידוע"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown characteristic: %@" = "מאפיין לא ידוע: %@"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown service: %@" = "שירות לא ידוע: %@"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/hu.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/hu.lproj/Localizable.strings deleted file mode 100644 index b8344eccc..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/hu.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Data exceeded maximum size of %@ bytes"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Input %@ is invalid"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Make sure the device is nearby, and the issue should resolve automatically"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Peripheral did not respond in time"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Peripheral isnʼt connected"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Pump did not respond in time"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Response %@ is invalid"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "RileyLink firmware does not support the %@ command"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "The RileyLink was temporarily disconnected"; - -/* Error description */ -"Unknown characteristic" = "Unknown characteristic"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/it.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/it.lproj/Localizable.strings deleted file mode 100644 index 3367aeb14..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/it.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* PeripheralManagerError.emptyValue error description */ -"Characteristic value was empty" = "Il valore caratteristico era vuoto"; - -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "I dati superano la dimensione massima di %@ bytes"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Il dato inserito %@ non e' valido"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Fai attenzione che il device sia vicino e il problema dovrebbe risolversi automaticamente"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "La periferica non ha risposto nel tempo limite"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "La periferica non e' connessa"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Il microinfusore non ha risposto nel tempo limite"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "La risposta %@ non e' valida"; - -/* commandsBlocked error description */ -"RileyLink command did not respond" = "Rileylink non ha risposto al comando"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "Il Rileylink non ha risposto in tempo"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "Il firmware del RileyLink non supporta il comando %@"; - -/* PeripheralManagerError.busy error description */ -"RileyLink is busy" = "RileyLink è occupato"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "Il Rileylink non è connesso"; - -/* commandsBlocked recovery suggestion */ -"RileyLink may need to be turned off and back on" = "Potrebbe essere necessario spegnere e riaccendere RileyLink"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "Il RileyLink e' stato temporaneamente disconnesso"; - -/* Error description */ -"Unknown characteristic" = "Caratteristica sconosciuta"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown characteristic: %@" = "Caratteristica sconosciuta: %@"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown service: %@" = "Servizio sconosciuto: %@"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/ja.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/ja.lproj/Localizable.strings deleted file mode 100644 index 5a2eee93b..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/ja.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "データが最大サイズの %@バイトを超えました"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "%@のインプットは無効です"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "デバイスを近くにおいてください。問題は自動的に解決されます。"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "危機が時間内に反応しませんでした"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "危機が接続されていません"; - -/* Response timeout error description */ -"Pump did not respond in time" = "ポンプが時間内に反応しませんでした"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "%@のレスポンスは無効です"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "RileyLinkファームウェアは%@ コマンドをサポートしていません"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "RileyLinkの接続が一時的に切れました"; - -/* Error description */ -"Unknown characteristic" = "エラー不明"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/nb.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/nb.lproj/Localizable.strings deleted file mode 100644 index 6f22d1d6d..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/nb.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* PeripheralManagerError.emptyValue error description */ -"Characteristic value was empty" = "Karakteristisk verdi var tom"; - -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Data overskrider maks størrelse på %@ bytes"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Inndata %@ er ikke gyldig"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Forsikre deg at enheten er i nærheten, så skal problemet automatisk løse seg selv."; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Tilbehøret svarte ikke i tide"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Tilbehøret er ikke tilkoblet"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Pumpen svarte ikke i tide"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Responsen %@ er ikke gyldig"; - -/* commandsBlocked error description */ -"RileyLink command did not respond" = "RileyLink-kommandoen svarte ikke"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "RileyLink svarte ikke i tide"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "RileyLink firmware støtter ikke %@ kommandoen"; - -/* PeripheralManagerError.busy error description */ -"RileyLink is busy" = "RileyLink er opptatt"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "RileyLink er ikke tilkoblet"; - -/* commandsBlocked recovery suggestion */ -"RileyLink may need to be turned off and back on" = "RileyLink må kanskje slås av og på igjen"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "RileyLink ble midlertidig frakoblet"; - -/* Error description */ -"Unknown characteristic" = "Ukjent karakteristikk"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown characteristic: %@" = "Ukjent karakteristikk: %@"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown service: %@" = "Ukjent tjeneste: %@"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/nl.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/nl.lproj/Localizable.strings deleted file mode 100644 index 2347cca76..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/nl.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* PeripheralManagerError.emptyValue error description */ -"Characteristic value was empty" = "Karakteristieke waarde was leeg"; - -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Gegevens overschrijden maximale grootte van %@ bytes"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Invoer %@ is ongeldig"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Zorg ervoor dat het apparaat in de buurt is, wat het probleem automatisch zou moeten oplossen."; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Apparaat reageerde niet op tijd"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Apparaat is niet verbonden"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Pomp reageerde niet op tijd"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Reactie %@ is ongeldig"; - -/* commandsBlocked error description */ -"RileyLink command did not respond" = "Er was geen reactie van het RileyLink commando"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "RileyLink reageerde niet op tijd"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "De RileyLink firmware ondersteunt het %@ commando niet"; - -/* PeripheralManagerError.busy error description */ -"RileyLink is busy" = "RileyLink is bezig"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "RileyLink is niet verbonden"; - -/* commandsBlocked recovery suggestion */ -"RileyLink may need to be turned off and back on" = "RileyLink moet mogelijk uit- en weer ingeschakeld worden"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "The RileyLink was tijdelijk niet verbonden"; - -/* Error description */ -"Unknown characteristic" = "Onbekende eigenschap"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown characteristic: %@" = "Onbekende eigenschap: %@"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown service: %@" = "Onbekende service: %@"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/pl.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/pl.lproj/Localizable.strings deleted file mode 100644 index f9d653581..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/pl.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* PeripheralManagerError.emptyValue error description */ -"Characteristic value was empty" = "Wartość charakterystyczna była pusta"; - -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Dane przekraczają maksymalną pojemność %@ bajtów"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Wprowadzona %@ jest nieprawidłowa"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Upewnij się, że urządzenie jest w pobliżu; problem powinien rozwiązać się automatycznie"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Urz. peryferyjne nie odpowiada"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Urz. peryferyjne jest niepodłączone"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Czas oczekiwania na odpowiedź pompy został przekroczony"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Odpowiedź %@ jest nieprawidłowa"; - -/* commandsBlocked error description */ -"RileyLink command did not respond" = "Komenda RileyLink nie odpowiedziała"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "RileyLink nie odpowiedział na czas"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "Oprogramowanie RileyLink nie obsługuje polecenia %@"; - -/* PeripheralManagerError.busy error description */ -"RileyLink is busy" = "RileyLink jest zajęty"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "RileyLink nie jest podłączony"; - -/* commandsBlocked recovery suggestion */ -"RileyLink may need to be turned off and back on" = "RileyLink może wymagać wyłączenia i ponownego włączenia"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "RileyLink został tymczasowo rozłączony"; - -/* Error description */ -"Unknown characteristic" = "Nieznany błąd"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown characteristic: %@" = "Nieznane powiadomienie: %@"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown service: %@" = "Nieznana usługa: %@"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/pt-BR.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/pt-BR.lproj/Localizable.strings deleted file mode 100644 index b70832a2d..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Dados excederam o tamanho máximo de %@ bytes"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Entrada %@ é inválida"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Confira que o dispositivo esteja próximo, e o problema deve se resolver automaticamente."; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Acessório não respondeu a tempo"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Acessório não está conectado"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Bomba não respondeu a tempo"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Resposta %@ é inválida"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "O firmware do RileyLink não suporta o comando %@"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "O RileyLink foi temporariamente desconectado"; - -/* Error description */ -"Unknown characteristic" = "Característica Desconhecida"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/ro.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/ro.lproj/Localizable.strings deleted file mode 100644 index 46d1d2e20..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/ro.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* PeripheralManagerError.emptyValue error description */ -"Characteristic value was empty" = "Valoarea caracteristică era goală"; - -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Datele depășesc cantitatea maximă de %@ bytes"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Introducerea %@ este invalidă"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Asigurați-vă că dispozitivul este în apropiere, iar problema ar trebui să se rezolve automat"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Dispozitivul periferic nu a răspuns în timp util"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Dispozitivul periferic nu este conectat"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Pompa nu a răspuns în timp util"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Răspunsul %@ este invalid"; - -/* commandsBlocked error description */ -"RileyLink command did not respond" = "Comanda RileyLink nu a răspuns"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "RileyLink nu a răspuns în timp util"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "Firmware-ul RileyLink nu poate efectua %@ comanda"; - -/* PeripheralManagerError.busy error description */ -"RileyLink is busy" = "RileyLink-ul este ocupat"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "RileyLink nu este conectat"; - -/* commandsBlocked recovery suggestion */ -"RileyLink may need to be turned off and back on" = "Poate fi necesar ca RileyLink să fie oprit și repornit"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "RileyLink a fost temporar deconectat"; - -/* Error description */ -"Unknown characteristic" = "Caracteristică necunoscută"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown characteristic: %@" = "Caracteristică necunoscută: %@"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown service: %@" = "Serviciu necunoscut: %@"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/ru.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/ru.lproj/Localizable.strings deleted file mode 100644 index f7a324138..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/ru.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* PeripheralManagerError.emptyValue error description */ -"Characteristic value was empty" = "Значение характеристики было пустым"; - -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Данные превышают максимальный объем %@ байт"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Введенная величина %@ неверна"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Убедитесь в том, что устройство находится рядом и проблема должна устраниться автоматически"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Периферийное устройство не отозвалось вовремя"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Соединение с периферийным устройством не установлено"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Отклик от помпы не получен вовремя"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Отклик %@ неверен"; - -/* commandsBlocked error description */ -"RileyLink command did not respond" = "RileyLink не получил ответ на команду"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "RileyLink не отвечает (завис)"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "Прошивка RileyLink не поддерживает команду %@"; - -/* PeripheralManagerError.busy error description */ -"RileyLink is busy" = "Rileylink занят"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "RileyLink не подключен"; - -/* commandsBlocked recovery suggestion */ -"RileyLink may need to be turned off and back on" = "RileyLink необходимо перезагрузить (выключить и включить)"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "Связь с RileyLink была временно потеряна"; - -/* Error description */ -"Unknown characteristic" = "Неизвестная характеристика"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown characteristic: %@" = "Неизвестная характеристика: %@"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown service: %@" = "Неизвестный сервис: %@"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/sk.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/sk.lproj/Localizable.strings deleted file mode 100644 index 52f957845..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/sk.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* PeripheralManagerError.emptyValue error description */ -"Characteristic value was empty" = "Charakteristická hodnota bola prázdna"; - -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Dáta prekročili maximálnu veľkosť %@ bajtov"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Vstup %@ je neplatný"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Uistite sa, že je zariadenie v blízkosti a problém by sa mal vyriešiť automaticky"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Periférne zariadenie nereagovalo načas"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Periférne zariadenie nie je pripojené"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Pumpa neodpovedala načas"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Odpoveď %@ je neplatná"; - -/* commandsBlocked error description */ -"RileyLink command did not respond" = "RileyLink príkaz neodpovedal"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "RileyLink neodpovedal včas"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "Firmvér RileyLink nepodporuje príkaz %@"; - -/* PeripheralManagerError.busy error description */ -"RileyLink is busy" = "RileyLink je zaneprázdnený"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "RileyLink nie je pripojený"; - -/* commandsBlocked recovery suggestion */ -"RileyLink may need to be turned off and back on" = "RileyLink môže byť potrebné vypnúť a znova zapnúť"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "RileyLink bol dočasne odpojený"; - -/* Error description */ -"Unknown characteristic" = "Neznáma charakteristika"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown characteristic: %@" = "Neznáma charakteristika: %@"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown service: %@" = "Neznáma služba: %@"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/sv.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/sv.lproj/Localizable.strings deleted file mode 100644 index 7dee1f245..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/sv.lproj/Localizable.strings +++ /dev/null @@ -1,36 +0,0 @@ -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Kan inte skriva data då maxgränsen %@ bytes är uppnådd"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Inmatningen %@ är ogiltig"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Säkerställ att enheten är inom räckhåll så borde problemet lösas automatiskt"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Enhet svarade inte inom utsatt tid"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Enheten är inte ansluten"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Pumpen svarade inte inom utsatt tid"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Respons %@ ogiltig"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "Din RileyLink svarade inte i tid"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "RileyLink-enhetens firmware stöder inte kommandot %@"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "RileyLink är inte ansluten"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "RileyLink-enheten har blivit frånkopplad temporärt"; - -/* Error description */ -"Unknown characteristic" = "Okänd data"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/tr.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/tr.lproj/Localizable.strings deleted file mode 100644 index bcc89bf71..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/tr.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* PeripheralManagerError.emptyValue error description */ -"Characteristic value was empty" = "Karakteristik değer boştu"; - -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Veri maksimum %@ bayt boyutunu aştı"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "%@ girişi geçersiz"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Cihazın yakında olduğundan emin olun ve sorun otomatik olarak çözülecektir."; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Çevre birimi zamanında yanıt vermedi"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Çevre birimi bağlı değil"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Pompa zamanında yanıt vermedi"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Yanıt %@ geçersiz"; - -/* commandsBlocked error description */ -"RileyLink command did not respond" = "RileyLink komutu yanıt vermedi"; - -/* PeripheralManagerError.timeout error description */ -"RileyLink did not respond in time" = "RileyLink zamanında yanıt vermedi"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "RileyLink aygıt yazılımı %@ komutunu desteklemiyor"; - -/* PeripheralManagerError.busy error description */ -"RileyLink is busy" = "RileyLink meşgul"; - -/* PeripheralManagerError.notReady error description */ -"RileyLink is not connected" = "RileyLink bağlı değil"; - -/* commandsBlocked recovery suggestion */ -"RileyLink may need to be turned off and back on" = "RileyLink'in kapatılıp tekrar açılması gerekebilir"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "RileyLink'in bağlantısı geçici olarak kesildi"; - -/* Error description */ -"Unknown characteristic" = "Bilinmeyen karakteristik"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown characteristic: %@" = "Bilinmeyen karakteristik: %@"; - -/* PeripheralManagerError.unknownCharacteristic error description */ -"Unknown service: %@" = "Bilinmeyen hizmet: %@"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/vi.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/vi.lproj/Localizable.strings deleted file mode 100644 index 0b2446654..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/vi.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "Dữ liệu vượt quá dung lượng cho phép %@ bytes"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "Nguồn nhập liệu %@ không tồn tại"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "Chắc chắn rằng thiết bị đang bên cạnh và các vấn đề sẽ được giải quyết tự động"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "Ngoại vi không đáp ứng kịp thời"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "Ngoại vi không được kết nối"; - -/* Response timeout error description */ -"Pump did not respond in time" = "Bơm không phản ứng kịp lúc"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "Phản hồi %@ không hợp lệ"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "Chương trình cơ sở của RileyLink không hỗ trợ lệnh %@"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "Rileylink tạm thời mất kết nối"; - -/* Error description */ -"Unknown characteristic" = "Đặc điểm không xác định"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKit/zh-Hans.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkBLEKit/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 8f932a421..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKit/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,30 +0,0 @@ -/* Write size limit exceeded error description (1: size limit) */ -"Data exceeded maximum size of %@ bytes" = "数据超过最大%@字节"; - -/* Invalid input error description (1: input) */ -"Input %@ is invalid" = "输入%@无效"; - -/* Recovery suggestion for unknown peripheral characteristic */ -"Make sure the device is nearby, and the issue should resolve automatically" = "确保设备在附近,该问题可自动解决"; - -/* Timeout error description */ -"Peripheral did not respond in time" = "外设没有及时响应"; - -/* Not ready error description */ -"Peripheral isnʼt connected" = "外围设备未连接"; - -/* Response timeout error description */ -"Pump did not respond in time" = "泵没有及时响应"; - -/* Invalid response error description (1: response) */ -"Response %@ is invalid" = "响应%@无效"; - -/* Unsupported command error description */ -"RileyLink firmware does not support the %@ command" = "RileyLink固件不支持%@命令"; - -/* Failure reason: unknown peripheral characteristic */ -"The RileyLink was temporarily disconnected" = "RileyLink暂时断开连接"; - -/* Error description */ -"Unknown characteristic" = "未知特性"; - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKitTests/Info.plist b/Dependencies/rileylink_ios/RileyLinkBLEKitTests/Info.plist deleted file mode 100644 index 713b7c93b..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKitTests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 3.0 - CFBundleVersion - 1 - - diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKitTests/RFPacketTests.swift b/Dependencies/rileylink_ios/RileyLinkBLEKitTests/RFPacketTests.swift deleted file mode 100644 index 116bc17cb..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKitTests/RFPacketTests.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// RFPacketTests.swift -// RileyLinkBLEKitTests -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import XCTest -@testable import RileyLinkBLEKit - -class RFPacketTests: XCTestCase { - - func testDecodeRF() { - let response = Data(hexadecimalString: "4926a965a5d1a8dab0e5635635555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555559a35") - let packet = RFPacket(rfspyResponse: response!)! - XCTAssertEqual("a965a5d1a8dab0e5635635555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555559a35", packet.data.hexadecimalString) - XCTAssertEqual(-37, packet.rssi) - } - -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKitTests/RadioFirmwareVersionTests.swift b/Dependencies/rileylink_ios/RileyLinkBLEKitTests/RadioFirmwareVersionTests.swift deleted file mode 100644 index 001f29029..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKitTests/RadioFirmwareVersionTests.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// RadioFirmwareVersionTests.swift -// RileyLinkBLEKitTests -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import XCTest -@testable import RileyLinkBLEKit - -class RadioFirmwareVersionTests: XCTestCase { - - func testVersionParsing() { - let version = RadioFirmwareVersion(versionString: "subg_rfspy 0.8")! - - XCTAssertEqual([0, 8], version.components) - } - -} diff --git a/Dependencies/rileylink_ios/RileyLinkBLEKitTests/ResponseBufferTests.swift b/Dependencies/rileylink_ios/RileyLinkBLEKitTests/ResponseBufferTests.swift deleted file mode 100644 index eec2d7e7e..000000000 --- a/Dependencies/rileylink_ios/RileyLinkBLEKitTests/ResponseBufferTests.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// ResponseBufferTests.swift -// RileyLinkBLEKitTests -// -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import XCTest -@testable import RileyLinkBLEKit - -class ResponseBufferTests: XCTestCase { - - func testSingleError() { - var buffer = ResponseBuffer(endMarker: 0x00) - - buffer.append(Data(hexadecimalString: "bb00")!) - - let responses = buffer.responses - - XCTAssertEqual(1, responses.count) - } - -} diff --git a/Dependencies/rileylink_ios/RileyLinkKit/Info.plist b/Dependencies/rileylink_ios/RileyLinkKit/Info.plist deleted file mode 100644 index 21baa19b4..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKit/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.0 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkDevice.swift b/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkDevice.swift deleted file mode 100644 index c052030f6..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkDevice.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// RileyLinkDevice.swift -// RileyLinkKit -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -import RileyLinkBLEKit - -extension Notification.Name { - public static let DeviceRadioConfigDidChange = Notification.Name(rawValue: "com.rileylink.RileyLinkKit.DeviceRadioConfigDidChange") - - public static let DeviceStateDidChange = Notification.Name(rawValue: "com.rileylink.RileyLinkKit.DeviceStateDidChange") -} diff --git a/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkDeviceManager.swift b/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkDeviceManager.swift deleted file mode 100644 index 8fafc5b4e..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkDeviceManager.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// RileyLinkDeviceManager.swift -// Loop -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import RileyLinkBLEKit - -extension RileyLinkDeviceProvider { - public func firstConnectedDevice(_ completion: @escaping (_ device: RileyLinkDevice?) -> Void) { - getDevices { (devices) in - completion(devices.firstConnected) - } - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkKit.h b/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkKit.h deleted file mode 100644 index 472a86e7f..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkKit.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// RileyLinkKit.h -// RileyLinkKit -// -// Created by Nathan Racklyeft on 4/9/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import - -//! Project version number for RileyLinkKit. -FOUNDATION_EXPORT double RileyLinkKitVersionNumber; - -//! Project version string for RileyLinkKit. -FOUNDATION_EXPORT const unsigned char RileyLinkKitVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import diff --git a/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkListDataSource.swift b/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkListDataSource.swift deleted file mode 100644 index b34094819..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkListDataSource.swift +++ /dev/null @@ -1,93 +0,0 @@ -// -// RileyLinkListDataSource.swift -// RileyLinkKit -// -// Created by Pete Schwamb on 6/7/22. -// Copyright © 2022 Pete Schwamb. All rights reserved. -// - -import Foundation -import RileyLinkBLEKit -import SwiftUI - -public class RileyLinkListDataSource: ObservableObject { - - public let rileyLinkPumpManager: RileyLinkPumpManager - - @Published private(set) public var devices: [RileyLinkDevice] = [] - - public init(rileyLinkPumpManager: RileyLinkPumpManager) { - self.rileyLinkPumpManager = rileyLinkPumpManager - - // Register for manager notifications - NotificationCenter.default.addObserver(self, selector: #selector(reloadDevices), name: .ManagerDevicesDidChange, object: rileyLinkPumpManager.rileyLinkDeviceProvider) - - // Register for device notifications - for name in [.DeviceConnectionStateDidChange, .DeviceRSSIDidChange, .DeviceNameDidChange] as [Notification.Name] { - NotificationCenter.default.addObserver(self, selector: #selector(reloadDevices), name: name, object: nil) - } - - reloadDevices() - } - - public func autoconnectBinding(for device: RileyLinkDevice) -> Binding { - return Binding( - get: { [weak self] in - if let connectionManager = self?.rileyLinkPumpManager.rileyLinkDeviceProvider { - return connectionManager.shouldConnect(to: device.peripheralIdentifier.uuidString) - } else { - return false - } - }, - set: { [weak self] in - if $0 { - self?.rileyLinkPumpManager.connectToRileyLink(device) - } else { - self?.rileyLinkPumpManager.disconnectFromRileyLink(device) - } - }) - } - - @objc private func reloadDevices() { - rileyLinkPumpManager.rileyLinkDeviceProvider.getDevices { (devices) in - DispatchQueue.main.async { [weak self] in - self?.devices = devices - } - } - } - - public var isScanningEnabled: Bool = false { - didSet { - rileyLinkPumpManager.rileyLinkDeviceProvider.setScanningEnabled(isScanningEnabled) - - if isScanningEnabled { - rssiFetchTimer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(updateRSSI), userInfo: nil, repeats: true) - updateRSSI() - } else { - rssiFetchTimer = nil - } - } - } - - var connecting: Bool { - #if targetEnvironment(simulator) - return true - #else - - return rileyLinkPumpManager.rileyLinkDeviceProvider.connectingCount > 0 - #endif - } - - - private var rssiFetchTimer: Timer? { - willSet { - rssiFetchTimer?.invalidate() - } - } - - @objc public func updateRSSI() { - for device in devices { - device.readRSSI() - } - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkPumpManager.swift b/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkPumpManager.swift deleted file mode 100644 index 8cd1c7548..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKit/RileyLinkPumpManager.swift +++ /dev/null @@ -1,117 +0,0 @@ -// -// RileyLinkPumpManager.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import LoopKit -import RileyLinkBLEKit - -open class RileyLinkPumpManager { - - open var rileyLinkConnectionManagerState: RileyLinkConnectionState? - - public init(rileyLinkDeviceProvider: RileyLinkDeviceProvider) { - - self.rileyLinkDeviceProvider = rileyLinkDeviceProvider - - rileyLinkDeviceProvider.delegate = self - - // Listen for device notifications - NotificationCenter.default.addObserver(self, selector: #selector(receivedRileyLinkPacketNotification(_:)), name: .DevicePacketReceived, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(receivedRileyLinkTimerTickNotification(_:)), name: .DeviceTimerDidTick, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(receivedRileyLinkBatteryUpdate(_:)), name: .DeviceBatteryLevelUpdated, object: nil) - - } - - /// Access to rileylink devices - public let rileyLinkDeviceProvider: RileyLinkDeviceProvider - - // TODO: Put this on each RileyLinkDevice? - private var lastTimerTick = Locked(Date.distantPast) - - /// Called when one of the connected devices receives a packet outside of a session - /// - /// - Parameters: - /// - device: The device - /// - packet: The received packet - open func device(_ device: RileyLinkDevice, didReceivePacket packet: RFPacket) { } - - open func deviceTimerDidTick(_ device: RileyLinkDevice) { } - - open func device(_ device: RileyLinkDevice, didUpdateBattery level: Int) { } - - // MARK: - CustomDebugStringConvertible - - open var debugDescription: String { - return [ - "## RileyLinkPumpManager", - "lastTimerTick: \(String(describing: lastTimerTick.value))", - "", - String(reflecting: rileyLinkDeviceProvider), - ].joined(separator: "\n") - } -} - -// MARK: - RileyLink Updates -extension RileyLinkPumpManager { - - /** - Called when a new idle message is received by the RileyLink. - - Only MySentryPumpStatus messages are handled. - - - parameter note: The notification object - */ - @objc private func receivedRileyLinkPacketNotification(_ note: Notification) { - guard let device = note.object as? RileyLinkDevice, - let packet = note.userInfo?[RileyLinkBluetoothDevice.notificationPacketKey] as? RFPacket - else { - return - } - - device.assertOnSessionQueue() - - self.device(device, didReceivePacket: packet) - } - - - @objc private func receivedRileyLinkTimerTickNotification(_ note: Notification) { - guard let device = note.object as? RileyLinkDevice else { - return - } - - self.lastTimerTick.value = Date() - self.deviceTimerDidTick(device) - } - - - @objc private func receivedRileyLinkBatteryUpdate(_ note: Notification) { - guard let device = note.object as? RileyLinkDevice, - let batteryLevel = note.userInfo?[RileyLinkBluetoothDevice.batteryLevelKey] as? Int - else { - return - } - - device.assertOnSessionQueue() - - self.device(device, didUpdateBattery: batteryLevel) - } - - - public func connectToRileyLink(_ device: RileyLinkDevice) { - rileyLinkDeviceProvider.connect(device) - } - - public func disconnectFromRileyLink(_ device: RileyLinkDevice) { - rileyLinkDeviceProvider.disconnect(device) - } - -} - -extension RileyLinkPumpManager: RileyLinkDeviceProviderDelegate { - public func rileylinkDeviceProvider(_ rileylinkDeviceProvider: RileyLinkBLEKit.RileyLinkDeviceProvider, didChange state: RileyLinkBLEKit.RileyLinkConnectionState) { - self.rileyLinkConnectionManagerState = state - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkKitTests/Info.plist b/Dependencies/rileylink_ios/RileyLinkKitTests/Info.plist deleted file mode 100644 index 7506bdc29..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitTests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 2.2.0 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - - diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/Base.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/Base.lproj/Localizable.strings deleted file mode 100644 index 56422d08e..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/Base.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Alert"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Auto"; - -/* The title of the cell showing battery level */ -"Battery level" = "Battery level"; - -/* The title of the section describing commands */ -"Commands" = "Commands"; - -/* The connected state */ -"Connected" = "Connected"; - -/* The in-progress connecting state */ -"Connecting" = "Connecting"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Connection LED"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Connection Monitoring"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Connection State"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Connection Vibration"; - -/* The title of the section describing the device */ -"Device" = "Device"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Devices"; - -/* The disconnected state */ -"Disconnected" = "Disconnected"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Disconnecting"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Find Device"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frequency" ; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Get RileyLink Statistics"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Get Statistics…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Lighten Red LED"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Lighten Yellow LED"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Low Battery Alert"; - -/* The title of the cell showing device name */ -"Name" = "Name"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Off"; - -/* Text indicating LED Mode is on */ -"On" = "On"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink allows for communication with the pump over Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Signal Strength"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Test Commands"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Test Vibration"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Toggle Diagnostic LEDs"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Updating diagnostic LEDs mode"; - -/* The title of the cell showing uptime */ -"Uptime" = "Uptime"; - -/* The title of the cell showing ORL */ -"Voltage" = "Voltage"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/CBPeripheralState.swift b/Dependencies/rileylink_ios/RileyLinkKitUI/CBPeripheralState.swift deleted file mode 100644 index 89f653989..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/CBPeripheralState.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// CBPeripheralState.swift -// Naterade -// -// Created by Nathan Racklyeft on 3/5/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import CoreBluetooth - - -extension CBPeripheralState { - - // MARK: - CustomStringConvertible - - public var description: String { - switch self { - case .connected: - return LocalizedString("Connected", comment: "The connected state") - case .connecting: - return LocalizedString("Connecting", comment: "The in-progress connecting state") - case .disconnected: - return LocalizedString("Disconnected", comment: "The disconnected state") - case .disconnecting: - return LocalizedString("Disconnecting", comment: "The in-progress disconnecting state") - @unknown default: - return "Unknown: \(rawValue)" - } - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/CommandResponseViewController.swift b/Dependencies/rileylink_ios/RileyLinkKitUI/CommandResponseViewController.swift deleted file mode 100644 index 4301f380f..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/CommandResponseViewController.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// CommandResponseViewController.swift -// RileyLinkKitUI -// -// Created by Pete Schwamb on 7/19/21. -// Copyright © 2021 Pete Schwamb. All rights reserved. -// - -import Foundation -import LoopKitUI -import RileyLinkBLEKit - -extension CommandResponseViewController { - typealias T = CommandResponseViewController - - static func getStatistics(device: RileyLinkDevice) -> T { - return T { (completionHandler) -> String in - device.runSession(withName: "Get Statistics") { session in - let response: String - - do { - let stats = try session.getRileyLinkStatistics() - response = String(describing: stats) - } catch let error { - response = String(describing: error) - } - - DispatchQueue.main.async { - completionHandler(response) - } - } - - return LocalizedString("Get Statistics…", comment: "Progress message for getting statistics.") - } - } - - static func setDiagnosticLEDMode(device: RileyLinkDevice, mode: RileyLinkLEDMode) -> T { - return T { (completionHandler) -> String in - device.setDiagnosticeLEDModeForBLEChip(mode) - device.runSession(withName: "Update diagnostic LED mode") { session in - let response: String - do { - try session.setCCLEDMode(mode) - switch mode { - case .on: - response = "Diagnostic mode enabled" - default: - response = "Diagnostic mode disabled" - } - } catch let error { - response = String(describing: error) - } - - DispatchQueue.main.async { - completionHandler(response) - } - } - - return LocalizedString("Updating diagnostic LEDs mode", comment: "Progress message for changing diagnostic LED mode") - } - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/Info.plist b/Dependencies/rileylink_ios/RileyLinkKitUI/Info.plist deleted file mode 100644 index 7a3ea75eb..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkDeviceTableViewCell.swift b/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkDeviceTableViewCell.swift deleted file mode 100644 index 179dec045..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkDeviceTableViewCell.swift +++ /dev/null @@ -1,97 +0,0 @@ -// -// RileyLinkDeviceTableViewCell.swift -// Naterade -// -// Created by Nathan Racklyeft on 8/29/15. -// Copyright © 2015 Nathan Racklyeft. All rights reserved. -// - -import CoreBluetooth -import UIKit - -public class RileyLinkDeviceTableViewCell: UITableViewCell { - - public var connectSwitch: UISwitch? - - public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: .value1, reuseIdentifier: reuseIdentifier) - - setup() - } - - public required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - } - - public override func awakeFromNib() { - super.awakeFromNib() - - setup() - } - - private func setup() { - // Manually layout the switch with an 8pt left margin - // TODO: Adjust appropriately for RTL - let connectSwitch = UISwitch(frame: .zero) - connectSwitch.sizeToFit() - connectSwitch.frame = connectSwitch.frame.offsetBy(dx: 8, dy: 0) - - var switchFrame = connectSwitch.frame - switchFrame.origin = .zero - switchFrame.size.width += 8 - - let switchContainer = UIView(frame: switchFrame) - switchContainer.addSubview(connectSwitch) - - self.connectSwitch = connectSwitch - - accessoryView = switchContainer - accessoryType = .disclosureIndicator - } - - override public func layoutSubviews() { - super.layoutSubviews() - - contentView.layoutMargins.left = separatorInset.left - contentView.layoutMargins.right = separatorInset.left - } - - public func configureCellWithName(_ name: String?, signal: String?, peripheralState: CBPeripheralState?) { - textLabel?.text = name - if peripheralState == .connecting { - detailTextLabel?.text = "..." - } else { - detailTextLabel?.text = " \(signal ?? "") " - } - - if let state = peripheralState { - switch state { - case .connected: - connectSwitch?.isOn = true - connectSwitch?.isEnabled = true - case .connecting: - connectSwitch?.isOn = true - connectSwitch?.isEnabled = true - case .disconnected: - connectSwitch?.isOn = false - connectSwitch?.isEnabled = true - case .disconnecting: - fallthrough - @unknown default: - connectSwitch?.isOn = false - connectSwitch?.isEnabled = false - } - } else { - connectSwitch?.isHidden = true - } - } - - public override func prepareForReuse() { - super.prepareForReuse() - - connectSwitch?.removeTarget(nil, action: nil, for: .valueChanged) - } - -} - - diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkDeviceTableViewController.swift b/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkDeviceTableViewController.swift deleted file mode 100644 index c66a02ed9..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkDeviceTableViewController.swift +++ /dev/null @@ -1,846 +0,0 @@ -// -// RileyLinkDeviceTableViewController.swift -// Naterade -// -// Created by Nathan Racklyeft on 3/5/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit -import LoopKitUI -import RileyLinkBLEKit -import RileyLinkKit -import os.log - -let CellIdentifier = "Cell" - -public class RileyLinkSwitch: UISwitch { - - public var index: Int = 0 - public var section: Int = 0 -} - -public class RileyLinkCell: UITableViewCell { - public let switchView = RileyLinkSwitch() - - public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - contentView.addSubview(switchView) - } - - public required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - } - - public override func layoutSubviews() { - super.layoutSubviews() - switchView.frame = CGRect(x: frame.width - 51 - 20, y: (frame.height - 31) / 2, width: 51, height: 31) - } -} - -public class RileyLinkDeviceTableViewController: UITableViewController { - - private let log = OSLog(category: "RileyLinkDeviceTableViewController") - - public let device: RileyLinkDevice - - private var bleRSSI: Int? - - private var firmwareVersion: String? { - didSet { - guard isViewLoaded else { - return - } - - cellForRow(.version)?.detailTextLabel?.text = firmwareVersion - } - } - - private var uptime: TimeInterval? { - didSet { - guard isViewLoaded else { - return - } - - cellForRow(.uptime)?.setDetailAge(uptime) - } - } - - private var battery: Int? { - didSet { - guard isViewLoaded else { - return - } - cellForRow(.battery)?.setDetailBatteryLevel(battery) - } - } - - private var frequency: Measurement? { - didSet { - guard isViewLoaded else { - return - } - - cellForRow(.frequency)?.setDetailFrequency(frequency, formatter: frequencyFormatter) - } - } - - private var ledMode: RileyLinkLEDMode? { - didSet { - guard isViewLoaded else { - return - } - cellForRow(.diagnosticLEDSMode)?.setLEDMode(ledMode) - } - } - - var rssiFetchTimer: Timer? { - willSet { - rssiFetchTimer?.invalidate() - } - } - - private var hasPiezo: Bool = false - - private var appeared = false - - private var batteryAlertLevel: Int? { - didSet { - batteryAlertLevelChanged?(batteryAlertLevel) - } - } - - private var batteryAlertLevelChanged: ((Int?) -> Void)? - - public init(device: RileyLinkDevice, batteryAlertLevel: Int?, batteryAlertLevelChanged: ((Int?) -> Void)? ) { - self.device = device - self.batteryAlertLevel = batteryAlertLevel - self.batteryAlertLevelChanged = batteryAlertLevelChanged - - super.init(style: .grouped) - - updateDeviceStatus() - - NotificationCenter.default.addObserver(forName: .DeviceStatusUpdated, object: device, queue: .main) - { (notification) in - self.updateDeviceStatus() - } - } - - required public init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public override func viewDidLoad() { - super.viewDidLoad() - - title = device.name - - switch device.hardwareType { - case .riley, .none: - deviceRows = [ - .customName, - .version, - .rssi, - .connection, - .uptime, - .frequency - ] - - sections = [ - .device, - .rileyLinkCommands - ] - case .ema: - deviceRows = [ - .customName, - .version, - .rssi, - .connection, - .uptime, - .frequency, - .battery - ] - - sections = [ - .device, - .alert, - .rileyLinkCommands - ] - case .orange: - deviceRows = [ - .customName, - .version, - .rssi, - .connection, - .uptime, - .battery, - .voltage - ] - - if device.hasOrangeLinkService { - sections = [ - .device, - .alert, - .configureCommand, - .orangeLinkCommands - ] - } else { - sections = [ - .device - ] - } - } - - self.observe() - } - - @objc func updateRSSI() { - device.readRSSI() - } - - // This does not trigger any BLE reads; it just gets status from the device in a safe manner, and reloads the table - func updateDeviceStatus() { - device.getStatus { (status) in - DispatchQueue.main.async { - self.firmwareVersion = status.version - self.ledOn = status.ledOn - self.vibrationOn = status.vibrationOn - self.voltage = status.voltage - self.battery = status.battery - self.hasPiezo = status.hasPiezo - self.tableView.reloadData() - } - } - } - - func updateUptime() { - device.runSession(withName: "Get stats for uptime") { (session) in - do { - let statistics = try session.getRileyLinkStatistics() - DispatchQueue.main.async { - self.uptime = statistics.uptime - } - } catch let error { - self.log.error("Failed to get stats for uptime: %{public}@", String(describing: error)) - } - } - } - - func updateFrequency() { - - device.runSession(withName: "Get base frequency") { (session) in - do { - let frequency = try session.readBaseFrequency() - DispatchQueue.main.async { - self.frequency = frequency - } - } catch let error { - self.log.error("Failed to get base frequency: %{public}@", String(describing: error)) - } - } - } - - func readDiagnosticLEDMode() { - device.readDiagnosticLEDModeForBLEChip(completion: { ledMode in - DispatchQueue.main.async { - self.ledMode = ledMode - } - }) - } - - // References to registered notification center observers - private var notificationObservers: [Any] = [] - - deinit { - for observer in notificationObservers { - NotificationCenter.default.removeObserver(observer) - } - } - - private func observe() { - let center = NotificationCenter.default - let mainQueue = OperationQueue.main - - notificationObservers = [ - center.addObserver(forName: .DeviceNameDidChange, object: device, queue: mainQueue) { [weak self] (note) -> Void in - if let cell = self?.cellForRow(.customName) { - cell.detailTextLabel?.text = self?.device.name - } - self?.title = self?.device.name - self?.tableView.reloadData() - }, - center.addObserver(forName: .DeviceConnectionStateDidChange, object: device, queue: mainQueue) { [weak self] (note) -> Void in - if let cell = self?.cellForRow(.connection) { - cell.detailTextLabel?.text = self?.device.peripheralState.description - } - }, - center.addObserver(forName: .DeviceRSSIDidChange, object: device, queue: mainQueue) { [weak self] (note) -> Void in - self?.bleRSSI = note.userInfo?[RileyLinkBluetoothDevice.notificationRSSIKey] as? Int - - if let cell = self?.cellForRow(.rssi), let formatter = self?.integerFormatter { - cell.setDetailRSSI(self?.bleRSSI, formatter: formatter) - } - }, - center.addObserver(forName: .DeviceDidStartIdle, object: device, queue: mainQueue) { [weak self] (note) in - self?.updateDeviceStatus() - }, - center.addObserver(forName: .DeviceStatusUpdated, object: device, queue: mainQueue) { [weak self] (note) in - self?.updateDeviceStatus() - }, - ] - } - - public override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - if appeared { - tableView.reloadData() - } - - rssiFetchTimer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(updateRSSI), userInfo: nil, repeats: true) - - appeared = true - - updateRSSI() - - if deviceRows.contains(.frequency) { - updateFrequency() - } - - updateUptime() - - switch device.hardwareType { - case .riley: - readDiagnosticLEDMode() - case .ema: - device.updateBatteryLevel() - readDiagnosticLEDMode() - case .orange: - device.updateBatteryLevel() - device.orangeWritePwd() - device.orangeReadSet() - device.orangeReadVDC() - device.orangeAction(.fw_hw) - default: - break - } - } - - public override func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - if redOn || yellowOn { - device.orangeAction(.off) - } - - if shakeOn { - device.orangeAction(.shakeOff) - } - } - - public override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - rssiFetchTimer = nil - } - - - // MARK: - Formatters - - private lazy var dateFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - - dateFormatter.dateStyle = .none - dateFormatter.timeStyle = .medium - - return dateFormatter - }() - - private lazy var integerFormatter = NumberFormatter() - - private lazy var decimalFormatter: NumberFormatter = { - let decimalFormatter = NumberFormatter() - - decimalFormatter.numberStyle = .decimal - decimalFormatter.maximumFractionDigits = 2 - return decimalFormatter - }() - - private lazy var frequencyFormatter: MeasurementFormatter = { - let formatter = MeasurementFormatter() - formatter.numberFormatter = decimalFormatter - return formatter - }() - - // MARK: - Table view data source - - private enum Section: Int, CaseIterable { - case device - case alert - case configureCommand - case orangeLinkCommands - case rileyLinkCommands - } - - private var sections: [Section] = [] - - private enum AlertRow: Int, CaseIterable { - case battery - } - - private enum DeviceRow: Int, CaseIterable { - case customName - case version - case rssi - case connection - case uptime - case frequency - case battery - case voltage - } - - private var deviceRows: [DeviceRow] = [] - - private enum RileyLinkCommandRow: Int, CaseIterable { - case diagnosticLEDSMode - case getStatistics - } - - private enum OrangeLinkCommandRow: Int, CaseIterable { - case yellow - case red - case shake - case findDevice - } - - private enum OrangeConfigureCommandRow: Int, CaseIterable { - case connectionLED - case connectionVibrate - } - - private func cellForRow(_ row: DeviceRow) -> UITableViewCell? { - guard let rowIndex = deviceRows.firstIndex(of: row), - let sectionIndex = sections.firstIndex(of: Section.device) else - { - return nil - } - return tableView.cellForRow(at: IndexPath(row: rowIndex, section: sectionIndex)) - } - - private func cellForRow(_ row: OrangeConfigureCommandRow) -> UITableViewCell? { - guard let sectionIndex = sections.firstIndex(of: Section.orangeLinkCommands) else - { - return nil - } - return tableView.cellForRow(at: IndexPath(row: row.rawValue, section: sectionIndex)) - } - - private func cellForRow(_ row: OrangeLinkCommandRow) -> UITableViewCell? { - guard let sectionIndex = sections.firstIndex(of: Section.orangeLinkCommands) else - { - return nil - } - return tableView.cellForRow(at: IndexPath(row: row.rawValue, section: sectionIndex)) - } - - private func cellForRow(_ row: RileyLinkCommandRow) -> UITableViewCell? { - guard let sectionIndex = sections.firstIndex(of: Section.rileyLinkCommands) else - { - return nil - } - return tableView.cellForRow(at: IndexPath(row: row.rawValue, section: sectionIndex)) - } - - public override func numberOfSections(in tableView: UITableView) -> Int { - return sections.count - } - - public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - guard section < sections.count else { - return 0 - } - - switch sections[section] { - case .device: - return deviceRows.count - case .rileyLinkCommands: - return RileyLinkCommandRow.allCases.count - case .configureCommand: - return OrangeConfigureCommandRow.allCases.count - case .orangeLinkCommands: - let count = OrangeLinkCommandRow.allCases.count - return hasPiezo ? count : count-1 - case .alert: - return AlertRow.allCases.count - } - } - - @objc - func switchAction(sender: RileyLinkSwitch) { - switch sections[sender.section] { - case .orangeLinkCommands: - switch OrangeLinkCommandRow(rawValue: sender.index)! { - case .yellow: - if sender.isOn { - device.orangeAction(.yellow) - } else { - device.orangeAction(.off) - } - yellowOn = sender.isOn - redOn = false - case .red: - if sender.isOn { - device.orangeAction(.red) - } else { - device.orangeAction(.off) - } - yellowOn = false - redOn = sender.isOn - case .shake: - if sender.isOn { - device.orangeAction(.shake) - } else { - device.orangeAction(.shakeOff) - } - shakeOn = sender.isOn - default: - break - } - case .configureCommand: - switch OrangeConfigureCommandRow(rawValue: sender.index)! { - case .connectionLED: - device.setOrangeConfig(.connectionLED, isOn: sender.isOn) - ledOn = sender.isOn - case .connectionVibrate: - device.setOrangeConfig(.connectionVibrate, isOn: sender.isOn) - vibrationOn = sender.isOn - } - default: - break - } - tableView.reloadData() - } - - var yellowOn = false - var redOn = false - var shakeOn = false - private var ledOn: Bool = false - private var vibrationOn: Bool = false - var voltage: Float? - - public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell: RileyLinkCell - - if let reusableCell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier) as? RileyLinkCell { - cell = reusableCell - } else { - cell = RileyLinkCell(style: .value1, reuseIdentifier: CellIdentifier) - cell.switchView.addTarget(self, action: #selector(switchAction(sender:)), for: .valueChanged) - } - - let switchView = cell.switchView - switchView.isHidden = true - switchView.index = indexPath.row - switchView.section = indexPath.section - - cell.accessoryType = .none - cell.detailTextLabel?.text = nil - - switch sections[indexPath.section] { - case .device: - switch deviceRows[indexPath.row] { - case .customName: - cell.textLabel?.text = LocalizedString("Name", comment: "The title of the cell showing device name") - cell.detailTextLabel?.text = device.name - cell.accessoryType = .disclosureIndicator - case .version: - cell.textLabel?.text = LocalizedString("Firmware", comment: "The title of the cell showing firmware version") - cell.detailTextLabel?.text = firmwareVersion - case .connection: - cell.textLabel?.text = LocalizedString("Connection State", comment: "The title of the cell showing BLE connection state") - cell.detailTextLabel?.text = device.peripheralState.description - case .rssi: - cell.textLabel?.text = LocalizedString("Signal Strength", comment: "The title of the cell showing BLE signal strength (RSSI)") - cell.setDetailRSSI(bleRSSI, formatter: integerFormatter) - case .uptime: - cell.textLabel?.text = LocalizedString("Uptime", comment: "The title of the cell showing uptime") - cell.setDetailAge(uptime) - case .frequency: - cell.textLabel?.text = LocalizedString("Frequency", comment: "The title of the cell showing current rileylink frequency") - cell.setDetailFrequency(frequency, formatter: frequencyFormatter) - case .battery: - cell.textLabel?.text = LocalizedString("Battery level", comment: "The title of the cell showing battery level") - cell.setDetailBatteryLevel(battery) - case .voltage: - cell.textLabel?.text = LocalizedString("Voltage", comment: "The title of the cell showing ORL") - cell.setVoltage(voltage) - } - case .alert: - switch AlertRow(rawValue: indexPath.row)! { - case .battery: - cell.accessoryType = .disclosureIndicator - cell.textLabel?.text = LocalizedString("Low Battery Alert", comment: "The title of the cell showing battery level") - cell.setBatteryAlert(batteryAlertLevel, formatter: integerFormatter) - } - case .rileyLinkCommands: - switch RileyLinkCommandRow(rawValue: indexPath.row)! { - case .diagnosticLEDSMode: - cell.textLabel?.text = LocalizedString("Toggle Diagnostic LEDs", comment: "The title of the command to update diagnostic LEDs") - cell.setLEDMode(ledMode) - case .getStatistics: - cell.textLabel?.text = LocalizedString("Get RileyLink Statistics", comment: "The title of the command to fetch RileyLink statistics") - } - case .orangeLinkCommands: - cell.accessoryType = .disclosureIndicator - cell.detailTextLabel?.text = nil - - switch OrangeLinkCommandRow(rawValue: indexPath.row)! { - case .yellow: - switchView.isHidden = false - cell.accessoryType = .none - switchView.isOn = yellowOn - cell.textLabel?.text = LocalizedString("Lighten Yellow LED", comment: "The title of the cell showing Lighten Yellow LED") - case .red: - switchView.isHidden = false - cell.accessoryType = .none - switchView.isOn = redOn - cell.textLabel?.text = LocalizedString("Lighten Red LED", comment: "The title of the cell showing Lighten Red LED") - case .shake: - switchView.isHidden = false - switchView.isOn = shakeOn - cell.accessoryType = .none - cell.textLabel?.text = LocalizedString("Test Vibration", comment: "The title of the cell showing Test Vibration") - case .findDevice: - cell.textLabel?.text = LocalizedString("Find Device", comment: "The title of the cell for sounding device finding piezo") - cell.detailTextLabel?.text = nil - } - case .configureCommand: - switch OrangeConfigureCommandRow(rawValue: indexPath.row)! { - case .connectionLED: - switchView.isHidden = false - switchView.isOn = ledOn - cell.accessoryType = .none - cell.textLabel?.text = LocalizedString("Connection LED", comment: "The title of the cell for connection LED") - case .connectionVibrate: - switchView.isHidden = false - switchView.isOn = vibrationOn - cell.accessoryType = .none - cell.textLabel?.text = LocalizedString("Connection Vibration", comment: "The title of the cell for connection vibration") - } - } - - return cell - } - - public override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - switch sections[section] { - case .device: - return LocalizedString("Device", comment: "The title of the section describing the device") - case .rileyLinkCommands: - return LocalizedString("Test Commands", comment: "The title of the section for rileylink commands") - case .orangeLinkCommands: - return LocalizedString("Test Commands", comment: "The title of the section for orangelink commands") - case .configureCommand: - return LocalizedString("Connection Monitoring", comment: "The title of the section for connection monitoring") - case .alert: - return LocalizedString("Alert", comment: "The title of the section for alerts") - } - } - - // MARK: - UITableViewDelegate - - public override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { - switch sections[indexPath.section] { - case .device: - switch deviceRows[indexPath.row] { - case .customName: - return true - default: - return false - } - case .configureCommand: - return false - case .orangeLinkCommands: - switch OrangeLinkCommandRow(rawValue: indexPath.row)! { - case .findDevice: - return true - default: - return false - } - case .rileyLinkCommands: - return device.isConnected - case .alert: - return true - } - } - - public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - switch sections[indexPath.section] { - case .device: - switch deviceRows[indexPath.row] { - case .customName: - let vc = TextFieldTableViewController() - if let cell = tableView.cellForRow(at: indexPath) { - vc.title = cell.textLabel?.text - vc.value = device.name - vc.delegate = self - vc.keyboardType = .default - } - - show(vc, sender: indexPath) - default: - break - } - case .rileyLinkCommands: - var vc: CommandResponseViewController? - - switch RileyLinkCommandRow(rawValue: indexPath.row)! { - case .diagnosticLEDSMode: - let nextMode: RileyLinkLEDMode - switch ledMode { - case.on: - nextMode = .off - default: - nextMode = .on - } - vc = .setDiagnosticLEDMode(device: device, mode: nextMode) - case .getStatistics: - vc = .getStatistics(device: device) - } - if let cell = tableView.cellForRow(at: indexPath) { - vc?.title = cell.textLabel?.text - } - - if let vc = vc { - show(vc, sender: indexPath) - } - - case .orangeLinkCommands: - switch OrangeLinkCommandRow(rawValue: indexPath.row)! { - case .findDevice: - device.findDevice() - tableView.deselectRow(at: indexPath, animated: true) - default: - break - } - case .configureCommand: - break - case .alert: - switch AlertRow(rawValue: indexPath.row)! { - case .battery: - let alert = UIAlertController.init(title: "Battery level Alert", message: nil, preferredStyle: .actionSheet) - let action = UIAlertAction.init(title: "OFF", style: .default) { _ in - self.batteryAlertLevel = nil - self.tableView.reloadData() - } - alert.addAction(action) - - for value in [20,30,40,50] { - let action = UIAlertAction.init(title: "\(value)%", style: .default) { _ in - self.batteryAlertLevel = value - self.tableView.reloadData() - } - alert.addAction(action) - } - present(alert, animated: true, completion: nil) - } - } - } -} - - -extension RileyLinkDeviceTableViewController: TextFieldTableViewControllerDelegate { - public func textFieldTableViewControllerDidReturn(_ controller: TextFieldTableViewController) { - _ = navigationController?.popViewController(animated: true) - } - - public func textFieldTableViewControllerDidEndEditing(_ controller: TextFieldTableViewController) { - if let indexPath = tableView.indexPathForSelectedRow { - switch sections[indexPath.section] { - case .device: - switch deviceRows[indexPath.row] { - case .customName: - device.setCustomName(controller.value!) - default: - break - } - default: - break - } - } - } -} - -private extension TimeInterval { - func format(using units: NSCalendar.Unit) -> String? { - let formatter = DateComponentsFormatter() - formatter.allowedUnits = units - formatter.unitsStyle = .full - formatter.zeroFormattingBehavior = .dropLeading - formatter.maximumUnitCount = 2 - - return formatter.string(from: self) - } -} - -private extension UITableViewCell { - func setDetailDate(_ date: Date?, formatter: DateFormatter) { - if let date = date { - detailTextLabel?.text = formatter.string(from: date) - } else { - detailTextLabel?.text = "-" - } - } - - func setDetailRSSI(_ decibles: Int?, formatter: NumberFormatter) { - detailTextLabel?.text = formatter.decibleString(from: decibles) ?? "-" - } - - func setDetailAge(_ age: TimeInterval?) { - if let age = age { - detailTextLabel?.text = age.format(using: [.day, .hour, .minute]) - } else { - detailTextLabel?.text = "" - } - } - - func setDetailBatteryLevel(_ batteryLevel: Int?) { - if let batteryLevel = batteryLevel { - detailTextLabel?.text = "\(batteryLevel)" + " %" - } else { - detailTextLabel?.text = "" - } - } - - func setDetailFrequency(_ frequency: Measurement?, formatter: MeasurementFormatter) { - if let frequency = frequency { - detailTextLabel?.text = formatter.string(from: frequency) - } else { - detailTextLabel?.text = "" - } - } - - func setLEDMode(_ mode: RileyLinkLEDMode?) { - switch mode { - case .on: - detailTextLabel?.text = LocalizedString("On", comment: "Text indicating LED Mode is on") - case .off: - detailTextLabel?.text = LocalizedString("Off", comment: "Text indicating LED Mode is off") - case .auto: - detailTextLabel?.text = LocalizedString("Auto", comment: "Text indicating LED Mode is auto") - case .none: - detailTextLabel?.text = "" - } - } - - func setVoltage(_ voltage: Float?) { - if let voltage = voltage { - detailTextLabel?.text = String(format: "%.1f%", voltage) - } else { - detailTextLabel?.text = "" - } - } - - func setBatteryAlert(_ level: Int?, formatter: NumberFormatter) { - detailTextLabel?.text = formatter.percentString(from: level) ?? LocalizedString("Off", comment: "Detail text when battery alert disabled.") - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkDevicesHeaderView.swift b/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkDevicesHeaderView.swift deleted file mode 100644 index 17e61b9bd..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkDevicesHeaderView.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// RileyLinkDevicesHeaderView.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit - -public class RileyLinkDevicesHeaderView: UITableViewHeaderFooterView, IdentifiableClass { - - override public init(reuseIdentifier: String?) { - super.init(reuseIdentifier: reuseIdentifier) - - setup() - } - - required public init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - - setup() - } - - public let spinner = UIActivityIndicatorView(style: .default) - - private func setup() { - contentView.addSubview(spinner) - spinner.startAnimating() - } - - override public func layoutSubviews() { - super.layoutSubviews() - - spinner.center.y = textLabel?.center.y ?? 0 - spinner.frame.origin.x = contentView.bounds.size.width - contentView.directionalLayoutMargins.trailing - spinner.frame.size.width - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkDevicesTableViewDataSource.swift b/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkDevicesTableViewDataSource.swift deleted file mode 100644 index 13948a2fa..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkDevicesTableViewDataSource.swift +++ /dev/null @@ -1,212 +0,0 @@ -// -// RileyLinkDevicesTableViewDataSource.swift -// RileyLinkKitUI -// -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import UIKit -import CoreBluetooth -import RileyLinkBLEKit -import RileyLinkKit - - -public class RileyLinkDevicesTableViewDataSource: NSObject { - public let rileyLinkPumpManager: RileyLinkPumpManager - - public var devicesSectionIndex: Int - - public var tableView: UITableView! { - didSet { - tableView.register(RileyLinkDeviceTableViewCell.self, forCellReuseIdentifier: RileyLinkDeviceTableViewCell.className) - - tableView.register(RileyLinkDevicesHeaderView.self, forHeaderFooterViewReuseIdentifier: RileyLinkDevicesHeaderView.className) - - // Register for manager notifications - NotificationCenter.default.addObserver(self, selector: #selector(reloadDevices), name: .ManagerDevicesDidChange, object: rileyLinkPumpManager.rileyLinkDeviceProvider) - - // Register for device notifications - for name in [.DeviceConnectionStateDidChange, .DeviceRSSIDidChange, .DeviceNameDidChange] as [Notification.Name] { - NotificationCenter.default.addObserver(self, selector: #selector(deviceDidUpdate(_:)), name: name, object: nil) - } - - reloadDevices() - } - } - - public init(rileyLinkPumpManager: RileyLinkPumpManager, devicesSectionIndex: Int) { - self.rileyLinkPumpManager = rileyLinkPumpManager - self.devicesSectionIndex = devicesSectionIndex - super.init() - } - - // MARK: - - - lazy var decimalFormatter: NumberFormatter = { - let formatter = NumberFormatter() - - formatter.numberStyle = .decimal - formatter.minimumFractionDigits = 0 - formatter.maximumFractionDigits = 2 - - return formatter - }() - - public var isScanningEnabled: Bool = false { - didSet { - rileyLinkPumpManager.rileyLinkDeviceProvider.setScanningEnabled(isScanningEnabled) - - if isScanningEnabled { - rssiFetchTimer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(updateRSSI), userInfo: nil, repeats: true) - updateRSSI() - } else { - rssiFetchTimer = nil - } - } - } - - private(set) public var devices: [RileyLinkDevice] = [] { - didSet { - // Assume only appends are possible when count changes for algorithmic simplicity - guard oldValue.count < devices.count else { - tableView.reloadSections(IndexSet(integer: devicesSectionIndex), with: .fade) - return - } - - tableView.beginUpdates() - - - let insertedPaths = (oldValue.count.. IndexPath in - return IndexPath(row: index, section: devicesSectionIndex) - } - tableView.insertRows(at: insertedPaths, with: .automatic) - - tableView.endUpdates() - } - } - - /// Returns an adjusted peripheral state reflecting the user's auto-connect preference. - /// Peripherals connected to the system will show as disconnected if the user hasn't designated them - /// - /// - Parameter device: The peripheral - /// - Returns: The adjusted connection state - private func preferenceStateForDevice(_ device: RileyLinkDevice) -> CBPeripheralState? { - let isAutoConnectDevice = rileyLinkPumpManager.rileyLinkDeviceProvider.shouldConnect(to: device.peripheralIdentifier.uuidString) - var state = device.peripheralState - - switch state { - case .disconnected, .disconnecting: - break - case .connecting, .connected: - if !isAutoConnectDevice { - state = .disconnected - } - @unknown default: - break - } - - return state - } - - private var deviceRSSI: [UUID: Int] = [:] - - private var rssiFetchTimer: Timer? { - willSet { - rssiFetchTimer?.invalidate() - } - } - - @objc private func reloadDevices() { - rileyLinkPumpManager.rileyLinkDeviceProvider.getDevices { (devices) in - DispatchQueue.main.async { [weak self] in - self?.devices = devices - } - } - } - - @objc private func deviceDidUpdate(_ note: Notification) { - DispatchQueue.main.async { - if let device = note.object as? RileyLinkDevice, let index = self.devices.firstIndex(where: { $0.peripheralIdentifier == device.peripheralIdentifier }) { - if let rssi = note.userInfo?[RileyLinkBluetoothDevice.notificationRSSIKey] as? Int { - self.deviceRSSI[device.peripheralIdentifier] = rssi - } - - if let cell = self.tableView.cellForRow(at: IndexPath(row: index, section: self.devicesSectionIndex)) as? RileyLinkDeviceTableViewCell { - cell.configureCellWithName( - device.name, - signal: self.decimalFormatter.decibleString(from: self.deviceRSSI[device.peripheralIdentifier]), - peripheralState: self.preferenceStateForDevice(device) - ) - } - } - } - } - - @objc public func updateRSSI() { - for device in devices { - device.readRSSI() - } - } - - @objc private func deviceConnectionChanged(_ connectSwitch: UISwitch) { - let switchOrigin = connectSwitch.convert(CGPoint.zero, to: tableView) - - if let indexPath = tableView.indexPathForRow(at: switchOrigin), indexPath.section == devicesSectionIndex - { - let device = devices[indexPath.row] - - if connectSwitch.isOn { - rileyLinkPumpManager.connectToRileyLink(device) - } else { - rileyLinkPumpManager.disconnectFromRileyLink(device) - } - } - } -} - -extension RileyLinkDevicesTableViewDataSource: UITableViewDataSource { - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return devices.count - } - - public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let deviceCell = tableView.dequeueReusableCell(withIdentifier: RileyLinkDeviceTableViewCell.className) as! RileyLinkDeviceTableViewCell - let device = devices[indexPath.row] - - deviceCell.configureCellWithName( - device.name, - signal: decimalFormatter.decibleString(from: deviceRSSI[device.peripheralIdentifier]), - peripheralState: self.preferenceStateForDevice(device) - ) - - deviceCell.connectSwitch?.addTarget(self, action: #selector(deviceConnectionChanged(_:)), for: .valueChanged) - - return deviceCell - } - - public func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - return LocalizedString("Devices", comment: "The title of the devices table section in RileyLink settings") - } -} - -extension RileyLinkDevicesTableViewDataSource: UITableViewDelegate { - public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - return tableView.dequeueReusableHeaderFooterView(withIdentifier: RileyLinkDevicesHeaderView.className) - } - - public func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { - return 44 - } - - public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - return UITableView.automaticDimension - } - - public func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat { - return 55 - } - - public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return UITableView.automaticDimension - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.h b/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.h deleted file mode 100644 index 236c99f79..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// RileyLinkKitUI.h -// RileyLinkKitUI -// -// Copyright © 2017 Pete Schwamb. All rights reserved. -// - -#import - -//! Project version number for RileyLinkKitUI. -FOUNDATION_EXPORT double RileyLinkKitUIVersionNumber; - -//! Project version string for RileyLinkKitUI. -FOUNDATION_EXPORT const unsigned char RileyLinkKitUIVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.xcassets/Contents.json b/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.xcassets/Contents.json deleted file mode 100644 index da4a164c9..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.xcassets/RileyLink Tint.colorset/Contents.json b/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.xcassets/RileyLink Tint.colorset/Contents.json deleted file mode 100644 index bb0dcbefa..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.xcassets/RileyLink Tint.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - }, - "colors" : [ - { - "idiom" : "universal", - "color" : { - "color-space" : "srgb", - "components" : { - "red" : "0.345", - "alpha" : "1.000", - "blue" : "0.839", - "green" : "0.337" - } - } - } - ] -} \ No newline at end of file diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.xcassets/RileyLink.imageset/Contents.json b/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.xcassets/RileyLink.imageset/Contents.json deleted file mode 100644 index cfe31b855..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.xcassets/RileyLink.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "RileyLink.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template" - } -} \ No newline at end of file diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.xcassets/RileyLink.imageset/RileyLink.pdf b/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.xcassets/RileyLink.imageset/RileyLink.pdf deleted file mode 100644 index 69cc898de..000000000 Binary files a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkKitUI.xcassets/RileyLink.imageset/RileyLink.pdf and /dev/null differ diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkManagerSetupViewController.swift b/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkManagerSetupViewController.swift deleted file mode 100644 index afb58abc4..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkManagerSetupViewController.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// RileyLinkManagerSetupViewController.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit -import LoopKitUI -import RileyLinkKit - - -open class RileyLinkManagerSetupViewController: UINavigationController, PumpManagerOnboarding, UINavigationControllerDelegate, CompletionNotifying { - - open var maxBasalRateUnitsPerHour: Double? - - open var maxBolusUnits: Double? - - open var basalSchedule: BasalRateSchedule? - - open weak var pumpManagerOnboardingDelegate: PumpManagerOnboardingDelegate? - - open weak var completionDelegate: CompletionDelegate? - - open var rileyLinkPumpManager: RileyLinkPumpManager? - - open override func viewDidLoad() { - super.viewDidLoad() - - if #available(iOSApplicationExtension 13.0, *) { - // Prevent interactive dismissal - isModalInPresentation = true - } - - delegate = self - } - - open func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { - let viewControllers = navigationController.viewControllers - let count = navigationController.viewControllers.count - - if count >= 2, let setupViewController = viewControllers[count - 2] as? RileyLinkSetupTableViewController { - rileyLinkPumpManager = setupViewController.rileyLinkPumpManager - } - } - - open func finishedSetup() { - completionDelegate?.completionNotifyingDidComplete(self) - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkSettingsViewController.swift b/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkSettingsViewController.swift deleted file mode 100644 index 81c51dbee..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkSettingsViewController.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// RileyLinkSettingsViewController.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import CoreBluetooth -import RileyLinkBLEKit -import RileyLinkKit - - -open class RileyLinkSettingsViewController: UITableViewController { - - public let devicesDataSource: RileyLinkDevicesTableViewDataSource - - public init(rileyLinkPumpManager: RileyLinkPumpManager, devicesSectionIndex: Int, style: UITableView.Style) { - devicesDataSource = RileyLinkDevicesTableViewDataSource(rileyLinkPumpManager: rileyLinkPumpManager, devicesSectionIndex: devicesSectionIndex) - super.init(style: style) - } - - public required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override open func viewDidLoad() { - super.viewDidLoad() - - devicesDataSource.tableView = tableView - } - - override open func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - devicesDataSource.isScanningEnabled = true - } - - override open func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - - devicesDataSource.isScanningEnabled = false - } - - // MARK: - UITableViewDataSource - - override open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return devicesDataSource.tableView(tableView, numberOfRowsInSection: section) - } - - override open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - return devicesDataSource.tableView(tableView, cellForRowAt: indexPath) - } - - override open func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - return devicesDataSource.tableView(tableView, titleForHeaderInSection: section) - } - - // MARK: - UITableViewDelegate - - override open func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - return devicesDataSource.tableView(tableView, viewForHeaderInSection: section) - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkSetupTableViewController.swift b/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkSetupTableViewController.swift deleted file mode 100644 index a879bc476..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/RileyLinkSetupTableViewController.swift +++ /dev/null @@ -1,167 +0,0 @@ -// -// RileyLinkSetupTableViewController.swift -// Loop -// -// Copyright © 2018 LoopKit Authors. All rights reserved. -// - -import UIKit -import LoopKit -import LoopKitUI -import RileyLinkKit -import RileyLinkBLEKit - -public class RileyLinkSetupTableViewController: SetupTableViewController { - - let rileyLinkPumpManager: RileyLinkPumpManager - - private lazy var devicesDataSource: RileyLinkDevicesTableViewDataSource = { - return RileyLinkDevicesTableViewDataSource( - rileyLinkPumpManager: rileyLinkPumpManager, - devicesSectionIndex: Section.devices.rawValue - ) - }() - - public required init?(coder aDecoder: NSCoder) { - let deviceProvider = RileyLinkBluetoothDeviceProvider(autoConnectIDs: []) - rileyLinkPumpManager = RileyLinkPumpManager(rileyLinkDeviceProvider: deviceProvider) - super.init(coder: aDecoder) - } - - - public override func viewDidLoad() { - super.viewDidLoad() - - devicesDataSource.tableView = tableView - - tableView.register(SetupImageTableViewCell.nib(), forCellReuseIdentifier: SetupImageTableViewCell.className) - - NotificationCenter.default.addObserver(self, selector: #selector(deviceConnectionStateDidChange), name: .DeviceConnectionStateDidChange, object: nil) - - updateContinueButtonState() - } - - public override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - devicesDataSource.isScanningEnabled = true - } - - public override func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - - devicesDataSource.isScanningEnabled = false - } - - // MARK: - Table view data source - - private enum Section: Int { - case info - case devices - - static let count = 2 - } - - private enum InfoRow: Int { - case image - case description - - static let count = 2 - } - - public override func numberOfSections(in tableView: UITableView) -> Int { - return Section.count - } - - public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch Section(rawValue: section)! { - case .info: - return InfoRow.count - case .devices: - return devicesDataSource.tableView(tableView, numberOfRowsInSection: section) - } - } - - public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch Section(rawValue: indexPath.section)! { - case .info: - switch InfoRow(rawValue: indexPath.row)! { - case .image: - let cell = tableView.dequeueReusableCell(withIdentifier: SetupImageTableViewCell.className, for: indexPath) as! SetupImageTableViewCell - let bundle = Bundle(for: type(of: self)) - cell.mainImageView?.image = UIImage(named: "RileyLink", in: bundle, compatibleWith: cell.traitCollection) - cell.mainImageView?.tintColor = UIColor(named: "RileyLink Tint", in: bundle, compatibleWith: cell.traitCollection) - if #available(iOSApplicationExtension 13.0, *) { - cell.backgroundColor = .systemBackground - } - return cell - case .description: - var cell = tableView.dequeueReusableCell(withIdentifier: "DescriptionCell") - if cell == nil { - cell = UITableViewCell(style: .default, reuseIdentifier: "DescriptionCell") - cell?.selectionStyle = .none - cell?.textLabel?.text = LocalizedString("RileyLink allows for communication with the pump over Bluetooth Low Energy.", comment: "RileyLink setup description") - cell?.textLabel?.numberOfLines = 0 - - if #available(iOSApplicationExtension 13.0, *) { - cell?.backgroundColor = .systemBackground - } - } - return cell! - } - case .devices: - return devicesDataSource.tableView(tableView, cellForRowAt: indexPath) - } - } - - public override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - switch Section(rawValue: section)! { - case .info: - return nil - case .devices: - return devicesDataSource.tableView(tableView, titleForHeaderInSection: section) - } - } - - public override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - switch Section(rawValue: section)! { - case .info: - return nil - case .devices: - return devicesDataSource.tableView(tableView, viewForHeaderInSection: section) - } - } - - public override func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat { - return devicesDataSource.tableView(tableView, estimatedHeightForHeaderInSection: section) - } - - public override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { - return false - } - - // MARK: - Navigation - - private var shouldContinue: Bool { - #if targetEnvironment(simulator) - return true - #else - return rileyLinkPumpManager.rileyLinkDeviceProvider.connectingCount > 0 - #endif - } - - @objc private func deviceConnectionStateDidChange() { - DispatchQueue.main.async { - self.updateContinueButtonState() - } - } - - private func updateContinueButtonState() { - footerView.primaryButton.isEnabled = shouldContinue - } - - public override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { - return shouldContinue - } - -} diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/SetupImageTableViewCell.swift b/Dependencies/rileylink_ios/RileyLinkKitUI/SetupImageTableViewCell.swift deleted file mode 100644 index 33c20ad09..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/SetupImageTableViewCell.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// SetupImageTableViewCell.swift -// RileyLinkKitUI -// -// Copyright © 2018 Pete Schwamb. All rights reserved. -// - -import UIKit - -public class SetupImageTableViewCell: UITableViewCell, NibLoadable { - - @IBOutlet public var mainImageView: UIImageView? - -} diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/SetupImageTableViewCell.xib b/Dependencies/rileylink_ios/RileyLinkKitUI/SetupImageTableViewCell.xib deleted file mode 100644 index 6fff1b9aa..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/SetupImageTableViewCell.xib +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/UIActivityIndicatorView.swift b/Dependencies/rileylink_ios/RileyLinkKitUI/UIActivityIndicatorView.swift deleted file mode 100644 index d97a80735..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/UIActivityIndicatorView.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// UIActivityIndicatorView.swift -// LoopKitUI -// -// Copyright © 2019 LoopKit Authors. All rights reserved. -// - -import UIKit - - -extension UIActivityIndicatorView.Style { - static var `default`: UIActivityIndicatorView.Style { - if #available(iOSApplicationExtension 13.0, iOS 13.0, *) { - return .medium - } else { - return .gray - } - } -} diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/UITableViewCell.swift b/Dependencies/rileylink_ios/RileyLinkKitUI/UITableViewCell.swift deleted file mode 100644 index 269425371..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/UITableViewCell.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// UITableViewCell.swift -// CarbKit -// -// Created by Nathan Racklyeft on 1/15/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import UIKit - - -extension UITableViewCell: IdentifiableClass { -} diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/ar.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/ar.lproj/Localizable.strings deleted file mode 100644 index f74714bf3..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/ar.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Alert"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Auto"; - -/* The title of the cell showing battery level */ -"Battery level" = "Battery level"; - -/* The title of the section describing commands */ -"Commands" = "Commands"; - -/* The connected state */ -"Connected" = "Connected"; - -/* The in-progress connecting state */ -"Connecting" = "Connecting"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Connection LED"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Connection Monitoring"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Connection State"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Connection Vibration"; - -/* The title of the section describing the device */ -"Device" = "Device"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Devices"; - -/* The disconnected state */ -"Disconnected" = "Disconnected"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Disconnecting"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Find Device"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frequency"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Get RileyLink Statistics"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Get Statistics…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Lighten Red LED"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Lighten Yellow LED"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Low Battery Alert"; - -/* The title of the cell showing device name */ -"Name" = "Name"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Off"; - -/* Text indicating LED Mode is on */ -"On" = "On"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink allows for communication with the pump over Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Signal Strength"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Test Commands"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Test Vibration"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Toggle Diagnostic LEDs"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Updating diagnostic LEDs mode"; - -/* The title of the cell showing uptime */ -"Uptime" = "Uptime"; - -/* The title of the cell showing ORL */ -"Voltage" = "Voltage"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/ca.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/ca.lproj/Localizable.strings deleted file mode 100644 index f74714bf3..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/ca.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Alert"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Auto"; - -/* The title of the cell showing battery level */ -"Battery level" = "Battery level"; - -/* The title of the section describing commands */ -"Commands" = "Commands"; - -/* The connected state */ -"Connected" = "Connected"; - -/* The in-progress connecting state */ -"Connecting" = "Connecting"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Connection LED"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Connection Monitoring"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Connection State"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Connection Vibration"; - -/* The title of the section describing the device */ -"Device" = "Device"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Devices"; - -/* The disconnected state */ -"Disconnected" = "Disconnected"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Disconnecting"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Find Device"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frequency"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Get RileyLink Statistics"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Get Statistics…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Lighten Red LED"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Lighten Yellow LED"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Low Battery Alert"; - -/* The title of the cell showing device name */ -"Name" = "Name"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Off"; - -/* Text indicating LED Mode is on */ -"On" = "On"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink allows for communication with the pump over Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Signal Strength"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Test Commands"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Test Vibration"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Toggle Diagnostic LEDs"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Updating diagnostic LEDs mode"; - -/* The title of the cell showing uptime */ -"Uptime" = "Uptime"; - -/* The title of the cell showing ORL */ -"Voltage" = "Voltage"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/cs.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/cs.lproj/Localizable.strings deleted file mode 100644 index 764c32371..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/cs.lproj/Localizable.strings +++ /dev/null @@ -1,68 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@ %%"; - -/* The connected state */ -"Connected" = "Připojeno"; - -/* The in-progress connecting state */ -"Connecting" = "Připojuji"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frekvence"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Získat statistiky RileyLink"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Získávám statistiky…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Rozsvícení červené LED diody"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Rozsvícení žluté LED diody"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Upozornění na vybitou baterii"; - -/* The title of the cell showing device name */ -"Name" = "Název"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Vypnuto"; - -/* Text indicating LED Mode is on */ -"On" = "Zapnuto"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink umožňuje komunikaci s pumpou přes Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Síla signálu"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Testovací příkazy"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Vibrační test"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Přepínání diagnostických LED"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Aktualizace režimu diagnostických LED"; - -/* The title of the cell showing uptime */ -"Uptime" = "Doba provozu"; - -/* The title of the cell showing ORL */ -"Voltage" = "Napětí"; - diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/da.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/da.lproj/Localizable.strings deleted file mode 100644 index 00ebe40b2..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/da.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Advarsel"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Auto"; - -/* The title of the cell showing battery level */ -"Battery level" = "Batteriniveau"; - -/* The title of the section describing commands */ -"Commands" = "Kommandoer"; - -/* The connected state */ -"Connected" = "Tilsluttet"; - -/* The in-progress connecting state */ -"Connecting" = "Tilslutter"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Forbindelse-LED"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Forbindelsesovervågning"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Tilslutningstilstand"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Vibration ved forbindelse"; - -/* The title of the section describing the device */ -"Device" = "Enhed"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Enheder"; - -/* The disconnected state */ -"Disconnected" = "Frakoblet"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Frakobler"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Find enhed"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frekvens"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Hent RileyLink statistik..."; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Hent statistik..."; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Tænd rød LED"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Tænd gul LED"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Advarsel for lavt batteri"; - -/* The title of the cell showing device name */ -"Name" = "Navn"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Slukket"; - -/* Text indicating LED Mode is on */ -"On" = "Tændt"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink tillader kommunikation med pumpen via Bluetooth Lav Energi (BLE)"; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Signalstyrke"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Test-kommandoer"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Test vibration"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Skift diagnostiserings-LED'er"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Opdaterer diagnoserings-LED’er"; - -/* The title of the cell showing uptime */ -"Uptime" = "Oppetid"; - -/* The title of the cell showing ORL */ -"Voltage" = "Spænding"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/de.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/de.lproj/Localizable.strings deleted file mode 100644 index 5c3aba063..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/de.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Alarm"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Automatisch"; - -/* The title of the cell showing battery level */ -"Battery level" = "Batteriefüllung"; - -/* The title of the section describing commands */ -"Commands" = "Befehle"; - -/* The connected state */ -"Connected" = "Verbunden"; - -/* The in-progress connecting state */ -"Connecting" = "Verbinden"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Verbindungs LED"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Verbindungsüberwachung"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Verbindungsstatus"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Verbindungsvibration"; - -/* The title of the section describing the device */ -"Device" = "Gerät"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Geräte"; - -/* The disconnected state */ -"Disconnected" = "Getrennt"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "trennen"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Gerät finden"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frequenz"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Lade RileyLink Statistiken"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Lade Statistiken…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "rote LED leuchtet"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "gelbe LED leuchtet"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Niedrige Batterie-Warnung"; - -/* The title of the cell showing device name */ -"Name" = "Name"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Aus"; - -/* Text indicating LED Mode is on */ -"On" = "An"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink ermöglicht Kommunikation zur Pumpe über Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Signalstärke"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Test Befehle"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Vibrationstest"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Diagnose LED umschalten"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Ändere Diagnostik LED Modus"; - -/* The title of the cell showing uptime */ -"Uptime" = "Betriebszeit"; - -/* The title of the cell showing ORL */ -"Voltage" = "Spannung"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/en.lproj/InfoPlist.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/en.lproj/InfoPlist.strings deleted file mode 100644 index bbcf8f904..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/en.lproj/InfoPlist.strings +++ /dev/null @@ -1,3 +0,0 @@ -/* Bundle name */ -"CFBundleName" = "$(PRODUCT_NAME)"; - diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/es.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/es.lproj/Localizable.strings deleted file mode 100644 index 9e7e169df..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/es.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Alerta"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Automático"; - -/* The title of the cell showing battery level */ -"Battery level" = "Nivel de bateria"; - -/* The title of the section describing commands */ -"Commands" = "Comandos"; - -/* The connected state */ -"Connected" = "Conectado"; - -/* The in-progress connecting state */ -"Connecting" = "Conectando"; - -/* The title of the cell for connection LED */ -"Connection LED" = "LED Conexión"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Supervisión De conexiones"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Estado de Conexión"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Conexión Vibración"; - -/* The title of the section describing the device */ -"Device" = "Dispositivo"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Dispositivos"; - -/* The disconnected state */ -"Disconnected" = "Desconectado"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Desconectando"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Encontrar Dispositivo"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frequencia"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Obtener Estadísticas de RileyLink"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Obtener Estadísticas…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Aclarar el LED rojo"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Aclarar LED amarillo"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Alerta de Batería Baja"; - -/* The title of the cell showing device name */ -"Name" = "Nombre"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Apagado"; - -/* Text indicating LED Mode is on */ -"On" = "Encendido"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink permite la comunicación con la microinfusora a través del uso de Bluetooth de baja energía."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Intensidad de señal"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Prueba de Comandos"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Prueba de Vibración"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Pasar diagnóstico LEDs"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Actualización del modo LED de diagnóstico"; - -/* The title of the cell showing uptime */ -"Uptime" = "Uptime"; - -/* The title of the cell showing ORL */ -"Voltage" = "Voltaje"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/fi.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/fi.lproj/Localizable.strings deleted file mode 100644 index 36f2f2dea..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/fi.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Alert"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Auto"; - -/* The title of the cell showing battery level */ -"Battery level" = "Battery level"; - -/* The title of the section describing commands */ -"Commands" = "Komennot"; - -/* The connected state */ -"Connected" = "Yhdistetty"; - -/* The in-progress connecting state */ -"Connecting" = "Yhdistetään"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Connection LED"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Connection Monitoring"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Yhteyden tila"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Connection Vibration"; - -/* The title of the section describing the device */ -"Device" = "Laite"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Laitteet"; - -/* The disconnected state */ -"Disconnected" = "Ei yhteydessä"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Katkaistaan"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Etsi laite"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Laiteohjelmisto"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Taajuus"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Get RileyLink Statistics"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Hae tilastotiedot…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Lighten Red LED"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Lighten Yellow LED"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Low Battery Alert"; - -/* The title of the cell showing device name */ -"Name" = "Nimi"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Pois päältä"; - -/* Text indicating LED Mode is on */ -"On" = "Päällä"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink mahdollistaa tiedonsiirron pumpun kanssa Bluetooth Low Energy -yhteyden kautta."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Signaalin vahvuus"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Test Commands"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Test Vibration"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Toggle Diagnostic LEDs"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Updating diagnostic LEDs mode"; - -/* The title of the cell showing uptime */ -"Uptime" = "Päällä"; - -/* The title of the cell showing ORL */ -"Voltage" = "Voltage"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/fr.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/fr.lproj/Localizable.strings deleted file mode 100644 index 30a839d7c..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/fr.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Alerte"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Auto"; - -/* The title of the cell showing battery level */ -"Battery level" = "Niveau de la batterie"; - -/* The title of the section describing commands */ -"Commands" = "Commandes"; - -/* The connected state */ -"Connected" = "Connecté"; - -/* The in-progress connecting state */ -"Connecting" = "Connexion en cours"; - -/* The title of the cell for connection LED */ -"Connection LED" = "DEL de connexion"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Surveillance de la connexion"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "État de connexion"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Vibration lors de la connexion"; - -/* The title of the section describing the device */ -"Device" = "Dispositif"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Dispositifs"; - -/* The disconnected state */ -"Disconnected" = "Déconnecté"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Déconnexion en cours"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Découvrir dispositif"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Microprogramme"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Fréquence"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Obtenir les statistiques du RileyLink"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Obtenir les statistiques…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Réduire l'intensité de la DEL rouge"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Réduire l'intensité de la DEL jaune"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Alerte bas niveau de batterie"; - -/* The title of the cell showing device name */ -"Name" = "Nom"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Désactivé"; - -/* Text indicating LED Mode is on */ -"On" = "Activé"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink permet la communication avec la pompe via Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Intensité du signal"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Tester les commandes"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Tester la vibration"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Basculer DEL diagnostique"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Mise à jour du mode de DEL diagnostique"; - -/* The title of the cell showing uptime */ -"Uptime" = "Temps fonctionnement"; - -/* The title of the cell showing ORL */ -"Voltage" = "Voltage"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/he.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/he.lproj/Localizable.strings deleted file mode 100644 index 3135ac294..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/he.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "התראה"; - -/* Text indicating LED Mode is auto */ -"Auto" = "אוטומטי"; - -/* The title of the cell showing battery level */ -"Battery level" = "מצב הסוללה"; - -/* The title of the section describing commands */ -"Commands" = "פקודות"; - -/* The connected state */ -"Connected" = "מחובר"; - -/* The in-progress connecting state */ -"Connecting" = "מתחבר"; - -/* The title of the cell for connection LED */ -"Connection LED" = "נורית חיבור"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Connection Monitoring"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "מצב החיבור"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "רטט חיבור"; - -/* The title of the section describing the device */ -"Device" = "Device"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Devices"; - -/* The disconnected state */ -"Disconnected" = "מנותק"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "מתנתק"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Find Device"; - -/* The title of the cell showing firmware version */ -"Firmware" = "קושחה"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frequency"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Get RileyLink Statistics"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Get Statistics…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "הבהב נורית אדומה"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "הבהב נורית צהובה"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "התראת סוללה נמוכה"; - -/* The title of the cell showing device name */ -"Name" = "Name"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "כבוי"; - -/* Text indicating LED Mode is on */ -"On" = "דולק"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "ריילי לינק מאפשר תקשורת עם המשאבה באמצעות בלוטוס' באנרגיה נמוכה (BLE)."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "עוצמת אות"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "בדוק פקודות"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "בדוק רטט"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Toggle Diagnostic LEDs"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Updating diagnostic LEDs mode"; - -/* The title of the cell showing uptime */ -"Uptime" = "Uptime"; - -/* The title of the cell showing ORL */ -"Voltage" = "מתח"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/hi.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/hi.lproj/Localizable.strings deleted file mode 100644 index da0563a0b..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/hi.lproj/Localizable.strings +++ /dev/null @@ -1,9 +0,0 @@ -/* The connected state */ -"Connected" = "कनेक्ट हो गया"; - -/* The in-progress connecting state */ -"Connecting" = "कनेक्ट हो रहा है"; - -/* The title of the cell showing device name */ -"Name" = "नाम"; - diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/hu.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/hu.lproj/Localizable.strings deleted file mode 100644 index ca01e606f..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/hu.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Alert"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Auto"; - -/* The title of the cell showing battery level */ -"Battery level" = "Battery level"; - -/* The title of the section describing commands */ -"Commands" = "Commands"; - -/* The connected state */ -"Connected" = "Connected"; - -/* The in-progress connecting state */ -"Connecting" = "Connecting"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Connection LED"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Connection Monitoring"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Kapcsolat állapota"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Connection Vibration"; - -/* The title of the section describing the device */ -"Device" = "Device"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Eszközök"; - -/* The disconnected state */ -"Disconnected" = "Disconnected"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Disconnecting"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Find Device"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frequency"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Get RileyLink Statistics"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Get Statistics…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Lighten Red LED"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Lighten Yellow LED"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Low Battery Alert"; - -/* The title of the cell showing device name */ -"Name" = "Megnevezés"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Off"; - -/* Text indicating LED Mode is on */ -"On" = "On"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink allows for communication with the pump over Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Signal Strength"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Test Commands"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Test Vibration"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Toggle Diagnostic LEDs"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Updating diagnostic LEDs mode"; - -/* The title of the cell showing uptime */ -"Uptime" = "Uptime"; - -/* The title of the cell showing ORL */ -"Voltage" = "Voltage"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/it.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/it.lproj/Localizable.strings deleted file mode 100644 index 171306d1d..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/it.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@ %%"; - -/* The title of the section for alerts */ -"Alert" = "Avviso"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Auto"; - -/* The title of the cell showing battery level */ -"Battery level" = "Livello Batteria"; - -/* The title of the section describing commands */ -"Commands" = "Comandi"; - -/* The connected state */ -"Connected" = "Connesso"; - -/* The in-progress connecting state */ -"Connecting" = "In fase di Connessione"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Led di connessione"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Monitoraggio della connessione"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Stato Connessione"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Vibrazioni di connessione"; - -/* The title of the section describing the device */ -"Device" = "Dispositivo"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Dispositivi"; - -/* The disconnected state */ -"Disconnected" = "Disconnesso"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Disconnessione"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Trova Dispositivo"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frequenza"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Ottieni Statistiche RileyLink"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Ottieni Statistiche..."; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Accensione LED Rosso"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Accensione LED Giallo"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Avviso Livello Batteria Basso"; - -/* The title of the cell showing device name */ -"Name" = "Nome"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Spento"; - -/* Text indicating LED Mode is on */ -"On" = "Acceso"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink consente la comunicazione con il microinfusore tramite Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Potenza segnale"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Prova Comandi"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Vibrazione di prova"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Attiva/disattiva LED diagnostici"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Aggiornamento modalità LED diagnostici"; - -/* The title of the cell showing uptime */ -"Uptime" = "Tempo attività"; - -/* The title of the cell showing ORL */ -"Voltage" = "Voltaggio"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/ja.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/ja.lproj/Localizable.strings deleted file mode 100644 index 1b0a572a4..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/ja.lproj/Localizable.strings +++ /dev/null @@ -1,54 +0,0 @@ -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section describing commands */ -"Commands" = "コマンド"; - -/* The connected state */ -"Connected" = "接続済み"; - -/* The in-progress connecting state */ -"Connecting" = "接続しています"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "接続状態"; - -/* The title of the section describing the device */ -"Device" = "デバイス"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "デバイス"; - -/* The disconnected state */ -"Disconnected" = "無接続"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "接続を切っています"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "デバイスを探す"; - -/* The title of the cell showing firmware version */ -"Firmware" = "ファームウェア"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frequency"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "統計を取得…"; - -/* The title of the cell showing device name */ -"Name" = "プリセット名"; - -/* Text indicating LED Mode is on */ -"On" = "オン"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink は Bluetooth Low Energy を通してポンプと通信します。"; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "シグナル強度"; - -/* The title of the cell showing uptime */ -"Uptime" = "アップタイム"; - diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/nb.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/nb.lproj/Localizable.strings deleted file mode 100644 index 8fd3e8c67..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/nb.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Varsel"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Auto"; - -/* The title of the cell showing battery level */ -"Battery level" = "Batterinivå"; - -/* The title of the section describing commands */ -"Commands" = "Kommandoer"; - -/* The connected state */ -"Connected" = "Tilkoblet"; - -/* The in-progress connecting state */ -"Connecting" = "Kobler til"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Lysdiode for tilkobling"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Overvåking av tilkobling"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Tilkoblingsstatus"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Tilkoblingsvibrasjon"; - -/* The title of the section describing the device */ -"Device" = "Enhet"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Enheter"; - -/* The disconnected state */ -"Disconnected" = "Frakoblet"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Kobler fra"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Finn enhet"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Fastvare"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frekvens"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Vis Rileylink statistikk"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Henter statistikk…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Øke rødt LED"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Øke gult LED"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Varsel om lavt batterinivå"; - -/* The title of the cell showing device name */ -"Name" = "Navn"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Av"; - -/* Text indicating LED Mode is on */ -"On" = "På"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink tillater kommunikasjon med pumpen over Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Signalstyrke"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Testkommandoer"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Test Vibrering"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Slå av/på diagnoselysdioder"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Oppdaterer innstillinger for diagnoselysdioder"; - -/* The title of the cell showing uptime */ -"Uptime" = "Oppetid"; - -/* The title of the cell showing ORL */ -"Voltage" = "Spenning (V)"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/nl.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/nl.lproj/Localizable.strings deleted file mode 100644 index 5bac2f264..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/nl.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Alarm"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Automatisch"; - -/* The title of the cell showing battery level */ -"Battery level" = "Batterijniveau"; - -/* The title of the section describing commands */ -"Commands" = "Commando's"; - -/* The connected state */ -"Connected" = "Verbonden"; - -/* The in-progress connecting state */ -"Connecting" = "Bezig met verbinden"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Verbindings-LED"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Controle van de verbinding"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Verbindingsstatus"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Verbinding vibraties"; - -/* The title of the section describing the device */ -"Device" = "Apparaat"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Apparaten"; - -/* The disconnected state */ -"Disconnected" = "Ontkoppeld"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Ontkoppelen"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Zoek apparaat"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frequentie"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "RileyLink statistieken ophalen"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Statistieken ophalen..."; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Rode LED verlichten"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Gele LED verlichten"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Alarm: batterij bijna leeg"; - -/* The title of the cell showing device name */ -"Name" = "Naam"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Uit"; - -/* Text indicating LED Mode is on */ -"On" = "Aan"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink staat verbinding met de pomp toe via Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Signaalsterkte"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Commando's testen"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Test vibraties"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Schakelen tussen diagnostische LED's"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Diagnostische LED-modus aan het bijstellen"; - -/* The title of the cell showing uptime */ -"Uptime" = "Tijd"; - -/* The title of the cell showing ORL */ -"Voltage" = "Voltage"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/pl.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/pl.lproj/Localizable.strings deleted file mode 100644 index 425318e47..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/pl.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Alarm"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Automatyczny"; - -/* The title of the cell showing battery level */ -"Battery level" = "Poziom naładowania baterii"; - -/* The title of the section describing commands */ -"Commands" = "Komendy"; - -/* The connected state */ -"Connected" = "Połączono"; - -/* The in-progress connecting state */ -"Connecting" = "Łączenie"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Włącz LED, gdy połączono"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Monitorowanie połączenia"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Status połączenia"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Wibruj, gdy połączono"; - -/* The title of the section describing the device */ -"Device" = "Urządzenie"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Urządzenia"; - -/* The disconnected state */ -"Disconnected" = "Rozłączony"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Rozłączanie"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Znajdź urządzenie"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Oprogramowanie"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frequency"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Statystyki RileyLink"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Pobieranie statystyk…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Włącz czerwoną diodę LED"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Włącz żółtą diodę LED"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Ostrzeżenie o niskim stanie baterii"; - -/* The title of the cell showing device name */ -"Name" = "Nazwa"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Wyłącz"; - -/* Text indicating LED Mode is on */ -"On" = "Włącz"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink będzie łączył się z pompą poprzez Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Siła sygnału"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Polecenia testowe"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Testuj wibracje"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Przełącz diagnostyczne diody LED"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Aktualizacja trybu diod diagnostycznych"; - -/* The title of the cell showing uptime */ -"Uptime" = "Uptime"; - -/* The title of the cell showing ORL */ -"Voltage" = "Napięcie"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/pt-BR.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/pt-BR.lproj/Localizable.strings deleted file mode 100644 index 6e7c4703b..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/pt-BR.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Alert"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Auto"; - -/* The title of the cell showing battery level */ -"Battery level" = "Battery level"; - -/* The title of the section describing commands */ -"Commands" = "Comandos"; - -/* The connected state */ -"Connected" = "Conectado"; - -/* The in-progress connecting state */ -"Connecting" = "Conectando"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Connection LED"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Connection Monitoring"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Estado da Conexão"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Connection Vibration"; - -/* The title of the section describing the device */ -"Device" = "Dispositivo"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Dispositivos"; - -/* The disconnected state */ -"Disconnected" = "Desconectado"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Desconectando"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Localizar Dispositivo"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frequência"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Get RileyLink Statistics"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Extrair Estatísticas…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Lighten Red LED"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Lighten Yellow LED"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Low Battery Alert"; - -/* The title of the cell showing device name */ -"Name" = "Nome"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Off"; - -/* Text indicating LED Mode is on */ -"On" = "Ligado"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "O RileyLink permite a comunicação com a bomba por Bluetooth de Baixa Energia."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Potência do Sinal"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Test Commands"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Test Vibration"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Toggle Diagnostic LEDs"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Updating diagnostic LEDs mode"; - -/* The title of the cell showing uptime */ -"Uptime" = "Tempo de Atividade"; - -/* The title of the cell showing ORL */ -"Voltage" = "Voltage"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/pt-PT.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/pt-PT.lproj/Localizable.strings deleted file mode 100644 index 6b26da574..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/pt-PT.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Alert"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Auto"; - -/* The title of the cell showing battery level */ -"Battery level" = "Battery level"; - -/* The title of the section describing commands */ -"Commands" = "Commands"; - -/* The connected state */ -"Connected" = "Connected"; - -/* The in-progress connecting state */ -"Connecting" = "Connecting"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Connection LED"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Connection Monitoring"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Connection State"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Connection Vibration"; - -/* The title of the section describing the device */ -"Device" = "Device"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Dispositivos"; - -/* The disconnected state */ -"Disconnected" = "Disconnected"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Disconnecting"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Find Device"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frequency"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Get RileyLink Statistics"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Get Statistics…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Lighten Red LED"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Lighten Yellow LED"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Low Battery Alert"; - -/* The title of the cell showing device name */ -"Name" = "Nome"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Off"; - -/* Text indicating LED Mode is on */ -"On" = "On"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink allows for communication with the pump over Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Signal Strength"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Test Commands"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Test Vibration"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Toggle Diagnostic LEDs"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Updating diagnostic LEDs mode"; - -/* The title of the cell showing uptime */ -"Uptime" = "Uptime"; - -/* The title of the cell showing ORL */ -"Voltage" = "Voltage"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/ro.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/ro.lproj/Localizable.strings deleted file mode 100644 index ceee95854..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/ro.lproj/Localizable.strings +++ /dev/null @@ -1,107 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Alertă"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Automat"; - -/* The title of the cell showing battery level */ -"Battery level" = "Nivelul bateriei"; - -/* The title of the section describing commands */ -"Commands" = "Comenzi"; - -/* The connected state */ -"Connected" = "Conectat"; - -/* The in-progress connecting state */ -"Connecting" = "Conectare"; - -/* The title of the cell for connection LED */ -"Connection LED" = "LED de conectare"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Monitorizarea conexiunii"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Stare conexiune"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Vibrare la conexiune"; - -/* The title of the section describing the device */ -"Device" = "Dispozitiv"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Dispozitive"; - -/* The disconnected state */ -"Disconnected" = "Deconectat"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Se deconectează"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Caută dispozitivul"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frecvență"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Obțineți statisticile despre RileyLink"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Obțineți statistici..."; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Aprindeți LED-ul roșu"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Aprindeți LED-ul galben"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Alertă baterie scăzută"; - -/* The title of the cell showing device name */ -"Name" = "Nume"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Oprit"; - -/* Text indicating LED Mode is on */ -"On" = "Pornit"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink facilitează conexiunea cu pompa prin intermediul Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Putere semnal"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Testați comenzile"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Testați vibrația"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Comutarea LED-urilor de diagnosticare"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Actualizarea modului de diagnostic al LED-urilor"; - -/* The title of the cell showing uptime */ -"Uptime" = "Durată de funcționare"; - -/* The title of the cell showing ORL */ -"Voltage" = "Voltaj"; - diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/ru.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/ru.lproj/Localizable.strings deleted file mode 100644 index 3a2ba2715..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/ru.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ дБ"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Оповещение"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Авто"; - -/* The title of the cell showing battery level */ -"Battery level" = "Уровень заряда"; - -/* The title of the section describing commands */ -"Commands" = "Команды"; - -/* The connected state */ -"Connected" = "Подключено"; - -/* The in-progress connecting state */ -"Connecting" = "Подключение"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Индикатор соединения"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Мониторинг соединения"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Состояние соединения"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Вибрация при разъединении"; - -/* The title of the section describing the device */ -"Device" = "Устройство"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Устройства"; - -/* The disconnected state */ -"Disconnected" = "Разъединено"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Разъединяется"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Найти устройство"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Прошивка"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Частота"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Получить статистику Rileylink"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Получить статистику…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Светло-красный светодиод"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Светло-желтый светодиод"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Низкий заряд"; - -/* The title of the cell showing device name */ -"Name" = "Имя"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Выключено"; - -/* Text indicating LED Mode is on */ -"On" = "Включено"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink позволяет вести коммуникацию с помпой через Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Уровень сигнала"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Команды для проверки"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Проверить вибрацию"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Переключить режим светодиодов"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Изменить режим светодиодов"; - -/* The title of the cell showing uptime */ -"Uptime" = "Время работы"; - -/* The title of the cell showing ORL */ -"Voltage" = "Напряжение"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/sk.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/sk.lproj/Localizable.strings deleted file mode 100644 index 53ea6cb89..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/sk.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@ %%"; - -/* The title of the section for alerts */ -"Alert" = "Upozornenie"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Automatická "; - -/* The title of the cell showing battery level */ -"Battery level" = "Stav batérie"; - -/* The title of the section describing commands */ -"Commands" = "Príkazy"; - -/* The connected state */ -"Connected" = "Pripojené"; - -/* The in-progress connecting state */ -"Connecting" = "Pripája sa"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Pripojenie LED"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Monitorovanie pripojenia"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Stav pripojenia"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Vibrácie pripojenia"; - -/* The title of the section describing the device */ -"Device" = "Zariadenie"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Zariadenia"; - -/* The disconnected state */ -"Disconnected" = "Odpojené"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Odpája sa"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Nájsť zariadenie"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmvér"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frekvencia"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Získať štatistiky RileyLinku"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Získať štatistiky…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Rozsvietiť červené LED "; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Rozsvietiť žlté LED"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Slabá batéria"; - -/* The title of the cell showing device name */ -"Name" = "Názov"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Vypnuté"; - -/* Text indicating LED Mode is on */ -"On" = "Zapnuté"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink umožňuje komunikáciu s pumpou cez Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Sila signálu"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Testovať príkazy"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Testovať vibrácie"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Prepnutie diagnostických LED diód"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Aktualizuje sa režim diagnostických LED diód"; - -/* The title of the cell showing uptime */ -"Uptime" = "Doba prevádzky"; - -/* The title of the cell showing ORL */ -"Voltage" = "Napätie"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/sv.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/sv.lproj/Localizable.strings deleted file mode 100644 index 9c955c646..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/sv.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Larm"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Auto"; - -/* The title of the cell showing battery level */ -"Battery level" = "Batterinivå"; - -/* The title of the section describing commands */ -"Commands" = "Kommandon"; - -/* The connected state */ -"Connected" = "Ansluten"; - -/* The in-progress connecting state */ -"Connecting" = "Ansluter"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Anslutnings-LED"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Anslutningsstatus"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Anslutningsstatus"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Anslutningsvibration"; - -/* The title of the section describing the device */ -"Device" = "Enhet"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Enheter"; - -/* The disconnected state */ -"Disconnected" = "Frånkopplad"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Kopplar från"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Hitta enhet"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Firmware"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frekvens"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Hämta RileyLink-statistik"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Hämtar statistik…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Ljusare röd LED"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Ljusare gul LED"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Låg batterinivå"; - -/* The title of the cell showing device name */ -"Name" = "Namn"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Av"; - -/* Text indicating LED Mode is on */ -"On" = "På"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink kommunicerar med pumpen via Bluetooth lågenergianslutning."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Signalstyrka"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Testkommandon"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Testa vibration"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Slå på diagnostiska LED"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Uppdaterar diagnostiska LED"; - -/* The title of the cell showing uptime */ -"Uptime" = "Körs sedan"; - -/* The title of the cell showing ORL */ -"Voltage" = "Spänning (V)"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/tr.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/tr.lproj/Localizable.strings deleted file mode 100644 index a2a4d97de..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/tr.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Uyarı"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Otomatik"; - -/* The title of the cell showing battery level */ -"Battery level" = "Pil seviyesi"; - -/* The title of the section describing commands */ -"Commands" = "Komutlar"; - -/* The connected state */ -"Connected" = "Bağlandı"; - -/* The in-progress connecting state */ -"Connecting" = "Bağlanıyor"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Bağlantı LED'i"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Bağlantı İzleme"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Bağlantı Durumu"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Bağlantı Titreşimi"; - -/* The title of the section describing the device */ -"Device" = "Cihaz"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Cihazlar"; - -/* The disconnected state */ -"Disconnected" = "Bağlantı kesildi"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Bağlantı kesiliyor"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Cihaz Bul"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Donanım yazılımı"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frekans"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "RileyLink İstatistiklerini Alın"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "İstatistik Alınıyor…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Kırmızı LED'i Yak"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Sarı LED'i Yak"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Düşük Pil Uyarısı"; - -/* The title of the cell showing device name */ -"Name" = "İsim"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Kapalı"; - -/* Text indicating LED Mode is on */ -"On" = "Açık"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink, Bluetooth Düşük Enerji üzerinden pompa ile iletişim kurulmasını sağlar."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Sinyal Gücü"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Komutları Test Et"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Titreşim Testi"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Teşhis LED'lerini Değiştirme"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Teşhis LED'leri modunu güncelleme"; - -/* The title of the cell showing uptime */ -"Uptime" = "Çalışma süresi"; - -/* The title of the cell showing ORL */ -"Voltage" = "Voltaj"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/uk.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/uk.lproj/Localizable.strings deleted file mode 100644 index fb768b93c..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/uk.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Сповіщення"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Авто"; - -/* The title of the cell showing battery level */ -"Battery level" = "Рівень заряду"; - -/* The title of the section describing commands */ -"Commands" = "Команди"; - -/* The connected state */ -"Connected" = "Під'єднаний"; - -/* The in-progress connecting state */ -"Connecting" = "Під'єднання"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Індикатор з’єднання"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Моніторинг з'єднання"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Стан з'єднання"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Вібрація при роз'єднанні"; - -/* The title of the section describing the device */ -"Device" = "Пристрій"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Пристрої"; - -/* The disconnected state */ -"Disconnected" = "Від’єднано"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Від'єднання"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Знайти пристрій"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Прошивка"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Частота"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Отримати статистику RileyLink"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Отримати статистику…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Засвітіть червоний світлодіод"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Засвітіть жовтий світлодіод"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Низький заряд"; - -/* The title of the cell showing device name */ -"Name" = "Ім’я"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Вимкнути"; - -/* Text indicating LED Mode is on */ -"On" = "Увімкнути"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink дозволяє зв'язуватися з помпою через Bluetooth Low Energy."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Рівень сигналу"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Перевірка команд"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Перевірка вібрації"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Перемкнути діагностичні світлодіоди"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Змінити режим світлодіодів"; - -/* The title of the cell showing uptime */ -"Uptime" = "Час роботи"; - -/* The title of the cell showing ORL */ -"Voltage" = "Напруга"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/vi.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/vi.lproj/Localizable.strings deleted file mode 100644 index cae429cca..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/vi.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Cảnh báo"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Tự động"; - -/* The title of the cell showing battery level */ -"Battery level" = "Mức pin"; - -/* The title of the section describing commands */ -"Commands" = "Các câu lệnh"; - -/* The connected state */ -"Connected" = "Đã kết nối"; - -/* The in-progress connecting state */ -"Connecting" = "Đang kết nối"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Đèn báo kết nối"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Giám sát kết nối"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "Tình trạng kết nối"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Báo rung khi kết nối"; - -/* The title of the section describing the device */ -"Device" = "Thiết bị"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "Thiết bị"; - -/* The disconnected state */ -"Disconnected" = "Đã ngắt kết nối"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "Đang ngắt kết nối"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "Tìm kiếm thiết bị"; - -/* The title of the cell showing firmware version */ -"Firmware" = "Chương trình cơ sở"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Tần số"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Các thống kê của RileyLink"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Lấy các thống kê…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Sáng đèn Đỏ"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Sáng đèn Vàng"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Cảnh báo pin yếu"; - -/* The title of the cell showing device name */ -"Name" = "Tên"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Tắt"; - -/* Text indicating LED Mode is on */ -"On" = "Bật"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "RileyLink cho phép giao tiếp với bơm thông qua chuẩn kết nối bluetooth năng lượng thấp."; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "Cường độ tín hiệu"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Thử nghiệm câu lệnh"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Thử nghiệm độ rung"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Cho phép chuẩn đoán LEDs"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Cập nhật chế độ đèn LED chẩn đoán"; - -/* The title of the cell showing uptime */ -"Uptime" = "Thời gian hoạt động"; - -/* The title of the cell showing ORL */ -"Voltage" = "Điện áp"; diff --git a/Dependencies/rileylink_ios/RileyLinkKitUI/zh-Hans.lproj/Localizable.strings b/Dependencies/rileylink_ios/RileyLinkKitUI/zh-Hans.lproj/Localizable.strings deleted file mode 100644 index 3a858dbc3..000000000 --- a/Dependencies/rileylink_ios/RileyLinkKitUI/zh-Hans.lproj/Localizable.strings +++ /dev/null @@ -1,106 +0,0 @@ -/* Unit format string for an RSSI value in decibles */ -"%@ dB" = "%@ dB"; - -/* Unit format string for an value in percent */ -"%@%%" = "%@%%"; - -/* The title of the section for alerts */ -"Alert" = "Alert"; - -/* Text indicating LED Mode is auto */ -"Auto" = "Auto"; - -/* The title of the cell showing battery level */ -"Battery level" = "Battery level"; - -/* The title of the section describing commands */ -"Commands" = "命令"; - -/* The connected state */ -"Connected" = "已连接"; - -/* The in-progress connecting state */ -"Connecting" = "正在连接"; - -/* The title of the cell for connection LED */ -"Connection LED" = "Connection LED"; - -/* The title of the section for connection monitoring */ -"Connection Monitoring" = "Connection Monitoring"; - -/* The title of the cell showing BLE connection state */ -"Connection State" = "连接状态"; - -/* The title of the cell for connection vibration */ -"Connection Vibration" = "Connection Vibration"; - -/* The title of the section describing the device */ -"Device" = "设备"; - -/* The title of the devices table section in RileyLink settings */ -"Devices" = "设备"; - -/* The disconnected state */ -"Disconnected" = "已断开连接"; - -/* The in-progress disconnecting state */ -"Disconnecting" = "断开"; - -/* The title of the cell for sounding device finding piezo */ -"Find Device" = "发现设备"; - -/* The title of the cell showing firmware version */ -"Firmware" = "固件"; - -/* The title of the cell showing current rileylink frequency */ -"Frequency" = "Frequency"; - -/* The title of the command to fetch RileyLink statistics */ -"Get RileyLink Statistics" = "Get RileyLink Statistics"; - -/* Progress message for getting statistics. */ -"Get Statistics…" = "Get Statistics…"; - -/* The title of the cell showing Lighten Red LED */ -"Lighten Red LED" = "Lighten Red LED"; - -/* The title of the cell showing Lighten Yellow LED */ -"Lighten Yellow LED" = "Lighten Yellow LED"; - -/* The title of the cell showing battery level */ -"Low Battery Alert" = "Low Battery Alert"; - -/* The title of the cell showing device name */ -"Name" = "设备名称"; - -/* Detail text when battery alert disabled. - Text indicating LED Mode is off */ -"Off" = "Off"; - -/* Text indicating LED Mode is on */ -"On" = "开"; - -/* RileyLink setup description */ -"RileyLink allows for communication with the pump over Bluetooth Low Energy." = "允许RileyLink通过低功耗蓝牙与泵连接通信"; - -/* The title of the cell showing BLE signal strength (RSSI) */ -"Signal Strength" = "信号强度"; - -/* The title of the section for orangelink commands - The title of the section for rileylink commands */ -"Test Commands" = "Test Commands"; - -/* The title of the cell showing Test Vibration */ -"Test Vibration" = "Test Vibration"; - -/* The title of the command to update diagnostic LEDs */ -"Toggle Diagnostic LEDs" = "Toggle Diagnostic LEDs"; - -/* Progress message for changing diagnostic LED mode */ -"Updating diagnostic LEDs mode" = "Updating diagnostic LEDs mode"; - -/* The title of the cell showing uptime */ -"Uptime" = "Uptime"; - -/* The title of the cell showing ORL */ -"Voltage" = "Voltage"; diff --git a/Dependencies/rileylink_ios/RileyLinkTests/RileyLinkTests-Info.plist b/Dependencies/rileylink_ios/RileyLinkTests/RileyLinkTests-Info.plist deleted file mode 100644 index b6c35c5c8..000000000 --- a/Dependencies/rileylink_ios/RileyLinkTests/RileyLinkTests-Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - BNDL - CFBundleShortVersionString - 2.2.0 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - - diff --git a/Dependencies/rileylink_ios/RileyLinkTests/RileyLinkTests.m b/Dependencies/rileylink_ios/RileyLinkTests/RileyLinkTests.m deleted file mode 100644 index 2f2573650..000000000 --- a/Dependencies/rileylink_ios/RileyLinkTests/RileyLinkTests.m +++ /dev/null @@ -1,29 +0,0 @@ -// -// RileyLinkTests.m -// RileyLinkTests -// -// Created by Pete Schwamb on 7/31/14. -// Copyright (c) 2014 Pete Schwamb. All rights reserved. -// - -#import - -@interface RileyLinkTests : XCTestCase - -@end - -@implementation RileyLinkTests - -- (void)setUp -{ - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown -{ - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -@end diff --git a/FreeAPS.xcodeproj/project.pbxproj b/FreeAPS.xcodeproj/project.pbxproj index 038ce58df..da687a2a0 100644 --- a/FreeAPS.xcodeproj/project.pbxproj +++ b/FreeAPS.xcodeproj/project.pbxproj @@ -59,7 +59,6 @@ 2BE9A6FA20875F6F4F9CD461 /* PumpSettingsEditorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D97F14812C1AFED3621165A5 /* PumpSettingsEditorProvider.swift */; }; 3083261C4B268E353F36CD0B /* AutotuneConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DCCCCE633F5E98E41B0CD3C /* AutotuneConfigDataFlow.swift */; }; 3171D2818C7C72CD1584BB5E /* NotificationsConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC2C6489D29ECCCAD78E0721 /* NotificationsConfigStateModel.swift */; }; - 320D030F724170A637F06D50 /* CalibrationsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 212E8BFE6D66EE65AA26A114 /* CalibrationsProvider.swift */; }; 33E198D3039045D98C3DC5D4 /* AddCarbsStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E7C997E56DAF8D28D09014 /* AddCarbsStateModel.swift */; }; 3811DE0B25C9D32F00A708ED /* BaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3811DE0725C9D32E00A708ED /* BaseView.swift */; }; 3811DE0C25C9D32F00A708ED /* BaseProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3811DE0825C9D32F00A708ED /* BaseProvider.swift */; }; @@ -97,25 +96,6 @@ 3811DEEB25CA063400A708ED /* PersistedProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3811DEE725CA063400A708ED /* PersistedProperty.swift */; }; 3811DF0225CA9FEA00A708ED /* Credentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3811DF0125CA9FEA00A708ED /* Credentials.swift */; }; 3811DF1025CAAAE200A708ED /* APSManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3811DF0F25CAAAE200A708ED /* APSManager.swift */; }; - 3818AA47274C255A00843DB3 /* LibreTransmitter in Frameworks */ = {isa = PBXBuildFile; productRef = 3818AA46274C255A00843DB3 /* LibreTransmitter */; }; - 3818AA4A274C267000843DB3 /* CGMBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA49274C267000843DB3 /* CGMBLEKit.framework */; }; - 3818AA4B274C267100843DB3 /* CGMBLEKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA49274C267000843DB3 /* CGMBLEKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 3818AA58274C26A300843DB3 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4C274C26A300843DB3 /* LoopKit.framework */; }; - 3818AA59274C26A300843DB3 /* LoopKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4C274C26A300843DB3 /* LoopKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 3818AA5A274C26A300843DB3 /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4D274C26A300843DB3 /* LoopKitUI.framework */; }; - 3818AA5B274C26A300843DB3 /* LoopKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4D274C26A300843DB3 /* LoopKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 3818AA5C274C26A300843DB3 /* MockKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4E274C26A300843DB3 /* MockKit.framework */; }; - 3818AA5D274C26A300843DB3 /* MockKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4E274C26A300843DB3 /* MockKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 3818AA5E274C26A300843DB3 /* MockKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4F274C26A300843DB3 /* MockKitUI.framework */; }; - 3818AA5F274C26A300843DB3 /* MockKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4F274C26A300843DB3 /* MockKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 3818AA6A274C26A500843DB3 /* RileyLinkBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA55274C26A300843DB3 /* RileyLinkBLEKit.framework */; }; - 3818AA6B274C26A500843DB3 /* RileyLinkBLEKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA55274C26A300843DB3 /* RileyLinkBLEKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 3818AA6C274C26A500843DB3 /* RileyLinkKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA56274C26A300843DB3 /* RileyLinkKit.framework */; }; - 3818AA6D274C26A500843DB3 /* RileyLinkKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA56274C26A300843DB3 /* RileyLinkKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 3818AA6E274C26A500843DB3 /* RileyLinkKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA57274C26A300843DB3 /* RileyLinkKitUI.framework */; }; - 3818AA6F274C26A500843DB3 /* RileyLinkKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA57274C26A300843DB3 /* RileyLinkKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 3818AA71274C278200843DB3 /* LoopTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA70274C278200843DB3 /* LoopTestingKit.framework */; }; - 3818AA72274C278200843DB3 /* LoopTestingKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA70274C278200843DB3 /* LoopTestingKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 38192E04261B82FA0094D973 /* ReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38192E03261B82FA0094D973 /* ReachabilityManager.swift */; }; 38192E07261BA9960094D973 /* FetchTreatmentsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38192E06261BA9960094D973 /* FetchTreatmentsManager.swift */; }; 38192E0D261BAF980094D973 /* ConvenienceExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38192E0C261BAF980094D973 /* ConvenienceExtensions.swift */; }; @@ -136,10 +116,7 @@ 385CEA8225F23DFD002D6D5B /* NightscoutStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 385CEA8125F23DFD002D6D5B /* NightscoutStatus.swift */; }; 385CEAC125F2EA52002D6D5B /* Announcement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 385CEAC025F2EA52002D6D5B /* Announcement.swift */; }; 385CEAC425F2F154002D6D5B /* AnnouncementsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 385CEAC325F2F154002D6D5B /* AnnouncementsStorage.swift */; }; - 3862CC05273D152B00BF832C /* CalibrationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3862CC04273D152B00BF832C /* CalibrationService.swift */; }; - 3862CC1F273FDC9200BF832C /* CalibrationsChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3862CC1E273FDC9200BF832C /* CalibrationsChart.swift */; }; 3862CC2E2743F9F700BF832C /* CalendarManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3862CC2D2743F9F700BF832C /* CalendarManager.swift */; }; - 386A124F271707F000DDC61C /* DexcomSourceG6.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386A124E271707F000DDC61C /* DexcomSourceG6.swift */; }; 3870FF4725EC187A0088248F /* BloodGlucose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3870FF4225EC13F40088248F /* BloodGlucose.swift */; }; 3871F38725ED661C0013ECB5 /* Suggestion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3871F38625ED661C0013ECB5 /* Suggestion.swift */; }; 3871F39C25ED892B0013ECB5 /* TempTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3871F39B25ED892B0013ECB5 /* TempTarget.swift */; }; @@ -255,7 +232,6 @@ 38FEF3FA2737E42000574A46 /* BaseStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FEF3F92737E42000574A46 /* BaseStateModel.swift */; }; 38FEF3FC2737E53800574A46 /* MainStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FEF3FB2737E53800574A46 /* MainStateModel.swift */; }; 38FEF3FE2738083E00574A46 /* CGMProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FEF3FD2738083E00574A46 /* CGMProvider.swift */; }; - 38FEF408273B011A00574A46 /* LibreTransmitterSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FEF407273B011A00574A46 /* LibreTransmitterSource.swift */; }; 38FEF413273B317A00574A46 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FEF412273B317A00574A46 /* HKUnit.swift */; }; 44190F0BBA464D74B857D1FB /* PreferencesEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A965332F237348B119FB858 /* PreferencesEditorRootView.swift */; }; 448B6FCB252BD4796E2960C0 /* PumpSettingsEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0274EE6439B1C3ED70730D41 /* PumpSettingsEditorDataFlow.swift */; }; @@ -265,7 +241,6 @@ 53F2382465BF74DB1A967C8B /* PumpConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8630D58BDAD6D9C650B9B39 /* PumpConfigProvider.swift */; }; 5BFA1C2208114643B77F8CEB /* AddTempTargetProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE53A13D26F101B332EFFC8 /* AddTempTargetProvider.swift */; }; 5D16287A969E64D18CE40E44 /* PumpConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F60E97100041040446F44E7 /* PumpConfigStateModel.swift */; }; - 61962FCAF8A2D222553AC5A3 /* LibreConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66A5B83E7967C38F7CBD883C /* LibreConfigDataFlow.swift */; }; 63E890B4D951EAA91C071D5C /* BasalProfileEditorStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAFF91130F2FCCC7EBBA11AD /* BasalProfileEditorStateModel.swift */; }; 642F76A05A4FF530463A9FD0 /* NightscoutConfigRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8782B44544F38F2B2D82C38E /* NightscoutConfigRootView.swift */; }; 6632A0DC746872439A858B44 /* ISFEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79BDA519C9B890FD9A5DFCF3 /* ISFEditorDataFlow.swift */; }; @@ -273,7 +248,6 @@ 69B9A368029F7EB39F525422 /* CREditorStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA5E04A2761F6EEA6568E1 /* CREditorStateModel.swift */; }; 6B1F539F9FF75646D1606066 /* SnoozeDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36A708CDB546692C2230B385 /* SnoozeDataFlow.swift */; }; 6B9625766B697D1C98E455A2 /* PumpSettingsEditorStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72778B68C3004F71F6E79BDC /* PumpSettingsEditorStateModel.swift */; }; - 6EADD581738D64431902AC0A /* LibreConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2EBA7C03C26FCC67E16D798 /* LibreConfigProvider.swift */; }; 6FFAE524D1D9C262F2407CAE /* SnoozeProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CAE81192B118804DCD23034 /* SnoozeProvider.swift */; }; 711C0CB42CAABE788916BC9D /* ManualTempBasalDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96653287EDB276A111288305 /* ManualTempBasalDataFlow.swift */; }; 72F1BD388F42FCA6C52E4500 /* ConfigEditorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44080E4709E3AE4B73054563 /* ConfigEditorProvider.swift */; }; @@ -284,8 +258,6 @@ 891DECF7BC20968D7F566161 /* AutotuneConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EF98E22A39CD656A230704 /* AutotuneConfigProvider.swift */; }; 8B759CFCF47B392BB365C251 /* BasalProfileEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67F94DD2853CF42BA4E30616 /* BasalProfileEditorDataFlow.swift */; }; 8BC2F5A29AD1ED08AC0EE013 /* AddTempTargetRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9AAB83FB6C3B41EFD1846A0 /* AddTempTargetRootView.swift */; }; - 903D18976088B09110BCBE29 /* LibreConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E68CDC1E5C438D1BEAD4CF24 /* LibreConfigStateModel.swift */; }; - 9050F378F0063C064D7FFC86 /* LibreConfigRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC210C0F3CB6D3C86E5DED4E /* LibreConfigRootView.swift */; }; 919DBD08F13BAFB180DF6F47 /* AddTempTargetStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C3B5FD881CA45DFDEE0EDA9 /* AddTempTargetStateModel.swift */; }; 9702FF92A09C53942F20D7EA /* TargetsEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DD795BA46B193644D48138C /* TargetsEditorRootView.swift */; }; 9825E5E923F0B8FA80C8C7C7 /* NightscoutConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0A48AE3AC813A49A517846A /* NightscoutConfigStateModel.swift */; }; @@ -296,22 +268,16 @@ A33352ED40476125EBAC6EE0 /* CREditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E22146D3DF4853786C78132 /* CREditorDataFlow.swift */; }; A6F097A14CAAE0CE0D11BE1B /* AddCarbsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 618E62C9757B2F95431B5DC0 /* AddCarbsProvider.swift */; }; AD3D2CD42CD01B9EB8F26522 /* PumpConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF65DA88F972B56090AD6AC3 /* PumpConfigDataFlow.swift */; }; - B7C465E9472624D8A2BE2A6A /* CalibrationsDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA241FB1663EC96FDBE64C8A /* CalibrationsDataFlow.swift */; }; + B958F1B72BA0711600484851 /* MKRingProgressView in Frameworks */ = {isa = PBXBuildFile; productRef = B958F1B62BA0711600484851 /* MKRingProgressView */; }; B9CAAEFC2AE70836000F68BC /* branch.txt in Resources */ = {isa = PBXBuildFile; fileRef = B9CAAEFB2AE70836000F68BC /* branch.txt */; }; BA00D96F7B2FF169A06FB530 /* CGMStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C018D1680307A31C9ED7120 /* CGMStateModel.swift */; }; - BA90041DC8991147E5C8C3AA /* CalibrationsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500371C09F54F89A97D65FDB /* CalibrationsRootView.swift */; }; BD2B464E0745FBE7B79913F4 /* NightscoutConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF768BD6264FF7D71D66767 /* NightscoutConfigProvider.swift */; }; BF1667ADE69E4B5B111CECAE /* ManualTempBasalProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 680C4420C9A345D46D90D06C /* ManualTempBasalProvider.swift */; }; C967DACD3B1E638F8B43BE06 /* ManualTempBasalStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFCFE0781F9074C2917890E8 /* ManualTempBasalStateModel.swift */; }; CA370FC152BC98B3D1832968 /* BasalProfileEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8BCB0C37DEB5EC377B9612 /* BasalProfileEditorRootView.swift */; }; CC6C406E2ACDD69E009B8058 /* RawFetchedProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC6C406D2ACDD69E009B8058 /* RawFetchedProfile.swift */; }; CD78BB94E43B249D60CC1A1B /* NotificationsConfigRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22963BD06A9C83959D4914E4 /* NotificationsConfigRootView.swift */; }; - CE2FAD38297D69E1001A872C /* ShareClient.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CE398D1A297D69A900DF218F /* ShareClient.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; CE2FAD3A297D93F0001A872C /* BloodGlucoseExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2FAD39297D93F0001A872C /* BloodGlucoseExtensions.swift */; }; - CE398D16297C9D1D00DF218F /* dexcomSourceG7.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE398D15297C9D1D00DF218F /* dexcomSourceG7.swift */; }; - CE398D18297C9EE800DF218F /* G7SensorKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE398D17297C9EE800DF218F /* G7SensorKit.framework */; }; - CE398D19297C9EFD00DF218F /* G7SensorKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CE398D17297C9EE800DF218F /* G7SensorKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - CE398D1B297D69A900DF218F /* ShareClient.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE398D1A297D69A900DF218F /* ShareClient.framework */; }; CE48C86428CA69D5007C0598 /* OmniBLEPumpManagerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE48C86328CA69D5007C0598 /* OmniBLEPumpManagerExtensions.swift */; }; CE48C86628CA6B48007C0598 /* OmniPodManagerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE48C86528CA6B48007C0598 /* OmniPodManagerExtensions.swift */; }; CE51DD1C2A01970900F163F7 /* ConnectIQ 2.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE51DD1B2A01970800F163F7 /* ConnectIQ 2.xcframework */; }; @@ -319,12 +285,6 @@ CE6B025728F350FF000C5502 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE6B025628F350FF000C5502 /* HealthKit.framework */; }; CE7950242997D81700FA576E /* CGMSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE7950232997D81700FA576E /* CGMSettingsView.swift */; }; CE7950262998056D00FA576E /* CGMSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE7950252998056D00FA576E /* CGMSetupView.swift */; }; - CE79502829980C9600FA576E /* CGMBLEKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE79502729980C9600FA576E /* CGMBLEKitUI.framework */; }; - CE79502A29980C9F00FA576E /* G7SensorKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE79502929980C9F00FA576E /* G7SensorKitUI.framework */; }; - CE79502B29980CAF00FA576E /* CGMBLEKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CE79502729980C9600FA576E /* CGMBLEKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - CE79502C29980CB500FA576E /* G7SensorKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CE79502929980C9F00FA576E /* G7SensorKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - CE79502E29980E4D00FA576E /* ShareClientUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE79502D29980E4D00FA576E /* ShareClientUI.framework */; }; - CE79502F29980E5800FA576E /* ShareClientUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CE79502D29980E4D00FA576E /* ShareClientUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; CE7CA34E2A064973004BE681 /* AppShortcuts.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE7CA3432A064973004BE681 /* AppShortcuts.swift */; }; CE7CA34F2A064973004BE681 /* BaseIntentsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE7CA3442A064973004BE681 /* BaseIntentsRequest.swift */; }; CE7CA3502A064973004BE681 /* CancelTempPresetIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE7CA3462A064973004BE681 /* CancelTempPresetIntent.swift */; }; @@ -342,25 +302,24 @@ CE94598229E9E3D30047C9C6 /* WatchConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE94598129E9E3D30047C9C6 /* WatchConfigProvider.swift */; }; CE94598429E9E3E60047C9C6 /* WatchConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE94598329E9E3E60047C9C6 /* WatchConfigStateModel.swift */; }; CE94598729E9E4110047C9C6 /* WatchConfigRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE94598629E9E4110047C9C6 /* WatchConfigRootView.swift */; }; + CE95BF572BA5F5FE00DC3DE3 /* PluginManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE95BF562BA5F5FE00DC3DE3 /* PluginManager.swift */; }; + CE95BF5A2BA62E4A00DC3DE3 /* PluginSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE95BF592BA62E4A00DC3DE3 /* PluginSource.swift */; }; + CE95BF5B2BA770C300DC3DE3 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4C274C26A300843DB3 /* LoopKit.framework */; }; + CE95BF5C2BA770C300DC3DE3 /* LoopKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4C274C26A300843DB3 /* LoopKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + CE95BF5D2BA770C300DC3DE3 /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4D274C26A300843DB3 /* LoopKitUI.framework */; }; + CE95BF5E2BA770C300DC3DE3 /* LoopKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4D274C26A300843DB3 /* LoopKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + CE95BF5F2BA7715800DC3DE3 /* MockKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4E274C26A300843DB3 /* MockKit.framework */; }; + CE95BF602BA7715800DC3DE3 /* MockKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4E274C26A300843DB3 /* MockKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + CE95BF612BA7715900DC3DE3 /* MockKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4F274C26A300843DB3 /* MockKitUI.framework */; }; + CE95BF622BA7715900DC3DE3 /* MockKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA4F274C26A300843DB3 /* MockKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + CE95BF632BA771BE00DC3DE3 /* LoopTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA70274C278200843DB3 /* LoopTestingKit.framework */; }; + CE95BF642BA771BE00DC3DE3 /* LoopTestingKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3818AA70274C278200843DB3 /* LoopTestingKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; CEA4F62329BE10F70011ADF7 /* SavitzkyGolayFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA4F62229BE10F70011ADF7 /* SavitzkyGolayFilter.swift */; }; - CEB434DC28B8F5B900B70274 /* MKRingProgressView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB434DB28B8F5B900B70274 /* MKRingProgressView.framework */; }; - CEB434DD28B8F5B900B70274 /* MKRingProgressView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CEB434DB28B8F5B900B70274 /* MKRingProgressView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - CEB434DF28B8F5C400B70274 /* OmniBLE.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB434DE28B8F5C400B70274 /* OmniBLE.framework */; }; - CEB434E028B8F5C400B70274 /* OmniBLE.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CEB434DE28B8F5C400B70274 /* OmniBLE.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; CEB434E328B8F9DB00B70274 /* BluetoothStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB434E228B8F9DB00B70274 /* BluetoothStateManager.swift */; }; CEB434E528B8FF5D00B70274 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB434E428B8FF5D00B70274 /* UIColor.swift */; }; CEB434E728B9053300B70274 /* LoopUIColorPalette+Default.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB434E628B9053300B70274 /* LoopUIColorPalette+Default.swift */; }; CEB434FD28B90B7C00B70274 /* SwiftCharts in Frameworks */ = {isa = PBXBuildFile; productRef = CEB434FC28B90B7C00B70274 /* SwiftCharts */; }; CEB434FE28B90B8C00B70274 /* SwiftCharts in Embed Frameworks */ = {isa = PBXBuildFile; productRef = CEB434FC28B90B7C00B70274 /* SwiftCharts */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - CEC751D229D88257006E9D24 /* OmniKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEC751D129D88257006E9D24 /* OmniKit.framework */; }; - CEC751D429D88257006E9D24 /* OmniKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEC751D329D88257006E9D24 /* OmniKitUI.framework */; }; - CEC751D629D88262006E9D24 /* MinimedKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEC751D529D88262006E9D24 /* MinimedKit.framework */; }; - CEC751D829D88262006E9D24 /* MinimedKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEC751D729D88262006E9D24 /* MinimedKitUI.framework */; }; - CEC751D929D8827A006E9D24 /* OmniKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CEC751D129D88257006E9D24 /* OmniKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - CEC751DA29D8827A006E9D24 /* OmniKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CEC751D329D88257006E9D24 /* OmniKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - CEC751DB29D88280006E9D24 /* MinimedKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CEC751D529D88262006E9D24 /* MinimedKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - CEC751DC29D88280006E9D24 /* MinimedKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CEC751D729D88262006E9D24 /* MinimedKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - CECA4775298DA8310095139F /* DexcomSourceG5.swift in Sources */ = {isa = PBXBuildFile; fileRef = CECA4774298DA8310095139F /* DexcomSourceG5.swift */; }; D2165E9D78EFF692C1DED1C6 /* AddTempTargetDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8A42073A2D03A278914448 /* AddTempTargetDataFlow.swift */; }; D6D02515BBFBE64FEBE89856 /* DataTableRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 881E04BA5E0A003DE8E0A9C6 /* DataTableRootView.swift */; }; D6DEC113821A7F1056C4AA1E /* NightscoutConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2A13DF0EDEEEDC4106AA2A /* NightscoutConfigDataFlow.swift */; }; @@ -378,7 +337,6 @@ E0CC2C5C275B9F0F00A7BC71 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E0CC2C5B275B9DAE00A7BC71 /* HealthKit.framework */; }; E0D4F80527513ECF00BDF1FE /* HealthKitSample.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0D4F80427513ECF00BDF1FE /* HealthKitSample.swift */; }; E13B7DAB2A435F57066AF02E /* TargetsEditorStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36F58DDD71F0E795464FA3F0 /* TargetsEditorStateModel.swift */; }; - E25073BC86C11C3D6A42F5AC /* CalibrationsStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47DFCE895C930F784EF11843 /* CalibrationsStateModel.swift */; }; E39E418C56A5A46B61D960EE /* ConfigEditorStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D5B4F8B4194BB7E260EF251 /* ConfigEditorStateModel.swift */; }; E3A08AAE59538BC8A8ABE477 /* NotificationsConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3260468377DA9DB4DEE9AF6D /* NotificationsConfigDataFlow.swift */; }; E4984C5262A90469788754BB /* PreferencesEditorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F8BA8533F56BC55748CA877 /* PreferencesEditorProvider.swift */; }; @@ -433,28 +391,13 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - CEC751DB29D88280006E9D24 /* MinimedKit.framework in Embed Frameworks */, - CEC751DC29D88280006E9D24 /* MinimedKitUI.framework in Embed Frameworks */, - CEC751D929D8827A006E9D24 /* OmniKit.framework in Embed Frameworks */, - CEC751DA29D8827A006E9D24 /* OmniKitUI.framework in Embed Frameworks */, - CE79502F29980E5800FA576E /* ShareClientUI.framework in Embed Frameworks */, - CE79502C29980CB500FA576E /* G7SensorKitUI.framework in Embed Frameworks */, CE51DD1D2A01970900F163F7 /* ConnectIQ 2.xcframework in Embed Frameworks */, - CE79502B29980CAF00FA576E /* CGMBLEKitUI.framework in Embed Frameworks */, - CE2FAD38297D69E1001A872C /* ShareClient.framework in Embed Frameworks */, - CE398D19297C9EFD00DF218F /* G7SensorKit.framework in Embed Frameworks */, - 3818AA6F274C26A500843DB3 /* RileyLinkKitUI.framework in Embed Frameworks */, - 3818AA4B274C267100843DB3 /* CGMBLEKit.framework in Embed Frameworks */, - CEB434E028B8F5C400B70274 /* OmniBLE.framework in Embed Frameworks */, - CEB434DD28B8F5B900B70274 /* MKRingProgressView.framework in Embed Frameworks */, + CE95BF5C2BA770C300DC3DE3 /* LoopKit.framework in Embed Frameworks */, CEB434FE28B90B8C00B70274 /* SwiftCharts in Embed Frameworks */, - 3818AA6B274C26A500843DB3 /* RileyLinkBLEKit.framework in Embed Frameworks */, - 3818AA59274C26A300843DB3 /* LoopKit.framework in Embed Frameworks */, - 3818AA5B274C26A300843DB3 /* LoopKitUI.framework in Embed Frameworks */, - 3818AA72274C278200843DB3 /* LoopTestingKit.framework in Embed Frameworks */, - 3818AA6D274C26A500843DB3 /* RileyLinkKit.framework in Embed Frameworks */, - 3818AA5D274C26A300843DB3 /* MockKit.framework in Embed Frameworks */, - 3818AA5F274C26A300843DB3 /* MockKitUI.framework in Embed Frameworks */, + CE95BF642BA771BE00DC3DE3 /* LoopTestingKit.framework in Embed Frameworks */, + CE95BF622BA7715900DC3DE3 /* MockKitUI.framework in Embed Frameworks */, + CE95BF602BA7715800DC3DE3 /* MockKit.framework in Embed Frameworks */, + CE95BF5E2BA770C300DC3DE3 /* LoopKitUI.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -570,7 +513,6 @@ 19F95FF629F10FEE00314DDC /* StatStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatStateModel.swift; sourceTree = ""; }; 19F95FF929F1102A00314DDC /* StatRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatRootView.swift; sourceTree = ""; }; 1CAE81192B118804DCD23034 /* SnoozeProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SnoozeProvider.swift; sourceTree = ""; }; - 212E8BFE6D66EE65AA26A114 /* CalibrationsProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CalibrationsProvider.swift; sourceTree = ""; }; 223EC0494F55A91E3EA69EF4 /* BolusStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BolusStateModel.swift; sourceTree = ""; }; 22963BD06A9C83959D4914E4 /* NotificationsConfigRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NotificationsConfigRootView.swift; sourceTree = ""; }; 2AD22C985B79A2F0D2EA3D9D /* PumpConfigRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PumpConfigRootView.swift; sourceTree = ""; }; @@ -648,10 +590,7 @@ 385CEA8125F23DFD002D6D5B /* NightscoutStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NightscoutStatus.swift; sourceTree = ""; }; 385CEAC025F2EA52002D6D5B /* Announcement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Announcement.swift; sourceTree = ""; }; 385CEAC325F2F154002D6D5B /* AnnouncementsStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnnouncementsStorage.swift; sourceTree = ""; }; - 3862CC04273D152B00BF832C /* CalibrationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalibrationService.swift; sourceTree = ""; }; - 3862CC1E273FDC9200BF832C /* CalibrationsChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalibrationsChart.swift; sourceTree = ""; }; 3862CC2D2743F9F700BF832C /* CalendarManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarManager.swift; sourceTree = ""; }; - 386A124E271707F000DDC61C /* DexcomSourceG6.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DexcomSourceG6.swift; sourceTree = ""; }; 3870FF4225EC13F40088248F /* BloodGlucose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BloodGlucose.swift; sourceTree = ""; }; 3871F38625ED661C0013ECB5 /* Suggestion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Suggestion.swift; sourceTree = ""; }; 3871F39B25ED892B0013ECB5 /* TempTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TempTarget.swift; sourceTree = ""; }; @@ -769,7 +708,6 @@ 38FEF3F92737E42000574A46 /* BaseStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseStateModel.swift; sourceTree = ""; }; 38FEF3FB2737E53800574A46 /* MainStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainStateModel.swift; sourceTree = ""; }; 38FEF3FD2738083E00574A46 /* CGMProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGMProvider.swift; sourceTree = ""; }; - 38FEF407273B011A00574A46 /* LibreTransmitterSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibreTransmitterSource.swift; sourceTree = ""; }; 38FEF412273B317A00574A46 /* HKUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKUnit.swift; sourceTree = ""; }; 39E7C997E56DAF8D28D09014 /* AddCarbsStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AddCarbsStateModel.swift; sourceTree = ""; }; 3BDEA2DC60EDE0A3CA54DC73 /* TargetsEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorProvider.swift; sourceTree = ""; }; @@ -778,9 +716,7 @@ 3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorDataFlow.swift; sourceTree = ""; }; 42369F66CF91F30624C0B3A6 /* BasalProfileEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorProvider.swift; sourceTree = ""; }; 44080E4709E3AE4B73054563 /* ConfigEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorProvider.swift; sourceTree = ""; }; - 47DFCE895C930F784EF11843 /* CalibrationsStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CalibrationsStateModel.swift; sourceTree = ""; }; 4DD795BA46B193644D48138C /* TargetsEditorRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorRootView.swift; sourceTree = ""; }; - 500371C09F54F89A97D65FDB /* CalibrationsRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CalibrationsRootView.swift; sourceTree = ""; }; 505E09DC17A0C3D0AF4B66FE /* ISFEditorStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ISFEditorStateModel.swift; sourceTree = ""; }; 5B8A42073A2D03A278914448 /* AddTempTargetDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AddTempTargetDataFlow.swift; sourceTree = ""; }; 5C018D1680307A31C9ED7120 /* CGMStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CGMStateModel.swift; sourceTree = ""; }; @@ -789,7 +725,6 @@ 60744C3E9BB3652895C908CC /* DataTableProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DataTableProvider.swift; sourceTree = ""; }; 618E62C9757B2F95431B5DC0 /* AddCarbsProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AddCarbsProvider.swift; sourceTree = ""; }; 64AA5E04A2761F6EEA6568E1 /* CREditorStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CREditorStateModel.swift; sourceTree = ""; }; - 66A5B83E7967C38F7CBD883C /* LibreConfigDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LibreConfigDataFlow.swift; sourceTree = ""; }; 67F94DD2853CF42BA4E30616 /* BasalProfileEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorDataFlow.swift; sourceTree = ""; }; 680C4420C9A345D46D90D06C /* ManualTempBasalProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ManualTempBasalProvider.swift; sourceTree = ""; }; 6F8BA8533F56BC55748CA877 /* PreferencesEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PreferencesEditorProvider.swift; sourceTree = ""; }; @@ -820,7 +755,6 @@ B9B5C0607505A38F256BF99A /* CGMDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CGMDataFlow.swift; sourceTree = ""; }; B9CAAEFB2AE70836000F68BC /* branch.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = branch.txt; sourceTree = SOURCE_ROOT; }; BA49538D56989D8DA6FCF538 /* TargetsEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorDataFlow.swift; sourceTree = ""; }; - BC210C0F3CB6D3C86E5DED4E /* LibreConfigRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LibreConfigRootView.swift; sourceTree = ""; }; BF8BCB0C37DEB5EC377B9612 /* BasalProfileEditorRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorRootView.swift; sourceTree = ""; }; C19984D62EFC0035A9E9644D /* BolusProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BolusProvider.swift; sourceTree = ""; }; C377490C77661D75E8C50649 /* ManualTempBasalRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ManualTempBasalRootView.swift; sourceTree = ""; }; @@ -828,7 +762,6 @@ CC6C406D2ACDD69E009B8058 /* RawFetchedProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawFetchedProfile.swift; sourceTree = ""; }; CE2FAD39297D93F0001A872C /* BloodGlucoseExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloodGlucoseExtensions.swift; sourceTree = ""; }; CE398D012977349800DF218F /* CryptoKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CryptoKit.framework; path = System/Library/Frameworks/CryptoKit.framework; sourceTree = SDKROOT; }; - CE398D15297C9D1D00DF218F /* dexcomSourceG7.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dexcomSourceG7.swift; sourceTree = ""; }; CE398D17297C9EE800DF218F /* G7SensorKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = G7SensorKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CE398D1A297D69A900DF218F /* ShareClient.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ShareClient.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CE48C86328CA69D5007C0598 /* OmniBLEPumpManagerExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmniBLEPumpManagerExtensions.swift; sourceTree = ""; }; @@ -858,6 +791,10 @@ CE94598129E9E3D30047C9C6 /* WatchConfigProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchConfigProvider.swift; sourceTree = ""; }; CE94598329E9E3E60047C9C6 /* WatchConfigStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchConfigStateModel.swift; sourceTree = ""; }; CE94598629E9E4110047C9C6 /* WatchConfigRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchConfigRootView.swift; sourceTree = ""; }; + CE95BF492BA5CED700DC3DE3 /* LoopKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LoopKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + CE95BF4A2BA5CED700DC3DE3 /* LoopKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LoopKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + CE95BF562BA5F5FE00DC3DE3 /* PluginManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginManager.swift; sourceTree = ""; }; + CE95BF592BA62E4A00DC3DE3 /* PluginSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginSource.swift; sourceTree = ""; }; CEA4F62229BE10F70011ADF7 /* SavitzkyGolayFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavitzkyGolayFilter.swift; sourceTree = ""; }; CEB434DB28B8F5B900B70274 /* MKRingProgressView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MKRingProgressView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CEB434DE28B8F5C400B70274 /* OmniBLE.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = OmniBLE.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -868,12 +805,10 @@ CEC751D329D88257006E9D24 /* OmniKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = OmniKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CEC751D529D88262006E9D24 /* MinimedKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MinimedKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CEC751D729D88262006E9D24 /* MinimedKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MinimedKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - CECA4774298DA8310095139F /* DexcomSourceG5.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DexcomSourceG5.swift; sourceTree = ""; }; CFCFE0781F9074C2917890E8 /* ManualTempBasalStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ManualTempBasalStateModel.swift; sourceTree = ""; }; D0BDC6993C1087310EDFC428 /* CREditorRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CREditorRootView.swift; sourceTree = ""; }; D295A3F870E826BE371C0BB5 /* AutotuneConfigStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AutotuneConfigStateModel.swift; sourceTree = ""; }; D97F14812C1AFED3621165A5 /* PumpSettingsEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PumpSettingsEditorProvider.swift; sourceTree = ""; }; - DA241FB1663EC96FDBE64C8A /* CalibrationsDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CalibrationsDataFlow.swift; sourceTree = ""; }; DC2C6489D29ECCCAD78E0721 /* NotificationsConfigStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NotificationsConfigStateModel.swift; sourceTree = ""; }; E00EEBFD27368630002FF094 /* ServiceAssembly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceAssembly.swift; sourceTree = ""; }; E00EEBFE27368630002FF094 /* SecurityAssembly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecurityAssembly.swift; sourceTree = ""; }; @@ -886,9 +821,7 @@ E0CC2C5B275B9DAE00A7BC71 /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; }; E0D4F80427513ECF00BDF1FE /* HealthKitSample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HealthKitSample.swift; sourceTree = ""; }; E26904AACA8D9C15D229D675 /* SnoozeStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SnoozeStateModel.swift; sourceTree = ""; }; - E2EBA7C03C26FCC67E16D798 /* LibreConfigProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LibreConfigProvider.swift; sourceTree = ""; }; E625985B47742D498CB1681A /* NotificationsConfigProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NotificationsConfigProvider.swift; sourceTree = ""; }; - E68CDC1E5C438D1BEAD4CF24 /* LibreConfigStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LibreConfigStateModel.swift; sourceTree = ""; }; E9AAB83FB6C3B41EFD1846A0 /* AddTempTargetRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AddTempTargetRootView.swift; sourceTree = ""; }; F816825D28DB441200054060 /* HeartBeatManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeartBeatManager.swift; sourceTree = ""; }; F816825F28DB441800054060 /* BluetoothTransmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothTransmitter.swift; sourceTree = ""; }; @@ -911,36 +844,21 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CEC751D829D88262006E9D24 /* MinimedKitUI.framework in Frameworks */, - CEC751D629D88262006E9D24 /* MinimedKit.framework in Frameworks */, - CEC751D429D88257006E9D24 /* OmniKitUI.framework in Frameworks */, - CEC751D229D88257006E9D24 /* OmniKit.framework in Frameworks */, - CE79502E29980E4D00FA576E /* ShareClientUI.framework in Frameworks */, - CE79502A29980C9F00FA576E /* G7SensorKitUI.framework in Frameworks */, - CE79502829980C9600FA576E /* CGMBLEKitUI.framework in Frameworks */, - CEB434DC28B8F5B900B70274 /* MKRingProgressView.framework in Frameworks */, + CE95BF632BA771BE00DC3DE3 /* LoopTestingKit.framework in Frameworks */, 38E87403274F78C000975559 /* libswiftCoreNFC.tbd in Frameworks */, 38E87401274F77E400975559 /* CoreNFC.framework in Frameworks */, - CEB434DF28B8F5C400B70274 /* OmniBLE.framework in Frameworks */, - 3818AA71274C278200843DB3 /* LoopTestingKit.framework in Frameworks */, - 3818AA47274C255A00843DB3 /* LibreTransmitter in Frameworks */, - 3818AA4A274C267000843DB3 /* CGMBLEKit.framework in Frameworks */, CE51DD1C2A01970900F163F7 /* ConnectIQ 2.xcframework in Frameworks */, 3811DE1025C9D37700A708ED /* Swinject in Frameworks */, - 3818AA5C274C26A300843DB3 /* MockKit.framework in Frameworks */, - 3818AA6A274C26A500843DB3 /* RileyLinkBLEKit.framework in Frameworks */, - 3818AA6C274C26A500843DB3 /* RileyLinkKit.framework in Frameworks */, - 3818AA5E274C26A300843DB3 /* MockKitUI.framework in Frameworks */, - CE398D18297C9EE800DF218F /* G7SensorKit.framework in Frameworks */, - 3818AA5A274C26A300843DB3 /* LoopKitUI.framework in Frameworks */, - 3818AA58274C26A300843DB3 /* LoopKit.framework in Frameworks */, - CE398D1B297D69A900DF218F /* ShareClient.framework in Frameworks */, + B958F1B72BA0711600484851 /* MKRingProgressView in Frameworks */, + CE95BF5B2BA770C300DC3DE3 /* LoopKit.framework in Frameworks */, 38B17B6625DD90E0005CAE3D /* SwiftDate in Frameworks */, 3833B46D26012030003021B3 /* Algorithms in Frameworks */, CEB434FD28B90B7C00B70274 /* SwiftCharts in Frameworks */, + CE95BF5F2BA7715800DC3DE3 /* MockKit.framework in Frameworks */, 38DF1789276FC8C400B3528F /* SwiftMessages in Frameworks */, + CE95BF612BA7715900DC3DE3 /* MockKitUI.framework in Frameworks */, E0CC2C5C275B9F0F00A7BC71 /* HealthKit.framework in Frameworks */, - 3818AA6E274C26A500843DB3 /* RileyLinkKitUI.framework in Frameworks */, + CE95BF5D2BA770C300DC3DE3 /* LoopKitUI.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1166,14 +1084,12 @@ A42F1FEDFFD0DDE00AAD54D3 /* BasalProfileEditor */, 3811DE0425C9D32E00A708ED /* Base */, C2C98283C436DB934D7E7994 /* Bolus */, - E8176B120B55CE89F1591542 /* Calibrations */, F75CB57ED6971B46F8756083 /* CGM */, 0610F7D6D2EC00E3BA1569F0 /* ConfigEditor */, E42231DBF0DBE2B4B92D1B15 /* CREditor */, 9E56E3626FAD933385101B76 /* DataTable */, 3811DE2725C9D49500A708ED /* Home */, D8F047E14D567F2B5DBEFD96 /* ISFEditor */, - C11D545CED3ECEB525EDEE23 /* LibreConfig */, 3811DE1A25C9D48300A708ED /* Main */, 5031FE61F63C2A8A8B7674DD /* ManualTempBasal */, D533BF261CDC1C3F871E7BFD /* NightscoutConfig */, @@ -1403,6 +1319,7 @@ 3811DF0A25CAAAA500A708ED /* APS */ = { isa = PBXGroup; children = ( + CE95BF562BA5F5FE00DC3DE3 /* PluginManager.swift */, 3811DF0F25CAAAE200A708ED /* APSManager.swift */, 38BF021E25E7F0DE00579895 /* DeviceDataManager.swift */, 38A43597262E0E4900E80935 /* FetchAnnouncementsManager.swift */, @@ -1427,6 +1344,8 @@ 3818AA48274C267000843DB3 /* Frameworks */ = { isa = PBXGroup; children = ( + CE95BF492BA5CED700DC3DE3 /* LoopKit.framework */, + CE95BF4A2BA5CED700DC3DE3 /* LoopKitUI.framework */, CE51DD1B2A01970800F163F7 /* ConnectIQ 2.xcframework */, CE94597929E9DF7B0047C9C6 /* ConnectIQ.framework */, CEC751D529D88262006E9D24 /* MinimedKit.framework */, @@ -1483,29 +1402,17 @@ 3856933F270B57A00002C50D /* CGM */ = { isa = PBXGroup; children = ( - CE398D15297C9D1D00DF218F /* dexcomSourceG7.swift */, F816825F28DB441800054060 /* BluetoothTransmitter.swift */, F816825D28DB441200054060 /* HeartBeatManager.swift */, 38569346270B5DFB0002C50D /* AppGroupSource.swift */, 38569344270B5DFA0002C50D /* CGMType.swift */, - 386A124E271707F000DDC61C /* DexcomSourceG6.swift */, 38569345270B5DFA0002C50D /* GlucoseSource.swift */, E013D871273AC6FE0014109C /* GlucoseSimulatorSource.swift */, - 38FEF407273B011A00574A46 /* LibreTransmitterSource.swift */, - 3862CC03273D150600BF832C /* Calibrations */, - CECA4774298DA8310095139F /* DexcomSourceG5.swift */, + CE95BF592BA62E4A00DC3DE3 /* PluginSource.swift */, ); path = CGM; sourceTree = ""; }; - 3862CC03273D150600BF832C /* Calibrations */ = { - isa = PBXGroup; - children = ( - 3862CC04273D152B00BF832C /* CalibrationService.swift */, - ); - path = Calibrations; - sourceTree = ""; - }; 3862CC2C2743F9DC00BF832C /* Calendar */ = { isa = PBXGroup; children = ( @@ -1856,15 +1763,6 @@ path = View; sourceTree = ""; }; - 43952E72FE7AF85715FE020E /* View */ = { - isa = PBXGroup; - children = ( - 500371C09F54F89A97D65FDB /* CalibrationsRootView.swift */, - 3862CC1E273FDC9200BF832C /* CalibrationsChart.swift */, - ); - path = View; - sourceTree = ""; - }; 4E8C7B59F8065047ECE20965 /* View */ = { isa = PBXGroup; children = ( @@ -2016,14 +1914,6 @@ path = BasalProfileEditor; sourceTree = ""; }; - A56097CB1DCBCE98F2F42177 /* View */ = { - isa = PBXGroup; - children = ( - BC210C0F3CB6D3C86E5DED4E /* LibreConfigRootView.swift */, - ); - path = View; - sourceTree = ""; - }; A9A4C88374496B3C89058A89 /* AddTempTarget */ = { isa = PBXGroup; children = ( @@ -2043,17 +1933,6 @@ path = View; sourceTree = ""; }; - C11D545CED3ECEB525EDEE23 /* LibreConfig */ = { - isa = PBXGroup; - children = ( - 66A5B83E7967C38F7CBD883C /* LibreConfigDataFlow.swift */, - E2EBA7C03C26FCC67E16D798 /* LibreConfigProvider.swift */, - E68CDC1E5C438D1BEAD4CF24 /* LibreConfigStateModel.swift */, - A56097CB1DCBCE98F2F42177 /* View */, - ); - path = LibreConfig; - sourceTree = ""; - }; C2C98283C436DB934D7E7994 /* Bolus */ = { isa = PBXGroup; children = ( @@ -2182,17 +2061,6 @@ path = PumpSettingsEditor; sourceTree = ""; }; - E8176B120B55CE89F1591542 /* Calibrations */ = { - isa = PBXGroup; - children = ( - DA241FB1663EC96FDBE64C8A /* CalibrationsDataFlow.swift */, - 212E8BFE6D66EE65AA26A114 /* CalibrationsProvider.swift */, - 47DFCE895C930F784EF11843 /* CalibrationsStateModel.swift */, - 43952E72FE7AF85715FE020E /* View */, - ); - path = Calibrations; - sourceTree = ""; - }; EEC747824D6593B5CD87E195 /* View */ = { isa = PBXGroup; children = ( @@ -2272,6 +2140,7 @@ 388E595625AD948C0019842D /* Resources */, 3821ECD025DC703C00BC42AD /* Embed Frameworks */, 38E8753D27554D5900975559 /* Embed Watch Content */, + CE95BF582BA5F8F300DC3DE3 /* Install plugins */, ); buildRules = ( ); @@ -2283,9 +2152,9 @@ 3811DE0F25C9D37700A708ED /* Swinject */, 38B17B6525DD90E0005CAE3D /* SwiftDate */, 3833B46C26012030003021B3 /* Algorithms */, - 3818AA46274C255A00843DB3 /* LibreTransmitter */, 38DF1788276FC8C400B3528F /* SwiftMessages */, CEB434FC28B90B7C00B70274 /* SwiftCharts */, + B958F1B62BA0711600484851 /* MKRingProgressView */, ); productName = FreeAPS; productReference = 388E595825AD948C0019842D /* FreeAPS.app */; @@ -2407,6 +2276,7 @@ 3833B46B26012030003021B3 /* XCRemoteSwiftPackageReference "swift-algorithms" */, 38DF1787276FC8C300B3528F /* XCRemoteSwiftPackageReference "SwiftMessages" */, CEB434FB28B90B7C00B70274 /* XCRemoteSwiftPackageReference "SwiftCharts" */, + B958F1B52BA0711600484851 /* XCRemoteSwiftPackageReference "MKRingProgressView" */, ); productRefGroup = 388E595925AD948C0019842D /* Products */; projectDirPath = ""; @@ -2467,7 +2337,7 @@ /* Begin PBXShellScriptBuildPhase section */ 3811DEF525CA169200A708ED /* Swiftformat */ = { isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; + buildActionMask = 12; files = ( ); inputFileListPaths = ( @@ -2502,6 +2372,25 @@ shellPath = /bin/sh; shellScript = "# Prints a message\necho \"writing BRANCH to branch.txt\"\n\n# Retrieves version, branch, and tag information from Git\ngit_version=$(git log -1 --format=\"%h\" --abbrev=7)\ngit_branch=$(git symbolic-ref --short -q HEAD)\ngit_tag=$(git describe --tags --exact-match 2>/dev/null)\n\n# Determines branch or tag information\ngit_branch_or_tag=\"${git_branch:-${git_tag}}\"\ngit_branch_or_tag_version=\"${git_branch_or_tag} ${git_version}\"\n\necho \"BRANCH = ${git_branch_or_tag_version}\" > \"./branch.txt\"\n\n# Prints a message about the working directory and branch.txt\necho \"branch.txt is created/modified in ${PWD}\"\n"; }; + CE95BF582BA5F8F300DC3DE3 /* Install plugins */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Install plugins"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Scripts/copy-plugins.sh\"\n"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -2533,10 +2422,8 @@ 38AEE75725F0F18E0013F05B /* CarbsStorage.swift in Sources */, 38B4F3CA25E502E200E76A18 /* SwiftNotificationCenter.swift in Sources */, 38AEE75225F022080013F05B /* SettingsManager.swift in Sources */, - 38FEF408273B011A00574A46 /* LibreTransmitterSource.swift in Sources */, 3894873A2614928B004DF424 /* DispatchTimer.swift in Sources */, 3895E4C625B9E00D00214B37 /* Preferences.swift in Sources */, - 386A124F271707F000DDC61C /* DexcomSourceG6.swift in Sources */, CE94598429E9E3E60047C9C6 /* WatchConfigStateModel.swift in Sources */, 38DF1786276A73D400B3528F /* TagCloudView.swift in Sources */, 38B4F3CD25E5031100E76A18 /* Broadcaster.swift in Sources */, @@ -2559,6 +2446,7 @@ 3883583425EEB38000E024B2 /* PumpSettings.swift in Sources */, 38DAB280260CBB7F00F74C1A /* PumpView.swift in Sources */, 3811DEB125C9D88300A708ED /* Keychain.swift in Sources */, + CE95BF572BA5F5FE00DC3DE3 /* PluginManager.swift in Sources */, 382C133725F13A1E00715CE1 /* InsulinSensitivities.swift in Sources */, 19D466A529AA2BD4004D5F33 /* FPUConfigProvider.swift in Sources */, 383948D625CD4D8900E91849 /* FileStorage.swift in Sources */, @@ -2611,10 +2499,10 @@ 3811DEAD25C9D88300A708ED /* UserDefaults+Cache.swift in Sources */, CE48C86628CA6B48007C0598 /* OmniPodManagerExtensions.swift in Sources */, CEB434E728B9053300B70274 /* LoopUIColorPalette+Default.swift in Sources */, - CECA4775298DA8310095139F /* DexcomSourceG5.swift in Sources */, 19F95FF329F10FBC00314DDC /* StatDataFlow.swift in Sources */, 3811DE2225C9D48300A708ED /* MainProvider.swift in Sources */, 3811DE0C25C9D32F00A708ED /* BaseProvider.swift in Sources */, + CE95BF5A2BA62E4A00DC3DE3 /* PluginSource.swift in Sources */, 3811DE5C25C9D4D500A708ED /* Formatters.swift in Sources */, 3871F39F25ED895A0013ECB5 /* Decimal+Extensions.swift in Sources */, 3811DE3525C9D49500A708ED /* HomeRootView.swift in Sources */, @@ -2639,7 +2527,6 @@ CE82E02528E867BA00473A9C /* AlertStorage.swift in Sources */, 38BF021D25E7E3AF00579895 /* Reservoir.swift in Sources */, 38BF021B25E7D06400579895 /* PumpSettingsView.swift in Sources */, - 3862CC05273D152B00BF832C /* CalibrationService.swift in Sources */, 3811DEEA25CA063400A708ED /* SyncAccess.swift in Sources */, 190EBCC829FF13AA00BA767D /* StatConfigStateModel.swift in Sources */, 38BF021F25E7F0DE00579895 /* DeviceDataManager.swift in Sources */, @@ -2704,7 +2591,6 @@ CE7CA3512A064973004BE681 /* ApplyTempPresetIntent.swift in Sources */, FA630397F76B582C8D8681A7 /* BasalProfileEditorProvider.swift in Sources */, 63E890B4D951EAA91C071D5C /* BasalProfileEditorStateModel.swift in Sources */, - CE398D16297C9D1D00DF218F /* dexcomSourceG7.swift in Sources */, 38FEF3FA2737E42000574A46 /* BaseStateModel.swift in Sources */, CC6C406E2ACDD69E009B8058 /* RawFetchedProfile.swift in Sources */, 385CEA8225F23DFD002D6D5B /* NightscoutStatus.swift in Sources */, @@ -2773,7 +2659,6 @@ 19D4E4EB29FC6A9F00351451 /* TIRforChart.swift in Sources */, FEFFA7A22929FE49007B8193 /* UIDevice+Extensions.swift in Sources */, F90692D3274B9A130037068D /* AppleHealthKitRootView.swift in Sources */, - 3862CC1F273FDC9200BF832C /* CalibrationsChart.swift in Sources */, 19E1F7EC29D082FE005C8D20 /* IconConfigStateModel.swift in Sources */, 711C0CB42CAABE788916BC9D /* ManualTempBasalDataFlow.swift in Sources */, BF1667ADE69E4B5B111CECAE /* ManualTempBasalProvider.swift in Sources */, @@ -2796,16 +2681,8 @@ 38569349270B5DFB0002C50D /* AppGroupSource.swift in Sources */, F5CA3DB1F9DC8B05792BBFAA /* CGMDataFlow.swift in Sources */, BA00D96F7B2FF169A06FB530 /* CGMStateModel.swift in Sources */, - 61962FCAF8A2D222553AC5A3 /* LibreConfigDataFlow.swift in Sources */, - 6EADD581738D64431902AC0A /* LibreConfigProvider.swift in Sources */, CE94598729E9E4110047C9C6 /* WatchConfigRootView.swift in Sources */, - 903D18976088B09110BCBE29 /* LibreConfigStateModel.swift in Sources */, - 9050F378F0063C064D7FFC86 /* LibreConfigRootView.swift in Sources */, - B7C465E9472624D8A2BE2A6A /* CalibrationsDataFlow.swift in Sources */, - 320D030F724170A637F06D50 /* CalibrationsProvider.swift in Sources */, 19E1F7E829D082D0005C8D20 /* IconConfigDataFlow.swift in Sources */, - E25073BC86C11C3D6A42F5AC /* CalibrationsStateModel.swift in Sources */, - BA90041DC8991147E5C8C3AA /* CalibrationsRootView.swift in Sources */, E3A08AAE59538BC8A8ABE477 /* NotificationsConfigDataFlow.swift in Sources */, 0F7A65FBD2CD8D6477ED4539 /* NotificationsConfigProvider.swift in Sources */, 3171D2818C7C72CD1584BB5E /* NotificationsConfigStateModel.swift in Sources */, @@ -3298,7 +3175,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = "$(DEVELOPER_TEAM)"; INFOPLIST_FILE = FreeAPSTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.4; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -3319,7 +3196,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = "$(DEVELOPER_TEAM)"; INFOPLIST_FILE = FreeAPSTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.4; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -3416,6 +3293,14 @@ minimumVersion = 9.0.0; }; }; + B958F1B52BA0711600484851 /* XCRemoteSwiftPackageReference "MKRingProgressView" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/maxkonovalov/MKRingProgressView.git"; + requirement = { + branch = master; + kind = branch; + }; + }; CEB434FB28B90B7C00B70274 /* XCRemoteSwiftPackageReference "SwiftCharts" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/ivanschuetz/SwiftCharts.git"; @@ -3432,10 +3317,6 @@ package = 3811DE0E25C9D37700A708ED /* XCRemoteSwiftPackageReference "Swinject" */; productName = Swinject; }; - 3818AA46274C255A00843DB3 /* LibreTransmitter */ = { - isa = XCSwiftPackageProductDependency; - productName = LibreTransmitter; - }; 3833B46C26012030003021B3 /* Algorithms */ = { isa = XCSwiftPackageProductDependency; package = 3833B46B26012030003021B3 /* XCRemoteSwiftPackageReference "swift-algorithms" */; @@ -3456,6 +3337,11 @@ package = 38B17B6425DD90E0005CAE3D /* XCRemoteSwiftPackageReference "SwiftDate" */; productName = SwiftDate; }; + B958F1B62BA0711600484851 /* MKRingProgressView */ = { + isa = XCSwiftPackageProductDependency; + package = B958F1B52BA0711600484851 /* XCRemoteSwiftPackageReference "MKRingProgressView" */; + productName = MKRingProgressView; + }; CEB434FC28B90B7C00B70274 /* SwiftCharts */ = { isa = XCSwiftPackageProductDependency; package = CEB434FB28B90B7C00B70274 /* XCRemoteSwiftPackageReference "SwiftCharts" */; diff --git a/FreeAPS.xcodeproj/xcshareddata/xcschemes/FreeAPS X.xcscheme b/FreeAPS.xcodeproj/xcshareddata/xcschemes/FreeAPS X.xcscheme index ae75876b1..e35119541 100644 --- a/FreeAPS.xcodeproj/xcshareddata/xcschemes/FreeAPS X.xcscheme +++ b/FreeAPS.xcodeproj/xcshareddata/xcschemes/FreeAPS X.xcscheme @@ -3,9 +3,219 @@ LastUpgradeVersion = "1240" version = "1.3"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + location = "group:MinimedKit/MinimedKit.xcodeproj"> + location = "group:LibreTransmitter/LibreTransmitter.xcodeproj"> + location = "group:OmniBLE/OmniBLE.xcodeproj"> + location = "group:RileyLinkKit/RileyLinkKit.xcodeproj"> + location = "group:CGMBLEKit/CGMBLEKit.xcodeproj"> + location = "group:dexcom-share-client-swift/ShareClient.xcodeproj"> + location = "group:LoopKit/LoopKit.xcodeproj"> + location = "group:OmniKit/OmniKit.xcodeproj"> + location = "group:G7SensorKit/G7SensorKit.xcodeproj"> diff --git a/FreeAPS.xcworkspace/xcshareddata/swiftpm/Package.resolved b/FreeAPS.xcworkspace/xcshareddata/swiftpm/Package.resolved index 2cfe78ebf..62562ae63 100644 --- a/FreeAPS.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/FreeAPS.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,70 +1,86 @@ { - "object": { - "pins": [ - { - "package": "CryptoSwift", - "repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift", - "state": { - "branch": null, - "revision": "19b3c3ceed117c5cc883517c4e658548315ba70b", - "version": "1.6.0" - } - }, - { - "package": "swift-algorithms", - "repositoryURL": "https://github.com/apple/swift-algorithms", - "state": { - "branch": null, - "revision": "2327673b0e9c7e90e6b1826376526ec3627210e4", - "version": "0.2.1" - } - }, - { - "package": "swift-numerics", - "repositoryURL": "https://github.com/apple/swift-numerics", - "state": { - "branch": null, - "revision": "6583ac70c326c3ee080c1d42d9ca3361dca816cd", - "version": "0.1.0" - } - }, - { - "package": "SwiftCharts", - "repositoryURL": "https://github.com/ivanschuetz/SwiftCharts.git", - "state": { - "branch": "master", - "revision": "c354c1945bb35a1f01b665b22474f6db28cba4a2", - "version": null - } - }, - { - "package": "SwiftDate", - "repositoryURL": "https://github.com/malcommac/SwiftDate", - "state": { - "branch": null, - "revision": "6190d0cefff3013e77ed567e6b074f324e5c5bf5", - "version": "6.3.1" - } - }, - { - "package": "SwiftMessages", - "repositoryURL": "https://github.com/SwiftKickMobile/SwiftMessages", - "state": { - "branch": null, - "revision": "b29dd21090b708aa0ae9ecbaf6e2d0487028dc3f", - "version": "9.0.6" - } - }, - { - "package": "Swinject", - "repositoryURL": "https://github.com/Swinject/Swinject", - "state": { - "branch": null, - "revision": "8bc503e60965298984fb58cf47b71c541449fe2a", - "version": "2.8.3" - } + "pins" : [ + { + "identity" : "cryptoswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/krzyzanowskim/CryptoSwift", + "state" : { + "revision" : "19b3c3ceed117c5cc883517c4e658548315ba70b", + "version" : "1.6.0" } - ] - }, - "version": 1 + }, + { + "identity" : "mkringprogressview", + "kind" : "remoteSourceControl", + "location" : "https://github.com/maxkonovalov/MKRingProgressView.git", + "state" : { + "branch" : "master", + "revision" : "660888aab1d2ab0ed7eb9eb53caec12af4955fa7" + } + }, + { + "identity" : "slidebutton", + "kind" : "remoteSourceControl", + "location" : "https://github.com/no-comment/SlideButton", + "state" : { + "branch" : "main", + "revision" : "5eacebba4d7deeb693592bc9a62ab2d2181e133b" + } + }, + { + "identity" : "swift-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-algorithms", + "state" : { + "revision" : "2327673b0e9c7e90e6b1826376526ec3627210e4", + "version" : "0.2.1" + } + }, + { + "identity" : "swift-numerics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-numerics", + "state" : { + "revision" : "6583ac70c326c3ee080c1d42d9ca3361dca816cd", + "version" : "0.1.0" + } + }, + { + "identity" : "swiftcharts", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ivanschuetz/SwiftCharts.git", + "state" : { + "branch" : "master", + "revision" : "c354c1945bb35a1f01b665b22474f6db28cba4a2" + } + }, + { + "identity" : "swiftdate", + "kind" : "remoteSourceControl", + "location" : "https://github.com/malcommac/SwiftDate", + "state" : { + "revision" : "6190d0cefff3013e77ed567e6b074f324e5c5bf5", + "version" : "6.3.1" + } + }, + { + "identity" : "swiftmessages", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SwiftKickMobile/SwiftMessages", + "state" : { + "revision" : "b29dd21090b708aa0ae9ecbaf6e2d0487028dc3f", + "version" : "9.0.6" + } + }, + { + "identity" : "swinject", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Swinject/Swinject", + "state" : { + "revision" : "8bc503e60965298984fb58cf47b71c541449fe2a", + "version" : "2.8.3" + } + } + ], + "version" : 2 } diff --git a/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json b/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json index bec8a8989..bae61cdd7 100644 --- a/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json +++ b/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json @@ -12,6 +12,7 @@ "skipBolusScreenAfterCarbs" : false, "displayHR" : false, "cgm" : "nightscout", + "cgmManagerTypeByIdentifier":"", "uploadGlucose" : true, "useCalendar" : false, "glucoseBadge" : false, diff --git a/FreeAPS/Sources/APS/CGM/AppGroupSource.swift b/FreeAPS/Sources/APS/CGM/AppGroupSource.swift index e1ebca97e..5863e9b1c 100644 --- a/FreeAPS/Sources/APS/CGM/AppGroupSource.swift +++ b/FreeAPS/Sources/APS/CGM/AppGroupSource.swift @@ -1,8 +1,29 @@ import Combine import Foundation -import LibreTransmitter +import LoopKit import LoopKitUI +public extension GlucoseTrend { + var direction: String { + switch self { + case .upUpUp: + return "DoubleUp" + case .upUp: + return "SingleUp" + case .up: + return "FortyFiveUp" + case .flat: + return "Flat" + case .down: + return "FortyFiveDown" + case .downDown: + return "SingleDown" + case .downDownDown: + return "DoubleDown" + } + } +} + struct AppGroupSource: GlucoseSource { var cgmManager: CGMManagerUI? var glucoseManager: FetchGlucoseManager? diff --git a/FreeAPS/Sources/APS/CGM/CGMType.swift b/FreeAPS/Sources/APS/CGM/CGMType.swift index a77810cc9..f3deb3136 100644 --- a/FreeAPS/Sources/APS/CGM/CGMType.swift +++ b/FreeAPS/Sources/APS/CGM/CGMType.swift @@ -2,59 +2,67 @@ import Foundation enum CGMType: String, JSON, CaseIterable, Identifiable { var id: String { rawValue } - + case none case nightscout case xdrip - case dexcomG5 - case dexcomG6 - case dexcomG7 +// case dexcomG5 +// case dexcomG6 +// case dexcomG7 case simulator - case libreTransmitter +// case libreTransmitter case glucoseDirect case enlite + case plugin var displayName: String { switch self { + case .none: + return "None" case .nightscout: return "Nightscout" case .xdrip: return "xDrip4iOS" case .glucoseDirect: return "Glucose Direct" - case .dexcomG5: - return "Dexcom G5" - case .dexcomG6: - return "Dexcom G6" - case .dexcomG7: - return "Dexcom G7" +// case .dexcomG5: +// return "Dexcom G5" +// case .dexcomG6: +// return "Dexcom G6" +// case .dexcomG7: +// return "Dexcom G7" case .simulator: return NSLocalizedString("Glucose Simulator", comment: "Glucose Simulator CGM type") - case .libreTransmitter: - return NSLocalizedString("Libre Transmitter", comment: "Libre Transmitter type") +// case .libreTransmitter: +// return NSLocalizedString("Libre Transmitter", comment: "Libre Transmitter type") case .enlite: return "Medtronic Enlite" + case .plugin: + return "plugin CGM" } } var appURL: URL? { switch self { case .enlite, - .nightscout: + .nightscout, + .none: return nil case .xdrip: return URL(string: "xdripswift://")! case .glucoseDirect: return URL(string: "libredirect://")! - case .dexcomG5: - return URL(string: "dexcomgcgm://")! - case .dexcomG6: - return URL(string: "dexcomg6://")! - case .dexcomG7: - return URL(string: "dexcomg7://")! +// case .dexcomG5: +// return URL(string: "dexcomgcgm://")! +// case .dexcomG6: +// return URL(string: "dexcomg6://")! +// case .dexcomG7: +// return URL(string: "dexcomg7://")! case .simulator: return nil - case .libreTransmitter: - return URL(string: "Open-iAPS://libre-transmitter")! +// case .libreTransmitter: +// return URL(string: "Open-iAPS://libre-transmitter")! + case .plugin: + return nil } } @@ -70,6 +78,8 @@ enum CGMType: String, JSON, CaseIterable, Identifiable { var subtitle: String { switch self { + case .none: + return NSLocalizedString("None", comment: "No CGM choiced") case .nightscout: return NSLocalizedString("Online or internal server", comment: "Online or internal server") case .xdrip: @@ -77,19 +87,19 @@ enum CGMType: String, JSON, CaseIterable, Identifiable { "Using shared app group with external CGM app xDrip4iOS", comment: "Shared app group xDrip4iOS" ) - case .dexcomG5: - return NSLocalizedString("Native G5 app", comment: "Native G5 app") - case .dexcomG6: - return NSLocalizedString("Dexcom G6 app", comment: "Dexcom G6 app") - case .dexcomG7: - return NSLocalizedString("Dexcom G7 app", comment: "Dexcom G76 app") +// case .dexcomG5: +// return NSLocalizedString("Native G5 app", comment: "Native G5 app") +// case .dexcomG6: +// return NSLocalizedString("Dexcom G6 app", comment: "Dexcom G6 app") +// case .dexcomG7: +// return NSLocalizedString("Dexcom G7 app", comment: "Dexcom G76 app") case .simulator: return NSLocalizedString("Simple simulator", comment: "Simple simulator") - case .libreTransmitter: - return NSLocalizedString( - "Direct connection with Libre 1 transmitters or European Libre 2 sensors", - comment: "Direct connection with Libre 1 transmitters or European Libre 2 sensors" - ) +// case .libreTransmitter: +// return NSLocalizedString( +// "Direct connection with Libre 1 transmitters or European Libre 2 sensors", +// comment: "Direct connection with Libre 1 transmitters or European Libre 2 sensors" +// ) case .glucoseDirect: return NSLocalizedString( "Using shared app group with external CGM app GlucoseDirect", @@ -97,6 +107,8 @@ enum CGMType: String, JSON, CaseIterable, Identifiable { ) case .enlite: return NSLocalizedString("Minilink transmitter", comment: "Minilink transmitter") + case .plugin: + return NSLocalizedString("Plugin CGM", comment: "Plugin CGM") } } } diff --git a/FreeAPS/Sources/APS/CGM/Calibrations/CalibrationService.swift b/FreeAPS/Sources/APS/CGM/Calibrations/CalibrationService.swift deleted file mode 100644 index 33b1d0bc9..000000000 --- a/FreeAPS/Sources/APS/CGM/Calibrations/CalibrationService.swift +++ /dev/null @@ -1,119 +0,0 @@ -import Foundation -import LibreTransmitter -import Swinject - -struct Calibration: JSON, Hashable, Identifiable { - let x: Double - let y: Double - var date = Date() - - static let zero = Calibration(x: 0, y: 0) - - var id = UUID() -} - -protocol CalibrationService { - var slope: Double { get } - var intercept: Double { get } - var calibrations: [Calibration] { get } - - func addCalibration(_ calibration: Calibration) - func removeCalibration(_ calibration: Calibration) - func removeAllCalibrations() - func removeLast() - - func calibrate(value: Double) -> Double -} - -final class BaseCalibrationService: CalibrationService, Injectable { - private enum Config { - static let minSlope = 0.8 - static let maxSlope = 1.25 - static let minIntercept = -100.0 - static let maxIntercept = 100.0 - static let maxValue = 500.0 - static let minValue = 0.0 - } - - @Injected() var storage: FileStorage! - @Injected() var notificationCenter: NotificationCenter! - private var lifetime = Lifetime() - - private(set) var calibrations: [Calibration] = [] { - didSet { - storage.save(calibrations, as: OpenAPS.FreeAPS.calibrations) - } - } - - init(resolver: Resolver) { - injectServices(resolver) - calibrations = storage.retrieve(OpenAPS.FreeAPS.calibrations, as: [Calibration].self) ?? [] - subscribe() - } - - private func subscribe() { - notificationCenter.publisher(for: .newSensorDetected) - .sink { [weak self] _ in - self?.removeAllCalibrations() - } - .store(in: &lifetime) - } - - var slope: Double { - guard calibrations.count >= 2 else { - return 1 - } - - let xs = calibrations.map(\.x) - let ys = calibrations.map(\.y) - let sum1 = average(multiply(xs, ys)) - average(xs) * average(ys) - let sum2 = average(multiply(xs, xs)) - pow(average(xs), 2) - let slope = sum1 / sum2 - - return min(max(slope, Config.minSlope), Config.maxSlope) - } - - var intercept: Double { - guard calibrations.count >= 1 else { - return 0 - } - let xs = calibrations.map(\.x) - let ys = calibrations.map(\.y) - - let intercept = average(ys) - slope * average(xs) - - return min(max(intercept, Config.minIntercept), Config.maxIntercept) - } - - func calibrate(value: Double) -> Double { - linearRegression(value) - } - - func addCalibration(_ calibration: Calibration) { - calibrations.append(calibration) - } - - func removeCalibration(_ calibration: Calibration) { - calibrations.removeAll { $0 == calibration } - } - - func removeAllCalibrations() { - calibrations.removeAll() - } - - func removeLast() { - calibrations.removeLast() - } - - private func average(_ input: [Double]) -> Double { - input.reduce(0, +) / Double(input.count) - } - - private func multiply(_ a: [Double], _ b: [Double]) -> [Double] { - zip(a, b).map(*) - } - - private func linearRegression(_ x: Double) -> Double { - (intercept + slope * x).clamped(Config.minValue ... Config.maxValue) - } -} diff --git a/FreeAPS/Sources/APS/CGM/DexcomSourceG5.swift b/FreeAPS/Sources/APS/CGM/DexcomSourceG5.swift deleted file mode 100644 index 831dfd2a5..000000000 --- a/FreeAPS/Sources/APS/CGM/DexcomSourceG5.swift +++ /dev/null @@ -1,184 +0,0 @@ -import CGMBLEKit -import Combine -import Foundation -import LoopKit -import LoopKitUI -import ShareClient - -final class DexcomSourceG5: GlucoseSource { - private let processQueue = DispatchQueue(label: "DexcomSource.processQueue") - private let glucoseStorage: GlucoseStorage! - var glucoseManager: FetchGlucoseManager? - - var cgmManager: CGMManagerUI? - var cgmType: CGMType = .dexcomG5 - - var cgmHasValidSensorSession: Bool = false - - private var promise: Future<[BloodGlucose], Error>.Promise? - - init(glucoseStorage: GlucoseStorage, glucoseManager: FetchGlucoseManager) { - self.glucoseStorage = glucoseStorage - self.glucoseManager = glucoseManager - cgmManager = G5CGMManager - .init(state: TransmitterManagerState( - transmitterID: UserDefaults.standard - .dexcomTransmitterID ?? "000000", - shouldSyncToRemoteService: glucoseManager.settingsManager.settings.uploadGlucose - )) - cgmManager?.cgmManagerDelegate = self - } - - var transmitterID: String { - guard let cgmG5Manager = cgmManager as? G5CGMManager else { return "000000" } - return cgmG5Manager.transmitter.ID - } - - func fetch(_: DispatchTimer?) -> AnyPublisher<[BloodGlucose], Never> { - Future<[BloodGlucose], Error> { [weak self] promise in - self?.promise = promise - } - .timeout(60 * 5, scheduler: processQueue, options: nil, customError: nil) - .replaceError(with: []) - .replaceEmpty(with: []) - .eraseToAnyPublisher() - } - - func fetchIfNeeded() -> AnyPublisher<[BloodGlucose], Never> { - Future<[BloodGlucose], Error> { _ in - self.processQueue.async { - guard let cgmManager = self.cgmManager else { return } - cgmManager.fetchNewDataIfNeeded { result in - self.processCGMReadingResult(cgmManager, readingResult: result) { - // nothing to do - } - } - } - } - .timeout(60, scheduler: processQueue, options: nil, customError: nil) - .replaceError(with: []) - .replaceEmpty(with: []) - .eraseToAnyPublisher() - } - - deinit { - // dexcomManager.transmitter.stopScanning() - } -} - -extension DexcomSourceG5: CGMManagerDelegate { - func deviceManager( - _: LoopKit.DeviceManager, - logEventForDeviceIdentifier deviceIdentifier: String?, - type _: LoopKit.DeviceLogEntryType, - message: String, - completion _: ((Error?) -> Void)? - ) { - debug(.deviceManager, "device Manager for \(String(describing: deviceIdentifier)) : \(message)") - } - - func issueAlert(_: LoopKit.Alert) {} - - func retractAlert(identifier _: LoopKit.Alert.Identifier) {} - - func doesIssuedAlertExist(identifier _: LoopKit.Alert.Identifier, completion _: @escaping (Result) -> Void) {} - - func lookupAllUnretracted( - managerIdentifier _: String, - completion _: @escaping (Result<[LoopKit.PersistedAlert], Error>) -> Void - ) {} - - func lookupAllUnacknowledgedUnretracted( - managerIdentifier _: String, - completion _: @escaping (Result<[LoopKit.PersistedAlert], Error>) -> Void - ) {} - - func recordRetractedAlert(_: LoopKit.Alert, at _: Date) {} - - func cgmManagerWantsDeletion(_ manager: CGMManager) { - dispatchPrecondition(condition: .onQueue(.main)) - debug(.deviceManager, " CGM Manager with identifier \(manager.managerIdentifier) wants deletion") - glucoseManager?.cgmGlucoseSourceType = nil - } - - func cgmManager(_ manager: CGMManager, hasNew readingResult: CGMReadingResult) { - dispatchPrecondition(condition: .onQueue(.main)) - processCGMReadingResult(manager, readingResult: readingResult) { - debug(.deviceManager, "DEXCOM - Direct return done") - } - } - - func startDateToFilterNewData(for _: CGMManager) -> Date? { - dispatchPrecondition(condition: .onQueue(.main)) - return glucoseStorage.lastGlucoseDate() - // return glucoseStore.latestGlucose?.startDate - } - - func cgmManagerDidUpdateState(_ manager: CGMManager) { - dispatchPrecondition(condition: .onQueue(processQueue)) - guard let g5Manager = manager as? TransmitterManager else { - return - } - glucoseManager?.settingsManager.settings.uploadGlucose = g5Manager.shouldSyncToRemoteService - UserDefaults.standard.dexcomTransmitterID = g5Manager.rawState["transmitterID"] as? String - } - - func credentialStoragePrefix(for _: CGMManager) -> String { - // return string unique to this instance of the CGMManager - UUID().uuidString - } - - func cgmManager(_: CGMManager, didUpdate status: CGMManagerStatus) { - DispatchQueue.main.async { - if self.cgmHasValidSensorSession != status.hasValidSensorSession { - self.cgmHasValidSensorSession = status.hasValidSensorSession - } - } - } - - private func processCGMReadingResult( - _: CGMManager, - readingResult: CGMReadingResult, - completion: @escaping () -> Void - ) { - debug(.deviceManager, "DEXCOM - Process CGM Reading Result launched") - switch readingResult { - case let .newData(values): - let bloodGlucose = values.compactMap { newGlucoseSample -> BloodGlucose? in - let quantity = newGlucoseSample.quantity - let value = Int(quantity.doubleValue(for: .milligramsPerDeciliter)) - return BloodGlucose( - _id: UUID().uuidString, - sgv: value, - direction: .init(trendType: newGlucoseSample.trend), - date: Decimal(Int(newGlucoseSample.date.timeIntervalSince1970 * 1000)), - dateString: newGlucoseSample.date, - unfiltered: Decimal(value), - filtered: nil, - noise: nil, - glucose: value, - type: "sgv", - transmitterID: self.transmitterID - ) - } - promise?(.success(bloodGlucose)) - completion() - case .unreliableData: - // loopManager.receivedUnreliableCGMReading() - promise?(.failure(GlucoseDataError.unreliableData)) - completion() - case .noData: - promise?(.failure(GlucoseDataError.noData)) - completion() - case let .error(error): - promise?(.failure(error)) - completion() - } - } -} - -extension DexcomSourceG5 { - func sourceInfo() -> [String: Any]? { - [GlucoseSourceKey.description.rawValue: "Dexcom tramsmitter ID: \(transmitterID)"] - } -} diff --git a/FreeAPS/Sources/APS/CGM/DexcomSourceG6.swift b/FreeAPS/Sources/APS/CGM/DexcomSourceG6.swift deleted file mode 100644 index ad5a3afee..000000000 --- a/FreeAPS/Sources/APS/CGM/DexcomSourceG6.swift +++ /dev/null @@ -1,195 +0,0 @@ -import CGMBLEKit -import Combine -import Foundation -import LoopKit -import LoopKitUI -import ShareClient - -final class DexcomSourceG6: GlucoseSource { - private let processQueue = DispatchQueue(label: "DexcomSource.processQueue") - private let glucoseStorage: GlucoseStorage! - var glucoseManager: FetchGlucoseManager? - - var cgmManager: CGMManagerUI? - var cgmType: CGMType = .dexcomG6 - - var cgmHasValidSensorSession: Bool = false - - private var promise: Future<[BloodGlucose], Error>.Promise? - - init(glucoseStorage: GlucoseStorage, glucoseManager: FetchGlucoseManager) { - self.glucoseStorage = glucoseStorage - self.glucoseManager = glucoseManager - cgmManager = G6CGMManager - .init(state: TransmitterManagerState( - transmitterID: UserDefaults.standard - .dexcomTransmitterID ?? "000000", - shouldSyncToRemoteService: glucoseManager.settingsManager.settings.uploadGlucose - )) - cgmManager?.delegateQueue = processQueue - cgmManager?.cgmManagerDelegate = self - } - - var transmitterID: String { - guard let cgmG6Manager = cgmManager as? G6CGMManager else { return "000000" } - return cgmG6Manager.transmitter.ID - } - - func fetch(_: DispatchTimer?) -> AnyPublisher<[BloodGlucose], Never> { - Future<[BloodGlucose], Error> { [weak self] promise in - self?.promise = promise - } - .timeout(60 * 5, scheduler: processQueue, options: nil, customError: nil) - .replaceError(with: []) - .replaceEmpty(with: []) - .eraseToAnyPublisher() - } - - func fetchIfNeeded() -> AnyPublisher<[BloodGlucose], Never> { - Future<[BloodGlucose], Error> { _ in - self.processQueue.async { - guard let cgmManager = self.cgmManager else { return } - cgmManager.fetchNewDataIfNeeded { result in - self.processCGMReadingResult(cgmManager, readingResult: result) { - // nothing to do - } - } - } - } - .timeout(60, scheduler: processQueue, options: nil, customError: nil) - .replaceError(with: []) - .replaceEmpty(with: []) - .eraseToAnyPublisher() - } - - deinit { - // dexcomManager.transmitter.stopScanning() - } -} - -extension DexcomSourceG6: CGMManagerDelegate { - func deviceManager( - _: LoopKit.DeviceManager, - logEventForDeviceIdentifier deviceIdentifier: String?, - type _: LoopKit.DeviceLogEntryType, - message: String, - completion _: ((Error?) -> Void)? - ) { - debug(.deviceManager, "device Manager for \(String(describing: deviceIdentifier)) : \(message)") - } - - func issueAlert(_: LoopKit.Alert) {} - - func retractAlert(identifier _: LoopKit.Alert.Identifier) {} - - func doesIssuedAlertExist(identifier _: LoopKit.Alert.Identifier, completion _: @escaping (Result) -> Void) {} - - func lookupAllUnretracted( - managerIdentifier _: String, - completion _: @escaping (Result<[LoopKit.PersistedAlert], Error>) -> Void - ) {} - - func lookupAllUnacknowledgedUnretracted( - managerIdentifier _: String, - completion _: @escaping (Result<[LoopKit.PersistedAlert], Error>) -> Void - ) {} - - func recordRetractedAlert(_: LoopKit.Alert, at _: Date) {} - - func cgmManagerWantsDeletion(_ manager: CGMManager) { - dispatchPrecondition(condition: .onQueue(processQueue)) - debug(.deviceManager, " CGM Manager with identifier \(manager.managerIdentifier) wants deletion") - glucoseManager?.cgmGlucoseSourceType = nil - } - - func cgmManager(_ manager: CGMManager, hasNew readingResult: CGMReadingResult) { - dispatchPrecondition(condition: .onQueue(processQueue)) - processCGMReadingResult(manager, readingResult: readingResult) { - debug(.deviceManager, "DEXCOM - Direct return done") - } - } - - func startDateToFilterNewData(for _: CGMManager) -> Date? { - dispatchPrecondition(condition: .onQueue(processQueue)) - return glucoseStorage.lastGlucoseDate() - // return glucoseStore.latestGlucose?.startDate - } - - func cgmManagerDidUpdateState(_ manager: CGMManager) { - dispatchPrecondition(condition: .onQueue(processQueue)) - guard let g6Manager = manager as? TransmitterManager else { - return - } - glucoseManager?.settingsManager.settings.uploadGlucose = g6Manager.shouldSyncToRemoteService - UserDefaults.standard.dexcomTransmitterID = g6Manager.rawState["transmitterID"] as? String - } - - func credentialStoragePrefix(for _: CGMManager) -> String { - // return string unique to this instance of the CGMManager - UUID().uuidString - } - - func cgmManager(_: CGMManager, didUpdate status: CGMManagerStatus) { - processQueue.async { - if self.cgmHasValidSensorSession != status.hasValidSensorSession { - self.cgmHasValidSensorSession = status.hasValidSensorSession - } - } - } - - private func processCGMReadingResult( - _: CGMManager, - readingResult: CGMReadingResult, - completion: @escaping () -> Void - ) { - debug(.deviceManager, "DEXCOM - Process CGM Reading Result launched with \(readingResult)") - switch readingResult { - case let .newData(values): - if let cgmG6Manager = cgmManager as? G6CGMManager, - let activationDate = cgmG6Manager.latestReading?.activationDate, - let sessionStartDate = cgmG6Manager.latestReading?.sessionStartDate - { - let bloodGlucose = values.compactMap { newGlucoseSample -> BloodGlucose? in - let quantity = newGlucoseSample.quantity - let value = Int(quantity.doubleValue(for: .milligramsPerDeciliter)) - return BloodGlucose( - _id: UUID().uuidString, - sgv: value, - direction: .init(trendType: newGlucoseSample.trend), - date: Decimal(Int(newGlucoseSample.date.timeIntervalSince1970 * 1000)), - dateString: newGlucoseSample.date, - unfiltered: Decimal(value), - filtered: nil, - noise: nil, - glucose: value, - type: "sgv", - activationDate: activationDate, - sessionStartDate: sessionStartDate, - transmitterID: self.transmitterID - ) - } - promise?(.success(bloodGlucose)) - completion() - } else { - // Handle the case where activationDate or sessionStartDate is nil - completion() - } - case .unreliableData: - // loopManager.receivedUnreliableCGMReading() - promise?(.failure(GlucoseDataError.unreliableData)) - completion() - case .noData: - promise?(.failure(GlucoseDataError.noData)) - completion() - case let .error(error): - promise?(.failure(error)) - completion() - } - } -} - -extension DexcomSourceG6 { - func sourceInfo() -> [String: Any]? { - [GlucoseSourceKey.description.rawValue: "Dexcom tramsmitter ID: \(transmitterID)"] - } -} diff --git a/FreeAPS/Sources/APS/CGM/GlucoseSimulatorSource.swift b/FreeAPS/Sources/APS/CGM/GlucoseSimulatorSource.swift index 5dbb0efeb..145f5ebc9 100644 --- a/FreeAPS/Sources/APS/CGM/GlucoseSimulatorSource.swift +++ b/FreeAPS/Sources/APS/CGM/GlucoseSimulatorSource.swift @@ -29,7 +29,6 @@ import LoopKitUI final class GlucoseSimulatorSource: GlucoseSource { var cgmManager: CGMManagerUI? var glucoseManager: FetchGlucoseManager? - var cgmType: CGMType = .simulator private enum Config { // min time period to publish data diff --git a/FreeAPS/Sources/APS/CGM/GlucoseSource.swift b/FreeAPS/Sources/APS/CGM/GlucoseSource.swift index 6e3a9f183..dc576010f 100644 --- a/FreeAPS/Sources/APS/CGM/GlucoseSource.swift +++ b/FreeAPS/Sources/APS/CGM/GlucoseSource.swift @@ -11,7 +11,6 @@ protocol GlucoseSource: SourceInfoProvider { func fetchIfNeeded() -> AnyPublisher<[BloodGlucose], Never> var glucoseManager: FetchGlucoseManager? { get set } var cgmManager: CGMManagerUI? { get set } - var cgmType: CGMType { get } } extension GlucoseSource { diff --git a/FreeAPS/Sources/APS/CGM/LibreTransmitterSource.swift b/FreeAPS/Sources/APS/CGM/LibreTransmitterSource.swift deleted file mode 100644 index 49b430f71..000000000 --- a/FreeAPS/Sources/APS/CGM/LibreTransmitterSource.swift +++ /dev/null @@ -1,103 +0,0 @@ -import Combine -import Foundation -import LibreTransmitter -import LoopKitUI -import Swinject - -protocol LibreTransmitterSource: GlucoseSource { - var manager: LibreTransmitterManager? { get set } -} - -final class BaseLibreTransmitterSource: LibreTransmitterSource, Injectable { - var cgmManager: CGMManagerUI? - var cgmType: CGMType = .libreTransmitter - - private let processQueue = DispatchQueue(label: "BaseLibreTransmitterSource.processQueue") - - @Injected() var glucoseStorage: GlucoseStorage! - @Injected() var calibrationService: CalibrationService! - - private var promise: Future<[BloodGlucose], Error>.Promise? - - var glucoseManager: FetchGlucoseManager? - - var manager: LibreTransmitterManager? { - didSet { - configured = manager != nil - manager?.cgmManagerDelegate = self - } - } - - @Persisted(key: "LibreTransmitterManager.configured") private(set) var configured = false - - init(resolver: Resolver) { - if configured { - manager = LibreTransmitterManager() - manager?.cgmManagerDelegate = self - } - injectServices(resolver) - } - - func fetch(_: DispatchTimer?) -> AnyPublisher<[BloodGlucose], Never> { - Future<[BloodGlucose], Error> { [weak self] promise in - self?.promise = promise - } - .timeout(60, scheduler: processQueue, options: nil, customError: nil) - .replaceError(with: []) - .replaceEmpty(with: []) - .eraseToAnyPublisher() - } - - func fetchIfNeeded() -> AnyPublisher<[BloodGlucose], Never> { - fetch(nil) - } - - func sourceInfo() -> [String: Any]? { - if let battery = manager?.battery { - return ["transmitterBattery": battery] - } - return nil - } -} - -extension BaseLibreTransmitterSource: LibreTransmitterManagerDelegate { - var queue: DispatchQueue { processQueue } - - func startDateToFilterNewData(for _: LibreTransmitterManager) -> Date? { - glucoseStorage.syncDate() - } - - func cgmManager(_ manager: LibreTransmitterManager, hasNew result: Result<[LibreGlucose], Error>) { - switch result { - case let .success(newGlucose): - let glucose = newGlucose.map { value -> BloodGlucose in - BloodGlucose( - _id: UUID().uuidString, - sgv: Int(value.glucose), - direction: manager.glucoseDisplay?.trendType - .map { .init(trendType: $0) }, - date: Decimal(Int(value.startDate.timeIntervalSince1970 * 1000)), - dateString: value.startDate, - unfiltered: Decimal(value.unsmoothedGlucose), - filtered: nil, - noise: nil, - glucose: Int(value.glucose), - type: "sgv", - activationDate: value.sensorStartDate ?? manager.sensorStartDate, - sessionStartDate: value.sensorStartDate ?? manager.sensorStartDate, - transmitterID: manager.sensorSerialNumber - ) - } - NSLog("Debug Libre \(glucose)") - promise?(.success(glucose)) - - case let .failure(error): - warning(.service, "LibreTransmitter error:", error: error) - promise?(.failure(error)) - } - } - - func overcalibration(for _: LibreTransmitterManager) -> ((Double) -> (Double))? { - calibrationService.calibrate - } -} diff --git a/FreeAPS/Sources/APS/CGM/dexcomSourceG7.swift b/FreeAPS/Sources/APS/CGM/PluginSource.swift similarity index 77% rename from FreeAPS/Sources/APS/CGM/dexcomSourceG7.swift rename to FreeAPS/Sources/APS/CGM/PluginSource.swift index ddb54b3cd..8cf840cf1 100644 --- a/FreeAPS/Sources/APS/CGM/dexcomSourceG7.swift +++ b/FreeAPS/Sources/APS/CGM/PluginSource.swift @@ -1,17 +1,15 @@ - import Combine import Foundation -import G7SensorKit import LoopKit import LoopKitUI -final class DexcomSourceG7: GlucoseSource { +final class PluginSource: GlucoseSource { private let processQueue = DispatchQueue(label: "DexcomSource.processQueue") - private var glucoseStorage: GlucoseStorage! + private let glucoseStorage: GlucoseStorage! var glucoseManager: FetchGlucoseManager? var cgmManager: CGMManagerUI? - var cgmType: CGMType = .dexcomG7 + var cgmHasValidSensorSession: Bool = false private var promise: Future<[BloodGlucose], Error>.Promise? @@ -19,14 +17,10 @@ final class DexcomSourceG7: GlucoseSource { init(glucoseStorage: GlucoseStorage, glucoseManager: FetchGlucoseManager) { self.glucoseStorage = glucoseStorage self.glucoseManager = glucoseManager - cgmManager = G7CGMManager() - cgmManager?.cgmManagerDelegate = self - cgmManager?.delegateQueue = processQueue - // initial value of upload Readings - if let cgmManagerG7 = cgmManager as? G7CGMManager { - cgmManagerG7.uploadReadings = glucoseManager.settingsManager.settings.uploadGlucose - } + cgmManager = glucoseManager.cgmManager + cgmManager?.delegateQueue = processQueue + cgmManager?.cgmManagerDelegate = self } func fetch(_: DispatchTimer?) -> AnyPublisher<[BloodGlucose], Never> { @@ -61,7 +55,7 @@ final class DexcomSourceG7: GlucoseSource { } } -extension DexcomSourceG7: CGMManagerDelegate { +extension PluginSource: CGMManagerDelegate { func deviceManager( _: LoopKit.DeviceManager, logEventForDeviceIdentifier deviceIdentifier: String?, @@ -92,26 +86,37 @@ extension DexcomSourceG7: CGMManagerDelegate { func cgmManagerWantsDeletion(_ manager: CGMManager) { dispatchPrecondition(condition: .onQueue(processQueue)) - debug(.deviceManager, " CGM Manager with identifier \(manager.managerIdentifier) wants deletion") + debug(.deviceManager, " CGM Manager with identifier \(manager.pluginIdentifier) wants deletion") + // TODO: glucoseManager?.cgmGlucoseSourceType = nil } func cgmManager(_ manager: CGMManager, hasNew readingResult: CGMReadingResult) { dispatchPrecondition(condition: .onQueue(processQueue)) processCGMReadingResult(manager, readingResult: readingResult) { - debug(.deviceManager, "DEXCOM - Direct return done") + debug(.deviceManager, "CGM PLUGIN - Direct return done") } } + func cgmManager(_: LoopKit.CGMManager, hasNew events: [LoopKit.PersistedCgmEvent]) { + dispatchPrecondition(condition: .onQueue(processQueue)) + // TODO: Events in APS ? + // currently only display in log the date of the event + events.forEach { debug(.deviceManager, "events from CGM at \($0.date)") } + } + func startDateToFilterNewData(for _: CGMManager) -> Date? { dispatchPrecondition(condition: .onQueue(processQueue)) return glucoseStorage.lastGlucoseDate() } - func cgmManagerDidUpdateState(_ cgmManager: CGMManager) { - if let cgmManagerG7 = cgmManager as? G7CGMManager { - glucoseManager?.settingsManager.settings.uploadGlucose = cgmManagerG7.uploadReadings - } + func cgmManagerDidUpdateState(_: CGMManager) { + dispatchPrecondition(condition: .onQueue(processQueue)) +// guard let g6Manager = manager as? TransmitterManager else { +// return +// } +// glucoseManager?.settingsManager.settings.uploadGlucose = g6Manager.shouldSyncToRemoteService +// UserDefaults.standard.dexcomTransmitterID = g6Manager.rawState["transmitterID"] as? String } func credentialStoragePrefix(for _: CGMManager) -> String { @@ -132,18 +137,10 @@ extension DexcomSourceG7: CGMManagerDelegate { readingResult: CGMReadingResult, completion: @escaping () -> Void ) { - debug(.deviceManager, "DEXCOMG7 - Process CGM Reading Result launched") + debug(.deviceManager, "PLUGIN CGM - Process CGM Reading Result launched with \(readingResult)") switch readingResult { case let .newData(values): - var activationDate: Date = .distantPast - var sessionStart: Date = .distantPast - if let cgmG7Manager = cgmManager as? G7CGMManager { - activationDate = cgmG7Manager.sensorActivatedAt ?? .distantPast - sessionStart = cgmG7Manager.sensorFinishesWarmupAt ?? .distantPast - print("Activastion date: " + activationDate.description) - } - let bloodGlucose = values.compactMap { newGlucoseSample -> BloodGlucose? in let quantity = newGlucoseSample.quantity let value = Int(quantity.doubleValue(for: .milligramsPerDeciliter)) @@ -157,14 +154,13 @@ extension DexcomSourceG7: CGMManagerDelegate { filtered: nil, noise: nil, glucose: value, - type: "sgv", - activationDate: activationDate, - sessionStartDate: sessionStart + type: "sgv" +// activationDate: activationDate, +// sessionStartDate: sessionStartDate +// transmitterID: self.transmitterID ) } - promise?(.success(bloodGlucose)) - completion() case .unreliableData: // loopManager.receivedUnreliableCGMReading() @@ -179,3 +175,9 @@ extension DexcomSourceG7: CGMManagerDelegate { } } } + +extension PluginSource { + func sourceInfo() -> [String: Any]? { + [GlucoseSourceKey.description.rawValue: "Plugin CGM source"] + } +} diff --git a/FreeAPS/Sources/APS/DeviceDataManager.swift b/FreeAPS/Sources/APS/DeviceDataManager.swift index 8d2abb088..3b6f71eab 100644 --- a/FreeAPS/Sources/APS/DeviceDataManager.swift +++ b/FreeAPS/Sources/APS/DeviceDataManager.swift @@ -37,10 +37,10 @@ private let staticPumpManagers: [PumpManagerUI.Type] = [ ] private let staticPumpManagersByIdentifier: [String: PumpManagerUI.Type] = [ - MinimedPumpManager.managerIdentifier: MinimedPumpManager.self, - OmnipodPumpManager.managerIdentifier: OmnipodPumpManager.self, - OmniBLEPumpManager.managerIdentifier: OmniBLEPumpManager.self, - MockPumpManager.managerIdentifier: MockPumpManager.self + MinimedPumpManager.pluginIdentifier: MinimedPumpManager.self, + OmnipodPumpManager.pluginIdentifier: OmnipodPumpManager.self, + OmniBLEPumpManager.pluginIdentifier: OmniBLEPumpManager.self, + MockPumpManager.pluginIdentifier: MockPumpManager.self ] // private let staticPumpManagersByIdentifier: [String: PumpManagerUI.Type] = staticPumpManagers.reduce(into: [:]) { map, Type in @@ -218,7 +218,6 @@ final class BaseDeviceDataManager: DeviceDataManager, Injectable { var glucoseManager: FetchGlucoseManager? var cgmManager: CGMManagerUI? - var cgmType: CGMType = .enlite func fetchIfNeeded() -> AnyPublisher<[BloodGlucose], Never> { fetch(nil) @@ -293,6 +292,18 @@ final class BaseDeviceDataManager: DeviceDataManager, Injectable { // MARK: - PumpManagerDelegate extension BaseDeviceDataManager: PumpManagerDelegate { + var automaticDosingEnabled: Bool { + settingsManager.settings.closedLoop // Take if close or open loop + } + + func pumpManager( + _: LoopKit.PumpManager, + didRequestBasalRateScheduleChange _: LoopKit.BasalRateSchedule, + completion _: @escaping (Error?) -> Void + ) { + debug(.deviceManager, "pumpManagerBasalRateChange") + } + func pumpManagerPumpWasReplaced(_: PumpManager) { debug(.deviceManager, "pumpManagerPumpWasReplaced") } @@ -433,6 +444,7 @@ extension BaseDeviceDataManager: PumpManagerDelegate { _: PumpManager, hasNewPumpEvents events: [NewPumpEvent], lastReconciliation _: Date?, + replacePendingEvents _: Bool, completion: @escaping (_ error: Error?) -> Void ) { dispatchPrecondition(condition: .onQueue(processQueue)) @@ -573,6 +585,8 @@ extension BaseDeviceDataManager: CGMManagerDelegate { func cgmManager(_: CGMManager, hasNew _: CGMReadingResult) {} + func cgmManager(_: LoopKit.CGMManager, hasNew _: [LoopKit.PersistedCgmEvent]) {} + func cgmManagerWantsDeletion(_: CGMManager) {} func cgmManagerDidUpdateState(_: CGMManager) {} diff --git a/FreeAPS/Sources/APS/Extensions/BloodGlucoseExtensions.swift b/FreeAPS/Sources/APS/Extensions/BloodGlucoseExtensions.swift index 1ba06f67b..9cd7ee081 100644 --- a/FreeAPS/Sources/APS/Extensions/BloodGlucoseExtensions.swift +++ b/FreeAPS/Sources/APS/Extensions/BloodGlucoseExtensions.swift @@ -47,23 +47,4 @@ extension BloodGlucose.Direction { self = .none } } - - init(trendType: LibreTransmitter.GlucoseTrend) { - switch trendType { - case .upUpUp: - self = .doubleUp - case .upUp: - self = .singleUp - case .up: - self = .fortyFiveUp - case .flat: - self = .flat - case .down: - self = .fortyFiveDown - case .downDown: - self = .singleDown - case .downDownDown: - self = .doubleDown - } - } } diff --git a/FreeAPS/Sources/APS/Extensions/LoopUIColorPalette+Default.swift b/FreeAPS/Sources/APS/Extensions/LoopUIColorPalette+Default.swift index 890247a8e..1b1fe5f1d 100644 --- a/FreeAPS/Sources/APS/Extensions/LoopUIColorPalette+Default.swift +++ b/FreeAPS/Sources/APS/Extensions/LoopUIColorPalette+Default.swift @@ -26,7 +26,8 @@ extension ChartColorPalette { axisLabel: .axisLabelColor, grid: .gridColor, glucoseTint: .glucoseTintColor, - insulinTint: .insulinTintColor + insulinTint: .insulinTintColor, + carbTint: .carbTintColor ) } } diff --git a/FreeAPS/Sources/APS/Extensions/PumpManagerExtensions.swift b/FreeAPS/Sources/APS/Extensions/PumpManagerExtensions.swift index e3ad89c76..237aaa8d8 100644 --- a/FreeAPS/Sources/APS/Extensions/PumpManagerExtensions.swift +++ b/FreeAPS/Sources/APS/Extensions/PumpManagerExtensions.swift @@ -4,7 +4,7 @@ import LoopKitUI extension PumpManager { var rawValue: [String: Any] { [ - "managerIdentifier": managerIdentifier, // "managerIdentifier": type(of: self).managerIdentifier, + "managerIdentifier": pluginIdentifier, // "managerIdentifier": type(of: self).managerIdentifier, "state": rawState ] } @@ -26,7 +26,7 @@ extension PumpManagerUI { var vc = settingsViewController( bluetoothProvider: bluetoothProvider, colorPalette: .default, - allowDebugFeatures: false, + allowDebugFeatures: true, allowedInsulinTypes: [.apidra, .humalog, .novolog, .fiasp, .lyumjev] ) vc.pumpManagerOnboardingDelegate = pumpManagerOnboardingDelegate diff --git a/FreeAPS/Sources/APS/FetchGlucoseManager.swift b/FreeAPS/Sources/APS/FetchGlucoseManager.swift index 98da3c076..b0de0f881 100644 --- a/FreeAPS/Sources/APS/FetchGlucoseManager.swift +++ b/FreeAPS/Sources/APS/FetchGlucoseManager.swift @@ -1,5 +1,7 @@ import Combine import Foundation +import LoopKit +import LoopKitUI import SwiftDate import Swinject import UIKit @@ -7,10 +9,20 @@ import UIKit protocol FetchGlucoseManager: SourceInfoProvider { func updateGlucoseStore(newBloodGlucose: [BloodGlucose]) func refreshCGM() - func updateGlucoseSource() + func updateGlucoseSource(cgmGlucoseSourceType: CGMType, cgmGlucosePluginId: String, newManager: CGMManagerUI?) + func deleteGlucoseSource() var glucoseSource: GlucoseSource! { get } + var cgmManager: CGMManagerUI? { get } var cgmGlucoseSourceType: CGMType? { get set } + var cgmGlucosePluginId: String? { get } var settingsManager: SettingsManager! { get } + var shouldSyncToRemoteService: Bool { get } +} + +extension FetchGlucoseManager { + func updateGlucoseSource(cgmGlucoseSourceType: CGMType, cgmGlucosePluginId: String) { + updateGlucoseSource(cgmGlucoseSourceType: cgmGlucoseSourceType, cgmGlucosePluginId: cgmGlucosePluginId, newManager: nil) + } } final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable { @@ -19,56 +31,99 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable { @Injected() var nightscoutManager: NightscoutManager! @Injected() var apsManager: APSManager! @Injected() var settingsManager: SettingsManager! - @Injected() var libreTransmitter: LibreTransmitterSource! @Injected() var healthKitManager: HealthKitManager! @Injected() var deviceDataManager: DeviceDataManager! + @Injected() var pluginCGMManager: PluginManager! private var lifetime = Lifetime() private let timer = DispatchTimer(timeInterval: 1.minutes.timeInterval) var cgmGlucoseSourceType: CGMType? + var cgmGlucosePluginId: String? + var cgmManager: CGMManagerUI? { + didSet { + rawCGMManager = cgmManager?.rawValue + } + } + + @PersistedProperty(key: "CGMManagerState") var rawCGMManager: CGMManager.RawValue? - private lazy var dexcomSourceG5 = DexcomSourceG5(glucoseStorage: glucoseStorage, glucoseManager: self) - private lazy var dexcomSourceG6 = DexcomSourceG6(glucoseStorage: glucoseStorage, glucoseManager: self) - private lazy var dexcomSourceG7 = DexcomSourceG7(glucoseStorage: glucoseStorage, glucoseManager: self) private lazy var simulatorSource = GlucoseSimulatorSource() + var shouldSyncToRemoteService: Bool { + guard let cgmManager = cgmManager else { + return true + } + return cgmManager.shouldSyncToRemoteService + } + init(resolver: Resolver) { injectServices(resolver) - updateGlucoseSource() + updateGlucoseSource( + cgmGlucoseSourceType: settingsManager.settings.cgm, + cgmGlucosePluginId: settingsManager.settings.cgmPluginIdentifier + ) subscribe() } var glucoseSource: GlucoseSource! - func updateGlucoseSource() { - switch settingsManager.settings.cgm { + func deleteGlucoseSource() { + cgmManager = nil + updateGlucoseSource( + cgmGlucoseSourceType: CGMType.none, + cgmGlucosePluginId: "" + ) + } + + func updateGlucoseSource(cgmGlucoseSourceType: CGMType, cgmGlucosePluginId: String, newManager: CGMManagerUI?) { + self.cgmGlucoseSourceType = cgmGlucoseSourceType + self.cgmGlucosePluginId = cgmGlucosePluginId + + // if not plugin, manager is not changed and stay with the "old" value if the user come back to previous cgmtype + // if plugin, if the same pluginID, no change required because the manager is available + // if plugin, if not the same pluginID, need to reset the cgmManager + // if plugin and newManager provides, update cgmManager + debug(.apsManager, "plugin : \(String(describing: cgmManager?.pluginIdentifier))") + if let manager = newManager + { + cgmManager = manager + } else if self.cgmGlucoseSourceType == .plugin, cgmManager == nil, let rawCGMManager = rawCGMManager { + cgmManager = cgmManagerFromRawValue(rawCGMManager) + } +// } else if self.cgmGlucoseSourceType == .plugin, self.cgmGlucosePluginId != , self.cgmGlucosePluginId != cgmManager?.pluginIdentifier { +// cgmManager = nil +// } + + switch self.cgmGlucoseSourceType { + case nil, + .none?: + glucoseSource = nil case .xdrip: glucoseSource = AppGroupSource(from: "xDrip", cgmType: .xdrip) - case .dexcomG5: - glucoseSource = dexcomSourceG5 - case .dexcomG6: - glucoseSource = dexcomSourceG6 - case .dexcomG7: - glucoseSource = dexcomSourceG7 case .nightscout: glucoseSource = nightscoutManager case .simulator: glucoseSource = simulatorSource - case .libreTransmitter: - glucoseSource = libreTransmitter case .glucoseDirect: glucoseSource = AppGroupSource(from: "GlucoseDirect", cgmType: .glucoseDirect) case .enlite: glucoseSource = deviceDataManager + case .plugin: + glucoseSource = PluginSource(glucoseStorage: glucoseStorage, glucoseManager: self) } // update the config - cgmGlucoseSourceType = settingsManager.settings.cgm + } - if settingsManager.settings.cgm != .libreTransmitter { - libreTransmitter.manager = nil - } else { - libreTransmitter.glucoseManager = self + /// Upload cgmManager from raw value + func cgmManagerFromRawValue(_ rawValue: [String: Any]) -> CGMManagerUI? { + guard let rawState = rawValue["state"] as? CGMManager.RawStateValue, + let cgmGlucosePluginId = self.cgmGlucosePluginId, + let Manager = pluginCGMManager.getCGMManagerTypeByIdentifier(cgmGlucosePluginId) + else { + return nil } + + return Manager.init(rawState: rawState) } /// function called when a callback is fired by CGM BLE - no more used @@ -81,7 +136,8 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable { /// function to try to force the refresh of the CGM - generally provide by the pump heartbeat public func refreshCGM() { debug(.deviceManager, "refreshCGM by pump") - updateGlucoseSource() + // updateGlucoseSource(cgmGlucoseSourceType: settingsManager.settings.cgm, cgmGlucosePluginId: settingsManager.settings.cgmPluginIdentifier) + Publishers.CombineLatest3( Just(glucoseStorage.syncDate()), healthKitManager.fetch(nil), @@ -176,8 +232,12 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable { .receive(on: processQueue) .flatMap { _ -> AnyPublisher<[BloodGlucose], Never> in debug(.nightscout, "FetchGlucoseManager timer heartbeat") - self.updateGlucoseSource() - return self.glucoseSource.fetch(self.timer).eraseToAnyPublisher() + // self.updateGlucoseSource(manager: nil) + if let glucoseSource = self.glucoseSource { + return glucoseSource.fetch(self.timer).eraseToAnyPublisher() + } else { + return Empty(completeImmediately: false).eraseToAnyPublisher() + } } .sink { glucose in debug(.nightscout, "FetchGlucoseManager callback sensor") @@ -199,22 +259,6 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable { .store(in: &lifetime) timer.fire() timer.resume() - - UserDefaults.standard - .publisher(for: \.dexcomTransmitterID) - .removeDuplicates() - .sink { id in - if self.settingsManager.settings.cgm == .dexcomG5 { - if id != self.dexcomSourceG5.transmitterID { - self.dexcomSourceG5 = DexcomSourceG5(glucoseStorage: self.glucoseStorage, glucoseManager: self) - } - } else if self.settingsManager.settings.cgm == .dexcomG6 { - if id != self.dexcomSourceG6.transmitterID { - self.dexcomSourceG6 = DexcomSourceG6(glucoseStorage: self.glucoseStorage, glucoseManager: self) - } - } - } - .store(in: &lifetime) } func sourceInfo() -> [String: Any]? { @@ -222,13 +266,13 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable { } } -extension UserDefaults { - @objc var dexcomTransmitterID: String? { - get { - string(forKey: "DexcomSource.transmitterID")?.nonEmpty - } - set { - set(newValue, forKey: "DexcomSource.transmitterID") - } +extension CGMManager { + typealias RawValue = [String: Any] + + var rawValue: [String: Any] { + [ + "managerIdentifier": pluginIdentifier, + "state": rawState + ] } } diff --git a/FreeAPS/Sources/APS/PluginManager.swift b/FreeAPS/Sources/APS/PluginManager.swift new file mode 100644 index 000000000..8f66f4f9a --- /dev/null +++ b/FreeAPS/Sources/APS/PluginManager.swift @@ -0,0 +1,277 @@ +import Foundation +import LoopKit +import LoopKitUI +import Swinject + +protocol PluginManager { + var availablePumpManagers: [PumpManagerDescriptor] { get } + var availableCGMManagers: [CGMManagerDescriptor] { get } + func getPumpManagerTypeByIdentifier(_ identifier: String) -> PumpManagerUI.Type? + func getCGMManagerTypeByIdentifier(_ identifier: String) -> CGMManagerUI.Type? +} + +class BasePluginManager: Injectable, PluginManager { + let pluginBundles: [Bundle] + + init(resolver: Resolver) { + let pluginsURL: URL? = Bundle.main.privateFrameworksURL + var bundles = [Bundle]() + + if let pluginsURL = pluginsURL { + do { + for pluginURL in try FileManager.default.contentsOfDirectory(at: pluginsURL, includingPropertiesForKeys: nil) + .filter({ $0.path.hasSuffix(".framework") }) + { + if let bundle = Bundle(url: pluginURL) { + if let bname = bundle.object(forInfoDictionaryKey: "CFBundleName") as? String { + debug(.deviceManager, "bundle name2:\(bname)") + } + if let bcgm = bundle.object(forInfoDictionaryKey: "com.loopkit.Loop.CGMManagerIdentifier") as? String { + debug(.deviceManager, "bundle is CGM") + } + + if bundle.isLoopPlugin { + debug(.deviceManager, "Found loop plugin:\(pluginURL.absoluteString)") + bundles.append(bundle) + } + } + } + } catch { + debug(.deviceManager, "Error loading plugin: \(error)") + } + } + pluginBundles = bundles + injectServices(resolver) + } + + func getPumpManagerTypeByIdentifier(_ identifier: String) -> PumpManagerUI.Type? { + for bundle in pluginBundles { + if let name = bundle.object(forInfoDictionaryKey: LoopPluginBundleKey.pumpManagerIdentifier.rawValue) as? String, + name == identifier + { + do { + try bundle.loadAndReturnError() + + if let principalClass = bundle.principalClass as? NSObject.Type { + if let plugin = principalClass.init() as? PumpManagerUIPlugin { + return plugin.pumpManagerType + } else { + fatalError("PrincipalClass does not conform to PumpManagerUIPlugin") + } + + } else { + fatalError("PrincipalClass not found") + } + } catch { + debug(.deviceManager, "Error loading plugin: \(error)") + } + } + } + return nil + } + + var availablePumpManagers: [PumpManagerDescriptor] { + pluginBundles.compactMap({ (bundle) -> PumpManagerDescriptor? in + guard let title = bundle.object(forInfoDictionaryKey: LoopPluginBundleKey.pumpManagerDisplayName.rawValue) as? String, + let identifier = bundle + .object(forInfoDictionaryKey: LoopPluginBundleKey.pumpManagerIdentifier.rawValue) as? String + else { + return nil + } + + return PumpManagerDescriptor(identifier: identifier, localizedTitle: title) + }) + } + + func getCGMManagerTypeByIdentifier(_ identifier: String) -> CGMManagerUI.Type? { + for bundle in pluginBundles { + if let name = bundle.object(forInfoDictionaryKey: LoopPluginBundleKey.cgmManagerIdentifier.rawValue) as? String, + name == identifier + { + do { + try bundle.loadAndReturnError() + + if let principalClass = bundle.principalClass as? NSObject.Type { + if let plugin = principalClass.init() as? CGMManagerUIPlugin { + return plugin.cgmManagerType + } else { + fatalError("PrincipalClass does not conform to CGMManagerUIPlugin") + } + + } else { + fatalError("PrincipalClass not found") + } + } catch { + debug(.deviceManager, "Error loading plugin: \(error)") + } + } + } + return nil + } + + var availableCGMManagers: [CGMManagerDescriptor] { + pluginBundles.compactMap({ (bundle) -> CGMManagerDescriptor? in + guard let title = bundle.object(forInfoDictionaryKey: LoopPluginBundleKey.cgmManagerDisplayName.rawValue) as? String, + let identifier = bundle + .object(forInfoDictionaryKey: LoopPluginBundleKey.cgmManagerIdentifier.rawValue) as? String + else { + return nil + } + + return CGMManagerDescriptor(identifier: identifier, localizedTitle: title) + }) + } + + func getServiceTypeByIdentifier(_ identifier: String) -> ServiceUI.Type? { + for bundle in pluginBundles { + if let name = bundle.object(forInfoDictionaryKey: LoopPluginBundleKey.serviceIdentifier.rawValue) as? String, + name == identifier + { + do { + try bundle.loadAndReturnError() + + if let principalClass = bundle.principalClass as? NSObject.Type { + if let plugin = principalClass.init() as? ServiceUIPlugin { + return plugin.serviceType + } else { + fatalError("PrincipalClass does not conform to ServiceUIPlugin") + } + + } else { + fatalError("PrincipalClass not found") + } + } catch { + debug(.deviceManager, "Error loading plugin: \(error)") + } + } + } + return nil + } + + var availableServices: [ServiceDescriptor] { + pluginBundles.compactMap({ (bundle) -> ServiceDescriptor? in + guard let title = bundle.object(forInfoDictionaryKey: LoopPluginBundleKey.serviceDisplayName.rawValue) as? String, + let identifier = bundle.object(forInfoDictionaryKey: LoopPluginBundleKey.serviceIdentifier.rawValue) as? String + else { + return nil + } + + return ServiceDescriptor(identifier: identifier, localizedTitle: title) + }) + } + + func getStatefulPluginTypeByIdentifier(_ identifier: String) -> StatefulPluggable.Type? { + for bundle in pluginBundles { + if let name = bundle.object(forInfoDictionaryKey: LoopPluginBundleKey.statefulPluginIdentifier.rawValue) as? String, + name == identifier + { + do { + try bundle.loadAndReturnError() + + if let principalClass = bundle.principalClass as? NSObject.Type { + if let plugin = principalClass.init() as? StatefulPlugin { + return plugin.pluginType + } else { + fatalError("PrincipalClass does not conform to StatefulPlugin") + } + + } else { + fatalError("PrincipalClass not found") + } + } catch { + debug(.deviceManager, "Error loading plugin: \(error)") + } + } + } + return nil + } + + var availableStatefulPluginIdentifiers: [String] { + pluginBundles.compactMap({ (bundle) -> String? in + bundle.object(forInfoDictionaryKey: LoopPluginBundleKey.statefulPluginIdentifier.rawValue) as? String + }) + } + + func getOnboardingTypeByIdentifier(_ identifier: String) -> OnboardingUI.Type? { + for bundle in pluginBundles { + if let name = bundle.object(forInfoDictionaryKey: LoopPluginBundleKey.onboardingIdentifier.rawValue) as? String, + name == identifier + { + do { + try bundle.loadAndReturnError() + + if let principalClass = bundle.principalClass as? NSObject.Type { + if let plugin = principalClass.init() as? OnboardingUIPlugin { + return plugin.onboardingType + } else { + fatalError("PrincipalClass does not conform to OnboardingUIPlugin") + } + + } else { + fatalError("PrincipalClass not found") + } + } catch { + debug(.deviceManager, "Error loading plugin: \(error)") + } + } + } + return nil + } + + var availableOnboardingIdentifiers: [String] { + pluginBundles.compactMap({ (bundle) -> String? in + bundle.object(forInfoDictionaryKey: LoopPluginBundleKey.onboardingIdentifier.rawValue) as? String + }) + } + + func getSupportUITypeByIdentifier(_ identifier: String) -> SupportUI.Type? { + for bundle in pluginBundles { + if let name = bundle.object(forInfoDictionaryKey: LoopPluginBundleKey.supportIdentifier.rawValue) as? String, + name == identifier + { + do { + try bundle.loadAndReturnError() + + if let principalClass = bundle.principalClass as? NSObject.Type { + if let plugin = principalClass.init() as? SupportUIPlugin { + return type(of: plugin.support) + } else { + fatalError("PrincipalClass does not conform to SupportUIPlugin") + } + + } else { + fatalError("PrincipalClass not found") + } + } catch { + debug(.deviceManager, "Error loading plugin: \(error)") + } + } + } + return nil + } +} + +extension Bundle { + var isPumpManagerPlugin: Bool { + object(forInfoDictionaryKey: LoopPluginBundleKey.pumpManagerIdentifier.rawValue) as? String != nil } + + var isCGMManagerPlugin: Bool { + object(forInfoDictionaryKey: LoopPluginBundleKey.cgmManagerIdentifier.rawValue) as? String != nil } + + var isStatefulPlugin: Bool { + object(forInfoDictionaryKey: LoopPluginBundleKey.statefulPluginIdentifier.rawValue) as? String != nil } + + var isServicePlugin: Bool { object(forInfoDictionaryKey: LoopPluginBundleKey.serviceIdentifier.rawValue) as? String != nil } + var isOnboardingPlugin: Bool { + object(forInfoDictionaryKey: LoopPluginBundleKey.onboardingIdentifier.rawValue) as? String != nil } + + var isSupportPlugin: Bool { object(forInfoDictionaryKey: LoopPluginBundleKey.supportIdentifier.rawValue) as? String != nil } + + var isLoopPlugin: Bool { + isPumpManagerPlugin || isCGMManagerPlugin || isStatefulPlugin || isServicePlugin || isOnboardingPlugin || isSupportPlugin + } + + var isLoopExtension: Bool { object(forInfoDictionaryKey: LoopPluginBundleKey.extensionIdentifier.rawValue) as? String != nil } + + var isSimulator: Bool { object(forInfoDictionaryKey: LoopPluginBundleKey.pluginIsSimulator.rawValue) as? Bool == true } +} diff --git a/FreeAPS/Sources/Application/FreeAPSApp.swift b/FreeAPS/Sources/Application/FreeAPSApp.swift index 907e4f010..b6e344605 100644 --- a/FreeAPS/Sources/Application/FreeAPSApp.swift +++ b/FreeAPS/Sources/Application/FreeAPSApp.swift @@ -45,6 +45,7 @@ import Swinject _ = resolver.resolve(WatchManager.self)! _ = resolver.resolve(HealthKitManager.self)! _ = resolver.resolve(BluetoothStateManager.self)! + _ = resolver.resolve(PluginManager.self)! } init() { diff --git a/FreeAPS/Sources/Assemblies/APSAssembly.swift b/FreeAPS/Sources/Assemblies/APSAssembly.swift index 5385deae7..d5d3253ce 100644 --- a/FreeAPS/Sources/Assemblies/APSAssembly.swift +++ b/FreeAPS/Sources/Assemblies/APSAssembly.swift @@ -3,13 +3,12 @@ import Swinject final class APSAssembly: Assembly { func assemble(container: Container) { - container.register(CalibrationService.self) { r in BaseCalibrationService(resolver: r) } - container.register(LibreTransmitterSource.self) { r in BaseLibreTransmitterSource(resolver: r) } container.register(DeviceDataManager.self) { r in BaseDeviceDataManager(resolver: r) } container.register(APSManager.self) { r in BaseAPSManager(resolver: r) } container.register(FetchGlucoseManager.self) { r in BaseFetchGlucoseManager(resolver: r) } container.register(FetchTreatmentsManager.self) { r in BaseFetchTreatmentsManager(resolver: r) } container.register(FetchAnnouncementsManager.self) { r in BaseFetchAnnouncementsManager(resolver: r) } container.register(BluetoothStateManager.self) { r in BaseBluetoothStateManager(resolver: r) } + container.register(PluginManager.self) { r in BasePluginManager(resolver: r) } } } diff --git a/FreeAPS/Sources/Helpers/PropertyWrappers/PersistedProperty.swift b/FreeAPS/Sources/Helpers/PropertyWrappers/PersistedProperty.swift index e8f74554b..3e50baa15 100644 --- a/FreeAPS/Sources/Helpers/PropertyWrappers/PersistedProperty.swift +++ b/FreeAPS/Sources/Helpers/PropertyWrappers/PersistedProperty.swift @@ -48,3 +48,53 @@ import Foundation } } } + +@propertyWrapper public struct PersistedProperty { + let key: String + let storageURL: URL + + public init(key: String) { + self.key = key + + let documents: URL + + guard let localDocuments = try? FileManager.default.url( + for: .documentDirectory, + in: .userDomainMask, + appropriateFor: nil, + create: true + ) else { + preconditionFailure("Could not get a documents directory URL.") + } + documents = localDocuments + storageURL = documents.appendingPathComponent(key + ".plist") + } + + public var wrappedValue: Value? { + get { + do { + let data = try Data(contentsOf: storageURL) + + guard let value = try PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? Value + else { + return nil + } + return value + } catch {} + return nil + } + set { + guard let newValue = newValue else { + do { + try FileManager.default.removeItem(at: storageURL) + } catch {} + return + } + do { + let data = try PropertyListSerialization.data(fromPropertyList: newValue, format: .binary, options: 0) + try data.write(to: storageURL, options: .atomic) + + } catch {} + } + } +} diff --git a/FreeAPS/Sources/Models/FreeAPSSettings.swift b/FreeAPS/Sources/Models/FreeAPSSettings.swift index 1c9a07c2c..e1fd443f7 100644 --- a/FreeAPS/Sources/Models/FreeAPSSettings.swift +++ b/FreeAPS/Sources/Models/FreeAPSSettings.swift @@ -12,7 +12,8 @@ struct FreeAPSSettings: JSON, Equatable { var insulinReqPercentage: Decimal = 70 var skipBolusScreenAfterCarbs: Bool = false var displayHR: Bool = false - var cgm: CGMType = .nightscout + var cgm: CGMType = .none + var cgmPluginIdentifier: String = "" var uploadGlucose: Bool = true var useCalendar: Bool = false var glucoseBadge: Bool = false @@ -105,6 +106,10 @@ extension FreeAPSSettings: Decodable { settings.cgm = cgm } + if let cgmPluginIdentifier = try? container.decode(String.self, forKey: .cgmPluginIdentifier) { + settings.cgmPluginIdentifier = cgmPluginIdentifier + } + if let uploadGlucose = try? container.decode(Bool.self, forKey: .uploadGlucose) { settings.uploadGlucose = uploadGlucose } diff --git a/FreeAPS/Sources/Modules/CGM/CGMStateModel.swift b/FreeAPS/Sources/Modules/CGM/CGMStateModel.swift index cc7190c8b..e12f21fc8 100644 --- a/FreeAPS/Sources/Modules/CGM/CGMStateModel.swift +++ b/FreeAPS/Sources/Modules/CGM/CGMStateModel.swift @@ -4,25 +4,67 @@ import G7SensorKit import LoopKitUI import SwiftUI +struct cgmName: Identifiable, Hashable { + var id: String + var type: CGMType + var displayName: String + var subtitle: String +} + +let cgmDefaultName = cgmName( + id: CGMType.none.id, + type: .none, + displayName: CGMType.none.displayName, + subtitle: CGMType.none.subtitle +) + extension CGM { final class StateModel: BaseStateModel { - @Injected() var libreSource: LibreTransmitterSource! @Injected() var cgmManager: FetchGlucoseManager! @Injected() var calendarManager: CalendarManager! + @Injected() var pluginCGMManager: PluginManager! @Published var setupCGM: Bool = false - @Published var cgm: CGMType = .nightscout - // @Published var transmitterID = "" - @Published var uploadGlucose = true + @Published var cgmCurrent = cgmDefaultName @Published var smoothGlucose = false @Published var createCalendarEvents = false @Published var calendarIDs: [String] = [] @Published var currentCalendarID: String = "" @Persisted(key: "CalendarManager.currentCalendarID") var storedCalendarID: String? = nil @Published var cgmTransmitterDeviceAddress: String? = nil + @Published var listOfCGM: [cgmName] = [] override func subscribe() { - cgm = settingsManager.settings.cgm + // collect the list of CGM available with plugins and CGMType defined manually + listOfCGM = CGMType.allCases.filter { $0 != CGMType.plugin }.map { + cgmName(id: $0.id, type: $0, displayName: $0.displayName, subtitle: $0.subtitle) + } + + pluginCGMManager.availableCGMManagers.map { + cgmName(id: $0.identifier, type: CGMType.plugin, displayName: $0.localizedTitle, subtitle: $0.localizedTitle) + } + + switch settingsManager.settings.cgm { + case .plugin: + if let cgmPluginInfo = listOfCGM.first(where: { $0.id == settingsManager.settings.cgmPluginIdentifier }) { + cgmCurrent = cgmName( + id: settingsManager.settings.cgmPluginIdentifier, + type: .plugin, + displayName: cgmPluginInfo.displayName, + subtitle: cgmPluginInfo.subtitle + ) + } else { + // no more type of plugin available - restart to defaut + cgmCurrent = cgmDefaultName + } + default: + cgmCurrent = cgmName( + id: settingsManager.settings.cgm.id, + type: settingsManager.settings.cgm, + displayName: settingsManager.settings.cgm.displayName, + subtitle: settingsManager.settings.cgm.subtitle + ) + } + currentCalendarID = storedCalendarID ?? "" calendarIDs = calendarManager.calendarIDs() cgmTransmitterDeviceAddress = UserDefaults.standard.cgmTransmitterDeviceAddress @@ -30,7 +72,7 @@ extension CGM { subscribeSetting(\.useCalendar, on: $createCalendarEvents) { createCalendarEvents = $0 } subscribeSetting(\.smoothGlucose, on: $smoothGlucose, initial: { smoothGlucose = $0 }) - $cgm + $cgmCurrent .removeDuplicates() .sink { [weak self] value in guard let self = self else { return } @@ -38,7 +80,16 @@ extension CGM { self.settingsManager.settings.cgm = .nightscout return } - self.settingsManager.settings.cgm = value + if value.type != self.settingsManager.settings.cgm || + value.id != self.settingsManager.settings.cgmPluginIdentifier + { + self.settingsManager.settings.cgm = value.type + self.settingsManager.settings.cgmPluginIdentifier = value.id + self.cgmManager.updateGlucoseSource( + cgmGlucoseSourceType: value.type, + cgmGlucosePluginId: value.id + ) + } } .store(in: &lifetime) @@ -73,26 +124,35 @@ extension CGM { extension CGM.StateModel: CompletionDelegate { func completionNotifyingDidComplete(_: CompletionNotifying) { setupCGM = false + // if CGM was deleted if cgmManager.cgmGlucoseSourceType == nil { - cgm = .nightscout + cgmCurrent = cgmDefaultName + settingsManager.settings.cgm = cgmDefaultName.type + settingsManager.settings.cgmPluginIdentifier = cgmDefaultName.id + cgmManager.deleteGlucoseSource() + } else { + cgmManager.updateGlucoseSource(cgmGlucoseSourceType: cgmCurrent.type, cgmGlucosePluginId: cgmCurrent.id) } + // refresh the upload options - uploadGlucose = settingsManager.settings.uploadGlucose - cgmManager.updateGlucoseSource() + settingsManager.settings.uploadGlucose = cgmManager.shouldSyncToRemoteService + + // update if required the Glucose source } } extension CGM.StateModel: CGMManagerOnboardingDelegate { func cgmManagerOnboarding(didCreateCGMManager manager: LoopKitUI.CGMManagerUI) { - // Possibility add the dexcom number ! - if let dexcomG6Manager: G6CGMManager = manager as? G6CGMManager { - UserDefaults.standard.dexcomTransmitterID = dexcomG6Manager.transmitter.ID + // update the setting of upload Glucose in services + settingsManager.settings.uploadGlucose = cgmManager.shouldSyncToRemoteService - } else if let dexcomG5Manager: G5CGMManager = manager as? G5CGMManager { - UserDefaults.standard.dexcomTransmitterID = dexcomG5Manager.transmitter.ID - } - cgmManager.updateGlucoseSource() + // update the glucose source + cgmManager.updateGlucoseSource( + cgmGlucoseSourceType: cgmCurrent.type, + cgmGlucosePluginId: cgmCurrent.id, + newManager: manager + ) } func cgmManagerOnboarding(didOnboardCGMManager _: LoopKitUI.CGMManagerUI) { diff --git a/FreeAPS/Sources/Modules/CGM/View/CGMRootView.swift b/FreeAPS/Sources/Modules/CGM/View/CGMRootView.swift index 6dddaa0d5..6a80023b5 100644 --- a/FreeAPS/Sources/Modules/CGM/View/CGMRootView.swift +++ b/FreeAPS/Sources/Modules/CGM/View/CGMRootView.swift @@ -14,28 +14,28 @@ extension CGM { NavigationView { Form { Section(header: Text("CGM")) { - Picker("Type", selection: $state.cgm) { - ForEach(CGMType.allCases) { type in + Picker("Type", selection: $state.cgmCurrent) { + ForEach(state.listOfCGM) { type in VStack(alignment: .leading) { Text(type.displayName) Text(type.subtitle).font(.caption).foregroundColor(.secondary) }.tag(type) } } - if let link = state.cgm.externalLink { + if let link = state.cgmCurrent.type.externalLink { Button("About this source") { UIApplication.shared.open(link, options: [:], completionHandler: nil) } } } - if [.dexcomG5, .dexcomG6, .dexcomG7].contains(state.cgm) { + if state.cgmCurrent.type == .plugin { Section { Button("CGM Configuration") { setupCGM.toggle() } } } - if state.cgm == .xdrip { + if state.cgmCurrent.type == .xdrip { Section(header: Text("Heartbeat")) { VStack(alignment: .leading) { if let cgmTransmitterDeviceAddress = state.cgmTransmitterDeviceAddress { @@ -47,12 +47,6 @@ extension CGM { } } } - if state.cgm == .libreTransmitter { - Button("Configure Libre Transmitter") { - state.showModal(for: .libreConfig) - } - Text("Calibrations").navigationLink(to: .calibrations, from: self) - } Section(header: Text("Calendar")) { Toggle("Create events in calendar", isOn: $state.createCalendarEvents) if state.calendarIDs.isNotEmpty { @@ -73,20 +67,25 @@ extension CGM { .navigationTitle("CGM") .navigationBarTitleDisplayMode(.automatic) .sheet(isPresented: $setupCGM) { - if let cgmFetchManager = state.cgmManager, cgmFetchManager.glucoseSource.cgmType == state.cgm { + if let cgmFetchManager = state.cgmManager, + let cgmManager = cgmFetchManager.cgmManager, + state.cgmCurrent.type == cgmFetchManager.cgmGlucoseSourceType, + state.cgmCurrent.id == cgmFetchManager.cgmGlucosePluginId + { CGMSettingsView( - cgmManager: cgmFetchManager.glucoseSource.cgmManager!, + cgmManager: cgmManager, bluetoothManager: state.provider.apsManager.bluetoothManager!, unit: state.settingsManager.settings.units, completionDelegate: state ) } else { CGMSetupView( - CGMType: state.cgm, + CGMType: state.cgmCurrent, bluetoothManager: state.provider.apsManager.bluetoothManager!, unit: state.settingsManager.settings.units, completionDelegate: state, - setupDelegate: state + setupDelegate: state, + pluginCGMManager: self.state.pluginCGMManager ) } } diff --git a/FreeAPS/Sources/Modules/CGM/View/CGMSettingsView.swift b/FreeAPS/Sources/Modules/CGM/View/CGMSettingsView.swift index 6dbf24394..074dcf591 100644 --- a/FreeAPS/Sources/Modules/CGM/View/CGMSettingsView.swift +++ b/FreeAPS/Sources/Modules/CGM/View/CGMSettingsView.swift @@ -5,23 +5,25 @@ import UIKit extension CGM { struct CGMSettingsView: UIViewControllerRepresentable { - let cgmManager: CGMManagerUI + let cgmManager: CGMManagerUI? let bluetoothManager: BluetoothStateManager let unit: GlucoseUnits weak var completionDelegate: CompletionDelegate? func makeUIViewController(context _: UIViewControllerRepresentableContext) -> UIViewController { - let displayGlucoseUnitObservable: DisplayGlucoseUnitObservable + let displayGlucosePreference: DisplayGlucosePreference switch unit { case .mgdL: - displayGlucoseUnitObservable = DisplayGlucoseUnitObservable(displayGlucoseUnit: .milligramsPerDeciliter) + displayGlucosePreference = DisplayGlucosePreference(displayGlucoseUnit: .milligramsPerDeciliter) case .mmolL: - displayGlucoseUnitObservable = DisplayGlucoseUnitObservable(displayGlucoseUnit: .millimolesPerLiter) + displayGlucosePreference = DisplayGlucosePreference(displayGlucoseUnit: .millimolesPerLiter) } + guard let cgmManager = cgmManager else { return UIViewController() } + var vc = cgmManager.settingsViewController( bluetoothProvider: bluetoothManager, - displayGlucoseUnitObservable: displayGlucoseUnitObservable, + displayGlucosePreference: displayGlucosePreference, colorPalette: .default, allowDebugFeatures: false ) diff --git a/FreeAPS/Sources/Modules/CGM/View/CGMSetupView.swift b/FreeAPS/Sources/Modules/CGM/View/CGMSetupView.swift index a192c8189..a53857300 100644 --- a/FreeAPS/Sources/Modules/CGM/View/CGMSetupView.swift +++ b/FreeAPS/Sources/Modules/CGM/View/CGMSetupView.swift @@ -1,7 +1,3 @@ -import CGMBLEKit -import CGMBLEKitUI -import G7SensorKit -import G7SensorKitUI import LoopKit import LoopKitUI import SwiftUI @@ -9,11 +5,12 @@ import UIKit extension CGM { struct CGMSetupView: UIViewControllerRepresentable { - let CGMType: CGMType + let CGMType: cgmName let bluetoothManager: BluetoothStateManager let unit: GlucoseUnits weak var completionDelegate: CompletionDelegate? weak var setupDelegate: CGMManagerOnboardingDelegate? + let pluginCGMManager: PluginManager func makeUIViewController(context _: UIViewControllerRepresentableContext) -> UIViewController { var setupViewController: SetupUIResult< @@ -21,37 +18,27 @@ extension CGM { CGMManagerUI >? - let displayGlucoseUnitObservable: DisplayGlucoseUnitObservable + let displayGlucosePreference: DisplayGlucosePreference switch unit { case .mgdL: - displayGlucoseUnitObservable = DisplayGlucoseUnitObservable(displayGlucoseUnit: .milligramsPerDeciliter) + displayGlucosePreference = DisplayGlucosePreference(displayGlucoseUnit: .milligramsPerDeciliter) case .mmolL: - displayGlucoseUnitObservable = DisplayGlucoseUnitObservable(displayGlucoseUnit: .millimolesPerLiter) + displayGlucosePreference = DisplayGlucosePreference(displayGlucoseUnit: .millimolesPerLiter) } - switch CGMType { - case .dexcomG5: - setupViewController = G5CGMManager.setupViewController( - bluetoothProvider: bluetoothManager, - displayGlucoseUnitObservable: displayGlucoseUnitObservable, - colorPalette: .default, - allowDebugFeatures: false - ) - case .dexcomG6: - setupViewController = G6CGMManager.setupViewController( - bluetoothProvider: bluetoothManager, - displayGlucoseUnitObservable: displayGlucoseUnitObservable, - colorPalette: .default, - allowDebugFeatures: false - ) - case .dexcomG7: - setupViewController = - G7CGMManager.setupViewController( + switch CGMType.type { + case .plugin: + if let cgmManagerUIType = pluginCGMManager.getCGMManagerTypeByIdentifier(CGMType.id) { + setupViewController = cgmManagerUIType.setupViewController( bluetoothProvider: bluetoothManager, - displayGlucoseUnitObservable: displayGlucoseUnitObservable, + displayGlucosePreference: displayGlucosePreference, colorPalette: .default, - allowDebugFeatures: false + allowDebugFeatures: false, + prefersToSkipUserInteraction: false ) + } else { + break + } default: break } diff --git a/FreeAPS/Sources/Modules/Calibrations/CalibrationsDataFlow.swift b/FreeAPS/Sources/Modules/Calibrations/CalibrationsDataFlow.swift deleted file mode 100644 index 2f385bdc0..000000000 --- a/FreeAPS/Sources/Modules/Calibrations/CalibrationsDataFlow.swift +++ /dev/null @@ -1,13 +0,0 @@ -enum Calibrations { - enum Config {} - - struct Item: Hashable, Identifiable { - let calibration: Calibration - - var id: String { - calibration.id.uuidString - } - } -} - -protocol CalibrationsProvider {} diff --git a/FreeAPS/Sources/Modules/Calibrations/CalibrationsProvider.swift b/FreeAPS/Sources/Modules/Calibrations/CalibrationsProvider.swift deleted file mode 100644 index 28e75281f..000000000 --- a/FreeAPS/Sources/Modules/Calibrations/CalibrationsProvider.swift +++ /dev/null @@ -1,3 +0,0 @@ -extension Calibrations { - final class Provider: BaseProvider, CalibrationsProvider {} -} diff --git a/FreeAPS/Sources/Modules/Calibrations/CalibrationsStateModel.swift b/FreeAPS/Sources/Modules/Calibrations/CalibrationsStateModel.swift deleted file mode 100644 index 67e459cc0..000000000 --- a/FreeAPS/Sources/Modules/Calibrations/CalibrationsStateModel.swift +++ /dev/null @@ -1,73 +0,0 @@ -import SwiftDate -import SwiftUI - -extension Calibrations { - final class StateModel: BaseStateModel { - @Injected() var glucoseStorage: GlucoseStorage! - @Injected() var calibrationService: CalibrationService! - - @Published var slope: Double = 1 - @Published var intercept: Double = 1 - @Published var newCalibration: Decimal = 0 - @Published var calibrations: [Calibration] = [] - @Published var calibrate: (Double) -> Double = { $0 } - @Published var items: [Item] = [] - - var units: GlucoseUnits = .mmolL - - override func subscribe() { - units = settingsManager.settings.units - calibrate = calibrationService.calibrate - setupCalibrations() - } - - private func setupCalibrations() { - slope = calibrationService.slope - intercept = calibrationService.intercept - calibrations = calibrationService.calibrations - items = calibrations.map { - Item(calibration: $0) - } - } - - func addCalibration() { - defer { - UIApplication.shared.endEditing() - setupCalibrations() - } - - var glucose = newCalibration - if units == .mmolL { - glucose = newCalibration.asMgdL - } - - guard let lastGlucose = glucoseStorage.recent().last, - lastGlucose.dateString.addingTimeInterval(60 * 4.5) > Date(), - let unfiltered = lastGlucose.unfiltered - else { - info(.service, "Glucose is stale for calibration") - return - } - - let calibration = Calibration(x: Double(unfiltered), y: Double(glucose)) - - calibrationService.addCalibration(calibration) - } - - func removeLast() { - calibrationService.removeLast() - setupCalibrations() - } - - func removeAll() { - calibrationService.removeAllCalibrations() - setupCalibrations() - } - - func removeAtIndex(_ index: Int) { - let calibration = calibrations[index] - calibrationService.removeCalibration(calibration) - setupCalibrations() - } - } -} diff --git a/FreeAPS/Sources/Modules/Calibrations/View/CalibrationsChart.swift b/FreeAPS/Sources/Modules/Calibrations/View/CalibrationsChart.swift deleted file mode 100644 index 2968ce86d..000000000 --- a/FreeAPS/Sources/Modules/Calibrations/View/CalibrationsChart.swift +++ /dev/null @@ -1,60 +0,0 @@ -import SwiftUI - -struct CalibrationsChart: View { - @EnvironmentObject var state: Calibrations.StateModel - - private var dateFormatter: DateFormatter { - let formatter = DateFormatter() - formatter.timeStyle = .short - formatter.dateStyle = .short - return formatter - } - - private let maxValue = 400.0 - - var body: some View { - GeometryReader { geo in - ZStack(alignment: .top) { - Rectangle().fill(Color.secondary) - .frame(height: geo.size.width) - Path { path in - let size = geo.size.width - path.move( - to: - CGPoint( - x: 0, - y: size - state.calibrate(0) / maxValue * geo.size.width - ) - ) - path.addLine( - to: CGPoint( - x: size, - y: size - state.calibrate(maxValue) / maxValue * geo.size.width - ) - ) - } - .stroke(.blue, lineWidth: 2) - - ForEach(state.calibrations, id: \.self) { value in - ZStack { - Circle().fill(.red) - .frame(width: 6, height: 6) - .position( - x: value.x / maxValue * geo.size.width, - y: geo.size.width - (value.y / maxValue * geo.size.width) - ) - Text(dateFormatter.string(from: value.date)) - .foregroundColor(.white) - .font(.system(size: 10)) - .position( - x: value.x / maxValue * geo.size.width, - y: geo.size.width - (value.y / maxValue * geo.size.width) + 10 - ) - } - } - } - .frame(height: geo.size.width) - .clipped() - } - } -} diff --git a/FreeAPS/Sources/Modules/Calibrations/View/CalibrationsRootView.swift b/FreeAPS/Sources/Modules/Calibrations/View/CalibrationsRootView.swift deleted file mode 100644 index e7fde5af9..000000000 --- a/FreeAPS/Sources/Modules/Calibrations/View/CalibrationsRootView.swift +++ /dev/null @@ -1,108 +0,0 @@ -import SwiftUI -import Swinject - -extension Calibrations { - struct RootView: BaseView { - let resolver: Resolver - @StateObject var state = StateModel() - - private var formatter: NumberFormatter { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.maximumFractionDigits = 2 - return formatter - } - - private var dateFormatter: DateFormatter { - let formatter = DateFormatter() - formatter.timeStyle = .short - formatter.dateStyle = .short - return formatter - } - - var body: some View { - GeometryReader { geo in - Form { - Section(header: Text("Add calibration")) { - HStack { - Text("Meter glucose") - Spacer() - DecimalTextField( - "0", - value: $state.newCalibration, - formatter: formatter, - autofocus: false, - cleanInput: true - ) - Text(state.units.rawValue).foregroundColor(.secondary) - } - Button { - state.addCalibration() - } - label: { Text("Add") } - .disabled(state.newCalibration <= 0) - } - - Section(header: Text("Info")) { - HStack { - Text("Slope") - Spacer() - Text(formatter.string(from: state.slope as NSNumber)!) - } - HStack { - Text("Intercept") - Spacer() - Text(formatter.string(from: state.intercept as NSNumber)!) - } - } - - Section(header: Text("Remove")) { - Button { - state.removeLast() - } - label: { Text("Remove Last") } - .disabled(state.calibrations.isEmpty) - - Button { - state.removeAll() - } - label: { Text("Remove All") } - .disabled(state.calibrations.isEmpty) - List { - ForEach(state.items) { item in - HStack { - Text(dateFormatter.string(from: item.calibration.date)) - Spacer() - VStack(alignment: .leading) { - Text("raw: \(item.calibration.x)") - .font(.caption2) - .foregroundColor(.secondary) - Text("value: \(item.calibration.y)") - .font(.caption2) - .foregroundColor(.secondary) - } - } - - }.onDelete(perform: delete) - } - } - - if state.calibrations.isNotEmpty { - Section(header: Text("Chart")) { - CalibrationsChart().environmentObject(state) - .frame(minHeight: geo.size.width) - } - } - } - } - .onAppear(perform: configureView) - .navigationTitle("Calibrations") - .navigationBarItems(trailing: EditButton().disabled(state.calibrations.isEmpty)) - .navigationBarTitleDisplayMode(.automatic) - } - - private func delete(at offsets: IndexSet) { - state.removeAtIndex(offsets[offsets.startIndex]) - } - } -} diff --git a/FreeAPS/Sources/Modules/Home/HomeStateModel.swift b/FreeAPS/Sources/Modules/Home/HomeStateModel.swift index ce2f41af0..40f870770 100644 --- a/FreeAPS/Sources/Modules/Home/HomeStateModel.swift +++ b/FreeAPS/Sources/Modules/Home/HomeStateModel.swift @@ -357,8 +357,8 @@ extension Home { url = URL(string: "spikeapp://")! case "http://127.0.0.1:17580": url = URL(string: "diabox://")! - case CGMType.libreTransmitter.appURL?.absoluteString: - showModal(for: .libreConfig) +// case CGMType.libreTransmitter.appURL?.absoluteString: +// showModal(for: .libreConfig) default: break } UIApplication.shared.open(url, options: [:], completionHandler: nil) diff --git a/FreeAPS/Sources/Modules/LibreConfig/LibreConfigDataFlow.swift b/FreeAPS/Sources/Modules/LibreConfig/LibreConfigDataFlow.swift deleted file mode 100644 index 0bf914907..000000000 --- a/FreeAPS/Sources/Modules/LibreConfig/LibreConfigDataFlow.swift +++ /dev/null @@ -1,5 +0,0 @@ -enum LibreConfig { - enum Config {} -} - -protocol LibreConfigProvider {} diff --git a/FreeAPS/Sources/Modules/LibreConfig/LibreConfigProvider.swift b/FreeAPS/Sources/Modules/LibreConfig/LibreConfigProvider.swift deleted file mode 100644 index f8234690f..000000000 --- a/FreeAPS/Sources/Modules/LibreConfig/LibreConfigProvider.swift +++ /dev/null @@ -1,3 +0,0 @@ -extension LibreConfig { - final class Provider: BaseProvider, LibreConfigProvider {} -} diff --git a/FreeAPS/Sources/Modules/LibreConfig/LibreConfigStateModel.swift b/FreeAPS/Sources/Modules/LibreConfig/LibreConfigStateModel.swift deleted file mode 100644 index d513847b4..000000000 --- a/FreeAPS/Sources/Modules/LibreConfig/LibreConfigStateModel.swift +++ /dev/null @@ -1,17 +0,0 @@ -import HealthKit -import SwiftUI - -extension LibreConfig { - final class StateModel: BaseStateModel { - @Injected() var source: LibreTransmitterSource! - - @Published var configured = false - - var unit = HKUnit.millimolesPerLiter - - override func subscribe() { - configured = source.manager != nil - unit = settingsManager.settings.units == .mmolL ? .millimolesPerLiter : .milligramsPerDeciliter - } - } -} diff --git a/FreeAPS/Sources/Modules/LibreConfig/View/LibreConfigRootView.swift b/FreeAPS/Sources/Modules/LibreConfig/View/LibreConfigRootView.swift deleted file mode 100644 index f0b2f3654..000000000 --- a/FreeAPS/Sources/Modules/LibreConfig/View/LibreConfigRootView.swift +++ /dev/null @@ -1,36 +0,0 @@ -import LibreTransmitter -import SwiftUI -import Swinject - -extension LibreConfig { - struct RootView: BaseView { - let resolver: Resolver - @StateObject var state = StateModel() - - var body: some View { - Group { - if state.configured, let manager = state.source.manager { - LibreTransmitterSettingsView( - manager: manager, - glucoseUnit: state.unit - ) { - self.state.source.manager = nil - self.state.configured = false - } completion: { - state.hideModal() - } - } else { - LibreTransmitterSetupView { manager in - self.state.source.manager = manager - self.state.configured = true - } completion: { - state.hideModal() - } - } - } - .navigationBarTitle("") - .navigationBarHidden(true) - .onAppear(perform: configureView) - } - } -} diff --git a/FreeAPS/Sources/Modules/NightscoutConfig/NightscoutConfigStateModel.swift b/FreeAPS/Sources/Modules/NightscoutConfig/NightscoutConfigStateModel.swift index 72bef139d..9ee7f5742 100644 --- a/FreeAPS/Sources/Modules/NightscoutConfig/NightscoutConfigStateModel.swift +++ b/FreeAPS/Sources/Modules/NightscoutConfig/NightscoutConfigStateModel.swift @@ -1,7 +1,5 @@ -import CGMBLEKit import Combine import CoreData -import G7SensorKit import LoopKit import SwiftDate import SwiftUI @@ -26,6 +24,7 @@ extension NightscoutConfig { @Published var isUploadEnabled = false // Allow uploads @Published var uploadStats = false // Upload Statistics @Published var uploadGlucose = true // Upload Glucose + @Published var changeUploadGlucose = true // if plugin, need to be change in CGM configuration @Published var useLocalSource = false @Published var localPort: Decimal = 0 @Published var units: GlucoseUnits = .mmolL @@ -41,23 +40,14 @@ extension NightscoutConfig { dia = settingsManager.pumpSettings.insulinActionCurve maxBasal = settingsManager.pumpSettings.maxBasal maxBolus = settingsManager.pumpSettings.maxBolus + changeUploadGlucose = (cgmManager.cgmGlucoseSourceType != CGMType.plugin) subscribeSetting(\.allowAnnouncements, on: $allowAnnouncements) { allowAnnouncements = $0 } subscribeSetting(\.isUploadEnabled, on: $isUploadEnabled) { isUploadEnabled = $0 } subscribeSetting(\.useLocalGlucoseSource, on: $useLocalSource) { useLocalSource = $0 } subscribeSetting(\.localGlucosePort, on: $localPort.map(Int.init)) { localPort = Decimal($0) } subscribeSetting(\.uploadStats, on: $uploadStats) { uploadStats = $0 } - subscribeSetting(\.uploadGlucose, on: $uploadGlucose, initial: { uploadGlucose = $0 }, didSet: { val in - if let cgmManagerG5 = self.cgmManager.glucoseSource.cgmManager as? G5CGMManager { - cgmManagerG5.shouldSyncToRemoteService = val - } - if let cgmManagerG6 = self.cgmManager.glucoseSource.cgmManager as? G6CGMManager { - cgmManagerG6.shouldSyncToRemoteService = val - } - if let cgmManagerG7 = self.cgmManager.glucoseSource.cgmManager as? G7CGMManager { - cgmManagerG7.uploadReadings = val - } - }) + subscribeSetting(\.uploadGlucose, on: $uploadGlucose, initial: { uploadGlucose = $0 }) } func connect() { diff --git a/FreeAPS/Sources/Modules/NightscoutConfig/View/NightscoutConfigRootView.swift b/FreeAPS/Sources/Modules/NightscoutConfig/View/NightscoutConfigRootView.swift index 6c07ccdea..f75e0f4da 100644 --- a/FreeAPS/Sources/Modules/NightscoutConfig/View/NightscoutConfigRootView.swift +++ b/FreeAPS/Sources/Modules/NightscoutConfig/View/NightscoutConfigRootView.swift @@ -58,7 +58,7 @@ extension NightscoutConfig { Toggle("Upload", isOn: $state.isUploadEnabled) if state.isUploadEnabled { Toggle("Statistics", isOn: $state.uploadStats) - Toggle("Glucose", isOn: $state.uploadGlucose) + Toggle("Glucose", isOn: $state.uploadGlucose).disabled(!state.changeUploadGlucose) } } header: { Text("Allow Uploads") diff --git a/FreeAPS/Sources/Modules/PumpConfig/View/PumpSetupView.swift b/FreeAPS/Sources/Modules/PumpConfig/View/PumpSetupView.swift index ffb6d528a..574ec2882 100644 --- a/FreeAPS/Sources/Modules/PumpConfig/View/PumpSetupView.swift +++ b/FreeAPS/Sources/Modules/PumpConfig/View/PumpSetupView.swift @@ -37,7 +37,8 @@ extension PumpConfig { initialSettings: initialSettings, bluetoothProvider: bluetoothManager, colorPalette: .default, - allowDebugFeatures: false, + allowDebugFeatures: true, + prefersToSkipUserInteraction: false, allowedInsulinTypes: [.apidra, .humalog, .novolog, .fiasp, .lyumjev] ) case .omnipod: @@ -45,7 +46,8 @@ extension PumpConfig { initialSettings: initialSettings, bluetoothProvider: bluetoothManager, colorPalette: .default, - allowDebugFeatures: false, + allowDebugFeatures: true, + prefersToSkipUserInteraction: false, allowedInsulinTypes: [.apidra, .humalog, .novolog, .fiasp, .lyumjev] ) case .omnipodBLE: @@ -53,7 +55,7 @@ extension PumpConfig { initialSettings: initialSettings, bluetoothProvider: bluetoothManager, colorPalette: .default, - allowDebugFeatures: false, + allowDebugFeatures: true, allowedInsulinTypes: [.apidra, .humalog, .novolog, .fiasp, .lyumjev] ) case .simulator: @@ -61,7 +63,8 @@ extension PumpConfig { initialSettings: initialSettings, bluetoothProvider: bluetoothManager, colorPalette: .default, - allowDebugFeatures: false, + allowDebugFeatures: true, + prefersToSkipUserInteraction: false, allowedInsulinTypes: [.apidra, .humalog, .novolog, .fiasp, .lyumjev] ) } diff --git a/FreeAPS/Sources/Router/Screen.swift b/FreeAPS/Sources/Router/Screen.swift index af152733c..5e281b38d 100644 --- a/FreeAPS/Sources/Router/Screen.swift +++ b/FreeAPS/Sources/Router/Screen.swift @@ -22,8 +22,6 @@ enum Screen: Identifiable, Hashable { case dataTable case cgm case healthkit - case libreConfig - case calibrations case notificationsConfig case fpuConfig case iconConfig @@ -79,10 +77,6 @@ extension Screen { CGM.RootView(resolver: resolver) case .healthkit: AppleHealthKit.RootView(resolver: resolver) - case .libreConfig: - LibreConfig.RootView(resolver: resolver) - case .calibrations: - Calibrations.RootView(resolver: resolver) case .notificationsConfig: NotificationsConfig.RootView(resolver: resolver) case .fpuConfig: diff --git a/FreeAPS/Sources/Services/HealthKit/HealthKitManager.swift b/FreeAPS/Sources/Services/HealthKit/HealthKitManager.swift index e098713b5..cf3d0279d 100644 --- a/FreeAPS/Sources/Services/HealthKit/HealthKitManager.swift +++ b/FreeAPS/Sources/Services/HealthKit/HealthKitManager.swift @@ -472,7 +472,6 @@ final class BaseHealthKitManager: HealthKitManager, Injectable, CarbsObserver { var glucoseManager: FetchGlucoseManager? var cgmManager: CGMManagerUI? - var cgmType: CGMType = .nightscout func fetch(_: DispatchTimer?) -> AnyPublisher<[BloodGlucose], Never> { Future { [weak self] promise in diff --git a/FreeAPS/Sources/Services/Network/NightscoutManager.swift b/FreeAPS/Sources/Services/Network/NightscoutManager.swift index 56458178d..ff5e26dc6 100644 --- a/FreeAPS/Sources/Services/Network/NightscoutManager.swift +++ b/FreeAPS/Sources/Services/Network/NightscoutManager.swift @@ -131,7 +131,6 @@ final class BaseNightscoutManager: NightscoutManager, Injectable { var glucoseManager: FetchGlucoseManager? var cgmManager: CGMManagerUI? - var cgmType: CGMType = .nightscout func fetch(_: DispatchTimer?) -> AnyPublisher<[BloodGlucose], Never> { fetchGlucose(since: glucoseStorage.syncDate()) diff --git a/FreeAPSTests/FileStorageTests.swift b/FreeAPSTests/FileStorageTests.swift index 4786a868b..676890046 100644 --- a/FreeAPSTests/FileStorageTests.swift +++ b/FreeAPSTests/FileStorageTests.swift @@ -4,11 +4,18 @@ import XCTest class FileStorageTests: XCTestCase { let fileStorage = BaseFileStorage() - struct DummyObject: JSON { + struct DummyObject: JSON, Equatable { let id: String let value: Decimal } + func testFileStorageOiAPS() { + let dummyObject = DummyObject(id: "21342Z", value: 78.2) + fileStorage.save(dummyObject, as: "dummyObject") + let dummyObjectRetrieve = fileStorage.retrieve("dummyObject", as: DummyObject.self) + XCTAssertTrue(dummyObject == dummyObjectRetrieve) + } + override func setUpWithError() throws { // Put setup code here. This method is called before the invocation of each test method in the class. } diff --git a/G7SensorKit b/G7SensorKit new file mode 160000 index 000000000..83d8aafd7 --- /dev/null +++ b/G7SensorKit @@ -0,0 +1 @@ +Subproject commit 83d8aafd7fc7630e51d7292bbb287d865aba72c7 diff --git a/LibreTransmitter b/LibreTransmitter new file mode 160000 index 000000000..c01eba63e --- /dev/null +++ b/LibreTransmitter @@ -0,0 +1 @@ +Subproject commit c01eba63e94e9f6f2841a8835680c4e39c61b18d diff --git a/LoopKit b/LoopKit new file mode 160000 index 000000000..2f535b3ca --- /dev/null +++ b/LoopKit @@ -0,0 +1 @@ +Subproject commit 2f535b3ca46825e82e0dd1b5ef9daccd53a3f0ca diff --git a/MinimedKit b/MinimedKit new file mode 160000 index 000000000..d29ee3611 --- /dev/null +++ b/MinimedKit @@ -0,0 +1 @@ +Subproject commit d29ee3611a31be1096c3886835e5fef081f8b211 diff --git a/OmniBLE b/OmniBLE new file mode 160000 index 000000000..bfe2795cb --- /dev/null +++ b/OmniBLE @@ -0,0 +1 @@ +Subproject commit bfe2795cb4933c5ecc6f6d8040aefc4b281563de diff --git a/OmniKit b/OmniKit new file mode 160000 index 000000000..a78fdcd96 --- /dev/null +++ b/OmniKit @@ -0,0 +1 @@ +Subproject commit a78fdcd96deb22638f8a3451468b0b18b70fd1d9 diff --git a/RileyLinkKit b/RileyLinkKit new file mode 160000 index 000000000..a0e419da3 --- /dev/null +++ b/RileyLinkKit @@ -0,0 +1 @@ +Subproject commit a0e419da314d0ad42b41ccb04af73cd1fbf41257 diff --git a/dexcom-share-client-swift b/dexcom-share-client-swift new file mode 160000 index 000000000..0f93513d5 --- /dev/null +++ b/dexcom-share-client-swift @@ -0,0 +1 @@ +Subproject commit 0f93513d5c306342c4d3ce85f5ab062da1e1b145 diff --git a/scripts/copy-plugins.sh b/scripts/copy-plugins.sh new file mode 100755 index 000000000..a81e22156 --- /dev/null +++ b/scripts/copy-plugins.sh @@ -0,0 +1,41 @@ +#!/bin/sh -e + +# copy-plugins.sh +# Loop +# +# Copyright © 2019 LoopKit Authors. All rights reserved. + + +shopt -s nullglob + +# Copy device plugins +function copy_plugins { + echo "Looking for plugins in $1" + for f in "$1"/*.loopplugin; do + plugin=$(basename "$f") + echo Copying plugin: $plugin to frameworks directory in app + plugin_path="$(readlink -f "$f" || echo "$f")" + plugin_as_framework_path="${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/${plugin%.*}.framework" + rsync -va --exclude=Frameworks "$plugin_path/." "${plugin_as_framework_path}" + # Rename .plugin to .framework + if [ "$EXPANDED_CODE_SIGN_IDENTITY" != "-" ] && [ "$EXPANDED_CODE_SIGN_IDENTITY" != "" ]; then + export CODESIGN_ALLOCATE=${DT_TOOLCHAIN_DIR}/usr/bin/codesign_allocate + echo "Signing ${plugin} with ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --timestamp=none --preserve-metadata=identifier,entitlements,flags "$plugin_as_framework_path" + else + echo "Skipping signing, no identity set" + fi + for framework_path in "${f}"/Frameworks/*.framework; do + framework=$(basename "$framework_path") + echo "Copying plugin's framework $framework_path to ${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/." + cp -avf "$framework_path" "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/." + plugin_path="$(readlink -f "$f" || echo "$f")" + if [ "$EXPANDED_CODE_SIGN_IDENTITY" != "-" ] && [ "$EXPANDED_CODE_SIGN_IDENTITY" != "" ]; then + echo "Signing $framework for $plugin with $EXPANDED_CODE_SIGN_IDENTITY_NAME" + /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --timestamp=none --preserve-metadata=identifier,entitlements,flags "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/${framework}" + fi + done + done +} + +copy_plugins "$BUILT_PRODUCTS_DIR" diff --git a/scripts/swiftformat.sh b/scripts/swiftformat.sh index d60d8f6c4..dc625331a 100755 --- a/scripts/swiftformat.sh +++ b/scripts/swiftformat.sh @@ -97,4 +97,4 @@ trailingClosures \ --typeattributes same-line \ --varattributes same-line \ --wrapcollections before-first \ ---exclude Pods,Generated,R.generated.swift,fastlane/swift,Dependencies +--exclude Pods,Generated,R.generated.swift,fastlane/swift,Dependencies, LoopKit, LibreTransmitter,G7SensorKit,OmniKit, dexcom-share-client-swift,CGMBLEKit,RileyLinkKit,OmniBLE,MinimedKit